aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap12
-rw-r--r--CREDITS8
-rw-r--r--Documentation/ABI/testing/debugfs-vfio25
-rw-r--r--Documentation/ABI/testing/sysfs-bus-cdx7
-rw-r--r--Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc16
-rw-r--r--Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm159
-rw-r--r--Documentation/ABI/testing/sysfs-bus-cxl34
-rw-r--r--Documentation/ABI/testing/sysfs-bus-i3c15
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio42
-rw-r--r--Documentation/ABI/testing/sysfs-class-led-trigger-netdev39
-rw-r--r--Documentation/ABI/testing/sysfs-class-led-trigger-tty56
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-initrd8
-rw-r--r--Documentation/ABI/testing/sysfs-nvmem-cells21
-rw-r--r--Documentation/PCI/boot-interrupts.rst2
-rw-r--r--Documentation/PCI/msi-howto.rst2
-rw-r--r--Documentation/RCU/checklist.rst25
-rw-r--r--Documentation/RCU/rcu_dereference.rst27
-rw-r--r--Documentation/RCU/torture.rst2
-rw-r--r--Documentation/admin-guide/acpi/cppc_sysfs.rst2
-rw-r--r--Documentation/admin-guide/devices.txt3
-rw-r--r--Documentation/admin-guide/features.rst2
-rw-r--r--Documentation/admin-guide/hw_random.rst5
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt20
-rw-r--r--Documentation/admin-guide/media/starfive_camss.rst72
-rw-r--r--Documentation/admin-guide/media/starfive_camss_graph.dot12
-rw-r--r--Documentation/admin-guide/media/v4l-drivers.rst1
-rw-r--r--Documentation/admin-guide/media/visl.rst2
-rw-r--r--Documentation/admin-guide/pm/amd-pstate.rst2
-rw-r--r--Documentation/admin-guide/sysrq.rst11
-rw-r--r--Documentation/arch/arc/features.rst2
-rw-r--r--Documentation/arch/arm/features.rst2
-rw-r--r--Documentation/arch/arm64/features.rst2
-rw-r--r--Documentation/arch/arm64/silicon-errata.rst10
-rw-r--r--Documentation/arch/loongarch/features.rst2
-rw-r--r--Documentation/arch/m68k/features.rst2
-rw-r--r--Documentation/arch/mips/features.rst2
-rw-r--r--Documentation/arch/nios2/features.rst2
-rw-r--r--Documentation/arch/openrisc/features.rst2
-rw-r--r--Documentation/arch/parisc/features.rst2
-rw-r--r--Documentation/arch/powerpc/features.rst2
-rw-r--r--Documentation/arch/riscv/features.rst2
-rw-r--r--Documentation/arch/riscv/hwprobe.rst122
-rw-r--r--Documentation/arch/s390/features.rst2
-rw-r--r--Documentation/arch/sh/features.rst2
-rw-r--r--Documentation/arch/sparc/features.rst2
-rw-r--r--Documentation/arch/x86/features.rst2
-rw-r--r--Documentation/arch/x86/tdx.rst207
-rw-r--r--Documentation/arch/xtensa/features.rst2
-rw-r--r--Documentation/core-api/workqueue.rst2
-rw-r--r--Documentation/dev-tools/kunit/running_tips.rst11
-rw-r--r--Documentation/devicetree/bindings/Makefile2
-rw-r--r--Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml2
-rw-r--r--Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt29
-rw-r--r--Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml1
-rw-r--r--Documentation/devicetree/bindings/arm/msm/qcom,idle-state.txt84
-rw-r--r--Documentation/devicetree/bindings/arm/qcom,coresight-remote-etm.yaml51
-rw-r--r--Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml20
-rw-r--r--Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml2
-rw-r--r--Documentation/devicetree/bindings/cache/qcom,llcc.yaml2
-rw-r--r--Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml2
-rw-r--r--Documentation/devicetree/bindings/clock/brcm,kona-ccu.txt138
-rw-r--r--Documentation/devicetree/bindings/clock/brcm,kona-ccu.yaml181
-rw-r--r--Documentation/devicetree/bindings/clock/fsl,imx93-anatop.yaml42
-rw-r--r--Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml1
-rw-r--r--Documentation/devicetree/bindings/clock/mediatek,ethsys.yaml55
-rw-r--r--Documentation/devicetree/bindings/clock/mediatek,mt7988-ethwarp.yaml52
-rw-r--r--Documentation/devicetree/bindings/clock/mediatek,mt7988-xfi-pll.yaml48
-rw-r--r--Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml2
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,a53pll.yaml1
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,gcc-ipq6018.yaml57
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml3
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,qdu1000-ecpricc.yaml68
-rw-r--r--Documentation/devicetree/bindings/clock/renesas,9series.yaml10
-rw-r--r--Documentation/devicetree/bindings/clock/silabs,si5351.txt126
-rw-r--r--Documentation/devicetree/bindings/clock/silabs,si5351.yaml265
-rw-r--r--Documentation/devicetree/bindings/clock/sophgo,cv1800-clk.yaml46
-rw-r--r--Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml76
-rw-r--r--Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml1
-rw-r--r--Documentation/devicetree/bindings/clock/xlnx,versal-clk.yaml31
-rw-r--r--Documentation/devicetree/bindings/connector/usb-connector.yaml124
-rw-r--r--Documentation/devicetree/bindings/cpu/idle-states.yaml81
-rw-r--r--Documentation/devicetree/bindings/display/panel/synaptics,r63353.yaml61
-rw-r--r--Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt49
-rw-r--r--Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml139
-rw-r--r--Documentation/devicetree/bindings/dts-coding-style.rst196
-rw-r--r--Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml4
-rw-r--r--Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt13
-rw-r--r--Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt20
-rw-r--r--Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt36
-rw-r--r--Documentation/devicetree/bindings/fpga/altr,freeze-bridge-controller.yaml41
-rw-r--r--Documentation/devicetree/bindings/fpga/altr,socfpga-fpga2sdram-bridge.yaml33
-rw-r--r--Documentation/devicetree/bindings/fpga/altr,socfpga-hps2fpga-bridge.yaml49
-rw-r--r--Documentation/devicetree/bindings/fpga/fpga-bridge.txt13
-rw-r--r--Documentation/devicetree/bindings/fpga/fpga-bridge.yaml30
-rw-r--r--Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml5
-rw-r--r--Documentation/devicetree/bindings/gnss/u-blox,neo-6m.yaml6
-rw-r--r--Documentation/devicetree/bindings/gpu/samsung-g2d.yaml71
-rw-r--r--Documentation/devicetree/bindings/gpu/samsung-rotator.yaml9
-rw-r--r--Documentation/devicetree/bindings/gpu/samsung-scaler.yaml81
-rw-r--r--Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml82
-rw-r--r--Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml6
-rw-r--r--Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml139
-rw-r--r--Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml10
-rw-r--r--Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml4
-rw-r--r--Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml9
-rw-r--r--Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml15
-rw-r--r--Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml4
-rw-r--r--Documentation/devicetree/bindings/iio/chemical/aosong,ags02ma.yaml47
-rw-r--r--Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml5
-rw-r--r--Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml86
-rw-r--r--Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml55
-rw-r--r--Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml4
-rw-r--r--Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml4
-rw-r--r--Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml77
-rw-r--r--Documentation/devicetree/bindings/iio/light/liteon,ltr390.yaml56
-rw-r--r--Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml39
-rw-r--r--Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml142
-rw-r--r--Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml2
-rw-r--r--Documentation/devicetree/bindings/iio/temperature/melexis,mlx90632.yaml19
-rw-r--r--Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml70
-rw-r--r--Documentation/devicetree/bindings/index.rst1
-rw-r--r--Documentation/devicetree/bindings/input/elan,ekth6915.yaml5
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml4
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml4
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml4
-rw-r--r--Documentation/devicetree/bindings/iommu/apple,dart.yaml1
-rw-r--r--Documentation/devicetree/bindings/iommu/arm,smmu.yaml77
-rw-r--r--Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml11
-rw-r--r--Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml137
-rw-r--r--Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml95
-rw-r--r--Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml10
-rw-r--r--Documentation/devicetree/bindings/leds/common.yaml2
-rw-r--r--Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml4
-rw-r--r--Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml62
-rw-r--r--Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml1
-rw-r--r--Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml132
-rw-r--r--Documentation/devicetree/bindings/media/cnm,wave521c.yaml61
-rw-r--r--Documentation/devicetree/bindings/media/i2c/alliedvision,alvium-csi2.yaml81
-rw-r--r--Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml4
-rw-r--r--Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml108
-rw-r--r--Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml113
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ov8856.yaml24
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml103
-rw-r--r--Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml13
-rw-r--r--Documentation/devicetree/bindings/media/i2c/techwell,tw9900.yaml137
-rw-r--r--Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml224
-rw-r--r--Documentation/devicetree/bindings/media/rockchip-isp1.yaml11
-rw-r--r--Documentation/devicetree/bindings/media/samsung,s5p-mfc.yaml47
-rw-r--r--Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml89
-rw-r--r--Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml180
-rw-r--r--Documentation/devicetree/bindings/mfd/ams,as3711.yaml223
-rw-r--r--Documentation/devicetree/bindings/mfd/as3711.txt73
-rw-r--r--Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml140
-rw-r--r--Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml6
-rw-r--r--Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml7
-rw-r--r--Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml2
-rw-r--r--Documentation/devicetree/bindings/mfd/sprd,ums512-glbreg.yaml4
-rw-r--r--Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml2
-rw-r--r--Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml2
-rw-r--r--Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml8
-rw-r--r--Documentation/devicetree/bindings/mmc/arm,pl18x.yaml2
-rw-r--r--Documentation/devicetree/bindings/mmc/brcm,sdhci-brcmstb.yaml4
-rw-r--r--Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.yaml4
-rw-r--r--Documentation/devicetree/bindings/mmc/mtk-sd.yaml9
-rw-r--r--Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml2
-rw-r--r--Documentation/devicetree/bindings/mmc/sdhci-msm.yaml2
-rw-r--r--Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml4
-rw-r--r--Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml1
-rw-r--r--Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.yaml4
-rw-r--r--Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml65
-rw-r--r--Documentation/devicetree/bindings/net/sff,sfp.yaml2
-rw-r--r--Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml1
-rw-r--r--Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml18
-rw-r--r--Documentation/devicetree/bindings/pci/qcom,pcie.yaml63
-rw-r--r--Documentation/devicetree/bindings/pci/rcar-pci-host.yaml11
-rw-r--r--Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml2
-rw-r--r--Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml39
-rw-r--r--Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml39
-rw-r--r--Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml1
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,ipq5018-tlmm.yaml12
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml8
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,ipq9574-tlmm.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,lpass-lpi-common.yaml75
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml18
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml18
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml8
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml18
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml7
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml62
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml12
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml21
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml49
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml30
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml20
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml49
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml18
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml10
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml19
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml10
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml8
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml8
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sdx75-tlmm.yaml12
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm4450-tlmm.yaml151
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm6115-lpass-lpi-pinctrl.yaml48
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml8
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml20
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml20
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml18
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm7150-tlmm.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml49
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm8350-lpass-lpi-pinctrl.yaml49
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml20
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml49
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml20
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml55
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml12
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml107
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,sm8650-tlmm.yaml141
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,x1e80100-tlmm.yaml137
-rw-r--r--Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml6
-rw-r--r--Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml45
-rw-r--r--Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml5
-rw-r--r--Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml2
-rw-r--r--Documentation/devicetree/bindings/power/fsl,scu-pd.yaml1
-rw-r--r--Documentation/devicetree/bindings/power/qcom,rpmpd.yaml2
-rw-r--r--Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml8
-rw-r--r--Documentation/devicetree/bindings/power/wakeup-source.txt18
-rw-r--r--Documentation/devicetree/bindings/pwm/mediatek,pwm-disp.yaml1
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-omap-dmtimer.txt22
-rw-r--r--Documentation/devicetree/bindings/pwm/ti,omap-dmtimer-pwm.yaml59
-rw-r--r--Documentation/devicetree/bindings/regulator/mps,mp5416.yaml4
-rw-r--r--Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml4
-rw-r--r--Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml8
-rw-r--r--Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml21
-rw-r--r--Documentation/devicetree/bindings/riscv/cpus.yaml1
-rw-r--r--Documentation/devicetree/bindings/riscv/extensions.yaml219
-rw-r--r--Documentation/devicetree/bindings/security/tpm/google,cr50.txt19
-rw-r--r--Documentation/devicetree/bindings/security/tpm/ibmvtpm.txt41
-rw-r--r--Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt34
-rw-r--r--Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt32
-rw-r--r--Documentation/devicetree/bindings/security/tpm/tpm-i2c.txt26
-rw-r--r--Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt25
-rw-r--r--Documentation/devicetree/bindings/security/tpm/tpm_tis_spi.txt23
-rw-r--r--Documentation/devicetree/bindings/serial/arm,dcc.yaml30
-rw-r--r--Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml2
-rw-r--r--Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml29
-rw-r--r--Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml13
-rw-r--r--Documentation/devicetree/bindings/serial/renesas,sci.yaml2
-rw-r--r--Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml1
-rw-r--r--Documentation/devicetree/bindings/serial/sprd-uart.yaml1
-rw-r--r--Documentation/devicetree/bindings/tpm/google,cr50.yaml65
-rw-r--r--Documentation/devicetree/bindings/tpm/ibm,vtpm.yaml104
-rw-r--r--Documentation/devicetree/bindings/tpm/microsoft,ftpm.yaml47
-rw-r--r--Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml90
-rw-r--r--Documentation/devicetree/bindings/tpm/tcg,tpm-tis-mmio.yaml49
-rw-r--r--Documentation/devicetree/bindings/tpm/tcg,tpm_tis-spi.yaml75
-rw-r--r--Documentation/devicetree/bindings/tpm/tpm-common.yaml87
-rw-r--r--Documentation/devicetree/bindings/trivial-devices.yaml18
-rw-r--r--Documentation/devicetree/bindings/usb/generic-xhci.yaml25
-rw-r--r--Documentation/devicetree/bindings/usb/genesys,gl850g.yaml5
-rw-r--r--Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml11
-rw-r--r--Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml2
-rw-r--r--Documentation/devicetree/bindings/usb/qcom,dwc3.yaml151
-rw-r--r--Documentation/devicetree/bindings/usb/qcom,wcd939x-usbss.yaml102
-rw-r--r--Documentation/devicetree/bindings/usb/renesas,usbhs.yaml2
-rw-r--r--Documentation/devicetree/bindings/usb/snps,dwc3.yaml4
-rw-r--r--Documentation/devicetree/bindings/usb/ti,tps6598x.yaml6
-rw-r--r--Documentation/devicetree/bindings/usb/usb-xhci.yaml6
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.yaml10
-rw-r--r--Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml44
-rw-r--r--Documentation/driver-api/media/camera-sensor.rst7
-rwxr-xr-xDocumentation/driver-api/media/drivers/ccs/mk-ccs-regs104
-rw-r--r--Documentation/driver-api/media/tx-rx.rst25
-rw-r--r--Documentation/driver-api/media/v4l2-subdev.rst11
-rw-r--r--Documentation/driver-api/pci/p2pdma.rst16
-rw-r--r--Documentation/driver-api/pwm.rst17
-rw-r--r--Documentation/fb/index.rst1
-rw-r--r--Documentation/fb/intelfb.rst155
-rw-r--r--Documentation/memory-barriers.txt17
-rw-r--r--Documentation/sphinx/kernel_feat.py55
-rw-r--r--Documentation/sphinx/requirements.txt2
-rw-r--r--Documentation/staging/rpmsg.rst50
-rw-r--r--Documentation/trace/coresight/coresight.rst4
-rw-r--r--Documentation/trace/ftrace.rst21
-rw-r--r--Documentation/trace/kprobes.rst3
-rw-r--r--Documentation/translations/zh_CN/arch/loongarch/features.rst2
-rw-r--r--Documentation/translations/zh_CN/arch/mips/features.rst2
-rw-r--r--Documentation/translations/zh_TW/arch/loongarch/features.rst2
-rw-r--r--Documentation/translations/zh_TW/arch/mips/features.rst2
-rw-r--r--Documentation/usb/gadget-testing.rst20
-rw-r--r--Documentation/usb/raw-gadget.rst3
-rw-r--r--Documentation/userspace-api/ioctl/ioctl-number.rst1
-rw-r--r--Documentation/userspace-api/media/drivers/index.rst1
-rw-r--r--Documentation/userspace-api/media/drivers/thp7312.rst39
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst8
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst8
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst1
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst9
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst7
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst7
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst5
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst7
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst5
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst20
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst7
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst7
-rw-r--r--Documentation/virt/kvm/api.rst219
-rw-r--r--Documentation/virt/kvm/locking.rst7
-rw-r--r--MAINTAINERS255
-rw-r--r--arch/Kconfig5
-rw-r--r--arch/alpha/kernel/srmcons.c34
-rw-r--r--arch/arc/include/asm/cacheflush.h1
-rw-r--r--arch/arc/mm/dma.c2
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi5
-rw-r--r--arch/arm/boot/dts/broadcom/bcm2711.dtsi14
-rw-r--r--arch/arm/common/locomo.c4
-rw-r--r--arch/arm/include/asm/cacheflush.h2
-rw-r--r--arch/arm/include/asm/hardware/locomo.h2
-rw-r--r--arch/arm/include/asm/pgtable.h2
-rw-r--r--arch/arm/mach-davinci/Kconfig1
-rw-r--r--arch/arm/mm/dma-mapping-nommu.c2
-rw-r--r--arch/arm/mm/dma-mapping.c15
-rw-r--r--arch/arm/mm/fault.c30
-rw-r--r--arch/arm/mm/kasan_init.c8
-rw-r--r--arch/arm/vfp/vfpmodule.c18
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/boot/dts/freescale/imx8mp-evk.dts22
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi2
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916.dtsi9
-rw-r--r--arch/arm64/boot/dts/qcom/msm8939.dtsi12
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996.dtsi43
-rw-r--r--arch/arm64/boot/dts/qcom/msm8998.dtsi5
-rw-r--r--arch/arm64/boot/dts/qcom/qcs404.dtsi9
-rw-r--r--arch/arm64/boot/dts/qcom/qrb5165-rb5.dts2
-rw-r--r--arch/arm64/boot/dts/qcom/sdm630.dtsi53
-rw-r--r--arch/arm64/include/asm/cpu.h1
-rw-r--r--arch/arm64/include/asm/esr.h15
-rw-r--r--arch/arm64/include/asm/kvm_arm.h63
-rw-r--r--arch/arm64/include/asm/kvm_emulate.h34
-rw-r--r--arch/arm64/include/asm/kvm_host.h140
-rw-r--r--arch/arm64/include/asm/kvm_nested.h56
-rw-r--r--arch/arm64/include/asm/kvm_pgtable.h80
-rw-r--r--arch/arm64/include/asm/kvm_pkvm.h5
-rw-r--r--arch/arm64/include/asm/vncr_mapping.h103
-rw-r--r--arch/arm64/kernel/cpufeature.c2
-rw-r--r--arch/arm64/kernel/setup.c13
-rw-r--r--arch/arm64/kvm/Kconfig7
-rw-r--r--arch/arm64/kvm/arch_timer.c3
-rw-r--r--arch/arm64/kvm/arm.c12
-rw-r--r--arch/arm64/kvm/emulate-nested.c63
-rw-r--r--arch/arm64/kvm/hyp/include/hyp/fault.h2
-rw-r--r--arch/arm64/kvm/hyp/include/hyp/switch.h93
-rw-r--r--arch/arm64/kvm/hyp/include/nvhe/fixed_config.h22
-rw-r--r--arch/arm64/kvm/hyp/nvhe/hyp-init.S6
-rw-r--r--arch/arm64/kvm/hyp/nvhe/mem_protect.c6
-rw-r--r--arch/arm64/kvm/hyp/nvhe/mm.c4
-rw-r--r--arch/arm64/kvm/hyp/nvhe/pkvm.c4
-rw-r--r--arch/arm64/kvm/hyp/nvhe/setup.c2
-rw-r--r--arch/arm64/kvm/hyp/pgtable.c90
-rw-r--r--arch/arm64/kvm/mmu.c49
-rw-r--r--arch/arm64/kvm/nested.c22
-rw-r--r--arch/arm64/kvm/reset.c9
-rw-r--r--arch/arm64/kvm/sys_regs.c235
-rw-r--r--arch/arm64/kvm/vgic/vgic-its.c5
-rw-r--r--arch/arm64/kvm/vgic/vgic-mmio-v3.c28
-rw-r--r--arch/arm64/kvm/vgic/vgic-mmio.c101
-rw-r--r--arch/arm64/mm/dma-mapping.c4
-rw-r--r--arch/csky/abiv1/inc/abi/cacheflush.h1
-rw-r--r--arch/csky/abiv2/inc/abi/cacheflush.h1
-rw-r--r--arch/loongarch/Kconfig2
-rw-r--r--arch/loongarch/include/asm/kvm_host.h25
-rw-r--r--arch/loongarch/include/asm/kvm_vcpu.h21
-rw-r--r--arch/loongarch/include/uapi/asm/kvm.h1
-rw-r--r--arch/loongarch/kernel/fpu.S2
-rw-r--r--arch/loongarch/kernel/topology.c42
-rw-r--r--arch/loongarch/kvm/Kconfig5
-rw-r--r--arch/loongarch/kvm/exit.c50
-rw-r--r--arch/loongarch/kvm/main.c1
-rw-r--r--arch/loongarch/kvm/mmu.c124
-rw-r--r--arch/loongarch/kvm/switch.S31
-rw-r--r--arch/loongarch/kvm/timer.c129
-rw-r--r--arch/loongarch/kvm/trace.h6
-rw-r--r--arch/loongarch/kvm/vcpu.c307
-rw-r--r--arch/m68k/emu/nfcon.c4
-rw-r--r--arch/m68k/include/asm/cacheflush_mm.h1
-rw-r--r--arch/microblaze/configs/mmu_defconfig13
-rw-r--r--arch/mips/alchemy/devboards/db1200.c2
-rw-r--r--arch/mips/alchemy/devboards/db1550.c2
-rw-r--r--arch/mips/bcm47xx/buttons.c6
-rw-r--r--arch/mips/bcm63xx/clk.c4
-rw-r--r--arch/mips/boot/compressed/dbg.c2
-rw-r--r--arch/mips/boot/compressed/head.S4
-rw-r--r--arch/mips/boot/elf2ecoff.c2
-rw-r--r--arch/mips/cavium-octeon/csrc-octeon.c2
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-boot-vector.c2
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-bootmem.c2
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c4
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-jtag.c2
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-pko.c2
-rw-r--r--arch/mips/cavium-octeon/octeon-platform.c2
-rw-r--r--arch/mips/fw/arc/promlib.c6
-rw-r--r--arch/mips/include/asm/cacheflush.h2
-rw-r--r--arch/mips/include/asm/debug.h2
-rw-r--r--arch/mips/include/asm/dmi.h2
-rw-r--r--arch/mips/include/asm/io.h4
-rw-r--r--arch/mips/include/asm/kvm_host.h2
-rw-r--r--arch/mips/include/asm/mach-au1x00/au1000_dma.h2
-rw-r--r--arch/mips/include/asm/mach-au1x00/gpio-au1000.h2
-rw-r--r--arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h2
-rw-r--r--arch/mips/include/asm/mach-loongson64/loongson_hwmon.h2
-rw-r--r--arch/mips/include/asm/mach-loongson64/loongson_regs.h2
-rw-r--r--arch/mips/include/asm/mach-malta/spaces.h4
-rw-r--r--arch/mips/include/asm/mips-boards/bonito64.h2
-rw-r--r--arch/mips/include/asm/mips-cpc.h2
-rw-r--r--arch/mips/include/asm/mipsregs.h4
-rw-r--r--arch/mips/include/asm/octeon/cvmx-bootinfo.h2
-rw-r--r--arch/mips/include/asm/octeon/cvmx-cmd-queue.h6
-rw-r--r--arch/mips/include/asm/octeon/cvmx-pko.h2
-rw-r--r--arch/mips/include/asm/octeon/cvmx-pow.h4
-rw-r--r--arch/mips/include/asm/octeon/octeon-model.h4
-rw-r--r--arch/mips/include/asm/page.h2
-rw-r--r--arch/mips/include/asm/pci.h2
-rw-r--r--arch/mips/include/asm/pgtable-bits.h2
-rw-r--r--arch/mips/include/asm/sgi/mc.h2
-rw-r--r--arch/mips/include/asm/sn/klconfig.h2
-rw-r--r--arch/mips/include/asm/sync.h2
-rw-r--r--arch/mips/include/asm/thread_info.h2
-rw-r--r--arch/mips/include/asm/timex.h2
-rw-r--r--arch/mips/include/asm/vdso/vdso.h2
-rw-r--r--arch/mips/include/uapi/asm/mman.h2
-rw-r--r--arch/mips/include/uapi/asm/msgbuf.h2
-rw-r--r--arch/mips/kernel/cpu-probe.c2
-rw-r--r--arch/mips/kernel/genex.S8
-rw-r--r--arch/mips/kernel/kprobes.c2
-rw-r--r--arch/mips/kernel/prom.c2
-rw-r--r--arch/mips/kernel/relocate.c2
-rw-r--r--arch/mips/kernel/relocate_kernel.S2
-rw-r--r--arch/mips/kernel/setup.c6
-rw-r--r--arch/mips/kernel/signal.c2
-rw-r--r--arch/mips/kernel/traps.c93
-rw-r--r--arch/mips/kernel/vpe.c4
-rw-r--r--arch/mips/kvm/Kconfig6
-rw-r--r--arch/mips/kvm/emulate.c2
-rw-r--r--arch/mips/loongson2ef/common/platform.c2
-rw-r--r--arch/mips/loongson64/smp.c2
-rw-r--r--arch/mips/mm/c-r4k.c2
-rw-r--r--arch/mips/mm/cex-gen.S2
-rw-r--r--arch/mips/mm/dma-noncoherent.c2
-rw-r--r--arch/mips/mm/init.c16
-rw-r--r--arch/mips/mm/ioremap.c4
-rw-r--r--arch/mips/mm/tlb-r3k.c2
-rw-r--r--arch/mips/mm/tlb-r4k.c2
-rw-r--r--arch/mips/mm/tlbex.c4
-rw-r--r--arch/mips/net/bpf_jit_comp32.c2
-rw-r--r--arch/mips/pci/ops-loongson2.c2
-rw-r--r--arch/mips/pci/pci-alchemy.c2
-rw-r--r--arch/mips/pci/pci-ar2315.c2
-rw-r--r--arch/mips/pci/pci-lantiq.c2
-rw-r--r--arch/mips/pci/pci-octeon.c2
-rw-r--r--arch/mips/pci/pci-xtalk-bridge.c2
-rw-r--r--arch/mips/pci/pcie-octeon.c2
-rw-r--r--arch/mips/ralink/mt7621.c2
-rw-r--r--arch/mips/sgi-ip27/ip27-hubio.c2
-rw-r--r--arch/mips/txx9/generic/pci.c2
-rw-r--r--arch/nios2/include/asm/cacheflush.h1
-rw-r--r--arch/parisc/include/asm/cacheflush.h1
-rw-r--r--arch/parisc/kernel/firmware.c4
-rw-r--r--arch/parisc/video/fbdev.c2
-rw-r--r--arch/powerpc/include/asm/hvconsole.h4
-rw-r--r--arch/powerpc/include/asm/hvsi.h18
-rw-r--r--arch/powerpc/include/asm/kvm_host.h2
-rw-r--r--arch/powerpc/include/asm/opal.h8
-rw-r--r--arch/powerpc/kvm/Kconfig14
-rw-r--r--arch/powerpc/kvm/book3s_hv.c2
-rw-r--r--arch/powerpc/kvm/powerpc.c10
-rw-r--r--arch/powerpc/platforms/powernv/opal.c14
-rw-r--r--arch/powerpc/platforms/pseries/hvconsole.c4
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c4
-rw-r--r--arch/riscv/Kconfig29
-rw-r--r--arch/riscv/configs/rv32_defconfig139
-rw-r--r--arch/riscv/include/asm/cacheflush.h3
-rw-r--r--arch/riscv/include/asm/cpu_ops.h14
-rw-r--r--arch/riscv/include/asm/cpufeature.h4
-rw-r--r--arch/riscv/include/asm/hwcap.h38
-rw-r--r--arch/riscv/include/asm/hwprobe.h24
-rw-r--r--arch/riscv/include/asm/kfence.h4
-rw-r--r--arch/riscv/include/asm/kvm_host.h12
-rw-r--r--arch/riscv/include/asm/kvm_vcpu_sbi.h20
-rw-r--r--arch/riscv/include/asm/paravirt.h28
-rw-r--r--arch/riscv/include/asm/paravirt_api_clock.h1
-rw-r--r--arch/riscv/include/asm/pgtable-64.h22
-rw-r--r--arch/riscv/include/asm/pgtable.h33
-rw-r--r--arch/riscv/include/asm/sbi.h17
-rw-r--r--arch/riscv/include/asm/sections.h1
-rw-r--r--arch/riscv/include/asm/thread_info.h1
-rw-r--r--arch/riscv/include/asm/tlbflush.h1
-rw-r--r--arch/riscv/include/asm/xip_fixup.h2
-rw-r--r--arch/riscv/include/uapi/asm/hwprobe.h32
-rw-r--r--arch/riscv/include/uapi/asm/kvm.h13
-rw-r--r--arch/riscv/kernel/Makefile2
-rw-r--r--arch/riscv/kernel/cpu-hotplug.c19
-rw-r--r--arch/riscv/kernel/cpu_ops.c14
-rw-r--r--arch/riscv/kernel/cpu_ops_sbi.c19
-rw-r--r--arch/riscv/kernel/cpu_ops_spinwait.c11
-rw-r--r--arch/riscv/kernel/cpufeature.c195
-rw-r--r--arch/riscv/kernel/efi.c2
-rw-r--r--arch/riscv/kernel/head.S6
-rw-r--r--arch/riscv/kernel/mcount-dyn.S2
-rw-r--r--arch/riscv/kernel/mcount.S2
-rw-r--r--arch/riscv/kernel/module.c3
-rw-r--r--arch/riscv/kernel/paravirt.c135
-rw-r--r--arch/riscv/kernel/patch.c11
-rw-r--r--arch/riscv/kernel/setup.c19
-rw-r--r--arch/riscv/kernel/signal.c2
-rw-r--r--arch/riscv/kernel/smp.c2
-rw-r--r--arch/riscv/kernel/smpboot.c38
-rw-r--r--arch/riscv/kernel/sys_hwprobe.c411
-rw-r--r--arch/riscv/kernel/sys_riscv.c285
-rw-r--r--arch/riscv/kernel/time.c3
-rw-r--r--arch/riscv/kernel/traps_misaligned.c6
-rw-r--r--arch/riscv/kernel/vdso/hwprobe.c86
-rw-r--r--arch/riscv/kernel/vmlinux-xip.lds.S2
-rw-r--r--arch/riscv/kernel/vmlinux.lds.S2
-rw-r--r--arch/riscv/kvm/Kconfig7
-rw-r--r--arch/riscv/kvm/Makefile1
-rw-r--r--arch/riscv/kvm/mmu.c22
-rw-r--r--arch/riscv/kvm/vcpu.c10
-rw-r--r--arch/riscv/kvm/vcpu_onereg.c135
-rw-r--r--arch/riscv/kvm/vcpu_sbi.c142
-rw-r--r--arch/riscv/kvm/vcpu_sbi_replace.c2
-rw-r--r--arch/riscv/kvm/vcpu_sbi_sta.c208
-rw-r--r--arch/riscv/kvm/vcpu_switch.S32
-rw-r--r--arch/riscv/kvm/vcpu_vector.c16
-rw-r--r--arch/riscv/kvm/vm.c1
-rw-r--r--arch/riscv/lib/clear_page.S2
-rw-r--r--arch/riscv/lib/tishift.S2
-rw-r--r--arch/riscv/lib/uaccess.S2
-rw-r--r--arch/riscv/mm/Makefile3
-rw-r--r--arch/riscv/mm/dma-noncoherent.c2
-rw-r--r--arch/riscv/mm/fault.c16
-rw-r--r--arch/riscv/mm/hugetlbpage.c12
-rw-r--r--arch/riscv/mm/init.c8
-rw-r--r--arch/riscv/mm/kasan_init.c53
-rw-r--r--arch/riscv/mm/pageattr.c55
-rw-r--r--arch/riscv/mm/pgtable.c51
-rw-r--r--arch/riscv/mm/tlbflush.c5
-rw-r--r--arch/s390/Kconfig7
-rw-r--r--arch/s390/configs/debug_defconfig1
-rw-r--r--arch/s390/configs/defconfig1
-rw-r--r--arch/s390/configs/zfcpdump_defconfig1
-rw-r--r--arch/s390/include/asm/facility.h6
-rw-r--r--arch/s390/include/asm/kvm_host.h2
-rw-r--r--arch/s390/include/asm/pci_io.h32
-rw-r--r--arch/s390/kernel/Makefile2
-rw-r--r--arch/s390/kernel/facility.c21
-rw-r--r--arch/s390/kernel/fpu.c1
-rw-r--r--arch/s390/kernel/perf_pai_crypto.c80
-rw-r--r--arch/s390/kernel/perf_pai_ext.c79
-rw-r--r--arch/s390/kernel/ptrace.c1
-rw-r--r--arch/s390/kvm/Kconfig5
-rw-r--r--arch/s390/kvm/guestdbg.c4
-rw-r--r--arch/s390/kvm/kvm-s390.c1
-rw-r--r--arch/s390/kvm/vsie.c19
-rw-r--r--arch/s390/mm/fault.c4
-rw-r--r--arch/s390/pci/pci_mmio.c12
-rw-r--r--arch/sh/include/asm/cacheflush.h1
-rw-r--r--arch/sparc/include/asm/cacheflush_32.h1
-rw-r--r--arch/sparc/include/asm/cacheflush_64.h1
-rw-r--r--arch/um/Makefile-skas5
-rw-r--r--arch/um/drivers/chan.h2
-rw-r--r--arch/um/drivers/chan_kern.c9
-rw-r--r--arch/um/drivers/chan_user.c46
-rw-r--r--arch/um/drivers/chan_user.h9
-rw-r--r--arch/um/drivers/line.c15
-rw-r--r--arch/um/drivers/line.h6
-rw-r--r--arch/um/drivers/net_kern.c2
-rw-r--r--arch/um/drivers/null.c2
-rw-r--r--arch/um/drivers/virt-pci.c2
-rw-r--r--arch/um/include/asm/mmu.h1
-rw-r--r--arch/um/include/asm/processor-generic.h1
-rw-r--r--arch/um/include/shared/kern_util.h5
-rw-r--r--arch/um/include/shared/os.h3
-rw-r--r--arch/um/include/shared/ptrace_user.h41
-rw-r--r--arch/um/include/shared/registers.h2
-rw-r--r--arch/um/kernel/process.c14
-rw-r--r--arch/um/kernel/ptrace.c2
-rw-r--r--arch/um/kernel/signal.c12
-rw-r--r--arch/um/kernel/skas/uaccess.c4
-rw-r--r--arch/um/kernel/time.c32
-rw-r--r--arch/um/os-Linux/helper.c6
-rw-r--r--arch/um/os-Linux/registers.c20
-rw-r--r--arch/um/os-Linux/skas/process.c117
-rw-r--r--arch/um/os-Linux/start_up.c111
-rw-r--r--arch/um/os-Linux/util.c19
-rw-r--r--arch/x86/Kconfig8
-rw-r--r--arch/x86/coco/tdx/tdx-shared.c6
-rw-r--r--arch/x86/include/asm/cpu.h4
-rw-r--r--arch/x86/include/asm/cpufeatures.h2
-rw-r--r--arch/x86/include/asm/kvm-x86-ops.h3
-rw-r--r--arch/x86/include/asm/kvm-x86-pmu-ops.h2
-rw-r--r--arch/x86/include/asm/kvm_host.h75
-rw-r--r--arch/x86/include/asm/msr-index.h3
-rw-r--r--arch/x86/include/asm/shared/tdx.h6
-rw-r--r--arch/x86/include/asm/tdx.h38
-rw-r--r--arch/x86/include/uapi/asm/kvm.h3
-rw-r--r--arch/x86/kernel/aperture_64.c3
-rw-r--r--arch/x86/kernel/cpu/common.c2
-rw-r--r--arch/x86/kernel/cpu/mce/core.c17
-rw-r--r--arch/x86/kernel/early-quirks.c4
-rw-r--r--arch/x86/kernel/kvmclock.c12
-rw-r--r--arch/x86/kernel/setup.c2
-rw-r--r--arch/x86/kernel/topology.c33
-rw-r--r--arch/x86/kernel/traps.c4
-rw-r--r--arch/x86/kvm/Kconfig47
-rw-r--r--arch/x86/kvm/Makefile16
-rw-r--r--arch/x86/kvm/cpuid.c33
-rw-r--r--arch/x86/kvm/cpuid.h13
-rw-r--r--arch/x86/kvm/debugfs.c2
-rw-r--r--arch/x86/kvm/emulate.c27
-rw-r--r--arch/x86/kvm/governed_features.h1
-rw-r--r--arch/x86/kvm/hyperv.h85
-rw-r--r--arch/x86/kvm/irq.c2
-rw-r--r--arch/x86/kvm/irq_comm.c9
-rw-r--r--arch/x86/kvm/kvm_emulate.h9
-rw-r--r--arch/x86/kvm/kvm_onhyperv.h20
-rw-r--r--arch/x86/kvm/lapic.c5
-rw-r--r--arch/x86/kvm/mmu.h8
-rw-r--r--arch/x86/kvm/mmu/mmu.c293
-rw-r--r--arch/x86/kvm/mmu/mmu_internal.h3
-rw-r--r--arch/x86/kvm/mmu/paging_tmpl.h2
-rw-r--r--arch/x86/kvm/mmu/tdp_mmu.c95
-rw-r--r--arch/x86/kvm/mmu/tdp_mmu.h3
-rw-r--r--arch/x86/kvm/pmu.c140
-rw-r--r--arch/x86/kvm/pmu.h47
-rw-r--r--arch/x86/kvm/reverse_cpuid.h35
-rw-r--r--arch/x86/kvm/svm/hyperv.h9
-rw-r--r--arch/x86/kvm/svm/nested.c49
-rw-r--r--arch/x86/kvm/svm/pmu.c17
-rw-r--r--arch/x86/kvm/svm/sev.c7
-rw-r--r--arch/x86/kvm/svm/svm.c18
-rw-r--r--arch/x86/kvm/svm/svm.h2
-rw-r--r--arch/x86/kvm/svm/svm_onhyperv.c10
-rw-r--r--arch/x86/kvm/svm/vmenter.S10
-rw-r--r--arch/x86/kvm/vmx/hyperv.c447
-rw-r--r--arch/x86/kvm/vmx/hyperv.h204
-rw-r--r--arch/x86/kvm/vmx/hyperv_evmcs.c315
-rw-r--r--arch/x86/kvm/vmx/hyperv_evmcs.h166
-rw-r--r--arch/x86/kvm/vmx/nested.c160
-rw-r--r--arch/x86/kvm/vmx/nested.h3
-rw-r--r--arch/x86/kvm/vmx/pmu_intel.c22
-rw-r--r--arch/x86/kvm/vmx/sgx.c1
-rw-r--r--arch/x86/kvm/vmx/vmenter.S2
-rw-r--r--arch/x86/kvm/vmx/vmx.c86
-rw-r--r--arch/x86/kvm/vmx/vmx.h14
-rw-r--r--arch/x86/kvm/vmx/vmx_onhyperv.c36
-rw-r--r--arch/x86/kvm/vmx/vmx_onhyperv.h125
-rw-r--r--arch/x86/kvm/vmx/vmx_ops.h2
-rw-r--r--arch/x86/kvm/x86.c168
-rw-r--r--arch/x86/kvm/x86.h2
-rw-r--r--arch/x86/kvm/xen.c9
-rw-r--r--arch/x86/pci/acpi.c3
-rw-r--r--arch/x86/pci/mmconfig-shared.c180
-rw-r--r--arch/x86/pci/mmconfig_32.c2
-rw-r--r--arch/x86/pci/mmconfig_64.c42
-rw-r--r--arch/x86/pci/pcbios.c28
-rw-r--r--arch/x86/um/asm/elf.h4
-rw-r--r--arch/x86/um/asm/processor_64.h3
-rw-r--r--arch/x86/um/os-Linux/Makefile1
-rw-r--r--arch/x86/um/os-Linux/prctl.c12
-rw-r--r--arch/x86/um/ptrace_32.c24
-rw-r--r--arch/x86/um/ptrace_64.c26
-rw-r--r--arch/x86/um/shared/sysdep/ptrace_32.h4
-rw-r--r--arch/x86/um/shared/sysdep/ptrace_user.h12
-rw-r--r--arch/x86/um/shared/sysdep/stub_32.h39
-rw-r--r--arch/x86/um/shared/sysdep/stub_64.h17
-rw-r--r--arch/x86/um/syscalls_64.c62
-rw-r--r--arch/x86/um/tls_64.c2
-rw-r--r--arch/x86/virt/vmx/tdx/Makefile2
-rw-r--r--arch/x86/virt/vmx/tdx/tdx.c1492
-rw-r--r--arch/x86/virt/vmx/tdx/tdx.h121
-rw-r--r--arch/xtensa/Kconfig2
-rw-r--r--arch/xtensa/Makefile6
-rw-r--r--arch/xtensa/include/asm/asmmacro.h2
-rw-r--r--arch/xtensa/include/asm/cacheflush.h6
-rw-r--r--arch/xtensa/lib/pci-auto.c8
-rw-r--r--arch/xtensa/platforms/iss/console.c2
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/acpi/Kconfig1
-rw-r--r--drivers/acpi/acpi_processor.c18
-rw-r--r--drivers/acpi/apei/ghes.c89
-rw-r--r--drivers/acpi/nfit/core.c65
-rw-r--r--drivers/acpi/numa/hmat.c193
-rw-r--r--drivers/acpi/property.c4
-rw-r--r--drivers/acpi/resource.c21
-rw-r--r--drivers/acpi/scan.c32
-rw-r--r--drivers/acpi/tables.c5
-rw-r--r--drivers/android/binder.c27
-rw-r--r--drivers/android/binder_alloc.c860
-rw-r--r--drivers/android/binder_alloc.h61
-rw-r--r--drivers/android/binder_alloc_selftest.c18
-rw-r--r--drivers/android/binder_trace.h2
-rw-r--r--drivers/android/binderfs.c1
-rw-r--r--drivers/base/arch_topology.c38
-rw-r--r--drivers/base/auxiliary.c2
-rw-r--r--drivers/base/bus.c8
-rw-r--r--drivers/base/class.c1
-rw-r--r--drivers/base/container.c2
-rw-r--r--drivers/base/core.c13
-rw-r--r--drivers/base/cpu.c39
-rw-r--r--drivers/base/dd.c2
-rw-r--r--drivers/base/init.c2
-rw-r--r--drivers/base/isa.c2
-rw-r--r--drivers/base/memory.c2
-rw-r--r--drivers/base/node.c23
-rw-r--r--drivers/base/power/Makefile1
-rw-r--r--drivers/base/power/clock_ops.c2
-rw-r--r--drivers/base/power/main.c117
-rw-r--r--drivers/base/power/qos.c2
-rw-r--r--drivers/base/property.c66
-rw-r--r--drivers/base/soc.c6
-rw-r--r--drivers/base/swnode.c11
-rw-r--r--drivers/bluetooth/btmtkuart.c4
-rw-r--r--drivers/bluetooth/btnxpuart.c4
-rw-r--r--drivers/bluetooth/btusb.c6
-rw-r--r--drivers/bluetooth/hci_serdev.c4
-rw-r--r--drivers/bus/mhi/ep/internal.h4
-rw-r--r--drivers/bus/mhi/ep/main.c387
-rw-r--r--drivers/bus/mhi/ep/ring.c60
-rw-r--r--drivers/bus/mhi/host/init.c1
-rw-r--r--drivers/bus/mhi/host/internal.h2
-rw-r--r--drivers/bus/mhi/host/main.c34
-rw-r--r--drivers/bus/mhi/host/pci_generic.c22
-rw-r--r--drivers/bus/mhi/host/pm.c24
-rw-r--r--drivers/bus/moxtet.c2
-rw-r--r--drivers/cdx/cdx.c171
-rw-r--r--drivers/char/ppdev.c6
-rw-r--r--drivers/char/ttyprintk.c6
-rw-r--r--drivers/char/virtio_console.c58
-rw-r--r--drivers/clk/Kconfig11
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk-renesas-pcie.c37
-rw-r--r--drivers/clk/clk-si5341.c4
-rw-r--r--drivers/clk/clk-si5351.c47
-rw-r--r--drivers/clk/clk-sp7021.c12
-rw-r--r--drivers/clk/clk-versaclock3.c88
-rw-r--r--drivers/clk/hisilicon/clk-hi3620.c4
-rw-r--r--drivers/clk/imx/clk-imx8qxp.c24
-rw-r--r--drivers/clk/imx/clk-pll14xx.c23
-rw-r--r--drivers/clk/imx/clk-scu.c4
-rw-r--r--drivers/clk/mediatek/Kconfig9
-rw-r--r--drivers/clk/mediatek/Makefile5
-rw-r--r--drivers/clk/mediatek/clk-mt7988-apmixed.c114
-rw-r--r--drivers/clk/mediatek/clk-mt7988-eth.c150
-rw-r--r--drivers/clk/mediatek/clk-mt7988-infracfg.c275
-rw-r--r--drivers/clk/mediatek/clk-mt7988-topckgen.c325
-rw-r--r--drivers/clk/mediatek/clk-mt7988-xfipll.c82
-rw-r--r--drivers/clk/mediatek/clk-mt8188-topckgen.c27
-rw-r--r--drivers/clk/mediatek/clk-mt8195-topckgen.c27
-rw-r--r--drivers/clk/mediatek/clk-mux.c14
-rw-r--r--drivers/clk/mediatek/clk-mux.h43
-rw-r--r--drivers/clk/mediatek/clk-pll.c5
-rw-r--r--drivers/clk/mediatek/clk-pll.h1
-rw-r--r--drivers/clk/meson/g12a.c115
-rw-r--r--drivers/clk/meson/g12a.h1
-rw-r--r--drivers/clk/microchip/clk-mpfs-ccc.c2
-rw-r--r--drivers/clk/mmp/clk-of-pxa168.c3
-rw-r--r--drivers/clk/qcom/Kconfig63
-rw-r--r--drivers/clk/qcom/Makefile7
-rw-r--r--drivers/clk/qcom/apss-ipq-pll.c21
-rw-r--r--drivers/clk/qcom/camcc-sc8280xp.c3045
-rw-r--r--drivers/clk/qcom/clk-branch.c38
-rw-r--r--drivers/clk/qcom/clk-branch.h21
-rw-r--r--drivers/clk/qcom/clk-rpmh.c58
-rw-r--r--drivers/clk/qcom/dispcc-sm8550.c12
-rw-r--r--drivers/clk/qcom/dispcc-sm8650.c1818
-rw-r--r--drivers/clk/qcom/ecpricc-qdu1000.c2456
-rw-r--r--drivers/clk/qcom/gcc-msm8939.c110
-rw-r--r--drivers/clk/qcom/gcc-sm8550.c110
-rw-r--r--drivers/clk/qcom/gcc-sm8650.c3849
-rw-r--r--drivers/clk/qcom/gcc-x1e80100.c6807
-rw-r--r--drivers/clk/qcom/gpucc-sm8150.c4
-rw-r--r--drivers/clk/qcom/gpucc-sm8550.c6
-rw-r--r--drivers/clk/qcom/gpucc-sm8650.c663
-rw-r--r--drivers/clk/qcom/tcsrcc-sm8650.c182
-rw-r--r--drivers/clk/qcom/videocc-sm8150.c25
-rw-r--r--drivers/clk/renesas/r8a779g0-cpg-mssr.c3
-rw-r--r--drivers/clk/renesas/r9a08g045-cpg.c13
-rw-r--r--drivers/clk/renesas/rzg2l-cpg.c91
-rw-r--r--drivers/clk/rockchip/clk-rk3568.c3
-rw-r--r--drivers/clk/samsung/clk-cpu.h30
-rw-r--r--drivers/clk/samsung/clk.h157
-rw-r--r--drivers/clk/starfive/clk-starfive-jh7100-audio.c2
-rw-r--r--drivers/clk/starfive/clk-starfive-jh7100.c32
-rw-r--r--drivers/clk/starfive/clk-starfive-jh7110-aon.c6
-rw-r--r--drivers/clk/starfive/clk-starfive-jh7110-isp.c2
-rw-r--r--drivers/clk/starfive/clk-starfive-jh7110-sys.c26
-rw-r--r--drivers/clk/starfive/clk-starfive-jh71x0.h4
-rw-r--r--drivers/clk/stm32/Kconfig29
-rw-r--r--drivers/clk/stm32/Makefile1
-rw-r--r--drivers/clk/stm32/clk-stm32-core.c5
-rw-r--r--drivers/clk/stm32/clk-stm32-core.h5
-rw-r--r--drivers/clk/stm32/clk-stm32mp1.c (renamed from drivers/clk/clk-stm32mp1.c)127
-rw-r--r--drivers/clk/stm32/clk-stm32mp13.c9
-rw-r--r--drivers/clk/stm32/reset-stm32.c14
-rw-r--r--drivers/clk/stm32/reset-stm32.h8
-rw-r--r--drivers/clk/sunxi-ng/ccu_nkm.c5
-rw-r--r--drivers/clk/xilinx/clk-xlnx-clock-wizard.c628
-rw-r--r--drivers/clk/zynqmp/clk-mux-zynqmp.c2
-rw-r--r--drivers/clk/zynqmp/divider.c66
-rw-r--r--drivers/comedi/comedi_fops.c4
-rw-r--r--drivers/cpufreq/intel_pstate.c21
-rw-r--r--drivers/cxl/Kconfig3
-rw-r--r--drivers/cxl/acpi.c155
-rw-r--r--drivers/cxl/core/Makefile1
-rw-r--r--drivers/cxl/core/cdat.c521
-rw-r--r--drivers/cxl/core/core.h2
-rw-r--r--drivers/cxl/core/mbox.c83
-rw-r--r--drivers/cxl/core/memdev.c2
-rw-r--r--drivers/cxl/core/pci.c36
-rw-r--r--drivers/cxl/core/pmem.c8
-rw-r--r--drivers/cxl/core/port.c167
-rw-r--r--drivers/cxl/core/region.c15
-rw-r--r--drivers/cxl/core/trace.h14
-rw-r--r--drivers/cxl/cxl.h47
-rw-r--r--drivers/cxl/cxlmem.h132
-rw-r--r--drivers/cxl/cxlpci.h13
-rw-r--r--drivers/cxl/mem.c67
-rw-r--r--drivers/cxl/pci.c58
-rw-r--r--drivers/cxl/port.c8
-rw-r--r--drivers/dma/tegra186-gpc-dma.c8
-rw-r--r--drivers/edac/edac_device.h2
-rw-r--r--drivers/edac/edac_device_sysfs.c2
-rw-r--r--drivers/edac/edac_module.c4
-rw-r--r--drivers/edac/edac_pci_sysfs.c2
-rw-r--r--drivers/edac/versal_edac.c4
-rw-r--r--drivers/extcon/extcon-qcom-spmi-misc.c2
-rw-r--r--drivers/extcon/extcon-usbc-tusb320.c9
-rw-r--r--drivers/extcon/extcon.c3
-rw-r--r--drivers/firewire/.kunitconfig1
-rw-r--r--drivers/firewire/Kconfig16
-rw-r--r--drivers/firewire/core-device.c129
-rw-r--r--drivers/firewire/device-attribute-test.c251
-rw-r--r--drivers/firmware/Kconfig9
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/arm_scmi/Kconfig25
-rw-r--r--drivers/firmware/arm_scmi/driver.c6
-rw-r--r--drivers/firmware/arm_scpi.c6
-rw-r--r--drivers/firmware/imx/imx-dsp.c6
-rw-r--r--drivers/firmware/mtk-adsp-ipc.c6
-rw-r--r--drivers/firmware/qemu_fw_cfg.c5
-rw-r--r--drivers/firmware/raspberrypi.c6
-rw-r--r--drivers/firmware/stratix10-rsu.c5
-rw-r--r--drivers/firmware/stratix10-svc.c6
-rw-r--r--drivers/firmware/sysfb.c14
-rw-r--r--drivers/firmware/turris-mox-rwtm.c6
-rw-r--r--drivers/firmware/xilinx/zynqmp.c396
-rw-r--r--drivers/fpga/altera-fpga2sdram.c6
-rw-r--r--drivers/fpga/altera-freeze-bridge.c6
-rw-r--r--drivers/fpga/altera-hps2fpga.c6
-rw-r--r--drivers/fpga/dfl-afu-main.c6
-rw-r--r--drivers/fpga/dfl-fme-br.c6
-rw-r--r--drivers/fpga/dfl-fme-main.c6
-rw-r--r--drivers/fpga/dfl-fme-region.c6
-rw-r--r--drivers/fpga/dfl.c4
-rw-r--r--drivers/fpga/intel-m10-bmc-sec-update.c6
-rw-r--r--drivers/fpga/of-fpga-region.c6
-rw-r--r--drivers/fpga/socfpga-a10.c6
-rw-r--r--drivers/fpga/stratix10-soc.c6
-rw-r--r--drivers/fpga/xilinx-pr-decoupler.c6
-rw-r--r--drivers/fpga/zynq-fpga.c6
-rw-r--r--drivers/gnss/serial.c4
-rw-r--r--drivers/gnss/sirf.c4
-rw-r--r--drivers/gnss/ubx.c31
-rw-r--r--drivers/gpio/gpiolib-of.c4
-rw-r--r--drivers/gpu/drm/hyperv/hyperv_drm_drv.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_backlight.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_cx0_phy.c25
-rw-r--r--drivers/gpu/drm/i915/display/intel_display_power.c4
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp.c2
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c10
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_context_types.h4
-rw-r--r--drivers/gpu/drm/i915/gt/intel_gsc.h7
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc.h75
-rw-r--r--drivers/gpu/drm/i915/i915_perf_types.h9
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c9
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop2.c4
-rw-r--r--drivers/gpu/drm/solomon/ssd130x.c2
-rw-r--r--drivers/gpu/drm/v3d/v3d_debugfs.c20
-rw-r--r--drivers/greybus/gb-beagleplay.c63
-rw-r--r--drivers/hid/Kconfig22
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/amd-sfh-hid/amd_sfh_common.h6
-rw-r--r--drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c28
-rw-r--r--drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c20
-rw-r--r--drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c59
-rw-r--r--drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h2
-rw-r--r--drivers/hid/hid-core.c2
-rw-r--r--drivers/hid/hid-ids.h6
-rw-r--r--drivers/hid/hid-magicmouse.c3
-rw-r--r--drivers/hid/hid-mcp2200.c392
-rw-r--r--drivers/hid/hid-mcp2221.c72
-rw-r--r--drivers/hid/hid-nintendo.c897
-rw-r--r--drivers/hid/hid-sensor-hub.c2
-rw-r--r--drivers/hid/hid-steam.c547
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-core.c137
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-of-elan.c8
-rw-r--r--drivers/hid/intel-ish-hid/ipc/pci-ish.c67
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-fw-loader.c60
-rw-r--r--drivers/hid/intel-ish-hid/ishtp-hid-client.c63
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/bus.c2
-rw-r--r--drivers/hid/intel-ish-hid/ishtp/client.c185
-rw-r--r--drivers/hid/wacom.h1
-rw-r--r--drivers/hid/wacom_sys.c8
-rw-r--r--drivers/hid/wacom_wac.c44
-rw-r--r--drivers/hid/wacom_wac.h1
-rw-r--r--drivers/hsi/controllers/omap_ssi_core.c6
-rw-r--r--drivers/hv/hv_common.c2
-rw-r--r--drivers/hwmon/npcm750-pwm-fan.c7
-rw-r--r--drivers/hwmon/pwm-fan.c8
-rw-r--r--drivers/hwspinlock/hwspinlock_core.c53
-rw-r--r--drivers/hwspinlock/qcom_hwspinlock.c1
-rw-r--r--drivers/hwtracing/coresight/coresight-core.c3
-rw-r--r--drivers/hwtracing/coresight/coresight-dummy.c5
-rw-r--r--drivers/hwtracing/coresight/coresight-etm-perf.c2
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x-core.c52
-rw-r--r--drivers/hwtracing/coresight/coresight-etm4x.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-funnel.c5
-rw-r--r--drivers/hwtracing/coresight/coresight-replicator.c5
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-core.c15
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc-etr.c111
-rw-r--r--drivers/hwtracing/coresight/coresight-tmc.h3
-rw-r--r--drivers/hwtracing/coresight/coresight-tpda.c126
-rw-r--r--drivers/hwtracing/coresight/coresight-tpda.h2
-rw-r--r--drivers/hwtracing/coresight/coresight-tpdm.c718
-rw-r--r--drivers/hwtracing/coresight/coresight-tpdm.h161
-rw-r--r--drivers/hwtracing/coresight/coresight-trbe.c28
-rw-r--r--drivers/hwtracing/coresight/coresight-trbe.h2
-rw-r--r--drivers/hwtracing/coresight/ultrasoc-smb.c76
-rw-r--r--drivers/hwtracing/ptt/hisi_ptt.c19
-rw-r--r--drivers/hwtracing/ptt/hisi_ptt.h1
-rw-r--r--drivers/i3c/master.c95
-rw-r--r--drivers/i3c/master/i3c-master-cdns.c7
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/cmd_v1.c7
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/core.c49
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/dma.c4
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/hci.h1
-rw-r--r--drivers/i3c/master/svc-i3c-master.c95
-rw-r--r--drivers/iio/accel/Kconfig7
-rw-r--r--drivers/iio/accel/bmi088-accel-core.c2
-rw-r--r--drivers/iio/accel/bmi088-accel-spi.c2
-rw-r--r--drivers/iio/adc/Kconfig29
-rw-r--r--drivers/iio/adc/Makefile5
-rw-r--r--drivers/iio/adc/ad7091r-base.c280
-rw-r--r--drivers/iio/adc/ad7091r-base.h83
-rw-r--r--drivers/iio/adc/ad7091r5.c120
-rw-r--r--drivers/iio/adc/ad7091r8.c272
-rw-r--r--drivers/iio/adc/ad9467.c207
-rw-r--r--drivers/iio/adc/adi-axi-adc.c159
-rw-r--r--drivers/iio/adc/max34408.c276
-rw-r--r--drivers/iio/adc/mcp3911.c64
-rw-r--r--drivers/iio/amplifiers/hmc425a.c23
-rw-r--r--drivers/iio/buffer/industrialio-buffer-dma.c87
-rw-r--r--drivers/iio/chemical/Kconfig11
-rw-r--r--drivers/iio/chemical/Makefile1
-rw-r--r--drivers/iio/chemical/ags02ma.c165
-rw-r--r--drivers/iio/chemical/pms7003.c6
-rw-r--r--drivers/iio/chemical/scd30_serial.c6
-rw-r--r--drivers/iio/chemical/sps30_serial.c18
-rw-r--r--drivers/iio/dac/Kconfig10
-rw-r--r--drivers/iio/dac/Makefile1
-rw-r--r--drivers/iio/dac/ad5791.c9
-rw-r--r--drivers/iio/dac/mcp4821.c236
-rw-r--r--drivers/iio/frequency/adf4377.c16
-rw-r--r--drivers/iio/frequency/admv1014.c31
-rw-r--r--drivers/iio/humidity/hdc3020.c473
-rw-r--r--drivers/iio/imu/Kconfig1
-rw-r--r--drivers/iio/imu/Makefile1
-rw-r--r--drivers/iio/imu/adis.c18
-rw-r--r--drivers/iio/imu/bmi323/Kconfig33
-rw-r--r--drivers/iio/imu/bmi323/Makefile7
-rw-r--r--drivers/iio/imu/bmi323/bmi323.h209
-rw-r--r--drivers/iio/imu/bmi323/bmi323_core.c2139
-rw-r--r--drivers/iio/imu/bmi323/bmi323_i2c.c121
-rw-r--r--drivers/iio/imu/bmi323/bmi323_spi.c92
-rw-r--r--drivers/iio/imu/bno055/bno055_ser_core.c6
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c5
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c5
-rw-r--r--drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c5
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c9
-rw-r--r--drivers/iio/industrialio-buffer.c22
-rw-r--r--drivers/iio/industrialio-core.c66
-rw-r--r--drivers/iio/light/Kconfig37
-rw-r--r--drivers/iio/light/Makefile3
-rw-r--r--drivers/iio/light/isl76682.c345
-rw-r--r--drivers/iio/light/ltr390.c196
-rw-r--r--drivers/iio/light/ltrf216a.c10
-rw-r--r--drivers/iio/light/pa12203001.c2
-rw-r--r--drivers/iio/light/rohm-bu27008.c201
-rw-r--r--drivers/iio/light/veml6075.c474
-rw-r--r--drivers/iio/magnetometer/tmag5273.c10
-rw-r--r--drivers/iio/pressure/Kconfig22
-rw-r--r--drivers/iio/pressure/Makefile3
-rw-r--r--drivers/iio/pressure/bmp280-core.c42
-rw-r--r--drivers/iio/pressure/bmp280-i2c.c8
-rw-r--r--drivers/iio/pressure/bmp280-spi.c10
-rw-r--r--drivers/iio/pressure/bmp280.h6
-rw-r--r--drivers/iio/pressure/hsc030pa.c494
-rw-r--r--drivers/iio/pressure/hsc030pa.h74
-rw-r--r--drivers/iio/pressure/hsc030pa_i2c.c69
-rw-r--r--drivers/iio/pressure/hsc030pa_spi.c61
-rw-r--r--drivers/iio/proximity/irsd200.c1
-rw-r--r--drivers/iio/proximity/sx9324.c24
-rw-r--r--drivers/iio/resolver/ad2s1210.c162
-rw-r--r--drivers/iio/temperature/Kconfig22
-rw-r--r--drivers/iio/temperature/Makefile2
-rw-r--r--drivers/iio/temperature/mcp9600.c139
-rw-r--r--drivers/iio/temperature/mlx90635.c1097
-rw-r--r--drivers/infiniband/hw/bnxt_re/bnxt_re.h3
-rw-r--r--drivers/infiniband/hw/bnxt_re/hw_counters.c4
-rw-r--r--drivers/infiniband/hw/bnxt_re/ib_verbs.c233
-rw-r--r--drivers/infiniband/hw/bnxt_re/ib_verbs.h10
-rw-r--r--drivers/infiniband/hw/bnxt_re/main.c47
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_fp.c215
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_fp.h35
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_rcfw.c21
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_rcfw.h4
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_res.c4
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_res.h117
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_sp.c11
-rw-r--r--drivers/infiniband/hw/bnxt_re/roce_hsi.h67
-rw-r--r--drivers/infiniband/hw/efa/efa.h12
-rw-r--r--drivers/infiniband/hw/efa/efa_admin_cmds_defs.h33
-rw-r--r--drivers/infiniband/hw/efa/efa_com_cmd.c11
-rw-r--r--drivers/infiniband/hw/efa/efa_com_cmd.h12
-rw-r--r--drivers/infiniband/hw/efa/efa_main.c7
-rw-r--r--drivers/infiniband/hw/efa/efa_verbs.c71
-rw-r--r--drivers/infiniband/hw/erdma/erdma.h2
-rw-r--r--drivers/infiniband/hw/erdma/erdma_hw.h39
-rw-r--r--drivers/infiniband/hw/erdma/erdma_main.c26
-rw-r--r--drivers/infiniband/hw/erdma/erdma_verbs.c90
-rw-r--r--drivers/infiniband/hw/erdma/erdma_verbs.h4
-rw-r--r--drivers/infiniband/hw/hfi1/user_exp_rcv.c4
-rw-r--r--drivers/infiniband/hw/hfi1/user_sdma.c4
-rw-r--r--drivers/infiniband/hw/hns/Makefile3
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_ah.c13
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_cmd.c19
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_cq.c17
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_debugfs.c110
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_debugfs.h33
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_device.h26
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_hw_v2.c71
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_main.c48
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_mr.c28
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_pd.c12
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_qp.c8
-rw-r--r--drivers/infiniband/hw/hns/hns_roce_srq.c6
-rw-r--r--drivers/infiniband/hw/irdma/utils.c11
-rw-r--r--drivers/infiniband/hw/mana/cq.c34
-rw-r--r--drivers/infiniband/hw/mana/device.c31
-rw-r--r--drivers/infiniband/hw/mana/main.c69
-rw-r--r--drivers/infiniband/hw/mana/mana_ib.h53
-rw-r--r--drivers/infiniband/hw/mana/qp.c91
-rw-r--r--drivers/infiniband/hw/mlx5/dm.c5
-rw-r--r--drivers/infiniband/hw/mlx5/main.c24
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c4
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c2
-rw-r--r--drivers/infiniband/sw/siw/siw.h14
-rw-r--r--drivers/infiniband/sw/siw/siw_cm.c145
-rw-r--r--drivers/infiniband/sw/siw/siw_main.c30
-rw-r--r--drivers/infiniband/sw/siw/siw_mem.c121
-rw-r--r--drivers/infiniband/sw/siw/siw_mem.h5
-rw-r--r--drivers/infiniband/sw/siw/siw_qp.c2
-rw-r--r--drivers/infiniband/sw/siw/siw_qp_rx.c84
-rw-r--r--drivers/infiniband/sw/siw/siw_qp_tx.c51
-rw-r--r--drivers/infiniband/sw/siw/siw_verbs.c52
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c26
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c33
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c7
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h7
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c5
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c8
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c1
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs-clt.c12
-rw-r--r--drivers/infiniband/ulp/rtrs/rtrs.c4
-rw-r--r--drivers/input/misc/da7280.c4
-rw-r--r--drivers/input/misc/pwm-beeper.c4
-rw-r--r--drivers/input/misc/pwm-vibra.c8
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c2
-rw-r--r--drivers/input/touchscreen/sur40.c7
-rw-r--r--drivers/interconnect/imx/imx8mm.c9
-rw-r--r--drivers/interconnect/imx/imx8mn.c9
-rw-r--r--drivers/interconnect/imx/imx8mp.c9
-rw-r--r--drivers/interconnect/imx/imx8mq.c9
-rw-r--r--drivers/interconnect/qcom/Kconfig27
-rw-r--r--drivers/interconnect/qcom/Makefile6
-rw-r--r--drivers/interconnect/qcom/icc-rpm.c4
-rw-r--r--drivers/interconnect/qcom/icc-rpm.h2
-rw-r--r--drivers/interconnect/qcom/msm8916.c2
-rw-r--r--drivers/interconnect/qcom/msm8939.c2
-rw-r--r--drivers/interconnect/qcom/msm8974.c6
-rw-r--r--drivers/interconnect/qcom/msm8996.c2
-rw-r--r--drivers/interconnect/qcom/osm-l3.c6
-rw-r--r--drivers/interconnect/qcom/qcm2290.c2
-rw-r--r--drivers/interconnect/qcom/qcs404.c2
-rw-r--r--drivers/interconnect/qcom/sdm660.c2
-rw-r--r--drivers/interconnect/qcom/sm6115.c1423
-rw-r--r--drivers/interconnect/qcom/sm8650.c1674
-rw-r--r--drivers/interconnect/qcom/sm8650.h143
-rw-r--r--drivers/interconnect/qcom/smd-rpm.c6
-rw-r--r--drivers/interconnect/qcom/x1e80100.c2328
-rw-r--r--drivers/interconnect/qcom/x1e80100.h192
-rw-r--r--drivers/interconnect/samsung/exynos.c6
-rw-r--r--drivers/iommu/Kconfig1
-rw-r--r--drivers/iommu/amd/amd_iommu.h8
-rw-r--r--drivers/iommu/amd/amd_iommu_types.h6
-rw-r--r--drivers/iommu/amd/init.c8
-rw-r--r--drivers/iommu/amd/io_pgtable.c5
-rw-r--r--drivers/iommu/amd/io_pgtable_v2.c10
-rw-r--r--drivers/iommu/amd/iommu.c189
-rw-r--r--drivers/iommu/apple-dart.c40
-rw-r--r--drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c23
-rw-r--r--drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c79
-rw-r--r--drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h8
-rw-r--r--drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c2
-rw-r--r--drivers/iommu/arm/arm-smmu/arm-smmu.c166
-rw-r--r--drivers/iommu/arm/arm-smmu/arm-smmu.h1
-rw-r--r--drivers/iommu/arm/arm-smmu/qcom_iommu.c26
-rw-r--r--drivers/iommu/dma-iommu.c3
-rw-r--r--drivers/iommu/intel/debugfs.c3
-rw-r--r--drivers/iommu/intel/iommu.c241
-rw-r--r--drivers/iommu/intel/iommu.h179
-rw-r--r--drivers/iommu/intel/nested.c88
-rw-r--r--drivers/iommu/intel/pasid.c274
-rw-r--r--drivers/iommu/intel/pasid.h223
-rw-r--r--drivers/iommu/intel/svm.c34
-rw-r--r--drivers/iommu/io-pgtable-arm.c55
-rw-r--r--drivers/iommu/io-pgtable.c23
-rw-r--r--drivers/iommu/iommu-sva.c97
-rw-r--r--drivers/iommu/iommu.c154
-rw-r--r--drivers/iommu/iommufd/hw_pagetable.c43
-rw-r--r--drivers/iommu/iommufd/iommufd_private.h10
-rw-r--r--drivers/iommu/iommufd/iommufd_test.h23
-rw-r--r--drivers/iommu/iommufd/main.c3
-rw-r--r--drivers/iommu/iommufd/selftest.c104
-rw-r--r--drivers/iommu/mtk_iommu.c7
-rw-r--r--drivers/iommu/mtk_iommu_v1.c3
-rw-r--r--drivers/iommu/of_iommu.c73
-rw-r--r--drivers/iommu/omap-iommu.c1
-rw-r--r--drivers/iommu/sprd-iommu.c8
-rw-r--r--drivers/iommu/virtio-iommu.c36
-rw-r--r--drivers/ipack/devices/ipoctal.c14
-rw-r--r--drivers/ipack/ipack.c4
-rw-r--r--drivers/isdn/capi/capi.c4
-rw-r--r--drivers/leds/Kconfig35
-rw-r--r--drivers/leds/Makefile2
-rw-r--r--drivers/leds/led-triggers.c13
-rw-r--r--drivers/leds/leds-aw200xx.c98
-rw-r--r--drivers/leds/leds-gpio.c2
-rw-r--r--drivers/leds/leds-max5970.c111
-rw-r--r--drivers/leds/leds-pwm.c2
-rw-r--r--drivers/leds/leds-sun50i-a100.c584
-rw-r--r--drivers/leds/leds-syscon.c3
-rw-r--r--drivers/leds/leds-tca6507.c30
-rw-r--r--drivers/leds/rgb/Kconfig2
-rw-r--r--drivers/leds/rgb/leds-pwm-multicolor.c4
-rw-r--r--drivers/leds/rgb/leds-qcom-lpg.c63
-rw-r--r--drivers/leds/trigger/ledtrig-gpio.c26
-rw-r--r--drivers/leds/trigger/ledtrig-netdev.c47
-rw-r--r--drivers/leds/trigger/ledtrig-panic.c5
-rw-r--r--drivers/leds/trigger/ledtrig-tty.c247
-rw-r--r--drivers/mailbox/arm_mhuv2.c3
-rw-r--r--drivers/mailbox/bcm-flexrm-mailbox.c6
-rw-r--r--drivers/mailbox/bcm-pdc-mailbox.c5
-rw-r--r--drivers/mailbox/imx-mailbox.c6
-rw-r--r--drivers/mailbox/mailbox-test.c6
-rw-r--r--drivers/mailbox/mtk-cmdq-mailbox.c49
-rw-r--r--drivers/mailbox/omap-mailbox.c6
-rw-r--r--drivers/mailbox/qcom-apcs-ipc-mailbox.c16
-rw-r--r--drivers/mailbox/qcom-ipcc.c6
-rw-r--r--drivers/mailbox/stm32-ipcc.c6
-rw-r--r--drivers/mailbox/sun6i-msgbox.c6
-rw-r--r--drivers/mailbox/tegra-hsp.c6
-rw-r--r--drivers/mailbox/zynqmp-ipi-mailbox.c7
-rw-r--r--drivers/mcb/mcb-core.c5
-rw-r--r--drivers/media/cec/core/cec-adap.c54
-rw-r--r--drivers/media/cec/platform/cros-ec/cros-ec-cec.c2
-rw-r--r--drivers/media/common/saa7146/saa7146_fops.c2
-rw-r--r--drivers/media/common/videobuf2/videobuf2-core.c518
-rw-r--r--drivers/media/common/videobuf2/videobuf2-dma-sg.c10
-rw-r--r--drivers/media/common/videobuf2/videobuf2-v4l2.c87
-rw-r--r--drivers/media/dvb-core/dvb_vb2.c21
-rw-r--r--drivers/media/dvb-core/dvbdev.c2
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.c7
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c5
-rw-r--r--drivers/media/i2c/Kconfig73
-rw-r--r--drivers/media/i2c/Makefile6
-rw-r--r--drivers/media/i2c/adv7180.c28
-rw-r--r--drivers/media/i2c/adv7183.c2
-rw-r--r--drivers/media/i2c/adv748x/adv748x-afe.c6
-rw-r--r--drivers/media/i2c/adv748x/adv748x-csi2.c2
-rw-r--r--drivers/media/i2c/adv748x/adv748x-hdmi.c6
-rw-r--r--drivers/media/i2c/adv7511-v4l2.c4
-rw-r--r--drivers/media/i2c/adv7604.c4
-rw-r--r--drivers/media/i2c/adv7842.c4
-rw-r--r--drivers/media/i2c/ak7375.c132
-rw-r--r--drivers/media/i2c/alvium-csi2.c2558
-rw-r--r--drivers/media/i2c/alvium-csi2.h475
-rw-r--r--drivers/media/i2c/ar0521.c5
-rw-r--r--drivers/media/i2c/ccs/Kconfig1
-rw-r--r--drivers/media/i2c/ccs/ccs-core.c134
-rw-r--r--drivers/media/i2c/ccs/ccs-reg-access.c213
-rw-r--r--drivers/media/i2c/ccs/ccs-regs.h906
-rw-r--r--drivers/media/i2c/ccs/ccs.h3
-rw-r--r--drivers/media/i2c/ccs/smiapp-reg-defs.h951
-rw-r--r--drivers/media/i2c/ds90ub913.c13
-rw-r--r--drivers/media/i2c/ds90ub953.c13
-rw-r--r--drivers/media/i2c/ds90ub960.c23
-rw-r--r--drivers/media/i2c/et8ek8/et8ek8_driver.c23
-rw-r--r--drivers/media/i2c/gc0308.c1451
-rw-r--r--drivers/media/i2c/gc2145.c1450
-rw-r--r--drivers/media/i2c/hi556.c13
-rw-r--r--drivers/media/i2c/hi846.c21
-rw-r--r--drivers/media/i2c/hi847.c9
-rw-r--r--drivers/media/i2c/imx208.c9
-rw-r--r--drivers/media/i2c/imx214.c207
-rw-r--r--drivers/media/i2c/imx219.c21
-rw-r--r--drivers/media/i2c/imx258.c9
-rw-r--r--drivers/media/i2c/imx274.c74
-rw-r--r--drivers/media/i2c/imx290.c60
-rw-r--r--drivers/media/i2c/imx296.c28
-rw-r--r--drivers/media/i2c/imx319.c19
-rw-r--r--drivers/media/i2c/imx334.c16
-rw-r--r--drivers/media/i2c/imx335.c227
-rw-r--r--drivers/media/i2c/imx355.c19
-rw-r--r--drivers/media/i2c/imx412.c16
-rw-r--r--drivers/media/i2c/imx415.c16
-rw-r--r--drivers/media/i2c/isl7998x.c6
-rw-r--r--drivers/media/i2c/max9286.c32
-rw-r--r--drivers/media/i2c/mt9m001.c16
-rw-r--r--drivers/media/i2c/mt9m111.c44
-rw-r--r--drivers/media/i2c/mt9m114.c104
-rw-r--r--drivers/media/i2c/mt9p031.c14
-rw-r--r--drivers/media/i2c/mt9t112.c1
-rw-r--r--drivers/media/i2c/mt9v011.c34
-rw-r--r--drivers/media/i2c/mt9v032.c10
-rw-r--r--drivers/media/i2c/mt9v111.c44
-rw-r--r--drivers/media/i2c/og01a1b.c10
-rw-r--r--drivers/media/i2c/ov01a10.c30
-rw-r--r--drivers/media/i2c/ov02a10.c16
-rw-r--r--drivers/media/i2c/ov08d10.c9
-rw-r--r--drivers/media/i2c/ov08x40.c7
-rw-r--r--drivers/media/i2c/ov13858.c10
-rw-r--r--drivers/media/i2c/ov13b10.c24
-rw-r--r--drivers/media/i2c/ov2640.c16
-rw-r--r--drivers/media/i2c/ov2659.c6
-rw-r--r--drivers/media/i2c/ov2680.c34
-rw-r--r--drivers/media/i2c/ov2685.c4
-rw-r--r--drivers/media/i2c/ov2740.c396
-rw-r--r--drivers/media/i2c/ov4689.c2
-rw-r--r--drivers/media/i2c/ov5640.c49
-rw-r--r--drivers/media/i2c/ov5645.c16
-rw-r--r--drivers/media/i2c/ov5647.c12
-rw-r--r--drivers/media/i2c/ov5648.c72
-rw-r--r--drivers/media/i2c/ov5670.c23
-rw-r--r--drivers/media/i2c/ov5675.c9
-rw-r--r--drivers/media/i2c/ov5693.c18
-rw-r--r--drivers/media/i2c/ov5695.c8
-rw-r--r--drivers/media/i2c/ov64a40.c3690
-rw-r--r--drivers/media/i2c/ov6650.c64
-rw-r--r--drivers/media/i2c/ov7251.c36
-rw-r--r--drivers/media/i2c/ov7670.c37
-rw-r--r--drivers/media/i2c/ov772x.c30
-rw-r--r--drivers/media/i2c/ov7740.c47
-rw-r--r--drivers/media/i2c/ov8856.c9
-rw-r--r--drivers/media/i2c/ov8858.c16
-rw-r--r--drivers/media/i2c/ov8865.c66
-rw-r--r--drivers/media/i2c/ov9282.c18
-rw-r--r--drivers/media/i2c/ov9640.c2
-rw-r--r--drivers/media/i2c/ov9650.c35
-rw-r--r--drivers/media/i2c/ov9734.c28
-rw-r--r--drivers/media/i2c/rj54n1cb0c.c4
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c65
-rw-r--r--drivers/media/i2c/s5k5baf.c69
-rw-r--r--drivers/media/i2c/s5k6a3.c8
-rw-r--r--drivers/media/i2c/saa6752hs.c4
-rw-r--r--drivers/media/i2c/st-mipid02.c481
-rw-r--r--drivers/media/i2c/st-vgxy61.c34
-rw-r--r--drivers/media/i2c/tc358746.c22
-rw-r--r--drivers/media/i2c/tda1997x.c16
-rw-r--r--drivers/media/i2c/thp7312.c2256
-rw-r--r--drivers/media/i2c/tvp514x.c41
-rw-r--r--drivers/media/i2c/tvp5150.c8
-rw-r--r--drivers/media/i2c/tvp7002.c6
-rw-r--r--drivers/media/i2c/tw9900.c781
-rw-r--r--drivers/media/i2c/tw9910.c2
-rw-r--r--drivers/media/i2c/video-i2c.c7
-rw-r--r--drivers/media/mc/Kconfig7
-rw-r--r--drivers/media/mc/mc-device.c4
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c29
-rw-r--r--drivers/media/pci/bt8xx/bttv-vbi.c8
-rw-r--r--drivers/media/pci/cobalt/cobalt-v4l2.c2
-rw-r--r--drivers/media/pci/cx18/cx18-streams.c7
-rw-r--r--drivers/media/pci/cx23885/cx23885-417.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c4
-rw-r--r--drivers/media/pci/cx25821/cx25821-video.c2
-rw-r--r--drivers/media/pci/cx88/cx88-blackbird.c2
-rw-r--r--drivers/media/pci/cx88/cx88-dvb.c2
-rw-r--r--drivers/media/pci/cx88/cx88-video.c4
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-main.c2
-rw-r--r--drivers/media/pci/dt3155/dt3155.c4
-rw-r--r--drivers/media/pci/intel/ipu-bridge.c2
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2.c26
-rw-r--r--drivers/media/pci/intel/ivsc/mei_csi.c83
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.h1
-rw-r--r--drivers/media/pci/ivtv/ivtv-streams.c4
-rw-r--r--drivers/media/pci/mgb4/mgb4_vin.c2
-rw-r--r--drivers/media/pci/mgb4/mgb4_vout.c2
-rw-r--r--drivers/media/pci/netup_unidvb/netup_unidvb_core.c5
-rw-r--r--drivers/media/pci/tw5864/tw5864-video.c2
-rw-r--r--drivers/media/pci/tw68/tw68-video.c7
-rw-r--r--drivers/media/pci/tw686x/tw686x-video.c7
-rw-r--r--drivers/media/pci/zoran/zoran_driver.c6
-rw-r--r--drivers/media/platform/amphion/vpu.h3
-rw-r--r--drivers/media/platform/amphion/vpu_cmds.c28
-rw-r--r--drivers/media/platform/amphion/vpu_core.c2
-rw-r--r--drivers/media/platform/amphion/vpu_dbg.c30
-rw-r--r--drivers/media/platform/amphion/vpu_v4l2.c9
-rw-r--r--drivers/media/platform/aspeed/aspeed-video.c2
-rw-r--r--drivers/media/platform/atmel/atmel-isi.c15
-rw-r--r--drivers/media/platform/cadence/cdns-csi2rx.c14
-rw-r--r--drivers/media/platform/cadence/cdns-csi2tx.c3
-rw-r--r--drivers/media/platform/chips-media/Kconfig18
-rw-r--r--drivers/media/platform/chips-media/Makefile6
-rw-r--r--drivers/media/platform/chips-media/coda/Kconfig18
-rw-r--r--drivers/media/platform/chips-media/coda/Makefile6
-rw-r--r--drivers/media/platform/chips-media/coda/coda-bit.c (renamed from drivers/media/platform/chips-media/coda-bit.c)0
-rw-r--r--drivers/media/platform/chips-media/coda/coda-common.c (renamed from drivers/media/platform/chips-media/coda-common.c)4
-rw-r--r--drivers/media/platform/chips-media/coda/coda-gdi.c (renamed from drivers/media/platform/chips-media/coda-gdi.c)0
-rw-r--r--drivers/media/platform/chips-media/coda/coda-h264.c (renamed from drivers/media/platform/chips-media/coda-h264.c)0
-rw-r--r--drivers/media/platform/chips-media/coda/coda-jpeg.c (renamed from drivers/media/platform/chips-media/coda-jpeg.c)0
-rw-r--r--drivers/media/platform/chips-media/coda/coda-mpeg2.c (renamed from drivers/media/platform/chips-media/coda-mpeg2.c)0
-rw-r--r--drivers/media/platform/chips-media/coda/coda-mpeg4.c (renamed from drivers/media/platform/chips-media/coda-mpeg4.c)0
-rw-r--r--drivers/media/platform/chips-media/coda/coda.h (renamed from drivers/media/platform/chips-media/coda.h)0
-rw-r--r--drivers/media/platform/chips-media/coda/coda_regs.h (renamed from drivers/media/platform/chips-media/coda_regs.h)0
-rw-r--r--drivers/media/platform/chips-media/coda/imx-vdoa.c (renamed from drivers/media/platform/chips-media/imx-vdoa.c)0
-rw-r--r--drivers/media/platform/chips-media/coda/imx-vdoa.h (renamed from drivers/media/platform/chips-media/imx-vdoa.h)0
-rw-r--r--drivers/media/platform/chips-media/coda/trace.h (renamed from drivers/media/platform/chips-media/trace.h)2
-rw-r--r--drivers/media/platform/chips-media/wave5/Kconfig15
-rw-r--r--drivers/media/platform/chips-media/wave5/Makefile10
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-helper.c213
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-helper.h31
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-hw.c2551
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-regdefine.h732
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vdi.c205
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vdi.h35
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c1932
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c1794
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu.c291
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu.h83
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuapi.c960
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuapi.h870
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h77
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuerror.h292
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5.h114
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c20
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c16
-rw-r--r--drivers/media/platform/mediatek/vcodec/Kconfig1
-rw-r--r--drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c24
-rw-r--r--drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c26
-rw-r--r--drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h14
-rw-r--r--drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c168
-rw-r--r--drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c9
-rw-r--r--drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c2
-rw-r--r--drivers/media/platform/microchip/microchip-csi2dc.c25
-rw-r--r--drivers/media/platform/microchip/microchip-isc-base.c41
-rw-r--r--drivers/media/platform/microchip/microchip-isc-scaler.c26
-rw-r--r--drivers/media/platform/nuvoton/npcm-video.c34
-rw-r--r--drivers/media/platform/nvidia/tegra-vde/Kconfig1
-rw-r--r--drivers/media/platform/nvidia/tegra-vde/v4l2.c2
-rw-r--r--drivers/media/platform/nxp/imx-mipi-csis.c37
-rw-r--r--drivers/media/platform/nxp/imx7-media-csi.c58
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c20
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c27
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c28
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c4
-rw-r--r--drivers/media/platform/nxp/imx8mq-mipi-csi2.c23
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid-gen2.c31
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid.c20
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid.h7
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy.c15
-rw-r--r--drivers/media/platform/qcom/camss/camss-ispif.c17
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-170.c36
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-4-1.c8
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-4-7.c36
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-4-8.c31
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-480.c69
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.c115
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.h26
-rw-r--r--drivers/media/platform/qcom/camss/camss.c122
-rw-r--r--drivers/media/platform/qcom/camss/camss.h10
-rw-r--r--drivers/media/platform/qcom/venus/core.c4
-rw-r--r--drivers/media/platform/qcom/venus/vdec.c4
-rw-r--r--drivers/media/platform/qcom/venus/venc.c4
-rw-r--r--drivers/media/platform/renesas/rcar-isp.c4
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-csi2.c4
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-dma.c2
-rw-r--r--drivers/media/platform/renesas/rcar_drif.c5
-rw-r--r--drivers/media/platform/renesas/renesas-ceu.c2
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c16
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c16
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c2
-rw-r--r--drivers/media/platform/renesas/sh_vou.c2
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_brx.c43
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_clu.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_entity.c138
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_entity.h12
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_hgo.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_hgt.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_histo.c24
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_hsit.c12
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_lif.c3
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_lut.c1
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_rpf.c8
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_rwpf.c41
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_sru.c37
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_uds.c40
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_uif.c25
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_video.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_wpf.c10
-rw-r--r--drivers/media/platform/rockchip/rga/rga-buf.c162
-rw-r--r--drivers/media/platform/rockchip/rga/rga-hw.c146
-rw-r--r--drivers/media/platform/rockchip/rga/rga.c189
-rw-r--r--drivers/media/platform/rockchip/rga/rga.h35
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c2
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-common.h12
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c40
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c6
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c41
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c136
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h9
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c101
-rw-r--r--drivers/media/platform/samsung/exynos-gsc/gsc-core.h1
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-capture.c12
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-core.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c1
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-isp.c24
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-lite.c16
-rw-r--r--drivers/media/platform/samsung/exynos4-is/mipi-csis.c3
-rw-r--r--drivers/media/platform/samsung/s3c-camif/camif-capture.c8
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h52
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h1
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h3
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c36
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h33
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c14
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c60
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c150
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h14
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c12
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c299
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h7
-rw-r--r--drivers/media/platform/st/sti/hva/hva-v4l2.c13
-rw-r--r--drivers/media/platform/st/stm32/Kconfig16
-rw-r--r--drivers/media/platform/st/stm32/Makefile1
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmi.c10
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmipp/Makefile4
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c956
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c565
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.c111
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.h217
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c604
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c440
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c1
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h1
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c2
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c17
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c18
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c2
-rw-r--r--drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c18
-rw-r--r--drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c18
-rw-r--r--drivers/media/platform/sunxi/sun8i-di/sun8i-di.c4
-rw-r--r--drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c4
-rw-r--r--drivers/media/platform/ti/am437x/am437x-vpfe.c7
-rw-r--r--drivers/media/platform/ti/cal/cal-camerarx.c28
-rw-r--r--drivers/media/platform/ti/cal/cal-video.c9
-rw-r--r--drivers/media/platform/ti/davinci/vpif_capture.c7
-rw-r--r--drivers/media/platform/ti/davinci/vpif_display.c7
-rw-r--r--drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c2
-rw-r--r--drivers/media/platform/ti/omap/omap_vout.c7
-rw-r--r--drivers/media/platform/ti/omap3isp/ispccdc.c19
-rw-r--r--drivers/media/platform/ti/omap3isp/ispccp2.c13
-rw-r--r--drivers/media/platform/ti/omap3isp/ispcsi2.c9
-rw-r--r--drivers/media/platform/ti/omap3isp/isppreview.c18
-rw-r--r--drivers/media/platform/ti/omap3isp/ispresizer.c21
-rw-r--r--drivers/media/platform/verisilicon/Kconfig1
-rw-r--r--drivers/media/platform/verisilicon/hantro.h9
-rw-r--r--drivers/media/platform/verisilicon/hantro_drv.c6
-rw-r--r--drivers/media/platform/verisilicon/hantro_g2.c14
-rw-r--r--drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c18
-rw-r--r--drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c28
-rw-r--r--drivers/media/platform/verisilicon/hantro_hw.h7
-rw-r--r--drivers/media/platform/verisilicon/hantro_postproc.c93
-rw-r--r--drivers/media/platform/verisilicon/hantro_v4l2.c29
-rw-r--r--drivers/media/platform/video-mux.c28
-rw-r--r--drivers/media/platform/xilinx/xilinx-csi2rxss.c74
-rw-r--r--drivers/media/platform/xilinx/xilinx-tpg.c9
-rw-r--r--drivers/media/platform/xilinx/xilinx-vip.c4
-rw-r--r--drivers/media/rc/ir-hix5hd2.c10
-rw-r--r--drivers/media/rc/meson-ir-tx.c34
-rw-r--r--drivers/media/rc/pwm-ir-tx.c87
-rw-r--r--drivers/media/test-drivers/Kconfig1
-rw-r--r--drivers/media/test-drivers/vicodec/Kconfig1
-rw-r--r--drivers/media/test-drivers/vicodec/vicodec-core.c20
-rw-r--r--drivers/media/test-drivers/vimc/vimc-capture.c2
-rw-r--r--drivers/media/test-drivers/vimc/vimc-debayer.c21
-rw-r--r--drivers/media/test-drivers/vimc/vimc-scaler.c20
-rw-r--r--drivers/media/test-drivers/vimc/vimc-sensor.c17
-rw-r--r--drivers/media/test-drivers/visl/Kconfig1
-rw-r--r--drivers/media/test-drivers/visl/visl-core.c21
-rw-r--r--drivers/media/test-drivers/visl/visl-dec.c104
-rw-r--r--drivers/media/test-drivers/visl/visl-dec.h8
-rw-r--r--drivers/media/test-drivers/visl/visl-trace-av1.h314
-rw-r--r--drivers/media/test-drivers/visl/visl-trace-points.c1
-rw-r--r--drivers/media/test-drivers/visl/visl-video.c21
-rw-r--r--drivers/media/test-drivers/visl/visl-video.h1
-rw-r--r--drivers/media/test-drivers/visl/visl.h1
-rw-r--r--drivers/media/test-drivers/vivid/Kconfig1
-rw-r--r--drivers/media/test-drivers/vivid/vivid-core.c18
-rw-r--r--drivers/media/test-drivers/vivid/vivid-meta-cap.c3
-rw-r--r--drivers/media/test-drivers/vivid/vivid-meta-out.c5
-rw-r--r--drivers/media/test-drivers/vivid/vivid-touch-cap.c5
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vbi-cap.c3
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vbi-out.c3
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-cap.c3
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-out.c5
-rw-r--r--drivers/media/usb/airspy/airspy.c5
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c7
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-core.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c9
-rw-r--r--drivers/media/usb/dvb-usb/cxusb-analog.c2
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c6
-rw-r--r--drivers/media/usb/gspca/gspca.c6
-rw-r--r--drivers/media/usb/hackrf/hackrf.c5
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-context.c3
-rw-r--r--drivers/media/usb/stk1160/stk1160-video.c5
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c5
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c18
-rw-r--r--drivers/media/usb/uvc/uvc_video.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-async.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-cci.c52
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c11
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c10
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c6
-rw-r--r--drivers/media/v4l2-core/v4l2-fwnode.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c6
-rw-r--r--drivers/media/v4l2-core/v4l2-mem2mem.c9
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c334
-rw-r--r--drivers/memory/tegra/tegra186.c14
-rw-r--r--drivers/mfd/Kconfig1
-rw-r--r--drivers/mfd/ab8500-sysctrl.c8
-rw-r--r--drivers/mfd/cros_ec_dev.c5
-rw-r--r--drivers/mfd/cs42l43-sdw.c76
-rw-r--r--drivers/mfd/da9062-core.c22
-rw-r--r--drivers/mfd/exynos-lpass.c6
-rw-r--r--drivers/mfd/fsl-imx25-tsadc.c6
-rw-r--r--drivers/mfd/hi655x-pmic.c5
-rw-r--r--drivers/mfd/intel-lpss-acpi.c33
-rw-r--r--drivers/mfd/intel-lpss-pci.c27
-rw-r--r--drivers/mfd/intel-lpss.c52
-rw-r--r--drivers/mfd/intel-lpss.h28
-rw-r--r--drivers/mfd/kempld-core.c6
-rw-r--r--drivers/mfd/mcp-sa11x0.c6
-rw-r--r--drivers/mfd/mxs-lradc.c6
-rw-r--r--drivers/mfd/omap-usb-host.c5
-rw-r--r--drivers/mfd/omap-usb-tll.c5
-rw-r--r--drivers/mfd/pcf50633-adc.c6
-rw-r--r--drivers/mfd/qcom-pm8xxx.c6
-rw-r--r--drivers/mfd/qcom-spmi-pmic.c1
-rw-r--r--drivers/mfd/rave-sp.c10
-rw-r--r--drivers/mfd/rk8xx-core.c34
-rw-r--r--drivers/mfd/sm501.c6
-rw-r--r--drivers/mfd/stm32-timers.c6
-rw-r--r--drivers/mfd/syscon.c4
-rw-r--r--drivers/mfd/ti_am335x_tscadc.c6
-rw-r--r--drivers/mfd/tps65086.c1
-rw-r--r--drivers/mfd/tps65911-comparator.c6
-rw-r--r--drivers/mfd/tps6594-core.c3
-rw-r--r--drivers/mfd/twl4030-audio.c6
-rw-r--r--drivers/mfd/twl6030-irq.c10
-rw-r--r--drivers/misc/Kconfig12
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/bcm-vk/bcm_vk_tty.c4
-rw-r--r--drivers/misc/cardreader/Makefile2
-rw-r--r--drivers/misc/cardreader/rts5264.c886
-rw-r--r--drivers/misc/cardreader/rts5264.h278
-rw-r--r--drivers/misc/cardreader/rtsx_pcr.c30
-rw-r--r--drivers/misc/cardreader/rtsx_pcr.h1
-rw-r--r--drivers/misc/dw-xdata-pcie.c6
-rw-r--r--drivers/misc/eeprom/at24.c43
-rw-r--r--drivers/misc/eeprom/ee1004.c113
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d_i2c.c1
-rw-r--r--drivers/misc/mei/Kconfig35
-rw-r--r--drivers/misc/mei/Makefile7
-rw-r--r--drivers/misc/mei/gsc_proxy/Kconfig2
-rw-r--r--drivers/misc/mei/hdcp/Kconfig2
-rw-r--r--drivers/misc/mei/platform-vsc.c450
-rw-r--r--drivers/misc/mei/pxp/Kconfig3
-rw-r--r--drivers/misc/mei/vsc-fw-loader.c770
-rw-r--r--drivers/misc/mei/vsc-tp.c555
-rw-r--r--drivers/misc/mei/vsc-tp.h50
-rw-r--r--drivers/misc/nsm.c506
-rw-r--r--drivers/misc/pci_endpoint_test.c50
-rw-r--r--drivers/misc/pvpanic/pvpanic-mmio.c7
-rw-r--r--drivers/misc/pvpanic/pvpanic-pci.c6
-rw-r--r--drivers/misc/pvpanic/pvpanic.c12
-rw-r--r--drivers/misc/pvpanic/pvpanic.h5
-rw-r--r--drivers/misc/vmw_vmci/vmci_handle_array.c12
-rw-r--r--drivers/misc/vmw_vmci/vmci_handle_array.h6
-rw-r--r--drivers/mmc/core/block.c46
-rw-r--r--drivers/mmc/core/host.c3
-rw-r--r--drivers/mmc/core/mmc.c30
-rw-r--r--drivers/mmc/core/mmc_test.c33
-rw-r--r--drivers/mmc/core/sdio_uart.c22
-rw-r--r--drivers/mmc/host/Kconfig10
-rw-r--r--drivers/mmc/host/mmc_spi.c186
-rw-r--r--drivers/mmc/host/mmci.c69
-rw-r--r--drivers/mmc/host/mmci.h2
-rw-r--r--drivers/mmc/host/mtk-sd.c166
-rw-r--r--drivers/mmc/host/rtsx_pci_sdmmc.c17
-rw-r--r--drivers/mmc/host/sdhci-brcmstb.c69
-rw-r--r--drivers/mmc/host/sdhci-of-dwcmshc.c349
-rw-r--r--drivers/mmc/host/sdhci-omap.c2
-rw-r--r--drivers/mmc/host/sdhci-xenon.c31
-rw-r--r--drivers/mmc/host/sdhci-xenon.h3
-rw-r--r--drivers/mmc/host/sdhci.c3
-rw-r--r--drivers/mmc/host/sdhci.h1
-rw-r--r--drivers/mmc/host/sdhci_am654.c37
-rw-r--r--drivers/mtd/mtdcore.c5
-rw-r--r--drivers/mtd/ubi/Kconfig9
-rw-r--r--drivers/mtd/ubi/block.c2
-rw-r--r--drivers/mtd/ubi/debug.c108
-rw-r--r--drivers/mtd/ubi/debug.h304
-rw-r--r--drivers/mtd/ubi/io.c86
-rw-r--r--drivers/mtd/ubi/ubi.h45
-rw-r--r--drivers/mux/mmio.c19
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/eswitch.h7
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c38
-rw-r--r--drivers/net/ethernet/microsoft/mana/gdma_main.c5
-rw-r--r--drivers/net/ethernet/qualcomm/qca_uart.c5
-rw-r--r--drivers/net/usb/hso.c11
-rw-r--r--drivers/net/usb/r8152.c16
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c2
-rw-r--r--drivers/net/wireless/marvell/mwifiex/usb.c2
-rw-r--r--drivers/nfc/pn533/uart.c4
-rw-r--r--drivers/nfc/s3fwrn5/uart.c5
-rw-r--r--drivers/nvdimm/btt.c15
-rw-r--r--drivers/nvdimm/btt_devs.c6
-rw-r--r--drivers/nvdimm/bus.c4
-rw-r--r--drivers/nvdimm/dax_devs.c4
-rw-r--r--drivers/nvdimm/dimm_devs.c17
-rw-r--r--drivers/nvdimm/namespace_devs.c19
-rw-r--r--drivers/nvdimm/pfn_devs.c4
-rw-r--r--drivers/nvdimm/virtio_pmem.c36
-rw-r--r--drivers/nvmem/Kconfig1
-rw-r--r--drivers/nvmem/Makefile2
-rw-r--r--drivers/nvmem/core.c359
-rw-r--r--drivers/nvmem/imx-ocotp.c11
-rw-r--r--drivers/nvmem/internals.h59
-rw-r--r--drivers/nvmem/layouts.c201
-rw-r--r--drivers/nvmem/layouts/Kconfig8
-rw-r--r--drivers/nvmem/layouts/onie-tlv.c29
-rw-r--r--drivers/nvmem/layouts/sl28vpd.c29
-rw-r--r--drivers/nvmem/mtk-efuse.c11
-rw-r--r--drivers/nvmem/stm32-romem.c16
-rw-r--r--drivers/nvmem/u-boot-env.c84
-rw-r--r--drivers/of/base.c1
-rw-r--r--drivers/of/device.c65
-rw-r--r--drivers/of/overlay.c2
-rw-r--r--drivers/of/platform.c62
-rw-r--r--drivers/of/property.c7
-rw-r--r--drivers/of/unittest-data/tests-phandle.dtsi10
-rw-r--r--drivers/of/unittest.c74
-rw-r--r--drivers/parisc/power.c2
-rw-r--r--drivers/parport/parport_serial.c64
-rw-r--r--drivers/parport/share.c8
-rw-r--r--drivers/pci/controller/cadence/Kconfig2
-rw-r--r--drivers/pci/controller/cadence/pci-j721e.c45
-rw-r--r--drivers/pci/controller/cadence/pcie-cadence-ep.c19
-rw-r--r--drivers/pci/controller/cadence/pcie-cadence.h12
-rw-r--r--drivers/pci/controller/dwc/Kconfig2
-rw-r--r--drivers/pci/controller/dwc/pci-dra7xx.c14
-rw-r--r--drivers/pci/controller/dwc/pci-exynos.c8
-rw-r--r--drivers/pci/controller/dwc/pci-imx6.c17
-rw-r--r--drivers/pci/controller/dwc/pci-keystone.c109
-rw-r--r--drivers/pci/controller/dwc/pci-layerscape-ep.c33
-rw-r--r--drivers/pci/controller/dwc/pci-layerscape.c193
-rw-r--r--drivers/pci/controller/dwc/pci-meson.c2
-rw-r--r--drivers/pci/controller/dwc/pcie-al.c2
-rw-r--r--drivers/pci/controller/dwc/pcie-armada8k.c2
-rw-r--r--drivers/pci/controller/dwc/pcie-artpec6.c12
-rw-r--r--drivers/pci/controller/dwc/pcie-bt1.c4
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-ep.c197
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-host.c30
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-plat.c13
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.h111
-rw-r--r--drivers/pci/controller/dwc/pcie-dw-rockchip.c6
-rw-r--r--drivers/pci/controller/dwc/pcie-fu740.c2
-rw-r--r--drivers/pci/controller/dwc/pcie-histb.c2
-rw-r--r--drivers/pci/controller/dwc/pcie-intel-gw.c2
-rw-r--r--drivers/pci/controller/dwc/pcie-keembay.c15
-rw-r--r--drivers/pci/controller/dwc/pcie-kirin.c21
-rw-r--r--drivers/pci/controller/dwc/pcie-qcom-ep.c10
-rw-r--r--drivers/pci/controller/dwc/pcie-qcom.c6
-rw-r--r--drivers/pci/controller/dwc/pcie-rcar-gen4.c23
-rw-r--r--drivers/pci/controller/dwc/pcie-spear13xx.c2
-rw-r--r--drivers/pci/controller/dwc/pcie-tegra194.c21
-rw-r--r--drivers/pci/controller/dwc/pcie-uniphier-ep.c13
-rw-r--r--drivers/pci/controller/dwc/pcie-uniphier.c14
-rw-r--r--drivers/pci/controller/dwc/pcie-visconti.c2
-rw-r--r--drivers/pci/controller/pci-host-common.c4
-rw-r--r--drivers/pci/controller/pci-host-generic.c2
-rw-r--r--drivers/pci/controller/pcie-brcmstb.c96
-rw-r--r--drivers/pci/controller/pcie-iproc-platform.c2
-rw-r--r--drivers/pci/controller/pcie-mediatek-gen3.c85
-rw-r--r--drivers/pci/controller/pcie-mediatek.c10
-rw-r--r--drivers/pci/controller/pcie-rcar-ep.c7
-rw-r--r--drivers/pci/controller/pcie-rcar-host.c18
-rw-r--r--drivers/pci/controller/pcie-rockchip-ep.c23
-rw-r--r--drivers/pci/controller/pcie-rockchip-host.c4
-rw-r--r--drivers/pci/controller/pcie-xilinx-dma-pl.c14
-rw-r--r--drivers/pci/controller/pcie-xilinx-nwl.c52
-rw-r--r--drivers/pci/controller/vmd.c6
-rw-r--r--drivers/pci/endpoint/functions/pci-epf-mhi.c320
-rw-r--r--drivers/pci/endpoint/functions/pci-epf-ntb.c6
-rw-r--r--drivers/pci/endpoint/functions/pci-epf-test.c16
-rw-r--r--drivers/pci/endpoint/functions/pci-epf-vntb.c9
-rw-r--r--drivers/pci/endpoint/pci-epc-core.c6
-rw-r--r--drivers/pci/iov.c7
-rw-r--r--drivers/pci/pci.c123
-rw-r--r--drivers/pci/pci.h4
-rw-r--r--drivers/pci/pcie/aer.c21
-rw-r--r--drivers/pci/probe.c218
-rw-r--r--drivers/pci/quirks.c34
-rw-r--r--drivers/pci/setup-bus.c30
-rw-r--r--drivers/pci/setup-res.c72
-rw-r--r--drivers/pci/switch/switchtec.c25
-rw-r--r--drivers/pcmcia/bcm63xx_pcmcia.c5
-rw-r--r--drivers/pcmcia/db1xxx_ss.c6
-rw-r--r--drivers/pcmcia/electra_cf.c6
-rw-r--r--drivers/pcmcia/omap_cf.c5
-rw-r--r--drivers/pcmcia/pxa2xx_base.c6
-rw-r--r--drivers/pcmcia/sa1100_generic.c8
-rw-r--r--drivers/pcmcia/xxs1500_ss.c6
-rw-r--r--drivers/pinctrl/Kconfig16
-rw-r--r--drivers/pinctrl/Makefile1
-rw-r--r--drivers/pinctrl/bcm/pinctrl-ns.c4
-rw-r--r--drivers/pinctrl/core.c59
-rw-r--r--drivers/pinctrl/core.h33
-rw-r--r--drivers/pinctrl/devicetree.c8
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx.c44
-rw-r--r--drivers/pinctrl/intel/Kconfig21
-rw-r--r--drivers/pinctrl/intel/Makefile2
-rw-r--r--drivers/pinctrl/intel/pinctrl-alderlake.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-baytrail.c229
-rw-r--r--drivers/pinctrl/intel/pinctrl-broxton.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-cannonlake.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-cedarfork.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-denverton.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-elkhartlake.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-emmitsburg.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-geminilake.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-icelake.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel-platform.c225
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.c32
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.h14
-rw-r--r--drivers/pinctrl/intel/pinctrl-jasperlake.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-lakefield.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-lewisburg.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-lynxpoint.c72
-rw-r--r--drivers/pinctrl/intel/pinctrl-meteorlake.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-meteorpoint.c465
-rw-r--r--drivers/pinctrl/intel/pinctrl-sunrisepoint.c5
-rw-r--r--drivers/pinctrl/intel/pinctrl-tangier.c32
-rw-r--r--drivers/pinctrl/intel/pinctrl-tigerlake.c5
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-moore.c13
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-moore.h10
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt2701.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt2712.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt6795.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8167.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8173.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8183.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8186.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8188.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8192.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8195.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8365.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8516.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c5
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-paris.c5
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-paris.h10
-rw-r--r--drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c2
-rw-r--r--drivers/pinctrl/nuvoton/pinctrl-wpcm450.c9
-rw-r--r--drivers/pinctrl/pinconf-generic.c16
-rw-r--r--drivers/pinctrl/pinconf.c14
-rw-r--r--drivers/pinctrl/pinconf.h10
-rw-r--r--drivers/pinctrl/pinctrl-as3722.c17
-rw-r--r--drivers/pinctrl/pinctrl-cy8c95x0.c458
-rw-r--r--drivers/pinctrl/pinctrl-equilibrium.c42
-rw-r--r--drivers/pinctrl/pinctrl-ingenic.c35
-rw-r--r--drivers/pinctrl/pinctrl-keembay.c6
-rw-r--r--drivers/pinctrl/pinctrl-single.c5
-rw-r--r--drivers/pinctrl/pinctrl-tps6594.c373
-rw-r--r--drivers/pinctrl/pinctrl-utils.c26
-rw-r--r--drivers/pinctrl/pinctrl-utils.h18
-rw-r--r--drivers/pinctrl/pinmux.c36
-rw-r--r--drivers/pinctrl/pinmux.h20
-rw-r--r--drivers/pinctrl/qcom/Kconfig10
-rw-r--r--drivers/pinctrl/qcom/Kconfig.msm26
-rw-r--r--drivers/pinctrl/qcom/Makefile4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-lpass-lpi.c70
-rw-r--r--drivers/pinctrl/qcom/pinctrl-lpass-lpi.h13
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.c46
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.h5
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c16
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c20
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm4450.c1014
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c20
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c15
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8350-lpass-lpi.c16
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c24
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c24
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c231
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sm8650.c1762
-rw-r--r--drivers/pinctrl/qcom/pinctrl-x1e80100.c1876
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rza1.c2
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rza2.c10
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rzg2l.c171
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rzv2m.c6
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos-arm64.c280
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos.c111
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos.h25
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.c11
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.h14
-rw-r--r--drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c8
-rw-r--r--drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c8
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32.c3
-rw-r--r--drivers/pinctrl/tegra/pinctrl-tegra.c8
-rw-r--r--drivers/platform/chrome/cros_ec_ishtp.c74
-rw-r--r--drivers/platform/chrome/cros_ec_uart.c5
-rw-r--r--drivers/platform/goldfish/goldfish_pipe.c5
-rw-r--r--drivers/platform/surface/aggregator/bus.c5
-rw-r--r--drivers/platform/surface/aggregator/controller.h4
-rw-r--r--drivers/platform/surface/aggregator/core.c4
-rw-r--r--drivers/platform/surface/aggregator/ssh_packet_layer.c4
-rw-r--r--drivers/platform/surface/aggregator/ssh_packet_layer.h2
-rw-r--r--drivers/platform/x86/intel/chtwc_int33fe.c2
-rw-r--r--drivers/platform/x86/lenovo-yogabook.c2
-rw-r--r--drivers/pmdomain/Kconfig1
-rw-r--r--drivers/pmdomain/Makefile1
-rw-r--r--drivers/pmdomain/amlogic/meson-ee-pwrc.c16
-rw-r--r--drivers/pmdomain/arm/Kconfig37
-rw-r--r--drivers/pmdomain/arm/Makefile1
-rw-r--r--drivers/pmdomain/arm/scpi_pm_domain.c (renamed from drivers/firmware/scpi_pm_domain.c)0
-rw-r--r--drivers/pmdomain/core.c (renamed from drivers/base/power/domain.c)36
-rw-r--r--drivers/pmdomain/governor.c (renamed from drivers/base/power/domain_governor.c)8
-rw-r--r--drivers/pmdomain/imx/gpc.c28
-rw-r--r--drivers/pmdomain/imx/gpcv2.c6
-rw-r--r--drivers/pmdomain/imx/imx8m-blk-ctrl.c6
-rw-r--r--drivers/pmdomain/imx/imx8mp-blk-ctrl.c6
-rw-r--r--drivers/pmdomain/imx/imx93-blk-ctrl.c6
-rw-r--r--drivers/pmdomain/imx/imx93-pd.c6
-rw-r--r--drivers/pmdomain/qcom/cpr.c6
-rw-r--r--drivers/pmdomain/qcom/rpmhpd.c12
-rw-r--r--drivers/pmdomain/xilinx/zynqmp-pm-domains.c6
-rw-r--r--drivers/pnp/driver.c2
-rw-r--r--drivers/pwm/core.c166
-rw-r--r--drivers/pwm/pwm-atmel-hlcdc.c8
-rw-r--r--drivers/pwm/pwm-atmel-tcb.c8
-rw-r--r--drivers/pwm/pwm-bcm-kona.c2
-rw-r--r--drivers/pwm/pwm-bcm2835.c36
-rw-r--r--drivers/pwm/pwm-berlin.c8
-rw-r--r--drivers/pwm/pwm-brcmstb.c8
-rw-r--r--drivers/pwm/pwm-crc.c16
-rw-r--r--drivers/pwm/pwm-cros-ec.c2
-rw-r--r--drivers/pwm/pwm-dwc.c6
-rw-r--r--drivers/pwm/pwm-img.c10
-rw-r--r--drivers/pwm/pwm-imx-tpm.c10
-rw-r--r--drivers/pwm/pwm-jz4740.c13
-rw-r--r--drivers/pwm/pwm-lpc18xx-sct.c6
-rw-r--r--drivers/pwm/pwm-lpc32xx.c2
-rw-r--r--drivers/pwm/pwm-mediatek.c2
-rw-r--r--drivers/pwm/pwm-meson.c35
-rw-r--r--drivers/pwm/pwm-omap-dmtimer.c20
-rw-r--r--drivers/pwm/pwm-renesas-tpu.c3
-rw-r--r--drivers/pwm/pwm-rockchip.c9
-rw-r--r--drivers/pwm/pwm-samsung.c6
-rw-r--r--drivers/pwm/pwm-sti.c2
-rw-r--r--drivers/pwm/pwm-stm32-lp.c10
-rw-r--r--drivers/pwm/pwm-stm32.c106
-rw-r--r--drivers/pwm/pwm-stmpe.c14
-rw-r--r--drivers/pwm/pwm-tegra.c2
-rw-r--r--drivers/pwm/pwm-tiecap.c6
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c8
-rw-r--r--drivers/pwm/pwm-twl-led.c6
-rw-r--r--drivers/pwm/pwm-twl.c4
-rw-r--r--drivers/pwm/pwm-vt8500.c4
-rw-r--r--drivers/pwm/sysfs.c12
-rw-r--r--drivers/regulator/pwm-regulator.c4
-rw-r--r--drivers/remoteproc/imx_dsp_rproc.c1
-rw-r--r--drivers/remoteproc/qcom_q6v5_pas.c19
-rw-r--r--drivers/remoteproc/ti_k3_dsp_remoteproc.c87
-rw-r--r--drivers/rpmsg/virtio_rpmsg_bus.c1
-rw-r--r--drivers/s390/char/con3215.c25
-rw-r--r--drivers/s390/char/con3270.c12
-rw-r--r--drivers/s390/char/uvdevice.c3
-rw-r--r--drivers/s390/crypto/vfio_ap_ops.c268
-rw-r--r--drivers/s390/crypto/vfio_ap_private.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c2
-rw-r--r--drivers/scsi/virtio_scsi.c78
-rw-r--r--drivers/sh/maple/maple.c4
-rw-r--r--drivers/soc/xilinx/xlnx_event_manager.c33
-rw-r--r--drivers/soc/xilinx/zynqmp_power.c2
-rw-r--r--drivers/spmi/Makefile2
-rw-r--r--drivers/spmi/hisi-spmi-controller.c32
-rw-r--r--drivers/spmi/spmi-devres.c64
-rw-r--r--drivers/spmi/spmi-mtk-pmif.c61
-rw-r--r--drivers/spmi/spmi-pmic-arb.c87
-rw-r--r--drivers/spmi/spmi.c6
-rw-r--r--drivers/staging/media/Kconfig2
-rw-r--r--drivers/staging/media/Makefile1
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc0310.c16
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-gc2235.c16
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c16
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-ov2722.c16
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_cmd.c4
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_csi2.c3
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_ioctl.c8
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_subdev.c6
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_tpg.c2
-rw-r--r--drivers/staging/media/deprecated/atmel/atmel-isc-base.c12
-rw-r--r--drivers/staging/media/imx/imx-ic-prp.c34
-rw-r--r--drivers/staging/media/imx/imx-ic-prpencvf.c34
-rw-r--r--drivers/staging/media/imx/imx-media-capture.c15
-rw-r--r--drivers/staging/media/imx/imx-media-csi.c38
-rw-r--r--drivers/staging/media/imx/imx-media-utils.c10
-rw-r--r--drivers/staging/media/imx/imx-media-vdic.c32
-rw-r--r--drivers/staging/media/imx/imx-media.h4
-rw-r--r--drivers/staging/media/imx/imx6-mipi-csi2.c4
-rw-r--r--drivers/staging/media/ipu3/ipu3-v4l2.c16
-rw-r--r--drivers/staging/media/meson/vdec/vdec.c19
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.c9
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipe.c11
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipeif.c11
-rw-r--r--drivers/staging/media/omap4iss/iss_resizer.c11
-rw-r--r--drivers/staging/media/rkvdec/Kconfig1
-rw-r--r--drivers/staging/media/rkvdec/rkvdec.c3
-rw-r--r--drivers/staging/media/starfive/Kconfig5
-rw-r--r--drivers/staging/media/starfive/Makefile2
-rw-r--r--drivers/staging/media/starfive/camss/Kconfig18
-rw-r--r--drivers/staging/media/starfive/camss/Makefile13
-rw-r--r--drivers/staging/media/starfive/camss/TODO.txt4
-rw-r--r--drivers/staging/media/starfive/camss/stf-camss.c436
-rw-r--r--drivers/staging/media/starfive/camss/stf-camss.h134
-rw-r--r--drivers/staging/media/starfive/camss/stf-capture.c603
-rw-r--r--drivers/staging/media/starfive/camss/stf-capture.h86
-rw-r--r--drivers/staging/media/starfive/camss/stf-isp-hw-ops.c445
-rw-r--r--drivers/staging/media/starfive/camss/stf-isp.c385
-rw-r--r--drivers/staging/media/starfive/camss/stf-isp.h428
-rw-r--r--drivers/staging/media/starfive/camss/stf-video.c572
-rw-r--r--drivers/staging/media/starfive/camss/stf-video.h100
-rw-r--r--drivers/staging/media/sunxi/cedrus/Kconfig1
-rw-r--r--drivers/staging/media/sunxi/cedrus/TODO23
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_h264.c9
-rw-r--r--drivers/staging/media/sunxi/cedrus/cedrus_h265.c9
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c2
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c2
-rw-r--r--drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c18
-rw-r--r--drivers/staging/media/tegra-video/csi.c22
-rw-r--r--drivers/staging/media/tegra-video/vi.c22
-rw-r--r--drivers/staging/media/tegra-video/vip.c6
-rw-r--r--drivers/staging/rtl8192e/Makefile1
-rw-r--r--drivers/staging/rtl8192e/dot11d.c165
-rw-r--r--drivers/staging/rtl8192e/dot11d.h84
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c41
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c12
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.c101
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.h11
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.c22
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.c22
-rw-r--r--drivers/staging/rtl8192e/rtl819x_BAProc.c228
-rw-r--r--drivers/staging/rtl8192e/rtl819x_HT.h35
-rw-r--r--drivers/staging/rtl8192e/rtl819x_HTProc.c371
-rw-r--r--drivers/staging/rtl8192e/rtl819x_Qos.h2
-rw-r--r--drivers/staging/rtl8192e/rtl819x_TS.h22
-rw-r--r--drivers/staging/rtl8192e/rtl819x_TSProc.c156
-rw-r--r--drivers/staging/rtl8192e/rtllib.h71
-rw-r--r--drivers/staging/rtl8192e/rtllib_module.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c82
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac.c387
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac_wx.c11
-rw-r--r--drivers/staging/rtl8192e/rtllib_tx.c66
-rw-r--r--drivers/staging/rtl8192e/rtllib_wx.c2
-rw-r--r--drivers/staging/rtl8712/os_intfs.c3
-rw-r--r--drivers/staging/rtl8712/rtl8712_efuse.c9
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.c3
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.c60
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.c159
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.h37
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_linux.c203
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h2
-rw-r--r--drivers/staging/vc04_services/interface/TODO5
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c271
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h7
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c8
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h4
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c668
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h54
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c10
-rw-r--r--drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c113
-rw-r--r--drivers/staging/vme_user/Kconfig22
-rw-r--r--drivers/staging/vme_user/vme.c4
-rw-r--r--drivers/staging/vt6655/card.c90
-rw-r--r--drivers/staging/vt6655/card.h18
-rw-r--r--drivers/staging/vt6655/device.h4
-rw-r--r--drivers/staging/vt6655/device_main.c18
-rw-r--r--drivers/staging/vt6655/rxtx.c2
-rw-r--r--drivers/thermal/Kconfig7
-rw-r--r--drivers/thermal/Makefile2
-rw-r--r--drivers/thermal/gov_power_allocator.c2
-rw-r--r--drivers/thermal/intel/intel_hfi.c28
-rw-r--r--drivers/thermal/thermal_core.c38
-rw-r--r--drivers/thermal/thermal_core.h1
-rw-r--r--drivers/thermal/thermal_debugfs.c839
-rw-r--r--drivers/thermal/thermal_debugfs.h28
-rw-r--r--drivers/thermal/thermal_helpers.c21
-rw-r--r--drivers/thermal/thermal_netlink.c95
-rw-r--r--drivers/thermal/thermal_netlink.h75
-rw-r--r--drivers/thermal/thermal_trip.c8
-rw-r--r--drivers/thunderbolt/domain.c2
-rw-r--r--drivers/thunderbolt/icm.c2
-rw-r--r--drivers/thunderbolt/nhi.c4
-rw-r--r--drivers/thunderbolt/nhi.h2
-rw-r--r--drivers/thunderbolt/switch.c33
-rw-r--r--drivers/thunderbolt/tb.c74
-rw-r--r--drivers/thunderbolt/tb.h18
-rw-r--r--drivers/thunderbolt/tmu.c2
-rw-r--r--drivers/thunderbolt/tunnel.c46
-rw-r--r--drivers/thunderbolt/xdomain.c54
-rw-r--r--drivers/tty/amiserial.c16
-rw-r--r--drivers/tty/ehv_bytechan.c18
-rw-r--r--drivers/tty/goldfish.c23
-rw-r--r--drivers/tty/hvc/hvc_console.c7
-rw-r--r--drivers/tty/hvc/hvc_console.h8
-rw-r--r--drivers/tty/hvc/hvc_dcc.c32
-rw-r--r--drivers/tty/hvc/hvc_iucv.c18
-rw-r--r--drivers/tty/hvc/hvc_opal.c22
-rw-r--r--drivers/tty/hvc/hvc_riscv_sbi.c9
-rw-r--r--drivers/tty/hvc/hvc_rtas.c11
-rw-r--r--drivers/tty/hvc/hvc_udbg.c9
-rw-r--r--drivers/tty/hvc/hvc_vio.c18
-rw-r--r--drivers/tty/hvc/hvc_xen.c23
-rw-r--r--drivers/tty/hvc/hvsi_lib.c20
-rw-r--r--drivers/tty/ipwireless/main.h3
-rw-r--r--drivers/tty/mips_ejtag_fdc.c10
-rw-r--r--drivers/tty/moxa.c15
-rw-r--r--drivers/tty/mxser.c8
-rw-r--r--drivers/tty/n_gsm.c17
-rw-r--r--drivers/tty/n_hdlc.c10
-rw-r--r--drivers/tty/nozomi.c27
-rw-r--r--drivers/tty/serdev/core.c31
-rw-r--r--drivers/tty/serdev/serdev-ttyport.c5
-rw-r--r--drivers/tty/serial/8250/8250_aspeed_vuart.c6
-rw-r--r--drivers/tty/serial/8250/8250_bcm2835aux.c8
-rw-r--r--drivers/tty/serial/8250/8250_bcm7271.c5
-rw-r--r--drivers/tty/serial/8250/8250_core.c5
-rw-r--r--drivers/tty/serial/8250/8250_dw.c6
-rw-r--r--drivers/tty/serial/8250/8250_dwlib.c16
-rw-r--r--drivers/tty/serial/8250/8250_em.c5
-rw-r--r--drivers/tty/serial/8250/8250_exar.c5
-rw-r--r--drivers/tty/serial/8250/8250_fsl.c8
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c5
-rw-r--r--drivers/tty/serial/8250/8250_ioc3.c5
-rw-r--r--drivers/tty/serial/8250/8250_lpc18xx.c6
-rw-r--r--drivers/tty/serial/8250/8250_lpss.c7
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c6
-rw-r--r--drivers/tty/serial/8250/8250_of.c5
-rw-r--r--drivers/tty/serial/8250/8250_omap.c7
-rw-r--r--drivers/tty/serial/8250/8250_pci.c61
-rw-r--r--drivers/tty/serial/8250/8250_pci1xxxx.c210
-rw-r--r--drivers/tty/serial/8250/8250_pxa.c6
-rw-r--r--drivers/tty/serial/8250/8250_tegra.c6
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c6
-rw-r--r--drivers/tty/serial/8250/serial_cs.c6
-rw-r--r--drivers/tty/serial/Kconfig3
-rw-r--r--drivers/tty/serial/altera_jtaguart.c6
-rw-r--r--drivers/tty/serial/altera_uart.c8
-rw-r--r--drivers/tty/serial/amba-pl011.c272
-rw-r--r--drivers/tty/serial/apbuart.c2
-rw-r--r--drivers/tty/serial/ar933x_uart.c6
-rw-r--r--drivers/tty/serial/atmel_serial.c22
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c5
-rw-r--r--drivers/tty/serial/clps711x.c6
-rw-r--r--drivers/tty/serial/cpm_uart.c6
-rw-r--r--drivers/tty/serial/digicolor-usart.c6
-rw-r--r--drivers/tty/serial/esp32_acm.c7
-rw-r--r--drivers/tty/serial/esp32_uart.c16
-rw-r--r--drivers/tty/serial/fsl_linflexuart.c6
-rw-r--r--drivers/tty/serial/fsl_lpuart.c5
-rw-r--r--drivers/tty/serial/imx.c63
-rw-r--r--drivers/tty/serial/jsm/jsm.h5
-rw-r--r--drivers/tty/serial/jsm/jsm_cls.c36
-rw-r--r--drivers/tty/serial/jsm/jsm_neo.c40
-rw-r--r--drivers/tty/serial/lantiq.c6
-rw-r--r--drivers/tty/serial/liteuart.c6
-rw-r--r--drivers/tty/serial/lpc32xx_hs.c6
-rw-r--r--drivers/tty/serial/ma35d1_serial.c7
-rw-r--r--drivers/tty/serial/max310x.c2
-rw-r--r--drivers/tty/serial/mcf.c6
-rw-r--r--drivers/tty/serial/meson_uart.c8
-rw-r--r--drivers/tty/serial/milbeaut_usio.c6
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c7
-rw-r--r--drivers/tty/serial/msm_serial.c25
-rw-r--r--drivers/tty/serial/mxs-auart.c20
-rw-r--r--drivers/tty/serial/omap-serial.c33
-rw-r--r--drivers/tty/serial/owl-uart.c6
-rw-r--r--drivers/tty/serial/pic32_uart.c7
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c6
-rw-r--r--drivers/tty/serial/rda-uart.c6
-rw-r--r--drivers/tty/serial/rp2.c1
-rw-r--r--drivers/tty/serial/sa1100.c6
-rw-r--r--drivers/tty/serial/samsung_tty.c6
-rw-r--r--drivers/tty/serial/sc16is7xx.c573
-rw-r--r--drivers/tty/serial/sccnxp.c13
-rw-r--r--drivers/tty/serial/serial-tegra.c5
-rw-r--r--drivers/tty/serial/serial_core.c88
-rw-r--r--drivers/tty/serial/serial_txx9.c5
-rw-r--r--drivers/tty/serial/sh-sci.c13
-rw-r--r--drivers/tty/serial/sifive.c10
-rw-r--r--drivers/tty/serial/sprd_serial.c6
-rw-r--r--drivers/tty/serial/st-asc.c6
-rw-r--r--drivers/tty/serial/stm32-usart.c14
-rw-r--r--drivers/tty/serial/sunhv.c6
-rw-r--r--drivers/tty/serial/sunplus-uart.c6
-rw-r--r--drivers/tty/serial/sunsab.c22
-rw-r--r--drivers/tty/serial/sunsu.c6
-rw-r--r--drivers/tty/serial/sunzilog.c6
-rw-r--r--drivers/tty/serial/tegra-tcu.c6
-rw-r--r--drivers/tty/serial/timbuart.c6
-rw-r--r--drivers/tty/serial/uartlite.c20
-rw-r--r--drivers/tty/serial/ucc_uart.c34
-rw-r--r--drivers/tty/serial/xilinx_uartps.c7
-rw-r--r--drivers/tty/sysrq.c19
-rw-r--r--drivers/tty/tty_io.c49
-rw-r--r--drivers/tty/tty_ioctl.c4
-rw-r--r--drivers/tty/tty_port.c18
-rw-r--r--drivers/tty/vt/consolemap.c2
-rw-r--r--drivers/tty/vt/keyboard.c10
-rw-r--r--drivers/uio/uio.c7
-rw-r--r--drivers/usb/atm/ueagle-atm.c19
-rw-r--r--drivers/usb/cdns3/cdns3-gadget.c149
-rw-r--r--drivers/usb/cdns3/cdns3-gadget.h3
-rw-r--r--drivers/usb/cdns3/cdns3-plat.c16
-rw-r--r--drivers/usb/cdns3/cdns3-starfive.c2
-rw-r--r--drivers/usb/cdns3/cdnsp-debug.h354
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c17
-rw-r--r--drivers/usb/chipidea/core.c13
-rw-r--r--drivers/usb/chipidea/udc.c3
-rw-r--r--drivers/usb/class/cdc-acm.c3
-rw-r--r--drivers/usb/core/driver.c64
-rw-r--r--drivers/usb/core/generic.c16
-rw-r--r--drivers/usb/core/hub.c48
-rw-r--r--drivers/usb/core/quirks.c7
-rw-r--r--drivers/usb/core/usb.c2
-rw-r--r--drivers/usb/core/usb.h8
-rw-r--r--drivers/usb/dwc2/params.c1
-rw-r--r--drivers/usb/dwc3/core.c60
-rw-r--r--drivers/usb/dwc3/core.h6
-rw-r--r--drivers/usb/dwc3/dwc3-imx8mp.c4
-rw-r--r--drivers/usb/dwc3/dwc3-qcom.c22
-rw-r--r--drivers/usb/dwc3/dwc3-xilinx.c11
-rw-r--r--drivers/usb/dwc3/ep0.c5
-rw-r--r--drivers/usb/dwc3/gadget.c25
-rw-r--r--drivers/usb/dwc3/gadget.h2
-rw-r--r--drivers/usb/fotg210/fotg210-hcd.c12
-rw-r--r--drivers/usb/fotg210/fotg210-udc.c6
-rw-r--r--drivers/usb/gadget/configfs.c13
-rw-r--r--drivers/usb/gadget/function/f_fs.c5
-rw-r--r--drivers/usb/gadget/function/f_midi.c4
-rw-r--r--drivers/usb/gadget/function/f_ncm.c69
-rw-r--r--drivers/usb/gadget/function/f_tcm.c4
-rw-r--r--drivers/usb/gadget/function/f_uac1.c83
-rw-r--r--drivers/usb/gadget/function/f_uac2.c6
-rw-r--r--drivers/usb/gadget/function/f_uvc.c74
-rw-r--r--drivers/usb/gadget/function/f_uvc.h2
-rw-r--r--drivers/usb/gadget/function/u_ether.c2
-rw-r--r--drivers/usb/gadget/function/u_ncm.h2
-rw-r--r--drivers/usb/gadget/function/u_uvc.h6
-rw-r--r--drivers/usb/gadget/function/uvc.h14
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.c2
-rw-r--r--drivers/usb/gadget/function/uvc_v4l2.c16
-rw-r--r--drivers/usb/gadget/function/uvc_video.c445
-rw-r--r--drivers/usb/gadget/function/uvc_video.h3
-rw-r--r--drivers/usb/gadget/legacy/webcam.c333
-rw-r--r--drivers/usb/gadget/udc/at91_udc.c13
-rw-r--r--drivers/usb/gadget/udc/atmel_usba_udc.c3
-rw-r--r--drivers/usb/gadget/udc/cdns2/cdns2-debug.h138
-rw-r--r--drivers/usb/gadget/udc/fsl_udc_core.c15
-rw-r--r--drivers/usb/gadget/udc/gr_udc.c13
-rw-r--r--drivers/usb/gadget/udc/lpc32xx_udc.c13
-rw-r--r--drivers/usb/gadget/udc/mv_udc_core.c2
-rw-r--r--drivers/usb/gadget/udc/pxa25x_udc.c12
-rw-r--r--drivers/usb/host/max3421-hcd.c18
-rw-r--r--drivers/usb/host/xhci-dbgcap.c132
-rw-r--r--drivers/usb/host/xhci-dbgcap.h1
-rw-r--r--drivers/usb/host/xhci-debugfs.c2
-rw-r--r--drivers/usb/host/xhci-mem.c110
-rw-r--r--drivers/usb/host/xhci-mtk.c40
-rw-r--r--drivers/usb/host/xhci-mtk.h2
-rw-r--r--drivers/usb/host/xhci-pci.c140
-rw-r--r--drivers/usb/host/xhci-plat.c26
-rw-r--r--drivers/usb/host/xhci-ring.c13
-rw-r--r--drivers/usb/host/xhci.c213
-rw-r--r--drivers/usb/host/xhci.h19
-rw-r--r--drivers/usb/misc/iowarrior.c1
-rw-r--r--drivers/usb/misc/onboard_usb_hub.c26
-rw-r--r--drivers/usb/misc/onboard_usb_hub.h6
-rw-r--r--drivers/usb/misc/qcom_eud.c3
-rw-r--r--drivers/usb/misc/yurex.c14
-rw-r--r--drivers/usb/mon/mon_bin.c7
-rw-r--r--drivers/usb/mon/mon_stat.c6
-rw-r--r--drivers/usb/mon/mon_text.c28
-rw-r--r--drivers/usb/phy/phy-generic.c14
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c3
-rw-r--r--drivers/usb/phy/phy-twl6030-usb.c8
-rw-r--r--drivers/usb/serial/bus.c2
-rw-r--r--drivers/usb/serial/usb-serial.c2
-rw-r--r--drivers/usb/storage/sierra_ms.c16
-rw-r--r--drivers/usb/storage/uas.c2
-rw-r--r--drivers/usb/typec/class.c17
-rw-r--r--drivers/usb/typec/mux/Kconfig10
-rw-r--r--drivers/usb/typec/mux/Makefile1
-rw-r--r--drivers/usb/typec/mux/wcd939x-usbss.c779
-rw-r--r--drivers/usb/typec/pd.c6
-rw-r--r--drivers/usb/typec/tcpm/tcpci_maxim_core.c20
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c419
-rw-r--r--drivers/usb/typec/tipd/core.c177
-rw-r--r--drivers/usb/typec/tipd/tps6598x.h18
-rw-r--r--drivers/usb/usbip/stub_main.c8
-rw-r--r--drivers/usb/usbip/vudc.h2
-rw-r--r--drivers/usb/usbip/vudc_dev.c3
-rw-r--r--drivers/usb/usbip/vudc_main.c2
-rw-r--r--drivers/vdpa/alibaba/eni_vdpa.c6
-rw-r--r--drivers/vdpa/mlx5/core/mlx5_vdpa.h10
-rw-r--r--drivers/vdpa/mlx5/core/mr.c69
-rw-r--r--drivers/vdpa/mlx5/net/mlx5_vnet.c209
-rw-r--r--drivers/vdpa/vdpa.c4
-rw-r--r--drivers/vfio/Kconfig10
-rw-r--r--drivers/vfio/Makefile1
-rw-r--r--drivers/vfio/debugfs.c92
-rw-r--r--drivers/vfio/pci/Kconfig2
-rw-r--r--drivers/vfio/pci/Makefile2
-rw-r--r--drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c7
-rw-r--r--drivers/vfio/pci/pds/dirty.c309
-rw-r--r--drivers/vfio/pci/pds/dirty.h18
-rw-r--r--drivers/vfio/pci/vfio_pci_rdwr.c57
-rw-r--r--drivers/vfio/pci/virtio/Kconfig15
-rw-r--r--drivers/vfio/pci/virtio/Makefile3
-rw-r--r--drivers/vfio/pci/virtio/main.c576
-rw-r--r--drivers/vfio/vfio.h14
-rw-r--r--drivers/vfio/vfio_iommu_type1.c8
-rw-r--r--drivers/vfio/vfio_main.c4
-rw-r--r--drivers/vhost/vdpa.c26
-rw-r--r--drivers/video/backlight/Kconfig18
-rw-r--r--drivers/video/backlight/Makefile2
-rw-r--r--drivers/video/backlight/cr_bllcd.c264
-rw-r--r--drivers/video/backlight/hx8357.c74
-rw-r--r--drivers/video/backlight/ili922x.c8
-rw-r--r--drivers/video/backlight/lm3630a_bl.c2
-rw-r--r--drivers/video/backlight/lp855x_bl.c2
-rw-r--r--drivers/video/backlight/mp3309c.c444
-rw-r--r--drivers/video/backlight/pwm_bl.c46
-rw-r--r--drivers/video/console/Kconfig2
-rw-r--r--drivers/video/fbdev/Kconfig72
-rw-r--r--drivers/video/fbdev/Makefile2
-rw-r--r--drivers/video/fbdev/amba-clcd.c986
-rw-r--r--drivers/video/fbdev/core/fb_defio.c8
-rw-r--r--drivers/video/fbdev/fsl-diu-fb.c2
-rw-r--r--drivers/video/fbdev/hgafb.c13
-rw-r--r--drivers/video/fbdev/hyperv_fb.c20
-rw-r--r--drivers/video/fbdev/imxfb.c179
-rw-r--r--drivers/video/fbdev/intelfb/Makefile8
-rw-r--r--drivers/video/fbdev/intelfb/intelfb.h382
-rw-r--r--drivers/video/fbdev/intelfb/intelfb_i2c.c209
-rw-r--r--drivers/video/fbdev/intelfb/intelfbdrv.c1680
-rw-r--r--drivers/video/fbdev/intelfb/intelfbhw.c2115
-rw-r--r--drivers/video/fbdev/intelfb/intelfbhw.h609
-rw-r--r--drivers/video/fbdev/mmp/hw/mmp_spi.c2
-rw-r--r--drivers/video/fbdev/sis/sis_main.c37
-rw-r--r--drivers/video/fbdev/ssd1307fb.c2
-rw-r--r--drivers/video/fbdev/stifb.c109
-rw-r--r--drivers/video/fbdev/vermilion/Makefile6
-rw-r--r--drivers/video/fbdev/vermilion/cr_pll.c195
-rw-r--r--drivers/video/fbdev/vermilion/vermilion.c1175
-rw-r--r--drivers/video/fbdev/vermilion/vermilion.h245
-rw-r--r--drivers/video/logo/pnmtologo.c6
-rw-r--r--drivers/video/sticore.c5
-rw-r--r--drivers/virt/vboxguest/vboxguest_core.c154
-rw-r--r--drivers/virt/vboxguest/vboxguest_linux.c22
-rw-r--r--drivers/virt/vboxguest/vboxguest_utils.c33
-rw-r--r--drivers/virt/vmgenid.c2
-rw-r--r--drivers/virtio/Kconfig5
-rw-r--r--drivers/virtio/Makefile1
-rw-r--r--drivers/virtio/virtio.c37
-rw-r--r--drivers/virtio/virtio_balloon.c57
-rw-r--r--drivers/virtio/virtio_pci_admin_legacy_io.c244
-rw-r--r--drivers/virtio/virtio_pci_common.c48
-rw-r--r--drivers/virtio/virtio_pci_common.h42
-rw-r--r--drivers/virtio/virtio_pci_modern.c259
-rw-r--r--drivers/virtio/virtio_pci_modern_dev.c24
-rw-r--r--drivers/w1/masters/Kconfig11
-rw-r--r--drivers/w1/masters/Makefile1
-rw-r--r--drivers/w1/masters/amd_axi_w1.c396
-rw-r--r--drivers/w1/masters/ds2490.c25
-rw-r--r--drivers/w1/masters/w1-gpio.c118
-rw-r--r--drivers/w1/slaves/w1_ds2433.c162
-rw-r--r--drivers/xen/gntdev-dmabuf.c50
-rw-r--r--drivers/xen/xenbus/xenbus_client.c59
-rw-r--r--fs/anon_inodes.c51
-rw-r--r--fs/bcachefs/fs-ioctl.c31
-rw-r--r--fs/exfat/balloc.c87
-rw-r--r--fs/exfat/exfat_fs.h5
-rw-r--r--fs/exfat/file.c193
-rw-r--r--fs/exfat/inode.c136
-rw-r--r--fs/exfat/namei.c6
-rw-r--r--fs/f2fs/super.c1
-rw-r--r--fs/kernfs/dir.c62
-rw-r--r--fs/kernfs/file.c2
-rw-r--r--fs/kernfs/mount.c3
-rw-r--r--fs/namei.c16
-rw-r--r--fs/namespace.c50
-rw-r--r--fs/proc/task_mmu.c24
-rw-r--r--fs/sysfs/dir.c2
-rw-r--r--fs/tracefs/event_inode.c347
-rw-r--r--fs/tracefs/inode.c193
-rw-r--r--fs/tracefs/internal.h3
-rw-r--r--fs/ubifs/auth.c21
-rw-r--r--fs/ubifs/commit.c13
-rw-r--r--fs/ubifs/dir.c2
-rw-r--r--fs/ubifs/file.c30
-rw-r--r--fs/ubifs/replay.c2
-rw-r--r--fs/userfaultfd.c5
-rw-r--r--include/acpi/acpi_bus.h2
-rw-r--r--include/acpi/actbl2.h12
-rw-r--r--include/asm-generic/cacheflush.h6
-rw-r--r--include/dt-bindings/clock/g12a-clkc.h8
-rw-r--r--include/dt-bindings/clock/mediatek,mt7988-clk.h280
-rw-r--r--include/dt-bindings/clock/qcom,gcc-msm8939.h6
-rw-r--r--include/dt-bindings/clock/qcom,qdu1000-ecpricc.h147
-rw-r--r--include/dt-bindings/clock/qcom,videocc-sm8150.h4
-rw-r--r--include/dt-bindings/clock/sophgo,cv1800.h176
-rw-r--r--include/dt-bindings/clock/st,stm32mp25-rcc.h492
-rw-r--r--include/dt-bindings/power/meson-g12a-power.h1
-rw-r--r--include/dt-bindings/reset/mediatek,mt7988-resets.h13
-rw-r--r--include/dt-bindings/reset/st,stm32mp25-rcc.h167
-rw-r--r--include/linux/acpi.h11
-rw-r--r--include/linux/aer.h8
-rw-r--r--include/linux/amba/clcd-regs.h87
-rw-r--r--include/linux/amba/clcd.h290
-rw-r--r--include/linux/amba/serial.h261
-rw-r--r--include/linux/amd-pmf-io.h50
-rw-r--r--include/linux/anon_inodes.h4
-rw-r--r--include/linux/cdx/cdx_bus.h12
-rw-r--r--include/linux/clk-provider.h4
-rw-r--r--include/linux/container.h2
-rw-r--r--include/linux/coresight.h1
-rw-r--r--include/linux/cpu.h5
-rw-r--r--include/linux/cxl-event.h161
-rw-r--r--include/linux/device.h9
-rw-r--r--include/linux/device/bus.h7
-rw-r--r--include/linux/device/class.h2
-rw-r--r--include/linux/dma-map-ops.h9
-rw-r--r--include/linux/edac.h4
-rw-r--r--include/linux/firewire.h2
-rw-r--r--include/linux/firmware/xlnx-zynqmp.h59
-rw-r--r--include/linux/fsnotify.h19
-rw-r--r--include/linux/fw_table.h21
-rw-r--r--include/linux/hid.h2
-rw-r--r--include/linux/hid_bpf.h2
-rw-r--r--include/linux/i3c/device.h2
-rw-r--r--include/linux/i3c/master.h9
-rw-r--r--include/linux/iio/adc/adi-axi-adc.h4
-rw-r--r--include/linux/iio/buffer-dma.h7
-rw-r--r--include/linux/iio/iio.h6
-rw-r--r--include/linux/iio/types.h1
-rw-r--r--include/linux/intel-ish-client-if.h3
-rw-r--r--include/linux/io-pgtable.h34
-rw-r--r--include/linux/iommu.h124
-rw-r--r--include/linux/kvm_host.h181
-rw-r--r--include/linux/kvm_types.h1
-rw-r--r--include/linux/leds.h20
-rw-r--r--include/linux/maple.h1
-rw-r--r--include/linux/memory-tiers.h10
-rw-r--r--include/linux/mfd/max77693-private.h2
-rw-r--r--include/linux/mfd/max77843-private.h2
-rw-r--r--include/linux/mfd/si476x-platform.h2
-rw-r--r--include/linux/mfd/tps65910.h2
-rw-r--r--include/linux/mhi.h4
-rw-r--r--include/linux/mhi_ep.h36
-rw-r--r--include/linux/mlx5/driver.h1
-rw-r--r--include/linux/mlx5/eswitch.h8
-rw-r--r--include/linux/mlx5/mlx5_ifc.h12
-rw-r--r--include/linux/mlx5/mlx5_ifc_vdpa.h4
-rw-r--r--include/linux/mm_types.h5
-rw-r--r--include/linux/mmc/card.h5
-rw-r--r--include/linux/mmc/core.h1
-rw-r--r--include/linux/mmc/mmc.h10
-rw-r--r--include/linux/moxtet.h2
-rw-r--r--include/linux/namei.h1
-rw-r--r--include/linux/node.h8
-rw-r--r--include/linux/nvmem-consumer.h8
-rw-r--r--include/linux/nvmem-provider.h70
-rw-r--r--include/linux/of_device.h6
-rw-r--r--include/linux/of_iommu.h13
-rw-r--r--include/linux/pagemap.h17
-rw-r--r--include/linux/pci-ecam.h2
-rw-r--r--include/linux/pci-epc.h13
-rw-r--r--include/linux/pci-epf.h4
-rw-r--r--include/linux/pci.h22
-rw-r--r--include/linux/pgtable.h21
-rw-r--r--include/linux/pinctrl/machine.h6
-rw-r--r--include/linux/pinctrl/pinconf-generic.h10
-rw-r--r--include/linux/pinctrl/pinconf.h16
-rw-r--r--include/linux/pinctrl/pinctrl.h24
-rw-r--r--include/linux/pinctrl/pinmux.h22
-rw-r--r--include/linux/platform_data/si5351.h2
-rw-r--r--include/linux/pm.h1
-rw-r--r--include/linux/pm_clock.h4
-rw-r--r--include/linux/pm_domain.h12
-rw-r--r--include/linux/pnp.h2
-rw-r--r--include/linux/property.h13
-rw-r--r--include/linux/pwm.h84
-rw-r--r--include/linux/rcu_notifier.h6
-rw-r--r--include/linux/rculist.h2
-rw-r--r--include/linux/rcupdate.h9
-rw-r--r--include/linux/ring_buffer.h18
-rw-r--r--include/linux/rtsx_pci.h8
-rw-r--r--include/linux/sched.h2
-rw-r--r--include/linux/seq_buf.h3
-rw-r--r--include/linux/serdev.h29
-rw-r--r--include/linux/serial_core.h4
-rw-r--r--include/linux/spmi.h3
-rw-r--r--include/linux/srcu.h2
-rw-r--r--include/linux/surface_aggregator/device.h1
-rw-r--r--include/linux/syscalls.h2
-rw-r--r--include/linux/thermal.h9
-rw-r--r--include/linux/thunderbolt.h2
-rw-r--r--include/linux/trace.h4
-rw-r--r--include/linux/trace_seq.h9
-rw-r--r--include/linux/tty.h20
-rw-r--r--include/linux/tty_driver.h9
-rw-r--r--include/linux/tty_port.h8
-rw-r--r--include/linux/usb.h31
-rw-r--r--include/linux/usb/gadget.h1
-rw-r--r--include/linux/usb/hcd.h5
-rw-r--r--include/linux/usb/quirks.h3
-rw-r--r--include/linux/usb/tcpci.h5
-rw-r--r--include/linux/usb/tcpm.h1
-rw-r--r--include/linux/vfio.h7
-rw-r--r--include/linux/vfio_pci_core.h20
-rw-r--r--include/linux/virtio.h8
-rw-r--r--include/linux/virtio_config.h4
-rw-r--r--include/linux/virtio_console.h38
-rw-r--r--include/linux/virtio_pci_admin.h23
-rw-r--r--include/linux/virtio_pci_modern.h2
-rw-r--r--include/linux/w1-gpio.h22
-rw-r--r--include/media/cec.h22
-rw-r--r--include/media/v4l2-cci.h16
-rw-r--r--include/media/v4l2-common.h4
-rw-r--r--include/media/v4l2-mem2mem.h9
-rw-r--r--include/media/v4l2-subdev.h419
-rw-r--r--include/media/videobuf2-core.h48
-rw-r--r--include/net/mana/gdma.h5
-rw-r--r--include/soc/qcom/qcom-spmi-pmic.h1
-rw-r--r--include/trace/events/kvm.h8
-rw-r--r--include/uapi/linux/android/binder.h30
-rw-r--r--include/uapi/linux/cxl_mem.h1
-rw-r--r--include/uapi/linux/iio/types.h2
-rw-r--r--include/uapi/linux/iommufd.h79
-rw-r--r--include/uapi/linux/kvm.h140
-rw-r--r--include/uapi/linux/mei.h4
-rw-r--r--include/uapi/linux/nsm.h31
-rw-r--r--include/uapi/linux/pcitest.h3
-rw-r--r--include/uapi/linux/serial.h19
-rw-r--r--include/uapi/linux/thp7312.h19
-rw-r--r--include/uapi/linux/usb/functionfs.h6
-rw-r--r--include/uapi/linux/v4l2-controls.h6
-rw-r--r--include/uapi/linux/v4l2-subdev.h15
-rw-r--r--include/uapi/linux/vfio.h1
-rw-r--r--include/uapi/linux/videodev2.h11
-rw-r--r--include/uapi/linux/virtio_config.h8
-rw-r--r--include/uapi/linux/virtio_pci.h68
-rw-r--r--include/uapi/linux/virtio_pmem.h7
-rw-r--r--include/uapi/rdma/bnxt_re-abi.h41
-rw-r--r--include/uapi/rdma/efa-abi.h21
-rw-r--r--include/uapi/rdma/hns-abi.h5
-rw-r--r--include/uapi/rdma/mlx5-abi.h2
-rw-r--r--include/uapi/rdma/mlx5_user_ioctl_verbs.h1
-rw-r--r--include/video/sticore.h6
-rw-r--r--include/xen/interface/io/displif.h2
-rw-r--r--include/xen/interface/io/ring.h2
-rw-r--r--include/xen/interface/io/sndif.h2
-rw-r--r--init/do_mounts.c9
-rw-r--r--init/initramfs.c18
-rw-r--r--io_uring/io_uring.c3
-rw-r--r--kernel/cgroup/cgroup-v1.c2
-rw-r--r--kernel/cgroup/cgroup.c35
-rw-r--r--kernel/cgroup/cpuset.c2
-rw-r--r--kernel/crash_core.c16
-rw-r--r--kernel/dma/debug.c5
-rw-r--r--kernel/dma/swiotlb.c3
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/kexec_core.c1
-rw-r--r--kernel/locking/locktorture.c18
-rw-r--r--kernel/rcu/Kconfig.debug25
-rw-r--r--kernel/rcu/rcu.h8
-rw-r--r--kernel/rcu/rcutorture.c16
-rw-r--r--kernel/rcu/srcutree.c24
-rw-r--r--kernel/rcu/tasks.h4
-rw-r--r--kernel/rcu/tree.c2
-rw-r--r--kernel/rcu/tree_stall.h11
-rw-r--r--kernel/rcu/update.c6
-rw-r--r--kernel/sched/cpufreq_schedutil.c6
-rw-r--r--kernel/trace/ring_buffer.c733
-rw-r--r--kernel/trace/ring_buffer_benchmark.c10
-rw-r--r--kernel/trace/trace.c234
-rw-r--r--kernel/trace/trace.h2
-rw-r--r--kernel/trace/trace_boot.c2
-rw-r--r--kernel/trace/trace_events.c107
-rw-r--r--kernel/trace/trace_events_hist.c49
-rw-r--r--kernel/trace/trace_kprobe.c4
-rw-r--r--kernel/trace/trace_seq.c3
-rw-r--r--lib/Kconfig.debug2
-rw-r--r--lib/fw_table.c73
-rw-r--r--mm/Kconfig3
-rw-r--r--mm/compaction.c43
-rw-r--r--mm/init-mm.c3
-rw-r--r--mm/kasan/generic.c10
-rw-r--r--mm/memblock.c2
-rw-r--r--mm/memory-tiers.c12
-rw-r--r--mm/memory_hotplug.c8
-rw-r--r--mm/migrate.c2
-rw-r--r--mm/mm_init.c6
-rw-r--r--mm/percpu.c8
-rw-r--r--mm/userfaultfd.c6
-rw-r--r--net/bluetooth/rfcomm/tty.c2
-rw-r--r--samples/ftrace/sample-trace-array.c2
-rw-r--r--samples/v4l/v4l2-pci-skeleton.c7
-rwxr-xr-xscripts/checkpatch.pl1
-rwxr-xr-xscripts/decode_stacktrace.sh19
-rwxr-xr-xscripts/tags.sh17
-rw-r--r--sound/drivers/serial-generic.c4
-rw-r--r--tools/counter/Build1
-rw-r--r--tools/counter/Makefile12
-rw-r--r--tools/counter/counter_watch_events.c406
-rw-r--r--tools/iio/iio_event_monitor.c2
-rw-r--r--tools/testing/cxl/Kbuild1
-rw-r--r--tools/testing/cxl/test/cxl.c4
-rw-r--r--tools/testing/cxl/test/mem.c163
-rw-r--r--tools/testing/nvdimm/test/Kbuild1
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/ringbuffer_subbuf_size.tc95
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/trace_marker.tc82
-rw-r--r--tools/testing/selftests/hid/tests/base.py7
-rw-r--r--tools/testing/selftests/hid/tests/test_mouse.py14
-rw-r--r--tools/testing/selftests/hid/tests/test_tablet.py764
-rw-r--r--tools/testing/selftests/hid/tests/test_wacom_generic.py282
-rwxr-xr-xtools/testing/selftests/hid/vmtest.sh46
-rw-r--r--tools/testing/selftests/iommu/iommufd.c152
-rw-r--r--tools/testing/selftests/iommu/iommufd_utils.h55
-rw-r--r--tools/testing/selftests/kvm/Makefile9
-rw-r--r--tools/testing/selftests/kvm/aarch64/page_fault_test.c2
-rw-r--r--tools/testing/selftests/kvm/dirty_log_test.c2
-rw-r--r--tools/testing/selftests/kvm/guest_memfd_test.c198
-rw-r--r--tools/testing/selftests/kvm/include/aarch64/processor.h4
-rw-r--r--tools/testing/selftests/kvm/include/guest_modes.h4
-rw-r--r--tools/testing/selftests/kvm/include/kvm_util_base.h217
-rw-r--r--tools/testing/selftests/kvm/include/riscv/processor.h62
-rw-r--r--tools/testing/selftests/kvm/include/test_util.h7
-rw-r--r--tools/testing/selftests/kvm/include/ucall_common.h18
-rw-r--r--tools/testing/selftests/kvm/include/x86_64/processor.h15
-rw-r--r--tools/testing/selftests/kvm/kvm_page_table_test.c2
-rw-r--r--tools/testing/selftests/kvm/lib/aarch64/processor.c69
-rw-r--r--tools/testing/selftests/kvm/lib/guest_modes.c50
-rw-r--r--tools/testing/selftests/kvm/lib/kvm_util.c229
-rw-r--r--tools/testing/selftests/kvm/lib/memstress.c3
-rw-r--r--tools/testing/selftests/kvm/lib/riscv/processor.c49
-rw-r--r--tools/testing/selftests/kvm/lib/riscv/ucall.c26
-rw-r--r--tools/testing/selftests/kvm/riscv/get-reg-list.c588
-rw-r--r--tools/testing/selftests/kvm/s390x/cmma_test.c11
-rw-r--r--tools/testing/selftests/kvm/set_memory_region_test.c161
-rw-r--r--tools/testing/selftests/kvm/steal_time.c99
-rw-r--r--tools/testing/selftests/kvm/x86_64/hyperv_clock.c2
-rw-r--r--tools/testing/selftests/kvm/x86_64/hyperv_evmcs.c5
-rw-r--r--tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c2
-rw-r--r--tools/testing/selftests/kvm/x86_64/hyperv_features.c12
-rw-r--r--tools/testing/selftests/kvm/x86_64/hyperv_ipi.c2
-rw-r--r--tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c1
-rw-r--r--tools/testing/selftests/kvm/x86_64/hyperv_tlb_flush.c2
-rw-r--r--tools/testing/selftests/kvm/x86_64/mmio_warning_test.c121
-rw-r--r--tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c6
-rw-r--r--tools/testing/selftests/kvm/x86_64/private_mem_conversions_test.c482
-rw-r--r--tools/testing/selftests/kvm/x86_64/private_mem_kvm_exits_test.c120
-rw-r--r--tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c4
-rw-r--r--tools/testing/selftests/kvm/x86_64/ucna_injection_test.c2
-rw-r--r--tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c2
-rw-r--r--tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c16
-rw-r--r--tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c8
-rw-r--r--tools/testing/selftests/mm/hugepage-vmemmap.c29
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/mkinitrd.sh5
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot3
-rw-r--r--tools/testing/selftests/riscv/hwprobe/Makefile5
-rw-r--r--tools/testing/selftests/riscv/hwprobe/hwprobe.c2
-rw-r--r--tools/testing/selftests/riscv/hwprobe/hwprobe.h2
-rw-r--r--tools/testing/selftests/riscv/hwprobe/which-cpus.c154
-rw-r--r--tools/testing/selftests/riscv/vector/vstate_prctl.c10
-rw-r--r--tools/testing/selftests/sgx/Makefile14
-rw-r--r--tools/testing/selftests/sgx/defines.h2
-rw-r--r--tools/testing/selftests/sgx/load.c9
-rw-r--r--tools/testing/selftests/sgx/sigstruct.c5
-rw-r--r--tools/testing/selftests/sgx/test_encl.c67
-rw-r--r--tools/testing/selftests/sgx/test_encl.lds10
-rw-r--r--tools/testing/selftests/sgx/test_encl_bootstrap.S28
-rw-r--r--virt/kvm/Kconfig30
-rw-r--r--virt/kvm/Makefile.kvm1
-rw-r--r--virt/kvm/dirty_ring.c2
-rw-r--r--virt/kvm/eventfd.c28
-rw-r--r--virt/kvm/guest_memfd.c532
-rw-r--r--virt/kvm/kvm_main.c522
-rw-r--r--virt/kvm/kvm_mm.h26
2669 files changed, 135712 insertions, 37286 deletions
diff --git a/.mailmap b/.mailmap
index 1f6ad79b45e4..04998f7bda81 100644
--- a/.mailmap
+++ b/.mailmap
@@ -363,7 +363,6 @@ Maheshwar Ajja <[email protected]> <[email protected]>
Manikanta Pubbisetty <[email protected]> <[email protected]>
Manivannan Sadhasivam <[email protected]> <[email protected]>
-Manivannan Sadhasivam <[email protected]> <[email protected]>
Marcin Nowakowski <[email protected]> <[email protected]>
@@ -391,9 +390,10 @@ Matthias Fuchs <[email protected]> <[email protected]>
Matthieu CASTET <[email protected]>
-Matt Ranostay <[email protected]> Matthew Ranostay <[email protected]>
+Matt Ranostay <[email protected]> Matthew Ranostay <[email protected]>
Mauro Carvalho Chehab <[email protected]> <[email protected]>
@@ -504,6 +504,9 @@ Ralf Baechle <[email protected]>
Ralf Wildenhues <[email protected]>
Ram Chandra Jangir <[email protected]> <[email protected]>
Ravi Kumar Siddojigari <[email protected]> <[email protected]>
Rémi Denis-Courmont <[email protected]>
@@ -582,6 +585,7 @@ Surabhi Vishnoi <[email protected]> <[email protected]>
Takashi YOSHII <[email protected]>
Tamizh Chelvam Raja <[email protected]> <[email protected]>
Tejun Heo <[email protected]>
Thomas Graf <[email protected]>
diff --git a/CREDITS b/CREDITS
index 06b177c6af6a..d36c1949fa2c 100644
--- a/CREDITS
+++ b/CREDITS
@@ -3950,6 +3950,10 @@ S: 21513 Conradia Ct
S: Cupertino, CA 95014
S: USA
+N: Manohar Vanga
+D: VME subsystem maintainer
+
N: Thibaut Varène
W: http://hacks.slashdirt.org/
@@ -4050,6 +4054,10 @@ D: Fixes for the NE/2-driver
D: Miscellaneous MCA-support
D: Cleanup of the Config-files
+N: Martyn Welch
+D: VME subsystem maintainer
+
N: Matt Welsh
W: http://www.cs.berkeley.edu/~mdw
diff --git a/Documentation/ABI/testing/debugfs-vfio b/Documentation/ABI/testing/debugfs-vfio
new file mode 100644
index 000000000000..90f7c262f591
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-vfio
@@ -0,0 +1,25 @@
+What: /sys/kernel/debug/vfio
+Date: December 2023
+KernelVersion: 6.8
+Contact: Longfang Liu <[email protected]>
+Description: This debugfs file directory is used for debugging
+ of vfio devices, it's a common directory for all vfio devices.
+ Vfio core will create a device subdirectory under this
+ directory.
+
+What: /sys/kernel/debug/vfio/<device>/migration
+Date: December 2023
+KernelVersion: 6.8
+Contact: Longfang Liu <[email protected]>
+Description: This debugfs file directory is used for debugging
+ of vfio devices that support live migration.
+ The debugfs of each vfio device that supports live migration
+ could be created under this directory.
+
+What: /sys/kernel/debug/vfio/<device>/migration/state
+Date: December 2023
+KernelVersion: 6.8
+Contact: Longfang Liu <[email protected]>
+Description: Read the live migration status of the vfio device.
+ The contents of the state file reflects the migration state
+ relative to those defined in the vfio_device_mig_state enum
diff --git a/Documentation/ABI/testing/sysfs-bus-cdx b/Documentation/ABI/testing/sysfs-bus-cdx
index 8c067ff99e54..e84277531414 100644
--- a/Documentation/ABI/testing/sysfs-bus-cdx
+++ b/Documentation/ABI/testing/sysfs-bus-cdx
@@ -98,6 +98,13 @@ Description:
# echo 1 > /sys/bus/cdx/devices/.../remove
+What: /sys/bus/cdx/devices/.../resource<N>
+Date: July 2023
+Description:
+ The resource binary file contains the content of the memory
+ regions. These files can be m'maped from userspace.
+
What: /sys/bus/cdx/devices/.../modalias
Date: July 2023
diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc
index 6aa527296c71..96aafa66b4a5 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc
@@ -91,3 +91,19 @@ Contact: Mathieu Poirier <[email protected]>
Description: (RW) Size of the trace buffer for TMC-ETR when used in SYSFS
mode. Writable only for TMC-ETR configurations. The value
should be aligned to the kernel pagesize.
+
+What: /sys/bus/coresight/devices/<memory_map>.tmc/buf_modes_available
+Date: August 2023
+KernelVersion: 6.7
+Contact: Anshuman Khandual <[email protected]>
+Description: (Read) Shows all supported Coresight TMC-ETR buffer modes available
+ for the users to configure explicitly. This file is avaialble only
+ for TMC ETR devices.
+
+What: /sys/bus/coresight/devices/<memory_map>.tmc/buf_mode_preferred
+Date: August 2023
+KernelVersion: 6.7
+Contact: Anshuman Khandual <[email protected]>
+Description: (RW) Current Coresight TMC-ETR buffer mode selected. But user could
+ only provide a mode which is supported for a given ETR device. This
+ file is available only for TMC ETR devices.
diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm
index 4a58e649550d..4dd49b159543 100644
--- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm
+++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm
@@ -11,3 +11,162 @@ Description:
Accepts only one of the 2 values - 1 or 2.
1 : Generate 64 bits data
2 : Generate 32 bits data
+
+What: /sys/bus/coresight/devices/<tpdm-name>/reset_dataset
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ (Write) Reset the dataset of the tpdm.
+
+ Accepts only one value - 1.
+ 1 : Reset the dataset of the tpdm
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_trig_type
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ (RW) Set/Get the trigger type of the DSB for tpdm.
+
+ Accepts only one of the 2 values - 0 or 1.
+ 0 : Set the DSB trigger type to false
+ 1 : Set the DSB trigger type to true
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_trig_ts
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ (RW) Set/Get the trigger timestamp of the DSB for tpdm.
+
+ Accepts only one of the 2 values - 0 or 1.
+ 0 : Set the DSB trigger type to false
+ 1 : Set the DSB trigger type to true
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_mode
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ (RW) Set/Get the programming mode of the DSB for tpdm.
+
+ Accepts the value needs to be greater than 0. What data
+ bits do is listed below.
+ Bit[0:1] : Test mode control bit for choosing the inputs.
+ Bit[3] : Set to 0 for low performance mode. Set to 1 for high
+ performance mode.
+ Bit[4:8] : Select byte lane for high performance mode.
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/ctrl_idx
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ (RW) Set/Get the index number of the edge detection for the DSB
+ subunit TPDM. Since there are at most 256 edge detections, this
+ value ranges from 0 to 255.
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/ctrl_val
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ Write a data to control the edge detection corresponding to
+ the index number. Before writing data to this sysfs file,
+ "ctrl_idx" should be written first to configure the index
+ number of the edge detection which needs to be controlled.
+
+ Accepts only one of the following values.
+ 0 - Rising edge detection
+ 1 - Falling edge detection
+ 2 - Rising and falling edge detection (toggle detection)
+
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/ctrl_mask
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ Write a data to mask the edge detection corresponding to the index
+ number. Before writing data to this sysfs file, "ctrl_idx" should
+ be written first to configure the index number of the edge detection
+ which needs to be masked.
+
+ Accepts only one of the 2 values - 0 or 1.
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/edcr[0:15]
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ Read a set of the edge control value of the DSB in TPDM.
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_edge/edcmr[0:7]
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ Read a set of the edge control mask of the DSB in TPDM.
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_trig_patt/xpr[0:7]
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ (RW) Set/Get the value of the trigger pattern for the DSB
+ subunit TPDM.
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_trig_patt/xpmr[0:7]
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ (RW) Set/Get the mask of the trigger pattern for the DSB
+ subunit TPDM.
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpr[0:7]
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ (RW) Set/Get the value of the pattern for the DSB subunit TPDM.
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/tpmr[0:7]
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ (RW) Set/Get the mask of the pattern for the DSB subunit TPDM.
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/enable_ts
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ (Write) Set the pattern timestamp of DSB tpdm. Read
+ the pattern timestamp of DSB tpdm.
+
+ Accepts only one of the 2 values - 0 or 1.
+ 0 : Disable DSB pattern timestamp.
+ 1 : Enable DSB pattern timestamp.
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_patt/set_type
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ (Write) Set the pattern type of DSB tpdm. Read
+ the pattern type of DSB tpdm.
+
+ Accepts only one of the 2 values - 0 or 1.
+ 0 : Set the DSB pattern type to value.
+ 1 : Set the DSB pattern type to toggle.
+
+What: /sys/bus/coresight/devices/<tpdm-name>/dsb_msr/msr[0:31]
+Date: March 2023
+KernelVersion 6.7
+Contact: Jinlong Mao (QUIC) <[email protected]>, Tao Zhang (QUIC) <[email protected]>
+Description:
+ (RW) Set/Get the MSR(mux select register) for the DSB subunit
+ TPDM.
diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
index e76c3600607f..fff2581b8033 100644
--- a/Documentation/ABI/testing/sysfs-bus-cxl
+++ b/Documentation/ABI/testing/sysfs-bus-cxl
@@ -28,6 +28,23 @@ Description:
Payload in the CXL-2.0 specification.
+What: /sys/bus/cxl/devices/memX/ram/qos_class
+Date: May, 2023
+KernelVersion: v6.8
+Description:
+ (RO) For CXL host platforms that support "QoS Telemmetry"
+ this attribute conveys a comma delimited list of platform
+ specific cookies that identifies a QoS performance class
+ for the volatile partition of the CXL mem device. These
+ class-ids can be compared against a similar "qos_class"
+ published for a root decoder. While it is not required
+ that the endpoints map their local memory-class to a
+ matching platform class, mismatches are not recommended
+ and there are platform specific performance related
+ side-effects that may result. First class-id is displayed.
+
+
What: /sys/bus/cxl/devices/memX/pmem/size
Date: December, 2020
KernelVersion: v5.12
@@ -38,6 +55,23 @@ Description:
Payload in the CXL-2.0 specification.
+What: /sys/bus/cxl/devices/memX/pmem/qos_class
+Date: May, 2023
+KernelVersion: v6.8
+Description:
+ (RO) For CXL host platforms that support "QoS Telemmetry"
+ this attribute conveys a comma delimited list of platform
+ specific cookies that identifies a QoS performance class
+ for the persistent partition of the CXL mem device. These
+ class-ids can be compared against a similar "qos_class"
+ published for a root decoder. While it is not required
+ that the endpoints map their local memory-class to a
+ matching platform class, mismatches are not recommended
+ and there are platform specific performance related
+ side-effects that may result. First class-id is displayed.
+
+
What: /sys/bus/cxl/devices/memX/serial
Date: January, 2022
KernelVersion: v5.18
diff --git a/Documentation/ABI/testing/sysfs-bus-i3c b/Documentation/ABI/testing/sysfs-bus-i3c
index e5248fd67a56..c812ab180ff4 100644
--- a/Documentation/ABI/testing/sysfs-bus-i3c
+++ b/Documentation/ABI/testing/sysfs-bus-i3c
@@ -88,6 +88,21 @@ Description:
This entry describes the HDRCAP of the master controller
driving the bus.
+What: /sys/bus/i3c/devices/i3c-<bus-id>/hotjoin
+KernelVersion: 6.8
+Description:
+ I3C’s Hot-Join mechanism allows an I3C Device to inform the
+ Active Controller that a newly-joined Target is present on the
+ I3C Bus and is ready to receive a Dynamic Address, in order to
+ become fully functional on the Bus. Hot-Join is used when the
+ Target is mounted on the same I3C bus and remains depowered
+ until needed or until the Target is physically inserted into the
+ I3C bus
+
+ This entry allows to enable or disable Hot-join of the Current
+ Controller driving the bus.
+
What: /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>
KernelVersion: 5.0
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 19cde14f3869..2e6d5ebfd3c7 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -362,10 +362,21 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_peak_raw
What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_peak_raw
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_peak_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_peak_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_temp_peak_raw
KernelVersion: 2.6.36
Description:
- Highest value since some reset condition. These
+ Highest value since some reset condition. These
+ attributes allow access to this and are otherwise
+ the direct equivalent of the <type>Y[_name]_raw attributes.
+
+What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_trough_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_temp_trough_raw
+KernelVersion: 6.7
+Description:
+ Lowest value since some reset condition. These
attributes allow access to this and are otherwise
the direct equivalent of the <type>Y[_name]_raw attributes.
@@ -618,7 +629,9 @@ KernelVersion: 2.6.35
Description:
If a discrete set of scale values is available, they
- are listed in this attribute.
+ are listed in this attribute. Unlike illumination,
+ multiplying intensity by intensity_scale does not
+ yield value with any standardized unit.
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain
What: /sys/bus/iio/devices/iio:deviceX/in_intensity_hardwaregain
@@ -1574,6 +1587,8 @@ What: /sys/.../iio:deviceX/in_intensityY_raw
What: /sys/.../iio:deviceX/in_intensityY_ir_raw
What: /sys/.../iio:deviceX/in_intensityY_both_raw
What: /sys/.../iio:deviceX/in_intensityY_uv_raw
+What: /sys/.../iio:deviceX/in_intensityY_uva_raw
+What: /sys/.../iio:deviceX/in_intensityY_uvb_raw
What: /sys/.../iio:deviceX/in_intensityY_duv_raw
KernelVersion: 3.4
@@ -1582,8 +1597,9 @@ Description:
that measurements contain visible and infrared light
components or just infrared light, respectively. Modifier
uv indicates that measurements contain ultraviolet light
- components. Modifier duv indicates that measurements
- contain deep ultraviolet light components.
+ components. Modifiers uva, uvb and duv indicate that
+ measurements contain A, B or deep (C) ultraviolet light
+ components respectively.
What: /sys/.../iio:deviceX/in_uvindex_input
KernelVersion: 4.6
@@ -2254,3 +2270,21 @@ Description:
If a label is defined for this event add that to the event
specific attributes. This is useful for userspace to be able to
better identify an individual event.
+
+What: /sys/.../events/in_accel_gesture_tap_wait_timeout
+KernelVersion: 6.7
+Description:
+ Enable tap gesture confirmation with timeout.
+
+What: /sys/.../events/in_accel_gesture_tap_wait_dur
+KernelVersion: 6.7
+Description:
+ Timeout value in seconds for tap gesture confirmation.
+
+What: /sys/.../events/in_accel_gesture_tap_wait_dur_available
+KernelVersion: 6.7
+Description:
+ List of available timeout value for tap gesture confirmation.
diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev
index f6d9d72ce77b..a6c307c4befa 100644
--- a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev
+++ b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev
@@ -114,6 +114,45 @@ Description:
speed of 1000Mbps of the named network device.
Setting this value also immediately changes the LED state.
+What: /sys/class/leds/<led>/link_2500
+Date: Nov 2023
+KernelVersion: 6.8
+Description:
+ Signal the link speed state of 2500Mbps of the named network device.
+
+ If set to 0 (default), the LED's normal state is off.
+
+ If set to 1, the LED's normal state reflects the link state
+ speed of 2500Mbps of the named network device.
+ Setting this value also immediately changes the LED state.
+
+What: /sys/class/leds/<led>/link_5000
+Date: Nov 2023
+KernelVersion: 6.8
+Description:
+ Signal the link speed state of 5000Mbps of the named network device.
+
+ If set to 0 (default), the LED's normal state is off.
+
+ If set to 1, the LED's normal state reflects the link state
+ speed of 5000Mbps of the named network device.
+ Setting this value also immediately changes the LED state.
+
+What: /sys/class/leds/<led>/link_10000
+Date: Nov 2023
+KernelVersion: 6.8
+Description:
+ Signal the link speed state of 10000Mbps of the named network device.
+
+ If set to 0 (default), the LED's normal state is off.
+
+ If set to 1, the LED's normal state reflects the link state
+ speed of 10000Mbps of the named network device.
+ Setting this value also immediately changes the LED state.
+
What: /sys/class/leds/<led>/half_duplex
Date: Jun 2023
KernelVersion: 6.5
diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-tty b/Documentation/ABI/testing/sysfs-class-led-trigger-tty
index 2bf6b24e781b..30cef9ac0f49 100644
--- a/Documentation/ABI/testing/sysfs-class-led-trigger-tty
+++ b/Documentation/ABI/testing/sysfs-class-led-trigger-tty
@@ -4,3 +4,59 @@ KernelVersion: 5.10
Description:
Specifies the tty device name of the triggering tty
+
+What: /sys/class/leds/<led>/rx
+Date: February 2024
+KernelVersion: 6.8
+Description:
+ Signal reception (rx) of data on the named tty device.
+ If set to 0, the LED will not blink on reception.
+ If set to 1 (default), the LED will blink on reception.
+
+What: /sys/class/leds/<led>/tx
+Date: February 2024
+KernelVersion: 6.8
+Description:
+ Signal transmission (tx) of data on the named tty device.
+ If set to 0, the LED will not blink on transmission.
+ If set to 1 (default), the LED will blink on transmission.
+
+What: /sys/class/leds/<led>/cts
+Date: February 2024
+KernelVersion: 6.8
+Description:
+ CTS = Clear To Send
+ DCE is ready to accept data from the DTE.
+ If the line state is detected, the LED is switched on.
+ If set to 0 (default), the LED will not evaluate CTS.
+ If set to 1, the LED will evaluate CTS.
+
+What: /sys/class/leds/<led>/dsr
+Date: February 2024
+KernelVersion: 6.8
+Description:
+ DSR = Data Set Ready
+ DCE is ready to receive and send data.
+ If the line state is detected, the LED is switched on.
+ If set to 0 (default), the LED will not evaluate DSR.
+ If set to 1, the LED will evaluate DSR.
+
+What: /sys/class/leds/<led>/dcd
+Date: February 2024
+KernelVersion: 6.8
+Description:
+ DCD = Data Carrier Detect
+ DTE is receiving a carrier from the DCE.
+ If the line state is detected, the LED is switched on.
+ If set to 0 (default), the LED will not evaluate CAR (DCD).
+ If set to 1, the LED will evaluate CAR (DCD).
+
+What: /sys/class/leds/<led>/rng
+Date: February 2024
+KernelVersion: 6.8
+Description:
+ RNG = Ring Indicator
+ DCE has detected an incoming ring signal on the telephone
+ line. If the line state is detected, the LED is switched on.
+ If set to 0 (default), the LED will not evaluate RNG.
+ If set to 1, the LED will evaluate RNG.
diff --git a/Documentation/ABI/testing/sysfs-firmware-initrd b/Documentation/ABI/testing/sysfs-firmware-initrd
new file mode 100644
index 000000000000..20bf7cf77a19
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-initrd
@@ -0,0 +1,8 @@
+What: /sys/firmware/initrd
+Date: December 2023
+Contact: Alexander Graf <[email protected]>
+Description:
+ When the kernel was booted with an initrd and the
+ "retain_initrd" option is set on the kernel command
+ line, /sys/firmware/initrd contains the contents of the
+ initrd that the kernel was booted with.
diff --git a/Documentation/ABI/testing/sysfs-nvmem-cells b/Documentation/ABI/testing/sysfs-nvmem-cells
new file mode 100644
index 000000000000..7af70adf3690
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-nvmem-cells
@@ -0,0 +1,21 @@
+What: /sys/bus/nvmem/devices/.../cells/<cell-name>
+Date: May 2023
+KernelVersion: 6.5
+Contact: Miquel Raynal <[email protected]>
+Description:
+ The "cells" folder contains one file per cell exposed by the
+ NVMEM device. The name of the file is: <name>@<where>, with
+ <name> being the cell name and <where> its location in the NVMEM
+ device, in hexadecimal (without the '0x' prefix, to mimic device
+ tree node names). The length of the file is the size of the cell
+ (when known). The content of the file is the binary content of
+ the cell (may sometimes be ASCII, likely without trailing
+ character).
+ Note: This file is only present if CONFIG_NVMEM_SYSFS
+ is enabled.
+
+ Example::
+
+ hexdump -C /sys/bus/nvmem/devices/1-00563/cells/product-name@d
+ 00000000 54 4e 34 38 4d 2d 50 2d 44 4e |TN48M-P-DN|
+ 0000000a
diff --git a/Documentation/PCI/boot-interrupts.rst b/Documentation/PCI/boot-interrupts.rst
index 2ec70121bfca..931077bb0953 100644
--- a/Documentation/PCI/boot-interrupts.rst
+++ b/Documentation/PCI/boot-interrupts.rst
@@ -61,7 +61,7 @@ Conditions
==========
The use of threaded interrupts is the most likely condition to trigger
-this problem today. Threaded interrupts may not be reenabled after the IRQ
+this problem today. Threaded interrupts may not be re-enabled after the IRQ
handler wakes. These "one shot" conditions mean that the threaded interrupt
needs to keep the interrupt line masked until the threaded handler has run.
Especially when dealing with high data rate interrupts, the thread needs to
diff --git a/Documentation/PCI/msi-howto.rst b/Documentation/PCI/msi-howto.rst
index c9400f02333b..783d30b7bb42 100644
--- a/Documentation/PCI/msi-howto.rst
+++ b/Documentation/PCI/msi-howto.rst
@@ -236,7 +236,7 @@ including a full 'lspci -v' so we can add the quirks to the kernel.
Disabling MSIs below a bridge
-----------------------------
-Some PCI bridges are not able to route MSIs between busses properly.
+Some PCI bridges are not able to route MSIs between buses properly.
In this case, MSIs must be disabled on all devices behind the bridge.
Some bridges allow you to enable MSIs by changing some bits in their
diff --git a/Documentation/RCU/checklist.rst b/Documentation/RCU/checklist.rst
index bd3c58c44bef..2d42998a89a6 100644
--- a/Documentation/RCU/checklist.rst
+++ b/Documentation/RCU/checklist.rst
@@ -241,15 +241,22 @@ over a rather long period of time, but improvements are always welcome!
srcu_struct. The rules for the expedited RCU grace-period-wait
primitives are the same as for their non-expedited counterparts.
- If the updater uses call_rcu_tasks() or synchronize_rcu_tasks(),
- then the readers must refrain from executing voluntary
- context switches, that is, from blocking. If the updater uses
- call_rcu_tasks_trace() or synchronize_rcu_tasks_trace(), then
- the corresponding readers must use rcu_read_lock_trace() and
- rcu_read_unlock_trace(). If an updater uses call_rcu_tasks_rude()
- or synchronize_rcu_tasks_rude(), then the corresponding readers
- must use anything that disables preemption, for example,
- preempt_disable() and preempt_enable().
+ Similarly, it is necessary to correctly use the RCU Tasks flavors:
+
+ a. If the updater uses synchronize_rcu_tasks() or
+ call_rcu_tasks(), then the readers must refrain from
+ executing voluntary context switches, that is, from
+ blocking.
+
+ b. If the updater uses call_rcu_tasks_trace()
+ or synchronize_rcu_tasks_trace(), then the
+ corresponding readers must use rcu_read_lock_trace()
+ and rcu_read_unlock_trace().
+
+ c. If an updater uses call_rcu_tasks_rude() or
+ synchronize_rcu_tasks_rude(), then the corresponding
+ readers must use anything that disables preemption,
+ for example, preempt_disable() and preempt_enable().
Mixing things up will result in confusion and broken kernels, and
has even resulted in an exploitable security issue. Therefore,
diff --git a/Documentation/RCU/rcu_dereference.rst b/Documentation/RCU/rcu_dereference.rst
index 3b739f6243c8..659d5913784d 100644
--- a/Documentation/RCU/rcu_dereference.rst
+++ b/Documentation/RCU/rcu_dereference.rst
@@ -3,13 +3,26 @@
PROPER CARE AND FEEDING OF RETURN VALUES FROM rcu_dereference()
===============================================================
-Most of the time, you can use values from rcu_dereference() or one of
-the similar primitives without worries. Dereferencing (prefix "*"),
-field selection ("->"), assignment ("="), address-of ("&"), addition and
-subtraction of constants, and casts all work quite naturally and safely.
-
-It is nevertheless possible to get into trouble with other operations.
-Follow these rules to keep your RCU code working properly:
+Proper care and feeding of address and data dependencies is critically
+important to correct use of things like RCU. To this end, the pointers
+returned from the rcu_dereference() family of primitives carry address and
+data dependencies. These dependencies extend from the rcu_dereference()
+macro's load of the pointer to the later use of that pointer to compute
+either the address of a later memory access (representing an address
+dependency) or the value written by a later memory access (representing
+a data dependency).
+
+Most of the time, these dependencies are preserved, permitting you to
+freely use values from rcu_dereference(). For example, dereferencing
+(prefix "*"), field selection ("->"), assignment ("="), address-of
+("&"), casts, and addition or subtraction of constants all work quite
+naturally and safely. However, because current compilers do not take
+either address or data dependencies into account it is still possible
+to get into trouble.
+
+Follow these rules to preserve the address and data dependencies emanating
+from your calls to rcu_dereference() and friends, thus keeping your RCU
+readers working properly:
- You must use one of the rcu_dereference() family of primitives
to load an RCU-protected pointer, otherwise CONFIG_PROVE_RCU
diff --git a/Documentation/RCU/torture.rst b/Documentation/RCU/torture.rst
index b3b6dfa85248..49e7beea6ae1 100644
--- a/Documentation/RCU/torture.rst
+++ b/Documentation/RCU/torture.rst
@@ -185,7 +185,7 @@ argument.
Not all changes require that all scenarios be run. For example, a change
to Tree SRCU might run only the SRCU-N and SRCU-P scenarios using the
--configs argument to kvm.sh as follows: "--configs 'SRCU-N SRCU-P'".
-Large systems can run multiple copies of of the full set of scenarios,
+Large systems can run multiple copies of the full set of scenarios,
for example, a system with 448 hardware threads can run five instances
of the full set concurrently. To make this happen::
diff --git a/Documentation/admin-guide/acpi/cppc_sysfs.rst b/Documentation/admin-guide/acpi/cppc_sysfs.rst
index e53d76365aa7..36981c667823 100644
--- a/Documentation/admin-guide/acpi/cppc_sysfs.rst
+++ b/Documentation/admin-guide/acpi/cppc_sysfs.rst
@@ -75,4 +75,4 @@ taking two different snapshots of feedback counters at time T1 and T2.
delivered_counter_delta = fbc_t2[del] - fbc_t1[del]
reference_counter_delta = fbc_t2[ref] - fbc_t1[ref]
- delivered_perf = (refernce_perf x delivered_counter_delta) / reference_counter_delta
+ delivered_perf = (reference_perf x delivered_counter_delta) / reference_counter_delta
diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt
index 839054923530..94c98be1329a 100644
--- a/Documentation/admin-guide/devices.txt
+++ b/Documentation/admin-guide/devices.txt
@@ -2704,6 +2704,9 @@
...
185 = /dev/ttyNX15 Hilscher netX serial port 15
186 = /dev/ttyJ0 JTAG1 DCC protocol based serial port emulation
+
+ If maximum number of uartlite serial ports is more than 4, then the driver
+ uses dynamic allocation instead of static allocation for major number.
187 = /dev/ttyUL0 Xilinx uartlite - port 0
...
190 = /dev/ttyUL3 Xilinx uartlite - port 3
diff --git a/Documentation/admin-guide/features.rst b/Documentation/admin-guide/features.rst
index 8c167082a84f..7651eca38227 100644
--- a/Documentation/admin-guide/features.rst
+++ b/Documentation/admin-guide/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features
+.. kernel-feat:: features
diff --git a/Documentation/admin-guide/hw_random.rst b/Documentation/admin-guide/hw_random.rst
index d494601717f1..bfc39f1cf470 100644
--- a/Documentation/admin-guide/hw_random.rst
+++ b/Documentation/admin-guide/hw_random.rst
@@ -14,10 +14,9 @@ into that core.
To make the most effective use of these mechanisms, you
should download the support software as well. Download the
-latest version of the "rng-tools" package from the
-hw_random driver's official Web site:
+latest version of the "rng-tools" package from:
- http://sourceforge.net/projects/gkernel/
+ https://github.com/nhorman/rng-tools
Those tools use /dev/hwrng to fill the kernel entropy pool,
which is used internally and exported by the /dev/urandom and
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 505af40e97bc..2e76c3476e2a 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2449,7 +2449,7 @@
between unregistering the boot console and initializing
the real console.
- keepinitrd [HW,ARM]
+ keepinitrd [HW,ARM] See retain_initrd.
kernelcore= [KNL,X86,IA-64,PPC]
Format: nn[KMGTPE] | nn% | "mirror"
@@ -3996,9 +3996,9 @@
vulnerability. System may allow data leaks with this
option.
- no-steal-acc [X86,PV_OPS,ARM64,PPC/PSERIES] Disable paravirtualized
- steal time accounting. steal time is computed, but
- won't influence scheduler behaviour
+ no-steal-acc [X86,PV_OPS,ARM64,PPC/PSERIES,RISCV] Disable
+ paravirtualized steal time accounting. steal time is
+ computed, but won't influence scheduler behaviour
nosync [HW,M68K] Disables sync negotiation for all devices.
@@ -5313,6 +5313,12 @@
Dump ftrace buffer after reporting RCU CPU
stall warning.
+ rcupdate.rcu_cpu_stall_notifiers= [KNL]
+ Provide RCU CPU stall notifiers, but see the
+ warnings in the RCU_CPU_STALL_NOTIFIER Kconfig
+ option's help text. TL;DR: You almost certainly
+ do not want rcupdate.rcu_cpu_stall_notifiers.
+
rcupdate.rcu_cpu_stall_suppress= [KNL]
Suppress RCU CPU stall warning messages.
@@ -5598,7 +5604,8 @@
Useful for devices that are detected asynchronously
(e.g. USB and MMC devices).
- retain_initrd [RAM] Keep initrd memory after extraction
+ retain_initrd [RAM] Keep initrd memory after extraction. After boot, it will
+ be accessible via /sys/firmware/initrd.
retbleed= [X86] Control mitigation of RETBleed (Arbitrary
Speculative Code Execution with Return Instructions)
@@ -6926,6 +6933,9 @@
pause after every control message);
o = USB_QUIRK_HUB_SLOW_RESET (Hub needs extra
delay after resetting its port);
+ p = USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT
+ (Reduce timeout of the SET_ADDRESS
+ request from 5000 ms to 500 ms);
Example: quirks=0781:5580:bk,0a5c:5834:gij
usbhid.mousepoll=
diff --git a/Documentation/admin-guide/media/starfive_camss.rst b/Documentation/admin-guide/media/starfive_camss.rst
new file mode 100644
index 000000000000..ca42e9447c47
--- /dev/null
+++ b/Documentation/admin-guide/media/starfive_camss.rst
@@ -0,0 +1,72 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: <isonum.txt>
+
+================================
+Starfive Camera Subsystem driver
+================================
+
+Introduction
+------------
+
+This file documents the driver for the Starfive Camera Subsystem found on
+Starfive JH7110 SoC. The driver is located under drivers/staging/media/starfive/
+camss.
+
+The driver implements V4L2, Media controller and v4l2_subdev interfaces. Camera
+sensor using V4L2 subdev interface in the kernel is supported.
+
+The driver has been successfully used on the Gstreamer 1.18.5 with v4l2src
+plugin.
+
+
+Starfive Camera Subsystem hardware
+----------------------------------
+
+The Starfive Camera Subsystem hardware consists of::
+
+ |\ +---------------+ +-----------+
+ +----------+ | \ | | | |
+ | | | | | | | |
+ | MIPI |----->| |----->| ISP |----->| |
+ | | | | | | | |
+ +----------+ | | | | | Memory |
+ |MUX| +---------------+ | Interface |
+ +----------+ | | | |
+ | | | |---------------------------->| |
+ | Parallel |----->| | | |
+ | | | | | |
+ +----------+ | / | |
+ |/ +-----------+
+
+- MIPI: The MIPI interface, receiving data from a MIPI CSI-2 camera sensor.
+
+- Parallel: The parallel interface, receiving data from a parallel sensor.
+
+- ISP: The ISP, processing raw Bayer data from an image sensor and producing
+ YUV frames.
+
+
+Topology
+--------
+
+The media controller pipeline graph is as follows:
+
+.. _starfive_camss_graph:
+
+.. kernel-figure:: starfive_camss_graph.dot
+ :alt: starfive_camss_graph.dot
+ :align: center
+
+The driver has 2 video devices:
+
+- capture_raw: The capture device, capturing image data directly from a sensor.
+- capture_yuv: The capture device, capturing YUV frame data processed by the
+ ISP module
+
+The driver has 3 subdevices:
+
+- stf_isp: is responsible for all the isp operations, outputs YUV frames.
+- cdns_csi2rx: a CSI-2 bridge supporting up to 4 CSI lanes in input, and 4
+ different pixel streams in output.
+- imx219: an image sensor, image data is sent through MIPI CSI-2.
diff --git a/Documentation/admin-guide/media/starfive_camss_graph.dot b/Documentation/admin-guide/media/starfive_camss_graph.dot
new file mode 100644
index 000000000000..8eff1f161ac7
--- /dev/null
+++ b/Documentation/admin-guide/media/starfive_camss_graph.dot
@@ -0,0 +1,12 @@
+digraph board {
+ rankdir=TB
+ n00000001 [label="{{<port0> 0} | stf_isp\n/dev/v4l-subdev0 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
+ n00000001:port1 -> n00000008 [style=dashed]
+ n00000004 [label="capture_raw\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
+ n00000008 [label="capture_yuv\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
+ n0000000e [label="{{<port0> 0} | cdns_csi2rx.19800000.csi-bridge\n | {<port1> 1 | <port2> 2 | <port3> 3 | <port4> 4}}", shape=Mrecord, style=filled, fillcolor=green]
+ n0000000e:port1 -> n00000001:port0 [style=dashed]
+ n0000000e:port1 -> n00000004 [style=dashed]
+ n00000018 [label="{{} | imx219 6-0010\n/dev/v4l-subdev1 | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
+ n00000018:port0 -> n0000000e:port0 [style=bold]
+}
diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst
index 61283d67ceef..f4bb2605f07e 100644
--- a/Documentation/admin-guide/media/v4l-drivers.rst
+++ b/Documentation/admin-guide/media/v4l-drivers.rst
@@ -28,6 +28,7 @@ Video4Linux (V4L) driver-specific documentation
si470x
si4713
si476x
+ starfive_camss
vimc
visl
vivid
diff --git a/Documentation/admin-guide/media/visl.rst b/Documentation/admin-guide/media/visl.rst
index 4328c6c72d30..db1ef29438e1 100644
--- a/Documentation/admin-guide/media/visl.rst
+++ b/Documentation/admin-guide/media/visl.rst
@@ -71,6 +71,7 @@ The following codecs are supported:
- VP9
- H.264
- HEVC
+- AV1
visl trace events
-----------------
@@ -79,6 +80,7 @@ The trace events are defined on a per-codec basis, e.g.:
.. code-block:: bash
$ ls /sys/kernel/tracing/events/ | grep visl
+ visl_av1_controls
visl_fwht_controls
visl_h264_controls
visl_hevc_controls
diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
index 1cf40f69278c..9eb26014d34b 100644
--- a/Documentation/admin-guide/pm/amd-pstate.rst
+++ b/Documentation/admin-guide/pm/amd-pstate.rst
@@ -361,7 +361,7 @@ Global Attributes
``amd-pstate`` exposes several global attributes (files) in ``sysfs`` to
control its functionality at the system level. They are located in the
-``/sys/devices/system/cpu/amd-pstate/`` directory and affect all CPUs.
+``/sys/devices/system/cpu/amd_pstate/`` directory and affect all CPUs.
``status``
Operation mode of the driver: "active", "passive" or "disable".
diff --git a/Documentation/admin-guide/sysrq.rst b/Documentation/admin-guide/sysrq.rst
index 51906e47327b..2f2e5bd440f9 100644
--- a/Documentation/admin-guide/sysrq.rst
+++ b/Documentation/admin-guide/sysrq.rst
@@ -75,10 +75,19 @@ On other
submit a patch to be included in this section.
On all
- Write a character to /proc/sysrq-trigger. e.g.::
+ Write a single character to /proc/sysrq-trigger.
+ Only the first character is processed, the rest of the string is
+ ignored. However, it is not recommended to write any extra characters
+ as the behavior is undefined and might change in the future versions.
+ E.g.::
echo t > /proc/sysrq-trigger
+ Alternatively, write multiple characters prepended by underscore.
+ This way, all characters will be processed. E.g.::
+
+ echo _reisub > /proc/sysrq-trigger
+
The :kbd:`<command key>` is case sensitive.
What are the 'command' keys?
diff --git a/Documentation/arch/arc/features.rst b/Documentation/arch/arc/features.rst
index b793583d688a..49ff446ff744 100644
--- a/Documentation/arch/arc/features.rst
+++ b/Documentation/arch/arc/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features arc
+.. kernel-feat:: features arc
diff --git a/Documentation/arch/arm/features.rst b/Documentation/arch/arm/features.rst
index 7414ec03dd15..0e76aaf68eca 100644
--- a/Documentation/arch/arm/features.rst
+++ b/Documentation/arch/arm/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features arm
+.. kernel-feat:: features arm
diff --git a/Documentation/arch/arm64/features.rst b/Documentation/arch/arm64/features.rst
index dfa4cb3cd3ef..03321f4309d0 100644
--- a/Documentation/arch/arm64/features.rst
+++ b/Documentation/arch/arm64/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features arm64
+.. kernel-feat:: features arm64
diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
index f47f63bcf67c..bfdf236e2af3 100644
--- a/Documentation/arch/arm64/silicon-errata.rst
+++ b/Documentation/arch/arm64/silicon-errata.rst
@@ -117,6 +117,10 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A76 | #1463225 | ARM64_ERRATUM_1463225 |
+----------------+-----------------+-----------------+-----------------------------+
+| ARM | Cortex-A76 | #1490853 | N/A |
++----------------+-----------------+-----------------+-----------------------------+
+| ARM | Cortex-A77 | #1491015 | N/A |
++----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A77 | #1508412 | ARM64_ERRATUM_1508412 |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A710 | #2119858 | ARM64_ERRATUM_2119858 |
@@ -127,6 +131,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A715 | #2645198 | ARM64_ERRATUM_2645198 |
+----------------+-----------------+-----------------+-----------------------------+
+| ARM | Cortex-X1 | #1502854 | N/A |
++----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-X2 | #2119858 | ARM64_ERRATUM_2119858 |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-X2 | #2224489 | ARM64_ERRATUM_2224489 |
@@ -135,6 +141,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Neoverse-N1 | #1349291 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
+| ARM | Neoverse-N1 | #1490853 | N/A |
++----------------+-----------------+-----------------+-----------------------------+
| ARM | Neoverse-N1 | #1542419 | ARM64_ERRATUM_1542419 |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Neoverse-N2 | #2139208 | ARM64_ERRATUM_2139208 |
@@ -143,6 +151,8 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Neoverse-N2 | #2253138 | ARM64_ERRATUM_2253138 |
+----------------+-----------------+-----------------+-----------------------------+
+| ARM | Neoverse-V1 | #1619801 | N/A |
++----------------+-----------------+-----------------+-----------------------------+
| ARM | MMU-500 | #841119,826419 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | MMU-600 | #1076982,1209401| N/A |
diff --git a/Documentation/arch/loongarch/features.rst b/Documentation/arch/loongarch/features.rst
index ebacade3ea45..009f44c7951f 100644
--- a/Documentation/arch/loongarch/features.rst
+++ b/Documentation/arch/loongarch/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features loongarch
+.. kernel-feat:: features loongarch
diff --git a/Documentation/arch/m68k/features.rst b/Documentation/arch/m68k/features.rst
index 5107a2119472..de7f0ccf7fc8 100644
--- a/Documentation/arch/m68k/features.rst
+++ b/Documentation/arch/m68k/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features m68k
+.. kernel-feat:: features m68k
diff --git a/Documentation/arch/mips/features.rst b/Documentation/arch/mips/features.rst
index 1973d729b29a..6e0ffe3e7354 100644
--- a/Documentation/arch/mips/features.rst
+++ b/Documentation/arch/mips/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features mips
+.. kernel-feat:: features mips
diff --git a/Documentation/arch/nios2/features.rst b/Documentation/arch/nios2/features.rst
index 8449e63f69b2..89913810ccb5 100644
--- a/Documentation/arch/nios2/features.rst
+++ b/Documentation/arch/nios2/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features nios2
+.. kernel-feat:: features nios2
diff --git a/Documentation/arch/openrisc/features.rst b/Documentation/arch/openrisc/features.rst
index 3f7c40d219f2..bae2e25adfd6 100644
--- a/Documentation/arch/openrisc/features.rst
+++ b/Documentation/arch/openrisc/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features openrisc
+.. kernel-feat:: features openrisc
diff --git a/Documentation/arch/parisc/features.rst b/Documentation/arch/parisc/features.rst
index 501d7c450037..b3aa4d243b93 100644
--- a/Documentation/arch/parisc/features.rst
+++ b/Documentation/arch/parisc/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features parisc
+.. kernel-feat:: features parisc
diff --git a/Documentation/arch/powerpc/features.rst b/Documentation/arch/powerpc/features.rst
index aeae73df86b0..ee4b95e04202 100644
--- a/Documentation/arch/powerpc/features.rst
+++ b/Documentation/arch/powerpc/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features powerpc
+.. kernel-feat:: features powerpc
diff --git a/Documentation/arch/riscv/features.rst b/Documentation/arch/riscv/features.rst
index c70ef6ac2368..36e90144adab 100644
--- a/Documentation/arch/riscv/features.rst
+++ b/Documentation/arch/riscv/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features riscv
+.. kernel-feat:: features riscv
diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index 7b2384de471f..b2bcc9eed9aa 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -12,7 +12,7 @@ is defined in <asm/hwprobe.h>::
};
long sys_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
- size_t cpu_count, cpu_set_t *cpus,
+ size_t cpusetsize, cpu_set_t *cpus,
unsigned int flags);
The arguments are split into three groups: an array of key-value pairs, a CPU
@@ -20,12 +20,26 @@ set, and some flags. The key-value pairs are supplied with a count. Userspace
must prepopulate the key field for each element, and the kernel will fill in the
value if the key is recognized. If a key is unknown to the kernel, its key field
will be cleared to -1, and its value set to 0. The CPU set is defined by
-CPU_SET(3). For value-like keys (eg. vendor/arch/impl), the returned value will
-be only be valid if all CPUs in the given set have the same value. Otherwise -1
-will be returned. For boolean-like keys, the value returned will be a logical
-AND of the values for the specified CPUs. Usermode can supply NULL for cpus and
-0 for cpu_count as a shortcut for all online CPUs. There are currently no flags,
-this value must be zero for future compatibility.
+CPU_SET(3) with size ``cpusetsize`` bytes. For value-like keys (eg. vendor,
+arch, impl), the returned value will only be valid if all CPUs in the given set
+have the same value. Otherwise -1 will be returned. For boolean-like keys, the
+value returned will be a logical AND of the values for the specified CPUs.
+Usermode can supply NULL for ``cpus`` and 0 for ``cpusetsize`` as a shortcut for
+all online CPUs. The currently supported flags are:
+
+* :c:macro:`RISCV_HWPROBE_WHICH_CPUS`: This flag basically reverses the behavior
+ of sys_riscv_hwprobe(). Instead of populating the values of keys for a given
+ set of CPUs, the values of each key are given and the set of CPUs is reduced
+ by sys_riscv_hwprobe() to only those which match each of the key-value pairs.
+ How matching is done depends on the key type. For value-like keys, matching
+ means to be the exact same as the value. For boolean-like keys, matching
+ means the result of a logical AND of the pair's value with the CPU's value is
+ exactly the same as the pair's value. Additionally, when ``cpus`` is an empty
+ set, then it is initialized to all online CPUs which fit within it, i.e. the
+ CPU set returned is the reduction of all the online CPUs which can be
+ represented with a CPU set of size ``cpusetsize``.
+
+All other flags are reserved for future compatibility and must be zero.
On success 0 is returned, on failure a negative error code is returned.
@@ -80,6 +94,100 @@ The following keys are defined:
* :c:macro:`RISCV_HWPROBE_EXT_ZICBOZ`: The Zicboz extension is supported, as
ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
+ * :c:macro:`RISCV_HWPROBE_EXT_ZBC` The Zbc extension is supported, as defined
+ in version 1.0 of the Bit-Manipulation ISA extensions.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZBKB` The Zbkb extension is supported, as
+ defined in version 1.0 of the Scalar Crypto ISA extensions.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZBKC` The Zbkc extension is supported, as
+ defined in version 1.0 of the Scalar Crypto ISA extensions.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZBKX` The Zbkx extension is supported, as
+ defined in version 1.0 of the Scalar Crypto ISA extensions.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZKND` The Zknd extension is supported, as
+ defined in version 1.0 of the Scalar Crypto ISA extensions.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZKNE` The Zkne extension is supported, as
+ defined in version 1.0 of the Scalar Crypto ISA extensions.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZKNH` The Zknh extension is supported, as
+ defined in version 1.0 of the Scalar Crypto ISA extensions.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZKSED` The Zksed extension is supported, as
+ defined in version 1.0 of the Scalar Crypto ISA extensions.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZKSH` The Zksh extension is supported, as
+ defined in version 1.0 of the Scalar Crypto ISA extensions.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZKT` The Zkt extension is supported, as defined
+ in version 1.0 of the Scalar Crypto ISA extensions.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZVBB`: The Zvbb extension is supported as
+ defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZVBC`: The Zvbc extension is supported as
+ defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZVKB`: The Zvkb extension is supported as
+ defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZVKG`: The Zvkg extension is supported as
+ defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZVKNED`: The Zvkned extension is supported as
+ defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZVKNHA`: The Zvknha extension is supported as
+ defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZVKNHB`: The Zvknhb extension is supported as
+ defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZVKSED`: The Zvksed extension is supported as
+ defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZVKSH`: The Zvksh extension is supported as
+ defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZVKT`: The Zvkt extension is supported as
+ defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZFH`: The Zfh extension version 1.0 is supported
+ as defined in the RISC-V ISA manual.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZFHMIN`: The Zfhmin extension version 1.0 is
+ supported as defined in the RISC-V ISA manual.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZIHINTNTL`: The Zihintntl extension version 1.0
+ is supported as defined in the RISC-V ISA manual.
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZVFH`: The Zvfh extension is supported as
+ defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
+ ("Remove draft warnings from Zvfh[min]").
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZVFHMIN`: The Zvfhmin extension is supported as
+ defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
+ ("Remove draft warnings from Zvfh[min]").
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZFA`: The Zfa extension is supported as
+ defined in the RISC-V ISA manual starting from commit 056b6ff467c7
+ ("Zfa is ratified").
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZTSO`: The Ztso extension is supported as
+ defined in the RISC-V ISA manual starting from commit 5618fb5a216b
+ ("Ztso is now ratified.")
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZACAS`: The Zacas extension is supported as
+ defined in the Atomic Compare-and-Swap (CAS) instructions manual starting
+ from commit 5059e0ca641c ("update to ratified").
+
+ * :c:macro:`RISCV_HWPROBE_EXT_ZICOND`: The Zicond extension is supported as
+ defined in the RISC-V Integer Conditional (Zicond) operations extension
+ manual starting from commit 95cf1f9 ("Add changes requested by Ved
+ during signoff")
+
* :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: A bitmask that contains performance
information about the selected set of processors.
diff --git a/Documentation/arch/s390/features.rst b/Documentation/arch/s390/features.rst
index 57c296a9d8f3..2883dc950681 100644
--- a/Documentation/arch/s390/features.rst
+++ b/Documentation/arch/s390/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features s390
+.. kernel-feat:: features s390
diff --git a/Documentation/arch/sh/features.rst b/Documentation/arch/sh/features.rst
index f722af3b6c99..fae48fe81e9b 100644
--- a/Documentation/arch/sh/features.rst
+++ b/Documentation/arch/sh/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features sh
+.. kernel-feat:: features sh
diff --git a/Documentation/arch/sparc/features.rst b/Documentation/arch/sparc/features.rst
index c0c92468b0fe..96835b6d598a 100644
--- a/Documentation/arch/sparc/features.rst
+++ b/Documentation/arch/sparc/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features sparc
+.. kernel-feat:: features sparc
diff --git a/Documentation/arch/x86/features.rst b/Documentation/arch/x86/features.rst
index b663f15053ce..a33616346a38 100644
--- a/Documentation/arch/x86/features.rst
+++ b/Documentation/arch/x86/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features x86
+.. kernel-feat:: features x86
diff --git a/Documentation/arch/x86/tdx.rst b/Documentation/arch/x86/tdx.rst
index dc8d9fd2c3f7..719043cd8b46 100644
--- a/Documentation/arch/x86/tdx.rst
+++ b/Documentation/arch/x86/tdx.rst
@@ -10,6 +10,191 @@ encrypting the guest memory. In TDX, a special module running in a special
mode sits between the host and the guest and manages the guest/host
separation.
+TDX Host Kernel Support
+=======================
+
+TDX introduces a new CPU mode called Secure Arbitration Mode (SEAM) and
+a new isolated range pointed by the SEAM Ranger Register (SEAMRR). A
+CPU-attested software module called 'the TDX module' runs inside the new
+isolated range to provide the functionalities to manage and run protected
+VMs.
+
+TDX also leverages Intel Multi-Key Total Memory Encryption (MKTME) to
+provide crypto-protection to the VMs. TDX reserves part of MKTME KeyIDs
+as TDX private KeyIDs, which are only accessible within the SEAM mode.
+BIOS is responsible for partitioning legacy MKTME KeyIDs and TDX KeyIDs.
+
+Before the TDX module can be used to create and run protected VMs, it
+must be loaded into the isolated range and properly initialized. The TDX
+architecture doesn't require the BIOS to load the TDX module, but the
+kernel assumes it is loaded by the BIOS.
+
+TDX boot-time detection
+-----------------------
+
+The kernel detects TDX by detecting TDX private KeyIDs during kernel
+boot. Below dmesg shows when TDX is enabled by BIOS::
+
+ [..] virt/tdx: BIOS enabled: private KeyID range: [16, 64)
+
+TDX module initialization
+---------------------------------------
+
+The kernel talks to the TDX module via the new SEAMCALL instruction. The
+TDX module implements SEAMCALL leaf functions to allow the kernel to
+initialize it.
+
+If the TDX module isn't loaded, the SEAMCALL instruction fails with a
+special error. In this case the kernel fails the module initialization
+and reports the module isn't loaded::
+
+ [..] virt/tdx: module not loaded
+
+Initializing the TDX module consumes roughly ~1/256th system RAM size to
+use it as 'metadata' for the TDX memory. It also takes additional CPU
+time to initialize those metadata along with the TDX module itself. Both
+are not trivial. The kernel initializes the TDX module at runtime on
+demand.
+
+Besides initializing the TDX module, a per-cpu initialization SEAMCALL
+must be done on one cpu before any other SEAMCALLs can be made on that
+cpu.
+
+The kernel provides two functions, tdx_enable() and tdx_cpu_enable() to
+allow the user of TDX to enable the TDX module and enable TDX on local
+cpu respectively.
+
+Making SEAMCALL requires VMXON has been done on that CPU. Currently only
+KVM implements VMXON. For now both tdx_enable() and tdx_cpu_enable()
+don't do VMXON internally (not trivial), but depends on the caller to
+guarantee that.
+
+To enable TDX, the caller of TDX should: 1) temporarily disable CPU
+hotplug; 2) do VMXON and tdx_enable_cpu() on all online cpus; 3) call
+tdx_enable(). For example::
+
+ cpus_read_lock();
+ on_each_cpu(vmxon_and_tdx_cpu_enable());
+ ret = tdx_enable();
+ cpus_read_unlock();
+ if (ret)
+ goto no_tdx;
+ // TDX is ready to use
+
+And the caller of TDX must guarantee the tdx_cpu_enable() has been
+successfully done on any cpu before it wants to run any other SEAMCALL.
+A typical usage is do both VMXON and tdx_cpu_enable() in CPU hotplug
+online callback, and refuse to online if tdx_cpu_enable() fails.
+
+User can consult dmesg to see whether the TDX module has been initialized.
+
+If the TDX module is initialized successfully, dmesg shows something
+like below::
+
+ [..] virt/tdx: 262668 KBs allocated for PAMT
+ [..] virt/tdx: module initialized
+
+If the TDX module failed to initialize, dmesg also shows it failed to
+initialize::
+
+ [..] virt/tdx: module initialization failed ...
+
+TDX Interaction to Other Kernel Components
+------------------------------------------
+
+TDX Memory Policy
+~~~~~~~~~~~~~~~~~
+
+TDX reports a list of "Convertible Memory Region" (CMR) to tell the
+kernel which memory is TDX compatible. The kernel needs to build a list
+of memory regions (out of CMRs) as "TDX-usable" memory and pass those
+regions to the TDX module. Once this is done, those "TDX-usable" memory
+regions are fixed during module's lifetime.
+
+To keep things simple, currently the kernel simply guarantees all pages
+in the page allocator are TDX memory. Specifically, the kernel uses all
+system memory in the core-mm "at the time of TDX module initialization"
+as TDX memory, and in the meantime, refuses to online any non-TDX-memory
+in the memory hotplug.
+
+Physical Memory Hotplug
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Note TDX assumes convertible memory is always physically present during
+machine's runtime. A non-buggy BIOS should never support hot-removal of
+any convertible memory. This implementation doesn't handle ACPI memory
+removal but depends on the BIOS to behave correctly.
+
+CPU Hotplug
+~~~~~~~~~~~
+
+TDX module requires the per-cpu initialization SEAMCALL must be done on
+one cpu before any other SEAMCALLs can be made on that cpu. The kernel
+provides tdx_cpu_enable() to let the user of TDX to do it when the user
+wants to use a new cpu for TDX task.
+
+TDX doesn't support physical (ACPI) CPU hotplug. During machine boot,
+TDX verifies all boot-time present logical CPUs are TDX compatible before
+enabling TDX. A non-buggy BIOS should never support hot-add/removal of
+physical CPU. Currently the kernel doesn't handle physical CPU hotplug,
+but depends on the BIOS to behave correctly.
+
+Note TDX works with CPU logical online/offline, thus the kernel still
+allows to offline logical CPU and online it again.
+
+Kexec()
+~~~~~~~
+
+TDX host support currently lacks the ability to handle kexec. For
+simplicity only one of them can be enabled in the Kconfig. This will be
+fixed in the future.
+
+Erratum
+~~~~~~~
+
+The first few generations of TDX hardware have an erratum. A partial
+write to a TDX private memory cacheline will silently "poison" the
+line. Subsequent reads will consume the poison and generate a machine
+check.
+
+A partial write is a memory write where a write transaction of less than
+cacheline lands at the memory controller. The CPU does these via
+non-temporal write instructions (like MOVNTI), or through UC/WC memory
+mappings. Devices can also do partial writes via DMA.
+
+Theoretically, a kernel bug could do partial write to TDX private memory
+and trigger unexpected machine check. What's more, the machine check
+code will present these as "Hardware error" when they were, in fact, a
+software-triggered issue. But in the end, this issue is hard to trigger.
+
+If the platform has such erratum, the kernel prints additional message in
+machine check handler to tell user the machine check may be caused by
+kernel bug on TDX private memory.
+
+Interaction vs S3 and deeper states
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+TDX cannot survive from S3 and deeper states. The hardware resets and
+disables TDX completely when platform goes to S3 and deeper. Both TDX
+guests and the TDX module get destroyed permanently.
+
+The kernel uses S3 for suspend-to-ram, and use S4 and deeper states for
+hibernation. Currently, for simplicity, the kernel chooses to make TDX
+mutually exclusive with S3 and hibernation.
+
+The kernel disables TDX during early boot when hibernation support is
+available::
+
+ [..] virt/tdx: initialization failed: Hibernation support is enabled
+
+Add 'nohibernate' kernel command line to disable hibernation in order to
+use TDX.
+
+ACPI S3 is disabled during kernel early boot if TDX is enabled. The user
+needs to turn off TDX in the BIOS in order to use S3.
+
+TDX Guest Support
+=================
Since the host cannot directly access guest registers or memory, much
normal functionality of a hypervisor must be moved into the guest. This is
implemented using a Virtualization Exception (#VE) that is handled by the
@@ -20,7 +205,7 @@ TDX includes new hypercall-like mechanisms for communicating from the
guest to the hypervisor or the TDX module.
New TDX Exceptions
-==================
+------------------
TDX guests behave differently from bare-metal and traditional VMX guests.
In TDX guests, otherwise normal instructions or memory accesses can cause
@@ -30,7 +215,7 @@ Instructions marked with an '*' conditionally cause exceptions. The
details for these instructions are discussed below.
Instruction-based #VE
----------------------
+~~~~~~~~~~~~~~~~~~~~~
- Port I/O (INS, OUTS, IN, OUT)
- HLT
@@ -41,7 +226,7 @@ Instruction-based #VE
- CPUID*
Instruction-based #GP
----------------------
+~~~~~~~~~~~~~~~~~~~~~
- All VMX instructions: INVEPT, INVVPID, VMCLEAR, VMFUNC, VMLAUNCH,
VMPTRLD, VMPTRST, VMREAD, VMRESUME, VMWRITE, VMXOFF, VMXON
@@ -52,7 +237,7 @@ Instruction-based #GP
- RDMSR*,WRMSR*
RDMSR/WRMSR Behavior
---------------------
+~~~~~~~~~~~~~~~~~~~~
MSR access behavior falls into three categories:
@@ -73,7 +258,7 @@ trapping and handling in the TDX module. Other than possibly being slow,
these MSRs appear to function just as they would on bare metal.
CPUID Behavior
---------------
+~~~~~~~~~~~~~~
For some CPUID leaves and sub-leaves, the virtualized bit fields of CPUID
return values (in guest EAX/EBX/ECX/EDX) are configurable by the
@@ -93,7 +278,7 @@ not know how to handle. The guest kernel may ask the hypervisor for the
value with a hypercall.
#VE on Memory Accesses
-======================
+----------------------
There are essentially two classes of TDX memory: private and shared.
Private memory receives full TDX protections. Its content is protected
@@ -107,7 +292,7 @@ entries. This helps ensure that a guest does not place sensitive
information in shared memory, exposing it to the untrusted hypervisor.
#VE on Shared Memory
---------------------
+~~~~~~~~~~~~~~~~~~~~
Access to shared mappings can cause a #VE. The hypervisor ultimately
controls whether a shared memory access causes a #VE, so the guest must be
@@ -127,7 +312,7 @@ be careful not to access device MMIO regions unless it is also prepared to
handle a #VE.
#VE on Private Pages
---------------------
+~~~~~~~~~~~~~~~~~~~~
An access to private mappings can also cause a #VE. Since all kernel
memory is also private memory, the kernel might theoretically need to
@@ -145,7 +330,7 @@ The hypervisor is permitted to unilaterally move accepted pages to a
to handle the exception.
Linux #VE handler
-=================
+-----------------
Just like page faults or #GP's, #VE exceptions can be either handled or be
fatal. Typically, an unhandled userspace #VE results in a SIGSEGV.
@@ -167,7 +352,7 @@ While the block is in place, any #VE is elevated to a double fault (#DF)
which is not recoverable.
MMIO handling
-=============
+-------------
In non-TDX VMs, MMIO is usually implemented by giving a guest access to a
mapping which will cause a VMEXIT on access, and then the hypervisor
@@ -189,7 +374,7 @@ MMIO access via other means (like structure overlays) may result in an
oops.
Shared Memory Conversions
-=========================
+-------------------------
All TDX guest memory starts out as private at boot. This memory can not
be accessed by the hypervisor. However, some kernel users like device
diff --git a/Documentation/arch/xtensa/features.rst b/Documentation/arch/xtensa/features.rst
index 6b92c7bfa19d..28dcce1759be 100644
--- a/Documentation/arch/xtensa/features.rst
+++ b/Documentation/arch/xtensa/features.rst
@@ -1,3 +1,3 @@
.. SPDX-License-Identifier: GPL-2.0
-.. kernel-feat:: $srctree/Documentation/features xtensa
+.. kernel-feat:: features xtensa
diff --git a/Documentation/core-api/workqueue.rst b/Documentation/core-api/workqueue.rst
index 33c4539155d9..3599cf9267b4 100644
--- a/Documentation/core-api/workqueue.rst
+++ b/Documentation/core-api/workqueue.rst
@@ -446,7 +446,7 @@ The command used: ::
There are 24 issuers, each issuing 64 IOs concurrently. ``--verify=sha512``
makes ``fio`` generate and read back the content each time which makes
-execution locality matter between the issuer and ``kcryptd``. The followings
+execution locality matter between the issuer and ``kcryptd``. The following
are the read bandwidths and CPU utilizations depending on different affinity
scope settings on ``kcryptd`` measured over five runs. Bandwidths are in
MiBps, and CPU util in percents.
diff --git a/Documentation/dev-tools/kunit/running_tips.rst b/Documentation/dev-tools/kunit/running_tips.rst
index 024e9ad1d1e9..bd689db6fdd2 100644
--- a/Documentation/dev-tools/kunit/running_tips.rst
+++ b/Documentation/dev-tools/kunit/running_tips.rst
@@ -139,6 +139,17 @@ If your installed version of gcc doesn't work, you can tweak the steps:
$ ./tools/testing/kunit/kunit.py run --make_options=CC=/usr/bin/gcc-6
$ lcov -t "my_kunit_tests" -o coverage.info -c -d .kunit/ --gcov-tool=/usr/bin/gcov-6
+Alternatively, LLVM-based toolchains can also be used:
+
+.. code-block:: bash
+
+ # Build with LLVM and append coverage options to the current config
+ $ ./tools/testing/kunit/kunit.py run --make_options LLVM=1 --kunitconfig=.kunit/ --kunitconfig=tools/testing/kunit/configs/coverage_uml.config
+ $ llvm-profdata merge -sparse default.profraw -o default.profdata
+ $ llvm-cov export --format=lcov .kunit/vmlinux -instr-profile default.profdata > coverage.info
+ # The coverage.info file is in lcov-compatible format and it can be used to e.g. generate HTML report
+ $ genhtml -o /tmp/coverage_html coverage.info
+
Running tests manually
======================
diff --git a/Documentation/devicetree/bindings/Makefile b/Documentation/devicetree/bindings/Makefile
index 3e886194b043..2323fd5b7cda 100644
--- a/Documentation/devicetree/bindings/Makefile
+++ b/Documentation/devicetree/bindings/Makefile
@@ -28,7 +28,7 @@ $(obj)/%.example.dts: $(src)/%.yaml check_dtschema_version FORCE
find_all_cmd = find $(srctree)/$(src) \( -name '*.yaml' ! \
-name 'processed-schema*' \)
-find_cmd = $(find_all_cmd) | grep -F -e "$(subst :," -e ",$(DT_SCHEMA_FILES))"
+find_cmd = $(find_all_cmd) | sed 's|^$(srctree)/$(src)/||' | grep -F -e "$(subst :," -e ",$(DT_SCHEMA_FILES))" | sed 's|^|$(srctree)/$(src)/|'
CHK_DT_DOCS := $(shell $(find_cmd))
quiet_cmd_yamllint = LINT $(src)
diff --git a/Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml b/Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml
index a9fe01238a88..76b65ea149b6 100644
--- a/Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml
+++ b/Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml
@@ -16,7 +16,7 @@ maintainers:
properties:
compatible:
- const: "calxeda,hb-sregs-l2-ecc"
+ const: calxeda,hb-sregs-l2-ecc
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt
deleted file mode 100644
index eccd4b706a78..000000000000
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-Mediatek ethsys controller
-============================
-
-The Mediatek ethsys controller provides various clocks to the system.
-
-Required Properties:
-
-- compatible: Should be:
- - "mediatek,mt2701-ethsys", "syscon"
- - "mediatek,mt7622-ethsys", "syscon"
- - "mediatek,mt7623-ethsys", "mediatek,mt2701-ethsys", "syscon"
- - "mediatek,mt7629-ethsys", "syscon"
- - "mediatek,mt7981-ethsys", "syscon"
- - "mediatek,mt7986-ethsys", "syscon"
-- #clock-cells: Must be 1
-- #reset-cells: Must be 1
-
-The ethsys controller uses the common clk binding from
-Documentation/devicetree/bindings/clock/clock-bindings.txt
-The available clocks are defined in dt-bindings/clock/mt*-clk.h.
-
-Example:
-
-ethsys: clock-controller@1b000000 {
- compatible = "mediatek,mt2701-ethsys", "syscon";
- reg = <0 0x1b000000 0 0x1000>;
- #clock-cells = <1>;
- #reset-cells = <1>;
-};
diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml
index ea98043c6ba3..230b5188a88d 100644
--- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml
+++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml
@@ -30,6 +30,7 @@ properties:
- mediatek,mt7629-infracfg
- mediatek,mt7981-infracfg
- mediatek,mt7986-infracfg
+ - mediatek,mt7988-infracfg
- mediatek,mt8135-infracfg
- mediatek,mt8167-infracfg
- mediatek,mt8173-infracfg
diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,idle-state.txt b/Documentation/devicetree/bindings/arm/msm/qcom,idle-state.txt
deleted file mode 100644
index 606b4b1b709d..000000000000
--- a/Documentation/devicetree/bindings/arm/msm/qcom,idle-state.txt
+++ /dev/null
@@ -1,84 +0,0 @@
-QCOM Idle States for cpuidle driver
-
-ARM provides idle-state node to define the cpuidle states, as defined in [1].
-cpuidle-qcom is the cpuidle driver for Qualcomm SoCs and uses these idle
-states. Idle states have different enter/exit latency and residency values.
-The idle states supported by the QCOM SoC are defined as -
-
- * Standby
- * Retention
- * Standalone Power Collapse (Standalone PC or SPC)
- * Power Collapse (PC)
-
-Standby: Standby does a little more in addition to architectural clock gating.
-When the WFI instruction is executed the ARM core would gate its internal
-clocks. In addition to gating the clocks, QCOM cpus use this instruction as a
-trigger to execute the SPM state machine. The SPM state machine waits for the
-interrupt to trigger the core back in to active. This triggers the cache
-hierarchy to enter standby states, when all cpus are idle. An interrupt brings
-the SPM state machine out of its wait, the next step is to ensure that the
-cache hierarchy is also out of standby, and then the cpu is allowed to resume
-execution. This state is defined as a generic ARM WFI state by the ARM cpuidle
-driver and is not defined in the DT. The SPM state machine should be
-configured to execute this state by default and after executing every other
-state below.
-
-Retention: Retention is a low power state where the core is clock gated and
-the memory and the registers associated with the core are retained. The
-voltage may be reduced to the minimum value needed to keep the processor
-registers active. The SPM should be configured to execute the retention
-sequence and would wait for interrupt, before restoring the cpu to execution
-state. Retention may have a slightly higher latency than Standby.
-
-Standalone PC: A cpu can power down and warmboot if there is a sufficient time
-between the time it enters idle and the next known wake up. SPC mode is used
-to indicate a core entering a power down state without consulting any other
-cpu or the system resources. This helps save power only on that core. The SPM
-sequence for this idle state is programmed to power down the supply to the
-core, wait for the interrupt, restore power to the core, and ensure the
-system state including cache hierarchy is ready before allowing core to
-resume. Applying power and resetting the core causes the core to warmboot
-back into Elevation Level (EL) which trampolines the control back to the
-kernel. Entering a power down state for the cpu, needs to be done by trapping
-into a EL. Failing to do so, would result in a crash enforced by the warm boot
-code in the EL for the SoC. On SoCs with write-back L1 cache, the cache has to
-be flushed in s/w, before powering down the core.
-
-Power Collapse: This state is similar to the SPC mode, but distinguishes
-itself in that the cpu acknowledges and permits the SoC to enter deeper sleep
-modes. In a hierarchical power domain SoC, this means L2 and other caches can
-be flushed, system bus, clocks - lowered, and SoC main XO clock gated and
-voltages reduced, provided all cpus enter this state. Since the span of low
-power modes possible at this state is vast, the exit latency and the residency
-of this low power mode would be considered high even though at a cpu level,
-this essentially is cpu power down. The SPM in this state also may handshake
-with the Resource power manager (RPM) processor in the SoC to indicate a
-complete application processor subsystem shut down.
-
-The idle-state for QCOM SoCs are distinguished by the compatible property of
-the idle-states device node.
-
-The devicetree representation of the idle state should be -
-
-Required properties:
-
-- compatible: Must be one of -
- "qcom,idle-state-ret",
- "qcom,idle-state-spc",
- "qcom,idle-state-pc",
- and "arm,idle-state".
-
-Other required and optional properties are specified in [1].
-
-Example:
-
- idle-states {
- CPU_SPC: spc {
- compatible = "qcom,idle-state-spc", "arm,idle-state";
- entry-latency-us = <150>;
- exit-latency-us = <200>;
- min-residency-us = <2000>;
- };
- };
-
-[1]. Documentation/devicetree/bindings/cpu/idle-states.yaml
diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-remote-etm.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-remote-etm.yaml
new file mode 100644
index 000000000000..4fd5752978cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/qcom,coresight-remote-etm.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/qcom,coresight-remote-etm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Coresight Remote ETM(Embedded Trace Macrocell)
+
+maintainers:
+ - Jinlong Mao <[email protected]>
+ - Tao Zhang <[email protected]>
+
+description:
+ Support for ETM trace collection on remote processor using coresight
+ framework. Enabling this will allow turning on ETM tracing on remote
+ processor like modem processor via sysfs and collecting the trace
+ via coresight TMC sinks.
+
+properties:
+ compatible:
+ const: qcom,coresight-remote-etm
+
+ out-ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+ additionalProperties: false
+
+ properties:
+ port:
+ description: Output connection to the CoreSight Trace bus.
+ $ref: /schemas/graph.yaml#/properties/port
+
+required:
+ - compatible
+ - out-ports
+
+additionalProperties: false
+
+examples:
+ - |
+ etm {
+ compatible = "qcom,coresight-remote-etm";
+
+ out-ports {
+ port {
+ modem_etm0_out_funnel_modem: endpoint {
+ remote-endpoint = <&funnel_modem_in_modem_etm0>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml
index 3bad47b7b02b..61ddc3b5b247 100644
--- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml
+++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml
@@ -44,6 +44,23 @@ properties:
minItems: 1
maxItems: 2
+ qcom,dsb-element-size:
+ description:
+ Specifies the DSB(Discrete Single Bit) element size supported by
+ the monitor. The associated aggregator will read this size before it
+ is enabled. DSB element size currently only supports 32-bit and 64-bit.
+ $ref: /schemas/types.yaml#/definitions/uint8
+ enum: [32, 64]
+
+ qcom,dsb-msrs-num:
+ description:
+ Specifies the number of DSB(Discrete Single Bit) MSR(mux select register)
+ registers supported by the monitor. If this property is not configured
+ or set to 0, it means this DSB TPDM doesn't support MSR.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 32
+
clocks:
maxItems: 1
@@ -77,6 +94,9 @@ examples:
compatible = "qcom,coresight-tpdm", "arm,primecell";
reg = <0x0684c000 0x1000>;
+ qcom,dsb-element-size = /bits/ 8 <32>;
+ qcom,dsb-msrs-num = <16>;
+
clocks = <&aoss_qmp>;
clock-names = "apb_pclk";
diff --git a/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml b/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml
index fde07e4b119d..406a922a714e 100644
--- a/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml
+++ b/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml
@@ -113,7 +113,7 @@ examples:
hd44780 {
compatible = "hit,hd44780";
display-height-chars = <2>;
- display-width-chars = <16>;
+ display-width-chars = <16>;
data-gpios = <&pcf8574 4 0>,
<&pcf8574 5 0>,
<&pcf8574 6 0>,
diff --git a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml
index b9a9f2cf32a1..07ccbda4a0ab 100644
--- a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml
+++ b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml
@@ -66,6 +66,7 @@ allOf:
compatible:
contains:
enum:
+ - qcom,qdu1000-llcc
- qcom,sc7180-llcc
- qcom,sm6350-llcc
then:
@@ -103,7 +104,6 @@ allOf:
compatible:
contains:
enum:
- - qcom,qdu1000-llcc
- qcom,sc8180x-llcc
- qcom,sc8280xp-llcc
- qcom,x1e80100-llcc
diff --git a/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml b/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml
index 624984d51c10..7f8d98226437 100644
--- a/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml
+++ b/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml
@@ -125,7 +125,7 @@ examples:
clk25m: clock-oscillator-25m {
compatible = "fixed-clock";
#clock-cells = <0>;
- clock-frequency = <25000000>;
+ clock-frequency = <25000000>;
clock-output-names = "clk25m";
};
...
diff --git a/Documentation/devicetree/bindings/clock/brcm,kona-ccu.txt b/Documentation/devicetree/bindings/clock/brcm,kona-ccu.txt
deleted file mode 100644
index 8e5a7d868557..000000000000
--- a/Documentation/devicetree/bindings/clock/brcm,kona-ccu.txt
+++ /dev/null
@@ -1,138 +0,0 @@
-Broadcom Kona Family Clocks
-
-This binding is associated with Broadcom SoCs having "Kona" style
-clock control units (CCUs). A CCU is a clock provider that manages
-a set of clock signals. Each CCU is represented by a node in the
-device tree.
-
-This binding uses the common clock binding:
- Documentation/devicetree/bindings/clock/clock-bindings.txt
-
-Required properties:
-- compatible
- Shall have a value of the form "brcm,<model>-<which>-ccu",
- where <model> is a Broadcom SoC model number and <which> is
- the name of a defined CCU. For example:
- "brcm,bcm11351-root-ccu"
- The compatible strings used for each supported SoC family
- are defined below.
-- reg
- Shall define the base and range of the address space
- containing clock control registers
-- #clock-cells
- Shall have value <1>. The permitted clock-specifier values
- are defined below.
-- clock-output-names
- Shall be an ordered list of strings defining the names of
- the clocks provided by the CCU.
-
-Device tree example:
-
- slave_ccu: slave_ccu {
- compatible = "brcm,bcm11351-slave-ccu";
- reg = <0x3e011000 0x0f00>;
- #clock-cells = <1>;
- clock-output-names = "uartb",
- "uartb2",
- "uartb3",
- "uartb4";
- };
-
- ref_crystal_clk: ref_crystal {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <26000000>;
- };
-
- uart@3e002000 {
- compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart";
- reg = <0x3e002000 0x1000>;
- clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>;
- interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
- reg-shift = <2>;
- reg-io-width = <4>;
- };
-
-BCM281XX family
----------------
-CCU compatible string values for SoCs in the BCM281XX family are:
- "brcm,bcm11351-root-ccu"
- "brcm,bcm11351-aon-ccu"
- "brcm,bcm11351-hub-ccu"
- "brcm,bcm11351-master-ccu"
- "brcm,bcm11351-slave-ccu"
-
-The following table defines the set of CCUs and clock specifiers for
-BCM281XX family clocks. When a clock consumer references a clocks,
-its symbolic specifier (rather than its numeric index value) should
-be used. These specifiers are defined in:
- "include/dt-bindings/clock/bcm281xx.h"
-
- CCU Clock Type Index Specifier
- --- ----- ---- ----- ---------
- root frac_1m peri 0 BCM281XX_ROOT_CCU_FRAC_1M
-
- aon hub_timer peri 0 BCM281XX_AON_CCU_HUB_TIMER
- aon pmu_bsc peri 1 BCM281XX_AON_CCU_PMU_BSC
- aon pmu_bsc_var peri 2 BCM281XX_AON_CCU_PMU_BSC_VAR
-
- hub tmon_1m peri 0 BCM281XX_HUB_CCU_TMON_1M
-
- master sdio1 peri 0 BCM281XX_MASTER_CCU_SDIO1
- master sdio2 peri 1 BCM281XX_MASTER_CCU_SDIO2
- master sdio3 peri 2 BCM281XX_MASTER_CCU_SDIO3
- master sdio4 peri 3 BCM281XX_MASTER_CCU_SDIO4
- master dmac peri 4 BCM281XX_MASTER_CCU_DMAC
- master usb_ic peri 5 BCM281XX_MASTER_CCU_USB_IC
- master hsic2_48m peri 6 BCM281XX_MASTER_CCU_HSIC_48M
- master hsic2_12m peri 7 BCM281XX_MASTER_CCU_HSIC_12M
-
- slave uartb peri 0 BCM281XX_SLAVE_CCU_UARTB
- slave uartb2 peri 1 BCM281XX_SLAVE_CCU_UARTB2
- slave uartb3 peri 2 BCM281XX_SLAVE_CCU_UARTB3
- slave uartb4 peri 3 BCM281XX_SLAVE_CCU_UARTB4
- slave ssp0 peri 4 BCM281XX_SLAVE_CCU_SSP0
- slave ssp2 peri 5 BCM281XX_SLAVE_CCU_SSP2
- slave bsc1 peri 6 BCM281XX_SLAVE_CCU_BSC1
- slave bsc2 peri 7 BCM281XX_SLAVE_CCU_BSC2
- slave bsc3 peri 8 BCM281XX_SLAVE_CCU_BSC3
- slave pwm peri 9 BCM281XX_SLAVE_CCU_PWM
-
-
-BCM21664 family
----------------
-CCU compatible string values for SoCs in the BCM21664 family are:
- "brcm,bcm21664-root-ccu"
- "brcm,bcm21664-aon-ccu"
- "brcm,bcm21664-master-ccu"
- "brcm,bcm21664-slave-ccu"
-
-The following table defines the set of CCUs and clock specifiers for
-BCM21664 family clocks. When a clock consumer references a clocks,
-its symbolic specifier (rather than its numeric index value) should
-be used. These specifiers are defined in:
- "include/dt-bindings/clock/bcm21664.h"
-
- CCU Clock Type Index Specifier
- --- ----- ---- ----- ---------
- root frac_1m peri 0 BCM21664_ROOT_CCU_FRAC_1M
-
- aon hub_timer peri 0 BCM21664_AON_CCU_HUB_TIMER
-
- master sdio1 peri 0 BCM21664_MASTER_CCU_SDIO1
- master sdio2 peri 1 BCM21664_MASTER_CCU_SDIO2
- master sdio3 peri 2 BCM21664_MASTER_CCU_SDIO3
- master sdio4 peri 3 BCM21664_MASTER_CCU_SDIO4
- master sdio1_sleep peri 4 BCM21664_MASTER_CCU_SDIO1_SLEEP
- master sdio2_sleep peri 5 BCM21664_MASTER_CCU_SDIO2_SLEEP
- master sdio3_sleep peri 6 BCM21664_MASTER_CCU_SDIO3_SLEEP
- master sdio4_sleep peri 7 BCM21664_MASTER_CCU_SDIO4_SLEEP
-
- slave uartb peri 0 BCM21664_SLAVE_CCU_UARTB
- slave uartb2 peri 1 BCM21664_SLAVE_CCU_UARTB2
- slave uartb3 peri 2 BCM21664_SLAVE_CCU_UARTB3
- slave uartb4 peri 3 BCM21664_SLAVE_CCU_UARTB4
- slave bsc1 peri 4 BCM21664_SLAVE_CCU_BSC1
- slave bsc2 peri 5 BCM21664_SLAVE_CCU_BSC2
- slave bsc3 peri 6 BCM21664_SLAVE_CCU_BSC3
- slave bsc4 peri 7 BCM21664_SLAVE_CCU_BSC4
diff --git a/Documentation/devicetree/bindings/clock/brcm,kona-ccu.yaml b/Documentation/devicetree/bindings/clock/brcm,kona-ccu.yaml
new file mode 100644
index 000000000000..e5656950b3bd
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/brcm,kona-ccu.yaml
@@ -0,0 +1,181 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/brcm,kona-ccu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Broadcom Kona family clock control units (CCU)
+
+maintainers:
+ - Florian Fainelli <[email protected]>
+ - Ray Jui <[email protected]>
+ - Scott Branden <[email protected]>
+
+description: |
+ Broadcom "Kona" style clock control unit (CCU) is a clock provider that
+ manages a set of clock signals.
+
+ All available clock IDs are defined in
+ - include/dt-bindings/clock/bcm281xx.h for BCM281XX family
+ - include/dt-bindings/clock/bcm21664.h for BCM21664 family
+
+properties:
+ compatible:
+ enum:
+ - brcm,bcm11351-aon-ccu
+ - brcm,bcm11351-hub-ccu
+ - brcm,bcm11351-master-ccu
+ - brcm,bcm11351-root-ccu
+ - brcm,bcm11351-slave-ccu
+ - brcm,bcm21664-aon-ccu
+ - brcm,bcm21664-master-ccu
+ - brcm,bcm21664-root-ccu
+ - brcm,bcm21664-slave-ccu
+
+ reg:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+
+ clock-output-names:
+ minItems: 1
+ maxItems: 10
+
+required:
+ - compatible
+ - reg
+ - '#clock-cells'
+ - clock-output-names
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: brcm,bcm11351-aon-ccu
+ then:
+ properties:
+ clock-output-names:
+ items:
+ - const: hub_timer
+ - const: pmu_bsc
+ - const: pmu_bsc_var
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: brcm,bcm11351-hub-ccu
+ then:
+ properties:
+ clock-output-names:
+ const: tmon_1m
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: brcm,bcm11351-master-ccu
+ then:
+ properties:
+ clock-output-names:
+ items:
+ - const: sdio1
+ - const: sdio2
+ - const: sdio3
+ - const: sdio4
+ - const: usb_ic
+ - const: hsic2_48m
+ - const: hsic2_12m
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - brcm,bcm11351-root-ccu
+ - brcm,bcm21664-root-ccu
+ then:
+ properties:
+ clock-output-names:
+ const: frac_1m
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: brcm,bcm11351-slave-ccu
+ then:
+ properties:
+ clock-output-names:
+ items:
+ - const: uartb
+ - const: uartb2
+ - const: uartb3
+ - const: uartb4
+ - const: ssp0
+ - const: ssp2
+ - const: bsc1
+ - const: bsc2
+ - const: bsc3
+ - const: pwm
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: brcm,bcm21664-aon-ccu
+ then:
+ properties:
+ clock-output-names:
+ const: hub_timer
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: brcm,bcm21664-master-ccu
+ then:
+ properties:
+ clock-output-names:
+ items:
+ - const: sdio1
+ - const: sdio2
+ - const: sdio3
+ - const: sdio4
+ - const: sdio1_sleep
+ - const: sdio2_sleep
+ - const: sdio3_sleep
+ - const: sdio4_sleep
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: brcm,bcm21664-slave-ccu
+ then:
+ properties:
+ clock-output-names:
+ items:
+ - const: uartb
+ - const: uartb2
+ - const: uartb3
+ - const: bsc1
+ - const: bsc2
+ - const: bsc3
+ - const: bsc4
+
+additionalProperties: false
+
+examples:
+ - |
+ clock-controller@3e011000 {
+ compatible = "brcm,bcm11351-slave-ccu";
+ reg = <0x3e011000 0x0f00>;
+ #clock-cells = <1>;
+ clock-output-names = "uartb",
+ "uartb2",
+ "uartb3",
+ "uartb4",
+ "ssp0",
+ "ssp2",
+ "bsc1",
+ "bsc2",
+ "bsc3",
+ "pwm";
+ };
+...
diff --git a/Documentation/devicetree/bindings/clock/fsl,imx93-anatop.yaml b/Documentation/devicetree/bindings/clock/fsl,imx93-anatop.yaml
new file mode 100644
index 000000000000..8a3b2476419a
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/fsl,imx93-anatop.yaml
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/fsl,imx93-anatop.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP i.MX93 ANATOP Clock Module
+
+maintainers:
+ - Peng Fan <[email protected]>
+
+description: |
+ NXP i.MX93 ANATOP module which contains PLL and OSC to Clock Controller
+ Module.
+
+properties:
+ compatible:
+ items:
+ - const: fsl,imx93-anatop
+
+ reg:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ clock-controller@44480000 {
+ compatible = "fsl,imx93-anatop";
+ reg = <0x44480000 0x2000>;
+ #clock-cells = <1>;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml b/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml
index 372c1d744bc2..685535846cbb 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml
@@ -22,6 +22,7 @@ properties:
- mediatek,mt7622-apmixedsys
- mediatek,mt7981-apmixedsys
- mediatek,mt7986-apmixedsys
+ - mediatek,mt7988-apmixedsys
- mediatek,mt8135-apmixedsys
- mediatek,mt8173-apmixedsys
- mediatek,mt8516-apmixedsys
diff --git a/Documentation/devicetree/bindings/clock/mediatek,ethsys.yaml b/Documentation/devicetree/bindings/clock/mediatek,ethsys.yaml
new file mode 100644
index 000000000000..f9cddacc2eae
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mediatek,ethsys.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/mediatek,ethsys.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek ethsys controller
+
+description:
+ The available clocks are defined in dt-bindings/clock/mt*-clk.h.
+
+maintainers:
+ - James Liao <[email protected]>
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - mediatek,mt2701-ethsys
+ - mediatek,mt7622-ethsys
+ - mediatek,mt7629-ethsys
+ - mediatek,mt7981-ethsys
+ - mediatek,mt7986-ethsys
+ - mediatek,mt7988-ethsys
+ - const: syscon
+ - items:
+ - const: mediatek,mt7623-ethsys
+ - const: mediatek,mt2701-ethsys
+ - const: syscon
+
+ reg:
+ maxItems: 1
+
+ "#clock-cells":
+ const: 1
+
+ "#reset-cells":
+ const: 1
+
+required:
+ - reg
+ - "#clock-cells"
+ - "#reset-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ clock-controller@1b000000 {
+ compatible = "mediatek,mt2701-ethsys", "syscon";
+ reg = <0x1b000000 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7988-ethwarp.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7988-ethwarp.yaml
new file mode 100644
index 000000000000..e32a0251ff6a
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt7988-ethwarp.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/mediatek,mt7988-ethwarp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT7988 ethwarp Controller
+
+maintainers:
+ - Daniel Golle <[email protected]>
+
+description:
+ The Mediatek MT7988 ethwarp controller provides clocks and resets for the
+ Ethernet related subsystems found the MT7988 SoC.
+ The clock values can be found in <dt-bindings/clock/mt*-clk.h>.
+
+properties:
+ compatible:
+ items:
+ - const: mediatek,mt7988-ethwarp
+
+ reg:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+
+ '#reset-cells':
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - '#clock-cells'
+ - '#reset-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/reset/ti-syscon.h>
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ clock-controller@15031000 {
+ compatible = "mediatek,mt7988-ethwarp";
+ reg = <0 0x15031000 0 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7988-xfi-pll.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7988-xfi-pll.yaml
new file mode 100644
index 000000000000..192f1451f0af
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mediatek,mt7988-xfi-pll.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/mediatek,mt7988-xfi-pll.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT7988 XFI PLL Clock Controller
+
+maintainers:
+ - Daniel Golle <[email protected]>
+
+description:
+ The MediaTek XFI PLL controller provides the 156.25MHz clock for the
+ Ethernet SerDes PHY from the 40MHz top_xtal clock.
+
+properties:
+ compatible:
+ const: mediatek,mt7988-xfi-pll
+
+ reg:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - resets
+ - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ clock-controller@11f40000 {
+ compatible = "mediatek,mt7988-xfi-pll";
+ reg = <0 0x11f40000 0 0x1000>;
+ resets = <&watchdog 16>;
+ #clock-cells = <1>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml b/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml
index 6d087ded7437..bdf3b55bd56f 100644
--- a/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml
+++ b/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml
@@ -37,6 +37,8 @@ properties:
- mediatek,mt7629-topckgen
- mediatek,mt7981-topckgen
- mediatek,mt7986-topckgen
+ - mediatek,mt7988-mcusys
+ - mediatek,mt7988-topckgen
- mediatek,mt8167-topckgen
- mediatek,mt8183-topckgen
- const: syscon
diff --git a/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml b/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml
index 9436266828af..5ca927a8b1d5 100644
--- a/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml
@@ -16,6 +16,7 @@ description:
properties:
compatible:
enum:
+ - qcom,ipq5018-a53pll
- qcom,ipq5332-a53pll
- qcom,ipq6018-a53pll
- qcom,ipq8074-a53pll
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-ipq6018.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-ipq6018.yaml
new file mode 100644
index 000000000000..af5d883cfdc8
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc-ipq6018.yaml
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,gcc-ipq6018.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Global Clock & Reset Controller on IPQ6018
+
+maintainers:
+ - Stephen Boyd <[email protected]>
+ - Taniya Das <[email protected]>
+ - Robert Marko <[email protected]>
+
+description: |
+ Qualcomm global clock control module provides the clocks, resets and power
+ domains on IPQ6018.
+
+ See also::
+ include/dt-bindings/clock/qcom,gcc-ipq6018.h
+ include/dt-bindings/reset/qcom,gcc-ipq6018.h
+
+allOf:
+ - $ref: qcom,gcc.yaml#
+
+properties:
+ compatible:
+ const: qcom,gcc-ipq6018
+
+ clocks:
+ items:
+ - description: board XO clock
+ - description: sleep clock
+
+ clock-names:
+ items:
+ - const: xo
+ - const: sleep_clk
+
+required:
+ - compatible
+ - clocks
+ - clock-names
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ clock-controller@1800000 {
+ compatible = "qcom,gcc-ipq6018";
+ reg = <0x01800000 0x80000>;
+ clocks = <&xo>, <&sleep_clk>;
+ clock-names = "xo", "sleep_clk";
+ #clock-cells = <1>;
+ #power-domain-cells = <1>;
+ #reset-cells = <1>;
+ };
+...
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml
index 559fc21435c8..7d05f0f63cef 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml
@@ -15,8 +15,6 @@ description: |
domains.
See also::
- include/dt-bindings/clock/qcom,gcc-ipq6018.h
- include/dt-bindings/reset/qcom,gcc-ipq6018.h
include/dt-bindings/clock/qcom,gcc-msm8953.h
include/dt-bindings/clock/qcom,gcc-mdm9607.h
@@ -26,7 +24,6 @@ allOf:
properties:
compatible:
enum:
- - qcom,gcc-ipq6018
- qcom,gcc-mdm9607
required:
diff --git a/Documentation/devicetree/bindings/clock/qcom,qdu1000-ecpricc.yaml b/Documentation/devicetree/bindings/clock/qcom,qdu1000-ecpricc.yaml
new file mode 100644
index 000000000000..fd21df0e7697
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,qdu1000-ecpricc.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,qdu1000-ecpricc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm ECPRI Clock & Reset Controller for QDU1000 and QRU1000
+
+maintainers:
+ - Taniya Das <[email protected]>
+ - Imran Shaik <[email protected]>
+
+description: |
+ Qualcomm ECPRI Specification V2.0 Common Public Radio Interface clock control
+ module which supports the clocks, resets on QDU1000 and QRU1000
+
+ See also:: include/dt-bindings/clock/qcom,qdu1000-ecpricc.h
+
+properties:
+ compatible:
+ enum:
+ - qcom,qdu1000-ecpricc
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Board XO source
+ - description: GPLL0 source from GCC
+ - description: GPLL1 source from GCC
+ - description: GPLL2 source from GCC
+ - description: GPLL3 source from GCC
+ - description: GPLL4 source from GCC
+ - description: GPLL5 source from GCC
+
+ '#clock-cells':
+ const: 1
+
+ '#reset-cells':
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - '#clock-cells'
+ - '#reset-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,qdu1000-gcc.h>
+ #include <dt-bindings/clock/qcom,rpmh.h>
+ clock-controller@280000 {
+ compatible = "qcom,qdu1000-ecpricc";
+ reg = <0x00280000 0x31c00>;
+ clocks = <&rpmhcc RPMH_CXO_CLK>,
+ <&gcc GCC_ECPRI_CC_GPLL0_CLK_SRC>,
+ <&gcc GCC_ECPRI_CC_GPLL1_EVEN_CLK_SRC>,
+ <&gcc GCC_ECPRI_CC_GPLL2_EVEN_CLK_SRC>,
+ <&gcc GCC_ECPRI_CC_GPLL3_CLK_SRC>,
+ <&gcc GCC_ECPRI_CC_GPLL4_CLK_SRC>,
+ <&gcc GCC_ECPRI_CC_GPLL5_EVEN_CLK_SRC>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/renesas,9series.yaml b/Documentation/devicetree/bindings/clock/renesas,9series.yaml
index 3afdebdb52ad..af6319697b1c 100644
--- a/Documentation/devicetree/bindings/clock/renesas,9series.yaml
+++ b/Documentation/devicetree/bindings/clock/renesas,9series.yaml
@@ -21,6 +21,15 @@ description: |
1 -- DIF1
2 -- DIF2
3 -- DIF3
+ - 9FGV0841:
+ 0 -- DIF0
+ 1 -- DIF1
+ 2 -- DIF2
+ 3 -- DIF3
+ 4 -- DIF4
+ 5 -- DIF5
+ 6 -- DIF6
+ 7 -- DIF7
maintainers:
- Marek Vasut <[email protected]>
@@ -30,6 +39,7 @@ properties:
enum:
- renesas,9fgv0241
- renesas,9fgv0441
+ - renesas,9fgv0841
reg:
description: I2C device address
diff --git a/Documentation/devicetree/bindings/clock/silabs,si5351.txt b/Documentation/devicetree/bindings/clock/silabs,si5351.txt
deleted file mode 100644
index bfda6af76bee..000000000000
--- a/Documentation/devicetree/bindings/clock/silabs,si5351.txt
+++ /dev/null
@@ -1,126 +0,0 @@
-Binding for Silicon Labs Si5351a/b/c programmable i2c clock generator.
-
-Reference
-[1] Si5351A/B/C Data Sheet
- https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/Si5351-B.pdf
-
-The Si5351a/b/c are programmable i2c clock generators with up to 8 output
-clocks. Si5351a also has a reduced pin-count package (MSOP10) where only
-3 output clocks are accessible. The internal structure of the clock
-generators can be found in [1].
-
-==I2C device node==
-
-Required properties:
-- compatible: shall be one of the following:
- "silabs,si5351a" - Si5351a, QFN20 package
- "silabs,si5351a-msop" - Si5351a, MSOP10 package
- "silabs,si5351b" - Si5351b, QFN20 package
- "silabs,si5351c" - Si5351c, QFN20 package
-- reg: i2c device address, shall be 0x60 or 0x61.
-- #clock-cells: from common clock binding; shall be set to 1.
-- clocks: from common clock binding; list of parent clock
- handles, shall be xtal reference clock or xtal and clkin for
- si5351c only. Corresponding clock input names are "xtal" and
- "clkin" respectively.
-- #address-cells: shall be set to 1.
-- #size-cells: shall be set to 0.
-
-Optional properties:
-- silabs,pll-source: pair of (number, source) for each pll. Allows
- to overwrite clock source of pll A (number=0) or B (number=1).
-
-==Child nodes==
-
-Each of the clock outputs can be overwritten individually by
-using a child node to the I2C device node. If a child node for a clock
-output is not set, the eeprom configuration is not overwritten.
-
-Required child node properties:
-- reg: number of clock output.
-
-Optional child node properties:
-- silabs,clock-source: source clock of the output divider stage N, shall be
- 0 = multisynth N
- 1 = multisynth 0 for output clocks 0-3, else multisynth4
- 2 = xtal
- 3 = clkin (si5351c only)
-- silabs,drive-strength: output drive strength in mA, shall be one of {2,4,6,8}.
-- silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth
- divider.
-- silabs,pll-master: boolean, multisynth can change pll frequency.
-- silabs,pll-reset: boolean, clock output can reset its pll.
-- silabs,disable-state : clock output disable state, shall be
- 0 = clock output is driven LOW when disabled
- 1 = clock output is driven HIGH when disabled
- 2 = clock output is FLOATING (HIGH-Z) when disabled
- 3 = clock output is NEVER disabled
-
-==Example==
-
-/* 25MHz reference crystal */
-ref25: ref25M {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <25000000>;
-};
-
-i2c-master-node {
-
- /* Si5351a msop10 i2c clock generator */
- si5351a: clock-generator@60 {
- compatible = "silabs,si5351a-msop";
- reg = <0x60>;
- #address-cells = <1>;
- #size-cells = <0>;
- #clock-cells = <1>;
-
- /* connect xtal input to 25MHz reference */
- clocks = <&ref25>;
- clock-names = "xtal";
-
- /* connect xtal input as source of pll0 and pll1 */
- silabs,pll-source = <0 0>, <1 0>;
-
- /*
- * overwrite clkout0 configuration with:
- * - 8mA output drive strength
- * - pll0 as clock source of multisynth0
- * - multisynth0 as clock source of output divider
- * - multisynth0 can change pll0
- * - set initial clock frequency of 74.25MHz
- */
- clkout0 {
- reg = <0>;
- silabs,drive-strength = <8>;
- silabs,multisynth-source = <0>;
- silabs,clock-source = <0>;
- silabs,pll-master;
- clock-frequency = <74250000>;
- };
-
- /*
- * overwrite clkout1 configuration with:
- * - 4mA output drive strength
- * - pll1 as clock source of multisynth1
- * - multisynth1 as clock source of output divider
- * - multisynth1 can change pll1
- */
- clkout1 {
- reg = <1>;
- silabs,drive-strength = <4>;
- silabs,multisynth-source = <1>;
- silabs,clock-source = <0>;
- pll-master;
- };
-
- /*
- * overwrite clkout2 configuration with:
- * - xtal as clock source of output divider
- */
- clkout2 {
- reg = <2>;
- silabs,clock-source = <2>;
- };
- };
-};
diff --git a/Documentation/devicetree/bindings/clock/silabs,si5351.yaml b/Documentation/devicetree/bindings/clock/silabs,si5351.yaml
new file mode 100644
index 000000000000..d3e0ec29993b
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/silabs,si5351.yaml
@@ -0,0 +1,265 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/silabs,si5351.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Silicon Labs Si5351A/B/C programmable I2C clock generators
+
+description: |
+ The Silicon Labs Si5351A/B/C are programmable I2C clock generators with up to
+ 8 outputs. Si5351A also has a reduced pin-count package (10-MSOP) where only 3
+ output clocks are accessible. The internal structure of the clock generators
+ can be found in [1].
+
+ [1] Si5351A/B/C Data Sheet
+ https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/Si5351-B.pdf
+
+maintainers:
+ - Alvin Å ipraga <[email protected]>
+
+properties:
+ compatible:
+ enum:
+ - silabs,si5351a # Si5351A, 20-QFN package
+ - silabs,si5351a-msop # Si5351A, 10-MSOP package
+ - silabs,si5351b # Si5351B, 20-QFN package
+ - silabs,si5351c # Si5351C, 20-QFN package
+
+ reg:
+ enum:
+ - 0x60
+ - 0x61
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ "#clock-cells":
+ const: 1
+
+ clocks:
+ minItems: 1
+ maxItems: 2
+
+ clock-names:
+ minItems: 1
+ items:
+ - const: xtal
+ - const: clkin
+
+ silabs,pll-source:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ description: |
+ A list of cell pairs containing a PLL index and its source. Allows to
+ overwrite clock source of the internal PLLs.
+ items:
+ items:
+ - description: PLL A (0) or PLL B (1)
+ enum: [ 0, 1 ]
+ - description: PLL source, XTAL (0) or CLKIN (1, Si5351C only).
+ enum: [ 0, 1 ]
+
+ silabs,pll-reset-mode:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ minItems: 1
+ maxItems: 2
+ description: A list of cell pairs containing a PLL index and its reset mode.
+ items:
+ items:
+ - description: PLL A (0) or PLL B (1)
+ enum: [ 0, 1 ]
+ - description: |
+ Reset mode for the PLL. Mode can be one of:
+
+ 0 - reset whenever PLL rate is adjusted (default mode)
+ 1 - do not reset when PLL rate is adjusted
+
+ In mode 1, the PLL is only reset if the silabs,pll-reset is
+ specified in one of the clock output child nodes that also sources
+ the PLL. This mode may be preferable if output clocks are expected
+ to be adjusted without glitches.
+ enum: [ 0, 1 ]
+
+patternProperties:
+ "^clkout@[0-7]$":
+ type: object
+
+ additionalProperties: false
+
+ properties:
+ reg:
+ description: Clock output number.
+
+ clock-frequency: true
+
+ silabs,clock-source:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ Source clock of the this output's divider stage.
+
+ 0 - use multisynth N for this output, where N is the output number
+ 1 - use either multisynth 0 (if output number is 0-3) or multisynth 4
+ (otherwise) for this output
+ 2 - use XTAL for this output
+ 3 - use CLKIN for this output (Si5351C only)
+
+ silabs,drive-strength:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [ 2, 4, 6, 8 ]
+ description: Output drive strength in mA.
+
+ silabs,multisynth-source:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [ 0, 1 ]
+ description:
+ Source PLL A (0) or B (1) for the corresponding multisynth divider.
+
+ silabs,pll-master:
+ type: boolean
+ description: |
+ The frequency of the source PLL is allowed to be changed by the
+ multisynth when setting the rate of this clock output.
+
+ silabs,pll-reset:
+ type: boolean
+ description: Reset the source PLL when enabling this clock output.
+
+ silabs,disable-state:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [ 0, 1, 2, 3 ]
+ description: |
+ Clock output disable state. The state can be one of:
+
+ 0 - clock output is driven LOW when disabled
+ 1 - clock output is driven HIGH when disabled
+ 2 - clock output is FLOATING (HIGH-Z) when disabled
+ 3 - clock output is never disabled
+
+ allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: silabs,si5351a-msop
+ then:
+ properties:
+ reg:
+ maximum: 2
+ else:
+ properties:
+ reg:
+ maximum: 7
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: silabs,si5351c
+ then:
+ properties:
+ silabs,clock-source:
+ enum: [ 0, 1, 2, 3 ]
+ else:
+ properties:
+ silabs,clock-source:
+ enum: [ 0, 1, 2 ]
+
+ required:
+ - reg
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - silabs,si5351a
+ - silabs,si5351a-msop
+ - silabs,si5351b
+ then:
+ properties:
+ clocks:
+ maxItems: 1
+ clock-names:
+ maxItems: 1
+
+required:
+ - reg
+ - "#address-cells"
+ - "#size-cells"
+ - "#clock-cells"
+ - clocks
+ - clock-names
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ clock-generator@60 {
+ compatible = "silabs,si5351a-msop";
+ reg = <0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #clock-cells = <1>;
+
+ /* Connect XTAL input to 25MHz reference */
+ clocks = <&ref25>;
+ clock-names = "xtal";
+
+ /* Use XTAL input as source of PLL0 and PLL1 */
+ silabs,pll-source = <0 0>, <1 0>;
+
+ /* Don't reset PLL1 on rate adjustment */
+ silabs,pll-reset-mode = <1 1>;
+
+ /*
+ * Overwrite CLK0 configuration with:
+ * - 8 mA output drive strength
+ * - PLL0 as clock source of multisynth 0
+ * - Multisynth 0 as clock source of output divider
+ * - Multisynth 0 can change PLL0
+ * - Set initial clock frequency of 74.25MHz
+ */
+ clkout@0 {
+ reg = <0>;
+ silabs,drive-strength = <8>;
+ silabs,multisynth-source = <0>;
+ silabs,clock-source = <0>;
+ silabs,pll-master;
+ clock-frequency = <74250000>;
+ };
+
+ /*
+ * Overwrite CLK1 configuration with:
+ * - 4 mA output drive strength
+ * - PLL1 as clock source of multisynth 1
+ * - Multisynth 1 as clock source of output divider
+ * - Multisynth 1 can change PLL1
+ * - Reset PLL1 when enabling this clock output
+ */
+ clkout@1 {
+ reg = <1>;
+ silabs,drive-strength = <4>;
+ silabs,multisynth-source = <1>;
+ silabs,clock-source = <0>;
+ silabs,pll-master;
+ silabs,pll-reset;
+ };
+
+ /*
+ * Overwrite CLK2 configuration with:
+ * - XTAL as clock source of output divider
+ */
+ clkout@2 {
+ reg = <2>;
+ silabs,clock-source = <2>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/clock/sophgo,cv1800-clk.yaml b/Documentation/devicetree/bindings/clock/sophgo,cv1800-clk.yaml
new file mode 100644
index 000000000000..c1dc24673c0d
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sophgo,cv1800-clk.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/sophgo,cv1800-clk.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sophgo CV1800 Series Clock Controller
+
+maintainers:
+ - Inochi Amaoto <[email protected]>
+
+properties:
+ compatible:
+ enum:
+ - sophgo,cv1800-clk
+ - sophgo,cv1810-clk
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ "#clock-cells":
+ const: 1
+ description:
+ See <dt-bindings/clock/sophgo,cv1800.h> for valid indices.
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - "#clock-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ clock-controller@3002000 {
+ compatible = "sophgo,cv1800-clk";
+ reg = <0x03002000 0x1000>;
+ clocks = <&osc>;
+ #clock-cells = <1>;
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml
new file mode 100644
index 000000000000..7732e79a42b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/st,stm32mp25-rcc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STM32MP25 Reset Clock Controller
+
+maintainers:
+ - Gabriel Fernandez <[email protected]>
+
+description: |
+ The RCC hardware block is both a reset and a clock controller.
+ RCC makes also power management (resume/supend).
+
+ See also::
+ include/dt-bindings/clock/st,stm32mp25-rcc.h
+ include/dt-bindings/reset/st,stm32mp25-rcc.h
+
+properties:
+ compatible:
+ enum:
+ - st,stm32mp25-rcc
+
+ reg:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+
+ '#reset-cells':
+ const: 1
+
+ clocks:
+ items:
+ - description: CK_SCMI_HSE High Speed External oscillator (8 to 48 MHz)
+ - description: CK_SCMI_HSI High Speed Internal oscillator (~ 64 MHz)
+ - description: CK_SCMI_MSI Low Power Internal oscillator (~ 4 MHz or ~ 16 MHz)
+ - description: CK_SCMI_LSE Low Speed External oscillator (32 KHz)
+ - description: CK_SCMI_LSI Low Speed Internal oscillator (~ 32 KHz)
+
+ clock-names:
+ items:
+ - const: hse
+ - const: hsi
+ - const: msi
+ - const: lse
+ - const: lsi
+
+required:
+ - compatible
+ - reg
+ - '#clock-cells'
+ - '#reset-cells'
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/st,stm32mp25-rcc.h>
+
+ rcc: clock-controller@44200000 {
+ compatible = "st,stm32mp25-rcc";
+ reg = <0x44200000 0x10000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ clock-names = "hse", "hsi", "msi", "lse", "lsi";
+ clocks = <&scmi_clk CK_SCMI_HSE>,
+ <&scmi_clk CK_SCMI_HSI>,
+ <&scmi_clk CK_SCMI_MSI>,
+ <&scmi_clk CK_SCMI_LSE>,
+ <&scmi_clk CK_SCMI_LSI>;
+ };
+...
diff --git a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml
index 02bd556bd91a..9d5324dc1027 100644
--- a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml
+++ b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml
@@ -20,6 +20,7 @@ properties:
- xlnx,clocking-wizard
- xlnx,clocking-wizard-v5.2
- xlnx,clocking-wizard-v6.0
+ - xlnx,versal-clk-wizard
reg:
diff --git a/Documentation/devicetree/bindings/clock/xlnx,versal-clk.yaml b/Documentation/devicetree/bindings/clock/xlnx,versal-clk.yaml
index 1ba687d433b1..bef109d163a8 100644
--- a/Documentation/devicetree/bindings/clock/xlnx,versal-clk.yaml
+++ b/Documentation/devicetree/bindings/clock/xlnx,versal-clk.yaml
@@ -31,11 +31,11 @@ properties:
clocks:
description: List of clock specifiers which are external input
clocks to the given clock controller.
- minItems: 3
+ minItems: 2
maxItems: 8
clock-names:
- minItems: 3
+ minItems: 2
maxItems: 8
required:
@@ -59,13 +59,11 @@ allOf:
clocks:
items:
- description: reference clock
- - description: alternate reference clock
- description: alternate reference clock for programmable logic
clock-names:
items:
- const: ref
- - const: alt_ref
- const: pl_alt_ref
- if:
@@ -73,6 +71,27 @@ allOf:
compatible:
contains:
enum:
+ - xlnx,versal-net-clk
+
+ then:
+ properties:
+ clocks:
+ items:
+ - description: reference clock
+ - description: alternate reference clock for programmable logic
+ - description: alternate reference clock
+
+ clock-names:
+ items:
+ - const: ref
+ - const: pl_alt_ref
+ - const: alt_ref
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
- xlnx,zynqmp-clk
then:
@@ -110,8 +129,8 @@ examples:
versal_clk: clock-controller {
#clock-cells = <1>;
compatible = "xlnx,versal-clk";
- clocks = <&ref>, <&alt_ref>, <&pl_alt_ref>;
- clock-names = "ref", "alt_ref", "pl_alt_ref";
+ clocks = <&ref>, <&pl_alt_ref>;
+ clock-names = "ref", "pl_alt_ref";
};
};
};
diff --git a/Documentation/devicetree/bindings/connector/usb-connector.yaml b/Documentation/devicetree/bindings/connector/usb-connector.yaml
index 7c8a3e8430d3..fb216ce68bb3 100644
--- a/Documentation/devicetree/bindings/connector/usb-connector.yaml
+++ b/Documentation/devicetree/bindings/connector/usb-connector.yaml
@@ -66,7 +66,6 @@ properties:
Particularly, if use an output GPIO to control a VBUS regulator, should
model it as a regulator. See bindings/regulator/fixed-regulator.yaml
- # The following are optional properties for "usb-c-connector".
power-role:
description: Determines the power role that the Type C connector will
support. "dual" refers to Dual Role Port (DRP).
@@ -119,30 +118,6 @@ properties:
# The following are optional properties for "usb-c-connector" with power
# delivery support.
- source-pdos:
- description: An array of u32 with each entry providing supported power
- source data object(PDO), the detailed bit definitions of PDO can be found
- in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2
- Source_Capabilities Message, the order of each entry(PDO) should follow
- the PD spec chapter 6.4.1. Required for power source and power dual role.
- User can specify the source PDO array via PDO_FIXED/BATT/VAR/PPS_APDO()
- defined in dt-bindings/usb/pd.h.
- minItems: 1
- maxItems: 7
- $ref: /schemas/types.yaml#/definitions/uint32-array
-
- sink-pdos:
- description: An array of u32 with each entry providing supported power sink
- data object(PDO), the detailed bit definitions of PDO can be found in
- "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3
- Sink Capabilities Message, the order of each entry(PDO) should follow the
- PD spec chapter 6.4.1. Required for power sink and power dual role. User
- can specify the sink PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() defined
- in dt-bindings/usb/pd.h.
- minItems: 1
- maxItems: 7
- $ref: /schemas/types.yaml#/definitions/uint32-array
-
sink-vdos:
description: An array of u32 with each entry, a Vendor Defined Message Object (VDO),
providing additional information corresponding to the product, the detailed bit
@@ -166,10 +141,43 @@ properties:
maxItems: 6
$ref: /schemas/types.yaml#/definitions/uint32-array
- op-sink-microwatt:
- description: Sink required operating power in microwatt, if source can't
- offer the power, Capability Mismatch is set. Required for power sink and
- power dual role.
+ accessory-mode-audio:
+ type: boolean
+ description: Whether the device supports Audio Adapter Accessory Mode. This
+ is only necessary if there are no other means to discover supported
+ alternative modes (e.g. through the UCSI firmware interface).
+
+ accessory-mode-debug:
+ type: boolean
+ description: Whether the device supports Debug Accessory Mode. This
+ is only necessary if there are no other means to discover supported
+ alternative modes (e.g. through the UCSI firmware interface).
+
+ altmodes:
+ type: object
+ description: List of Alternative Modes supported by the schematics on the
+ particular device. This is only necessary if there are no other means to
+ discover supported alternative modes (e.g. through the UCSI firmware
+ interface).
+
+ additionalProperties: false
+
+ patternProperties:
+ "^(displayport)$":
+ type: object
+ description:
+ A single USB-C Alternative Mode as supported by the USB-C connector logic.
+
+ additionalProperties: false
+
+ properties:
+ svid:
+ $ref: /schemas/types.yaml#/definitions/uint16
+ description: Unique value assigned by USB-IF to the Vendor / AltMode.
+ enum: [ 0xff01 ]
+ vdo:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: VDO returned by Discover Modes USB PD command.
port:
$ref: /schemas/graph.yaml#/properties/port
@@ -231,6 +239,20 @@ properties:
SNK_READY for non-pd link.
type: boolean
+ capabilities:
+ description: A child node to contain all the selectable USB Power Delivery capabilities.
+ type: object
+
+ patternProperties:
+ "^caps-[0-9]+$":
+ description: Child nodes under "capabilities" node. Each node contains a selectable USB
+ Power Delivery capability.
+ type: object
+ $ref: "#/$defs/capabilities"
+ unevaluatedProperties: false
+
+ additionalProperties: false
+
dependencies:
sink-vdos-v1: [ sink-vdos ]
sink-vdos: [ sink-vdos-v1 ]
@@ -238,7 +260,42 @@ dependencies:
required:
- compatible
+$defs:
+ capabilities:
+ type: object
+
+ properties:
+ source-pdos:
+ description: An array of u32 with each entry providing supported power
+ source data object(PDO), the detailed bit definitions of PDO can be found
+ in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2
+ Source_Capabilities Message, the order of each entry(PDO) should follow
+ the PD spec chapter 6.4.1. Required for power source and power dual role.
+ User can specify the source PDO array via PDO_FIXED/BATT/VAR/PPS_APDO()
+ defined in dt-bindings/usb/pd.h.
+ minItems: 1
+ maxItems: 7
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+
+ sink-pdos:
+ description: An array of u32 with each entry providing supported power sink
+ data object(PDO), the detailed bit definitions of PDO can be found in
+ "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3
+ Sink Capabilities Message, the order of each entry(PDO) should follow the
+ PD spec chapter 6.4.1. Required for power sink and power dual role. User
+ can specify the sink PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() defined
+ in dt-bindings/usb/pd.h.
+ minItems: 1
+ maxItems: 7
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+
+ op-sink-microwatt:
+ description: Sink required operating power in microwatt, if source can't
+ offer the power, Capability Mismatch is set. Required for power sink and
+ power dual role.
+
allOf:
+ - $ref: "#/$defs/capabilities"
- if:
properties:
compatible:
@@ -267,7 +324,7 @@ anyOf:
- typec-power-opmode
- new-source-frs-typec-current
-additionalProperties: false
+unevaluatedProperties: false
examples:
# Micro-USB connector with HS lines routed via controller (MUIC).
@@ -289,6 +346,13 @@ examples:
compatible = "usb-c-connector";
label = "USB-C";
+ altmodes {
+ displayport {
+ svid = /bits/ 16 <0xff01>;
+ vdo = <0x00001c46>;
+ };
+ };
+
ports {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/Documentation/devicetree/bindings/cpu/idle-states.yaml b/Documentation/devicetree/bindings/cpu/idle-states.yaml
index b3a5356f9916..239480ef7c30 100644
--- a/Documentation/devicetree/bindings/cpu/idle-states.yaml
+++ b/Documentation/devicetree/bindings/cpu/idle-states.yaml
@@ -243,7 +243,64 @@ description: |+
just supports idle_standby, an idle-states node is not required.
===========================================
- 6 - References
+ 6 - Qualcomm specific STATES
+ ===========================================
+
+ Idle states have different enter/exit latency and residency values.
+ The idle states supported by the QCOM SoC are defined as -
+
+ * Standby
+ * Retention
+ * Standalone Power Collapse (Standalone PC or SPC)
+ * Power Collapse (PC)
+
+ Standby: Standby does a little more in addition to architectural clock gating.
+ When the WFI instruction is executed the ARM core would gate its internal
+ clocks. In addition to gating the clocks, QCOM cpus use this instruction as a
+ trigger to execute the SPM state machine. The SPM state machine waits for the
+ interrupt to trigger the core back in to active. This triggers the cache
+ hierarchy to enter standby states, when all cpus are idle. An interrupt brings
+ the SPM state machine out of its wait, the next step is to ensure that the
+ cache hierarchy is also out of standby, and then the cpu is allowed to resume
+ execution. This state is defined as a generic ARM WFI state by the ARM cpuidle
+ driver and is not defined in the DT. The SPM state machine should be
+ configured to execute this state by default and after executing every other
+ state below.
+
+ Retention: Retention is a low power state where the core is clock gated and
+ the memory and the registers associated with the core are retained. The
+ voltage may be reduced to the minimum value needed to keep the processor
+ registers active. The SPM should be configured to execute the retention
+ sequence and would wait for interrupt, before restoring the cpu to execution
+ state. Retention may have a slightly higher latency than Standby.
+
+ Standalone PC: A cpu can power down and warmboot if there is a sufficient time
+ between the time it enters idle and the next known wake up. SPC mode is used
+ to indicate a core entering a power down state without consulting any other
+ cpu or the system resources. This helps save power only on that core. The SPM
+ sequence for this idle state is programmed to power down the supply to the
+ core, wait for the interrupt, restore power to the core, and ensure the
+ system state including cache hierarchy is ready before allowing core to
+ resume. Applying power and resetting the core causes the core to warmboot
+ back into Elevation Level (EL) which trampolines the control back to the
+ kernel. Entering a power down state for the cpu, needs to be done by trapping
+ into a EL. Failing to do so, would result in a crash enforced by the warm boot
+ code in the EL for the SoC. On SoCs with write-back L1 cache, the cache has to
+ be flushed in s/w, before powering down the core.
+
+ Power Collapse: This state is similar to the SPC mode, but distinguishes
+ itself in that the cpu acknowledges and permits the SoC to enter deeper sleep
+ modes. In a hierarchical power domain SoC, this means L2 and other caches can
+ be flushed, system bus, clocks - lowered, and SoC main XO clock gated and
+ voltages reduced, provided all cpus enter this state. Since the span of low
+ power modes possible at this state is vast, the exit latency and the residency
+ of this low power mode would be considered high even though at a cpu level,
+ this essentially is cpu power down. The SPM in this state also may handshake
+ with the Resource power manager (RPM) processor in the SoC to indicate a
+ complete application processor subsystem shut down.
+
+ ===========================================
+ 7 - References
===========================================
[1] ARM Linux Kernel documentation - CPUs bindings
@@ -301,9 +358,16 @@ patternProperties:
properties:
compatible:
- enum:
- - arm,idle-state
- - riscv,idle-state
+ oneOf:
+ - items:
+ - enum:
+ - qcom,idle-state-ret
+ - qcom,idle-state-spc
+ - qcom,idle-state-pc
+ - const: arm,idle-state
+ - enum:
+ - arm,idle-state
+ - riscv,idle-state
arm,psci-suspend-param:
$ref: /schemas/types.yaml#/definitions/uint32
@@ -852,4 +916,13 @@ examples:
};
};
+ // Example 4 - Qualcomm SPC
+ idle-states {
+ cpu_spc: cpu-spc {
+ compatible = "qcom,idle-state-spc", "arm,idle-state";
+ entry-latency-us = <150>;
+ exit-latency-us = <200>;
+ min-residency-us = <2000>;
+ };
+ };
...
diff --git a/Documentation/devicetree/bindings/display/panel/synaptics,r63353.yaml b/Documentation/devicetree/bindings/display/panel/synaptics,r63353.yaml
new file mode 100644
index 000000000000..e5617d125567
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/synaptics,r63353.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/synaptics,r63353.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synaptics R63353 based MIPI-DSI panels
+
+maintainers:
+ - Michael Trimarchi <[email protected]>
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - sharp,ls068b3sx02
+ - const: syna,r63353
+
+ avdd-supply: true
+ dvdd-supply: true
+ reg: true
+
+required:
+ - compatible
+ - avdd-supply
+ - dvdd-supply
+ - reg
+ - reset-gpios
+ - port
+ - backlight
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel@0 {
+ compatible = "sharp,ls068b3sx02", "syna,r63353";
+ reg = <0>;
+ avdd-supply = <&avdd_display>;
+ dvdd-supply = <&dvdd_display>;
+ reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL05 */
+ backlight = <&backlight>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&mipi_dsi_out>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt
deleted file mode 100644
index cec21714f0e0..000000000000
--- a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt
+++ /dev/null
@@ -1,49 +0,0 @@
-Rockchip specific extensions to the Innosilicon HDMI
-================================
-
-Required properties:
-- compatible:
- "rockchip,rk3036-inno-hdmi";
-- reg:
- Physical base address and length of the controller's registers.
-- clocks, clock-names:
- Phandle to hdmi controller clock, name should be "pclk"
-- interrupts:
- HDMI interrupt number
-- ports:
- Contain one port node with endpoint definitions as defined in
- Documentation/devicetree/bindings/graph.txt.
-- pinctrl-0, pinctrl-name:
- Switch the iomux of HPD/CEC pins to HDMI function.
-
-Example:
-hdmi: hdmi@20034000 {
- compatible = "rockchip,rk3036-inno-hdmi";
- reg = <0x20034000 0x4000>;
- interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&cru PCLK_HDMI>;
- clock-names = "pclk";
- pinctrl-names = "default";
- pinctrl-0 = <&hdmi_ctl>;
-
- hdmi_in: port {
- #address-cells = <1>;
- #size-cells = <0>;
- hdmi_in_lcdc: endpoint@0 {
- reg = <0>;
- remote-endpoint = <&lcdc_out_hdmi>;
- };
- };
-};
-
-&pinctrl {
- hdmi {
- hdmi_ctl: hdmi-ctl {
- rockchip,pins = <1 8 RK_FUNC_1 &pcfg_pull_none>,
- <1 9 RK_FUNC_1 &pcfg_pull_none>,
- <1 10 RK_FUNC_1 &pcfg_pull_none>,
- <1 11 RK_FUNC_1 &pcfg_pull_none>;
- };
- };
-
-};
diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml
new file mode 100644
index 000000000000..be78dcfa1c76
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml
@@ -0,0 +1,139 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/rockchip/rockchip,inno-hdmi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip Innosilicon HDMI controller
+
+maintainers:
+ - Sandy Huang <[email protected]>
+ - Heiko Stuebner <[email protected]>
+
+properties:
+ compatible:
+ enum:
+ - rockchip,rk3036-inno-hdmi
+ - rockchip,rk3128-inno-hdmi
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ minItems: 1
+ items:
+ - description: The HDMI controller main clock
+ - description: The HDMI PHY reference clock
+
+ clock-names:
+ minItems: 1
+ items:
+ - const: pclk
+ - const: ref
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ Port node with one endpoint connected to a vop node.
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ Port node with one endpoint connected to a hdmi-connector node.
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - pinctrl-0
+ - pinctrl-names
+ - ports
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: rockchip,rk3036-inno-hdmi
+
+ then:
+ properties:
+ power-domains: false
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: rockchip,rk3128-inno-hdmi
+
+ then:
+ properties:
+ clocks:
+ minItems: 2
+ clock-names:
+ minItems: 2
+ required:
+ - power-domains
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/rk3036-cru.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/pinctrl/rockchip.h>
+ hdmi: hdmi@20034000 {
+ compatible = "rockchip,rk3036-inno-hdmi";
+ reg = <0x20034000 0x4000>;
+ interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru PCLK_HDMI>;
+ clock-names = "pclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_ctl>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hdmi_in: port@0 {
+ reg = <0>;
+ hdmi_in_vop: endpoint {
+ remote-endpoint = <&vop_out_hdmi>;
+ };
+ };
+
+ hdmi_out: port@1 {
+ reg = <1>;
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+ };
+ };
+ };
+
+ pinctrl {
+ hdmi {
+ hdmi_ctl: hdmi-ctl {
+ rockchip,pins = <1 RK_PB0 1 &pcfg_pull_none>,
+ <1 RK_PB1 1 &pcfg_pull_none>,
+ <1 RK_PB2 1 &pcfg_pull_none>,
+ <1 RK_PB3 1 &pcfg_pull_none>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/dts-coding-style.rst b/Documentation/devicetree/bindings/dts-coding-style.rst
new file mode 100644
index 000000000000..a9bdd2b59dca
--- /dev/null
+++ b/Documentation/devicetree/bindings/dts-coding-style.rst
@@ -0,0 +1,196 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================================
+Devicetree Sources (DTS) Coding Style
+=====================================
+
+When writing Devicetree Sources (DTS) please observe below guidelines. They
+should be considered complementary to any rules expressed already in
+the Devicetree Specification and the dtc compiler (including W=1 and W=2
+builds).
+
+Individual architectures and subarchitectures can define additional rules,
+making the coding style stricter.
+
+Naming and Valid Characters
+---------------------------
+
+The Devicetree Specification allows a broad range of characters in node
+and property names, but this coding style narrows the range down to achieve
+better code readability.
+
+1. Node and property names can use only the following characters:
+
+ * Lowercase characters: [a-z]
+ * Digits: [0-9]
+ * Dash: -
+
+2. Labels can use only the following characters:
+
+ * Lowercase characters: [a-z]
+ * Digits: [0-9]
+ * Underscore: _
+
+3. Unless a bus defines differently, unit addresses shall use lowercase
+ hexadecimal digits, without leading zeros (padding).
+
+4. Hex values in properties, e.g. "reg", shall use lowercase hex. The address
+ part can be padded with leading zeros.
+
+Example::
+
+ gpi_dma2: dma-controller@a00000 {
+ compatible = "qcom,sm8550-gpi-dma", "qcom,sm6350-gpi-dma";
+ reg = <0x0 0x00a00000 0x0 0x60000>;
+ }
+
+Order of Nodes
+--------------
+
+1. Nodes on any bus, thus using unit addresses for children, shall be
+ ordered by unit address in ascending order.
+ Alternatively for some subarchitectures, nodes of the same type can be
+ grouped together, e.g. all I2C controllers one after another even if this
+ breaks unit address ordering.
+
+2. Nodes without unit addresses shall be ordered alpha-numerically by the node
+ name. For a few node types, they can be ordered by the main property, e.g.
+ pin configuration states ordered by value of "pins" property.
+
+3. When extending nodes in the board DTS via &label, the entries shall be
+ ordered either alpha-numerically or by keeping the order from DTSI, where
+ the choice depends on the subarchitecture.
+
+The above-described ordering rules are easy to enforce during review, reduce
+chances of conflicts for simultaneous additions of new nodes to a file and help
+in navigating through the DTS source.
+
+Example::
+
+ /* SoC DTSI */
+
+ / {
+ cpus {
+ /* ... */
+ };
+
+ psci {
+ /* ... */
+ };
+
+ soc@0 {
+ dma: dma-controller@10000 {
+ /* ... */
+ };
+
+ clk: clock-controller@80000 {
+ /* ... */
+ };
+ };
+ };
+
+ /* Board DTS - alphabetical order */
+
+ &clk {
+ /* ... */
+ };
+
+ &dma {
+ /* ... */
+ };
+
+ /* Board DTS - alternative order, keep as DTSI */
+
+ &dma {
+ /* ... */
+ };
+
+ &clk {
+ /* ... */
+ };
+
+Order of Properties in Device Node
+----------------------------------
+
+The following order of properties in device nodes is preferred:
+
+1. "compatible"
+2. "reg"
+3. "ranges"
+4. Standard/common properties (defined by common bindings, e.g. without
+ vendor-prefixes)
+5. Vendor-specific properties
+6. "status" (if applicable)
+7. Child nodes, where each node is preceded with a blank line
+
+The "status" property is by default "okay", thus it can be omitted.
+
+The above-described ordering follows this approach:
+
+1. Most important properties start the node: compatible then bus addressing to
+ match unit address.
+2. Each node will have common properties in similar place.
+3. Status is the last information to annotate that device node is or is not
+ finished (board resources are needed).
+
+Example::
+
+ /* SoC DTSI */
+
+ device_node: device-class@6789abc {
+ compatible = "vendor,device";
+ reg = <0x0 0x06789abc 0x0 0xa123>;
+ ranges = <0x0 0x0 0x06789abc 0x1000>;
+ #dma-cells = <1>;
+ clocks = <&clock_controller 0>, <&clock_controller 1>;
+ clock-names = "bus", "host";
+ vendor,custom-property = <2>;
+ status = "disabled";
+
+ child_node: child-class@100 {
+ reg = <0x100 0x200>;
+ /* ... */
+ };
+ };
+
+ /* Board DTS */
+
+ &device_node {
+ vdd-supply = <&board_vreg1>;
+ status = "okay";
+ }
+
+Indentation
+-----------
+
+1. Use indentation according to Documentation/process/coding-style.rst.
+2. Each entry in arrays with multiple cells, e.g. "reg" with two IO addresses,
+ shall be enclosed in <>.
+3. For arrays spanning across lines, it is preferred to align the continued
+ entries with opening < from the first line.
+
+Example::
+
+ thermal-sensor@c271000 {
+ compatible = "qcom,sm8550-tsens", "qcom,tsens-v2";
+ reg = <0x0 0x0c271000 0x0 0x1000>,
+ <0x0 0x0c222000 0x0 0x1000>;
+ };
+
+Organizing DTSI and DTS
+-----------------------
+
+The DTSI and DTS files shall be organized in a way representing the common,
+reusable parts of hardware. Typically, this means organizing DTSI and DTS files
+into several files:
+
+1. DTSI with contents of the entire SoC, without nodes for hardware not present
+ on the SoC.
+2. If applicable: DTSI with common or re-usable parts of the hardware, e.g.
+ entire System-on-Module.
+3. DTS representing the board.
+
+Hardware components that are present on the board shall be placed in the
+board DTS, not in the SoC or SoM DTSI. A partial exception is a common
+external reference SoC input clock, which could be coded as a fixed-clock in
+the SoC DTSI with its frequency provided by each board DTS.
diff --git a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
index 822864488dcb..8e584857ddd4 100644
--- a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
+++ b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml
@@ -95,8 +95,8 @@ examples:
versal_clk: clock-controller {
#clock-cells = <1>;
compatible = "xlnx,versal-clk";
- clocks = <&ref>, <&alt_ref>, <&pl_alt_ref>;
- clock-names = "ref", "alt_ref", "pl_alt_ref";
+ clocks = <&ref>, <&pl_alt_ref>;
+ clock-names = "ref", "pl_alt_ref";
};
};
diff --git a/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt
deleted file mode 100644
index 5dd0ff0f7b4e..000000000000
--- a/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Altera FPGA To SDRAM Bridge Driver
-
-Required properties:
-- compatible : Should contain "altr,socfpga-fpga2sdram-bridge"
-
-See Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings.
-
-Example:
- fpga_bridge3: fpga-bridge@ffc25080 {
- compatible = "altr,socfpga-fpga2sdram-bridge";
- reg = <0xffc25080 0x4>;
- bridge-enable = <0>;
- };
diff --git a/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt
deleted file mode 100644
index 8b26fbcff3c6..000000000000
--- a/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-Altera Freeze Bridge Controller Driver
-
-The Altera Freeze Bridge Controller manages one or more freeze bridges.
-The controller can freeze/disable the bridges which prevents signal
-changes from passing through the bridge. The controller can also
-unfreeze/enable the bridges which allows traffic to pass through the
-bridge normally.
-
-Required properties:
-- compatible : Should contain "altr,freeze-bridge-controller"
-- regs : base address and size for freeze bridge module
-
-See Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings.
-
-Example:
- freeze-controller@100000450 {
- compatible = "altr,freeze-bridge-controller";
- regs = <0x1000 0x10>;
- bridge-enable = <0>;
- };
diff --git a/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt
deleted file mode 100644
index 68cce3945b10..000000000000
--- a/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-Altera FPGA/HPS Bridge Driver
-
-Required properties:
-- regs : base address and size for AXI bridge module
-- compatible : Should contain one of:
- "altr,socfpga-lwhps2fpga-bridge",
- "altr,socfpga-hps2fpga-bridge", or
- "altr,socfpga-fpga2hps-bridge"
-- resets : Phandle and reset specifier for this bridge's reset
-- clocks : Clocks used by this module.
-
-See Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings.
-
-Example:
- fpga_bridge0: fpga-bridge@ff400000 {
- compatible = "altr,socfpga-lwhps2fpga-bridge";
- reg = <0xff400000 0x100000>;
- resets = <&rst LWHPS2FPGA_RESET>;
- clocks = <&l4_main_clk>;
- bridge-enable = <0>;
- };
-
- fpga_bridge1: fpga-bridge@ff500000 {
- compatible = "altr,socfpga-hps2fpga-bridge";
- reg = <0xff500000 0x10000>;
- resets = <&rst HPS2FPGA_RESET>;
- clocks = <&l4_main_clk>;
- bridge-enable = <1>;
- };
-
- fpga_bridge2: fpga-bridge@ff600000 {
- compatible = "altr,socfpga-fpga2hps-bridge";
- reg = <0xff600000 0x100000>;
- resets = <&rst FPGA2HPS_RESET>;
- clocks = <&l4_main_clk>;
- };
diff --git a/Documentation/devicetree/bindings/fpga/altr,freeze-bridge-controller.yaml b/Documentation/devicetree/bindings/fpga/altr,freeze-bridge-controller.yaml
new file mode 100644
index 000000000000..fccffeebb256
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/altr,freeze-bridge-controller.yaml
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fpga/altr,freeze-bridge-controller.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Altera Freeze Bridge Controller
+
+description:
+ The Altera Freeze Bridge Controller manages one or more freeze bridges.
+ The controller can freeze/disable the bridges which prevents signal
+ changes from passing through the bridge. The controller can also
+ unfreeze/enable the bridges which allows traffic to pass through the bridge
+ normally.
+
+maintainers:
+ - Xu Yilun <[email protected]>
+
+allOf:
+ - $ref: fpga-bridge.yaml#
+
+properties:
+ compatible:
+ const: altr,freeze-bridge-controller
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ fpga-bridge@100000450 {
+ compatible = "altr,freeze-bridge-controller";
+ reg = <0x1000 0x10>;
+ bridge-enable = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/fpga/altr,socfpga-fpga2sdram-bridge.yaml b/Documentation/devicetree/bindings/fpga/altr,socfpga-fpga2sdram-bridge.yaml
new file mode 100644
index 000000000000..22b58453c5ff
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/altr,socfpga-fpga2sdram-bridge.yaml
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fpga/altr,socfpga-fpga2sdram-bridge.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Altera FPGA To SDRAM Bridge
+
+maintainers:
+ - Xu Yilun <[email protected]>
+
+allOf:
+ - $ref: fpga-bridge.yaml#
+
+properties:
+ compatible:
+ const: altr,socfpga-fpga2sdram-bridge
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ fpga-bridge@ffc25080 {
+ compatible = "altr,socfpga-fpga2sdram-bridge";
+ reg = <0xffc25080 0x4>;
+ bridge-enable = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/fpga/altr,socfpga-hps2fpga-bridge.yaml b/Documentation/devicetree/bindings/fpga/altr,socfpga-hps2fpga-bridge.yaml
new file mode 100644
index 000000000000..d19c6660d6c9
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/altr,socfpga-hps2fpga-bridge.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fpga/altr,socfpga-hps2fpga-bridge.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Altera FPGA/HPS Bridge
+
+maintainers:
+ - Xu Yilun <[email protected]>
+
+allOf:
+ - $ref: fpga-bridge.yaml#
+
+properties:
+ compatible:
+ enum:
+ - altr,socfpga-lwhps2fpga-bridge
+ - altr,socfpga-hps2fpga-bridge
+ - altr,socfpga-fpga2hps-bridge
+
+ reg:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - resets
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/reset/altr,rst-mgr.h>
+
+ fpga-bridge@ff400000 {
+ compatible = "altr,socfpga-lwhps2fpga-bridge";
+ reg = <0xff400000 0x100000>;
+ bridge-enable = <0>;
+ clocks = <&l4_main_clk>;
+ resets = <&rst LWHPS2FPGA_RESET>;
+ };
diff --git a/Documentation/devicetree/bindings/fpga/fpga-bridge.txt b/Documentation/devicetree/bindings/fpga/fpga-bridge.txt
deleted file mode 100644
index 72e06917288a..000000000000
--- a/Documentation/devicetree/bindings/fpga/fpga-bridge.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-FPGA Bridge Device Tree Binding
-
-Optional properties:
-- bridge-enable : 0 if driver should disable bridge at startup
- 1 if driver should enable bridge at startup
- Default is to leave bridge in current state.
-
-Example:
- fpga_bridge3: fpga-bridge@ffc25080 {
- compatible = "altr,socfpga-fpga2sdram-bridge";
- reg = <0xffc25080 0x4>;
- bridge-enable = <0>;
- };
diff --git a/Documentation/devicetree/bindings/fpga/fpga-bridge.yaml b/Documentation/devicetree/bindings/fpga/fpga-bridge.yaml
new file mode 100644
index 000000000000..1ccb2aa18726
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/fpga-bridge.yaml
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fpga/fpga-bridge.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: FPGA Bridge
+
+maintainers:
+ - Michal Simek <[email protected]>
+
+properties:
+ $nodename:
+ pattern: "^fpga-bridge(@.*|-([0-9]|[1-9][0-9]+))?$"
+
+ bridge-enable:
+ description: |
+ 0 if driver should disable bridge at startup
+ 1 if driver should enable bridge at startup
+ Default is to leave bridge in current state.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [ 0, 1 ]
+
+additionalProperties: true
+
+examples:
+ - |
+ fpga-bridge {
+ bridge-enable = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml b/Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml
index a7d4b8e59e19..5bf731f9d99a 100644
--- a/Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml
+++ b/Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml
@@ -9,6 +9,9 @@ title: Xilinx LogiCORE Partial Reconfig Decoupler/AXI shutdown manager Softcore
maintainers:
- Nava kishore Manne <[email protected]>
+allOf:
+ - $ref: fpga-bridge.yaml#
+
description: |
The Xilinx LogiCORE Partial Reconfig(PR) Decoupler manages one or more
decouplers/fpga bridges. The controller can decouple/disable the bridges
@@ -51,7 +54,7 @@ required:
- clocks
- clock-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/gnss/u-blox,neo-6m.yaml b/Documentation/devicetree/bindings/gnss/u-blox,neo-6m.yaml
index 4835a280b3bf..cd80668182b6 100644
--- a/Documentation/devicetree/bindings/gnss/u-blox,neo-6m.yaml
+++ b/Documentation/devicetree/bindings/gnss/u-blox,neo-6m.yaml
@@ -28,6 +28,9 @@ properties:
port or the USB host-controller port to which this device is attached,
depending on the bus used. Required for the DDC, SPI or USB busses.
+ reset-gpios:
+ maxItems: 1
+
vcc-supply:
description: >
Main voltage regulator
@@ -49,10 +52,13 @@ unevaluatedProperties: false
examples:
- |
+ #include <dt-bindings/gpio/gpio.h>
+
serial {
gnss {
compatible = "u-blox,neo-8";
v-bckp-supply = <&gnss_v_bckp_reg>;
vcc-supply = <&gnss_vcc_reg>;
+ reset-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
};
};
diff --git a/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml b/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml
index e7daae862578..132aaa49597b 100644
--- a/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml
+++ b/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml
@@ -22,36 +22,20 @@ properties:
interrupts:
maxItems: 1
- clocks: {}
- clock-names: {}
- iommus: {}
- power-domains: {}
-
-if:
- properties:
- compatible:
- contains:
- const: samsung,exynos5250-g2d
-
-then:
- properties:
- clocks:
- items:
- - description: fimg2d clock
- clock-names:
- items:
- - const: fimg2d
-
-else:
- properties:
- clocks:
- items:
- - description: sclk_fimg2d clock
- - description: fimg2d clock
- clock-names:
- items:
- - const: sclk_fimg2d
- - const: fimg2d
+ clocks:
+ minItems: 1
+ maxItems: 2
+
+ clock-names:
+ minItems: 1
+ maxItems: 2
+
+ iommus:
+ minItems: 1
+ maxItems: 2
+
+ power-domains:
+ maxItems: 1
required:
- compatible
@@ -60,6 +44,33 @@ required:
- clocks
- clock-names
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: samsung,exynos5250-g2d
+
+ then:
+ properties:
+ clocks:
+ items:
+ - description: fimg2d clock
+ clock-names:
+ items:
+ - const: fimg2d
+
+ else:
+ properties:
+ clocks:
+ items:
+ - description: sclk_fimg2d clock
+ - description: fimg2d clock
+ clock-names:
+ items:
+ - const: sclk_fimg2d
+ - const: fimg2d
+
additionalProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml b/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml
index d60626ffb28e..18bf44e06e8f 100644
--- a/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml
+++ b/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml
@@ -12,10 +12,11 @@ maintainers:
properties:
compatible:
enum:
- - "samsung,s5pv210-rotator"
- - "samsung,exynos4210-rotator"
- - "samsung,exynos4212-rotator"
- - "samsung,exynos5250-rotator"
+ - samsung,s5pv210-rotator
+ - samsung,exynos4210-rotator
+ - samsung,exynos4212-rotator
+ - samsung,exynos5250-rotator
+
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml b/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml
index 5317ac64426a..9fb530e65d0e 100644
--- a/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml
+++ b/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml
@@ -21,40 +21,20 @@ properties:
interrupts:
maxItems: 1
- clocks: {}
- clock-names: {}
- iommus: {}
- power-domains: {}
-
-if:
- properties:
- compatible:
- contains:
- const: samsung,exynos5420-scaler
-
-then:
- properties:
- clocks:
- items:
- - description: mscl clock
-
- clock-names:
- items:
- - const: mscl
-
-else:
- properties:
- clocks:
- items:
- - description: pclk clock
- - description: aclk clock
- - description: aclk_xiu clock
-
- clock-names:
- items:
- - const: pclk
- - const: aclk
- - const: aclk_xiu
+ clocks:
+ minItems: 1
+ maxItems: 3
+
+ clock-names:
+ minItems: 1
+ maxItems: 3
+
+ iommus:
+ minItems: 1
+ maxItems: 2
+
+ power-domains:
+ maxItems: 1
required:
- compatible
@@ -63,6 +43,39 @@ required:
- clocks
- clock-names
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: samsung,exynos5420-scaler
+
+ then:
+ properties:
+ clocks:
+ items:
+ - description: mscl clock
+ clock-names:
+ items:
+ - const: mscl
+ iommus:
+ minItems: 2
+
+ else:
+ properties:
+ clocks:
+ items:
+ - description: pclk clock
+ - description: aclk clock
+ - description: aclk_xiu clock
+ clock-names:
+ items:
+ - const: pclk
+ - const: aclk
+ - const: aclk_xiu
+ iommus:
+ maxItems: 1
+
additionalProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml
index ce7ba634643c..ddec9747436c 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml
@@ -4,36 +4,92 @@
$id: http://devicetree.org/schemas/iio/adc/adi,ad7091r5.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Analog Devices AD7091R5 4-Channel 12-Bit ADC
+title: Analog Devices AD7091R-2/-4/-5/-8 Multi-Channel 12-Bit ADCs
maintainers:
- Michael Hennerich <[email protected]>
+ - Marcelo Schmitt <[email protected]>
description: |
- Analog Devices AD7091R5 4-Channel 12-Bit ADC
+ Analog Devices AD7091R5 4-Channel 12-Bit ADC supporting I2C interface
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf
+ Analog Devices AD7091R-2/AD7091R-4/AD7091R-8 2-/4-/8-Channel 12-Bit ADCs
+ supporting SPI interface
+ https://www.analog.com/media/en/technical-documentation/data-sheets/AD7091R-2_7091R-4_7091R-8.pdf
properties:
compatible:
enum:
+ - adi,ad7091r2
+ - adi,ad7091r4
- adi,ad7091r5
+ - adi,ad7091r8
reg:
maxItems: 1
+ vdd-supply:
+ description:
+ Provide VDD power to the sensor (VDD range is from 2.7V to 5.25V).
+
+ vdrive-supply:
+ description:
+ Determines the voltage level at which the interface logic will operate.
+ The V_drive voltage range is from 1.8V to 5.25V and must not exceed VDD by
+ more than 0.3V.
+
vref-supply:
description:
Phandle to the vref power supply
- interrupts:
+ convst-gpios:
+ description:
+ GPIO connected to the CONVST pin.
+ This logic input is used to initiate conversions on the analog
+ input channels.
maxItems: 1
+ reset-gpios:
+ maxItems: 1
+
+ interrupts:
+ description:
+ Interrupt for signaling when conversion results exceed the high limit for
+ ADC readings or fall below the low limit for them. Interrupt source must
+ be attached to ALERT/BUSY/GPO0 pin.
+ maxItems: 1
required:
- compatible
- reg
-additionalProperties: false
+allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+ # AD7091R-2 does not have ALERT/BUSY/GPO pin
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad7091r2
+ then:
+ properties:
+ interrupts: false
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad7091r2
+ - adi,ad7091r4
+ - adi,ad7091r8
+ then:
+ required:
+ - convst-gpios
+
+unevaluatedProperties: false
examples:
- |
@@ -51,4 +107,22 @@ examples:
interrupt-parent = <&gpio>;
};
};
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@0 {
+ compatible = "adi,ad7091r8";
+ reg = <0x0>;
+ spi-max-frequency = <1000000>;
+ vref-supply = <&adc_vref>;
+ convst-gpios = <&gpio 25 GPIO_ACTIVE_LOW>;
+ reset-gpios = <&gpio 27 GPIO_ACTIVE_LOW>;
+ interrupts = <22 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-parent = <&gpio>;
+ };
+ };
...
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml
index 5fcc8dd012f1..be2616ff9af6 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml
@@ -80,9 +80,9 @@ examples:
compatible = "adi,ad7780";
reg = <0>;
- avdd-supply = <&vdd_supply>;
- powerdown-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
- adi,gain-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
+ avdd-supply = <&vdd_supply>;
+ powerdown-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+ adi,gain-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>;
adi,filter-gpios = <&gpio2 15 GPIO_ACTIVE_LOW>;
};
};
diff --git a/Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml b/Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml
new file mode 100644
index 000000000000..4cba856e8d47
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml
@@ -0,0 +1,139 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/maxim,max34408.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim MAX34408/MAX34409 current monitors with overcurrent control
+
+maintainers:
+ - Ivan Mikhaylov <[email protected]>
+
+description: |
+ The MAX34408/MAX34409 are two- and four-channel current monitors that are
+ configured and monitored with a standard I2C/SMBus serial interface. Each
+ unidirectional current sensor offers precision high-side operation with a
+ low full-scale sense voltage. The devices automatically sequence through
+ two or four channels and collect the current-sense samples and average them
+ to reduce the effect of impulse noise. The raw ADC samples are compared to
+ user-programmable digital thresholds to indicate overcurrent conditions.
+ Overcurrent conditions trigger a hardware output to provide an immediate
+ indication to shut down any necessary external circuitry.
+
+ Specifications about the devices can be found at:
+ https://www.analog.com/media/en/technical-documentation/data-sheets/MAX34408-MAX34409.pdf
+
+properties:
+ compatible:
+ enum:
+ - maxim,max34408
+ - maxim,max34409
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ powerdown-gpios:
+ description:
+ Shutdown Output. Open-drain output. This output transitions to high impedance
+ when any of the digital comparator thresholds are exceeded as long as the ENA
+ pin is high.
+ maxItems: 1
+
+ powerdown-status-gpios:
+ description:
+ SHTDN Enable Input. CMOS digital input. Connect to GND to clear the latch and
+ unconditionally deassert (force low) the SHTDN output and reset the shutdown
+ delay. Connect to VDD to enable normal latch operation of the SHTDN output.
+ maxItems: 1
+
+ vdd-supply: true
+
+patternProperties:
+ "^channel@[0-3]$":
+ $ref: adc.yaml
+ type: object
+ description:
+ Represents the internal channels of the ADC.
+
+ properties:
+ reg:
+ items:
+ - minimum: 0
+ maximum: 3
+
+ maxim,rsense-val-micro-ohms:
+ description:
+ Adjust the Rsense value to monitor higher or lower current levels for
+ input.
+ enum: [250, 500, 1000, 5000, 10000, 50000, 100000, 200000, 500000]
+ default: 1000
+
+ required:
+ - reg
+ - maxim,rsense-val-micro-ohms
+
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: maxim,max34408
+ then:
+ patternProperties:
+ "^channel@[2-3]$": false
+ "^channel@[0-1]$":
+ properties:
+ reg:
+ maximum: 1
+ else:
+ patternProperties:
+ "^channel@[0-3]$":
+ properties:
+ reg:
+ maximum: 3
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@1e {
+ compatible = "maxim,max34409";
+ reg = <0x1e>;
+ powerdown-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
+ powerdown-status-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ channel@0 {
+ reg = <0x0>;
+ maxim,rsense-val-micro-ohms = <5000>;
+ };
+
+ channel@1 {
+ reg = <0x1>;
+ maxim,rsense-val-micro-ohms = <10000>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml
index 73def67fbe01..5ed893ef5c18 100644
--- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml
@@ -25,7 +25,7 @@ properties:
- const: qcom,spmi-iadc
reg:
- description: IADC base address and length in the SPMI PMIC register map
+ description: IADC base address in the SPMI PMIC register map
maxItems: 1
qcom,external-resistor-micro-ohms:
@@ -50,15 +50,17 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
- spmi {
+
+ pmic {
#address-cells = <1>;
#size-cells = <0>;
- pmic_iadc: adc@3600 {
+
+ adc@3600 {
compatible = "qcom,pm8941-iadc", "qcom,spmi-iadc";
reg = <0x3600>;
interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>;
qcom,external-resistor-micro-ohms = <10000>;
- #io-channel-cells = <1>;
+ #io-channel-cells = <1>;
};
};
...
diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml
index b3a626389870..f39bc92c2b99 100644
--- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml
@@ -43,9 +43,9 @@ examples:
#address-cells = <1>;
#size-cells = <0>;
- pmic_rradc: adc@4500 {
+ adc@4500 {
compatible = "qcom,pmi8998-rradc";
reg = <0x4500>;
- #io-channel-cells = <1>;
+ #io-channel-cells = <1>;
};
};
diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml
index ad7d6fc49de5..40fa0710f1f0 100644
--- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml
@@ -236,11 +236,11 @@ additionalProperties: false
examples:
- |
- spmi {
+ pmic {
#address-cells = <1>;
#size-cells = <0>;
- /* VADC node */
- pmic_vadc: adc@3100 {
+
+ adc@3100 {
compatible = "qcom,spmi-vadc";
reg = <0x3100>;
interrupts = <0x0 0x31 0x0 0x1>;
@@ -281,9 +281,10 @@ examples:
#include <dt-bindings/iio/qcom,spmi-adc7-pm8350.h>
#include <dt-bindings/interrupt-controller/irq.h>
- spmi {
+ pmic {
#address-cells = <1>;
#size-cells = <0>;
+
adc@3100 {
reg = <0x3100>;
compatible = "qcom,spmi-adc7";
diff --git a/Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml b/Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml
index 720c16a108d4..f94057d8f605 100644
--- a/Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml
@@ -67,19 +67,4 @@ required:
- compatible
- "#io-channel-cells"
-examples:
- - |
- #include <dt-bindings/clock/mt8183-clk.h>
- pmic {
- compatible = "ti,twl6035-pmic", "ti,palmas-pmic";
- adc {
- compatible = "ti,palmas-gpadc";
- interrupts = <18 0>,
- <16 0>,
- <17 0>;
- #io-channel-cells = <1>;
- ti,channel0-current-microamp = <5>;
- ti,channel3-current-microamp = <10>;
- };
- };
...
diff --git a/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml b/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml
index 2ee6080deac7..67de9d4e3a1d 100644
--- a/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml
+++ b/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml
@@ -12,6 +12,9 @@ maintainers:
description: |
Digital Step Attenuator IIO devices with gpio interface.
Offer various frequency and attenuation ranges.
+ ADRF5750 2 dB LSB, 4-Bit, Silicon Digital Attenuator, 10 MHz to 60 GHz
+ https://www.analog.com/media/en/technical-documentation/data-sheets/adrf5740.pdf
+
HMC425A 0.5 dB LSB GaAs MMIC 6-BIT DIGITAL POSITIVE CONTROL ATTENUATOR, 2.2 - 8.0 GHz
https://www.analog.com/media/en/technical-documentation/data-sheets/hmc425A.pdf
@@ -22,6 +25,7 @@ description: |
properties:
compatible:
enum:
+ - adi,adrf5740
- adi,hmc425a
- adi,hmc540s
diff --git a/Documentation/devicetree/bindings/iio/chemical/aosong,ags02ma.yaml b/Documentation/devicetree/bindings/iio/chemical/aosong,ags02ma.yaml
new file mode 100644
index 000000000000..35e7b094e878
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/chemical/aosong,ags02ma.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/chemical/aosong,ags02ma.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Aosong AGS02MA VOC Sensor
+
+description: |
+ AGS02MA is an TVOC (Total Volatile Organic Compounds) i2c sensor with default
+ address of 0x1a.
+
+ Datasheet:
+ https://asairsensors.com/wp-content/uploads/2021/09/AGS02MA.pdf
+
+maintainers:
+ - Anshul Dalal <[email protected]>
+
+properties:
+ compatible:
+ enum:
+ - aosong,ags02ma
+
+ reg:
+ maxItems: 1
+
+ vdd-supply: true
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ voc-sensor@1a {
+ compatible = "aosong,ags02ma";
+ reg = <0x1a>;
+ vdd-supply = <&vdd_regulator>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml
index 3a84739736f6..c81285d84db7 100644
--- a/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml
+++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml
@@ -26,6 +26,11 @@ properties:
vdd-supply: true
vss-supply: true
+ adi,rbuf-gain2-en:
+ description: Specify to allow an external amplifier to be connected in a
+ gain of two configuration.
+ type: boolean
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml b/Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml
new file mode 100644
index 000000000000..0dc577c33918
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/dac/microchip,mcp4821.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip MCP4821 and similar DACs
+
+description: |
+ Supports MCP48x1 (single channel) and MCP48x2 (dual channel) series of DACs.
+ Device supports simplex communication over SPI in Mode 0 and Mode 3.
+
+ +---------+--------------+-------------+
+ | Device | Resolution | Channels |
+ |---------|--------------|-------------|
+ | MCP4801 | 8-bit | 1 |
+ | MCP4802 | 8-bit | 2 |
+ | MCP4811 | 10-bit | 1 |
+ | MCP4812 | 10-bit | 2 |
+ | MCP4821 | 12-bit | 1 |
+ | MCP4822 | 12-bit | 2 |
+ +---------+--------------+-------------+
+
+ Datasheet:
+ MCP48x1: https://ww1.microchip.com/downloads/en/DeviceDoc/22244B.pdf
+ MCP48x2: https://ww1.microchip.com/downloads/en/DeviceDoc/20002249B.pdf
+
+maintainers:
+ - Anshul Dalal <[email protected]>
+
+allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+ compatible:
+ enum:
+ - microchip,mcp4801
+ - microchip,mcp4802
+ - microchip,mcp4811
+ - microchip,mcp4812
+ - microchip,mcp4821
+ - microchip,mcp4822
+
+ reg:
+ maxItems: 1
+
+ vdd-supply: true
+
+ ldac-gpios:
+ description: |
+ Active Low LDAC (Latch DAC Input) pin used to update the DAC output.
+ maxItems: 1
+
+ powerdown-gpios:
+ description: |
+ Active Low SHDN pin used to enter the shutdown mode.
+ maxItems: 1
+
+ spi-cpha: true
+ spi-cpol: true
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dac@0 {
+ compatible = "microchip,mcp4821";
+ reg = <0>;
+ vdd-supply = <&vdd_regulator>;
+ ldac-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
+ powerdown-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
+ spi-cpha;
+ spi-cpol;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml b/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml
new file mode 100644
index 000000000000..7f6d0f9edc75
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/humidity/ti,hdc3020.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HDC3020/HDC3021/HDC3022 humidity and temperature iio sensors
+
+maintainers:
+ - Li peiyu <[email protected]>
+ - Javier Carrasco <[email protected]>
+
+description:
+ https://www.ti.com/lit/ds/symlink/hdc3020.pdf
+
+ The HDC302x is an integrated capacitive based relative humidity (RH)
+ and temperature sensor.
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - ti,hdc3021
+ - ti,hdc3022
+ - const: ti,hdc3020
+ - const: ti,hdc3020
+
+ interrupts:
+ maxItems: 1
+
+ vdd-supply: true
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ humidity-sensor@47 {
+ compatible = "ti,hdc3021", "ti,hdc3020";
+ reg = <0x47>;
+ vdd-supply = <&vcc_3v3>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
index 4e43c80e5119..4cacc9948726 100644
--- a/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
@@ -25,6 +25,10 @@ properties:
spi-cpol: true
+ spi-cs-inactive-delay-ns:
+ minimum: 16000
+ default: 16000
+
interrupts:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
index c73533c54588..9b7ad609f7db 100644
--- a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml
@@ -47,6 +47,10 @@ properties:
spi-max-frequency:
maximum: 2000000
+ spi-cs-inactive-delay-ns:
+ minimum: 16000
+ default: 16000
+
interrupts:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml b/Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml
new file mode 100644
index 000000000000..64ef26e19669
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/imu/bosch,bmi323.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Bosch BMI323 6-Axis IMU
+
+maintainers:
+ - Jagath Jog J <[email protected]>
+
+description:
+ BMI323 is a 6-axis inertial measurement unit that supports acceleration and
+ gyroscopic measurements with hardware fifo buffering. Sensor also provides
+ events information such as motion, steps, orientation, single and double
+ tap detection.
+
+properties:
+ compatible:
+ const: bosch,bmi323
+
+ reg:
+ maxItems: 1
+
+ vdd-supply: true
+ vddio-supply: true
+
+ interrupts:
+ minItems: 1
+ maxItems: 2
+
+ interrupt-names:
+ minItems: 1
+ maxItems: 2
+ items:
+ enum:
+ - INT1
+ - INT2
+
+ drive-open-drain:
+ description:
+ set if the specified interrupt pin should be configured as
+ open drain. If not set, defaults to push-pull.
+
+ mount-matrix:
+ description:
+ an optional 3x3 mounting rotation matrix.
+
+required:
+ - compatible
+ - reg
+ - vdd-supply
+ - vddio-supply
+
+allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ // Example for I2C
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ imu@68 {
+ compatible = "bosch,bmi323";
+ reg = <0x68>;
+ vddio-supply = <&vddio>;
+ vdd-supply = <&vdd>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <29 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "INT1";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/light/liteon,ltr390.yaml b/Documentation/devicetree/bindings/iio/light/liteon,ltr390.yaml
new file mode 100644
index 000000000000..5d98ef2af74d
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/light/liteon,ltr390.yaml
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/liteon,ltr390.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Lite-On LTR390 ALS and UV Sensor
+
+description: |
+ The Lite-On LTR390 is an ALS (Ambient Light Sensor) and a UV sensor in a
+ single package with i2c address of 0x53.
+
+ Datasheet:
+ https://optoelectronics.liteon.com/upload/download/DS86-2015-0004/LTR-390UV_Final_%20DS_V1%201.pdf
+
+maintainers:
+ - Anshul Dalal <[email protected]>
+
+properties:
+ compatible:
+ enum:
+ - liteon,ltr390
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+ description: |
+ Level interrupt pin with open drain output.
+ The sensor pulls this pin low when the measured reading is greater than
+ some configured threshold.
+
+ vdd-supply: true
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ light-sensor@53 {
+ compatible = "liteon,ltr390";
+ reg = <0x53>;
+ interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+ vdd-supply = <&vdd_regulator>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml b/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml
new file mode 100644
index 000000000000..abee04cd126e
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/vishay,veml6075.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Vishay VEML6075 UVA and UVB sensor
+
+maintainers:
+ - Javier Carrasco <[email protected]>
+
+properties:
+ compatible:
+ const: vishay,veml6075
+
+ reg:
+ maxItems: 1
+
+ vdd-supply: true
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ uv-sensor@10 {
+ compatible = "vishay,veml6075";
+ reg = <0x10>;
+ vdd-supply = <&vdd_reg>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml b/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml
new file mode 100644
index 000000000000..65a24ed67b3c
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml
@@ -0,0 +1,142 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/pressure/honeywell,hsc030pa.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Honeywell TruStability HSC and SSC pressure sensor series
+
+description: |
+ support for Honeywell TruStability HSC and SSC digital pressure sensor
+ series.
+
+ These sensors have either an I2C, an SPI or an analog interface. Only the
+ digital versions are supported by this driver.
+
+ There are 118 models with different pressure ranges available in each family.
+ The vendor calls them "HSC series" and "SSC series". All of them have an
+ identical programming model but differ in pressure range, unit and transfer
+ function.
+
+ To support different models one needs to specify the pressure range as well
+ as the transfer function. Pressure range can either be provided via
+ pressure-triplet (directly extracted from the part number) or in case it's
+ a custom chip via numerical range limits converted to pascals.
+
+ The transfer function defines the ranges of raw conversion values delivered
+ by the sensor. pmin-pascal and pmax-pascal corespond to the minimum and
+ maximum pressure that can be measured.
+
+ Please note that in case of an SPI-based sensor, the clock signal should not
+ exceed 800kHz and the MOSI signal is not required.
+
+ Specifications about the devices can be found at:
+ https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf
+ https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-ssc-series/documents/sps-siot-trustability-ssc-series-standard-accuracy-board-mount-pressure-sensors-50099533-a-en-ciid-151134.pdf
+
+maintainers:
+ - Petre Rodan <[email protected]>
+
+properties:
+ compatible:
+ const: honeywell,hsc030pa
+
+ reg:
+ maxItems: 1
+
+ honeywell,transfer-function:
+ description: |
+ Transfer function which defines the range of valid values delivered by
+ the sensor.
+ 0 - A, 10% to 90% of 2^14
+ 1 - B, 5% to 95% of 2^14
+ 2 - C, 5% to 85% of 2^14
+ 3 - F, 4% to 94% of 2^14
+ enum: [0, 1, 2, 3]
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ honeywell,pressure-triplet:
+ description: |
+ Case-sensitive five character string that defines pressure range, unit
+ and type as part of the device nomenclature. In the unlikely case of a
+ custom chip, set to "NA" and provide pmin-pascal and pmax-pascal.
+ enum: [001BA, 1.6BA, 2.5BA, 004BA, 006BA, 010BA, 1.6MD, 2.5MD, 004MD,
+ 006MD, 010MD, 016MD, 025MD, 040MD, 060MD, 100MD, 160MD, 250MD,
+ 400MD, 600MD, 001BD, 1.6BD, 2.5BD, 004BD, 2.5MG, 004MG, 006MG,
+ 010MG, 016MG, 025MG, 040MG, 060MG, 100MG, 160MG, 250MG, 400MG,
+ 600MG, 001BG, 1.6BG, 2.5BG, 004BG, 006BG, 010BG, 100KA, 160KA,
+ 250KA, 400KA, 600KA, 001GA, 160LD, 250LD, 400LD, 600LD, 001KD,
+ 1.6KD, 2.5KD, 004KD, 006KD, 010KD, 016KD, 025KD, 040KD, 060KD,
+ 100KD, 160KD, 250KD, 400KD, 250LG, 400LG, 600LG, 001KG, 1.6KG,
+ 2.5KG, 004KG, 006KG, 010KG, 016KG, 025KG, 040KG, 060KG, 100KG,
+ 160KG, 250KG, 400KG, 600KG, 001GG, 015PA, 030PA, 060PA, 100PA,
+ 150PA, 0.5ND, 001ND, 002ND, 004ND, 005ND, 010ND, 020ND, 030ND,
+ 001PD, 005PD, 015PD, 030PD, 060PD, 001NG, 002NG, 004NG, 005NG,
+ 010NG, 020NG, 030NG, 001PG, 005PG, 015PG, 030PG, 060PG, 100PG,
+ 150PG, NA]
+ $ref: /schemas/types.yaml#/definitions/string
+
+ honeywell,pmin-pascal:
+ description: |
+ Minimum pressure value the sensor can measure in pascal.
+ To be specified only if honeywell,pressure-triplet is set to "NA".
+
+ honeywell,pmax-pascal:
+ description: |
+ Maximum pressure value the sensor can measure in pascal.
+ To be specified only if honeywell,pressure-triplet is set to "NA".
+
+ vdd-supply:
+ description:
+ Provide VDD power to the sensor (either 3.3V or 5V depending on the chip)
+
+ spi-max-frequency:
+ maximum: 800000
+
+required:
+ - compatible
+ - reg
+ - honeywell,transfer-function
+ - honeywell,pressure-triplet
+
+additionalProperties: false
+
+dependentSchemas:
+ honeywell,pmin-pascal:
+ properties:
+ honeywell,pressure-triplet:
+ const: NA
+ honeywell,pmax-pascal:
+ properties:
+ honeywell,pressure-triplet:
+ const: NA
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pressure@28 {
+ compatible = "honeywell,hsc030pa";
+ reg = <0x28>;
+ honeywell,transfer-function = <0>;
+ honeywell,pressure-triplet = "030PA";
+ };
+ };
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pressure@0 {
+ compatible = "honeywell,hsc030pa";
+ reg = <0>;
+ spi-max-frequency = <800000>;
+ honeywell,transfer-function = <0>;
+ honeywell,pressure-triplet = "NA";
+ honeywell,pmin-pascal = <0>;
+ honeywell,pmax-pascal = <200000>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml b/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml
index b31f8120f14e..d9e903fbfd99 100644
--- a/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml
+++ b/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml
@@ -53,12 +53,10 @@ properties:
honeywell,pmin-pascal:
description:
Minimum pressure value the sensor can measure in pascal.
- $ref: /schemas/types.yaml#/definitions/uint32
honeywell,pmax-pascal:
description:
Maximum pressure value the sensor can measure in pascal.
- $ref: /schemas/types.yaml#/definitions/uint32
honeywell,transfer-function:
description: |
diff --git a/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90632.yaml b/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90632.yaml
index 4a55e7f25ae7..03bb5d4fa8b5 100644
--- a/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90632.yaml
+++ b/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90632.yaml
@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/iio/temperature/melexis,mlx90632.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Melexis MLX90632 contactless Infra Red temperature sensor
+title: Melexis MLX90632 and MLX90635 contactless Infra Red temperature sensor
maintainers:
- Crt Mori <[email protected]>
@@ -27,9 +27,24 @@ description: |
Since measured object emissivity effects Infra Red energy emitted,
emissivity should be set before requesting the object temperature.
+ https://www.melexis.com/en/documents/documentation/datasheets/datasheet-mlx90635
+
+ MLX90635 is most suitable for consumer applications where
+ measured object temperature is in range between -20 to 100 degrees
+ Celsius with relative error of measurement 2 degree Celsius in
+ object temperature range for industrial applications, while just 0.2
+ degree Celsius for human body measurement applications. Since it can
+ operate and measure ambient temperature in range of -20 to 85 degrees
+ Celsius it is suitable also for outdoor use.
+
+ Since measured object emissivity effects Infra Red energy emitted,
+ emissivity should be set before requesting the object temperature.
+
properties:
compatible:
- const: melexis,mlx90632
+ enum:
+ - melexis,mlx90632
+ - melexis,mlx90635
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml b/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml
new file mode 100644
index 000000000000..d2cafa38a544
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/temperature/microchip,mcp9600.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip MCP9600 thermocouple EMF converter
+
+maintainers:
+ - Andrew Hepp <[email protected]>
+
+description:
+ https://ww1.microchip.com/downloads/en/DeviceDoc/MCP960X-Data-Sheet-20005426.pdf
+
+properties:
+ compatible:
+ const: microchip,mcp9600
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ minItems: 1
+ maxItems: 6
+
+ interrupt-names:
+ minItems: 1
+ maxItems: 6
+ items:
+ enum:
+ - open-circuit
+ - short-circuit
+ - alert1
+ - alert2
+ - alert3
+ - alert4
+
+ thermocouple-type:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Type of thermocouple (THERMOCOUPLE_TYPE_K if omitted).
+ Use defines in dt-bindings/iio/temperature/thermocouple.h.
+ Supported types are B, E, J, K, N, R, S, T.
+
+ vdd-supply: true
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/iio/temperature/thermocouple.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ temperature-sensor@60 {
+ compatible = "microchip,mcp9600";
+ reg = <0x60>;
+ interrupt-parent = <&gpio>;
+ interrupts = <25 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "open-circuit";
+ thermocouple-type = <THERMOCOUPLE_TYPE_K>;
+ vdd-supply = <&vdd>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/index.rst b/Documentation/devicetree/bindings/index.rst
index d9002a3a0abb..cc1fbdc05657 100644
--- a/Documentation/devicetree/bindings/index.rst
+++ b/Documentation/devicetree/bindings/index.rst
@@ -4,6 +4,7 @@
:maxdepth: 1
ABI
+ dts-coding-style
writing-bindings
writing-schema
submitting-patches
diff --git a/Documentation/devicetree/bindings/input/elan,ekth6915.yaml b/Documentation/devicetree/bindings/input/elan,ekth6915.yaml
index 3e2d216c6432..dc4ac41f2441 100644
--- a/Documentation/devicetree/bindings/input/elan,ekth6915.yaml
+++ b/Documentation/devicetree/bindings/input/elan,ekth6915.yaml
@@ -18,8 +18,9 @@ allOf:
properties:
compatible:
- items:
- - const: elan,ekth6915
+ enum:
+ - elan,ekth6915
+ - ilitek,ili2901
reg:
const: 0x10
diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml
index 73f809cdb783..05067e197abe 100644
--- a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml
+++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml
@@ -25,13 +25,16 @@ properties:
- const: qcom,msm8998-bwmon # BWMON v4
- items:
- enum:
+ - qcom,qcm2290-cpu-bwmon
- qcom,sc7180-cpu-bwmon
- qcom,sc7280-cpu-bwmon
- qcom,sc8280xp-cpu-bwmon
- qcom,sdm845-cpu-bwmon
+ - qcom,sm6115-cpu-bwmon
- qcom,sm6350-llcc-bwmon
- qcom,sm8250-cpu-bwmon
- qcom,sm8550-cpu-bwmon
+ - qcom,sm8650-cpu-bwmon
- const: qcom,sdm845-bwmon # BWMON v4, unified register space
- items:
- enum:
@@ -40,6 +43,7 @@ properties:
- qcom,sm6350-cpu-bwmon
- qcom,sm8250-llcc-bwmon
- qcom,sm8550-llcc-bwmon
+ - qcom,sm8650-llcc-bwmon
- const: qcom,sc7280-llcc-bwmon
- const: qcom,sc7280-llcc-bwmon # BWMON v5
- const: qcom,sdm845-llcc-bwmon # BWMON v5
diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml
index 86d61896f591..4bdc8321904b 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml
@@ -35,12 +35,16 @@ properties:
- qcom,sdm845-pdc
- qcom,sdx55-pdc
- qcom,sdx65-pdc
+ - qcom,sdx75-pdc
- qcom,sm4450-pdc
- qcom,sm6350-pdc
- qcom,sm8150-pdc
- qcom,sm8250-pdc
- qcom,sm8350-pdc
- qcom,sm8450-pdc
+ - qcom,sm8550-pdc
+ - qcom,sm8650-pdc
+ - qcom,x1e80100-pdc
- const: qcom,pdc
reg:
diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml b/Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml
index 2b153d7c5421..e44e4e5708a7 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml
@@ -55,8 +55,8 @@ examples:
- |
#include <dt-bindings/interrupt-controller/irq-st.h>
irq-syscfg {
- compatible = "st,stih407-irq-syscfg";
- st,syscfg = <&syscfg_cpu>;
+ compatible = "st,stih407-irq-syscfg";
+ st,syscfg = <&syscfg_cpu>;
st,irq-device = <ST_IRQ_SYSCFG_PMU_0>,
<ST_IRQ_SYSCFG_PMU_1>;
st,fiq-device = <ST_IRQ_SYSCFG_DISABLED>,
diff --git a/Documentation/devicetree/bindings/iommu/apple,dart.yaml b/Documentation/devicetree/bindings/iommu/apple,dart.yaml
index 903edf85d72e..7adb1de455a5 100644
--- a/Documentation/devicetree/bindings/iommu/apple,dart.yaml
+++ b/Documentation/devicetree/bindings/iommu/apple,dart.yaml
@@ -24,6 +24,7 @@ properties:
compatible:
enum:
- apple,t8103-dart
+ - apple,t8103-usb4-dart
- apple,t8110-dart
- apple,t6000-dart
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
index aa9e1c0895a5..a4042ae24770 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
@@ -56,6 +56,8 @@ properties:
- qcom,sm8350-smmu-500
- qcom,sm8450-smmu-500
- qcom,sm8550-smmu-500
+ - qcom,sm8650-smmu-500
+ - qcom,x1e80100-smmu-500
- const: qcom,smmu-500
- const: arm,mmu-500
@@ -89,6 +91,8 @@ properties:
- qcom,sm8150-smmu-500
- qcom,sm8250-smmu-500
- qcom,sm8350-smmu-500
+ - qcom,sm8450-smmu-500
+ - qcom,sm8550-smmu-500
- const: qcom,adreno-smmu
- const: qcom,smmu-500
- const: arm,mmu-500
@@ -434,6 +438,30 @@ allOf:
compatible:
items:
- enum:
+ - qcom,sm8350-smmu-500
+ - const: qcom,adreno-smmu
+ - const: qcom,smmu-500
+ - const: arm,mmu-500
+ then:
+ properties:
+ clock-names:
+ items:
+ - const: bus
+ - const: iface
+ - const: ahb
+ - const: hlos1_vote_gpu_smmu
+ - const: cx_gmu
+ - const: hub_cx_int
+ - const: hub_aon
+ clocks:
+ minItems: 7
+ maxItems: 7
+
+ - if:
+ properties:
+ compatible:
+ items:
+ - enum:
- qcom,sm6115-smmu-500
- qcom,sm6125-smmu-500
- const: qcom,adreno-smmu
@@ -453,6 +481,50 @@ allOf:
- description: Voter clock required for HLOS SMMU access
- description: Interface clock required for register access
+ - if:
+ properties:
+ compatible:
+ const: qcom,sm8450-smmu-500
+ then:
+ properties:
+ clock-names:
+ items:
+ - const: gmu
+ - const: hub
+ - const: hlos
+ - const: bus
+ - const: iface
+ - const: ahb
+
+ clocks:
+ items:
+ - description: GMU clock
+ - description: GPU HUB clock
+ - description: HLOS vote clock
+ - description: GPU memory bus clock
+ - description: GPU SNoC bus clock
+ - description: GPU AHB clock
+
+ - if:
+ properties:
+ compatible:
+ const: qcom,sm8550-smmu-500
+ then:
+ properties:
+ clock-names:
+ items:
+ - const: hlos
+ - const: bus
+ - const: iface
+ - const: ahb
+
+ clocks:
+ items:
+ - description: HLOS vote clock
+ - description: GPU memory bus clock
+ - description: GPU SNoC bus clock
+ - description: GPU AHB clock
+
# Disallow clocks for all other platforms with specific compatibles
- if:
properties:
@@ -472,9 +544,8 @@ allOf:
- qcom,sdx65-smmu-500
- qcom,sm6350-smmu-500
- qcom,sm6375-smmu-500
- - qcom,sm8350-smmu-500
- - qcom,sm8450-smmu-500
- - qcom,sm8550-smmu-500
+ - qcom,sm8650-smmu-500
+ - qcom,x1e80100-smmu-500
then:
properties:
clock-names: false
diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml b/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml
index ba9124f721f1..621dde0e45d8 100644
--- a/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml
+++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml
@@ -19,9 +19,14 @@ description: |+
properties:
compatible:
- enum:
- - rockchip,iommu
- - rockchip,rk3568-iommu
+ oneOf:
+ - enum:
+ - rockchip,iommu
+ - rockchip,rk3568-iommu
+ - items:
+ - enum:
+ - rockchip,rk3588-iommu
+ - const: rockchip,rk3568-iommu
reg:
items:
diff --git a/Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml b/Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml
new file mode 100644
index 000000000000..760cb336dccb
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml
@@ -0,0 +1,137 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/allwinner,sun50i-a100-ledc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A100 LED Controller
+
+maintainers:
+ - Samuel Holland <[email protected]>
+
+description:
+ The LED controller found in Allwinner sunxi SoCs uses a one-wire serial
+ interface to drive up to 1024 RGB LEDs.
+
+properties:
+ compatible:
+ oneOf:
+ - const: allwinner,sun50i-a100-ledc
+ - items:
+ - enum:
+ - allwinner,sun20i-d1-ledc
+ - allwinner,sun50i-r329-ledc
+ - const: allwinner,sun50i-a100-ledc
+
+ reg:
+ maxItems: 1
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Bus clock
+ - description: Module clock
+
+ clock-names:
+ items:
+ - const: bus
+ - const: mod
+
+ resets:
+ maxItems: 1
+
+ dmas:
+ maxItems: 1
+ description: TX DMA channel
+
+ dma-names:
+ const: tx
+
+ allwinner,pixel-format:
+ description: Pixel format (subpixel transmission order), default is "grb"
+ enum:
+ - bgr
+ - brg
+ - gbr
+ - grb
+ - rbg
+ - rgb
+
+ allwinner,t0h-ns:
+ default: 336
+ description: Length of high pulse when transmitting a "0" bit
+
+ allwinner,t0l-ns:
+ default: 840
+ description: Length of low pulse when transmitting a "0" bit
+
+ allwinner,t1h-ns:
+ default: 882
+ description: Length of high pulse when transmitting a "1" bit
+
+ allwinner,t1l-ns:
+ default: 294
+ description: Length of low pulse when transmitting a "1" bit
+
+ allwinner,treset-ns:
+ default: 300000
+ description: Minimum delay between transmission frames
+
+patternProperties:
+ "^multi-led@[0-9a-f]+$":
+ type: object
+ $ref: leds-class-multicolor.yaml#
+ unevaluatedProperties: false
+ properties:
+ reg:
+ minimum: 0
+ maximum: 1023
+ description: Index of the LED in the series (must be contiguous)
+
+ required:
+ - reg
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - resets
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/leds/common.h>
+
+ ledc: led-controller@2008000 {
+ compatible = "allwinner,sun20i-d1-ledc",
+ "allwinner,sun50i-a100-ledc";
+ reg = <0x2008000 0x400>;
+ interrupts = <36 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu 12>, <&ccu 34>;
+ clock-names = "bus", "mod";
+ resets = <&ccu 12>;
+ dmas = <&dma 42>;
+ dma-names = "tx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ multi-led@0 {
+ reg = <0x0>;
+ color = <LED_COLOR_ID_RGB>;
+ function = LED_FUNCTION_INDICATOR;
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml b/Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml
index feb5febaf361..54d6d1f08e24 100644
--- a/Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml
+++ b/Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml
@@ -10,15 +10,19 @@ maintainers:
- Martin Kurbanov <[email protected]>
description: |
- This controller is present on AW20036/AW20054/AW20072.
- It is a 3x12/6x9/6x12 matrix LED programmed via
- an I2C interface, up to 36/54/72 LEDs or 12/18/24 RGBs,
- 3 pattern controllers for auto breathing or group dimming control.
+ It is a matrix LED driver programmed via an I2C interface. Devices have
+ a set of individually controlled leds and support 3 pattern controllers
+ for auto breathing or group dimming control. Supported devices:
+ - AW20036 (3x12) 36 LEDs
+ - AW20054 (6x9) 54 LEDs
+ - AW20072 (6x12) 72 LEDs
+ - AW20108 (9x12) 108 LEDs
For more product information please see the link below:
aw20036 - https://www.awinic.com/en/productDetail/AW20036QNR#tech-docs
aw20054 - https://www.awinic.com/en/productDetail/AW20054QNR#tech-docs
aw20072 - https://www.awinic.com/en/productDetail/AW20072QNR#tech-docs
+ aw20108 - https://www.awinic.com/en/productDetail/AW20108QNR#tech-docs
properties:
compatible:
@@ -26,6 +30,7 @@ properties:
- awinic,aw20036
- awinic,aw20054
- awinic,aw20072
+ - awinic,aw20108
reg:
maxItems: 1
@@ -36,13 +41,11 @@ properties:
"#size-cells":
const: 0
- awinic,display-rows:
- $ref: /schemas/types.yaml#/definitions/uint32
- description:
- Leds matrix size
+ enable-gpios:
+ maxItems: 1
patternProperties:
- "^led@[0-9a-f]$":
+ "^led@[0-9a-f]+$":
type: object
$ref: common.yaml#
unevaluatedProperties: false
@@ -60,16 +63,11 @@ patternProperties:
since the chip has a single global setting.
The maximum output current of each LED is calculated by the
following formula:
- IMAXled = 160000 * (592 / 600.5) * (1 / display-rows)
+ IMAXled = 160000 * (592 / 600.5) * (1 / max-current-switch-number)
And the minimum output current formula:
- IMINled = 3300 * (592 / 600.5) * (1 / display-rows)
-
-required:
- - compatible
- - reg
- - "#address-cells"
- - "#size-cells"
- - awinic,display-rows
+ IMINled = 3300 * (592 / 600.5) * (1 / max-current-switch-number)
+ where max-current-switch-number is determinated by led configuration
+ and depends on how leds are physically connected to the led driver.
allOf:
- if:
@@ -78,18 +76,67 @@ allOf:
contains:
const: awinic,aw20036
then:
+ patternProperties:
+ "^led@[0-9a-f]+$":
+ properties:
+ reg:
+ items:
+ minimum: 0
+ maximum: 36
+
+ - if:
properties:
- awinic,display-rows:
- enum: [1, 2, 3]
- else:
+ compatible:
+ contains:
+ const: awinic,aw20054
+ then:
+ patternProperties:
+ "^led@[0-9a-f]+$":
+ properties:
+ reg:
+ items:
+ minimum: 0
+ maximum: 54
+
+ - if:
properties:
- awinic,display-rows:
- enum: [1, 2, 3, 4, 5, 6, 7]
+ compatible:
+ contains:
+ const: awinic,aw20072
+ then:
+ patternProperties:
+ "^led@[0-9a-f]+$":
+ properties:
+ reg:
+ items:
+ minimum: 0
+ maximum: 72
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: awinic,aw20108
+ then:
+ patternProperties:
+ "^led@[0-9a-f]+$":
+ properties:
+ reg:
+ items:
+ minimum: 0
+ maximum: 108
+
+required:
+ - compatible
+ - reg
+ - "#address-cells"
+ - "#size-cells"
additionalProperties: false
examples:
- |
+ #include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
i2c {
@@ -101,7 +148,7 @@ examples:
reg = <0x3a>;
#address-cells = <1>;
#size-cells = <0>;
- awinic,display-rows = <3>;
+ enable-gpios = <&gpio 3 GPIO_ACTIVE_HIGH>;
led@0 {
reg = <0x0>;
diff --git a/Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml b/Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml
index 4191e33626f5..527a37368ed7 100644
--- a/Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml
+++ b/Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml
@@ -14,8 +14,8 @@ description: |
programmable switching frequency to optimize efficiency.
It supports two different dimming modes:
- - analog mode, via I2C commands (default)
- - PWM controlled mode.
+ - analog mode, via I2C commands, as default mode (32 dimming levels)
+ - PWM controlled mode (optional)
The datasheet is available at:
https://www.monolithicpower.com/en/mp3309c.html
@@ -50,8 +50,6 @@ properties:
required:
- compatible
- reg
- - max-brightness
- - default-brightness
unevaluatedProperties: false
@@ -66,8 +64,8 @@ examples:
compatible = "mps,mp3309c";
reg = <0x17>;
pwms = <&pwm1 0 3333333 0>; /* 300 Hz --> (1/f) * 1*10^9 */
- max-brightness = <100>;
- default-brightness = <80>;
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness = <6>;
mps,overvoltage-protection-microvolt = <24000000>;
};
};
diff --git a/Documentation/devicetree/bindings/leds/common.yaml b/Documentation/devicetree/bindings/leds/common.yaml
index c8d0ba5f2327..55a8d1385e21 100644
--- a/Documentation/devicetree/bindings/leds/common.yaml
+++ b/Documentation/devicetree/bindings/leds/common.yaml
@@ -167,7 +167,7 @@ properties:
Note that this flag is mainly used for PWM-LEDs, where it is not possible
to map brightness to current. Drivers for other controllers should use
led-max-microamp.
- $ref: /schemas/types.yaml#definitions/uint32
+ $ref: /schemas/types.yaml#/definitions/uint32
panic-indicator:
description:
diff --git a/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml b/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml
index a8736fd5a539..1ba607685f5f 100644
--- a/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml
+++ b/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml
@@ -89,9 +89,11 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/leds/common.h>
- spmi {
+
+ pmic {
#address-cells = <1>;
#size-cells = <0>;
+
led-controller@ee00 {
compatible = "qcom,pm8350c-flash-led", "qcom,spmi-flash-led";
reg = <0xee00>;
diff --git a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml
index a38413f8d132..79eb523b8436 100644
--- a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml
+++ b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml
@@ -25,6 +25,24 @@ properties:
- const: qcom,ipq6018-apcs-apps-global
- items:
- enum:
+ - qcom,qcs404-apcs-apps-global
+ - const: qcom,msm8916-apcs-kpss-global
+ - const: syscon
+ - items:
+ - enum:
+ - qcom,msm8976-apcs-kpss-global
+ - const: qcom,msm8994-apcs-kpss-global
+ - const: syscon
+ - items:
+ - enum:
+ - qcom,msm8998-apcs-hmss-global
+ - qcom,sdm660-apcs-hmss-global
+ - qcom,sm4250-apcs-hmss-global
+ - qcom,sm6115-apcs-hmss-global
+ - qcom,sm6125-apcs-hmss-global
+ - const: qcom,msm8994-apcs-kpss-global
+ - items:
+ - enum:
- qcom,sc7180-apss-shared
- qcom,sc8180x-apss-shared
- qcom,sm8150-apss-shared
@@ -34,22 +52,14 @@ properties:
- qcom,msm8916-apcs-kpss-global
- qcom,msm8939-apcs-kpss-global
- qcom,msm8953-apcs-kpss-global
- - qcom,msm8976-apcs-kpss-global
- qcom,msm8994-apcs-kpss-global
- - qcom,qcs404-apcs-apps-global
- qcom,sdx55-apcs-gcc
- const: syscon
- enum:
- qcom,ipq6018-apcs-apps-global
- - qcom,ipq8074-apcs-apps-global
- qcom,msm8996-apcs-hmss-global
- - qcom,msm8998-apcs-hmss-global
- qcom,qcm2290-apcs-hmss-global
- - qcom,sdm660-apcs-hmss-global
- qcom,sdm845-apss-shared
- - qcom,sm4250-apcs-hmss-global
- - qcom,sm6115-apcs-hmss-global
- - qcom,sm6125-apcs-hmss-global
reg:
maxItems: 1
@@ -80,20 +90,38 @@ allOf:
- if:
properties:
compatible:
- enum:
- - qcom,msm8916-apcs-kpss-global
- - qcom,msm8939-apcs-kpss-global
- - qcom,qcs404-apcs-apps-global
+ contains:
+ enum:
+ - qcom,msm8916-apcs-kpss-global
+ then:
+ properties:
+ clocks:
+ items:
+ - description: primary pll parent of the clock driver
+ - description: auxiliary parent
+ clock-names:
+ items:
+ - const: pll
+ - const: aux
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,msm8939-apcs-kpss-global
then:
properties:
clocks:
items:
- description: primary pll parent of the clock driver
- description: auxiliary parent
+ - description: reference clock
clock-names:
items:
- const: pll
- const: aux
+ - const: ref
- if:
properties:
@@ -113,6 +141,7 @@ allOf:
- const: ref
- const: pll
- const: aux
+
- if:
properties:
compatible:
@@ -137,16 +166,10 @@ allOf:
compatible:
enum:
- qcom,msm8953-apcs-kpss-global
- - qcom,msm8976-apcs-kpss-global
- qcom,msm8994-apcs-kpss-global
- qcom,msm8996-apcs-hmss-global
- - qcom,msm8998-apcs-hmss-global
- qcom,qcm2290-apcs-hmss-global
- - qcom,sdm660-apcs-hmss-global
- qcom,sdm845-apss-shared
- - qcom,sm4250-apcs-hmss-global
- - qcom,sm6115-apcs-hmss-global
- - qcom,sm6125-apcs-hmss-global
then:
properties:
clocks: false
@@ -192,7 +215,8 @@ examples:
#define GCC_APSS_AHB_CLK_SRC 1
#define GCC_GPLL0_AO_OUT_MAIN 123
apcs: mailbox@b011000 {
- compatible = "qcom,qcs404-apcs-apps-global", "syscon";
+ compatible = "qcom,qcs404-apcs-apps-global",
+ "qcom,msm8916-apcs-kpss-global", "syscon";
reg = <0x0b011000 0x1000>;
#mbox-cells = <1>;
clocks = <&apcs_hfpll>, <&gcc GCC_GPLL0_AO_OUT_MAIN>;
diff --git a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml
index a35f9483dc71..8f004868aad9 100644
--- a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml
+++ b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml
@@ -35,6 +35,7 @@ properties:
- qcom,sm8450-ipcc
- qcom,sm8550-ipcc
- qcom,sm8650-ipcc
+ - qcom,x1e80100-ipcc
- const: qcom,ipcc
reg:
diff --git a/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml b/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml
index 8b15a0532120..fe83b5cb1278 100644
--- a/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml
+++ b/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml
@@ -37,7 +37,9 @@ maintainers:
properties:
compatible:
- const: xlnx,zynqmp-ipi-mailbox
+ enum:
+ - xlnx,zynqmp-ipi-mailbox
+ - xlnx,versal-ipi-mailbox
method:
description: |
@@ -58,6 +60,12 @@ properties:
'#size-cells':
const: 2
+ reg:
+ maxItems: 2
+
+ reg-names:
+ maxItems: 2
+
xlnx,ipi-id:
description: |
Remote Xilinx IPI agent ID of which the mailbox is connected to.
@@ -76,7 +84,17 @@ patternProperties:
properties:
compatible:
- const: xlnx,zynqmp-ipi-dest-mailbox
+ enum:
+ - xlnx,zynqmp-ipi-dest-mailbox
+ - xlnx,versal-ipi-dest-mailbox
+
+ reg:
+ minItems: 1
+ maxItems: 4
+
+ reg-names:
+ minItems: 1
+ maxItems: 4
xlnx,ipi-id:
description:
@@ -88,23 +106,44 @@ patternProperties:
description:
It contains tx(0) or rx(1) channel IPI id number.
- reg:
- maxItems: 4
-
- reg-names:
- items:
- - const: local_request_region
- - const: local_response_region
- - const: remote_request_region
- - const: remote_response_region
+ allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - xlnx,zynqmp-ipi-dest-mailbox
+ then:
+ properties:
+ reg:
+ maxItems: 4
+
+ reg-names:
+ items:
+ - const: local_request_region
+ - const: local_response_region
+ - const: remote_request_region
+ - const: remote_response_region
+ else:
+ properties:
+ reg:
+ minItems: 1
+ items:
+ - description: Remote IPI agent control register region
+ - description: Remote IPI agent optional message buffers
+
+ reg-names:
+ minItems: 1
+ items:
+ - const: ctrl
+ - const: msg
required:
- compatible
- reg
- reg-names
- "#mbox-cells"
-
-additionalProperties: false
+ - xlnx,ipi-id
required:
- compatible
@@ -113,6 +152,36 @@ required:
- '#size-cells'
- xlnx,ipi-id
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - xlnx,zynqmp-ipi-mailbox
+ then:
+ properties:
+ reg: false
+ reg-names: false
+
+ else:
+ properties:
+ reg:
+ items:
+ - description: Host IPI agent control register region
+ - description: Host IPI agent optional message buffers
+
+ reg-names:
+ items:
+ - const: ctrl
+ - const: msg
+
+ required:
+ - reg
+ - reg-names
+
+additionalProperties: false
+
examples:
- |
#include<dt-bindings/interrupt-controller/arm-gic.h>
@@ -144,4 +213,41 @@ examples:
};
};
+ - |
+ #include<dt-bindings/interrupt-controller/arm-gic.h>
+
+ bus {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ mailbox@ff300000 {
+ compatible = "xlnx,versal-ipi-mailbox";
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ reg = <0x0 0xff300000 0x0 0x1000>,
+ <0x0 0xff990000 0x0 0x1ff>;
+ reg-names = "ctrl", "msg";
+ xlnx,ipi-id = <0>;
+ ranges;
+
+ /* buffered IPI */
+ mailbox@ff340000 {
+ compatible = "xlnx,versal-ipi-dest-mailbox";
+ reg = <0x0 0xff340000 0x0 0x1000>,
+ <0x0 0xff990400 0x0 0x1ff>;
+ reg-names = "ctrl", "msg";
+ #mbox-cells = <1>;
+ xlnx,ipi-id = <4>;
+ };
+
+ /* bufferless IPI */
+ mailbox@ff370000 {
+ compatible = "xlnx,versal-ipi-dest-mailbox";
+ reg = <0x0 0xff370000 0x0 0x1000>;
+ reg-names = "ctrl";
+ #mbox-cells = <1>;
+ xlnx,ipi-id = <7>;
+ };
+ };
+ };
...
diff --git a/Documentation/devicetree/bindings/media/cnm,wave521c.yaml b/Documentation/devicetree/bindings/media/cnm,wave521c.yaml
new file mode 100644
index 000000000000..6d5569e77b7a
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/cnm,wave521c.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/cnm,wave521c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Chips&Media Wave 5 Series multi-standard codec IP
+
+maintainers:
+ - Nas Chung <[email protected]>
+ - Jackson Lee <[email protected]>
+
+description:
+ The Chips&Media WAVE codec IP is a multi format video encoder/decoder
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - ti,k3-j721s2-wave521c
+ - const: cnm,wave521c
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: VCODEC clock
+
+ interrupts:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ sram:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ The VPU uses the SRAM to store some of the reference data instead of
+ storing it on DMA memory. It is mainly used for the purpose of reducing
+ bandwidth.
+
+required:
+ - compatible
+ - reg
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ vpu: video-codec@12345678 {
+ compatible = "ti,k3-j721s2-wave521c", "cnm,wave521c";
+ reg = <0x12345678 0x1000>;
+ clocks = <&clks 42>;
+ interrupts = <42>;
+ sram = <&sram>;
+ };
diff --git a/Documentation/devicetree/bindings/media/i2c/alliedvision,alvium-csi2.yaml b/Documentation/devicetree/bindings/media/i2c/alliedvision,alvium-csi2.yaml
new file mode 100644
index 000000000000..d3329e991d16
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/alliedvision,alvium-csi2.yaml
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/alliedvision,alvium-csi2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allied Vision Alvium Camera
+
+maintainers:
+ - Tommaso Merciai <[email protected]>
+ - Martin Hecht <[email protected]>
+
+allOf:
+ - $ref: /schemas/media/video-interface-devices.yaml#
+
+properties:
+ compatible:
+ const: alliedvision,alvium-csi2
+
+ reg:
+ maxItems: 1
+
+ vcc-ext-in-supply:
+ description: |
+ The regulator that supplies power to the VCC_EXT_IN pins.
+
+ port:
+ description: Digital Output Port
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ link-frequencies: true
+
+ data-lanes:
+ minItems: 1
+ items:
+ - const: 1
+ - const: 2
+ - const: 3
+ - const: 4
+
+ required:
+ - data-lanes
+ - link-frequencies
+
+required:
+ - compatible
+ - reg
+ - vcc-ext-in-supply
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ alvium: camera@3c {
+ compatible = "alliedvision,alvium-csi2";
+ reg = <0x3c>;
+ vcc-ext-in-supply = <&reg_vcc_ext_in>;
+
+ port {
+ alvium_out: endpoint {
+ remote-endpoint = <&mipi_csi_0_in>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <681250000>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml b/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml
index 22a810fc7222..fe312cc6a873 100644
--- a/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml
@@ -15,7 +15,9 @@ description:
properties:
compatible:
- const: asahi-kasei,ak7375
+ enum:
+ - asahi-kasei,ak7345
+ - asahi-kasei,ak7375
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml
new file mode 100644
index 000000000000..f81e7daed67b
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml
@@ -0,0 +1,108 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/galaxycore,gc0308.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Galaxycore GC0308 and GC0309 Image Sensors
+
+maintainers:
+ - Sebastian Reichel <[email protected]>
+
+description: |
+ The GalaxyCore GC0308 (1/6.5") and GC0309 (1/9") are 640x480 VGA sensors
+ programmable through an I2C interface and connected via parallel bus.
+ They include an ISP capable of auto exposure and auto white balance.
+
+allOf:
+ - $ref: ../video-interface-devices.yaml#
+
+properties:
+ compatible:
+ oneOf:
+ - const: galaxycore,gc0308
+ - items:
+ - const: galaxycore,gc0309
+ - const: galaxycore,gc0308
+
+ reg:
+ const: 0x21
+
+ clocks:
+ description: Reference to the xclk clock.
+ maxItems: 1
+
+ reset-gpios:
+ description: GPIO descriptor for the reset pin.
+ maxItems: 1
+
+ powerdown-gpios:
+ description: GPIO descriptor for the powerdown pin.
+ maxItems: 1
+
+ vdd28-supply:
+ description: 2.8V supply
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ description: |
+ Video output port.
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ bus-width: true
+ data-shift: true
+ hsync-active: true
+ vsync-active: true
+ data-active: true
+ pclk-sample: true
+
+ required:
+ - bus-width
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - powerdown-gpios
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ camera-sensor@21 {
+ compatible = "galaxycore,gc0308";
+ reg = <0x21>;
+ clocks = <&camera_clk>;
+ powerdown-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
+ vdd28-supply = <&vdd28>;
+
+ port {
+ gc0308_ep: endpoint {
+ remote-endpoint = <&parallel_from_gc0308>;
+ bus-width = <8>;
+ data-shift = <2>; /* lines 9:2 are used */
+ hsync-active = <1>; /* active high */
+ vsync-active = <1>; /* active high */
+ data-active = <1>; /* active high */
+ pclk-sample = <1>; /* sample on rising edge */
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml
new file mode 100644
index 000000000000..1726ecca4c77
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/galaxycore,gc2145.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Galaxy Core 1/5'' UXGA CMOS Image Sensor
+
+maintainers:
+ - Alain Volmat <[email protected]>
+
+description:
+ The Galaxy Core GC2145 is a 2 Megapixel CMOS image sensor, for mobile
+ phone camera applications and digital camera products. GC2145 incorporates a
+ 1616V x 1232H active pixel array, on-chip 10-bit ADC, and image signal
+ processor allowing AE/AWB/interpolation/de-noise/color-conversion and
+ gamma correction. Bayer RGB, RGB565 and YCbCr 4:2:2 can be provided by the
+ sensor. It is programmable through an I2C interface. Image data is sent
+ either through a parallel interface or through MIPI CSI-2.
+
+allOf:
+ - $ref: ../video-interface-devices.yaml#
+
+properties:
+ compatible:
+ const: galaxycore,gc2145
+
+ reg:
+ const: 0x3c
+
+ clocks:
+ maxItems: 1
+
+ powerdown-gpios:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+
+ iovdd-supply:
+ description: Power Supply for I/O circuits (1.7 - 3V).
+
+ avdd-supply:
+ description: Power for analog circuit/sensor array (2.7 - 3V).
+
+ dvdd-supply:
+ description: Power for digital core (1.7 - 1.9V).
+
+ orientation: true
+
+ rotation: true
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ link-frequencies: true
+
+ required:
+ - link-frequencies
+
+ required:
+ - endpoint
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - powerdown-gpios
+ - reset-gpios
+ - iovdd-supply
+ - avdd-supply
+ - dvdd-supply
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ camera@3c {
+ compatible = "galaxycore,gc2145";
+ reg = <0x3c>;
+ clocks = <&clk_ext_camera>;
+ iovdd-supply = <&scmi_v3v3_sw>;
+ avdd-supply = <&scmi_v3v3_sw>;
+ dvdd-supply = <&scmi_v3v3_sw>;
+ powerdown-gpios = <&mcp23017 3 (GPIO_ACTIVE_LOW | GPIO_PUSH_PULL)>;
+ reset-gpios = <&mcp23017 4 (GPIO_ACTIVE_LOW | GPIO_PUSH_PULL)>;
+
+ port {
+ endpoint {
+ remote-endpoint = <&mipid02_0>;
+ data-lanes = <1 2>;
+ link-frequencies = /bits/ 64 <120000000 192000000 240000000>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/ov8856.yaml b/Documentation/devicetree/bindings/media/i2c/ov8856.yaml
index 57f5e48fd8e0..816dac9c6f60 100644
--- a/Documentation/devicetree/bindings/media/i2c/ov8856.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/ov8856.yaml
@@ -67,19 +67,17 @@ properties:
properties:
data-lanes:
- description: |-
- The driver only supports four-lane operation.
- items:
- - const: 1
- - const: 2
- - const: 3
- - const: 4
-
- link-frequencies:
- description: Frequencies listed are driver, not h/w limitations.
- maxItems: 2
- items:
- enum: [ 360000000, 180000000 ]
+ oneOf:
+ - items:
+ - const: 1
+ - items:
+ - const: 1
+ - const: 2
+ - items:
+ - const: 1
+ - const: 2
+ - const: 3
+ - const: 4
required:
- link-frequencies
diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml
new file mode 100644
index 000000000000..2b6143aff391
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml
@@ -0,0 +1,103 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ovti,ov64a40.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: OmniVision OV64A40 Image Sensor
+
+maintainers:
+ - Jacopo Mondi <[email protected]>
+
+allOf:
+ - $ref: /schemas/media/video-interface-devices.yaml#
+
+properties:
+ compatible:
+ const: ovti,ov64a40
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ avdd-supply:
+ description: Analog voltage supply, 2.8 volts
+
+ dvdd-supply:
+ description: Digital core voltage supply, 1.1 volts
+
+ dovdd-supply:
+ description: Digital I/O voltage supply, 1.8 volts
+
+ powerdown-gpios:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ additionalProperties: false
+
+ properties:
+ bus-type:
+ enum:
+ - 1 # MIPI CSI-2 C-PHY
+ - 4 # MIPI CSI-2 D-PHY
+ data-lanes: true
+ link-frequencies: true
+ clock-noncontinuous: true
+ remote-endpoint: true
+
+ required:
+ - bus-type
+ - data-lanes
+ - link-frequencies
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - port
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ camera@36 {
+ compatible = "ovti,ov64a40";
+ reg = <0x36>;
+ clocks = <&camera_clk>;
+ dovdd-supply = <&vgen4_reg>;
+ avdd-supply = <&vgen3_reg>;
+ dvdd-supply = <&vgen2_reg>;
+ powerdown-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+ rotation = <180>;
+ orientation = <2>;
+
+ port {
+ endpoint {
+ remote-endpoint = <&mipi_csi2_in>;
+ bus-type = <4>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <456000000>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml
index a167dcdb3a32..106c36ee966d 100644
--- a/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml
@@ -32,6 +32,15 @@ properties:
description: Clock frequency from 6 to 27 MHz, 37.125MHz, 74.25MHz
maxItems: 1
+ avdd-supply:
+ description: Analog power supply (2.9V)
+
+ ovdd-supply:
+ description: Interface power supply (1.8V)
+
+ dvdd-supply:
+ description: Digital power supply (1.2V)
+
reset-gpios:
description: Reference to the GPIO connected to the XCLR pin, if any.
maxItems: 1
@@ -79,6 +88,10 @@ examples:
assigned-clock-parents = <&imx335_clk_parent>;
assigned-clock-rates = <24000000>;
+ avdd-supply = <&camera_vdda_2v9>;
+ ovdd-supply = <&camera_vddo_1v8>;
+ dvdd-supply = <&camera_vddd_1v2>;
+
port {
imx335: endpoint {
remote-endpoint = <&cam>;
diff --git a/Documentation/devicetree/bindings/media/i2c/techwell,tw9900.yaml b/Documentation/devicetree/bindings/media/i2c/techwell,tw9900.yaml
new file mode 100644
index 000000000000..e37317f81072
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/techwell,tw9900.yaml
@@ -0,0 +1,137 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/techwell,tw9900.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Techwell TW9900 NTSC/PAL video decoder
+
+maintainers:
+ - Mehdi Djait <[email protected]>
+
+description:
+ The tw9900 is a multi-standard video decoder, supporting NTSC, PAL standards
+ with auto-detection features.
+
+properties:
+ compatible:
+ const: techwell,tw9900
+
+ reg:
+ maxItems: 1
+
+ vdd-supply:
+ description: VDD power supply
+
+ reset-gpios:
+ description: GPIO descriptor for the RESET input pin
+ maxItems: 1
+
+ powerdown-gpios:
+ description: GPIO descriptor for the POWERDOWN input pin
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ description: Analog input port
+
+ properties:
+ endpoint@0:
+ $ref: /schemas/graph.yaml#/properties/endpoint
+ description: CVBS over MUX0
+
+ endpoint@1:
+ $ref: /schemas/graph.yaml#/properties/endpoint
+ description: CVBS over MUX1
+
+ endpoint@2:
+ $ref: /schemas/graph.yaml#/properties/endpoint
+ description: Chroma over CIN0 and Y over MUX0
+
+ endpoint@3:
+ $ref: /schemas/graph.yaml#/properties/endpoint
+ description: Chroma over CIN0 and Y over MUX1
+
+ oneOf:
+ - required:
+ - endpoint@0
+ - required:
+ - endpoint@1
+ - required:
+ - endpoint@2
+ - required:
+ - endpoint@3
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Video port for the decoder output.
+
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - ports
+ - reg
+ - vdd-supply
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/display/sdtv-standards.h>
+ #include <dt-bindings/gpio/gpio.h>
+
+ composite_connector {
+ compatible = "composite-video-connector";
+ label = "tv";
+ sdtv-standards = <(SDTV_STD_PAL | SDTV_STD_NTSC)>;
+
+ port {
+ composite_to_tw9900: endpoint {
+ remote-endpoint = <&tw9900_to_composite>;
+ };
+ };
+ };
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ video-decoder@44 {
+ compatible = "techwell,tw9900";
+ reg = <0x44>;
+
+ vdd-supply = <&tw9900_supply>;
+ reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg = <0>;
+ tw9900_to_composite: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&composite_to_tw9900>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ endpoint {
+ remote-endpoint = <&cif_in>;
+ };
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml b/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml
new file mode 100644
index 000000000000..1978fbb77a6c
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml
@@ -0,0 +1,224 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2023 Ideas on Board
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/thine,thp7312.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: THine THP7312
+
+maintainers:
+ - Paul Elder <paul.elder@@ideasonboard.com>
+
+description:
+ The THP7312 is a standalone ISP controlled over i2c, and is capable of
+ various image processing and correction functions, including 3A control. It
+ can be connected to CMOS image sensors from various vendors, supporting both
+ MIPI CSI-2 and parallel interfaces. It can also output on either MIPI CSI-2
+ or parallel. The hardware is capable of transmitting and receiving MIPI
+ interlaved data strams with data types or multiple virtual channel
+ identifiers.
+
+allOf:
+ - $ref: /schemas/media/video-interface-devices.yaml#
+
+properties:
+ compatible:
+ const: thine,thp7312
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+ description: CLKI clock input
+
+ thine,boot-mode:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 1
+ default: 1
+ description:
+ Boot mode of the THP7312, reflecting the value of the BOOT[0] pin strap.
+ 0 is for the SPI/2-wire slave boot, 1 is for the SPI master boot (from
+ external flash ROM).
+
+ reset-gpios:
+ maxItems: 1
+ description:
+ Reference to the GPIO connected to the RESET_N pin, if any.
+ Must be released (set high) after all supplies are applied.
+
+ vddcore-supply:
+ description:
+ 1.2V supply for core, PLL, MIPI rx and MIPI tx.
+
+ vhtermrx-supply:
+ description:
+ Supply for input (RX). 1.8V for MIPI, or 1.8/2.8/3.3V for parallel.
+
+ vddtx-supply:
+ description:
+ Supply for output (TX). 1.8V for MIPI, or 1.8/2.8/3.3V for parallel.
+
+ vddhost-supply:
+ description:
+ Supply for host interface. 1.8V, 2.8V, or 3.3V.
+
+ vddcmos-supply:
+ description:
+ Supply for sensor interface. 1.8V, 2.8V, or 3.3V.
+
+ vddgpio-0-supply:
+ description:
+ Supply for GPIO_0. 1.8V, 2.8V, or 3.3V.
+
+ vddgpio-1-supply:
+ description:
+ Supply for GPIO_1. 1.8V, 2.8V, or 3.3V.
+
+ orientation: true
+ rotation: true
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ bus-type:
+ const: 4 # CSI-2 D-PHY
+
+ data-lanes:
+ description:
+ This property is for lane reordering between the THP7312 and the
+ SoC. The sensor supports either two-lane, or four-lane operation.
+ If this property is omitted four-lane operation is assumed. For
+ two-lane operation the property must be set to <1 2>.
+ minItems: 2
+ maxItems: 4
+ items:
+ maximum: 4
+
+ sensors:
+ type: object
+ description: List of connected sensors
+
+ properties:
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ patternProperties:
+ "^sensor@[01]$":
+ type: object
+ description:
+ Sensors connected to the first and second input, with one node per
+ sensor.
+
+ properties:
+ thine,model:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ Model of the connected sensors. Must be a valid compatible string.
+
+ reg:
+ description: THP7312 input port number
+ items:
+ - maximum: 1
+
+ data-lanes:
+ $ref: /schemas/media/video-interfaces.yaml#/properties/data-lanes
+ items:
+ maxItems: 4
+ description:
+ This property is for lane reordering between the THP7312 and the imaging
+ sensor that it is connected to.
+
+ required:
+ - reg
+ - data-lanes
+
+ additionalProperties: false
+
+ required:
+ - "#address-cells"
+ - "#size-cells"
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - reset-gpios
+ - clocks
+ - vddcore-supply
+ - vhtermrx-supply
+ - vddtx-supply
+ - vddhost-supply
+ - vddcmos-supply
+ - vddgpio-0-supply
+ - vddgpio-1-supply
+ - sensors
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/media/video-interfaces.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ camera@61 {
+ compatible = "thine,thp7312";
+ reg = <0x61>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&cam1_pins_default>;
+
+ reset-gpios = <&pio 119 GPIO_ACTIVE_LOW>;
+ clocks = <&camera61_clk>;
+
+ vddcore-supply = <&vsys_v4p2>;
+ vhtermrx-supply = <&vsys_v4p2>;
+ vddtx-supply = <&vsys_v4p2>;
+ vddhost-supply = <&vsys_v4p2>;
+ vddcmos-supply = <&vsys_v4p2>;
+ vddgpio-0-supply = <&vsys_v4p2>;
+ vddgpio-1-supply = <&vsys_v4p2>;
+
+ orientation = <0>;
+ rotation = <0>;
+
+ sensors {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@0 {
+ thine,model = "sony,imx258";
+ reg = <0>;
+
+ data-lanes = <4 1 3 2>;
+ };
+ };
+
+ port {
+ thp7312_2_endpoint: endpoint {
+ remote-endpoint = <&mipi_thp7312_2>;
+ bus-type = <MEDIA_BUS_TYPE_CSI2_DPHY>;
+ data-lanes = <4 2 1 3>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml
index e466dff8286d..afcaa427d48b 100644
--- a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml
+++ b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml
@@ -90,15 +90,16 @@ properties:
description: connection point for input on the parallel interface
properties:
- bus-type:
- enum: [5, 6]
-
endpoint:
$ref: video-interfaces.yaml#
unevaluatedProperties: false
- required:
- - bus-type
+ properties:
+ bus-type:
+ enum: [5, 6]
+
+ required:
+ - bus-type
anyOf:
- required:
diff --git a/Documentation/devicetree/bindings/media/samsung,s5p-mfc.yaml b/Documentation/devicetree/bindings/media/samsung,s5p-mfc.yaml
index 084b44582a43..b46cc780703c 100644
--- a/Documentation/devicetree/bindings/media/samsung,s5p-mfc.yaml
+++ b/Documentation/devicetree/bindings/media/samsung,s5p-mfc.yaml
@@ -24,6 +24,7 @@ properties:
- samsung,mfc-v7 # Exynos5420
- samsung,mfc-v8 # Exynos5800
- samsung,mfc-v10 # Exynos7880
+ - tesla,fsd-mfc # Tesla FSD
- items:
- enum:
- samsung,exynos3250-mfc # Exynos3250
@@ -49,7 +50,9 @@ properties:
iommu-names:
minItems: 1
- maxItems: 2
+ items:
+ - const: left
+ - const: right
power-domains:
maxItems: 1
@@ -84,7 +87,7 @@ allOf:
- const: sclk_mfc
iommus:
maxItems: 1
- iommus-names: false
+ iommu-names: false
- if:
properties:
@@ -102,11 +105,9 @@ allOf:
- const: aclk
- const: aclk_xiu
iommus:
- maxItems: 2
- iommus-names:
- items:
- - const: left
- - const: right
+ minItems: 2
+ iommu-names:
+ minItems: 2
- if:
properties:
@@ -123,11 +124,9 @@ allOf:
- const: mfc
- const: sclk_mfc
iommus:
- maxItems: 2
- iommus-names:
- items:
- - const: left
- - const: right
+ minItems: 2
+ iommu-names:
+ minItems: 2
- if:
properties:
@@ -144,11 +143,9 @@ allOf:
items:
- const: mfc
iommus:
- maxItems: 2
- iommus-names:
- items:
- - const: left
- - const: right
+ minItems: 2
+ iommu-names:
+ minItems: 2
- if:
properties:
@@ -161,9 +158,23 @@ allOf:
clocks:
minItems: 1
maxItems: 2
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - tesla,fsd-mfc
+ then:
+ properties:
+ clocks:
+ maxItems: 1
+ clock-names:
+ items:
+ - const: mfc
iommus:
- minItems: 1
maxItems: 2
+ iommus-names: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml
new file mode 100644
index 000000000000..87731f3ce7bd
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/st,stm32-dcmipp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 DCMIPP Digital Camera Memory Interface Pixel Processor
+
+maintainers:
+ - Hugues Fruchet <[email protected]>
+ - Alain Volmat <[email protected]>
+
+properties:
+ compatible:
+ const: st,stm32mp13-dcmipp
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description:
+ DCMIPP supports a single port node with parallel bus.
+
+ properties:
+ endpoint:
+ $ref: video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ bus-type:
+ enum: [5, 6]
+ default: 5
+
+ bus-width:
+ enum: [8, 10, 12, 14]
+ default: 8
+
+ pclk-sample: true
+ hsync-active: true
+ vsync-active: true
+
+ required:
+ - pclk-sample
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - resets
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/stm32mp13-clks.h>
+ #include <dt-bindings/reset/stm32mp13-resets.h>
+ dcmipp@5a000000 {
+ compatible = "st,stm32mp13-dcmipp";
+ reg = <0x5a000000 0x400>;
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&rcc DCMIPP_R>;
+ clocks = <&rcc DCMIPP_K>;
+
+ port {
+ endpoint {
+ remote-endpoint = <&mipid02_2>;
+ bus-width = <8>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ pclk-sample = <0>;
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml b/Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml
new file mode 100644
index 000000000000..c66586d90fa2
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml
@@ -0,0 +1,180 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/starfive,jh7110-camss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Starfive SoC CAMSS ISP
+
+maintainers:
+ - Jack Zhu <[email protected]>
+ - Changhuang Liang <[email protected]>
+
+description:
+ The Starfive CAMSS ISP is a Camera interface for Starfive JH7110 SoC. It
+ consists of a VIN controller (Video In Controller, a top-level control unit)
+ and an ISP.
+
+properties:
+ compatible:
+ const: starfive,jh7110-camss
+
+ reg:
+ maxItems: 2
+
+ reg-names:
+ items:
+ - const: syscon
+ - const: isp
+
+ clocks:
+ maxItems: 7
+
+ clock-names:
+ items:
+ - const: apb_func
+ - const: wrapper_clk_c
+ - const: dvp_inv
+ - const: axiwr
+ - const: mipi_rx0_pxl
+ - const: ispcore_2x
+ - const: isp_axi
+
+ resets:
+ maxItems: 6
+
+ reset-names:
+ items:
+ - const: wrapper_p
+ - const: wrapper_c
+ - const: axird
+ - const: axiwr
+ - const: isp_top_n
+ - const: isp_top_axi
+
+ power-domains:
+ items:
+ - description: JH7110 ISP Power Domain Switch Controller.
+
+ interrupts:
+ maxItems: 4
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description: Input port for receiving DVP data.
+
+ properties:
+ endpoint:
+ $ref: video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ bus-type:
+ enum: [5, 6]
+
+ bus-width:
+ enum: [8, 10, 12]
+
+ data-shift:
+ enum: [0, 2]
+ default: 0
+
+ hsync-active:
+ enum: [0, 1]
+ default: 1
+
+ vsync-active:
+ enum: [0, 1]
+ default: 1
+
+ required:
+ - bus-type
+ - bus-width
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Input port for receiving CSI data.
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - power-domains
+ - interrupts
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ isp@19840000 {
+ compatible = "starfive,jh7110-camss";
+ reg = <0x19840000 0x10000>,
+ <0x19870000 0x30000>;
+ reg-names = "syscon", "isp";
+ clocks = <&ispcrg 0>,
+ <&ispcrg 13>,
+ <&ispcrg 2>,
+ <&ispcrg 12>,
+ <&ispcrg 1>,
+ <&syscrg 51>,
+ <&syscrg 52>;
+ clock-names = "apb_func",
+ "wrapper_clk_c",
+ "dvp_inv",
+ "axiwr",
+ "mipi_rx0_pxl",
+ "ispcore_2x",
+ "isp_axi";
+ resets = <&ispcrg 0>,
+ <&ispcrg 1>,
+ <&ispcrg 10>,
+ <&ispcrg 11>,
+ <&syscrg 41>,
+ <&syscrg 42>;
+ reset-names = "wrapper_p",
+ "wrapper_c",
+ "axird",
+ "axiwr",
+ "isp_top_n",
+ "isp_top_axi";
+ power-domains = <&pwrc 5>;
+ interrupts = <92>, <87>, <88>, <90>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ vin_from_sc2235: endpoint {
+ remote-endpoint = <&sc2235_to_vin>;
+ bus-type = <5>;
+ bus-width = <8>;
+ data-shift = <2>;
+ hsync-active = <1>;
+ vsync-active = <0>;
+ pclk-sample = <1>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ vin_from_csi2rx: endpoint {
+ remote-endpoint = <&csi2rx_to_vin>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mfd/ams,as3711.yaml b/Documentation/devicetree/bindings/mfd/ams,as3711.yaml
new file mode 100644
index 000000000000..ad8649cbb2cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/ams,as3711.yaml
@@ -0,0 +1,223 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/ams,as3711.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Austria MicroSystems AS3711 Quad Buck High Current PMIC with Charger
+
+maintainers:
+ - Guennadi Liakhovetski <[email protected]>
+
+description:
+ AS3711 is an I2C PMIC from Austria MicroSystems with multiple DC/DC and LDO
+ power supplies, a battery charger and an RTC. So far only bindings for the
+ two step-up DC/DC converters are defined.
+
+properties:
+ compatible:
+ const: ams,as3711
+
+ reg:
+ maxItems: 1
+
+ backlight:
+ description:
+ Step-up converter configuration, to be used as a backlight source
+ type: object
+ additionalProperties: false
+ properties:
+ compatible:
+ const: ams,as3711-bl
+
+ su1-dev:
+ description: Framebuffer phandle for the first step-up converter
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ su1-max-uA:
+ description: Maximum current for the first step-up converter
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ su2-dev:
+ description: Framebuffer phandle for the second step-up converter
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ su2-max-uA:
+ description: Maximum current for the second step-up converter
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ su2-feedback-voltage:
+ description: Second step-up converter uses voltage feedback
+ type: boolean
+
+ su2-feedback-curr1:
+ description:
+ Second step-up converter uses CURR1 input for current feedback
+ type: boolean
+
+ su2-feedback-curr2:
+ description:
+ Second step-up converter uses CURR2 input for current feedback
+ type: boolean
+
+ su2-feedback-curr3:
+ description:
+ Second step-up converter uses CURR3 input for current feedback
+ type: boolean
+
+ su2-feedback-curr-auto:
+ description:
+ Second step-up converter uses automatic current feedback selection
+ type: boolean
+
+ su2-fbprot-lx-sd4:
+ description:
+ Second step-up converter uses LX_SD4 for over-voltage protection
+ type: boolean
+
+ su2-fbprot-gpio2:
+ description:
+ Second step-up converter uses GPIO2 for over-voltage protection
+ type: boolean
+
+ su2-fbprot-gpio3:
+ description:
+ Second step-up converter uses GPIO3 for over-voltage protection
+ type: boolean
+
+ su2-fbprot-gpio4:
+ description:
+ Second step-up converter uses GPIO4 for over-voltage protection
+ type: boolean
+
+ su2-auto-curr1:
+ description:
+ Second step-up converter uses CURR1 input for automatic current
+ feedback
+ type: boolean
+
+ su2-auto-curr2:
+ description:
+ Second step-up converter uses CURR2 input for automatic current
+ feedback
+ type: boolean
+
+ su2-auto-curr3:
+ description:
+ Second step-up converter uses CURR3 input for automatic current
+ feedback
+ type: boolean
+
+ required:
+ - compatible
+
+ dependentRequired:
+ # To use the SU1 converter as a backlight source the following two
+ # properties must be provided:
+ su1-dev: [ su1-max-uA ]
+ su1-max-uA: [ su1-dev ]
+
+ # To use the SU2 converter as a backlight source the following two
+ # properties must be provided:
+ su2-dev: [ su2-max-uA ]
+ su2-max-uA: [ su2-dev ]
+
+ su2-feedback-voltage: [ su2-dev ]
+ su2-feedback-curr1: [ su2-dev ]
+ su2-feedback-curr2: [ su2-dev ]
+ su2-feedback-curr3: [ su2-dev ]
+ su2-feedback-curr-auto: [ su2-dev ]
+ su2-fbprot-lx-sd4: [ su2-dev ]
+ su2-fbprot-gpio2: [ su2-dev ]
+ su2-fbprot-gpio3: [ su2-dev ]
+ su2-fbprot-gpio4: [ su2-dev ]
+ su2-auto-curr1: [ su2-feedback-curr-auto ]
+ su2-auto-curr2: [ su2-feedback-curr-auto ]
+ su2-auto-curr3: [ su2-feedback-curr-auto ]
+
+ dependentSchemas:
+ su2-dev:
+ allOf:
+ - oneOf:
+ - required:
+ - su2-feedback-voltage
+ - required:
+ - su2-feedback-curr1
+ - required:
+ - su2-feedback-curr2
+ - required:
+ - su2-feedback-curr3
+ - required:
+ - su2-feedback-curr-auto
+ - oneOf:
+ - required:
+ - su2-fbprot-lx-sd4
+ - required:
+ - su2-fbprot-gpio2
+ - required:
+ - su2-fbprot-gpio3
+ - required:
+ - su2-fbprot-gpio4
+
+ su2-feedback-curr-auto:
+ anyOf:
+ - required:
+ - su2-auto-curr1
+ - required:
+ - su2-auto-curr2
+ - required:
+ - su2-auto-curr3
+
+ regulators:
+ description: Other DC/DC and LDO supplies
+ type: object
+ unevaluatedProperties: false
+ patternProperties:
+ "^(sd[1-4]|ldo[1-8])$":
+ type: object
+ $ref: /schemas/regulator/regulator.yaml#
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmic@40 {
+ compatible = "ams,as3711";
+ reg = <0x40>;
+
+ regulators {
+ sd4 {
+ regulator-name = "1.215V";
+ regulator-min-microvolt = <1215000>;
+ regulator-max-microvolt = <1235000>;
+ };
+ ldo2 {
+ regulator-name = "2.8V CPU";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ };
+
+ backlight {
+ compatible = "ams,as3711-bl";
+ su2-dev = <&lcdc>;
+ su2-max-uA = <36000>;
+ su2-feedback-curr-auto;
+ su2-fbprot-gpio4;
+ su2-auto-curr1;
+ su2-auto-curr2;
+ su2-auto-curr3;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mfd/as3711.txt b/Documentation/devicetree/bindings/mfd/as3711.txt
deleted file mode 100644
index d98cf18c721c..000000000000
--- a/Documentation/devicetree/bindings/mfd/as3711.txt
+++ /dev/null
@@ -1,73 +0,0 @@
-AS3711 is an I2C PMIC from Austria MicroSystems with multiple DCDC and LDO power
-supplies, a battery charger and an RTC. So far only bindings for the two stepup
-DCDC converters are defined. Other DCDC and LDO supplies are configured, using
-standard regulator properties, they must belong to a sub-node, called
-"regulators" and be called "sd1" to "sd4" and "ldo1" to "ldo8." Stepup converter
-configuration should be placed in a subnode, called "backlight."
-
-Compulsory properties:
-- compatible : must be "ams,as3711"
-- reg : specifies the I2C address
-
-To use the SU1 converter as a backlight source the following two properties must
-be provided:
-- su1-dev : framebuffer phandle
-- su1-max-uA : maximum current
-
-To use the SU2 converter as a backlight source the following two properties must
-be provided:
-- su2-dev : framebuffer phandle
-- su1-max-uA : maximum current
-
-Additionally one of these properties must be provided to select the type of
-feedback used:
-- su2-feedback-voltage : voltage feedback is used
-- su2-feedback-curr1 : CURR1 input used for current feedback
-- su2-feedback-curr2 : CURR2 input used for current feedback
-- su2-feedback-curr3 : CURR3 input used for current feedback
-- su2-feedback-curr-auto: automatic current feedback selection
-
-and one of these to select the over-voltage protection pin
-- su2-fbprot-lx-sd4 : LX_SD4 is used for over-voltage protection
-- su2-fbprot-gpio2 : GPIO2 is used for over-voltage protection
-- su2-fbprot-gpio3 : GPIO3 is used for over-voltage protection
-- su2-fbprot-gpio4 : GPIO4 is used for over-voltage protection
-
-If "su2-feedback-curr-auto" is selected, one or more of the following properties
-have to be specified:
-- su2-auto-curr1 : use CURR1 input for current feedback
-- su2-auto-curr2 : use CURR2 input for current feedback
-- su2-auto-curr3 : use CURR3 input for current feedback
-
-Example:
-
-as3711@40 {
- compatible = "ams,as3711";
- reg = <0x40>;
-
- regulators {
- sd4 {
- regulator-name = "1.215V";
- regulator-min-microvolt = <1215000>;
- regulator-max-microvolt = <1235000>;
- };
- ldo2 {
- regulator-name = "2.8V CPU";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- regulator-boot-on;
- };
- };
-
- backlight {
- compatible = "ams,as3711-bl";
- su2-dev = <&lcdc>;
- su2-max-uA = <36000>;
- su2-feedback-curr-auto;
- su2-fbprot-gpio4;
- su2-auto-curr1;
- su2-auto-curr2;
- su2-auto-curr3;
- };
-};
diff --git a/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
index bdff5b653453..6a824351834e 100644
--- a/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
+++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
@@ -17,7 +17,7 @@ description: |
node.
The SPMI controller part is provided by
- Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml
+ Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml
properties:
$nodename:
@@ -42,13 +42,6 @@ properties:
additionalProperties: false
- properties:
- '#address-cells':
- const: 1
-
- '#size-cells':
- const: 0
-
patternProperties:
'^ldo[0-9]+$':
type: object
@@ -66,72 +59,75 @@ additionalProperties: false
examples:
- |
+ #include <dt-bindings/spmi/spmi.h>
- pmic: pmic@0 {
- compatible = "hisilicon,hi6421v600-spmi";
- reg = <0 0>;
-
- #interrupt-cells = <2>;
- interrupt-controller;
- interrupt-parent = <&gpio28>;
- interrupts = <0 0>;
-
- regulators {
- #address-cells = <1>;
+ spmi {
+ #address-cells = <2>;
#size-cells = <0>;
- ldo3: ldo3 {
- regulator-name = "ldo3";
- regulator-min-microvolt = <1500000>;
- regulator-max-microvolt = <2000000>;
- regulator-boot-on;
- };
-
- ldo4: ldo4 {
- regulator-name = "ldo4";
- regulator-min-microvolt = <1725000>;
- regulator-max-microvolt = <1900000>;
- regulator-boot-on;
- };
-
- ldo9: ldo9 {
- regulator-name = "ldo9";
- regulator-min-microvolt = <1750000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
- };
-
- ldo15: ldo15 {
- regulator-name = "ldo15";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3000000>;
- regulator-always-on;
- };
-
- ldo16: ldo16 {
- regulator-name = "ldo16";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3000000>;
- regulator-boot-on;
- };
-
- ldo17: ldo17 {
- regulator-name = "ldo17";
- regulator-min-microvolt = <2500000>;
- regulator-max-microvolt = <3300000>;
- };
-
- ldo33: ldo33 {
- regulator-name = "ldo33";
- regulator-min-microvolt = <2500000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
- };
-
- ldo34: ldo34 {
- regulator-name = "ldo34";
- regulator-min-microvolt = <2600000>;
- regulator-max-microvolt = <3300000>;
+ pmic@0 {
+ compatible = "hisilicon,hi6421v600-spmi";
+ reg = <0 SPMI_USID>;
+
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ interrupt-parent = <&gpio28>;
+ interrupts = <0 0>;
+
+ regulators {
+ ldo3 {
+ regulator-name = "ldo3";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-boot-on;
+ };
+
+ ldo4 {
+ regulator-name = "ldo4";
+ regulator-min-microvolt = <1725000>;
+ regulator-max-microvolt = <1900000>;
+ regulator-boot-on;
+ };
+
+ ldo9 {
+ regulator-name = "ldo9";
+ regulator-min-microvolt = <1750000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ ldo15 {
+ regulator-name = "ldo15";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ };
+
+ ldo16 {
+ regulator-name = "ldo16";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ };
+
+ ldo17 {
+ regulator-name = "ldo17";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo33 {
+ regulator-name = "ldo33";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ ldo34 {
+ regulator-name = "ldo34";
+ regulator-min-microvolt = <2600000>;
+ regulator-max-microvolt = <3300000>;
+ };
+ };
};
- };
};
diff --git a/Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml b/Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml
index 9e4eed34dae8..0c75d8bde568 100644
--- a/Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml
+++ b/Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml
@@ -99,10 +99,12 @@ examples:
- |
#include <dt-bindings/mfd/qcom-pm8008.h>
#include <dt-bindings/interrupt-controller/irq.h>
- qupv3_se13_i2c {
+
+ i2c {
#address-cells = <1>;
#size-cells = <0>;
- pm8008i@8 {
+
+ pmic@8 {
compatible = "qcom,pm8008";
reg = <0x8>;
#address-cells = <1>;
diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
index 9fa568603930..8103fb61a16c 100644
--- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
+++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
@@ -66,6 +66,7 @@ properties:
- qcom,pm8841
- qcom,pm8909
- qcom,pm8916
+ - qcom,pm8937
- qcom,pm8941
- qcom,pm8950
- qcom,pm8953
@@ -134,9 +135,15 @@ patternProperties:
type: object
$ref: /schemas/sound/qcom,pm8916-wcd-analog-codec.yaml#
+ "^battery@[0-9a-f]+$":
+ type: object
+ oneOf:
+ - $ref: /schemas/power/supply/qcom,pm8916-bms-vm.yaml#
+
"^charger@[0-9a-f]+$":
type: object
oneOf:
+ - $ref: /schemas/power/supply/qcom,pm8916-lbc.yaml#
- $ref: /schemas/power/supply/qcom,pm8941-charger.yaml#
- $ref: /schemas/power/supply/qcom,pm8941-coincell.yaml#
- $ref: /schemas/power/supply/qcom,pmi8998-charger.yaml#
diff --git a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml
index 33c3d023a106..798705ab6a46 100644
--- a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml
+++ b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml
@@ -29,6 +29,8 @@ properties:
- qcom,sdx65-tcsr
- qcom,sm4450-tcsr
- qcom,sm8150-tcsr
+ - qcom,sm8250-tcsr
+ - qcom,sm8350-tcsr
- qcom,sm8450-tcsr
- qcom,tcsr-apq8064
- qcom,tcsr-apq8084
diff --git a/Documentation/devicetree/bindings/mfd/sprd,ums512-glbreg.yaml b/Documentation/devicetree/bindings/mfd/sprd,ums512-glbreg.yaml
index 996bd4a17ca3..a750fa23d7e7 100644
--- a/Documentation/devicetree/bindings/mfd/sprd,ums512-glbreg.yaml
+++ b/Documentation/devicetree/bindings/mfd/sprd,ums512-glbreg.yaml
@@ -19,7 +19,9 @@ description:
properties:
compatible:
items:
- - const: sprd,ums512-glbregs
+ - enum:
+ - sprd,ums512-glbregs
+ - sprd,ums9620-glbregs
- const: syscon
- const: simple-mfd
diff --git a/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml b/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml
index 23a63265be3c..70b5dfce07d2 100644
--- a/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml
+++ b/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml
@@ -61,8 +61,6 @@ required:
- interrupts
- clocks
- clock-names
- - dmas
- - dma-names
additionalProperties: false
diff --git a/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml b/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml
index 8cc951feb7df..59b83ea5e05e 100644
--- a/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml
+++ b/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml
@@ -12,7 +12,7 @@ maintainers:
properties:
compatible:
- const: "fsl,dpaa2-console"
+ const: fsl,dpaa2-console
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
index 3e99801f77d2..9075add020bf 100644
--- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
+++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml
@@ -226,8 +226,8 @@ examples:
interrupt-parent = <&gic>;
interrupts = <0 48 4>;
reg = <0xff160000 0x1000>;
- clocks = <&clk200>, <&clk200>;
- clock-names = "clk_xin", "clk_ahb";
+ clocks = <&clk200>, <&clk200>, <&clk1200>;
+ clock-names = "clk_xin", "clk_ahb", "gate";
clock-output-names = "clk_out_sd0", "clk_in_sd0";
#clock-cells = <1>;
clk-phase-sd-hs = <63>, <72>;
@@ -239,8 +239,8 @@ examples:
interrupt-parent = <&gic>;
interrupts = <0 126 4>;
reg = <0xf1040000 0x10000>;
- clocks = <&clk200>, <&clk200>;
- clock-names = "clk_xin", "clk_ahb";
+ clocks = <&clk200>, <&clk200>, <&clk1200>;
+ clock-names = "clk_xin", "clk_ahb", "gate";
clock-output-names = "clk_out_sd0", "clk_in_sd0";
#clock-cells = <1>;
clk-phase-sd-hs = <132>, <60>;
diff --git a/Documentation/devicetree/bindings/mmc/arm,pl18x.yaml b/Documentation/devicetree/bindings/mmc/arm,pl18x.yaml
index 2459a55ed540..940b12688167 100644
--- a/Documentation/devicetree/bindings/mmc/arm,pl18x.yaml
+++ b/Documentation/devicetree/bindings/mmc/arm,pl18x.yaml
@@ -203,7 +203,7 @@ examples:
bus-width = <4>;
cap-sd-highspeed;
cap-mmc-highspeed;
- cd-gpios = <&gpio2 31 0x4>;
+ cd-gpios = <&gpio2 31 0x4>;
st,sig-dir-dat0;
st,sig-dir-dat2;
st,sig-dir-cmd;
diff --git a/Documentation/devicetree/bindings/mmc/brcm,sdhci-brcmstb.yaml b/Documentation/devicetree/bindings/mmc/brcm,sdhci-brcmstb.yaml
index c028039bc477..cbd3d6c6c77f 100644
--- a/Documentation/devicetree/bindings/mmc/brcm,sdhci-brcmstb.yaml
+++ b/Documentation/devicetree/bindings/mmc/brcm,sdhci-brcmstb.yaml
@@ -20,10 +20,8 @@ properties:
- const: brcm,sdhci-brcmstb
- items:
- enum:
+ - brcm,bcm74165b0-sdhci
- brcm,bcm7445-sdhci
- - const: brcm,sdhci-brcmstb
- - items:
- - enum:
- brcm,bcm7425-sdhci
- const: brcm,sdhci-brcmstb
diff --git a/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.yaml b/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.yaml
index 3a8e74894ae0..cfe6237716f4 100644
--- a/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.yaml
+++ b/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.yaml
@@ -27,7 +27,9 @@ properties:
- marvell,armada-ap806-sdhci
- items:
- - const: marvell,armada-ap807-sdhci
+ - enum:
+ - marvell,armada-ap807-sdhci
+ - marvell,ac5-sdhci
- const: marvell,armada-ap806-sdhci
- items:
diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml
index 3fffa467e4e1..c532ec92d2d9 100644
--- a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml
+++ b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml
@@ -145,6 +145,15 @@ properties:
minimum: 0
maximum: 7
+ mediatek,tuning-step:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ Some SoCs need extend tuning step for better delay value to avoid CRC issue.
+ If not present, default tuning step is 32. For eMMC and SD, this can yield
+ satisfactory calibration results in most cases.
+ enum: [32, 64]
+ default: 32
+
resets:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml b/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml
index 94e228787630..f7a4c6bc70f6 100644
--- a/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml
+++ b/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml
@@ -56,7 +56,7 @@ properties:
- renesas,sdhi-r8a77980 # R-Car V3H
- renesas,sdhi-r8a77990 # R-Car E3
- renesas,sdhi-r8a77995 # R-Car D3
- - renesas,sdhi-r9a07g043 # RZ/G2UL
+ - renesas,sdhi-r9a07g043 # RZ/G2UL and RZ/Five
- renesas,sdhi-r9a07g044 # RZ/G2{L,LC}
- renesas,sdhi-r9a07g054 # RZ/V2L
- renesas,sdhi-r9a08g045 # RZ/G3S
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml
index 86fae733d9a0..c24c537f62b1 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml
@@ -22,6 +22,8 @@ properties:
- items:
- enum:
- qcom,apq8084-sdhci
+ - qcom,ipq4019-sdhci
+ - qcom,ipq8074-sdhci
- qcom,msm8226-sdhci
- qcom,msm8953-sdhci
- qcom,msm8974-sdhci
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml b/Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml
index 09455f9fa8de..4869ddef36fd 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml
+++ b/Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml
@@ -18,7 +18,7 @@ allOf:
const: marvell,armada-380-sdhci
then:
properties:
- regs:
+ reg:
minItems: 3
reg-names:
minItems: 3
@@ -26,7 +26,7 @@ allOf:
- reg-names
else:
properties:
- regs:
+ reg:
maxItems: 1
reg-names:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
index a43eb837f8da..42804d955293 100644
--- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
+++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml
@@ -19,6 +19,7 @@ properties:
- rockchip,rk3568-dwcmshc
- rockchip,rk3588-dwcmshc
- snps,dwcmshc-sdhci
+ - thead,th1520-dwcmshc
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.yaml b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.yaml
index b13b5166d20a..a6292777e376 100644
--- a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.yaml
+++ b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.yaml
@@ -35,6 +35,9 @@ properties:
- const: biu
- const: ciu
+ iommus:
+ maxItems: 1
+
altr,sysmgr-syscon:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
@@ -62,6 +65,7 @@ allOf:
altr,sysmgr-syscon: true
else:
properties:
+ iommus: false
altr,sysmgr-syscon: false
required:
diff --git a/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml b/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
index 66a95191bd77..1bacc0eeff75 100644
--- a/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
+++ b/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml
@@ -15,15 +15,22 @@ description:
properties:
compatible:
- items:
- - enum:
- - mediatek,mt7622-sgmiisys
- - mediatek,mt7629-sgmiisys
- - mediatek,mt7981-sgmiisys_0
- - mediatek,mt7981-sgmiisys_1
- - mediatek,mt7986-sgmiisys_0
- - mediatek,mt7986-sgmiisys_1
- - const: syscon
+ oneOf:
+ - items:
+ - enum:
+ - mediatek,mt7622-sgmiisys
+ - mediatek,mt7629-sgmiisys
+ - mediatek,mt7981-sgmiisys_0
+ - mediatek,mt7981-sgmiisys_1
+ - mediatek,mt7986-sgmiisys_0
+ - mediatek,mt7986-sgmiisys_1
+ - const: syscon
+ - items:
+ - enum:
+ - mediatek,mt7988-sgmiisys0
+ - mediatek,mt7988-sgmiisys1
+ - const: simple-mfd
+ - const: syscon
reg:
maxItems: 1
@@ -35,11 +42,51 @@ properties:
description: Invert polarity of the SGMII data lanes
type: boolean
+ pcs:
+ type: object
+ description: MediaTek LynxI HSGMII PCS
+ properties:
+ compatible:
+ const: mediatek,mt7988-sgmii
+
+ clocks:
+ maxItems: 3
+
+ clock-names:
+ items:
+ - const: sgmii_sel
+ - const: sgmii_tx
+ - const: sgmii_rx
+
+ required:
+ - compatible
+ - clocks
+ - clock-names
+
+ additionalProperties: false
+
required:
- compatible
- reg
- '#clock-cells'
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - mediatek,mt7988-sgmiisys0
+ - mediatek,mt7988-sgmiisys1
+
+ then:
+ required:
+ - pcs
+
+ else:
+ properties:
+ pcs: false
+
additionalProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/net/sff,sfp.yaml b/Documentation/devicetree/bindings/net/sff,sfp.yaml
index 973e478a399d..bf6cbc7c2ba3 100644
--- a/Documentation/devicetree/bindings/net/sff,sfp.yaml
+++ b/Documentation/devicetree/bindings/net/sff,sfp.yaml
@@ -120,7 +120,7 @@ examples:
pinctrl-names = "default";
pinctrl-0 = <&cps_sfpp0_pins>;
tx-disable-gpios = <&cps_gpio1 29 GPIO_ACTIVE_HIGH>;
- tx-fault-gpios = <&cps_gpio1 26 GPIO_ACTIVE_HIGH>;
+ tx-fault-gpios = <&cps_gpio1 26 GPIO_ACTIVE_HIGH>;
};
mdio {
diff --git a/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml b/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml
index a69de3e92282..92bfe25f0571 100644
--- a/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml
+++ b/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml
@@ -24,6 +24,7 @@ properties:
- st,stm32f4-otp
- st,stm32mp13-bsec
- st,stm32mp15-bsec
+ - st,stm32mp25-bsec
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
index 7e15aae7d69e..22491f7f8852 100644
--- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml
@@ -64,6 +64,24 @@ properties:
aspm-no-l0s: true
+ brcm,clkreq-mode:
+ description: A string that determines the operating
+ clkreq mode of the PCIe RC HW with respect to controlling the refclk
+ signal. There are three different modes -- "safe", which drives the
+ refclk signal unconditionally and will work for all devices but does
+ not provide any power savings; "no-l1ss" -- which provides Clock
+ Power Management, L0s, and L1, but cannot provide L1 substate (L1SS)
+ power savings. If the downstream device connected to the RC is L1SS
+ capable AND the OS enables L1SS, all PCIe traffic may abruptly halt,
+ potentially hanging the system; "default" -- which provides L0s, L1,
+ and L1SS, but not compliant to provide Clock Power Management;
+ specifically, may not be able to meet the T_CLRon max timing of 400ns
+ as specified in "Dynamic Clock Control", section 3.2.5.2.2 PCI
+ Express Mini CEM 2.1 specification. This situation is atypical and
+ should happen only with older devices.
+ $ref: /schemas/types.yaml#/definitions/string
+ enum: [ safe, no-l1ss, default ]
+
brcm,scb-sizes:
description: u64 giving the 64bit PCIe memory
viewport size of a memory controller. There may be up to
diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml
index eadba38171e1..a93ab3b54066 100644
--- a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml
@@ -42,6 +42,10 @@ properties:
- qcom,pcie-sm8450-pcie1
- qcom,pcie-sm8550
- items:
+ - enum:
+ - qcom,pcie-sm8650
+ - const: qcom,pcie-sm8550
+ - items:
- const: qcom,pcie-msm8998
- const: qcom,pcie-msm8996
@@ -62,7 +66,8 @@ properties:
maxItems: 8
iommu-map:
- maxItems: 2
+ minItems: 1
+ maxItems: 16
# Common definitions for clocks, clock-names and reset.
# Platform constraints are described later.
@@ -88,7 +93,7 @@ properties:
minItems: 1
maxItems: 12
- resets-names:
+ reset-names:
minItems: 1
maxItems: 12
@@ -483,6 +488,33 @@ allOf:
compatible:
contains:
enum:
+ - qcom,pcie-sc8180x
+ then:
+ properties:
+ clocks:
+ minItems: 8
+ maxItems: 8
+ clock-names:
+ items:
+ - const: pipe # PIPE clock
+ - const: aux # Auxiliary clock
+ - const: cfg # Configuration clock
+ - const: bus_master # Master AXI clock
+ - const: bus_slave # Slave AXI clock
+ - const: slave_q2a # Slave Q2A clock
+ - const: ref # REFERENCE clock
+ - const: tbu # PCIe TBU clock
+ resets:
+ maxItems: 1
+ reset-names:
+ items:
+ - const: pci # PCIe core reset
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
- qcom,pcie-sdm845
then:
oneOf:
@@ -526,8 +558,33 @@ allOf:
compatible:
contains:
enum:
- - qcom,pcie-sc8180x
- qcom,pcie-sm8150
+ then:
+ properties:
+ clocks:
+ minItems: 8
+ maxItems: 8
+ clock-names:
+ items:
+ - const: pipe # PIPE clock
+ - const: aux # Auxiliary clock
+ - const: cfg # Configuration clock
+ - const: bus_master # Master AXI clock
+ - const: bus_slave # Slave AXI clock
+ - const: slave_q2a # Slave Q2A clock
+ - const: tbu # PCIe TBU clock
+ - const: ref # REFERENCE clock
+ resets:
+ maxItems: 1
+ reset-names:
+ items:
+ - const: pci # PCIe core reset
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
- qcom,pcie-sm8250
then:
oneOf:
diff --git a/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml b/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml
index 8fdfbc763d70..b6a7cb32f61e 100644
--- a/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml
+++ b/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml
@@ -68,6 +68,15 @@ properties:
phy-names:
const: pcie
+ vpcie1v5-supply:
+ description: The 1.5v regulator to use for PCIe.
+
+ vpcie3v3-supply:
+ description: The 3.3v regulator to use for PCIe.
+
+ vpcie12v-supply:
+ description: The 12v regulator to use for PCIe.
+
required:
- compatible
- reg
@@ -121,5 +130,7 @@ examples:
clock-names = "pcie", "pcie_bus";
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
resets = <&cpg 319>;
+ vpcie3v3-supply = <&pcie_3v3>;
+ vpcie12v-supply = <&pcie_12v>;
};
};
diff --git a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
index 1ae8dcfa072c..5f719218c472 100644
--- a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
@@ -49,6 +49,7 @@ properties:
- description: APB clock for PCIe
- description: Auxiliary clock for PCIe
- description: PIPE clock
+ - description: Reference clock for PCIe
clock-names:
minItems: 5
@@ -59,6 +60,7 @@ properties:
- const: pclk
- const: aux
- const: pipe
+ - const: ref
interrupts:
items:
diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
index 62292185fe2e..97f2579ea908 100644
--- a/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
+++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml
@@ -10,13 +10,11 @@ title: TI J721E PCI EP (PCIe Wrapper)
maintainers:
- Kishon Vijay Abraham I <[email protected]>
-allOf:
- - $ref: cdns-pcie-ep.yaml#
-
properties:
compatible:
oneOf:
- const: ti,j721e-pcie-ep
+ - const: ti,j784s4-pcie-ep
- description: PCIe EP controller in AM64
items:
- const: ti,am64-pcie-ep
@@ -65,6 +63,41 @@ properties:
items:
- const: link_state
+allOf:
+ - $ref: cdns-pcie-ep.yaml#
+ - if:
+ properties:
+ compatible:
+ enum:
+ - ti,am64-pcie-ep
+ then:
+ properties:
+ num-lanes:
+ const: 1
+
+ - if:
+ properties:
+ compatible:
+ enum:
+ - ti,j7200-pcie-ep
+ - ti,j721e-pcie-ep
+ then:
+ properties:
+ num-lanes:
+ minimum: 1
+ maximum: 2
+
+ - if:
+ properties:
+ compatible:
+ enum:
+ - ti,j784s4-pcie-ep
+ then:
+ properties:
+ num-lanes:
+ minimum: 1
+ maximum: 4
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
index a2c5eaea57f5..b7a534cef24d 100644
--- a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
+++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml
@@ -10,13 +10,11 @@ title: TI J721E PCI Host (PCIe Wrapper)
maintainers:
- Kishon Vijay Abraham I <[email protected]>
-allOf:
- - $ref: cdns-pcie-host.yaml#
-
properties:
compatible:
oneOf:
- const: ti,j721e-pcie-host
+ - const: ti,j784s4-pcie-host
- description: PCIe controller in AM64
items:
- const: ti,am64-pcie-host
@@ -94,6 +92,41 @@ properties:
interrupts:
maxItems: 1
+allOf:
+ - $ref: cdns-pcie-host.yaml#
+ - if:
+ properties:
+ compatible:
+ enum:
+ - ti,am64-pcie-host
+ then:
+ properties:
+ num-lanes:
+ const: 1
+
+ - if:
+ properties:
+ compatible:
+ enum:
+ - ti,j7200-pcie-host
+ - ti,j721e-pcie-host
+ then:
+ properties:
+ num-lanes:
+ minimum: 1
+ maximum: 2
+
+ - if:
+ properties:
+ compatible:
+ enum:
+ - ti,j784s4-pcie-host
+ then:
+ properties:
+ num-lanes:
+ minimum: 1
+ maximum: 4
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml b/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
index 53da2edd7c9a..120e3bb1e545 100644
--- a/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml
@@ -83,7 +83,7 @@ examples:
<0x0 0x28050000 0x0 0x00010000>,
<0x0 0x24200000 0x0 0x00002000>,
<0x0 0x24162000 0x0 0x00001000>;
- reg-names = "dbi", "config", "ulreg", "smu", "mpu";
+ reg-names = "dbi", "config", "ulreg", "smu", "mpu";
device_type = "pci";
bus-range = <0x00 0xff>;
num-lanes = <2>;
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml
index 45a307d3ce16..c11495524dd2 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml
@@ -31,6 +31,7 @@ properties:
- ti,omap3-padconf
- ti,omap4-padconf
- ti,omap5-padconf
+ - ti,j7200-padconf
- const: pinctrl-single
reg:
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq5018-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq5018-tlmm.yaml
index fad0118fd521..23300606547c 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq5018-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq5018-tlmm.yaml
@@ -23,13 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 24
@@ -95,7 +88,10 @@ required:
- compatible
- reg
-additionalProperties: false
+allOf:
+ - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml#
+
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml
index 3d3086ae1ba6..e571cd64418f 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml
@@ -26,13 +26,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 27
@@ -100,7 +93,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml
index 7c3e5e043f07..ed00fbaec11b 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml
@@ -22,12 +22,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
-
patternProperties:
"-state$":
oneOf:
@@ -100,7 +94,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml
index e053fbd588b5..6f90dbbdbdcc 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml
@@ -23,13 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 35
@@ -103,7 +96,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq9574-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq9574-tlmm.yaml
index e5e9962b2174..bca903b5da6d 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq9574-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq9574-tlmm.yaml
@@ -23,13 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 33
@@ -97,7 +90,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,lpass-lpi-common.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,lpass-lpi-common.yaml
new file mode 100644
index 000000000000..3b5045730471
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,lpass-lpi-common.yaml
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/qcom,lpass-lpi-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SoC LPASS LPI TLMM Common Properties
+
+maintainers:
+ - Bjorn Andersson <[email protected]>
+ - Srinivas Kandagatla <[email protected]>
+ - Krzysztof Kozlowski <[email protected]>
+
+description:
+ Common properties for the Top Level Mode Multiplexer pin controllers in the
+ Low Power Audio SubSystem (LPASS) Low Power Island (LPI) of Qualcomm SoCs.
+
+properties:
+ gpio-controller: true
+
+ "#gpio-cells":
+ description:
+ Specifying the pin number and flags, as defined in
+ include/dt-bindings/gpio/gpio.h
+ const: 2
+
+ gpio-ranges:
+ maxItems: 1
+
+required:
+ - gpio-controller
+ - "#gpio-cells"
+ - gpio-ranges
+
+allOf:
+ - $ref: pinctrl.yaml#
+
+additionalProperties: true
+
+$defs:
+ qcom-tlmm-state:
+ properties:
+ drive-strength:
+ enum: [2, 4, 6, 8, 10, 12, 14, 16]
+ default: 2
+ description:
+ Selects the drive strength for the specified pins, in mA.
+
+ slew-rate:
+ enum: [0, 1, 2, 3]
+ default: 0
+ description: |
+ 0: No adjustments
+ 1: Higher Slew rate (faster edges)
+ 2: Lower Slew rate (slower edges)
+ 3: Reserved (No adjustments)
+
+ bias-bus-hold: true
+ bias-pull-down: true
+ bias-pull-up: true
+ bias-disable: true
+ input-enable: true
+ output-high: true
+ output-low: true
+
+ required:
+ - pins
+ - function
+
+ allOf:
+ - $ref: pincfg-node.yaml#
+ - $ref: pinmux-node.yaml#
+
+ additionalProperties: true
+
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml
index 5ece3b9d676b..bd3cbb44c99a 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml
@@ -25,19 +25,7 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
gpio-reserved-ranges: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
-required:
- - compatible
- - reg
-
-additionalProperties: false
patternProperties:
"-state$":
@@ -110,6 +98,12 @@ $defs:
required:
- pins
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml
index 5885aee95c98..299e0b4b0ab4 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml
@@ -23,18 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- '#interrupt-cells': true
- gpio-controller: true
- '#gpio-cells': true
- gpio-ranges: true
-
-required:
- - compatible
- - reg
-
-additionalProperties: false
-
patternProperties:
"-state$":
oneOf:
@@ -74,6 +62,12 @@ $defs:
required:
- pins
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml
index a602bf0d27fb..68d3fa2105b8 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml
@@ -23,12 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
-
gpio-reserved-ranges:
maxItems: 1
@@ -82,7 +76,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml
index a05971611780..61f5be21f30c 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml
@@ -23,13 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 86
@@ -92,7 +85,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml
index 5095e86fe9a2..295dd5fcf4c3 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml
@@ -25,19 +25,7 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
gpio-reserved-ranges: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
-required:
- - compatible
- - reg
-
-additionalProperties: false
patternProperties:
"-state$":
@@ -108,6 +96,12 @@ $defs:
required:
- pins
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml
index 063d004967bb..904af87f9eaf 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml
@@ -23,13 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 61
@@ -114,7 +107,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml
index 798aac9e6e31..8a3a962f6c00 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml
@@ -22,12 +22,7 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
gpio-reserved-ranges: true
- "#gpio-cells": true
- gpio-ranges: true
patternProperties:
"-state$":
@@ -117,7 +112,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml
index 9172b50f7a98..46618740bd31 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml
@@ -23,13 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 76
@@ -108,7 +101,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml
index 8a3be65c51ed..840fdaabde12 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml
@@ -23,13 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 73
@@ -124,7 +117,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml
index ca95de0b87a6..d4391c194ff7 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml
@@ -23,13 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 73
@@ -104,7 +97,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml
index 41525ecfa8e3..fa90981db40b 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml
@@ -25,13 +25,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 73
@@ -114,7 +107,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml
index 59d406b60957..c5010c175b23 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml
@@ -23,13 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 75
@@ -133,7 +126,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml
index bd6d7caf499a..bcaa231adaf7 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml
@@ -23,13 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 75
@@ -118,7 +111,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml
index 80f960671857..fe717d8d4798 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml
@@ -158,34 +158,40 @@ examples:
- |
#include <dt-bindings/pinctrl/qcom,pmic-mpp.h>
- pm8841_mpp: mpps@a000 {
- compatible = "qcom,pm8841-mpp", "qcom,spmi-mpp";
- reg = <0xa000 0>;
- gpio-controller;
- #gpio-cells = <2>;
- gpio-ranges = <&pm8841_mpp 0 0 4>;
- gpio-line-names = "VDD_PX_BIAS", "WLAN_LED_CTRL",
- "BT_LED_CTRL", "GPIO-F";
- interrupt-controller;
- #interrupt-cells = <2>;
-
- pinctrl-names = "default";
- pinctrl-0 = <&pm8841_default>;
-
- mpp1-state {
- pins = "mpp1";
- function = "digital";
- input-enable;
- power-source = <PM8841_MPP_S3>;
- };
-
- default-state {
- gpio-pins {
- pins = "mpp1", "mpp2", "mpp3", "mpp4";
- function = "digital";
- input-enable;
- power-source = <PM8841_MPP_S3>;
+ pmic {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pm8841_mpp: mpps@a000 {
+ compatible = "qcom,pm8841-mpp", "qcom,spmi-mpp";
+ reg = <0xa000>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pm8841_mpp 0 0 4>;
+ gpio-line-names = "VDD_PX_BIAS", "WLAN_LED_CTRL",
+ "BT_LED_CTRL", "GPIO-F";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pm8841_default>;
+
+ mpp1-state {
+ pins = "mpp1";
+ function = "digital";
+ input-enable;
+ power-source = <PM8841_MPP_S3>;
+ };
+
+ default-state {
+ gpio-pins {
+ pins = "mpp1", "mpp2", "mpp3", "mpp4";
+ function = "digital";
+ input-enable;
+ power-source = <PM8841_MPP_S3>;
+ };
+ };
};
- };
};
...
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml
index c323f6d495a4..e123beb33aef 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml
@@ -22,13 +22,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
patternProperties:
"-state$":
oneOf:
@@ -92,7 +85,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml
index b1b9cd319e50..4009501b3414 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml
@@ -29,13 +29,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 60
@@ -130,7 +123,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml
index 237cac4f6ce1..88afeae530c6 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml
@@ -23,10 +23,8 @@ properties:
reg:
maxItems: 1
- interrupts: true
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
+ interrupts:
+ maxItems: 1
gpio-reserved-ranges:
minItems: 1
@@ -35,10 +33,6 @@ properties:
gpio-line-names:
maxItems: 151
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
patternProperties:
"-state$":
oneOf:
@@ -101,7 +95,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml
index 2173c5255638..e9abbf2c0689 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml
@@ -22,13 +22,8 @@ properties:
reg:
maxItems: 1
- interrupts: true
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
+ interrupts:
+ maxItems: 1
gpio-reserved-ranges:
minItems: 1
@@ -37,12 +32,6 @@ properties:
gpio-line-names:
maxItems: 148
-required:
- - compatible
- - reg
-
-additionalProperties: false
-
patternProperties:
"-state$":
oneOf:
@@ -108,6 +97,12 @@ $defs:
required:
- pins
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml
index 573e459b1c44..5606f2136ad1 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml
@@ -29,13 +29,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 60
@@ -112,7 +105,7 @@ required:
- reg
- reg-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml
index 00c5a00e35fc..08801cc4e476 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml
@@ -20,16 +20,6 @@ properties:
reg:
maxItems: 2
- gpio-controller: true
-
- "#gpio-cells":
- description: Specifying the pin number and flags, as defined in
- include/dt-bindings/gpio/gpio.h
- const: 2
-
- gpio-ranges:
- maxItems: 1
-
patternProperties:
"-state$":
oneOf:
@@ -45,7 +35,8 @@ $defs:
description:
Pinctrl node's client devices use subnodes for desired pin configuration.
Client device subnodes use below standard properties.
- $ref: /schemas/pinctrl/pincfg-node.yaml
+ $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
properties:
pins:
@@ -68,42 +59,14 @@ $defs:
Specify the alternative function to be configured for the specified
pins.
- drive-strength:
- enum: [2, 4, 6, 8, 10, 12, 14, 16]
- default: 2
- description:
- Selects the drive strength for the specified pins, in mA.
-
- slew-rate:
- enum: [0, 1, 2, 3]
- default: 0
- description: |
- 0: No adjustments
- 1: Higher Slew rate (faster edges)
- 2: Lower Slew rate (slower edges)
- 3: Reserved (No adjustments)
-
- bias-pull-down: true
- bias-pull-up: true
- bias-bus-hold: true
- bias-disable: true
- output-high: true
- output-low: true
-
- required:
- - pins
- - function
-
- additionalProperties: false
-
required:
- compatible
- reg
- - gpio-controller
- - "#gpio-cells"
- - gpio-ranges
-additionalProperties: false
+allOf:
+ - $ref: qcom,lpass-lpi-common.yaml#
+
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml
index c8735ab97e40..5329fe2a4397 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml
@@ -23,24 +23,6 @@ properties:
description: Specifies the TLMM summary IRQ
maxItems: 1
- interrupt-controller: true
-
- '#interrupt-cells':
- description:
- Specifies the PIN numbers and Flags, as defined in defined in
- include/dt-bindings/interrupt-controller/irq.h
- const: 2
-
- gpio-controller: true
-
- '#gpio-cells':
- description: Specifying the pin number and flags, as defined in
- include/dt-bindings/gpio/gpio.h
- const: 2
-
- gpio-ranges:
- maxItems: 1
-
gpio-reserved-ranges:
minItems: 1
maxItems: 88
@@ -48,8 +30,6 @@ properties:
gpio-line-names:
maxItems: 175
- wakeup-parent: true
-
patternProperties:
"-state$":
oneOf:
@@ -124,14 +104,8 @@ allOf:
required:
- compatible
- reg
- - interrupts
- - interrupt-controller
- - '#interrupt-cells'
- - gpio-controller
- - '#gpio-cells'
- - gpio-ranges
-
-additionalProperties: false
+
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml
index b086a5184235..c122bb849f0f 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml
@@ -31,20 +31,7 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- '#interrupt-cells': true
- gpio-controller: true
gpio-reserved-ranges: true
- '#gpio-cells': true
- gpio-ranges: true
- wakeup-parent: true
-
-required:
- - compatible
- - reg
- - reg-names
-
-additionalProperties: false
patternProperties:
"-state$":
@@ -106,6 +93,13 @@ $defs:
required:
- pins
+required:
+ - compatible
+ - reg
+ - reg-names
+
+unevaluatedProperties: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml
index a9167dac9ab5..240e6d45cc95 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml
@@ -32,16 +32,6 @@ properties:
- const: core
- const: audio
- gpio-controller: true
-
- "#gpio-cells":
- description: Specifying the pin number and flags, as defined in
- include/dt-bindings/gpio/gpio.h
- const: 2
-
- gpio-ranges:
- maxItems: 1
-
patternProperties:
"-state$":
oneOf:
@@ -57,7 +47,8 @@ $defs:
description:
Pinctrl node's client devices use subnodes for desired pin configuration.
Client device subnodes use below standard properties.
- $ref: /schemas/pinctrl/pincfg-node.yaml
+ $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
properties:
pins:
@@ -79,48 +70,16 @@ $defs:
Specify the alternative function to be configured for the specified
pins.
- drive-strength:
- enum: [2, 4, 6, 8, 10, 12, 14, 16]
- default: 2
- description:
- Selects the drive strength for the specified pins, in mA.
-
- slew-rate:
- enum: [0, 1, 2, 3]
- default: 0
- description: |
- 0: No adjustments
- 1: Higher Slew rate (faster edges)
- 2: Lower Slew rate (slower edges)
- 3: Reserved (No adjustments)
-
- bias-bus-hold: true
- bias-pull-down: true
- bias-pull-up: true
- bias-disable: true
- input-enable: true
- output-high: true
- output-low: true
-
- required:
- - pins
- - function
-
- additionalProperties: false
-
allOf:
- - $ref: pinctrl.yaml#
+ - $ref: qcom,lpass-lpi-common.yaml#
required:
- compatible
- reg
- clocks
- clock-names
- - gpio-controller
- - "#gpio-cells"
- - gpio-ranges
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml
index 4bd6d7977d3e..ed344deaf8b9 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml
@@ -25,19 +25,7 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
gpio-reserved-ranges: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
-required:
- - compatible
- - reg
-
-additionalProperties: false
patternProperties:
"-state$":
@@ -108,6 +96,12 @@ $defs:
required:
- pins
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml
index 508e0633b253..a00cb43df144 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml
@@ -34,10 +34,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 57
@@ -45,10 +41,6 @@ properties:
gpio-line-names:
maxItems: 114
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
patternProperties:
"-state$":
oneOf:
@@ -130,7 +122,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml
index 84a15f77e710..b56e717aa28e 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml
@@ -25,23 +25,10 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
gpio-reserved-ranges:
minItems: 1
maxItems: 75
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
-required:
- - compatible
- - reg
-
-additionalProperties: false
-
patternProperties:
"-state$":
oneOf:
@@ -98,6 +85,12 @@ $defs:
required:
- pins
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml
index d301881ddfa8..dfe5616b9b85 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml
@@ -26,10 +26,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 75
@@ -37,10 +33,6 @@ properties:
gpio-line-names:
maxItems: 150
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
patternProperties:
"-state$":
oneOf:
@@ -110,7 +102,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml
index 67af99dd8f14..edbcff92bbf9 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml
@@ -23,12 +23,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
-
gpio-reserved-ranges:
maxItems: 1
@@ -102,7 +96,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml
index 27319782d94b..a31b638c456d 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml
@@ -22,12 +22,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
-
gpio-reserved-ranges:
maxItems: 1
@@ -122,7 +116,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdx75-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdx75-tlmm.yaml
index 7cb96aa75b08..cb1d978d02c9 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sdx75-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdx75-tlmm.yaml
@@ -22,10 +22,8 @@ properties:
reg:
maxItems: 1
- interrupts: true
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
+ interrupts:
+ maxItems: 1
gpio-reserved-ranges:
minItems: 1
@@ -34,10 +32,6 @@ properties:
gpio-line-names:
maxItems: 133
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
patternProperties:
"-state$":
oneOf:
@@ -100,7 +94,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm4450-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm4450-tlmm.yaml
new file mode 100644
index 000000000000..bb08ca5a1509
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm4450-tlmm.yaml
@@ -0,0 +1,151 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/qcom,sm4450-tlmm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies, Inc. SM4450 TLMM block
+
+maintainers:
+ - Tengfei Fan <[email protected]>
+
+description:
+ Top Level Mode Multiplexer pin controller in Qualcomm SM4450 SoC.
+
+allOf:
+ - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,sm4450-pinctrl
+
+ reg:
+ maxItems: 1
+
+ interrupts: true
+ interrupt-controller: true
+ "#interrupt-cells": true
+ gpio-controller: true
+
+ gpio-reserved-ranges:
+ minItems: 1
+ maxItems: 68
+
+ gpio-line-names:
+ maxItems: 136
+
+ "#gpio-cells": true
+ gpio-ranges: true
+ wakeup-parent: true
+
+patternProperties:
+ "-state$":
+ oneOf:
+ - $ref: "#/$defs/qcom-sm4450-tlmm-state"
+ - patternProperties:
+ "-pins$":
+ $ref: "#/$defs/qcom-sm4450-tlmm-state"
+ additionalProperties: false
+
+$defs:
+ qcom-sm4450-tlmm-state:
+ type: object
+ description:
+ Pinctrl node's client devices use subnodes for desired pin configuration.
+ Client device subnodes use below standard properties.
+ $ref: qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
+
+ properties:
+ pins:
+ description:
+ List of gpio pins affected by the properties specified in this
+ subnode.
+ items:
+ oneOf:
+ - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-2][0-9]|13[0-5])$"
+ - enum: [ sdc2_clk, sdc2_cmd, sdc2_data, ufs_reset ]
+ minItems: 1
+ maxItems: 36
+
+ function:
+ description:
+ Specify the alternative function to be configured for the specified
+ pins.
+ enum: [ gpio, atest_char, atest_char0, atest_char1, atest_char2,
+ atest_char3, atest_usb0, atest_usb00, atest_usb01, atest_usb02,
+ atest_usb03, audio_ref, cam_mclk, cci_async, cci_i2c,
+ cci_timer0, cci_timer1, cci_timer2, cci_timer3, cci_timer4,
+ cmu_rng0, cmu_rng1, cmu_rng2, cmu_rng3, coex_uart1, cri_trng,
+ cri_trng0, cri_trng1, dbg_out, ddr_bist, ddr_pxi0, ddr_pxi1,
+ dp0_hot, gcc_gp1, gcc_gp2, gcc_gp3, host2wlan_sol, ibi_i3c,
+ jitter_bist, mdp_vsync, mdp_vsync0, mdp_vsync1, mdp_vsync2,
+ mdp_vsync3, mi2s0_data0, mi2s0_data1, mi2s0_sck, mi2s0_ws,
+ mi2s2_data0, mi2s2_data1, mi2s2_sck, mi2s2_ws, mi2s_mclk0,
+ mi2s_mclk1, nav_gpio0, nav_gpio1, nav_gpio2, pcie0_clk,
+ phase_flag0, phase_flag1, phase_flag10, phase_flag11,
+ phase_flag12, phase_flag13, phase_flag14, phase_flag15,
+ phase_flag16, phase_flag17, phase_flag18, phase_flag19,
+ phase_flag2, phase_flag20, phase_flag21, phase_flag22,
+ phase_flag23, phase_flag24, phase_flag25, phase_flag26,
+ phase_flag27, phase_flag28, phase_flag29, phase_flag3,
+ phase_flag30, phase_flag31, phase_flag4, phase_flag5,
+ phase_flag6, phase_flag7, phase_flag8, phase_flag9,
+ pll_bist, pll_clk, prng_rosc0, prng_rosc1, prng_rosc2,
+ prng_rosc3, qdss_cti, qdss_gpio, qdss_gpio0, qdss_gpio1,
+ qdss_gpio10, qdss_gpio11, qdss_gpio12, qdss_gpio13, qdss_gpio14,
+ qdss_gpio15, qdss_gpio2, qdss_gpio3, qdss_gpio4, qdss_gpio5,
+ qdss_gpio6, qdss_gpio7, qdss_gpio8, qdss_gpio9, qlink0_enable,
+ qlink0_request, qlink0_wmss, qlink1_enable, qlink1_request,
+ qlink1_wmss, qlink2_enable, qlink2_request, qlink2_wmss,
+ qup0_se0, qup0_se1, qup0_se2, qup0_se3, qup0_se4, qup0_se5,
+ qup0_se6, qup0_se7, qup1_se0, qup1_se1, qup1_se2, qup1_se3,
+ qup1_se4, qup1_se5, qup1_se6, sd_write, tb_trig, tgu_ch0,
+ tgu_ch1, tgu_ch2, tgu_ch3, tmess_prng0, tmess_prng1,
+ tmess_prng2, tmess_prng3, tsense_pwm1, tsense_pwm2, uim0_clk,
+ uim0_data, uim0_present, uim0_reset, uim1_clk, uim1_data,
+ uim1_present, uim1_reset, usb0_hs, usb0_phy, vfr_0, vfr_1,
+ vsense_trigger ]
+
+ required:
+ - pins
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ tlmm: pinctrl@f100000 {
+ compatible = "qcom,sm4450-tlmm";
+ reg = <0x0f100000 0x300000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&tlmm 0 0 137>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+
+ gpio-wo-state {
+ pins = "gpio1";
+ function = "gpio";
+ };
+
+ uart-w-state {
+ rx-pins {
+ pins = "gpio23";
+ function = "qup1_se2";
+ bias-pull-up;
+ };
+
+ tx-pins {
+ pins = "gpio22";
+ function = "qup1_se2";
+ bias-disable;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-lpass-lpi-pinctrl.yaml
index abac3311fc55..f4cf2ce86fcd 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-lpass-lpi-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-lpass-lpi-pinctrl.yaml
@@ -31,16 +31,6 @@ properties:
items:
- const: audio
- gpio-controller: true
-
- "#gpio-cells":
- description: Specifying the pin number and flags, as defined in
- include/dt-bindings/gpio/gpio.h
- const: 2
-
- gpio-ranges:
- maxItems: 1
-
patternProperties:
"-state$":
oneOf:
@@ -56,7 +46,8 @@ $defs:
description:
Pinctrl node's client devices use subnodes for desired pin configuration.
Client device subnodes use below standard properties.
- $ref: /schemas/pinctrl/pincfg-node.yaml
+ $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
properties:
pins:
@@ -75,48 +66,17 @@ $defs:
Specify the alternative function to be configured for the specified
pins.
- drive-strength:
- enum: [2, 4, 6, 8, 10, 12, 14, 16]
- default: 2
- description:
- Selects the drive strength for the specified pins, in mA.
-
- slew-rate:
- enum: [0, 1, 2, 3]
- default: 0
- description: |
- 0: No adjustments
- 1: Higher Slew rate (faster edges)
- 2: Lower Slew rate (slower edges)
- 3: Reserved (No adjustments)
-
- bias-bus-hold: true
- bias-pull-down: true
- bias-pull-up: true
- bias-disable: true
- input-enable: true
- output-high: true
- output-low: true
-
- required:
- - pins
- - function
-
- additionalProperties: false
allOf:
- - $ref: pinctrl.yaml#
+ - $ref: qcom,lpass-lpi-common.yaml#
required:
- compatible
- reg
- clocks
- clock-names
- - gpio-controller
- - "#gpio-cells"
- - gpio-ranges
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml
index 871df54f69a2..7f36f9b93333 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml
@@ -29,13 +29,7 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
gpio-reserved-ranges: true
- wakeup-parent: true
patternProperties:
"-state$":
@@ -97,7 +91,7 @@ required:
- reg
- reg-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml
index 8d77707b02b9..ddeaeaa9a450 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml
@@ -30,20 +30,7 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
gpio-reserved-ranges: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
-required:
- - compatible
- - reg
- - reg-names
-
-additionalProperties: false
patternProperties:
"-state$":
@@ -105,6 +92,13 @@ $defs:
required:
- pins
+required:
+ - compatible
+ - reg
+ - reg-names
+
+unevaluatedProperties: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml
index 27af379cf791..a4771f87d936 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml
@@ -26,10 +26,6 @@ properties:
minItems: 9
maxItems: 9
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 78
@@ -37,16 +33,6 @@ properties:
gpio-line-names:
maxItems: 156
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
-required:
- - compatible
- - reg
-
-additionalProperties: false
-
patternProperties:
"-state$":
oneOf:
@@ -112,6 +98,12 @@ $defs:
required:
- pins
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml
index 6e02ba24825f..047f82863f9b 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml
@@ -25,19 +25,7 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
gpio-reserved-ranges: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
-required:
- - compatible
- - reg
-
-additionalProperties: false
patternProperties:
"-state$":
@@ -113,6 +101,12 @@ $defs:
required:
- pins
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm7150-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm7150-tlmm.yaml
index ede0f3acad9c..7f23f939ad32 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm7150-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm7150-tlmm.yaml
@@ -32,13 +32,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 60
@@ -111,7 +104,7 @@ required:
- reg
- reg-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml
index c6439626464e..bdb7ed4be026 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml
@@ -30,13 +30,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 88
@@ -113,7 +106,7 @@ required:
- reg
- reg-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml
index 4b4be7efc150..750c996c10a7 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml
@@ -30,16 +30,6 @@ properties:
- const: core
- const: audio
- gpio-controller: true
-
- "#gpio-cells":
- description: Specifying the pin number and flags, as defined in
- include/dt-bindings/gpio/gpio.h
- const: 2
-
- gpio-ranges:
- maxItems: 1
-
patternProperties:
"-state$":
oneOf:
@@ -55,7 +45,8 @@ $defs:
description:
Pinctrl node's client devices use subnodes for desired pin configuration.
Client device subnodes use below standard properties.
- $ref: /schemas/pinctrl/pincfg-node.yaml
+ $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
properties:
pins:
@@ -78,48 +69,16 @@ $defs:
Specify the alternative function to be configured for the specified
pins.
- drive-strength:
- enum: [2, 4, 6, 8, 10, 12, 14, 16]
- default: 2
- description:
- Selects the drive strength for the specified pins, in mA.
-
- slew-rate:
- enum: [0, 1, 2, 3]
- default: 0
- description: |
- 0: No adjustments
- 1: Higher Slew rate (faster edges)
- 2: Lower Slew rate (slower edges)
- 3: Reserved (No adjustments)
-
- bias-pull-down: true
- bias-pull-up: true
- bias-bus-hold: true
- bias-disable: true
- input-enable: true
- output-high: true
- output-low: true
-
- required:
- - pins
- - function
-
- additionalProperties: false
-
allOf:
- - $ref: pinctrl.yaml#
+ - $ref: qcom,lpass-lpi-common.yaml#
required:
- compatible
- reg
- clocks
- clock-names
- - gpio-controller
- - "#gpio-cells"
- - gpio-ranges
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml
index 021c54708524..b5d04347c064 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml
@@ -28,13 +28,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 90
@@ -106,7 +99,7 @@ required:
- reg
- reg-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-lpass-lpi-pinctrl.yaml
index 2e65ae08dd21..9d782f910b31 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-lpass-lpi-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-lpass-lpi-pinctrl.yaml
@@ -33,16 +33,6 @@ properties:
- const: core
- const: audio
- gpio-controller: true
-
- "#gpio-cells":
- description: Specifying the pin number and flags, as defined in
- include/dt-bindings/gpio/gpio.h
- const: 2
-
- gpio-ranges:
- maxItems: 1
-
patternProperties:
"-state$":
oneOf:
@@ -58,7 +48,8 @@ $defs:
description:
Pinctrl node's client devices use subnodes for desired pin configuration.
Client device subnodes use below standard properties.
- $ref: /schemas/pinctrl/pincfg-node.yaml
+ $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
properties:
pins:
@@ -81,48 +72,16 @@ $defs:
Specify the alternative function to be configured for the specified
pins.
- drive-strength:
- enum: [2, 4, 6, 8, 10, 12, 14, 16]
- default: 2
- description:
- Selects the drive strength for the specified pins, in mA.
-
- slew-rate:
- enum: [0, 1, 2, 3]
- default: 0
- description: |
- 0: No adjustments
- 1: Higher Slew rate (faster edges)
- 2: Lower Slew rate (slower edges)
- 3: Reserved (No adjustments)
-
- bias-bus-hold: true
- bias-pull-down: true
- bias-pull-up: true
- bias-disable: true
- input-enable: true
- output-high: true
- output-low: true
-
- required:
- - pins
- - function
-
- additionalProperties: false
-
allOf:
- - $ref: pinctrl.yaml#
+ - $ref: qcom,lpass-lpi-common.yaml#
required:
- compatible
- reg
- clocks
- clock-names
- - gpio-controller
- - "#gpio-cells"
- - gpio-ranges
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml
index 6e8f41ff0a76..ec5e09611d81 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml
@@ -25,10 +25,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 102
@@ -36,16 +32,6 @@ properties:
gpio-line-names:
maxItems: 203
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
-required:
- - compatible
- - reg
-
-additionalProperties: false
-
patternProperties:
"-state$":
oneOf:
@@ -108,6 +94,12 @@ $defs:
required:
- pins
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml
index 1eefa9aa6a86..e7565592da86 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml
@@ -32,16 +32,6 @@ properties:
- const: core
- const: audio
- gpio-controller: true
-
- "#gpio-cells":
- description: Specifying the pin number and flags, as defined in
- include/dt-bindings/gpio/gpio.h
- const: 2
-
- gpio-ranges:
- maxItems: 1
-
patternProperties:
"-state$":
oneOf:
@@ -57,7 +47,8 @@ $defs:
description:
Pinctrl node's client devices use subnodes for desired pin configuration.
Client device subnodes use below standard properties.
- $ref: /schemas/pinctrl/pincfg-node.yaml
+ $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
properties:
pins:
@@ -81,48 +72,16 @@ $defs:
Specify the alternative function to be configured for the specified
pins.
- drive-strength:
- enum: [2, 4, 6, 8, 10, 12, 14, 16]
- default: 2
- description:
- Selects the drive strength for the specified pins, in mA.
-
- slew-rate:
- enum: [0, 1, 2, 3]
- default: 0
- description: |
- 0: No adjustments
- 1: Higher Slew rate (faster edges)
- 2: Lower Slew rate (slower edges)
- 3: Reserved (No adjustments)
-
- bias-bus-hold: true
- bias-pull-down: true
- bias-pull-up: true
- bias-disable: true
- input-enable: true
- output-high: true
- output-low: true
-
- required:
- - pins
- - function
-
- additionalProperties: false
-
allOf:
- - $ref: pinctrl.yaml#
+ - $ref: qcom,lpass-lpi-common.yaml#
required:
- compatible
- reg
- clocks
- clock-names
- - gpio-controller
- - "#gpio-cells"
- - gpio-ranges
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml
index 5163fe3f5365..16fd2c5e2339 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml
@@ -25,10 +25,6 @@ properties:
interrupts:
maxItems: 1
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
-
gpio-reserved-ranges:
minItems: 1
maxItems: 105
@@ -36,16 +32,6 @@ properties:
gpio-line-names:
maxItems: 210
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
-required:
- - compatible
- - reg
-
-additionalProperties: false
-
patternProperties:
"-state$":
oneOf:
@@ -107,6 +93,12 @@ $defs:
required:
- pins
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml
index ef9743246849..bf4a72facae1 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml
@@ -16,7 +16,11 @@ description:
properties:
compatible:
- const: qcom,sm8550-lpass-lpi-pinctrl
+ oneOf:
+ - const: qcom,sm8550-lpass-lpi-pinctrl
+ - items:
+ - const: qcom,x1e80100-lpass-lpi-pinctrl
+ - const: qcom,sm8550-lpass-lpi-pinctrl
reg:
items:
@@ -33,16 +37,6 @@ properties:
- const: core
- const: audio
- gpio-controller: true
-
- "#gpio-cells":
- description: Specifying the pin number and flags, as defined in
- include/dt-bindings/gpio/gpio.h
- const: 2
-
- gpio-ranges:
- maxItems: 1
-
patternProperties:
"-state$":
oneOf:
@@ -58,7 +52,8 @@ $defs:
description:
Pinctrl node's client devices use subnodes for desired pin configuration.
Client device subnodes use below standard properties.
- $ref: /schemas/pinctrl/pincfg-node.yaml
+ $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
properties:
pins:
@@ -81,48 +76,16 @@ $defs:
Specify the alternative function to be configured for the specified
pins.
- drive-strength:
- enum: [2, 4, 6, 8, 10, 12, 14, 16]
- default: 2
- description:
- Selects the drive strength for the specified pins, in mA.
-
- slew-rate:
- enum: [0, 1, 2, 3]
- default: 0
- description: |
- 0: No adjustments
- 1: Higher Slew rate (faster edges)
- 2: Lower Slew rate (slower edges)
- 3: Reserved (No adjustments)
-
- bias-bus-hold: true
- bias-pull-down: true
- bias-pull-up: true
- bias-disable: true
- input-enable: true
- output-high: true
- output-low: true
-
- required:
- - pins
- - function
-
- additionalProperties: false
-
allOf:
- - $ref: pinctrl.yaml#
+ - $ref: qcom,lpass-lpi-common.yaml#
required:
- compatible
- reg
- clocks
- clock-names
- - gpio-controller
- - "#gpio-cells"
- - gpio-ranges
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml
index f789c7753a92..c2ae79df424f 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml
@@ -22,10 +22,8 @@ properties:
reg:
maxItems: 1
- interrupts: true
- interrupt-controller: true
- "#interrupt-cells": true
- gpio-controller: true
+ interrupts:
+ maxItems: 1
gpio-reserved-ranges:
minItems: 1
@@ -34,10 +32,6 @@ properties:
gpio-line-names:
maxItems: 210
- "#gpio-cells": true
- gpio-ranges: true
- wakeup-parent: true
-
patternProperties:
"-state$":
oneOf:
@@ -117,7 +111,7 @@ required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml
new file mode 100644
index 000000000000..db7214362301
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm SM8650 SoC LPASS LPI TLMM
+
+maintainers:
+ - Krzysztof Kozlowski <[email protected]>
+ - Srinivas Kandagatla <[email protected]>
+
+description:
+ Top Level Mode Multiplexer pin controller in the Low Power Audio SubSystem
+ (LPASS) Low Power Island (LPI) of Qualcomm SM8650 SoC.
+
+properties:
+ compatible:
+ const: qcom,sm8650-lpass-lpi-pinctrl
+
+ reg:
+ items:
+ - description: LPASS LPI TLMM Control and Status registers
+
+ clocks:
+ items:
+ - description: LPASS Core voting clock
+ - description: LPASS Audio voting clock
+
+ clock-names:
+ items:
+ - const: core
+ - const: audio
+
+patternProperties:
+ "-state$":
+ oneOf:
+ - $ref: "#/$defs/qcom-sm8650-lpass-state"
+ - patternProperties:
+ "-pins$":
+ $ref: "#/$defs/qcom-sm8650-lpass-state"
+ additionalProperties: false
+
+$defs:
+ qcom-sm8650-lpass-state:
+ type: object
+ description:
+ Pinctrl node's client devices use subnodes for desired pin configuration.
+ Client device subnodes use below standard properties.
+ $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
+
+ properties:
+ pins:
+ description:
+ List of gpio pins affected by the properties specified in this
+ subnode.
+ items:
+ pattern: "^gpio([0-9]|1[0-9]|2[0-2])$"
+
+ function:
+ enum: [ dmic1_clk, dmic1_data, dmic2_clk, dmic2_data, dmic3_clk,
+ dmic3_data, dmic4_clk, dmic4_data, ext_mclk1_a, ext_mclk1_b,
+ ext_mclk1_c, ext_mclk1_d, ext_mclk1_e, gpio, i2s0_clk,
+ i2s0_data, i2s0_ws, i2s1_clk, i2s1_data, i2s1_ws, i2s2_clk,
+ i2s2_data, i2s2_ws, i2s3_clk, i2s3_data, i2s3_ws, i2s4_clk,
+ i2s4_data, i2s4_ws, qca_swr_clk, qca_swr_data, slimbus_clk,
+ slimbus_data, swr_rx_clk, swr_rx_data, swr_tx_clk, swr_tx_data,
+ wsa_swr_clk, wsa_swr_data, wsa2_swr_clk, wsa2_swr_data ]
+ description:
+ Specify the alternative function to be configured for the specified
+ pins.
+
+allOf:
+ - $ref: qcom,lpass-lpi-common.yaml#
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h>
+
+ lpass_tlmm: pinctrl@6e80000 {
+ compatible = "qcom,sm8650-lpass-lpi-pinctrl";
+ reg = <0x06e80000 0x20000>;
+
+ clocks = <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
+ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>;
+ clock-names = "core", "audio";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&lpass_tlmm 0 0 23>;
+
+ tx-swr-sleep-clk-state {
+ pins = "gpio0";
+ function = "swr_tx_clk";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-tlmm.yaml
new file mode 100644
index 000000000000..c0a06abf851d
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-tlmm.yaml
@@ -0,0 +1,141 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/qcom,sm8650-tlmm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies, Inc. SM8650 TLMM block
+
+maintainers:
+ - Bjorn Andersson <[email protected]>
+
+description:
+ Top Level Mode Multiplexer pin controller in Qualcomm SM8650 SoC.
+
+allOf:
+ - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,sm8650-tlmm
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ gpio-reserved-ranges:
+ minItems: 1
+ maxItems: 105
+
+ gpio-line-names:
+ maxItems: 210
+
+patternProperties:
+ "-state$":
+ oneOf:
+ - $ref: "#/$defs/qcom-sm8650-tlmm-state"
+ - patternProperties:
+ "-pins$":
+ $ref: "#/$defs/qcom-sm8650-tlmm-state"
+ additionalProperties: false
+
+$defs:
+ qcom-sm8650-tlmm-state:
+ type: object
+ description:
+ Pinctrl node's client devices use subnodes for desired pin configuration.
+ Client device subnodes use below standard properties.
+ $ref: qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
+
+ properties:
+ pins:
+ description:
+ List of gpio pins affected by the properties specified in this
+ subnode.
+ items:
+ oneOf:
+ - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-9][0-9]|20[0-9])$"
+ - enum: [ ufs_reset, sdc2_clk, sdc2_cmd, sdc2_data ]
+ minItems: 1
+ maxItems: 36
+
+ function:
+ description:
+ Specify the alternative function to be configured for the specified
+ pins.
+ enum: [ gpio, aoss_cti, atest_char, atest_usb, audio_ext_mclk0,
+ audio_ext_mclk1, audio_ref_clk, cam_aon_mclk2, cam_aon_mclk4,
+ cam_mclk, cci_async_in, cci_i2c_scl, cci_i2c_sda, cci_timer,
+ cmu_rng, coex_uart1_rx, coex_uart1_tx, coex_uart2_rx,
+ coex_uart2_tx, cri_trng, dbg_out_clk, ddr_bist_complete,
+ ddr_bist_fail, ddr_bist_start, ddr_bist_stop, ddr_pxi0,
+ ddr_pxi1, ddr_pxi2, ddr_pxi3, do_not, dp_hot, gcc_gp1,
+ gcc_gp2, gcc_gp3, gnss_adc0, gnss_adc1, i2chub0_se0,
+ i2chub0_se1, i2chub0_se2, i2chub0_se3, i2chub0_se4,
+ i2chub0_se5, i2chub0_se6, i2chub0_se7, i2chub0_se8,
+ i2chub0_se9, i2s0_data0, i2s0_data1, i2s0_sck, i2s0_ws,
+ i2s1_data0, i2s1_data1, i2s1_sck, i2s1_ws, ibi_i3c,
+ jitter_bist, mdp_vsync, mdp_vsync0_out, mdp_vsync1_out,
+ mdp_vsync2_out, mdp_vsync3_out, mdp_vsync_e, nav_gpio0,
+ nav_gpio1, nav_gpio2, nav_gpio3, pcie0_clk_req_n,
+ pcie1_clk_req_n, phase_flag, pll_bist_sync, pll_clk_aux,
+ prng_rosc0, prng_rosc1, prng_rosc2, prng_rosc3, qdss_cti,
+ qdss_gpio, qlink_big_enable, qlink_big_request,
+ qlink_little_enable, qlink_little_request, qlink_wmss,
+ qspi0, qspi1, qspi2, qspi3, qspi_clk, qspi_cs, qup1_se0,
+ qup1_se1, qup1_se2, qup1_se3, qup1_se4, qup1_se5, qup1_se6,
+ qup1_se7, qup2_se0, qup2_se1, qup2_se2, qup2_se3, qup2_se4,
+ qup2_se5, qup2_se6, qup2_se7, sd_write_protect, sdc40, sdc41,
+ sdc42, sdc43, sdc4_clk, sdc4_cmd, tb_trig_sdc2, tb_trig_sdc4,
+ tgu_ch0_trigout, tgu_ch1_trigout, tgu_ch2_trigout,
+ tgu_ch3_trigout, tmess_prng0, tmess_prng1, tmess_prng2,
+ tmess_prng3, tsense_pwm1, tsense_pwm2, tsense_pwm3, uim0_clk,
+ uim0_data, uim0_present, uim0_reset, uim1_clk, uim1_data,
+ uim1_present, uim1_reset, usb1_hs, usb_phy, vfr_0, vfr_1,
+ vsense_trigger_mirnat ]
+
+ required:
+ - pins
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ tlmm: pinctrl@f100000 {
+ compatible = "qcom,sm8650-tlmm";
+ reg = <0x0f100000 0x300000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&tlmm 0 0 211>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+
+ gpio-wo-state {
+ pins = "gpio1";
+ function = "gpio";
+ };
+
+ uart-w-state {
+ rx-pins {
+ pins = "gpio60";
+ function = "qup1_se7";
+ bias-pull-up;
+ };
+
+ tx-pins {
+ pins = "gpio61";
+ function = "qup1_se7";
+ bias-disable;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,x1e80100-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,x1e80100-tlmm.yaml
new file mode 100644
index 000000000000..a1333e0743a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,x1e80100-tlmm.yaml
@@ -0,0 +1,137 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/qcom,x1e80100-tlmm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies, Inc. X1E80100 TLMM block
+
+maintainers:
+ - Rajendra Nayak <[email protected]>
+
+description:
+ Top Level Mode Multiplexer pin controller in Qualcomm X1E80100 SoC.
+
+allOf:
+ - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,x1e80100-tlmm
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ gpio-reserved-ranges:
+ minItems: 1
+ maxItems: 119
+
+ gpio-line-names:
+ maxItems: 238
+
+patternProperties:
+ "-state$":
+ oneOf:
+ - $ref: "#/$defs/qcom-x1e80100-tlmm-state"
+ - patternProperties:
+ "-pins$":
+ $ref: "#/$defs/qcom-x1e80100-tlmm-state"
+ additionalProperties: false
+
+$defs:
+ qcom-x1e80100-tlmm-state:
+ type: object
+ description:
+ Pinctrl node's client devices use subnodes for desired pin configuration.
+ Client device subnodes use below standard properties.
+ $ref: qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
+
+ properties:
+ pins:
+ description:
+ List of gpio pins affected by the properties specified in this
+ subnode.
+ items:
+ oneOf:
+ - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-2][0-9]|23[0-7])$"
+ - enum: [ ufs_reset, sdc2_clk, sdc2_cmd, sdc2_data ]
+ minItems: 1
+ maxItems: 36
+
+ function:
+ description:
+ Specify the alternative function to be configured for the specified
+ pins.
+ enum: [ aon_cci, aoss_cti, atest_char, atest_char0,
+ atest_char1, atest_char2, atest_char3, atest_usb,
+ audio_ext, audio_ref, cam_aon, cam_mclk, cci_async,
+ cci_i2c, cci_timer0, cci_timer1, cci_timer2, cci_timer3,
+ cci_timer4, cmu_rng0, cmu_rng1, cmu_rng2, cmu_rng3,
+ cri_trng, dbg_out, ddr_bist, ddr_pxi0, ddr_pxi1,
+ ddr_pxi2, ddr_pxi3, ddr_pxi4, ddr_pxi5, ddr_pxi6, ddr_pxi7,
+ edp0_hot, edp0_lcd, edp1_hot, edp1_lcd, eusb0_ac, eusb1_ac,
+ eusb2_ac, eusb3_ac, eusb5_ac, eusb6_ac, gcc_gp1, gcc_gp2,
+ gcc_gp3, gpio, i2s0_data0, i2s0_data1, i2s0_sck, i2s0_ws, i2s1_data0,
+ i2s1_data1, i2s1_sck, i2s1_ws, ibi_i3c, jitter_bist, mdp_vsync0,
+ mdp_vsync1, mdp_vsync2, mdp_vsync3, mdp_vsync4, mdp_vsync5,
+ mdp_vsync6, mdp_vsync7, mdp_vsync8, pcie3_clk, pcie4_clk,
+ pcie5_clk, pcie6a_clk, pcie6b_clk, phase_flag, pll_bist, pll_clk,
+ prng_rosc0, prng_rosc1, prng_rosc2, prng_rosc3, qdss_cti,
+ qdss_gpio, qspi00, qspi01, qspi02, qspi03, qspi0_clk, qspi0_cs0,
+ qspi0_cs1, qup0_se0, qup0_se1, qup0_se2, qup0_se3, qup0_se4,
+ qup0_se5, qup0_se6, qup0_se7, qup1_se0, qup1_se1, qup1_se2, qup1_se3,
+ qup1_se4, qup1_se5, qup1_se6, qup1_se7, qup2_se0, qup2_se1, qup2_se2,
+ qup2_se3, qup2_se4, qup2_se5, qup2_se6, qup2_se7, sd_write, sdc4_clk,
+ sdc4_cmd, sdc4_data0, sdc4_data1, sdc4_data2, sdc4_data3, sys_throttle,
+ tb_trig, tgu_ch0, tgu_ch1, tgu_ch2, tgu_ch3, tgu_ch4, tgu_ch5,
+ tgu_ch6, tgu_ch7, tmess_prng0, tmess_prng1, tmess_prng2, tmess_prng3,
+ tsense_pwm1, tsense_pwm2, sense_pwm3, tsense_pwm4, usb0_dp, usb0_phy,
+ usb0_sbrx, usb0_sbtx, usb1_dp, usb1_phy, usb1_sbrx, usb1_sbtx,
+ usb2_dp, usb2_phy, usb2_sbrx, usb2_sbtx, vsense_trigger ]
+
+ required:
+ - pins
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ tlmm: pinctrl@f100000 {
+ compatible = "qcom,x1e80100-tlmm";
+ reg = <0x0f100000 0xf00000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&tlmm 0 0 239>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+
+ gpio-wo-state {
+ pins = "gpio1";
+ function = "gpio";
+ };
+
+ uart-w-state {
+ rx-pins {
+ pins = "gpio26";
+ function = "qup2_se7";
+ bias-pull-up;
+ };
+
+ tx-pins {
+ pins = "gpio27";
+ function = "qup2_se7";
+ bias-disable;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml
index 8271e7b2c162..8b8e4e1a000f 100644
--- a/Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml
@@ -20,7 +20,7 @@ description:
properties:
compatible:
- const: "renesas,r7s9210-pinctrl" # RZ/A2M
+ const: renesas,r7s9210-pinctrl # RZ/A2M
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml
index b5ca40d0e251..d476de82e5c3 100644
--- a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml
@@ -185,17 +185,17 @@ examples:
sd1_mux {
pinmux = <RZG2L_PORT_PINMUX(19, 0, 1)>, /* CD */
<RZG2L_PORT_PINMUX(19, 1, 1)>; /* WP */
- power-source = <3300>;
+ power-source = <3300>;
};
sd1_data {
pins = "SD1_DATA0", "SD1_DATA1", "SD1_DATA2", "SD1_DATA3";
- power-source = <3300>;
+ power-source = <3300>;
};
sd1_ctrl {
pins = "SD1_CLK", "SD1_CMD";
- power-source = <3300>;
+ power-source = <3300>;
};
};
};
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml
index 1de91a51234d..4dfb49b0e07f 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml
@@ -28,15 +28,27 @@ description: |
properties:
compatible:
- enum:
- - samsung,s3c2410-wakeup-eint
- - samsung,s3c2412-wakeup-eint
- - samsung,s3c64xx-wakeup-eint
- - samsung,s5pv210-wakeup-eint
- - samsung,exynos4210-wakeup-eint
- - samsung,exynos7-wakeup-eint
- - samsung,exynos850-wakeup-eint
- - samsung,exynosautov9-wakeup-eint
+ oneOf:
+ - enum:
+ - samsung,s3c2410-wakeup-eint
+ - samsung,s3c2412-wakeup-eint
+ - samsung,s3c64xx-wakeup-eint
+ - samsung,s5pv210-wakeup-eint
+ - samsung,exynos4210-wakeup-eint
+ - samsung,exynos7-wakeup-eint
+ - samsung,exynosautov920-wakeup-eint
+ - items:
+ - enum:
+ - samsung,exynos5433-wakeup-eint
+ - samsung,exynos7885-wakeup-eint
+ - samsung,exynos850-wakeup-eint
+ - const: samsung,exynos7-wakeup-eint
+ - items:
+ - enum:
+ - google,gs101-wakeup-eint
+ - samsung,exynosautov9-wakeup-eint
+ - const: samsung,exynos850-wakeup-eint
+ - const: samsung,exynos7-wakeup-eint
interrupts:
description:
@@ -79,11 +91,14 @@ allOf:
- if:
properties:
compatible:
- contains:
- enum:
- - samsung,s5pv210-wakeup-eint
- - samsung,exynos4210-wakeup-eint
- - samsung,exynos7-wakeup-eint
+ # Match without "contains", to skip newer variants which are still
+ # compatible with samsung,exynos7-wakeup-eint
+ enum:
+ - samsung,s5pv210-wakeup-eint
+ - samsung,exynos4210-wakeup-eint
+ - samsung,exynos5433-wakeup-eint
+ - samsung,exynos7-wakeup-eint
+ - samsung,exynos7885-wakeup-eint
then:
properties:
interrupts:
@@ -98,7 +113,7 @@ allOf:
contains:
enum:
- samsung,exynos850-wakeup-eint
- - samsung,exynosautov9-wakeup-eint
+ - samsung,exynosautov920-wakeup-eint
then:
properties:
interrupts: false
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml
index 26614621774a..118549c25976 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml
@@ -35,6 +35,7 @@ properties:
compatible:
enum:
+ - google,gs101-pinctrl
- samsung,s3c2412-pinctrl
- samsung,s3c2416-pinctrl
- samsung,s3c2440-pinctrl
@@ -53,6 +54,7 @@ properties:
- samsung,exynos7885-pinctrl
- samsung,exynos850-pinctrl
- samsung,exynosautov9-pinctrl
+ - samsung,exynosautov920-pinctrl
- tesla,fsd-pinctrl
interrupts:
@@ -313,7 +315,8 @@ examples:
pinctrl-0 = <&initial_alive>;
wakeup-interrupt-controller {
- compatible = "samsung,exynos7-wakeup-eint";
+ compatible = "samsung,exynos5433-wakeup-eint",
+ "samsung,exynos7-wakeup-eint";
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
};
diff --git a/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml
index b85f9e36ce4b..d2676f92ef5b 100644
--- a/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml
@@ -39,7 +39,7 @@ properties:
phandle to the SLCR.
patternProperties:
- '^(.*-)?(default|gpio)$':
+ '^(.*-)?(default|gpio-grp)$':
type: object
patternProperties:
'^mux':
diff --git a/Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml
index 01b6f2b57843..f13d315b5d5e 100644
--- a/Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml
@@ -31,7 +31,7 @@ properties:
const: xlnx,zynqmp-pinctrl
patternProperties:
- '^(.*-)?(default|gpio)$':
+ '^(.*-)?(default|gpio-grp)$':
type: object
patternProperties:
'^mux':
diff --git a/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml b/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml
index 407b7cfec783..7a0f1a400868 100644
--- a/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml
+++ b/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml
@@ -20,6 +20,7 @@ properties:
compatible:
items:
- enum:
+ - fsl,imx8dl-scu-pd
- fsl,imx8qm-scu-pd
- fsl,imx8qxp-scu-pd
- const: fsl,scu-pd
diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
index da9c5846f4e1..2ff246cf8b81 100644
--- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
+++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
@@ -39,7 +39,6 @@ properties:
- qcom,sc7280-rpmhpd
- qcom,sc8180x-rpmhpd
- qcom,sc8280xp-rpmhpd
- - qcom,sc8380xp-rpmhpd
- qcom,sdm660-rpmpd
- qcom,sdm670-rpmhpd
- qcom,sdm845-rpmhpd
@@ -57,6 +56,7 @@ properties:
- qcom,sm8450-rpmhpd
- qcom,sm8550-rpmhpd
- qcom,sm8650-rpmhpd
+ - qcom,x1e80100-rpmhpd
- items:
- enum:
- qcom,msm8937-rpmpd
diff --git a/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml b/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml
index 07e38be39f1b..89f9603499b4 100644
--- a/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml
+++ b/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml
@@ -79,10 +79,10 @@ examples:
interrupt-parent = <&gpio1>;
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
- richtek,output-charge-current = <500000>;
- richtek,end-of-charge-percentage = <10>;
- richtek,battery-regulation-voltage = <4200000>;
- richtek,boost-output-voltage = <5050000>;
+ richtek,output-charge-current = <500000>;
+ richtek,end-of-charge-percentage = <10>;
+ richtek,battery-regulation-voltage = <4200000>;
+ richtek,boost-output-voltage = <5050000>;
richtek,min-input-voltage-regulation = <4500000>;
richtek,avg-input-current-regulation = <500000>;
diff --git a/Documentation/devicetree/bindings/power/wakeup-source.txt b/Documentation/devicetree/bindings/power/wakeup-source.txt
index 697333a56d5e..75bc20b95688 100644
--- a/Documentation/devicetree/bindings/power/wakeup-source.txt
+++ b/Documentation/devicetree/bindings/power/wakeup-source.txt
@@ -3,16 +3,20 @@ Specifying wakeup capability for devices
Any device nodes
----------------
-Nodes that describe devices which has wakeup capability must contain an
+Nodes that describe devices which have wakeup capability may contain a
"wakeup-source" boolean property.
-Also, if device is marked as a wakeup source, then all the primary
-interrupt(s) can be used as wakeup interrupt(s).
+If the device is marked as a wakeup-source, interrupt wake capability depends
+on the device specific "interrupt-names" property. If no interrupts are labeled
+as wake capable, then it is up to the device to determine which interrupts can
+wake the system.
-However if the devices have dedicated interrupt as the wakeup source
-then they need to specify/identify the same using device specific
-interrupt name. In such cases only that interrupt can be used as wakeup
-interrupt.
+However if a device has a dedicated interrupt as the wakeup source, then it
+needs to specify/identify it using a device specific interrupt name. In such
+cases only that interrupt can be used as a wakeup interrupt.
+
+While various legacy interrupt names exist, new devices should use "wakeup" as
+the canonical interrupt name.
List of legacy properties and respective binding document
---------------------------------------------------------
diff --git a/Documentation/devicetree/bindings/pwm/mediatek,pwm-disp.yaml b/Documentation/devicetree/bindings/pwm/mediatek,pwm-disp.yaml
index 153e146df7d4..afcdeed4e88a 100644
--- a/Documentation/devicetree/bindings/pwm/mediatek,pwm-disp.yaml
+++ b/Documentation/devicetree/bindings/pwm/mediatek,pwm-disp.yaml
@@ -8,7 +8,6 @@ title: MediaTek DISP_PWM Controller
maintainers:
- Jitao Shi <[email protected]>
- - Xinlei Lee <[email protected]>
allOf:
- $ref: pwm.yaml#
diff --git a/Documentation/devicetree/bindings/pwm/pwm-omap-dmtimer.txt b/Documentation/devicetree/bindings/pwm/pwm-omap-dmtimer.txt
deleted file mode 100644
index 25ecfe14c698..000000000000
--- a/Documentation/devicetree/bindings/pwm/pwm-omap-dmtimer.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-* OMAP PWM for dual-mode timers
-
-Required properties:
-- compatible: Shall contain "ti,omap-dmtimer-pwm".
-- ti,timers: phandle to PWM capable OMAP timer. See timer/ti,timer-dm.yaml for info
- about these timers.
-- #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of
- the cells format.
-
-Optional properties:
-- ti,prescaler: Should be a value between 0 and 7, see the timers datasheet
-- ti,clock-source: Set dmtimer parent clock, values between 0 and 2:
- - 0x00 - high-frequency system clock (timer_sys_ck)
- - 0x01 - 32-kHz always-on clock (timer_32k_ck)
- - 0x02 - external clock (timer_ext_ck, OMAP2 only)
-
-Example:
- pwm9: dmtimer-pwm@9 {
- compatible = "ti,omap-dmtimer-pwm";
- ti,timers = <&timer9>;
- #pwm-cells = <3>;
- };
diff --git a/Documentation/devicetree/bindings/pwm/ti,omap-dmtimer-pwm.yaml b/Documentation/devicetree/bindings/pwm/ti,omap-dmtimer-pwm.yaml
new file mode 100644
index 000000000000..1e8e094aad74
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/ti,omap-dmtimer-pwm.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/ti,omap-dmtimer-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TI dual mode timer PWM controller
+
+maintainers:
+ - Tony Lindgren <[email protected]>
+
+description:
+ TI dual mode timer instances have an IO pin for PWM capability
+
+allOf:
+ - $ref: pwm.yaml#
+
+properties:
+ compatible:
+ const: ti,omap-dmtimer-pwm
+
+ "#pwm-cells":
+ const: 3
+
+ ti,timers:
+ description: Timer instance phandle for the PWM
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ ti,prescaler:
+ description: |
+ Legacy clock prescaler for timer. The timer counter is prescaled
+ with 2^n where n is the prescaler.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [ 0, 1, 2, 3, 4, 5, 6, 7 ]
+ deprecated: true
+
+ ti,clock-source:
+ description: |
+ Legacy clock for timer, please use assigned-clocks instead.
+ 0x00 - high-frequency system clock (timer_sys_ck)
+ 0x01 - 32-kHz always-on clock (timer_32k_ck)
+ 0x02 - external clock (timer_ext_ck, OMAP2 only)
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [ 0, 1, 2 ]
+ deprecated: true
+
+required:
+ - compatible
+ - ti,timers
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ pwm9: pwm {
+ compatible = "ti,omap-dmtimer-pwm";
+ ti,timers = <&timer9>;
+ #pwm-cells = <3>;
+ };
diff --git a/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml b/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml
index 0221397eb51e..f825ee9efd81 100644
--- a/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml
+++ b/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml
@@ -62,8 +62,8 @@ examples:
regulator-name = "buck1";
regulator-min-microvolt = <600000>;
regulator-max-microvolt = <2187500>;
- regulator-min-microamp = <3800000>;
- regulator-max-microamp = <6800000>;
+ regulator-min-microamp = <3800000>;
+ regulator-max-microamp = <6800000>;
regulator-boot-on;
};
diff --git a/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml b/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml
index 6de5b027f990..0d34af98403f 100644
--- a/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml
+++ b/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml
@@ -98,8 +98,8 @@ examples:
regulator-name = "buck1";
regulator-min-microvolt = <400000>;
regulator-max-microvolt = <3587500>;
- regulator-min-microamp = <460000>;
- regulator-max-microamp = <7600000>;
+ regulator-min-microamp = <460000>;
+ regulator-max-microamp = <7600000>;
regulator-boot-on;
mps,buck-ovp-disable;
mps,buck-phase-delay = /bits/ 8 <2>;
diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
index 30632efdad8b..df36e29d974c 100644
--- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml
@@ -113,10 +113,10 @@ examples:
};
imx7d-cm4 {
- compatible = "fsl,imx7d-cm4";
- memory-region = <&m4_reserved_sysmem1>, <&m4_reserved_sysmem2>;
- syscon = <&src>;
- clocks = <&clks IMX7D_ARM_M4_ROOT_CLK>;
+ compatible = "fsl,imx7d-cm4";
+ memory-region = <&m4_reserved_sysmem1>, <&m4_reserved_sysmem2>;
+ syscon = <&src>;
+ clocks = <&clks IMX7D_ARM_M4_ROOT_CLK>;
};
- |
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml
index f10f329677d8..c054b84fdcd5 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml
@@ -18,7 +18,10 @@ properties:
enum:
- qcom,sc7180-adsp-pas
- qcom,sc7180-mpss-pas
+ - qcom,sc7280-adsp-pas
+ - qcom,sc7280-cdsp-pas
- qcom,sc7280-mpss-pas
+ - qcom,sc7280-wpss-pas
reg:
maxItems: 1
@@ -75,6 +78,7 @@ allOf:
compatible:
enum:
- qcom,sc7180-adsp-pas
+ - qcom,sc7280-adsp-pas
then:
properties:
power-domains:
@@ -114,6 +118,23 @@ allOf:
power-domains:
items:
- description: CX power domain
+ - description: MSS power domain
+ power-domain-names:
+ items:
+ - const: cx
+ - const: mss
+
+ - if:
+ properties:
+ compatible:
+ enum:
+ - qcom,sc7280-cdsp-pas
+ - qcom,sc7280-wpss-pas
+ then:
+ properties:
+ power-domains:
+ items:
+ - description: CX power domain
- description: MX power domain
power-domain-names:
items:
diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml
index f392e367d673..23646b684ea2 100644
--- a/Documentation/devicetree/bindings/riscv/cpus.yaml
+++ b/Documentation/devicetree/bindings/riscv/cpus.yaml
@@ -32,6 +32,7 @@ properties:
oneOf:
- items:
- enum:
+ - amd,mbv32
- andestech,ax45mp
- canaan,k210
- sifive,bullet0
diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index c91ab0e46648..27beedb98198 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -171,6 +171,12 @@ properties:
memory types as ratified in the 20191213 version of the privileged
ISA specification.
+ - const: zacas
+ description: |
+ The Zacas extension for Atomic Compare-and-Swap (CAS) instructions
+ is supported as ratified at commit 5059e0ca641c ("update to
+ ratified") of the riscv-zacas.
+
- const: zba
description: |
The standard Zba bit-manipulation extension for address generation
@@ -190,12 +196,111 @@ properties:
multiplication as ratified at commit 6d33919 ("Merge pull request
#158 from hirooih/clmul-fix-loop-end-condition") of riscv-bitmanip.
+ - const: zbkb
+ description:
+ The standard Zbkb bitmanip instructions for cryptography as ratified
+ in version 1.0 of RISC-V Cryptography Extensions Volume I
+ specification.
+
+ - const: zbkc
+ description:
+ The standard Zbkc carry-less multiply instructions as ratified
+ in version 1.0 of RISC-V Cryptography Extensions Volume I
+ specification.
+
+ - const: zbkx
+ description:
+ The standard Zbkx crossbar permutation instructions as ratified
+ in version 1.0 of RISC-V Cryptography Extensions Volume I
+ specification.
+
- const: zbs
description: |
The standard Zbs bit-manipulation extension for single-bit
instructions as ratified at commit 6d33919 ("Merge pull request #158
from hirooih/clmul-fix-loop-end-condition") of riscv-bitmanip.
+ - const: zfa
+ description:
+ The standard Zfa extension for additional floating point
+ instructions, as ratified in commit 056b6ff ("Zfa is ratified") of
+ riscv-isa-manual.
+
+ - const: zfh
+ description:
+ The standard Zfh extension for 16-bit half-precision binary
+ floating-point instructions, as ratified in commit 64074bc ("Update
+ version numbers for Zfh/Zfinx") of riscv-isa-manual.
+
+ - const: zfhmin
+ description:
+ The standard Zfhmin extension which provides minimal support for
+ 16-bit half-precision binary floating-point instructions, as ratified
+ in commit 64074bc ("Update version numbers for Zfh/Zfinx") of
+ riscv-isa-manual.
+
+ - const: zk
+ description:
+ The standard Zk Standard Scalar cryptography extension as ratified
+ in version 1.0 of RISC-V Cryptography Extensions Volume I
+ specification.
+
+ - const: zkn
+ description:
+ The standard Zkn NIST algorithm suite extensions as ratified in
+ version 1.0 of RISC-V Cryptography Extensions Volume I
+ specification.
+
+ - const: zknd
+ description: |
+ The standard Zknd for NIST suite: AES decryption instructions as
+ ratified in version 1.0 of RISC-V Cryptography Extensions Volume I
+ specification.
+
+ - const: zkne
+ description: |
+ The standard Zkne for NIST suite: AES encryption instructions as
+ ratified in version 1.0 of RISC-V Cryptography Extensions Volume I
+ specification.
+
+ - const: zknh
+ description: |
+ The standard Zknh for NIST suite: hash function instructions as
+ ratified in version 1.0 of RISC-V Cryptography Extensions Volume I
+ specification.
+
+ - const: zkr
+ description:
+ The standard Zkr entropy source extension as ratified in version
+ 1.0 of RISC-V Cryptography Extensions Volume I specification.
+ This string being present means that the CSR associated to this
+ extension is accessible at the privilege level to which that
+ device-tree has been provided.
+
+ - const: zks
+ description:
+ The standard Zks ShangMi algorithm suite extensions as ratified in
+ version 1.0 of RISC-V Cryptography Extensions Volume I
+ specification.
+
+ - const: zksed
+ description: |
+ The standard Zksed for ShangMi suite: SM4 block cipher instructions
+ as ratified in version 1.0 of RISC-V Cryptography Extensions
+ Volume I specification.
+
+ - const: zksh
+ description: |
+ The standard Zksh for ShangMi suite: SM3 hash function instructions
+ as ratified in version 1.0 of RISC-V Cryptography Extensions
+ Volume I specification.
+
+ - const: zkt
+ description:
+ The standard Zkt for data independent execution latency as ratified
+ in version 1.0 of RISC-V Cryptography Extensions Volume I
+ specification.
+
- const: zicbom
description:
The standard Zicbom extension for base cache management operations as
@@ -246,6 +351,12 @@ properties:
The standard Zihintpause extension for pause hints, as ratified in
commit d8ab5c7 ("Zihintpause is ratified") of the riscv-isa-manual.
+ - const: zihintntl
+ description:
+ The standard Zihintntl extension for non-temporal locality hints, as
+ ratified in commit 0dc91f5 ("Zihintntl is ratified") of the
+ riscv-isa-manual.
+
- const: zihpm
description:
The standard Zihpm extension for hardware performance counters, as
@@ -258,5 +369,113 @@ properties:
in commit 2e5236 ("Ztso is now ratified.") of the
riscv-isa-manual.
+ - const: zvbb
+ description:
+ The standard Zvbb extension for vectored basic bit-manipulation
+ instructions, as ratified in commit 56ed795 ("Update
+ riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvbc
+ description:
+ The standard Zvbc extension for vectored carryless multiplication
+ instructions, as ratified in commit 56ed795 ("Update
+ riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvfh
+ description:
+ The standard Zvfh extension for vectored half-precision
+ floating-point instructions, as ratified in commit e2ccd05
+ ("Remove draft warnings from Zvfh[min]") of riscv-v-spec.
+
+ - const: zvfhmin
+ description:
+ The standard Zvfhmin extension for vectored minimal half-precision
+ floating-point instructions, as ratified in commit e2ccd05
+ ("Remove draft warnings from Zvfh[min]") of riscv-v-spec.
+
+ - const: zvkb
+ description:
+ The standard Zvkb extension for vector cryptography bit-manipulation
+ instructions, as ratified in commit 56ed795 ("Update
+ riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvkg
+ description:
+ The standard Zvkg extension for vector GCM/GMAC instructions, as
+ ratified in commit 56ed795 ("Update riscv-crypto-spec-vector.adoc")
+ of riscv-crypto.
+
+ - const: zvkn
+ description:
+ The standard Zvkn extension for NIST algorithm suite instructions, as
+ ratified in commit 56ed795 ("Update riscv-crypto-spec-vector.adoc")
+ of riscv-crypto.
+
+ - const: zvknc
+ description:
+ The standard Zvknc extension for NIST algorithm suite with carryless
+ multiply instructions, as ratified in commit 56ed795 ("Update
+ riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvkned
+ description:
+ The standard Zvkned extension for Vector AES block cipher
+ instructions, as ratified in commit 56ed795 ("Update
+ riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvkng
+ description:
+ The standard Zvkng extension for NIST algorithm suite with GCM
+ instructions, as ratified in commit 56ed795 ("Update
+ riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvknha
+ description: |
+ The standard Zvknha extension for NIST suite: vector SHA-2 secure,
+ hash (SHA-256 only) instructions, as ratified in commit
+ 56ed795 ("Update riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvknhb
+ description: |
+ The standard Zvknhb extension for NIST suite: vector SHA-2 secure,
+ hash (SHA-256 and SHA-512) instructions, as ratified in commit
+ 56ed795 ("Update riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvks
+ description:
+ The standard Zvks extension for ShangMi algorithm suite
+ instructions, as ratified in commit 56ed795 ("Update
+ riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvksc
+ description:
+ The standard Zvksc extension for ShangMi algorithm suite with
+ carryless multiplication instructions, as ratified in commit 56ed795
+ ("Update riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvksed
+ description: |
+ The standard Zvksed extension for ShangMi suite: SM4 block cipher
+ instructions, as ratified in commit 56ed795 ("Update
+ riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvksh
+ description: |
+ The standard Zvksh extension for ShangMi suite: SM3 secure hash
+ instructions, as ratified in commit 56ed795 ("Update
+ riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvksg
+ description:
+ The standard Zvksg extension for ShangMi algorithm suite with GCM
+ instructions, as ratified in commit 56ed795 ("Update
+ riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
+ - const: zvkt
+ description:
+ The standard Zvkt extension for vector data-independent execution
+ latency, as ratified in commit 56ed795 ("Update
+ riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
additionalProperties: true
...
diff --git a/Documentation/devicetree/bindings/security/tpm/google,cr50.txt b/Documentation/devicetree/bindings/security/tpm/google,cr50.txt
deleted file mode 100644
index cd69c2efdd37..000000000000
--- a/Documentation/devicetree/bindings/security/tpm/google,cr50.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-* H1 Secure Microcontroller with Cr50 Firmware on SPI Bus.
-
-H1 Secure Microcontroller running Cr50 firmware provides several
-functions, including TPM-like functionality. It communicates over
-SPI using the FIFO protocol described in the PTP Spec, section 6.
-
-Required properties:
-- compatible: Should be "google,cr50".
-- spi-max-frequency: Maximum SPI frequency.
-
-Example:
-
-&spi0 {
- tpm@0 {
- compatible = "google,cr50";
- reg = <0>;
- spi-max-frequency = <800000>;
- };
-};
diff --git a/Documentation/devicetree/bindings/security/tpm/ibmvtpm.txt b/Documentation/devicetree/bindings/security/tpm/ibmvtpm.txt
deleted file mode 100644
index d89f99971368..000000000000
--- a/Documentation/devicetree/bindings/security/tpm/ibmvtpm.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-* Device Tree Bindings for IBM Virtual Trusted Platform Module(vtpm)
-
-Required properties:
-
-- compatible : property name that conveys the platform architecture
- identifiers, as 'IBM,vtpm'
-- device_type : specifies type of virtual device
-- interrupts : property specifying the interrupt source number and
- sense code associated with this virtual I/O Adapters
-- ibm,my-drc-index : integer index for the connector between the device
- and its parent - present only if Dynamic
- Reconfiguration(DR) Connector is enabled
-- ibm,#dma-address-cells: specifies the number of cells that are used to
- encode the physical address field of dma-window
- properties
-- ibm,#dma-size-cells : specifies the number of cells that are used to
- encode the size field of dma-window properties
-- ibm,my-dma-window : specifies DMA window associated with this virtual
- IOA
-- ibm,loc-code : specifies the unique and persistent location code
- associated with this virtual I/O Adapters
-- linux,sml-base : 64-bit base address of the reserved memory allocated
- for the firmware event log
-- linux,sml-size : size of the memory allocated for the firmware event log
-
-Example (IBM Virtual Trusted Platform Module)
----------------------------------------------
-
- vtpm@30000003 {
- ibm,#dma-size-cells = <0x2>;
- compatible = "IBM,vtpm";
- device_type = "IBM,vtpm";
- ibm,my-drc-index = <0x30000003>;
- ibm,#dma-address-cells = <0x2>;
- linux,sml-base = <0xc60e 0x0>;
- interrupts = <0xa0003 0x0>;
- ibm,my-dma-window = <0x10000003 0x0 0x0 0x0 0x10000000>;
- ibm,loc-code = "U8286.41A.10082DV-V3-C3";
- reg = <0x30000003>;
- linux,sml-size = <0xbce10200>;
- };
diff --git a/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt b/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt
deleted file mode 100644
index 0dc121b6eace..000000000000
--- a/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-* STMicroelectronics SAS. ST33ZP24 TPM SoC
-
-Required properties:
-- compatible: Should be "st,st33zp24-i2c".
-- clock-frequency: I²C work frequency.
-- reg: address on the bus
-
-Optional ST33ZP24 Properties:
-- interrupts: GPIO interrupt to which the chip is connected
-- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state.
-If set, power must be present when the platform is going into sleep/hibernate mode.
-
-Optional SoC Specific Properties:
-- pinctrl-names: Contains only one value - "default".
-- pintctrl-0: Specifies the pin control groups used for this controller.
-
-Example (for ARM-based BeagleBoard xM with ST33ZP24 on I2C2):
-
-&i2c2 {
-
-
- st33zp24: st33zp24@13 {
-
- compatible = "st,st33zp24-i2c";
-
- reg = <0x13>;
- clock-frequency = <400000>;
-
- interrupt-parent = <&gpio5>;
- interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
-
- lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
- };
-};
diff --git a/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt b/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt
deleted file mode 100644
index 37198971f17b..000000000000
--- a/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-* STMicroelectronics SAS. ST33ZP24 TPM SoC
-
-Required properties:
-- compatible: Should be "st,st33zp24-spi".
-- spi-max-frequency: Maximum SPI frequency (<= 10000000).
-
-Optional ST33ZP24 Properties:
-- interrupts: GPIO interrupt to which the chip is connected
-- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state.
-If set, power must be present when the platform is going into sleep/hibernate mode.
-
-Optional SoC Specific Properties:
-- pinctrl-names: Contains only one value - "default".
-- pintctrl-0: Specifies the pin control groups used for this controller.
-
-Example (for ARM-based BeagleBoard xM with ST33ZP24 on SPI4):
-
-&mcspi4 {
-
-
- st33zp24@0 {
-
- compatible = "st,st33zp24-spi";
-
- spi-max-frequency = <10000000>;
-
- interrupt-parent = <&gpio5>;
- interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
-
- lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
- };
-};
diff --git a/Documentation/devicetree/bindings/security/tpm/tpm-i2c.txt b/Documentation/devicetree/bindings/security/tpm/tpm-i2c.txt
deleted file mode 100644
index a65d7b71e81a..000000000000
--- a/Documentation/devicetree/bindings/security/tpm/tpm-i2c.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-* Device Tree Bindings for I2C based Trusted Platform Module(TPM)
-
-Required properties:
-
-- compatible : 'manufacturer,model', eg. nuvoton,npct650
-- label : human readable string describing the device, eg. "tpm"
-- linux,sml-base : 64-bit base address of the reserved memory allocated for
- the firmware event log
-- linux,sml-size : size of the memory allocated for the firmware event log
-
-Optional properties:
-
-- powered-while-suspended: present when the TPM is left powered on between
- suspend and resume (makes the suspend/resume
- callbacks do nothing).
-
-Example (for OpenPower Systems with Nuvoton TPM 2.0 on I2C)
-----------------------------------------------------------
-
-tpm@57 {
- reg = <0x57>;
- label = "tpm";
- compatible = "nuvoton,npct650", "nuvoton,npct601";
- linux,sml-base = <0x7f 0xfd450000>;
- linux,sml-size = <0x10000>;
-};
diff --git a/Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt b/Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt
deleted file mode 100644
index 7c6304426da1..000000000000
--- a/Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-Trusted Computing Group MMIO Trusted Platform Module
-
-The TCG defines multi vendor standard for accessing a TPM chip, this
-is the standard protocol defined to access the TPM via MMIO. Typically
-this interface will be implemented over Intel's LPC bus.
-
-Refer to the 'TCG PC Client Specific TPM Interface Specification (TIS)' TCG
-publication for the specification.
-
-Required properties:
-
-- compatible: should contain a string below for the chip, followed by
- "tcg,tpm-tis-mmio". Valid chip strings are:
- * "atmel,at97sc3204"
-- reg: The location of the MMIO registers, should be at least 0x5000 bytes
-- interrupts: An optional interrupt indicating command completion.
-
-Example:
-
- tpm_tis@90000 {
- compatible = "atmel,at97sc3204", "tcg,tpm-tis-mmio";
- reg = <0x90000 0x5000>;
- interrupt-parent = <&EIC0>;
- interrupts = <1 2>;
- };
diff --git a/Documentation/devicetree/bindings/security/tpm/tpm_tis_spi.txt b/Documentation/devicetree/bindings/security/tpm/tpm_tis_spi.txt
deleted file mode 100644
index b800667da92b..000000000000
--- a/Documentation/devicetree/bindings/security/tpm/tpm_tis_spi.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-Required properties:
-- compatible: should be one of the following
- "st,st33htpm-spi"
- "infineon,slb9670"
- "tcg,tpm_tis-spi"
-- spi-max-frequency: Maximum SPI frequency (depends on TPMs).
-
-Optional SoC Specific Properties:
-- pinctrl-names: Contains only one value - "default".
-- pintctrl-0: Specifies the pin control groups used for this controller.
-
-Example (for ARM-based BeagleBoard xM with TPM_TIS on SPI4):
-
-&mcspi4 {
-
-
- tpm_tis@0 {
-
- compatible = "tcg,tpm_tis-spi";
-
- spi-max-frequency = <10000000>;
- };
-};
diff --git a/Documentation/devicetree/bindings/serial/arm,dcc.yaml b/Documentation/devicetree/bindings/serial/arm,dcc.yaml
new file mode 100644
index 000000000000..fd0589356617
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/arm,dcc.yaml
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/serial/arm,dcc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ARM DCC (Data communication channel) serial emulation
+
+maintainers:
+ - Michal Simek <[email protected]>
+
+description: |
+ ARM DCC (Data communication channel) serial emulation interface available
+ via JTAG can be also used as one of serial line tightly coupled with every
+ ARM CPU available in the system.
+
+properties:
+ compatible:
+ const: arm,dcc
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ serial {
+ compatible = "arm,dcc";
+ };
diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
index 920539926d7e..7a105551fa6a 100644
--- a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
+++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
@@ -13,7 +13,7 @@ description: |
https://www.nxp.com/webapp/Download?colCode=S32V234RM.
maintainers:
- - Chester Lin <[email protected]>
+ - Chester Lin <[email protected]>
allOf:
- $ref: serial.yaml#
diff --git a/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml b/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml
index 83035553044a..9c6dc16f88a6 100644
--- a/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml
@@ -9,10 +9,6 @@ title: Freescale i.MX Universal Asynchronous Receiver/Transmitter (UART)
maintainers:
- Fabio Estevam <[email protected]>
-allOf:
- - $ref: serial.yaml#
- - $ref: rs485.yaml#
-
properties:
compatible:
oneOf:
@@ -68,7 +64,11 @@ properties:
- const: tx
interrupts:
- maxItems: 1
+ items:
+ - description: UART RX Interrupt
+ - description: UART TX Interrupt
+ - description: UART RTS Interrupt
+ minItems: 1
wakeup-source: true
@@ -110,6 +110,25 @@ required:
- clock-names
- interrupts
+allOf:
+ - $ref: serial.yaml#
+ - $ref: rs485.yaml#
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: fsl,imx1-uart
+ then:
+ properties:
+ interrupts:
+ minItems: 3
+ maxItems: 3
+ else:
+ properties:
+ interrupts:
+ maxItems: 1
+
unevaluatedProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml b/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml
index ee52bf8e8917..e0fa363ad7e2 100644
--- a/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml
+++ b/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml
@@ -48,9 +48,17 @@ properties:
- const: tx
- const: rx
+ interconnects:
+ maxItems: 1
+
interrupts:
maxItems: 1
+ operating-points-v2: true
+
+ power-domains:
+ maxItems: 1
+
qcom,rx-crci:
$ref: /schemas/types.yaml#/definitions/uint32
description:
@@ -99,7 +107,9 @@ unevaluatedProperties: false
examples:
- |
+ #include <dt-bindings/interconnect/qcom,msm8996.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/power/qcom-rpmpd.h>
serial@f991e000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
@@ -109,4 +119,7 @@ examples:
clock-names = "core", "iface";
dmas = <&dma0 0>, <&dma0 1>;
dma-names = "tx", "rx";
+ power-domains = <&rpmpd MSM8996_VDDCX>;
+ operating-points-v2 = <&uart_opp_table>;
+ interconnects = <&pnoc MASTER_BLSP_1 &bimc SLAVE_EBI_CH0>;
};
diff --git a/Documentation/devicetree/bindings/serial/renesas,sci.yaml b/Documentation/devicetree/bindings/serial/renesas,sci.yaml
index 9f7305200c47..64d3db6e54e5 100644
--- a/Documentation/devicetree/bindings/serial/renesas,sci.yaml
+++ b/Documentation/devicetree/bindings/serial/renesas,sci.yaml
@@ -17,7 +17,7 @@ properties:
oneOf:
- items:
- enum:
- - renesas,r9a07g043-sci # RZ/G2UL
+ - renesas,r9a07g043-sci # RZ/G2UL and RZ/Five
- renesas,r9a07g044-sci # RZ/G2{L,LC}
- renesas,r9a07g054-sci # RZ/V2L
- const: renesas,sci # generic SCI compatible UART
diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
index 17c553123f96..1001d2a6ace8 100644
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
@@ -11,6 +11,7 @@ maintainers:
allOf:
- $ref: serial.yaml#
+ - $ref: rs485.yaml#
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/serial/sprd-uart.yaml b/Documentation/devicetree/bindings/serial/sprd-uart.yaml
index 28ff77aa86c8..f4dbb6dc2b6e 100644
--- a/Documentation/devicetree/bindings/serial/sprd-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/sprd-uart.yaml
@@ -20,6 +20,7 @@ properties:
- sprd,sc9860-uart
- sprd,sc9863a-uart
- sprd,ums512-uart
+ - sprd,ums9620-uart
- const: sprd,sc9836-uart
- const: sprd,sc9836-uart
diff --git a/Documentation/devicetree/bindings/tpm/google,cr50.yaml b/Documentation/devicetree/bindings/tpm/google,cr50.yaml
new file mode 100644
index 000000000000..9302e12e9fc7
--- /dev/null
+++ b/Documentation/devicetree/bindings/tpm/google,cr50.yaml
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/tpm/google,cr50.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Google Security Chip H1 (running Cr50 firmware)
+
+maintainers:
+ - Andrey Pronin <[email protected]>
+
+description: |
+ Google has designed a family of security chips called "Titan".
+ One member is the H1 built into Chromebooks and running Cr50 firmware:
+ https://www.osfc.io/2018/talks/google-secure-microcontroller-and-ccd-closed-case-debugging/
+
+ The chip provides several functions, including TPM 2.0 like functionality.
+ It communicates over SPI or I²C using the FIFO protocol described in the
+ TCG PC Client Platform TPM Profile Specification for TPM 2.0 (PTP), sec 6:
+ https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/
+
+properties:
+ compatible:
+ const: google,cr50
+
+allOf:
+ - $ref: tpm-common.yaml#
+
+anyOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+ - $ref: tcg,tpm-tis-i2c.yaml#/properties/reg
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tpm@0 {
+ reg = <0>;
+ compatible = "google,cr50";
+ spi-max-frequency = <800000>;
+ };
+ };
+
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tpm@50 {
+ compatible = "google,cr50";
+ reg = <0x50>;
+ interrupts-extended = <&pio 88 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&cr50_int>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/tpm/ibm,vtpm.yaml b/Documentation/devicetree/bindings/tpm/ibm,vtpm.yaml
new file mode 100644
index 000000000000..50a3fd31241c
--- /dev/null
+++ b/Documentation/devicetree/bindings/tpm/ibm,vtpm.yaml
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/tpm/ibm,vtpm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: IBM Virtual Trusted Platform Module (vTPM)
+
+maintainers:
+ - Nayna Jain <[email protected]>
+
+description: |
+ Virtual TPM is used on IBM POWER7+ and POWER8 systems running POWERVM.
+ It is supported through the adjunct partition with firmware release 740
+ or higher. With vTPM support, each lpar is able to have its own vTPM
+ without the physical TPM hardware. The TPM functionality is provided by
+ communicating with the vTPM adjunct partition through Hypervisor calls
+ (Hcalls) and Command/Response Queue (CRQ) commands.
+
+properties:
+ compatible:
+ enum:
+ - IBM,vtpm
+ - IBM,vtpm20
+
+ device_type:
+ description:
+ type of virtual device
+ enum:
+ - IBM,vtpm
+ - IBM,vtpm20
+
+ reg:
+ maxItems: 1
+
+ 'ibm,#dma-address-cells':
+ description:
+ number of cells that are used to encode the physical address field of
+ dma-window properties
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+
+ 'ibm,#dma-size-cells':
+ description:
+ number of cells that are used to encode the size field of
+ dma-window properties
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+
+ ibm,my-dma-window:
+ description:
+ DMA window associated with this virtual I/O Adapter
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ minItems: 5
+ maxItems: 5
+
+ ibm,my-drc-index:
+ description:
+ integer index for the connector between the device and its parent;
+ present only if Dynamic Reconfiguration (DR) Connector is enabled
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ ibm,loc-code:
+ description:
+ unique and persistent location code associated with this virtual
+ I/O Adapter
+ $ref: /schemas/types.yaml#/definitions/string
+
+required:
+ - compatible
+ - device_type
+ - reg
+ - interrupts
+ - ibm,#dma-address-cells
+ - ibm,#dma-size-cells
+ - ibm,my-dma-window
+ - ibm,my-drc-index
+ - ibm,loc-code
+ - linux,sml-base
+ - linux,sml-size
+
+allOf:
+ - $ref: tpm-common.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ soc {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tpm@30000003 {
+ compatible = "IBM,vtpm";
+ device_type = "IBM,vtpm";
+ reg = <0x30000003>;
+ interrupts = <0xa0003 0x0>;
+ ibm,#dma-address-cells = <0x2>;
+ ibm,#dma-size-cells = <0x2>;
+ ibm,my-dma-window = <0x10000003 0x0 0x0 0x0 0x10000000>;
+ ibm,my-drc-index = <0x30000003>;
+ ibm,loc-code = "U8286.41A.10082DV-V3-C3";
+ linux,sml-base = <0xc60e 0x0>;
+ linux,sml-size = <0xbce10200>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/tpm/microsoft,ftpm.yaml b/Documentation/devicetree/bindings/tpm/microsoft,ftpm.yaml
new file mode 100644
index 000000000000..fdb81968f03d
--- /dev/null
+++ b/Documentation/devicetree/bindings/tpm/microsoft,ftpm.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/tpm/microsoft,ftpm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microsoft firmware-based Trusted Platform Module (fTPM)
+
+maintainers:
+ - Thirupathaiah Annapureddy <[email protected]>
+ - Sasha Levin <[email protected]>
+
+description: |
+ Commodity CPU architectures, such as ARM and Intel CPUs, have started to
+ offer trusted computing features in their CPUs aimed at displacing dedicated
+ trusted hardware. Unfortunately, these CPU architectures raise serious
+ challenges to building trusted systems because they omit providing secure
+ resources outside the CPU perimeter.
+
+ Microsoft's firmware-based TPM 2.0 (fTPM) leverages ARM TrustZone to overcome
+ these challenges and provide software with security guarantees similar to
+ those of dedicated trusted hardware.
+
+ https://www.microsoft.com/en-us/research/publication/ftpm-software-implementation-tpm-chip/
+ https://github.com/Microsoft/ms-tpm-20-ref/tree/main/Samples/ARM32-FirmwareTPM
+
+properties:
+ compatible:
+ const: microsoft,ftpm
+
+required:
+ - compatible
+ - linux,sml-base
+ - linux,sml-size
+
+allOf:
+ - $ref: tpm-common.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ tpm {
+ compatible = "microsoft,ftpm";
+ linux,sml-base = <0x0 0xc0000000>;
+ linux,sml-size = <0x10000>;
+ };
diff --git a/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml b/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml
new file mode 100644
index 000000000000..3ab4434b7352
--- /dev/null
+++ b/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/tpm/tcg,tpm-tis-i2c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: I²C-attached Trusted Platform Module conforming to TCG TIS specification
+
+maintainers:
+ - Lukas Wunner <[email protected]>
+
+description: |
+ The Trusted Computing Group (TCG) has defined a multi-vendor standard
+ for accessing a TPM chip. It can be transported over various buses,
+ one of them being I²C. The standard is named:
+ TCG PC Client Specific TPM Interface Specification (TIS)
+ https://trustedcomputinggroup.org/resource/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/
+
+ The I²C interface was not originally part of the standard, but added
+ in 2017 with a separate document:
+ TCG PC Client Platform TPM Profile Specification for TPM 2.0 (PTP)
+ https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/
+
+ Recent TPM 2.0 chips conform to this generic interface, others use a
+ vendor-specific I²C interface.
+
+properties:
+ compatible:
+ oneOf:
+ - description: Generic TPM 2.0 chips conforming to TCG PTP interface
+ items:
+ - enum:
+ - infineon,slb9673
+ - nuvoton,npct75x
+ - const: tcg,tpm-tis-i2c
+
+ - description: TPM 1.2 and 2.0 chips with vendor-specific I²C interface
+ items:
+ - enum:
+ - atmel,at97sc3204t # TPM 1.2
+ - infineon,slb9635tt # TPM 1.2 (maximum 100 kHz)
+ - infineon,slb9645tt # TPM 1.2 (maximum 400 kHz)
+ - infineon,tpm_i2c_infineon # TPM 1.2
+ - nuvoton,npct501 # TPM 1.2
+ - nuvoton,npct601 # TPM 2.0
+ - st,st33zp24-i2c # TPM 2.0
+ - winbond,wpct301 # TPM 1.2
+
+ reg:
+ description: address of TPM on the I²C bus
+
+allOf:
+ - $ref: tpm-common.yaml#
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tpm@57 {
+ label = "tpm";
+ compatible = "nuvoton,npct601";
+ reg = <0x57>;
+ linux,sml-base = <0x7f 0xfd450000>;
+ linux,sml-size = <0x10000>;
+ };
+ };
+
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tpm@13 {
+ reg = <0x13>;
+ compatible = "st,st33zp24-i2c";
+ interrupt-parent = <&gpio5>;
+ interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
+ lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-mmio.yaml b/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-mmio.yaml
new file mode 100644
index 000000000000..87bce0692129
--- /dev/null
+++ b/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-mmio.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/tpm/tcg,tpm-tis-mmio.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MMIO-accessed Trusted Platform Module conforming to TCG TIS specification
+
+maintainers:
+ - Lukas Wunner <[email protected]>
+
+description: |
+ The Trusted Computing Group (TCG) has defined a multi-vendor standard
+ for accessing a TPM chip. It can be transported over various buses,
+ one of them being LPC (via MMIO). The standard is named:
+ TCG PC Client Specific TPM Interface Specification (TIS)
+ https://trustedcomputinggroup.org/resource/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - at97sc3201
+ - atmel,at97sc3204
+ - socionext,synquacer-tpm-mmio
+ - const: tcg,tpm-tis-mmio
+
+ reg:
+ description:
+ location and length of the MMIO registers, length should be
+ at least 0x5000 bytes
+
+allOf:
+ - $ref: tpm-common.yaml#
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ tpm@90000 {
+ compatible = "atmel,at97sc3204", "tcg,tpm-tis-mmio";
+ reg = <0x90000 0x5000>;
+ interrupt-parent = <&EIC0>;
+ interrupts = <1 2>;
+ };
diff --git a/Documentation/devicetree/bindings/tpm/tcg,tpm_tis-spi.yaml b/Documentation/devicetree/bindings/tpm/tcg,tpm_tis-spi.yaml
new file mode 100644
index 000000000000..c3413b47ac3d
--- /dev/null
+++ b/Documentation/devicetree/bindings/tpm/tcg,tpm_tis-spi.yaml
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/tpm/tcg,tpm_tis-spi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: SPI-attached Trusted Platform Module conforming to TCG TIS specification
+
+maintainers:
+ - Lukas Wunner <[email protected]>
+
+description: |
+ The Trusted Computing Group (TCG) has defined a multi-vendor standard
+ for accessing a TPM chip. It can be transported over various buses,
+ one of them being SPI. The standard is named:
+ TCG PC Client Specific TPM Interface Specification (TIS)
+ https://trustedcomputinggroup.org/resource/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - infineon,slb9670
+ - st,st33htpm-spi
+ - st,st33zp24-spi
+ - const: tcg,tpm_tis-spi
+
+allOf:
+ - $ref: tpm-common.yaml#
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: st,st33zp24-spi
+ then:
+ properties:
+ spi-max-frequency:
+ maximum: 10000000
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tpm@0 {
+ reg = <0>;
+ compatible = "infineon,slb9670", "tcg,tpm_tis-spi";
+ spi-max-frequency = <10000000>;
+ };
+ };
+
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tpm@0 {
+ reg = <0>;
+ compatible = "st,st33zp24-spi", "tcg,tpm_tis-spi";
+ spi-max-frequency = <10000000>;
+ interrupt-parent = <&gpio5>;
+ interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
+ lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/tpm/tpm-common.yaml b/Documentation/devicetree/bindings/tpm/tpm-common.yaml
new file mode 100644
index 000000000000..90390624a8be
--- /dev/null
+++ b/Documentation/devicetree/bindings/tpm/tpm-common.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/tpm/tpm-common.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Trusted Platform Module common properties
+
+maintainers:
+ - Lukas Wunner <[email protected]>
+
+properties:
+ $nodename:
+ pattern: '^tpm(@[0-9a-f]+)?$'
+
+ interrupts:
+ description: indicates command completion
+ maxItems: 1
+
+ label:
+ description: human readable string describing the device, e.g. "tpm"
+
+ linux,sml-base:
+ description:
+ base address of reserved memory allocated for firmware event log
+ $ref: /schemas/types.yaml#/definitions/uint64
+
+ linux,sml-size:
+ description:
+ size of reserved memory allocated for firmware event log
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ memory-region:
+ description: reserved memory allocated for firmware event log
+ maxItems: 1
+
+ powered-while-suspended:
+ description:
+ present when the TPM is left powered on between suspend and resume
+ (makes the suspend/resume callbacks do nothing)
+ type: boolean
+
+ resets:
+ description: Reset controller to reset the TPM
+ $ref: /schemas/types.yaml#/definitions/phandle
+
+ reset-gpios:
+ description: Output GPIO pin to reset the TPM
+ maxItems: 1
+
+# must always have both linux,sml-base and linux,sml-size
+dependentRequired:
+ linux,sml-base: ['linux,sml-size']
+ linux,sml-size: ['linux,sml-base']
+
+# must only have either memory-region or linux,sml-base
+# as well as either resets or reset-gpios
+dependentSchemas:
+ memory-region:
+ properties:
+ linux,sml-base: false
+ linux,sml-base:
+ properties:
+ memory-region: false
+ resets:
+ properties:
+ reset-gpios: false
+ reset-gpios:
+ properties:
+ resets: false
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ pattern: '^st,st33zp24'
+ then:
+ properties:
+ lpcpd-gpios:
+ description:
+ Output GPIO pin used for ST33ZP24 power management of D1/D2 state.
+ If set, power must be present when the platform is going into
+ sleep/hibernate mode.
+ maxItems: 1
+
+additionalProperties: true
diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml
index a5fb2fa22026..79dcd92c4a43 100644
--- a/Documentation/devicetree/bindings/trivial-devices.yaml
+++ b/Documentation/devicetree/bindings/trivial-devices.yaml
@@ -49,8 +49,6 @@ properties:
- ams,iaq-core
# i2c serial eeprom (24cxx)
- at,24c08
- # i2c trusted platform module (TPM)
- - atmel,at97sc3204t
# ATSHA204 - i2c h/w symmetric crypto module
- atmel,atsha204
# ATSHA204A - i2c h/w symmetric crypto module
@@ -151,12 +149,6 @@ properties:
- infineon,ir38263
# Infineon IRPS5401 Voltage Regulator (PMIC)
- infineon,irps5401
- # Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz)
- - infineon,slb9635tt
- # Infineon SLB9645 I2C TPM (new protocol, max 400khz)
- - infineon,slb9645tt
- # Infineon SLB9673 I2C TPM 2.0
- - infineon,slb9673
# Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor
- infineon,tlv493d-a1b6
# Infineon Multi-phase Digital VR Controller xdpe11280
@@ -185,6 +177,8 @@ properties:
- isil,isl29030
# Intersil ISL68137 Digital Output Configurable PWM Controller
- isil,isl68137
+ # Intersil ISL76682 Ambient Light Sensor
+ - isil,isl76682
# Linear Technology LTC2488
- lineartechnology,ltc2488
# 5 Bit Programmable, Pulse-Width Modulator
@@ -307,10 +301,6 @@ properties:
- national,lm85
# I2C ±0.33°C Accurate, 12-Bit + Sign Temperature Sensor and Thermal Window Comparator
- national,lm92
- # i2c trusted platform module (TPM)
- - nuvoton,npct501
- # i2c trusted platform module (TPM2)
- - nuvoton,npct601
# Nuvoton Temperature Sensor
- nuvoton,w83773g
# OKI ML86V7667 video decoder
@@ -355,8 +345,6 @@ properties:
- silabs,si7020
# Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply
- skyworks,sky81452
- # Socionext SynQuacer TPM MMIO module
- - socionext,synquacer-tpm-mmio
# SparkFun Qwiic Joystick (COM-15168) with i2c interface
- sparkfun,qwiic-joystick
# i2c serial eeprom (24cxx)
@@ -411,8 +399,6 @@ properties:
- winbond,w83793
# Vicor Corporation Digital Supervisor
- vicor,pli1209bc
- # i2c trusted platform module (TPM)
- - winbond,wpct301
required:
- compatible
diff --git a/Documentation/devicetree/bindings/usb/generic-xhci.yaml b/Documentation/devicetree/bindings/usb/generic-xhci.yaml
index 594ebb3ee432..6ceafa4af292 100644
--- a/Documentation/devicetree/bindings/usb/generic-xhci.yaml
+++ b/Documentation/devicetree/bindings/usb/generic-xhci.yaml
@@ -9,9 +9,6 @@ title: USB xHCI Controller
maintainers:
- Mathias Nyman <[email protected]>
-allOf:
- - $ref: usb-xhci.yaml#
-
properties:
compatible:
oneOf:
@@ -25,6 +22,11 @@ properties:
- marvell,armada-380-xhci
- marvell,armada-8k-xhci
- const: generic-xhci
+ - description: Broadcom SoCs with power domains
+ items:
+ - enum:
+ - brcm,bcm2711-xhci
+ - const: brcm,xhci-brcm-v2
- description: Broadcom STB SoCs with xHCI
enum:
- brcm,xhci-brcm-v2
@@ -49,6 +51,9 @@ properties:
- const: core
- const: reg
+ power-domains:
+ maxItems: 1
+
unevaluatedProperties: false
required:
@@ -56,6 +61,20 @@ required:
- reg
- interrupts
+allOf:
+ - $ref: usb-xhci.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: brcm,bcm2711-xhci
+ then:
+ required:
+ - power-domains
+ else:
+ properties:
+ power-domains: false
+
examples:
- |
usb@f0931000 {
diff --git a/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml b/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml
index ee08b9c3721f..37cf5249e526 100644
--- a/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml
+++ b/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml
@@ -29,6 +29,11 @@ properties:
description:
the regulator that provides 3.3V core power to the hub.
+ peer-hub:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ phandle to the peer hub on the controller.
+
required:
- compatible
- reg
diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml
index e9644e333d78..924fd3d748a8 100644
--- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml
+++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml
@@ -124,6 +124,17 @@ properties:
defined in the xHCI spec on MTK's controller.
default: 5000
+ rx-fifo-depth:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description:
+ It is a quirk used to work around Gen1 isoc-in endpoint transfer issue
+ that still send out unexpected ACK after device finishes the burst
+ transfer with a short packet and cause an exception, specially on a 4K
+ camera device, it happens on controller before about IPM v1.6.0;
+ the side-effect is that it may cause performance drop about 10%,
+ including bulk transfer, prefer to use 3k here. The size is in bytes.
+ enum: [1024, 2048, 3072, 4096]
+
# the following properties are only used for case 1
wakeup-source:
description: enable USB remote wakeup, see power/wakeup-source.txt
diff --git a/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml b/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml
index 28eb25ecba74..eaedb4cc6b6c 100644
--- a/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml
+++ b/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml
@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/usb/nxp,ptn5110.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: NXP PTN5110 Typec Port Cotroller
+title: NXP PTN5110 Type-C Port Controller
maintainers:
- Li Jun <[email protected]>
diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
index 915c8205623b..63d150b216c5 100644
--- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml
@@ -46,6 +46,8 @@ properties:
- qcom,sm8350-dwc3
- qcom,sm8450-dwc3
- qcom,sm8550-dwc3
+ - qcom,sm8650-dwc3
+ - qcom,x1e80100-dwc3
- const: qcom,dwc3
reg:
@@ -97,12 +99,29 @@ properties:
- const: apps-usb
interrupts:
- minItems: 1
- maxItems: 4
+ description: |
+ Different types of interrupts are used based on HS PHY used on target:
+ - pwr_event: Used for wakeup based on other power events.
+ - hs_phY_irq: Apart from DP/DM/QUSB2 PHY interrupts, there is
+ hs_phy_irq which is not triggered by default and its
+ functionality is mutually exclusive to that of
+ {dp/dm}_hs_phy_irq and qusb2_phy_irq.
+ - qusb2_phy: SoCs with QUSB2 PHY do not have separate DP/DM IRQs and
+ expose only a single IRQ whose behavior can be modified
+ by the QUSB2PHY_INTR_CTRL register. The required DPSE/
+ DMSE configuration is done in QUSB2PHY_INTR_CTRL register
+ of PHY address space.
+ - {dp/dm}_hs_phy_irq: These IRQ's directly reflect changes on the DP/
+ DM pads of the SoC. These are used for wakeup
+ only on SoCs with non-QUSB2 targets with
+ exception of SDM670/SDM845/SM6350.
+ - ss_phy_irq: Used for remote wakeup in Super Speed mode of operation.
+ minItems: 2
+ maxItems: 5
interrupt-names:
- minItems: 1
- maxItems: 4
+ minItems: 2
+ maxItems: 5
qcom,select-utmi-as-pipe-clk:
description:
@@ -263,6 +282,7 @@ allOf:
contains:
enum:
- qcom,sc8280xp-dwc3
+ - qcom,x1e80100-dwc3
then:
properties:
clocks:
@@ -288,8 +308,8 @@ allOf:
then:
properties:
clocks:
- minItems: 5
- maxItems: 6
+ minItems: 4
+ maxItems: 5
clock-names:
oneOf:
- items:
@@ -298,13 +318,11 @@ allOf:
- const: iface
- const: sleep
- const: mock_utmi
- - const: bus
- items:
- const: cfg_noc
- const: core
- const: sleep
- const: mock_utmi
- - const: bus
- if:
properties:
@@ -318,6 +336,7 @@ allOf:
- qcom,sm8250-dwc3
- qcom,sm8450-dwc3
- qcom,sm8550-dwc3
+ - qcom,sm8650-dwc3
then:
properties:
clocks:
@@ -357,59 +376,20 @@ allOf:
compatible:
contains:
enum:
- - qcom,ipq4019-dwc3
+ - qcom,ipq5018-dwc3
- qcom,ipq6018-dwc3
- - qcom,ipq8064-dwc3
- qcom,ipq8074-dwc3
- - qcom,msm8994-dwc3
- - qcom,qcs404-dwc3
- - qcom,sc7180-dwc3
- - qcom,sdm670-dwc3
- - qcom,sdm845-dwc3
- - qcom,sdx55-dwc3
- - qcom,sdx65-dwc3
- - qcom,sdx75-dwc3
- - qcom,sm4250-dwc3
- - qcom,sm6125-dwc3
- - qcom,sm6350-dwc3
- - qcom,sm8150-dwc3
- - qcom,sm8250-dwc3
- - qcom,sm8350-dwc3
- - qcom,sm8450-dwc3
- - qcom,sm8550-dwc3
- then:
- properties:
- interrupts:
- items:
- - description: The interrupt that is asserted
- when a wakeup event is received on USB2 bus.
- - description: The interrupt that is asserted
- when a wakeup event is received on USB3 bus.
- - description: Wakeup event on DM line.
- - description: Wakeup event on DP line.
- interrupt-names:
- items:
- - const: hs_phy_irq
- - const: ss_phy_irq
- - const: dm_hs_phy_irq
- - const: dp_hs_phy_irq
-
- - if:
- properties:
- compatible:
- contains:
- enum:
- qcom,msm8953-dwc3
- - qcom,msm8996-dwc3
- qcom,msm8998-dwc3
- - qcom,sm6115-dwc3
then:
properties:
interrupts:
- maxItems: 2
+ minItems: 2
+ maxItems: 3
interrupt-names:
items:
- - const: hs_phy_irq
+ - const: pwr_event
+ - const: qusb2_phy
- const: ss_phy_irq
- if:
@@ -417,37 +397,21 @@ allOf:
compatible:
contains:
enum:
- - qcom,ipq5018-dwc3
- - qcom,ipq5332-dwc3
+ - qcom,msm8996-dwc3
+ - qcom,qcs404-dwc3
- qcom,sdm660-dwc3
- then:
- properties:
- interrupts:
- minItems: 1
- maxItems: 2
- interrupt-names:
- minItems: 1
- items:
- - const: hs_phy_irq
- - const: ss_phy_irq
-
- - if:
- properties:
- compatible:
- contains:
- enum:
- - qcom,sc7280-dwc3
+ - qcom,sm6115-dwc3
+ - qcom,sm6125-dwc3
then:
properties:
interrupts:
minItems: 3
maxItems: 4
interrupt-names:
- minItems: 3
items:
+ - const: pwr_event
+ - const: qusb2_phy
- const: hs_phy_irq
- - const: dp_hs_phy_irq
- - const: dm_hs_phy_irq
- const: ss_phy_irq
- if:
@@ -455,7 +419,8 @@ allOf:
compatible:
contains:
enum:
- - qcom,sc8280xp-dwc3
+ - qcom,ipq5332-dwc3
+ - qcom,x1e80100-dwc3
then:
properties:
interrupts:
@@ -472,16 +437,35 @@ allOf:
compatible:
contains:
enum:
+ - qcom,ipq4019-dwc3
+ - qcom,ipq8064-dwc3
+ - qcom,msm8994-dwc3
- qcom,sa8775p-dwc3
+ - qcom,sc7180-dwc3
+ - qcom,sc7280-dwc3
+ - qcom,sc8280xp-dwc3
+ - qcom,sdm670-dwc3
+ - qcom,sdm845-dwc3
+ - qcom,sdx55-dwc3
+ - qcom,sdx65-dwc3
+ - qcom,sdx75-dwc3
+ - qcom,sm4250-dwc3
+ - qcom,sm6350-dwc3
+ - qcom,sm8150-dwc3
+ - qcom,sm8250-dwc3
+ - qcom,sm8350-dwc3
+ - qcom,sm8450-dwc3
+ - qcom,sm8550-dwc3
+ - qcom,sm8650-dwc3
then:
properties:
interrupts:
- minItems: 3
- maxItems: 4
+ minItems: 4
+ maxItems: 5
interrupt-names:
- minItems: 3
items:
- const: pwr_event
+ - const: hs_phy_irq
- const: dp_hs_phy_irq
- const: dm_hs_phy_irq
- const: ss_phy_irq
@@ -519,12 +503,13 @@ examples:
<&gcc GCC_USB30_PRIM_MASTER_CLK>;
assigned-clock-rates = <19200000>, <150000000>;
- interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 486 IRQ_TYPE_LEVEL_HIGH>,
+ interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 489 IRQ_TYPE_EDGE_BOTH>,
<GIC_SPI 488 IRQ_TYPE_EDGE_BOTH>,
- <GIC_SPI 489 IRQ_TYPE_EDGE_BOTH>;
- interrupt-names = "hs_phy_irq", "ss_phy_irq",
- "dm_hs_phy_irq", "dp_hs_phy_irq";
+ <GIC_SPI 486 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "pwr_event", "hs_phy_irq",
+ "dp_hs_phy_irq", "dm_hs_phy_irq", "ss_phy_irq";
power-domains = <&gcc USB30_PRIM_GDSC>;
diff --git a/Documentation/devicetree/bindings/usb/qcom,wcd939x-usbss.yaml b/Documentation/devicetree/bindings/usb/qcom,wcd939x-usbss.yaml
new file mode 100644
index 000000000000..7ddfd3313a18
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/qcom,wcd939x-usbss.yaml
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/qcom,wcd939x-usbss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm WCD9380/WCD9385 USB SubSystem Altmode/Analog Audio Switch
+
+maintainers:
+ - Neil Armstrong <[email protected]>
+
+description:
+ Qualcomm WCD9390/WCD9395 is a standalone Hi-Fi audio codec IC with a
+ functionally separate USB SubSystem for Altmode/Analog Audio Switch
+ accessible over an I2C interface.
+ The Audio Headphone and Microphone data path between the Codec and the
+ USB-C Mux subsystems are external to the IC, thus requiring DT port-endpoint
+ graph description to handle USB-C altmode & orientation switching for Audio
+ Accessory Mode.
+
+properties:
+ compatible:
+ oneOf:
+ - const: qcom,wcd9390-usbss
+ - items:
+ - const: qcom,wcd9395-usbss
+ - const: qcom,wcd9390-usbss
+
+ reg:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+
+ vdd-supply:
+ description: USBSS VDD power supply
+
+ mode-switch:
+ description: Flag the port as possible handle of altmode switching
+ type: boolean
+
+ orientation-switch:
+ description: Flag the port as possible handler of orientation switching
+ type: boolean
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ A port node to link the WCD939x USB SubSystem to a TypeC controller for the
+ purpose of handling altmode muxing and orientation switching.
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description:
+ A port node to link the WCD939x USB SubSystem to the Codec SubSystem for the
+ purpose of handling USB-C Audio Accessory Mode muxing and orientation switching.
+
+required:
+ - compatible
+ - reg
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ typec-mux@42 {
+ compatible = "qcom,wcd9390-usbss";
+ reg = <0x42>;
+
+ vdd-supply = <&vreg_bob>;
+
+ mode-switch;
+ orientation-switch;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ wcd9390_usbss_sbu: endpoint {
+ remote-endpoint = <&typec_sbu>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ wcd9390_usbss_codec: endpoint {
+ remote-endpoint = <&wcd9390_codec_usbss>;
+ };
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml
index bad55dfb2fa0..40ada78f2328 100644
--- a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml
+++ b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml
@@ -19,7 +19,7 @@ properties:
- items:
- enum:
- renesas,usbhs-r7s9210 # RZ/A2
- - renesas,usbhs-r9a07g043 # RZ/G2UL
+ - renesas,usbhs-r9a07g043 # RZ/G2UL and RZ/Five
- renesas,usbhs-r9a07g044 # RZ/G2{L,LC}
- renesas,usbhs-r9a07g054 # RZ/V2L
- const: renesas,rza2-usbhs
diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml
index ee5af4b381b1..203a1eb66691 100644
--- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml
+++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml
@@ -432,6 +432,10 @@ properties:
items:
enum: [1, 4, 8, 16, 32, 64, 128, 256]
+ num-hc-interrupters:
+ maximum: 8
+ default: 1
+
port:
$ref: /schemas/graph.yaml#/properties/port
description:
diff --git a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml
index 323d664ae06a..1745e28b3110 100644
--- a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml
+++ b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml
@@ -38,6 +38,10 @@ properties:
- const: main
- const: patch-address
+ reset-gpios:
+ description: GPIO used for the HRESET pin.
+ maxItems: 1
+
wakeup-source: true
interrupts:
@@ -90,6 +94,7 @@ additionalProperties: false
examples:
- |
+ #include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
@@ -106,6 +111,7 @@ examples:
pinctrl-names = "default";
pinctrl-0 = <&typec_pins>;
+ reset-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
typec_con: connector {
compatible = "usb-c-connector";
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.yaml b/Documentation/devicetree/bindings/usb/usb-xhci.yaml
index 180a261c3e8f..4238ae896ef6 100644
--- a/Documentation/devicetree/bindings/usb/usb-xhci.yaml
+++ b/Documentation/devicetree/bindings/usb/usb-xhci.yaml
@@ -29,6 +29,12 @@ properties:
description: Interrupt moderation interval
default: 5000
+ num-hc-interrupters:
+ description: Maximum number of interrupters to allocate
+ $ref: /schemas/types.yaml#/definitions/uint16
+ minimum: 1
+ maximum: 1024
+
additionalProperties: true
examples:
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 100fbf9826dc..1a0dc04f1db4 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -79,6 +79,8 @@ patternProperties:
description: ALFA Network Inc.
"^allegro,.*":
description: Allegro DVT
+ "^alliedvision,.*":
+ description: Allied Vision Technologies GmbH
"^allo,.*":
description: Allo.com
"^allwinner,.*":
@@ -119,6 +121,8 @@ patternProperties:
description: Andes Technology Corporation
"^anvo,.*":
description: Anvo-Systems Dresden GmbH
+ "^aosong,.*":
+ description: Guangzhou Aosong Electronic Co., Ltd.
"^apm,.*":
description: Applied Micro Circuits Corporation (APM)
"^apple,.*":
@@ -508,6 +512,8 @@ patternProperties:
description: Fujitsu Ltd.
"^fxtec,.*":
description: FX Technology Ltd.
+ "^galaxycore,.*":
+ description: GalaxyCore Inc.
"^gardena,.*":
description: GARDENA GmbH
"^gateway,.*":
@@ -1291,6 +1297,8 @@ patternProperties:
description: Skyworks Solutions, Inc.
"^smartlabs,.*":
description: SmartLabs LLC
+ "^smi,.*":
+ description: Silicon Motion Technology Corporation
"^smsc,.*":
description: Standard Microsystems Corporation
"^snps,.*":
@@ -1391,6 +1399,8 @@ patternProperties:
description: Technologic Systems
"^techstar,.*":
description: Shenzhen Techstar Electronics Co., Ltd.
+ "^techwell,.*":
+ description: Techwell, Inc.
"^teejet,.*":
description: TeeJet
"^teltonika,.*":
diff --git a/Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml b/Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml
new file mode 100644
index 000000000000..ef70fa2c0c5d
--- /dev/null
+++ b/Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/w1/amd,axi-1wire-host.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AMD AXI 1-wire bus host for programmable logic
+
+maintainers:
+ - Kris Chaplin <[email protected]>
+
+properties:
+ compatible:
+ const: amd,axi-1wire-host
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - interrupts
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ onewire@a0000000 {
+ compatible = "amd,axi-1wire-host";
+ reg = <0xa0000000 0x10000>;
+ clocks = <&zynqmp_clk 0x47>;
+ interrupts = <GIC_SPI 0x59 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+...
diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst
index 6456145f96ed..b4920b34cebc 100644
--- a/Documentation/driver-api/media/camera-sensor.rst
+++ b/Documentation/driver-api/media/camera-sensor.rst
@@ -9,8 +9,8 @@ This document covers the in-kernel APIs only. For the best practices on
userspace API implementation in camera sensor drivers, please see
:ref:`media_using_camera_sensor_drivers`.
-CSI-2 and parallel (BT.601 and BT.656) busses
----------------------------------------------
+CSI-2, parallel and BT.656 buses
+--------------------------------
Please see :ref:`transmitter-receiver`.
@@ -60,7 +60,8 @@ management over the pipeline.
Camera sensor drivers are responsible for controlling the power state of the
device they otherwise control as well. They shall use runtime PM to manage
power states. Runtime PM shall be enabled at probe time and disabled at remove
-time. Drivers should enable runtime PM autosuspend.
+time. Drivers should enable runtime PM autosuspend. Also see
+:ref:`async sub-device registration <media-registering-async-subdevs>`.
The runtime PM handlers shall handle clocks, regulators, GPIOs, and other
system resources required to power the sensor up and down. For drivers that
diff --git a/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs b/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs
index 2a4edc7e051a..3d3152b45821 100755
--- a/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs
+++ b/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs
@@ -82,14 +82,6 @@ for my $fh ($H, $LH) {
print $fh "/* $license */\n$copyright$note\n";
}
-sub bit_def($) {
- my $bit = shift @_;
-
- return "BIT($bit)" if defined $kernel;
- return "(1U << $bit)" if $bit =~ /^[a-zA-Z0-9_]+$/;
- return "(1U << ($bit))";
-}
-
print $H <<EOF
#ifndef __${uc_header}__
#define __${uc_header}__
@@ -97,23 +89,63 @@ print $H <<EOF
EOF
;
-print $H "#include <linux/bits.h>\n\n" if defined $kernel;
-
print $H <<EOF
-#define CCS_FL_BASE 16
+#include <linux/bits.h>
+
+#include <media/v4l2-cci.h>
+
EOF
- ;
+ if defined $kernel;
+
+print $H "#define CCS_FL_BASE " .
+ (defined $kernel ? "CCI_REG_PRIVATE_SHIFT" : 16) . "\n";
+
+my $flag = -1;
+my $all_flags;
+
+sub bit_def($) {
+ my $bit = shift @_;
+
+ if (defined $kernel) {
+ return "BIT$bit" if $bit =~ /^\(.*\)$/;
+ return "BIT($bit)";
+ }
+ return "(1U << $bit)";
+}
+
+sub flag_str($$) {
+ my ($flag, $check) = @_;
-print $H "#define CCS_FL_16BIT " . bit_def("CCS_FL_BASE") . "\n";
-print $H "#define CCS_FL_32BIT " . bit_def("CCS_FL_BASE + 1") . "\n";
-print $H "#define CCS_FL_FLOAT_IREAL " . bit_def("CCS_FL_BASE + 2") . "\n";
-print $H "#define CCS_FL_IREAL " . bit_def("CCS_FL_BASE + 3") . "\n";
+ $$flag++;
+
+ my $flag_str = !$$flag ? "CCS_FL_BASE" : "(CCS_FL_BASE + $$flag)";
+
+ $flag_str = bit_def($flag_str);
+
+ $$check .= " | " if defined $$check;
+
+ $$check .= $flag_str;
+
+ return $flag_str;
+}
+
+if (! defined $kernel) {
+ print $H "#define CCS_FL_16BIT " . flag_str(\$flag, \$all_flags) . "\n";
+ print $H "#define CCS_FL_32BIT " . flag_str(\$flag, \$all_flags) . "\n";
+}
+
+print $H "#define CCS_FL_FLOAT_IREAL " . flag_str(\$flag, \$all_flags) . "\n";
+print $H "#define CCS_FL_IREAL " . flag_str(\$flag, \$all_flags) . "\n";
+print $H "#define CCS_BUILD_BUG \\
+ BUILD_BUG_ON(~CCI_REG_PRIVATE_MASK & ($all_flags))\n"
+ if defined $kernel;
print $H <<EOF
+
#define CCS_R_ADDR(r) ((r) & 0xffff)
EOF
- ;
+ if ! defined $kernel;
print $A <<EOF
#include <stdint.h>
@@ -189,12 +221,12 @@ sub tabconv($) {
return (join "\n", @l) . "\n";
}
-sub elem_size(@) {
+sub elem_bits(@) {
my @flags = @_;
- return 2 if grep /^16$/, @flags;
- return 4 if grep /^32$/, @flags;
- return 1;
+ return 16 if grep /^16$/, @flags;
+ return 32 if grep /^32$/, @flags;
+ return 8;
}
sub arr_size($) {
@@ -296,9 +328,13 @@ while (<$R>) {
next if $#{$this{args}} + 1 != scalar keys %{$this{argparams}};
- my $reg_formula = "($this{addr}";
+ my $reg_formula = "$this{addr}";
my $lim_formula;
+ chop $reg_formula;
+
+ $reg_formula = "(" . $reg_formula if $this{flagstring} ne "";
+
foreach my $arg (@{$this{args}}) {
my $d = $h->{$arg}->{discontig};
my $times = $h->{$arg}->{elsize} != 1 ?
@@ -315,11 +351,13 @@ while (<$R>) {
$lim_formula .= (defined $lim_formula ? " + " : "") . "($arg)$times";
}
- $reg_formula .= ")\n";
+ $reg_formula .= ")";
$lim_formula =~ s/^\(([a-z0-9]+)\)$/$1/i;
print $H tabconv sprintf("#define %-62s %s", "CCS_R_" . (uc $this{name}) .
- $this{arglist}, $reg_formula);
+ $this{arglist}, $reg_formula .
+ (($this{flagstring} eq "") ? "" :
+ " | " . $this{flagstring} . ")") . "\n");
print $H tabconv $hdr_data;
undef $hdr_data;
@@ -369,16 +407,23 @@ while (<$R>) {
$name =~ s/[,\.-]/_/g;
my $flagstring = "";
- my $size = elem_size(@flags);
- $flagstring .= "| CCS_FL_16BIT " if $size eq "2";
- $flagstring .= "| CCS_FL_32BIT " if $size eq "4";
+ my $bits = elem_bits(@flags);
+ if (! defined $kernel) {
+ $flagstring .= "| CCS_FL_16BIT " if $bits == 16;
+ $flagstring .= "| CCS_FL_32BIT " if $bits == 32;
+ }
$flagstring .= "| CCS_FL_FLOAT_IREAL " if grep /^float_ireal$/, @flags;
$flagstring .= "| CCS_FL_IREAL " if grep /^ireal$/, @flags;
$flagstring =~ s/^\| //;
$flagstring =~ s/ $//;
$flagstring = "($flagstring)" if $flagstring =~ /\|/;
my $base_addr = $addr;
- $addr = "($addr | $flagstring)" if $flagstring ne "";
+ $addr = "CCI_REG$bits($addr)" if defined $kernel;
+
+ if ($flagstring ne "" && !@$args) {
+ $addr = "($addr | $flagstring)";
+ $flagstring = "";
+ }
my $arglist = @$args ? "(" . (join ", ", @$args) . ")" : "";
$hdr_data .= sprintf "#define %-62s %s\n", "CCS_R_" . (uc $name), $addr
@@ -388,11 +433,12 @@ while (<$R>) {
%this = ( name => $name,
addr => $addr,
+ flagstring => $flagstring,
base_addr => $base_addr,
argparams => {},
args => $args,
arglist => $arglist,
- elsize => $size,
+ elsize => $bits / 8,
);
if (!@$args) {
diff --git a/Documentation/driver-api/media/tx-rx.rst b/Documentation/driver-api/media/tx-rx.rst
index e1e9258dd862..29d66a47b56e 100644
--- a/Documentation/driver-api/media/tx-rx.rst
+++ b/Documentation/driver-api/media/tx-rx.rst
@@ -6,8 +6,8 @@ Pixel data transmitter and receiver drivers
===========================================
V4L2 supports various devices that transmit and receive pixel data. Examples of
-these devices include a camera sensor, a TV tuner and a parallel or a CSI-2
-receiver in an SoC.
+these devices include a camera sensor, a TV tuner and a parallel, a BT.656 or a
+CSI-2 receiver in an SoC.
Bus types
---------
@@ -22,12 +22,13 @@ the host SoC. It is defined by the `MIPI alliance`_.
.. _`MIPI alliance`: https://www.mipi.org/
-Parallel
-^^^^^^^^
+Parallel and BT.656
+^^^^^^^^^^^^^^^^^^^
-`BT.601`_ and `BT.656`_ are the most common parallel busses.
+The parallel and `BT.656`_ buses transport one bit of data on each clock cycle
+per data line. The parallel bus uses synchronisation and other additional
+signals whereas BT.656 embeds synchronisation.
-.. _`BT.601`: https://en.wikipedia.org/wiki/Rec._601
.. _`BT.656`: https://en.wikipedia.org/wiki/ITU-R_BT.656
Transmitter drivers
@@ -90,8 +91,8 @@ where
pixel rate on the camera sensor's pixel array which is indicated by the
:ref:`V4L2_CID_PIXEL_RATE <v4l2-cid-pixel-rate>` control.
-LP-11 and LP-111 modes
-^^^^^^^^^^^^^^^^^^^^^^
+LP-11 and LP-111 states
+^^^^^^^^^^^^^^^^^^^^^^^
As part of transitioning to high speed mode, a CSI-2 transmitter typically
briefly sets the bus to LP-11 or LP-111 state, depending on the PHY. This period
@@ -105,7 +106,7 @@ in software, especially when there is no interrupt telling something is
happening.
One way to address this is to configure the transmitter side explicitly to LP-11
-or LP-111 mode, which requires support from the transmitter hardware. This is
+or LP-111 state, which requires support from the transmitter hardware. This is
not universally available. Many devices return to this state once streaming is
stopped while the state after power-on is LP-00 or LP-000.
@@ -116,11 +117,11 @@ transitioning to streaming state, but not yet start streaming. Similarly, the
to call ``.post_streamoff()`` for each successful call of ``.pre_streamon()``.
In the context of CSI-2, the ``.pre_streamon()`` callback is used to transition
-the transmitter to the LP-11 or LP-111 mode. This also requires powering on the
+the transmitter to the LP-11 or LP-111 state. This also requires powering on the
device, so this should be only done when it is needed.
-Receiver drivers that do not need explicit LP-11 or LP-111 mode setup are waived
-from calling the two callbacks.
+Receiver drivers that do not need explicit LP-11 or LP-111 state setup are
+waived from calling the two callbacks.
Stopping the transmitter
^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst
index e56b50b3f203..1db2ba27c54c 100644
--- a/Documentation/driver-api/media/v4l2-subdev.rst
+++ b/Documentation/driver-api/media/v4l2-subdev.rst
@@ -181,6 +181,8 @@ You can unregister a sub-device using:
Afterwards the subdev module can be unloaded and
:c:type:`sd <v4l2_subdev>`->dev == ``NULL``.
+.. _media-registering-async-subdevs:
+
Registering asynchronous sub-devices
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -195,6 +197,11 @@ performed using the :c:func:`v4l2_async_unregister_subdev` call. Subdevices
registered this way are stored in a global list of subdevices, ready to be
picked up by bridge drivers.
+Drivers must complete all initialization of the sub-device before
+registering it using :c:func:`v4l2_async_register_subdev`, including
+enabling runtime PM. This is because the sub-device becomes accessible
+as soon as it gets registered.
+
Asynchronous sub-device notifiers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -562,8 +569,8 @@ device configuration. This is often implemented as e.g. an array of struct
v4l2_mbus_framefmt, one entry for each pad, and similarly for crop and compose
rectangles.
-In addition to the active configuration, each subdev file handle has an array of
-struct v4l2_subdev_pad_config, managed by the V4L2 core, which contains the try
+In addition to the active configuration, each subdev file handle has a struct
+v4l2_subdev_state, managed by the V4L2 core, which contains the try
configuration.
To simplify the subdev drivers the V4L2 subdev API now optionally supports a
diff --git a/Documentation/driver-api/pci/p2pdma.rst b/Documentation/driver-api/pci/p2pdma.rst
index 44deb52beeb4..d0b241628cf1 100644
--- a/Documentation/driver-api/pci/p2pdma.rst
+++ b/Documentation/driver-api/pci/p2pdma.rst
@@ -83,19 +83,9 @@ this to include other types of resources like doorbells.
Client Drivers
--------------
-A client driver typically only has to conditionally change its DMA map
-routine to use the mapping function :c:func:`pci_p2pdma_map_sg()` instead
-of the usual :c:func:`dma_map_sg()` function. Memory mapped in this
-way does not need to be unmapped.
-
-The client may also, optionally, make use of
-:c:func:`is_pci_p2pdma_page()` to determine when to use the P2P mapping
-functions and when to use the regular mapping functions. In some
-situations, it may be more appropriate to use a flag to indicate a
-given request is P2P memory and map appropriately. It is important to
-ensure that struct pages that back P2P memory stay out of code that
-does not have support for them as other code may treat the pages as
-regular memory which may not be appropriate.
+A client driver only has to use the mapping API :c:func:`dma_map_sg()`
+and :c:func:`dma_unmap_sg()` functions as usual, and the implementation
+will do the right thing for the P2P capable memory.
Orchestrator Drivers
diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst
index bb264490a87a..3c28ccc4b611 100644
--- a/Documentation/driver-api/pwm.rst
+++ b/Documentation/driver-api/pwm.rst
@@ -41,11 +41,20 @@ the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist.
After being requested, a PWM has to be configured using::
- int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state);
+ int pwm_apply_might_sleep(struct pwm_device *pwm, struct pwm_state *state);
This API controls both the PWM period/duty_cycle config and the
enable/disable state.
+PWM devices can be used from atomic context, if the PWM does not sleep. You
+can check if this the case with::
+
+ bool pwm_might_sleep(struct pwm_device *pwm);
+
+If false, the PWM can also be configured from atomic context with::
+
+ int pwm_apply_atomic(struct pwm_device *pwm, struct pwm_state *state);
+
As a consumer, don't rely on the output's state for a disabled PWM. If it's
easily possible, drivers are supposed to emit the inactive state, but some
drivers cannot. If you rely on getting the inactive state, use .duty_cycle=0,
@@ -57,13 +66,13 @@ If supported by the driver, the signal can be optimized, for example to improve
EMI by phase shifting the individual channels of a chip.
The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers
-around pwm_apply_state() and should not be used if the user wants to change
+around pwm_apply_might_sleep() and should not be used if the user wants to change
several parameter at once. For example, if you see pwm_config() and
pwm_{enable,disable}() calls in the same function, this probably means you
-should switch to pwm_apply_state().
+should switch to pwm_apply_might_sleep().
The PWM user API also allows one to query the PWM state that was passed to the
-last invocation of pwm_apply_state() using pwm_get_state(). Note this is
+last invocation of pwm_apply_might_sleep() using pwm_get_state(). Note this is
different to what the driver has actually implemented if the request cannot be
satisfied exactly with the hardware in use. There is currently no way for
consumers to get the actually implemented settings.
diff --git a/Documentation/fb/index.rst b/Documentation/fb/index.rst
index baf02393d8ee..33e3c49f8856 100644
--- a/Documentation/fb/index.rst
+++ b/Documentation/fb/index.rst
@@ -19,7 +19,6 @@ Frame Buffer
framebuffer
gxfb
intel810
- intelfb
internals
lxfb
matroxfb
diff --git a/Documentation/fb/intelfb.rst b/Documentation/fb/intelfb.rst
deleted file mode 100644
index e2d0903f4efb..000000000000
--- a/Documentation/fb/intelfb.rst
+++ /dev/null
@@ -1,155 +0,0 @@
-=============================================================
-Intel 830M/845G/852GM/855GM/865G/915G/945G Framebuffer driver
-=============================================================
-
-A. Introduction
-===============
-
-This is a framebuffer driver for various Intel 8xx/9xx compatible
-graphics devices. These would include:
-
- - Intel 830M
- - Intel 845G
- - Intel 852GM
- - Intel 855GM
- - Intel 865G
- - Intel 915G
- - Intel 915GM
- - Intel 945G
- - Intel 945GM
- - Intel 945GME
- - Intel 965G
- - Intel 965GM
-
-B. List of available options
-=============================
-
- a. "video=intelfb"
- enables the intelfb driver
-
- Recommendation: required
-
- b. "mode=<xres>x<yres>[-<bpp>][@<refresh>]"
- select mode
-
- Recommendation: user preference
- (default = 1024x768-32@70)
-
- c. "vram=<value>"
- select amount of system RAM in MB to allocate for the video memory
- if not enough RAM was already allocated by the BIOS.
-
- Recommendation: 1 - 4 MB.
- (default = 4 MB)
-
- d. "voffset=<value>"
- select at what offset in MB of the logical memory to allocate the
- framebuffer memory. The intent is to avoid the memory blocks
- used by standard graphics applications (XFree86). Depending on your
- usage, adjust the value up or down, (0 for maximum usage, 63/127 MB
- for the least amount). Note, an arbitrary setting may conflict
- with XFree86.
-
- Recommendation: do not set
- (default = 48 MB)
-
- e. "accel"
- enable text acceleration. This can be enabled/reenabled anytime
- by using 'fbset -accel true/false'.
-
- Recommendation: enable
- (default = set)
-
- f. "hwcursor"
- enable cursor acceleration.
-
- Recommendation: enable
- (default = set)
-
- g. "mtrr"
- enable MTRR. This allows data transfers to the framebuffer memory
- to occur in bursts which can significantly increase performance.
- Not very helpful with the intel chips because of 'shared memory'.
-
- Recommendation: set
- (default = set)
-
- h. "fixed"
- disable mode switching.
-
- Recommendation: do not set
- (default = not set)
-
- The binary parameters can be unset with a "no" prefix, example "noaccel".
- The default parameter (not named) is the mode.
-
-C. Kernel booting
-=================
-
-Separate each option/option-pair by commas (,) and the option from its value
-with an equals sign (=) as in the following::
-
- video=intelfb:option1,option2=value2
-
-Sample Usage
-------------
-
-In /etc/lilo.conf, add the line::
-
- append="video=intelfb:mode=800x600-32@75,accel,hwcursor,vram=8"
-
-This will initialize the framebuffer to 800x600 at 32bpp and 75Hz. The
-framebuffer will use 8 MB of System RAM. hw acceleration of text and cursor
-will be enabled.
-
-Remarks
--------
-
-If setting this parameter doesn't work (you stay in a 80x25 text-mode),
-you might need to set the "vga=<mode>" parameter too - see vesafb.txt
-in this directory.
-
-
-D. Module options
-==================
-
-The module parameters are essentially similar to the kernel
-parameters. The main difference is that you need to include a Boolean value
-(1 for TRUE, and 0 for FALSE) for those options which don't need a value.
-
-Example, to enable MTRR, include "mtrr=1".
-
-Sample Usage
-------------
-
-Using the same setup as described above, load the module like this::
-
- modprobe intelfb mode=800x600-32@75 vram=8 accel=1 hwcursor=1
-
-Or just add the following to a configuration file in /etc/modprobe.d/::
-
- options intelfb mode=800x600-32@75 vram=8 accel=1 hwcursor=1
-
-and just do a::
-
- modprobe intelfb
-
-
-E. Acknowledgment:
-===================
-
- 1. Geert Uytterhoeven - his excellent howto and the virtual
- framebuffer driver code made this possible.
-
- 2. Jeff Hartmann for his agpgart code.
-
- 3. David Dawes for his original kernel 2.4 code.
-
- 4. The X developers. Insights were provided just by reading the
- XFree86 source code.
-
- 5. Antonino A. Daplas for his inspiring i810fb driver.
-
- 6. Andrew Morton for his kernel patches maintenance.
-
-Sylvain
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index d414e145f912..4202174a6262 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -396,10 +396,11 @@ Memory barriers come in four basic varieties:
(2) Address-dependency barriers (historical).
- [!] This section is marked as HISTORICAL: For more up-to-date
- information, including how compiler transformations related to pointer
- comparisons can sometimes cause problems, see
- Documentation/RCU/rcu_dereference.rst.
+ [!] This section is marked as HISTORICAL: it covers the long-obsolete
+ smp_read_barrier_depends() macro, the semantics of which are now
+ implicit in all marked accesses. For more up-to-date information,
+ including how compiler transformations can sometimes break address
+ dependencies, see Documentation/RCU/rcu_dereference.rst.
An address-dependency barrier is a weaker form of read barrier. In the
case where two loads are performed such that the second depends on the
@@ -560,9 +561,11 @@ There are certain things that the Linux kernel memory barriers do not guarantee:
ADDRESS-DEPENDENCY BARRIERS (HISTORICAL)
----------------------------------------
-[!] This section is marked as HISTORICAL: For more up-to-date information,
-including how compiler transformations related to pointer comparisons can
-sometimes cause problems, see Documentation/RCU/rcu_dereference.rst.
+[!] This section is marked as HISTORICAL: it covers the long-obsolete
+smp_read_barrier_depends() macro, the semantics of which are now implicit
+in all marked accesses. For more up-to-date information, including
+how compiler transformations can sometimes break address dependencies,
+see Documentation/RCU/rcu_dereference.rst.
As of v4.15 of the Linux kernel, an smp_mb() was added to READ_ONCE() for
DEC Alpha, which means that about the only people who need to pay attention
diff --git a/Documentation/sphinx/kernel_feat.py b/Documentation/sphinx/kernel_feat.py
index b5fa2f0542a5..b9df61eb4501 100644
--- a/Documentation/sphinx/kernel_feat.py
+++ b/Documentation/sphinx/kernel_feat.py
@@ -37,8 +37,6 @@ import re
import subprocess
import sys
-from os import path
-
from docutils import nodes, statemachine
from docutils.statemachine import ViewList
from docutils.parsers.rst import directives, Directive
@@ -76,33 +74,26 @@ class KernelFeat(Directive):
self.state.document.settings.env.app.warn(message, prefix="")
def run(self):
-
doc = self.state.document
if not doc.settings.file_insertion_enabled:
raise self.warning("docutils: file insertion disabled")
env = doc.settings.env
- cwd = path.dirname(doc.current_source)
- cmd = "get_feat.pl rest --enable-fname --dir "
- cmd += self.arguments[0]
-
- if len(self.arguments) > 1:
- cmd += " --arch " + self.arguments[1]
- srctree = path.abspath(os.environ["srctree"])
+ srctree = os.path.abspath(os.environ["srctree"])
- fname = cmd
+ args = [
+ os.path.join(srctree, 'scripts/get_feat.pl'),
+ 'rest',
+ '--enable-fname',
+ '--dir',
+ os.path.join(srctree, 'Documentation', self.arguments[0]),
+ ]
- # extend PATH with $(srctree)/scripts
- path_env = os.pathsep.join([
- srctree + os.sep + "scripts",
- os.environ["PATH"]
- ])
- shell_env = os.environ.copy()
- shell_env["PATH"] = path_env
- shell_env["srctree"] = srctree
+ if len(self.arguments) > 1:
+ args.extend(['--arch', self.arguments[1]])
- lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
+ lines = subprocess.check_output(args, cwd=os.path.dirname(doc.current_source)).decode('utf-8')
line_regex = re.compile(r"^\.\. FILE (\S+)$")
@@ -121,30 +112,6 @@ class KernelFeat(Directive):
nodeList = self.nestedParse(out_lines, fname)
return nodeList
- def runCmd(self, cmd, **kwargs):
- u"""Run command ``cmd`` and return its stdout as unicode."""
-
- try:
- proc = subprocess.Popen(
- cmd
- , stdout = subprocess.PIPE
- , stderr = subprocess.PIPE
- , **kwargs
- )
- out, err = proc.communicate()
-
- out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
-
- if proc.returncode != 0:
- raise self.severe(
- u"command '%s' failed with return code %d"
- % (cmd, proc.returncode)
- )
- except OSError as exc:
- raise self.severe(u"problems with '%s' directive: %s."
- % (self.name, ErrorString(exc)))
- return out
-
def nestedParse(self, lines, fname):
content = ViewList()
node = nodes.section()
diff --git a/Documentation/sphinx/requirements.txt b/Documentation/sphinx/requirements.txt
index a8a1aff6445e..5d47ed443949 100644
--- a/Documentation/sphinx/requirements.txt
+++ b/Documentation/sphinx/requirements.txt
@@ -1,4 +1,6 @@
# jinja2>=3.1 is not compatible with Sphinx<4.0
jinja2<3.1
+# alabaster>=0.7.14 is not compatible with Sphinx<=3.3
+alabaster<0.7.14
Sphinx==2.4.4
pyyaml
diff --git a/Documentation/staging/rpmsg.rst b/Documentation/staging/rpmsg.rst
index 1ce353cb232a..dba3e5f65612 100644
--- a/Documentation/staging/rpmsg.rst
+++ b/Documentation/staging/rpmsg.rst
@@ -68,13 +68,14 @@ User API
::
- int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len);
+ int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len);
-sends a message across to the remote processor on a given channel.
-The caller should specify the channel, the data it wants to send,
+sends a message across to the remote processor from the given endpoint.
+The caller should specify the endpoint, the data it wants to send,
and its length (in bytes). The message will be sent on the specified
-channel, i.e. its source and destination address fields will be
-set to the channel's src and dst addresses.
+endpoint's channel, i.e. its source and destination address fields will be
+respectively set to the endpoint's src address and its parent channel
+dst addresses.
In case there are no TX buffers available, the function will block until
one becomes available (i.e. until the remote processor consumes
@@ -87,17 +88,18 @@ Returns 0 on success and an appropriate error value on failure.
::
- int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst);
+ int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst);
-sends a message across to the remote processor on a given channel,
+sends a message across to the remote processor from a given endpoint,
to a destination address provided by the caller.
-The caller should specify the channel, the data it wants to send,
+The caller should specify the endpoint, the data it wants to send,
its length (in bytes), and an explicit destination address.
The message will then be sent to the remote processor to which the
-channel belongs, using the channel's src address, and the user-provided
-dst address (thus the channel's dst address will be ignored).
+endpoints's channel belongs, using the endpoints's src address,
+and the user-provided dst address (thus the channel's dst address
+will be ignored).
In case there are no TX buffers available, the function will block until
one becomes available (i.e. until the remote processor consumes
@@ -110,18 +112,19 @@ Returns 0 on success and an appropriate error value on failure.
::
- int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+ int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
void *data, int len);
sends a message across to the remote processor, using the src and dst
addresses provided by the user.
-The caller should specify the channel, the data it wants to send,
+The caller should specify the endpoint, the data it wants to send,
its length (in bytes), and explicit source and destination addresses.
The message will then be sent to the remote processor to which the
-channel belongs, but the channel's src and dst addresses will be
-ignored (and the user-provided addresses will be used instead).
+endpoint's channel belongs, but the endpoint's src and channel dst
+addresses will be ignored (and the user-provided addresses will
+be used instead).
In case there are no TX buffers available, the function will block until
one becomes available (i.e. until the remote processor consumes
@@ -134,13 +137,14 @@ Returns 0 on success and an appropriate error value on failure.
::
- int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len);
+ int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len);
-sends a message across to the remote processor on a given channel.
-The caller should specify the channel, the data it wants to send,
+sends a message across to the remote processor from a given endpoint.
+The caller should specify the endpoint, the data it wants to send,
and its length (in bytes). The message will be sent on the specified
-channel, i.e. its source and destination address fields will be
-set to the channel's src and dst addresses.
+endpoint's channel, i.e. its source and destination address fields will be
+respectively set to the endpoint's src address and its parent channel
+dst addresses.
In case there are no TX buffers available, the function will immediately
return -ENOMEM without waiting until one becomes available.
@@ -150,10 +154,10 @@ Returns 0 on success and an appropriate error value on failure.
::
- int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
+ int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst)
-sends a message across to the remote processor on a given channel,
+sends a message across to the remote processor from a given endoint,
to a destination address provided by the user.
The user should specify the channel, the data it wants to send,
@@ -171,7 +175,7 @@ Returns 0 on success and an appropriate error value on failure.
::
- int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst,
void *data, int len);
@@ -284,7 +288,7 @@ content to the console.
dev_info(&rpdev->dev, "chnl: 0x%x -> 0x%x\n", rpdev->src, rpdev->dst);
/* send a message on our channel */
- err = rpmsg_send(rpdev, "hello!", 6);
+ err = rpmsg_send(rpdev->ept, "hello!", 6);
if (err) {
pr_err("rpmsg_send failed: %d\n", err);
return err;
diff --git a/Documentation/trace/coresight/coresight.rst b/Documentation/trace/coresight/coresight.rst
index 826e59a698da..d4f93d6a2d63 100644
--- a/Documentation/trace/coresight/coresight.rst
+++ b/Documentation/trace/coresight/coresight.rst
@@ -624,6 +624,10 @@ They are also listed in the folder /sys/bus/event_source/devices/cs_etm/format/
* - timestamp
- Session local version of the system wide setting: :ref:`ETMv4_MODE_TIMESTAMP
<coresight-timestamp>`
+ * - cc_threshold
+ - Cycle count threshold value. If nothing is provided here or the provided value is 0, then the
+ default value i.e 0x100 will be used. If provided value is less than minimum cycles threshold
+ value, as indicated via TRCIDR3.CCITMIN, then the minimum value will be used instead.
How to use the STM module
-------------------------
diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst
index 16122a8895ba..7e7b8ec17934 100644
--- a/Documentation/trace/ftrace.rst
+++ b/Documentation/trace/ftrace.rst
@@ -218,6 +218,27 @@ of ftrace. Here is a list of some of the key files:
This displays the total combined size of all the trace buffers.
+ buffer_subbuf_size_kb:
+
+ This sets or displays the sub buffer size. The ring buffer is broken up
+ into several same size "sub buffers". An event can not be bigger than
+ the size of the sub buffer. Normally, the sub buffer is the size of the
+ architecture's page (4K on x86). The sub buffer also contains meta data
+ at the start which also limits the size of an event. That means when
+ the sub buffer is a page size, no event can be larger than the page
+ size minus the sub buffer meta data.
+
+ Note, the buffer_subbuf_size_kb is a way for the user to specify the
+ minimum size of the subbuffer. The kernel may make it bigger due to the
+ implementation details, or simply fail the operation if the kernel can
+ not handle the request.
+
+ Changing the sub buffer size allows for events to be larger than the
+ page size.
+
+ Note: When changing the sub-buffer size, tracing is stopped and any
+ data in the ring buffer and the snapshot buffer will be discarded.
+
free_buffer:
If a process is performing tracing, and the ring buffer should be
diff --git a/Documentation/trace/kprobes.rst b/Documentation/trace/kprobes.rst
index f825970a1495..e1636e579c9c 100644
--- a/Documentation/trace/kprobes.rst
+++ b/Documentation/trace/kprobes.rst
@@ -4,7 +4,7 @@ Kernel Probes (Kprobes)
:Author: Jim Keniston <[email protected]>
:Author: Prasanna S Panchamukhi <[email protected]>
-:Author: Masami Hiramatsu <[email protected]>
+:Author: Masami Hiramatsu <[email protected]>
.. CONTENTS
@@ -321,6 +321,7 @@ architectures:
- mips
- s390
- parisc
+- loongarch
Configuring Kprobes
===================
diff --git a/Documentation/translations/zh_CN/arch/loongarch/features.rst b/Documentation/translations/zh_CN/arch/loongarch/features.rst
index 82bfac180bdc..cec38dda8298 100644
--- a/Documentation/translations/zh_CN/arch/loongarch/features.rst
+++ b/Documentation/translations/zh_CN/arch/loongarch/features.rst
@@ -5,4 +5,4 @@
:Original: Documentation/arch/loongarch/features.rst
:Translator: Huacai Chen <[email protected]>
-.. kernel-feat:: $srctree/Documentation/features loongarch
+.. kernel-feat:: features loongarch
diff --git a/Documentation/translations/zh_CN/arch/mips/features.rst b/Documentation/translations/zh_CN/arch/mips/features.rst
index da1b956e4a40..0d6df97db069 100644
--- a/Documentation/translations/zh_CN/arch/mips/features.rst
+++ b/Documentation/translations/zh_CN/arch/mips/features.rst
@@ -10,4 +10,4 @@
.. _cn_features:
-.. kernel-feat:: $srctree/Documentation/features mips
+.. kernel-feat:: features mips
diff --git a/Documentation/translations/zh_TW/arch/loongarch/features.rst b/Documentation/translations/zh_TW/arch/loongarch/features.rst
index b64e430f55ae..c2175fd32b54 100644
--- a/Documentation/translations/zh_TW/arch/loongarch/features.rst
+++ b/Documentation/translations/zh_TW/arch/loongarch/features.rst
@@ -5,5 +5,5 @@
:Original: Documentation/arch/loongarch/features.rst
:Translator: Huacai Chen <[email protected]>
-.. kernel-feat:: $srctree/Documentation/features loongarch
+.. kernel-feat:: features loongarch
diff --git a/Documentation/translations/zh_TW/arch/mips/features.rst b/Documentation/translations/zh_TW/arch/mips/features.rst
index f69410420035..3d3906c4d08e 100644
--- a/Documentation/translations/zh_TW/arch/mips/features.rst
+++ b/Documentation/translations/zh_TW/arch/mips/features.rst
@@ -10,5 +10,5 @@
.. _tw_features:
-.. kernel-feat:: $srctree/Documentation/features mips
+.. kernel-feat:: features mips
diff --git a/Documentation/usb/gadget-testing.rst b/Documentation/usb/gadget-testing.rst
index 29072c166d23..8cd62c466d20 100644
--- a/Documentation/usb/gadget-testing.rst
+++ b/Documentation/usb/gadget-testing.rst
@@ -448,15 +448,17 @@ Function-specific configfs interface
The function name to use when creating the function directory is "ncm".
The NCM function provides these attributes in its function directory:
- =============== ==================================================
- ifname network device interface name associated with this
- function instance
- qmult queue length multiplier for high and super speed
- host_addr MAC address of host's end of this
- Ethernet over USB link
- dev_addr MAC address of device's end of this
- Ethernet over USB link
- =============== ==================================================
+ =============== ==================================================
+ ifname network device interface name associated with this
+ function instance
+ qmult queue length multiplier for high and super speed
+ host_addr MAC address of host's end of this
+ Ethernet over USB link
+ dev_addr MAC address of device's end of this
+ Ethernet over USB link
+ max_segment_size Segment size required for P2P connections. This
+ will set MTU to (max_segment_size - 14 bytes)
+ =============== ==================================================
and after creating the functions/ncm.<instance name> they contain default
values: qmult is 5, dev_addr and host_addr are randomly selected.
diff --git a/Documentation/usb/raw-gadget.rst b/Documentation/usb/raw-gadget.rst
index 818a1648b387..59b2132b584d 100644
--- a/Documentation/usb/raw-gadget.rst
+++ b/Documentation/usb/raw-gadget.rst
@@ -81,9 +81,6 @@ feature must be kept in the implementation.
Potential future improvements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Report more events (suspend, resume, etc.) through
- ``USB_RAW_IOCTL_EVENT_FETCH``.
-
- Support ``O_NONBLOCK`` I/O. This would be another mode of operation, where
Raw Gadget would not wait until the completion of each USB request.
diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
index d8b6cb1a3636..457e16f06e04 100644
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
@@ -128,7 +128,6 @@ Code Seq# Include File Comments
'F' all linux/fb.h conflict!
'F' 01-02 drivers/scsi/pmcraid.h conflict!
'F' 20 drivers/video/fsl-diu-fb.h conflict!
-'F' 20 drivers/video/intelfb/intelfb.h conflict!
'F' 20 linux/ivtvfb.h conflict!
'F' 20 linux/matroxfb.h conflict!
'F' 20 drivers/video/aty/atyfb_base.c conflict!
diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst
index e5e7deb0d392..2252063593bf 100644
--- a/Documentation/userspace-api/media/drivers/index.rst
+++ b/Documentation/userspace-api/media/drivers/index.rst
@@ -36,4 +36,5 @@ For more details see the file COPYING in the source distribution of Linux.
npcm-video
omap3isp-uapi
st-vgxy61
+ thp7312
uvcvideo
diff --git a/Documentation/userspace-api/media/drivers/thp7312.rst b/Documentation/userspace-api/media/drivers/thp7312.rst
new file mode 100644
index 000000000000..7c777e6fb7d2
--- /dev/null
+++ b/Documentation/userspace-api/media/drivers/thp7312.rst
@@ -0,0 +1,39 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+
+THine THP7312 ISP driver
+========================
+
+The THP7312 driver implements the following driver-specific controls:
+
+``V4L2_CID_THP7312_LOW_LIGHT_COMPENSATION``
+ Enable/Disable auto-adjustment, based on lighting conditions, of the frame
+ rate when auto-exposure is enabled.
+
+``V4L2_CID_THP7312_AUTO_FOCUS_METHOD``
+ Set method of auto-focus. Only takes effect when auto-focus is enabled.
+
+ .. flat-table::
+ :header-rows: 0
+ :stub-columns: 0
+ :widths: 1 4
+
+ * - ``0``
+ - Contrast-based auto-focus
+ * - ``1``
+ - PDAF
+ * - ``2``
+ - Hybrid of contrast-based and PDAF
+
+ Supported values for the control depend on the camera sensor module
+ connected to the THP7312. If the module doesn't have a focus lens actuator,
+ this control will not be exposed by the THP7312 driver. If the module has a
+ controllable focus lens but the sensor doesn't support PDAF, only the
+ contrast-based auto-focus value will be valid. Otherwise all values for the
+ controls will be supported.
+
+``V4L2_CID_THP7312_NOISE_REDUCTION_AUTO``
+ Enable/Disable auto noise reduction.
+
+``V4L2_CID_THP7312_NOISE_REDUCTION_ABSOLUTE``
+ Set the noise reduction strength, where 0 is the weakest and 10 is the
+ strongest.
diff --git a/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst b/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst
index a048a9f6b7b6..49232c9006c2 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst
@@ -116,9 +116,13 @@ than the number requested.
- ``flags``
- Specifies additional buffer management attributes.
See :ref:`memory-flags`.
-
* - __u32
- - ``reserved``\ [6]
+ - ``max_num_buffers``
+ - If the V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS capability flag is set
+ this field indicates the maximum possible number of buffers
+ for this queue.
+ * - __u32
+ - ``reserved``\ [5]
- A place holder for future extensions. Drivers and applications
must set the array to zero.
diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
index f9f73530a6be..4d56c0528ad7 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
@@ -295,6 +295,14 @@ still cause this situation.
- ``p_av1_film_grain``
- A pointer to a struct :c:type:`v4l2_ctrl_av1_film_grain`. Valid if this control is
of type ``V4L2_CTRL_TYPE_AV1_FILM_GRAIN``.
+ * - struct :c:type:`v4l2_ctrl_hdr10_cll_info` *
+ - ``p_hdr10_cll_info``
+ - A pointer to a struct :c:type:`v4l2_ctrl_hdr10_cll_info`. Valid if this control is
+ of type ``V4L2_CTRL_TYPE_HDR10_CLL_INFO``.
+ * - struct :c:type:`v4l2_ctrl_hdr10_mastering_display` *
+ - ``p_hdr10_mastering_display``
+ - A pointer to a struct :c:type:`v4l2_ctrl_hdr10_mastering_display`. Valid if this control is
+ of type ``V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY``.
* - void *
- ``ptr``
- A pointer to a compound type which can be an N-dimensional array
diff --git a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst
index 099fa6695167..0b3a41a45d05 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst
@@ -120,6 +120,7 @@ aborting or finishing any DMA in progress, an implicit
.. _V4L2-BUF-CAP-SUPPORTS-ORPHANED-BUFS:
.. _V4L2-BUF-CAP-SUPPORTS-M2M-HOLD-CAPTURE-BUF:
.. _V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS:
+.. _V4L2-BUF-CAP-SUPPORTS-MAX-NUM-BUFFERS:
.. raw:: latex
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst
index 8def4c05d3da..c935bacc3bc2 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst
@@ -107,8 +107,7 @@ appropriately. The generic error codes are described at the
:ref:`Generic Error Codes <gen-errors>` chapter.
EINVAL
- The struct
- :c:type:`v4l2_subdev_frame_interval_enum`
- ``pad`` references a non-existing pad, one of the ``code``,
- ``width`` or ``height`` fields are invalid for the given pad or the
- ``index`` field is out of bounds.
+ The struct :c:type:`v4l2_subdev_frame_interval_enum` ``pad`` references a
+ non-existing pad, the ``which`` field has an unsupported value, one of the
+ ``code``, ``width`` or ``height`` fields are invalid for the given pad, or
+ the ``index`` field is out of bounds.
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst
index e3ae84df5486..65f0cfeca973 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst
@@ -126,7 +126,6 @@ appropriately. The generic error codes are described at the
:ref:`Generic Error Codes <gen-errors>` chapter.
EINVAL
- The struct
- :c:type:`v4l2_subdev_frame_size_enum`
- ``pad`` references a non-existing pad, the ``code`` is invalid for
- the given pad or the ``index`` field is out of bounds.
+ The struct :c:type:`v4l2_subdev_frame_size_enum` ``pad`` references a
+ non-existing pad, the ``which`` field has an unsupported value, the ``code``
+ is invalid for the given pad, or the ``index`` field is out of bounds.
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst
index 4ad7dec27e25..3050966b199f 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst
@@ -158,7 +158,6 @@ appropriately. The generic error codes are described at the
:ref:`Generic Error Codes <gen-errors>` chapter.
EINVAL
- The struct
- :c:type:`v4l2_subdev_mbus_code_enum`
- ``pad`` references a non-existing pad, or the ``index`` field is out
- of bounds.
+ The struct :c:type:`v4l2_subdev_mbus_code_enum` ``pad`` references a
+ non-existing pad, the ``which`` field has an unsupported value, or the
+ ``index`` field is out of bounds.
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst
index 20f12a1cc0f7..810b6a859dc8 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst
@@ -71,6 +71,11 @@ is unknown to the kernel.
of 'stream' fields (referring to the stream number) with various
ioctls. If this is not set (which is the default), the 'stream' fields
will be forced to 0 by the kernel.
+ * - ``V4L2_SUBDEV_CLIENT_CAP_INTERVAL_USES_WHICH``
+ - The client is aware of the :c:type:`v4l2_subdev_frame_interval`
+ ``which`` field. If this is not set (which is the default), the
+ ``which`` field is forced to ``V4L2_SUBDEV_FORMAT_ACTIVE`` by the
+ kernel.
Return Value
============
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst
index 1d267f7e7991..92d933631fda 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst
@@ -118,10 +118,9 @@ EBUSY
``VIDIOC_SUBDEV_S_CROP``
EINVAL
- The struct :c:type:`v4l2_subdev_crop` ``pad``
- references a non-existing pad, the ``which`` field references a
- non-existing format, or cropping is not supported on the given
- subdev pad.
+ The struct :c:type:`v4l2_subdev_crop` ``pad`` references a non-existing pad,
+ the ``which`` field has an unsupported value, or cropping is not supported
+ on the given subdev pad.
EPERM
The ``VIDIOC_SUBDEV_S_CROP`` ioctl has been called on a read-only subdevice
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst
index ed253a1e44b7..4a2b4e4f0152 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst
@@ -140,9 +140,8 @@ EBUSY
fix the problem first. Only returned by ``VIDIOC_SUBDEV_S_FMT``
EINVAL
- The struct :c:type:`v4l2_subdev_format`
- ``pad`` references a non-existing pad, or the ``which`` field
- references a non-existing format.
+ The struct :c:type:`v4l2_subdev_format` ``pad`` references a non-existing
+ pad, or the ``which`` field has an unsupported value.
EPERM
The ``VIDIOC_SUBDEV_S_FMT`` ioctl has been called on a read-only subdevice
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst
index 842f962d2aea..c8022809ac35 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst
@@ -58,8 +58,9 @@ struct
contains the current frame interval as would be returned by a
``VIDIOC_SUBDEV_G_FRAME_INTERVAL`` call.
-Calling ``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` on a subdev device node that has been
-registered in read-only mode is not allowed. An error is returned and the errno
+If the subdev device node has been registered in read-only mode, calls to
+``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` are only valid if the ``which`` field is set
+to ``V4L2_SUBDEV_FORMAT_TRY``, otherwise an error is returned and the errno
variable is set to ``-EPERM``.
Drivers must not return an error solely because the requested interval
@@ -93,7 +94,11 @@ the same sub-device is not defined.
- ``stream``
- Stream identifier.
* - __u32
- - ``reserved``\ [8]
+ - ``which``
+ - Active or try frame interval, from enum
+ :ref:`v4l2_subdev_format_whence <v4l2-subdev-format-whence>`.
+ * - __u32
+ - ``reserved``\ [7]
- Reserved for future extensions. Applications and drivers must set
the array to zero.
@@ -112,11 +117,10 @@ EBUSY
``VIDIOC_SUBDEV_S_FRAME_INTERVAL``
EINVAL
- The struct
- :c:type:`v4l2_subdev_frame_interval`
- ``pad`` references a non-existing pad, or the pad doesn't support
- frame intervals.
+ The struct :c:type:`v4l2_subdev_frame_interval` ``pad`` references a
+ non-existing pad, the ``which`` field has an unsupported value, or the pad
+ doesn't support frame intervals.
EPERM
The ``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` ioctl has been called on a read-only
- subdevice.
+ subdevice and the ``which`` field is set to ``V4L2_SUBDEV_FORMAT_ACTIVE``.
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst
index 72677a280cd6..26b5004bfe6d 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst
@@ -72,7 +72,7 @@ On a successful ``VIDIOC_SUBDEV_G_ROUTING`` call the driver updates the
* - __u32
- ``which``
- - Format to modified, from enum
+ - Routing table to be accessed, from enum
:ref:`v4l2_subdev_format_whence <v4l2-subdev-format-whence>`.
* - struct :c:type:`v4l2_subdev_route`
- ``routes[]``
@@ -140,8 +140,9 @@ ENOSPC
all the available routes the subdevice exposes.
EINVAL
- The sink or source pad identifiers reference a non-existing pad, or reference
- pads of different types (ie. the sink_pad identifiers refers to a source pad).
+ The sink or source pad identifiers reference a non-existing pad or reference
+ pads of different types (ie. the sink_pad identifiers refers to a source
+ pad), or the ``which`` field has an unsupported value.
E2BIG
The application provided ``num_routes`` for ``VIDIOC_SUBDEV_S_ROUTING`` is
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst
index 6b629c19168c..19e6c3e9c06d 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst
@@ -116,10 +116,9 @@ EBUSY
``VIDIOC_SUBDEV_S_SELECTION``
EINVAL
- The struct :c:type:`v4l2_subdev_selection`
- ``pad`` references a non-existing pad, the ``which`` field
- references a non-existing format, or the selection target is not
- supported on the given subdev pad.
+ The struct :c:type:`v4l2_subdev_selection` ``pad`` references a
+ non-existing pad, the ``which`` field has an unsupported value, or the
+ selection target is not supported on the given subdev pad.
EPERM
The ``VIDIOC_SUBDEV_S_SELECTION`` ioctl has been called on a read-only
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 7025b3751027..3ec0b7a455a0 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -147,10 +147,29 @@ described as 'basic' will be available.
The new VM has no virtual cpus and no memory.
You probably want to use 0 as machine type.
+X86:
+^^^^
+
+Supported X86 VM types can be queried via KVM_CAP_VM_TYPES.
+
+S390:
+^^^^^
+
In order to create user controlled virtual machines on S390, check
KVM_CAP_S390_UCONTROL and use the flag KVM_VM_S390_UCONTROL as
privileged user (CAP_SYS_ADMIN).
+MIPS:
+^^^^^
+
+To use hardware assisted virtualization on MIPS (VZ ASE) rather than
+the default trap & emulate implementation (which changes the virtual
+memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the
+flag KVM_VM_MIPS_VZ.
+
+ARM64:
+^^^^^^
+
On arm64, the physical address size for a VM (IPA Size limit) is limited
to 40bits by default. The limit can be configured if the host supports the
extension KVM_CAP_ARM_VM_IPA_SIZE. When supported, use
@@ -608,18 +627,6 @@ interrupt number dequeues the interrupt.
This is an asynchronous vcpu ioctl and can be invoked from any thread.
-4.17 KVM_DEBUG_GUEST
---------------------
-
-:Capability: basic
-:Architectures: none
-:Type: vcpu ioctl
-:Parameters: none)
-:Returns: -1 on error
-
-Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead.
-
-
4.18 KVM_GET_MSRS
-----------------
@@ -6192,6 +6199,130 @@ to know what fields can be changed for the system register described by
``op0, op1, crn, crm, op2``. KVM rejects ID register values that describe a
superset of the features supported by the system.
+4.140 KVM_SET_USER_MEMORY_REGION2
+---------------------------------
+
+:Capability: KVM_CAP_USER_MEMORY2
+:Architectures: all
+:Type: vm ioctl
+:Parameters: struct kvm_userspace_memory_region2 (in)
+:Returns: 0 on success, -1 on error
+
+KVM_SET_USER_MEMORY_REGION2 is an extension to KVM_SET_USER_MEMORY_REGION that
+allows mapping guest_memfd memory into a guest. All fields shared with
+KVM_SET_USER_MEMORY_REGION identically. Userspace can set KVM_MEM_GUEST_MEMFD
+in flags to have KVM bind the memory region to a given guest_memfd range of
+[guest_memfd_offset, guest_memfd_offset + memory_size]. The target guest_memfd
+must point at a file created via KVM_CREATE_GUEST_MEMFD on the current VM, and
+the target range must not be bound to any other memory region. All standard
+bounds checks apply (use common sense).
+
+::
+
+ struct kvm_userspace_memory_region2 {
+ __u32 slot;
+ __u32 flags;
+ __u64 guest_phys_addr;
+ __u64 memory_size; /* bytes */
+ __u64 userspace_addr; /* start of the userspace allocated memory */
+ __u64 guest_memfd_offset;
+ __u32 guest_memfd;
+ __u32 pad1;
+ __u64 pad2[14];
+ };
+
+A KVM_MEM_GUEST_MEMFD region _must_ have a valid guest_memfd (private memory) and
+userspace_addr (shared memory). However, "valid" for userspace_addr simply
+means that the address itself must be a legal userspace address. The backing
+mapping for userspace_addr is not required to be valid/populated at the time of
+KVM_SET_USER_MEMORY_REGION2, e.g. shared memory can be lazily mapped/allocated
+on-demand.
+
+When mapping a gfn into the guest, KVM selects shared vs. private, i.e consumes
+userspace_addr vs. guest_memfd, based on the gfn's KVM_MEMORY_ATTRIBUTE_PRIVATE
+state. At VM creation time, all memory is shared, i.e. the PRIVATE attribute
+is '0' for all gfns. Userspace can control whether memory is shared/private by
+toggling KVM_MEMORY_ATTRIBUTE_PRIVATE via KVM_SET_MEMORY_ATTRIBUTES as needed.
+
+4.141 KVM_SET_MEMORY_ATTRIBUTES
+-------------------------------
+
+:Capability: KVM_CAP_MEMORY_ATTRIBUTES
+:Architectures: x86
+:Type: vm ioctl
+:Parameters: struct kvm_memory_attributes (in)
+:Returns: 0 on success, <0 on error
+
+KVM_SET_MEMORY_ATTRIBUTES allows userspace to set memory attributes for a range
+of guest physical memory.
+
+::
+
+ struct kvm_memory_attributes {
+ __u64 address;
+ __u64 size;
+ __u64 attributes;
+ __u64 flags;
+ };
+
+ #define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3)
+
+The address and size must be page aligned. The supported attributes can be
+retrieved via ioctl(KVM_CHECK_EXTENSION) on KVM_CAP_MEMORY_ATTRIBUTES. If
+executed on a VM, KVM_CAP_MEMORY_ATTRIBUTES precisely returns the attributes
+supported by that VM. If executed at system scope, KVM_CAP_MEMORY_ATTRIBUTES
+returns all attributes supported by KVM. The only attribute defined at this
+time is KVM_MEMORY_ATTRIBUTE_PRIVATE, which marks the associated gfn as being
+guest private memory.
+
+Note, there is no "get" API. Userspace is responsible for explicitly tracking
+the state of a gfn/page as needed.
+
+The "flags" field is reserved for future extensions and must be '0'.
+
+4.142 KVM_CREATE_GUEST_MEMFD
+----------------------------
+
+:Capability: KVM_CAP_GUEST_MEMFD
+:Architectures: none
+:Type: vm ioctl
+:Parameters: struct kvm_create_guest_memfd(in)
+:Returns: 0 on success, <0 on error
+
+KVM_CREATE_GUEST_MEMFD creates an anonymous file and returns a file descriptor
+that refers to it. guest_memfd files are roughly analogous to files created
+via memfd_create(), e.g. guest_memfd files live in RAM, have volatile storage,
+and are automatically released when the last reference is dropped. Unlike
+"regular" memfd_create() files, guest_memfd files are bound to their owning
+virtual machine (see below), cannot be mapped, read, or written by userspace,
+and cannot be resized (guest_memfd files do however support PUNCH_HOLE).
+
+::
+
+ struct kvm_create_guest_memfd {
+ __u64 size;
+ __u64 flags;
+ __u64 reserved[6];
+ };
+
+Conceptually, the inode backing a guest_memfd file represents physical memory,
+i.e. is coupled to the virtual machine as a thing, not to a "struct kvm". The
+file itself, which is bound to a "struct kvm", is that instance's view of the
+underlying memory, e.g. effectively provides the translation of guest addresses
+to host memory. This allows for use cases where multiple KVM structures are
+used to manage a single virtual machine, e.g. when performing intrahost
+migration of a virtual machine.
+
+KVM currently only supports mapping guest_memfd via KVM_SET_USER_MEMORY_REGION2,
+and more specifically via the guest_memfd and guest_memfd_offset fields in
+"struct kvm_userspace_memory_region2", where guest_memfd_offset is the offset
+into the guest_memfd instance. For a given guest_memfd file, there can be at
+most one mapping per page, i.e. binding multiple memory regions to a single
+guest_memfd range is not allowed (any number of memory regions can be bound to
+a single guest_memfd file, but the bound ranges must not overlap).
+
+See KVM_SET_USER_MEMORY_REGION2 for additional details.
+
5. The kvm_run structure
========================
@@ -6826,6 +6957,30 @@ spec refer, https://github.com/riscv/riscv-sbi-doc.
::
+ /* KVM_EXIT_MEMORY_FAULT */
+ struct {
+ #define KVM_MEMORY_EXIT_FLAG_PRIVATE (1ULL << 3)
+ __u64 flags;
+ __u64 gpa;
+ __u64 size;
+ } memory_fault;
+
+KVM_EXIT_MEMORY_FAULT indicates the vCPU has encountered a memory fault that
+could not be resolved by KVM. The 'gpa' and 'size' (in bytes) describe the
+guest physical address range [gpa, gpa + size) of the fault. The 'flags' field
+describes properties of the faulting access that are likely pertinent:
+
+ - KVM_MEMORY_EXIT_FLAG_PRIVATE - When set, indicates the memory fault occurred
+ on a private memory access. When clear, indicates the fault occurred on a
+ shared access.
+
+Note! KVM_EXIT_MEMORY_FAULT is unique among all KVM exit reasons in that it
+accompanies a return code of '-1', not '0'! errno will always be set to EFAULT
+or EHWPOISON when KVM exits with KVM_EXIT_MEMORY_FAULT, userspace should assume
+kvm_run.exit_reason is stale/undefined for all other error numbers.
+
+::
+
/* KVM_EXIT_NOTIFY */
struct {
#define KVM_NOTIFY_CONTEXT_INVALID (1 << 0)
@@ -7858,6 +8013,27 @@ This capability is aimed to mitigate the threat that malicious VMs can
cause CPU stuck (due to event windows don't open up) and make the CPU
unavailable to host or other VMs.
+7.34 KVM_CAP_MEMORY_FAULT_INFO
+------------------------------
+
+:Architectures: x86
+:Returns: Informational only, -EINVAL on direct KVM_ENABLE_CAP.
+
+The presence of this capability indicates that KVM_RUN will fill
+kvm_run.memory_fault if KVM cannot resolve a guest page fault VM-Exit, e.g. if
+there is a valid memslot but no backing VMA for the corresponding host virtual
+address.
+
+The information in kvm_run.memory_fault is valid if and only if KVM_RUN returns
+an error with errno=EFAULT or errno=EHWPOISON *and* kvm_run.exit_reason is set
+to KVM_EXIT_MEMORY_FAULT.
+
+Note: Userspaces which attempt to resolve memory faults so that they can retry
+KVM_RUN are encouraged to guard against repeatedly receiving the same
+error/annotated fault.
+
+See KVM_EXIT_MEMORY_FAULT for more information.
+
8. Other capabilities.
======================
@@ -8374,6 +8550,7 @@ PVHVM guests. Valid flags are::
#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4)
#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5)
#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6)
+ #define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE (1 << 7)
The KVM_XEN_HVM_CONFIG_HYPERCALL_MSR flag indicates that the KVM_XEN_HVM_CONFIG
ioctl is available, for the guest to set its hypercall page.
@@ -8417,6 +8594,11 @@ behave more correctly, not using the XEN_RUNSTATE_UPDATE flag until/unless
specifically enabled (by the guest making the hypercall, causing the VMM
to enable the KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG attribute).
+The KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE flag indicates that KVM supports
+clearing the PVCLOCK_TSC_STABLE_BIT flag in Xen pvclock sources. This will be
+done when the KVM_CAP_XEN_HVM ioctl sets the
+KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE flag.
+
8.31 KVM_CAP_PPC_MULTITCE
-------------------------
@@ -8596,6 +8778,19 @@ block sizes is exposed in KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES as a
64-bit bitmap (each bit describing a block size). The default value is
0, to disable the eager page splitting.
+8.41 KVM_CAP_VM_TYPES
+---------------------
+
+:Capability: KVM_CAP_MEMORY_ATTRIBUTES
+:Architectures: x86
+:Type: system ioctl
+
+This capability returns a bitmap of support VM types. The 1-setting of bit @n
+means the VM type with value @n is supported. Possible values of @n are::
+
+ #define KVM_X86_DEFAULT_VM 0
+ #define KVM_X86_SW_PROTECTED_VM 1
+
9. Known KVM API problems
=========================
diff --git a/Documentation/virt/kvm/locking.rst b/Documentation/virt/kvm/locking.rst
index 3a034db5e55f..02880d5552d5 100644
--- a/Documentation/virt/kvm/locking.rst
+++ b/Documentation/virt/kvm/locking.rst
@@ -43,10 +43,9 @@ On x86:
- vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock and kvm->arch.xen.xen_lock
-- kvm->arch.mmu_lock is an rwlock. kvm->arch.tdp_mmu_pages_lock and
- kvm->arch.mmu_unsync_pages_lock are taken inside kvm->arch.mmu_lock, and
- cannot be taken without already holding kvm->arch.mmu_lock (typically with
- ``read_lock`` for the TDP MMU, thus the need for additional spinlocks).
+- kvm->arch.mmu_lock is an rwlock; critical sections for
+ kvm->arch.tdp_mmu_pages_lock and kvm->arch.mmu_unsync_pages_lock must
+ also take kvm->arch.mmu_lock
Everything else is a leaf: no other lock is taken inside the critical
sections.
diff --git a/MAINTAINERS b/MAINTAINERS
index 517f0e7c8327..c755a8f7b93e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -699,6 +699,15 @@ S: Maintained
F: Documentation/devicetree/bindings/media/allegro,al5e.yaml
F: drivers/media/platform/allegro-dvt/
+ALLIED VISION ALVIUM CAMERA DRIVER
+M: Tommaso Merciai <[email protected]>
+M: Martin Hecht <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/media/i2c/alliedvision,alvium-csi2.yaml
+F: drivers/media/i2c/alvium-csi2.c
+F: drivers/media/i2c/alvium-csi2.h
+
ALLWINNER A10 CSI DRIVER
M: Maxime Ripard <[email protected]>
@@ -881,6 +890,14 @@ Q: https://patchwork.kernel.org/project/linux-rdma/list/
F: drivers/infiniband/hw/efa/
F: include/uapi/rdma/efa-abi.h
+AMD AXI W1 DRIVER
+M: Kris Chaplin <[email protected]>
+R: Thomas Delev <[email protected]>
+R: Michal Simek <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml
+F: drivers/w1/masters/amd_axi_w1.c
+
AMD CDX BUS DRIVER
M: Nipun Gupta <[email protected]>
M: Nikhil Agarwal <[email protected]>
@@ -1114,6 +1131,14 @@ F: Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130
F: Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml
F: drivers/iio/adc/ad4130.c
+ANALOG DEVICES INC AD7091R DRIVER
+M: Marcelo Schmitt <[email protected]>
+S: Supported
+W: http://ez.analog.com/community/linux-device-drivers
+F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r*
+F: drivers/iio/adc/drivers/iio/adc/ad7091r*
+
ANALOG DEVICES INC AD7192 DRIVER
M: Alexandru Tachici <[email protected]>
@@ -1684,11 +1709,6 @@ S: Odd Fixes
F: drivers/amba/
F: include/linux/amba/bus.h
-ARM PRIMECELL CLCD PL110 DRIVER
-M: Russell King <[email protected]>
-S: Odd Fixes
-F: drivers/video/fbdev/amba-clcd.*
-
ARM PRIMECELL KMI PL050 DRIVER
M: Russell King <[email protected]>
S: Odd Fixes
@@ -2044,7 +2064,6 @@ ARM/CORESIGHT FRAMEWORK AND DRIVERS
M: Suzuki K Poulose <[email protected]>
R: Mike Leach <[email protected]>
R: James Clark <[email protected]>
-R: Leo Yan <[email protected]>
L: [email protected] (moderated for non-subscribers)
L: [email protected] (moderated for non-subscribers)
S: Maintained
@@ -3040,6 +3059,13 @@ S: Supported
W: http://www.akm.com/
F: drivers/iio/magnetometer/ak8974.c
+AOSONG AGS02MA TVOC SENSOR DRIVER
+M: Anshul Dalal <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/iio/chemical/aosong,ags02ma.yaml
+F: drivers/iio/chemical/ags02ma.c
+
ASC7621 HARDWARE MONITOR DRIVER
M: George Joseph <[email protected]>
@@ -3639,6 +3665,13 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
F: drivers/iio/accel/bma400*
+BOSCH SENSORTEC BMI323 IMU IIO DRIVER
+M: Jagath Jog J <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml
+F: drivers/iio/imu/bmi323/
+
BPF JIT for ARM
M: Russell King <[email protected]>
M: Puranjay Mohan <[email protected]>
@@ -5160,7 +5193,7 @@ M: Philipp Zabel <[email protected]>
S: Maintained
F: Documentation/devicetree/bindings/media/coda.yaml
-F: drivers/media/platform/chips-media/
+F: drivers/media/platform/chips-media/coda
CODE OF CONDUCT
M: Greg Kroah-Hartman <[email protected]>
@@ -5247,6 +5280,7 @@ M: Dan Williams <[email protected]>
S: Maintained
F: drivers/cxl/
+F: include/linux/cxl-event.h
F: include/uapi/linux/cxl_mem.h
F: tools/testing/cxl/
@@ -5380,6 +5414,12 @@ F: include/linux/counter.h
F: include/uapi/linux/counter.h
F: tools/counter/
+COUNTER WATCH EVENTS TOOL
+M: Fabrice Gasnier <[email protected]>
+S: Maintained
+F: tools/counter/counter_watch_events.c
+
CP2615 I2C DRIVER
M: Bence Csókás <[email protected]>
S: Maintained
@@ -8757,6 +8797,21 @@ F: kernel/futex/*
F: tools/perf/bench/futex*
F: tools/testing/selftests/futex/
+GALAXYCORE GC0308 CAMERA SENSOR DRIVER
+M: Sebastian Reichel <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml
+F: drivers/media/i2c/gc0308.c
+
+GALAXYCORE GC2145 SENSOR DRIVER
+M: Alain Volmat <[email protected]>
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml
+F: drivers/media/i2c/gc2145.c
+
GATEWORKS SYSTEM CONTROLLER (GSC) DRIVER
M: Tim Harvey <[email protected]>
S: Maintained
@@ -8875,21 +8930,13 @@ F: Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml
F: drivers/i2c/muxes/i2c-demux-pinctrl.c
GENERIC PM DOMAINS
-M: "Rafael J. Wysocki" <[email protected]>
-M: Kevin Hilman <[email protected]>
M: Ulf Hansson <[email protected]>
S: Supported
F: Documentation/devicetree/bindings/power/power?domain*
-F: drivers/base/power/domain*.c
-F: include/linux/pm_domain.h
-
-GENERIC PM DOMAIN PROVIDERS
-M: Ulf Hansson <[email protected]>
-S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git
F: drivers/pmdomain/
+F: include/linux/pm_domain.h
GENERIC RADIX TREE
M: Kent Overstreet <[email protected]>
@@ -9720,6 +9767,13 @@ F: lib/test_hmm*
F: mm/hmm*
F: tools/testing/selftests/mm/*hmm*
+HONEYWELL HSC030PA PRESSURE SENSOR SERIES IIO DRIVER
+M: Petre Rodan <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml
+F: drivers/iio/pressure/hsc030pa*
+
HONEYWELL MPRLS0025PA PRESSURE SENSOR SERIES IIO DRIVER
M: Andreas Klinger <[email protected]>
@@ -10335,8 +10389,8 @@ IIO LIGHT SENSOR GAIN-TIME-SCALE HELPERS
M: Matti Vaittinen <[email protected]>
S: Maintained
-F: drivers/iio/light/gain-time-scale-helper.c
-F: drivers/iio/light/gain-time-scale-helper.h
+F: drivers/iio/industrialio-gts-helper.c
+F: include/linux/iio/iio-gts-helper.h
IIO MULTIPLEXER
M: Peter Rosin <[email protected]>
@@ -10716,13 +10770,6 @@ S: Supported
F: drivers/infiniband/hw/irdma/
F: include/uapi/rdma/irdma-abi.h
-INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)
-M: Maik Broemme <[email protected]>
-S: Maintained
-F: Documentation/fb/intelfb.rst
-F: drivers/video/fbdev/intelfb/
-
INTEL GPIO DRIVERS
M: Andy Shevchenko <[email protected]>
@@ -12720,17 +12767,23 @@ F: Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
F: drivers/i2c/muxes/i2c-mux-ltc4306.c
LTP (Linux Test Project)
-M: Mike Frysinger <[email protected]>
M: Cyril Hrubis <[email protected]>
-M: Wanlong Gao <[email protected]>
M: Jan Stancek <[email protected]>
-M: Stanislav Kholmanskikh <[email protected]>
-M: Alexey Kodanev <[email protected]>
+M: Petr Vorel <[email protected]>
+M: Li Wang <[email protected]>
+M: Yang Xu <[email protected]>
L: [email protected] (subscribers-only)
S: Maintained
W: http://linux-test-project.github.io/
T: git https://github.com/linux-test-project/ltp.git
+LTR390 AMBIENT/UV LIGHT SENSOR DRIVER
+M: Anshul Dalal <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/iio/light/liteon,ltr390.yaml
+F: drivers/iio/light/ltr390.c
+
LYNX 28G SERDES PHY DRIVER
M: Ioana Ciornei <[email protected]>
@@ -13095,6 +13148,7 @@ MAX96712 QUAD GMSL2 DESERIALIZER DRIVER
M: Niklas Söderlund <[email protected]>
S: Maintained
+F: Documentation/devicetree/bindings/media/i2c/maxim,max96712.yaml
F: drivers/staging/media/max96712/max96712.c
MAX9860 MONO AUDIO VOICE CODEC DRIVER
@@ -13274,6 +13328,13 @@ F: Documentation/ABI/testing/sysfs-bus-iio-potentiometer-mcp4531
F: drivers/iio/potentiometer/mcp4018.c
F: drivers/iio/potentiometer/mcp4531.c
+MCP4821 DAC DRIVER
+M: Anshul Dalal <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml
+F: drivers/iio/dac/mcp4821.c
+
MCR20A IEEE-802.15.4 RADIO DRIVER
M: Stefan Schmidt <[email protected]>
@@ -13515,13 +13576,16 @@ W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: drivers/media/dvb-frontends/stv6111*
-MEDIA DRIVERS FOR STM32 - DCMI
+MEDIA DRIVERS FOR STM32 - DCMI / DCMIPP
M: Hugues Fruchet <[email protected]>
+M: Alain Volmat <[email protected]>
S: Supported
T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
+F: Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml
F: drivers/media/platform/st/stm32/stm32-dcmi.c
+F: drivers/media/platform/st/stm32/stm32-dcmipp/*
MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
M: Mauro Carvalho Chehab <[email protected]>
@@ -13798,6 +13862,13 @@ S: Supported
W: http://www.melexis.com
F: drivers/iio/temperature/mlx90632.c
+MELEXIS MLX90635 DRIVER
+M: Crt Mori <[email protected]>
+S: Supported
+W: http://www.melexis.com
+F: drivers/iio/temperature/mlx90635.c
+
MELFAS MIP4 TOUCHSCREEN DRIVER
M: Sangwon Jee <[email protected]>
S: Supported
@@ -14268,11 +14339,12 @@ F: Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt
F: drivers/regulator/mcp16502.c
MICROCHIP MCP3564 ADC DRIVER
-M: Marius Cristea <[email protected]>
-S: Supported
-F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3564.yaml
-F: drivers/iio/adc/mcp3564.c
+M: Marius Cristea <[email protected]>
+S: Supported
+F: Documentation/ABI/testing/sysfs-bus-iio-adc-mcp3564
+F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3564.yaml
+F: drivers/iio/adc/mcp3564.c
MICROCHIP MCP3911 ADC DRIVER
M: Marcus Folkesson <[email protected]>
@@ -14732,6 +14804,13 @@ S: Maintained
F: Documentation/driver-api/tty/moxa-smartio.rst
F: drivers/tty/mxser.*
+MP3309C BACKLIGHT DRIVER
+M: Flavio Suligoi <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml
+F: drivers/video/backlight/mp3309c.c
+
MR800 AVERMEDIA USB FM RADIO DRIVER
M: Alexey Klimov <[email protected]>
@@ -15367,6 +15446,15 @@ F: include/linux/nitro_enclaves.h
F: include/uapi/linux/nitro_enclaves.h
F: samples/nitro_enclaves/
+NITRO SECURE MODULE (NSM)
+M: Alexander Graf <[email protected]>
+L: The AWS Nitro Enclaves Team <[email protected]>
+S: Supported
+W: https://aws.amazon.com/ec2/nitro/nitro-enclaves/
+F: drivers/misc/nsm.c
+F: include/uapi/linux/nsm.h
+
NOHZ, DYNTICKS SUPPORT
M: Frederic Weisbecker <[email protected]>
M: Thomas Gleixner <[email protected]>
@@ -16098,6 +16186,14 @@ S: Maintained
T: git git://linuxtv.org/media_tree.git
F: drivers/media/i2c/ov5695.c
+OMNIVISION OV64A40 SENSOR DRIVER
+M: Jacopo Mondi <[email protected]>
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml
+F: drivers/media/i2c/ov64a40.c
+
OMNIVISION OV7670 SENSOR DRIVER
S: Orphan
@@ -17629,12 +17725,11 @@ F: Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.yaml
F: drivers/media/rc/pwm-ir-tx.c
PWM SUBSYSTEM
-M: Thierry Reding <[email protected]>
-R: Uwe Kleine-König <[email protected]>
+M: Uwe Kleine-König <[email protected]>
S: Maintained
Q: https://patchwork.ozlabs.org/project/linux-pwm/list/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm.git
+T: git https://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux.git
F: Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml
F: Documentation/devicetree/bindings/pwm/
F: Documentation/driver-api/pwm.rst
@@ -17644,7 +17739,7 @@ F: drivers/video/backlight/pwm_bl.c
F: include/dt-bindings/pwm/
F: include/linux/pwm.h
F: include/linux/pwm_backlight.h
-K: pwm_(config|apply_state|ops)
+K: pwm_(config|apply_might_sleep|apply_atomic|ops)
PXA GPIO DRIVER
M: Robert Jarzmik <[email protected]>
@@ -18182,6 +18277,7 @@ F: drivers/media/cec/usb/rainshadow/
RALINK MIPS ARCHITECTURE
M: John Crispin <[email protected]>
+M: Sergio Paracuellos <[email protected]>
S: Maintained
F: arch/mips/ralink
@@ -19036,7 +19132,7 @@ F: drivers/iommu/s390-iommu.c
S390 IUCV NETWORK LAYER
M: Alexandra Winter <[email protected]>
-M: Wenjia Zhang <[email protected]>
+M: Thorsten Winkler <[email protected]>
S: Supported
@@ -19055,7 +19151,7 @@ F: arch/s390/mm
S390 NETWORK DRIVERS
M: Alexandra Winter <[email protected]>
-M: Wenjia Zhang <[email protected]>
+M: Thorsten Winkler <[email protected]>
S: Supported
@@ -19273,7 +19369,6 @@ R: Alim Akhtar <[email protected]>
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git
F: Documentation/devicetree/bindings/clock/samsung,*.yaml
F: Documentation/devicetree/bindings/clock/samsung,s3c*
F: drivers/clk/samsung/
@@ -19723,6 +19818,19 @@ T: git git://linuxtv.org/media_tree.git
F: drivers/media/i2c/rj54n1cb0c.c
F: include/media/i2c/rj54n1cb0c.h
+SHRINKER
+M: Andrew Morton <[email protected]>
+M: Dave Chinner <[email protected]>
+R: Qi Zheng <[email protected]>
+R: Roman Gushchin <[email protected]>
+R: Muchun Song <[email protected]>
+S: Maintained
+F: Documentation/admin-guide/mm/shrinker_debugfs.rst
+F: include/linux/shrinker.h
+F: mm/shrinker.c
+F: mm/shrinker_debug.c
+
SH_VOU V4L2 OUTPUT DRIVER
S: Orphan
@@ -20689,6 +20797,15 @@ M: Ion Badulescu <[email protected]>
S: Odd Fixes
F: drivers/net/ethernet/adaptec/starfire*
+STARFIVE CAMERA SUBSYSTEM DRIVER
+M: Jack Zhu <[email protected]>
+M: Changhuang Liang <[email protected]>
+S: Maintained
+F: Documentation/admin-guide/media/starfive_camss.rst
+F: Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml
+F: drivers/staging/media/starfive/camss
+
STARFIVE CRYPTO DRIVER
M: Jia Jie Ho <[email protected]>
M: William Qiu <[email protected]>
@@ -21389,6 +21506,12 @@ L: [email protected]
S: Maintained
F: drivers/media/rc/ttusbir.c
+TECHWELL TW9900 VIDEO DECODER
+M: Mehdi Djait <[email protected]>
+S: Maintained
+F: drivers/media/i2c/tw9900.c
+
TECHWELL TW9910 VIDEO DECODER
S: Orphan
@@ -21697,6 +21820,17 @@ S: Maintained
F: Documentation/ABI/testing/sysfs-class-firmware-attributes
F: drivers/platform/x86/think-lmi.?
+THP7312 ISP DRIVER
+M: Laurent Pinchart <[email protected]>
+M: Paul Elder <[email protected]>
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml
+F: Documentation/userspace-api/media/drivers/thp7312.rst
+F: drivers/media/i2c/thp7312.c
+F: include/uapi/linux/thp7312.h
+
THUNDERBOLT DMA TRAFFIC TEST DRIVER
M: Isaac Hazan <[email protected]>
@@ -22842,6 +22976,7 @@ S: Maintained
F: Documentation/driver-api/media/camera-sensor.rst
F: Documentation/driver-api/media/tx-rx.rst
F: drivers/media/i2c/ar*
+F: drivers/media/i2c/gc*
F: drivers/media/i2c/hi*
F: drivers/media/i2c/imx*
F: drivers/media/i2c/mt*
@@ -22875,6 +23010,7 @@ M: Alex Williamson <[email protected]>
S: Maintained
T: git https://github.com/awilliam/linux-vfio.git
+F: Documentation/ABI/testing/debugfs-vfio
F: Documentation/ABI/testing/sysfs-devices-vfio-dev
F: Documentation/driver-api/vfio.rst
F: drivers/vfio/
@@ -22910,6 +23046,13 @@ L: [email protected]
S: Maintained
F: drivers/vfio/pci/mlx5/
+VFIO VIRTIO PCI DRIVER
+M: Yishai Hadas <[email protected]>
+S: Maintained
+F: drivers/vfio/pci/virtio
+
VFIO PCI DEVICE SPECIFIC DRIVERS
R: Jason Gunthorpe <[email protected]>
R: Yishai Hadas <[email protected]>
@@ -23058,7 +23201,6 @@ M: Amit Shah <[email protected]>
S: Maintained
F: drivers/char/virtio_console.c
-F: include/linux/virtio_console.h
F: include/uapi/linux/virtio_console.h
VIRTIO CORE AND NET DRIVERS
@@ -23234,6 +23376,12 @@ S: Maintained
F: drivers/input/serio/userio.c
F: include/uapi/linux/userio.h
+VISHAY VEML6075 UVA AND UVB LIGHT SENSOR DRIVER
+M: Javier Carrasco <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml
+F: drivers/iio/light/veml6075.c
+
VISL VIRTUAL STATELESS DECODER DRIVER
M: Daniel Almeida <[email protected]>
@@ -23274,11 +23422,8 @@ F: include/linux/vmalloc.h
F: mm/vmalloc.c
VME SUBSYSTEM
-M: Martyn Welch <[email protected]>
-M: Manohar Vanga <[email protected]>
-M: Greg Kroah-Hartman <[email protected]>
-S: Odd fixes
+S: Orphan
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
F: Documentation/driver-api/vme.rst
F: drivers/staging/vme_user/
@@ -23484,6 +23629,14 @@ F: include/linux/watchdog.h
F: include/trace/events/watchdog.h
F: include/uapi/linux/watchdog.h
+WAVE5 VPU CODEC DRIVER
+M: Nas Chung <[email protected]>
+M: Jackson Lee <[email protected]>
+S: Maintained
+F: Documentation/devicetree/bindings/media/cnm,wave521c.yaml
+F: drivers/media/platform/chips-media/wave5/
+
WHISKEYCOVE PMIC GPIO DRIVER
M: Kuppuswamy Sathyanarayanan <[email protected]>
@@ -24213,11 +24366,13 @@ N: zstd
K: zstd
ZSWAP COMPRESSED SWAP CACHING
-M: Seth Jennings <[email protected]>
-M: Dan Streetman <[email protected]>
-M: Vitaly Wool <[email protected]>
+M: Johannes Weiner <[email protected]>
+M: Yosry Ahmed <[email protected]>
+M: Nhat Pham <[email protected]>
S: Maintained
+F: Documentation/admin-guide/mm/zswap.rst
+F: include/linux/zswap.h
F: mm/zswap.c
THE REST
diff --git a/arch/Kconfig b/arch/Kconfig
index 5ca66aad0d08..c91917b50873 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -301,6 +301,11 @@ config ARCH_HAS_DMA_CLEAR_UNCACHED
config ARCH_HAS_CPU_FINALIZE_INIT
bool
+# The architecture has a per-task state that includes the mm's PASID
+config ARCH_HAS_CPU_PASID
+ bool
+ select IOMMU_MM_DATA
+
config HAVE_ARCH_THREAD_STRUCT_WHITELIST
bool
help
diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
index d6139dbae4ac..feaf89f6936b 100644
--- a/arch/alpha/kernel/srmcons.c
+++ b/arch/alpha/kernel/srmcons.c
@@ -53,7 +53,7 @@ srmcons_do_receive_chars(struct tty_port *port)
do {
result.as_long = callback_getc(0);
if (result.bits.status < 2) {
- tty_insert_flip_char(port, (char)result.bits.c, 0);
+ tty_insert_flip_char(port, (u8)result.bits.c, 0);
count++;
}
} while((result.bits.status & 1) && (++loops < 10));
@@ -88,30 +88,27 @@ srmcons_receive_chars(struct timer_list *t)
}
/* called with callback_lock held */
-static int
-srmcons_do_write(struct tty_port *port, const char *buf, int count)
+static void
+srmcons_do_write(struct tty_port *port, const u8 *buf, size_t count)
{
- static char str_cr[1] = "\r";
- long c, remaining = count;
+ size_t c;
srmcons_result result;
- char *cur;
- int need_cr;
- for (cur = (char *)buf; remaining > 0; ) {
- need_cr = 0;
+ while (count > 0) {
+ bool need_cr = false;
/*
* Break it up into reasonable size chunks to allow a chance
* for input to get in
*/
- for (c = 0; c < min_t(long, 128L, remaining) && !need_cr; c++)
- if (cur[c] == '\n')
- need_cr = 1;
+ for (c = 0; c < min_t(size_t, 128U, count) && !need_cr; c++)
+ if (buf[c] == '\n')
+ need_cr = true;
while (c > 0) {
- result.as_long = callback_puts(0, cur, c);
+ result.as_long = callback_puts(0, buf, c);
c -= result.bits.c;
- remaining -= result.bits.c;
- cur += result.bits.c;
+ count -= result.bits.c;
+ buf += result.bits.c;
/*
* Check for pending input iff a tty port was provided
@@ -121,12 +118,11 @@ srmcons_do_write(struct tty_port *port, const char *buf, int count)
}
while (need_cr) {
- result.as_long = callback_puts(0, str_cr, 1);
+ result.as_long = callback_puts(0, "\r", 1);
if (result.bits.c > 0)
- need_cr = 0;
+ need_cr = false;
}
}
- return count;
}
static ssize_t
@@ -135,7 +131,7 @@ srmcons_write(struct tty_struct *tty, const u8 *buf, size_t count)
unsigned long flags;
spin_lock_irqsave(&srmcons_callback_lock, flags);
- srmcons_do_write(tty->port, (const char *) buf, count);
+ srmcons_do_write(tty->port, buf, count);
spin_unlock_irqrestore(&srmcons_callback_lock, flags);
return count;
diff --git a/arch/arc/include/asm/cacheflush.h b/arch/arc/include/asm/cacheflush.h
index 563af3e75f01..329c94cd45d8 100644
--- a/arch/arc/include/asm/cacheflush.h
+++ b/arch/arc/include/asm/cacheflush.h
@@ -40,6 +40,7 @@ void dma_cache_wback(phys_addr_t start, unsigned long sz);
/* TBD: optimize this */
#define flush_cache_vmap(start, end) flush_cache_all()
+#define flush_cache_vmap_early(start, end) do { } while (0)
#define flush_cache_vunmap(start, end) flush_cache_all()
#define flush_cache_dup_mm(mm) /* called on fork (VIVT only) */
diff --git a/arch/arc/mm/dma.c b/arch/arc/mm/dma.c
index 2a7fbbb83b70..197707bc7658 100644
--- a/arch/arc/mm/dma.c
+++ b/arch/arc/mm/dma.c
@@ -91,7 +91,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
* Plug in direct dma map ops.
*/
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
- const struct iommu_ops *iommu, bool coherent)
+ bool coherent)
{
/*
* IOC hardware snoops all DMA traffic keeping the caches consistent
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b67d05468251..0af6709570d1 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -35,6 +35,7 @@ config ARM
select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT if CPU_V7
select ARCH_SUPPORTS_ATOMIC_RMW
select ARCH_SUPPORTS_HUGETLBFS if ARM_LPAE
+ select ARCH_SUPPORTS_PER_VMA_LOCK
select ARCH_USE_BUILTIN_BSWAP
select ARCH_USE_CMPXCHG_LOCKREF
select ARCH_USE_MEMTEST
diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi
index 98817a6675b9..d233a191c139 100644
--- a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "bcm2835-rpi.dtsi"
+#include <dt-bindings/power/raspberrypi-power.h>
#include <dt-bindings/reset/raspberrypi,firmware-reset.h>
/ {
@@ -76,3 +77,7 @@
&vchiq {
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
};
+
+&xhci {
+ power-domains = <&power RPI_POWER_DOMAIN_USB>;
+};
diff --git a/arch/arm/boot/dts/broadcom/bcm2711.dtsi b/arch/arm/boot/dts/broadcom/bcm2711.dtsi
index 4a379a14966d..22c7f1561344 100644
--- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi
@@ -604,6 +604,20 @@
};
};
+ xhci: usb@7e9c0000 {
+ compatible = "brcm,bcm2711-xhci", "brcm,xhci-brcm-v2";
+ reg = <0x0 0x7e9c0000 0x100000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+ /* DWC2 and this IP block share the same USB PHY,
+ * enabling both at the same time results in lockups.
+ * So keep this node disabled and let the bootloader
+ * decide which interface should be enabled.
+ */
+ status = "disabled";
+ };
+
v3d: gpu@7ec00000 {
compatible = "brcm,2711-v3d";
reg = <0x0 0x7ec00000 0x4000>,
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index 70480dd9e96d..6d0c9f7268ba 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -68,6 +68,8 @@ struct locomo {
#endif
};
+static const struct bus_type locomo_bus_type;
+
struct locomo_dev_info {
unsigned long offset;
unsigned long length;
@@ -842,7 +844,7 @@ static void locomo_bus_remove(struct device *dev)
drv->remove(ldev);
}
-struct bus_type locomo_bus_type = {
+static const struct bus_type locomo_bus_type = {
.name = "locomo-bus",
.match = locomo_match,
.probe = locomo_bus_probe,
diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h
index f6181f69577f..1075534b0a2e 100644
--- a/arch/arm/include/asm/cacheflush.h
+++ b/arch/arm/include/asm/cacheflush.h
@@ -340,6 +340,8 @@ static inline void flush_cache_vmap(unsigned long start, unsigned long end)
dsb(ishst);
}
+#define flush_cache_vmap_early(start, end) do { } while (0)
+
static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
{
if (!cache_is_vipt_nonaliasing())
diff --git a/arch/arm/include/asm/hardware/locomo.h b/arch/arm/include/asm/hardware/locomo.h
index aaaedafef7cc..9fd9ad5d9202 100644
--- a/arch/arm/include/asm/hardware/locomo.h
+++ b/arch/arm/include/asm/hardware/locomo.h
@@ -158,8 +158,6 @@
#define LOCOMO_LPT_TOH(TOH) ((TOH & 0x7) << 4)
#define LOCOMO_LPT_TOL(TOL) ((TOL & 0x7))
-extern struct bus_type locomo_bus_type;
-
#define LOCOMO_DEVID_KEYBOARD 0
#define LOCOMO_DEVID_FRONTLIGHT 1
#define LOCOMO_DEVID_BACKLIGHT 2
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 16b02f44c7d3..d657b84b6bf7 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -151,6 +151,8 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+#define pgdp_get(pgpd) READ_ONCE(*pgdp)
+
#define pud_page(pud) pmd_page(__pmd(pud_val(pud)))
#define pud_write(pud) pmd_write(__pmd(pud_val(pud)))
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index 59de137c6f53..2a8a9fe46586 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -11,6 +11,7 @@ menuconfig ARCH_DAVINCI
select PM_GENERIC_DOMAINS_OF if PM && OF
select REGMAP_MMIO
select RESET_CONTROLLER
+ select PINCTRL
select PINCTRL_SINGLE
if ARCH_DAVINCI
diff --git a/arch/arm/mm/dma-mapping-nommu.c b/arch/arm/mm/dma-mapping-nommu.c
index cfd9c933d2f0..b94850b57995 100644
--- a/arch/arm/mm/dma-mapping-nommu.c
+++ b/arch/arm/mm/dma-mapping-nommu.c
@@ -34,7 +34,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
}
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
- const struct iommu_ops *iommu, bool coherent)
+ bool coherent)
{
if (IS_ENABLED(CONFIG_CPU_V7M)) {
/*
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 5409225b4abc..f68db05eba29 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -859,10 +859,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size,
int i = 0;
int order_idx = 0;
- if (array_size <= PAGE_SIZE)
- pages = kzalloc(array_size, GFP_KERNEL);
- else
- pages = vzalloc(array_size);
+ pages = kvzalloc(array_size, GFP_KERNEL);
if (!pages)
return NULL;
@@ -1713,7 +1710,7 @@ void arm_iommu_detach_device(struct device *dev)
EXPORT_SYMBOL_GPL(arm_iommu_detach_device);
static void arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
- const struct iommu_ops *iommu, bool coherent)
+ bool coherent)
{
struct dma_iommu_mapping *mapping;
@@ -1748,7 +1745,7 @@ static void arm_teardown_iommu_dma_ops(struct device *dev)
#else
static void arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
- const struct iommu_ops *iommu, bool coherent)
+ bool coherent)
{
}
@@ -1757,7 +1754,7 @@ static void arm_teardown_iommu_dma_ops(struct device *dev) { }
#endif /* CONFIG_ARM_DMA_USE_IOMMU */
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
- const struct iommu_ops *iommu, bool coherent)
+ bool coherent)
{
/*
* Due to legacy code that sets the ->dma_coherent flag from a bus
@@ -1776,8 +1773,8 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
if (dev->dma_ops)
return;
- if (iommu)
- arm_setup_iommu_dma_ops(dev, dma_base, size, iommu, coherent);
+ if (device_iommu_mapped(dev))
+ arm_setup_iommu_dma_ops(dev, dma_base, size, coherent);
xen_setup_dma_ops(dev);
dev->archdata.dma_ops_setup = true;
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index fef62e4a9edd..e96fb40b9cc3 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -278,6 +278,35 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
+ if (!(flags & FAULT_FLAG_USER))
+ goto lock_mmap;
+
+ vma = lock_vma_under_rcu(mm, addr);
+ if (!vma)
+ goto lock_mmap;
+
+ if (!(vma->vm_flags & vm_flags)) {
+ vma_end_read(vma);
+ goto lock_mmap;
+ }
+ fault = handle_mm_fault(vma, addr, flags | FAULT_FLAG_VMA_LOCK, regs);
+ if (!(fault & (VM_FAULT_RETRY | VM_FAULT_COMPLETED)))
+ vma_end_read(vma);
+
+ if (!(fault & VM_FAULT_RETRY)) {
+ count_vm_vma_lock_event(VMA_LOCK_SUCCESS);
+ goto done;
+ }
+ count_vm_vma_lock_event(VMA_LOCK_RETRY);
+
+ /* Quick path to respond to signals */
+ if (fault_signal_pending(fault, regs)) {
+ if (!user_mode(regs))
+ goto no_context;
+ return 0;
+ }
+lock_mmap:
+
retry:
vma = lock_mm_and_find_vma(mm, addr, regs);
if (unlikely(!vma)) {
@@ -316,6 +345,7 @@ retry:
}
mmap_read_unlock(mm);
+done:
/*
* Handle the "normal" case first - VM_FAULT_MAJOR
diff --git a/arch/arm/mm/kasan_init.c b/arch/arm/mm/kasan_init.c
index 24d71b5db62d..111d4f703136 100644
--- a/arch/arm/mm/kasan_init.c
+++ b/arch/arm/mm/kasan_init.c
@@ -28,6 +28,12 @@ static pgd_t tmp_pgd_table[PTRS_PER_PGD] __initdata __aligned(PGD_SIZE);
pmd_t tmp_pmd_table[PTRS_PER_PMD] __page_aligned_bss;
+static __init void *kasan_alloc_block_raw(size_t size)
+{
+ return memblock_alloc_try_nid_raw(size, size, __pa(MAX_DMA_ADDRESS),
+ MEMBLOCK_ALLOC_NOLEAKTRACE, NUMA_NO_NODE);
+}
+
static __init void *kasan_alloc_block(size_t size)
{
return memblock_alloc_try_nid(size, size, __pa(MAX_DMA_ADDRESS),
@@ -50,7 +56,7 @@ static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr,
if (!pte_none(READ_ONCE(*ptep)))
continue;
- p = kasan_alloc_block(PAGE_SIZE);
+ p = kasan_alloc_block_raw(PAGE_SIZE);
if (!p) {
panic("%s failed to allocate shadow page for address 0x%lx\n",
__func__, addr);
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 7e8773a2d99d..b68efe643a12 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -800,6 +800,24 @@ static struct undef_hook neon_support_hook[] = {{
.cpsr_mask = PSR_T_BIT,
.cpsr_val = PSR_T_BIT,
.fn = vfp_support_entry,
+}, {
+ .instr_mask = 0xff000800,
+ .instr_val = 0xfc000800,
+ .cpsr_mask = 0,
+ .cpsr_val = 0,
+ .fn = vfp_support_entry,
+}, {
+ .instr_mask = 0xff000800,
+ .instr_val = 0xfd000800,
+ .cpsr_mask = 0,
+ .cpsr_val = 0,
+ .fn = vfp_support_entry,
+}, {
+ .instr_mask = 0xff000800,
+ .instr_val = 0xfe000800,
+ .cpsr_mask = 0,
+ .cpsr_val = 0,
+ .fn = vfp_support_entry,
}};
static struct undef_hook vfp_support_hook = {
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 8f6cf1221b6a..ea01a2c43efa 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -133,6 +133,7 @@ config ARM64
select GENERIC_ARCH_TOPOLOGY
select GENERIC_CLOCKEVENTS_BROADCAST
select GENERIC_CPU_AUTOPROBE
+ select GENERIC_CPU_DEVICES
select GENERIC_CPU_VULNERABILITIES
select GENERIC_EARLY_IOREMAP
select GENERIC_IDLE_POLL_SETUP
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
index cc9d468b43ab..f87fa5a948cc 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts
@@ -137,6 +137,28 @@
};
};
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ dsp_vdev0vring0: vdev0vring0@942f0000 {
+ reg = <0 0x942f0000 0 0x8000>;
+ no-map;
+ };
+
+ dsp_vdev0vring1: vdev0vring1@942f8000 {
+ reg = <0 0x942f8000 0 0x8000>;
+ no-map;
+ };
+
+ dsp_vdev0buffer: vdev0buffer@94300000 {
+ compatible = "shared-dma-pool";
+ reg = <0 0x94300000 0 0x100000>;
+ no-map;
+ };
+ };
};
&flexspi {
diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
index bbdcd441c049..3c6079edda19 100644
--- a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi
@@ -1294,6 +1294,7 @@
&xhci0 {
status = "okay";
+ rx-fifo-depth = <3072>;
vusb33-supply = <&mt6359_vusb_ldo_reg>;
vbus-supply = <&usb_vbus>;
};
@@ -1301,6 +1302,7 @@
&xhci1 {
status = "okay";
+ rx-fifo-depth = <3072>;
vusb33-supply = <&mt6359_vusb_ldo_reg>;
vbus-supply = <&usb_vbus>;
};
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 7f8327b0dbdb..e423c57ddd41 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -540,9 +540,6 @@
compatible = "qcom,msm8916-bimc";
reg = <0x00400000 0x62000>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
- <&rpmcc RPM_SMD_BIMC_A_CLK>;
};
tsens: thermal-sensor@4a9000 {
@@ -575,18 +572,12 @@
compatible = "qcom,msm8916-pcnoc";
reg = <0x00500000 0x11000>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
- <&rpmcc RPM_SMD_PCNOC_A_CLK>;
};
snoc: interconnect@580000 {
compatible = "qcom,msm8916-snoc";
reg = <0x00580000 0x14000>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
- <&rpmcc RPM_SMD_SNOC_A_CLK>;
};
stm: stm@802000 {
diff --git a/arch/arm64/boot/dts/qcom/msm8939.dtsi b/arch/arm64/boot/dts/qcom/msm8939.dtsi
index 29f6bd9df2eb..82d85ff61045 100644
--- a/arch/arm64/boot/dts/qcom/msm8939.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8939.dtsi
@@ -602,9 +602,6 @@
bimc: interconnect@400000 {
compatible = "qcom,msm8939-bimc";
reg = <0x00400000 0x62000>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
- <&rpmcc RPM_SMD_BIMC_A_CLK>;
#interconnect-cells = <1>;
};
@@ -648,25 +645,16 @@
pcnoc: interconnect@500000 {
compatible = "qcom,msm8939-pcnoc";
reg = <0x00500000 0x11000>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
- <&rpmcc RPM_SMD_PCNOC_A_CLK>;
#interconnect-cells = <1>;
};
snoc: interconnect@580000 {
compatible = "qcom,msm8939-snoc";
reg = <0x00580000 0x14080>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
- <&rpmcc RPM_SMD_SNOC_A_CLK>;
#interconnect-cells = <1>;
snoc_mm: interconnect-snoc {
compatible = "qcom,msm8939-snoc-mm";
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_SYSMMNOC_CLK>,
- <&rpmcc RPM_SMD_SYSMMNOC_A_CLK>;
#interconnect-cells = <1>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index 8c6a7efa90c4..8d41ed261adf 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -838,9 +838,6 @@
compatible = "qcom,msm8996-bimc";
reg = <0x00408000 0x5a000>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
- <&rpmcc RPM_SMD_BIMC_A_CLK>;
};
tsens0: thermal-sensor@4a9000 {
@@ -891,18 +888,12 @@
compatible = "qcom,msm8996-cnoc";
reg = <0x00500000 0x1000>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_CNOC_CLK>,
- <&rpmcc RPM_SMD_CNOC_A_CLK>;
};
snoc: interconnect@524000 {
compatible = "qcom,msm8996-snoc";
reg = <0x00524000 0x1c000>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
- <&rpmcc RPM_SMD_SNOC_A_CLK>;
};
a0noc: interconnect@543000 {
@@ -922,19 +913,14 @@
compatible = "qcom,msm8996-a1noc";
reg = <0x00562000 0x5000>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_AGGR1_NOC_CLK>,
- <&rpmcc RPM_SMD_AGGR1_NOC_A_CLK>;
};
a2noc: interconnect@583000 {
compatible = "qcom,msm8996-a2noc";
reg = <0x00583000 0x7000>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a", "aggre2_ufs_axi", "ufs_axi";
- clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>,
- <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>,
- <&gcc GCC_AGGRE2_UFS_AXI_CLK>,
+ clock-names = "aggre2_ufs_axi", "ufs_axi";
+ clocks = <&gcc GCC_AGGRE2_UFS_AXI_CLK>,
<&gcc GCC_UFS_AXI_CLK>;
};
@@ -942,19 +928,14 @@
compatible = "qcom,msm8996-mnoc";
reg = <0x005a4000 0x1c000>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a", "iface";
- clocks = <&rpmcc RPM_SMD_MMAXI_CLK>,
- <&rpmcc RPM_SMD_MMAXI_A_CLK>,
- <&mmcc AHB_CLK_SRC>;
+ clock-names = "iface";
+ clocks = <&mmcc AHB_CLK_SRC>;
};
pnoc: interconnect@5c0000 {
compatible = "qcom,msm8996-pnoc";
reg = <0x005c0000 0x3000>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
- <&rpmcc RPM_SMD_PCNOC_A_CLK>;
};
tcsr_mutex: hwlock@740000 {
@@ -2486,9 +2467,8 @@
"handover",
"stop-ack";
- clocks = <&xo_board>,
- <&rpmcc RPM_SMD_AGGR2_NOC_CLK>;
- clock-names = "xo", "aggre2";
+ clocks = <&xo_board>;
+ clock-names = "xo";
memory-region = <&slpi_mem>;
@@ -2533,10 +2513,15 @@
<&gcc GCC_MSS_GPLL0_DIV_CLK>,
<&gcc GCC_MSS_SNOC_AXI_CLK>,
<&gcc GCC_MSS_MNOC_BIMC_AXI_CLK>,
- <&rpmcc RPM_SMD_PCNOC_CLK>,
<&rpmcc RPM_SMD_QDSS_CLK>;
- clock-names = "iface", "bus", "mem", "xo", "gpll0_mss",
- "snoc_axi", "mnoc_axi", "pnoc", "qdss";
+ clock-names = "iface",
+ "bus",
+ "mem",
+ "xo",
+ "gpll0_mss",
+ "snoc_axi",
+ "mnoc_axi",
+ "qdss";
resets = <&gcc GCC_MSS_RESTART>;
reset-names = "mss_restart";
diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi
index bb591c6bf573..2793cc22d381 100644
--- a/arch/arm64/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi
@@ -1605,9 +1605,8 @@
px-supply = <&vreg_lvs2a_1p8>;
- clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>,
- <&rpmcc RPM_SMD_AGGR2_NOC_CLK>;
- clock-names = "xo", "aggre2";
+ clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>;
+ clock-names = "xo";
memory-region = <&slpi_mem>;
diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi
index 6ac64ce9bb68..2f2eeaf2e945 100644
--- a/arch/arm64/boot/dts/qcom/qcs404.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi
@@ -558,9 +558,6 @@
reg = <0x00400000 0x80000>;
compatible = "qcom,qcs404-bimc";
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
- <&rpmcc RPM_SMD_BIMC_A_CLK>;
};
tsens: thermal-sensor@4a9000 {
@@ -601,18 +598,12 @@
reg = <0x00500000 0x15080>;
compatible = "qcom,qcs404-pcnoc";
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_PNOC_CLK>,
- <&rpmcc RPM_SMD_PNOC_A_CLK>;
};
snoc: interconnect@580000 {
reg = <0x00580000 0x23080>;
compatible = "qcom,qcs404-snoc";
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
- <&rpmcc RPM_SMD_SNOC_A_CLK>;
};
remoteproc_cdsp: remoteproc@b00000 {
diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts
index 043184557873..cd0db4f31d4a 100644
--- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts
+++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts
@@ -1454,7 +1454,7 @@
altmodes {
displayport {
- svid = <0xff01>;
+ svid = /bits/ 16 <0xff01>;
vdo = <0x00001c46>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi
index 775700f78e0f..513fe5e76b68 100644
--- a/arch/arm64/boot/dts/qcom/sdm630.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi
@@ -606,9 +606,6 @@
compatible = "qcom,sdm660-bimc";
reg = <0x01008000 0x78000>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
- <&rpmcc RPM_SMD_BIMC_A_CLK>;
};
restart@10ac000 {
@@ -620,28 +617,17 @@
compatible = "qcom,sdm660-cnoc";
reg = <0x01500000 0x10000>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_CNOC_CLK>,
- <&rpmcc RPM_SMD_CNOC_A_CLK>;
};
snoc: interconnect@1626000 {
compatible = "qcom,sdm660-snoc";
reg = <0x01626000 0x7090>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a";
- clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
- <&rpmcc RPM_SMD_SNOC_A_CLK>;
};
anoc2_smmu: iommu@16c0000 {
compatible = "qcom,sdm630-smmu-v2", "qcom,smmu-v2";
reg = <0x016c0000 0x40000>;
-
- assigned-clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>;
- assigned-clock-rates = <1000>;
- clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>;
- clock-names = "bus";
#global-interrupts = <2>;
#iommu-cells = <1>;
@@ -686,16 +672,12 @@
compatible = "qcom,sdm660-a2noc";
reg = <0x01704000 0xc100>;
#interconnect-cells = <1>;
- clock-names = "bus",
- "bus_a",
- "ipa",
+ clock-names = "ipa",
"ufs_axi",
"aggre2_ufs_axi",
"aggre2_usb3_axi",
"cfg_noc_usb2_axi";
- clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>,
- <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>,
- <&rpmcc RPM_SMD_IPA_CLK>,
+ clocks = <&rpmcc RPM_SMD_IPA_CLK>,
<&gcc GCC_UFS_AXI_CLK>,
<&gcc GCC_AGGRE2_UFS_AXI_CLK>,
<&gcc GCC_AGGRE2_USB3_AXI_CLK>,
@@ -706,10 +688,8 @@
compatible = "qcom,sdm660-mnoc";
reg = <0x01745000 0xa010>;
#interconnect-cells = <1>;
- clock-names = "bus", "bus_a", "iface";
- clocks = <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK>,
- <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK_A>,
- <&mmcc AHB_CLK_SRC>;
+ clock-names = "iface";
+ clocks = <&mmcc AHB_CLK_SRC>;
};
tsens: thermal-sensor@10ae000 {
@@ -1186,7 +1166,9 @@
clocks = <&gcc GCC_GPU_CFG_AHB_CLK>,
<&gcc GCC_BIMC_GFX_CLK>,
<&gcc GCC_GPU_BIMC_GFX_CLK>;
- clock-names = "iface", "mem", "mem_iface";
+ clock-names = "iface",
+ "mem",
+ "mem_iface";
#global-interrupts = <2>;
#iommu-cells = <1>;
@@ -1288,20 +1270,16 @@
<&gcc GCC_USB30_MASTER_CLK>,
<&gcc GCC_AGGRE2_USB3_AXI_CLK>,
<&gcc GCC_USB30_SLEEP_CLK>,
- <&gcc GCC_USB30_MOCK_UTMI_CLK>,
- <&rpmcc RPM_SMD_AGGR2_NOC_CLK>;
+ <&gcc GCC_USB30_MOCK_UTMI_CLK>;
clock-names = "cfg_noc",
"core",
"iface",
"sleep",
- "mock_utmi",
- "bus";
+ "mock_utmi";
assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>,
- <&gcc GCC_USB30_MASTER_CLK>,
- <&rpmcc RPM_SMD_AGGR2_NOC_CLK>;
- assigned-clock-rates = <19200000>, <120000000>,
- <19200000>;
+ <&gcc GCC_USB30_MASTER_CLK>;
+ assigned-clock-rates = <19200000>, <120000000>;
interrupts = <GIC_SPI 347 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>;
@@ -2204,10 +2182,9 @@
clocks = <&mmcc MNOC_AHB_CLK>,
<&mmcc BIMC_SMMU_AHB_CLK>,
- <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK>,
<&mmcc BIMC_SMMU_AXI_CLK>;
clock-names = "iface-mm", "iface-smmu",
- "bus-mm", "bus-smmu";
+ "bus-smmu";
#global-interrupts = <2>;
#iommu-cells = <1>;
@@ -2324,12 +2301,6 @@
compatible = "qcom,sdm660-gnoc";
reg = <0x17900000 0xe000>;
#interconnect-cells = <1>;
- /*
- * This one apparently features no clocks,
- * so let's not mess with the driver needlessly
- */
- clock-names = "bus", "bus_a";
- clocks = <&xo_board>, <&xo_board>;
};
apcs_glb: mailbox@17911000 {
diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h
index f3034099fd95..b1e43f56ee46 100644
--- a/arch/arm64/include/asm/cpu.h
+++ b/arch/arm64/include/asm/cpu.h
@@ -38,7 +38,6 @@ struct cpuinfo_32bit {
};
struct cpuinfo_arm64 {
- struct cpu cpu;
struct kobject kobj;
u64 reg_ctr;
u64 reg_cntfrq;
diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index ae35939f395b..353fe08546cf 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -392,6 +392,21 @@ static inline bool esr_is_data_abort(unsigned long esr)
return ec == ESR_ELx_EC_DABT_LOW || ec == ESR_ELx_EC_DABT_CUR;
}
+static inline bool esr_fsc_is_translation_fault(unsigned long esr)
+{
+ return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_FAULT;
+}
+
+static inline bool esr_fsc_is_permission_fault(unsigned long esr)
+{
+ return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM;
+}
+
+static inline bool esr_fsc_is_access_flag_fault(unsigned long esr)
+{
+ return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_ACCESS;
+}
+
const char *esr_get_class_string(unsigned long esr);
#endif /* __ASSEMBLY */
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index b85f46a73e21..3c6f8ba1e479 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -108,6 +108,7 @@
#define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En)
/* TCR_EL2 Registers bits */
+#define TCR_EL2_DS (1UL << 32)
#define TCR_EL2_RES1 ((1U << 31) | (1 << 23))
#define TCR_EL2_TBI (1 << 20)
#define TCR_EL2_PS_SHIFT 16
@@ -122,6 +123,7 @@
TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK | TCR_EL2_T0SZ_MASK)
/* VTCR_EL2 Registers bits */
+#define VTCR_EL2_DS TCR_EL2_DS
#define VTCR_EL2_RES1 (1U << 31)
#define VTCR_EL2_HD (1 << 22)
#define VTCR_EL2_HA (1 << 21)
@@ -344,36 +346,47 @@
* Once we get to a point where the two describe the same thing, we'll
* merge the definitions. One day.
*/
-#define __HFGRTR_EL2_RES0 (GENMASK(63, 56) | GENMASK(53, 51))
+#define __HFGRTR_EL2_RES0 HFGxTR_EL2_RES0
#define __HFGRTR_EL2_MASK GENMASK(49, 0)
-#define __HFGRTR_EL2_nMASK (GENMASK(58, 57) | GENMASK(55, 54) | BIT(50))
+#define __HFGRTR_EL2_nMASK ~(__HFGRTR_EL2_RES0 | __HFGRTR_EL2_MASK)
-#define __HFGWTR_EL2_RES0 (GENMASK(63, 56) | GENMASK(53, 51) | \
- BIT(46) | BIT(42) | BIT(40) | BIT(28) | \
- GENMASK(26, 25) | BIT(21) | BIT(18) | \
+/*
+ * The HFGWTR bits are a subset of HFGRTR bits. To ensure we don't miss any
+ * future additions, define __HFGWTR* macros relative to __HFGRTR* ones.
+ */
+#define __HFGRTR_ONLY_MASK (BIT(46) | BIT(42) | BIT(40) | BIT(28) | \
+ GENMASK(26, 25) | BIT(21) | BIT(18) | \
GENMASK(15, 14) | GENMASK(10, 9) | BIT(2))
-#define __HFGWTR_EL2_MASK GENMASK(49, 0)
-#define __HFGWTR_EL2_nMASK (GENMASK(58, 57) | GENMASK(55, 54) | BIT(50))
-
-#define __HFGITR_EL2_RES0 GENMASK(63, 57)
-#define __HFGITR_EL2_MASK GENMASK(54, 0)
-#define __HFGITR_EL2_nMASK GENMASK(56, 55)
-
-#define __HDFGRTR_EL2_RES0 (BIT(49) | BIT(42) | GENMASK(39, 38) | \
- GENMASK(21, 20) | BIT(8))
-#define __HDFGRTR_EL2_MASK ~__HDFGRTR_EL2_nMASK
-#define __HDFGRTR_EL2_nMASK GENMASK(62, 59)
-
-#define __HDFGWTR_EL2_RES0 (BIT(63) | GENMASK(59, 58) | BIT(51) | BIT(47) | \
- BIT(43) | GENMASK(40, 38) | BIT(34) | BIT(30) | \
- BIT(22) | BIT(9) | BIT(6))
-#define __HDFGWTR_EL2_MASK ~__HDFGWTR_EL2_nMASK
-#define __HDFGWTR_EL2_nMASK GENMASK(62, 60)
+#define __HFGWTR_EL2_RES0 (__HFGRTR_EL2_RES0 | __HFGRTR_ONLY_MASK)
+#define __HFGWTR_EL2_MASK (__HFGRTR_EL2_MASK & ~__HFGRTR_ONLY_MASK)
+#define __HFGWTR_EL2_nMASK ~(__HFGWTR_EL2_RES0 | __HFGWTR_EL2_MASK)
+
+#define __HFGITR_EL2_RES0 HFGITR_EL2_RES0
+#define __HFGITR_EL2_MASK (BIT(62) | BIT(60) | GENMASK(54, 0))
+#define __HFGITR_EL2_nMASK ~(__HFGITR_EL2_RES0 | __HFGITR_EL2_MASK)
+
+#define __HDFGRTR_EL2_RES0 HDFGRTR_EL2_RES0
+#define __HDFGRTR_EL2_MASK (BIT(63) | GENMASK(58, 50) | GENMASK(48, 43) | \
+ GENMASK(41, 40) | GENMASK(37, 22) | \
+ GENMASK(19, 9) | GENMASK(7, 0))
+#define __HDFGRTR_EL2_nMASK ~(__HDFGRTR_EL2_RES0 | __HDFGRTR_EL2_MASK)
+
+#define __HDFGWTR_EL2_RES0 HDFGWTR_EL2_RES0
+#define __HDFGWTR_EL2_MASK (GENMASK(57, 52) | GENMASK(50, 48) | \
+ GENMASK(46, 44) | GENMASK(42, 41) | \
+ GENMASK(37, 35) | GENMASK(33, 31) | \
+ GENMASK(29, 23) | GENMASK(21, 10) | \
+ GENMASK(8, 7) | GENMASK(5, 0))
+#define __HDFGWTR_EL2_nMASK ~(__HDFGWTR_EL2_RES0 | __HDFGWTR_EL2_MASK)
+
+#define __HAFGRTR_EL2_RES0 HAFGRTR_EL2_RES0
+#define __HAFGRTR_EL2_MASK (GENMASK(49, 17) | GENMASK(4, 0))
+#define __HAFGRTR_EL2_nMASK ~(__HAFGRTR_EL2_RES0 | __HAFGRTR_EL2_MASK)
/* Similar definitions for HCRX_EL2 */
-#define __HCRX_EL2_RES0 (GENMASK(63, 16) | GENMASK(13, 12))
-#define __HCRX_EL2_MASK (0)
-#define __HCRX_EL2_nMASK (GENMASK(15, 14) | GENMASK(4, 0))
+#define __HCRX_EL2_RES0 HCRX_EL2_RES0
+#define __HCRX_EL2_MASK (BIT(6))
+#define __HCRX_EL2_nMASK ~(__HCRX_EL2_RES0 | __HCRX_EL2_MASK)
/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
#define HPFAR_MASK (~UL(0xf))
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 78a550537b67..b804fe832184 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -17,6 +17,7 @@
#include <asm/esr.h>
#include <asm/kvm_arm.h>
#include <asm/kvm_hyp.h>
+#include <asm/kvm_nested.h>
#include <asm/ptrace.h>
#include <asm/cputype.h>
#include <asm/virt.h>
@@ -54,11 +55,6 @@ void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu);
int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2);
int kvm_inject_nested_irq(struct kvm_vcpu *vcpu);
-static inline bool vcpu_has_feature(const struct kvm_vcpu *vcpu, int feature)
-{
- return test_bit(feature, vcpu->kvm->arch.vcpu_features);
-}
-
#if defined(__KVM_VHE_HYPERVISOR__) || defined(__KVM_NVHE_HYPERVISOR__)
static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
{
@@ -248,7 +244,7 @@ static inline bool __is_hyp_ctxt(const struct kvm_cpu_context *ctxt)
static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
{
- return __is_hyp_ctxt(&vcpu->arch.ctxt);
+ return vcpu_has_nv(vcpu) && __is_hyp_ctxt(&vcpu->arch.ctxt);
}
/*
@@ -404,14 +400,25 @@ static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC;
}
-static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
+static inline
+bool kvm_vcpu_trap_is_permission_fault(const struct kvm_vcpu *vcpu)
{
- return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_TYPE;
+ return esr_fsc_is_permission_fault(kvm_vcpu_get_esr(vcpu));
}
-static __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
+static inline
+bool kvm_vcpu_trap_is_translation_fault(const struct kvm_vcpu *vcpu)
{
- return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL;
+ return esr_fsc_is_translation_fault(kvm_vcpu_get_esr(vcpu));
+}
+
+static inline
+u64 kvm_vcpu_trap_get_perm_fault_granule(const struct kvm_vcpu *vcpu)
+{
+ unsigned long esr = kvm_vcpu_get_esr(vcpu);
+
+ BUG_ON(!esr_fsc_is_permission_fault(esr));
+ return BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(esr & ESR_ELx_FSC_LEVEL));
}
static __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu)
@@ -454,12 +461,7 @@ static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
* first), then a permission fault to allow the flags
* to be set.
*/
- switch (kvm_vcpu_trap_get_fault_type(vcpu)) {
- case ESR_ELx_FSC_PERM:
- return true;
- default:
- return false;
- }
+ return kvm_vcpu_trap_is_permission_fault(vcpu);
}
if (kvm_vcpu_trap_is_iabt(vcpu))
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 824f29f04916..21c57b812569 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -27,6 +27,7 @@
#include <asm/fpsimd.h>
#include <asm/kvm.h>
#include <asm/kvm_asm.h>
+#include <asm/vncr_mapping.h>
#define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -306,6 +307,7 @@ struct kvm_arch {
* Atomic access to multiple idregs are guarded by kvm_arch.config_lock.
*/
#define IDREG_IDX(id) (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))
+#define IDX_IDREG(idx) sys_reg(3, 0, 0, ((idx) >> 3) + 1, (idx) & Op2_mask)
#define IDREG(kvm, id) ((kvm)->arch.id_regs[IDREG_IDX(id)])
#define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
u64 id_regs[KVM_ARM_ID_REG_NUM];
@@ -324,33 +326,33 @@ struct kvm_vcpu_fault_info {
u64 disr_el1; /* Deferred [SError] Status Register */
};
+/*
+ * VNCR() just places the VNCR_capable registers in the enum after
+ * __VNCR_START__, and the value (after correction) to be an 8-byte offset
+ * from the VNCR base. As we don't require the enum to be otherwise ordered,
+ * we need the terrible hack below to ensure that we correctly size the
+ * sys_regs array, no matter what.
+ *
+ * The __MAX__ macro has been lifted from Sean Eron Anderson's wonderful
+ * treasure trove of bit hacks:
+ * https://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
+ */
+#define __MAX__(x,y) ((x) ^ (((x) ^ (y)) & -((x) < (y))))
+#define VNCR(r) \
+ __before_##r, \
+ r = __VNCR_START__ + ((VNCR_ ## r) / 8), \
+ __after_##r = __MAX__(__before_##r - 1, r)
+
enum vcpu_sysreg {
__INVALID_SYSREG__, /* 0 is reserved as an invalid value */
MPIDR_EL1, /* MultiProcessor Affinity Register */
CLIDR_EL1, /* Cache Level ID Register */
CSSELR_EL1, /* Cache Size Selection Register */
- SCTLR_EL1, /* System Control Register */
- ACTLR_EL1, /* Auxiliary Control Register */
- CPACR_EL1, /* Coprocessor Access Control */
- ZCR_EL1, /* SVE Control */
- TTBR0_EL1, /* Translation Table Base Register 0 */
- TTBR1_EL1, /* Translation Table Base Register 1 */
- TCR_EL1, /* Translation Control Register */
- TCR2_EL1, /* Extended Translation Control Register */
- ESR_EL1, /* Exception Syndrome Register */
- AFSR0_EL1, /* Auxiliary Fault Status Register 0 */
- AFSR1_EL1, /* Auxiliary Fault Status Register 1 */
- FAR_EL1, /* Fault Address Register */
- MAIR_EL1, /* Memory Attribute Indirection Register */
- VBAR_EL1, /* Vector Base Address Register */
- CONTEXTIDR_EL1, /* Context ID Register */
TPIDR_EL0, /* Thread ID, User R/W */
TPIDRRO_EL0, /* Thread ID, User R/O */
TPIDR_EL1, /* Thread ID, Privileged */
- AMAIR_EL1, /* Aux Memory Attribute Indirection Register */
CNTKCTL_EL1, /* Timer Control Register (EL1) */
PAR_EL1, /* Physical Address Register */
- MDSCR_EL1, /* Monitor Debug System Control Register */
MDCCINT_EL1, /* Monitor Debug Comms Channel Interrupt Enable Reg */
OSLSR_EL1, /* OS Lock Status Register */
DISR_EL1, /* Deferred Interrupt Status Register */
@@ -381,26 +383,11 @@ enum vcpu_sysreg {
APGAKEYLO_EL1,
APGAKEYHI_EL1,
- ELR_EL1,
- SP_EL1,
- SPSR_EL1,
-
- CNTVOFF_EL2,
- CNTV_CVAL_EL0,
- CNTV_CTL_EL0,
- CNTP_CVAL_EL0,
- CNTP_CTL_EL0,
-
/* Memory Tagging Extension registers */
RGSR_EL1, /* Random Allocation Tag Seed Register */
GCR_EL1, /* Tag Control Register */
- TFSR_EL1, /* Tag Fault Status Register (EL1) */
TFSRE0_EL1, /* Tag Fault Status Register (EL0) */
- /* Permission Indirection Extension registers */
- PIR_EL1, /* Permission Indirection Register 1 (EL1) */
- PIRE0_EL1, /* Permission Indirection Register 0 (EL1) */
-
/* 32bit specific registers. */
DACR32_EL2, /* Domain Access Control Register */
IFSR32_EL2, /* Instruction Fault Status Register */
@@ -408,21 +395,14 @@ enum vcpu_sysreg {
DBGVCR32_EL2, /* Debug Vector Catch Register */
/* EL2 registers */
- VPIDR_EL2, /* Virtualization Processor ID Register */
- VMPIDR_EL2, /* Virtualization Multiprocessor ID Register */
SCTLR_EL2, /* System Control Register (EL2) */
ACTLR_EL2, /* Auxiliary Control Register (EL2) */
- HCR_EL2, /* Hypervisor Configuration Register */
MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */
CPTR_EL2, /* Architectural Feature Trap Register (EL2) */
- HSTR_EL2, /* Hypervisor System Trap Register */
HACR_EL2, /* Hypervisor Auxiliary Control Register */
- HCRX_EL2, /* Extended Hypervisor Configuration Register */
TTBR0_EL2, /* Translation Table Base Register 0 (EL2) */
TTBR1_EL2, /* Translation Table Base Register 1 (EL2) */
TCR_EL2, /* Translation Control Register (EL2) */
- VTTBR_EL2, /* Virtualization Translation Table Base Register */
- VTCR_EL2, /* Virtualization Translation Control Register */
SPSR_EL2, /* EL2 saved program status register */
ELR_EL2, /* EL2 exception link register */
AFSR0_EL2, /* Auxiliary Fault Status Register 0 (EL2) */
@@ -435,19 +415,62 @@ enum vcpu_sysreg {
VBAR_EL2, /* Vector Base Address Register (EL2) */
RVBAR_EL2, /* Reset Vector Base Address Register */
CONTEXTIDR_EL2, /* Context ID Register (EL2) */
- TPIDR_EL2, /* EL2 Software Thread ID Register */
CNTHCTL_EL2, /* Counter-timer Hypervisor Control register */
SP_EL2, /* EL2 Stack Pointer */
- HFGRTR_EL2,
- HFGWTR_EL2,
- HFGITR_EL2,
- HDFGRTR_EL2,
- HDFGWTR_EL2,
CNTHP_CTL_EL2,
CNTHP_CVAL_EL2,
CNTHV_CTL_EL2,
CNTHV_CVAL_EL2,
+ __VNCR_START__, /* Any VNCR-capable reg goes after this point */
+
+ VNCR(SCTLR_EL1),/* System Control Register */
+ VNCR(ACTLR_EL1),/* Auxiliary Control Register */
+ VNCR(CPACR_EL1),/* Coprocessor Access Control */
+ VNCR(ZCR_EL1), /* SVE Control */
+ VNCR(TTBR0_EL1),/* Translation Table Base Register 0 */
+ VNCR(TTBR1_EL1),/* Translation Table Base Register 1 */
+ VNCR(TCR_EL1), /* Translation Control Register */
+ VNCR(TCR2_EL1), /* Extended Translation Control Register */
+ VNCR(ESR_EL1), /* Exception Syndrome Register */
+ VNCR(AFSR0_EL1),/* Auxiliary Fault Status Register 0 */
+ VNCR(AFSR1_EL1),/* Auxiliary Fault Status Register 1 */
+ VNCR(FAR_EL1), /* Fault Address Register */
+ VNCR(MAIR_EL1), /* Memory Attribute Indirection Register */
+ VNCR(VBAR_EL1), /* Vector Base Address Register */
+ VNCR(CONTEXTIDR_EL1), /* Context ID Register */
+ VNCR(AMAIR_EL1),/* Aux Memory Attribute Indirection Register */
+ VNCR(MDSCR_EL1),/* Monitor Debug System Control Register */
+ VNCR(ELR_EL1),
+ VNCR(SP_EL1),
+ VNCR(SPSR_EL1),
+ VNCR(TFSR_EL1), /* Tag Fault Status Register (EL1) */
+ VNCR(VPIDR_EL2),/* Virtualization Processor ID Register */
+ VNCR(VMPIDR_EL2),/* Virtualization Multiprocessor ID Register */
+ VNCR(HCR_EL2), /* Hypervisor Configuration Register */
+ VNCR(HSTR_EL2), /* Hypervisor System Trap Register */
+ VNCR(VTTBR_EL2),/* Virtualization Translation Table Base Register */
+ VNCR(VTCR_EL2), /* Virtualization Translation Control Register */
+ VNCR(TPIDR_EL2),/* EL2 Software Thread ID Register */
+ VNCR(HCRX_EL2), /* Extended Hypervisor Configuration Register */
+
+ /* Permission Indirection Extension registers */
+ VNCR(PIR_EL1), /* Permission Indirection Register 1 (EL1) */
+ VNCR(PIRE0_EL1), /* Permission Indirection Register 0 (EL1) */
+
+ VNCR(HFGRTR_EL2),
+ VNCR(HFGWTR_EL2),
+ VNCR(HFGITR_EL2),
+ VNCR(HDFGRTR_EL2),
+ VNCR(HDFGWTR_EL2),
+ VNCR(HAFGRTR_EL2),
+
+ VNCR(CNTVOFF_EL2),
+ VNCR(CNTV_CVAL_EL0),
+ VNCR(CNTV_CTL_EL0),
+ VNCR(CNTP_CVAL_EL0),
+ VNCR(CNTP_CTL_EL0),
+
NR_SYS_REGS /* Nothing after this line! */
};
@@ -464,6 +487,9 @@ struct kvm_cpu_context {
u64 sys_regs[NR_SYS_REGS];
struct kvm_vcpu *__hyp_running_vcpu;
+
+ /* This pointer has to be 4kB aligned. */
+ u64 *vncr_array;
};
struct kvm_host_data {
@@ -826,8 +852,19 @@ struct kvm_vcpu_arch {
* accessed by a running VCPU. For example, for userspace access or
* for system registers that are never context switched, but only
* emulated.
+ *
+ * Don't bother with VNCR-based accesses in the nVHE code, it has no
+ * business dealing with NV.
*/
-#define __ctxt_sys_reg(c,r) (&(c)->sys_regs[(r)])
+static inline u64 *__ctxt_sys_reg(const struct kvm_cpu_context *ctxt, int r)
+{
+#if !defined (__KVM_NVHE_HYPERVISOR__)
+ if (unlikely(cpus_have_final_cap(ARM64_HAS_NESTED_VIRT) &&
+ r >= __VNCR_START__ && ctxt->vncr_array))
+ return &ctxt->vncr_array[r - __VNCR_START__];
+#endif
+ return (u64 *)&ctxt->sys_regs[r];
+}
#define ctxt_sys_reg(c,r) (*__ctxt_sys_reg(c,r))
@@ -871,6 +908,7 @@ static inline bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val)
case AMAIR_EL1: *val = read_sysreg_s(SYS_AMAIR_EL12); break;
case CNTKCTL_EL1: *val = read_sysreg_s(SYS_CNTKCTL_EL12); break;
case ELR_EL1: *val = read_sysreg_s(SYS_ELR_EL12); break;
+ case SPSR_EL1: *val = read_sysreg_s(SYS_SPSR_EL12); break;
case PAR_EL1: *val = read_sysreg_par(); break;
case DACR32_EL2: *val = read_sysreg_s(SYS_DACR32_EL2); break;
case IFSR32_EL2: *val = read_sysreg_s(SYS_IFSR32_EL2); break;
@@ -915,6 +953,7 @@ static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg)
case AMAIR_EL1: write_sysreg_s(val, SYS_AMAIR_EL12); break;
case CNTKCTL_EL1: write_sysreg_s(val, SYS_CNTKCTL_EL12); break;
case ELR_EL1: write_sysreg_s(val, SYS_ELR_EL12); break;
+ case SPSR_EL1: write_sysreg_s(val, SYS_SPSR_EL12); break;
case PAR_EL1: write_sysreg_s(val, SYS_PAR_EL1); break;
case DACR32_EL2: write_sysreg_s(val, SYS_DACR32_EL2); break;
case IFSR32_EL2: write_sysreg_s(val, SYS_IFSR32_EL2); break;
@@ -954,8 +993,6 @@ int __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
struct kvm_vcpu_events *events);
-#define KVM_ARCH_WANT_MMU_NOTIFIER
-
void kvm_arm_halt_guest(struct kvm *kvm);
void kvm_arm_resume_guest(struct kvm *kvm);
@@ -1177,6 +1214,13 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
#define kvm_vm_has_ran_once(kvm) \
(test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &(kvm)->arch.flags))
+static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature)
+{
+ return test_bit(feature, ka->vcpu_features);
+}
+
+#define vcpu_has_feature(v, f) __vcpu_has_feature(&(v)->kvm->arch, (f))
+
int kvm_trng_call(struct kvm_vcpu *vcpu);
#ifdef CONFIG_KVM
extern phys_addr_t hyp_mem_base;
diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h
index 6cec8e9c6c91..4882905357f4 100644
--- a/arch/arm64/include/asm/kvm_nested.h
+++ b/arch/arm64/include/asm/kvm_nested.h
@@ -2,8 +2,9 @@
#ifndef __ARM64_KVM_NESTED_H
#define __ARM64_KVM_NESTED_H
-#include <asm/kvm_emulate.h>
+#include <linux/bitfield.h>
#include <linux/kvm_host.h>
+#include <asm/kvm_emulate.h>
static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu)
{
@@ -12,12 +13,55 @@ static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu)
vcpu_has_feature(vcpu, KVM_ARM_VCPU_HAS_EL2));
}
-extern bool __check_nv_sr_forward(struct kvm_vcpu *vcpu);
+/* Translation helpers from non-VHE EL2 to EL1 */
+static inline u64 tcr_el2_ps_to_tcr_el1_ips(u64 tcr_el2)
+{
+ return (u64)FIELD_GET(TCR_EL2_PS_MASK, tcr_el2) << TCR_IPS_SHIFT;
+}
+
+static inline u64 translate_tcr_el2_to_tcr_el1(u64 tcr)
+{
+ return TCR_EPD1_MASK | /* disable TTBR1_EL1 */
+ ((tcr & TCR_EL2_TBI) ? TCR_TBI0 : 0) |
+ tcr_el2_ps_to_tcr_el1_ips(tcr) |
+ (tcr & TCR_EL2_TG0_MASK) |
+ (tcr & TCR_EL2_ORGN0_MASK) |
+ (tcr & TCR_EL2_IRGN0_MASK) |
+ (tcr & TCR_EL2_T0SZ_MASK);
+}
+
+static inline u64 translate_cptr_el2_to_cpacr_el1(u64 cptr_el2)
+{
+ u64 cpacr_el1 = 0;
+
+ if (cptr_el2 & CPTR_EL2_TTA)
+ cpacr_el1 |= CPACR_ELx_TTA;
+ if (!(cptr_el2 & CPTR_EL2_TFP))
+ cpacr_el1 |= CPACR_ELx_FPEN;
+ if (!(cptr_el2 & CPTR_EL2_TZ))
+ cpacr_el1 |= CPACR_ELx_ZEN;
-struct sys_reg_params;
-struct sys_reg_desc;
+ return cpacr_el1;
+}
+
+static inline u64 translate_sctlr_el2_to_sctlr_el1(u64 val)
+{
+ /* Only preserve the minimal set of bits we support */
+ val &= (SCTLR_ELx_M | SCTLR_ELx_A | SCTLR_ELx_C | SCTLR_ELx_SA |
+ SCTLR_ELx_I | SCTLR_ELx_IESB | SCTLR_ELx_WXN | SCTLR_ELx_EE);
+ val |= SCTLR_EL1_RES1;
+
+ return val;
+}
+
+static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0)
+{
+ /* Clear the ASID field */
+ return ttbr0 & ~GENMASK_ULL(63, 48);
+}
+
+extern bool __check_nv_sr_forward(struct kvm_vcpu *vcpu);
-void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p,
- const struct sys_reg_desc *r);
+int kvm_init_nv_sysregs(struct kvm *kvm);
#endif /* __ARM64_KVM_NESTED_H */
diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h
index 10068500d601..cfdf40f734b1 100644
--- a/arch/arm64/include/asm/kvm_pgtable.h
+++ b/arch/arm64/include/asm/kvm_pgtable.h
@@ -11,7 +11,8 @@
#include <linux/kvm_host.h>
#include <linux/types.h>
-#define KVM_PGTABLE_MAX_LEVELS 4U
+#define KVM_PGTABLE_FIRST_LEVEL -1
+#define KVM_PGTABLE_LAST_LEVEL 3
/*
* The largest supported block sizes for KVM (no 52-bit PA support):
@@ -20,19 +21,29 @@
* - 64K (level 2): 512MB
*/
#ifdef CONFIG_ARM64_4K_PAGES
-#define KVM_PGTABLE_MIN_BLOCK_LEVEL 1U
+#define KVM_PGTABLE_MIN_BLOCK_LEVEL 1
#else
-#define KVM_PGTABLE_MIN_BLOCK_LEVEL 2U
+#define KVM_PGTABLE_MIN_BLOCK_LEVEL 2
#endif
-#define kvm_lpa2_is_enabled() false
+#define kvm_lpa2_is_enabled() system_supports_lpa2()
+
+static inline u64 kvm_get_parange_max(void)
+{
+ if (kvm_lpa2_is_enabled() ||
+ (IS_ENABLED(CONFIG_ARM64_PA_BITS_52) && PAGE_SHIFT == 16))
+ return ID_AA64MMFR0_EL1_PARANGE_52;
+ else
+ return ID_AA64MMFR0_EL1_PARANGE_48;
+}
static inline u64 kvm_get_parange(u64 mmfr0)
{
+ u64 parange_max = kvm_get_parange_max();
u64 parange = cpuid_feature_extract_unsigned_field(mmfr0,
ID_AA64MMFR0_EL1_PARANGE_SHIFT);
- if (parange > ID_AA64MMFR0_EL1_PARANGE_MAX)
- parange = ID_AA64MMFR0_EL1_PARANGE_MAX;
+ if (parange > parange_max)
+ parange = parange_max;
return parange;
}
@@ -43,6 +54,8 @@ typedef u64 kvm_pte_t;
#define KVM_PTE_ADDR_MASK GENMASK(47, PAGE_SHIFT)
#define KVM_PTE_ADDR_51_48 GENMASK(15, 12)
+#define KVM_PTE_ADDR_MASK_LPA2 GENMASK(49, PAGE_SHIFT)
+#define KVM_PTE_ADDR_51_50_LPA2 GENMASK(9, 8)
#define KVM_PHYS_INVALID (-1ULL)
@@ -53,21 +66,34 @@ static inline bool kvm_pte_valid(kvm_pte_t pte)
static inline u64 kvm_pte_to_phys(kvm_pte_t pte)
{
- u64 pa = pte & KVM_PTE_ADDR_MASK;
-
- if (PAGE_SHIFT == 16)
- pa |= FIELD_GET(KVM_PTE_ADDR_51_48, pte) << 48;
+ u64 pa;
+
+ if (kvm_lpa2_is_enabled()) {
+ pa = pte & KVM_PTE_ADDR_MASK_LPA2;
+ pa |= FIELD_GET(KVM_PTE_ADDR_51_50_LPA2, pte) << 50;
+ } else {
+ pa = pte & KVM_PTE_ADDR_MASK;
+ if (PAGE_SHIFT == 16)
+ pa |= FIELD_GET(KVM_PTE_ADDR_51_48, pte) << 48;
+ }
return pa;
}
static inline kvm_pte_t kvm_phys_to_pte(u64 pa)
{
- kvm_pte_t pte = pa & KVM_PTE_ADDR_MASK;
-
- if (PAGE_SHIFT == 16) {
- pa &= GENMASK(51, 48);
- pte |= FIELD_PREP(KVM_PTE_ADDR_51_48, pa >> 48);
+ kvm_pte_t pte;
+
+ if (kvm_lpa2_is_enabled()) {
+ pte = pa & KVM_PTE_ADDR_MASK_LPA2;
+ pa &= GENMASK(51, 50);
+ pte |= FIELD_PREP(KVM_PTE_ADDR_51_50_LPA2, pa >> 50);
+ } else {
+ pte = pa & KVM_PTE_ADDR_MASK;
+ if (PAGE_SHIFT == 16) {
+ pa &= GENMASK(51, 48);
+ pte |= FIELD_PREP(KVM_PTE_ADDR_51_48, pa >> 48);
+ }
}
return pte;
@@ -78,28 +104,28 @@ static inline kvm_pfn_t kvm_pte_to_pfn(kvm_pte_t pte)
return __phys_to_pfn(kvm_pte_to_phys(pte));
}
-static inline u64 kvm_granule_shift(u32 level)
+static inline u64 kvm_granule_shift(s8 level)
{
- /* Assumes KVM_PGTABLE_MAX_LEVELS is 4 */
+ /* Assumes KVM_PGTABLE_LAST_LEVEL is 3 */
return ARM64_HW_PGTABLE_LEVEL_SHIFT(level);
}
-static inline u64 kvm_granule_size(u32 level)
+static inline u64 kvm_granule_size(s8 level)
{
return BIT(kvm_granule_shift(level));
}
-static inline bool kvm_level_supports_block_mapping(u32 level)
+static inline bool kvm_level_supports_block_mapping(s8 level)
{
return level >= KVM_PGTABLE_MIN_BLOCK_LEVEL;
}
static inline u32 kvm_supported_block_sizes(void)
{
- u32 level = KVM_PGTABLE_MIN_BLOCK_LEVEL;
+ s8 level = KVM_PGTABLE_MIN_BLOCK_LEVEL;
u32 r = 0;
- for (; level < KVM_PGTABLE_MAX_LEVELS; level++)
+ for (; level <= KVM_PGTABLE_LAST_LEVEL; level++)
r |= BIT(kvm_granule_shift(level));
return r;
@@ -144,7 +170,7 @@ struct kvm_pgtable_mm_ops {
void* (*zalloc_page)(void *arg);
void* (*zalloc_pages_exact)(size_t size);
void (*free_pages_exact)(void *addr, size_t size);
- void (*free_unlinked_table)(void *addr, u32 level);
+ void (*free_unlinked_table)(void *addr, s8 level);
void (*get_page)(void *addr);
void (*put_page)(void *addr);
int (*page_count)(void *addr);
@@ -240,7 +266,7 @@ struct kvm_pgtable_visit_ctx {
u64 start;
u64 addr;
u64 end;
- u32 level;
+ s8 level;
enum kvm_pgtable_walk_flags flags;
};
@@ -343,7 +369,7 @@ static inline bool kvm_pgtable_walk_lock_held(void)
*/
struct kvm_pgtable {
u32 ia_bits;
- u32 start_level;
+ s8 start_level;
kvm_pteref_t pgd;
struct kvm_pgtable_mm_ops *mm_ops;
@@ -477,7 +503,7 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt);
* The page-table is assumed to be unreachable by any hardware walkers prior to
* freeing and therefore no TLB invalidation is performed.
*/
-void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, u32 level);
+void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level);
/**
* kvm_pgtable_stage2_create_unlinked() - Create an unlinked stage-2 paging structure.
@@ -501,7 +527,7 @@ void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *p
* an ERR_PTR(error) on failure.
*/
kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt,
- u64 phys, u32 level,
+ u64 phys, s8 level,
enum kvm_pgtable_prot prot,
void *mc, bool force_pte);
@@ -727,7 +753,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size,
* Return: 0 on success, negative error code on failure.
*/
int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr,
- kvm_pte_t *ptep, u32 *level);
+ kvm_pte_t *ptep, s8 *level);
/**
* kvm_pgtable_stage2_pte_prot() - Retrieve the protection attributes of a
diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index e46250a02017..ad9cfb5c1ff4 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -56,10 +56,11 @@ static inline unsigned long hyp_vm_table_pages(void)
static inline unsigned long __hyp_pgtable_max_pages(unsigned long nr_pages)
{
- unsigned long total = 0, i;
+ unsigned long total = 0;
+ int i;
/* Provision the worst case scenario */
- for (i = 0; i < KVM_PGTABLE_MAX_LEVELS; i++) {
+ for (i = KVM_PGTABLE_FIRST_LEVEL; i <= KVM_PGTABLE_LAST_LEVEL; i++) {
nr_pages = DIV_ROUND_UP(nr_pages, PTRS_PER_PTE);
total += nr_pages;
}
diff --git a/arch/arm64/include/asm/vncr_mapping.h b/arch/arm64/include/asm/vncr_mapping.h
new file mode 100644
index 000000000000..df2c47c55972
--- /dev/null
+++ b/arch/arm64/include/asm/vncr_mapping.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * System register offsets in the VNCR page
+ * All offsets are *byte* displacements!
+ */
+
+#ifndef __ARM64_VNCR_MAPPING_H__
+#define __ARM64_VNCR_MAPPING_H__
+
+#define VNCR_VTTBR_EL2 0x020
+#define VNCR_VTCR_EL2 0x040
+#define VNCR_VMPIDR_EL2 0x050
+#define VNCR_CNTVOFF_EL2 0x060
+#define VNCR_HCR_EL2 0x078
+#define VNCR_HSTR_EL2 0x080
+#define VNCR_VPIDR_EL2 0x088
+#define VNCR_TPIDR_EL2 0x090
+#define VNCR_HCRX_EL2 0x0A0
+#define VNCR_VNCR_EL2 0x0B0
+#define VNCR_CPACR_EL1 0x100
+#define VNCR_CONTEXTIDR_EL1 0x108
+#define VNCR_SCTLR_EL1 0x110
+#define VNCR_ACTLR_EL1 0x118
+#define VNCR_TCR_EL1 0x120
+#define VNCR_AFSR0_EL1 0x128
+#define VNCR_AFSR1_EL1 0x130
+#define VNCR_ESR_EL1 0x138
+#define VNCR_MAIR_EL1 0x140
+#define VNCR_AMAIR_EL1 0x148
+#define VNCR_MDSCR_EL1 0x158
+#define VNCR_SPSR_EL1 0x160
+#define VNCR_CNTV_CVAL_EL0 0x168
+#define VNCR_CNTV_CTL_EL0 0x170
+#define VNCR_CNTP_CVAL_EL0 0x178
+#define VNCR_CNTP_CTL_EL0 0x180
+#define VNCR_SCXTNUM_EL1 0x188
+#define VNCR_TFSR_EL1 0x190
+#define VNCR_HFGRTR_EL2 0x1B8
+#define VNCR_HFGWTR_EL2 0x1C0
+#define VNCR_HFGITR_EL2 0x1C8
+#define VNCR_HDFGRTR_EL2 0x1D0
+#define VNCR_HDFGWTR_EL2 0x1D8
+#define VNCR_ZCR_EL1 0x1E0
+#define VNCR_HAFGRTR_EL2 0x1E8
+#define VNCR_TTBR0_EL1 0x200
+#define VNCR_TTBR1_EL1 0x210
+#define VNCR_FAR_EL1 0x220
+#define VNCR_ELR_EL1 0x230
+#define VNCR_SP_EL1 0x240
+#define VNCR_VBAR_EL1 0x250
+#define VNCR_TCR2_EL1 0x270
+#define VNCR_PIRE0_EL1 0x290
+#define VNCR_PIRE0_EL2 0x298
+#define VNCR_PIR_EL1 0x2A0
+#define VNCR_ICH_LR0_EL2 0x400
+#define VNCR_ICH_LR1_EL2 0x408
+#define VNCR_ICH_LR2_EL2 0x410
+#define VNCR_ICH_LR3_EL2 0x418
+#define VNCR_ICH_LR4_EL2 0x420
+#define VNCR_ICH_LR5_EL2 0x428
+#define VNCR_ICH_LR6_EL2 0x430
+#define VNCR_ICH_LR7_EL2 0x438
+#define VNCR_ICH_LR8_EL2 0x440
+#define VNCR_ICH_LR9_EL2 0x448
+#define VNCR_ICH_LR10_EL2 0x450
+#define VNCR_ICH_LR11_EL2 0x458
+#define VNCR_ICH_LR12_EL2 0x460
+#define VNCR_ICH_LR13_EL2 0x468
+#define VNCR_ICH_LR14_EL2 0x470
+#define VNCR_ICH_LR15_EL2 0x478
+#define VNCR_ICH_AP0R0_EL2 0x480
+#define VNCR_ICH_AP0R1_EL2 0x488
+#define VNCR_ICH_AP0R2_EL2 0x490
+#define VNCR_ICH_AP0R3_EL2 0x498
+#define VNCR_ICH_AP1R0_EL2 0x4A0
+#define VNCR_ICH_AP1R1_EL2 0x4A8
+#define VNCR_ICH_AP1R2_EL2 0x4B0
+#define VNCR_ICH_AP1R3_EL2 0x4B8
+#define VNCR_ICH_HCR_EL2 0x4C0
+#define VNCR_ICH_VMCR_EL2 0x4C8
+#define VNCR_VDISR_EL2 0x500
+#define VNCR_PMBLIMITR_EL1 0x800
+#define VNCR_PMBPTR_EL1 0x810
+#define VNCR_PMBSR_EL1 0x820
+#define VNCR_PMSCR_EL1 0x828
+#define VNCR_PMSEVFR_EL1 0x830
+#define VNCR_PMSICR_EL1 0x838
+#define VNCR_PMSIRR_EL1 0x840
+#define VNCR_PMSLATFR_EL1 0x848
+#define VNCR_TRFCR_EL1 0x880
+#define VNCR_MPAM1_EL1 0x900
+#define VNCR_MPAMHCR_EL2 0x930
+#define VNCR_MPAMVPMV_EL2 0x938
+#define VNCR_MPAMVPM0_EL2 0x940
+#define VNCR_MPAMVPM1_EL2 0x948
+#define VNCR_MPAMVPM2_EL2 0x950
+#define VNCR_MPAMVPM3_EL2 0x958
+#define VNCR_MPAMVPM4_EL2 0x960
+#define VNCR_MPAMVPM5_EL2 0x968
+#define VNCR_MPAMVPM6_EL2 0x970
+#define VNCR_MPAMVPM7_EL2 0x978
+
+#endif /* __ARM64_VNCR_MAPPING_H__ */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 01a4c1d7fc09..8d1a634a403e 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -2341,7 +2341,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
.capability = ARM64_HAS_NESTED_VIRT,
.type = ARM64_CPUCAP_SYSTEM_FEATURE,
.matches = has_nested_virt_support,
- ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, NV, IMP)
+ ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, NV, NV2)
},
{
.capability = ARM64_HAS_32BIT_EL0_DO_NOT_USE,
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 417a8a86b2db..42c690bb2d60 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -402,19 +402,10 @@ static inline bool cpu_can_disable(unsigned int cpu)
return false;
}
-static int __init topology_init(void)
+bool arch_cpu_is_hotpluggable(int num)
{
- int i;
-
- for_each_possible_cpu(i) {
- struct cpu *cpu = &per_cpu(cpu_data.cpu, i);
- cpu->hotpluggable = cpu_can_disable(i);
- register_cpu(cpu, i);
- }
-
- return 0;
+ return cpu_can_disable(num);
}
-subsys_initcall(topology_init);
static void dump_kernel_offset(void)
{
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index 83c1e09be42e..6c3c8ca73e7f 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -21,16 +21,14 @@ if VIRTUALIZATION
menuconfig KVM
bool "Kernel-based Virtual Machine (KVM) support"
depends on HAVE_KVM
+ select KVM_COMMON
select KVM_GENERIC_HARDWARE_ENABLING
- select MMU_NOTIFIER
- select PREEMPT_NOTIFIERS
+ select KVM_GENERIC_MMU_NOTIFIER
select HAVE_KVM_CPU_RELAX_INTERCEPT
select KVM_MMIO
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
select KVM_XFER_TO_GUEST_WORK
select KVM_VFIO
- select HAVE_KVM_EVENTFD
- select HAVE_KVM_IRQFD
select HAVE_KVM_DIRTY_RING_ACQ_REL
select NEED_KVM_DIRTY_RING_WITH_BITMAP
select HAVE_KVM_MSI
@@ -41,7 +39,6 @@ menuconfig KVM
select HAVE_KVM_VCPU_RUN_PID_CHANGE
select SCHED_INFO
select GUEST_PERF_EVENTS if PERF_EVENTS
- select INTERVAL_TREE
select XARRAY_MULTI
help
Support hosting virtualized guest machines.
diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 13ba691b848f..9dec8c419bf4 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -295,8 +295,7 @@ static u64 wfit_delay_ns(struct kvm_vcpu *vcpu)
u64 val = vcpu_get_reg(vcpu, kvm_vcpu_sys_get_rt(vcpu));
struct arch_timer_context *ctx;
- ctx = (vcpu_has_nv(vcpu) && is_hyp_ctxt(vcpu)) ? vcpu_hvtimer(vcpu)
- : vcpu_vtimer(vcpu);
+ ctx = is_hyp_ctxt(vcpu) ? vcpu_hvtimer(vcpu) : vcpu_vtimer(vcpu);
return kvm_counter_compute_delta(ctx, val);
}
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 4796104c4471..a25265aca432 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -221,7 +221,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
r = vgic_present;
break;
case KVM_CAP_IOEVENTFD:
- case KVM_CAP_DEVICE_CTRL:
case KVM_CAP_USER_MEMORY:
case KVM_CAP_SYNC_MMU:
case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
@@ -669,6 +668,12 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu)
return ret;
}
+ if (vcpu_has_nv(vcpu)) {
+ ret = kvm_init_nv_sysregs(vcpu->kvm);
+ if (ret)
+ return ret;
+ }
+
ret = kvm_timer_enable(vcpu);
if (ret)
return ret;
@@ -1837,6 +1842,7 @@ static int kvm_init_vector_slots(void)
static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
{
struct kvm_nvhe_init_params *params = per_cpu_ptr_nvhe_sym(kvm_init_params, cpu);
+ u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
unsigned long tcr;
/*
@@ -1859,6 +1865,10 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
}
tcr &= ~TCR_T0SZ_MASK;
tcr |= TCR_T0SZ(hyp_va_bits);
+ tcr &= ~TCR_EL2_PS_MASK;
+ tcr |= FIELD_PREP(TCR_EL2_PS_MASK, kvm_get_parange(mmfr0));
+ if (kvm_lpa2_is_enabled())
+ tcr |= TCR_EL2_DS;
params->tcr_el2 = tcr;
params->pgd_pa = kvm_mmu_get_httbr();
diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c
index 06185216a297..431fd429932d 100644
--- a/arch/arm64/kvm/emulate-nested.c
+++ b/arch/arm64/kvm/emulate-nested.c
@@ -1012,6 +1012,7 @@ enum fgt_group_id {
HDFGRTR_GROUP,
HDFGWTR_GROUP,
HFGITR_GROUP,
+ HAFGRTR_GROUP,
/* Must be last */
__NR_FGT_GROUP_IDS__
@@ -1042,10 +1043,20 @@ enum fg_filter_id {
static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
/* HFGRTR_EL2, HFGWTR_EL2 */
+ SR_FGT(SYS_AMAIR2_EL1, HFGxTR, nAMAIR2_EL1, 0),
+ SR_FGT(SYS_MAIR2_EL1, HFGxTR, nMAIR2_EL1, 0),
+ SR_FGT(SYS_S2POR_EL1, HFGxTR, nS2POR_EL1, 0),
+ SR_FGT(SYS_POR_EL1, HFGxTR, nPOR_EL1, 0),
+ SR_FGT(SYS_POR_EL0, HFGxTR, nPOR_EL0, 0),
SR_FGT(SYS_PIR_EL1, HFGxTR, nPIR_EL1, 0),
SR_FGT(SYS_PIRE0_EL1, HFGxTR, nPIRE0_EL1, 0),
+ SR_FGT(SYS_RCWMASK_EL1, HFGxTR, nRCWMASK_EL1, 0),
SR_FGT(SYS_TPIDR2_EL0, HFGxTR, nTPIDR2_EL0, 0),
SR_FGT(SYS_SMPRI_EL1, HFGxTR, nSMPRI_EL1, 0),
+ SR_FGT(SYS_GCSCR_EL1, HFGxTR, nGCS_EL1, 0),
+ SR_FGT(SYS_GCSPR_EL1, HFGxTR, nGCS_EL1, 0),
+ SR_FGT(SYS_GCSCRE0_EL1, HFGxTR, nGCS_EL0, 0),
+ SR_FGT(SYS_GCSPR_EL0, HFGxTR, nGCS_EL0, 0),
SR_FGT(SYS_ACCDATA_EL1, HFGxTR, nACCDATA_EL1, 0),
SR_FGT(SYS_ERXADDR_EL1, HFGxTR, ERXADDR_EL1, 1),
SR_FGT(SYS_ERXPFGCDN_EL1, HFGxTR, ERXPFGCDN_EL1, 1),
@@ -1107,6 +1118,11 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
SR_FGT(SYS_AFSR1_EL1, HFGxTR, AFSR1_EL1, 1),
SR_FGT(SYS_AFSR0_EL1, HFGxTR, AFSR0_EL1, 1),
/* HFGITR_EL2 */
+ SR_FGT(OP_AT_S1E1A, HFGITR, ATS1E1A, 1),
+ SR_FGT(OP_COSP_RCTX, HFGITR, COSPRCTX, 1),
+ SR_FGT(OP_GCSPUSHX, HFGITR, nGCSEPP, 0),
+ SR_FGT(OP_GCSPOPX, HFGITR, nGCSEPP, 0),
+ SR_FGT(OP_GCSPUSHM, HFGITR, nGCSPUSHM_EL1, 0),
SR_FGT(OP_BRB_IALL, HFGITR, nBRBIALL, 0),
SR_FGT(OP_BRB_INJ, HFGITR, nBRBINJ, 0),
SR_FGT(SYS_DC_CVAC, HFGITR, DCCVAC, 1),
@@ -1674,6 +1690,49 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = {
SR_FGT(SYS_PMCR_EL0, HDFGWTR, PMCR_EL0, 1),
SR_FGT(SYS_PMSWINC_EL0, HDFGWTR, PMSWINC_EL0, 1),
SR_FGT(SYS_OSLAR_EL1, HDFGWTR, OSLAR_EL1, 1),
+ /*
+ * HAFGRTR_EL2
+ */
+ SR_FGT(SYS_AMEVTYPER1_EL0(15), HAFGRTR, AMEVTYPER115_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(14), HAFGRTR, AMEVTYPER114_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(13), HAFGRTR, AMEVTYPER113_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(12), HAFGRTR, AMEVTYPER112_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(11), HAFGRTR, AMEVTYPER111_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(10), HAFGRTR, AMEVTYPER110_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(9), HAFGRTR, AMEVTYPER19_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(8), HAFGRTR, AMEVTYPER18_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(7), HAFGRTR, AMEVTYPER17_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(6), HAFGRTR, AMEVTYPER16_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(5), HAFGRTR, AMEVTYPER15_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(4), HAFGRTR, AMEVTYPER14_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(3), HAFGRTR, AMEVTYPER13_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(2), HAFGRTR, AMEVTYPER12_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(1), HAFGRTR, AMEVTYPER11_EL0, 1),
+ SR_FGT(SYS_AMEVTYPER1_EL0(0), HAFGRTR, AMEVTYPER10_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(15), HAFGRTR, AMEVCNTR115_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(14), HAFGRTR, AMEVCNTR114_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(13), HAFGRTR, AMEVCNTR113_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(12), HAFGRTR, AMEVCNTR112_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(11), HAFGRTR, AMEVCNTR111_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(10), HAFGRTR, AMEVCNTR110_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(9), HAFGRTR, AMEVCNTR19_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(8), HAFGRTR, AMEVCNTR18_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(7), HAFGRTR, AMEVCNTR17_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(6), HAFGRTR, AMEVCNTR16_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(5), HAFGRTR, AMEVCNTR15_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(4), HAFGRTR, AMEVCNTR14_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(3), HAFGRTR, AMEVCNTR13_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(2), HAFGRTR, AMEVCNTR12_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(1), HAFGRTR, AMEVCNTR11_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR1_EL0(0), HAFGRTR, AMEVCNTR10_EL0, 1),
+ SR_FGT(SYS_AMCNTENCLR1_EL0, HAFGRTR, AMCNTEN1, 1),
+ SR_FGT(SYS_AMCNTENSET1_EL0, HAFGRTR, AMCNTEN1, 1),
+ SR_FGT(SYS_AMCNTENCLR0_EL0, HAFGRTR, AMCNTEN0, 1),
+ SR_FGT(SYS_AMCNTENSET0_EL0, HAFGRTR, AMCNTEN0, 1),
+ SR_FGT(SYS_AMEVCNTR0_EL0(3), HAFGRTR, AMEVCNTR03_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR0_EL0(2), HAFGRTR, AMEVCNTR02_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR0_EL0(1), HAFGRTR, AMEVCNTR01_EL0, 1),
+ SR_FGT(SYS_AMEVCNTR0_EL0(0), HAFGRTR, AMEVCNTR00_EL0, 1),
};
static union trap_config get_trap_config(u32 sysreg)
@@ -1894,6 +1953,10 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu)
val = sanitised_sys_reg(vcpu, HDFGWTR_EL2);
break;
+ case HAFGRTR_GROUP:
+ val = sanitised_sys_reg(vcpu, HAFGRTR_EL2);
+ break;
+
case HFGITR_GROUP:
val = sanitised_sys_reg(vcpu, HFGITR_EL2);
switch (tc.fgf) {
diff --git a/arch/arm64/kvm/hyp/include/hyp/fault.h b/arch/arm64/kvm/hyp/include/hyp/fault.h
index 9ddcfe2c3e57..9e13c1bc2ad5 100644
--- a/arch/arm64/kvm/hyp/include/hyp/fault.h
+++ b/arch/arm64/kvm/hyp/include/hyp/fault.h
@@ -60,7 +60,7 @@ static inline bool __get_fault_info(u64 esr, struct kvm_vcpu_fault_info *fault)
*/
if (!(esr & ESR_ELx_S1PTW) &&
(cpus_have_final_cap(ARM64_WORKAROUND_834220) ||
- (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM)) {
+ esr_fsc_is_permission_fault(esr))) {
if (!__translate_far_to_hpfar(far, &hpfar))
return false;
} else {
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index f99d8af0b9af..a038320cdb08 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -79,6 +79,45 @@ static inline void __activate_traps_fpsimd32(struct kvm_vcpu *vcpu)
clr |= ~hfg & __ ## reg ## _nMASK; \
} while(0)
+#define update_fgt_traps_cs(vcpu, reg, clr, set) \
+ do { \
+ struct kvm_cpu_context *hctxt = \
+ &this_cpu_ptr(&kvm_host_data)->host_ctxt; \
+ u64 c = 0, s = 0; \
+ \
+ ctxt_sys_reg(hctxt, reg) = read_sysreg_s(SYS_ ## reg); \
+ compute_clr_set(vcpu, reg, c, s); \
+ s |= set; \
+ c |= clr; \
+ if (c || s) { \
+ u64 val = __ ## reg ## _nMASK; \
+ val |= s; \
+ val &= ~c; \
+ write_sysreg_s(val, SYS_ ## reg); \
+ } \
+ } while(0)
+
+#define update_fgt_traps(vcpu, reg) \
+ update_fgt_traps_cs(vcpu, reg, 0, 0)
+
+/*
+ * Validate the fine grain trap masks.
+ * Check that the masks do not overlap and that all bits are accounted for.
+ */
+#define CHECK_FGT_MASKS(reg) \
+ do { \
+ BUILD_BUG_ON((__ ## reg ## _MASK) & (__ ## reg ## _nMASK)); \
+ BUILD_BUG_ON(~((__ ## reg ## _RES0) ^ (__ ## reg ## _MASK) ^ \
+ (__ ## reg ## _nMASK))); \
+ } while(0)
+
+static inline bool cpu_has_amu(void)
+{
+ u64 pfr0 = read_sysreg_s(SYS_ID_AA64PFR0_EL1);
+
+ return cpuid_feature_extract_unsigned_field(pfr0,
+ ID_AA64PFR0_EL1_AMU_SHIFT);
+}
static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
{
@@ -86,6 +125,14 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
u64 r_clr = 0, w_clr = 0, r_set = 0, w_set = 0, tmp;
u64 r_val, w_val;
+ CHECK_FGT_MASKS(HFGRTR_EL2);
+ CHECK_FGT_MASKS(HFGWTR_EL2);
+ CHECK_FGT_MASKS(HFGITR_EL2);
+ CHECK_FGT_MASKS(HDFGRTR_EL2);
+ CHECK_FGT_MASKS(HDFGWTR_EL2);
+ CHECK_FGT_MASKS(HAFGRTR_EL2);
+ CHECK_FGT_MASKS(HCRX_EL2);
+
if (!cpus_have_final_cap(ARM64_HAS_FGT))
return;
@@ -110,12 +157,15 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
compute_clr_set(vcpu, HFGWTR_EL2, w_clr, w_set);
}
- /* The default is not to trap anything but ACCDATA_EL1 */
- r_val = __HFGRTR_EL2_nMASK & ~HFGxTR_EL2_nACCDATA_EL1;
+ /* The default to trap everything not handled or supported in KVM. */
+ tmp = HFGxTR_EL2_nAMAIR2_EL1 | HFGxTR_EL2_nMAIR2_EL1 | HFGxTR_EL2_nS2POR_EL1 |
+ HFGxTR_EL2_nPOR_EL1 | HFGxTR_EL2_nPOR_EL0 | HFGxTR_EL2_nACCDATA_EL1;
+
+ r_val = __HFGRTR_EL2_nMASK & ~tmp;
r_val |= r_set;
r_val &= ~r_clr;
- w_val = __HFGWTR_EL2_nMASK & ~HFGxTR_EL2_nACCDATA_EL1;
+ w_val = __HFGWTR_EL2_nMASK & ~tmp;
w_val |= w_set;
w_val &= ~w_clr;
@@ -125,34 +175,12 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu)
if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu))
return;
- ctxt_sys_reg(hctxt, HFGITR_EL2) = read_sysreg_s(SYS_HFGITR_EL2);
+ update_fgt_traps(vcpu, HFGITR_EL2);
+ update_fgt_traps(vcpu, HDFGRTR_EL2);
+ update_fgt_traps(vcpu, HDFGWTR_EL2);
- r_set = r_clr = 0;
- compute_clr_set(vcpu, HFGITR_EL2, r_clr, r_set);
- r_val = __HFGITR_EL2_nMASK;
- r_val |= r_set;
- r_val &= ~r_clr;
-
- write_sysreg_s(r_val, SYS_HFGITR_EL2);
-
- ctxt_sys_reg(hctxt, HDFGRTR_EL2) = read_sysreg_s(SYS_HDFGRTR_EL2);
- ctxt_sys_reg(hctxt, HDFGWTR_EL2) = read_sysreg_s(SYS_HDFGWTR_EL2);
-
- r_clr = r_set = w_clr = w_set = 0;
-
- compute_clr_set(vcpu, HDFGRTR_EL2, r_clr, r_set);
- compute_clr_set(vcpu, HDFGWTR_EL2, w_clr, w_set);
-
- r_val = __HDFGRTR_EL2_nMASK;
- r_val |= r_set;
- r_val &= ~r_clr;
-
- w_val = __HDFGWTR_EL2_nMASK;
- w_val |= w_set;
- w_val &= ~w_clr;
-
- write_sysreg_s(r_val, SYS_HDFGRTR_EL2);
- write_sysreg_s(w_val, SYS_HDFGWTR_EL2);
+ if (cpu_has_amu())
+ update_fgt_traps(vcpu, HAFGRTR_EL2);
}
static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu)
@@ -171,6 +199,9 @@ static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu)
write_sysreg_s(ctxt_sys_reg(hctxt, HFGITR_EL2), SYS_HFGITR_EL2);
write_sysreg_s(ctxt_sys_reg(hctxt, HDFGRTR_EL2), SYS_HDFGRTR_EL2);
write_sysreg_s(ctxt_sys_reg(hctxt, HDFGWTR_EL2), SYS_HDFGWTR_EL2);
+
+ if (cpu_has_amu())
+ write_sysreg_s(ctxt_sys_reg(hctxt, HAFGRTR_EL2), SYS_HAFGRTR_EL2);
}
static inline void __activate_traps_common(struct kvm_vcpu *vcpu)
@@ -591,7 +622,7 @@ static bool kvm_hyp_handle_dabt_low(struct kvm_vcpu *vcpu, u64 *exit_code)
if (static_branch_unlikely(&vgic_v2_cpuif_trap)) {
bool valid;
- valid = kvm_vcpu_trap_get_fault_type(vcpu) == ESR_ELx_FSC_FAULT &&
+ valid = kvm_vcpu_trap_is_translation_fault(vcpu) &&
kvm_vcpu_dabt_isvalid(vcpu) &&
!kvm_vcpu_abt_issea(vcpu) &&
!kvm_vcpu_abt_iss1tw(vcpu);
diff --git a/arch/arm64/kvm/hyp/include/nvhe/fixed_config.h b/arch/arm64/kvm/hyp/include/nvhe/fixed_config.h
index e91922daa8ca..51f043649146 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/fixed_config.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/fixed_config.h
@@ -69,6 +69,8 @@
ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SSBS) \
)
+#define PVM_ID_AA64PFR2_ALLOW 0ULL
+
/*
* Allow for protected VMs:
* - Mixed-endian
@@ -101,6 +103,7 @@
* - Privileged Access Never
* - SError interrupt exceptions from speculative reads
* - Enhanced Translation Synchronization
+ * - Control for cache maintenance permission
*/
#define PVM_ID_AA64MMFR1_ALLOW (\
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_HAFDBS) | \
@@ -108,7 +111,8 @@
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_HPDS) | \
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_PAN) | \
ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_SpecSEI) | \
- ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_ETS) \
+ ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_ETS) | \
+ ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_CMOW) \
)
/*
@@ -133,6 +137,8 @@
ARM64_FEATURE_MASK(ID_AA64MMFR2_EL1_E0PD) \
)
+#define PVM_ID_AA64MMFR3_ALLOW (0ULL)
+
/*
* No support for Scalable Vectors for protected VMs:
* Requires additional support from KVM, e.g., context-switching and
@@ -178,10 +184,18 @@
ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_RNDR) \
)
+/* Restrict pointer authentication to the basic version. */
+#define PVM_ID_AA64ISAR1_RESTRICT_UNSIGNED (\
+ FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA), ID_AA64ISAR1_EL1_APA_PAuth) | \
+ FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API), ID_AA64ISAR1_EL1_API_PAuth) \
+ )
+
+#define PVM_ID_AA64ISAR2_RESTRICT_UNSIGNED (\
+ FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3), ID_AA64ISAR2_EL1_APA3_PAuth) \
+ )
+
#define PVM_ID_AA64ISAR1_ALLOW (\
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_DPB) | \
- ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA) | \
- ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API) | \
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_JSCVT) | \
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_FCMA) | \
ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_LRCPC) | \
@@ -196,8 +210,8 @@
)
#define PVM_ID_AA64ISAR2_ALLOW (\
+ ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_ATS1A)| \
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3) | \
- ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) | \
ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_MOPS) \
)
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
index 1cc06e6797bd..2994878d68ea 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
@@ -122,11 +122,7 @@ alternative_if ARM64_HAS_CNP
alternative_else_nop_endif
msr ttbr0_el2, x2
- /*
- * Set the PS bits in TCR_EL2.
- */
ldr x0, [x0, #NVHE_INIT_TCR_EL2]
- tcr_compute_pa_size x0, #TCR_EL2_PS_SHIFT, x1, x2
msr tcr_el2, x0
isb
@@ -292,6 +288,8 @@ alternative_else_nop_endif
mov sp, x0
/* And turn the MMU back on! */
+ dsb nsh
+ isb
set_sctlr_el2 x2
ret x1
SYM_FUNC_END(__pkvm_init_switch_pgd)
diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
index 8d0a5834e883..861c76021a25 100644
--- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c
+++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
@@ -91,7 +91,7 @@ static void host_s2_put_page(void *addr)
hyp_put_page(&host_s2_pool, addr);
}
-static void host_s2_free_unlinked_table(void *addr, u32 level)
+static void host_s2_free_unlinked_table(void *addr, s8 level)
{
kvm_pgtable_stage2_free_unlinked(&host_mmu.mm_ops, addr, level);
}
@@ -443,7 +443,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
{
struct kvm_mem_range cur;
kvm_pte_t pte;
- u32 level;
+ s8 level;
int ret;
hyp_assert_lock_held(&host_mmu.lock);
@@ -462,7 +462,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
cur.start = ALIGN_DOWN(addr, granule);
cur.end = cur.start + granule;
level++;
- } while ((level < KVM_PGTABLE_MAX_LEVELS) &&
+ } while ((level <= KVM_PGTABLE_LAST_LEVEL) &&
!(kvm_level_supports_block_mapping(level) &&
range_included(&cur, range)));
diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c
index 65a7a186d7b2..b01a3d1078a8 100644
--- a/arch/arm64/kvm/hyp/nvhe/mm.c
+++ b/arch/arm64/kvm/hyp/nvhe/mm.c
@@ -260,7 +260,7 @@ static void fixmap_clear_slot(struct hyp_fixmap_slot *slot)
* https://lore.kernel.org/kvm/[email protected]/T/#mf10dfbaf1eaef9274c581b81c53758918c1d0f03
*/
dsb(ishst);
- __tlbi_level(vale2is, __TLBI_VADDR(addr, 0), (KVM_PGTABLE_MAX_LEVELS - 1));
+ __tlbi_level(vale2is, __TLBI_VADDR(addr, 0), KVM_PGTABLE_LAST_LEVEL);
dsb(ish);
isb();
}
@@ -275,7 +275,7 @@ static int __create_fixmap_slot_cb(const struct kvm_pgtable_visit_ctx *ctx,
{
struct hyp_fixmap_slot *slot = per_cpu_ptr(&fixmap_slots, (u64)ctx->arg);
- if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_MAX_LEVELS - 1)
+ if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_LAST_LEVEL)
return -EINVAL;
slot->addr = ctx->addr;
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index b29f15418c0a..26dd9a20ad6e 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -136,6 +136,10 @@ static void pvm_init_traps_aa64dfr0(struct kvm_vcpu *vcpu)
cptr_set |= CPTR_EL2_TTA;
}
+ /* Trap External Trace */
+ if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_ExtTrcBuff), feature_ids))
+ mdcr_clear |= MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT;
+
vcpu->arch.mdcr_el2 |= mdcr_set;
vcpu->arch.mdcr_el2 &= ~mdcr_clear;
vcpu->arch.cptr_el2 |= cptr_set;
diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c
index 0d5e0a89ddce..bc58d1b515af 100644
--- a/arch/arm64/kvm/hyp/nvhe/setup.c
+++ b/arch/arm64/kvm/hyp/nvhe/setup.c
@@ -181,7 +181,7 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
if (!kvm_pte_valid(ctx->old))
return 0;
- if (ctx->level != (KVM_PGTABLE_MAX_LEVELS - 1))
+ if (ctx->level != KVM_PGTABLE_LAST_LEVEL)
return -EINVAL;
phys = kvm_pte_to_phys(ctx->old);
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index 1966fdee740e..c651df904fe3 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -79,7 +79,10 @@ static bool kvm_pgtable_walk_skip_cmo(const struct kvm_pgtable_visit_ctx *ctx)
static bool kvm_phys_is_valid(u64 phys)
{
- return phys < BIT(id_aa64mmfr0_parange_to_phys_shift(ID_AA64MMFR0_EL1_PARANGE_MAX));
+ u64 parange_max = kvm_get_parange_max();
+ u8 shift = id_aa64mmfr0_parange_to_phys_shift(parange_max);
+
+ return phys < BIT(shift);
}
static bool kvm_block_mapping_supported(const struct kvm_pgtable_visit_ctx *ctx, u64 phys)
@@ -98,7 +101,7 @@ static bool kvm_block_mapping_supported(const struct kvm_pgtable_visit_ctx *ctx,
return IS_ALIGNED(ctx->addr, granule);
}
-static u32 kvm_pgtable_idx(struct kvm_pgtable_walk_data *data, u32 level)
+static u32 kvm_pgtable_idx(struct kvm_pgtable_walk_data *data, s8 level)
{
u64 shift = kvm_granule_shift(level);
u64 mask = BIT(PAGE_SHIFT - 3) - 1;
@@ -114,7 +117,7 @@ static u32 kvm_pgd_page_idx(struct kvm_pgtable *pgt, u64 addr)
return (addr & mask) >> shift;
}
-static u32 kvm_pgd_pages(u32 ia_bits, u32 start_level)
+static u32 kvm_pgd_pages(u32 ia_bits, s8 start_level)
{
struct kvm_pgtable pgt = {
.ia_bits = ia_bits,
@@ -124,9 +127,9 @@ static u32 kvm_pgd_pages(u32 ia_bits, u32 start_level)
return kvm_pgd_page_idx(&pgt, -1ULL) + 1;
}
-static bool kvm_pte_table(kvm_pte_t pte, u32 level)
+static bool kvm_pte_table(kvm_pte_t pte, s8 level)
{
- if (level == KVM_PGTABLE_MAX_LEVELS - 1)
+ if (level == KVM_PGTABLE_LAST_LEVEL)
return false;
if (!kvm_pte_valid(pte))
@@ -154,11 +157,11 @@ static kvm_pte_t kvm_init_table_pte(kvm_pte_t *childp, struct kvm_pgtable_mm_ops
return pte;
}
-static kvm_pte_t kvm_init_valid_leaf_pte(u64 pa, kvm_pte_t attr, u32 level)
+static kvm_pte_t kvm_init_valid_leaf_pte(u64 pa, kvm_pte_t attr, s8 level)
{
kvm_pte_t pte = kvm_phys_to_pte(pa);
- u64 type = (level == KVM_PGTABLE_MAX_LEVELS - 1) ? KVM_PTE_TYPE_PAGE :
- KVM_PTE_TYPE_BLOCK;
+ u64 type = (level == KVM_PGTABLE_LAST_LEVEL) ? KVM_PTE_TYPE_PAGE :
+ KVM_PTE_TYPE_BLOCK;
pte |= attr & (KVM_PTE_LEAF_ATTR_LO | KVM_PTE_LEAF_ATTR_HI);
pte |= FIELD_PREP(KVM_PTE_TYPE, type);
@@ -203,11 +206,11 @@ static bool kvm_pgtable_walk_continue(const struct kvm_pgtable_walker *walker,
}
static int __kvm_pgtable_walk(struct kvm_pgtable_walk_data *data,
- struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, u32 level);
+ struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, s8 level);
static inline int __kvm_pgtable_visit(struct kvm_pgtable_walk_data *data,
struct kvm_pgtable_mm_ops *mm_ops,
- kvm_pteref_t pteref, u32 level)
+ kvm_pteref_t pteref, s8 level)
{
enum kvm_pgtable_walk_flags flags = data->walker->flags;
kvm_pte_t *ptep = kvm_dereference_pteref(data->walker, pteref);
@@ -272,12 +275,13 @@ out:
}
static int __kvm_pgtable_walk(struct kvm_pgtable_walk_data *data,
- struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, u32 level)
+ struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, s8 level)
{
u32 idx;
int ret = 0;
- if (WARN_ON_ONCE(level >= KVM_PGTABLE_MAX_LEVELS))
+ if (WARN_ON_ONCE(level < KVM_PGTABLE_FIRST_LEVEL ||
+ level > KVM_PGTABLE_LAST_LEVEL))
return -EINVAL;
for (idx = kvm_pgtable_idx(data, level); idx < PTRS_PER_PTE; ++idx) {
@@ -340,7 +344,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size,
struct leaf_walk_data {
kvm_pte_t pte;
- u32 level;
+ s8 level;
};
static int leaf_walker(const struct kvm_pgtable_visit_ctx *ctx,
@@ -355,7 +359,7 @@ static int leaf_walker(const struct kvm_pgtable_visit_ctx *ctx,
}
int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr,
- kvm_pte_t *ptep, u32 *level)
+ kvm_pte_t *ptep, s8 *level)
{
struct leaf_walk_data data;
struct kvm_pgtable_walker walker = {
@@ -408,7 +412,8 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep)
}
attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_AP, ap);
- attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh);
+ if (!kvm_lpa2_is_enabled())
+ attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh);
attr |= KVM_PTE_LEAF_ATTR_LO_S1_AF;
attr |= prot & KVM_PTE_LEAF_ATTR_HI_SW;
*ptep = attr;
@@ -467,7 +472,7 @@ static int hyp_map_walker(const struct kvm_pgtable_visit_ctx *ctx,
if (hyp_map_walker_try_leaf(ctx, data))
return 0;
- if (WARN_ON(ctx->level == KVM_PGTABLE_MAX_LEVELS - 1))
+ if (WARN_ON(ctx->level == KVM_PGTABLE_LAST_LEVEL))
return -EINVAL;
childp = (kvm_pte_t *)mm_ops->zalloc_page(NULL);
@@ -563,14 +568,19 @@ u64 kvm_pgtable_hyp_unmap(struct kvm_pgtable *pgt, u64 addr, u64 size)
int kvm_pgtable_hyp_init(struct kvm_pgtable *pgt, u32 va_bits,
struct kvm_pgtable_mm_ops *mm_ops)
{
- u64 levels = ARM64_HW_PGTABLE_LEVELS(va_bits);
+ s8 start_level = KVM_PGTABLE_LAST_LEVEL + 1 -
+ ARM64_HW_PGTABLE_LEVELS(va_bits);
+
+ if (start_level < KVM_PGTABLE_FIRST_LEVEL ||
+ start_level > KVM_PGTABLE_LAST_LEVEL)
+ return -EINVAL;
pgt->pgd = (kvm_pteref_t)mm_ops->zalloc_page(NULL);
if (!pgt->pgd)
return -ENOMEM;
pgt->ia_bits = va_bits;
- pgt->start_level = KVM_PGTABLE_MAX_LEVELS - levels;
+ pgt->start_level = start_level;
pgt->mm_ops = mm_ops;
pgt->mmu = NULL;
pgt->force_pte_cb = NULL;
@@ -624,7 +634,7 @@ struct stage2_map_data {
u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
{
u64 vtcr = VTCR_EL2_FLAGS;
- u8 lvls;
+ s8 lvls;
vtcr |= kvm_get_parange(mmfr0) << VTCR_EL2_PS_SHIFT;
vtcr |= VTCR_EL2_T0SZ(phys_shift);
@@ -635,6 +645,15 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
lvls = stage2_pgtable_levels(phys_shift);
if (lvls < 2)
lvls = 2;
+
+ /*
+ * When LPA2 is enabled, the HW supports an extra level of translation
+ * (for 5 in total) when using 4K pages. It also introduces VTCR_EL2.SL2
+ * to as an addition to SL0 to enable encoding this extra start level.
+ * However, since we always use concatenated pages for the first level
+ * lookup, we will never need this extra level and therefore do not need
+ * to touch SL2.
+ */
vtcr |= VTCR_EL2_LVLS_TO_SL0(lvls);
#ifdef CONFIG_ARM64_HW_AFDBM
@@ -654,6 +673,9 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
vtcr |= VTCR_EL2_HA;
#endif /* CONFIG_ARM64_HW_AFDBM */
+ if (kvm_lpa2_is_enabled())
+ vtcr |= VTCR_EL2_DS;
+
/* Set the vmid bits */
vtcr |= (get_vmid_bits(mmfr1) == 16) ?
VTCR_EL2_VS_16BIT :
@@ -711,7 +733,9 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p
if (prot & KVM_PGTABLE_PROT_W)
attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W;
- attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);
+ if (!kvm_lpa2_is_enabled())
+ attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh);
+
attr |= KVM_PTE_LEAF_ATTR_LO_S2_AF;
attr |= prot & KVM_PTE_LEAF_ATTR_HI_SW;
*ptep = attr;
@@ -902,7 +926,7 @@ static bool stage2_leaf_mapping_allowed(const struct kvm_pgtable_visit_ctx *ctx,
{
u64 phys = stage2_map_walker_phys_addr(ctx, data);
- if (data->force_pte && (ctx->level < (KVM_PGTABLE_MAX_LEVELS - 1)))
+ if (data->force_pte && ctx->level < KVM_PGTABLE_LAST_LEVEL)
return false;
return kvm_block_mapping_supported(ctx, phys);
@@ -981,7 +1005,7 @@ static int stage2_map_walk_leaf(const struct kvm_pgtable_visit_ctx *ctx,
if (ret != -E2BIG)
return ret;
- if (WARN_ON(ctx->level == KVM_PGTABLE_MAX_LEVELS - 1))
+ if (WARN_ON(ctx->level == KVM_PGTABLE_LAST_LEVEL))
return -EINVAL;
if (!data->memcache)
@@ -1151,7 +1175,7 @@ struct stage2_attr_data {
kvm_pte_t attr_set;
kvm_pte_t attr_clr;
kvm_pte_t pte;
- u32 level;
+ s8 level;
};
static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx,
@@ -1194,7 +1218,7 @@ static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx,
static int stage2_update_leaf_attrs(struct kvm_pgtable *pgt, u64 addr,
u64 size, kvm_pte_t attr_set,
kvm_pte_t attr_clr, kvm_pte_t *orig_pte,
- u32 *level, enum kvm_pgtable_walk_flags flags)
+ s8 *level, enum kvm_pgtable_walk_flags flags)
{
int ret;
kvm_pte_t attr_mask = KVM_PTE_LEAF_ATTR_LO | KVM_PTE_LEAF_ATTR_HI;
@@ -1296,7 +1320,7 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
enum kvm_pgtable_prot prot)
{
int ret;
- u32 level;
+ s8 level;
kvm_pte_t set = 0, clr = 0;
if (prot & KVM_PTE_LEAF_ATTR_HI_SW)
@@ -1349,7 +1373,7 @@ int kvm_pgtable_stage2_flush(struct kvm_pgtable *pgt, u64 addr, u64 size)
}
kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt,
- u64 phys, u32 level,
+ u64 phys, s8 level,
enum kvm_pgtable_prot prot,
void *mc, bool force_pte)
{
@@ -1407,7 +1431,7 @@ kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt,
* fully populated tree up to the PTE entries. Note that @level is
* interpreted as in "level @level entry".
*/
-static int stage2_block_get_nr_page_tables(u32 level)
+static int stage2_block_get_nr_page_tables(s8 level)
{
switch (level) {
case 1:
@@ -1418,7 +1442,7 @@ static int stage2_block_get_nr_page_tables(u32 level)
return 0;
default:
WARN_ON_ONCE(level < KVM_PGTABLE_MIN_BLOCK_LEVEL ||
- level >= KVM_PGTABLE_MAX_LEVELS);
+ level > KVM_PGTABLE_LAST_LEVEL);
return -EINVAL;
};
}
@@ -1431,13 +1455,13 @@ static int stage2_split_walker(const struct kvm_pgtable_visit_ctx *ctx,
struct kvm_s2_mmu *mmu;
kvm_pte_t pte = ctx->old, new, *childp;
enum kvm_pgtable_prot prot;
- u32 level = ctx->level;
+ s8 level = ctx->level;
bool force_pte;
int nr_pages;
u64 phys;
/* No huge-pages exist at the last level */
- if (level == KVM_PGTABLE_MAX_LEVELS - 1)
+ if (level == KVM_PGTABLE_LAST_LEVEL)
return 0;
/* We only split valid block mappings */
@@ -1514,7 +1538,7 @@ int __kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu,
u64 vtcr = mmu->vtcr;
u32 ia_bits = VTCR_EL2_IPA(vtcr);
u32 sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr);
- u32 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
+ s8 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
pgd_sz = kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE;
pgt->pgd = (kvm_pteref_t)mm_ops->zalloc_pages_exact(pgd_sz);
@@ -1537,7 +1561,7 @@ size_t kvm_pgtable_stage2_pgd_size(u64 vtcr)
{
u32 ia_bits = VTCR_EL2_IPA(vtcr);
u32 sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr);
- u32 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
+ s8 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
return kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE;
}
@@ -1573,7 +1597,7 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt)
pgt->pgd = NULL;
}
-void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, u32 level)
+void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level)
{
kvm_pteref_t ptep = (kvm_pteref_t)pgtable;
struct kvm_pgtable_walker walker = {
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index d87c8fcc4c24..d14504821b79 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -223,12 +223,12 @@ static void stage2_free_unlinked_table_rcu_cb(struct rcu_head *head)
{
struct page *page = container_of(head, struct page, rcu_head);
void *pgtable = page_to_virt(page);
- u32 level = page_private(page);
+ s8 level = page_private(page);
kvm_pgtable_stage2_free_unlinked(&kvm_s2_mm_ops, pgtable, level);
}
-static void stage2_free_unlinked_table(void *addr, u32 level)
+static void stage2_free_unlinked_table(void *addr, s8 level)
{
struct page *page = virt_to_page(addr);
@@ -804,13 +804,13 @@ static int get_user_mapping_size(struct kvm *kvm, u64 addr)
struct kvm_pgtable pgt = {
.pgd = (kvm_pteref_t)kvm->mm->pgd,
.ia_bits = vabits_actual,
- .start_level = (KVM_PGTABLE_MAX_LEVELS -
- CONFIG_PGTABLE_LEVELS),
+ .start_level = (KVM_PGTABLE_LAST_LEVEL -
+ CONFIG_PGTABLE_LEVELS + 1),
.mm_ops = &kvm_user_mm_ops,
};
unsigned long flags;
kvm_pte_t pte = 0; /* Keep GCC quiet... */
- u32 level = ~0;
+ s8 level = S8_MAX;
int ret;
/*
@@ -829,7 +829,9 @@ static int get_user_mapping_size(struct kvm *kvm, u64 addr)
* Not seeing an error, but not updating level? Something went
* deeply wrong...
*/
- if (WARN_ON(level >= KVM_PGTABLE_MAX_LEVELS))
+ if (WARN_ON(level > KVM_PGTABLE_LAST_LEVEL))
+ return -EFAULT;
+ if (WARN_ON(level < KVM_PGTABLE_FIRST_LEVEL))
return -EFAULT;
/* Oops, the userspace PTs are gone... Replay the fault */
@@ -1374,7 +1376,7 @@ static bool kvm_vma_mte_allowed(struct vm_area_struct *vma)
static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
struct kvm_memory_slot *memslot, unsigned long hva,
- unsigned long fault_status)
+ bool fault_is_perm)
{
int ret = 0;
bool write_fault, writable, force_pte = false;
@@ -1388,17 +1390,17 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
gfn_t gfn;
kvm_pfn_t pfn;
bool logging_active = memslot_is_logging(memslot);
- unsigned long fault_level = kvm_vcpu_trap_get_fault_level(vcpu);
long vma_pagesize, fault_granule;
enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R;
struct kvm_pgtable *pgt;
- fault_granule = 1UL << ARM64_HW_PGTABLE_LEVEL_SHIFT(fault_level);
+ if (fault_is_perm)
+ fault_granule = kvm_vcpu_trap_get_perm_fault_granule(vcpu);
write_fault = kvm_is_write_fault(vcpu);
exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu);
VM_BUG_ON(write_fault && exec_fault);
- if (fault_status == ESR_ELx_FSC_PERM && !write_fault && !exec_fault) {
+ if (fault_is_perm && !write_fault && !exec_fault) {
kvm_err("Unexpected L2 read permission error\n");
return -EFAULT;
}
@@ -1409,8 +1411,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
* only exception to this is when dirty logging is enabled at runtime
* and a write fault needs to collapse a block entry into a table.
*/
- if (fault_status != ESR_ELx_FSC_PERM ||
- (logging_active && write_fault)) {
+ if (!fault_is_perm || (logging_active && write_fault)) {
ret = kvm_mmu_topup_memory_cache(memcache,
kvm_mmu_cache_min_pages(vcpu->arch.hw_mmu));
if (ret)
@@ -1527,8 +1528,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
* backed by a THP and thus use block mapping if possible.
*/
if (vma_pagesize == PAGE_SIZE && !(force_pte || device)) {
- if (fault_status == ESR_ELx_FSC_PERM &&
- fault_granule > PAGE_SIZE)
+ if (fault_is_perm && fault_granule > PAGE_SIZE)
vma_pagesize = fault_granule;
else
vma_pagesize = transparent_hugepage_adjust(kvm, memslot,
@@ -1541,7 +1541,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
}
}
- if (fault_status != ESR_ELx_FSC_PERM && !device && kvm_has_mte(kvm)) {
+ if (!fault_is_perm && !device && kvm_has_mte(kvm)) {
/* Check the VMM hasn't introduced a new disallowed VMA */
if (mte_allowed) {
sanitise_mte_tags(kvm, pfn, vma_pagesize);
@@ -1567,7 +1567,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
* permissions only if vma_pagesize equals fault_granule. Otherwise,
* kvm_pgtable_stage2_map() should be called to change block size.
*/
- if (fault_status == ESR_ELx_FSC_PERM && vma_pagesize == fault_granule)
+ if (fault_is_perm && vma_pagesize == fault_granule)
ret = kvm_pgtable_stage2_relax_perms(pgt, fault_ipa, prot);
else
ret = kvm_pgtable_stage2_map(pgt, fault_ipa, vma_pagesize,
@@ -1618,7 +1618,7 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
*/
int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
{
- unsigned long fault_status;
+ unsigned long esr;
phys_addr_t fault_ipa;
struct kvm_memory_slot *memslot;
unsigned long hva;
@@ -1626,12 +1626,12 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
gfn_t gfn;
int ret, idx;
- fault_status = kvm_vcpu_trap_get_fault_type(vcpu);
+ esr = kvm_vcpu_get_esr(vcpu);
fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
- if (fault_status == ESR_ELx_FSC_FAULT) {
+ if (esr_fsc_is_permission_fault(esr)) {
/* Beyond sanitised PARange (which is the IPA limit) */
if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) {
kvm_inject_size_fault(vcpu);
@@ -1666,9 +1666,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
kvm_vcpu_get_hfar(vcpu), fault_ipa);
/* Check the stage-2 fault is trans. fault or write fault */
- if (fault_status != ESR_ELx_FSC_FAULT &&
- fault_status != ESR_ELx_FSC_PERM &&
- fault_status != ESR_ELx_FSC_ACCESS) {
+ if (!esr_fsc_is_translation_fault(esr) &&
+ !esr_fsc_is_permission_fault(esr) &&
+ !esr_fsc_is_access_flag_fault(esr)) {
kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n",
kvm_vcpu_trap_get_class(vcpu),
(unsigned long)kvm_vcpu_trap_get_fault(vcpu),
@@ -1730,13 +1730,14 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu)
/* Userspace should not be able to register out-of-bounds IPAs */
VM_BUG_ON(fault_ipa >= kvm_phys_size(vcpu->arch.hw_mmu));
- if (fault_status == ESR_ELx_FSC_ACCESS) {
+ if (esr_fsc_is_access_flag_fault(esr)) {
handle_access_fault(vcpu, fault_ipa);
ret = 1;
goto out_unlock;
}
- ret = user_mem_abort(vcpu, fault_ipa, memslot, hva, fault_status);
+ ret = user_mem_abort(vcpu, fault_ipa, memslot, hva,
+ esr_fsc_is_permission_fault(esr));
if (ret == 0)
ret = 1;
out:
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index 042695a210ce..ba95d044bc98 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -23,13 +23,9 @@
* This list should get updated as new features get added to the NV
* support, and new extension to the architecture.
*/
-void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p,
- const struct sys_reg_desc *r)
+static u64 limit_nv_id_reg(u32 id, u64 val)
{
- u32 id = reg_to_encoding(r);
- u64 val, tmp;
-
- val = p->regval;
+ u64 tmp;
switch (id) {
case SYS_ID_AA64ISAR0_EL1:
@@ -158,5 +154,17 @@ void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p,
break;
}
- p->regval = val;
+ return val;
+}
+int kvm_init_nv_sysregs(struct kvm *kvm)
+{
+ mutex_lock(&kvm->arch.config_lock);
+
+ for (int i = 0; i < KVM_ARM_ID_REG_NUM; i++)
+ kvm->arch.id_regs[i] = limit_nv_id_reg(IDX_IDREG(i),
+ kvm->arch.id_regs[i]);
+
+ mutex_unlock(&kvm->arch.config_lock);
+
+ return 0;
}
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index 5bb4de162cab..68d1d05672bd 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -280,12 +280,11 @@ int __init kvm_set_ipa_limit(void)
parange = cpuid_feature_extract_unsigned_field(mmfr0,
ID_AA64MMFR0_EL1_PARANGE_SHIFT);
/*
- * IPA size beyond 48 bits could not be supported
- * on either 4K or 16K page size. Hence let's cap
- * it to 48 bits, in case it's reported as larger
- * on the system.
+ * IPA size beyond 48 bits for 4K and 16K page size is only supported
+ * when LPA2 is available. So if we have LPA2, enable it, else cap to 48
+ * bits, in case it's reported as larger on the system.
*/
- if (PAGE_SIZE != SZ_64K)
+ if (!kvm_lpa2_is_enabled() && PAGE_SIZE != SZ_64K)
parange = min(parange, (unsigned int)ID_AA64MMFR0_EL1_PARANGE_48);
/*
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index ff45d688bd7d..30253bd19917 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -45,44 +45,170 @@ static u64 sys_reg_to_index(const struct sys_reg_desc *reg);
static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
u64 val);
-static bool read_from_write_only(struct kvm_vcpu *vcpu,
- struct sys_reg_params *params,
- const struct sys_reg_desc *r)
+static bool bad_trap(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *params,
+ const struct sys_reg_desc *r,
+ const char *msg)
{
- WARN_ONCE(1, "Unexpected sys_reg read to write-only register\n");
+ WARN_ONCE(1, "Unexpected %s\n", msg);
print_sys_reg_instr(params);
kvm_inject_undefined(vcpu);
return false;
}
+static bool read_from_write_only(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *params,
+ const struct sys_reg_desc *r)
+{
+ return bad_trap(vcpu, params, r,
+ "sys_reg read to write-only register");
+}
+
static bool write_to_read_only(struct kvm_vcpu *vcpu,
struct sys_reg_params *params,
const struct sys_reg_desc *r)
{
- WARN_ONCE(1, "Unexpected sys_reg write to read-only register\n");
- print_sys_reg_instr(params);
- kvm_inject_undefined(vcpu);
- return false;
+ return bad_trap(vcpu, params, r,
+ "sys_reg write to read-only register");
+}
+
+#define PURE_EL2_SYSREG(el2) \
+ case el2: { \
+ *el1r = el2; \
+ return true; \
+ }
+
+#define MAPPED_EL2_SYSREG(el2, el1, fn) \
+ case el2: { \
+ *xlate = fn; \
+ *el1r = el1; \
+ return true; \
+ }
+
+static bool get_el2_to_el1_mapping(unsigned int reg,
+ unsigned int *el1r, u64 (**xlate)(u64))
+{
+ switch (reg) {
+ PURE_EL2_SYSREG( VPIDR_EL2 );
+ PURE_EL2_SYSREG( VMPIDR_EL2 );
+ PURE_EL2_SYSREG( ACTLR_EL2 );
+ PURE_EL2_SYSREG( HCR_EL2 );
+ PURE_EL2_SYSREG( MDCR_EL2 );
+ PURE_EL2_SYSREG( HSTR_EL2 );
+ PURE_EL2_SYSREG( HACR_EL2 );
+ PURE_EL2_SYSREG( VTTBR_EL2 );
+ PURE_EL2_SYSREG( VTCR_EL2 );
+ PURE_EL2_SYSREG( RVBAR_EL2 );
+ PURE_EL2_SYSREG( TPIDR_EL2 );
+ PURE_EL2_SYSREG( HPFAR_EL2 );
+ PURE_EL2_SYSREG( CNTHCTL_EL2 );
+ MAPPED_EL2_SYSREG(SCTLR_EL2, SCTLR_EL1,
+ translate_sctlr_el2_to_sctlr_el1 );
+ MAPPED_EL2_SYSREG(CPTR_EL2, CPACR_EL1,
+ translate_cptr_el2_to_cpacr_el1 );
+ MAPPED_EL2_SYSREG(TTBR0_EL2, TTBR0_EL1,
+ translate_ttbr0_el2_to_ttbr0_el1 );
+ MAPPED_EL2_SYSREG(TTBR1_EL2, TTBR1_EL1, NULL );
+ MAPPED_EL2_SYSREG(TCR_EL2, TCR_EL1,
+ translate_tcr_el2_to_tcr_el1 );
+ MAPPED_EL2_SYSREG(VBAR_EL2, VBAR_EL1, NULL );
+ MAPPED_EL2_SYSREG(AFSR0_EL2, AFSR0_EL1, NULL );
+ MAPPED_EL2_SYSREG(AFSR1_EL2, AFSR1_EL1, NULL );
+ MAPPED_EL2_SYSREG(ESR_EL2, ESR_EL1, NULL );
+ MAPPED_EL2_SYSREG(FAR_EL2, FAR_EL1, NULL );
+ MAPPED_EL2_SYSREG(MAIR_EL2, MAIR_EL1, NULL );
+ MAPPED_EL2_SYSREG(AMAIR_EL2, AMAIR_EL1, NULL );
+ MAPPED_EL2_SYSREG(ELR_EL2, ELR_EL1, NULL );
+ MAPPED_EL2_SYSREG(SPSR_EL2, SPSR_EL1, NULL );
+ default:
+ return false;
+ }
}
u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg)
{
u64 val = 0x8badf00d8badf00d;
+ u64 (*xlate)(u64) = NULL;
+ unsigned int el1r;
+
+ if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU))
+ goto memory_read;
- if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) &&
- __vcpu_read_sys_reg_from_cpu(reg, &val))
+ if (unlikely(get_el2_to_el1_mapping(reg, &el1r, &xlate))) {
+ if (!is_hyp_ctxt(vcpu))
+ goto memory_read;
+
+ /*
+ * If this register does not have an EL1 counterpart,
+ * then read the stored EL2 version.
+ */
+ if (reg == el1r)
+ goto memory_read;
+
+ /*
+ * If we have a non-VHE guest and that the sysreg
+ * requires translation to be used at EL1, use the
+ * in-memory copy instead.
+ */
+ if (!vcpu_el2_e2h_is_set(vcpu) && xlate)
+ goto memory_read;
+
+ /* Get the current version of the EL1 counterpart. */
+ WARN_ON(!__vcpu_read_sys_reg_from_cpu(el1r, &val));
return val;
+ }
+ /* EL1 register can't be on the CPU if the guest is in vEL2. */
+ if (unlikely(is_hyp_ctxt(vcpu)))
+ goto memory_read;
+
+ if (__vcpu_read_sys_reg_from_cpu(reg, &val))
+ return val;
+
+memory_read:
return __vcpu_sys_reg(vcpu, reg);
}
void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg)
{
- if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) &&
- __vcpu_write_sys_reg_to_cpu(val, reg))
+ u64 (*xlate)(u64) = NULL;
+ unsigned int el1r;
+
+ if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU))
+ goto memory_write;
+
+ if (unlikely(get_el2_to_el1_mapping(reg, &el1r, &xlate))) {
+ if (!is_hyp_ctxt(vcpu))
+ goto memory_write;
+
+ /*
+ * Always store a copy of the write to memory to avoid having
+ * to reverse-translate virtual EL2 system registers for a
+ * non-VHE guest hypervisor.
+ */
+ __vcpu_sys_reg(vcpu, reg) = val;
+
+ /* No EL1 counterpart? We're done here.? */
+ if (reg == el1r)
+ return;
+
+ if (!vcpu_el2_e2h_is_set(vcpu) && xlate)
+ val = xlate(val);
+
+ /* Redirect this to the EL1 version of the register. */
+ WARN_ON(!__vcpu_write_sys_reg_to_cpu(val, el1r));
+ return;
+ }
+
+ /* EL1 register can't be on the CPU if the guest is in vEL2. */
+ if (unlikely(is_hyp_ctxt(vcpu)))
+ goto memory_write;
+
+ if (__vcpu_write_sys_reg_to_cpu(val, reg))
return;
- __vcpu_sys_reg(vcpu, reg) = val;
+memory_write:
+ __vcpu_sys_reg(vcpu, reg) = val;
}
/* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */
@@ -1505,8 +1631,6 @@ static bool access_id_reg(struct kvm_vcpu *vcpu,
return write_to_read_only(vcpu, p, r);
p->regval = read_id_reg(vcpu, r);
- if (vcpu_has_nv(vcpu))
- access_nested_id_reg(vcpu, p, r);
return true;
}
@@ -1885,6 +2009,32 @@ static unsigned int el2_visibility(const struct kvm_vcpu *vcpu,
return REG_HIDDEN;
}
+static bool bad_vncr_trap(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ /*
+ * We really shouldn't be here, and this is likely the result
+ * of a misconfigured trap, as this register should target the
+ * VNCR page, and nothing else.
+ */
+ return bad_trap(vcpu, p, r,
+ "trap of VNCR-backed register");
+}
+
+static bool bad_redir_trap(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ /*
+ * We really shouldn't be here, and this is likely the result
+ * of a misconfigured trap, as this register should target the
+ * corresponding EL1, and nothing else.
+ */
+ return bad_trap(vcpu, p, r,
+ "trap of EL2 register redirected to EL1");
+}
+
#define EL2_REG(name, acc, rst, v) { \
SYS_DESC(SYS_##name), \
.access = acc, \
@@ -1894,6 +2044,9 @@ static unsigned int el2_visibility(const struct kvm_vcpu *vcpu,
.val = v, \
}
+#define EL2_REG_VNCR(name, rst, v) EL2_REG(name, bad_vncr_trap, rst, v)
+#define EL2_REG_REDIR(name, rst, v) EL2_REG(name, bad_redir_trap, rst, v)
+
/*
* EL{0,1}2 registers are the EL2 view on an EL0 or EL1 register when
* HCR_EL2.E2H==1, and only in the sysreg table for convenience of
@@ -2508,32 +2661,33 @@ static const struct sys_reg_desc sys_reg_descs[] = {
{ PMU_SYS_REG(PMCCFILTR_EL0), .access = access_pmu_evtyper,
.reset = reset_val, .reg = PMCCFILTR_EL0, .val = 0 },
- EL2_REG(VPIDR_EL2, access_rw, reset_unknown, 0),
- EL2_REG(VMPIDR_EL2, access_rw, reset_unknown, 0),
+ EL2_REG_VNCR(VPIDR_EL2, reset_unknown, 0),
+ EL2_REG_VNCR(VMPIDR_EL2, reset_unknown, 0),
EL2_REG(SCTLR_EL2, access_rw, reset_val, SCTLR_EL2_RES1),
EL2_REG(ACTLR_EL2, access_rw, reset_val, 0),
- EL2_REG(HCR_EL2, access_rw, reset_val, 0),
+ EL2_REG_VNCR(HCR_EL2, reset_val, 0),
EL2_REG(MDCR_EL2, access_rw, reset_val, 0),
EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1),
- EL2_REG(HSTR_EL2, access_rw, reset_val, 0),
- EL2_REG(HFGRTR_EL2, access_rw, reset_val, 0),
- EL2_REG(HFGWTR_EL2, access_rw, reset_val, 0),
- EL2_REG(HFGITR_EL2, access_rw, reset_val, 0),
- EL2_REG(HACR_EL2, access_rw, reset_val, 0),
+ EL2_REG_VNCR(HSTR_EL2, reset_val, 0),
+ EL2_REG_VNCR(HFGRTR_EL2, reset_val, 0),
+ EL2_REG_VNCR(HFGWTR_EL2, reset_val, 0),
+ EL2_REG_VNCR(HFGITR_EL2, reset_val, 0),
+ EL2_REG_VNCR(HACR_EL2, reset_val, 0),
- EL2_REG(HCRX_EL2, access_rw, reset_val, 0),
+ EL2_REG_VNCR(HCRX_EL2, reset_val, 0),
EL2_REG(TTBR0_EL2, access_rw, reset_val, 0),
EL2_REG(TTBR1_EL2, access_rw, reset_val, 0),
EL2_REG(TCR_EL2, access_rw, reset_val, TCR_EL2_RES1),
- EL2_REG(VTTBR_EL2, access_rw, reset_val, 0),
- EL2_REG(VTCR_EL2, access_rw, reset_val, 0),
+ EL2_REG_VNCR(VTTBR_EL2, reset_val, 0),
+ EL2_REG_VNCR(VTCR_EL2, reset_val, 0),
{ SYS_DESC(SYS_DACR32_EL2), trap_undef, reset_unknown, DACR32_EL2 },
- EL2_REG(HDFGRTR_EL2, access_rw, reset_val, 0),
- EL2_REG(HDFGWTR_EL2, access_rw, reset_val, 0),
- EL2_REG(SPSR_EL2, access_rw, reset_val, 0),
- EL2_REG(ELR_EL2, access_rw, reset_val, 0),
+ EL2_REG_VNCR(HDFGRTR_EL2, reset_val, 0),
+ EL2_REG_VNCR(HDFGWTR_EL2, reset_val, 0),
+ EL2_REG_VNCR(HAFGRTR_EL2, reset_val, 0),
+ EL2_REG_REDIR(SPSR_EL2, reset_val, 0),
+ EL2_REG_REDIR(ELR_EL2, reset_val, 0),
{ SYS_DESC(SYS_SP_EL1), access_sp_el1},
/* AArch32 SPSR_* are RES0 if trapped from a NV guest */
@@ -2549,10 +2703,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
{ SYS_DESC(SYS_IFSR32_EL2), trap_undef, reset_unknown, IFSR32_EL2 },
EL2_REG(AFSR0_EL2, access_rw, reset_val, 0),
EL2_REG(AFSR1_EL2, access_rw, reset_val, 0),
- EL2_REG(ESR_EL2, access_rw, reset_val, 0),
+ EL2_REG_REDIR(ESR_EL2, reset_val, 0),
{ SYS_DESC(SYS_FPEXC32_EL2), trap_undef, reset_val, FPEXC32_EL2, 0x700 },
- EL2_REG(FAR_EL2, access_rw, reset_val, 0),
+ EL2_REG_REDIR(FAR_EL2, reset_val, 0),
EL2_REG(HPFAR_EL2, access_rw, reset_val, 0),
EL2_REG(MAIR_EL2, access_rw, reset_val, 0),
@@ -2565,24 +2719,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
EL2_REG(CONTEXTIDR_EL2, access_rw, reset_val, 0),
EL2_REG(TPIDR_EL2, access_rw, reset_val, 0),
- EL2_REG(CNTVOFF_EL2, access_rw, reset_val, 0),
+ EL2_REG_VNCR(CNTVOFF_EL2, reset_val, 0),
EL2_REG(CNTHCTL_EL2, access_rw, reset_val, 0),
- EL12_REG(SCTLR, access_vm_reg, reset_val, 0x00C50078),
- EL12_REG(CPACR, access_rw, reset_val, 0),
- EL12_REG(TTBR0, access_vm_reg, reset_unknown, 0),
- EL12_REG(TTBR1, access_vm_reg, reset_unknown, 0),
- EL12_REG(TCR, access_vm_reg, reset_val, 0),
- { SYS_DESC(SYS_SPSR_EL12), access_spsr},
- { SYS_DESC(SYS_ELR_EL12), access_elr},
- EL12_REG(AFSR0, access_vm_reg, reset_unknown, 0),
- EL12_REG(AFSR1, access_vm_reg, reset_unknown, 0),
- EL12_REG(ESR, access_vm_reg, reset_unknown, 0),
- EL12_REG(FAR, access_vm_reg, reset_unknown, 0),
- EL12_REG(MAIR, access_vm_reg, reset_unknown, 0),
- EL12_REG(AMAIR, access_vm_reg, reset_amair_el1, 0),
- EL12_REG(VBAR, access_rw, reset_val, 0),
- EL12_REG(CONTEXTIDR, access_vm_reg, reset_val, 0),
EL12_REG(CNTKCTL, access_rw, reset_val, 0),
EL2_REG(SP_EL2, NULL, reset_unknown, 0),
diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
index 2dad2d095160..e2764d0ffa9f 100644
--- a/arch/arm64/kvm/vgic/vgic-its.c
+++ b/arch/arm64/kvm/vgic/vgic-its.c
@@ -590,7 +590,11 @@ static struct vgic_irq *vgic_its_check_cache(struct kvm *kvm, phys_addr_t db,
unsigned long flags;
raw_spin_lock_irqsave(&dist->lpi_list_lock, flags);
+
irq = __vgic_its_check_cache(dist, db, devid, eventid);
+ if (irq)
+ vgic_get_irq_kref(irq);
+
raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
return irq;
@@ -769,6 +773,7 @@ int vgic_its_inject_cached_translation(struct kvm *kvm, struct kvm_msi *msi)
raw_spin_lock_irqsave(&irq->irq_lock, flags);
irq->pending_latch = true;
vgic_queue_irq_unlock(kvm, irq, flags);
+ vgic_put_irq(kvm, irq);
return 0;
}
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
index a764b0ab8bf9..c15ee1df036a 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
@@ -357,31 +357,13 @@ static int vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val)
{
- u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
- int i;
- unsigned long flags;
-
- for (i = 0; i < len * 8; i++) {
- struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
-
- raw_spin_lock_irqsave(&irq->irq_lock, flags);
- if (test_bit(i, &val)) {
- /*
- * pending_latch is set irrespective of irq type
- * (level or edge) to avoid dependency that VM should
- * restore irq config before pending info.
- */
- irq->pending_latch = true;
- vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
- } else {
- irq->pending_latch = false;
- raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
- }
+ int ret;
- vgic_put_irq(vcpu->kvm, irq);
- }
+ ret = vgic_uaccess_write_spending(vcpu, addr, len, val);
+ if (ret)
+ return ret;
- return 0;
+ return vgic_uaccess_write_cpending(vcpu, addr, len, ~val);
}
/* We want to avoid outer shareable. */
diff --git a/arch/arm64/kvm/vgic/vgic-mmio.c b/arch/arm64/kvm/vgic/vgic-mmio.c
index ff558c05e990..cf76523a2194 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio.c
@@ -301,9 +301,8 @@ static bool is_vgic_v2_sgi(struct kvm_vcpu *vcpu, struct vgic_irq *irq)
vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2);
}
-void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
- gpa_t addr, unsigned int len,
- unsigned long val)
+static void __set_pending(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len,
+ unsigned long val, bool is_user)
{
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
int i;
@@ -312,14 +311,22 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
for_each_set_bit(i, &val, len * 8) {
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
- /* GICD_ISPENDR0 SGI bits are WI */
- if (is_vgic_v2_sgi(vcpu, irq)) {
+ /* GICD_ISPENDR0 SGI bits are WI when written from the guest. */
+ if (is_vgic_v2_sgi(vcpu, irq) && !is_user) {
vgic_put_irq(vcpu->kvm, irq);
continue;
}
raw_spin_lock_irqsave(&irq->irq_lock, flags);
+ /*
+ * GICv2 SGIs are terribly broken. We can't restore
+ * the source of the interrupt, so just pick the vcpu
+ * itself as the source...
+ */
+ if (is_vgic_v2_sgi(vcpu, irq))
+ irq->source |= BIT(vcpu->vcpu_id);
+
if (irq->hw && vgic_irq_is_sgi(irq->intid)) {
/* HW SGI? Ask the GIC to inject it */
int err;
@@ -335,7 +342,7 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
}
irq->pending_latch = true;
- if (irq->hw)
+ if (irq->hw && !is_user)
vgic_irq_set_phys_active(irq, true);
vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
@@ -343,33 +350,18 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
}
}
+void vgic_mmio_write_spending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ __set_pending(vcpu, addr, len, val, false);
+}
+
int vgic_uaccess_write_spending(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val)
{
- u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
- int i;
- unsigned long flags;
-
- for_each_set_bit(i, &val, len * 8) {
- struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
-
- raw_spin_lock_irqsave(&irq->irq_lock, flags);
- irq->pending_latch = true;
-
- /*
- * GICv2 SGIs are terribly broken. We can't restore
- * the source of the interrupt, so just pick the vcpu
- * itself as the source...
- */
- if (is_vgic_v2_sgi(vcpu, irq))
- irq->source |= BIT(vcpu->vcpu_id);
-
- vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
-
- vgic_put_irq(vcpu->kvm, irq);
- }
-
+ __set_pending(vcpu, addr, len, val, true);
return 0;
}
@@ -394,9 +386,9 @@ static void vgic_hw_irq_cpending(struct kvm_vcpu *vcpu, struct vgic_irq *irq)
vgic_irq_set_phys_active(irq, false);
}
-void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
- gpa_t addr, unsigned int len,
- unsigned long val)
+static void __clear_pending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val, bool is_user)
{
u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
int i;
@@ -405,14 +397,22 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
for_each_set_bit(i, &val, len * 8) {
struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
- /* GICD_ICPENDR0 SGI bits are WI */
- if (is_vgic_v2_sgi(vcpu, irq)) {
+ /* GICD_ICPENDR0 SGI bits are WI when written from the guest. */
+ if (is_vgic_v2_sgi(vcpu, irq) && !is_user) {
vgic_put_irq(vcpu->kvm, irq);
continue;
}
raw_spin_lock_irqsave(&irq->irq_lock, flags);
+ /*
+ * More fun with GICv2 SGIs! If we're clearing one of them
+ * from userspace, which source vcpu to clear? Let's not
+ * even think of it, and blow the whole set.
+ */
+ if (is_vgic_v2_sgi(vcpu, irq))
+ irq->source = 0;
+
if (irq->hw && vgic_irq_is_sgi(irq->intid)) {
/* HW SGI? Ask the GIC to clear its pending bit */
int err;
@@ -427,7 +427,7 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
continue;
}
- if (irq->hw)
+ if (irq->hw && !is_user)
vgic_hw_irq_cpending(vcpu, irq);
else
irq->pending_latch = false;
@@ -437,33 +437,18 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
}
}
+void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu,
+ gpa_t addr, unsigned int len,
+ unsigned long val)
+{
+ __clear_pending(vcpu, addr, len, val, false);
+}
+
int vgic_uaccess_write_cpending(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len,
unsigned long val)
{
- u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
- int i;
- unsigned long flags;
-
- for_each_set_bit(i, &val, len * 8) {
- struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
-
- raw_spin_lock_irqsave(&irq->irq_lock, flags);
- /*
- * More fun with GICv2 SGIs! If we're clearing one of them
- * from userspace, which source vcpu to clear? Let's not
- * even think of it, and blow the whole set.
- */
- if (is_vgic_v2_sgi(vcpu, irq))
- irq->source = 0;
-
- irq->pending_latch = false;
-
- raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
-
- vgic_put_irq(vcpu->kvm, irq);
- }
-
+ __clear_pending(vcpu, addr, len, val, true);
return 0;
}
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 3cb101e8cb29..61886e43e3a1 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -47,7 +47,7 @@ void arch_teardown_dma_ops(struct device *dev)
#endif
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
- const struct iommu_ops *iommu, bool coherent)
+ bool coherent)
{
int cls = cache_line_size_of_cpu();
@@ -58,7 +58,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
ARCH_DMA_MINALIGN, cls);
dev->dma_coherent = coherent;
- if (iommu)
+ if (device_iommu_mapped(dev))
iommu_setup_dma_ops(dev, dma_base, dma_base + size - 1);
xen_setup_dma_ops(dev);
diff --git a/arch/csky/abiv1/inc/abi/cacheflush.h b/arch/csky/abiv1/inc/abi/cacheflush.h
index 908d8b0bc4fd..d011a81575d2 100644
--- a/arch/csky/abiv1/inc/abi/cacheflush.h
+++ b/arch/csky/abiv1/inc/abi/cacheflush.h
@@ -43,6 +43,7 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
*/
extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
#define flush_cache_vmap(start, end) cache_wbinv_all()
+#define flush_cache_vmap_early(start, end) do { } while (0)
#define flush_cache_vunmap(start, end) cache_wbinv_all()
#define flush_icache_range(start, end) cache_wbinv_range(start, end)
diff --git a/arch/csky/abiv2/inc/abi/cacheflush.h b/arch/csky/abiv2/inc/abi/cacheflush.h
index 40be16907267..6513ac5d2578 100644
--- a/arch/csky/abiv2/inc/abi/cacheflush.h
+++ b/arch/csky/abiv2/inc/abi/cacheflush.h
@@ -41,6 +41,7 @@ void flush_icache_mm_range(struct mm_struct *mm,
void flush_icache_deferred(struct mm_struct *mm);
#define flush_cache_vmap(start, end) do { } while (0)
+#define flush_cache_vmap_early(start, end) do { } while (0)
#define flush_cache_vunmap(start, end) do { } while (0)
#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index ee123820a476..15d05dd2b7f3 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -5,6 +5,7 @@ config LOONGARCH
select ACPI
select ACPI_GENERIC_GSI if ACPI
select ACPI_MCFG if ACPI
+ select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU
select ACPI_PPTT if ACPI
select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
select ARCH_BINFMT_ELF_STATE
@@ -71,6 +72,7 @@ config LOONGARCH
select GENERIC_CLOCKEVENTS
select GENERIC_CMOS_UPDATE
select GENERIC_CPU_AUTOPROBE
+ select GENERIC_CPU_DEVICES
select GENERIC_ENTRY
select GENERIC_GETTIMEOFDAY
select GENERIC_IOREMAP if !ARCH_IOREMAP
diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index 11328700d4fa..2d62f7b0d377 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -45,7 +45,10 @@ struct kvm_vcpu_stat {
u64 signal_exits;
};
+#define KVM_MEM_HUGEPAGE_CAPABLE (1UL << 0)
+#define KVM_MEM_HUGEPAGE_INCAPABLE (1UL << 1)
struct kvm_arch_memory_slot {
+ unsigned long flags;
};
struct kvm_context {
@@ -92,8 +95,10 @@ enum emulation_result {
};
#define KVM_LARCH_FPU (0x1 << 0)
-#define KVM_LARCH_SWCSR_LATEST (0x1 << 1)
-#define KVM_LARCH_HWCSR_USABLE (0x1 << 2)
+#define KVM_LARCH_LSX (0x1 << 1)
+#define KVM_LARCH_LASX (0x1 << 2)
+#define KVM_LARCH_SWCSR_LATEST (0x1 << 3)
+#define KVM_LARCH_HWCSR_USABLE (0x1 << 4)
struct kvm_vcpu_arch {
/*
@@ -175,6 +180,21 @@ static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned
csr->csrs[reg] = val;
}
+static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch)
+{
+ return arch->cpucfg[2] & CPUCFG2_FP;
+}
+
+static inline bool kvm_guest_has_lsx(struct kvm_vcpu_arch *arch)
+{
+ return arch->cpucfg[2] & CPUCFG2_LSX;
+}
+
+static inline bool kvm_guest_has_lasx(struct kvm_vcpu_arch *arch)
+{
+ return arch->cpucfg[2] & CPUCFG2_LASX;
+}
+
/* Debug: dump vcpu state */
int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu);
@@ -183,7 +203,6 @@ void kvm_flush_tlb_all(void);
void kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa);
int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write);
-#define KVM_ARCH_WANT_MMU_NOTIFIER
void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end, bool blockable);
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h
index 553cfa2b2b1c..e71ceb88f29e 100644
--- a/arch/loongarch/include/asm/kvm_vcpu.h
+++ b/arch/loongarch/include/asm/kvm_vcpu.h
@@ -55,7 +55,26 @@ void kvm_save_fpu(struct loongarch_fpu *fpu);
void kvm_restore_fpu(struct loongarch_fpu *fpu);
void kvm_restore_fcsr(struct loongarch_fpu *fpu);
-void kvm_acquire_timer(struct kvm_vcpu *vcpu);
+#ifdef CONFIG_CPU_HAS_LSX
+int kvm_own_lsx(struct kvm_vcpu *vcpu);
+void kvm_save_lsx(struct loongarch_fpu *fpu);
+void kvm_restore_lsx(struct loongarch_fpu *fpu);
+#else
+static inline int kvm_own_lsx(struct kvm_vcpu *vcpu) { }
+static inline void kvm_save_lsx(struct loongarch_fpu *fpu) { }
+static inline void kvm_restore_lsx(struct loongarch_fpu *fpu) { }
+#endif
+
+#ifdef CONFIG_CPU_HAS_LASX
+int kvm_own_lasx(struct kvm_vcpu *vcpu);
+void kvm_save_lasx(struct loongarch_fpu *fpu);
+void kvm_restore_lasx(struct loongarch_fpu *fpu);
+#else
+static inline int kvm_own_lasx(struct kvm_vcpu *vcpu) { }
+static inline void kvm_save_lasx(struct loongarch_fpu *fpu) { }
+static inline void kvm_restore_lasx(struct loongarch_fpu *fpu) { }
+#endif
+
void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long hz);
void kvm_reset_timer(struct kvm_vcpu *vcpu);
void kvm_save_timer(struct kvm_vcpu *vcpu);
diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
index c6ad2ee6106c..923d0bd38294 100644
--- a/arch/loongarch/include/uapi/asm/kvm.h
+++ b/arch/loongarch/include/uapi/asm/kvm.h
@@ -79,6 +79,7 @@ struct kvm_fpu {
#define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT))
#define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG)
#define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG)
+#define KVM_LOONGARCH_VCPU_CPUCFG 0
struct kvm_debug_exit_arch {
};
diff --git a/arch/loongarch/kernel/fpu.S b/arch/loongarch/kernel/fpu.S
index d53ab10f4644..4382e36ae3d4 100644
--- a/arch/loongarch/kernel/fpu.S
+++ b/arch/loongarch/kernel/fpu.S
@@ -349,6 +349,7 @@ SYM_FUNC_START(_restore_lsx_upper)
lsx_restore_all_upper a0 t0 t1
jr ra
SYM_FUNC_END(_restore_lsx_upper)
+EXPORT_SYMBOL(_restore_lsx_upper)
SYM_FUNC_START(_init_lsx_upper)
lsx_init_all_upper t1
@@ -384,6 +385,7 @@ SYM_FUNC_START(_restore_lasx_upper)
lasx_restore_all_upper a0 t0 t1
jr ra
SYM_FUNC_END(_restore_lasx_upper)
+EXPORT_SYMBOL(_restore_lasx_upper)
SYM_FUNC_START(_init_lasx_upper)
lasx_init_all_upper t1
diff --git a/arch/loongarch/kernel/topology.c b/arch/loongarch/kernel/topology.c
index 3fd166006698..75d5c51a7cd3 100644
--- a/arch/loongarch/kernel/topology.c
+++ b/arch/loongarch/kernel/topology.c
@@ -10,47 +10,9 @@
#include <acpi/processor.h>
-static DEFINE_PER_CPU(struct cpu, cpu_devices);
-
#ifdef CONFIG_HOTPLUG_CPU
-int arch_register_cpu(int cpu)
+bool arch_cpu_is_hotpluggable(int cpu)
{
- int ret;
- struct cpu *c = &per_cpu(cpu_devices, cpu);
-
- c->hotpluggable = 1;
- ret = register_cpu(c, cpu);
- if (ret < 0)
- pr_warn("register_cpu %d failed (%d)\n", cpu, ret);
-
- return ret;
-}
-EXPORT_SYMBOL(arch_register_cpu);
-
-void arch_unregister_cpu(int cpu)
-{
- struct cpu *c = &per_cpu(cpu_devices, cpu);
-
- c->hotpluggable = 0;
- unregister_cpu(c);
+ return !io_master(cpu);
}
-EXPORT_SYMBOL(arch_unregister_cpu);
#endif
-
-static int __init topology_init(void)
-{
- int i, ret;
-
- for_each_present_cpu(i) {
- struct cpu *c = &per_cpu(cpu_devices, i);
-
- c->hotpluggable = !io_master(i);
- ret = register_cpu(c, i);
- if (ret < 0)
- pr_warn("topology_init: register_cpu %d failed (%d)\n", i, ret);
- }
-
- return 0;
-}
-
-subsys_initcall(topology_init);
diff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig
index fda425babfb2..61f7e33b1f95 100644
--- a/arch/loongarch/kvm/Kconfig
+++ b/arch/loongarch/kvm/Kconfig
@@ -22,14 +22,13 @@ config KVM
depends on AS_HAS_LVZ_EXTENSION
depends on HAVE_KVM
select HAVE_KVM_DIRTY_RING_ACQ_REL
- select HAVE_KVM_EVENTFD
select HAVE_KVM_VCPU_ASYNC_IOCTL
+ select KVM_COMMON
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
select KVM_GENERIC_HARDWARE_ENABLING
+ select KVM_GENERIC_MMU_NOTIFIER
select KVM_MMIO
select KVM_XFER_TO_GUEST_WORK
- select MMU_NOTIFIER
- select PREEMPT_NOTIFIERS
help
Support hosting virtualized guest machines using
hardware virtualization extensions. You will need
diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index ce8de3fa472c..ed1d89d53e2e 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -200,17 +200,8 @@ int kvm_emu_idle(struct kvm_vcpu *vcpu)
++vcpu->stat.idle_exits;
trace_kvm_exit_idle(vcpu, KVM_TRACE_EXIT_IDLE);
- if (!kvm_arch_vcpu_runnable(vcpu)) {
- /*
- * Switch to the software timer before halt-polling/blocking as
- * the guest's timer may be a break event for the vCPU, and the
- * hypervisor timer runs only when the CPU is in guest mode.
- * Switch before halt-polling so that KVM recognizes an expired
- * timer before blocking.
- */
- kvm_save_timer(vcpu);
- kvm_vcpu_block(vcpu);
- }
+ if (!kvm_arch_vcpu_runnable(vcpu))
+ kvm_vcpu_halt(vcpu);
return EMULATE_DONE;
}
@@ -643,6 +634,11 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
+ if (!kvm_guest_has_fpu(&vcpu->arch)) {
+ kvm_queue_exception(vcpu, EXCCODE_INE, 0);
+ return RESUME_GUEST;
+ }
+
/*
* If guest FPU not present, the FPU operation should have been
* treated as a reserved instruction!
@@ -660,6 +656,36 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu)
}
/*
+ * kvm_handle_lsx_disabled() - Guest used LSX while disabled in root.
+ * @vcpu: Virtual CPU context.
+ *
+ * Handle when the guest attempts to use LSX when it is disabled in the root
+ * context.
+ */
+static int kvm_handle_lsx_disabled(struct kvm_vcpu *vcpu)
+{
+ if (kvm_own_lsx(vcpu))
+ kvm_queue_exception(vcpu, EXCCODE_INE, 0);
+
+ return RESUME_GUEST;
+}
+
+/*
+ * kvm_handle_lasx_disabled() - Guest used LASX while disabled in root.
+ * @vcpu: Virtual CPU context.
+ *
+ * Handle when the guest attempts to use LASX when it is disabled in the root
+ * context.
+ */
+static int kvm_handle_lasx_disabled(struct kvm_vcpu *vcpu)
+{
+ if (kvm_own_lasx(vcpu))
+ kvm_queue_exception(vcpu, EXCCODE_INE, 0);
+
+ return RESUME_GUEST;
+}
+
+/*
* LoongArch KVM callback handling for unimplemented guest exiting
*/
static int kvm_fault_ni(struct kvm_vcpu *vcpu)
@@ -687,6 +713,8 @@ static exit_handle_fn kvm_fault_tables[EXCCODE_INT_START] = {
[EXCCODE_TLBS] = kvm_handle_write_fault,
[EXCCODE_TLBM] = kvm_handle_write_fault,
[EXCCODE_FPDIS] = kvm_handle_fpu_disabled,
+ [EXCCODE_LSXDIS] = kvm_handle_lsx_disabled,
+ [EXCCODE_LASXDIS] = kvm_handle_lasx_disabled,
[EXCCODE_GSPR] = kvm_handle_gspr,
};
diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c
index 1c1d5199500e..86a2f2d0cb27 100644
--- a/arch/loongarch/kvm/main.c
+++ b/arch/loongarch/kvm/main.c
@@ -287,7 +287,6 @@ int kvm_arch_hardware_enable(void)
if (env & CSR_GCFG_MATC_ROOT)
gcfg |= CSR_GCFG_MATC_ROOT;
- gcfg |= CSR_GCFG_TIT;
write_csr_gcfg(gcfg);
kvm_flush_tlb_all();
diff --git a/arch/loongarch/kvm/mmu.c b/arch/loongarch/kvm/mmu.c
index 80480df5f550..915f17527893 100644
--- a/arch/loongarch/kvm/mmu.c
+++ b/arch/loongarch/kvm/mmu.c
@@ -13,6 +13,16 @@
#include <asm/tlb.h>
#include <asm/kvm_mmu.h>
+static inline bool kvm_hugepage_capable(struct kvm_memory_slot *slot)
+{
+ return slot->arch.flags & KVM_MEM_HUGEPAGE_CAPABLE;
+}
+
+static inline bool kvm_hugepage_incapable(struct kvm_memory_slot *slot)
+{
+ return slot->arch.flags & KVM_MEM_HUGEPAGE_INCAPABLE;
+}
+
static inline void kvm_ptw_prepare(struct kvm *kvm, kvm_ptw_ctx *ctx)
{
ctx->level = kvm->arch.root_level;
@@ -365,6 +375,69 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
kvm_ptw_top(kvm->arch.pgd, start << PAGE_SHIFT, end << PAGE_SHIFT, &ctx);
}
+int kvm_arch_prepare_memory_region(struct kvm *kvm, const struct kvm_memory_slot *old,
+ struct kvm_memory_slot *new, enum kvm_mr_change change)
+{
+ gpa_t gpa_start;
+ hva_t hva_start;
+ size_t size, gpa_offset, hva_offset;
+
+ if ((change != KVM_MR_MOVE) && (change != KVM_MR_CREATE))
+ return 0;
+ /*
+ * Prevent userspace from creating a memory region outside of the
+ * VM GPA address space
+ */
+ if ((new->base_gfn + new->npages) > (kvm->arch.gpa_size >> PAGE_SHIFT))
+ return -ENOMEM;
+
+ new->arch.flags = 0;
+ size = new->npages * PAGE_SIZE;
+ gpa_start = new->base_gfn << PAGE_SHIFT;
+ hva_start = new->userspace_addr;
+ if (IS_ALIGNED(size, PMD_SIZE) && IS_ALIGNED(gpa_start, PMD_SIZE)
+ && IS_ALIGNED(hva_start, PMD_SIZE))
+ new->arch.flags |= KVM_MEM_HUGEPAGE_CAPABLE;
+ else {
+ /*
+ * Pages belonging to memslots that don't have the same
+ * alignment within a PMD for userspace and GPA cannot be
+ * mapped with PMD entries, because we'll end up mapping
+ * the wrong pages.
+ *
+ * Consider a layout like the following:
+ *
+ * memslot->userspace_addr:
+ * +-----+--------------------+--------------------+---+
+ * |abcde|fgh Stage-1 block | Stage-1 block tv|xyz|
+ * +-----+--------------------+--------------------+---+
+ *
+ * memslot->base_gfn << PAGE_SIZE:
+ * +---+--------------------+--------------------+-----+
+ * |abc|def Stage-2 block | Stage-2 block |tvxyz|
+ * +---+--------------------+--------------------+-----+
+ *
+ * If we create those stage-2 blocks, we'll end up with this
+ * incorrect mapping:
+ * d -> f
+ * e -> g
+ * f -> h
+ */
+ gpa_offset = gpa_start & (PMD_SIZE - 1);
+ hva_offset = hva_start & (PMD_SIZE - 1);
+ if (gpa_offset != hva_offset) {
+ new->arch.flags |= KVM_MEM_HUGEPAGE_INCAPABLE;
+ } else {
+ if (gpa_offset == 0)
+ gpa_offset = PMD_SIZE;
+ if ((size + gpa_offset) < (PMD_SIZE * 2))
+ new->arch.flags |= KVM_MEM_HUGEPAGE_INCAPABLE;
+ }
+ }
+
+ return 0;
+}
+
void kvm_arch_commit_memory_region(struct kvm *kvm,
struct kvm_memory_slot *old,
const struct kvm_memory_slot *new,
@@ -562,47 +635,23 @@ out:
}
static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot,
- unsigned long hva, unsigned long map_size, bool write)
+ unsigned long hva, bool write)
{
- size_t size;
- gpa_t gpa_start;
- hva_t uaddr_start, uaddr_end;
+ hva_t start, end;
/* Disable dirty logging on HugePages */
if (kvm_slot_dirty_track_enabled(memslot) && write)
return false;
- size = memslot->npages * PAGE_SIZE;
- gpa_start = memslot->base_gfn << PAGE_SHIFT;
- uaddr_start = memslot->userspace_addr;
- uaddr_end = uaddr_start + size;
+ if (kvm_hugepage_capable(memslot))
+ return true;
- /*
- * Pages belonging to memslots that don't have the same alignment
- * within a PMD for userspace and GPA cannot be mapped with stage-2
- * PMD entries, because we'll end up mapping the wrong pages.
- *
- * Consider a layout like the following:
- *
- * memslot->userspace_addr:
- * +-----+--------------------+--------------------+---+
- * |abcde|fgh Stage-1 block | Stage-1 block tv|xyz|
- * +-----+--------------------+--------------------+---+
- *
- * memslot->base_gfn << PAGE_SIZE:
- * +---+--------------------+--------------------+-----+
- * |abc|def Stage-2 block | Stage-2 block |tvxyz|
- * +---+--------------------+--------------------+-----+
- *
- * If we create those stage-2 blocks, we'll end up with this incorrect
- * mapping:
- * d -> f
- * e -> g
- * f -> h
- */
- if ((gpa_start & (map_size - 1)) != (uaddr_start & (map_size - 1)))
+ if (kvm_hugepage_incapable(memslot))
return false;
+ start = memslot->userspace_addr;
+ end = start + memslot->npages * PAGE_SIZE;
+
/*
* Next, let's make sure we're not trying to map anything not covered
* by the memslot. This means we have to prohibit block size mappings
@@ -615,8 +664,7 @@ static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot,
* userspace_addr or the base_gfn, as both are equally aligned (per
* the check above) and equally sized.
*/
- return (hva & ~(map_size - 1)) >= uaddr_start &&
- (hva & ~(map_size - 1)) + map_size <= uaddr_end;
+ return (hva >= ALIGN(start, PMD_SIZE)) && (hva < ALIGN_DOWN(end, PMD_SIZE));
}
/*
@@ -842,7 +890,7 @@ retry:
/* Disable dirty logging on HugePages */
level = 0;
- if (!fault_supports_huge_mapping(memslot, hva, PMD_SIZE, write)) {
+ if (!fault_supports_huge_mapping(memslot, hva, write)) {
level = 0;
} else {
level = host_pfn_mapping_level(kvm, gfn, memslot);
@@ -901,12 +949,6 @@ void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
{
}
-int kvm_arch_prepare_memory_region(struct kvm *kvm, const struct kvm_memory_slot *old,
- struct kvm_memory_slot *new, enum kvm_mr_change change)
-{
- return 0;
-}
-
void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
const struct kvm_memory_slot *memslot)
{
diff --git a/arch/loongarch/kvm/switch.S b/arch/loongarch/kvm/switch.S
index 0ed9040307b7..ba976509bfe8 100644
--- a/arch/loongarch/kvm/switch.S
+++ b/arch/loongarch/kvm/switch.S
@@ -245,6 +245,37 @@ SYM_FUNC_START(kvm_restore_fpu)
jr ra
SYM_FUNC_END(kvm_restore_fpu)
+#ifdef CONFIG_CPU_HAS_LSX
+SYM_FUNC_START(kvm_save_lsx)
+ fpu_save_csr a0 t1
+ fpu_save_cc a0 t1 t2
+ lsx_save_data a0 t1
+ jr ra
+SYM_FUNC_END(kvm_save_lsx)
+
+SYM_FUNC_START(kvm_restore_lsx)
+ lsx_restore_data a0 t1
+ fpu_restore_cc a0 t1 t2
+ fpu_restore_csr a0 t1 t2
+ jr ra
+SYM_FUNC_END(kvm_restore_lsx)
+#endif
+
+#ifdef CONFIG_CPU_HAS_LASX
+SYM_FUNC_START(kvm_save_lasx)
+ fpu_save_csr a0 t1
+ fpu_save_cc a0 t1 t2
+ lasx_save_data a0 t1
+ jr ra
+SYM_FUNC_END(kvm_save_lasx)
+
+SYM_FUNC_START(kvm_restore_lasx)
+ lasx_restore_data a0 t1
+ fpu_restore_cc a0 t1 t2
+ fpu_restore_csr a0 t1 t2
+ jr ra
+SYM_FUNC_END(kvm_restore_lasx)
+#endif
.section ".rodata"
SYM_DATA(kvm_exception_size, .quad kvm_exc_entry_end - kvm_exc_entry)
SYM_DATA(kvm_enter_guest_size, .quad kvm_enter_guest_end - kvm_enter_guest)
diff --git a/arch/loongarch/kvm/timer.c b/arch/loongarch/kvm/timer.c
index 284bf553fefe..111328f60872 100644
--- a/arch/loongarch/kvm/timer.c
+++ b/arch/loongarch/kvm/timer.c
@@ -65,40 +65,23 @@ void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long timer_hz)
}
/*
- * Restore hard timer state and enable guest to access timer registers
- * without trap, should be called with irq disabled
- */
-void kvm_acquire_timer(struct kvm_vcpu *vcpu)
-{
- unsigned long cfg;
-
- cfg = read_csr_gcfg();
- if (!(cfg & CSR_GCFG_TIT))
- return;
-
- /* Enable guest access to hard timer */
- write_csr_gcfg(cfg & ~CSR_GCFG_TIT);
-
- /*
- * Freeze the soft-timer and sync the guest stable timer with it. We do
- * this with interrupts disabled to avoid latency.
- */
- hrtimer_cancel(&vcpu->arch.swtimer);
-}
-
-/*
* Restore soft timer state from saved context.
*/
void kvm_restore_timer(struct kvm_vcpu *vcpu)
{
- unsigned long cfg, delta, period;
+ unsigned long cfg, estat;
+ unsigned long ticks, delta, period;
ktime_t expire, now;
struct loongarch_csrs *csr = vcpu->arch.csr;
/*
* Set guest stable timer cfg csr
+ * Disable timer before restore estat CSR register, avoid to
+ * get invalid timer interrupt for old timer cfg
*/
cfg = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG);
+
+ write_gcsr_timercfg(0);
kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ESTAT);
kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TCFG);
if (!(cfg & CSR_TCFG_EN)) {
@@ -108,23 +91,55 @@ void kvm_restore_timer(struct kvm_vcpu *vcpu)
}
/*
+ * Freeze the soft-timer and sync the guest stable timer with it.
+ */
+ hrtimer_cancel(&vcpu->arch.swtimer);
+
+ /*
+ * From LoongArch Reference Manual Volume 1 Chapter 7.6.2
+ * If oneshot timer is fired, CSR TVAL will be -1, there are two
+ * conditions:
+ * 1) timer is fired during exiting to host
+ * 2) timer is fired and vm is doing timer irq, and then exiting to
+ * host. Host should not inject timer irq to avoid spurious
+ * timer interrupt again
+ */
+ ticks = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TVAL);
+ estat = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT);
+ if (!(cfg & CSR_TCFG_PERIOD) && (ticks > cfg)) {
+ /*
+ * Writing 0 to LOONGARCH_CSR_TVAL will inject timer irq
+ * and set CSR TVAL with -1
+ */
+ write_gcsr_timertick(0);
+
+ /*
+ * Writing CSR_TINTCLR_TI to LOONGARCH_CSR_TINTCLR will clear
+ * timer interrupt, and CSR TVAL keeps unchanged with -1, it
+ * avoids spurious timer interrupt
+ */
+ if (!(estat & CPU_TIMER))
+ gcsr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR);
+ return;
+ }
+
+ /*
* Set remainder tick value if not expired
*/
+ delta = 0;
now = ktime_get();
expire = vcpu->arch.expire;
if (ktime_before(now, expire))
delta = ktime_to_tick(vcpu, ktime_sub(expire, now));
- else {
- if (cfg & CSR_TCFG_PERIOD) {
- period = cfg & CSR_TCFG_VAL;
- delta = ktime_to_tick(vcpu, ktime_sub(now, expire));
- delta = period - (delta % period);
- } else
- delta = 0;
+ else if (cfg & CSR_TCFG_PERIOD) {
+ period = cfg & CSR_TCFG_VAL;
+ delta = ktime_to_tick(vcpu, ktime_sub(now, expire));
+ delta = period - (delta % period);
+
/*
* Inject timer here though sw timer should inject timer
* interrupt async already, since sw timer may be cancelled
- * during injecting intr async in function kvm_acquire_timer
+ * during injecting intr async
*/
kvm_queue_irq(vcpu, INT_TI);
}
@@ -139,27 +154,41 @@ void kvm_restore_timer(struct kvm_vcpu *vcpu)
*/
static void _kvm_save_timer(struct kvm_vcpu *vcpu)
{
- unsigned long ticks, delta;
+ unsigned long ticks, delta, cfg;
ktime_t expire;
struct loongarch_csrs *csr = vcpu->arch.csr;
+ cfg = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG);
ticks = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TVAL);
- delta = tick_to_ns(vcpu, ticks);
- expire = ktime_add_ns(ktime_get(), delta);
- vcpu->arch.expire = expire;
- if (ticks) {
+
+ /*
+ * From LoongArch Reference Manual Volume 1 Chapter 7.6.2
+ * If period timer is fired, CSR TVAL will be reloaded from CSR TCFG
+ * If oneshot timer is fired, CSR TVAL will be -1
+ * Here judge one-shot timer fired by checking whether TVAL is larger
+ * than TCFG
+ */
+ if (ticks < cfg) {
+ delta = tick_to_ns(vcpu, ticks);
+ expire = ktime_add_ns(ktime_get(), delta);
+ vcpu->arch.expire = expire;
+
/*
- * Update hrtimer to use new timeout
* HRTIMER_MODE_PINNED is suggested since vcpu may run in
* the same physical cpu in next time
*/
- hrtimer_cancel(&vcpu->arch.swtimer);
hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
- } else
+ } else if (vcpu->stat.generic.blocking) {
/*
- * Inject timer interrupt so that hall polling can dectect and exit
+ * Inject timer interrupt so that halt polling can dectect and exit.
+ * VCPU is scheduled out already and sleeps in rcuwait queue and
+ * will not poll pending events again. kvm_queue_irq() is not enough,
+ * hrtimer swtimer should be used here.
*/
- kvm_queue_irq(vcpu, INT_TI);
+ expire = ktime_add_ns(ktime_get(), 10);
+ vcpu->arch.expire = expire;
+ hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
+ }
}
/*
@@ -168,21 +197,15 @@ static void _kvm_save_timer(struct kvm_vcpu *vcpu)
*/
void kvm_save_timer(struct kvm_vcpu *vcpu)
{
- unsigned long cfg;
struct loongarch_csrs *csr = vcpu->arch.csr;
preempt_disable();
- cfg = read_csr_gcfg();
- if (!(cfg & CSR_GCFG_TIT)) {
- /* Disable guest use of hard timer */
- write_csr_gcfg(cfg | CSR_GCFG_TIT);
-
- /* Save hard timer state */
- kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TCFG);
- kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TVAL);
- if (kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG) & CSR_TCFG_EN)
- _kvm_save_timer(vcpu);
- }
+
+ /* Save hard timer state */
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TCFG);
+ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TVAL);
+ if (kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG) & CSR_TCFG_EN)
+ _kvm_save_timer(vcpu);
/* Save timer-related state to vCPU context */
kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ESTAT);
diff --git a/arch/loongarch/kvm/trace.h b/arch/loongarch/kvm/trace.h
index a1e35d655418..c2484ad4cffa 100644
--- a/arch/loongarch/kvm/trace.h
+++ b/arch/loongarch/kvm/trace.h
@@ -102,6 +102,8 @@ TRACE_EVENT(kvm_exit_gspr,
#define KVM_TRACE_AUX_DISCARD 4
#define KVM_TRACE_AUX_FPU 1
+#define KVM_TRACE_AUX_LSX 2
+#define KVM_TRACE_AUX_LASX 3
#define kvm_trace_symbol_aux_op \
{ KVM_TRACE_AUX_SAVE, "save" }, \
@@ -111,7 +113,9 @@ TRACE_EVENT(kvm_exit_gspr,
{ KVM_TRACE_AUX_DISCARD, "discard" }
#define kvm_trace_symbol_aux_state \
- { KVM_TRACE_AUX_FPU, "FPU" }
+ { KVM_TRACE_AUX_FPU, "FPU" }, \
+ { KVM_TRACE_AUX_LSX, "LSX" }, \
+ { KVM_TRACE_AUX_LASX, "LASX" }
TRACE_EVENT(kvm_aux,
TP_PROTO(struct kvm_vcpu *vcpu, unsigned int op,
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 73d0c2b9c1a5..27701991886d 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -95,7 +95,6 @@ static int kvm_pre_enter_guest(struct kvm_vcpu *vcpu)
* check vmid before vcpu enter guest
*/
local_irq_disable();
- kvm_acquire_timer(vcpu);
kvm_deliver_intr(vcpu);
kvm_deliver_exception(vcpu);
/* Make sure the vcpu mode has been written */
@@ -187,8 +186,15 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
{
- return kvm_pending_timer(vcpu) ||
+ int ret;
+
+ /* Protect from TOD sync and vcpu_load/put() */
+ preempt_disable();
+ ret = kvm_pending_timer(vcpu) ||
kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT) & (1 << INT_TI);
+ preempt_enable();
+
+ return ret;
}
int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu)
@@ -244,23 +250,6 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
return -EINVAL;
}
-/**
- * kvm_migrate_count() - Migrate timer.
- * @vcpu: Virtual CPU.
- *
- * Migrate hrtimer to the current CPU by cancelling and restarting it
- * if the hrtimer is active.
- *
- * Must be called when the vCPU is migrated to a different CPU, so that
- * the timer can interrupt the guest at the new CPU, and the timer irq can
- * be delivered to the vCPU.
- */
-static void kvm_migrate_count(struct kvm_vcpu *vcpu)
-{
- if (hrtimer_cancel(&vcpu->arch.swtimer))
- hrtimer_restart(&vcpu->arch.swtimer);
-}
-
static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val)
{
unsigned long gintc;
@@ -309,6 +298,76 @@ static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val)
return ret;
}
+static int _kvm_get_cpucfg(int id, u64 *v)
+{
+ int ret = 0;
+
+ if (id < 0 && id >= KVM_MAX_CPUCFG_REGS)
+ return -EINVAL;
+
+ switch (id) {
+ case 2:
+ /* Return CPUCFG2 features which have been supported by KVM */
+ *v = CPUCFG2_FP | CPUCFG2_FPSP | CPUCFG2_FPDP |
+ CPUCFG2_FPVERS | CPUCFG2_LLFTP | CPUCFG2_LLFTPREV |
+ CPUCFG2_LAM;
+ /*
+ * If LSX is supported by CPU, it is also supported by KVM,
+ * as we implement it.
+ */
+ if (cpu_has_lsx)
+ *v |= CPUCFG2_LSX;
+ /*
+ * if LASX is supported by CPU, it is also supported by KVM,
+ * as we implement it.
+ */
+ if (cpu_has_lasx)
+ *v |= CPUCFG2_LASX;
+
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int kvm_check_cpucfg(int id, u64 val)
+{
+ u64 mask;
+ int ret = 0;
+
+ if (id < 0 && id >= KVM_MAX_CPUCFG_REGS)
+ return -EINVAL;
+
+ if (_kvm_get_cpucfg(id, &mask))
+ return ret;
+
+ switch (id) {
+ case 2:
+ /* CPUCFG2 features checking */
+ if (val & ~mask)
+ /* The unsupported features should not be set */
+ ret = -EINVAL;
+ else if (!(val & CPUCFG2_LLFTP))
+ /* The LLFTP must be set, as guest must has a constant timer */
+ ret = -EINVAL;
+ else if ((val & CPUCFG2_FP) && (!(val & CPUCFG2_FPSP) || !(val & CPUCFG2_FPDP)))
+ /* Single and double float point must both be set when enable FP */
+ ret = -EINVAL;
+ else if ((val & CPUCFG2_LSX) && !(val & CPUCFG2_FP))
+ /* FP should be set when enable LSX */
+ ret = -EINVAL;
+ else if ((val & CPUCFG2_LASX) && !(val & CPUCFG2_LSX))
+ /* LSX, FP should be set when enable LASX, and FP has been checked before. */
+ ret = -EINVAL;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
static int kvm_get_one_reg(struct kvm_vcpu *vcpu,
const struct kvm_one_reg *reg, u64 *v)
{
@@ -378,10 +437,10 @@ static int kvm_set_one_reg(struct kvm_vcpu *vcpu,
break;
case KVM_REG_LOONGARCH_CPUCFG:
id = KVM_GET_IOC_CPUCFG_IDX(reg->id);
- if (id >= 0 && id < KVM_MAX_CPUCFG_REGS)
- vcpu->arch.cpucfg[id] = (u32)v;
- else
- ret = -EINVAL;
+ ret = kvm_check_cpucfg(id, v);
+ if (ret)
+ break;
+ vcpu->arch.cpucfg[id] = (u32)v;
break;
case KVM_REG_LOONGARCH_KVM:
switch (reg->id) {
@@ -471,10 +530,94 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
return -EINVAL;
}
+static int kvm_loongarch_cpucfg_has_attr(struct kvm_vcpu *vcpu,
+ struct kvm_device_attr *attr)
+{
+ switch (attr->attr) {
+ case 2:
+ return 0;
+ default:
+ return -ENXIO;
+ }
+
+ return -ENXIO;
+}
+
+static int kvm_loongarch_vcpu_has_attr(struct kvm_vcpu *vcpu,
+ struct kvm_device_attr *attr)
+{
+ int ret = -ENXIO;
+
+ switch (attr->group) {
+ case KVM_LOONGARCH_VCPU_CPUCFG:
+ ret = kvm_loongarch_cpucfg_has_attr(vcpu, attr);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static int kvm_loongarch_get_cpucfg_attr(struct kvm_vcpu *vcpu,
+ struct kvm_device_attr *attr)
+{
+ int ret = 0;
+ uint64_t val;
+ uint64_t __user *uaddr = (uint64_t __user *)attr->addr;
+
+ ret = _kvm_get_cpucfg(attr->attr, &val);
+ if (ret)
+ return ret;
+
+ put_user(val, uaddr);
+
+ return ret;
+}
+
+static int kvm_loongarch_vcpu_get_attr(struct kvm_vcpu *vcpu,
+ struct kvm_device_attr *attr)
+{
+ int ret = -ENXIO;
+
+ switch (attr->group) {
+ case KVM_LOONGARCH_VCPU_CPUCFG:
+ ret = kvm_loongarch_get_cpucfg_attr(vcpu, attr);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static int kvm_loongarch_cpucfg_set_attr(struct kvm_vcpu *vcpu,
+ struct kvm_device_attr *attr)
+{
+ return -ENXIO;
+}
+
+static int kvm_loongarch_vcpu_set_attr(struct kvm_vcpu *vcpu,
+ struct kvm_device_attr *attr)
+{
+ int ret = -ENXIO;
+
+ switch (attr->group) {
+ case KVM_LOONGARCH_VCPU_CPUCFG:
+ ret = kvm_loongarch_cpucfg_set_attr(vcpu, attr);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
long kvm_arch_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
long r;
+ struct kvm_device_attr attr;
void __user *argp = (void __user *)arg;
struct kvm_vcpu *vcpu = filp->private_data;
@@ -514,6 +657,27 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
break;
}
+ case KVM_HAS_DEVICE_ATTR: {
+ r = -EFAULT;
+ if (copy_from_user(&attr, argp, sizeof(attr)))
+ break;
+ r = kvm_loongarch_vcpu_has_attr(vcpu, &attr);
+ break;
+ }
+ case KVM_GET_DEVICE_ATTR: {
+ r = -EFAULT;
+ if (copy_from_user(&attr, argp, sizeof(attr)))
+ break;
+ r = kvm_loongarch_vcpu_get_attr(vcpu, &attr);
+ break;
+ }
+ case KVM_SET_DEVICE_ATTR: {
+ r = -EFAULT;
+ if (copy_from_user(&attr, argp, sizeof(attr)))
+ break;
+ r = kvm_loongarch_vcpu_set_attr(vcpu, &attr);
+ break;
+ }
default:
r = -ENOIOCTLCMD;
break;
@@ -561,12 +725,96 @@ void kvm_own_fpu(struct kvm_vcpu *vcpu)
preempt_enable();
}
+#ifdef CONFIG_CPU_HAS_LSX
+/* Enable LSX and restore context */
+int kvm_own_lsx(struct kvm_vcpu *vcpu)
+{
+ if (!kvm_guest_has_fpu(&vcpu->arch) || !kvm_guest_has_lsx(&vcpu->arch))
+ return -EINVAL;
+
+ preempt_disable();
+
+ /* Enable LSX for guest */
+ set_csr_euen(CSR_EUEN_LSXEN | CSR_EUEN_FPEN);
+ switch (vcpu->arch.aux_inuse & KVM_LARCH_FPU) {
+ case KVM_LARCH_FPU:
+ /*
+ * Guest FPU state already loaded,
+ * only restore upper LSX state
+ */
+ _restore_lsx_upper(&vcpu->arch.fpu);
+ break;
+ default:
+ /* Neither FP or LSX already active,
+ * restore full LSX state
+ */
+ kvm_restore_lsx(&vcpu->arch.fpu);
+ break;
+ }
+
+ trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LSX);
+ vcpu->arch.aux_inuse |= KVM_LARCH_LSX | KVM_LARCH_FPU;
+ preempt_enable();
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_CPU_HAS_LASX
+/* Enable LASX and restore context */
+int kvm_own_lasx(struct kvm_vcpu *vcpu)
+{
+ if (!kvm_guest_has_fpu(&vcpu->arch) || !kvm_guest_has_lsx(&vcpu->arch) || !kvm_guest_has_lasx(&vcpu->arch))
+ return -EINVAL;
+
+ preempt_disable();
+
+ set_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN);
+ switch (vcpu->arch.aux_inuse & (KVM_LARCH_FPU | KVM_LARCH_LSX)) {
+ case KVM_LARCH_LSX:
+ case KVM_LARCH_LSX | KVM_LARCH_FPU:
+ /* Guest LSX state already loaded, only restore upper LASX state */
+ _restore_lasx_upper(&vcpu->arch.fpu);
+ break;
+ case KVM_LARCH_FPU:
+ /* Guest FP state already loaded, only restore upper LSX & LASX state */
+ _restore_lsx_upper(&vcpu->arch.fpu);
+ _restore_lasx_upper(&vcpu->arch.fpu);
+ break;
+ default:
+ /* Neither FP or LSX already active, restore full LASX state */
+ kvm_restore_lasx(&vcpu->arch.fpu);
+ break;
+ }
+
+ trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LASX);
+ vcpu->arch.aux_inuse |= KVM_LARCH_LASX | KVM_LARCH_LSX | KVM_LARCH_FPU;
+ preempt_enable();
+
+ return 0;
+}
+#endif
+
/* Save context and disable FPU */
void kvm_lose_fpu(struct kvm_vcpu *vcpu)
{
preempt_disable();
- if (vcpu->arch.aux_inuse & KVM_LARCH_FPU) {
+ if (vcpu->arch.aux_inuse & KVM_LARCH_LASX) {
+ kvm_save_lasx(&vcpu->arch.fpu);
+ vcpu->arch.aux_inuse &= ~(KVM_LARCH_LSX | KVM_LARCH_FPU | KVM_LARCH_LASX);
+ trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_LASX);
+
+ /* Disable LASX & LSX & FPU */
+ clear_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN);
+ } else if (vcpu->arch.aux_inuse & KVM_LARCH_LSX) {
+ kvm_save_lsx(&vcpu->arch.fpu);
+ vcpu->arch.aux_inuse &= ~(KVM_LARCH_LSX | KVM_LARCH_FPU);
+ trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_LSX);
+
+ /* Disable LSX & FPU */
+ clear_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN);
+ } else if (vcpu->arch.aux_inuse & KVM_LARCH_FPU) {
kvm_save_fpu(&vcpu->arch.fpu);
vcpu->arch.aux_inuse &= ~KVM_LARCH_FPU;
trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_FPU);
@@ -789,17 +1037,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
unsigned long flags;
local_irq_save(flags);
- if (vcpu->arch.last_sched_cpu != cpu) {
- kvm_debug("[%d->%d]KVM vCPU[%d] switch\n",
- vcpu->arch.last_sched_cpu, cpu, vcpu->vcpu_id);
- /*
- * Migrate the timer interrupt to the current CPU so that it
- * always interrupts the guest and synchronously triggers a
- * guest timer interrupt.
- */
- kvm_migrate_count(vcpu);
- }
-
/* Restore guest state to registers */
_kvm_vcpu_load(vcpu, cpu);
local_irq_restore(flags);
diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c
index 3a74d493eb3e..17b2987c2bf5 100644
--- a/arch/m68k/emu/nfcon.c
+++ b/arch/m68k/emu/nfcon.c
@@ -23,9 +23,9 @@ static int stderr_id;
static struct tty_port nfcon_tty_port;
static struct tty_driver *nfcon_tty_driver;
-static void nfputs(const char *str, unsigned int count)
+static void nfputs(const u8 *str, size_t count)
{
- char buf[68];
+ u8 buf[68];
unsigned long phys = virt_to_phys(buf);
buf[64] = 0;
diff --git a/arch/m68k/include/asm/cacheflush_mm.h b/arch/m68k/include/asm/cacheflush_mm.h
index ed12358c4783..9a71b0148461 100644
--- a/arch/m68k/include/asm/cacheflush_mm.h
+++ b/arch/m68k/include/asm/cacheflush_mm.h
@@ -191,6 +191,7 @@ extern void cache_push_v(unsigned long vaddr, int len);
#define flush_cache_all() __flush_cache_all()
#define flush_cache_vmap(start, end) flush_cache_all()
+#define flush_cache_vmap_early(start, end) do { } while (0)
#define flush_cache_vunmap(start, end) flush_cache_all()
static inline void flush_cache_mm(struct mm_struct *mm)
diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig
index 7b2d7f6f23c0..4da7bc4ac4a3 100644
--- a/arch/microblaze/configs/mmu_defconfig
+++ b/arch/microblaze/configs/mmu_defconfig
@@ -3,11 +3,9 @@ CONFIG_POSIX_MQUEUE=y
CONFIG_AUDIT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_EXPERT=y
# CONFIG_BASE_FULL is not set
CONFIG_KALLSYMS_ALL=y
-CONFIG_EXPERT=y
CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR=1
CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR=1
CONFIG_XILINX_MICROBLAZE0_USE_BARREL=1
@@ -20,7 +18,6 @@ CONFIG_CMDLINE_FORCE=y
CONFIG_HIGHMEM=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
CONFIG_PARTITION_ADVANCED=y
# CONFIG_EFI_PARTITION is not set
CONFIG_CMA=y
@@ -28,6 +25,10 @@ CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
# CONFIG_IPV6 is not set
CONFIG_BRIDGE=m
CONFIG_PCI=y
@@ -43,6 +44,7 @@ CONFIG_NETDEVICES=y
CONFIG_XILINX_EMACLITE=y
CONFIG_XILINX_AXI_EMAC=y
CONFIG_XILINX_LL_TEMAC=y
+CONFIG_MARVELL_PHY=y
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
@@ -77,14 +79,13 @@ CONFIG_TMPFS=y
CONFIG_CRAMFS=y
CONFIG_ROMFS_FS=y
CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
CONFIG_CIFS=y
-CONFIG_CIFS_STATS2=y
CONFIG_ENCRYPTED_KEYS=y
CONFIG_DMA_CMA=y
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
CONFIG_KGDB=y
CONFIG_KGDB_TESTS=y
CONFIG_KGDB_KDB=y
-CONFIG_DEBUG_SLAB=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEBUG_SPINLOCK=y
diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c
index f521874ebb07..67f067706af2 100644
--- a/arch/mips/alchemy/devboards/db1200.c
+++ b/arch/mips/alchemy/devboards/db1200.c
@@ -847,7 +847,7 @@ int __init db1200_dev_setup(void)
i2c_register_board_info(0, db1200_i2c_devs,
ARRAY_SIZE(db1200_i2c_devs));
spi_register_board_info(db1200_spi_devs,
- ARRAY_SIZE(db1200_i2c_devs));
+ ARRAY_SIZE(db1200_spi_devs));
/* SWITCHES: S6.8 I2C/SPI selector (OFF=I2C ON=SPI)
* S6.7 AC97/I2S selector (OFF=AC97 ON=I2S)
diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c
index fd91d9c9a252..6c6837181f55 100644
--- a/arch/mips/alchemy/devboards/db1550.c
+++ b/arch/mips/alchemy/devboards/db1550.c
@@ -589,7 +589,7 @@ int __init db1550_dev_setup(void)
i2c_register_board_info(0, db1550_i2c_devs,
ARRAY_SIZE(db1550_i2c_devs));
spi_register_board_info(db1550_spi_devs,
- ARRAY_SIZE(db1550_i2c_devs));
+ ARRAY_SIZE(db1550_spi_devs));
c = clk_get(NULL, "psc0_intclk");
if (!IS_ERR(c)) {
diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c
index 437a737c01dd..46994f9bb821 100644
--- a/arch/mips/bcm47xx/buttons.c
+++ b/arch/mips/bcm47xx/buttons.c
@@ -147,21 +147,21 @@ static const struct gpio_keys_button
bcm47xx_buttons_buffalo_whr_g125[] __initconst = {
BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
BCM47XX_GPIO_KEY(4, KEY_RESTART),
- BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */
+ BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode switch */
};
static const struct gpio_keys_button
bcm47xx_buttons_buffalo_whr_g54s[] __initconst = {
BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
BCM47XX_GPIO_KEY_H(4, KEY_RESTART),
- BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */
+ BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode switch */
};
static const struct gpio_keys_button
bcm47xx_buttons_buffalo_whr_hp_g54[] __initconst = {
BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
BCM47XX_GPIO_KEY(4, KEY_RESTART),
- BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */
+ BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode switch */
};
static const struct gpio_keys_button
diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c
index 86a6e2590866..3144965fb7dc 100644
--- a/arch/mips/bcm63xx/clk.c
+++ b/arch/mips/bcm63xx/clk.c
@@ -174,7 +174,7 @@ static void enetsw_set(struct clk *clk, int enable)
}
if (enable) {
- /* reset switch core afer clock change */
+ /* reset switch core after clock change */
bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1);
msleep(10);
bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0);
@@ -304,7 +304,7 @@ static void xtm_set(struct clk *clk, int enable)
bcm_hwclock_set(CKCTL_6368_SAR_EN, enable);
if (enable) {
- /* reset sar core afer clock change */
+ /* reset sar core after clock change */
bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1);
mdelay(1);
bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0);
diff --git a/arch/mips/boot/compressed/dbg.c b/arch/mips/boot/compressed/dbg.c
index 2f1ac38fe1cc..95405292accd 100644
--- a/arch/mips/boot/compressed/dbg.c
+++ b/arch/mips/boot/compressed/dbg.c
@@ -3,7 +3,7 @@
* MIPS-specific debug support for pre-boot environment
*
* NOTE: putc() is board specific, if your board have a 16550 compatible uart,
- * please select SYS_SUPPORTS_ZBOOT_UART16550 for your machine. othewise, you
+ * please select SYS_SUPPORTS_ZBOOT_UART16550 for your machine. otherwise, you
* need to implement your own putc().
*/
#include <linux/compiler.h>
diff --git a/arch/mips/boot/compressed/head.S b/arch/mips/boot/compressed/head.S
index 5795d0af1e1b..d237a834b85e 100644
--- a/arch/mips/boot/compressed/head.S
+++ b/arch/mips/boot/compressed/head.S
@@ -25,8 +25,8 @@
/* Clear BSS */
PTR_LA a0, _edata
PTR_LA a2, _end
-1: sw zero, 0(a0)
- addiu a0, a0, 4
+1: PTR_S zero, 0(a0)
+ PTR_ADDIU a0, a0, PTRSIZE
bne a2, a0, 1b
PTR_LA a0, (.heap) /* heap address */
diff --git a/arch/mips/boot/elf2ecoff.c b/arch/mips/boot/elf2ecoff.c
index 6972b97235da..549c5d6ef6d7 100644
--- a/arch/mips/boot/elf2ecoff.c
+++ b/arch/mips/boot/elf2ecoff.c
@@ -443,7 +443,7 @@ int main(int argc, char *argv[])
efh.f_symptr = 0;
efh.f_nsyms = 0;
efh.f_opthdr = sizeof eah;
- efh.f_flags = 0x100f; /* Stripped, not sharable. */
+ efh.f_flags = 0x100f; /* Stripped, not shareable. */
memset(esecs, 0, sizeof esecs);
strcpy(esecs[0].s_name, ".text");
diff --git a/arch/mips/cavium-octeon/csrc-octeon.c b/arch/mips/cavium-octeon/csrc-octeon.c
index 124817609ce0..af62a210a40b 100644
--- a/arch/mips/cavium-octeon/csrc-octeon.c
+++ b/arch/mips/cavium-octeon/csrc-octeon.c
@@ -113,7 +113,7 @@ static struct clocksource clocksource_mips = {
unsigned long long notrace sched_clock(void)
{
- /* 64-bit arithmatic can overflow, so use 128-bit. */
+ /* 64-bit arithmetic can overflow, so use 128-bit. */
u64 t1, t2, t3;
unsigned long long rv;
u64 mult = clocksource_mips.mult;
diff --git a/arch/mips/cavium-octeon/executive/cvmx-boot-vector.c b/arch/mips/cavium-octeon/executive/cvmx-boot-vector.c
index b7019d21808e..76446db66def 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-boot-vector.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-boot-vector.c
@@ -143,7 +143,7 @@ static void cvmx_boot_vector_init(void *mem)
uint64_t v = _cvmx_bootvector_data[i];
if (OCTEON_IS_OCTEON1PLUS() && (i == 0 || i == 7))
- v &= 0xffffffff00000000ull; /* KScratch not availble. */
+ v &= 0xffffffff00000000ull; /* KScratch not available */
cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, i * 8);
cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, v);
}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
index 334bf8e577e5..628ebdf4b9c5 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
@@ -264,7 +264,7 @@ int64_t cvmx_bootmem_phy_alloc(uint64_t req_size, uint64_t address_min,
* Convert !0 address_min and 0 address_max to special case of
* range that specifies an exact memory block to allocate. Do
* this before other checks and adjustments so that this
- * tranformation will be validated.
+ * transformation will be validated.
*/
if (address_min && !address_max)
address_max = address_min + req_size;
diff --git a/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c b/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c
index aa7bbf8d0df5..042a6bc44b5c 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c
@@ -192,7 +192,7 @@ cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id,
}
/*
- * Shutdown a queue a free it's command buffers to the FPA. The
+ * Shutdown a queue and free its command buffers to the FPA. The
* hardware connected to the queue must be stopped before this
* function is called.
*
@@ -285,7 +285,7 @@ int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id)
/*
* Return the command buffer to be written to. The purpose of this
- * function is to allow CVMX routine access t othe low level buffer
+ * function is to allow CVMX routine access to the low level buffer
* for initial hardware setup. User applications should not call this
* function directly.
*
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-jtag.c b/arch/mips/cavium-octeon/executive/cvmx-helper-jtag.c
index 607b4e659579..1fceb7fd2c94 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-helper-jtag.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-jtag.c
@@ -103,7 +103,7 @@ uint32_t cvmx_helper_qlm_jtag_shift(int qlm, int bits, uint32_t data)
/**
* Shift long sequences of zeros into the QLM JTAG chain. It is
* common to need to shift more than 32 bits of zeros into the
- * chain. This function is a convience wrapper around
+ * chain. This function is a convenience wrapper around
* cvmx_helper_qlm_jtag_shift() to shift more than 32 bits of
* zeros at a time.
*
diff --git a/arch/mips/cavium-octeon/executive/cvmx-pko.c b/arch/mips/cavium-octeon/executive/cvmx-pko.c
index 15faca494c80..6e70b859a0ac 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-pko.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-pko.c
@@ -615,7 +615,7 @@ int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst)
/*
* Each packet has a 12 bytes of interframe gap, an 8 byte
* preamble, and a 4 byte CRC. These are not included in the
- * per word count. Multiply by 8 to covert to bits and divide
+ * per word count. Multiply by 8 to convert to bits and divide
* by 256 for limit granularity.
*/
pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256;
diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c
index f76783c24338..5e1dd4e6e82f 100644
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -973,7 +973,7 @@ int __init octeon_prune_device_tree(void)
* zero.
*/
- /* Asume that CS1 immediately follows. */
+ /* Assume that CS1 immediately follows. */
mio_boot_reg_cfg.u64 =
cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs + 1));
region1_base = mio_boot_reg_cfg.s.base << 16;
diff --git a/arch/mips/fw/arc/promlib.c b/arch/mips/fw/arc/promlib.c
index 5e9e840a9314..93e1e70393ee 100644
--- a/arch/mips/fw/arc/promlib.c
+++ b/arch/mips/fw/arc/promlib.c
@@ -15,11 +15,11 @@
/*
* For 64bit kernels working with a 32bit ARC PROM pointer arguments
* for ARC calls need to reside in CKEG0/1. But as soon as the kernel
- * switches to it's first kernel thread stack is set to an address in
+ * switches to its first kernel thread stack is set to an address in
* XKPHYS, so anything on stack can't be used anymore. This is solved
- * by using a * static declartion variables are put into BSS, which is
+ * by using a * static declaration variables are put into BSS, which is
* linked to a CKSEG0 address. Since this is only used on UP platforms
- * there is not spinlock needed
+ * there is no spinlock needed
*/
#define O32_STATIC static
#else
diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h
index f36c2519ed97..1f14132b3fc9 100644
--- a/arch/mips/include/asm/cacheflush.h
+++ b/arch/mips/include/asm/cacheflush.h
@@ -97,6 +97,8 @@ static inline void flush_cache_vmap(unsigned long start, unsigned long end)
__flush_cache_vmap();
}
+#define flush_cache_vmap_early(start, end) do { } while (0)
+
extern void (*__flush_cache_vunmap)(void);
static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
diff --git a/arch/mips/include/asm/debug.h b/arch/mips/include/asm/debug.h
index c7013e1cb53f..e70392429246 100644
--- a/arch/mips/include/asm/debug.h
+++ b/arch/mips/include/asm/debug.h
@@ -10,7 +10,7 @@
/*
* mips_debugfs_dir corresponds to the "mips" directory at the top level
- * of the DebugFS hierarchy. MIPS-specific DebugFS entires should be
+ * of the DebugFS hierarchy. MIPS-specific DebugFS entries should be
* placed beneath this directory.
*/
extern struct dentry *mips_debugfs_dir;
diff --git a/arch/mips/include/asm/dmi.h b/arch/mips/include/asm/dmi.h
index 27415a288adf..dc397f630c66 100644
--- a/arch/mips/include/asm/dmi.h
+++ b/arch/mips/include/asm/dmi.h
@@ -5,7 +5,7 @@
#include <linux/io.h>
#include <linux/memblock.h>
-#define dmi_early_remap(x, l) ioremap_cache(x, l)
+#define dmi_early_remap(x, l) ioremap(x, l)
#define dmi_early_unmap(x, l) iounmap(x)
#define dmi_remap(x, l) ioremap_cache(x, l)
#define dmi_unmap(x) iounmap(x)
diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
index 85bbd967e05f..af58d6ae06b8 100644
--- a/arch/mips/include/asm/io.h
+++ b/arch/mips/include/asm/io.h
@@ -159,7 +159,7 @@ void iounmap(const volatile void __iomem *addr);
* address is not guaranteed to be usable directly as a virtual
* address.
*
- * This version of ioremap ensures that the memory is marked cachable by
+ * This version of ioremap ensures that the memory is marked cacheable by
* the CPU. Also enables full write-combining. Useful for some
* memory-like regions on I/O busses.
*/
@@ -177,7 +177,7 @@ void iounmap(const volatile void __iomem *addr);
* address is not guaranteed to be usable directly as a virtual
* address.
*
- * This version of ioremap ensures that the memory is marked uncachable
+ * This version of ioremap ensures that the memory is marked uncacheable
* but accelerated by means of write-combining feature. It is specifically
* useful for PCIe prefetchable windows, which may vastly improve a
* communications performance. If it was determined on boot stage, what
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index 54a85f1d4f2c..179f320cc231 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -810,8 +810,6 @@ int kvm_mips_mkclean_gpa_pt(struct kvm *kvm, gfn_t start_gfn, gfn_t end_gfn);
pgd_t *kvm_pgd_alloc(void);
void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);
-#define KVM_ARCH_WANT_MMU_NOTIFIER
-
/* Emulation */
enum emulation_result update_pc(struct kvm_vcpu *vcpu, u32 cause);
int kvm_get_badinstr(u32 *opc, struct kvm_vcpu *vcpu, u32 *out);
diff --git a/arch/mips/include/asm/mach-au1x00/au1000_dma.h b/arch/mips/include/asm/mach-au1x00/au1000_dma.h
index 0a0cd4270c6f..b82e513c8523 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000_dma.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000_dma.h
@@ -259,7 +259,7 @@ static inline void set_dma_mode(unsigned int dmanr, unsigned int mode)
if (!chan)
return;
/*
- * set_dma_mode is only allowed to change endianess, direction,
+ * set_dma_mode is only allowed to change endianness, direction,
* transfer size, device FIFO width, and coherency settings.
* Make sure anything else is masked off.
*/
diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
index 82bc2766e2ec..d820b481ac56 100644
--- a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
@@ -435,7 +435,7 @@ static inline void alchemy_gpio2_disable_int(int gpio2)
/**
* alchemy_gpio2_enable - Activate GPIO2 block.
*
- * The GPIO2 block must be enabled excplicitly to work. On systems
+ * The GPIO2 block must be enabled explicitly to work. On systems
* where this isn't done by the bootloader, this macro can be used.
*/
static inline void alchemy_gpio2_enable(void)
diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
index 5855ba1bd1ec..40eaa72e54d0 100644
--- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
+++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
@@ -55,7 +55,7 @@ extern __iomem void *ltq_sys1_membase;
#define ltq_sys1_w32_mask(clear, set, reg) \
ltq_sys1_w32((ltq_sys1_r32(reg) & ~(clear)) | (set), reg)
-/* allow the gpio and pinctrl drivers to talk to eachother */
+/* allow the gpio and pinctrl drivers to talk to each other */
extern int pinctrl_falcon_get_range_size(int id);
extern void pinctrl_falcon_add_gpio_range(struct pinctrl_gpio_range *range);
diff --git a/arch/mips/include/asm/mach-loongson64/loongson_hwmon.h b/arch/mips/include/asm/mach-loongson64/loongson_hwmon.h
index 545f91f2ae16..721eafc4644e 100644
--- a/arch/mips/include/asm/mach-loongson64/loongson_hwmon.h
+++ b/arch/mips/include/asm/mach-loongson64/loongson_hwmon.h
@@ -42,7 +42,7 @@ struct loongson_fan_policy {
/* period between two check. (Unit: S) */
u8 adjust_period;
- /* fan adjust usually depend on a temprature input */
+ /* fan adjust usually depend on a temperature input */
get_temp_fun depend_temp;
/* up_step/down_step used when type is STEP_SPEED_POLICY */
diff --git a/arch/mips/include/asm/mach-loongson64/loongson_regs.h b/arch/mips/include/asm/mach-loongson64/loongson_regs.h
index b5be7511f6cd..fec767507604 100644
--- a/arch/mips/include/asm/mach-loongson64/loongson_regs.h
+++ b/arch/mips/include/asm/mach-loongson64/loongson_regs.h
@@ -227,7 +227,7 @@ static inline void csr_writeq(u64 val, u32 reg)
#define LOONGSON_CSR_NODECNT 0x408
#define LOONGSON_CSR_CPUTEMP 0x428
-/* PerCore CSR, only accessable by local cores */
+/* PerCore CSR, only accessible by local cores */
#define LOONGSON_CSR_IPI_STATUS 0x1000
#define LOONGSON_CSR_IPI_EN 0x1004
#define LOONGSON_CSR_IPI_SET 0x1008
diff --git a/arch/mips/include/asm/mach-malta/spaces.h b/arch/mips/include/asm/mach-malta/spaces.h
index d7e54971ec66..1ce4ba97852f 100644
--- a/arch/mips/include/asm/mach-malta/spaces.h
+++ b/arch/mips/include/asm/mach-malta/spaces.h
@@ -23,13 +23,13 @@
* The kernel is still located in 0x80000000(kseg0). However,
* the physical mask has been shifted to 0x80000000 which exploits the alias
* on the Malta board. As a result of which, we override the __pa_symbol
- * to peform direct mapping from virtual to physical addresses. In other
+ * to perform direct mapping from virtual to physical addresses. In other
* words, the 0x80000000 virtual address maps to 0x80000000 physical address
* which in turn aliases to 0x0. We do this in order to be able to use a flat
* 2GB of memory (0x80000000 - 0xffffffff) so we can avoid the I/O hole in
* 0x10000000 - 0x1fffffff.
* The last 64KB of physical memory are reserved for correct HIGHMEM
- * macros arithmetics.
+ * macros arithmetic.
*
*/
diff --git a/arch/mips/include/asm/mips-boards/bonito64.h b/arch/mips/include/asm/mips-boards/bonito64.h
index 5368891d424b..31a31fe78d77 100644
--- a/arch/mips/include/asm/mips-boards/bonito64.h
+++ b/arch/mips/include/asm/mips-boards/bonito64.h
@@ -16,7 +16,7 @@
*/
/* Revision 1.48 autogenerated on 08/17/99 15:20:01 */
-/* This bonito64 version editted from bonito.h Revision 1.48 on 11/09/00 */
+/* This bonito64 version edited from bonito.h Revision 1.48 on 11/09/00 */
#ifndef _ASM_MIPS_BOARDS_BONITO64_H
#define _ASM_MIPS_BOARDS_BONITO64_H
diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h
index b54453f1648c..5f3a7a9f42bf 100644
--- a/arch/mips/include/asm/mips-cpc.h
+++ b/arch/mips/include/asm/mips-cpc.h
@@ -22,7 +22,7 @@ extern void __iomem *mips_cpc_base;
* the CPC
*
* Returns the default physical base address of the Cluster Power Controller
- * memory mapped registers. This is platform dependant & must therefore be
+ * memory mapped registers. This is platform dependent & must therefore be
* implemented per-platform.
*/
extern phys_addr_t mips_cpc_default_phys_base(void);
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index 2d53704d9f24..ec58cb76d076 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -98,7 +98,7 @@
/*
* R4640/R4650 cp0 register names. These registers are listed
- * here only for completeness; without MMU these CPUs are not useable
+ * here only for completeness; without MMU these CPUs are not usable
* by Linux. A future ELKS port might take make Linux run on them
* though ...
*/
@@ -461,7 +461,7 @@
#define EXCCODE_THREAD 25 /* Thread exceptions (MT) */
#define EXCCODE_DSPDIS 26 /* DSP disabled exception */
#define EXCCODE_GE 27 /* Virtualized guest exception (VZ) */
-#define EXCCODE_CACHEERR 30 /* Parity/ECC occured on a core */
+#define EXCCODE_CACHEERR 30 /* Parity/ECC occurred on a core */
/* Implementation specific trap codes used by MIPS cores */
#define MIPS_EXCCODE_TLBPAR 16 /* TLB parity error exception */
diff --git a/arch/mips/include/asm/octeon/cvmx-bootinfo.h b/arch/mips/include/asm/octeon/cvmx-bootinfo.h
index c1c0b3230e0a..028bf1d6daee 100644
--- a/arch/mips/include/asm/octeon/cvmx-bootinfo.h
+++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h
@@ -114,7 +114,7 @@ struct cvmx_bootinfo {
/*
* flags indicating various configuration options. These
- * flags supercede the 'flags' variable and should be used
+ * flags supersede the 'flags' variable and should be used
* instead if available.
*/
uint32_t config_flags;
diff --git a/arch/mips/include/asm/octeon/cvmx-cmd-queue.h b/arch/mips/include/asm/octeon/cvmx-cmd-queue.h
index a07a36f7d814..67e1b2162b19 100644
--- a/arch/mips/include/asm/octeon/cvmx-cmd-queue.h
+++ b/arch/mips/include/asm/octeon/cvmx-cmd-queue.h
@@ -145,7 +145,7 @@ typedef struct {
/**
* This structure contains the global state of all command queues.
* It is stored in a bootmem named block and shared by all
- * applications running on Octeon. Tickets are stored in a differnet
+ * applications running on Octeon. Tickets are stored in a different
* cache line that queue information to reduce the contention on the
* ll/sc used to get a ticket. If this is not the case, the update
* of queue state causes the ll/sc to fail quite often.
@@ -172,7 +172,7 @@ cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id,
int pool_size);
/**
- * Shutdown a queue a free it's command buffers to the FPA. The
+ * Shutdown a queue and free its command buffers to the FPA. The
* hardware connected to the queue must be stopped before this
* function is called.
*
@@ -194,7 +194,7 @@ int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id);
/**
* Return the command buffer to be written to. The purpose of this
- * function is to allow CVMX routine access t othe low level buffer
+ * function is to allow CVMX routine access to the low level buffer
* for initial hardware setup. User applications should not call this
* function directly.
*
diff --git a/arch/mips/include/asm/octeon/cvmx-pko.h b/arch/mips/include/asm/octeon/cvmx-pko.h
index 5fec8476e421..f18a7f24daf8 100644
--- a/arch/mips/include/asm/octeon/cvmx-pko.h
+++ b/arch/mips/include/asm/octeon/cvmx-pko.h
@@ -91,7 +91,7 @@ typedef enum {
} cvmx_pko_status_t;
/**
- * This enumeration represents the differnet locking modes supported by PKO.
+ * This enumeration represents the different locking modes supported by PKO.
*/
typedef enum {
/*
diff --git a/arch/mips/include/asm/octeon/cvmx-pow.h b/arch/mips/include/asm/octeon/cvmx-pow.h
index a3b23811e0c3..21b4378244fa 100644
--- a/arch/mips/include/asm/octeon/cvmx-pow.h
+++ b/arch/mips/include/asm/octeon/cvmx-pow.h
@@ -1342,7 +1342,7 @@ static inline void cvmx_pow_tag_sw_wait(void)
* This function does NOT wait for previous tag switches to complete,
* so the caller must ensure that there is not a pending tag switch.
*
- * @wait: When set, call stalls until work becomes avaiable, or times out.
+ * @wait: When set, call stalls until work becomes available, or times out.
* If not set, returns immediately.
*
* Returns: the WQE pointer from POW. Returns NULL if no work
@@ -1376,7 +1376,7 @@ static inline struct cvmx_wqe *cvmx_pow_work_request_sync_nocheck(cvmx_pow_wait_
* This function waits for any previous tag switch to complete before
* requesting the new work.
*
- * @wait: When set, call stalls until work becomes avaiable, or times out.
+ * @wait: When set, call stalls until work becomes available, or times out.
* If not set, returns immediately.
*
* Returns: the WQE pointer from POW. Returns NULL if no work
diff --git a/arch/mips/include/asm/octeon/octeon-model.h b/arch/mips/include/asm/octeon/octeon-model.h
index 6c68517c2770..e53b61a8e32f 100644
--- a/arch/mips/include/asm/octeon/octeon-model.h
+++ b/arch/mips/include/asm/octeon/octeon-model.h
@@ -54,7 +54,7 @@
#define OM_CHECK_SUBMODEL 0x02000000
/* Match all models previous than the one specified */
#define OM_MATCH_PREVIOUS_MODELS 0x04000000
-/* Ignores the minor revison on newer parts */
+/* Ignores the minor revision on newer parts */
#define OM_IGNORE_MINOR_REVISION 0x08000000
#define OM_FLAG_MASK 0xff000000
@@ -226,7 +226,7 @@
#define OCTEON_CN52XX_PASS2 OCTEON_CN52XX_PASS2_X
/*
- * CN3XXX models with old revision enconding
+ * CN3XXX models with old revision encoding
*/
#define OCTEON_CN38XX_PASS1 0x000d0000
#define OCTEON_CN38XX_PASS2 0x000d0001
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index 5978a8dfb917..ef9585d96f6b 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -173,7 +173,7 @@ static inline unsigned long ___pa(unsigned long x)
if (IS_ENABLED(CONFIG_64BIT)) {
/*
* For MIPS64 the virtual address may either be in one of
- * the compatibility segements ckseg0 or ckseg1, or it may
+ * the compatibility segments ckseg0 or ckseg1, or it may
* be in xkphys.
*/
return x < CKSEG0 ? XPHYSADDR(x) : CPHYSADDR(x);
diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h
index 3fd6e22c108b..d993df6302dc 100644
--- a/arch/mips/include/asm/pci.h
+++ b/arch/mips/include/asm/pci.h
@@ -23,7 +23,7 @@
#ifdef CONFIG_PCI_DRIVERS_LEGACY
/*
- * Each pci channel is a top-level PCI bus seem by CPU. A machine with
+ * Each PCI channel is a top-level PCI bus seem by CPU. A machine with
* multiple PCI channels may have multiple PCI host controllers or a
* single controller supporting multiple channels.
*/
diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h
index 421e78c30253..088623ba7b8b 100644
--- a/arch/mips/include/asm/pgtable-bits.h
+++ b/arch/mips/include/asm/pgtable-bits.h
@@ -201,7 +201,7 @@ enum pgtable_bits {
* The final layouts of the PTE bits are:
*
* 64-bit, R1 or earlier: CCC D V G [S H] M A W R P
- * 32-bit, R1 or earler: CCC D V G M A W R P
+ * 32-bit, R1 or earlier: CCC D V G M A W R P
* 64-bit, R2 or later: CCC D V G RI/R XI [S H] M A W P
* 32-bit, R2 or later: CCC D V G RI/R XI M A W P
*/
diff --git a/arch/mips/include/asm/sgi/mc.h b/arch/mips/include/asm/sgi/mc.h
index 3a070cec97e7..5e96f9d32624 100644
--- a/arch/mips/include/asm/sgi/mc.h
+++ b/arch/mips/include/asm/sgi/mc.h
@@ -96,7 +96,7 @@ struct sgimc_regs {
volatile u32 lbursttp; /* Time period for long bursts */
/* MC chip can drive up to 4 bank 4 SIMMs each. All SIMMs in bank must
- * be the same size. The size encoding for supported SIMMs is bellow */
+ * be the same size. The size encoding for supported SIMMs is below */
u32 _unused11[9];
volatile u32 mconfig0; /* Memory config register zero */
u32 _unused12;
diff --git a/arch/mips/include/asm/sn/klconfig.h b/arch/mips/include/asm/sn/klconfig.h
index 117f85e4bef5..3d1670b3e052 100644
--- a/arch/mips/include/asm/sn/klconfig.h
+++ b/arch/mips/include/asm/sn/klconfig.h
@@ -851,7 +851,7 @@ typedef union kldev_s { /* for device structure allocation */
/*
* TBD - Allocation issues.
*
- * Do we need to Mark off sepatate heaps for lboard_t, rboard_t, component,
+ * Do we need to Mark off separate heaps for lboard_t, rboard_t, component,
* errinfo and allocate from them, or have a single heap and allocate all
* structures from it. Debug is easier in the former method since we can
* dump all similar structs in one command, but there will be lots of holes,
diff --git a/arch/mips/include/asm/sync.h b/arch/mips/include/asm/sync.h
index aabd097933fe..44c04a82d0b7 100644
--- a/arch/mips/include/asm/sync.h
+++ b/arch/mips/include/asm/sync.h
@@ -19,7 +19,7 @@
*
* Ordering barriers can be more efficient than completion barriers, since:
*
- * a) Ordering barriers only require memory access instructions which preceed
+ * a) Ordering barriers only require memory access instructions which precede
* them in program order (older instructions) to reach a point in the
* load/store datapath beyond which reordering is not possible before
* allowing memory access instructions which follow them (younger
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index ecae7470faa4..b9d76e8ac5a2 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -27,7 +27,7 @@ struct thread_info {
unsigned long flags; /* low level flags */
unsigned long tp_value; /* thread pointer */
__u32 cpu; /* current CPU */
- int preempt_count; /* 0 => preemptable, <0 => BUG */
+ int preempt_count; /* 0 => preemptible, <0 => BUG */
struct pt_regs *regs;
long syscall; /* syscall number */
};
diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h
index 2e107886f97a..7ef06dcdc46e 100644
--- a/arch/mips/include/asm/timex.h
+++ b/arch/mips/include/asm/timex.h
@@ -46,7 +46,7 @@ typedef unsigned int cycles_t;
*
* There is a suggested workaround and also the erratum can't strike if
* the compare interrupt isn't being used as the clock source device.
- * However for now the implementaton of this function doesn't get these
+ * However for now the implementation of this function doesn't get these
* fine details right.
*/
static inline int can_use_mips_counter(unsigned int prid)
diff --git a/arch/mips/include/asm/vdso/vdso.h b/arch/mips/include/asm/vdso/vdso.h
index a327ca21270e..6cd88191fefa 100644
--- a/arch/mips/include/asm/vdso/vdso.h
+++ b/arch/mips/include/asm/vdso/vdso.h
@@ -32,7 +32,7 @@ static inline unsigned long get_vdso_base(void)
#else
/*
* Get the base load address of the VDSO. We have to avoid generating
- * relocations and references to the GOT because ld.so does not peform
+ * relocations and references to the GOT because ld.so does not perform
* relocations on the VDSO. We use the current offset from the VDSO base
* and perform a PC-relative branch which gives the absolute address in
* ra, and take the difference. The assembler chokes on
diff --git a/arch/mips/include/uapi/asm/mman.h b/arch/mips/include/uapi/asm/mman.h
index c6e1fc77c996..9c48d9a21aa0 100644
--- a/arch/mips/include/uapi/asm/mman.h
+++ b/arch/mips/include/uapi/asm/mman.h
@@ -88,7 +88,7 @@
#define MADV_HUGEPAGE 14 /* Worth backing with hugepages */
#define MADV_NOHUGEPAGE 15 /* Not worth backing with hugepages */
-#define MADV_DONTDUMP 16 /* Explicity exclude from the core dump,
+#define MADV_DONTDUMP 16 /* Explicitly exclude from core dump,
overrides the coredump filter bits */
#define MADV_DODUMP 17 /* Clear the MADV_NODUMP flag */
diff --git a/arch/mips/include/uapi/asm/msgbuf.h b/arch/mips/include/uapi/asm/msgbuf.h
index 128af72f2dfe..d546642fc67e 100644
--- a/arch/mips/include/uapi/asm/msgbuf.h
+++ b/arch/mips/include/uapi/asm/msgbuf.h
@@ -62,7 +62,7 @@ struct msqid64_ds {
unsigned long __unused5;
};
#else
-#warning no endianess set
+#warning no endianness set
#endif
#endif /* _ASM_MSGBUF_H */
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index de7460c3a72e..bda7f193baab 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -1138,7 +1138,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
* This processor doesn't have an MMU, so it's not
* "real easy" to run Linux on it. It is left purely
* for documentation. Commented out because it shares
- * it's c0_prid id number with the TX3900.
+ * its c0_prid id number with the TX3900.
*/
c->cputype = CPU_R4650;
__cpu_name[cpu] = "R4650";
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index b6de8e88c1bd..a572ce36a24f 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -272,18 +272,17 @@ NESTED(except_vec_vi, 0, sp)
.set push
.set noreorder
PTR_LA v1, except_vec_vi_handler
-FEXPORT(except_vec_vi_lui)
- lui v0, 0 /* Patched */
jr v1
FEXPORT(except_vec_vi_ori)
- ori v0, 0 /* Patched */
+ ori v0, zero, 0 /* Offset in vi_handlers[] */
.set pop
END(except_vec_vi)
EXPORT(except_vec_vi_end)
/*
* Common Vectored Interrupt code
- * Complete the register saves and invoke the handler which is passed in $v0
+ * Complete the register saves and invoke the handler, $v0 holds
+ * offset into vi_handlers[]
*/
NESTED(except_vec_vi_handler, 0, sp)
SAVE_TEMP
@@ -331,6 +330,7 @@ NESTED(except_vec_vi_handler, 0, sp)
/* Save task's sp on IRQ stack so that unwinding can follow it */
LONG_S s1, 0(sp)
2:
+ PTR_L v0, vi_handlers(v0)
jalr v0
/* Restore sp */
diff --git a/arch/mips/kernel/kprobes.c b/arch/mips/kernel/kprobes.c
index 316b27d0d2fb..dc39f5b3fb83 100644
--- a/arch/mips/kernel/kprobes.c
+++ b/arch/mips/kernel/kprobes.c
@@ -55,7 +55,7 @@ NOKPROBE_SYMBOL(insn_has_delayslot);
* one; putting breakpoint on top of atomic ll/sc pair is bad idea;
* so we need to prevent it and refuse kprobes insertion for such
* instructions; cannot do much about breakpoint in the middle of
- * ll/sc pair; it is upto user to avoid those places
+ * ll/sc pair; it is up to user to avoid those places
*/
static int insn_has_ll_or_sc(union mips_instruction insn)
{
diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c
index f88ce78e13e3..6062e6fa589a 100644
--- a/arch/mips/kernel/prom.c
+++ b/arch/mips/kernel/prom.c
@@ -28,6 +28,8 @@ __init void mips_set_machine_name(const char *name)
strscpy(mips_machine_name, name, sizeof(mips_machine_name));
pr_info("MIPS: machine is %s\n", mips_get_machine_name());
+
+ dump_stack_set_arch_desc(name);
}
char *mips_get_machine_name(void)
diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c
index 58fc8d089402..7eeeaf1ff95d 100644
--- a/arch/mips/kernel/relocate.c
+++ b/arch/mips/kernel/relocate.c
@@ -380,7 +380,7 @@ void *__init relocate_kernel(void)
}
#endif /* CONFIG_USE_OF */
- /* Copy the kernel to it's new location */
+ /* Copy the kernel to its new location */
memcpy(loc_new, &_text, kernel_length);
/* Perform relocations on the new kernel */
diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S
index 8f0a7263a9d6..de894a0211d7 100644
--- a/arch/mips/kernel/relocate_kernel.S
+++ b/arch/mips/kernel/relocate_kernel.S
@@ -70,7 +70,7 @@ copy_word:
done:
#ifdef CONFIG_SMP
/* kexec_flag reset is signal to other CPUs what kernel
- was moved to it's location. Note - we need relocated address
+ was moved to its location. Note - we need relocated address
of kexec_flag. */
bal 1f
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 328426c3ed6f..9c30de151597 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -147,7 +147,7 @@ static unsigned long __init init_initrd(void)
/*
* Board specific code or command line parser should have
* already set up initrd_start and initrd_end. In these cases
- * perfom sanity checks and use them if all looks good.
+ * perform sanity checks and use them if all looks good.
*/
if (!initrd_start || initrd_end <= initrd_start)
goto disable;
@@ -322,11 +322,11 @@ static void __init bootmem_init(void)
panic("Incorrect memory mapping !!!");
if (max_pfn > PFN_DOWN(HIGHMEM_START)) {
+ max_low_pfn = PFN_DOWN(HIGHMEM_START);
#ifdef CONFIG_HIGHMEM
- highstart_pfn = PFN_DOWN(HIGHMEM_START);
+ highstart_pfn = max_low_pfn;
highend_pfn = max_pfn;
#else
- max_low_pfn = PFN_DOWN(HIGHMEM_START);
max_pfn = max_low_pfn;
#endif
}
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index ccbf580827f6..4a10f18a8806 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -570,7 +570,7 @@ void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
return (void __user __force *)(-1UL);
/*
- * FPU emulator may have it's own trampoline active just
+ * FPU emulator may have its own trampoline active just
* above the user stack, 16-bytes before the next lowest
* 16 byte boundary. Try to avoid trashing it.
*/
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index c58c0c3c5b40..dec6878b35f6 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -2055,108 +2055,71 @@ static void do_default_vi(void)
panic("Caught unexpected vectored interrupt.");
}
-static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
+void *set_vi_handler(int n, vi_handler_t addr)
{
+ extern const u8 except_vec_vi[];
+ extern const u8 except_vec_vi_ori[], except_vec_vi_end[];
+ extern const u8 rollback_except_vec_vi[];
unsigned long handler;
unsigned long old_handler = vi_handlers[n];
int srssets = current_cpu_data.srsets;
u16 *h;
unsigned char *b;
+ const u8 *vec_start;
+ int ori_offset;
+ int handler_len;
BUG_ON(!cpu_has_veic && !cpu_has_vint);
if (addr == NULL) {
handler = (unsigned long) do_default_vi;
- srs = 0;
} else
handler = (unsigned long) addr;
vi_handlers[n] = handler;
b = (unsigned char *)(ebase + 0x200 + n*VECTORSPACING);
- if (srs >= srssets)
- panic("Shadow register set %d not supported", srs);
-
if (cpu_has_veic) {
if (board_bind_eic_interrupt)
- board_bind_eic_interrupt(n, srs);
+ board_bind_eic_interrupt(n, 0);
} else if (cpu_has_vint) {
/* SRSMap is only defined if shadow sets are implemented */
if (srssets > 1)
- change_c0_srsmap(0xf << n*4, srs << n*4);
+ change_c0_srsmap(0xf << n*4, 0 << n*4);
}
- if (srs == 0) {
- /*
- * If no shadow set is selected then use the default handler
- * that does normal register saving and standard interrupt exit
- */
- extern const u8 except_vec_vi[], except_vec_vi_lui[];
- extern const u8 except_vec_vi_ori[], except_vec_vi_end[];
- extern const u8 rollback_except_vec_vi[];
- const u8 *vec_start = using_rollback_handler() ?
- rollback_except_vec_vi : except_vec_vi;
+ vec_start = using_rollback_handler() ? rollback_except_vec_vi :
+ except_vec_vi;
#if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN)
- const int lui_offset = except_vec_vi_lui - vec_start + 2;
- const int ori_offset = except_vec_vi_ori - vec_start + 2;
+ ori_offset = except_vec_vi_ori - vec_start + 2;
#else
- const int lui_offset = except_vec_vi_lui - vec_start;
- const int ori_offset = except_vec_vi_ori - vec_start;
+ ori_offset = except_vec_vi_ori - vec_start;
#endif
- const int handler_len = except_vec_vi_end - vec_start;
-
- if (handler_len > VECTORSPACING) {
- /*
- * Sigh... panicing won't help as the console
- * is probably not configured :(
- */
- panic("VECTORSPACING too small");
- }
+ handler_len = except_vec_vi_end - vec_start;
- set_handler(((unsigned long)b - ebase), vec_start,
-#ifdef CONFIG_CPU_MICROMIPS
- (handler_len - 1));
-#else
- handler_len);
-#endif
- h = (u16 *)(b + lui_offset);
- *h = (handler >> 16) & 0xffff;
- h = (u16 *)(b + ori_offset);
- *h = (handler & 0xffff);
- local_flush_icache_range((unsigned long)b,
- (unsigned long)(b+handler_len));
- }
- else {
+ if (handler_len > VECTORSPACING) {
/*
- * In other cases jump directly to the interrupt handler. It
- * is the handler's responsibility to save registers if required
- * (eg hi/lo) and return from the exception using "eret".
+ * Sigh... panicing won't help as the console
+ * is probably not configured :(
*/
- u32 insn;
+ panic("VECTORSPACING too small");
+ }
- h = (u16 *)b;
- /* j handler */
+ set_handler(((unsigned long)b - ebase), vec_start,
#ifdef CONFIG_CPU_MICROMIPS
- insn = 0xd4000000 | (((u32)handler & 0x07ffffff) >> 1);
+ (handler_len - 1));
#else
- insn = 0x08000000 | (((u32)handler & 0x0fffffff) >> 2);
+ handler_len);
#endif
- h[0] = (insn >> 16) & 0xffff;
- h[1] = insn & 0xffff;
- h[2] = 0;
- h[3] = 0;
- local_flush_icache_range((unsigned long)b,
- (unsigned long)(b+8));
- }
+ /* insert offset into vi_handlers[] */
+ h = (u16 *)(b + ori_offset);
+ *h = n * sizeof(handler);
+ local_flush_icache_range((unsigned long)b,
+ (unsigned long)(b+handler_len));
return (void *)old_handler;
}
-void *set_vi_handler(int n, vi_handler_t addr)
-{
- return set_vi_srs_handler(n, addr, 0);
-}
-
/*
* Timer interrupt
*/
@@ -2416,7 +2379,7 @@ void __init trap_init(void)
set_except_vector(i, handle_reserved);
/*
- * Copy the EJTAG debug exception vector handler code to it's final
+ * Copy the EJTAG debug exception vector handler code to its final
* destination.
*/
if (cpu_has_ejtag && board_ejtag_handler_setup)
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index e9a0cfd02ae2..737d0d4fdcd3 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -6,9 +6,9 @@
* Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved.
* Copyright (C) 2013 Imagination Technologies Ltd.
*
- * VPE spport module for loading a MIPS SP program into VPE1. The SP
+ * VPE support module for loading a MIPS SP program into VPE1. The SP
* environment is rather simple since there are no TLBs. It needs
- * to be relocatable (or partiall linked). Initialize your stack in
+ * to be relocatable (or partially linked). Initialize your stack in
* the startup-code. The loader looks for the symbol __start and sets
* up the execution to resume from there. To load and run, simply do
* a cat SP 'binary' to the /dev/vpe1 device.
diff --git a/arch/mips/kvm/Kconfig b/arch/mips/kvm/Kconfig
index a8cdba75f98d..18e7a17d5115 100644
--- a/arch/mips/kvm/Kconfig
+++ b/arch/mips/kvm/Kconfig
@@ -20,13 +20,11 @@ config KVM
depends on HAVE_KVM
depends on MIPS_FP_SUPPORT
select EXPORT_UASM
- select PREEMPT_NOTIFIERS
+ select KVM_COMMON
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
- select HAVE_KVM_EVENTFD
select HAVE_KVM_VCPU_ASYNC_IOCTL
select KVM_MMIO
- select MMU_NOTIFIER
- select INTERVAL_TREE
+ select KVM_GENERIC_MMU_NOTIFIER
select KVM_GENERIC_HARDWARE_ENABLING
help
Support for hosting Guest kernels.
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c
index e64372b8f66a..0feec52222fb 100644
--- a/arch/mips/kvm/emulate.c
+++ b/arch/mips/kvm/emulate.c
@@ -531,7 +531,7 @@ static void kvm_mips_resume_hrtimer(struct kvm_vcpu *vcpu,
* to be used for a period of time, but the exact ktime corresponding to the
* final Count that must be restored is not known.
*
- * It is gauranteed that a timer interrupt immediately after restore will be
+ * It is guaranteed that a timer interrupt immediately after restore will be
* handled, but not if CP0_Compare is exactly at @count. That case should
* already be handled when the hardware timer state is saved.
*
diff --git a/arch/mips/loongson2ef/common/platform.c b/arch/mips/loongson2ef/common/platform.c
index 0084820cffaa..b10300a527af 100644
--- a/arch/mips/loongson2ef/common/platform.c
+++ b/arch/mips/loongson2ef/common/platform.c
@@ -17,7 +17,7 @@ static int __init loongson2_cpufreq_init(void)
{
struct cpuinfo_mips *c = &current_cpu_data;
- /* Only 2F revision and it's successors support CPUFreq */
+ /* Only 2F revision and its successors support CPUFreq */
if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_LOONGSON2F)
return platform_device_register(&loongson2_cpufreq_device);
diff --git a/arch/mips/loongson64/smp.c b/arch/mips/loongson64/smp.c
index 498bdc1bb0ed..5a990cdef91a 100644
--- a/arch/mips/loongson64/smp.c
+++ b/arch/mips/loongson64/smp.c
@@ -516,7 +516,7 @@ static void __init loongson3_prepare_cpus(unsigned int max_cpus)
}
/*
- * Setup the PC, SP, and GP of a secondary processor and start it runing!
+ * Setup the PC, SP, and GP of a secondary processor and start it running!
*/
static int loongson3_boot_secondary(int cpu, struct task_struct *idle)
{
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index b45bf026ee55..10413b6f6662 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -1650,7 +1650,7 @@ static void coherency_setup(void)
/*
* c0_status.cu=0 specifies that updates by the sc instruction use
- * the coherency mode specified by the TLB; 1 means cachable
+ * the coherency mode specified by the TLB; 1 means cacheable
* coherent update on write will be used. Not all processors have
* this bit and; some wire it to zero, others like Toshiba had the
* silly idea of putting something else there ...
diff --git a/arch/mips/mm/cex-gen.S b/arch/mips/mm/cex-gen.S
index 45dff5cd4b8e..e528583d1331 100644
--- a/arch/mips/mm/cex-gen.S
+++ b/arch/mips/mm/cex-gen.S
@@ -25,7 +25,7 @@
* This is a very bad place to be. Our cache error
* detection has triggered. If we have write-back data
* in the cache, we may not be able to recover. As a
- * first-order desperate measure, turn off KSEG0 cacheing.
+ * first-order desperate measure, turn off KSEG0 caching.
*/
mfc0 k0,CP0_CONFIG
li k1,~CONF_CM_CMASK
diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c
index 3c4fc97b9f39..0f3cec663a12 100644
--- a/arch/mips/mm/dma-noncoherent.c
+++ b/arch/mips/mm/dma-noncoherent.c
@@ -138,7 +138,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
#ifdef CONFIG_ARCH_HAS_SETUP_DMA_OPS
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
- const struct iommu_ops *iommu, bool coherent)
+ bool coherent)
{
dev->dma_coherent = coherent;
}
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index c2e0e5aebe90..39f129205b0c 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -422,8 +422,17 @@ void __init paging_init(void)
" %ldk highmem ignored\n",
(highend_pfn - max_low_pfn) << (PAGE_SHIFT - 10));
max_zone_pfns[ZONE_HIGHMEM] = max_low_pfn;
+
+ max_mapnr = max_low_pfn;
+ } else if (highend_pfn) {
+ max_mapnr = highend_pfn;
+ } else {
+ max_mapnr = max_low_pfn;
}
+#else
+ max_mapnr = max_low_pfn;
#endif
+ high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
free_area_init(max_zone_pfns);
}
@@ -459,13 +468,6 @@ void __init mem_init(void)
*/
BUILD_BUG_ON(IS_ENABLED(CONFIG_32BIT) && (PFN_PTE_SHIFT > PAGE_SHIFT));
-#ifdef CONFIG_HIGHMEM
- max_mapnr = highend_pfn ? highend_pfn : max_low_pfn;
-#else
- max_mapnr = max_low_pfn;
-#endif
- high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
-
maar_init();
memblock_free_all();
setup_zero_pages(); /* Setup zeroed pages. */
diff --git a/arch/mips/mm/ioremap.c b/arch/mips/mm/ioremap.c
index b6dad2fd5575..d8243d61ef32 100644
--- a/arch/mips/mm/ioremap.c
+++ b/arch/mips/mm/ioremap.c
@@ -72,6 +72,10 @@ void __iomem *ioremap_prot(phys_addr_t phys_addr, unsigned long size,
flags == _CACHE_UNCACHED)
return (void __iomem *) CKSEG1ADDR(phys_addr);
+ /* Early remaps should use the unmapped regions til' VM is available */
+ if (WARN_ON_ONCE(!slab_is_available()))
+ return NULL;
+
/*
* Don't allow anybody to remap RAM that may be allocated by the page
* allocator, since that could lead to races & data clobbering.
diff --git a/arch/mips/mm/tlb-r3k.c b/arch/mips/mm/tlb-r3k.c
index f6db65410c65..173f7b36033b 100644
--- a/arch/mips/mm/tlb-r3k.c
+++ b/arch/mips/mm/tlb-r3k.c
@@ -183,7 +183,7 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
int idx, pid;
/*
- * Handle debugger faulting in for debugee.
+ * Handle debugger faulting in for debuggee.
*/
if (current->active_mm != vma->vm_mm)
return;
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 7e2a0011a6fb..4106084e57d7 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -301,7 +301,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
int idx, pid;
/*
- * Handle debugger faulting in for debugee.
+ * Handle debugger faulting in for debuggee.
*/
if (current->active_mm != vma->vm_mm)
return;
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index b4e1c783e617..4017fa0e2f68 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -789,7 +789,7 @@ void build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
if (check_for_high_segbits) {
/*
- * The kernel currently implicitely assumes that the
+ * The kernel currently implicitly assumes that the
* MIPS SEGBITS parameter for the processor is
* (PGDIR_SHIFT+PGDIR_BITS) or less, and will never
* allocate virtual addresses outside the maximum
@@ -1715,7 +1715,7 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr,
/*
* Check if PTE is present, if not then jump to LABEL. PTR points to
* the page table where this PTE is located, PTE will be re-loaded
- * with it's original value.
+ * with its original value.
*/
static void
build_pte_present(u32 **p, struct uasm_reloc **r,
diff --git a/arch/mips/net/bpf_jit_comp32.c b/arch/mips/net/bpf_jit_comp32.c
index ace5db3fbd17..40a878b672f5 100644
--- a/arch/mips/net/bpf_jit_comp32.c
+++ b/arch/mips/net/bpf_jit_comp32.c
@@ -95,7 +95,7 @@
/*
* Mapping of 64-bit eBPF registers to 32-bit native MIPS registers.
*
- * 1) Native register pairs are ordered according to CPU endiannes, following
+ * 1) Native register pairs are ordered according to CPU endianness, following
* the MIPS convention for passing 64-bit arguments and return values.
* 2) The eBPF return value, arguments and callee-saved registers are mapped
* to their native MIPS equivalents.
diff --git a/arch/mips/pci/ops-loongson2.c b/arch/mips/pci/ops-loongson2.c
index 0d1b36ba1c21..068113f5c49d 100644
--- a/arch/mips/pci/ops-loongson2.c
+++ b/arch/mips/pci/ops-loongson2.c
@@ -49,7 +49,7 @@ static int loongson_pcibios_config_access(unsigned char access_type,
*/
#ifdef CONFIG_CS5536
/* cs5536_pci_conf_read4/write4() will call _rdmsr/_wrmsr() to
- * access the regsters PCI_MSR_ADDR, PCI_MSR_DATA_LO,
+ * access the registers PCI_MSR_ADDR, PCI_MSR_DATA_LO,
* PCI_MSR_DATA_HI, which is bigger than PCI_MSR_CTRL, so, it
* will not go this branch, but the others. so, no calling dead
* loop here.
diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c
index 1c722dd0c130..58625d1b6465 100644
--- a/arch/mips/pci/pci-alchemy.c
+++ b/arch/mips/pci/pci-alchemy.c
@@ -453,7 +453,7 @@ static int alchemy_pci_probe(struct platform_device *pdev)
/* we can't ioremap the entire pci config space because it's too large,
* nor can we dynamically ioremap it because some drivers use the
- * PCI config routines from within atomic contex and that becomes a
+ * PCI config routines from within atomic context and that becomes a
* problem in get_vm_area(). Instead we use one wired TLB entry to
* handle all config accesses for all busses.
*/
diff --git a/arch/mips/pci/pci-ar2315.c b/arch/mips/pci/pci-ar2315.c
index e17d862cfa4c..a925842ee125 100644
--- a/arch/mips/pci/pci-ar2315.c
+++ b/arch/mips/pci/pci-ar2315.c
@@ -16,7 +16,7 @@
* the CFG_SEL bit in the PCI_MISC_CONFIG register.
*
* Devices on the bus can perform DMA requests via chip BAR1. PCI host
- * controller BARs are programmend as if an external device is programmed.
+ * controller BARs are programmed as if an external device is programmed.
* Which means that during configuration, IDSEL pin of the chip should be
* asserted.
*
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
index 80f7293166bb..68a8cefed420 100644
--- a/arch/mips/pci/pci-lantiq.c
+++ b/arch/mips/pci/pci-lantiq.c
@@ -152,7 +152,7 @@ static int ltq_pci_startup(struct platform_device *pdev)
temp_buffer &= ~0xf0000;
/* enable internal arbiter */
temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT);
- /* enable internal PCI master reqest */
+ /* enable internal PCI master request */
temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS));
/* enable EBU request */
diff --git a/arch/mips/pci/pci-octeon.c b/arch/mips/pci/pci-octeon.c
index d19d9d456309..36d12cea3512 100644
--- a/arch/mips/pci/pci-octeon.c
+++ b/arch/mips/pci/pci-octeon.c
@@ -376,7 +376,7 @@ static void octeon_pci_initialize(void)
ctl_status.s.timer = 1;
cvmx_write_csr(CVMX_NPI_CTL_STATUS, ctl_status.u64);
- /* Deassert PCI reset and advertize PCX Host Mode Device Capability
+ /* Deassert PCI reset and advertise PCX Host Mode Device Capability
(64b) */
cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x4);
cvmx_read_csr(CVMX_CIU_SOFT_PRST);
diff --git a/arch/mips/pci/pci-xtalk-bridge.c b/arch/mips/pci/pci-xtalk-bridge.c
index 68d5211afea8..45ddbaa6c123 100644
--- a/arch/mips/pci/pci-xtalk-bridge.c
+++ b/arch/mips/pci/pci-xtalk-bridge.c
@@ -114,7 +114,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
*
* The function is complicated by the ultimate brokenness of the IOC3 chip
* which is used in SGI systems. The IOC3 can only handle 32-bit PCI
- * accesses and does only decode parts of it's address space.
+ * accesses and does only decode parts of its address space.
*/
static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 *value)
diff --git a/arch/mips/pci/pcie-octeon.c b/arch/mips/pci/pcie-octeon.c
index c9edd3fb380d..2583e318e8c6 100644
--- a/arch/mips/pci/pcie-octeon.c
+++ b/arch/mips/pci/pcie-octeon.c
@@ -1037,7 +1037,7 @@ retry:
in_fif_p_count = dbg_data.s.data & 0xff;
} while (in_fif_p_count != ((old_in_fif_p_count+1) & 0xff));
- /* Update in_fif_p_count for it's offset with respect to out_p_count */
+ /* Update in_fif_p_count for its offset with respect to out_p_count */
in_fif_p_count = (in_fif_p_count + in_p_offset) & 0xff;
/* Read the OUT_P_COUNT from the debug select */
diff --git a/arch/mips/ralink/mt7621.c b/arch/mips/ralink/mt7621.c
index 137781d0bd0a..5a9fd3fe41d7 100644
--- a/arch/mips/ralink/mt7621.c
+++ b/arch/mips/ralink/mt7621.c
@@ -175,7 +175,7 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info)
* mips_cm_probe() wipes out bootloader
* config for CM regions and we have to configure them
* again. This SoC cannot talk to pamlbus devices
- * witout proper iocu region set up.
+ * without proper iocu region set up.
*
* FIXME: it would be better to do this with values
* from DT, but we need this very early because
diff --git a/arch/mips/sgi-ip27/ip27-hubio.c b/arch/mips/sgi-ip27/ip27-hubio.c
index 8352eb6403b4..c57f0d8f3218 100644
--- a/arch/mips/sgi-ip27/ip27-hubio.c
+++ b/arch/mips/sgi-ip27/ip27-hubio.c
@@ -21,7 +21,7 @@ static int force_fire_and_forget = 1;
/**
* hub_pio_map - establish a HUB PIO mapping
*
- * @hub: hub to perform PIO mapping on
+ * @nasid: nasid to perform PIO mapping on
* @widget: widget ID to perform PIO mapping for
* @xtalk_addr: xtalk_address that needs to be mapped
* @size: size of the PIO mapping
diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c
index 5ae30b78d38d..d9249f5a632e 100644
--- a/arch/mips/txx9/generic/pci.c
+++ b/arch/mips/txx9/generic/pci.c
@@ -348,7 +348,7 @@ static void final_fixup(struct pci_dev *dev)
unsigned char bist;
int ret;
- /* Do build-in self test */
+ /* Do built-in self test */
ret = pci_read_config_byte(dev, PCI_BIST, &bist);
if ((ret != PCIBIOS_SUCCESSFUL) || !(bist & PCI_BIST_CAPABLE))
return;
diff --git a/arch/nios2/include/asm/cacheflush.h b/arch/nios2/include/asm/cacheflush.h
index 348cea097792..81484a776b33 100644
--- a/arch/nios2/include/asm/cacheflush.h
+++ b/arch/nios2/include/asm/cacheflush.h
@@ -38,6 +38,7 @@ void flush_icache_pages(struct vm_area_struct *vma, struct page *page,
#define flush_icache_pages flush_icache_pages
#define flush_cache_vmap(start, end) flush_dcache_range(start, end)
+#define flush_cache_vmap_early(start, end) do { } while (0)
#define flush_cache_vunmap(start, end) flush_dcache_range(start, end)
extern void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
index b4006f2a9705..ba4c05bc24d6 100644
--- a/arch/parisc/include/asm/cacheflush.h
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -41,6 +41,7 @@ void flush_kernel_vmap_range(void *vaddr, int size);
void invalidate_kernel_vmap_range(void *vaddr, int size);
#define flush_cache_vmap(start, end) flush_cache_all()
+#define flush_cache_vmap_early(start, end) do { } while (0)
#define flush_cache_vunmap(start, end) flush_cache_all()
void flush_dcache_folio(struct folio *folio);
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
index 904ca3b9e7a7..c69f6d5946e9 100644
--- a/arch/parisc/kernel/firmware.c
+++ b/arch/parisc/kernel/firmware.c
@@ -123,10 +123,10 @@ static unsigned long f_extend(unsigned long address)
#ifdef CONFIG_64BIT
if(unlikely(parisc_narrow_firmware)) {
if((address & 0xff000000) == 0xf0000000)
- return 0xf0f0f0f000000000UL | (u32)address;
+ return (0xfffffff0UL << 32) | (u32)address;
if((address & 0xf0000000) == 0xf0000000)
- return 0xffffffff00000000UL | (u32)address;
+ return (0xffffffffUL << 32) | (u32)address;
}
#endif
return address;
diff --git a/arch/parisc/video/fbdev.c b/arch/parisc/video/fbdev.c
index 137561d98246..e4f8ac99fc9e 100644
--- a/arch/parisc/video/fbdev.c
+++ b/arch/parisc/video/fbdev.c
@@ -21,6 +21,6 @@ int fb_is_primary_device(struct fb_info *info)
return true;
/* return true if it's the default built-in framebuffer driver */
- return (sti->info == info);
+ return (sti->dev == info->device);
}
EXPORT_SYMBOL(fb_is_primary_device);
diff --git a/arch/powerpc/include/asm/hvconsole.h b/arch/powerpc/include/asm/hvconsole.h
index ccb2034506f0..d841a97010a0 100644
--- a/arch/powerpc/include/asm/hvconsole.h
+++ b/arch/powerpc/include/asm/hvconsole.h
@@ -21,8 +21,8 @@
* Vio firmware always attempts to fetch MAX_VIO_GET_CHARS chars. The 'count'
* parm is included to conform to put_chars() function pointer template
*/
-extern int hvc_get_chars(uint32_t vtermno, char *buf, int count);
-extern int hvc_put_chars(uint32_t vtermno, const char *buf, int count);
+extern ssize_t hvc_get_chars(uint32_t vtermno, u8 *buf, size_t count);
+extern ssize_t hvc_put_chars(uint32_t vtermno, const u8 *buf, size_t count);
/* Provided by HVC VIO */
void hvc_vio_init_early(void);
diff --git a/arch/powerpc/include/asm/hvsi.h b/arch/powerpc/include/asm/hvsi.h
index 464a7519ed64..9058edcb632b 100644
--- a/arch/powerpc/include/asm/hvsi.h
+++ b/arch/powerpc/include/asm/hvsi.h
@@ -64,7 +64,7 @@ struct hvsi_priv {
unsigned int inbuf_len; /* data in input buffer */
unsigned char inbuf[HVSI_INBUF_SIZE];
unsigned int inbuf_cur; /* Cursor in input buffer */
- unsigned int inbuf_pktlen; /* packet length from cursor */
+ size_t inbuf_pktlen; /* packet length from cursor */
atomic_t seqno; /* packet sequence number */
unsigned int opened:1; /* driver opened */
unsigned int established:1; /* protocol established */
@@ -72,24 +72,26 @@ struct hvsi_priv {
unsigned int mctrl_update:1; /* modem control updated */
unsigned short mctrl; /* modem control */
struct tty_struct *tty; /* tty structure */
- int (*get_chars)(uint32_t termno, char *buf, int count);
- int (*put_chars)(uint32_t termno, const char *buf, int count);
+ ssize_t (*get_chars)(uint32_t termno, u8 *buf, size_t count);
+ ssize_t (*put_chars)(uint32_t termno, const u8 *buf, size_t count);
uint32_t termno;
};
/* hvsi lib functions */
struct hvc_struct;
extern void hvsilib_init(struct hvsi_priv *pv,
- int (*get_chars)(uint32_t termno, char *buf, int count),
- int (*put_chars)(uint32_t termno, const char *buf,
- int count),
+ ssize_t (*get_chars)(uint32_t termno, u8 *buf,
+ size_t count),
+ ssize_t (*put_chars)(uint32_t termno, const u8 *buf,
+ size_t count),
int termno, int is_console);
extern int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp);
extern void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp);
extern int hvsilib_read_mctrl(struct hvsi_priv *pv);
extern int hvsilib_write_mctrl(struct hvsi_priv *pv, int dtr);
extern void hvsilib_establish(struct hvsi_priv *pv);
-extern int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count);
-extern int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count);
+extern ssize_t hvsilib_get_chars(struct hvsi_priv *pv, u8 *buf, size_t count);
+extern ssize_t hvsilib_put_chars(struct hvsi_priv *pv, const u8 *buf,
+ size_t count);
#endif /* _HVSI_H */
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 8799b37be295..8abac532146e 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -63,8 +63,6 @@
#include <linux/mmu_notifier.h>
-#define KVM_ARCH_WANT_MMU_NOTIFIER
-
#define HPTEG_CACHE_NUM (1 << 15)
#define HPTEG_HASH_BITS_PTE 13
#define HPTEG_HASH_BITS_PTE_LONG 12
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index b66b0c615f4f..af304e6cb486 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -313,9 +313,11 @@ extern int early_init_dt_scan_recoverable_ranges(unsigned long node,
const char *uname, int depth, void *data);
void __init opal_configure_cores(void);
-extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
-extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
-extern int opal_put_chars_atomic(uint32_t vtermno, const char *buf, int total_len);
+extern ssize_t opal_get_chars(uint32_t vtermno, u8 *buf, size_t count);
+extern ssize_t opal_put_chars(uint32_t vtermno, const u8 *buf,
+ size_t total_len);
+extern ssize_t opal_put_chars_atomic(uint32_t vtermno, const u8 *buf,
+ size_t total_len);
extern int opal_flush_chars(uint32_t vtermno, bool wait);
extern int opal_flush_console(uint32_t vtermno);
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index 902611954200..074263429faf 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -19,13 +19,11 @@ if VIRTUALIZATION
config KVM
bool
- select PREEMPT_NOTIFIERS
- select HAVE_KVM_EVENTFD
+ select KVM_COMMON
select HAVE_KVM_VCPU_ASYNC_IOCTL
select KVM_VFIO
select IRQ_BYPASS_MANAGER
select HAVE_KVM_IRQ_BYPASS
- select INTERVAL_TREE
config KVM_BOOK3S_HANDLER
bool
@@ -42,7 +40,7 @@ config KVM_BOOK3S_64_HANDLER
config KVM_BOOK3S_PR_POSSIBLE
bool
select KVM_MMIO
- select MMU_NOTIFIER
+ select KVM_GENERIC_MMU_NOTIFIER
config KVM_BOOK3S_HV_POSSIBLE
bool
@@ -85,7 +83,7 @@ config KVM_BOOK3S_64_HV
tristate "KVM for POWER7 and later using hypervisor mode in host"
depends on KVM_BOOK3S_64 && PPC_POWERNV
select KVM_BOOK3S_HV_POSSIBLE
- select MMU_NOTIFIER
+ select KVM_GENERIC_MMU_NOTIFIER
select CMA
help
Support running unmodified book3s_64 guest kernels in
@@ -194,7 +192,7 @@ config KVM_E500V2
depends on !CONTEXT_TRACKING_USER
select KVM
select KVM_MMIO
- select MMU_NOTIFIER
+ select KVM_GENERIC_MMU_NOTIFIER
help
Support running unmodified E500 guest kernels in virtual machines on
E500v2 host processors.
@@ -211,7 +209,7 @@ config KVM_E500MC
select KVM
select KVM_MMIO
select KVM_BOOKE_HV
- select MMU_NOTIFIER
+ select KVM_GENERIC_MMU_NOTIFIER
help
Support running unmodified E500MC/E5500/E6500 guest kernels in
virtual machines on E500MC/E5500/E6500 host processors.
@@ -225,7 +223,6 @@ config KVM_MPIC
bool "KVM in-kernel MPIC emulation"
depends on KVM && PPC_E500
select HAVE_KVM_IRQCHIP
- select HAVE_KVM_IRQFD
select HAVE_KVM_IRQ_ROUTING
select HAVE_KVM_MSI
help
@@ -238,7 +235,6 @@ config KVM_XICS
bool "KVM in-kernel XICS emulation"
depends on KVM_BOOK3S_64 && !KVM_MPIC
select HAVE_KVM_IRQCHIP
- select HAVE_KVM_IRQFD
default y
help
Include support for the XICS (eXternal Interrupt Controller
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index e48126a59ba7..52427fc2a33f 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -6240,7 +6240,7 @@ static int kvmhv_svm_off(struct kvm *kvm)
}
srcu_idx = srcu_read_lock(&kvm->srcu);
- for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+ for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
struct kvm_memory_slot *memslot;
struct kvm_memslots *slots = __kvm_memslots(kvm, i);
int bkt;
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index f6af752698d0..23407fbd73c9 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -528,7 +528,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_ENABLE_CAP:
case KVM_CAP_ONE_REG:
case KVM_CAP_IOEVENTFD:
- case KVM_CAP_DEVICE_CTRL:
case KVM_CAP_IMMEDIATE_EXIT:
case KVM_CAP_SET_GUEST_DEBUG:
r = 1;
@@ -578,7 +577,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
break;
#endif
-#ifdef CONFIG_HAVE_KVM_IRQFD
+#ifdef CONFIG_HAVE_KVM_IRQCHIP
case KVM_CAP_IRQFD_RESAMPLE:
r = !xive_enabled();
break;
@@ -632,13 +631,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
break;
#endif
case KVM_CAP_SYNC_MMU:
-#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
- r = hv_enabled;
-#elif defined(KVM_ARCH_WANT_MMU_NOTIFIER)
+ BUILD_BUG_ON(!IS_ENABLED(CONFIG_KVM_GENERIC_MMU_NOTIFIER));
r = 1;
-#else
- r = 0;
-#endif
break;
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
case KVM_CAP_PPC_HTAB_FD:
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index cdf3838f08d3..45dd77e3ccf6 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -424,7 +424,7 @@ static int __init opal_message_init(struct device_node *opal_node)
return 0;
}
-int opal_get_chars(uint32_t vtermno, char *buf, int count)
+ssize_t opal_get_chars(uint32_t vtermno, u8 *buf, size_t count)
{
s64 rc;
__be64 evt, len;
@@ -441,10 +441,11 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count)
return 0;
}
-static int __opal_put_chars(uint32_t vtermno, const char *data, int total_len, bool atomic)
+static ssize_t __opal_put_chars(uint32_t vtermno, const u8 *data,
+ size_t total_len, bool atomic)
{
unsigned long flags = 0 /* shut up gcc */;
- int written;
+ ssize_t written;
__be64 olen;
s64 rc;
@@ -484,7 +485,7 @@ static int __opal_put_chars(uint32_t vtermno, const char *data, int total_len, b
if (atomic) {
/* Should not happen */
pr_warn("atomic console write returned partial "
- "len=%d written=%d\n", total_len, written);
+ "len=%zu written=%zd\n", total_len, written);
}
if (!written)
written = -EAGAIN;
@@ -497,7 +498,7 @@ out:
return written;
}
-int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
+ssize_t opal_put_chars(uint32_t vtermno, const u8 *data, size_t total_len)
{
return __opal_put_chars(vtermno, data, total_len, false);
}
@@ -508,7 +509,8 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
* true at the moment because console space can race with OPAL's console
* writes.
*/
-int opal_put_chars_atomic(uint32_t vtermno, const char *data, int total_len)
+ssize_t opal_put_chars_atomic(uint32_t vtermno, const u8 *data,
+ size_t total_len)
{
return __opal_put_chars(vtermno, data, total_len, true);
}
diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
index 1ac52963e08b..8803c947998e 100644
--- a/arch/powerpc/platforms/pseries/hvconsole.c
+++ b/arch/powerpc/platforms/pseries/hvconsole.c
@@ -25,7 +25,7 @@
* firmware.
* @count: not used?
*/
-int hvc_get_chars(uint32_t vtermno, char *buf, int count)
+ssize_t hvc_get_chars(uint32_t vtermno, u8 *buf, size_t count)
{
long ret;
unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
@@ -52,7 +52,7 @@ EXPORT_SYMBOL(hvc_get_chars);
* firmware. Must be at least 16 bytes, even if count is less than 16.
* @count: Send this number of characters.
*/
-int hvc_put_chars(uint32_t vtermno, const char *buf, int count)
+ssize_t hvc_put_chars(uint32_t vtermno, const u8 *buf, size_t count)
{
unsigned long *lbuf = (unsigned long *) buf;
long ret;
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 3868483fbe29..ef7707ea0db7 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -54,7 +54,7 @@ static void quirk_fsl_pcie_early(struct pci_dev *dev)
/* if we aren't in host mode don't bother */
pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type);
- if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ if ((hdr_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
return;
dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL;
@@ -581,7 +581,7 @@ static int fsl_add_bridge(struct platform_device *pdev, int is_primary)
hose->ops = &fsl_indirect_pcie_ops;
/* For PCIE read HEADER_TYPE to identify controller mode */
early_read_config_byte(hose, 0, 0, PCI_HEADER_TYPE, &hdr_type);
- if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+ if ((hdr_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
goto no_bridge;
} else {
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index cd4c9a204d08..b549499eb363 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -59,6 +59,7 @@ config RISCV
select ARCH_WANT_HUGE_PMD_SHARE if 64BIT
select ARCH_WANT_LD_ORPHAN_WARN if !XIP_KERNEL
select ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP
+ select ARCH_WANTS_NO_INSTR
select ARCH_WANTS_THP_SWAP if HAVE_ARCH_TRANSPARENT_HUGEPAGE
select BINFMT_FLAT_NO_DATA_START_OFFSET if !MMU
select BUILDTIME_TABLE_SORT if MMU
@@ -71,6 +72,7 @@ config RISCV
select GENERIC_ARCH_TOPOLOGY
select GENERIC_ATOMIC64 if !64BIT
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+ select GENERIC_CPU_DEVICES
select GENERIC_EARLY_IOREMAP
select GENERIC_ENTRY
select GENERIC_GETTIMEOFDAY if HAVE_GENERIC_VDSO
@@ -414,7 +416,9 @@ config NUMA
depends on SMP && MMU
select ARCH_SUPPORTS_NUMA_BALANCING
select GENERIC_ARCH_NUMA
+ select HAVE_SETUP_PER_CPU_AREA
select NEED_PER_CPU_EMBED_FIRST_CHUNK
+ select NEED_PER_CPU_PAGE_FIRST_CHUNK
select OF_NUMA
select USE_PERCPU_NUMA_NODE_ID
help
@@ -722,6 +726,25 @@ config COMPAT
If you want to execute 32-bit userspace applications, say Y.
+config PARAVIRT
+ bool "Enable paravirtualization code"
+ depends on RISCV_SBI
+ help
+ This changes the kernel so it can modify itself when it is run
+ under a hypervisor, potentially improving performance significantly
+ over full virtualization.
+
+config PARAVIRT_TIME_ACCOUNTING
+ bool "Paravirtual steal time accounting"
+ depends on PARAVIRT
+ help
+ Select this option to enable fine granularity task steal time
+ accounting. Time spent executing other tasks in parallel with
+ the current vCPU is discounted from the vCPU power. To account for
+ that, there can be a small performance impact.
+
+ If in doubt, say N here.
+
config RELOCATABLE
bool "Build a relocatable kernel"
depends on MMU && 64BIT && !XIP_KERNEL
@@ -902,13 +925,13 @@ config RISCV_ISA_FALLBACK
on the replacement properties, "riscv,isa-base" and
"riscv,isa-extensions".
-endmenu # "Boot options"
-
config BUILTIN_DTB
- bool
+ bool "Built-in device tree"
depends on OF && NONPORTABLE
default y if XIP_KERNEL
+endmenu # "Boot options"
+
config PORTABLE
bool
default !NONPORTABLE
diff --git a/arch/riscv/configs/rv32_defconfig b/arch/riscv/configs/rv32_defconfig
deleted file mode 100644
index 89b601e253a6..000000000000
--- a/arch/riscv/configs/rv32_defconfig
+++ /dev/null
@@ -1,139 +0,0 @@
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_NO_HZ_IDLE=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_BPF_SYSCALL=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_CFS_BANDWIDTH=y
-CONFIG_CGROUP_BPF=y
-CONFIG_NAMESPACES=y
-CONFIG_USER_NS=y
-CONFIG_CHECKPOINT_RESTORE=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EXPERT=y
-# CONFIG_SYSFS_SYSCALL is not set
-CONFIG_PROFILING=y
-CONFIG_SOC_SIFIVE=y
-CONFIG_SOC_VIRT=y
-CONFIG_NONPORTABLE=y
-CONFIG_ARCH_RV32I=y
-CONFIG_SMP=y
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PM=y
-CONFIG_CPU_IDLE=y
-CONFIG_VIRTUALIZATION=y
-CONFIG_KVM=m
-CONFIG_JUMP_LABEL=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-CONFIG_NETLINK_DIAG=y
-CONFIG_NET_9P=y
-CONFIG_NET_9P_VIRTIO=y
-CONFIG_PCI=y
-CONFIG_PCIEPORTBUS=y
-CONFIG_PCI_HOST_GENERIC=y
-CONFIG_PCIE_XILINX=y
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_VIRTIO_BLK=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_SCSI_VIRTIO=y
-CONFIG_ATA=y
-CONFIG_SATA_AHCI=y
-CONFIG_SATA_AHCI_PLATFORM=y
-CONFIG_NETDEVICES=y
-CONFIG_VIRTIO_NET=y
-CONFIG_MACB=y
-CONFIG_E1000E=y
-CONFIG_R8169=y
-CONFIG_MICROSEMI_PHY=y
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_OF_PLATFORM=y
-CONFIG_VIRTIO_CONSOLE=y
-CONFIG_HW_RANDOM=y
-CONFIG_HW_RANDOM_VIRTIO=y
-CONFIG_SPI=y
-CONFIG_SPI_SIFIVE=y
-# CONFIG_PTP_1588_CLOCK is not set
-CONFIG_DRM=y
-CONFIG_DRM_RADEON=y
-CONFIG_DRM_VIRTIO_GPU=y
-CONFIG_FB=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_USB=y
-CONFIG_USB_XHCI_HCD=y
-CONFIG_USB_XHCI_PLATFORM=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_HCD_PLATFORM=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PLATFORM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_UAS=y
-CONFIG_MMC=y
-CONFIG_MMC_SPI=y
-CONFIG_RTC_CLASS=y
-CONFIG_VIRTIO_PCI=y
-CONFIG_VIRTIO_BALLOON=y
-CONFIG_VIRTIO_INPUT=y
-CONFIG_VIRTIO_MMIO=y
-CONFIG_RPMSG_CHAR=y
-CONFIG_RPMSG_CTRL=y
-CONFIG_RPMSG_VIRTIO=y
-CONFIG_EXT4_FS=y
-CONFIG_EXT4_FS_POSIX_ACL=y
-CONFIG_AUTOFS_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_HUGETLBFS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V4=y
-CONFIG_NFS_V4_1=y
-CONFIG_NFS_V4_2=y
-CONFIG_ROOT_NFS=y
-CONFIG_9P_FS=y
-CONFIG_CRYPTO_USER_API_HASH=y
-CONFIG_CRYPTO_DEV_VIRTIO=y
-CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_PAGEALLOC=y
-CONFIG_SCHED_STACK_END_CHECK=y
-CONFIG_DEBUG_VM=y
-CONFIG_DEBUG_VM_PGFLAGS=y
-CONFIG_DEBUG_MEMORY_INIT=y
-CONFIG_DEBUG_PER_CPU_MAPS=y
-CONFIG_SOFTLOCKUP_DETECTOR=y
-CONFIG_WQ_WATCHDOG=y
-CONFIG_DEBUG_TIMEKEEPING=y
-CONFIG_DEBUG_RT_MUTEXES=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_RWSEMS=y
-CONFIG_DEBUG_ATOMIC_SLEEP=y
-CONFIG_STACKTRACE=y
-CONFIG_DEBUG_LIST=y
-CONFIG_DEBUG_PLIST=y
-CONFIG_DEBUG_SG=y
-# CONFIG_RCU_TRACE is not set
-CONFIG_RCU_EQS_DEBUG=y
-# CONFIG_FTRACE is not set
-# CONFIG_RUNTIME_TESTING_MENU is not set
-CONFIG_MEMTEST=y
diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h
index 3cb53c4df27c..a129dac4521d 100644
--- a/arch/riscv/include/asm/cacheflush.h
+++ b/arch/riscv/include/asm/cacheflush.h
@@ -37,7 +37,8 @@ static inline void flush_dcache_page(struct page *page)
flush_icache_mm(vma->vm_mm, 0)
#ifdef CONFIG_64BIT
-#define flush_cache_vmap(start, end) flush_tlb_kernel_range(start, end)
+#define flush_cache_vmap(start, end) flush_tlb_kernel_range(start, end)
+#define flush_cache_vmap_early(start, end) local_flush_tlb_kernel_range(start, end)
#endif
#ifndef CONFIG_SMP
diff --git a/arch/riscv/include/asm/cpu_ops.h b/arch/riscv/include/asm/cpu_ops.h
index aa128466c4d4..176b570ef982 100644
--- a/arch/riscv/include/asm/cpu_ops.h
+++ b/arch/riscv/include/asm/cpu_ops.h
@@ -13,33 +13,23 @@
/**
* struct cpu_operations - Callback operations for hotplugging CPUs.
*
- * @name: Name of the boot protocol.
- * @cpu_prepare: Early one-time preparation step for a cpu. If there
- * is a mechanism for doing so, tests whether it is
- * possible to boot the given HART.
* @cpu_start: Boots a cpu into the kernel.
- * @cpu_disable: Prepares a cpu to die. May fail for some
- * mechanism-specific reason, which will cause the hot
- * unplug to be aborted. Called from the cpu to be killed.
* @cpu_stop: Makes a cpu leave the kernel. Must not fail. Called from
* the cpu being stopped.
* @cpu_is_stopped: Ensures a cpu has left the kernel. Called from another
* cpu.
*/
struct cpu_operations {
- const char *name;
- int (*cpu_prepare)(unsigned int cpu);
int (*cpu_start)(unsigned int cpu,
struct task_struct *tidle);
#ifdef CONFIG_HOTPLUG_CPU
- int (*cpu_disable)(unsigned int cpu);
void (*cpu_stop)(void);
int (*cpu_is_stopped)(unsigned int cpu);
#endif
};
extern const struct cpu_operations cpu_ops_spinwait;
-extern const struct cpu_operations *cpu_ops[NR_CPUS];
-void __init cpu_set_ops(int cpu);
+extern const struct cpu_operations *cpu_ops;
+void __init cpu_set_ops(void);
#endif /* ifndef __ASM_CPU_OPS_H */
diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index a418c3112cd6..fbdde8b8a47e 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -59,6 +59,8 @@ struct riscv_isa_ext_data {
const unsigned int id;
const char *name;
const char *property;
+ const unsigned int *subset_ext_ids;
+ const unsigned int subset_ext_size;
};
extern const struct riscv_isa_ext_data riscv_isa_ext[];
@@ -67,7 +69,7 @@ extern bool riscv_isa_fallback;
unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);
-bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit);
+bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned int bit);
#define riscv_isa_extension_available(isa_bitmap, ext) \
__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext)
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 06d30526ef3b..5340f818746b 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -11,19 +11,13 @@
#include <uapi/asm/hwcap.h>
#define RISCV_ISA_EXT_a ('a' - 'a')
-#define RISCV_ISA_EXT_b ('b' - 'a')
#define RISCV_ISA_EXT_c ('c' - 'a')
#define RISCV_ISA_EXT_d ('d' - 'a')
#define RISCV_ISA_EXT_f ('f' - 'a')
#define RISCV_ISA_EXT_h ('h' - 'a')
#define RISCV_ISA_EXT_i ('i' - 'a')
-#define RISCV_ISA_EXT_j ('j' - 'a')
-#define RISCV_ISA_EXT_k ('k' - 'a')
#define RISCV_ISA_EXT_m ('m' - 'a')
-#define RISCV_ISA_EXT_p ('p' - 'a')
#define RISCV_ISA_EXT_q ('q' - 'a')
-#define RISCV_ISA_EXT_s ('s' - 'a')
-#define RISCV_ISA_EXT_u ('u' - 'a')
#define RISCV_ISA_EXT_v ('v' - 'a')
/*
@@ -57,8 +51,38 @@
#define RISCV_ISA_EXT_ZIHPM 42
#define RISCV_ISA_EXT_SMSTATEEN 43
#define RISCV_ISA_EXT_ZICOND 44
+#define RISCV_ISA_EXT_ZBC 45
+#define RISCV_ISA_EXT_ZBKB 46
+#define RISCV_ISA_EXT_ZBKC 47
+#define RISCV_ISA_EXT_ZBKX 48
+#define RISCV_ISA_EXT_ZKND 49
+#define RISCV_ISA_EXT_ZKNE 50
+#define RISCV_ISA_EXT_ZKNH 51
+#define RISCV_ISA_EXT_ZKR 52
+#define RISCV_ISA_EXT_ZKSED 53
+#define RISCV_ISA_EXT_ZKSH 54
+#define RISCV_ISA_EXT_ZKT 55
+#define RISCV_ISA_EXT_ZVBB 56
+#define RISCV_ISA_EXT_ZVBC 57
+#define RISCV_ISA_EXT_ZVKB 58
+#define RISCV_ISA_EXT_ZVKG 59
+#define RISCV_ISA_EXT_ZVKNED 60
+#define RISCV_ISA_EXT_ZVKNHA 61
+#define RISCV_ISA_EXT_ZVKNHB 62
+#define RISCV_ISA_EXT_ZVKSED 63
+#define RISCV_ISA_EXT_ZVKSH 64
+#define RISCV_ISA_EXT_ZVKT 65
+#define RISCV_ISA_EXT_ZFH 66
+#define RISCV_ISA_EXT_ZFHMIN 67
+#define RISCV_ISA_EXT_ZIHINTNTL 68
+#define RISCV_ISA_EXT_ZVFH 69
+#define RISCV_ISA_EXT_ZVFHMIN 70
+#define RISCV_ISA_EXT_ZFA 71
+#define RISCV_ISA_EXT_ZTSO 72
+#define RISCV_ISA_EXT_ZACAS 73
-#define RISCV_ISA_EXT_MAX 64
+#define RISCV_ISA_EXT_MAX 128
+#define RISCV_ISA_EXT_INVALID U32_MAX
#ifdef CONFIG_RISCV_M_MODE
#define RISCV_ISA_EXT_SxAIA RISCV_ISA_EXT_SMAIA
diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h
index 5c48f48e79a6..630507dff5ea 100644
--- a/arch/riscv/include/asm/hwprobe.h
+++ b/arch/riscv/include/asm/hwprobe.h
@@ -15,4 +15,28 @@ static inline bool riscv_hwprobe_key_is_valid(__s64 key)
return key >= 0 && key <= RISCV_HWPROBE_MAX_KEY;
}
+static inline bool hwprobe_key_is_bitmask(__s64 key)
+{
+ switch (key) {
+ case RISCV_HWPROBE_KEY_BASE_BEHAVIOR:
+ case RISCV_HWPROBE_KEY_IMA_EXT_0:
+ case RISCV_HWPROBE_KEY_CPUPERF_0:
+ return true;
+ }
+
+ return false;
+}
+
+static inline bool riscv_hwprobe_pair_cmp(struct riscv_hwprobe *pair,
+ struct riscv_hwprobe *other_pair)
+{
+ if (pair->key != other_pair->key)
+ return false;
+
+ if (hwprobe_key_is_bitmask(pair->key))
+ return (pair->value & other_pair->value) == other_pair->value;
+
+ return pair->value == other_pair->value;
+}
+
#endif
diff --git a/arch/riscv/include/asm/kfence.h b/arch/riscv/include/asm/kfence.h
index 0bbffd528096..7388edd88986 100644
--- a/arch/riscv/include/asm/kfence.h
+++ b/arch/riscv/include/asm/kfence.h
@@ -18,9 +18,9 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect)
pte_t *pte = virt_to_kpte(addr);
if (protect)
- set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT));
+ set_pte(pte, __pte(pte_val(ptep_get(pte)) & ~_PAGE_PRESENT));
else
- set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT));
+ set_pte(pte, __pte(pte_val(ptep_get(pte)) | _PAGE_PRESENT));
flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
index 0eefd9c991ae..484d04a92fa6 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -41,6 +41,7 @@
KVM_ARCH_REQ_FLAGS(4, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
#define KVM_REQ_HFENCE \
KVM_ARCH_REQ_FLAGS(5, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
+#define KVM_REQ_STEAL_UPDATE KVM_ARCH_REQ(6)
enum kvm_riscv_hfence_type {
KVM_RISCV_HFENCE_UNKNOWN = 0,
@@ -262,13 +263,17 @@ struct kvm_vcpu_arch {
/* 'static' configurations which are set only once */
struct kvm_vcpu_config cfg;
+
+ /* SBI steal-time accounting */
+ struct {
+ gpa_t shmem;
+ u64 last_steal;
+ } sta;
};
static inline void kvm_arch_sync_events(struct kvm *kvm) {}
static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
-#define KVM_ARCH_WANT_MMU_NOTIFIER
-
#define KVM_RISCV_GSTAGE_TLB_MIN_ORDER 12
void kvm_riscv_local_hfence_gvma_vmid_gpa(unsigned long vmid,
@@ -372,4 +377,7 @@ bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask);
void kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu);
void kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu);
+void kvm_riscv_vcpu_sbi_sta_reset(struct kvm_vcpu *vcpu);
+void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu);
+
#endif /* __RISCV_KVM_HOST_H__ */
diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h
index 6a453f7f8b56..b96705258cf9 100644
--- a/arch/riscv/include/asm/kvm_vcpu_sbi.h
+++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h
@@ -15,9 +15,10 @@
#define KVM_SBI_VERSION_MINOR 0
enum kvm_riscv_sbi_ext_status {
- KVM_RISCV_SBI_EXT_UNINITIALIZED,
- KVM_RISCV_SBI_EXT_AVAILABLE,
- KVM_RISCV_SBI_EXT_UNAVAILABLE,
+ KVM_RISCV_SBI_EXT_STATUS_UNINITIALIZED,
+ KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE,
+ KVM_RISCV_SBI_EXT_STATUS_ENABLED,
+ KVM_RISCV_SBI_EXT_STATUS_DISABLED,
};
struct kvm_vcpu_sbi_context {
@@ -36,7 +37,7 @@ struct kvm_vcpu_sbi_extension {
unsigned long extid_start;
unsigned long extid_end;
- bool default_unavail;
+ bool default_disabled;
/**
* SBI extension handler. It can be defined for a given extension or group of
@@ -59,11 +60,21 @@ int kvm_riscv_vcpu_set_reg_sbi_ext(struct kvm_vcpu *vcpu,
const struct kvm_one_reg *reg);
int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu,
const struct kvm_one_reg *reg);
+int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu,
+ const struct kvm_one_reg *reg);
+int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu,
+ const struct kvm_one_reg *reg);
const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(
struct kvm_vcpu *vcpu, unsigned long extid);
+bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx);
int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run);
void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu);
+int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num,
+ unsigned long *reg_val);
+int kvm_riscv_vcpu_set_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num,
+ unsigned long reg_val);
+
#ifdef CONFIG_RISCV_SBI_V01
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01;
#endif
@@ -74,6 +85,7 @@ extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence;
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst;
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm;
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn;
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta;
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental;
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor;
diff --git a/arch/riscv/include/asm/paravirt.h b/arch/riscv/include/asm/paravirt.h
new file mode 100644
index 000000000000..c0abde70fc2c
--- /dev/null
+++ b/arch/riscv/include/asm/paravirt.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_RISCV_PARAVIRT_H
+#define _ASM_RISCV_PARAVIRT_H
+
+#ifdef CONFIG_PARAVIRT
+#include <linux/static_call_types.h>
+
+struct static_key;
+extern struct static_key paravirt_steal_enabled;
+extern struct static_key paravirt_steal_rq_enabled;
+
+u64 dummy_steal_clock(int cpu);
+
+DECLARE_STATIC_CALL(pv_steal_clock, dummy_steal_clock);
+
+static inline u64 paravirt_steal_clock(int cpu)
+{
+ return static_call(pv_steal_clock)(cpu);
+}
+
+int __init pv_time_init(void);
+
+#else
+
+#define pv_time_init() do {} while (0)
+
+#endif /* CONFIG_PARAVIRT */
+#endif /* _ASM_RISCV_PARAVIRT_H */
diff --git a/arch/riscv/include/asm/paravirt_api_clock.h b/arch/riscv/include/asm/paravirt_api_clock.h
new file mode 100644
index 000000000000..65ac7cee0dad
--- /dev/null
+++ b/arch/riscv/include/asm/paravirt_api_clock.h
@@ -0,0 +1 @@
+#include <asm/paravirt.h>
diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h
index 9a2c780a11e9..b42017d76924 100644
--- a/arch/riscv/include/asm/pgtable-64.h
+++ b/arch/riscv/include/asm/pgtable-64.h
@@ -202,7 +202,7 @@ static inline int pud_user(pud_t pud)
static inline void set_pud(pud_t *pudp, pud_t pud)
{
- *pudp = pud;
+ WRITE_ONCE(*pudp, pud);
}
static inline void pud_clear(pud_t *pudp)
@@ -278,7 +278,7 @@ static inline unsigned long _pmd_pfn(pmd_t pmd)
static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
{
if (pgtable_l4_enabled)
- *p4dp = p4d;
+ WRITE_ONCE(*p4dp, p4d);
else
set_pud((pud_t *)p4dp, (pud_t){ p4d_val(p4d) });
}
@@ -340,18 +340,12 @@ static inline struct page *p4d_page(p4d_t p4d)
#define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
#define pud_offset pud_offset
-static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
-{
- if (pgtable_l4_enabled)
- return p4d_pgtable(*p4d) + pud_index(address);
-
- return (pud_t *)p4d;
-}
+pud_t *pud_offset(p4d_t *p4d, unsigned long address);
static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
{
if (pgtable_l5_enabled)
- *pgdp = pgd;
+ WRITE_ONCE(*pgdp, pgd);
else
set_p4d((p4d_t *)pgdp, (p4d_t){ pgd_val(pgd) });
}
@@ -404,12 +398,6 @@ static inline struct page *pgd_page(pgd_t pgd)
#define p4d_index(addr) (((addr) >> P4D_SHIFT) & (PTRS_PER_P4D - 1))
#define p4d_offset p4d_offset
-static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
-{
- if (pgtable_l5_enabled)
- return pgd_pgtable(*pgd) + p4d_index(address);
-
- return (p4d_t *)pgd;
-}
+p4d_t *p4d_offset(pgd_t *pgd, unsigned long address);
#endif /* _ASM_RISCV_PGTABLE_64_H */
diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 7b4287f36054..e3ffef1c6119 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -248,7 +248,7 @@ static inline int pmd_leaf(pmd_t pmd)
static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
{
- *pmdp = pmd;
+ WRITE_ONCE(*pmdp, pmd);
}
static inline void pmd_clear(pmd_t *pmdp)
@@ -510,7 +510,7 @@ static inline int pte_same(pte_t pte_a, pte_t pte_b)
*/
static inline void set_pte(pte_t *ptep, pte_t pteval)
{
- *ptep = pteval;
+ WRITE_ONCE(*ptep, pteval);
}
void flush_icache_pte(pte_t pte);
@@ -544,19 +544,12 @@ static inline void pte_clear(struct mm_struct *mm,
__set_pte_at(ptep, __pte(0));
}
-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-static inline int ptep_set_access_flags(struct vm_area_struct *vma,
- unsigned long address, pte_t *ptep,
- pte_t entry, int dirty)
-{
- if (!pte_same(*ptep, entry))
- __set_pte_at(ptep, entry);
- /*
- * update_mmu_cache will unconditionally execute, handling both
- * the case that the PTE changed and the spurious fault case.
- */
- return true;
-}
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS /* defined in mm/pgtable.c */
+extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
+ pte_t *ptep, pte_t entry, int dirty);
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG /* defined in mm/pgtable.c */
+extern int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long address,
+ pte_t *ptep);
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
@@ -569,16 +562,6 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
return pte;
}
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
- unsigned long address,
- pte_t *ptep)
-{
- if (!pte_young(*ptep))
- return 0;
- return test_and_clear_bit(_PAGE_ACCESSED_OFFSET, &pte_val(*ptep));
-}
-
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
static inline void ptep_set_wrprotect(struct mm_struct *mm,
unsigned long address, pte_t *ptep)
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
index 0892f4421bc4..b6f898c56940 100644
--- a/arch/riscv/include/asm/sbi.h
+++ b/arch/riscv/include/asm/sbi.h
@@ -31,6 +31,7 @@ enum sbi_ext_id {
SBI_EXT_SRST = 0x53525354,
SBI_EXT_PMU = 0x504D55,
SBI_EXT_DBCN = 0x4442434E,
+ SBI_EXT_STA = 0x535441,
/* Experimentals extensions must lie within this range */
SBI_EXT_EXPERIMENTAL_START = 0x08000000,
@@ -243,6 +244,22 @@ enum sbi_ext_dbcn_fid {
SBI_EXT_DBCN_CONSOLE_WRITE_BYTE = 2,
};
+/* SBI STA (steal-time accounting) extension */
+enum sbi_ext_sta_fid {
+ SBI_EXT_STA_STEAL_TIME_SET_SHMEM = 0,
+};
+
+struct sbi_sta_struct {
+ __le32 sequence;
+ __le32 flags;
+ __le64 steal;
+ u8 preempted;
+ u8 pad[47];
+} __packed;
+
+#define SBI_STA_SHMEM_DISABLE -1
+
+/* SBI spec version fields */
#define SBI_SPEC_VERSION_DEFAULT 0x1
#define SBI_SPEC_VERSION_MAJOR_SHIFT 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
diff --git a/arch/riscv/include/asm/sections.h b/arch/riscv/include/asm/sections.h
index 32336e8a17cb..a393d5035c54 100644
--- a/arch/riscv/include/asm/sections.h
+++ b/arch/riscv/include/asm/sections.h
@@ -13,6 +13,7 @@ extern char _start_kernel[];
extern char __init_data_begin[], __init_data_end[];
extern char __init_text_begin[], __init_text_end[];
extern char __alt_start[], __alt_end[];
+extern char __exittext_begin[], __exittext_end[];
static inline bool is_va_kernel_text(uintptr_t va)
{
diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h
index 574779900bfb..4856697c5f25 100644
--- a/arch/riscv/include/asm/thread_info.h
+++ b/arch/riscv/include/asm/thread_info.h
@@ -28,7 +28,6 @@
#define THREAD_SHIFT (PAGE_SHIFT + THREAD_SIZE_ORDER)
#define OVERFLOW_STACK_SIZE SZ_4K
-#define SHADOW_OVERFLOW_STACK_SIZE (1024)
#define IRQ_STACK_SIZE THREAD_SIZE
diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h
index 8f3418c5f172..a60416bbe190 100644
--- a/arch/riscv/include/asm/tlbflush.h
+++ b/arch/riscv/include/asm/tlbflush.h
@@ -41,6 +41,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr);
void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end);
void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+void local_flush_tlb_kernel_range(unsigned long start, unsigned long end);
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE
void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start,
diff --git a/arch/riscv/include/asm/xip_fixup.h b/arch/riscv/include/asm/xip_fixup.h
index d4ffc3c37649..b65bf6306f69 100644
--- a/arch/riscv/include/asm/xip_fixup.h
+++ b/arch/riscv/include/asm/xip_fixup.h
@@ -13,7 +13,7 @@
add \reg, \reg, t0
.endm
.macro XIP_FIXUP_FLASH_OFFSET reg
- la t1, __data_loc
+ la t0, __data_loc
REG_L t1, _xip_phys_offset
sub \reg, \reg, t1
add \reg, \reg, t0
diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
index b659ffcfcdb4..9f2a8e3ff204 100644
--- a/arch/riscv/include/uapi/asm/hwprobe.h
+++ b/arch/riscv/include/uapi/asm/hwprobe.h
@@ -30,6 +30,35 @@ struct riscv_hwprobe {
#define RISCV_HWPROBE_EXT_ZBB (1 << 4)
#define RISCV_HWPROBE_EXT_ZBS (1 << 5)
#define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6)
+#define RISCV_HWPROBE_EXT_ZBC (1 << 7)
+#define RISCV_HWPROBE_EXT_ZBKB (1 << 8)
+#define RISCV_HWPROBE_EXT_ZBKC (1 << 9)
+#define RISCV_HWPROBE_EXT_ZBKX (1 << 10)
+#define RISCV_HWPROBE_EXT_ZKND (1 << 11)
+#define RISCV_HWPROBE_EXT_ZKNE (1 << 12)
+#define RISCV_HWPROBE_EXT_ZKNH (1 << 13)
+#define RISCV_HWPROBE_EXT_ZKSED (1 << 14)
+#define RISCV_HWPROBE_EXT_ZKSH (1 << 15)
+#define RISCV_HWPROBE_EXT_ZKT (1 << 16)
+#define RISCV_HWPROBE_EXT_ZVBB (1 << 17)
+#define RISCV_HWPROBE_EXT_ZVBC (1 << 18)
+#define RISCV_HWPROBE_EXT_ZVKB (1 << 19)
+#define RISCV_HWPROBE_EXT_ZVKG (1 << 20)
+#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21)
+#define RISCV_HWPROBE_EXT_ZVKNHA (1 << 22)
+#define RISCV_HWPROBE_EXT_ZVKNHB (1 << 23)
+#define RISCV_HWPROBE_EXT_ZVKSED (1 << 24)
+#define RISCV_HWPROBE_EXT_ZVKSH (1 << 25)
+#define RISCV_HWPROBE_EXT_ZVKT (1 << 26)
+#define RISCV_HWPROBE_EXT_ZFH (1 << 27)
+#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28)
+#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29)
+#define RISCV_HWPROBE_EXT_ZVFH (1 << 30)
+#define RISCV_HWPROBE_EXT_ZVFHMIN (1 << 31)
+#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32)
+#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33)
+#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34)
+#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35)
#define RISCV_HWPROBE_KEY_CPUPERF_0 5
#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0)
@@ -40,4 +69,7 @@ struct riscv_hwprobe {
#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6
/* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
+/* Flags */
+#define RISCV_HWPROBE_WHICH_CPUS (1 << 0)
+
#endif
diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h
index 60d3b21dead7..d6b7a5b95874 100644
--- a/arch/riscv/include/uapi/asm/kvm.h
+++ b/arch/riscv/include/uapi/asm/kvm.h
@@ -157,9 +157,16 @@ enum KVM_RISCV_SBI_EXT_ID {
KVM_RISCV_SBI_EXT_EXPERIMENTAL,
KVM_RISCV_SBI_EXT_VENDOR,
KVM_RISCV_SBI_EXT_DBCN,
+ KVM_RISCV_SBI_EXT_STA,
KVM_RISCV_SBI_EXT_MAX,
};
+/* SBI STA extension registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
+struct kvm_riscv_sbi_sta {
+ unsigned long shmem_lo;
+ unsigned long shmem_hi;
+};
+
/* Possible states for kvm_riscv_timer */
#define KVM_RISCV_TIMER_STATE_OFF 0
#define KVM_RISCV_TIMER_STATE_ON 1
@@ -241,6 +248,12 @@ enum KVM_RISCV_SBI_EXT_ID {
#define KVM_REG_RISCV_VECTOR_REG(n) \
((n) + sizeof(struct __riscv_v_ext_state) / sizeof(unsigned long))
+/* Registers for specific SBI extensions are mapped as type 10 */
+#define KVM_REG_RISCV_SBI_STATE (0x0a << KVM_REG_RISCV_TYPE_SHIFT)
+#define KVM_REG_RISCV_SBI_STA (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT)
+#define KVM_REG_RISCV_SBI_STA_REG(name) \
+ (offsetof(struct kvm_riscv_sbi_sta, name) / sizeof(unsigned long))
+
/* Device Control API: RISC-V AIA */
#define KVM_DEV_RISCV_APLIC_ALIGN 0x1000
#define KVM_DEV_RISCV_APLIC_SIZE 0x4000
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index 82940b6a79a2..c92c623b311e 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -50,6 +50,7 @@ obj-y += setup.o
obj-y += signal.o
obj-y += syscall_table.o
obj-y += sys_riscv.o
+obj-y += sys_hwprobe.o
obj-y += time.o
obj-y += traps.o
obj-y += riscv_ksyms.o
@@ -85,6 +86,7 @@ obj-$(CONFIG_SMP) += sbi-ipi.o
obj-$(CONFIG_SMP) += cpu_ops_sbi.o
endif
obj-$(CONFIG_HOTPLUG_CPU) += cpu-hotplug.o
+obj-$(CONFIG_PARAVIRT) += paravirt.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_KEXEC_CORE) += kexec_relocate.o crash_save_regs.o machine_kexec.o
obj-$(CONFIG_KEXEC_FILE) += elf_kexec.o machine_kexec_file.o
diff --git a/arch/riscv/kernel/cpu-hotplug.c b/arch/riscv/kernel/cpu-hotplug.c
index 457a18efcb11..28b58fc5ad19 100644
--- a/arch/riscv/kernel/cpu-hotplug.c
+++ b/arch/riscv/kernel/cpu-hotplug.c
@@ -18,7 +18,7 @@
bool cpu_has_hotplug(unsigned int cpu)
{
- if (cpu_ops[cpu]->cpu_stop)
+ if (cpu_ops->cpu_stop)
return true;
return false;
@@ -29,25 +29,18 @@ bool cpu_has_hotplug(unsigned int cpu)
*/
int __cpu_disable(void)
{
- int ret = 0;
unsigned int cpu = smp_processor_id();
- if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_stop)
+ if (!cpu_ops->cpu_stop)
return -EOPNOTSUPP;
- if (cpu_ops[cpu]->cpu_disable)
- ret = cpu_ops[cpu]->cpu_disable(cpu);
-
- if (ret)
- return ret;
-
remove_cpu_topology(cpu);
numa_remove_cpu(cpu);
set_cpu_online(cpu, false);
riscv_ipi_disable();
irq_migrate_all_off_this_cpu();
- return ret;
+ return 0;
}
#ifdef CONFIG_HOTPLUG_CPU
@@ -62,8 +55,8 @@ void arch_cpuhp_cleanup_dead_cpu(unsigned int cpu)
pr_notice("CPU%u: off\n", cpu);
/* Verify from the firmware if the cpu is really stopped*/
- if (cpu_ops[cpu]->cpu_is_stopped)
- ret = cpu_ops[cpu]->cpu_is_stopped(cpu);
+ if (cpu_ops->cpu_is_stopped)
+ ret = cpu_ops->cpu_is_stopped(cpu);
if (ret)
pr_warn("CPU%d may not have stopped: %d\n", cpu, ret);
}
@@ -77,7 +70,7 @@ void __noreturn arch_cpu_idle_dead(void)
cpuhp_ap_report_dead();
- cpu_ops[smp_processor_id()]->cpu_stop();
+ cpu_ops->cpu_stop();
/* It should never reach here */
BUG();
}
diff --git a/arch/riscv/kernel/cpu_ops.c b/arch/riscv/kernel/cpu_ops.c
index eb479a88a954..6a8bd8f4db07 100644
--- a/arch/riscv/kernel/cpu_ops.c
+++ b/arch/riscv/kernel/cpu_ops.c
@@ -13,25 +13,21 @@
#include <asm/sbi.h>
#include <asm/smp.h>
-const struct cpu_operations *cpu_ops[NR_CPUS] __ro_after_init;
+const struct cpu_operations *cpu_ops __ro_after_init = &cpu_ops_spinwait;
extern const struct cpu_operations cpu_ops_sbi;
#ifndef CONFIG_RISCV_BOOT_SPINWAIT
const struct cpu_operations cpu_ops_spinwait = {
- .name = "",
- .cpu_prepare = NULL,
.cpu_start = NULL,
};
#endif
-void __init cpu_set_ops(int cpuid)
+void __init cpu_set_ops(void)
{
#if IS_ENABLED(CONFIG_RISCV_SBI)
if (sbi_probe_extension(SBI_EXT_HSM)) {
- if (!cpuid)
- pr_info("SBI HSM extension detected\n");
- cpu_ops[cpuid] = &cpu_ops_sbi;
- } else
+ pr_info("SBI HSM extension detected\n");
+ cpu_ops = &cpu_ops_sbi;
+ }
#endif
- cpu_ops[cpuid] = &cpu_ops_spinwait;
}
diff --git a/arch/riscv/kernel/cpu_ops_sbi.c b/arch/riscv/kernel/cpu_ops_sbi.c
index efa0f0816634..1cc7df740edd 100644
--- a/arch/riscv/kernel/cpu_ops_sbi.c
+++ b/arch/riscv/kernel/cpu_ops_sbi.c
@@ -79,23 +79,7 @@ static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle)
return sbi_hsm_hart_start(hartid, boot_addr, hsm_data);
}
-static int sbi_cpu_prepare(unsigned int cpuid)
-{
- if (!cpu_ops_sbi.cpu_start) {
- pr_err("cpu start method not defined for CPU [%d]\n", cpuid);
- return -ENODEV;
- }
- return 0;
-}
-
#ifdef CONFIG_HOTPLUG_CPU
-static int sbi_cpu_disable(unsigned int cpuid)
-{
- if (!cpu_ops_sbi.cpu_stop)
- return -EOPNOTSUPP;
- return 0;
-}
-
static void sbi_cpu_stop(void)
{
int ret;
@@ -118,11 +102,8 @@ static int sbi_cpu_is_stopped(unsigned int cpuid)
#endif
const struct cpu_operations cpu_ops_sbi = {
- .name = "sbi",
- .cpu_prepare = sbi_cpu_prepare,
.cpu_start = sbi_cpu_start,
#ifdef CONFIG_HOTPLUG_CPU
- .cpu_disable = sbi_cpu_disable,
.cpu_stop = sbi_cpu_stop,
.cpu_is_stopped = sbi_cpu_is_stopped,
#endif
diff --git a/arch/riscv/kernel/cpu_ops_spinwait.c b/arch/riscv/kernel/cpu_ops_spinwait.c
index d98d19226b5f..613872b0a21a 100644
--- a/arch/riscv/kernel/cpu_ops_spinwait.c
+++ b/arch/riscv/kernel/cpu_ops_spinwait.c
@@ -39,15 +39,6 @@ static void cpu_update_secondary_bootdata(unsigned int cpuid,
WRITE_ONCE(__cpu_spinwait_task_pointer[hartid], tidle);
}
-static int spinwait_cpu_prepare(unsigned int cpuid)
-{
- if (!cpu_ops_spinwait.cpu_start) {
- pr_err("cpu start method not defined for CPU [%d]\n", cpuid);
- return -ENODEV;
- }
- return 0;
-}
-
static int spinwait_cpu_start(unsigned int cpuid, struct task_struct *tidle)
{
/*
@@ -64,7 +55,5 @@ static int spinwait_cpu_start(unsigned int cpuid, struct task_struct *tidle)
}
const struct cpu_operations cpu_ops_spinwait = {
- .name = "spinwait",
- .cpu_prepare = spinwait_cpu_prepare,
.cpu_start = spinwait_cpu_start,
};
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index b3785ffc1570..e32591e9da90 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -70,7 +70,7 @@ EXPORT_SYMBOL_GPL(riscv_isa_extension_base);
*
* NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used.
*/
-bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit)
+bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned int bit)
{
const unsigned long *bmap = (isa_bitmap) ? isa_bitmap : riscv_isa;
@@ -102,17 +102,101 @@ static bool riscv_isa_extension_check(int id)
return false;
}
return true;
+ case RISCV_ISA_EXT_INVALID:
+ return false;
}
return true;
}
-#define __RISCV_ISA_EXT_DATA(_name, _id) { \
- .name = #_name, \
- .property = #_name, \
- .id = _id, \
+#define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size) { \
+ .name = #_name, \
+ .property = #_name, \
+ .id = _id, \
+ .subset_ext_ids = _subset_exts, \
+ .subset_ext_size = _subset_exts_size \
}
+#define __RISCV_ISA_EXT_DATA(_name, _id) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0)
+
+/* Used to declare pure "lasso" extension (Zk for instance) */
+#define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) \
+ _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, ARRAY_SIZE(_bundled_exts))
+
+/* Used to declare extensions that are a superset of other extensions (Zvbb for instance) */
+#define __RISCV_ISA_EXT_SUPERSET(_name, _id, _sub_exts) \
+ _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts))
+
+static const unsigned int riscv_zk_bundled_exts[] = {
+ RISCV_ISA_EXT_ZBKB,
+ RISCV_ISA_EXT_ZBKC,
+ RISCV_ISA_EXT_ZBKX,
+ RISCV_ISA_EXT_ZKND,
+ RISCV_ISA_EXT_ZKNE,
+ RISCV_ISA_EXT_ZKR,
+ RISCV_ISA_EXT_ZKT,
+};
+
+static const unsigned int riscv_zkn_bundled_exts[] = {
+ RISCV_ISA_EXT_ZBKB,
+ RISCV_ISA_EXT_ZBKC,
+ RISCV_ISA_EXT_ZBKX,
+ RISCV_ISA_EXT_ZKND,
+ RISCV_ISA_EXT_ZKNE,
+ RISCV_ISA_EXT_ZKNH,
+};
+
+static const unsigned int riscv_zks_bundled_exts[] = {
+ RISCV_ISA_EXT_ZBKB,
+ RISCV_ISA_EXT_ZBKC,
+ RISCV_ISA_EXT_ZKSED,
+ RISCV_ISA_EXT_ZKSH
+};
+
+#define RISCV_ISA_EXT_ZVKN \
+ RISCV_ISA_EXT_ZVKNED, \
+ RISCV_ISA_EXT_ZVKNHB, \
+ RISCV_ISA_EXT_ZVKB, \
+ RISCV_ISA_EXT_ZVKT
+
+static const unsigned int riscv_zvkn_bundled_exts[] = {
+ RISCV_ISA_EXT_ZVKN
+};
+
+static const unsigned int riscv_zvknc_bundled_exts[] = {
+ RISCV_ISA_EXT_ZVKN,
+ RISCV_ISA_EXT_ZVBC
+};
+
+static const unsigned int riscv_zvkng_bundled_exts[] = {
+ RISCV_ISA_EXT_ZVKN,
+ RISCV_ISA_EXT_ZVKG
+};
+
+#define RISCV_ISA_EXT_ZVKS \
+ RISCV_ISA_EXT_ZVKSED, \
+ RISCV_ISA_EXT_ZVKSH, \
+ RISCV_ISA_EXT_ZVKB, \
+ RISCV_ISA_EXT_ZVKT
+
+static const unsigned int riscv_zvks_bundled_exts[] = {
+ RISCV_ISA_EXT_ZVKS
+};
+
+static const unsigned int riscv_zvksc_bundled_exts[] = {
+ RISCV_ISA_EXT_ZVKS,
+ RISCV_ISA_EXT_ZVBC
+};
+
+static const unsigned int riscv_zvksg_bundled_exts[] = {
+ RISCV_ISA_EXT_ZVKS,
+ RISCV_ISA_EXT_ZVKG
+};
+
+static const unsigned int riscv_zvbb_exts[] = {
+ RISCV_ISA_EXT_ZVKB
+};
+
/*
* The canonical order of ISA extension names in the ISA string is defined in
* chapter 27 of the unprivileged specification.
@@ -160,10 +244,6 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
__RISCV_ISA_EXT_DATA(d, RISCV_ISA_EXT_d),
__RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_q),
__RISCV_ISA_EXT_DATA(c, RISCV_ISA_EXT_c),
- __RISCV_ISA_EXT_DATA(b, RISCV_ISA_EXT_b),
- __RISCV_ISA_EXT_DATA(k, RISCV_ISA_EXT_k),
- __RISCV_ISA_EXT_DATA(j, RISCV_ISA_EXT_j),
- __RISCV_ISA_EXT_DATA(p, RISCV_ISA_EXT_p),
__RISCV_ISA_EXT_DATA(v, RISCV_ISA_EXT_v),
__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h),
__RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM),
@@ -172,11 +252,49 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
__RISCV_ISA_EXT_DATA(zicond, RISCV_ISA_EXT_ZICOND),
__RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR),
__RISCV_ISA_EXT_DATA(zifencei, RISCV_ISA_EXT_ZIFENCEI),
+ __RISCV_ISA_EXT_DATA(zihintntl, RISCV_ISA_EXT_ZIHINTNTL),
__RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
__RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM),
+ __RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS),
+ __RISCV_ISA_EXT_DATA(zfa, RISCV_ISA_EXT_ZFA),
+ __RISCV_ISA_EXT_DATA(zfh, RISCV_ISA_EXT_ZFH),
+ __RISCV_ISA_EXT_DATA(zfhmin, RISCV_ISA_EXT_ZFHMIN),
__RISCV_ISA_EXT_DATA(zba, RISCV_ISA_EXT_ZBA),
__RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB),
+ __RISCV_ISA_EXT_DATA(zbc, RISCV_ISA_EXT_ZBC),
+ __RISCV_ISA_EXT_DATA(zbkb, RISCV_ISA_EXT_ZBKB),
+ __RISCV_ISA_EXT_DATA(zbkc, RISCV_ISA_EXT_ZBKC),
+ __RISCV_ISA_EXT_DATA(zbkx, RISCV_ISA_EXT_ZBKX),
__RISCV_ISA_EXT_DATA(zbs, RISCV_ISA_EXT_ZBS),
+ __RISCV_ISA_EXT_BUNDLE(zk, riscv_zk_bundled_exts),
+ __RISCV_ISA_EXT_BUNDLE(zkn, riscv_zkn_bundled_exts),
+ __RISCV_ISA_EXT_DATA(zknd, RISCV_ISA_EXT_ZKND),
+ __RISCV_ISA_EXT_DATA(zkne, RISCV_ISA_EXT_ZKNE),
+ __RISCV_ISA_EXT_DATA(zknh, RISCV_ISA_EXT_ZKNH),
+ __RISCV_ISA_EXT_DATA(zkr, RISCV_ISA_EXT_ZKR),
+ __RISCV_ISA_EXT_BUNDLE(zks, riscv_zks_bundled_exts),
+ __RISCV_ISA_EXT_DATA(zkt, RISCV_ISA_EXT_ZKT),
+ __RISCV_ISA_EXT_DATA(zksed, RISCV_ISA_EXT_ZKSED),
+ __RISCV_ISA_EXT_DATA(zksh, RISCV_ISA_EXT_ZKSH),
+ __RISCV_ISA_EXT_DATA(ztso, RISCV_ISA_EXT_ZTSO),
+ __RISCV_ISA_EXT_SUPERSET(zvbb, RISCV_ISA_EXT_ZVBB, riscv_zvbb_exts),
+ __RISCV_ISA_EXT_DATA(zvbc, RISCV_ISA_EXT_ZVBC),
+ __RISCV_ISA_EXT_DATA(zvfh, RISCV_ISA_EXT_ZVFH),
+ __RISCV_ISA_EXT_DATA(zvfhmin, RISCV_ISA_EXT_ZVFHMIN),
+ __RISCV_ISA_EXT_DATA(zvkb, RISCV_ISA_EXT_ZVKB),
+ __RISCV_ISA_EXT_DATA(zvkg, RISCV_ISA_EXT_ZVKG),
+ __RISCV_ISA_EXT_BUNDLE(zvkn, riscv_zvkn_bundled_exts),
+ __RISCV_ISA_EXT_BUNDLE(zvknc, riscv_zvknc_bundled_exts),
+ __RISCV_ISA_EXT_DATA(zvkned, RISCV_ISA_EXT_ZVKNED),
+ __RISCV_ISA_EXT_BUNDLE(zvkng, riscv_zvkng_bundled_exts),
+ __RISCV_ISA_EXT_DATA(zvknha, RISCV_ISA_EXT_ZVKNHA),
+ __RISCV_ISA_EXT_DATA(zvknhb, RISCV_ISA_EXT_ZVKNHB),
+ __RISCV_ISA_EXT_BUNDLE(zvks, riscv_zvks_bundled_exts),
+ __RISCV_ISA_EXT_BUNDLE(zvksc, riscv_zvksc_bundled_exts),
+ __RISCV_ISA_EXT_DATA(zvksed, RISCV_ISA_EXT_ZVKSED),
+ __RISCV_ISA_EXT_DATA(zvksh, RISCV_ISA_EXT_ZVKSH),
+ __RISCV_ISA_EXT_BUNDLE(zvksg, riscv_zvksg_bundled_exts),
+ __RISCV_ISA_EXT_DATA(zvkt, RISCV_ISA_EXT_ZVKT),
__RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA),
__RISCV_ISA_EXT_DATA(smstateen, RISCV_ISA_EXT_SMSTATEEN),
__RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
@@ -189,6 +307,31 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
const size_t riscv_isa_ext_count = ARRAY_SIZE(riscv_isa_ext);
+static void __init match_isa_ext(const struct riscv_isa_ext_data *ext, const char *name,
+ const char *name_end, struct riscv_isainfo *isainfo)
+{
+ if ((name_end - name == strlen(ext->name)) &&
+ !strncasecmp(name, ext->name, name_end - name)) {
+ /*
+ * If this is a bundle, enable all the ISA extensions that
+ * comprise the bundle.
+ */
+ if (ext->subset_ext_size) {
+ for (int i = 0; i < ext->subset_ext_size; i++) {
+ if (riscv_isa_extension_check(ext->subset_ext_ids[i]))
+ set_bit(ext->subset_ext_ids[i], isainfo->isa);
+ }
+ }
+
+ /*
+ * This is valid even for bundle extensions which uses the RISCV_ISA_EXT_INVALID id
+ * (rejected by riscv_isa_extension_check()).
+ */
+ if (riscv_isa_extension_check(ext->id))
+ set_bit(ext->id, isainfo->isa);
+ }
+}
+
static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct riscv_isainfo *isainfo,
unsigned long *isa2hwcap, const char *isa)
{
@@ -321,14 +464,6 @@ static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc
if (*isa == '_')
++isa;
-#define SET_ISA_EXT_MAP(name, bit) \
- do { \
- if ((ext_end - ext == strlen(name)) && \
- !strncasecmp(ext, name, strlen(name)) && \
- riscv_isa_extension_check(bit)) \
- set_bit(bit, isainfo->isa); \
- } while (false) \
-
if (unlikely(ext_err))
continue;
if (!ext_long) {
@@ -340,10 +475,8 @@ static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc
}
} else {
for (int i = 0; i < riscv_isa_ext_count; i++)
- SET_ISA_EXT_MAP(riscv_isa_ext[i].name,
- riscv_isa_ext[i].id);
+ match_isa_ext(&riscv_isa_ext[i], ext, ext_end, isainfo);
}
-#undef SET_ISA_EXT_MAP
}
}
@@ -442,18 +575,26 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
}
for (int i = 0; i < riscv_isa_ext_count; i++) {
+ const struct riscv_isa_ext_data *ext = &riscv_isa_ext[i];
+
if (of_property_match_string(cpu_node, "riscv,isa-extensions",
- riscv_isa_ext[i].property) < 0)
+ ext->property) < 0)
continue;
- if (!riscv_isa_extension_check(riscv_isa_ext[i].id))
- continue;
+ if (ext->subset_ext_size) {
+ for (int j = 0; j < ext->subset_ext_size; j++) {
+ if (riscv_isa_extension_check(ext->subset_ext_ids[i]))
+ set_bit(ext->subset_ext_ids[j], isainfo->isa);
+ }
+ }
- /* Only single letter extensions get set in hwcap */
- if (strnlen(riscv_isa_ext[i].name, 2) == 1)
- this_hwcap |= isa2hwcap[riscv_isa_ext[i].id];
+ if (riscv_isa_extension_check(ext->id)) {
+ set_bit(ext->id, isainfo->isa);
- set_bit(riscv_isa_ext[i].id, isainfo->isa);
+ /* Only single letter extensions get set in hwcap */
+ if (strnlen(riscv_isa_ext[i].name, 2) == 1)
+ this_hwcap |= isa2hwcap[riscv_isa_ext[i].id];
+ }
}
of_node_put(cpu_node);
diff --git a/arch/riscv/kernel/efi.c b/arch/riscv/kernel/efi.c
index aa6209a74c83..b64bf1624a05 100644
--- a/arch/riscv/kernel/efi.c
+++ b/arch/riscv/kernel/efi.c
@@ -60,7 +60,7 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data)
{
efi_memory_desc_t *md = data;
- pte_t pte = READ_ONCE(*ptep);
+ pte_t pte = ptep_get(ptep);
unsigned long val;
if (md->attribute & EFI_MEMORY_RO) {
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
index 76ace1e0b46f..4236a69c35cb 100644
--- a/arch/riscv/kernel/head.S
+++ b/arch/riscv/kernel/head.S
@@ -11,7 +11,6 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/csr.h>
-#include <asm/cpu_ops_sbi.h>
#include <asm/hwcap.h>
#include <asm/image.h>
#include <asm/scs.h>
@@ -89,6 +88,7 @@ relocate_enable_mmu:
/* Compute satp for kernel page tables, but don't load it yet */
srl a2, a0, PAGE_SHIFT
la a1, satp_mode
+ XIP_FIXUP_OFFSET a1
REG_L a1, 0(a1)
or a2, a2, a1
@@ -265,10 +265,12 @@ SYM_CODE_START(_start_kernel)
la sp, _end + THREAD_SIZE
XIP_FIXUP_OFFSET sp
mv s0, a0
+ mv s1, a1
call __copy_data
- /* Restore a0 copy */
+ /* Restore a0 & a1 copy */
mv a0, s0
+ mv a1, s1
#endif
#ifndef CONFIG_XIP_KERNEL
diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S
index 58dd96a2a153..79dc81223238 100644
--- a/arch/riscv/kernel/mcount-dyn.S
+++ b/arch/riscv/kernel/mcount-dyn.S
@@ -3,12 +3,12 @@
#include <linux/init.h>
#include <linux/linkage.h>
+#include <linux/export.h>
#include <asm/asm.h>
#include <asm/csr.h>
#include <asm/unistd.h>
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
-#include <asm-generic/export.h>
#include <asm/ftrace.h>
.text
diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S
index b4dd9ed6849e..d7ec69ac6910 100644
--- a/arch/riscv/kernel/mcount.S
+++ b/arch/riscv/kernel/mcount.S
@@ -4,12 +4,12 @@
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/cfi_types.h>
+#include <linux/export.h>
#include <asm/asm.h>
#include <asm/csr.h>
#include <asm/unistd.h>
#include <asm/thread_info.h>
#include <asm/asm-offsets.h>
-#include <asm-generic/export.h>
#include <asm/ftrace.h>
.text
diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c
index aac019ed63b1..862834bb1d64 100644
--- a/arch/riscv/kernel/module.c
+++ b/arch/riscv/kernel/module.c
@@ -894,7 +894,8 @@ void *module_alloc(unsigned long size)
{
return __vmalloc_node_range(size, 1, MODULES_VADDR,
MODULES_END, GFP_KERNEL,
- PAGE_KERNEL, 0, NUMA_NO_NODE,
+ PAGE_KERNEL, VM_FLUSH_RESET_PERMS,
+ NUMA_NO_NODE,
__builtin_return_address(0));
}
#endif
diff --git a/arch/riscv/kernel/paravirt.c b/arch/riscv/kernel/paravirt.c
new file mode 100644
index 000000000000..8e114f5930ce
--- /dev/null
+++ b/arch/riscv/kernel/paravirt.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Ventana Micro Systems Inc.
+ */
+
+#define pr_fmt(fmt) "riscv-pv: " fmt
+
+#include <linux/cpuhotplug.h>
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/jump_label.h>
+#include <linux/kconfig.h>
+#include <linux/kernel.h>
+#include <linux/percpu-defs.h>
+#include <linux/printk.h>
+#include <linux/static_call.h>
+#include <linux/types.h>
+
+#include <asm/barrier.h>
+#include <asm/page.h>
+#include <asm/paravirt.h>
+#include <asm/sbi.h>
+
+struct static_key paravirt_steal_enabled;
+struct static_key paravirt_steal_rq_enabled;
+
+static u64 native_steal_clock(int cpu)
+{
+ return 0;
+}
+
+DEFINE_STATIC_CALL(pv_steal_clock, native_steal_clock);
+
+static bool steal_acc = true;
+static int __init parse_no_stealacc(char *arg)
+{
+ steal_acc = false;
+ return 0;
+}
+
+early_param("no-steal-acc", parse_no_stealacc);
+
+DEFINE_PER_CPU(struct sbi_sta_struct, steal_time) __aligned(64);
+
+static bool __init has_pv_steal_clock(void)
+{
+ if (sbi_spec_version >= sbi_mk_version(2, 0) &&
+ sbi_probe_extension(SBI_EXT_STA) > 0) {
+ pr_info("SBI STA extension detected\n");
+ return true;
+ }
+
+ return false;
+}
+
+static int sbi_sta_steal_time_set_shmem(unsigned long lo, unsigned long hi,
+ unsigned long flags)
+{
+ struct sbiret ret;
+
+ ret = sbi_ecall(SBI_EXT_STA, SBI_EXT_STA_STEAL_TIME_SET_SHMEM,
+ lo, hi, flags, 0, 0, 0);
+ if (ret.error) {
+ if (lo == SBI_STA_SHMEM_DISABLE && hi == SBI_STA_SHMEM_DISABLE)
+ pr_warn("Failed to disable steal-time shmem");
+ else
+ pr_warn("Failed to set steal-time shmem");
+ return sbi_err_map_linux_errno(ret.error);
+ }
+
+ return 0;
+}
+
+static int pv_time_cpu_online(unsigned int cpu)
+{
+ struct sbi_sta_struct *st = this_cpu_ptr(&steal_time);
+ phys_addr_t pa = __pa(st);
+ unsigned long lo = (unsigned long)pa;
+ unsigned long hi = IS_ENABLED(CONFIG_32BIT) ? upper_32_bits((u64)pa) : 0;
+
+ return sbi_sta_steal_time_set_shmem(lo, hi, 0);
+}
+
+static int pv_time_cpu_down_prepare(unsigned int cpu)
+{
+ return sbi_sta_steal_time_set_shmem(SBI_STA_SHMEM_DISABLE,
+ SBI_STA_SHMEM_DISABLE, 0);
+}
+
+static u64 pv_time_steal_clock(int cpu)
+{
+ struct sbi_sta_struct *st = per_cpu_ptr(&steal_time, cpu);
+ u32 sequence;
+ u64 steal;
+
+ /*
+ * Check the sequence field before and after reading the steal
+ * field. Repeat the read if it is different or odd.
+ */
+ do {
+ sequence = READ_ONCE(st->sequence);
+ virt_rmb();
+ steal = READ_ONCE(st->steal);
+ virt_rmb();
+ } while ((le32_to_cpu(sequence) & 1) ||
+ sequence != READ_ONCE(st->sequence));
+
+ return le64_to_cpu(steal);
+}
+
+int __init pv_time_init(void)
+{
+ int ret;
+
+ if (!has_pv_steal_clock())
+ return 0;
+
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+ "riscv/pv_time:online",
+ pv_time_cpu_online,
+ pv_time_cpu_down_prepare);
+ if (ret < 0)
+ return ret;
+
+ static_call_update(pv_steal_clock, pv_time_steal_clock);
+
+ static_key_slow_inc(&paravirt_steal_enabled);
+ if (steal_acc)
+ static_key_slow_inc(&paravirt_steal_rq_enabled);
+
+ pr_info("Computing paravirt steal-time\n");
+
+ return 0;
+}
diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c
index 13ee7bf589a1..37e87fdcf6a0 100644
--- a/arch/riscv/kernel/patch.c
+++ b/arch/riscv/kernel/patch.c
@@ -14,6 +14,7 @@
#include <asm/fixmap.h>
#include <asm/ftrace.h>
#include <asm/patch.h>
+#include <asm/sections.h>
struct patch_insn {
void *addr;
@@ -25,6 +26,14 @@ struct patch_insn {
int riscv_patch_in_stop_machine = false;
#ifdef CONFIG_MMU
+
+static inline bool is_kernel_exittext(uintptr_t addr)
+{
+ return system_state < SYSTEM_RUNNING &&
+ addr >= (uintptr_t)__exittext_begin &&
+ addr < (uintptr_t)__exittext_end;
+}
+
/*
* The fix_to_virt(, idx) needs a const value (not a dynamic variable of
* reg-a0) or BUILD_BUG_ON failed with "idx >= __end_of_fixed_addresses".
@@ -35,7 +44,7 @@ static __always_inline void *patch_map(void *addr, const unsigned int fixmap)
uintptr_t uintaddr = (uintptr_t) addr;
struct page *page;
- if (core_kernel_text(uintaddr))
+ if (core_kernel_text(uintaddr) || is_kernel_exittext(uintaddr))
page = phys_to_page(__pa_symbol(addr));
else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
page = vmalloc_to_page(addr);
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index 535a837de55d..4f73c0ae44b2 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -26,7 +26,6 @@
#include <asm/alternative.h>
#include <asm/cacheflush.h>
#include <asm/cpufeature.h>
-#include <asm/cpu_ops.h>
#include <asm/early_ioremap.h>
#include <asm/pgtable.h>
#include <asm/setup.h>
@@ -51,7 +50,6 @@ atomic_t hart_lottery __section(".sdata")
#endif
;
unsigned long boot_cpu_hartid;
-static DEFINE_PER_CPU(struct cpu, cpu_devices);
/*
* Place kernel memory regions on the resource tree so that
@@ -299,23 +297,10 @@ void __init setup_arch(char **cmdline_p)
riscv_user_isa_enable();
}
-static int __init topology_init(void)
+bool arch_cpu_is_hotpluggable(int cpu)
{
- int i, ret;
-
- for_each_possible_cpu(i) {
- struct cpu *cpu = &per_cpu(cpu_devices, i);
-
- cpu->hotpluggable = cpu_has_hotplug(i);
- ret = register_cpu(cpu, i);
- if (unlikely(ret))
- pr_warn("Warning: %s: register_cpu %d failed (%d)\n",
- __func__, i, ret);
- }
-
- return 0;
+ return cpu_has_hotplug(cpu);
}
-subsys_initcall(topology_init);
void free_initmem(void)
{
diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
index 88b6220b2608..33dfb5078301 100644
--- a/arch/riscv/kernel/signal.c
+++ b/arch/riscv/kernel/signal.c
@@ -91,7 +91,7 @@ static long save_v_state(struct pt_regs *regs, void __user **sc_vec)
err = __copy_to_user(&state->v_state, &current->thread.vstate,
offsetof(struct __riscv_v_ext_state, datap));
/* Copy the pointer datap itself. */
- err |= __put_user(datap, &state->v_state.datap);
+ err |= __put_user((__force void *)datap, &state->v_state.datap);
/* Copy the whole vector content to user space datap. */
err |= __copy_to_user(datap, current->thread.vstate.datap, riscv_v_vsize);
/* Copy magic to the user space after saving all vector conetext */
diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c
index 40420afbb1a0..45dd4035416e 100644
--- a/arch/riscv/kernel/smp.c
+++ b/arch/riscv/kernel/smp.c
@@ -81,7 +81,7 @@ static inline void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs)
#ifdef CONFIG_HOTPLUG_CPU
if (cpu_has_hotplug(cpu))
- cpu_ops[cpu]->cpu_stop();
+ cpu_ops->cpu_stop();
#endif
for(;;)
diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
index d162bf339beb..519b6bd946e5 100644
--- a/arch/riscv/kernel/smpboot.c
+++ b/arch/riscv/kernel/smpboot.c
@@ -49,7 +49,6 @@ void __init smp_prepare_boot_cpu(void)
void __init smp_prepare_cpus(unsigned int max_cpus)
{
int cpuid;
- int ret;
unsigned int curr_cpuid;
init_cpu_topology();
@@ -66,11 +65,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
for_each_possible_cpu(cpuid) {
if (cpuid == curr_cpuid)
continue;
- if (cpu_ops[cpuid]->cpu_prepare) {
- ret = cpu_ops[cpuid]->cpu_prepare(cpuid);
- if (ret)
- continue;
- }
set_cpu_present(cpuid, true);
numa_store_cpu_info(cpuid);
}
@@ -125,18 +119,7 @@ static int __init acpi_parse_rintc(union acpi_subtable_headers *header, const un
static void __init acpi_parse_and_init_cpus(void)
{
- int cpuid;
-
- cpu_set_ops(0);
-
acpi_table_parse_madt(ACPI_MADT_TYPE_RINTC, acpi_parse_rintc, 0);
-
- for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++) {
- if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID) {
- cpu_set_ops(cpuid);
- set_cpu_possible(cpuid, true);
- }
- }
}
#else
#define acpi_parse_and_init_cpus(...) do { } while (0)
@@ -150,8 +133,6 @@ static void __init of_parse_and_init_cpus(void)
int cpuid = 1;
int rc;
- cpu_set_ops(0);
-
for_each_of_cpu_node(dn) {
rc = riscv_early_of_processor_hartid(dn, &hart);
if (rc < 0)
@@ -179,27 +160,28 @@ static void __init of_parse_and_init_cpus(void)
if (cpuid > nr_cpu_ids)
pr_warn("Total number of cpus [%d] is greater than nr_cpus option value [%d]\n",
cpuid, nr_cpu_ids);
-
- for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++) {
- if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID) {
- cpu_set_ops(cpuid);
- set_cpu_possible(cpuid, true);
- }
- }
}
void __init setup_smp(void)
{
+ int cpuid;
+
+ cpu_set_ops();
+
if (acpi_disabled)
of_parse_and_init_cpus();
else
acpi_parse_and_init_cpus();
+
+ for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++)
+ if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID)
+ set_cpu_possible(cpuid, true);
}
static int start_secondary_cpu(int cpu, struct task_struct *tidle)
{
- if (cpu_ops[cpu]->cpu_start)
- return cpu_ops[cpu]->cpu_start(cpu, tidle);
+ if (cpu_ops->cpu_start)
+ return cpu_ops->cpu_start(cpu, tidle);
return -EOPNOTSUPP;
}
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
new file mode 100644
index 000000000000..a7c56b41efd2
--- /dev/null
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -0,0 +1,411 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * The hwprobe interface, for allowing userspace to probe to see which features
+ * are supported by the hardware. See Documentation/arch/riscv/hwprobe.rst for
+ * more details.
+ */
+#include <linux/syscalls.h>
+#include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
+#include <asm/hwprobe.h>
+#include <asm/sbi.h>
+#include <asm/switch_to.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+#include <asm/vector.h>
+#include <vdso/vsyscall.h>
+
+
+static void hwprobe_arch_id(struct riscv_hwprobe *pair,
+ const struct cpumask *cpus)
+{
+ u64 id = -1ULL;
+ bool first = true;
+ int cpu;
+
+ for_each_cpu(cpu, cpus) {
+ u64 cpu_id;
+
+ switch (pair->key) {
+ case RISCV_HWPROBE_KEY_MVENDORID:
+ cpu_id = riscv_cached_mvendorid(cpu);
+ break;
+ case RISCV_HWPROBE_KEY_MIMPID:
+ cpu_id = riscv_cached_mimpid(cpu);
+ break;
+ case RISCV_HWPROBE_KEY_MARCHID:
+ cpu_id = riscv_cached_marchid(cpu);
+ break;
+ }
+
+ if (first) {
+ id = cpu_id;
+ first = false;
+ }
+
+ /*
+ * If there's a mismatch for the given set, return -1 in the
+ * value.
+ */
+ if (id != cpu_id) {
+ id = -1ULL;
+ break;
+ }
+ }
+
+ pair->value = id;
+}
+
+static void hwprobe_isa_ext0(struct riscv_hwprobe *pair,
+ const struct cpumask *cpus)
+{
+ int cpu;
+ u64 missing = 0;
+
+ pair->value = 0;
+ if (has_fpu())
+ pair->value |= RISCV_HWPROBE_IMA_FD;
+
+ if (riscv_isa_extension_available(NULL, c))
+ pair->value |= RISCV_HWPROBE_IMA_C;
+
+ if (has_vector())
+ pair->value |= RISCV_HWPROBE_IMA_V;
+
+ /*
+ * Loop through and record extensions that 1) anyone has, and 2) anyone
+ * doesn't have.
+ */
+ for_each_cpu(cpu, cpus) {
+ struct riscv_isainfo *isainfo = &hart_isa[cpu];
+
+#define EXT_KEY(ext) \
+ do { \
+ if (__riscv_isa_extension_available(isainfo->isa, RISCV_ISA_EXT_##ext)) \
+ pair->value |= RISCV_HWPROBE_EXT_##ext; \
+ else \
+ missing |= RISCV_HWPROBE_EXT_##ext; \
+ } while (false)
+
+ /*
+ * Only use EXT_KEY() for extensions which can be exposed to userspace,
+ * regardless of the kernel's configuration, as no other checks, besides
+ * presence in the hart_isa bitmap, are made.
+ */
+ EXT_KEY(ZBA);
+ EXT_KEY(ZBB);
+ EXT_KEY(ZBS);
+ EXT_KEY(ZICBOZ);
+ EXT_KEY(ZBC);
+
+ EXT_KEY(ZBKB);
+ EXT_KEY(ZBKC);
+ EXT_KEY(ZBKX);
+ EXT_KEY(ZKND);
+ EXT_KEY(ZKNE);
+ EXT_KEY(ZKNH);
+ EXT_KEY(ZKSED);
+ EXT_KEY(ZKSH);
+ EXT_KEY(ZKT);
+ EXT_KEY(ZIHINTNTL);
+ EXT_KEY(ZTSO);
+ EXT_KEY(ZACAS);
+ EXT_KEY(ZICOND);
+
+ if (has_vector()) {
+ EXT_KEY(ZVBB);
+ EXT_KEY(ZVBC);
+ EXT_KEY(ZVKB);
+ EXT_KEY(ZVKG);
+ EXT_KEY(ZVKNED);
+ EXT_KEY(ZVKNHA);
+ EXT_KEY(ZVKNHB);
+ EXT_KEY(ZVKSED);
+ EXT_KEY(ZVKSH);
+ EXT_KEY(ZVKT);
+ EXT_KEY(ZVFH);
+ EXT_KEY(ZVFHMIN);
+ }
+
+ if (has_fpu()) {
+ EXT_KEY(ZFH);
+ EXT_KEY(ZFHMIN);
+ EXT_KEY(ZFA);
+ }
+#undef EXT_KEY
+ }
+
+ /* Now turn off reporting features if any CPU is missing it. */
+ pair->value &= ~missing;
+}
+
+static bool hwprobe_ext0_has(const struct cpumask *cpus, unsigned long ext)
+{
+ struct riscv_hwprobe pair;
+
+ hwprobe_isa_ext0(&pair, cpus);
+ return (pair.value & ext);
+}
+
+static u64 hwprobe_misaligned(const struct cpumask *cpus)
+{
+ int cpu;
+ u64 perf = -1ULL;
+
+ for_each_cpu(cpu, cpus) {
+ int this_perf = per_cpu(misaligned_access_speed, cpu);
+
+ if (perf == -1ULL)
+ perf = this_perf;
+
+ if (perf != this_perf) {
+ perf = RISCV_HWPROBE_MISALIGNED_UNKNOWN;
+ break;
+ }
+ }
+
+ if (perf == -1ULL)
+ return RISCV_HWPROBE_MISALIGNED_UNKNOWN;
+
+ return perf;
+}
+
+static void hwprobe_one_pair(struct riscv_hwprobe *pair,
+ const struct cpumask *cpus)
+{
+ switch (pair->key) {
+ case RISCV_HWPROBE_KEY_MVENDORID:
+ case RISCV_HWPROBE_KEY_MARCHID:
+ case RISCV_HWPROBE_KEY_MIMPID:
+ hwprobe_arch_id(pair, cpus);
+ break;
+ /*
+ * The kernel already assumes that the base single-letter ISA
+ * extensions are supported on all harts, and only supports the
+ * IMA base, so just cheat a bit here and tell that to
+ * userspace.
+ */
+ case RISCV_HWPROBE_KEY_BASE_BEHAVIOR:
+ pair->value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA;
+ break;
+
+ case RISCV_HWPROBE_KEY_IMA_EXT_0:
+ hwprobe_isa_ext0(pair, cpus);
+ break;
+
+ case RISCV_HWPROBE_KEY_CPUPERF_0:
+ pair->value = hwprobe_misaligned(cpus);
+ break;
+
+ case RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE:
+ pair->value = 0;
+ if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOZ))
+ pair->value = riscv_cboz_block_size;
+ break;
+
+ /*
+ * For forward compatibility, unknown keys don't fail the whole
+ * call, but get their element key set to -1 and value set to 0
+ * indicating they're unrecognized.
+ */
+ default:
+ pair->key = -1;
+ pair->value = 0;
+ break;
+ }
+}
+
+static int hwprobe_get_values(struct riscv_hwprobe __user *pairs,
+ size_t pair_count, size_t cpusetsize,
+ unsigned long __user *cpus_user,
+ unsigned int flags)
+{
+ size_t out;
+ int ret;
+ cpumask_t cpus;
+
+ /* Check the reserved flags. */
+ if (flags != 0)
+ return -EINVAL;
+
+ /*
+ * The interface supports taking in a CPU mask, and returns values that
+ * are consistent across that mask. Allow userspace to specify NULL and
+ * 0 as a shortcut to all online CPUs.
+ */
+ cpumask_clear(&cpus);
+ if (!cpusetsize && !cpus_user) {
+ cpumask_copy(&cpus, cpu_online_mask);
+ } else {
+ if (cpusetsize > cpumask_size())
+ cpusetsize = cpumask_size();
+
+ ret = copy_from_user(&cpus, cpus_user, cpusetsize);
+ if (ret)
+ return -EFAULT;
+
+ /*
+ * Userspace must provide at least one online CPU, without that
+ * there's no way to define what is supported.
+ */
+ cpumask_and(&cpus, &cpus, cpu_online_mask);
+ if (cpumask_empty(&cpus))
+ return -EINVAL;
+ }
+
+ for (out = 0; out < pair_count; out++, pairs++) {
+ struct riscv_hwprobe pair;
+
+ if (get_user(pair.key, &pairs->key))
+ return -EFAULT;
+
+ pair.value = 0;
+ hwprobe_one_pair(&pair, &cpus);
+ ret = put_user(pair.key, &pairs->key);
+ if (ret == 0)
+ ret = put_user(pair.value, &pairs->value);
+
+ if (ret)
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int hwprobe_get_cpus(struct riscv_hwprobe __user *pairs,
+ size_t pair_count, size_t cpusetsize,
+ unsigned long __user *cpus_user,
+ unsigned int flags)
+{
+ cpumask_t cpus, one_cpu;
+ bool clear_all = false;
+ size_t i;
+ int ret;
+
+ if (flags != RISCV_HWPROBE_WHICH_CPUS)
+ return -EINVAL;
+
+ if (!cpusetsize || !cpus_user)
+ return -EINVAL;
+
+ if (cpusetsize > cpumask_size())
+ cpusetsize = cpumask_size();
+
+ ret = copy_from_user(&cpus, cpus_user, cpusetsize);
+ if (ret)
+ return -EFAULT;
+
+ if (cpumask_empty(&cpus))
+ cpumask_copy(&cpus, cpu_online_mask);
+
+ cpumask_and(&cpus, &cpus, cpu_online_mask);
+
+ cpumask_clear(&one_cpu);
+
+ for (i = 0; i < pair_count; i++) {
+ struct riscv_hwprobe pair, tmp;
+ int cpu;
+
+ ret = copy_from_user(&pair, &pairs[i], sizeof(pair));
+ if (ret)
+ return -EFAULT;
+
+ if (!riscv_hwprobe_key_is_valid(pair.key)) {
+ clear_all = true;
+ pair = (struct riscv_hwprobe){ .key = -1, };
+ ret = copy_to_user(&pairs[i], &pair, sizeof(pair));
+ if (ret)
+ return -EFAULT;
+ }
+
+ if (clear_all)
+ continue;
+
+ tmp = (struct riscv_hwprobe){ .key = pair.key, };
+
+ for_each_cpu(cpu, &cpus) {
+ cpumask_set_cpu(cpu, &one_cpu);
+
+ hwprobe_one_pair(&tmp, &one_cpu);
+
+ if (!riscv_hwprobe_pair_cmp(&tmp, &pair))
+ cpumask_clear_cpu(cpu, &cpus);
+
+ cpumask_clear_cpu(cpu, &one_cpu);
+ }
+ }
+
+ if (clear_all)
+ cpumask_clear(&cpus);
+
+ ret = copy_to_user(cpus_user, &cpus, cpusetsize);
+ if (ret)
+ return -EFAULT;
+
+ return 0;
+}
+
+static int do_riscv_hwprobe(struct riscv_hwprobe __user *pairs,
+ size_t pair_count, size_t cpusetsize,
+ unsigned long __user *cpus_user,
+ unsigned int flags)
+{
+ if (flags & RISCV_HWPROBE_WHICH_CPUS)
+ return hwprobe_get_cpus(pairs, pair_count, cpusetsize,
+ cpus_user, flags);
+
+ return hwprobe_get_values(pairs, pair_count, cpusetsize,
+ cpus_user, flags);
+}
+
+#ifdef CONFIG_MMU
+
+static int __init init_hwprobe_vdso_data(void)
+{
+ struct vdso_data *vd = __arch_get_k_vdso_data();
+ struct arch_vdso_data *avd = &vd->arch_data;
+ u64 id_bitsmash = 0;
+ struct riscv_hwprobe pair;
+ int key;
+
+ /*
+ * Initialize vDSO data with the answers for the "all CPUs" case, to
+ * save a syscall in the common case.
+ */
+ for (key = 0; key <= RISCV_HWPROBE_MAX_KEY; key++) {
+ pair.key = key;
+ hwprobe_one_pair(&pair, cpu_online_mask);
+
+ WARN_ON_ONCE(pair.key < 0);
+
+ avd->all_cpu_hwprobe_values[key] = pair.value;
+ /*
+ * Smash together the vendor, arch, and impl IDs to see if
+ * they're all 0 or any negative.
+ */
+ if (key <= RISCV_HWPROBE_KEY_MIMPID)
+ id_bitsmash |= pair.value;
+ }
+
+ /*
+ * If the arch, vendor, and implementation ID are all the same across
+ * all harts, then assume all CPUs are the same, and allow the vDSO to
+ * answer queries for arbitrary masks. However if all values are 0 (not
+ * populated) or any value returns -1 (varies across CPUs), then the
+ * vDSO should defer to the kernel for exotic cpu masks.
+ */
+ avd->homogeneous_cpus = id_bitsmash != 0 && id_bitsmash != -1;
+ return 0;
+}
+
+arch_initcall_sync(init_hwprobe_vdso_data);
+
+#endif /* CONFIG_MMU */
+
+SYSCALL_DEFINE5(riscv_hwprobe, struct riscv_hwprobe __user *, pairs,
+ size_t, pair_count, size_t, cpusetsize, unsigned long __user *,
+ cpus, unsigned int, flags)
+{
+ return do_riscv_hwprobe(pairs, pair_count, cpusetsize,
+ cpus, flags);
+}
diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c
index a2ca5b7756a5..f1c1416a9f1e 100644
--- a/arch/riscv/kernel/sys_riscv.c
+++ b/arch/riscv/kernel/sys_riscv.c
@@ -7,15 +7,7 @@
#include <linux/syscalls.h>
#include <asm/cacheflush.h>
-#include <asm/cpufeature.h>
-#include <asm/hwprobe.h>
-#include <asm/sbi.h>
-#include <asm/vector.h>
-#include <asm/switch_to.h>
-#include <asm/uaccess.h>
-#include <asm/unistd.h>
#include <asm-generic/mman-common.h>
-#include <vdso/vsyscall.h>
static long riscv_sys_mmap(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
@@ -77,283 +69,6 @@ SYSCALL_DEFINE3(riscv_flush_icache, uintptr_t, start, uintptr_t, end,
return 0;
}
-/*
- * The hwprobe interface, for allowing userspace to probe to see which features
- * are supported by the hardware. See Documentation/arch/riscv/hwprobe.rst for more
- * details.
- */
-static void hwprobe_arch_id(struct riscv_hwprobe *pair,
- const struct cpumask *cpus)
-{
- u64 id = -1ULL;
- bool first = true;
- int cpu;
-
- for_each_cpu(cpu, cpus) {
- u64 cpu_id;
-
- switch (pair->key) {
- case RISCV_HWPROBE_KEY_MVENDORID:
- cpu_id = riscv_cached_mvendorid(cpu);
- break;
- case RISCV_HWPROBE_KEY_MIMPID:
- cpu_id = riscv_cached_mimpid(cpu);
- break;
- case RISCV_HWPROBE_KEY_MARCHID:
- cpu_id = riscv_cached_marchid(cpu);
- break;
- }
-
- if (first) {
- id = cpu_id;
- first = false;
- }
-
- /*
- * If there's a mismatch for the given set, return -1 in the
- * value.
- */
- if (id != cpu_id) {
- id = -1ULL;
- break;
- }
- }
-
- pair->value = id;
-}
-
-static void hwprobe_isa_ext0(struct riscv_hwprobe *pair,
- const struct cpumask *cpus)
-{
- int cpu;
- u64 missing = 0;
-
- pair->value = 0;
- if (has_fpu())
- pair->value |= RISCV_HWPROBE_IMA_FD;
-
- if (riscv_isa_extension_available(NULL, c))
- pair->value |= RISCV_HWPROBE_IMA_C;
-
- if (has_vector())
- pair->value |= RISCV_HWPROBE_IMA_V;
-
- /*
- * Loop through and record extensions that 1) anyone has, and 2) anyone
- * doesn't have.
- */
- for_each_cpu(cpu, cpus) {
- struct riscv_isainfo *isainfo = &hart_isa[cpu];
-
-#define EXT_KEY(ext) \
- do { \
- if (__riscv_isa_extension_available(isainfo->isa, RISCV_ISA_EXT_##ext)) \
- pair->value |= RISCV_HWPROBE_EXT_##ext; \
- else \
- missing |= RISCV_HWPROBE_EXT_##ext; \
- } while (false)
-
- /*
- * Only use EXT_KEY() for extensions which can be exposed to userspace,
- * regardless of the kernel's configuration, as no other checks, besides
- * presence in the hart_isa bitmap, are made.
- */
- EXT_KEY(ZBA);
- EXT_KEY(ZBB);
- EXT_KEY(ZBS);
- EXT_KEY(ZICBOZ);
-#undef EXT_KEY
- }
-
- /* Now turn off reporting features if any CPU is missing it. */
- pair->value &= ~missing;
-}
-
-static bool hwprobe_ext0_has(const struct cpumask *cpus, u64 ext)
-{
- struct riscv_hwprobe pair;
-
- hwprobe_isa_ext0(&pair, cpus);
- return (pair.value & ext);
-}
-
-static u64 hwprobe_misaligned(const struct cpumask *cpus)
-{
- int cpu;
- u64 perf = -1ULL;
-
- for_each_cpu(cpu, cpus) {
- int this_perf = per_cpu(misaligned_access_speed, cpu);
-
- if (perf == -1ULL)
- perf = this_perf;
-
- if (perf != this_perf) {
- perf = RISCV_HWPROBE_MISALIGNED_UNKNOWN;
- break;
- }
- }
-
- if (perf == -1ULL)
- return RISCV_HWPROBE_MISALIGNED_UNKNOWN;
-
- return perf;
-}
-
-static void hwprobe_one_pair(struct riscv_hwprobe *pair,
- const struct cpumask *cpus)
-{
- switch (pair->key) {
- case RISCV_HWPROBE_KEY_MVENDORID:
- case RISCV_HWPROBE_KEY_MARCHID:
- case RISCV_HWPROBE_KEY_MIMPID:
- hwprobe_arch_id(pair, cpus);
- break;
- /*
- * The kernel already assumes that the base single-letter ISA
- * extensions are supported on all harts, and only supports the
- * IMA base, so just cheat a bit here and tell that to
- * userspace.
- */
- case RISCV_HWPROBE_KEY_BASE_BEHAVIOR:
- pair->value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA;
- break;
-
- case RISCV_HWPROBE_KEY_IMA_EXT_0:
- hwprobe_isa_ext0(pair, cpus);
- break;
-
- case RISCV_HWPROBE_KEY_CPUPERF_0:
- pair->value = hwprobe_misaligned(cpus);
- break;
-
- case RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE:
- pair->value = 0;
- if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOZ))
- pair->value = riscv_cboz_block_size;
- break;
-
- /*
- * For forward compatibility, unknown keys don't fail the whole
- * call, but get their element key set to -1 and value set to 0
- * indicating they're unrecognized.
- */
- default:
- pair->key = -1;
- pair->value = 0;
- break;
- }
-}
-
-static int do_riscv_hwprobe(struct riscv_hwprobe __user *pairs,
- size_t pair_count, size_t cpu_count,
- unsigned long __user *cpus_user,
- unsigned int flags)
-{
- size_t out;
- int ret;
- cpumask_t cpus;
-
- /* Check the reserved flags. */
- if (flags != 0)
- return -EINVAL;
-
- /*
- * The interface supports taking in a CPU mask, and returns values that
- * are consistent across that mask. Allow userspace to specify NULL and
- * 0 as a shortcut to all online CPUs.
- */
- cpumask_clear(&cpus);
- if (!cpu_count && !cpus_user) {
- cpumask_copy(&cpus, cpu_online_mask);
- } else {
- if (cpu_count > cpumask_size())
- cpu_count = cpumask_size();
-
- ret = copy_from_user(&cpus, cpus_user, cpu_count);
- if (ret)
- return -EFAULT;
-
- /*
- * Userspace must provide at least one online CPU, without that
- * there's no way to define what is supported.
- */
- cpumask_and(&cpus, &cpus, cpu_online_mask);
- if (cpumask_empty(&cpus))
- return -EINVAL;
- }
-
- for (out = 0; out < pair_count; out++, pairs++) {
- struct riscv_hwprobe pair;
-
- if (get_user(pair.key, &pairs->key))
- return -EFAULT;
-
- pair.value = 0;
- hwprobe_one_pair(&pair, &cpus);
- ret = put_user(pair.key, &pairs->key);
- if (ret == 0)
- ret = put_user(pair.value, &pairs->value);
-
- if (ret)
- return -EFAULT;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_MMU
-
-static int __init init_hwprobe_vdso_data(void)
-{
- struct vdso_data *vd = __arch_get_k_vdso_data();
- struct arch_vdso_data *avd = &vd->arch_data;
- u64 id_bitsmash = 0;
- struct riscv_hwprobe pair;
- int key;
-
- /*
- * Initialize vDSO data with the answers for the "all CPUs" case, to
- * save a syscall in the common case.
- */
- for (key = 0; key <= RISCV_HWPROBE_MAX_KEY; key++) {
- pair.key = key;
- hwprobe_one_pair(&pair, cpu_online_mask);
-
- WARN_ON_ONCE(pair.key < 0);
-
- avd->all_cpu_hwprobe_values[key] = pair.value;
- /*
- * Smash together the vendor, arch, and impl IDs to see if
- * they're all 0 or any negative.
- */
- if (key <= RISCV_HWPROBE_KEY_MIMPID)
- id_bitsmash |= pair.value;
- }
-
- /*
- * If the arch, vendor, and implementation ID are all the same across
- * all harts, then assume all CPUs are the same, and allow the vDSO to
- * answer queries for arbitrary masks. However if all values are 0 (not
- * populated) or any value returns -1 (varies across CPUs), then the
- * vDSO should defer to the kernel for exotic cpu masks.
- */
- avd->homogeneous_cpus = id_bitsmash != 0 && id_bitsmash != -1;
- return 0;
-}
-
-arch_initcall_sync(init_hwprobe_vdso_data);
-
-#endif /* CONFIG_MMU */
-
-SYSCALL_DEFINE5(riscv_hwprobe, struct riscv_hwprobe __user *, pairs,
- size_t, pair_count, size_t, cpu_count, unsigned long __user *,
- cpus, unsigned int, flags)
-{
- return do_riscv_hwprobe(pairs, pair_count, cpu_count,
- cpus, flags);
-}
-
/* Not defined using SYSCALL_DEFINE0 to avoid error injection */
asmlinkage long __riscv_sys_ni_syscall(const struct pt_regs *__unused)
{
diff --git a/arch/riscv/kernel/time.c b/arch/riscv/kernel/time.c
index 23641e82a9df..ba3477197789 100644
--- a/arch/riscv/kernel/time.c
+++ b/arch/riscv/kernel/time.c
@@ -12,6 +12,7 @@
#include <asm/sbi.h>
#include <asm/processor.h>
#include <asm/timex.h>
+#include <asm/paravirt.h>
unsigned long riscv_timebase __ro_after_init;
EXPORT_SYMBOL_GPL(riscv_timebase);
@@ -45,4 +46,6 @@ void __init time_init(void)
timer_probe();
tick_setup_hrtimer_broadcast();
+
+ pv_time_init();
}
diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
index 5255f8134aef..8ded225e8c5b 100644
--- a/arch/riscv/kernel/traps_misaligned.c
+++ b/arch/riscv/kernel/traps_misaligned.c
@@ -319,7 +319,7 @@ static inline int get_insn(struct pt_regs *regs, ulong mepc, ulong *r_insn)
static inline int load_u8(struct pt_regs *regs, const u8 *addr, u8 *r_val)
{
if (user_mode(regs)) {
- return __get_user(*r_val, addr);
+ return __get_user(*r_val, (u8 __user *)addr);
} else {
*r_val = *addr;
return 0;
@@ -329,7 +329,7 @@ static inline int load_u8(struct pt_regs *regs, const u8 *addr, u8 *r_val)
static inline int store_u8(struct pt_regs *regs, u8 *addr, u8 val)
{
if (user_mode(regs)) {
- return __put_user(val, addr);
+ return __put_user(val, (u8 __user *)addr);
} else {
*addr = val;
return 0;
@@ -343,7 +343,7 @@ static inline int store_u8(struct pt_regs *regs, u8 *addr, u8 val)
if (user_mode(regs)) { \
__ret = __get_user(insn, insn_addr); \
} else { \
- insn = *insn_addr; \
+ insn = *(__force u16 *)insn_addr; \
__ret = 0; \
} \
\
diff --git a/arch/riscv/kernel/vdso/hwprobe.c b/arch/riscv/kernel/vdso/hwprobe.c
index cadf725ef798..1e926e4b5881 100644
--- a/arch/riscv/kernel/vdso/hwprobe.c
+++ b/arch/riscv/kernel/vdso/hwprobe.c
@@ -3,26 +3,22 @@
* Copyright 2023 Rivos, Inc
*/
+#include <linux/string.h>
#include <linux/types.h>
#include <vdso/datapage.h>
#include <vdso/helpers.h>
extern int riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
- size_t cpu_count, unsigned long *cpus,
+ size_t cpusetsize, unsigned long *cpus,
unsigned int flags);
-/* Add a prototype to avoid -Wmissing-prototypes warning. */
-int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
- size_t cpu_count, unsigned long *cpus,
- unsigned int flags);
-
-int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
- size_t cpu_count, unsigned long *cpus,
- unsigned int flags)
+static int riscv_vdso_get_values(struct riscv_hwprobe *pairs, size_t pair_count,
+ size_t cpusetsize, unsigned long *cpus,
+ unsigned int flags)
{
const struct vdso_data *vd = __arch_get_vdso_data();
const struct arch_vdso_data *avd = &vd->arch_data;
- bool all_cpus = !cpu_count && !cpus;
+ bool all_cpus = !cpusetsize && !cpus;
struct riscv_hwprobe *p = pairs;
struct riscv_hwprobe *end = pairs + pair_count;
@@ -33,7 +29,7 @@ int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
* masks.
*/
if ((flags != 0) || (!all_cpus && !avd->homogeneous_cpus))
- return riscv_hwprobe(pairs, pair_count, cpu_count, cpus, flags);
+ return riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags);
/* This is something we can handle, fill out the pairs. */
while (p < end) {
@@ -50,3 +46,71 @@ int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
return 0;
}
+
+static int riscv_vdso_get_cpus(struct riscv_hwprobe *pairs, size_t pair_count,
+ size_t cpusetsize, unsigned long *cpus,
+ unsigned int flags)
+{
+ const struct vdso_data *vd = __arch_get_vdso_data();
+ const struct arch_vdso_data *avd = &vd->arch_data;
+ struct riscv_hwprobe *p = pairs;
+ struct riscv_hwprobe *end = pairs + pair_count;
+ unsigned char *c = (unsigned char *)cpus;
+ bool empty_cpus = true;
+ bool clear_all = false;
+ int i;
+
+ if (!cpusetsize || !cpus)
+ return -EINVAL;
+
+ for (i = 0; i < cpusetsize; i++) {
+ if (c[i]) {
+ empty_cpus = false;
+ break;
+ }
+ }
+
+ if (empty_cpus || flags != RISCV_HWPROBE_WHICH_CPUS || !avd->homogeneous_cpus)
+ return riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags);
+
+ while (p < end) {
+ if (riscv_hwprobe_key_is_valid(p->key)) {
+ struct riscv_hwprobe t = {
+ .key = p->key,
+ .value = avd->all_cpu_hwprobe_values[p->key],
+ };
+
+ if (!riscv_hwprobe_pair_cmp(&t, p))
+ clear_all = true;
+ } else {
+ clear_all = true;
+ p->key = -1;
+ p->value = 0;
+ }
+ p++;
+ }
+
+ if (clear_all) {
+ for (i = 0; i < cpusetsize; i++)
+ c[i] = 0;
+ }
+
+ return 0;
+}
+
+/* Add a prototype to avoid -Wmissing-prototypes warning. */
+int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
+ size_t cpusetsize, unsigned long *cpus,
+ unsigned int flags);
+
+int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
+ size_t cpusetsize, unsigned long *cpus,
+ unsigned int flags)
+{
+ if (flags & RISCV_HWPROBE_WHICH_CPUS)
+ return riscv_vdso_get_cpus(pairs, pair_count, cpusetsize,
+ cpus, flags);
+
+ return riscv_vdso_get_values(pairs, pair_count, cpusetsize,
+ cpus, flags);
+}
diff --git a/arch/riscv/kernel/vmlinux-xip.lds.S b/arch/riscv/kernel/vmlinux-xip.lds.S
index 50767647fbc6..8c3daa1b0531 100644
--- a/arch/riscv/kernel/vmlinux-xip.lds.S
+++ b/arch/riscv/kernel/vmlinux-xip.lds.S
@@ -29,10 +29,12 @@ SECTIONS
HEAD_TEXT_SECTION
INIT_TEXT_SECTION(PAGE_SIZE)
/* we have to discard exit text and such at runtime, not link time */
+ __exittext_begin = .;
.exit.text :
{
EXIT_TEXT
}
+ __exittext_end = .;
.text : {
_text = .;
diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S
index 492dd4b8f3d6..002ca58dd998 100644
--- a/arch/riscv/kernel/vmlinux.lds.S
+++ b/arch/riscv/kernel/vmlinux.lds.S
@@ -69,10 +69,12 @@ SECTIONS
__soc_builtin_dtb_table_end = .;
}
/* we have to discard exit text and such at runtime, not link time */
+ __exittext_begin = .;
.exit.text :
{
EXIT_TEXT
}
+ __exittext_end = .;
__init_text_end = .;
. = ALIGN(SECTION_ALIGN);
diff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig
index dfc237d7875b..d490db943858 100644
--- a/arch/riscv/kvm/Kconfig
+++ b/arch/riscv/kvm/Kconfig
@@ -20,18 +20,17 @@ if VIRTUALIZATION
config KVM
tristate "Kernel-based Virtual Machine (KVM) support (EXPERIMENTAL)"
depends on RISCV_SBI && MMU
- select HAVE_KVM_EVENTFD
select HAVE_KVM_IRQCHIP
- select HAVE_KVM_IRQFD
select HAVE_KVM_IRQ_ROUTING
select HAVE_KVM_MSI
select HAVE_KVM_VCPU_ASYNC_IOCTL
+ select KVM_COMMON
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
select KVM_GENERIC_HARDWARE_ENABLING
select KVM_MMIO
select KVM_XFER_TO_GUEST_WORK
- select MMU_NOTIFIER
- select PREEMPT_NOTIFIERS
+ select KVM_GENERIC_MMU_NOTIFIER
+ select SCHED_INFO
help
Support hosting virtualized guest machines.
diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile
index 4c2067fc59fc..c9646521f113 100644
--- a/arch/riscv/kvm/Makefile
+++ b/arch/riscv/kvm/Makefile
@@ -26,6 +26,7 @@ kvm-$(CONFIG_RISCV_SBI_V01) += vcpu_sbi_v01.o
kvm-y += vcpu_sbi_base.o
kvm-y += vcpu_sbi_replace.o
kvm-y += vcpu_sbi_hsm.o
+kvm-y += vcpu_sbi_sta.o
kvm-y += vcpu_timer.o
kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o vcpu_sbi_pmu.o
kvm-y += aia.o
diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index 068c74593871..a9e2fd7245e1 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -103,7 +103,7 @@ static bool gstage_get_leaf_entry(struct kvm *kvm, gpa_t addr,
*ptep_level = current_level;
ptep = (pte_t *)kvm->arch.pgd;
ptep = &ptep[gstage_pte_index(addr, current_level)];
- while (ptep && pte_val(*ptep)) {
+ while (ptep && pte_val(ptep_get(ptep))) {
if (gstage_pte_leaf(ptep)) {
*ptep_level = current_level;
*ptepp = ptep;
@@ -113,7 +113,7 @@ static bool gstage_get_leaf_entry(struct kvm *kvm, gpa_t addr,
if (current_level) {
current_level--;
*ptep_level = current_level;
- ptep = (pte_t *)gstage_pte_page_vaddr(*ptep);
+ ptep = (pte_t *)gstage_pte_page_vaddr(ptep_get(ptep));
ptep = &ptep[gstage_pte_index(addr, current_level)];
} else {
ptep = NULL;
@@ -149,25 +149,25 @@ static int gstage_set_pte(struct kvm *kvm, u32 level,
if (gstage_pte_leaf(ptep))
return -EEXIST;
- if (!pte_val(*ptep)) {
+ if (!pte_val(ptep_get(ptep))) {
if (!pcache)
return -ENOMEM;
next_ptep = kvm_mmu_memory_cache_alloc(pcache);
if (!next_ptep)
return -ENOMEM;
- *ptep = pfn_pte(PFN_DOWN(__pa(next_ptep)),
- __pgprot(_PAGE_TABLE));
+ set_pte(ptep, pfn_pte(PFN_DOWN(__pa(next_ptep)),
+ __pgprot(_PAGE_TABLE)));
} else {
if (gstage_pte_leaf(ptep))
return -EEXIST;
- next_ptep = (pte_t *)gstage_pte_page_vaddr(*ptep);
+ next_ptep = (pte_t *)gstage_pte_page_vaddr(ptep_get(ptep));
}
current_level--;
ptep = &next_ptep[gstage_pte_index(addr, current_level)];
}
- *ptep = *new_pte;
+ set_pte(ptep, *new_pte);
if (gstage_pte_leaf(ptep))
gstage_remote_tlb_flush(kvm, current_level, addr);
@@ -239,11 +239,11 @@ static void gstage_op_pte(struct kvm *kvm, gpa_t addr,
BUG_ON(addr & (page_size - 1));
- if (!pte_val(*ptep))
+ if (!pte_val(ptep_get(ptep)))
return;
if (ptep_level && !gstage_pte_leaf(ptep)) {
- next_ptep = (pte_t *)gstage_pte_page_vaddr(*ptep);
+ next_ptep = (pte_t *)gstage_pte_page_vaddr(ptep_get(ptep));
next_ptep_level = ptep_level - 1;
ret = gstage_level_to_page_size(next_ptep_level,
&next_page_size);
@@ -261,7 +261,7 @@ static void gstage_op_pte(struct kvm *kvm, gpa_t addr,
if (op == GSTAGE_OP_CLEAR)
set_pte(ptep, __pte(0));
else if (op == GSTAGE_OP_WP)
- set_pte(ptep, __pte(pte_val(*ptep) & ~_PAGE_WRITE));
+ set_pte(ptep, __pte(pte_val(ptep_get(ptep)) & ~_PAGE_WRITE));
gstage_remote_tlb_flush(kvm, ptep_level, addr);
}
}
@@ -603,7 +603,7 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
&ptep, &ptep_level))
return false;
- return pte_young(*ptep);
+ return pte_young(ptep_get(ptep));
}
int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu,
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index e087c809073c..b5ca9f2e98ac 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -83,6 +83,8 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu)
vcpu->arch.hfence_tail = 0;
memset(vcpu->arch.hfence_queue, 0, sizeof(vcpu->arch.hfence_queue));
+ kvm_riscv_vcpu_sbi_sta_reset(vcpu);
+
/* Reset the guest CSRs for hotplug usecase */
if (loaded)
kvm_arch_vcpu_load(vcpu, smp_processor_id());
@@ -541,6 +543,8 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_riscv_vcpu_aia_load(vcpu, cpu);
+ kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
+
vcpu->cpu = cpu;
}
@@ -614,6 +618,9 @@ static void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu)
if (kvm_check_request(KVM_REQ_HFENCE, vcpu))
kvm_riscv_hfence_process(vcpu);
+
+ if (kvm_check_request(KVM_REQ_STEAL_UPDATE, vcpu))
+ kvm_riscv_vcpu_record_steal_time(vcpu);
}
}
@@ -757,8 +764,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
/* Update HVIP CSR for current CPU */
kvm_riscv_update_hvip(vcpu);
- if (ret <= 0 ||
- kvm_riscv_gstage_vmid_ver_changed(&vcpu->kvm->arch.vmid) ||
+ if (kvm_riscv_gstage_vmid_ver_changed(&vcpu->kvm->arch.vmid) ||
kvm_request_pending(vcpu) ||
xfer_to_guest_mode_work_pending()) {
vcpu->mode = OUTSIDE_GUEST_MODE;
diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
index f8c9fa0c03c5..fc34557f5356 100644
--- a/arch/riscv/kvm/vcpu_onereg.c
+++ b/arch/riscv/kvm/vcpu_onereg.c
@@ -485,7 +485,7 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
rc = kvm_riscv_vcpu_smstateen_set_csr(vcpu, reg_num,
reg_val);
-break;
+ break;
default:
rc = -ENOENT;
break;
@@ -931,50 +931,106 @@ static inline unsigned long num_isa_ext_regs(const struct kvm_vcpu *vcpu)
return copy_isa_ext_reg_indices(vcpu, NULL);;
}
-static inline unsigned long num_sbi_ext_regs(void)
+static int copy_sbi_ext_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
{
- /*
- * number of KVM_REG_RISCV_SBI_SINGLE +
- * 2 x (number of KVM_REG_RISCV_SBI_MULTI)
- */
- return KVM_RISCV_SBI_EXT_MAX + 2*(KVM_REG_RISCV_SBI_MULTI_REG_LAST+1);
-}
-
-static int copy_sbi_ext_reg_indices(u64 __user *uindices)
-{
- int n;
+ unsigned int n = 0;
- /* copy KVM_REG_RISCV_SBI_SINGLE */
- n = KVM_RISCV_SBI_EXT_MAX;
- for (int i = 0; i < n; i++) {
+ for (int i = 0; i < KVM_RISCV_SBI_EXT_MAX; i++) {
u64 size = IS_ENABLED(CONFIG_32BIT) ?
KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT |
KVM_REG_RISCV_SBI_SINGLE | i;
+ if (!riscv_vcpu_supports_sbi_ext(vcpu, i))
+ continue;
+
if (uindices) {
if (put_user(reg, uindices))
return -EFAULT;
uindices++;
}
+
+ n++;
}
- /* copy KVM_REG_RISCV_SBI_MULTI */
- n = KVM_REG_RISCV_SBI_MULTI_REG_LAST + 1;
- for (int i = 0; i < n; i++) {
- u64 size = IS_ENABLED(CONFIG_32BIT) ?
- KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
- u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT |
- KVM_REG_RISCV_SBI_MULTI_EN | i;
+ return n;
+}
+
+static unsigned long num_sbi_ext_regs(struct kvm_vcpu *vcpu)
+{
+ return copy_sbi_ext_reg_indices(vcpu, NULL);
+}
+
+static int copy_sbi_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+ struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
+ int total = 0;
+
+ if (scontext->ext_status[KVM_RISCV_SBI_EXT_STA] == KVM_RISCV_SBI_EXT_STATUS_ENABLED) {
+ u64 size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
+ int n = sizeof(struct kvm_riscv_sbi_sta) / sizeof(unsigned long);
+
+ for (int i = 0; i < n; i++) {
+ u64 reg = KVM_REG_RISCV | size |
+ KVM_REG_RISCV_SBI_STATE |
+ KVM_REG_RISCV_SBI_STA | i;
+
+ if (uindices) {
+ if (put_user(reg, uindices))
+ return -EFAULT;
+ uindices++;
+ }
+ }
+
+ total += n;
+ }
+
+ return total;
+}
+
+static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu)
+{
+ return copy_sbi_reg_indices(vcpu, NULL);
+}
+
+static inline unsigned long num_vector_regs(const struct kvm_vcpu *vcpu)
+{
+ if (!riscv_isa_extension_available(vcpu->arch.isa, v))
+ return 0;
+
+ /* vstart, vl, vtype, vcsr, vlenb and 32 vector regs */
+ return 37;
+}
+
+static int copy_vector_reg_indices(const struct kvm_vcpu *vcpu,
+ u64 __user *uindices)
+{
+ const struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
+ int n = num_vector_regs(vcpu);
+ u64 reg, size;
+ int i;
+
+ if (n == 0)
+ return 0;
+
+ /* copy vstart, vl, vtype, vcsr and vlenb */
+ size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
+ for (i = 0; i < 5; i++) {
+ reg = KVM_REG_RISCV | size | KVM_REG_RISCV_VECTOR | i;
if (uindices) {
if (put_user(reg, uindices))
return -EFAULT;
uindices++;
}
+ }
- reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT |
- KVM_REG_RISCV_SBI_MULTI_DIS | i;
+ /* vector_regs have a variable 'vlenb' size */
+ size = __builtin_ctzl(cntx->vector.vlenb);
+ size <<= KVM_REG_SIZE_SHIFT;
+ for (i = 0; i < 32; i++) {
+ reg = KVM_REG_RISCV | KVM_REG_RISCV_VECTOR | size |
+ KVM_REG_RISCV_VECTOR_REG(i);
if (uindices) {
if (put_user(reg, uindices))
@@ -983,7 +1039,7 @@ static int copy_sbi_ext_reg_indices(u64 __user *uindices)
}
}
- return num_sbi_ext_regs();
+ return n;
}
/*
@@ -1001,8 +1057,10 @@ unsigned long kvm_riscv_vcpu_num_regs(struct kvm_vcpu *vcpu)
res += num_timer_regs();
res += num_fp_f_regs(vcpu);
res += num_fp_d_regs(vcpu);
+ res += num_vector_regs(vcpu);
res += num_isa_ext_regs(vcpu);
- res += num_sbi_ext_regs();
+ res += num_sbi_ext_regs(vcpu);
+ res += num_sbi_regs(vcpu);
return res;
}
@@ -1045,14 +1103,25 @@ int kvm_riscv_vcpu_copy_reg_indices(struct kvm_vcpu *vcpu,
return ret;
uindices += ret;
+ ret = copy_vector_reg_indices(vcpu, uindices);
+ if (ret < 0)
+ return ret;
+ uindices += ret;
+
ret = copy_isa_ext_reg_indices(vcpu, uindices);
if (ret < 0)
return ret;
uindices += ret;
- ret = copy_sbi_ext_reg_indices(uindices);
+ ret = copy_sbi_ext_reg_indices(vcpu, uindices);
if (ret < 0)
return ret;
+ uindices += ret;
+
+ ret = copy_sbi_reg_indices(vcpu, uindices);
+ if (ret < 0)
+ return ret;
+ uindices += ret;
return 0;
}
@@ -1075,12 +1144,14 @@ int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu,
case KVM_REG_RISCV_FP_D:
return kvm_riscv_vcpu_set_reg_fp(vcpu, reg,
KVM_REG_RISCV_FP_D);
+ case KVM_REG_RISCV_VECTOR:
+ return kvm_riscv_vcpu_set_reg_vector(vcpu, reg);
case KVM_REG_RISCV_ISA_EXT:
return kvm_riscv_vcpu_set_reg_isa_ext(vcpu, reg);
case KVM_REG_RISCV_SBI_EXT:
return kvm_riscv_vcpu_set_reg_sbi_ext(vcpu, reg);
- case KVM_REG_RISCV_VECTOR:
- return kvm_riscv_vcpu_set_reg_vector(vcpu, reg);
+ case KVM_REG_RISCV_SBI_STATE:
+ return kvm_riscv_vcpu_set_reg_sbi(vcpu, reg);
default:
break;
}
@@ -1106,12 +1177,14 @@ int kvm_riscv_vcpu_get_reg(struct kvm_vcpu *vcpu,
case KVM_REG_RISCV_FP_D:
return kvm_riscv_vcpu_get_reg_fp(vcpu, reg,
KVM_REG_RISCV_FP_D);
+ case KVM_REG_RISCV_VECTOR:
+ return kvm_riscv_vcpu_get_reg_vector(vcpu, reg);
case KVM_REG_RISCV_ISA_EXT:
return kvm_riscv_vcpu_get_reg_isa_ext(vcpu, reg);
case KVM_REG_RISCV_SBI_EXT:
return kvm_riscv_vcpu_get_reg_sbi_ext(vcpu, reg);
- case KVM_REG_RISCV_VECTOR:
- return kvm_riscv_vcpu_get_reg_vector(vcpu, reg);
+ case KVM_REG_RISCV_SBI_STATE:
+ return kvm_riscv_vcpu_get_reg_sbi(vcpu, reg);
default:
break;
}
diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c
index a04ff98085d9..72a2ffb8dcd1 100644
--- a/arch/riscv/kvm/vcpu_sbi.c
+++ b/arch/riscv/kvm/vcpu_sbi.c
@@ -71,6 +71,10 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = {
.ext_ptr = &vcpu_sbi_ext_dbcn,
},
{
+ .ext_idx = KVM_RISCV_SBI_EXT_STA,
+ .ext_ptr = &vcpu_sbi_ext_sta,
+ },
+ {
.ext_idx = KVM_RISCV_SBI_EXT_EXPERIMENTAL,
.ext_ptr = &vcpu_sbi_ext_experimental,
},
@@ -80,6 +84,34 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = {
},
};
+static const struct kvm_riscv_sbi_extension_entry *
+riscv_vcpu_get_sbi_ext(struct kvm_vcpu *vcpu, unsigned long idx)
+{
+ const struct kvm_riscv_sbi_extension_entry *sext = NULL;
+
+ if (idx >= KVM_RISCV_SBI_EXT_MAX)
+ return NULL;
+
+ for (int i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
+ if (sbi_ext[i].ext_idx == idx) {
+ sext = &sbi_ext[i];
+ break;
+ }
+ }
+
+ return sext;
+}
+
+bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx)
+{
+ struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
+ const struct kvm_riscv_sbi_extension_entry *sext;
+
+ sext = riscv_vcpu_get_sbi_ext(vcpu, idx);
+
+ return sext && scontext->ext_status[sext->ext_idx] != KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE;
+}
+
void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
@@ -140,28 +172,19 @@ static int riscv_vcpu_set_sbi_ext_single(struct kvm_vcpu *vcpu,
unsigned long reg_num,
unsigned long reg_val)
{
- unsigned long i;
- const struct kvm_riscv_sbi_extension_entry *sext = NULL;
struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
-
- if (reg_num >= KVM_RISCV_SBI_EXT_MAX)
- return -ENOENT;
+ const struct kvm_riscv_sbi_extension_entry *sext;
if (reg_val != 1 && reg_val != 0)
return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
- if (sbi_ext[i].ext_idx == reg_num) {
- sext = &sbi_ext[i];
- break;
- }
- }
- if (!sext)
+ sext = riscv_vcpu_get_sbi_ext(vcpu, reg_num);
+ if (!sext || scontext->ext_status[sext->ext_idx] == KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE)
return -ENOENT;
scontext->ext_status[sext->ext_idx] = (reg_val) ?
- KVM_RISCV_SBI_EXT_AVAILABLE :
- KVM_RISCV_SBI_EXT_UNAVAILABLE;
+ KVM_RISCV_SBI_EXT_STATUS_ENABLED :
+ KVM_RISCV_SBI_EXT_STATUS_DISABLED;
return 0;
}
@@ -170,24 +193,16 @@ static int riscv_vcpu_get_sbi_ext_single(struct kvm_vcpu *vcpu,
unsigned long reg_num,
unsigned long *reg_val)
{
- unsigned long i;
- const struct kvm_riscv_sbi_extension_entry *sext = NULL;
struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
+ const struct kvm_riscv_sbi_extension_entry *sext;
- if (reg_num >= KVM_RISCV_SBI_EXT_MAX)
- return -ENOENT;
-
- for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
- if (sbi_ext[i].ext_idx == reg_num) {
- sext = &sbi_ext[i];
- break;
- }
- }
- if (!sext)
+ sext = riscv_vcpu_get_sbi_ext(vcpu, reg_num);
+ if (!sext || scontext->ext_status[sext->ext_idx] == KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE)
return -ENOENT;
*reg_val = scontext->ext_status[sext->ext_idx] ==
- KVM_RISCV_SBI_EXT_AVAILABLE;
+ KVM_RISCV_SBI_EXT_STATUS_ENABLED;
+
return 0;
}
@@ -310,6 +325,69 @@ int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu,
return 0;
}
+int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu,
+ const struct kvm_one_reg *reg)
+{
+ unsigned long __user *uaddr =
+ (unsigned long __user *)(unsigned long)reg->addr;
+ unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
+ KVM_REG_SIZE_MASK |
+ KVM_REG_RISCV_SBI_STATE);
+ unsigned long reg_subtype, reg_val;
+
+ if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long))
+ return -EINVAL;
+
+ if (copy_from_user(&reg_val, uaddr, KVM_REG_SIZE(reg->id)))
+ return -EFAULT;
+
+ reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK;
+ reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK;
+
+ switch (reg_subtype) {
+ case KVM_REG_RISCV_SBI_STA:
+ return kvm_riscv_vcpu_set_reg_sbi_sta(vcpu, reg_num, reg_val);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu,
+ const struct kvm_one_reg *reg)
+{
+ unsigned long __user *uaddr =
+ (unsigned long __user *)(unsigned long)reg->addr;
+ unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK |
+ KVM_REG_SIZE_MASK |
+ KVM_REG_RISCV_SBI_STATE);
+ unsigned long reg_subtype, reg_val;
+ int ret;
+
+ if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long))
+ return -EINVAL;
+
+ reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK;
+ reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK;
+
+ switch (reg_subtype) {
+ case KVM_REG_RISCV_SBI_STA:
+ ret = kvm_riscv_vcpu_get_reg_sbi_sta(vcpu, reg_num, &reg_val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ret)
+ return ret;
+
+ if (copy_to_user(uaddr, &reg_val, KVM_REG_SIZE(reg->id)))
+ return -EFAULT;
+
+ return 0;
+}
+
const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(
struct kvm_vcpu *vcpu, unsigned long extid)
{
@@ -325,7 +403,7 @@ const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(
if (ext->extid_start <= extid && ext->extid_end >= extid) {
if (entry->ext_idx >= KVM_RISCV_SBI_EXT_MAX ||
scontext->ext_status[entry->ext_idx] ==
- KVM_RISCV_SBI_EXT_AVAILABLE)
+ KVM_RISCV_SBI_EXT_STATUS_ENABLED)
return ext;
return NULL;
@@ -413,12 +491,12 @@ void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu)
if (ext->probe && !ext->probe(vcpu)) {
scontext->ext_status[entry->ext_idx] =
- KVM_RISCV_SBI_EXT_UNAVAILABLE;
+ KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE;
continue;
}
- scontext->ext_status[entry->ext_idx] = ext->default_unavail ?
- KVM_RISCV_SBI_EXT_UNAVAILABLE :
- KVM_RISCV_SBI_EXT_AVAILABLE;
+ scontext->ext_status[entry->ext_idx] = ext->default_disabled ?
+ KVM_RISCV_SBI_EXT_STATUS_DISABLED :
+ KVM_RISCV_SBI_EXT_STATUS_ENABLED;
}
}
diff --git a/arch/riscv/kvm/vcpu_sbi_replace.c b/arch/riscv/kvm/vcpu_sbi_replace.c
index 23b57c931b15..9c2ab3dfa93a 100644
--- a/arch/riscv/kvm/vcpu_sbi_replace.c
+++ b/arch/riscv/kvm/vcpu_sbi_replace.c
@@ -204,6 +204,6 @@ static int kvm_sbi_ext_dbcn_handler(struct kvm_vcpu *vcpu,
const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn = {
.extid_start = SBI_EXT_DBCN,
.extid_end = SBI_EXT_DBCN,
- .default_unavail = true,
+ .default_disabled = true,
.handler = kvm_sbi_ext_dbcn_handler,
};
diff --git a/arch/riscv/kvm/vcpu_sbi_sta.c b/arch/riscv/kvm/vcpu_sbi_sta.c
new file mode 100644
index 000000000000..01f09fe8c3b0
--- /dev/null
+++ b/arch/riscv/kvm/vcpu_sbi_sta.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Ventana Micro Systems Inc.
+ */
+
+#include <linux/kconfig.h>
+#include <linux/kernel.h>
+#include <linux/kvm_host.h>
+#include <linux/mm.h>
+#include <linux/sizes.h>
+
+#include <asm/bug.h>
+#include <asm/current.h>
+#include <asm/kvm_vcpu_sbi.h>
+#include <asm/page.h>
+#include <asm/sbi.h>
+#include <asm/uaccess.h>
+
+void kvm_riscv_vcpu_sbi_sta_reset(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.sta.shmem = INVALID_GPA;
+ vcpu->arch.sta.last_steal = 0;
+}
+
+void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu)
+{
+ gpa_t shmem = vcpu->arch.sta.shmem;
+ u64 last_steal = vcpu->arch.sta.last_steal;
+ u32 *sequence_ptr, sequence;
+ u64 *steal_ptr, steal;
+ unsigned long hva;
+ gfn_t gfn;
+
+ if (shmem == INVALID_GPA)
+ return;
+
+ /*
+ * shmem is 64-byte aligned (see the enforcement in
+ * kvm_sbi_sta_steal_time_set_shmem()) and the size of sbi_sta_struct
+ * is 64 bytes, so we know all its offsets are in the same page.
+ */
+ gfn = shmem >> PAGE_SHIFT;
+ hva = kvm_vcpu_gfn_to_hva(vcpu, gfn);
+
+ if (WARN_ON(kvm_is_error_hva(hva))) {
+ vcpu->arch.sta.shmem = INVALID_GPA;
+ return;
+ }
+
+ sequence_ptr = (u32 *)(hva + offset_in_page(shmem) +
+ offsetof(struct sbi_sta_struct, sequence));
+ steal_ptr = (u64 *)(hva + offset_in_page(shmem) +
+ offsetof(struct sbi_sta_struct, steal));
+
+ if (WARN_ON(get_user(sequence, sequence_ptr)))
+ return;
+
+ sequence = le32_to_cpu(sequence);
+ sequence += 1;
+
+ if (WARN_ON(put_user(cpu_to_le32(sequence), sequence_ptr)))
+ return;
+
+ if (!WARN_ON(get_user(steal, steal_ptr))) {
+ steal = le64_to_cpu(steal);
+ vcpu->arch.sta.last_steal = READ_ONCE(current->sched_info.run_delay);
+ steal += vcpu->arch.sta.last_steal - last_steal;
+ WARN_ON(put_user(cpu_to_le64(steal), steal_ptr));
+ }
+
+ sequence += 1;
+ WARN_ON(put_user(cpu_to_le32(sequence), sequence_ptr));
+
+ kvm_vcpu_mark_page_dirty(vcpu, gfn);
+}
+
+static int kvm_sbi_sta_steal_time_set_shmem(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
+ unsigned long shmem_phys_lo = cp->a0;
+ unsigned long shmem_phys_hi = cp->a1;
+ u32 flags = cp->a2;
+ struct sbi_sta_struct zero_sta = {0};
+ unsigned long hva;
+ bool writable;
+ gpa_t shmem;
+ int ret;
+
+ if (flags != 0)
+ return SBI_ERR_INVALID_PARAM;
+
+ if (shmem_phys_lo == SBI_STA_SHMEM_DISABLE &&
+ shmem_phys_hi == SBI_STA_SHMEM_DISABLE) {
+ vcpu->arch.sta.shmem = INVALID_GPA;
+ return 0;
+ }
+
+ if (shmem_phys_lo & (SZ_64 - 1))
+ return SBI_ERR_INVALID_PARAM;
+
+ shmem = shmem_phys_lo;
+
+ if (shmem_phys_hi != 0) {
+ if (IS_ENABLED(CONFIG_32BIT))
+ shmem |= ((gpa_t)shmem_phys_hi << 32);
+ else
+ return SBI_ERR_INVALID_ADDRESS;
+ }
+
+ hva = kvm_vcpu_gfn_to_hva_prot(vcpu, shmem >> PAGE_SHIFT, &writable);
+ if (kvm_is_error_hva(hva) || !writable)
+ return SBI_ERR_INVALID_ADDRESS;
+
+ ret = kvm_vcpu_write_guest(vcpu, shmem, &zero_sta, sizeof(zero_sta));
+ if (ret)
+ return SBI_ERR_FAILURE;
+
+ vcpu->arch.sta.shmem = shmem;
+ vcpu->arch.sta.last_steal = current->sched_info.run_delay;
+
+ return 0;
+}
+
+static int kvm_sbi_ext_sta_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ struct kvm_vcpu_sbi_return *retdata)
+{
+ struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
+ unsigned long funcid = cp->a6;
+ int ret;
+
+ switch (funcid) {
+ case SBI_EXT_STA_STEAL_TIME_SET_SHMEM:
+ ret = kvm_sbi_sta_steal_time_set_shmem(vcpu);
+ break;
+ default:
+ ret = SBI_ERR_NOT_SUPPORTED;
+ break;
+ }
+
+ retdata->err_val = ret;
+
+ return 0;
+}
+
+static unsigned long kvm_sbi_ext_sta_probe(struct kvm_vcpu *vcpu)
+{
+ return !!sched_info_on();
+}
+
+const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta = {
+ .extid_start = SBI_EXT_STA,
+ .extid_end = SBI_EXT_STA,
+ .handler = kvm_sbi_ext_sta_handler,
+ .probe = kvm_sbi_ext_sta_probe,
+};
+
+int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu,
+ unsigned long reg_num,
+ unsigned long *reg_val)
+{
+ switch (reg_num) {
+ case KVM_REG_RISCV_SBI_STA_REG(shmem_lo):
+ *reg_val = (unsigned long)vcpu->arch.sta.shmem;
+ break;
+ case KVM_REG_RISCV_SBI_STA_REG(shmem_hi):
+ if (IS_ENABLED(CONFIG_32BIT))
+ *reg_val = upper_32_bits(vcpu->arch.sta.shmem);
+ else
+ *reg_val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int kvm_riscv_vcpu_set_reg_sbi_sta(struct kvm_vcpu *vcpu,
+ unsigned long reg_num,
+ unsigned long reg_val)
+{
+ switch (reg_num) {
+ case KVM_REG_RISCV_SBI_STA_REG(shmem_lo):
+ if (IS_ENABLED(CONFIG_32BIT)) {
+ gpa_t hi = upper_32_bits(vcpu->arch.sta.shmem);
+
+ vcpu->arch.sta.shmem = reg_val;
+ vcpu->arch.sta.shmem |= hi << 32;
+ } else {
+ vcpu->arch.sta.shmem = reg_val;
+ }
+ break;
+ case KVM_REG_RISCV_SBI_STA_REG(shmem_hi):
+ if (IS_ENABLED(CONFIG_32BIT)) {
+ gpa_t lo = lower_32_bits(vcpu->arch.sta.shmem);
+
+ vcpu->arch.sta.shmem = ((gpa_t)reg_val << 32);
+ vcpu->arch.sta.shmem |= lo;
+ } else if (reg_val != 0) {
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/arch/riscv/kvm/vcpu_switch.S b/arch/riscv/kvm/vcpu_switch.S
index d74df8eb4d71..0c26189aa01c 100644
--- a/arch/riscv/kvm/vcpu_switch.S
+++ b/arch/riscv/kvm/vcpu_switch.S
@@ -15,7 +15,7 @@
.altmacro
.option norelax
-ENTRY(__kvm_riscv_switch_to)
+SYM_FUNC_START(__kvm_riscv_switch_to)
/* Save Host GPRs (except A0 and T0-T6) */
REG_S ra, (KVM_ARCH_HOST_RA)(a0)
REG_S sp, (KVM_ARCH_HOST_SP)(a0)
@@ -45,7 +45,7 @@ ENTRY(__kvm_riscv_switch_to)
REG_L t0, (KVM_ARCH_GUEST_SSTATUS)(a0)
REG_L t1, (KVM_ARCH_GUEST_HSTATUS)(a0)
REG_L t2, (KVM_ARCH_GUEST_SCOUNTEREN)(a0)
- la t4, __kvm_switch_return
+ la t4, .Lkvm_switch_return
REG_L t5, (KVM_ARCH_GUEST_SEPC)(a0)
/* Save Host and Restore Guest SSTATUS */
@@ -113,7 +113,7 @@ ENTRY(__kvm_riscv_switch_to)
/* Back to Host */
.align 2
-__kvm_switch_return:
+.Lkvm_switch_return:
/* Swap Guest A0 with SSCRATCH */
csrrw a0, CSR_SSCRATCH, a0
@@ -208,9 +208,9 @@ __kvm_switch_return:
/* Return to C code */
ret
-ENDPROC(__kvm_riscv_switch_to)
+SYM_FUNC_END(__kvm_riscv_switch_to)
-ENTRY(__kvm_riscv_unpriv_trap)
+SYM_CODE_START(__kvm_riscv_unpriv_trap)
/*
* We assume that faulting unpriv load/store instruction is
* 4-byte long and blindly increment SEPC by 4.
@@ -231,12 +231,10 @@ ENTRY(__kvm_riscv_unpriv_trap)
csrr a1, CSR_HTINST
REG_S a1, (KVM_ARCH_TRAP_HTINST)(a0)
sret
-ENDPROC(__kvm_riscv_unpriv_trap)
+SYM_CODE_END(__kvm_riscv_unpriv_trap)
#ifdef CONFIG_FPU
- .align 3
- .global __kvm_riscv_fp_f_save
-__kvm_riscv_fp_f_save:
+SYM_FUNC_START(__kvm_riscv_fp_f_save)
csrr t2, CSR_SSTATUS
li t1, SR_FS
csrs CSR_SSTATUS, t1
@@ -276,10 +274,9 @@ __kvm_riscv_fp_f_save:
sw t0, KVM_ARCH_FP_F_FCSR(a0)
csrw CSR_SSTATUS, t2
ret
+SYM_FUNC_END(__kvm_riscv_fp_f_save)
- .align 3
- .global __kvm_riscv_fp_d_save
-__kvm_riscv_fp_d_save:
+SYM_FUNC_START(__kvm_riscv_fp_d_save)
csrr t2, CSR_SSTATUS
li t1, SR_FS
csrs CSR_SSTATUS, t1
@@ -319,10 +316,9 @@ __kvm_riscv_fp_d_save:
sw t0, KVM_ARCH_FP_D_FCSR(a0)
csrw CSR_SSTATUS, t2
ret
+SYM_FUNC_END(__kvm_riscv_fp_d_save)
- .align 3
- .global __kvm_riscv_fp_f_restore
-__kvm_riscv_fp_f_restore:
+SYM_FUNC_START(__kvm_riscv_fp_f_restore)
csrr t2, CSR_SSTATUS
li t1, SR_FS
lw t0, KVM_ARCH_FP_F_FCSR(a0)
@@ -362,10 +358,9 @@ __kvm_riscv_fp_f_restore:
fscsr t0
csrw CSR_SSTATUS, t2
ret
+SYM_FUNC_END(__kvm_riscv_fp_f_restore)
- .align 3
- .global __kvm_riscv_fp_d_restore
-__kvm_riscv_fp_d_restore:
+SYM_FUNC_START(__kvm_riscv_fp_d_restore)
csrr t2, CSR_SSTATUS
li t1, SR_FS
lw t0, KVM_ARCH_FP_D_FCSR(a0)
@@ -405,4 +400,5 @@ __kvm_riscv_fp_d_restore:
fscsr t0
csrw CSR_SSTATUS, t2
ret
+SYM_FUNC_END(__kvm_riscv_fp_d_restore)
#endif
diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
index b339a2682f25..d92d1348045c 100644
--- a/arch/riscv/kvm/vcpu_vector.c
+++ b/arch/riscv/kvm/vcpu_vector.c
@@ -76,6 +76,7 @@ int kvm_riscv_vcpu_alloc_vector_context(struct kvm_vcpu *vcpu,
cntx->vector.datap = kmalloc(riscv_v_vsize, GFP_KERNEL);
if (!cntx->vector.datap)
return -ENOMEM;
+ cntx->vector.vlenb = riscv_v_vsize / 32;
vcpu->arch.host_context.vector.datap = kzalloc(riscv_v_vsize, GFP_KERNEL);
if (!vcpu->arch.host_context.vector.datap)
@@ -115,6 +116,9 @@ static int kvm_riscv_vcpu_vreg_addr(struct kvm_vcpu *vcpu,
case KVM_REG_RISCV_VECTOR_CSR_REG(vcsr):
*reg_addr = &cntx->vector.vcsr;
break;
+ case KVM_REG_RISCV_VECTOR_CSR_REG(vlenb):
+ *reg_addr = &cntx->vector.vlenb;
+ break;
case KVM_REG_RISCV_VECTOR_CSR_REG(datap):
default:
return -ENOENT;
@@ -173,6 +177,18 @@ int kvm_riscv_vcpu_set_reg_vector(struct kvm_vcpu *vcpu,
if (!riscv_isa_extension_available(isa, v))
return -ENOENT;
+ if (reg_num == KVM_REG_RISCV_VECTOR_CSR_REG(vlenb)) {
+ struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
+ unsigned long reg_val;
+
+ if (copy_from_user(&reg_val, uaddr, reg_size))
+ return -EFAULT;
+ if (reg_val != cntx->vector.vlenb)
+ return -EINVAL;
+
+ return 0;
+ }
+
rc = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size, &reg_addr);
if (rc)
return rc;
diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c
index 7e2b50c692c1..ce58bc48e5b8 100644
--- a/arch/riscv/kvm/vm.c
+++ b/arch/riscv/kvm/vm.c
@@ -179,7 +179,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
r = kvm_riscv_aia_available();
break;
case KVM_CAP_IOEVENTFD:
- case KVM_CAP_DEVICE_CTRL:
case KVM_CAP_USER_MEMORY:
case KVM_CAP_SYNC_MMU:
case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
diff --git a/arch/riscv/lib/clear_page.S b/arch/riscv/lib/clear_page.S
index b22de1231144..20ff03f5b0f2 100644
--- a/arch/riscv/lib/clear_page.S
+++ b/arch/riscv/lib/clear_page.S
@@ -4,9 +4,9 @@
*/
#include <linux/linkage.h>
+#include <linux/export.h>
#include <asm/asm.h>
#include <asm/alternative-macros.h>
-#include <asm-generic/export.h>
#include <asm/hwcap.h>
#include <asm/insn-def.h>
#include <asm/page.h>
diff --git a/arch/riscv/lib/tishift.S b/arch/riscv/lib/tishift.S
index ef90075c4b0a..c8294bf72c06 100644
--- a/arch/riscv/lib/tishift.S
+++ b/arch/riscv/lib/tishift.S
@@ -4,7 +4,7 @@
*/
#include <linux/linkage.h>
-#include <asm-generic/export.h>
+#include <linux/export.h>
SYM_FUNC_START(__lshrti3)
beqz a2, .L1
diff --git a/arch/riscv/lib/uaccess.S b/arch/riscv/lib/uaccess.S
index 3ab438f30d13..a9d356d6c03c 100644
--- a/arch/riscv/lib/uaccess.S
+++ b/arch/riscv/lib/uaccess.S
@@ -1,5 +1,5 @@
#include <linux/linkage.h>
-#include <asm-generic/export.h>
+#include <linux/export.h>
#include <asm/asm.h>
#include <asm/asm-extable.h>
#include <asm/csr.h>
diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile
index 3a4dfc8babcf..2c869f8026a8 100644
--- a/arch/riscv/mm/Makefile
+++ b/arch/riscv/mm/Makefile
@@ -13,10 +13,9 @@ endif
KCOV_INSTRUMENT_init.o := n
obj-y += init.o
-obj-$(CONFIG_MMU) += extable.o fault.o pageattr.o
+obj-$(CONFIG_MMU) += extable.o fault.o pageattr.o pgtable.o
obj-y += cacheflush.o
obj-y += context.o
-obj-y += pgtable.o
obj-y += pmem.o
ifeq ($(CONFIG_MMU),y)
diff --git a/arch/riscv/mm/dma-noncoherent.c b/arch/riscv/mm/dma-noncoherent.c
index 4e4e469b8dd6..843107f834b2 100644
--- a/arch/riscv/mm/dma-noncoherent.c
+++ b/arch/riscv/mm/dma-noncoherent.c
@@ -129,7 +129,7 @@ void arch_dma_prep_coherent(struct page *page, size_t size)
}
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
- const struct iommu_ops *iommu, bool coherent)
+ bool coherent)
{
WARN_TAINT(!coherent && riscv_cbom_block_size > ARCH_DMA_MINALIGN,
TAINT_CPU_OUT_OF_SPEC,
diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c
index 081339ddf47e..3ba1d4dde5dd 100644
--- a/arch/riscv/mm/fault.c
+++ b/arch/riscv/mm/fault.c
@@ -136,24 +136,24 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a
pgd = (pgd_t *)pfn_to_virt(pfn) + index;
pgd_k = init_mm.pgd + index;
- if (!pgd_present(*pgd_k)) {
+ if (!pgd_present(pgdp_get(pgd_k))) {
no_context(regs, addr);
return;
}
- set_pgd(pgd, *pgd_k);
+ set_pgd(pgd, pgdp_get(pgd_k));
p4d_k = p4d_offset(pgd_k, addr);
- if (!p4d_present(*p4d_k)) {
+ if (!p4d_present(p4dp_get(p4d_k))) {
no_context(regs, addr);
return;
}
pud_k = pud_offset(p4d_k, addr);
- if (!pud_present(*pud_k)) {
+ if (!pud_present(pudp_get(pud_k))) {
no_context(regs, addr);
return;
}
- if (pud_leaf(*pud_k))
+ if (pud_leaf(pudp_get(pud_k)))
goto flush_tlb;
/*
@@ -161,11 +161,11 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a
* to copy individual PTEs
*/
pmd_k = pmd_offset(pud_k, addr);
- if (!pmd_present(*pmd_k)) {
+ if (!pmd_present(pmdp_get(pmd_k))) {
no_context(regs, addr);
return;
}
- if (pmd_leaf(*pmd_k))
+ if (pmd_leaf(pmdp_get(pmd_k)))
goto flush_tlb;
/*
@@ -175,7 +175,7 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a
* silently loop forever.
*/
pte_k = pte_offset_kernel(pmd_k, addr);
- if (!pte_present(*pte_k)) {
+ if (!pte_present(ptep_get(pte_k))) {
no_context(regs, addr);
return;
}
diff --git a/arch/riscv/mm/hugetlbpage.c b/arch/riscv/mm/hugetlbpage.c
index b52f0210481f..431596c0e20e 100644
--- a/arch/riscv/mm/hugetlbpage.c
+++ b/arch/riscv/mm/hugetlbpage.c
@@ -54,7 +54,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
}
if (sz == PMD_SIZE) {
- if (want_pmd_share(vma, addr) && pud_none(*pud))
+ if (want_pmd_share(vma, addr) && pud_none(pudp_get(pud)))
pte = huge_pmd_share(mm, vma, addr, pud);
else
pte = (pte_t *)pmd_alloc(mm, pud, addr);
@@ -93,11 +93,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm,
pmd_t *pmd;
pgd = pgd_offset(mm, addr);
- if (!pgd_present(*pgd))
+ if (!pgd_present(pgdp_get(pgd)))
return NULL;
p4d = p4d_offset(pgd, addr);
- if (!p4d_present(*p4d))
+ if (!p4d_present(p4dp_get(p4d)))
return NULL;
pud = pud_offset(p4d, addr);
@@ -105,7 +105,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm,
/* must be pud huge, non-present or none */
return (pte_t *)pud;
- if (!pud_present(*pud))
+ if (!pud_present(pudp_get(pud)))
return NULL;
pmd = pmd_offset(pud, addr);
@@ -113,7 +113,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm,
/* must be pmd huge, non-present or none */
return (pte_t *)pmd;
- if (!pmd_present(*pmd))
+ if (!pmd_present(pmdp_get(pmd)))
return NULL;
for_each_napot_order(order) {
@@ -293,7 +293,7 @@ void huge_pte_clear(struct mm_struct *mm,
pte_t *ptep,
unsigned long sz)
{
- pte_t pte = READ_ONCE(*ptep);
+ pte_t pte = ptep_get(ptep);
int i, pte_num;
if (!pte_napot(pte)) {
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 2e011cbddf3a..a65937336cdc 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -174,6 +174,9 @@ void __init mem_init(void)
/* Limit the memory size via mem. */
static phys_addr_t memory_limit;
+#ifdef CONFIG_XIP_KERNEL
+#define memory_limit (*(phys_addr_t *)XIP_FIXUP(&memory_limit))
+#endif /* CONFIG_XIP_KERNEL */
static int __init early_mem(char *p)
{
@@ -952,7 +955,7 @@ static void __init create_fdt_early_page_table(uintptr_t fix_fdt_va,
* setup_vm_final installs the linear mapping. For 32-bit kernel, as the
* kernel is mapped in the linear mapping, that makes no difference.
*/
- dtb_early_va = kernel_mapping_pa_to_va(XIP_FIXUP(dtb_pa));
+ dtb_early_va = kernel_mapping_pa_to_va(dtb_pa);
#endif
dtb_early_pa = dtb_pa;
@@ -1055,9 +1058,9 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
#endif
kernel_map.virt_addr = KERNEL_LINK_ADDR + kernel_map.virt_offset;
- kernel_map.page_offset = _AC(CONFIG_PAGE_OFFSET, UL);
#ifdef CONFIG_XIP_KERNEL
+ kernel_map.page_offset = PAGE_OFFSET_L3;
kernel_map.xiprom = (uintptr_t)CONFIG_XIP_PHYS_ADDR;
kernel_map.xiprom_sz = (uintptr_t)(&_exiprom) - (uintptr_t)(&_xiprom);
@@ -1067,6 +1070,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
kernel_map.va_kernel_xip_pa_offset = kernel_map.virt_addr - kernel_map.xiprom;
#else
+ kernel_map.page_offset = _AC(CONFIG_PAGE_OFFSET, UL);
kernel_map.phys_addr = (uintptr_t)(&_start);
kernel_map.size = (uintptr_t)(&_end) - kernel_map.phys_addr;
#endif
diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c
index 5e39dcf23fdb..c301c8d291d2 100644
--- a/arch/riscv/mm/kasan_init.c
+++ b/arch/riscv/mm/kasan_init.c
@@ -31,7 +31,7 @@ static void __init kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned
phys_addr_t phys_addr;
pte_t *ptep, *p;
- if (pmd_none(*pmd)) {
+ if (pmd_none(pmdp_get(pmd))) {
p = memblock_alloc(PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE);
set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(p)), PAGE_TABLE));
}
@@ -39,7 +39,7 @@ static void __init kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned
ptep = pte_offset_kernel(pmd, vaddr);
do {
- if (pte_none(*ptep)) {
+ if (pte_none(ptep_get(ptep))) {
phys_addr = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
set_pte(ptep, pfn_pte(PFN_DOWN(phys_addr), PAGE_KERNEL));
memset(__va(phys_addr), KASAN_SHADOW_INIT, PAGE_SIZE);
@@ -53,7 +53,7 @@ static void __init kasan_populate_pmd(pud_t *pud, unsigned long vaddr, unsigned
pmd_t *pmdp, *p;
unsigned long next;
- if (pud_none(*pud)) {
+ if (pud_none(pudp_get(pud))) {
p = memblock_alloc(PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE);
set_pud(pud, pfn_pud(PFN_DOWN(__pa(p)), PAGE_TABLE));
}
@@ -63,7 +63,8 @@ static void __init kasan_populate_pmd(pud_t *pud, unsigned long vaddr, unsigned
do {
next = pmd_addr_end(vaddr, end);
- if (pmd_none(*pmdp) && IS_ALIGNED(vaddr, PMD_SIZE) && (next - vaddr) >= PMD_SIZE) {
+ if (pmd_none(pmdp_get(pmdp)) && IS_ALIGNED(vaddr, PMD_SIZE) &&
+ (next - vaddr) >= PMD_SIZE) {
phys_addr = memblock_phys_alloc(PMD_SIZE, PMD_SIZE);
if (phys_addr) {
set_pmd(pmdp, pfn_pmd(PFN_DOWN(phys_addr), PAGE_KERNEL));
@@ -83,7 +84,7 @@ static void __init kasan_populate_pud(p4d_t *p4d,
pud_t *pudp, *p;
unsigned long next;
- if (p4d_none(*p4d)) {
+ if (p4d_none(p4dp_get(p4d))) {
p = memblock_alloc(PTRS_PER_PUD * sizeof(pud_t), PAGE_SIZE);
set_p4d(p4d, pfn_p4d(PFN_DOWN(__pa(p)), PAGE_TABLE));
}
@@ -93,7 +94,8 @@ static void __init kasan_populate_pud(p4d_t *p4d,
do {
next = pud_addr_end(vaddr, end);
- if (pud_none(*pudp) && IS_ALIGNED(vaddr, PUD_SIZE) && (next - vaddr) >= PUD_SIZE) {
+ if (pud_none(pudp_get(pudp)) && IS_ALIGNED(vaddr, PUD_SIZE) &&
+ (next - vaddr) >= PUD_SIZE) {
phys_addr = memblock_phys_alloc(PUD_SIZE, PUD_SIZE);
if (phys_addr) {
set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_KERNEL));
@@ -113,7 +115,7 @@ static void __init kasan_populate_p4d(pgd_t *pgd,
p4d_t *p4dp, *p;
unsigned long next;
- if (pgd_none(*pgd)) {
+ if (pgd_none(pgdp_get(pgd))) {
p = memblock_alloc(PTRS_PER_P4D * sizeof(p4d_t), PAGE_SIZE);
set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE));
}
@@ -123,7 +125,8 @@ static void __init kasan_populate_p4d(pgd_t *pgd,
do {
next = p4d_addr_end(vaddr, end);
- if (p4d_none(*p4dp) && IS_ALIGNED(vaddr, P4D_SIZE) && (next - vaddr) >= P4D_SIZE) {
+ if (p4d_none(p4dp_get(p4dp)) && IS_ALIGNED(vaddr, P4D_SIZE) &&
+ (next - vaddr) >= P4D_SIZE) {
phys_addr = memblock_phys_alloc(P4D_SIZE, P4D_SIZE);
if (phys_addr) {
set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_KERNEL));
@@ -145,7 +148,7 @@ static void __init kasan_populate_pgd(pgd_t *pgdp,
do {
next = pgd_addr_end(vaddr, end);
- if (pgd_none(*pgdp) && IS_ALIGNED(vaddr, PGDIR_SIZE) &&
+ if (pgd_none(pgdp_get(pgdp)) && IS_ALIGNED(vaddr, PGDIR_SIZE) &&
(next - vaddr) >= PGDIR_SIZE) {
phys_addr = memblock_phys_alloc(PGDIR_SIZE, PGDIR_SIZE);
if (phys_addr) {
@@ -168,7 +171,7 @@ static void __init kasan_early_clear_pud(p4d_t *p4dp,
if (!pgtable_l4_enabled) {
pudp = (pud_t *)p4dp;
} else {
- base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(*p4dp)));
+ base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(p4dp_get(p4dp))));
pudp = base_pud + pud_index(vaddr);
}
@@ -193,7 +196,7 @@ static void __init kasan_early_clear_p4d(pgd_t *pgdp,
if (!pgtable_l5_enabled) {
p4dp = (p4d_t *)pgdp;
} else {
- base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(*pgdp)));
+ base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(pgdp_get(pgdp))));
p4dp = base_p4d + p4d_index(vaddr);
}
@@ -239,14 +242,14 @@ static void __init kasan_early_populate_pud(p4d_t *p4dp,
if (!pgtable_l4_enabled) {
pudp = (pud_t *)p4dp;
} else {
- base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(*p4dp)));
+ base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(p4dp_get(p4dp))));
pudp = base_pud + pud_index(vaddr);
}
do {
next = pud_addr_end(vaddr, end);
- if (pud_none(*pudp) && IS_ALIGNED(vaddr, PUD_SIZE) &&
+ if (pud_none(pudp_get(pudp)) && IS_ALIGNED(vaddr, PUD_SIZE) &&
(next - vaddr) >= PUD_SIZE) {
phys_addr = __pa((uintptr_t)kasan_early_shadow_pmd);
set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_TABLE));
@@ -277,14 +280,14 @@ static void __init kasan_early_populate_p4d(pgd_t *pgdp,
if (!pgtable_l5_enabled) {
p4dp = (p4d_t *)pgdp;
} else {
- base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(*pgdp)));
+ base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(pgdp_get(pgdp))));
p4dp = base_p4d + p4d_index(vaddr);
}
do {
next = p4d_addr_end(vaddr, end);
- if (p4d_none(*p4dp) && IS_ALIGNED(vaddr, P4D_SIZE) &&
+ if (p4d_none(p4dp_get(p4dp)) && IS_ALIGNED(vaddr, P4D_SIZE) &&
(next - vaddr) >= P4D_SIZE) {
phys_addr = __pa((uintptr_t)kasan_early_shadow_pud);
set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_TABLE));
@@ -305,7 +308,7 @@ static void __init kasan_early_populate_pgd(pgd_t *pgdp,
do {
next = pgd_addr_end(vaddr, end);
- if (pgd_none(*pgdp) && IS_ALIGNED(vaddr, PGDIR_SIZE) &&
+ if (pgd_none(pgdp_get(pgdp)) && IS_ALIGNED(vaddr, PGDIR_SIZE) &&
(next - vaddr) >= PGDIR_SIZE) {
phys_addr = __pa((uintptr_t)kasan_early_shadow_p4d);
set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_TABLE));
@@ -381,7 +384,7 @@ static void __init kasan_shallow_populate_pud(p4d_t *p4d,
do {
next = pud_addr_end(vaddr, end);
- if (pud_none(*pud_k)) {
+ if (pud_none(pudp_get(pud_k))) {
p = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
set_pud(pud_k, pfn_pud(PFN_DOWN(__pa(p)), PAGE_TABLE));
continue;
@@ -401,7 +404,7 @@ static void __init kasan_shallow_populate_p4d(pgd_t *pgd,
do {
next = p4d_addr_end(vaddr, end);
- if (p4d_none(*p4d_k)) {
+ if (p4d_none(p4dp_get(p4d_k))) {
p = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
set_p4d(p4d_k, pfn_p4d(PFN_DOWN(__pa(p)), PAGE_TABLE));
continue;
@@ -420,7 +423,7 @@ static void __init kasan_shallow_populate_pgd(unsigned long vaddr, unsigned long
do {
next = pgd_addr_end(vaddr, end);
- if (pgd_none(*pgd_k)) {
+ if (pgd_none(pgdp_get(pgd_k))) {
p = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
set_pgd(pgd_k, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE));
continue;
@@ -438,6 +441,14 @@ static void __init kasan_shallow_populate(void *start, void *end)
kasan_shallow_populate_pgd(vaddr, vend);
}
+#ifdef CONFIG_KASAN_VMALLOC
+void __init kasan_populate_early_vm_area_shadow(void *start, unsigned long size)
+{
+ kasan_populate(kasan_mem_to_shadow(start),
+ kasan_mem_to_shadow(start + size));
+}
+#endif
+
static void __init create_tmp_mapping(void)
{
void *ptr;
@@ -451,7 +462,7 @@ static void __init create_tmp_mapping(void)
/* Copy the last p4d since it is shared with the kernel mapping. */
if (pgtable_l5_enabled) {
- ptr = (p4d_t *)pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_END));
+ ptr = (p4d_t *)pgd_page_vaddr(pgdp_get(pgd_offset_k(KASAN_SHADOW_END)));
memcpy(tmp_p4d, ptr, sizeof(p4d_t) * PTRS_PER_P4D);
set_pgd(&tmp_pg_dir[pgd_index(KASAN_SHADOW_END)],
pfn_pgd(PFN_DOWN(__pa(tmp_p4d)), PAGE_TABLE));
@@ -462,7 +473,7 @@ static void __init create_tmp_mapping(void)
/* Copy the last pud since it is shared with the kernel mapping. */
if (pgtable_l4_enabled) {
- ptr = (pud_t *)p4d_page_vaddr(*(base_p4d + p4d_index(KASAN_SHADOW_END)));
+ ptr = (pud_t *)p4d_page_vaddr(p4dp_get(base_p4d + p4d_index(KASAN_SHADOW_END)));
memcpy(tmp_pud, ptr, sizeof(pud_t) * PTRS_PER_PUD);
set_p4d(&base_p4d[p4d_index(KASAN_SHADOW_END)],
pfn_p4d(PFN_DOWN(__pa(tmp_pud)), PAGE_TABLE));
diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c
index fc5fc4f785c4..410056a50aa9 100644
--- a/arch/riscv/mm/pageattr.c
+++ b/arch/riscv/mm/pageattr.c
@@ -29,7 +29,7 @@ static unsigned long set_pageattr_masks(unsigned long val, struct mm_walk *walk)
static int pageattr_p4d_entry(p4d_t *p4d, unsigned long addr,
unsigned long next, struct mm_walk *walk)
{
- p4d_t val = READ_ONCE(*p4d);
+ p4d_t val = p4dp_get(p4d);
if (p4d_leaf(val)) {
val = __p4d(set_pageattr_masks(p4d_val(val), walk));
@@ -42,7 +42,7 @@ static int pageattr_p4d_entry(p4d_t *p4d, unsigned long addr,
static int pageattr_pud_entry(pud_t *pud, unsigned long addr,
unsigned long next, struct mm_walk *walk)
{
- pud_t val = READ_ONCE(*pud);
+ pud_t val = pudp_get(pud);
if (pud_leaf(val)) {
val = __pud(set_pageattr_masks(pud_val(val), walk));
@@ -55,7 +55,7 @@ static int pageattr_pud_entry(pud_t *pud, unsigned long addr,
static int pageattr_pmd_entry(pmd_t *pmd, unsigned long addr,
unsigned long next, struct mm_walk *walk)
{
- pmd_t val = READ_ONCE(*pmd);
+ pmd_t val = pmdp_get(pmd);
if (pmd_leaf(val)) {
val = __pmd(set_pageattr_masks(pmd_val(val), walk));
@@ -68,7 +68,7 @@ static int pageattr_pmd_entry(pmd_t *pmd, unsigned long addr,
static int pageattr_pte_entry(pte_t *pte, unsigned long addr,
unsigned long next, struct mm_walk *walk)
{
- pte_t val = READ_ONCE(*pte);
+ pte_t val = ptep_get(pte);
val = __pte(set_pageattr_masks(pte_val(val), walk));
set_pte(pte, val);
@@ -108,10 +108,10 @@ static int __split_linear_mapping_pmd(pud_t *pudp,
vaddr <= (vaddr & PMD_MASK) && end >= next)
continue;
- if (pmd_leaf(*pmdp)) {
+ if (pmd_leaf(pmdp_get(pmdp))) {
struct page *pte_page;
- unsigned long pfn = _pmd_pfn(*pmdp);
- pgprot_t prot = __pgprot(pmd_val(*pmdp) & ~_PAGE_PFN_MASK);
+ unsigned long pfn = _pmd_pfn(pmdp_get(pmdp));
+ pgprot_t prot = __pgprot(pmd_val(pmdp_get(pmdp)) & ~_PAGE_PFN_MASK);
pte_t *ptep_new;
int i;
@@ -148,10 +148,10 @@ static int __split_linear_mapping_pud(p4d_t *p4dp,
vaddr <= (vaddr & PUD_MASK) && end >= next)
continue;
- if (pud_leaf(*pudp)) {
+ if (pud_leaf(pudp_get(pudp))) {
struct page *pmd_page;
- unsigned long pfn = _pud_pfn(*pudp);
- pgprot_t prot = __pgprot(pud_val(*pudp) & ~_PAGE_PFN_MASK);
+ unsigned long pfn = _pud_pfn(pudp_get(pudp));
+ pgprot_t prot = __pgprot(pud_val(pudp_get(pudp)) & ~_PAGE_PFN_MASK);
pmd_t *pmdp_new;
int i;
@@ -197,10 +197,10 @@ static int __split_linear_mapping_p4d(pgd_t *pgdp,
vaddr <= (vaddr & P4D_MASK) && end >= next)
continue;
- if (p4d_leaf(*p4dp)) {
+ if (p4d_leaf(p4dp_get(p4dp))) {
struct page *pud_page;
- unsigned long pfn = _p4d_pfn(*p4dp);
- pgprot_t prot = __pgprot(p4d_val(*p4dp) & ~_PAGE_PFN_MASK);
+ unsigned long pfn = _p4d_pfn(p4dp_get(p4dp));
+ pgprot_t prot = __pgprot(p4d_val(p4dp_get(p4dp)) & ~_PAGE_PFN_MASK);
pud_t *pudp_new;
int i;
@@ -305,8 +305,13 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask,
goto unlock;
}
} else if (is_kernel_mapping(start) || is_linear_mapping(start)) {
- lm_start = (unsigned long)lm_alias(start);
- lm_end = (unsigned long)lm_alias(end);
+ if (is_kernel_mapping(start)) {
+ lm_start = (unsigned long)lm_alias(start);
+ lm_end = (unsigned long)lm_alias(end);
+ } else {
+ lm_start = start;
+ lm_end = end;
+ }
ret = split_linear_mapping(lm_start, lm_end);
if (ret)
@@ -378,7 +383,7 @@ int set_direct_map_invalid_noflush(struct page *page)
int set_direct_map_default_noflush(struct page *page)
{
return __set_memory((unsigned long)page_address(page), 1,
- PAGE_KERNEL, __pgprot(0));
+ PAGE_KERNEL, __pgprot(_PAGE_EXEC));
}
#ifdef CONFIG_DEBUG_PAGEALLOC
@@ -406,29 +411,29 @@ bool kernel_page_present(struct page *page)
pte_t *pte;
pgd = pgd_offset_k(addr);
- if (!pgd_present(*pgd))
+ if (!pgd_present(pgdp_get(pgd)))
return false;
- if (pgd_leaf(*pgd))
+ if (pgd_leaf(pgdp_get(pgd)))
return true;
p4d = p4d_offset(pgd, addr);
- if (!p4d_present(*p4d))
+ if (!p4d_present(p4dp_get(p4d)))
return false;
- if (p4d_leaf(*p4d))
+ if (p4d_leaf(p4dp_get(p4d)))
return true;
pud = pud_offset(p4d, addr);
- if (!pud_present(*pud))
+ if (!pud_present(pudp_get(pud)))
return false;
- if (pud_leaf(*pud))
+ if (pud_leaf(pudp_get(pud)))
return true;
pmd = pmd_offset(pud, addr);
- if (!pmd_present(*pmd))
+ if (!pmd_present(pmdp_get(pmd)))
return false;
- if (pmd_leaf(*pmd))
+ if (pmd_leaf(pmdp_get(pmd)))
return true;
pte = pte_offset_kernel(pmd, addr);
- return pte_present(*pte);
+ return pte_present(ptep_get(pte));
}
diff --git a/arch/riscv/mm/pgtable.c b/arch/riscv/mm/pgtable.c
index fef4e7328e49..ef887efcb679 100644
--- a/arch/riscv/mm/pgtable.c
+++ b/arch/riscv/mm/pgtable.c
@@ -5,6 +5,47 @@
#include <linux/kernel.h>
#include <linux/pgtable.h>
+int ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep,
+ pte_t entry, int dirty)
+{
+ if (!pte_same(ptep_get(ptep), entry))
+ __set_pte_at(ptep, entry);
+ /*
+ * update_mmu_cache will unconditionally execute, handling both
+ * the case that the PTE changed and the spurious fault case.
+ */
+ return true;
+}
+
+int ptep_test_and_clear_young(struct vm_area_struct *vma,
+ unsigned long address,
+ pte_t *ptep)
+{
+ if (!pte_young(ptep_get(ptep)))
+ return 0;
+ return test_and_clear_bit(_PAGE_ACCESSED_OFFSET, &pte_val(*ptep));
+}
+EXPORT_SYMBOL_GPL(ptep_test_and_clear_young);
+
+#ifdef CONFIG_64BIT
+pud_t *pud_offset(p4d_t *p4d, unsigned long address)
+{
+ if (pgtable_l4_enabled)
+ return p4d_pgtable(p4dp_get(p4d)) + pud_index(address);
+
+ return (pud_t *)p4d;
+}
+
+p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
+{
+ if (pgtable_l5_enabled)
+ return pgd_pgtable(pgdp_get(pgd)) + p4d_index(address);
+
+ return (p4d_t *)pgd;
+}
+#endif
+
#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
int p4d_set_huge(p4d_t *p4d, phys_addr_t addr, pgprot_t prot)
{
@@ -25,7 +66,7 @@ int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot)
int pud_clear_huge(pud_t *pud)
{
- if (!pud_leaf(READ_ONCE(*pud)))
+ if (!pud_leaf(pudp_get(pud)))
return 0;
pud_clear(pud);
return 1;
@@ -33,7 +74,7 @@ int pud_clear_huge(pud_t *pud)
int pud_free_pmd_page(pud_t *pud, unsigned long addr)
{
- pmd_t *pmd = pud_pgtable(*pud);
+ pmd_t *pmd = pud_pgtable(pudp_get(pud));
int i;
pud_clear(pud);
@@ -63,7 +104,7 @@ int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot)
int pmd_clear_huge(pmd_t *pmd)
{
- if (!pmd_leaf(READ_ONCE(*pmd)))
+ if (!pmd_leaf(pmdp_get(pmd)))
return 0;
pmd_clear(pmd);
return 1;
@@ -71,7 +112,7 @@ int pmd_clear_huge(pmd_t *pmd)
int pmd_free_pte_page(pmd_t *pmd, unsigned long addr)
{
- pte_t *pte = (pte_t *)pmd_page_vaddr(*pmd);
+ pte_t *pte = (pte_t *)pmd_page_vaddr(pmdp_get(pmd));
pmd_clear(pmd);
@@ -88,7 +129,7 @@ pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
pmd_t pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp);
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
- VM_BUG_ON(pmd_trans_huge(*pmdp));
+ VM_BUG_ON(pmd_trans_huge(pmdp_get(pmdp)));
/*
* When leaf PTE entries (regular pages) are collapsed into a leaf
* PMD entry (huge page), a valid non-leaf PTE is converted into a
diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c
index e6659d7368b3..8aadc5f71c93 100644
--- a/arch/riscv/mm/tlbflush.c
+++ b/arch/riscv/mm/tlbflush.c
@@ -66,6 +66,11 @@ static inline void local_flush_tlb_range_asid(unsigned long start,
local_flush_tlb_range_threshold_asid(start, size, stride, asid);
}
+void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ local_flush_tlb_range_asid(start, end, PAGE_SIZE, FLUSH_TLB_NO_ASID);
+}
+
static void __ipi_flush_tlb_all(void *info)
{
local_flush_tlb_all();
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 8f39f0424796..fe565f3a3a91 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -216,7 +216,6 @@ config S390
select HAVE_VIRT_CPU_ACCOUNTING_IDLE
select IOMMU_HELPER if PCI
select IOMMU_SUPPORT if PCI
- select KEXEC
select MMU_GATHER_MERGE_VMAS
select MMU_GATHER_NO_GATHER
select MMU_GATHER_RCU_TABLE_FREE
@@ -443,7 +442,7 @@ config COMMAND_LINE_SIZE
line.
config COMPAT
- def_bool y
+ def_bool n
prompt "Kernel support for 31 bit emulation"
select ARCH_WANT_OLD_COMPAT_IPC
select COMPAT_OLD_SIGACTION
@@ -454,7 +453,9 @@ config COMPAT
Select this option if you want to enable your system kernel to
handle system-calls from ELF binaries for 31 bit ESA. This option
(and some other stuff like libraries and such) is needed for
- executing 31 bit applications. It is safe to say "Y".
+ executing 31 bit applications.
+
+ If unsure say N.
config SMP
def_bool y
diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig
index 85490d9373fc..67ba0157fbdb 100644
--- a/arch/s390/configs/debug_defconfig
+++ b/arch/s390/configs/debug_defconfig
@@ -40,6 +40,7 @@ CONFIG_SCHED_AUTOGROUP=y
CONFIG_EXPERT=y
# CONFIG_SYSFS_SYSCALL is not set
CONFIG_PROFILING=y
+CONFIG_KEXEC=y
CONFIG_KEXEC_FILE=y
CONFIG_KEXEC_SIG=y
CONFIG_CRASH_DUMP=y
diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig
index fb690fbbf54b..4c2650c1fbdd 100644
--- a/arch/s390/configs/defconfig
+++ b/arch/s390/configs/defconfig
@@ -38,6 +38,7 @@ CONFIG_SCHED_AUTOGROUP=y
CONFIG_EXPERT=y
# CONFIG_SYSFS_SYSCALL is not set
CONFIG_PROFILING=y
+CONFIG_KEXEC=y
CONFIG_KEXEC_FILE=y
CONFIG_KEXEC_SIG=y
CONFIG_CRASH_DUMP=y
diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig
index 47028450eee1..30d2a1687665 100644
--- a/arch/s390/configs/zfcpdump_defconfig
+++ b/arch/s390/configs/zfcpdump_defconfig
@@ -10,7 +10,6 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_CRASH_DUMP=y
CONFIG_MARCH_Z13=y
-# CONFIG_COMPAT is not set
CONFIG_NR_CPUS=2
CONFIG_HZ_100=y
# CONFIG_CHSC_SCH is not set
diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h
index 94b6919026df..796007125dff 100644
--- a/arch/s390/include/asm/facility.h
+++ b/arch/s390/include/asm/facility.h
@@ -111,4 +111,10 @@ static inline void stfle(u64 *stfle_fac_list, int size)
preempt_enable();
}
+/**
+ * stfle_size - Actual size of the facility list as specified by stfle
+ * (number of double words)
+ */
+unsigned int stfle_size(void);
+
#endif /* __ASM_FACILITY_H */
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 67a298b6cf6e..52664105a473 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -818,7 +818,7 @@ struct s390_io_adapter {
struct kvm_s390_cpu_model {
/* facility mask supported by kvm & hosting machine */
- __u64 fac_mask[S390_ARCH_FAC_LIST_SIZE_U64];
+ __u64 fac_mask[S390_ARCH_FAC_MASK_SIZE_U64];
struct kvm_s390_vm_cpu_subfunc subfuncs;
/* facility list requested by guest (in dma page) */
__u64 *fac_list;
diff --git a/arch/s390/include/asm/pci_io.h b/arch/s390/include/asm/pci_io.h
index 287bb88f7698..2686bee800e3 100644
--- a/arch/s390/include/asm/pci_io.h
+++ b/arch/s390/include/asm/pci_io.h
@@ -11,6 +11,8 @@
/* I/O size constraints */
#define ZPCI_MAX_READ_SIZE 8
#define ZPCI_MAX_WRITE_SIZE 128
+#define ZPCI_BOUNDARY_SIZE (1 << 12)
+#define ZPCI_BOUNDARY_MASK (ZPCI_BOUNDARY_SIZE - 1)
/* I/O Map */
#define ZPCI_IOMAP_SHIFT 48
@@ -125,16 +127,18 @@ out:
int zpci_write_block(volatile void __iomem *dst, const void *src,
unsigned long len);
-static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max)
+static inline int zpci_get_max_io_size(u64 src, u64 dst, int len, int max)
{
- int count = len > max ? max : len, size = 1;
+ int offset = dst & ZPCI_BOUNDARY_MASK;
+ int size;
- while (!(src & 0x1) && !(dst & 0x1) && ((size << 1) <= count)) {
- dst = dst >> 1;
- src = src >> 1;
- size = size << 1;
- }
- return size;
+ size = min3(len, ZPCI_BOUNDARY_SIZE - offset, max);
+ if (IS_ALIGNED(src, 8) && IS_ALIGNED(dst, 8) && IS_ALIGNED(size, 8))
+ return size;
+
+ if (size >= 8)
+ return 8;
+ return rounddown_pow_of_two(size);
}
static inline int zpci_memcpy_fromio(void *dst,
@@ -144,9 +148,9 @@ static inline int zpci_memcpy_fromio(void *dst,
int size, rc = 0;
while (n > 0) {
- size = zpci_get_max_write_size((u64 __force) src,
- (u64) dst, n,
- ZPCI_MAX_READ_SIZE);
+ size = zpci_get_max_io_size((u64 __force) src,
+ (u64) dst, n,
+ ZPCI_MAX_READ_SIZE);
rc = zpci_read_single(dst, src, size);
if (rc)
break;
@@ -166,9 +170,9 @@ static inline int zpci_memcpy_toio(volatile void __iomem *dst,
return -EINVAL;
while (n > 0) {
- size = zpci_get_max_write_size((u64 __force) dst,
- (u64) src, n,
- ZPCI_MAX_WRITE_SIZE);
+ size = zpci_get_max_io_size((u64 __force) dst,
+ (u64) src, n,
+ ZPCI_MAX_WRITE_SIZE);
if (size > 8) /* main path */
rc = zpci_write_block(dst, src, size);
else
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 353def93973b..7a562b4199c8 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -41,7 +41,7 @@ obj-y += sysinfo.o lgr.o os_info.o ctlreg.o
obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o
obj-y += entry.o reipl.o kdebugfs.o alternative.o
obj-y += nospec-branch.o ipl_vmparm.o machine_kexec_reloc.o unwind_bc.o
-obj-y += smp.o text_amode31.o stacktrace.o abs_lowcore.o
+obj-y += smp.o text_amode31.o stacktrace.o abs_lowcore.o facility.o
extra-y += vmlinux.lds
diff --git a/arch/s390/kernel/facility.c b/arch/s390/kernel/facility.c
new file mode 100644
index 000000000000..f02127219a27
--- /dev/null
+++ b/arch/s390/kernel/facility.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright IBM Corp. 2023
+ */
+
+#include <asm/facility.h>
+
+unsigned int stfle_size(void)
+{
+ static unsigned int size;
+ unsigned int r;
+ u64 dummy;
+
+ r = READ_ONCE(size);
+ if (!r) {
+ r = __stfle_asm(&dummy, 1) + 1;
+ WRITE_ONCE(size, r);
+ }
+ return r;
+}
+EXPORT_SYMBOL(stfle_size);
diff --git a/arch/s390/kernel/fpu.c b/arch/s390/kernel/fpu.c
index 9e7c15fccfea..a4f3449cc814 100644
--- a/arch/s390/kernel/fpu.c
+++ b/arch/s390/kernel/fpu.c
@@ -208,7 +208,6 @@ void __load_fpu_regs(void)
}
clear_cpu_flag(CIF_FPU);
}
-EXPORT_SYMBOL(__load_fpu_regs);
void load_fpu_regs(void)
{
diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c
index 39a91b00438a..bf8a672b15a4 100644
--- a/arch/s390/kernel/perf_pai_crypto.c
+++ b/arch/s390/kernel/perf_pai_crypto.c
@@ -111,11 +111,11 @@ static void paicrypt_event_destroy(struct perf_event *event)
mutex_unlock(&pai_reserve_mutex);
}
-static u64 paicrypt_getctr(struct paicrypt_map *cpump, int nr, bool kernel)
+static u64 paicrypt_getctr(unsigned long *page, int nr, bool kernel)
{
if (kernel)
nr += PAI_CRYPTO_MAXCTR;
- return cpump->page[nr];
+ return page[nr];
}
/* Read the counter values. Return value from location in CMP. For event
@@ -129,13 +129,13 @@ static u64 paicrypt_getdata(struct perf_event *event, bool kernel)
int i;
if (event->attr.config != PAI_CRYPTO_BASE) {
- return paicrypt_getctr(cpump,
+ return paicrypt_getctr(cpump->page,
event->attr.config - PAI_CRYPTO_BASE,
kernel);
}
for (i = 1; i <= paicrypt_cnt; i++) {
- u64 val = paicrypt_getctr(cpump, i, kernel);
+ u64 val = paicrypt_getctr(cpump->page, i, kernel);
if (!val)
continue;
@@ -317,10 +317,14 @@ static void paicrypt_start(struct perf_event *event, int flags)
* Events are added, deleted and re-added when 2 or more events
* are active at the same time.
*/
- if (!event->hw.last_tag) {
- event->hw.last_tag = 1;
- sum = paicrypt_getall(event); /* Get current value */
- local64_set(&event->hw.prev_count, sum);
+ if (!event->attr.sample_period) { /* Counting */
+ if (!event->hw.last_tag) {
+ event->hw.last_tag = 1;
+ sum = paicrypt_getall(event); /* Get current value */
+ local64_set(&event->hw.prev_count, sum);
+ }
+ } else { /* Sampling */
+ perf_sched_cb_inc(event->pmu);
}
}
@@ -336,19 +340,18 @@ static int paicrypt_add(struct perf_event *event, int flags)
local_ctl_set_bit(0, CR0_CRYPTOGRAPHY_COUNTER_BIT);
}
cpump->event = event;
- if (flags & PERF_EF_START && !event->attr.sample_period) {
- /* Only counting needs initial counter value */
+ if (flags & PERF_EF_START)
paicrypt_start(event, PERF_EF_RELOAD);
- }
event->hw.state = 0;
- if (event->attr.sample_period)
- perf_sched_cb_inc(event->pmu);
return 0;
}
static void paicrypt_stop(struct perf_event *event, int flags)
{
- paicrypt_read(event);
+ if (!event->attr.sample_period) /* Counting */
+ paicrypt_read(event);
+ else /* Sampling */
+ perf_sched_cb_dec(event->pmu);
event->hw.state = PERF_HES_STOPPED;
}
@@ -357,11 +360,7 @@ static void paicrypt_del(struct perf_event *event, int flags)
struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr);
struct paicrypt_map *cpump = mp->mapptr;
- if (event->attr.sample_period)
- perf_sched_cb_dec(event->pmu);
- if (!event->attr.sample_period)
- /* Only counting needs to read counter */
- paicrypt_stop(event, PERF_EF_UPDATE);
+ paicrypt_stop(event, PERF_EF_UPDATE);
if (--cpump->active_events == 0) {
local_ctl_clear_bit(0, CR0_CRYPTOGRAPHY_COUNTER_BIT);
WRITE_ONCE(S390_lowcore.ccd, 0);
@@ -373,8 +372,7 @@ static void paicrypt_del(struct perf_event *event, int flags)
* 2 bytes: Number of counter
* 8 bytes: Value of counter
*/
-static size_t paicrypt_copy(struct pai_userdata *userdata,
- struct paicrypt_map *cpump,
+static size_t paicrypt_copy(struct pai_userdata *userdata, unsigned long *page,
bool exclude_user, bool exclude_kernel)
{
int i, outidx = 0;
@@ -383,9 +381,9 @@ static size_t paicrypt_copy(struct pai_userdata *userdata,
u64 val = 0;
if (!exclude_kernel)
- val += paicrypt_getctr(cpump, i, true);
+ val += paicrypt_getctr(page, i, true);
if (!exclude_user)
- val += paicrypt_getctr(cpump, i, false);
+ val += paicrypt_getctr(page, i, false);
if (val) {
userdata[outidx].num = i;
userdata[outidx].value = val;
@@ -395,25 +393,14 @@ static size_t paicrypt_copy(struct pai_userdata *userdata,
return outidx * sizeof(struct pai_userdata);
}
-static int paicrypt_push_sample(void)
+static int paicrypt_push_sample(size_t rawsize, struct paicrypt_map *cpump,
+ struct perf_event *event)
{
- struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr);
- struct paicrypt_map *cpump = mp->mapptr;
- struct perf_event *event = cpump->event;
struct perf_sample_data data;
struct perf_raw_record raw;
struct pt_regs regs;
- size_t rawsize;
int overflow;
- if (!cpump->event) /* No event active */
- return 0;
- rawsize = paicrypt_copy(cpump->save, cpump,
- cpump->event->attr.exclude_user,
- cpump->event->attr.exclude_kernel);
- if (!rawsize) /* No incremented counters */
- return 0;
-
/* Setup perf sample */
memset(&regs, 0, sizeof(regs));
memset(&raw, 0, sizeof(raw));
@@ -444,6 +431,25 @@ static int paicrypt_push_sample(void)
return overflow;
}
+/* Check if there is data to be saved on schedule out of a task. */
+static int paicrypt_have_sample(void)
+{
+ struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr);
+ struct paicrypt_map *cpump = mp->mapptr;
+ struct perf_event *event = cpump->event;
+ size_t rawsize;
+ int rc = 0;
+
+ if (!event) /* No event active */
+ return 0;
+ rawsize = paicrypt_copy(cpump->save, cpump->page,
+ cpump->event->attr.exclude_user,
+ cpump->event->attr.exclude_kernel);
+ if (rawsize) /* No incremented counters */
+ rc = paicrypt_push_sample(rawsize, cpump, event);
+ return rc;
+}
+
/* Called on schedule-in and schedule-out. No access to event structure,
* but for sampling only event CRYPTO_ALL is allowed.
*/
@@ -453,7 +459,7 @@ static void paicrypt_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sch
* results on schedule_out and if page was dirty, clear values.
*/
if (!sched_in)
- paicrypt_push_sample();
+ paicrypt_have_sample();
}
/* Attribute definitions for paicrypt interface. As with other CPU
diff --git a/arch/s390/kernel/perf_pai_ext.c b/arch/s390/kernel/perf_pai_ext.c
index e7013a2e8960..af7f2b538c8f 100644
--- a/arch/s390/kernel/perf_pai_ext.c
+++ b/arch/s390/kernel/perf_pai_ext.c
@@ -276,9 +276,9 @@ static int paiext_event_init(struct perf_event *event)
return 0;
}
-static u64 paiext_getctr(struct paiext_map *cpump, int nr)
+static u64 paiext_getctr(unsigned long *area, int nr)
{
- return cpump->area[nr];
+ return area[nr];
}
/* Read the counter values. Return value from location in buffer. For event
@@ -292,10 +292,11 @@ static u64 paiext_getdata(struct perf_event *event)
int i;
if (event->attr.config != PAI_NNPA_BASE)
- return paiext_getctr(cpump, event->attr.config - PAI_NNPA_BASE);
+ return paiext_getctr(cpump->area,
+ event->attr.config - PAI_NNPA_BASE);
for (i = 1; i <= paiext_cnt; i++)
- sum += paiext_getctr(cpump, i);
+ sum += paiext_getctr(cpump->area, i);
return sum;
}
@@ -320,11 +321,15 @@ static void paiext_start(struct perf_event *event, int flags)
{
u64 sum;
- if (event->hw.last_tag)
- return;
- event->hw.last_tag = 1;
- sum = paiext_getall(event); /* Get current value */
- local64_set(&event->hw.prev_count, sum);
+ if (!event->attr.sample_period) { /* Counting */
+ if (!event->hw.last_tag) {
+ event->hw.last_tag = 1;
+ sum = paiext_getall(event); /* Get current value */
+ local64_set(&event->hw.prev_count, sum);
+ }
+ } else { /* Sampling */
+ perf_sched_cb_inc(event->pmu);
+ }
}
static int paiext_add(struct perf_event *event, int flags)
@@ -341,21 +346,19 @@ static int paiext_add(struct perf_event *event, int flags)
debug_sprintf_event(paiext_dbg, 4, "%s 1508 %llx acc %llx\n",
__func__, S390_lowcore.aicd, pcb->acc);
}
- if (flags & PERF_EF_START && !event->attr.sample_period) {
- /* Only counting needs initial counter value */
+ cpump->event = event;
+ if (flags & PERF_EF_START)
paiext_start(event, PERF_EF_RELOAD);
- }
event->hw.state = 0;
- if (event->attr.sample_period) {
- cpump->event = event;
- perf_sched_cb_inc(event->pmu);
- }
return 0;
}
static void paiext_stop(struct perf_event *event, int flags)
{
- paiext_read(event);
+ if (!event->attr.sample_period) /* Counting */
+ paiext_read(event);
+ else /* Sampling */
+ perf_sched_cb_dec(event->pmu);
event->hw.state = PERF_HES_STOPPED;
}
@@ -365,12 +368,7 @@ static void paiext_del(struct perf_event *event, int flags)
struct paiext_map *cpump = mp->mapptr;
struct paiext_cb *pcb = cpump->paiext_cb;
- if (event->attr.sample_period)
- perf_sched_cb_dec(event->pmu);
- if (!event->attr.sample_period) {
- /* Only counting needs to read counter */
- paiext_stop(event, PERF_EF_UPDATE);
- }
+ paiext_stop(event, PERF_EF_UPDATE);
if (--cpump->active_events == 0) {
/* Disable CPU instruction lookup for PAIE1 control block */
local_ctl_clear_bit(0, CR0_PAI_EXTENSION_BIT);
@@ -386,13 +384,12 @@ static void paiext_del(struct perf_event *event, int flags)
* 2 bytes: Number of counter
* 8 bytes: Value of counter
*/
-static size_t paiext_copy(struct paiext_map *cpump)
+static size_t paiext_copy(struct pai_userdata *userdata, unsigned long *area)
{
- struct pai_userdata *userdata = cpump->save;
int i, outidx = 0;
for (i = 1; i <= paiext_cnt; i++) {
- u64 val = paiext_getctr(cpump, i);
+ u64 val = paiext_getctr(area, i);
if (val) {
userdata[outidx].num = i;
@@ -418,21 +415,14 @@ static size_t paiext_copy(struct paiext_map *cpump)
* sched_task() callback. That callback is not active after paiext_del()
* returns and has deleted the event on that CPU.
*/
-static int paiext_push_sample(void)
+static int paiext_push_sample(size_t rawsize, struct paiext_map *cpump,
+ struct perf_event *event)
{
- struct paiext_mapptr *mp = this_cpu_ptr(paiext_root.mapptr);
- struct paiext_map *cpump = mp->mapptr;
- struct perf_event *event = cpump->event;
struct perf_sample_data data;
struct perf_raw_record raw;
struct pt_regs regs;
- size_t rawsize;
int overflow;
- rawsize = paiext_copy(cpump);
- if (!rawsize) /* No incremented counters */
- return 0;
-
/* Setup perf sample */
memset(&regs, 0, sizeof(regs));
memset(&raw, 0, sizeof(raw));
@@ -461,6 +451,23 @@ static int paiext_push_sample(void)
return overflow;
}
+/* Check if there is data to be saved on schedule out of a task. */
+static int paiext_have_sample(void)
+{
+ struct paiext_mapptr *mp = this_cpu_ptr(paiext_root.mapptr);
+ struct paiext_map *cpump = mp->mapptr;
+ struct perf_event *event = cpump->event;
+ size_t rawsize;
+ int rc = 0;
+
+ if (!event)
+ return 0;
+ rawsize = paiext_copy(cpump->save, cpump->area);
+ if (rawsize) /* Incremented counters */
+ rc = paiext_push_sample(rawsize, cpump, event);
+ return rc;
+}
+
/* Called on schedule-in and schedule-out. No access to event structure,
* but for sampling only event NNPA_ALL is allowed.
*/
@@ -470,7 +477,7 @@ static void paiext_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched
* results on schedule_out and if page was dirty, clear values.
*/
if (!sched_in)
- paiext_push_sample();
+ paiext_have_sample();
}
/* Attribute definitions for pai extension1 interface. As with other CPU
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 2e6754b62b20..f1897a8bb221 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -917,7 +917,6 @@ static int s390_fpregs_set(struct task_struct *target,
else
memcpy(&fprs, target->thread.fpu.fprs, sizeof(fprs));
- /* If setting FPC, must validate it first. */
if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) {
u32 ufpc[2] = { target->thread.fpu.fpc, 0 };
rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ufpc,
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index 45fdf2a9b2e3..72e9b7dcdf7d 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -20,19 +20,16 @@ config KVM
def_tristate y
prompt "Kernel-based Virtual Machine (KVM) support"
depends on HAVE_KVM
- select PREEMPT_NOTIFIERS
select HAVE_KVM_CPU_RELAX_INTERCEPT
select HAVE_KVM_VCPU_ASYNC_IOCTL
- select HAVE_KVM_EVENTFD
select KVM_ASYNC_PF
select KVM_ASYNC_PF_SYNC
+ select KVM_COMMON
select HAVE_KVM_IRQCHIP
- select HAVE_KVM_IRQFD
select HAVE_KVM_IRQ_ROUTING
select HAVE_KVM_INVALID_WAKEUPS
select HAVE_KVM_NO_POLL
select KVM_VFIO
- select INTERVAL_TREE
select MMU_NOTIFIER
help
Support hosting paravirtualized guest machines using the SIE
diff --git a/arch/s390/kvm/guestdbg.c b/arch/s390/kvm/guestdbg.c
index 3765c4223bf9..80879fc73c90 100644
--- a/arch/s390/kvm/guestdbg.c
+++ b/arch/s390/kvm/guestdbg.c
@@ -213,8 +213,8 @@ int kvm_s390_import_bp_data(struct kvm_vcpu *vcpu,
else if (dbg->arch.nr_hw_bp > MAX_BP_COUNT)
return -EINVAL;
- bp_data = memdup_user(dbg->arch.hw_bp,
- sizeof(*bp_data) * dbg->arch.nr_hw_bp);
+ bp_data = memdup_array_user(dbg->arch.hw_bp, dbg->arch.nr_hw_bp,
+ sizeof(*bp_data));
if (IS_ERR(bp_data))
return PTR_ERR(bp_data);
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index acc81ca6492e..ea63ac769889 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -563,7 +563,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_ENABLE_CAP:
case KVM_CAP_S390_CSS_SUPPORT:
case KVM_CAP_IOEVENTFD:
- case KVM_CAP_DEVICE_CTRL:
case KVM_CAP_S390_IRQCHIP:
case KVM_CAP_VM_ATTRIBUTES:
case KVM_CAP_MP_STATE:
diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c
index 8207a892bbe2..fef42e2a80a2 100644
--- a/arch/s390/kvm/vsie.c
+++ b/arch/s390/kvm/vsie.c
@@ -19,6 +19,7 @@
#include <asm/nmi.h>
#include <asm/dis.h>
#include <asm/fpu/api.h>
+#include <asm/facility.h>
#include "kvm-s390.h"
#include "gaccess.h"
@@ -984,12 +985,26 @@ static void retry_vsie_icpt(struct vsie_page *vsie_page)
static int handle_stfle(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
{
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
- __u32 fac = READ_ONCE(vsie_page->scb_o->fac) & 0x7ffffff8U;
+ __u32 fac = READ_ONCE(vsie_page->scb_o->fac);
+ /*
+ * Alternate-STFLE-Interpretive-Execution facilities are not supported
+ * -> format-0 flcb
+ */
if (fac && test_kvm_facility(vcpu->kvm, 7)) {
retry_vsie_icpt(vsie_page);
+ /*
+ * The facility list origin (FLO) is in bits 1 - 28 of the FLD
+ * so we need to mask here before reading.
+ */
+ fac = fac & 0x7ffffff8U;
+ /*
+ * format-0 -> size of nested guest's facility list == guest's size
+ * guest's size == host's size, since STFLE is interpretatively executed
+ * using a format-0 for the guest, too.
+ */
if (read_guest_real(vcpu, fac, &vsie_page->fac,
- sizeof(vsie_page->fac)))
+ stfle_size() * sizeof(u64)))
return set_validity_icpt(scb_s, 0x1090U);
scb_s->fac = (__u32)(__u64) &vsie_page->fac;
}
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index ab4098886e56..ac4c78546d97 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -280,7 +280,6 @@ static void do_sigbus(struct pt_regs *regs)
static void do_exception(struct pt_regs *regs, int access)
{
struct vm_area_struct *vma;
- struct task_struct *tsk;
unsigned long address;
struct mm_struct *mm;
enum fault_type type;
@@ -289,7 +288,6 @@ static void do_exception(struct pt_regs *regs, int access)
vm_fault_t fault;
bool is_write;
- tsk = current;
/*
* The instruction that caused the program check has
* been nullified. Don't signal single step via SIGTRAP.
@@ -297,7 +295,7 @@ static void do_exception(struct pt_regs *regs, int access)
clear_thread_flag(TIF_PER_TRAP);
if (kprobe_page_fault(regs, 14))
return;
- mm = tsk->mm;
+ mm = current->mm;
address = get_fault_address(regs);
is_write = fault_is_write(regs);
type = get_fault_type(regs);
diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c
index 588089332931..a90499c087f0 100644
--- a/arch/s390/pci/pci_mmio.c
+++ b/arch/s390/pci/pci_mmio.c
@@ -97,9 +97,9 @@ static inline int __memcpy_toio_inuser(void __iomem *dst,
return -EINVAL;
while (n > 0) {
- size = zpci_get_max_write_size((u64 __force) dst,
- (u64 __force) src, n,
- ZPCI_MAX_WRITE_SIZE);
+ size = zpci_get_max_io_size((u64 __force) dst,
+ (u64 __force) src, n,
+ ZPCI_MAX_WRITE_SIZE);
if (size > 8) /* main path */
rc = __pcistb_mio_inuser(dst, src, size, &status);
else
@@ -242,9 +242,9 @@ static inline int __memcpy_fromio_inuser(void __user *dst,
u8 status;
while (n > 0) {
- size = zpci_get_max_write_size((u64 __force) src,
- (u64 __force) dst, n,
- ZPCI_MAX_READ_SIZE);
+ size = zpci_get_max_io_size((u64 __force) src,
+ (u64 __force) dst, n,
+ ZPCI_MAX_READ_SIZE);
rc = __pcilg_mio_inuser(dst, src, size, &status);
if (rc)
break;
diff --git a/arch/sh/include/asm/cacheflush.h b/arch/sh/include/asm/cacheflush.h
index 878b6b551bd2..51112f54552b 100644
--- a/arch/sh/include/asm/cacheflush.h
+++ b/arch/sh/include/asm/cacheflush.h
@@ -90,6 +90,7 @@ extern void copy_from_user_page(struct vm_area_struct *vma,
unsigned long len);
#define flush_cache_vmap(start, end) local_flush_cache_all(NULL)
+#define flush_cache_vmap_early(start, end) do { } while (0)
#define flush_cache_vunmap(start, end) local_flush_cache_all(NULL)
#define flush_dcache_mmap_lock(mapping) do { } while (0)
diff --git a/arch/sparc/include/asm/cacheflush_32.h b/arch/sparc/include/asm/cacheflush_32.h
index f3b7270bf71b..9fee0ccfccb8 100644
--- a/arch/sparc/include/asm/cacheflush_32.h
+++ b/arch/sparc/include/asm/cacheflush_32.h
@@ -48,6 +48,7 @@ static inline void flush_dcache_page(struct page *page)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
#define flush_cache_vmap(start, end) flush_cache_all()
+#define flush_cache_vmap_early(start, end) do { } while (0)
#define flush_cache_vunmap(start, end) flush_cache_all()
/* When a context switch happens we must flush all user windows so that
diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h
index 0e879004efff..2b1261b77ecd 100644
--- a/arch/sparc/include/asm/cacheflush_64.h
+++ b/arch/sparc/include/asm/cacheflush_64.h
@@ -75,6 +75,7 @@ void flush_ptrace_access(struct vm_area_struct *, struct page *,
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
#define flush_cache_vmap(start, end) do { } while (0)
+#define flush_cache_vmap_early(start, end) do { } while (0)
#define flush_cache_vunmap(start, end) do { } while (0)
#endif /* !__ASSEMBLY__ */
diff --git a/arch/um/Makefile-skas b/arch/um/Makefile-skas
index ac35de5316a6..67323b028999 100644
--- a/arch/um/Makefile-skas
+++ b/arch/um/Makefile-skas
@@ -4,7 +4,12 @@
#
GPROF_OPT += -pg
+
+ifdef CONFIG_CC_IS_CLANG
+GCOV_OPT += -fprofile-instr-generate -fcoverage-mapping
+else
GCOV_OPT += -fprofile-arcs -ftest-coverage
+endif
CFLAGS-$(CONFIG_GCOV) += $(GCOV_OPT)
CFLAGS-$(CONFIG_GPROF) += $(GPROF_OPT)
diff --git a/arch/um/drivers/chan.h b/arch/um/drivers/chan.h
index 3fec3b8406e9..e14b9cdf7a33 100644
--- a/arch/um/drivers/chan.h
+++ b/arch/um/drivers/chan.h
@@ -30,7 +30,7 @@ struct chan {
extern void chan_interrupt(struct line *line, int irq);
extern int parse_chan_pair(char *str, struct line *line, int device,
const struct chan_opts *opts, char **error_out);
-extern int write_chan(struct chan *chan, const char *buf, int len,
+extern int write_chan(struct chan *chan, const u8 *buf, size_t len,
int write_irq);
extern int console_write_chan(struct chan *chan, const char *buf,
int len);
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 26a702a06515..37538b4168da 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -33,14 +33,14 @@ static void not_configged_close(int fd, void *data)
"UML\n");
}
-static int not_configged_read(int fd, char *c_out, void *data)
+static int not_configged_read(int fd, u8 *c_out, void *data)
{
printk(KERN_ERR "Using a channel type which is configured out of "
"UML\n");
return -EIO;
}
-static int not_configged_write(int fd, const char *buf, int len, void *data)
+static int not_configged_write(int fd, const u8 *buf, size_t len, void *data)
{
printk(KERN_ERR "Using a channel type which is configured out of "
"UML\n");
@@ -247,8 +247,7 @@ void deactivate_chan(struct chan *chan, int irq)
deactivate_fd(chan->fd, irq);
}
-int write_chan(struct chan *chan, const char *buf, int len,
- int write_irq)
+int write_chan(struct chan *chan, const u8 *buf, size_t len, int write_irq)
{
int n, ret = 0;
@@ -540,7 +539,7 @@ void chan_interrupt(struct line *line, int irq)
struct tty_port *port = &line->port;
struct chan *chan = line->chan_in;
int err;
- char c;
+ u8 c;
if (!chan || !chan->ops->read)
goto out;
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index 25727ed648b7..ec04e47b9d79 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -19,7 +19,7 @@ void generic_close(int fd, void *unused)
close(fd);
}
-int generic_read(int fd, char *c_out, void *unused)
+int generic_read(int fd, __u8 *c_out, void *unused)
{
int n;
@@ -35,7 +35,7 @@ int generic_read(int fd, char *c_out, void *unused)
/* XXX Trivial wrapper around write */
-int generic_write(int fd, const char *buf, int n, void *unused)
+int generic_write(int fd, const __u8 *buf, size_t n, void *unused)
{
int err;
@@ -141,7 +141,7 @@ struct winch_data {
int pipe_fd;
};
-static int winch_thread(void *arg)
+static __noreturn int winch_thread(void *arg)
{
struct winch_data *data = arg;
sigset_t sigs;
@@ -153,8 +153,8 @@ static int winch_thread(void *arg)
pipe_fd = data->pipe_fd;
count = write(pipe_fd, &c, sizeof(c));
if (count != sizeof(c))
- printk(UM_KERN_ERR "winch_thread : failed to write "
- "synchronization byte, err = %d\n", -count);
+ os_info("winch_thread : failed to write synchronization byte, err = %d\n",
+ -count);
/*
* We are not using SIG_IGN on purpose, so don't fix it as I thought to
@@ -166,29 +166,29 @@ static int winch_thread(void *arg)
sigfillset(&sigs);
/* Block all signals possible. */
if (sigprocmask(SIG_SETMASK, &sigs, NULL) < 0) {
- printk(UM_KERN_ERR "winch_thread : sigprocmask failed, "
- "errno = %d\n", errno);
- exit(1);
+ os_info("winch_thread : sigprocmask failed, errno = %d\n",
+ errno);
+ goto wait_kill;
}
/* In sigsuspend(), block anything else than SIGWINCH. */
sigdelset(&sigs, SIGWINCH);
if (setsid() < 0) {
- printk(UM_KERN_ERR "winch_thread : setsid failed, errno = %d\n",
+ os_info("winch_thread : setsid failed, errno = %d\n",
errno);
- exit(1);
+ goto wait_kill;
}
if (ioctl(pty_fd, TIOCSCTTY, 0) < 0) {
- printk(UM_KERN_ERR "winch_thread : TIOCSCTTY failed on "
- "fd %d err = %d\n", pty_fd, errno);
- exit(1);
+ os_info("winch_thread : TIOCSCTTY failed on "
+ "fd %d err = %d\n", pty_fd, errno);
+ goto wait_kill;
}
if (tcsetpgrp(pty_fd, os_getpid()) < 0) {
- printk(UM_KERN_ERR "winch_thread : tcsetpgrp failed on "
- "fd %d err = %d\n", pty_fd, errno);
- exit(1);
+ os_info("winch_thread : tcsetpgrp failed on fd %d err = %d\n",
+ pty_fd, errno);
+ goto wait_kill;
}
/*
@@ -199,8 +199,8 @@ static int winch_thread(void *arg)
*/
count = read(pipe_fd, &c, sizeof(c));
if (count != sizeof(c))
- printk(UM_KERN_ERR "winch_thread : failed to read "
- "synchronization byte, err = %d\n", errno);
+ os_info("winch_thread : failed to read synchronization byte, err = %d\n",
+ errno);
while(1) {
/*
@@ -211,9 +211,15 @@ static int winch_thread(void *arg)
count = write(pipe_fd, &c, sizeof(c));
if (count != sizeof(c))
- printk(UM_KERN_ERR "winch_thread : write failed, "
- "err = %d\n", errno);
+ os_info("winch_thread : write failed, err = %d\n",
+ errno);
}
+
+wait_kill:
+ c = 2;
+ count = write(pipe_fd, &c, sizeof(c));
+ while (1)
+ pause();
}
static int winch_tramp(int fd, struct tty_port *port, int *fd_out,
diff --git a/arch/um/drivers/chan_user.h b/arch/um/drivers/chan_user.h
index 4e51b85e2a23..e158e16fb3cc 100644
--- a/arch/um/drivers/chan_user.h
+++ b/arch/um/drivers/chan_user.h
@@ -7,6 +7,7 @@
#define __CHAN_USER_H__
#include <init.h>
+#include <linux/types.h>
struct chan_opts {
void (*const announce)(char *dev_name, int dev);
@@ -19,8 +20,8 @@ struct chan_ops {
void *(*init)(char *, int, const struct chan_opts *);
int (*open)(int, int, int, void *, char **);
void (*close)(int, void *);
- int (*read)(int, char *, void *);
- int (*write)(int, const char *, int, void *);
+ int (*read)(int, __u8 *, void *);
+ int (*write)(int, const __u8 *, size_t, void *);
int (*console_write)(int, const char *, int);
int (*window_size)(int, void *, unsigned short *, unsigned short *);
void (*free)(void *);
@@ -31,8 +32,8 @@ extern const struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops,
tty_ops, xterm_ops;
extern void generic_close(int fd, void *unused);
-extern int generic_read(int fd, char *c_out, void *unused);
-extern int generic_write(int fd, const char *buf, int n, void *unused);
+extern int generic_read(int fd, __u8 *c_out, void *unused);
+extern int generic_write(int fd, const __u8 *buf, size_t n, void *unused);
extern int generic_console_write(int fd, const char *buf, int n);
extern int generic_window_size(int fd, void *unused, unsigned short *rows_out,
unsigned short *cols_out);
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index b98545f3edb5..ffc5cb92fa36 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -83,7 +83,7 @@ unsigned int line_chars_in_buffer(struct tty_struct *tty)
*
* Must be called while holding line->lock!
*/
-static int buffer_data(struct line *line, const char *buf, int len)
+static int buffer_data(struct line *line, const u8 *buf, size_t len)
{
int end, room;
@@ -629,15 +629,18 @@ static irqreturn_t winch_interrupt(int irq, void *data)
if (fd != -1) {
err = generic_read(fd, &c, NULL);
- if (err < 0) {
+ /* A read of 2 means the winch thread failed and has warned */
+ if (err < 0 || (err == 1 && c == 2)) {
if (err != -EAGAIN) {
winch->fd = -1;
list_del(&winch->list);
os_close_file(fd);
- printk(KERN_ERR "winch_interrupt : "
- "read failed, errno = %d\n", -err);
- printk(KERN_ERR "fd %d is losing SIGWINCH "
- "support\n", winch->tty_fd);
+ if (err < 0) {
+ printk(KERN_ERR "winch_interrupt : read failed, errno = %d\n",
+ -err);
+ printk(KERN_ERR "fd %d is losing SIGWINCH support\n",
+ winch->tty_fd);
+ }
INIT_WORK(&winch->work, __free_winch);
schedule_work(&winch->work);
return IRQ_HANDLED;
diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h
index e84fb9b4165e..e8bd6f3dfb50 100644
--- a/arch/um/drivers/line.h
+++ b/arch/um/drivers/line.h
@@ -47,9 +47,9 @@ struct line {
*
* buffer points to a buffer allocated on demand, of length
* LINE_BUFSIZE, head to the start of the ring, tail to the end.*/
- char *buffer;
- char *head;
- char *tail;
+ u8 *buffer;
+ u8 *head;
+ u8 *tail;
int sigio;
struct delayed_work task;
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 3d7836c46507..cabcc501b448 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -204,7 +204,7 @@ static int uml_net_close(struct net_device *dev)
return 0;
}
-static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct uml_net_private *lp = netdev_priv(dev);
unsigned long flags;
diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c
index 87087763a417..30d59b8481b4 100644
--- a/arch/um/drivers/null.c
+++ b/arch/um/drivers/null.c
@@ -28,7 +28,7 @@ static int null_open(int input, int output, int primary, void *d,
return (fd < 0) ? -errno : fd;
}
-static int null_read(int fd, char *c_out, void *unused)
+static int null_read(int fd, __u8 *c_out, void *unused)
{
return -ENODEV;
}
diff --git a/arch/um/drivers/virt-pci.c b/arch/um/drivers/virt-pci.c
index ffe2ee8a0246..97a37c062997 100644
--- a/arch/um/drivers/virt-pci.c
+++ b/arch/um/drivers/virt-pci.c
@@ -971,7 +971,7 @@ static long um_pci_map_platform(unsigned long offset, size_t size,
*ops = &um_pci_device_bar_ops;
*priv = &um_pci_platform_device->resptr[0];
- return 0;
+ return offset;
}
static const struct logic_iomem_region_ops um_pci_platform_ops = {
diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h
index 5b072aba5b65..a7555e43ed14 100644
--- a/arch/um/include/asm/mmu.h
+++ b/arch/um/include/asm/mmu.h
@@ -12,7 +12,6 @@
typedef struct mm_context {
struct mm_id id;
struct uml_arch_mm_context arch;
- struct page *stub_pages[2];
} mm_context_t;
extern void __switch_mm(struct mm_id * mm_idp);
diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h
index 7414154b8e9a..6c3779541845 100644
--- a/arch/um/include/asm/processor-generic.h
+++ b/arch/um/include/asm/processor-generic.h
@@ -22,7 +22,6 @@ struct mm_struct;
struct thread_struct {
struct pt_regs regs;
struct pt_regs *segv_regs;
- int singlestep_syscall;
void *fault_addr;
jmp_buf *fault_catcher;
struct task_struct *prev_sched;
diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h
index d8b8b4f07e42..789b83013f35 100644
--- a/arch/um/include/shared/kern_util.h
+++ b/arch/um/include/shared/kern_util.h
@@ -34,7 +34,6 @@ extern int handle_page_fault(unsigned long address, unsigned long ip,
extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs);
extern void initial_thread_cb(void (*proc)(void *), void *arg);
-extern int is_syscall(unsigned long addr);
extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
@@ -50,7 +49,7 @@ extern void do_uml_exitcalls(void);
* Are we disallowed to sleep? Used to choose between GFP_KERNEL and
* GFP_ATOMIC.
*/
-extern int __cant_sleep(void);
+extern int __uml_cant_sleep(void);
extern int get_current_pid(void);
extern int copy_from_user_proc(void *to, void *from, int size);
extern char *uml_strdup(const char *string);
@@ -58,7 +57,7 @@ extern char *uml_strdup(const char *string);
extern unsigned long to_irq_stack(unsigned long *mask_out);
extern unsigned long from_irq_stack(int nested);
-extern int singlestepping(void *t);
+extern int singlestepping(void);
extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs);
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index 0df646c6651e..aff8906304ea 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -323,9 +323,6 @@ extern void sigio_broken(int fd);
extern int __add_sigio_fd(int fd);
extern int __ignore_sigio_fd(int fd);
-/* prctl.c */
-extern int os_arch_prctl(int pid, int option, unsigned long *arg2);
-
/* tty.c */
extern int get_pty(void);
diff --git a/arch/um/include/shared/ptrace_user.h b/arch/um/include/shared/ptrace_user.h
index 95455e8996e7..8a705d8f96ce 100644
--- a/arch/um/include/shared/ptrace_user.h
+++ b/arch/um/include/shared/ptrace_user.h
@@ -12,45 +12,4 @@
extern int ptrace_getregs(long pid, unsigned long *regs_out);
extern int ptrace_setregs(long pid, unsigned long *regs_in);
-/* syscall emulation path in ptrace */
-
-#ifndef PTRACE_SYSEMU
-#define PTRACE_SYSEMU 31
-#endif
-#ifndef PTRACE_SYSEMU_SINGLESTEP
-#define PTRACE_SYSEMU_SINGLESTEP 32
-#endif
-
-/* On architectures, that started to support PTRACE_O_TRACESYSGOOD
- * in linux 2.4, there are two different definitions of
- * PTRACE_SETOPTIONS: linux 2.4 uses 21 while linux 2.6 uses 0x4200.
- * For binary compatibility, 2.6 also supports the old "21", named
- * PTRACE_OLDSETOPTION. On these architectures, UML always must use
- * "21", to ensure the kernel runs on 2.4 and 2.6 host without
- * recompilation. So, we use PTRACE_OLDSETOPTIONS in UML.
- * We also want to be able to build the kernel on 2.4, which doesn't
- * have PTRACE_OLDSETOPTIONS. So, if it is missing, we declare
- * PTRACE_OLDSETOPTIONS to be the same as PTRACE_SETOPTIONS.
- *
- * On architectures, that start to support PTRACE_O_TRACESYSGOOD on
- * linux 2.6, PTRACE_OLDSETOPTIONS never is defined, and also isn't
- * supported by the host kernel. In that case, our trick lets us use
- * the new 0x4200 with the name PTRACE_OLDSETOPTIONS.
- */
-#ifndef PTRACE_OLDSETOPTIONS
-#define PTRACE_OLDSETOPTIONS PTRACE_SETOPTIONS
-#endif
-
-void set_using_sysemu(int value);
-int get_using_sysemu(void);
-extern int sysemu_supported;
-
-#define SELECT_PTRACE_OPERATION(sysemu_mode, singlestep_mode) \
- (((int[3][3] ) { \
- { PTRACE_SYSCALL, PTRACE_SYSCALL, PTRACE_SINGLESTEP }, \
- { PTRACE_SYSEMU, PTRACE_SYSEMU, PTRACE_SINGLESTEP }, \
- { PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, \
- PTRACE_SYSEMU_SINGLESTEP } }) \
- [sysemu_mode][singlestep_mode])
-
#endif
diff --git a/arch/um/include/shared/registers.h b/arch/um/include/shared/registers.h
index 2f9c3ce5b45e..a0450326521c 100644
--- a/arch/um/include/shared/registers.h
+++ b/arch/um/include/shared/registers.h
@@ -14,8 +14,6 @@ extern int save_fp_registers(int pid, unsigned long *fp_regs);
extern int restore_fp_registers(int pid, unsigned long *fp_regs);
extern int save_fpx_registers(int pid, unsigned long *fp_regs);
extern int restore_fpx_registers(int pid, unsigned long *fp_regs);
-extern int save_registers(int pid, struct uml_pt_regs *regs);
-extern int restore_pid_registers(int pid, struct uml_pt_regs *regs);
extern int init_pid_registers(int pid);
extern void get_safe_registers(unsigned long *regs, unsigned long *fp_regs);
extern int get_fp_registers(int pid, unsigned long *regs);
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 106b7da2f8d6..ab95648e93e1 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -220,7 +220,7 @@ void arch_cpu_idle(void)
um_idle_sleep();
}
-int __cant_sleep(void) {
+int __uml_cant_sleep(void) {
return in_atomic() || irqs_disabled() || in_interrupt();
/* Is in_interrupt() really needed? */
}
@@ -332,17 +332,9 @@ int __init make_proc_sysemu(void)
late_initcall(make_proc_sysemu);
-int singlestepping(void * t)
+int singlestepping(void)
{
- struct task_struct *task = t ? t : current;
-
- if (!test_thread_flag(TIF_SINGLESTEP))
- return 0;
-
- if (task->thread.singlestep_syscall)
- return 1;
-
- return 2;
+ return test_thread_flag(TIF_SINGLESTEP);
}
/*
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index 5154b27de580..6600a2782796 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -12,7 +12,6 @@
void user_enable_single_step(struct task_struct *child)
{
set_tsk_thread_flag(child, TIF_SINGLESTEP);
- child->thread.singlestep_syscall = 0;
#ifdef SUBARCH_SET_SINGLESTEPPING
SUBARCH_SET_SINGLESTEPPING(child, 1);
@@ -22,7 +21,6 @@ void user_enable_single_step(struct task_struct *child)
void user_disable_single_step(struct task_struct *child)
{
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
- child->thread.singlestep_syscall = 0;
#ifdef SUBARCH_SET_SINGLESTEPPING
SUBARCH_SET_SINGLESTEPPING(child, 0);
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index ae4658f576ab..a56b44522766 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -121,18 +121,6 @@ void do_signal(struct pt_regs *regs)
}
/*
- * This closes a way to execute a system call on the host. If
- * you set a breakpoint on a system call instruction and singlestep
- * from it, the tracing thread used to PTRACE_SINGLESTEP the process
- * rather than PTRACE_SYSCALL it, allowing the system call to execute
- * on the host. The tracing thread will check this flag and
- * PTRACE_SYSCALL if necessary.
- */
- if (test_thread_flag(TIF_SINGLESTEP))
- current->thread.singlestep_syscall =
- is_syscall(PT_REGS_IP(&current->thread.regs));
-
- /*
* if there's no signal to deliver, we just put the saved sigmask
* back
*/
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
index aaee96f07172..198269e384c4 100644
--- a/arch/um/kernel/skas/uaccess.c
+++ b/arch/um/kernel/skas/uaccess.c
@@ -236,7 +236,9 @@ EXPORT_SYMBOL(strnlen_user);
* argument and comparison of the previous
* futex value with another constant.
*
- * @encoded_op: encoded operation to execute
+ * @op: operation to execute
+ * @oparg: argument to operation
+ * @oval: old value at uaddr
* @uaddr: pointer to user space address
*
* Return:
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index fddd1dec27e6..3e270da6b6f6 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -432,9 +432,29 @@ static void time_travel_update_time(unsigned long long next, bool idle)
time_travel_del_event(&ne);
}
+static void time_travel_update_time_rel(unsigned long long offs)
+{
+ unsigned long flags;
+
+ /*
+ * Disable interrupts before calculating the new time so
+ * that a real timer interrupt (signal) can't happen at
+ * a bad time e.g. after we read time_travel_time but
+ * before we've completed updating the time.
+ */
+ local_irq_save(flags);
+ time_travel_update_time(time_travel_time + offs, false);
+ local_irq_restore(flags);
+}
+
void time_travel_ndelay(unsigned long nsec)
{
- time_travel_update_time(time_travel_time + nsec, false);
+ /*
+ * Not strictly needed to use _rel() version since this is
+ * only used in INFCPU/EXT modes, but it doesn't hurt and
+ * is more readable too.
+ */
+ time_travel_update_time_rel(nsec);
}
EXPORT_SYMBOL(time_travel_ndelay);
@@ -568,7 +588,11 @@ static void time_travel_set_start(void)
#define time_travel_time 0
#define time_travel_ext_waiting 0
-static inline void time_travel_update_time(unsigned long long ns, bool retearly)
+static inline void time_travel_update_time(unsigned long long ns, bool idle)
+{
+}
+
+static inline void time_travel_update_time_rel(unsigned long long offs)
{
}
@@ -720,9 +744,7 @@ static u64 timer_read(struct clocksource *cs)
*/
if (!irqs_disabled() && !in_interrupt() && !in_softirq() &&
!time_travel_ext_waiting)
- time_travel_update_time(time_travel_time +
- TIMER_MULTIPLIER,
- false);
+ time_travel_update_time_rel(TIMER_MULTIPLIER);
return time_travel_time / TIMER_MULTIPLIER;
}
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
index b459745f52e2..3cb8ac63be6e 100644
--- a/arch/um/os-Linux/helper.c
+++ b/arch/um/os-Linux/helper.c
@@ -46,7 +46,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
unsigned long stack, sp;
int pid, fds[2], ret, n;
- stack = alloc_stack(0, __cant_sleep());
+ stack = alloc_stack(0, __uml_cant_sleep());
if (stack == 0)
return -ENOMEM;
@@ -70,7 +70,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
data.pre_data = pre_data;
data.argv = argv;
data.fd = fds[1];
- data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
+ data.buf = __uml_cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
uml_kmalloc(PATH_MAX, UM_GFP_KERNEL);
pid = clone(helper_child, (void *) sp, CLONE_VM, &data);
if (pid < 0) {
@@ -121,7 +121,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
unsigned long stack, sp;
int pid, status, err;
- stack = alloc_stack(0, __cant_sleep());
+ stack = alloc_stack(0, __uml_cant_sleep());
if (stack == 0)
return -ENOMEM;
diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c
index b123955be7ac..bd80b921add0 100644
--- a/arch/um/os-Linux/registers.c
+++ b/arch/um/os-Linux/registers.c
@@ -11,26 +11,6 @@
#include <sysdep/ptrace_user.h>
#include <registers.h>
-int save_registers(int pid, struct uml_pt_regs *regs)
-{
- int err;
-
- err = ptrace(PTRACE_GETREGS, pid, 0, regs->gp);
- if (err < 0)
- return -errno;
- return 0;
-}
-
-int restore_pid_registers(int pid, struct uml_pt_regs *regs)
-{
- int err;
-
- err = ptrace(PTRACE_SETREGS, pid, 0, regs->gp);
- if (err < 0)
- return -errno;
- return 0;
-}
-
/* This is set once at boot time and not changed thereafter */
static unsigned long exec_regs[MAX_REG_NR];
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 9464833e741a..1f5c3f2523d1 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -177,48 +177,11 @@ static void handle_segv(int pid, struct uml_pt_regs *regs, unsigned long *aux_fp
segv(regs->faultinfo, 0, 1, NULL);
}
-/*
- * To use the same value of using_sysemu as the caller, ask it that value
- * (in local_using_sysemu
- */
-static void handle_trap(int pid, struct uml_pt_regs *regs,
- int local_using_sysemu)
+static void handle_trap(int pid, struct uml_pt_regs *regs)
{
- int err, status;
-
if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END))
fatal_sigsegv();
- if (!local_using_sysemu)
- {
- err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
- __NR_getpid);
- if (err < 0) {
- printk(UM_KERN_ERR "%s - nullifying syscall failed, errno = %d\n",
- __func__, errno);
- fatal_sigsegv();
- }
-
- err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
- if (err < 0) {
- printk(UM_KERN_ERR "%s - continuing to end of syscall failed, errno = %d\n",
- __func__, errno);
- fatal_sigsegv();
- }
-
- CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL));
- if ((err < 0) || !WIFSTOPPED(status) ||
- (WSTOPSIG(status) != SIGTRAP + 0x80)) {
- err = ptrace_dump_regs(pid);
- if (err)
- printk(UM_KERN_ERR "Failed to get registers from process, errno = %d\n",
- -err);
- printk(UM_KERN_ERR "%s - failed to wait at end of syscall, errno = %d, status = %d\n",
- __func__, errno, status);
- fatal_sigsegv();
- }
- }
-
handle_syscall(regs);
}
@@ -226,7 +189,7 @@ extern char __syscall_stub_start[];
/**
* userspace_tramp() - userspace trampoline
- * @stack: pointer to the new userspace stack page, can be NULL, if? FIXME:
+ * @stack: pointer to the new userspace stack page
*
* The userspace trampoline is used to setup a new userspace process in start_userspace() after it was clone()'ed.
* This function will run on a temporary stack page.
@@ -241,9 +204,13 @@ extern char __syscall_stub_start[];
*/
static int userspace_tramp(void *stack)
{
+ struct sigaction sa;
void *addr;
int fd;
unsigned long long offset;
+ unsigned long segv_handler = STUB_CODE +
+ (unsigned long) stub_segv_handler -
+ (unsigned long) __syscall_stub_start;
ptrace(PTRACE_TRACEME, 0, 0, 0);
@@ -254,39 +221,30 @@ static int userspace_tramp(void *stack)
addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE,
PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
if (addr == MAP_FAILED) {
- printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, errno = %d\n",
- STUB_CODE, errno);
+ os_info("mapping mmap stub at 0x%lx failed, errno = %d\n",
+ STUB_CODE, errno);
exit(1);
}
- if (stack != NULL) {
- fd = phys_mapping(uml_to_phys(stack), &offset);
- addr = mmap((void *) STUB_DATA,
- 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",
- STUB_DATA, errno);
- exit(1);
- }
+ fd = phys_mapping(uml_to_phys(stack), &offset);
+ addr = mmap((void *) STUB_DATA,
+ STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_SHARED, fd, offset);
+ if (addr == MAP_FAILED) {
+ os_info("mapping segfault stack at 0x%lx failed, errno = %d\n",
+ STUB_DATA, errno);
+ exit(1);
}
- if (stack != NULL) {
- struct sigaction sa;
-
- unsigned long v = STUB_CODE +
- (unsigned long) stub_segv_handler -
- (unsigned long) __syscall_stub_start;
-
- 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;
- sa.sa_restorer = NULL;
- if (sigaction(SIGSEGV, &sa, NULL) < 0) {
- printk(UM_KERN_ERR "%s - setting SIGSEGV handler failed - errno = %d\n",
- __func__, errno);
- exit(1);
- }
+
+ 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 *) segv_handler;
+ sa.sa_restorer = NULL;
+ if (sigaction(SIGSEGV, &sa, NULL) < 0) {
+ os_info("%s - setting SIGSEGV handler failed - errno = %d\n",
+ __func__, errno);
+ exit(1);
}
kill(os_getpid(), SIGSTOP);
@@ -298,7 +256,7 @@ int kill_userspace_mm[NR_CPUS];
/**
* start_userspace() - prepare a new userspace process
- * @stub_stack: pointer to the stub stack. Can be NULL, if? FIXME:
+ * @stub_stack: pointer to the stub stack.
*
* Setups a new temporary stack page that is used while userspace_tramp() runs
* Clones the kernel process into a new userspace process, with FDs only.
@@ -355,10 +313,10 @@ int start_userspace(unsigned long stub_stack)
goto out_kill;
}
- if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
+ if (ptrace(PTRACE_SETOPTIONS, pid, NULL,
(void *) PTRACE_O_TRACESYSGOOD) < 0) {
err = -errno;
- printk(UM_KERN_ERR "%s : PTRACE_OLDSETOPTIONS failed, errno = %d\n",
+ printk(UM_KERN_ERR "%s : PTRACE_SETOPTIONS failed, errno = %d\n",
__func__, errno);
goto out_kill;
}
@@ -380,8 +338,6 @@ int start_userspace(unsigned long stub_stack)
void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
{
int err, status, op, pid = userspace_pid[0];
- /* To prevent races if using_sysemu changes under us.*/
- int local_using_sysemu;
siginfo_t si;
/* Handle any immediate reschedules or signals */
@@ -411,11 +367,10 @@ void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
fatal_sigsegv();
}
- /* Now we set local_using_sysemu to be used for one loop */
- local_using_sysemu = get_using_sysemu();
-
- op = SELECT_PTRACE_OPERATION(local_using_sysemu,
- singlestepping(NULL));
+ if (singlestepping())
+ op = PTRACE_SYSEMU_SINGLESTEP;
+ else
+ op = PTRACE_SYSEMU;
if (ptrace(op, pid, 0, 0)) {
printk(UM_KERN_ERR "%s - ptrace continue failed, op = %d, errno = %d\n",
@@ -474,7 +429,7 @@ void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
else handle_segv(pid, regs, aux_fp_regs);
break;
case SIGTRAP + 0x80:
- handle_trap(pid, regs, local_using_sysemu);
+ handle_trap(pid, regs);
break;
case SIGTRAP:
relay_signal(SIGTRAP, (struct siginfo *)&si, regs);
@@ -597,10 +552,10 @@ int copy_context_skas0(unsigned long new_stack, int pid)
goto out_kill;
}
- if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
+ if (ptrace(PTRACE_SETOPTIONS, pid, NULL,
(void *)PTRACE_O_TRACESYSGOOD) < 0) {
err = -errno;
- printk(UM_KERN_ERR "%s : PTRACE_OLDSETOPTIONS failed, errno = %d\n",
+ printk(UM_KERN_ERR "%s : PTRACE_SETOPTIONS failed, errno = %d\n",
__func__, errno);
goto out_kill;
}
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index e3ee4db58b40..8b0e98ab842c 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -112,102 +112,32 @@ static int start_ptraced_child(void)
return pid;
}
-/* When testing for SYSEMU support, if it is one of the broken versions, we
- * must just avoid using sysemu, not panic, but only if SYSEMU features are
- * broken.
- * So only for SYSEMU features we test mustpanic, while normal host features
- * must work anyway!
- */
-static int stop_ptraced_child(int pid, int exitcode, int mustexit)
+static void stop_ptraced_child(int pid, int exitcode)
{
- int status, n, ret = 0;
+ int status, n;
+
+ if (ptrace(PTRACE_CONT, pid, 0, 0) < 0)
+ fatal_perror("stop_ptraced_child : ptrace failed");
- if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) {
- perror("stop_ptraced_child : ptrace failed");
- return -1;
- }
CATCH_EINTR(n = waitpid(pid, &status, 0));
if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
int exit_with = WEXITSTATUS(status);
- if (exit_with == 2)
- non_fatal("check_ptrace : child exited with status 2. "
- "\nDisabling SYSEMU support.\n");
- non_fatal("check_ptrace : child exited with exitcode %d, while "
- "expecting %d; status 0x%x\n", exit_with,
- exitcode, status);
- if (mustexit)
- exit(1);
- ret = -1;
+ fatal("stop_ptraced_child : child exited with exitcode %d, "
+ "while expecting %d; status 0x%x\n", exit_with,
+ exitcode, status);
}
-
- return ret;
-}
-
-/* Changed only during early boot */
-static int force_sysemu_disabled = 0;
-
-static int __init nosysemu_cmd_param(char *str, int* add)
-{
- force_sysemu_disabled = 1;
- return 0;
}
-__uml_setup("nosysemu", nosysemu_cmd_param,
-"nosysemu\n"
-" Turns off syscall emulation patch for ptrace (SYSEMU).\n"
-" SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n"
-" behaviour of ptrace() and helps reduce host context switch rates.\n"
-" To make it work, you need a kernel patch for your host, too.\n"
-" See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n"
-" information.\n\n");
-
static void __init check_sysemu(void)
{
- unsigned long regs[MAX_REG_NR];
int pid, n, status, count=0;
- os_info("Checking syscall emulation patch for ptrace...");
- sysemu_supported = 0;
- pid = start_ptraced_child();
-
- if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
- goto fail;
-
- CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
- if (n < 0)
- fatal_perror("check_sysemu : wait failed");
- if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
- fatal("check_sysemu : expected SIGTRAP, got status = %d\n",
- status);
-
- if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
- fatal_perror("check_sysemu : PTRACE_GETREGS failed");
- if (PT_SYSCALL_NR(regs) != __NR_getpid) {
- non_fatal("check_sysemu got system call number %d, "
- "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid);
- goto fail;
- }
-
- n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid());
- if (n < 0) {
- non_fatal("check_sysemu : failed to modify system call "
- "return");
- goto fail;
- }
-
- if (stop_ptraced_child(pid, 0, 0) < 0)
- goto fail_stopped;
-
- sysemu_supported = 1;
- os_info("OK\n");
- set_using_sysemu(!force_sysemu_disabled);
-
- os_info("Checking advanced syscall emulation patch for ptrace...");
+ os_info("Checking syscall emulation for ptrace...");
pid = start_ptraced_child();
- if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
+ if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
(void *) PTRACE_O_TRACESYSGOOD) < 0))
- fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed");
+ fatal_perror("check_sysemu: PTRACE_SETOPTIONS failed");
while (1) {
count++;
@@ -240,20 +170,15 @@ static void __init check_sysemu(void)
goto fail;
}
}
- if (stop_ptraced_child(pid, 0, 0) < 0)
- goto fail_stopped;
+ stop_ptraced_child(pid, 0);
- sysemu_supported = 2;
os_info("OK\n");
- if (!force_sysemu_disabled)
- set_using_sysemu(sysemu_supported);
return;
fail:
- stop_ptraced_child(pid, 1, 0);
-fail_stopped:
- non_fatal("missing\n");
+ stop_ptraced_child(pid, 1);
+ fatal("missing\n");
}
static void __init check_ptrace(void)
@@ -263,9 +188,9 @@ static void __init check_ptrace(void)
os_info("Checking that ptrace can change system call numbers...");
pid = start_ptraced_child();
- if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0,
+ if ((ptrace(PTRACE_SETOPTIONS, pid, 0,
(void *) PTRACE_O_TRACESYSGOOD) < 0))
- fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed");
+ fatal_perror("check_ptrace: PTRACE_SETOPTIONS failed");
while (1) {
if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
@@ -291,7 +216,7 @@ static void __init check_ptrace(void)
break;
}
}
- stop_ptraced_child(pid, 0, 1);
+ stop_ptraced_child(pid, 0);
os_info("OK\n");
check_sysemu();
}
@@ -370,7 +295,7 @@ void __init os_early_checks(void)
pid = start_ptraced_child();
if (init_pid_registers(pid))
fatal("Failed to initialize default registers");
- stop_ptraced_child(pid, 1, 1);
+ stop_ptraced_child(pid, 1);
}
int __init parse_iomem(char *str, int *add)
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
index fc0f2a9dee5a..1dca4ffbd572 100644
--- a/arch/um/os-Linux/util.c
+++ b/arch/um/os-Linux/util.c
@@ -173,23 +173,38 @@ __uml_setup("quiet", quiet_cmd_param,
"quiet\n"
" Turns off information messages during boot.\n\n");
+/*
+ * The os_info/os_warn functions will be called by helper threads. These
+ * have a very limited stack size and using the libc formatting functions
+ * may overflow the stack.
+ * So pull in the kernel vscnprintf and use that instead with a fixed
+ * on-stack buffer.
+ */
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
void os_info(const char *fmt, ...)
{
+ char buf[256];
va_list list;
+ int len;
if (quiet_info)
return;
va_start(list, fmt);
- vfprintf(stderr, fmt, list);
+ len = vscnprintf(buf, sizeof(buf), fmt, list);
+ fwrite(buf, len, 1, stderr);
va_end(list);
}
void os_warn(const char *fmt, ...)
{
+ char buf[256];
va_list list;
+ int len;
va_start(list, fmt);
- vfprintf(stderr, fmt, list);
+ len = vscnprintf(buf, sizeof(buf), fmt, list);
+ fwrite(buf, len, 1, stderr);
va_end(list);
}
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 53f2e7797b1d..5edec175b9bf 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -59,6 +59,7 @@ config X86
#
select ACPI_LEGACY_TABLES_LOOKUP if ACPI
select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
+ select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU
select ARCH_32BIT_OFF_T if X86_32
select ARCH_CLOCKSOURCE_INIT
select ARCH_CORRECT_STACKTRACE_ON_KRETPROBE
@@ -71,6 +72,7 @@ config X86
select ARCH_HAS_CACHE_LINE_SIZE
select ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
select ARCH_HAS_CPU_FINALIZE_INIT
+ select ARCH_HAS_CPU_PASID if IOMMU_SVA
select ARCH_HAS_CURRENT_STACK_POINTER
select ARCH_HAS_DEBUG_VIRTUAL
select ARCH_HAS_DEBUG_VM_PGTABLE if !X86_PAE
@@ -148,6 +150,7 @@ config X86
select GENERIC_CLOCKEVENTS_MIN_ADJUST
select GENERIC_CMOS_UPDATE
select GENERIC_CPU_AUTOPROBE
+ select GENERIC_CPU_DEVICES
select GENERIC_CPU_VULNERABILITIES
select GENERIC_EARLY_IOREMAP
select GENERIC_ENTRY
@@ -1967,6 +1970,11 @@ config INTEL_TDX_HOST
depends on CPU_SUP_INTEL
depends on X86_64
depends on KVM_INTEL
+ depends on X86_X2APIC
+ select ARCH_KEEP_MEMBLOCK
+ depends on CONTIG_ALLOC
+ depends on !KEXEC_CORE
+ depends on X86_MCE
help
Intel Trust Domain Extensions (TDX) protects guest VMs from malicious
host and certain physical attacks. This option enables necessary TDX
diff --git a/arch/x86/coco/tdx/tdx-shared.c b/arch/x86/coco/tdx/tdx-shared.c
index 78e413269791..1655aa56a0a5 100644
--- a/arch/x86/coco/tdx/tdx-shared.c
+++ b/arch/x86/coco/tdx/tdx-shared.c
@@ -22,13 +22,13 @@ static unsigned long try_accept_one(phys_addr_t start, unsigned long len,
*/
switch (pg_level) {
case PG_LEVEL_4K:
- page_size = 0;
+ page_size = TDX_PS_4K;
break;
case PG_LEVEL_2M:
- page_size = 1;
+ page_size = TDX_PS_2M;
break;
case PG_LEVEL_1G:
- page_size = 2;
+ page_size = TDX_PS_1G;
break;
default:
return 0;
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index fecc4fe1d68a..f8f9a9b79395 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -23,10 +23,6 @@ static inline void prefill_possible_map(void) {}
#endif /* CONFIG_SMP */
-struct x86_cpu {
- struct cpu cpu;
-};
-
#ifdef CONFIG_HOTPLUG_CPU
extern void soft_restart_cpu(void);
#endif
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 632c26cdeeda..29cb275a219d 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -198,6 +198,7 @@
#define X86_FEATURE_CAT_L3 ( 7*32+ 4) /* Cache Allocation Technology L3 */
#define X86_FEATURE_CAT_L2 ( 7*32+ 5) /* Cache Allocation Technology L2 */
#define X86_FEATURE_CDP_L3 ( 7*32+ 6) /* Code and Data Prioritization L3 */
+#define X86_FEATURE_TDX_HOST_PLATFORM ( 7*32+ 7) /* Platform supports being a TDX host */
#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */
#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
#define X86_FEATURE_XCOMPACTED ( 7*32+10) /* "" Use compacted XSTATE (XSAVES or XSAVEC) */
@@ -499,6 +500,7 @@
#define X86_BUG_EIBRS_PBRSB X86_BUG(28) /* EIBRS is vulnerable to Post Barrier RSB Predictions */
#define X86_BUG_SMT_RSB X86_BUG(29) /* CPU is vulnerable to Cross-Thread Return Address Predictions */
#define X86_BUG_GDS X86_BUG(30) /* CPU is affected by Gather Data Sampling */
+#define X86_BUG_TDX_PW_MCE X86_BUG(31) /* CPU may incur #MC if non-TD software does partial write to TDX private memory */
/* BUG word 2 */
#define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */
diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h
index 26b628d84594..378ed944b849 100644
--- a/arch/x86/include/asm/kvm-x86-ops.h
+++ b/arch/x86/include/asm/kvm-x86-ops.h
@@ -55,8 +55,10 @@ KVM_X86_OP(set_rflags)
KVM_X86_OP(get_if_flag)
KVM_X86_OP(flush_tlb_all)
KVM_X86_OP(flush_tlb_current)
+#if IS_ENABLED(CONFIG_HYPERV)
KVM_X86_OP_OPTIONAL(flush_remote_tlbs)
KVM_X86_OP_OPTIONAL(flush_remote_tlbs_range)
+#endif
KVM_X86_OP(flush_tlb_gva)
KVM_X86_OP(flush_tlb_guest)
KVM_X86_OP(vcpu_pre_run)
@@ -135,6 +137,7 @@ KVM_X86_OP(msr_filter_changed)
KVM_X86_OP(complete_emulated_msr)
KVM_X86_OP(vcpu_deliver_sipi_vector)
KVM_X86_OP_OPTIONAL_RET0(vcpu_get_apicv_inhibit_reasons);
+KVM_X86_OP_OPTIONAL(get_untagged_addr)
#undef KVM_X86_OP
#undef KVM_X86_OP_OPTIONAL
diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h
index 6c98f4bb4228..058bc636356a 100644
--- a/arch/x86/include/asm/kvm-x86-pmu-ops.h
+++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h
@@ -22,7 +22,7 @@ KVM_X86_PMU_OP(get_msr)
KVM_X86_PMU_OP(set_msr)
KVM_X86_PMU_OP(refresh)
KVM_X86_PMU_OP(init)
-KVM_X86_PMU_OP(reset)
+KVM_X86_PMU_OP_OPTIONAL(reset)
KVM_X86_PMU_OP_OPTIONAL(deliver_pmi)
KVM_X86_PMU_OP_OPTIONAL(cleanup)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 6711da000bb7..b5b2d0fde579 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -133,7 +133,8 @@
| X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_PCIDE \
| X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_FSGSBASE \
| X86_CR4_OSXMMEXCPT | X86_CR4_LA57 | X86_CR4_VMXE \
- | X86_CR4_SMAP | X86_CR4_PKE | X86_CR4_UMIP))
+ | X86_CR4_SMAP | X86_CR4_PKE | X86_CR4_UMIP \
+ | X86_CR4_LAM_SUP))
#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR)
@@ -500,8 +501,23 @@ struct kvm_pmc {
u8 idx;
bool is_paused;
bool intr;
+ /*
+ * Base value of the PMC counter, relative to the *consumed* count in
+ * the associated perf_event. This value includes counter updates from
+ * the perf_event and emulated_count since the last time the counter
+ * was reprogrammed, but it is *not* the current value as seen by the
+ * guest or userspace.
+ *
+ * The count is relative to the associated perf_event so that KVM
+ * doesn't need to reprogram the perf_event every time the guest writes
+ * to the counter.
+ */
u64 counter;
- u64 prev_counter;
+ /*
+ * PMC events triggered by KVM emulation that haven't been fully
+ * processed, i.e. haven't undergone overflow detection.
+ */
+ u64 emulated_counter;
u64 eventsel;
struct perf_event *perf_event;
struct kvm_vcpu *vcpu;
@@ -937,8 +953,10 @@ struct kvm_vcpu_arch {
/* used for guest single stepping over the given code position */
unsigned long singlestep_rip;
+#ifdef CONFIG_KVM_HYPERV
bool hyperv_enabled;
struct kvm_vcpu_hv *hyperv;
+#endif
#ifdef CONFIG_KVM_XEN
struct kvm_vcpu_xen xen;
#endif
@@ -1095,6 +1113,7 @@ enum hv_tsc_page_status {
HV_TSC_PAGE_BROKEN,
};
+#ifdef CONFIG_KVM_HYPERV
/* Hyper-V emulation context */
struct kvm_hv {
struct mutex hv_lock;
@@ -1125,9 +1144,9 @@ struct kvm_hv {
*/
unsigned int synic_auto_eoi_used;
- struct hv_partition_assist_pg *hv_pa_pg;
struct kvm_hv_syndbg hv_syndbg;
};
+#endif
struct msr_bitmap_range {
u32 flags;
@@ -1136,6 +1155,7 @@ struct msr_bitmap_range {
unsigned long *bitmap;
};
+#ifdef CONFIG_KVM_XEN
/* Xen emulation context */
struct kvm_xen {
struct mutex xen_lock;
@@ -1147,6 +1167,7 @@ struct kvm_xen {
struct idr evtchn_ports;
unsigned long poll_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)];
};
+#endif
enum kvm_irqchip_mode {
KVM_IRQCHIP_NONE,
@@ -1255,6 +1276,7 @@ enum kvm_apicv_inhibit {
};
struct kvm_arch {
+ unsigned long vm_type;
unsigned long n_used_mmu_pages;
unsigned long n_requested_mmu_pages;
unsigned long n_max_mmu_pages;
@@ -1347,8 +1369,13 @@ struct kvm_arch {
/* reads protected by irq_srcu, writes by irq_lock */
struct hlist_head mask_notifier_list;
+#ifdef CONFIG_KVM_HYPERV
struct kvm_hv hyperv;
+#endif
+
+#ifdef CONFIG_KVM_XEN
struct kvm_xen xen;
+#endif
bool backwards_tsc_observed;
bool boot_vcpu_runs_old_kvmclock;
@@ -1406,9 +1433,8 @@ struct kvm_arch {
* the MMU lock in read mode + RCU or
* the MMU lock in write mode
*
- * For writes, this list is protected by:
- * the MMU lock in read mode + the tdp_mmu_pages_lock or
- * the MMU lock in write mode
+ * For writes, this list is protected by tdp_mmu_pages_lock; see
+ * below for the details.
*
* Roots will remain in the list until their tdp_mmu_root_count
* drops to zero, at which point the thread that decremented the
@@ -1425,8 +1451,10 @@ struct kvm_arch {
* - possible_nx_huge_pages;
* - the possible_nx_huge_page_link field of kvm_mmu_page structs used
* by the TDP MMU
- * It is acceptable, but not necessary, to acquire this lock when
- * the thread holds the MMU lock in write mode.
+ * Because the lock is only taken within the MMU lock, strictly
+ * speaking it is redundant to acquire this lock when the thread
+ * holds the MMU lock in write mode. However it often simplifies
+ * the code to do so.
*/
spinlock_t tdp_mmu_pages_lock;
#endif /* CONFIG_X86_64 */
@@ -1441,6 +1469,7 @@ struct kvm_arch {
#if IS_ENABLED(CONFIG_HYPERV)
hpa_t hv_root_tdp;
spinlock_t hv_root_tdp_lock;
+ struct hv_partition_assist_pg *hv_pa_pg;
#endif
/*
* VM-scope maximum vCPU ID. Used to determine the size of structures
@@ -1613,9 +1642,11 @@ struct kvm_x86_ops {
void (*flush_tlb_all)(struct kvm_vcpu *vcpu);
void (*flush_tlb_current)(struct kvm_vcpu *vcpu);
+#if IS_ENABLED(CONFIG_HYPERV)
int (*flush_remote_tlbs)(struct kvm *kvm);
int (*flush_remote_tlbs_range)(struct kvm *kvm, gfn_t gfn,
gfn_t nr_pages);
+#endif
/*
* Flush any TLB entries associated with the given GVA.
@@ -1761,6 +1792,8 @@ struct kvm_x86_ops {
* Returns vCPU specific APICv inhibit reasons
*/
unsigned long (*vcpu_get_apicv_inhibit_reasons)(struct kvm_vcpu *vcpu);
+
+ gva_t (*get_untagged_addr)(struct kvm_vcpu *vcpu, gva_t gva, unsigned int flags);
};
struct kvm_x86_nested_ops {
@@ -1824,6 +1857,7 @@ static inline struct kvm *kvm_arch_alloc_vm(void)
#define __KVM_HAVE_ARCH_VM_FREE
void kvm_arch_free_vm(struct kvm *kvm);
+#if IS_ENABLED(CONFIG_HYPERV)
#define __KVM_HAVE_ARCH_FLUSH_REMOTE_TLBS
static inline int kvm_arch_flush_remote_tlbs(struct kvm *kvm)
{
@@ -1835,6 +1869,15 @@ static inline int kvm_arch_flush_remote_tlbs(struct kvm *kvm)
}
#define __KVM_HAVE_ARCH_FLUSH_REMOTE_TLBS_RANGE
+static inline int kvm_arch_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn,
+ u64 nr_pages)
+{
+ if (!kvm_x86_ops.flush_remote_tlbs_range)
+ return -EOPNOTSUPP;
+
+ return static_call(kvm_x86_flush_remote_tlbs_range)(kvm, gfn, nr_pages);
+}
+#endif /* CONFIG_HYPERV */
#define kvm_arch_pmi_in_guest(vcpu) \
((vcpu) && (vcpu)->arch.handling_intr_from_guest)
@@ -1848,6 +1891,9 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu);
void kvm_mmu_init_vm(struct kvm *kvm);
void kvm_mmu_uninit_vm(struct kvm *kvm);
+void kvm_mmu_init_memslot_memory_attributes(struct kvm *kvm,
+ struct kvm_memory_slot *slot);
+
void kvm_mmu_after_set_cpuid(struct kvm_vcpu *vcpu);
void kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
@@ -2086,6 +2132,12 @@ void kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd);
void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level,
int tdp_max_root_level, int tdp_huge_page_level);
+#ifdef CONFIG_KVM_PRIVATE_MEM
+#define kvm_arch_has_private_mem(kvm) ((kvm)->arch.vm_type != KVM_X86_DEFAULT_VM)
+#else
+#define kvm_arch_has_private_mem(kvm) false
+#endif
+
static inline u16 kvm_read_ldt(void)
{
u16 ldt;
@@ -2133,16 +2185,15 @@ enum {
#define HF_SMM_MASK (1 << 1)
#define HF_SMM_INSIDE_NMI_MASK (1 << 2)
-# define __KVM_VCPU_MULTIPLE_ADDRESS_SPACE
-# define KVM_ADDRESS_SPACE_NUM 2
+# define KVM_MAX_NR_ADDRESS_SPACES 2
+/* SMM is currently unsupported for guests with private memory. */
+# define kvm_arch_nr_memslot_as_ids(kvm) (kvm_arch_has_private_mem(kvm) ? 1 : 2)
# define kvm_arch_vcpu_memslots_id(vcpu) ((vcpu)->arch.hflags & HF_SMM_MASK ? 1 : 0)
# define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, (role).smm)
#else
# define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, 0)
#endif
-#define KVM_ARCH_WANT_MMU_NOTIFIER
-
int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v);
int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
int kvm_cpu_has_extint(struct kvm_vcpu *v);
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 737a52b89e64..f1bd7b91b3c6 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -541,6 +541,9 @@
#define MSR_RELOAD_PMC0 0x000014c1
#define MSR_RELOAD_FIXED_CTR0 0x00001309
+/* KeyID partitioning between MKTME and TDX */
+#define MSR_IA32_MKTME_KEYID_PARTITIONING 0x00000087
+
/*
* AMD64 MSRs. Not complete. See the architecture manual for a more
* complete list.
diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h
index ccce7ebd8677..fdfd41511b02 100644
--- a/arch/x86/include/asm/shared/tdx.h
+++ b/arch/x86/include/asm/shared/tdx.h
@@ -55,6 +55,12 @@
(TDX_RDX | TDX_RBX | TDX_RSI | TDX_RDI | TDX_R8 | TDX_R9 | \
TDX_R10 | TDX_R11 | TDX_R12 | TDX_R13 | TDX_R14 | TDX_R15)
+/* TDX supported page sizes from the TDX module ABI. */
+#define TDX_PS_4K 0
+#define TDX_PS_2M 1
+#define TDX_PS_1G 2
+#define TDX_PS_NR (TDX_PS_1G + 1)
+
#ifndef __ASSEMBLY__
#include <linux/compiler_attributes.h>
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index f3d5305a60fc..eba178996d84 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -24,8 +24,16 @@
#define TDX_SEAMCALL_GP (TDX_SW_ERROR | X86_TRAP_GP)
#define TDX_SEAMCALL_UD (TDX_SW_ERROR | X86_TRAP_UD)
+/*
+ * TDX module SEAMCALL leaf function error codes
+ */
+#define TDX_SUCCESS 0ULL
+#define TDX_RND_NO_ENTROPY 0x8000020300000000ULL
+
#ifndef __ASSEMBLY__
+#include <uapi/asm/mce.h>
+
/*
* Used by the #VE exception handler to gather the #VE exception
* info from the TDX module. This is a software only structure
@@ -83,6 +91,36 @@ static inline long tdx_kvm_hypercall(unsigned int nr, unsigned long p1,
u64 __seamcall(u64 fn, struct tdx_module_args *args);
u64 __seamcall_ret(u64 fn, struct tdx_module_args *args);
u64 __seamcall_saved_ret(u64 fn, struct tdx_module_args *args);
+void tdx_init(void);
+
+#include <asm/archrandom.h>
+
+typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args);
+
+static inline u64 sc_retry(sc_func_t func, u64 fn,
+ struct tdx_module_args *args)
+{
+ int retry = RDRAND_RETRY_LOOPS;
+ u64 ret;
+
+ do {
+ ret = func(fn, args);
+ } while (ret == TDX_RND_NO_ENTROPY && --retry);
+
+ return ret;
+}
+
+#define seamcall(_fn, _args) sc_retry(__seamcall, (_fn), (_args))
+#define seamcall_ret(_fn, _args) sc_retry(__seamcall_ret, (_fn), (_args))
+#define seamcall_saved_ret(_fn, _args) sc_retry(__seamcall_saved_ret, (_fn), (_args))
+int tdx_cpu_enable(void);
+int tdx_enable(void);
+const char *tdx_dump_mce_info(struct mce *m);
+#else
+static inline void tdx_init(void) { }
+static inline int tdx_cpu_enable(void) { return -ENODEV; }
+static inline int tdx_enable(void) { return -ENODEV; }
+static inline const char *tdx_dump_mce_info(struct mce *m) { return NULL; }
#endif /* CONFIG_INTEL_TDX_HOST */
#endif /* !__ASSEMBLY__ */
diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
index 1a6a1f987949..a448d0964fc0 100644
--- a/arch/x86/include/uapi/asm/kvm.h
+++ b/arch/x86/include/uapi/asm/kvm.h
@@ -562,4 +562,7 @@ struct kvm_pmu_event_filter {
/* x86-specific KVM_EXIT_HYPERCALL flags. */
#define KVM_EXIT_HYPERCALL_LONG_MODE BIT(0)
+#define KVM_X86_DEFAULT_VM 0
+#define KVM_X86_SW_PROTECTED_VM 1
+
#endif /* _ASM_X86_KVM_H */
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c
index 4feaa670d578..89c0c8a3fc7e 100644
--- a/arch/x86/kernel/aperture_64.c
+++ b/arch/x86/kernel/aperture_64.c
@@ -259,10 +259,9 @@ static u32 __init search_agp_bridge(u32 *order, int *valid_agp)
order);
}
- /* No multi-function device? */
type = read_pci_config_byte(bus, slot, func,
PCI_HEADER_TYPE);
- if (!(type & 0x80))
+ if (!(type & PCI_HEADER_TYPE_MFD))
break;
}
}
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 94bff381ef20..0b97bcde70c6 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -66,6 +66,7 @@
#include <asm/set_memory.h>
#include <asm/traps.h>
#include <asm/sev.h>
+#include <asm/tdx.h>
#include "cpu.h"
@@ -1986,6 +1987,7 @@ static __init void identify_boot_cpu(void)
setup_cr_pinning();
tsx_init();
+ tdx_init();
lkgs_init();
}
diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c
index fd5ce12c4f9a..bc39252bc54f 100644
--- a/arch/x86/kernel/cpu/mce/core.c
+++ b/arch/x86/kernel/cpu/mce/core.c
@@ -53,6 +53,7 @@
#include <asm/mce.h>
#include <asm/msr.h>
#include <asm/reboot.h>
+#include <asm/tdx.h>
#include "internal.h"
@@ -229,12 +230,20 @@ static void wait_for_panic(void)
panic("Panicing machine check CPU died");
}
+static const char *mce_dump_aux_info(struct mce *m)
+{
+ if (boot_cpu_has_bug(X86_BUG_TDX_PW_MCE))
+ return tdx_dump_mce_info(m);
+
+ return NULL;
+}
+
static noinstr void mce_panic(const char *msg, struct mce *final, char *exp)
{
struct llist_node *pending;
struct mce_evt_llist *l;
int apei_err = 0;
- struct page *p;
+ const char *memmsg;
/*
* Allow instrumentation around external facilities usage. Not that it
@@ -285,6 +294,11 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp)
}
if (exp)
pr_emerg(HW_ERR "Machine check: %s\n", exp);
+
+ memmsg = mce_dump_aux_info(final);
+ if (memmsg)
+ pr_emerg(HW_ERR "Machine check: %s\n", memmsg);
+
if (!fake_panic) {
if (panic_timeout == 0)
panic_timeout = mca_cfg.panic_timeout;
@@ -297,6 +311,7 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp)
*/
if (kexec_crash_loaded()) {
if (final && (final->status & MCI_STATUS_ADDRV)) {
+ struct page *p;
p = pfn_to_online_page(final->addr >> PAGE_SHIFT);
if (p)
SetPageHWPoison(p);
diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c
index a6c1867fc7aa..59f4aefc6bc1 100644
--- a/arch/x86/kernel/early-quirks.c
+++ b/arch/x86/kernel/early-quirks.c
@@ -779,13 +779,13 @@ static int __init check_dev_quirk(int num, int slot, int func)
type = read_pci_config_byte(num, slot, func,
PCI_HEADER_TYPE);
- if ((type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
+ if ((type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) {
sec = read_pci_config_byte(num, slot, func, PCI_SECONDARY_BUS);
if (sec > num)
early_pci_scan_bus(sec);
}
- if (!(type & 0x80))
+ if (!(type & PCI_HEADER_TYPE_MFD))
return -1;
return 0;
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index a95d0900e8c6..5bb395551c44 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -24,8 +24,8 @@
static int kvmclock __initdata = 1;
static int kvmclock_vsyscall __initdata = 1;
-static int msr_kvm_system_time __ro_after_init = MSR_KVM_SYSTEM_TIME;
-static int msr_kvm_wall_clock __ro_after_init = MSR_KVM_WALL_CLOCK;
+static int msr_kvm_system_time __ro_after_init;
+static int msr_kvm_wall_clock __ro_after_init;
static u64 kvm_sched_clock_offset __ro_after_init;
static int __init parse_no_kvmclock(char *arg)
@@ -195,7 +195,8 @@ static void kvm_setup_secondary_clock(void)
void kvmclock_disable(void)
{
- native_write_msr(msr_kvm_system_time, 0, 0);
+ if (msr_kvm_system_time)
+ native_write_msr(msr_kvm_system_time, 0, 0);
}
static void __init kvmclock_init_mem(void)
@@ -294,7 +295,10 @@ void __init kvmclock_init(void)
if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE2)) {
msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW;
msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW;
- } else if (!kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) {
+ } else if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) {
+ msr_kvm_system_time = MSR_KVM_SYSTEM_TIME;
+ msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK;
+ } else {
return;
}
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index ec2c21a1844e..84201071dfac 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1031,6 +1031,8 @@ void __init setup_arch(char **cmdline_p)
*
* Moreover, on machines with SandyBridge graphics or in setups that use
* crashkernel the entire 1M is reserved anyway.
+ *
+ * Note the host kernel TDX also requires the first 1MB being reserved.
*/
x86_platform.realmode_reserve();
diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c
index 0bab03130033..d42c28b8bfd8 100644
--- a/arch/x86/kernel/topology.c
+++ b/arch/x86/kernel/topology.c
@@ -35,38 +35,9 @@
#include <asm/io_apic.h>
#include <asm/cpu.h>
-static DEFINE_PER_CPU(struct x86_cpu, cpu_devices);
-
#ifdef CONFIG_HOTPLUG_CPU
-int arch_register_cpu(int cpu)
+bool arch_cpu_is_hotpluggable(int cpu)
{
- struct x86_cpu *xc = per_cpu_ptr(&cpu_devices, cpu);
-
- xc->cpu.hotpluggable = cpu > 0;
- return register_cpu(&xc->cpu, cpu);
-}
-EXPORT_SYMBOL(arch_register_cpu);
-
-void arch_unregister_cpu(int num)
-{
- unregister_cpu(&per_cpu(cpu_devices, num).cpu);
-}
-EXPORT_SYMBOL(arch_unregister_cpu);
-#else /* CONFIG_HOTPLUG_CPU */
-
-int __init arch_register_cpu(int num)
-{
- return register_cpu(&per_cpu(cpu_devices, num).cpu, num);
+ return cpu > 0;
}
#endif /* CONFIG_HOTPLUG_CPU */
-
-static int __init topology_init(void)
-{
- int i;
-
- for_each_present_cpu(i)
- arch_register_cpu(i);
-
- return 0;
-}
-subsys_initcall(topology_init);
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index b0737a15c470..c3b2f863acf0 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -566,7 +566,7 @@ static bool fixup_iopl_exception(struct pt_regs *regs)
*/
static bool try_fixup_enqcmd_gp(void)
{
-#ifdef CONFIG_IOMMU_SVA
+#ifdef CONFIG_ARCH_HAS_CPU_PASID
u32 pasid;
/*
@@ -592,7 +592,7 @@ static bool try_fixup_enqcmd_gp(void)
if (!mm_valid_pasid(current->mm))
return false;
- pasid = current->mm->pasid;
+ pasid = mm_get_enqcmd_pasid(current->mm);
/*
* Did this thread already have its PASID activated?
diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index 950c12868d30..87e3da7b0439 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -23,17 +23,15 @@ config KVM
depends on HAVE_KVM
depends on HIGH_RES_TIMERS
depends on X86_LOCAL_APIC
- select PREEMPT_NOTIFIERS
- select MMU_NOTIFIER
+ select KVM_COMMON
+ select KVM_GENERIC_MMU_NOTIFIER
select HAVE_KVM_IRQCHIP
select HAVE_KVM_PFNCACHE
- select HAVE_KVM_IRQFD
select HAVE_KVM_DIRTY_RING_TSO
select HAVE_KVM_DIRTY_RING_ACQ_REL
select IRQ_BYPASS_MANAGER
select HAVE_KVM_IRQ_BYPASS
select HAVE_KVM_IRQ_ROUTING
- select HAVE_KVM_EVENTFD
select KVM_ASYNC_PF
select USER_RETURN_NOTIFIER
select KVM_MMIO
@@ -46,7 +44,6 @@ config KVM
select KVM_XFER_TO_GUEST_WORK
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
select KVM_VFIO
- select INTERVAL_TREE
select HAVE_KVM_PM_NOTIFIER if PM
select KVM_GENERIC_HARDWARE_ENABLING
help
@@ -65,18 +62,30 @@ config KVM
config KVM_WERROR
bool "Compile KVM with -Werror"
- # KASAN may cause the build to fail due to larger frames
- default y if X86_64 && !KASAN
- # We use the dependency on !COMPILE_TEST to not be enabled
- # blindly in allmodconfig or allyesconfig configurations
- depends on KVM
- depends on (X86_64 && !KASAN) || !COMPILE_TEST
- depends on EXPERT
+ # Disallow KVM's -Werror if KASAN is enabled, e.g. to guard against
+ # randomized configs from selecting KVM_WERROR=y, which doesn't play
+ # nice with KASAN. KASAN builds generates warnings for the default
+ # FRAME_WARN, i.e. KVM_WERROR=y with KASAN=y requires special tuning.
+ # Building KVM with -Werror and KASAN is still doable via enabling
+ # the kernel-wide WERROR=y.
+ depends on KVM && EXPERT && !KASAN
help
Add -Werror to the build flags for KVM.
If in doubt, say "N".
+config KVM_SW_PROTECTED_VM
+ bool "Enable support for KVM software-protected VMs"
+ depends on EXPERT
+ depends on KVM && X86_64
+ select KVM_GENERIC_PRIVATE_MEM
+ help
+ Enable support for KVM software-protected VMs. Currently "protected"
+ means the VM can be backed with memory provided by
+ KVM_CREATE_GUEST_MEMFD.
+
+ If unsure, say "N".
+
config KVM_INTEL
tristate "KVM for Intel (and compatible) processors support"
depends on KVM && IA32_FEAT_CTL
@@ -129,6 +138,20 @@ config KVM_SMM
If unsure, say Y.
+config KVM_HYPERV
+ bool "Support for Microsoft Hyper-V emulation"
+ depends on KVM
+ default y
+ help
+ Provides KVM support for emulating Microsoft Hyper-V. This allows KVM
+ to expose a subset of the paravirtualized interfaces defined in the
+ Hyper-V Hypervisor Top-Level Functional Specification (TLFS):
+ https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs
+ These interfaces are required for the correct and performant functioning
+ of Windows and Hyper-V guests on KVM.
+
+ If unsure, say "Y".
+
config KVM_XEN
bool "Support for Xen hypercall interface"
depends on KVM
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index 80e3fe184d17..475b5fa917a6 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -11,25 +11,27 @@ include $(srctree)/virt/kvm/Makefile.kvm
kvm-y += x86.o emulate.o i8259.o irq.o lapic.o \
i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \
- hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o \
+ debugfs.o mmu/mmu.o mmu/page_track.o \
mmu/spte.o
-ifdef CONFIG_HYPERV
-kvm-y += kvm_onhyperv.o
-endif
-
kvm-$(CONFIG_X86_64) += mmu/tdp_iter.o mmu/tdp_mmu.o
+kvm-$(CONFIG_KVM_HYPERV) += hyperv.o
kvm-$(CONFIG_KVM_XEN) += xen.o
kvm-$(CONFIG_KVM_SMM) += smm.o
kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \
- vmx/hyperv.o vmx/nested.o vmx/posted_intr.o
+ vmx/nested.o vmx/posted_intr.o
+
kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o
+kvm-intel-$(CONFIG_KVM_HYPERV) += vmx/hyperv.o vmx/hyperv_evmcs.o
kvm-amd-y += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o \
- svm/sev.o svm/hyperv.o
+ svm/sev.o
+kvm-amd-$(CONFIG_KVM_HYPERV) += svm/hyperv.o
ifdef CONFIG_HYPERV
+kvm-y += kvm_onhyperv.o
+kvm-intel-y += vmx/vmx_onhyperv.o vmx/hyperv_evmcs.o
kvm-amd-y += svm/svm_onhyperv.o
endif
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 42d3f47f4c07..adba49afb5fe 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -314,11 +314,15 @@ EXPORT_SYMBOL_GPL(kvm_update_cpuid_runtime);
static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent)
{
+#ifdef CONFIG_KVM_HYPERV
struct kvm_cpuid_entry2 *entry;
entry = cpuid_entry2_find(entries, nent, HYPERV_CPUID_INTERFACE,
KVM_CPUID_INDEX_NOT_SIGNIFICANT);
return entry && entry->eax == HYPERV_CPUID_SIGNATURE_EAX;
+#else
+ return false;
+#endif
}
static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
@@ -433,11 +437,13 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
return 0;
}
+#ifdef CONFIG_KVM_HYPERV
if (kvm_cpuid_has_hyperv(e2, nent)) {
r = kvm_hv_vcpu_init(vcpu);
if (r)
return r;
}
+#endif
r = kvm_check_cpuid(vcpu, e2, nent);
if (r)
@@ -469,7 +475,7 @@ int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
return -E2BIG;
if (cpuid->nent) {
- e = vmemdup_user(entries, array_size(sizeof(*e), cpuid->nent));
+ e = vmemdup_array_user(entries, cpuid->nent, sizeof(*e));
if (IS_ERR(e))
return PTR_ERR(e);
@@ -513,7 +519,7 @@ int kvm_vcpu_ioctl_set_cpuid2(struct kvm_vcpu *vcpu,
return -E2BIG;
if (cpuid->nent) {
- e2 = vmemdup_user(entries, array_size(sizeof(*e2), cpuid->nent));
+ e2 = vmemdup_array_user(entries, cpuid->nent, sizeof(*e2));
if (IS_ERR(e2))
return PTR_ERR(e2);
}
@@ -671,7 +677,7 @@ void kvm_set_cpu_caps(void)
kvm_cpu_cap_mask(CPUID_7_1_EAX,
F(AVX_VNNI) | F(AVX512_BF16) | F(CMPCCXADD) |
F(FZRM) | F(FSRS) | F(FSRC) |
- F(AMX_FP16) | F(AVX_IFMA)
+ F(AMX_FP16) | F(AVX_IFMA) | F(LAM)
);
kvm_cpu_cap_init_kvm_defined(CPUID_7_1_EDX,
@@ -679,6 +685,11 @@ void kvm_set_cpu_caps(void)
F(AMX_COMPLEX)
);
+ kvm_cpu_cap_init_kvm_defined(CPUID_7_2_EDX,
+ F(INTEL_PSFD) | F(IPRED_CTRL) | F(RRSBA_CTRL) | F(DDPD_U) |
+ F(BHI_CTRL) | F(MCDT_NO)
+ );
+
kvm_cpu_cap_mask(CPUID_D_1_EAX,
F(XSAVEOPT) | F(XSAVEC) | F(XGETBV1) | F(XSAVES) | f_xfd
);
@@ -960,13 +971,13 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
break;
/* function 7 has additional index. */
case 7:
- entry->eax = min(entry->eax, 1u);
+ max_idx = entry->eax = min(entry->eax, 2u);
cpuid_entry_override(entry, CPUID_7_0_EBX);
cpuid_entry_override(entry, CPUID_7_ECX);
cpuid_entry_override(entry, CPUID_7_EDX);
- /* KVM only supports 0x7.0 and 0x7.1, capped above via min(). */
- if (entry->eax == 1) {
+ /* KVM only supports up to 0x7.2, capped above via min(). */
+ if (max_idx >= 1) {
entry = do_host_cpuid(array, function, 1);
if (!entry)
goto out;
@@ -976,6 +987,16 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
entry->ebx = 0;
entry->ecx = 0;
}
+ if (max_idx >= 2) {
+ entry = do_host_cpuid(array, function, 2);
+ if (!entry)
+ goto out;
+
+ cpuid_entry_override(entry, CPUID_7_2_EDX);
+ entry->ecx = 0;
+ entry->ebx = 0;
+ entry->eax = 0;
+ }
break;
case 0xa: { /* Architectural Performance Monitoring */
union cpuid10_eax eax;
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index 0b90532b6e26..856e3037e74f 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -47,11 +47,6 @@ static inline bool kvm_vcpu_is_legal_gpa(struct kvm_vcpu *vcpu, gpa_t gpa)
return !(gpa & vcpu->arch.reserved_gpa_bits);
}
-static inline bool kvm_vcpu_is_illegal_gpa(struct kvm_vcpu *vcpu, gpa_t gpa)
-{
- return !kvm_vcpu_is_legal_gpa(vcpu, gpa);
-}
-
static inline bool kvm_vcpu_is_legal_aligned_gpa(struct kvm_vcpu *vcpu,
gpa_t gpa, gpa_t alignment)
{
@@ -279,4 +274,12 @@ static __always_inline bool guest_can_use(struct kvm_vcpu *vcpu,
vcpu->arch.governed_features.enabled);
}
+static inline bool kvm_vcpu_is_legal_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
+{
+ if (guest_can_use(vcpu, X86_FEATURE_LAM))
+ cr3 &= ~(X86_CR3_LAM_U48 | X86_CR3_LAM_U57);
+
+ return kvm_vcpu_is_legal_gpa(vcpu, cr3);
+}
+
#endif
diff --git a/arch/x86/kvm/debugfs.c b/arch/x86/kvm/debugfs.c
index eea6ea7f14af..95ea1a1f7403 100644
--- a/arch/x86/kvm/debugfs.c
+++ b/arch/x86/kvm/debugfs.c
@@ -111,7 +111,7 @@ static int kvm_mmu_rmaps_stat_show(struct seq_file *m, void *v)
mutex_lock(&kvm->slots_lock);
write_lock(&kvm->mmu_lock);
- for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+ for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
int bkt;
slots = __kvm_memslots(kvm, i);
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 2673cd5c46cb..e223043ef5b2 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -687,8 +687,8 @@ static unsigned insn_alignment(struct x86_emulate_ctxt *ctxt, unsigned size)
static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt,
struct segmented_address addr,
unsigned *max_size, unsigned size,
- bool write, bool fetch,
- enum x86emul_mode mode, ulong *linear)
+ enum x86emul_mode mode, ulong *linear,
+ unsigned int flags)
{
struct desc_struct desc;
bool usable;
@@ -701,7 +701,7 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt,
*max_size = 0;
switch (mode) {
case X86EMUL_MODE_PROT64:
- *linear = la;
+ *linear = la = ctxt->ops->get_untagged_addr(ctxt, la, flags);
va_bits = ctxt_virt_addr_bits(ctxt);
if (!__is_canonical_address(la, va_bits))
goto bad;
@@ -717,11 +717,11 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt,
if (!usable)
goto bad;
/* code segment in protected mode or read-only data segment */
- if ((((ctxt->mode != X86EMUL_MODE_REAL) && (desc.type & 8))
- || !(desc.type & 2)) && write)
+ if ((((ctxt->mode != X86EMUL_MODE_REAL) && (desc.type & 8)) || !(desc.type & 2)) &&
+ (flags & X86EMUL_F_WRITE))
goto bad;
/* unreadable code segment */
- if (!fetch && (desc.type & 8) && !(desc.type & 2))
+ if (!(flags & X86EMUL_F_FETCH) && (desc.type & 8) && !(desc.type & 2))
goto bad;
lim = desc_limit_scaled(&desc);
if (!(desc.type & 8) && (desc.type & 4)) {
@@ -757,8 +757,8 @@ static int linearize(struct x86_emulate_ctxt *ctxt,
ulong *linear)
{
unsigned max_size;
- return __linearize(ctxt, addr, &max_size, size, write, false,
- ctxt->mode, linear);
+ return __linearize(ctxt, addr, &max_size, size, ctxt->mode, linear,
+ write ? X86EMUL_F_WRITE : 0);
}
static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst)
@@ -771,7 +771,8 @@ static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst)
if (ctxt->op_bytes != sizeof(unsigned long))
addr.ea = dst & ((1UL << (ctxt->op_bytes << 3)) - 1);
- rc = __linearize(ctxt, addr, &max_size, 1, false, true, ctxt->mode, &linear);
+ rc = __linearize(ctxt, addr, &max_size, 1, ctxt->mode, &linear,
+ X86EMUL_F_FETCH);
if (rc == X86EMUL_CONTINUE)
ctxt->_eip = addr.ea;
return rc;
@@ -907,8 +908,8 @@ static int __do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size)
* boundary check itself. Instead, we use max_size to check
* against op_size.
*/
- rc = __linearize(ctxt, addr, &max_size, 0, false, true, ctxt->mode,
- &linear);
+ rc = __linearize(ctxt, addr, &max_size, 0, ctxt->mode, &linear,
+ X86EMUL_F_FETCH);
if (unlikely(rc != X86EMUL_CONTINUE))
return rc;
@@ -3439,8 +3440,10 @@ static int em_invlpg(struct x86_emulate_ctxt *ctxt)
{
int rc;
ulong linear;
+ unsigned int max_size;
- rc = linearize(ctxt, ctxt->src.addr.mem, 1, false, &linear);
+ rc = __linearize(ctxt, ctxt->src.addr.mem, &max_size, 1, ctxt->mode,
+ &linear, X86EMUL_F_INVLPG);
if (rc == X86EMUL_CONTINUE)
ctxt->ops->invlpg(ctxt, linear);
/* Disable writeback. */
diff --git a/arch/x86/kvm/governed_features.h b/arch/x86/kvm/governed_features.h
index 423a73395c10..ad463b1ed4e4 100644
--- a/arch/x86/kvm/governed_features.h
+++ b/arch/x86/kvm/governed_features.h
@@ -16,6 +16,7 @@ KVM_GOVERNED_X86_FEATURE(PAUSEFILTER)
KVM_GOVERNED_X86_FEATURE(PFTHRESHOLD)
KVM_GOVERNED_X86_FEATURE(VGIF)
KVM_GOVERNED_X86_FEATURE(VNMI)
+KVM_GOVERNED_X86_FEATURE(LAM)
#undef KVM_GOVERNED_X86_FEATURE
#undef KVM_GOVERNED_FEATURE
diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
index f83b8db72b11..1dc0b6604526 100644
--- a/arch/x86/kvm/hyperv.h
+++ b/arch/x86/kvm/hyperv.h
@@ -24,6 +24,8 @@
#include <linux/kvm_host.h>
#include "x86.h"
+#ifdef CONFIG_KVM_HYPERV
+
/* "Hv#1" signature */
#define HYPERV_CPUID_SIGNATURE_EAX 0x31237648
@@ -105,6 +107,17 @@ int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint);
void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector);
int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages);
+static inline bool kvm_hv_synic_has_vector(struct kvm_vcpu *vcpu, int vector)
+{
+ return to_hv_vcpu(vcpu) && test_bit(vector, to_hv_synic(vcpu)->vec_bitmap);
+}
+
+static inline bool kvm_hv_synic_auto_eoi_set(struct kvm_vcpu *vcpu, int vector)
+{
+ return to_hv_vcpu(vcpu) &&
+ test_bit(vector, to_hv_synic(vcpu)->auto_eoi_bitmap);
+}
+
void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu);
bool kvm_hv_assist_page_enabled(struct kvm_vcpu *vcpu);
@@ -236,6 +249,76 @@ static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu)
return kvm_hv_get_assist_page(vcpu);
}
+static inline void kvm_hv_nested_transtion_tlb_flush(struct kvm_vcpu *vcpu,
+ bool tdp_enabled)
+{
+ /*
+ * KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or
+ * L2's VP_ID upon request from the guest. Make sure we check for
+ * pending entries in the right FIFO upon L1/L2 transition as these
+ * requests are put by other vCPUs asynchronously.
+ */
+ if (to_hv_vcpu(vcpu) && tdp_enabled)
+ kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
+}
+
int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu);
+#else /* CONFIG_KVM_HYPERV */
+static inline void kvm_hv_setup_tsc_page(struct kvm *kvm,
+ struct pvclock_vcpu_time_info *hv_clock) {}
+static inline void kvm_hv_request_tsc_page_update(struct kvm *kvm) {}
+static inline void kvm_hv_init_vm(struct kvm *kvm) {}
+static inline void kvm_hv_destroy_vm(struct kvm *kvm) {}
+static inline int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+static inline void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu) {}
+static inline bool kvm_hv_hypercall_enabled(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+static inline int kvm_hv_hypercall(struct kvm_vcpu *vcpu)
+{
+ return HV_STATUS_ACCESS_DENIED;
+}
+static inline void kvm_hv_vcpu_purge_flush_tlb(struct kvm_vcpu *vcpu) {}
+static inline void kvm_hv_free_pa_page(struct kvm *kvm) {}
+static inline bool kvm_hv_synic_has_vector(struct kvm_vcpu *vcpu, int vector)
+{
+ return false;
+}
+static inline bool kvm_hv_synic_auto_eoi_set(struct kvm_vcpu *vcpu, int vector)
+{
+ return false;
+}
+static inline void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector) {}
+static inline bool kvm_hv_invtsc_suppressed(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+static inline void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu, bool hyperv_enabled) {}
+static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+static inline bool kvm_hv_is_tlb_flush_hcall(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+static inline bool guest_hv_cpuid_has_l2_tlb_flush(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu)
+{
+ return 0;
+}
+static inline u32 kvm_hv_get_vpindex(struct kvm_vcpu *vcpu)
+{
+ return vcpu->vcpu_idx;
+}
+static inline void kvm_hv_nested_transtion_tlb_flush(struct kvm_vcpu *vcpu, bool tdp_enabled) {}
+#endif /* CONFIG_KVM_HYPERV */
-#endif
+#endif /* __ARCH_X86_KVM_HYPERV_H__ */
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index b2c397dd2bc6..ad9ca8a60144 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -118,8 +118,10 @@ static int kvm_cpu_get_extint(struct kvm_vcpu *v)
if (!lapic_in_kernel(v))
return v->arch.interrupt.nr;
+#ifdef CONFIG_KVM_XEN
if (kvm_xen_has_interrupt(v))
return v->kvm->arch.xen.upcall_vector;
+#endif
if (irqchip_split(v->kvm)) {
int vector = v->arch.pending_external_vector;
diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c
index 16d076a1b91a..68f3f6c26046 100644
--- a/arch/x86/kvm/irq_comm.c
+++ b/arch/x86/kvm/irq_comm.c
@@ -144,7 +144,7 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
return kvm_irq_delivery_to_apic(kvm, NULL, &irq, NULL);
}
-
+#ifdef CONFIG_KVM_HYPERV
static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id, int level,
bool line_status)
@@ -154,6 +154,7 @@ static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
return kvm_hv_synic_set_irq(kvm, e->hv_sint.vcpu, e->hv_sint.sint);
}
+#endif
int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id, int level,
@@ -163,9 +164,11 @@ int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
int r;
switch (e->type) {
+#ifdef CONFIG_KVM_HYPERV
case KVM_IRQ_ROUTING_HV_SINT:
return kvm_hv_set_sint(e, kvm, irq_source_id, level,
line_status);
+#endif
case KVM_IRQ_ROUTING_MSI:
if (kvm_msi_route_invalid(kvm, e))
@@ -314,11 +317,13 @@ int kvm_set_routing_entry(struct kvm *kvm,
if (kvm_msi_route_invalid(kvm, e))
return -EINVAL;
break;
+#ifdef CONFIG_KVM_HYPERV
case KVM_IRQ_ROUTING_HV_SINT:
e->set = kvm_hv_set_sint;
e->hv_sint.vcpu = ue->u.hv_sint.vcpu;
e->hv_sint.sint = ue->u.hv_sint.sint;
break;
+#endif
#ifdef CONFIG_KVM_XEN
case KVM_IRQ_ROUTING_XEN_EVTCHN:
return kvm_xen_setup_evtchn(kvm, e, ue);
@@ -438,5 +443,7 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
void kvm_arch_irq_routing_update(struct kvm *kvm)
{
+#ifdef CONFIG_KVM_HYPERV
kvm_hv_irq_routing_update(kvm);
+#endif
}
diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h
index be7aeb9b8ea3..e6d149825169 100644
--- a/arch/x86/kvm/kvm_emulate.h
+++ b/arch/x86/kvm/kvm_emulate.h
@@ -88,6 +88,12 @@ struct x86_instruction_info {
#define X86EMUL_IO_NEEDED 5 /* IO is needed to complete emulation */
#define X86EMUL_INTERCEPTED 6 /* Intercepted by nested VMCB/VMCS */
+/* x86-specific emulation flags */
+#define X86EMUL_F_WRITE BIT(0)
+#define X86EMUL_F_FETCH BIT(1)
+#define X86EMUL_F_IMPLICIT BIT(2)
+#define X86EMUL_F_INVLPG BIT(3)
+
struct x86_emulate_ops {
void (*vm_bugged)(struct x86_emulate_ctxt *ctxt);
/*
@@ -224,6 +230,9 @@ struct x86_emulate_ops {
int (*leave_smm)(struct x86_emulate_ctxt *ctxt);
void (*triple_fault)(struct x86_emulate_ctxt *ctxt);
int (*set_xcr)(struct x86_emulate_ctxt *ctxt, u32 index, u64 xcr);
+
+ gva_t (*get_untagged_addr)(struct x86_emulate_ctxt *ctxt, gva_t addr,
+ unsigned int flags);
};
/* Type, address-of, and value of an instruction's operand. */
diff --git a/arch/x86/kvm/kvm_onhyperv.h b/arch/x86/kvm/kvm_onhyperv.h
index f9ca3e7432b2..eefab3dc8498 100644
--- a/arch/x86/kvm/kvm_onhyperv.h
+++ b/arch/x86/kvm/kvm_onhyperv.h
@@ -10,6 +10,26 @@
int hv_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, gfn_t nr_pages);
int hv_flush_remote_tlbs(struct kvm *kvm);
void hv_track_root_tdp(struct kvm_vcpu *vcpu, hpa_t root_tdp);
+static inline hpa_t hv_get_partition_assist_page(struct kvm_vcpu *vcpu)
+{
+ /*
+ * Partition assist page is something which Hyper-V running in L0
+ * requires from KVM running in L1 before direct TLB flush for L2
+ * guests can be enabled. KVM doesn't currently use the page but to
+ * comply with TLFS it still needs to be allocated. For now, this
+ * is a single page shared among all vCPUs.
+ */
+ struct hv_partition_assist_pg **p_hv_pa_pg =
+ &vcpu->kvm->arch.hv_pa_pg;
+
+ if (!*p_hv_pa_pg)
+ *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL_ACCOUNT);
+
+ if (!*p_hv_pa_pg)
+ return INVALID_PAGE;
+
+ return __pa(*p_hv_pa_pg);
+}
#else /* !CONFIG_HYPERV */
static inline int hv_flush_remote_tlbs(struct kvm *kvm)
{
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 245b20973cae..3242f3da2457 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1475,8 +1475,7 @@ static int apic_set_eoi(struct kvm_lapic *apic)
apic_clear_isr(vector, apic);
apic_update_ppr(apic);
- if (to_hv_vcpu(apic->vcpu) &&
- test_bit(vector, to_hv_synic(apic->vcpu)->vec_bitmap))
+ if (kvm_hv_synic_has_vector(apic->vcpu, vector))
kvm_hv_synic_send_eoi(apic->vcpu, vector);
kvm_ioapic_send_eoi(apic, vector);
@@ -2905,7 +2904,7 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
*/
apic_clear_irr(vector, apic);
- if (to_hv_vcpu(vcpu) && test_bit(vector, to_hv_synic(vcpu)->auto_eoi_bitmap)) {
+ if (kvm_hv_synic_auto_eoi_set(vcpu, vector)) {
/*
* For auto-EOI interrupts, there might be another pending
* interrupt above PPR, so check whether to raise another
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index bb8c86eefac0..60f21bb4c27b 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -146,6 +146,14 @@ static inline unsigned long kvm_get_active_pcid(struct kvm_vcpu *vcpu)
return kvm_get_pcid(vcpu, kvm_read_cr3(vcpu));
}
+static inline unsigned long kvm_get_active_cr3_lam_bits(struct kvm_vcpu *vcpu)
+{
+ if (!guest_can_use(vcpu, X86_FEATURE_LAM))
+ return 0;
+
+ return kvm_read_cr3(vcpu) & (X86_CR3_LAM_U48 | X86_CR3_LAM_U57);
+}
+
static inline void kvm_mmu_load_pgd(struct kvm_vcpu *vcpu)
{
u64 root_hpa = vcpu->arch.mmu->root.hpa;
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 0b1f991b9a31..2d6cdeab1f8a 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -271,15 +271,11 @@ static inline unsigned long kvm_mmu_get_guest_pgd(struct kvm_vcpu *vcpu,
static inline bool kvm_available_flush_remote_tlbs_range(void)
{
+#if IS_ENABLED(CONFIG_HYPERV)
return kvm_x86_ops.flush_remote_tlbs_range;
-}
-
-int kvm_arch_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, u64 nr_pages)
-{
- if (!kvm_x86_ops.flush_remote_tlbs_range)
- return -EOPNOTSUPP;
-
- return static_call(kvm_x86_flush_remote_tlbs_range)(kvm, gfn, nr_pages);
+#else
+ return false;
+#endif
}
static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index);
@@ -795,16 +791,26 @@ static struct kvm_lpage_info *lpage_info_slot(gfn_t gfn,
return &slot->arch.lpage_info[level - 2][idx];
}
+/*
+ * The most significant bit in disallow_lpage tracks whether or not memory
+ * attributes are mixed, i.e. not identical for all gfns at the current level.
+ * The lower order bits are used to refcount other cases where a hugepage is
+ * disallowed, e.g. if KVM has shadow a page table at the gfn.
+ */
+#define KVM_LPAGE_MIXED_FLAG BIT(31)
+
static void update_gfn_disallow_lpage_count(const struct kvm_memory_slot *slot,
gfn_t gfn, int count)
{
struct kvm_lpage_info *linfo;
- int i;
+ int old, i;
for (i = PG_LEVEL_2M; i <= KVM_MAX_HUGEPAGE_LEVEL; ++i) {
linfo = lpage_info_slot(gfn, slot, i);
+
+ old = linfo->disallow_lpage;
linfo->disallow_lpage += count;
- WARN_ON_ONCE(linfo->disallow_lpage < 0);
+ WARN_ON_ONCE((old ^ linfo->disallow_lpage) & KVM_LPAGE_MIXED_FLAG);
}
}
@@ -1382,7 +1388,7 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
gfn_t end = slot->base_gfn + gfn_offset + __fls(mask);
if (READ_ONCE(eager_page_split))
- kvm_mmu_try_split_huge_pages(kvm, slot, start, end, PG_LEVEL_4K);
+ kvm_mmu_try_split_huge_pages(kvm, slot, start, end + 1, PG_LEVEL_4K);
kvm_mmu_slot_gfn_write_protect(kvm, slot, start, PG_LEVEL_2M);
@@ -2840,9 +2846,9 @@ int mmu_try_to_unsync_pages(struct kvm *kvm, const struct kvm_memory_slot *slot,
/*
* Recheck after taking the spinlock, a different vCPU
* may have since marked the page unsync. A false
- * positive on the unprotected check above is not
+ * negative on the unprotected check above is not
* possible as clearing sp->unsync _must_ hold mmu_lock
- * for write, i.e. unsync cannot transition from 0->1
+ * for write, i.e. unsync cannot transition from 1->0
* while this CPU holds mmu_lock for read (or write).
*/
if (READ_ONCE(sp->unsync))
@@ -3056,7 +3062,7 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep)
*
* There are several ways to safely use this helper:
*
- * - Check mmu_invalidate_retry_hva() after grabbing the mapping level, before
+ * - Check mmu_invalidate_retry_gfn() after grabbing the mapping level, before
* consuming it. In this case, mmu_lock doesn't need to be held during the
* lookup, but it does need to be held while checking the MMU notifier.
*
@@ -3137,9 +3143,9 @@ out:
return level;
}
-int kvm_mmu_max_mapping_level(struct kvm *kvm,
- const struct kvm_memory_slot *slot, gfn_t gfn,
- int max_level)
+static int __kvm_mmu_max_mapping_level(struct kvm *kvm,
+ const struct kvm_memory_slot *slot,
+ gfn_t gfn, int max_level, bool is_private)
{
struct kvm_lpage_info *linfo;
int host_level;
@@ -3151,6 +3157,9 @@ int kvm_mmu_max_mapping_level(struct kvm *kvm,
break;
}
+ if (is_private)
+ return max_level;
+
if (max_level == PG_LEVEL_4K)
return PG_LEVEL_4K;
@@ -3158,6 +3167,16 @@ int kvm_mmu_max_mapping_level(struct kvm *kvm,
return min(host_level, max_level);
}
+int kvm_mmu_max_mapping_level(struct kvm *kvm,
+ const struct kvm_memory_slot *slot, gfn_t gfn,
+ int max_level)
+{
+ bool is_private = kvm_slot_can_be_private(slot) &&
+ kvm_mem_is_private(kvm, gfn);
+
+ return __kvm_mmu_max_mapping_level(kvm, slot, gfn, max_level, is_private);
+}
+
void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
{
struct kvm_memory_slot *slot = fault->slot;
@@ -3178,8 +3197,9 @@ void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
* Enforce the iTLB multihit workaround after capturing the requested
* level, which will be used to do precise, accurate accounting.
*/
- fault->req_level = kvm_mmu_max_mapping_level(vcpu->kvm, slot,
- fault->gfn, fault->max_level);
+ fault->req_level = __kvm_mmu_max_mapping_level(vcpu->kvm, slot,
+ fault->gfn, fault->max_level,
+ fault->is_private);
if (fault->req_level == PG_LEVEL_4K || fault->huge_page_disallowed)
return;
@@ -3556,7 +3576,7 @@ static void mmu_free_root_page(struct kvm *kvm, hpa_t *root_hpa,
return;
if (is_tdp_mmu_page(sp))
- kvm_tdp_mmu_put_root(kvm, sp, false);
+ kvm_tdp_mmu_put_root(kvm, sp);
else if (!--sp->root_count && sp->role.invalid)
kvm_mmu_prepare_zap_page(kvm, sp, invalid_list);
@@ -3739,7 +3759,7 @@ static int mmu_first_shadow_root_alloc(struct kvm *kvm)
kvm_page_track_write_tracking_enabled(kvm))
goto out_success;
- for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+ for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
slots = __kvm_memslots(kvm, i);
kvm_for_each_memslot(slot, bkt, slots) {
/*
@@ -3782,7 +3802,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
hpa_t root;
root_pgd = kvm_mmu_get_guest_pgd(vcpu, mmu);
- root_gfn = root_pgd >> PAGE_SHIFT;
+ root_gfn = (root_pgd & __PT_BASE_ADDR_MASK) >> PAGE_SHIFT;
if (!kvm_vcpu_is_visible_gfn(vcpu, root_gfn)) {
mmu->root.hpa = kvm_mmu_get_dummy_root();
@@ -4259,6 +4279,55 @@ void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, struct kvm_async_pf *work)
kvm_mmu_do_page_fault(vcpu, work->cr2_or_gpa, 0, true, NULL);
}
+static inline u8 kvm_max_level_for_order(int order)
+{
+ BUILD_BUG_ON(KVM_MAX_HUGEPAGE_LEVEL > PG_LEVEL_1G);
+
+ KVM_MMU_WARN_ON(order != KVM_HPAGE_GFN_SHIFT(PG_LEVEL_1G) &&
+ order != KVM_HPAGE_GFN_SHIFT(PG_LEVEL_2M) &&
+ order != KVM_HPAGE_GFN_SHIFT(PG_LEVEL_4K));
+
+ if (order >= KVM_HPAGE_GFN_SHIFT(PG_LEVEL_1G))
+ return PG_LEVEL_1G;
+
+ if (order >= KVM_HPAGE_GFN_SHIFT(PG_LEVEL_2M))
+ return PG_LEVEL_2M;
+
+ return PG_LEVEL_4K;
+}
+
+static void kvm_mmu_prepare_memory_fault_exit(struct kvm_vcpu *vcpu,
+ struct kvm_page_fault *fault)
+{
+ kvm_prepare_memory_fault_exit(vcpu, fault->gfn << PAGE_SHIFT,
+ PAGE_SIZE, fault->write, fault->exec,
+ fault->is_private);
+}
+
+static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu,
+ struct kvm_page_fault *fault)
+{
+ int max_order, r;
+
+ if (!kvm_slot_can_be_private(fault->slot)) {
+ kvm_mmu_prepare_memory_fault_exit(vcpu, fault);
+ return -EFAULT;
+ }
+
+ r = kvm_gmem_get_pfn(vcpu->kvm, fault->slot, fault->gfn, &fault->pfn,
+ &max_order);
+ if (r) {
+ kvm_mmu_prepare_memory_fault_exit(vcpu, fault);
+ return r;
+ }
+
+ fault->max_level = min(kvm_max_level_for_order(max_order),
+ fault->max_level);
+ fault->map_writable = !(fault->slot->flags & KVM_MEM_READONLY);
+
+ return RET_PF_CONTINUE;
+}
+
static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
{
struct kvm_memory_slot *slot = fault->slot;
@@ -4291,6 +4360,14 @@ static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
return RET_PF_EMULATE;
}
+ if (fault->is_private != kvm_mem_is_private(vcpu->kvm, fault->gfn)) {
+ kvm_mmu_prepare_memory_fault_exit(vcpu, fault);
+ return -EFAULT;
+ }
+
+ if (fault->is_private)
+ return kvm_faultin_pfn_private(vcpu, fault);
+
async = false;
fault->pfn = __gfn_to_pfn_memslot(slot, fault->gfn, false, false, &async,
fault->write, &fault->map_writable,
@@ -4366,7 +4443,7 @@ static bool is_page_fault_stale(struct kvm_vcpu *vcpu,
return true;
return fault->slot &&
- mmu_invalidate_retry_hva(vcpu->kvm, fault->mmu_seq, fault->hva);
+ mmu_invalidate_retry_gfn(vcpu->kvm, fault->mmu_seq, fault->gfn);
}
static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
@@ -6228,7 +6305,7 @@ static bool kvm_rmap_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_e
if (!kvm_memslots_have_rmaps(kvm))
return flush;
- for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+ for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
slots = __kvm_memslots(kvm, i);
kvm_for_each_memslot_in_gfn_range(&iter, slots, gfn_start, gfn_end) {
@@ -6260,7 +6337,9 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
write_lock(&kvm->mmu_lock);
- kvm_mmu_invalidate_begin(kvm, 0, -1ul);
+ kvm_mmu_invalidate_begin(kvm);
+
+ kvm_mmu_invalidate_range_add(kvm, gfn_start, gfn_end);
flush = kvm_rmap_zap_gfn_range(kvm, gfn_start, gfn_end);
@@ -6270,7 +6349,7 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
if (flush)
kvm_flush_remote_tlbs_range(kvm, gfn_start, gfn_end - gfn_start);
- kvm_mmu_invalidate_end(kvm, 0, -1ul);
+ kvm_mmu_invalidate_end(kvm);
write_unlock(&kvm->mmu_lock);
}
@@ -6723,7 +6802,7 @@ void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen)
* modifier prior to checking for a wrap of the MMIO generation so
* that a wrap in any address space is detected.
*/
- gen &= ~((u64)KVM_ADDRESS_SPACE_NUM - 1);
+ gen &= ~((u64)kvm_arch_nr_memslot_as_ids(kvm) - 1);
/*
* The very rare case: if the MMIO generation number has wrapped,
@@ -7176,3 +7255,163 @@ void kvm_mmu_pre_destroy_vm(struct kvm *kvm)
if (kvm->arch.nx_huge_page_recovery_thread)
kthread_stop(kvm->arch.nx_huge_page_recovery_thread);
}
+
+#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
+bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm,
+ struct kvm_gfn_range *range)
+{
+ /*
+ * Zap SPTEs even if the slot can't be mapped PRIVATE. KVM x86 only
+ * supports KVM_MEMORY_ATTRIBUTE_PRIVATE, and so it *seems* like KVM
+ * can simply ignore such slots. But if userspace is making memory
+ * PRIVATE, then KVM must prevent the guest from accessing the memory
+ * as shared. And if userspace is making memory SHARED and this point
+ * is reached, then at least one page within the range was previously
+ * PRIVATE, i.e. the slot's possible hugepage ranges are changing.
+ * Zapping SPTEs in this case ensures KVM will reassess whether or not
+ * a hugepage can be used for affected ranges.
+ */
+ if (WARN_ON_ONCE(!kvm_arch_has_private_mem(kvm)))
+ return false;
+
+ return kvm_unmap_gfn_range(kvm, range);
+}
+
+static bool hugepage_test_mixed(struct kvm_memory_slot *slot, gfn_t gfn,
+ int level)
+{
+ return lpage_info_slot(gfn, slot, level)->disallow_lpage & KVM_LPAGE_MIXED_FLAG;
+}
+
+static void hugepage_clear_mixed(struct kvm_memory_slot *slot, gfn_t gfn,
+ int level)
+{
+ lpage_info_slot(gfn, slot, level)->disallow_lpage &= ~KVM_LPAGE_MIXED_FLAG;
+}
+
+static void hugepage_set_mixed(struct kvm_memory_slot *slot, gfn_t gfn,
+ int level)
+{
+ lpage_info_slot(gfn, slot, level)->disallow_lpage |= KVM_LPAGE_MIXED_FLAG;
+}
+
+static bool hugepage_has_attrs(struct kvm *kvm, struct kvm_memory_slot *slot,
+ gfn_t gfn, int level, unsigned long attrs)
+{
+ const unsigned long start = gfn;
+ const unsigned long end = start + KVM_PAGES_PER_HPAGE(level);
+
+ if (level == PG_LEVEL_2M)
+ return kvm_range_has_memory_attributes(kvm, start, end, attrs);
+
+ for (gfn = start; gfn < end; gfn += KVM_PAGES_PER_HPAGE(level - 1)) {
+ if (hugepage_test_mixed(slot, gfn, level - 1) ||
+ attrs != kvm_get_memory_attributes(kvm, gfn))
+ return false;
+ }
+ return true;
+}
+
+bool kvm_arch_post_set_memory_attributes(struct kvm *kvm,
+ struct kvm_gfn_range *range)
+{
+ unsigned long attrs = range->arg.attributes;
+ struct kvm_memory_slot *slot = range->slot;
+ int level;
+
+ lockdep_assert_held_write(&kvm->mmu_lock);
+ lockdep_assert_held(&kvm->slots_lock);
+
+ /*
+ * Calculate which ranges can be mapped with hugepages even if the slot
+ * can't map memory PRIVATE. KVM mustn't create a SHARED hugepage over
+ * a range that has PRIVATE GFNs, and conversely converting a range to
+ * SHARED may now allow hugepages.
+ */
+ if (WARN_ON_ONCE(!kvm_arch_has_private_mem(kvm)))
+ return false;
+
+ /*
+ * The sequence matters here: upper levels consume the result of lower
+ * level's scanning.
+ */
+ for (level = PG_LEVEL_2M; level <= KVM_MAX_HUGEPAGE_LEVEL; level++) {
+ gfn_t nr_pages = KVM_PAGES_PER_HPAGE(level);
+ gfn_t gfn = gfn_round_for_level(range->start, level);
+
+ /* Process the head page if it straddles the range. */
+ if (gfn != range->start || gfn + nr_pages > range->end) {
+ /*
+ * Skip mixed tracking if the aligned gfn isn't covered
+ * by the memslot, KVM can't use a hugepage due to the
+ * misaligned address regardless of memory attributes.
+ */
+ if (gfn >= slot->base_gfn) {
+ if (hugepage_has_attrs(kvm, slot, gfn, level, attrs))
+ hugepage_clear_mixed(slot, gfn, level);
+ else
+ hugepage_set_mixed(slot, gfn, level);
+ }
+ gfn += nr_pages;
+ }
+
+ /*
+ * Pages entirely covered by the range are guaranteed to have
+ * only the attributes which were just set.
+ */
+ for ( ; gfn + nr_pages <= range->end; gfn += nr_pages)
+ hugepage_clear_mixed(slot, gfn, level);
+
+ /*
+ * Process the last tail page if it straddles the range and is
+ * contained by the memslot. Like the head page, KVM can't
+ * create a hugepage if the slot size is misaligned.
+ */
+ if (gfn < range->end &&
+ (gfn + nr_pages) <= (slot->base_gfn + slot->npages)) {
+ if (hugepage_has_attrs(kvm, slot, gfn, level, attrs))
+ hugepage_clear_mixed(slot, gfn, level);
+ else
+ hugepage_set_mixed(slot, gfn, level);
+ }
+ }
+ return false;
+}
+
+void kvm_mmu_init_memslot_memory_attributes(struct kvm *kvm,
+ struct kvm_memory_slot *slot)
+{
+ int level;
+
+ if (!kvm_arch_has_private_mem(kvm))
+ return;
+
+ for (level = PG_LEVEL_2M; level <= KVM_MAX_HUGEPAGE_LEVEL; level++) {
+ /*
+ * Don't bother tracking mixed attributes for pages that can't
+ * be huge due to alignment, i.e. process only pages that are
+ * entirely contained by the memslot.
+ */
+ gfn_t end = gfn_round_for_level(slot->base_gfn + slot->npages, level);
+ gfn_t start = gfn_round_for_level(slot->base_gfn, level);
+ gfn_t nr_pages = KVM_PAGES_PER_HPAGE(level);
+ gfn_t gfn;
+
+ if (start < slot->base_gfn)
+ start += nr_pages;
+
+ /*
+ * Unlike setting attributes, every potential hugepage needs to
+ * be manually checked as the attributes may already be mixed.
+ */
+ for (gfn = start; gfn < end; gfn += nr_pages) {
+ unsigned long attrs = kvm_get_memory_attributes(kvm, gfn);
+
+ if (hugepage_has_attrs(kvm, slot, gfn, level, attrs))
+ hugepage_clear_mixed(slot, gfn, level);
+ else
+ hugepage_set_mixed(slot, gfn, level);
+ }
+ }
+}
+#endif
diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h
index decc1f153669..0669a8a668ca 100644
--- a/arch/x86/kvm/mmu/mmu_internal.h
+++ b/arch/x86/kvm/mmu/mmu_internal.h
@@ -13,6 +13,7 @@
#endif
/* Page table builder macros common to shadow (host) PTEs and guest PTEs. */
+#define __PT_BASE_ADDR_MASK GENMASK_ULL(51, 12)
#define __PT_LEVEL_SHIFT(level, bits_per_level) \
(PAGE_SHIFT + ((level) - 1) * (bits_per_level))
#define __PT_INDEX(address, level, bits_per_level) \
@@ -201,6 +202,7 @@ struct kvm_page_fault {
/* Derived from mmu and global state. */
const bool is_tdp;
+ const bool is_private;
const bool nx_huge_page_workaround_enabled;
/*
@@ -296,6 +298,7 @@ static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
.max_level = KVM_MAX_HUGEPAGE_LEVEL,
.req_level = PG_LEVEL_4K,
.goal_level = PG_LEVEL_4K,
+ .is_private = kvm_mem_is_private(vcpu->kvm, cr2_or_gpa >> PAGE_SHIFT),
};
int r;
diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h
index c85255073f67..4d4e98fe4f35 100644
--- a/arch/x86/kvm/mmu/paging_tmpl.h
+++ b/arch/x86/kvm/mmu/paging_tmpl.h
@@ -62,7 +62,7 @@
#endif
/* Common logic, but per-type values. These also need to be undefined. */
-#define PT_BASE_ADDR_MASK ((pt_element_t)(((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1)))
+#define PT_BASE_ADDR_MASK ((pt_element_t)__PT_BASE_ADDR_MASK)
#define PT_LVL_ADDR_MASK(lvl) __PT_LVL_ADDR_MASK(PT_BASE_ADDR_MASK, lvl, PT_LEVEL_BITS)
#define PT_LVL_OFFSET_MASK(lvl) __PT_LVL_OFFSET_MASK(PT_BASE_ADDR_MASK, lvl, PT_LEVEL_BITS)
#define PT_INDEX(addr, lvl) __PT_INDEX(addr, lvl, PT_LEVEL_BITS)
diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
index 6cd4dd631a2f..6ae19b4ee5b1 100644
--- a/arch/x86/kvm/mmu/tdp_mmu.c
+++ b/arch/x86/kvm/mmu/tdp_mmu.c
@@ -73,11 +73,8 @@ static void tdp_mmu_free_sp_rcu_callback(struct rcu_head *head)
tdp_mmu_free_sp(sp);
}
-void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root,
- bool shared)
+void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root)
{
- kvm_lockdep_assert_mmu_lock_held(kvm, shared);
-
if (!refcount_dec_and_test(&root->tdp_mmu_root_count))
return;
@@ -106,10 +103,16 @@ void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root,
*/
static struct kvm_mmu_page *tdp_mmu_next_root(struct kvm *kvm,
struct kvm_mmu_page *prev_root,
- bool shared, bool only_valid)
+ bool only_valid)
{
struct kvm_mmu_page *next_root;
+ /*
+ * While the roots themselves are RCU-protected, fields such as
+ * role.invalid are protected by mmu_lock.
+ */
+ lockdep_assert_held(&kvm->mmu_lock);
+
rcu_read_lock();
if (prev_root)
@@ -132,7 +135,7 @@ static struct kvm_mmu_page *tdp_mmu_next_root(struct kvm *kvm,
rcu_read_unlock();
if (prev_root)
- kvm_tdp_mmu_put_root(kvm, prev_root, shared);
+ kvm_tdp_mmu_put_root(kvm, prev_root);
return next_root;
}
@@ -144,26 +147,22 @@ static struct kvm_mmu_page *tdp_mmu_next_root(struct kvm *kvm,
* recent root. (Unless keeping a live reference is desirable.)
*
* If shared is set, this function is operating under the MMU lock in read
- * mode. In the unlikely event that this thread must free a root, the lock
- * will be temporarily dropped and reacquired in write mode.
+ * mode.
*/
-#define __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared, _only_valid)\
- for (_root = tdp_mmu_next_root(_kvm, NULL, _shared, _only_valid); \
- _root; \
- _root = tdp_mmu_next_root(_kvm, _root, _shared, _only_valid)) \
- if (kvm_lockdep_assert_mmu_lock_held(_kvm, _shared) && \
- kvm_mmu_page_as_id(_root) != _as_id) { \
+#define __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _only_valid)\
+ for (_root = tdp_mmu_next_root(_kvm, NULL, _only_valid); \
+ ({ lockdep_assert_held(&(_kvm)->mmu_lock); }), _root; \
+ _root = tdp_mmu_next_root(_kvm, _root, _only_valid)) \
+ if (kvm_mmu_page_as_id(_root) != _as_id) { \
} else
-#define for_each_valid_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared) \
- __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared, true)
+#define for_each_valid_tdp_mmu_root_yield_safe(_kvm, _root, _as_id) \
+ __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, true)
-#define for_each_tdp_mmu_root_yield_safe(_kvm, _root, _shared) \
- for (_root = tdp_mmu_next_root(_kvm, NULL, _shared, false); \
- _root; \
- _root = tdp_mmu_next_root(_kvm, _root, _shared, false)) \
- if (!kvm_lockdep_assert_mmu_lock_held(_kvm, _shared)) { \
- } else
+#define for_each_tdp_mmu_root_yield_safe(_kvm, _root) \
+ for (_root = tdp_mmu_next_root(_kvm, NULL, false); \
+ ({ lockdep_assert_held(&(_kvm)->mmu_lock); }), _root; \
+ _root = tdp_mmu_next_root(_kvm, _root, false))
/*
* Iterate over all TDP MMU roots. Requires that mmu_lock be held for write,
@@ -276,28 +275,18 @@ static void tdp_unaccount_mmu_page(struct kvm *kvm, struct kvm_mmu_page *sp)
*
* @kvm: kvm instance
* @sp: the page to be removed
- * @shared: This operation may not be running under the exclusive use of
- * the MMU lock and the operation must synchronize with other
- * threads that might be adding or removing pages.
*/
-static void tdp_mmu_unlink_sp(struct kvm *kvm, struct kvm_mmu_page *sp,
- bool shared)
+static void tdp_mmu_unlink_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
{
tdp_unaccount_mmu_page(kvm, sp);
if (!sp->nx_huge_page_disallowed)
return;
- if (shared)
- spin_lock(&kvm->arch.tdp_mmu_pages_lock);
- else
- lockdep_assert_held_write(&kvm->mmu_lock);
-
+ spin_lock(&kvm->arch.tdp_mmu_pages_lock);
sp->nx_huge_page_disallowed = false;
untrack_possible_nx_huge_page(kvm, sp);
-
- if (shared)
- spin_unlock(&kvm->arch.tdp_mmu_pages_lock);
+ spin_unlock(&kvm->arch.tdp_mmu_pages_lock);
}
/**
@@ -326,7 +315,7 @@ static void handle_removed_pt(struct kvm *kvm, tdp_ptep_t pt, bool shared)
trace_kvm_mmu_prepare_zap_page(sp);
- tdp_mmu_unlink_sp(kvm, sp, shared);
+ tdp_mmu_unlink_sp(kvm, sp);
for (i = 0; i < SPTE_ENT_PER_PAGE; i++) {
tdp_ptep_t sptep = pt + i;
@@ -832,7 +821,8 @@ bool kvm_tdp_mmu_zap_leafs(struct kvm *kvm, gfn_t start, gfn_t end, bool flush)
{
struct kvm_mmu_page *root;
- for_each_tdp_mmu_root_yield_safe(kvm, root, false)
+ lockdep_assert_held_write(&kvm->mmu_lock);
+ for_each_tdp_mmu_root_yield_safe(kvm, root)
flush = tdp_mmu_zap_leafs(kvm, root, start, end, true, flush);
return flush;
@@ -854,7 +844,8 @@ void kvm_tdp_mmu_zap_all(struct kvm *kvm)
* is being destroyed or the userspace VMM has exited. In both cases,
* KVM_RUN is unreachable, i.e. no vCPUs will ever service the request.
*/
- for_each_tdp_mmu_root_yield_safe(kvm, root, false)
+ lockdep_assert_held_write(&kvm->mmu_lock);
+ for_each_tdp_mmu_root_yield_safe(kvm, root)
tdp_mmu_zap_root(kvm, root, false);
}
@@ -868,7 +859,7 @@ void kvm_tdp_mmu_zap_invalidated_roots(struct kvm *kvm)
read_lock(&kvm->mmu_lock);
- for_each_tdp_mmu_root_yield_safe(kvm, root, true) {
+ for_each_tdp_mmu_root_yield_safe(kvm, root) {
if (!root->tdp_mmu_scheduled_root_to_zap)
continue;
@@ -891,7 +882,7 @@ void kvm_tdp_mmu_zap_invalidated_roots(struct kvm *kvm)
* the root must be reachable by mmu_notifiers while it's being
* zapped
*/
- kvm_tdp_mmu_put_root(kvm, root, true);
+ kvm_tdp_mmu_put_root(kvm, root);
}
read_unlock(&kvm->mmu_lock);
@@ -1125,7 +1116,7 @@ bool kvm_tdp_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range,
{
struct kvm_mmu_page *root;
- __for_each_tdp_mmu_root_yield_safe(kvm, root, range->slot->as_id, false, false)
+ __for_each_tdp_mmu_root_yield_safe(kvm, root, range->slot->as_id, false)
flush = tdp_mmu_zap_leafs(kvm, root, range->start, range->end,
range->may_block, flush);
@@ -1314,7 +1305,7 @@ bool kvm_tdp_mmu_wrprot_slot(struct kvm *kvm,
lockdep_assert_held_read(&kvm->mmu_lock);
- for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true)
+ for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id)
spte_set |= wrprot_gfn_range(kvm, root, slot->base_gfn,
slot->base_gfn + slot->npages, min_level);
@@ -1346,6 +1337,8 @@ static struct kvm_mmu_page *tdp_mmu_alloc_sp_for_split(struct kvm *kvm,
{
struct kvm_mmu_page *sp;
+ kvm_lockdep_assert_mmu_lock_held(kvm, shared);
+
/*
* Since we are allocating while under the MMU lock we have to be
* careful about GFP flags. Use GFP_NOWAIT to avoid blocking on direct
@@ -1496,11 +1489,10 @@ void kvm_tdp_mmu_try_split_huge_pages(struct kvm *kvm,
int r = 0;
kvm_lockdep_assert_mmu_lock_held(kvm, shared);
-
- for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, shared) {
+ for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id) {
r = tdp_mmu_split_huge_pages_root(kvm, root, start, end, target_level, shared);
if (r) {
- kvm_tdp_mmu_put_root(kvm, root, shared);
+ kvm_tdp_mmu_put_root(kvm, root);
break;
}
}
@@ -1522,12 +1514,13 @@ static bool clear_dirty_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root,
rcu_read_lock();
- tdp_root_for_each_leaf_pte(iter, root, start, end) {
+ tdp_root_for_each_pte(iter, root, start, end) {
retry:
- if (tdp_mmu_iter_cond_resched(kvm, &iter, false, true))
+ if (!is_shadow_present_pte(iter.old_spte) ||
+ !is_last_spte(iter.old_spte, iter.level))
continue;
- if (!is_shadow_present_pte(iter.old_spte))
+ if (tdp_mmu_iter_cond_resched(kvm, &iter, false, true))
continue;
KVM_MMU_WARN_ON(kvm_ad_enabled() &&
@@ -1560,8 +1553,7 @@ bool kvm_tdp_mmu_clear_dirty_slot(struct kvm *kvm,
bool spte_set = false;
lockdep_assert_held_read(&kvm->mmu_lock);
-
- for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true)
+ for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id)
spte_set |= clear_dirty_gfn_range(kvm, root, slot->base_gfn,
slot->base_gfn + slot->npages);
@@ -1695,8 +1687,7 @@ void kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kvm,
struct kvm_mmu_page *root;
lockdep_assert_held_read(&kvm->mmu_lock);
-
- for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true)
+ for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id)
zap_collapsible_spte_range(kvm, root, slot);
}
diff --git a/arch/x86/kvm/mmu/tdp_mmu.h b/arch/x86/kvm/mmu/tdp_mmu.h
index 733a3aef3a96..20d97aa46c49 100644
--- a/arch/x86/kvm/mmu/tdp_mmu.h
+++ b/arch/x86/kvm/mmu/tdp_mmu.h
@@ -17,8 +17,7 @@ __must_check static inline bool kvm_tdp_mmu_get_root(struct kvm_mmu_page *root)
return refcount_inc_not_zero(&root->tdp_mmu_root_count);
}
-void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root,
- bool shared);
+void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root);
bool kvm_tdp_mmu_zap_leafs(struct kvm *kvm, gfn_t start, gfn_t end, bool flush);
bool kvm_tdp_mmu_zap_sp(struct kvm *kvm, struct kvm_mmu_page *sp);
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index 9ae07db6f0f6..87cc6c8809ad 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -127,9 +127,9 @@ static void kvm_perf_overflow(struct perf_event *perf_event,
struct kvm_pmc *pmc = perf_event->overflow_handler_context;
/*
- * Ignore overflow events for counters that are scheduled to be
- * reprogrammed, e.g. if a PMI for the previous event races with KVM's
- * handling of a related guest WRMSR.
+ * Ignore asynchronous overflow events for counters that are scheduled
+ * to be reprogrammed, e.g. if a PMI for the previous event races with
+ * KVM's handling of a related guest WRMSR.
*/
if (test_and_set_bit(pmc->idx, pmc_to_pmu(pmc)->reprogram_pmi))
return;
@@ -161,6 +161,15 @@ static u64 pmc_get_pebs_precise_level(struct kvm_pmc *pmc)
return 1;
}
+static u64 get_sample_period(struct kvm_pmc *pmc, u64 counter_value)
+{
+ u64 sample_period = (-counter_value) & pmc_bitmask(pmc);
+
+ if (!sample_period)
+ sample_period = pmc_bitmask(pmc) + 1;
+ return sample_period;
+}
+
static int pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, u64 config,
bool exclude_user, bool exclude_kernel,
bool intr)
@@ -215,17 +224,30 @@ static int pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, u64 config,
return 0;
}
-static void pmc_pause_counter(struct kvm_pmc *pmc)
+static bool pmc_pause_counter(struct kvm_pmc *pmc)
{
u64 counter = pmc->counter;
-
- if (!pmc->perf_event || pmc->is_paused)
- return;
+ u64 prev_counter;
/* update counter, reset event value to avoid redundant accumulation */
- counter += perf_event_pause(pmc->perf_event, true);
+ if (pmc->perf_event && !pmc->is_paused)
+ counter += perf_event_pause(pmc->perf_event, true);
+
+ /*
+ * Snapshot the previous counter *after* accumulating state from perf.
+ * If overflow already happened, hardware (via perf) is responsible for
+ * generating a PMI. KVM just needs to detect overflow on emulated
+ * counter events that haven't yet been processed.
+ */
+ prev_counter = counter & pmc_bitmask(pmc);
+
+ counter += pmc->emulated_counter;
pmc->counter = counter & pmc_bitmask(pmc);
+
+ pmc->emulated_counter = 0;
pmc->is_paused = true;
+
+ return pmc->counter < prev_counter;
}
static bool pmc_resume_counter(struct kvm_pmc *pmc)
@@ -250,6 +272,51 @@ static bool pmc_resume_counter(struct kvm_pmc *pmc)
return true;
}
+static void pmc_release_perf_event(struct kvm_pmc *pmc)
+{
+ if (pmc->perf_event) {
+ perf_event_release_kernel(pmc->perf_event);
+ pmc->perf_event = NULL;
+ pmc->current_config = 0;
+ pmc_to_pmu(pmc)->event_count--;
+ }
+}
+
+static void pmc_stop_counter(struct kvm_pmc *pmc)
+{
+ if (pmc->perf_event) {
+ pmc->counter = pmc_read_counter(pmc);
+ pmc_release_perf_event(pmc);
+ }
+}
+
+static void pmc_update_sample_period(struct kvm_pmc *pmc)
+{
+ if (!pmc->perf_event || pmc->is_paused ||
+ !is_sampling_event(pmc->perf_event))
+ return;
+
+ perf_event_period(pmc->perf_event,
+ get_sample_period(pmc, pmc->counter));
+}
+
+void pmc_write_counter(struct kvm_pmc *pmc, u64 val)
+{
+ /*
+ * Drop any unconsumed accumulated counts, the WRMSR is a write, not a
+ * read-modify-write. Adjust the counter value so that its value is
+ * relative to the current count, as reading the current count from
+ * perf is faster than pausing and repgrogramming the event in order to
+ * reset it to '0'. Note, this very sneakily offsets the accumulated
+ * emulated count too, by using pmc_read_counter()!
+ */
+ pmc->emulated_counter = 0;
+ pmc->counter += val - pmc_read_counter(pmc);
+ pmc->counter &= pmc_bitmask(pmc);
+ pmc_update_sample_period(pmc);
+}
+EXPORT_SYMBOL_GPL(pmc_write_counter);
+
static int filter_cmp(const void *pa, const void *pb, u64 mask)
{
u64 a = *(u64 *)pa & mask;
@@ -383,14 +450,15 @@ static void reprogram_counter(struct kvm_pmc *pmc)
struct kvm_pmu *pmu = pmc_to_pmu(pmc);
u64 eventsel = pmc->eventsel;
u64 new_config = eventsel;
+ bool emulate_overflow;
u8 fixed_ctr_ctrl;
- pmc_pause_counter(pmc);
+ emulate_overflow = pmc_pause_counter(pmc);
if (!pmc_event_is_allowed(pmc))
goto reprogram_complete;
- if (pmc->counter < pmc->prev_counter)
+ if (emulate_overflow)
__kvm_perf_overflow(pmc, false);
if (eventsel & ARCH_PERFMON_EVENTSEL_PIN_CONTROL)
@@ -430,7 +498,6 @@ static void reprogram_counter(struct kvm_pmc *pmc)
reprogram_complete:
clear_bit(pmc->idx, (unsigned long *)&pmc_to_pmu(pmc)->reprogram_pmi);
- pmc->prev_counter = 0;
}
void kvm_pmu_handle_event(struct kvm_vcpu *vcpu)
@@ -639,32 +706,60 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
return 0;
}
-/* refresh PMU settings. This function generally is called when underlying
- * settings are changed (such as changes of PMU CPUID by guest VMs), which
- * should rarely happen.
+static void kvm_pmu_reset(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ struct kvm_pmc *pmc;
+ int i;
+
+ pmu->need_cleanup = false;
+
+ bitmap_zero(pmu->reprogram_pmi, X86_PMC_IDX_MAX);
+
+ for_each_set_bit(i, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX) {
+ pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, i);
+ if (!pmc)
+ continue;
+
+ pmc_stop_counter(pmc);
+ pmc->counter = 0;
+ pmc->emulated_counter = 0;
+
+ if (pmc_is_gp(pmc))
+ pmc->eventsel = 0;
+ }
+
+ pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status = 0;
+
+ static_call_cond(kvm_x86_pmu_reset)(vcpu);
+}
+
+
+/*
+ * Refresh the PMU configuration for the vCPU, e.g. if userspace changes CPUID
+ * and/or PERF_CAPABILITIES.
*/
void kvm_pmu_refresh(struct kvm_vcpu *vcpu)
{
if (KVM_BUG_ON(kvm_vcpu_has_run(vcpu), vcpu->kvm))
return;
+ /*
+ * Stop/release all existing counters/events before realizing the new
+ * vPMU model.
+ */
+ kvm_pmu_reset(vcpu);
+
bitmap_zero(vcpu_to_pmu(vcpu)->all_valid_pmc_idx, X86_PMC_IDX_MAX);
static_call(kvm_x86_pmu_refresh)(vcpu);
}
-void kvm_pmu_reset(struct kvm_vcpu *vcpu)
-{
- static_call(kvm_x86_pmu_reset)(vcpu);
-}
-
void kvm_pmu_init(struct kvm_vcpu *vcpu)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
memset(pmu, 0, sizeof(*pmu));
static_call(kvm_x86_pmu_init)(vcpu);
- pmu->event_count = 0;
- pmu->need_cleanup = false;
kvm_pmu_refresh(vcpu);
}
@@ -700,8 +795,7 @@ void kvm_pmu_destroy(struct kvm_vcpu *vcpu)
static void kvm_pmu_incr_counter(struct kvm_pmc *pmc)
{
- pmc->prev_counter = pmc->counter;
- pmc->counter = (pmc->counter + 1) & pmc_bitmask(pmc);
+ pmc->emulated_counter++;
kvm_pmu_request_counter_reprogram(pmc);
}
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index 1d64113de488..7caeb3d8d4fd 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -66,7 +66,8 @@ static inline u64 pmc_read_counter(struct kvm_pmc *pmc)
{
u64 counter, enabled, running;
- counter = pmc->counter;
+ counter = pmc->counter + pmc->emulated_counter;
+
if (pmc->perf_event && !pmc->is_paused)
counter += perf_event_read_value(pmc->perf_event,
&enabled, &running);
@@ -74,29 +75,7 @@ static inline u64 pmc_read_counter(struct kvm_pmc *pmc)
return counter & pmc_bitmask(pmc);
}
-static inline void pmc_write_counter(struct kvm_pmc *pmc, u64 val)
-{
- pmc->counter += val - pmc_read_counter(pmc);
- pmc->counter &= pmc_bitmask(pmc);
-}
-
-static inline void pmc_release_perf_event(struct kvm_pmc *pmc)
-{
- if (pmc->perf_event) {
- perf_event_release_kernel(pmc->perf_event);
- pmc->perf_event = NULL;
- pmc->current_config = 0;
- pmc_to_pmu(pmc)->event_count--;
- }
-}
-
-static inline void pmc_stop_counter(struct kvm_pmc *pmc)
-{
- if (pmc->perf_event) {
- pmc->counter = pmc_read_counter(pmc);
- pmc_release_perf_event(pmc);
- }
-}
+void pmc_write_counter(struct kvm_pmc *pmc, u64 val);
static inline bool pmc_is_gp(struct kvm_pmc *pmc)
{
@@ -146,25 +125,6 @@ static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)
return NULL;
}
-static inline u64 get_sample_period(struct kvm_pmc *pmc, u64 counter_value)
-{
- u64 sample_period = (-counter_value) & pmc_bitmask(pmc);
-
- if (!sample_period)
- sample_period = pmc_bitmask(pmc) + 1;
- return sample_period;
-}
-
-static inline void pmc_update_sample_period(struct kvm_pmc *pmc)
-{
- if (!pmc->perf_event || pmc->is_paused ||
- !is_sampling_event(pmc->perf_event))
- return;
-
- perf_event_period(pmc->perf_event,
- get_sample_period(pmc, pmc->counter));
-}
-
static inline bool pmc_speculative_in_use(struct kvm_pmc *pmc)
{
struct kvm_pmu *pmu = pmc_to_pmu(pmc);
@@ -261,7 +221,6 @@ bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr);
int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
void kvm_pmu_refresh(struct kvm_vcpu *vcpu);
-void kvm_pmu_reset(struct kvm_vcpu *vcpu);
void kvm_pmu_init(struct kvm_vcpu *vcpu);
void kvm_pmu_cleanup(struct kvm_vcpu *vcpu);
void kvm_pmu_destroy(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h
index b81650678375..aadefcaa9561 100644
--- a/arch/x86/kvm/reverse_cpuid.h
+++ b/arch/x86/kvm/reverse_cpuid.h
@@ -16,6 +16,7 @@ enum kvm_only_cpuid_leafs {
CPUID_7_1_EDX,
CPUID_8000_0007_EDX,
CPUID_8000_0022_EAX,
+ CPUID_7_2_EDX,
NR_KVM_CPU_CAPS,
NKVMCAPINTS = NR_KVM_CPU_CAPS - NCAPINTS,
@@ -46,6 +47,14 @@ enum kvm_only_cpuid_leafs {
#define X86_FEATURE_AMX_COMPLEX KVM_X86_FEATURE(CPUID_7_1_EDX, 8)
#define X86_FEATURE_PREFETCHITI KVM_X86_FEATURE(CPUID_7_1_EDX, 14)
+/* Intel-defined sub-features, CPUID level 0x00000007:2 (EDX) */
+#define X86_FEATURE_INTEL_PSFD KVM_X86_FEATURE(CPUID_7_2_EDX, 0)
+#define X86_FEATURE_IPRED_CTRL KVM_X86_FEATURE(CPUID_7_2_EDX, 1)
+#define KVM_X86_FEATURE_RRSBA_CTRL KVM_X86_FEATURE(CPUID_7_2_EDX, 2)
+#define X86_FEATURE_DDPD_U KVM_X86_FEATURE(CPUID_7_2_EDX, 3)
+#define X86_FEATURE_BHI_CTRL KVM_X86_FEATURE(CPUID_7_2_EDX, 4)
+#define X86_FEATURE_MCDT_NO KVM_X86_FEATURE(CPUID_7_2_EDX, 5)
+
/* CPUID level 0x80000007 (EDX). */
#define KVM_X86_FEATURE_CONSTANT_TSC KVM_X86_FEATURE(CPUID_8000_0007_EDX, 8)
@@ -80,6 +89,7 @@ static const struct cpuid_reg reverse_cpuid[] = {
[CPUID_8000_0007_EDX] = {0x80000007, 0, CPUID_EDX},
[CPUID_8000_0021_EAX] = {0x80000021, 0, CPUID_EAX},
[CPUID_8000_0022_EAX] = {0x80000022, 0, CPUID_EAX},
+ [CPUID_7_2_EDX] = { 7, 2, CPUID_EDX},
};
/*
@@ -106,18 +116,19 @@ static __always_inline void reverse_cpuid_check(unsigned int x86_leaf)
*/
static __always_inline u32 __feature_translate(int x86_feature)
{
- if (x86_feature == X86_FEATURE_SGX1)
- return KVM_X86_FEATURE_SGX1;
- else if (x86_feature == X86_FEATURE_SGX2)
- return KVM_X86_FEATURE_SGX2;
- else if (x86_feature == X86_FEATURE_SGX_EDECCSSA)
- return KVM_X86_FEATURE_SGX_EDECCSSA;
- else if (x86_feature == X86_FEATURE_CONSTANT_TSC)
- return KVM_X86_FEATURE_CONSTANT_TSC;
- else if (x86_feature == X86_FEATURE_PERFMON_V2)
- return KVM_X86_FEATURE_PERFMON_V2;
-
- return x86_feature;
+#define KVM_X86_TRANSLATE_FEATURE(f) \
+ case X86_FEATURE_##f: return KVM_X86_FEATURE_##f
+
+ switch (x86_feature) {
+ KVM_X86_TRANSLATE_FEATURE(SGX1);
+ KVM_X86_TRANSLATE_FEATURE(SGX2);
+ KVM_X86_TRANSLATE_FEATURE(SGX_EDECCSSA);
+ KVM_X86_TRANSLATE_FEATURE(CONSTANT_TSC);
+ KVM_X86_TRANSLATE_FEATURE(PERFMON_V2);
+ KVM_X86_TRANSLATE_FEATURE(RRSBA_CTRL);
+ default:
+ return x86_feature;
+ }
}
static __always_inline u32 __feature_leaf(int x86_feature)
diff --git a/arch/x86/kvm/svm/hyperv.h b/arch/x86/kvm/svm/hyperv.h
index 02f4784b5d44..d3f8bfc05832 100644
--- a/arch/x86/kvm/svm/hyperv.h
+++ b/arch/x86/kvm/svm/hyperv.h
@@ -11,6 +11,7 @@
#include "../hyperv.h"
#include "svm.h"
+#ifdef CONFIG_KVM_HYPERV
static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -41,5 +42,13 @@ static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu)
}
void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
+#else /* CONFIG_KVM_HYPERV */
+static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu) {}
+static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu)
+{
+ return false;
+}
+static inline void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu) {}
+#endif /* CONFIG_KVM_HYPERV */
#endif /* __ARCH_X86_KVM_SVM_HYPERV_H__ */
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index 3fea8c47679e..dee62362a360 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -187,7 +187,6 @@ void recalc_intercepts(struct vcpu_svm *svm)
*/
static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
{
- struct hv_vmcb_enlightenments *hve = &svm->nested.ctl.hv_enlightenments;
int i;
/*
@@ -198,11 +197,16 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
* - Nested hypervisor (L1) is using Hyper-V emulation interface and
* tells KVM (L0) there were no changes in MSR bitmap for L2.
*/
- if (!svm->nested.force_msr_bitmap_recalc &&
- kvm_hv_hypercall_enabled(&svm->vcpu) &&
- hve->hv_enlightenments_control.msr_bitmap &&
- (svm->nested.ctl.clean & BIT(HV_VMCB_NESTED_ENLIGHTENMENTS)))
- goto set_msrpm_base_pa;
+#ifdef CONFIG_KVM_HYPERV
+ if (!svm->nested.force_msr_bitmap_recalc) {
+ struct hv_vmcb_enlightenments *hve = &svm->nested.ctl.hv_enlightenments;
+
+ if (kvm_hv_hypercall_enabled(&svm->vcpu) &&
+ hve->hv_enlightenments_control.msr_bitmap &&
+ (svm->nested.ctl.clean & BIT(HV_VMCB_NESTED_ENLIGHTENMENTS)))
+ goto set_msrpm_base_pa;
+ }
+#endif
if (!(vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_MSR_PROT)))
return true;
@@ -230,7 +234,9 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
svm->nested.force_msr_bitmap_recalc = false;
+#ifdef CONFIG_KVM_HYPERV
set_msrpm_base_pa:
+#endif
svm->vmcb->control.msrpm_base_pa = __sme_set(__pa(svm->nested.msrpm));
return true;
@@ -247,18 +253,6 @@ static bool nested_svm_check_bitmap_pa(struct kvm_vcpu *vcpu, u64 pa, u32 size)
kvm_vcpu_is_legal_gpa(vcpu, addr + size - 1);
}
-static bool nested_svm_check_tlb_ctl(struct kvm_vcpu *vcpu, u8 tlb_ctl)
-{
- /* Nested FLUSHBYASID is not supported yet. */
- switch(tlb_ctl) {
- case TLB_CONTROL_DO_NOTHING:
- case TLB_CONTROL_FLUSH_ALL_ASID:
- return true;
- default:
- return false;
- }
-}
-
static bool __nested_vmcb_check_controls(struct kvm_vcpu *vcpu,
struct vmcb_ctrl_area_cached *control)
{
@@ -278,9 +272,6 @@ static bool __nested_vmcb_check_controls(struct kvm_vcpu *vcpu,
IOPM_SIZE)))
return false;
- if (CC(!nested_svm_check_tlb_ctl(vcpu, control->tlb_ctl)))
- return false;
-
if (CC((control->int_ctl & V_NMI_ENABLE_MASK) &&
!vmcb12_is_intercept(control, INTERCEPT_NMI))) {
return false;
@@ -311,7 +302,7 @@ static bool __nested_vmcb_check_save(struct kvm_vcpu *vcpu,
if ((save->efer & EFER_LME) && (save->cr0 & X86_CR0_PG)) {
if (CC(!(save->cr4 & X86_CR4_PAE)) ||
CC(!(save->cr0 & X86_CR0_PE)) ||
- CC(kvm_vcpu_is_illegal_gpa(vcpu, save->cr3)))
+ CC(!kvm_vcpu_is_legal_cr3(vcpu, save->cr3)))
return false;
}
@@ -378,12 +369,14 @@ void __nested_copy_vmcb_control_to_cache(struct kvm_vcpu *vcpu,
to->msrpm_base_pa &= ~0x0fffULL;
to->iopm_base_pa &= ~0x0fffULL;
+#ifdef CONFIG_KVM_HYPERV
/* Hyper-V extensions (Enlightened VMCB) */
if (kvm_hv_hypercall_enabled(vcpu)) {
to->clean = from->clean;
memcpy(&to->hv_enlightenments, &from->hv_enlightenments,
sizeof(to->hv_enlightenments));
}
+#endif
}
void nested_copy_vmcb_control_to_cache(struct vcpu_svm *svm,
@@ -487,14 +480,8 @@ static void nested_save_pending_event_to_vmcb12(struct vcpu_svm *svm,
static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu)
{
- /*
- * KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or
- * L2's VP_ID upon request from the guest. Make sure we check for
- * pending entries in the right FIFO upon L1/L2 transition as these
- * requests are put by other vCPUs asynchronously.
- */
- if (to_hv_vcpu(vcpu) && npt_enabled)
- kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
+ /* Handle pending Hyper-V TLB flush requests */
+ kvm_hv_nested_transtion_tlb_flush(vcpu, npt_enabled);
/*
* TODO: optimize unconditional TLB flush/MMU sync. A partial list of
@@ -520,7 +507,7 @@ static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu)
static int nested_svm_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3,
bool nested_npt, bool reload_pdptrs)
{
- if (CC(kvm_vcpu_is_illegal_gpa(vcpu, cr3)))
+ if (CC(!kvm_vcpu_is_legal_cr3(vcpu, cr3)))
return -EINVAL;
if (reload_pdptrs && !nested_npt && is_pae_paging(vcpu) &&
diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c
index 373ff6a6687b..b6a7ad4d6914 100644
--- a/arch/x86/kvm/svm/pmu.c
+++ b/arch/x86/kvm/svm/pmu.c
@@ -161,7 +161,6 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
pmc = get_gp_pmc_amd(pmu, msr, PMU_TYPE_COUNTER);
if (pmc) {
pmc_write_counter(pmc, data);
- pmc_update_sample_period(pmc);
return 0;
}
/* MSR_EVNTSELn */
@@ -233,21 +232,6 @@ static void amd_pmu_init(struct kvm_vcpu *vcpu)
}
}
-static void amd_pmu_reset(struct kvm_vcpu *vcpu)
-{
- struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
- int i;
-
- for (i = 0; i < KVM_AMD_PMC_MAX_GENERIC; i++) {
- struct kvm_pmc *pmc = &pmu->gp_counters[i];
-
- pmc_stop_counter(pmc);
- pmc->counter = pmc->prev_counter = pmc->eventsel = 0;
- }
-
- pmu->global_ctrl = pmu->global_status = 0;
-}
-
struct kvm_pmu_ops amd_pmu_ops __initdata = {
.hw_event_available = amd_hw_event_available,
.pmc_idx_to_pmc = amd_pmc_idx_to_pmc,
@@ -259,7 +243,6 @@ struct kvm_pmu_ops amd_pmu_ops __initdata = {
.set_msr = amd_pmu_set_msr,
.refresh = amd_pmu_refresh,
.init = amd_pmu_init,
- .reset = amd_pmu_reset,
.EVENTSEL_EVENT = AMD64_EVENTSEL_EVENT,
.MAX_NR_GP_COUNTERS = KVM_AMD_PMC_MAX_GENERIC,
.MIN_NR_GP_COUNTERS = AMD64_NUM_COUNTERS,
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 6ee925d66648..f760106c31f8 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -2191,10 +2191,13 @@ void __init sev_hardware_setup(void)
/*
* SEV must obviously be supported in hardware. Sanity check that the
* CPU supports decode assists, which is mandatory for SEV guests to
- * support instruction emulation.
+ * support instruction emulation. Ditto for flushing by ASID, as SEV
+ * guests are bound to a single ASID, i.e. KVM can't rotate to a new
+ * ASID to effect a TLB flush.
*/
if (!boot_cpu_has(X86_FEATURE_SEV) ||
- WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_DECODEASSISTS)))
+ WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_DECODEASSISTS)) ||
+ WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_FLUSHBYASID)))
goto out;
/* Retrieve SEV CPUID information */
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 7fb51424fc74..e90b429c84f1 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3563,8 +3563,15 @@ static void svm_inject_nmi(struct kvm_vcpu *vcpu)
if (svm->nmi_l1_to_l2)
return;
- svm->nmi_masked = true;
- svm_set_iret_intercept(svm);
+ /*
+ * No need to manually track NMI masking when vNMI is enabled, hardware
+ * automatically sets V_NMI_BLOCKING_MASK as appropriate, including the
+ * case where software directly injects an NMI.
+ */
+ if (!is_vnmi_enabled(svm)) {
+ svm->nmi_masked = true;
+ svm_set_iret_intercept(svm);
+ }
++vcpu->stat.nmi_injections;
}
@@ -5079,6 +5086,13 @@ static __init void svm_set_cpu_caps(void)
kvm_cpu_cap_set(X86_FEATURE_SVM);
kvm_cpu_cap_set(X86_FEATURE_VMCBCLEAN);
+ /*
+ * KVM currently flushes TLBs on *every* nested SVM transition,
+ * and so for all intents and purposes KVM supports flushing by
+ * ASID, i.e. KVM is guaranteed to honor every L1 ASID flush.
+ */
+ kvm_cpu_cap_set(X86_FEATURE_FLUSHBYASID);
+
if (nrips)
kvm_cpu_cap_set(X86_FEATURE_NRIPS);
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index c409f934c377..8ef95139cd24 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -148,7 +148,9 @@ struct vmcb_ctrl_area_cached {
u64 virt_ext;
u32 clean;
union {
+#if IS_ENABLED(CONFIG_HYPERV) || IS_ENABLED(CONFIG_KVM_HYPERV)
struct hv_vmcb_enlightenments hv_enlightenments;
+#endif
u8 reserved_sw[32];
};
};
diff --git a/arch/x86/kvm/svm/svm_onhyperv.c b/arch/x86/kvm/svm/svm_onhyperv.c
index 7af8422d3382..3971b3ea5d04 100644
--- a/arch/x86/kvm/svm/svm_onhyperv.c
+++ b/arch/x86/kvm/svm/svm_onhyperv.c
@@ -18,18 +18,14 @@
int svm_hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu)
{
struct hv_vmcb_enlightenments *hve;
- struct hv_partition_assist_pg **p_hv_pa_pg =
- &to_kvm_hv(vcpu->kvm)->hv_pa_pg;
+ hpa_t partition_assist_page = hv_get_partition_assist_page(vcpu);
- if (!*p_hv_pa_pg)
- *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL);
-
- if (!*p_hv_pa_pg)
+ if (partition_assist_page == INVALID_PAGE)
return -ENOMEM;
hve = &to_svm(vcpu)->vmcb->control.hv_enlightenments;
- hve->partition_assist_page = __pa(*p_hv_pa_pg);
+ hve->partition_assist_page = partition_assist_page;
hve->hv_vm_id = (unsigned long)vcpu->kvm;
if (!hve->hv_enlightenments_control.nested_flush_hypercall) {
hve->hv_enlightenments_control.nested_flush_hypercall = 1;
diff --git a/arch/x86/kvm/svm/vmenter.S b/arch/x86/kvm/svm/vmenter.S
index ef2ebabb059c..9499f9c6b077 100644
--- a/arch/x86/kvm/svm/vmenter.S
+++ b/arch/x86/kvm/svm/vmenter.S
@@ -270,16 +270,16 @@ SYM_FUNC_START(__svm_vcpu_run)
RESTORE_GUEST_SPEC_CTRL_BODY
RESTORE_HOST_SPEC_CTRL_BODY
-10: cmpb $0, kvm_rebooting
+10: cmpb $0, _ASM_RIP(kvm_rebooting)
jne 2b
ud2
-30: cmpb $0, kvm_rebooting
+30: cmpb $0, _ASM_RIP(kvm_rebooting)
jne 4b
ud2
-50: cmpb $0, kvm_rebooting
+50: cmpb $0, _ASM_RIP(kvm_rebooting)
jne 6b
ud2
-70: cmpb $0, kvm_rebooting
+70: cmpb $0, _ASM_RIP(kvm_rebooting)
jne 8b
ud2
@@ -381,7 +381,7 @@ SYM_FUNC_START(__svm_sev_es_vcpu_run)
RESTORE_GUEST_SPEC_CTRL_BODY
RESTORE_HOST_SPEC_CTRL_BODY
-3: cmpb $0, kvm_rebooting
+3: cmpb $0, _ASM_RIP(kvm_rebooting)
jne 2b
ud2
diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c
index 313b8bb5b8a7..fab6a1ad98dc 100644
--- a/arch/x86/kvm/vmx/hyperv.c
+++ b/arch/x86/kvm/vmx/hyperv.c
@@ -13,419 +13,6 @@
#define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK
-/*
- * Enlightened VMCSv1 doesn't support these:
- *
- * POSTED_INTR_NV = 0x00000002,
- * GUEST_INTR_STATUS = 0x00000810,
- * APIC_ACCESS_ADDR = 0x00002014,
- * POSTED_INTR_DESC_ADDR = 0x00002016,
- * EOI_EXIT_BITMAP0 = 0x0000201c,
- * EOI_EXIT_BITMAP1 = 0x0000201e,
- * EOI_EXIT_BITMAP2 = 0x00002020,
- * EOI_EXIT_BITMAP3 = 0x00002022,
- * GUEST_PML_INDEX = 0x00000812,
- * PML_ADDRESS = 0x0000200e,
- * VM_FUNCTION_CONTROL = 0x00002018,
- * EPTP_LIST_ADDRESS = 0x00002024,
- * VMREAD_BITMAP = 0x00002026,
- * VMWRITE_BITMAP = 0x00002028,
- *
- * TSC_MULTIPLIER = 0x00002032,
- * PLE_GAP = 0x00004020,
- * PLE_WINDOW = 0x00004022,
- * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
- *
- * Currently unsupported in KVM:
- * GUEST_IA32_RTIT_CTL = 0x00002814,
- */
-#define EVMCS1_SUPPORTED_PINCTRL \
- (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
- PIN_BASED_EXT_INTR_MASK | \
- PIN_BASED_NMI_EXITING | \
- PIN_BASED_VIRTUAL_NMIS)
-
-#define EVMCS1_SUPPORTED_EXEC_CTRL \
- (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
- CPU_BASED_HLT_EXITING | \
- CPU_BASED_CR3_LOAD_EXITING | \
- CPU_BASED_CR3_STORE_EXITING | \
- CPU_BASED_UNCOND_IO_EXITING | \
- CPU_BASED_MOV_DR_EXITING | \
- CPU_BASED_USE_TSC_OFFSETTING | \
- CPU_BASED_MWAIT_EXITING | \
- CPU_BASED_MONITOR_EXITING | \
- CPU_BASED_INVLPG_EXITING | \
- CPU_BASED_RDPMC_EXITING | \
- CPU_BASED_INTR_WINDOW_EXITING | \
- CPU_BASED_CR8_LOAD_EXITING | \
- CPU_BASED_CR8_STORE_EXITING | \
- CPU_BASED_RDTSC_EXITING | \
- CPU_BASED_TPR_SHADOW | \
- CPU_BASED_USE_IO_BITMAPS | \
- CPU_BASED_MONITOR_TRAP_FLAG | \
- CPU_BASED_USE_MSR_BITMAPS | \
- CPU_BASED_NMI_WINDOW_EXITING | \
- CPU_BASED_PAUSE_EXITING | \
- CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
-
-#define EVMCS1_SUPPORTED_2NDEXEC \
- (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
- SECONDARY_EXEC_WBINVD_EXITING | \
- SECONDARY_EXEC_ENABLE_VPID | \
- SECONDARY_EXEC_ENABLE_EPT | \
- SECONDARY_EXEC_UNRESTRICTED_GUEST | \
- SECONDARY_EXEC_DESC | \
- SECONDARY_EXEC_ENABLE_RDTSCP | \
- SECONDARY_EXEC_ENABLE_INVPCID | \
- SECONDARY_EXEC_ENABLE_XSAVES | \
- SECONDARY_EXEC_RDSEED_EXITING | \
- SECONDARY_EXEC_RDRAND_EXITING | \
- SECONDARY_EXEC_TSC_SCALING | \
- SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
- SECONDARY_EXEC_PT_USE_GPA | \
- SECONDARY_EXEC_PT_CONCEAL_VMX | \
- SECONDARY_EXEC_BUS_LOCK_DETECTION | \
- SECONDARY_EXEC_NOTIFY_VM_EXITING | \
- SECONDARY_EXEC_ENCLS_EXITING)
-
-#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
-
-#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
- (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
- VM_EXIT_SAVE_DEBUG_CONTROLS | \
- VM_EXIT_ACK_INTR_ON_EXIT | \
- VM_EXIT_HOST_ADDR_SPACE_SIZE | \
- VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
- VM_EXIT_SAVE_IA32_PAT | \
- VM_EXIT_LOAD_IA32_PAT | \
- VM_EXIT_SAVE_IA32_EFER | \
- VM_EXIT_LOAD_IA32_EFER | \
- VM_EXIT_CLEAR_BNDCFGS | \
- VM_EXIT_PT_CONCEAL_PIP | \
- VM_EXIT_CLEAR_IA32_RTIT_CTL)
-
-#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
- (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
- VM_ENTRY_LOAD_DEBUG_CONTROLS | \
- VM_ENTRY_IA32E_MODE | \
- VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \
- VM_ENTRY_LOAD_IA32_PAT | \
- VM_ENTRY_LOAD_IA32_EFER | \
- VM_ENTRY_LOAD_BNDCFGS | \
- VM_ENTRY_PT_CONCEAL_PIP | \
- VM_ENTRY_LOAD_IA32_RTIT_CTL)
-
-#define EVMCS1_SUPPORTED_VMFUNC (0)
-
-#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
-#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
- {EVMCS1_OFFSET(name), clean_field}
-
-const struct evmcs_field vmcs_field_to_evmcs_1[] = {
- /* 64 bit rw */
- EVMCS1_FIELD(GUEST_RIP, guest_rip,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(GUEST_RSP, guest_rsp,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
- EVMCS1_FIELD(GUEST_RFLAGS, guest_rflags,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
- EVMCS1_FIELD(HOST_IA32_PAT, host_ia32_pat,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_IA32_EFER, host_ia32_efer,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_CR0, host_cr0,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_CR3, host_cr3,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_CR4, host_cr4,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_RIP, host_rip,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(IO_BITMAP_A, io_bitmap_a,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
- EVMCS1_FIELD(IO_BITMAP_B, io_bitmap_b,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
- EVMCS1_FIELD(MSR_BITMAP, msr_bitmap,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP),
- EVMCS1_FIELD(GUEST_ES_BASE, guest_es_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_CS_BASE, guest_cs_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_SS_BASE, guest_ss_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_DS_BASE, guest_ds_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_FS_BASE, guest_fs_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_GS_BASE, guest_gs_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_LDTR_BASE, guest_ldtr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_TR_BASE, guest_tr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_GDTR_BASE, guest_gdtr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_IDTR_BASE, guest_idtr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(TSC_OFFSET, tsc_offset,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
- EVMCS1_FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
- EVMCS1_FIELD(VMCS_LINK_POINTER, vmcs_link_pointer,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_IA32_PAT, guest_ia32_pat,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_IA32_EFER, guest_ia32_efer,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_PDPTR0, guest_pdptr0,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_PDPTR1, guest_pdptr1,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_PDPTR2, guest_pdptr2,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_PDPTR3, guest_pdptr3,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(CR0_READ_SHADOW, cr0_read_shadow,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(CR4_READ_SHADOW, cr4_read_shadow,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(GUEST_CR0, guest_cr0,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(GUEST_CR3, guest_cr3,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(GUEST_CR4, guest_cr4,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(GUEST_DR7, guest_dr7,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
- EVMCS1_FIELD(HOST_FS_BASE, host_fs_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
- EVMCS1_FIELD(HOST_GS_BASE, host_gs_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
- EVMCS1_FIELD(HOST_TR_BASE, host_tr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
- EVMCS1_FIELD(HOST_GDTR_BASE, host_gdtr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
- EVMCS1_FIELD(HOST_IDTR_BASE, host_idtr_base,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
- EVMCS1_FIELD(HOST_RSP, host_rsp,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
- EVMCS1_FIELD(EPT_POINTER, ept_pointer,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
- EVMCS1_FIELD(GUEST_BNDCFGS, guest_bndcfgs,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(XSS_EXIT_BITMAP, xss_exit_bitmap,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
- EVMCS1_FIELD(ENCLS_EXITING_BITMAP, encls_exiting_bitmap,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
- EVMCS1_FIELD(TSC_MULTIPLIER, tsc_multiplier,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
- /*
- * Not used by KVM:
- *
- * EVMCS1_FIELD(0x00006828, guest_ia32_s_cet,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- * EVMCS1_FIELD(0x0000682A, guest_ssp,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
- * EVMCS1_FIELD(0x0000682C, guest_ia32_int_ssp_table_addr,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- * EVMCS1_FIELD(0x00002816, guest_ia32_lbr_ctl,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- * EVMCS1_FIELD(0x00006C18, host_ia32_s_cet,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- * EVMCS1_FIELD(0x00006C1A, host_ssp,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- * EVMCS1_FIELD(0x00006C1C, host_ia32_int_ssp_table_addr,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- */
-
- /* 64 bit read only */
- EVMCS1_FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(EXIT_QUALIFICATION, exit_qualification,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- /*
- * Not defined in KVM:
- *
- * EVMCS1_FIELD(0x00006402, exit_io_instruction_ecx,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
- * EVMCS1_FIELD(0x00006404, exit_io_instruction_esi,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
- * EVMCS1_FIELD(0x00006406, exit_io_instruction_esi,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
- * EVMCS1_FIELD(0x00006408, exit_io_instruction_eip,
- * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
- */
- EVMCS1_FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
-
- /*
- * No mask defined in the spec as Hyper-V doesn't currently support
- * these. Future proof by resetting the whole clean field mask on
- * access.
- */
- EVMCS1_FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
-
- /* 32 bit rw */
- EVMCS1_FIELD(TPR_THRESHOLD, tpr_threshold,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
- EVMCS1_FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC),
- EVMCS1_FIELD(EXCEPTION_BITMAP, exception_bitmap,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN),
- EVMCS1_FIELD(VM_ENTRY_CONTROLS, vm_entry_controls,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY),
- EVMCS1_FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
- EVMCS1_FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE,
- vm_entry_exception_error_code,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
- EVMCS1_FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
- EVMCS1_FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
- EVMCS1_FIELD(VM_EXIT_CONTROLS, vm_exit_controls,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
- EVMCS1_FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
- EVMCS1_FIELD(GUEST_ES_LIMIT, guest_es_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_CS_LIMIT, guest_cs_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_SS_LIMIT, guest_ss_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_DS_LIMIT, guest_ds_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_FS_LIMIT, guest_fs_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_GS_LIMIT, guest_gs_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_TR_LIMIT, guest_tr_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_ACTIVITY_STATE, guest_activity_state,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
- EVMCS1_FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
-
- /* 32 bit read only */
- EVMCS1_FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(VM_EXIT_REASON, vm_exit_reason,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
- EVMCS1_FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
-
- /* No mask defined in the spec (not used) */
- EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(CR3_TARGET_COUNT, cr3_target_count,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
- EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
-
- /* 16 bit rw */
- EVMCS1_FIELD(HOST_ES_SELECTOR, host_es_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_CS_SELECTOR, host_cs_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_SS_SELECTOR, host_ss_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_DS_SELECTOR, host_ds_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_FS_SELECTOR, host_fs_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_GS_SELECTOR, host_gs_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(HOST_TR_SELECTOR, host_tr_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
- EVMCS1_FIELD(GUEST_ES_SELECTOR, guest_es_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_CS_SELECTOR, guest_cs_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_SS_SELECTOR, guest_ss_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_DS_SELECTOR, guest_ds_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_FS_SELECTOR, guest_fs_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_GS_SELECTOR, guest_gs_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(GUEST_TR_SELECTOR, guest_tr_selector,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
- EVMCS1_FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id,
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
-};
-const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
-
u64 nested_get_evmptr(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
@@ -608,40 +195,6 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
return 0;
}
-#if IS_ENABLED(CONFIG_HYPERV)
-DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
-
-/*
- * KVM on Hyper-V always uses the latest known eVMCSv1 revision, the assumption
- * is: in case a feature has corresponding fields in eVMCS described and it was
- * exposed in VMX feature MSRs, KVM is free to use it. Warn if KVM meets a
- * feature which has no corresponding eVMCS field, this likely means that KVM
- * needs to be updated.
- */
-#define evmcs_check_vmcs_conf(field, ctrl) \
- do { \
- typeof(vmcs_conf->field) unsupported; \
- \
- unsupported = vmcs_conf->field & ~EVMCS1_SUPPORTED_ ## ctrl; \
- if (unsupported) { \
- pr_warn_once(#field " unsupported with eVMCS: 0x%llx\n",\
- (u64)unsupported); \
- vmcs_conf->field &= EVMCS1_SUPPORTED_ ## ctrl; \
- } \
- } \
- while (0)
-
-void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf)
-{
- evmcs_check_vmcs_conf(cpu_based_exec_ctrl, EXEC_CTRL);
- evmcs_check_vmcs_conf(pin_based_exec_ctrl, PINCTRL);
- evmcs_check_vmcs_conf(cpu_based_2nd_exec_ctrl, 2NDEXEC);
- evmcs_check_vmcs_conf(cpu_based_3rd_exec_ctrl, 3RDEXEC);
- evmcs_check_vmcs_conf(vmentry_ctrl, VMENTRY_CTRL);
- evmcs_check_vmcs_conf(vmexit_ctrl, VMEXIT_CTRL);
-}
-#endif
-
int nested_enable_evmcs(struct kvm_vcpu *vcpu,
uint16_t *vmcs_version)
{
diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h
index 9623fe1651c4..a87407412615 100644
--- a/arch/x86/kvm/vmx/hyperv.h
+++ b/arch/x86/kvm/vmx/hyperv.h
@@ -2,199 +2,89 @@
#ifndef __KVM_X86_VMX_HYPERV_H
#define __KVM_X86_VMX_HYPERV_H
-#include <linux/jump_label.h>
-
-#include <asm/hyperv-tlfs.h>
-#include <asm/mshyperv.h>
-#include <asm/vmx.h>
-
-#include "../hyperv.h"
-
-#include "capabilities.h"
-#include "vmcs.h"
+#include <linux/kvm_host.h>
#include "vmcs12.h"
+#include "vmx.h"
-struct vmcs_config;
-
-#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs))
-
-#define KVM_EVMCS_VERSION 1
+#define EVMPTR_INVALID (-1ULL)
+#define EVMPTR_MAP_PENDING (-2ULL)
-struct evmcs_field {
- u16 offset;
- u16 clean_field;
+enum nested_evmptrld_status {
+ EVMPTRLD_DISABLED,
+ EVMPTRLD_SUCCEEDED,
+ EVMPTRLD_VMFAIL,
+ EVMPTRLD_ERROR,
};
-extern const struct evmcs_field vmcs_field_to_evmcs_1[];
-extern const unsigned int nr_evmcs_1_fields;
-
-static __always_inline int evmcs_field_offset(unsigned long field,
- u16 *clean_field)
-{
- unsigned int index = ROL16(field, 6);
- const struct evmcs_field *evmcs_field;
-
- if (unlikely(index >= nr_evmcs_1_fields))
- return -ENOENT;
-
- evmcs_field = &vmcs_field_to_evmcs_1[index];
-
- /*
- * Use offset=0 to detect holes in eVMCS. This offset belongs to
- * 'revision_id' but this field has no encoding and is supposed to
- * be accessed directly.
- */
- if (unlikely(!evmcs_field->offset))
- return -ENOENT;
-
- if (clean_field)
- *clean_field = evmcs_field->clean_field;
-
- return evmcs_field->offset;
-}
-
-static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
- unsigned long field, u16 offset)
+#ifdef CONFIG_KVM_HYPERV
+static inline bool evmptr_is_valid(u64 evmptr)
{
- /*
- * vmcs12_read_any() doesn't care whether the supplied structure
- * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes
- * the exact offset of the required field, use it for convenience
- * here.
- */
- return vmcs12_read_any((void *)evmcs, field, offset);
+ return evmptr != EVMPTR_INVALID && evmptr != EVMPTR_MAP_PENDING;
}
-#if IS_ENABLED(CONFIG_HYPERV)
-
-DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
-
-static __always_inline bool kvm_is_using_evmcs(void)
+static inline bool nested_vmx_is_evmptr12_valid(struct vcpu_vmx *vmx)
{
- return static_branch_unlikely(&__kvm_is_using_evmcs);
+ return evmptr_is_valid(vmx->nested.hv_evmcs_vmptr);
}
-static __always_inline int get_evmcs_offset(unsigned long field,
- u16 *clean_field)
+static inline bool evmptr_is_set(u64 evmptr)
{
- int offset = evmcs_field_offset(field, clean_field);
-
- WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field);
- return offset;
+ return evmptr != EVMPTR_INVALID;
}
-static __always_inline void evmcs_write64(unsigned long field, u64 value)
+static inline bool nested_vmx_is_evmptr12_set(struct vcpu_vmx *vmx)
{
- u16 clean_field;
- int offset = get_evmcs_offset(field, &clean_field);
-
- if (offset < 0)
- return;
-
- *(u64 *)((char *)current_evmcs + offset) = value;
-
- current_evmcs->hv_clean_fields &= ~clean_field;
+ return evmptr_is_set(vmx->nested.hv_evmcs_vmptr);
}
-static __always_inline void evmcs_write32(unsigned long field, u32 value)
+static inline struct hv_enlightened_vmcs *nested_vmx_evmcs(struct vcpu_vmx *vmx)
{
- u16 clean_field;
- int offset = get_evmcs_offset(field, &clean_field);
-
- if (offset < 0)
- return;
-
- *(u32 *)((char *)current_evmcs + offset) = value;
- current_evmcs->hv_clean_fields &= ~clean_field;
+ return vmx->nested.hv_evmcs;
}
-static __always_inline void evmcs_write16(unsigned long field, u16 value)
+static inline bool guest_cpuid_has_evmcs(struct kvm_vcpu *vcpu)
{
- u16 clean_field;
- int offset = get_evmcs_offset(field, &clean_field);
-
- if (offset < 0)
- return;
-
- *(u16 *)((char *)current_evmcs + offset) = value;
- current_evmcs->hv_clean_fields &= ~clean_field;
+ /*
+ * eVMCS is exposed to the guest if Hyper-V is enabled in CPUID and
+ * eVMCS has been explicitly enabled by userspace.
+ */
+ return vcpu->arch.hyperv_enabled &&
+ to_vmx(vcpu)->nested.enlightened_vmcs_enabled;
}
-static __always_inline u64 evmcs_read64(unsigned long field)
+u64 nested_get_evmptr(struct kvm_vcpu *vcpu);
+uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
+int nested_enable_evmcs(struct kvm_vcpu *vcpu,
+ uint16_t *vmcs_version);
+void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
+int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
+bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu);
+void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
+#else
+static inline bool evmptr_is_valid(u64 evmptr)
{
- int offset = get_evmcs_offset(field, NULL);
-
- if (offset < 0)
- return 0;
-
- return *(u64 *)((char *)current_evmcs + offset);
+ return false;
}
-static __always_inline u32 evmcs_read32(unsigned long field)
+static inline bool nested_vmx_is_evmptr12_valid(struct vcpu_vmx *vmx)
{
- int offset = get_evmcs_offset(field, NULL);
-
- if (offset < 0)
- return 0;
-
- return *(u32 *)((char *)current_evmcs + offset);
+ return false;
}
-static __always_inline u16 evmcs_read16(unsigned long field)
+static inline bool evmptr_is_set(u64 evmptr)
{
- int offset = get_evmcs_offset(field, NULL);
-
- if (offset < 0)
- return 0;
-
- return *(u16 *)((char *)current_evmcs + offset);
+ return false;
}
-static inline void evmcs_load(u64 phys_addr)
+static inline bool nested_vmx_is_evmptr12_set(struct vcpu_vmx *vmx)
{
- struct hv_vp_assist_page *vp_ap =
- hv_get_vp_assist_page(smp_processor_id());
-
- if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall)
- vp_ap->nested_control.features.directhypercall = 1;
- vp_ap->current_nested_vmcs = phys_addr;
- vp_ap->enlighten_vmentry = 1;
+ return false;
}
-void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
-#else /* !IS_ENABLED(CONFIG_HYPERV) */
-static __always_inline bool kvm_is_using_evmcs(void) { return false; }
-static __always_inline void evmcs_write64(unsigned long field, u64 value) {}
-static __always_inline void evmcs_write32(unsigned long field, u32 value) {}
-static __always_inline void evmcs_write16(unsigned long field, u16 value) {}
-static __always_inline u64 evmcs_read64(unsigned long field) { return 0; }
-static __always_inline u32 evmcs_read32(unsigned long field) { return 0; }
-static __always_inline u16 evmcs_read16(unsigned long field) { return 0; }
-static inline void evmcs_load(u64 phys_addr) {}
-#endif /* IS_ENABLED(CONFIG_HYPERV) */
-
-#define EVMPTR_INVALID (-1ULL)
-#define EVMPTR_MAP_PENDING (-2ULL)
-
-static inline bool evmptr_is_valid(u64 evmptr)
+static inline struct hv_enlightened_vmcs *nested_vmx_evmcs(struct vcpu_vmx *vmx)
{
- return evmptr != EVMPTR_INVALID && evmptr != EVMPTR_MAP_PENDING;
+ return NULL;
}
-
-enum nested_evmptrld_status {
- EVMPTRLD_DISABLED,
- EVMPTRLD_SUCCEEDED,
- EVMPTRLD_VMFAIL,
- EVMPTRLD_ERROR,
-};
-
-u64 nested_get_evmptr(struct kvm_vcpu *vcpu);
-uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu);
-int nested_enable_evmcs(struct kvm_vcpu *vcpu,
- uint16_t *vmcs_version);
-void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata);
-int nested_evmcs_check_controls(struct vmcs12 *vmcs12);
-bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu);
-void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu);
+#endif
#endif /* __KVM_X86_VMX_HYPERV_H */
diff --git a/arch/x86/kvm/vmx/hyperv_evmcs.c b/arch/x86/kvm/vmx/hyperv_evmcs.c
new file mode 100644
index 000000000000..904bfcd1519b
--- /dev/null
+++ b/arch/x86/kvm/vmx/hyperv_evmcs.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file contains common code for working with Enlightened VMCS which is
+ * used both by Hyper-V on KVM and KVM on Hyper-V.
+ */
+
+#include "hyperv_evmcs.h"
+
+#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x)
+#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \
+ {EVMCS1_OFFSET(name), clean_field}
+
+const struct evmcs_field vmcs_field_to_evmcs_1[] = {
+ /* 64 bit rw */
+ EVMCS1_FIELD(GUEST_RIP, guest_rip,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(GUEST_RSP, guest_rsp,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
+ EVMCS1_FIELD(GUEST_RFLAGS, guest_rflags,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
+ EVMCS1_FIELD(HOST_IA32_PAT, host_ia32_pat,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_IA32_EFER, host_ia32_efer,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_CR0, host_cr0,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_CR3, host_cr3,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_CR4, host_cr4,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_RIP, host_rip,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(IO_BITMAP_A, io_bitmap_a,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
+ EVMCS1_FIELD(IO_BITMAP_B, io_bitmap_b,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP),
+ EVMCS1_FIELD(MSR_BITMAP, msr_bitmap,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP),
+ EVMCS1_FIELD(GUEST_ES_BASE, guest_es_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_CS_BASE, guest_cs_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_SS_BASE, guest_ss_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_DS_BASE, guest_ds_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_FS_BASE, guest_fs_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_GS_BASE, guest_gs_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_LDTR_BASE, guest_ldtr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_TR_BASE, guest_tr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_GDTR_BASE, guest_gdtr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_IDTR_BASE, guest_idtr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(TSC_OFFSET, tsc_offset,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
+ EVMCS1_FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
+ EVMCS1_FIELD(VMCS_LINK_POINTER, vmcs_link_pointer,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_IA32_PAT, guest_ia32_pat,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_IA32_EFER, guest_ia32_efer,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_PDPTR0, guest_pdptr0,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_PDPTR1, guest_pdptr1,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_PDPTR2, guest_pdptr2,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_PDPTR3, guest_pdptr3,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(CR0_READ_SHADOW, cr0_read_shadow,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(CR4_READ_SHADOW, cr4_read_shadow,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(GUEST_CR0, guest_cr0,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(GUEST_CR3, guest_cr3,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(GUEST_CR4, guest_cr4,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(GUEST_DR7, guest_dr7,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR),
+ EVMCS1_FIELD(HOST_FS_BASE, host_fs_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
+ EVMCS1_FIELD(HOST_GS_BASE, host_gs_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
+ EVMCS1_FIELD(HOST_TR_BASE, host_tr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
+ EVMCS1_FIELD(HOST_GDTR_BASE, host_gdtr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
+ EVMCS1_FIELD(HOST_IDTR_BASE, host_idtr_base,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
+ EVMCS1_FIELD(HOST_RSP, host_rsp,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER),
+ EVMCS1_FIELD(EPT_POINTER, ept_pointer,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
+ EVMCS1_FIELD(GUEST_BNDCFGS, guest_bndcfgs,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(XSS_EXIT_BITMAP, xss_exit_bitmap,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
+ EVMCS1_FIELD(ENCLS_EXITING_BITMAP, encls_exiting_bitmap,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
+ EVMCS1_FIELD(TSC_MULTIPLIER, tsc_multiplier,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2),
+ /*
+ * Not used by KVM:
+ *
+ * EVMCS1_FIELD(0x00006828, guest_ia32_s_cet,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ * EVMCS1_FIELD(0x0000682A, guest_ssp,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
+ * EVMCS1_FIELD(0x0000682C, guest_ia32_int_ssp_table_addr,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ * EVMCS1_FIELD(0x00002816, guest_ia32_lbr_ctl,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ * EVMCS1_FIELD(0x00006C18, host_ia32_s_cet,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ * EVMCS1_FIELD(0x00006C1A, host_ssp,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ * EVMCS1_FIELD(0x00006C1C, host_ia32_int_ssp_table_addr,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ */
+
+ /* 64 bit read only */
+ EVMCS1_FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(EXIT_QUALIFICATION, exit_qualification,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ /*
+ * Not defined in KVM:
+ *
+ * EVMCS1_FIELD(0x00006402, exit_io_instruction_ecx,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
+ * EVMCS1_FIELD(0x00006404, exit_io_instruction_esi,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
+ * EVMCS1_FIELD(0x00006406, exit_io_instruction_esi,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
+ * EVMCS1_FIELD(0x00006408, exit_io_instruction_eip,
+ * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE);
+ */
+ EVMCS1_FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+
+ /*
+ * No mask defined in the spec as Hyper-V doesn't currently support
+ * these. Future proof by resetting the whole clean field mask on
+ * access.
+ */
+ EVMCS1_FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+
+ /* 32 bit rw */
+ EVMCS1_FIELD(TPR_THRESHOLD, tpr_threshold,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC),
+ EVMCS1_FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC),
+ EVMCS1_FIELD(EXCEPTION_BITMAP, exception_bitmap,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN),
+ EVMCS1_FIELD(VM_ENTRY_CONTROLS, vm_entry_controls,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY),
+ EVMCS1_FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
+ EVMCS1_FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE,
+ vm_entry_exception_error_code,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
+ EVMCS1_FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT),
+ EVMCS1_FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
+ EVMCS1_FIELD(VM_EXIT_CONTROLS, vm_exit_controls,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
+ EVMCS1_FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1),
+ EVMCS1_FIELD(GUEST_ES_LIMIT, guest_es_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_CS_LIMIT, guest_cs_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_SS_LIMIT, guest_ss_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_DS_LIMIT, guest_ds_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_FS_LIMIT, guest_fs_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_GS_LIMIT, guest_gs_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_TR_LIMIT, guest_tr_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_ACTIVITY_STATE, guest_activity_state,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+ EVMCS1_FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1),
+
+ /* 32 bit read only */
+ EVMCS1_FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(VM_EXIT_REASON, vm_exit_reason,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+ EVMCS1_FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE),
+
+ /* No mask defined in the spec (not used) */
+ EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(CR3_TARGET_COUNT, cr3_target_count,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+ EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL),
+
+ /* 16 bit rw */
+ EVMCS1_FIELD(HOST_ES_SELECTOR, host_es_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_CS_SELECTOR, host_cs_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_SS_SELECTOR, host_ss_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_DS_SELECTOR, host_ds_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_FS_SELECTOR, host_fs_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_GS_SELECTOR, host_gs_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(HOST_TR_SELECTOR, host_tr_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1),
+ EVMCS1_FIELD(GUEST_ES_SELECTOR, guest_es_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_CS_SELECTOR, guest_cs_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_SS_SELECTOR, guest_ss_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_DS_SELECTOR, guest_ds_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_FS_SELECTOR, guest_fs_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_GS_SELECTOR, guest_gs_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(GUEST_TR_SELECTOR, guest_tr_selector,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2),
+ EVMCS1_FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id,
+ HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT),
+};
+const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1);
diff --git a/arch/x86/kvm/vmx/hyperv_evmcs.h b/arch/x86/kvm/vmx/hyperv_evmcs.h
new file mode 100644
index 000000000000..a543fccfc574
--- /dev/null
+++ b/arch/x86/kvm/vmx/hyperv_evmcs.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file contains common definitions for working with Enlightened VMCS which
+ * are used both by Hyper-V on KVM and KVM on Hyper-V.
+ */
+#ifndef __KVM_X86_VMX_HYPERV_EVMCS_H
+#define __KVM_X86_VMX_HYPERV_EVMCS_H
+
+#include <asm/hyperv-tlfs.h>
+
+#include "capabilities.h"
+#include "vmcs12.h"
+
+#define KVM_EVMCS_VERSION 1
+
+/*
+ * Enlightened VMCSv1 doesn't support these:
+ *
+ * POSTED_INTR_NV = 0x00000002,
+ * GUEST_INTR_STATUS = 0x00000810,
+ * APIC_ACCESS_ADDR = 0x00002014,
+ * POSTED_INTR_DESC_ADDR = 0x00002016,
+ * EOI_EXIT_BITMAP0 = 0x0000201c,
+ * EOI_EXIT_BITMAP1 = 0x0000201e,
+ * EOI_EXIT_BITMAP2 = 0x00002020,
+ * EOI_EXIT_BITMAP3 = 0x00002022,
+ * GUEST_PML_INDEX = 0x00000812,
+ * PML_ADDRESS = 0x0000200e,
+ * VM_FUNCTION_CONTROL = 0x00002018,
+ * EPTP_LIST_ADDRESS = 0x00002024,
+ * VMREAD_BITMAP = 0x00002026,
+ * VMWRITE_BITMAP = 0x00002028,
+ *
+ * TSC_MULTIPLIER = 0x00002032,
+ * PLE_GAP = 0x00004020,
+ * PLE_WINDOW = 0x00004022,
+ * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
+ *
+ * Currently unsupported in KVM:
+ * GUEST_IA32_RTIT_CTL = 0x00002814,
+ */
+#define EVMCS1_SUPPORTED_PINCTRL \
+ (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
+ PIN_BASED_EXT_INTR_MASK | \
+ PIN_BASED_NMI_EXITING | \
+ PIN_BASED_VIRTUAL_NMIS)
+
+#define EVMCS1_SUPPORTED_EXEC_CTRL \
+ (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \
+ CPU_BASED_HLT_EXITING | \
+ CPU_BASED_CR3_LOAD_EXITING | \
+ CPU_BASED_CR3_STORE_EXITING | \
+ CPU_BASED_UNCOND_IO_EXITING | \
+ CPU_BASED_MOV_DR_EXITING | \
+ CPU_BASED_USE_TSC_OFFSETTING | \
+ CPU_BASED_MWAIT_EXITING | \
+ CPU_BASED_MONITOR_EXITING | \
+ CPU_BASED_INVLPG_EXITING | \
+ CPU_BASED_RDPMC_EXITING | \
+ CPU_BASED_INTR_WINDOW_EXITING | \
+ CPU_BASED_CR8_LOAD_EXITING | \
+ CPU_BASED_CR8_STORE_EXITING | \
+ CPU_BASED_RDTSC_EXITING | \
+ CPU_BASED_TPR_SHADOW | \
+ CPU_BASED_USE_IO_BITMAPS | \
+ CPU_BASED_MONITOR_TRAP_FLAG | \
+ CPU_BASED_USE_MSR_BITMAPS | \
+ CPU_BASED_NMI_WINDOW_EXITING | \
+ CPU_BASED_PAUSE_EXITING | \
+ CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)
+
+#define EVMCS1_SUPPORTED_2NDEXEC \
+ (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \
+ SECONDARY_EXEC_WBINVD_EXITING | \
+ SECONDARY_EXEC_ENABLE_VPID | \
+ SECONDARY_EXEC_ENABLE_EPT | \
+ SECONDARY_EXEC_UNRESTRICTED_GUEST | \
+ SECONDARY_EXEC_DESC | \
+ SECONDARY_EXEC_ENABLE_RDTSCP | \
+ SECONDARY_EXEC_ENABLE_INVPCID | \
+ SECONDARY_EXEC_ENABLE_XSAVES | \
+ SECONDARY_EXEC_RDSEED_EXITING | \
+ SECONDARY_EXEC_RDRAND_EXITING | \
+ SECONDARY_EXEC_TSC_SCALING | \
+ SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \
+ SECONDARY_EXEC_PT_USE_GPA | \
+ SECONDARY_EXEC_PT_CONCEAL_VMX | \
+ SECONDARY_EXEC_BUS_LOCK_DETECTION | \
+ SECONDARY_EXEC_NOTIFY_VM_EXITING | \
+ SECONDARY_EXEC_ENCLS_EXITING)
+
+#define EVMCS1_SUPPORTED_3RDEXEC (0ULL)
+
+#define EVMCS1_SUPPORTED_VMEXIT_CTRL \
+ (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \
+ VM_EXIT_SAVE_DEBUG_CONTROLS | \
+ VM_EXIT_ACK_INTR_ON_EXIT | \
+ VM_EXIT_HOST_ADDR_SPACE_SIZE | \
+ VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \
+ VM_EXIT_SAVE_IA32_PAT | \
+ VM_EXIT_LOAD_IA32_PAT | \
+ VM_EXIT_SAVE_IA32_EFER | \
+ VM_EXIT_LOAD_IA32_EFER | \
+ VM_EXIT_CLEAR_BNDCFGS | \
+ VM_EXIT_PT_CONCEAL_PIP | \
+ VM_EXIT_CLEAR_IA32_RTIT_CTL)
+
+#define EVMCS1_SUPPORTED_VMENTRY_CTRL \
+ (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \
+ VM_ENTRY_LOAD_DEBUG_CONTROLS | \
+ VM_ENTRY_IA32E_MODE | \
+ VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \
+ VM_ENTRY_LOAD_IA32_PAT | \
+ VM_ENTRY_LOAD_IA32_EFER | \
+ VM_ENTRY_LOAD_BNDCFGS | \
+ VM_ENTRY_PT_CONCEAL_PIP | \
+ VM_ENTRY_LOAD_IA32_RTIT_CTL)
+
+#define EVMCS1_SUPPORTED_VMFUNC (0)
+
+struct evmcs_field {
+ u16 offset;
+ u16 clean_field;
+};
+
+extern const struct evmcs_field vmcs_field_to_evmcs_1[];
+extern const unsigned int nr_evmcs_1_fields;
+
+static __always_inline int evmcs_field_offset(unsigned long field,
+ u16 *clean_field)
+{
+ const struct evmcs_field *evmcs_field;
+ unsigned int index = ROL16(field, 6);
+
+ if (unlikely(index >= nr_evmcs_1_fields))
+ return -ENOENT;
+
+ evmcs_field = &vmcs_field_to_evmcs_1[index];
+
+ /*
+ * Use offset=0 to detect holes in eVMCS. This offset belongs to
+ * 'revision_id' but this field has no encoding and is supposed to
+ * be accessed directly.
+ */
+ if (unlikely(!evmcs_field->offset))
+ return -ENOENT;
+
+ if (clean_field)
+ *clean_field = evmcs_field->clean_field;
+
+ return evmcs_field->offset;
+}
+
+static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs,
+ unsigned long field, u16 offset)
+{
+ /*
+ * vmcs12_read_any() doesn't care whether the supplied structure
+ * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes
+ * the exact offset of the required field, use it for convenience
+ * here.
+ */
+ return vmcs12_read_any((void *)evmcs, field, offset);
+}
+
+#endif /* __KVM_X86_VMX_HYPERV_H */
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 65826fe23f33..6329a306856b 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -179,7 +179,7 @@ static int nested_vmx_failValid(struct kvm_vcpu *vcpu,
* VM_INSTRUCTION_ERROR is not shadowed. Enlightened VMCS 'shadows' all
* fields and thus must be synced.
*/
- if (to_vmx(vcpu)->nested.hv_evmcs_vmptr != EVMPTR_INVALID)
+ if (nested_vmx_is_evmptr12_set(to_vmx(vcpu)))
to_vmx(vcpu)->nested.need_vmcs12_to_shadow_sync = true;
return kvm_skip_emulated_instruction(vcpu);
@@ -194,7 +194,7 @@ static int nested_vmx_fail(struct kvm_vcpu *vcpu, u32 vm_instruction_error)
* can't be done if there isn't a current VMCS.
*/
if (vmx->nested.current_vmptr == INVALID_GPA &&
- !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ !nested_vmx_is_evmptr12_valid(vmx))
return nested_vmx_failInvalid(vcpu);
return nested_vmx_failValid(vcpu, vm_instruction_error);
@@ -226,10 +226,11 @@ static void vmx_disable_shadow_vmcs(struct vcpu_vmx *vmx)
static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
{
+#ifdef CONFIG_KVM_HYPERV
struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu);
struct vcpu_vmx *vmx = to_vmx(vcpu);
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
+ if (nested_vmx_is_evmptr12_valid(vmx)) {
kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map, true);
vmx->nested.hv_evmcs = NULL;
}
@@ -241,6 +242,34 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
hv_vcpu->nested.vm_id = 0;
hv_vcpu->nested.vp_id = 0;
}
+#endif
+}
+
+static bool nested_evmcs_handle_vmclear(struct kvm_vcpu *vcpu, gpa_t vmptr)
+{
+#ifdef CONFIG_KVM_HYPERV
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+ /*
+ * When Enlightened VMEntry is enabled on the calling CPU we treat
+ * memory area pointer by vmptr as Enlightened VMCS (as there's no good
+ * way to distinguish it from VMCS12) and we must not corrupt it by
+ * writing to the non-existent 'launch_state' field. The area doesn't
+ * have to be the currently active EVMCS on the calling CPU and there's
+ * nothing KVM has to do to transition it from 'active' to 'non-active'
+ * state. It is possible that the area will stay mapped as
+ * vmx->nested.hv_evmcs but this shouldn't be a problem.
+ */
+ if (!guest_cpuid_has_evmcs(vcpu) ||
+ !evmptr_is_valid(nested_get_evmptr(vcpu)))
+ return false;
+
+ if (nested_vmx_evmcs(vmx) && vmptr == vmx->nested.hv_evmcs_vmptr)
+ nested_release_evmcs(vcpu);
+
+ return true;
+#else
+ return false;
+#endif
}
static void vmx_sync_vmcs_host_state(struct vcpu_vmx *vmx,
@@ -572,7 +601,6 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
int msr;
unsigned long *msr_bitmap_l1;
unsigned long *msr_bitmap_l0 = vmx->nested.vmcs02.msr_bitmap;
- struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
struct kvm_host_map *map = &vmx->nested.msr_bitmap_map;
/* Nothing to do if the MSR bitmap is not in use. */
@@ -588,10 +616,13 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
* - Nested hypervisor (L1) has enabled 'Enlightened MSR Bitmap' feature
* and tells KVM (L0) there were no changes in MSR bitmap for L2.
*/
- if (!vmx->nested.force_msr_bitmap_recalc && evmcs &&
- evmcs->hv_enlightenments_control.msr_bitmap &&
- evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP)
- return true;
+ if (!vmx->nested.force_msr_bitmap_recalc) {
+ struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
+
+ if (evmcs && evmcs->hv_enlightenments_control.msr_bitmap &&
+ evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP)
+ return true;
+ }
if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->msr_bitmap), map))
return false;
@@ -1085,7 +1116,7 @@ static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3,
bool nested_ept, bool reload_pdptrs,
enum vm_entry_failure_code *entry_failure_code)
{
- if (CC(kvm_vcpu_is_illegal_gpa(vcpu, cr3))) {
+ if (CC(!kvm_vcpu_is_legal_cr3(vcpu, cr3))) {
*entry_failure_code = ENTRY_FAIL_DEFAULT;
return -EINVAL;
}
@@ -1139,14 +1170,8 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu,
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
- /*
- * KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or
- * L2's VP_ID upon request from the guest. Make sure we check for
- * pending entries in the right FIFO upon L1/L2 transition as these
- * requests are put by other vCPUs asynchronously.
- */
- if (to_hv_vcpu(vcpu) && enable_ept)
- kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu);
+ /* Handle pending Hyper-V TLB flush requests */
+ kvm_hv_nested_transtion_tlb_flush(vcpu, enable_ept);
/*
* If vmcs12 doesn't use VPID, L1 expects linear and combined mappings
@@ -1578,8 +1603,9 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields)
{
+#ifdef CONFIG_KVM_HYPERV
struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12;
- struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
+ struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(&vmx->vcpu);
/* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE */
@@ -1818,12 +1844,16 @@ static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields
*/
return;
+#else /* CONFIG_KVM_HYPERV */
+ KVM_BUG_ON(1, vmx->vcpu.kvm);
+#endif /* CONFIG_KVM_HYPERV */
}
static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)
{
+#ifdef CONFIG_KVM_HYPERV
struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12;
- struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs;
+ struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
/*
* Should not be changed by KVM:
@@ -1992,6 +2022,9 @@ static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)
evmcs->guest_bndcfgs = vmcs12->guest_bndcfgs;
return;
+#else /* CONFIG_KVM_HYPERV */
+ KVM_BUG_ON(1, vmx->vcpu.kvm);
+#endif /* CONFIG_KVM_HYPERV */
}
/*
@@ -2001,6 +2034,7 @@ static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx)
static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(
struct kvm_vcpu *vcpu, bool from_launch)
{
+#ifdef CONFIG_KVM_HYPERV
struct vcpu_vmx *vmx = to_vmx(vcpu);
bool evmcs_gpa_changed = false;
u64 evmcs_gpa;
@@ -2082,13 +2116,16 @@ static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld(
}
return EVMPTRLD_SUCCEEDED;
+#else
+ return EVMPTRLD_DISABLED;
+#endif
}
void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (nested_vmx_is_evmptr12_valid(vmx))
copy_vmcs12_to_enlightened(vmx);
else
copy_vmcs12_to_shadow(vmx);
@@ -2242,7 +2279,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0
u32 exec_control;
u64 guest_efer = nested_vmx_calc_efer(vmx, vmcs12);
- if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (vmx->nested.dirty_vmcs12 || nested_vmx_is_evmptr12_valid(vmx))
prepare_vmcs02_early_rare(vmx, vmcs12);
/*
@@ -2403,7 +2440,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0
static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12)
{
- struct hv_enlightened_vmcs *hv_evmcs = vmx->nested.hv_evmcs;
+ struct hv_enlightened_vmcs *hv_evmcs = nested_vmx_evmcs(vmx);
if (!hv_evmcs || !(hv_evmcs->hv_clean_fields &
HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2)) {
@@ -2535,15 +2572,15 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
enum vm_entry_failure_code *entry_failure_code)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
+ struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
bool load_guest_pdptrs_vmcs12 = false;
- if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
+ if (vmx->nested.dirty_vmcs12 || nested_vmx_is_evmptr12_valid(vmx)) {
prepare_vmcs02_rare(vmx, vmcs12);
vmx->nested.dirty_vmcs12 = false;
- load_guest_pdptrs_vmcs12 = !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) ||
- !(vmx->nested.hv_evmcs->hv_clean_fields &
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
+ load_guest_pdptrs_vmcs12 = !nested_vmx_is_evmptr12_valid(vmx) ||
+ !(evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1);
}
if (vmx->nested.nested_run_pending &&
@@ -2664,9 +2701,8 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
* bits when it changes a field in eVMCS. Mark all fields as clean
* here.
*/
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
- vmx->nested.hv_evmcs->hv_clean_fields |=
- HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
+ if (nested_vmx_is_evmptr12_valid(vmx))
+ evmcs->hv_clean_fields |= HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL;
return 0;
}
@@ -2717,7 +2753,7 @@ static bool nested_vmx_check_eptp(struct kvm_vcpu *vcpu, u64 new_eptp)
}
/* Reserved bits should not be set */
- if (CC(kvm_vcpu_is_illegal_gpa(vcpu, new_eptp) || ((new_eptp >> 7) & 0x1f)))
+ if (CC(!kvm_vcpu_is_legal_gpa(vcpu, new_eptp) || ((new_eptp >> 7) & 0x1f)))
return false;
/* AD, if set, should be supported */
@@ -2888,8 +2924,10 @@ static int nested_vmx_check_controls(struct kvm_vcpu *vcpu,
nested_check_vm_entry_controls(vcpu, vmcs12))
return -EINVAL;
+#ifdef CONFIG_KVM_HYPERV
if (guest_cpuid_has_evmcs(vcpu))
return nested_evmcs_check_controls(vmcs12);
+#endif
return 0;
}
@@ -2912,7 +2950,7 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
if (CC(!nested_host_cr0_valid(vcpu, vmcs12->host_cr0)) ||
CC(!nested_host_cr4_valid(vcpu, vmcs12->host_cr4)) ||
- CC(kvm_vcpu_is_illegal_gpa(vcpu, vmcs12->host_cr3)))
+ CC(!kvm_vcpu_is_legal_cr3(vcpu, vmcs12->host_cr3)))
return -EINVAL;
if (CC(is_noncanonical_address(vmcs12->host_ia32_sysenter_esp, vcpu)) ||
@@ -3161,6 +3199,7 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu)
return 0;
}
+#ifdef CONFIG_KVM_HYPERV
static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -3188,6 +3227,7 @@ static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu)
return true;
}
+#endif
static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
{
@@ -3279,6 +3319,7 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu)
static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)
{
+#ifdef CONFIG_KVM_HYPERV
/*
* Note: nested_get_evmcs_page() also updates 'vp_assist_page' copy
* in 'struct kvm_vcpu_hv' in case eVMCS is in use, this is mandatory
@@ -3295,6 +3336,7 @@ static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu)
return false;
}
+#endif
if (is_guest_mode(vcpu) && !nested_get_vmcs12_pages(vcpu))
return false;
@@ -3538,7 +3580,7 @@ vmentry_fail_vmexit:
load_vmcs12_host_state(vcpu, vmcs12);
vmcs12->vm_exit_reason = exit_reason.full;
- if (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (enable_shadow_vmcs || nested_vmx_is_evmptr12_valid(vmx))
vmx->nested.need_vmcs12_to_shadow_sync = true;
return NVMX_VMENTRY_VMEXIT;
}
@@ -3569,7 +3611,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
if (CC(evmptrld_status == EVMPTRLD_VMFAIL))
return nested_vmx_failInvalid(vcpu);
- if (CC(!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) &&
+ if (CC(!nested_vmx_is_evmptr12_valid(vmx) &&
vmx->nested.current_vmptr == INVALID_GPA))
return nested_vmx_failInvalid(vcpu);
@@ -3584,8 +3626,10 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
if (CC(vmcs12->hdr.shadow_vmcs))
return nested_vmx_failInvalid(vcpu);
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
- copy_enlightened_to_vmcs12(vmx, vmx->nested.hv_evmcs->hv_clean_fields);
+ if (nested_vmx_is_evmptr12_valid(vmx)) {
+ struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx);
+
+ copy_enlightened_to_vmcs12(vmx, evmcs->hv_clean_fields);
/* Enlightened VMCS doesn't have launch state */
vmcs12->launch_state = !launch;
} else if (enable_shadow_vmcs) {
@@ -4329,11 +4373,11 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (nested_vmx_is_evmptr12_valid(vmx))
sync_vmcs02_to_vmcs12_rare(vcpu, vmcs12);
vmx->nested.need_sync_vmcs02_to_vmcs12_rare =
- !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr);
+ !nested_vmx_is_evmptr12_valid(vmx);
vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12);
vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12);
@@ -4732,6 +4776,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
/* trying to cancel vmlaunch/vmresume is a bug */
WARN_ON_ONCE(vmx->nested.nested_run_pending);
+#ifdef CONFIG_KVM_HYPERV
if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
/*
* KVM_REQ_GET_NESTED_STATE_PAGES is also used to map
@@ -4741,6 +4786,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
*/
(void)nested_get_evmcs_page(vcpu);
}
+#endif
/* Service pending TLB flush requests for L2 before switching to L1. */
kvm_service_local_tlb_flush_requests(vcpu);
@@ -4854,7 +4900,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
}
if ((vm_exit_reason != -1) &&
- (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)))
+ (enable_shadow_vmcs || nested_vmx_is_evmptr12_valid(vmx)))
vmx->nested.need_vmcs12_to_shadow_sync = true;
/* in case we halted in L2 */
@@ -4980,6 +5026,7 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification,
else
*ret = off;
+ *ret = vmx_get_untagged_addr(vcpu, *ret, 0);
/* Long mode: #GP(0)/#SS(0) if the memory address is in a
* non-canonical form. This is the only check on the memory
* destination for long mode!
@@ -5292,18 +5339,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
if (vmptr == vmx->nested.vmxon_ptr)
return nested_vmx_fail(vcpu, VMXERR_VMCLEAR_VMXON_POINTER);
- /*
- * When Enlightened VMEntry is enabled on the calling CPU we treat
- * memory area pointer by vmptr as Enlightened VMCS (as there's no good
- * way to distinguish it from VMCS12) and we must not corrupt it by
- * writing to the non-existent 'launch_state' field. The area doesn't
- * have to be the currently active EVMCS on the calling CPU and there's
- * nothing KVM has to do to transition it from 'active' to 'non-active'
- * state. It is possible that the area will stay mapped as
- * vmx->nested.hv_evmcs but this shouldn't be a problem.
- */
- if (likely(!guest_cpuid_has_evmcs(vcpu) ||
- !evmptr_is_valid(nested_get_evmptr(vcpu)))) {
+ if (likely(!nested_evmcs_handle_vmclear(vcpu, vmptr))) {
if (vmptr == vmx->nested.current_vmptr)
nested_release_vmcs12(vcpu);
@@ -5320,8 +5356,6 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
vmptr + offsetof(struct vmcs12,
launch_state),
&zero, sizeof(zero));
- } else if (vmx->nested.hv_evmcs && vmptr == vmx->nested.hv_evmcs_vmptr) {
- nested_release_evmcs(vcpu);
}
return nested_vmx_succeed(vcpu);
@@ -5360,7 +5394,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
/* Decode instruction info and find the field to read */
field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf));
- if (!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) {
+ if (!nested_vmx_is_evmptr12_valid(vmx)) {
/*
* In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA,
* any VMREAD sets the ALU flags for VMfailInvalid.
@@ -5398,7 +5432,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu)
return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT);
/* Read the field, zero-extended to a u64 value */
- value = evmcs_read_any(vmx->nested.hv_evmcs, field, offset);
+ value = evmcs_read_any(nested_vmx_evmcs(vmx), field, offset);
}
/*
@@ -5586,7 +5620,7 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
return nested_vmx_fail(vcpu, VMXERR_VMPTRLD_VMXON_POINTER);
/* Forbid normal VMPTRLD if Enlightened version was used */
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (nested_vmx_is_evmptr12_valid(vmx))
return 1;
if (vmx->nested.current_vmptr != vmptr) {
@@ -5649,7 +5683,7 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu)
if (!nested_vmx_check_permission(vcpu))
return 1;
- if (unlikely(evmptr_is_valid(to_vmx(vcpu)->nested.hv_evmcs_vmptr)))
+ if (unlikely(nested_vmx_is_evmptr12_valid(to_vmx(vcpu))))
return 1;
if (get_vmx_mem_address(vcpu, exit_qual, instr_info,
@@ -5797,6 +5831,10 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
vpid02 = nested_get_vpid02(vcpu);
switch (type) {
case VMX_VPID_EXTENT_INDIVIDUAL_ADDR:
+ /*
+ * LAM doesn't apply to addresses that are inputs to TLB
+ * invalidation.
+ */
if (!operand.vpid ||
is_noncanonical_address(operand.gla, vcpu))
return nested_vmx_fail(vcpu,
@@ -6208,11 +6246,13 @@ static bool nested_vmx_l0_wants_exit(struct kvm_vcpu *vcpu,
* Handle L2's bus locks in L0 directly.
*/
return true;
+#ifdef CONFIG_KVM_HYPERV
case EXIT_REASON_VMCALL:
/* Hyper-V L2 TLB flush hypercall is handled by L0 */
return guest_hv_cpuid_has_l2_tlb_flush(vcpu) &&
nested_evmcs_l2_tlb_flush_enabled(vcpu) &&
kvm_hv_is_tlb_flush_hcall(vcpu);
+#endif
default:
break;
}
@@ -6435,7 +6475,7 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
kvm_state.size += sizeof(user_vmx_nested_state->vmcs12);
/* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */
- if (vmx->nested.hv_evmcs_vmptr != EVMPTR_INVALID)
+ if (nested_vmx_is_evmptr12_set(vmx))
kvm_state.flags |= KVM_STATE_NESTED_EVMCS;
if (is_guest_mode(vcpu) &&
@@ -6491,7 +6531,7 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
} else {
copy_vmcs02_to_vmcs12_rare(vcpu, get_vmcs12(vcpu));
if (!vmx->nested.need_vmcs12_to_shadow_sync) {
- if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))
+ if (nested_vmx_is_evmptr12_valid(vmx))
/*
* L1 hypervisor is not obliged to keep eVMCS
* clean fields data always up-to-date while
@@ -6632,6 +6672,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
return -EINVAL;
set_current_vmptr(vmx, kvm_state->hdr.vmx.vmcs12_pa);
+#ifdef CONFIG_KVM_HYPERV
} else if (kvm_state->flags & KVM_STATE_NESTED_EVMCS) {
/*
* nested_vmx_handle_enlightened_vmptrld() cannot be called
@@ -6641,6 +6682,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
*/
vmx->nested.hv_evmcs_vmptr = EVMPTR_MAP_PENDING;
kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu);
+#endif
} else {
return -EINVAL;
}
@@ -7096,7 +7138,9 @@ struct kvm_x86_nested_ops vmx_nested_ops = {
.set_state = vmx_set_nested_state,
.get_nested_state_pages = vmx_get_nested_state_pages,
.write_log_dirty = nested_vmx_write_pml_buffer,
+#ifdef CONFIG_KVM_HYPERV
.enable_evmcs = nested_enable_evmcs,
.get_evmcs_version = nested_get_evmcs_version,
.hv_inject_synthetic_vmexit_post_tlb_flush = vmx_hv_inject_synthetic_vmexit_post_tlb_flush,
+#endif
};
diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h
index b4b9d51438c6..cce4e2aa30fb 100644
--- a/arch/x86/kvm/vmx/nested.h
+++ b/arch/x86/kvm/vmx/nested.h
@@ -3,6 +3,7 @@
#define __KVM_X86_VMX_NESTED_H
#include "kvm_cache_regs.h"
+#include "hyperv.h"
#include "vmcs12.h"
#include "vmx.h"
@@ -57,7 +58,7 @@ static inline int vmx_has_valid_vmcs12(struct kvm_vcpu *vcpu)
/* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */
return vmx->nested.current_vmptr != -1ull ||
- vmx->nested.hv_evmcs_vmptr != EVMPTR_INVALID;
+ nested_vmx_is_evmptr12_set(vmx);
}
static inline u16 nested_get_vpid02(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 820d3e1f6b4f..a6216c874729 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -437,11 +437,9 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
!(msr & MSR_PMC_FULL_WIDTH_BIT))
data = (s64)(s32)data;
pmc_write_counter(pmc, data);
- pmc_update_sample_period(pmc);
break;
} else if ((pmc = get_fixed_pmc(pmu, msr))) {
pmc_write_counter(pmc, data);
- pmc_update_sample_period(pmc);
break;
} else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
reserved_bits = pmu->reserved_bits;
@@ -632,26 +630,6 @@ static void intel_pmu_init(struct kvm_vcpu *vcpu)
static void intel_pmu_reset(struct kvm_vcpu *vcpu)
{
- struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
- struct kvm_pmc *pmc = NULL;
- int i;
-
- for (i = 0; i < KVM_INTEL_PMC_MAX_GENERIC; i++) {
- pmc = &pmu->gp_counters[i];
-
- pmc_stop_counter(pmc);
- pmc->counter = pmc->prev_counter = pmc->eventsel = 0;
- }
-
- for (i = 0; i < KVM_PMC_MAX_FIXED; i++) {
- pmc = &pmu->fixed_counters[i];
-
- pmc_stop_counter(pmc);
- pmc->counter = pmc->prev_counter = 0;
- }
-
- pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status = 0;
-
intel_pmu_release_guest_lbr_event(vcpu);
}
diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c
index 3e822e582497..6fef01e0536e 100644
--- a/arch/x86/kvm/vmx/sgx.c
+++ b/arch/x86/kvm/vmx/sgx.c
@@ -37,6 +37,7 @@ static int sgx_get_encls_gva(struct kvm_vcpu *vcpu, unsigned long offset,
if (!IS_ALIGNED(*gva, alignment)) {
fault = true;
} else if (likely(is_64_bit_mode(vcpu))) {
+ *gva = vmx_get_untagged_addr(vcpu, *gva, 0);
fault = is_noncanonical_address(*gva, vcpu);
} else {
*gva &= 0xffffffff;
diff --git a/arch/x86/kvm/vmx/vmenter.S b/arch/x86/kvm/vmx/vmenter.S
index be275a0410a8..906ecd001511 100644
--- a/arch/x86/kvm/vmx/vmenter.S
+++ b/arch/x86/kvm/vmx/vmenter.S
@@ -289,7 +289,7 @@ SYM_INNER_LABEL_ALIGN(vmx_vmexit, SYM_L_GLOBAL)
RET
.Lfixup:
- cmpb $0, kvm_rebooting
+ cmpb $0, _ASM_RIP(kvm_rebooting)
jne .Lvmfail
ud2
.Lvmfail:
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index e0f86f11c345..e262bc2ba4e5 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -66,6 +66,7 @@
#include "vmx.h"
#include "x86.h"
#include "smm.h"
+#include "vmx_onhyperv.h"
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
@@ -523,22 +524,14 @@ module_param(enlightened_vmcs, bool, 0444);
static int hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu)
{
struct hv_enlightened_vmcs *evmcs;
- struct hv_partition_assist_pg **p_hv_pa_pg =
- &to_kvm_hv(vcpu->kvm)->hv_pa_pg;
- /*
- * Synthetic VM-Exit is not enabled in current code and so All
- * evmcs in singe VM shares same assist page.
- */
- if (!*p_hv_pa_pg)
- *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL_ACCOUNT);
+ hpa_t partition_assist_page = hv_get_partition_assist_page(vcpu);
- if (!*p_hv_pa_pg)
+ if (partition_assist_page == INVALID_PAGE)
return -ENOMEM;
evmcs = (struct hv_enlightened_vmcs *)to_vmx(vcpu)->loaded_vmcs->vmcs;
- evmcs->partition_assist_page =
- __pa(*p_hv_pa_pg);
+ evmcs->partition_assist_page = partition_assist_page;
evmcs->hv_vm_id = (unsigned long)vcpu->kvm;
evmcs->hv_enlightenments_control.nested_flush_hypercall = 1;
@@ -2055,6 +2048,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
if (vmx_get_vmx_msr(&vmx->nested.msrs, msr_info->index,
&msr_info->data))
return 1;
+#ifdef CONFIG_KVM_HYPERV
/*
* Enlightened VMCS v1 doesn't have certain VMCS fields but
* instead of just ignoring the features, different Hyper-V
@@ -2065,6 +2059,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
if (!msr_info->host_initiated && guest_cpuid_has_evmcs(vcpu))
nested_evmcs_filter_control_msr(vcpu, msr_info->index,
&msr_info->data);
+#endif
break;
case MSR_IA32_RTIT_CTL:
if (!vmx_pt_mode_is_host_guest())
@@ -3400,7 +3395,8 @@ static void vmx_load_mmu_pgd(struct kvm_vcpu *vcpu, hpa_t root_hpa,
update_guest_cr3 = false;
vmx_ept_load_pdptrs(vcpu);
} else {
- guest_cr3 = root_hpa | kvm_get_active_pcid(vcpu);
+ guest_cr3 = root_hpa | kvm_get_active_pcid(vcpu) |
+ kvm_get_active_cr3_lam_bits(vcpu);
}
if (update_guest_cr3)
@@ -4833,7 +4829,10 @@ static void __vmx_vcpu_reset(struct kvm_vcpu *vcpu)
vmx->nested.posted_intr_nv = -1;
vmx->nested.vmxon_ptr = INVALID_GPA;
vmx->nested.current_vmptr = INVALID_GPA;
+
+#ifdef CONFIG_KVM_HYPERV
vmx->nested.hv_evmcs_vmptr = EVMPTR_INVALID;
+#endif
vcpu->arch.microcode_version = 0x100000000ULL;
vmx->msr_ia32_feature_control_valid_bits = FEAT_CTL_LOCKED;
@@ -5782,7 +5781,7 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu)
* would also use advanced VM-exit information for EPT violations to
* reconstruct the page fault error code.
*/
- if (unlikely(allow_smaller_maxphyaddr && kvm_vcpu_is_illegal_gpa(vcpu, gpa)))
+ if (unlikely(allow_smaller_maxphyaddr && !kvm_vcpu_is_legal_gpa(vcpu, gpa)))
return kvm_emulate_instruction(vcpu, 0);
return kvm_mmu_page_fault(vcpu, gpa, error_code, NULL, 0);
@@ -6757,10 +6756,10 @@ static void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu)
return;
/*
- * Grab the memslot so that the hva lookup for the mmu_notifier retry
- * is guaranteed to use the same memslot as the pfn lookup, i.e. rely
- * on the pfn lookup's validation of the memslot to ensure a valid hva
- * is used for the retry check.
+ * Explicitly grab the memslot using KVM's internal slot ID to ensure
+ * KVM doesn't unintentionally grab a userspace memslot. It _should_
+ * be impossible for userspace to create a memslot for the APIC when
+ * APICv is enabled, but paranoia won't hurt in this case.
*/
slot = id_to_memslot(slots, APIC_ACCESS_PAGE_PRIVATE_MEMSLOT);
if (!slot || slot->flags & KVM_MEMSLOT_INVALID)
@@ -6785,8 +6784,7 @@ static void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu)
return;
read_lock(&vcpu->kvm->mmu_lock);
- if (mmu_invalidate_retry_hva(kvm, mmu_seq,
- gfn_to_hva_memslot(slot, gfn))) {
+ if (mmu_invalidate_retry_gfn(kvm, mmu_seq, gfn)) {
kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu);
read_unlock(&vcpu->kvm->mmu_lock);
goto out;
@@ -7674,6 +7672,9 @@ static void nested_vmx_cr_fixed1_bits_update(struct kvm_vcpu *vcpu)
cr4_fixed1_update(X86_CR4_UMIP, ecx, feature_bit(UMIP));
cr4_fixed1_update(X86_CR4_LA57, ecx, feature_bit(LA57));
+ entry = kvm_find_cpuid_entry_index(vcpu, 0x7, 1);
+ cr4_fixed1_update(X86_CR4_LAM_SUP, eax, feature_bit(LAM));
+
#undef cr4_fixed1_update
}
@@ -7760,6 +7761,7 @@ static void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_XSAVES);
kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_VMX);
+ kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_LAM);
vmx_setup_uret_msrs(vmx);
@@ -8206,6 +8208,50 @@ static void vmx_vm_destroy(struct kvm *kvm)
free_pages((unsigned long)kvm_vmx->pid_table, vmx_get_pid_table_order(kvm));
}
+/*
+ * Note, the SDM states that the linear address is masked *after* the modified
+ * canonicality check, whereas KVM masks (untags) the address and then performs
+ * a "normal" canonicality check. Functionally, the two methods are identical,
+ * and when the masking occurs relative to the canonicality check isn't visible
+ * to software, i.e. KVM's behavior doesn't violate the SDM.
+ */
+gva_t vmx_get_untagged_addr(struct kvm_vcpu *vcpu, gva_t gva, unsigned int flags)
+{
+ int lam_bit;
+ unsigned long cr3_bits;
+
+ if (flags & (X86EMUL_F_FETCH | X86EMUL_F_IMPLICIT | X86EMUL_F_INVLPG))
+ return gva;
+
+ if (!is_64_bit_mode(vcpu))
+ return gva;
+
+ /*
+ * Bit 63 determines if the address should be treated as user address
+ * or a supervisor address.
+ */
+ if (!(gva & BIT_ULL(63))) {
+ cr3_bits = kvm_get_active_cr3_lam_bits(vcpu);
+ if (!(cr3_bits & (X86_CR3_LAM_U57 | X86_CR3_LAM_U48)))
+ return gva;
+
+ /* LAM_U48 is ignored if LAM_U57 is set. */
+ lam_bit = cr3_bits & X86_CR3_LAM_U57 ? 56 : 47;
+ } else {
+ if (!kvm_is_cr4_bit_set(vcpu, X86_CR4_LAM_SUP))
+ return gva;
+
+ lam_bit = kvm_is_cr4_bit_set(vcpu, X86_CR4_LA57) ? 56 : 47;
+ }
+
+ /*
+ * Untag the address by sign-extending the lam_bit, but NOT to bit 63.
+ * Bit 63 is retained from the raw virtual address so that untagging
+ * doesn't change a user access to a supervisor access, and vice versa.
+ */
+ return (sign_extend64(gva, lam_bit) & ~BIT_ULL(63)) | (gva & BIT_ULL(63));
+}
+
static struct kvm_x86_ops vmx_x86_ops __initdata = {
.name = KBUILD_MODNAME,
@@ -8346,6 +8392,8 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
.complete_emulated_msr = kvm_complete_insn_gp,
.vcpu_deliver_sipi_vector = kvm_vcpu_deliver_sipi_vector,
+
+ .get_untagged_addr = vmx_get_untagged_addr,
};
static unsigned int vmx_handle_intel_pt_intr(void)
diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
index c2130d2c8e24..e3b0985bb74a 100644
--- a/arch/x86/kvm/vmx/vmx.h
+++ b/arch/x86/kvm/vmx/vmx.h
@@ -241,9 +241,11 @@ struct nested_vmx {
bool guest_mode;
} smm;
+#ifdef CONFIG_KVM_HYPERV
gpa_t hv_evmcs_vmptr;
struct kvm_host_map hv_evmcs_map;
struct hv_enlightened_vmcs *hv_evmcs;
+#endif
};
struct vcpu_vmx {
@@ -420,6 +422,8 @@ void vmx_enable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type);
u64 vmx_get_l2_tsc_offset(struct kvm_vcpu *vcpu);
u64 vmx_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu);
+gva_t vmx_get_untagged_addr(struct kvm_vcpu *vcpu, gva_t gva, unsigned int flags);
+
static inline void vmx_set_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr,
int type, bool value)
{
@@ -745,14 +749,4 @@ static inline bool vmx_can_use_ipiv(struct kvm_vcpu *vcpu)
return lapic_in_kernel(vcpu) && enable_ipiv;
}
-static inline bool guest_cpuid_has_evmcs(struct kvm_vcpu *vcpu)
-{
- /*
- * eVMCS is exposed to the guest if Hyper-V is enabled in CPUID and
- * eVMCS has been explicitly enabled by userspace.
- */
- return vcpu->arch.hyperv_enabled &&
- to_vmx(vcpu)->nested.enlightened_vmcs_enabled;
-}
-
#endif /* __KVM_X86_VMX_H */
diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.c b/arch/x86/kvm/vmx/vmx_onhyperv.c
new file mode 100644
index 000000000000..b9a8b91166d0
--- /dev/null
+++ b/arch/x86/kvm/vmx/vmx_onhyperv.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "capabilities.h"
+#include "vmx_onhyperv.h"
+
+DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
+
+/*
+ * KVM on Hyper-V always uses the latest known eVMCSv1 revision, the assumption
+ * is: in case a feature has corresponding fields in eVMCS described and it was
+ * exposed in VMX feature MSRs, KVM is free to use it. Warn if KVM meets a
+ * feature which has no corresponding eVMCS field, this likely means that KVM
+ * needs to be updated.
+ */
+#define evmcs_check_vmcs_conf(field, ctrl) \
+ do { \
+ typeof(vmcs_conf->field) unsupported; \
+ \
+ unsupported = vmcs_conf->field & ~EVMCS1_SUPPORTED_ ## ctrl; \
+ if (unsupported) { \
+ pr_warn_once(#field " unsupported with eVMCS: 0x%llx\n",\
+ (u64)unsupported); \
+ vmcs_conf->field &= EVMCS1_SUPPORTED_ ## ctrl; \
+ } \
+ } \
+ while (0)
+
+void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf)
+{
+ evmcs_check_vmcs_conf(cpu_based_exec_ctrl, EXEC_CTRL);
+ evmcs_check_vmcs_conf(pin_based_exec_ctrl, PINCTRL);
+ evmcs_check_vmcs_conf(cpu_based_2nd_exec_ctrl, 2NDEXEC);
+ evmcs_check_vmcs_conf(cpu_based_3rd_exec_ctrl, 3RDEXEC);
+ evmcs_check_vmcs_conf(vmentry_ctrl, VMENTRY_CTRL);
+ evmcs_check_vmcs_conf(vmexit_ctrl, VMEXIT_CTRL);
+}
diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.h b/arch/x86/kvm/vmx/vmx_onhyperv.h
new file mode 100644
index 000000000000..eb48153bfd73
--- /dev/null
+++ b/arch/x86/kvm/vmx/vmx_onhyperv.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ARCH_X86_KVM_VMX_ONHYPERV_H__
+#define __ARCH_X86_KVM_VMX_ONHYPERV_H__
+
+#include <asm/hyperv-tlfs.h>
+#include <asm/mshyperv.h>
+
+#include <linux/jump_label.h>
+
+#include "capabilities.h"
+#include "hyperv_evmcs.h"
+#include "vmcs12.h"
+
+#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs))
+
+#if IS_ENABLED(CONFIG_HYPERV)
+
+DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs);
+
+static __always_inline bool kvm_is_using_evmcs(void)
+{
+ return static_branch_unlikely(&__kvm_is_using_evmcs);
+}
+
+static __always_inline int get_evmcs_offset(unsigned long field,
+ u16 *clean_field)
+{
+ int offset = evmcs_field_offset(field, clean_field);
+
+ WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field);
+ return offset;
+}
+
+static __always_inline void evmcs_write64(unsigned long field, u64 value)
+{
+ u16 clean_field;
+ int offset = get_evmcs_offset(field, &clean_field);
+
+ if (offset < 0)
+ return;
+
+ *(u64 *)((char *)current_evmcs + offset) = value;
+
+ current_evmcs->hv_clean_fields &= ~clean_field;
+}
+
+static __always_inline void evmcs_write32(unsigned long field, u32 value)
+{
+ u16 clean_field;
+ int offset = get_evmcs_offset(field, &clean_field);
+
+ if (offset < 0)
+ return;
+
+ *(u32 *)((char *)current_evmcs + offset) = value;
+ current_evmcs->hv_clean_fields &= ~clean_field;
+}
+
+static __always_inline void evmcs_write16(unsigned long field, u16 value)
+{
+ u16 clean_field;
+ int offset = get_evmcs_offset(field, &clean_field);
+
+ if (offset < 0)
+ return;
+
+ *(u16 *)((char *)current_evmcs + offset) = value;
+ current_evmcs->hv_clean_fields &= ~clean_field;
+}
+
+static __always_inline u64 evmcs_read64(unsigned long field)
+{
+ int offset = get_evmcs_offset(field, NULL);
+
+ if (offset < 0)
+ return 0;
+
+ return *(u64 *)((char *)current_evmcs + offset);
+}
+
+static __always_inline u32 evmcs_read32(unsigned long field)
+{
+ int offset = get_evmcs_offset(field, NULL);
+
+ if (offset < 0)
+ return 0;
+
+ return *(u32 *)((char *)current_evmcs + offset);
+}
+
+static __always_inline u16 evmcs_read16(unsigned long field)
+{
+ int offset = get_evmcs_offset(field, NULL);
+
+ if (offset < 0)
+ return 0;
+
+ return *(u16 *)((char *)current_evmcs + offset);
+}
+
+static inline void evmcs_load(u64 phys_addr)
+{
+ struct hv_vp_assist_page *vp_ap =
+ hv_get_vp_assist_page(smp_processor_id());
+
+ if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall)
+ vp_ap->nested_control.features.directhypercall = 1;
+ vp_ap->current_nested_vmcs = phys_addr;
+ vp_ap->enlighten_vmentry = 1;
+}
+
+void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf);
+#else /* !IS_ENABLED(CONFIG_HYPERV) */
+static __always_inline bool kvm_is_using_evmcs(void) { return false; }
+static __always_inline void evmcs_write64(unsigned long field, u64 value) {}
+static __always_inline void evmcs_write32(unsigned long field, u32 value) {}
+static __always_inline void evmcs_write16(unsigned long field, u16 value) {}
+static __always_inline u64 evmcs_read64(unsigned long field) { return 0; }
+static __always_inline u32 evmcs_read32(unsigned long field) { return 0; }
+static __always_inline u16 evmcs_read16(unsigned long field) { return 0; }
+static inline void evmcs_load(u64 phys_addr) {}
+#endif /* IS_ENABLED(CONFIG_HYPERV) */
+
+#endif /* __ARCH_X86_KVM_VMX_ONHYPERV_H__ */
diff --git a/arch/x86/kvm/vmx/vmx_ops.h b/arch/x86/kvm/vmx/vmx_ops.h
index 33af7b4c6eb4..f41ce3c24123 100644
--- a/arch/x86/kvm/vmx/vmx_ops.h
+++ b/arch/x86/kvm/vmx/vmx_ops.h
@@ -6,7 +6,7 @@
#include <asm/vmx.h>
-#include "hyperv.h"
+#include "vmx_onhyperv.h"
#include "vmcs.h"
#include "../x86.h"
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index cec0fc2a4b1c..363b1c080205 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1284,7 +1284,7 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
* stuff CR3, e.g. for RSM emulation, and there is no guarantee that
* the current vCPU mode is accurate.
*/
- if (kvm_vcpu_is_illegal_gpa(vcpu, cr3))
+ if (!kvm_vcpu_is_legal_cr3(vcpu, cr3))
return 1;
if (is_pae_paging(vcpu) && !load_pdptrs(vcpu, cr3))
@@ -1504,6 +1504,8 @@ static unsigned num_msrs_to_save;
static const u32 emulated_msrs_all[] = {
MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW,
+
+#ifdef CONFIG_KVM_HYPERV
HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
HV_X64_MSR_TIME_REF_COUNT, HV_X64_MSR_REFERENCE_TSC,
HV_X64_MSR_TSC_FREQUENCY, HV_X64_MSR_APIC_FREQUENCY,
@@ -1521,6 +1523,7 @@ static const u32 emulated_msrs_all[] = {
HV_X64_MSR_SYNDBG_CONTROL, HV_X64_MSR_SYNDBG_STATUS,
HV_X64_MSR_SYNDBG_SEND_BUFFER, HV_X64_MSR_SYNDBG_RECV_BUFFER,
HV_X64_MSR_SYNDBG_PENDING_BUFFER,
+#endif
MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
MSR_KVM_PV_EOI_EN, MSR_KVM_ASYNC_PF_INT, MSR_KVM_ASYNC_PF_ACK,
@@ -2510,26 +2513,29 @@ static inline int gtod_is_based_on_tsc(int mode)
}
#endif
-static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu)
+static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool new_generation)
{
#ifdef CONFIG_X86_64
- bool vcpus_matched;
struct kvm_arch *ka = &vcpu->kvm->arch;
struct pvclock_gtod_data *gtod = &pvclock_gtod_data;
- vcpus_matched = (ka->nr_vcpus_matched_tsc + 1 ==
- atomic_read(&vcpu->kvm->online_vcpus));
+ /*
+ * To use the masterclock, the host clocksource must be based on TSC
+ * and all vCPUs must have matching TSCs. Note, the count for matching
+ * vCPUs doesn't include the reference vCPU, hence "+1".
+ */
+ bool use_master_clock = (ka->nr_vcpus_matched_tsc + 1 ==
+ atomic_read(&vcpu->kvm->online_vcpus)) &&
+ gtod_is_based_on_tsc(gtod->clock.vclock_mode);
/*
- * Once the masterclock is enabled, always perform request in
- * order to update it.
- *
- * In order to enable masterclock, the host clocksource must be TSC
- * and the vcpus need to have matched TSCs. When that happens,
- * perform request to enable masterclock.
+ * Request a masterclock update if the masterclock needs to be toggled
+ * on/off, or when starting a new generation and the masterclock is
+ * enabled (compute_guest_tsc() requires the masterclock snapshot to be
+ * taken _after_ the new generation is created).
*/
- if (ka->use_master_clock ||
- (gtod_is_based_on_tsc(gtod->clock.vclock_mode) && vcpus_matched))
+ if ((ka->use_master_clock && new_generation) ||
+ (ka->use_master_clock != use_master_clock))
kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
trace_kvm_track_tsc(vcpu->vcpu_id, ka->nr_vcpus_matched_tsc,
@@ -2706,7 +2712,7 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc,
vcpu->arch.this_tsc_nsec = kvm->arch.cur_tsc_nsec;
vcpu->arch.this_tsc_write = kvm->arch.cur_tsc_write;
- kvm_track_tsc_matching(vcpu);
+ kvm_track_tsc_matching(vcpu, !matched);
}
static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value)
@@ -3104,7 +3110,8 @@ u64 get_kvmclock_ns(struct kvm *kvm)
static void kvm_setup_guest_pvclock(struct kvm_vcpu *v,
struct gfn_to_pfn_cache *gpc,
- unsigned int offset)
+ unsigned int offset,
+ bool force_tsc_unstable)
{
struct kvm_vcpu_arch *vcpu = &v->arch;
struct pvclock_vcpu_time_info *guest_hv_clock;
@@ -3141,6 +3148,10 @@ static void kvm_setup_guest_pvclock(struct kvm_vcpu *v,
}
memcpy(guest_hv_clock, &vcpu->hv_clock, sizeof(*guest_hv_clock));
+
+ if (force_tsc_unstable)
+ guest_hv_clock->flags &= ~PVCLOCK_TSC_STABLE_BIT;
+
smp_wmb();
guest_hv_clock->version = ++vcpu->hv_clock.version;
@@ -3161,6 +3172,16 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
u64 tsc_timestamp, host_tsc;
u8 pvclock_flags;
bool use_master_clock;
+#ifdef CONFIG_KVM_XEN
+ /*
+ * For Xen guests we may need to override PVCLOCK_TSC_STABLE_BIT as unless
+ * explicitly told to use TSC as its clocksource Xen will not set this bit.
+ * This default behaviour led to bugs in some guest kernels which cause
+ * problems if they observe PVCLOCK_TSC_STABLE_BIT in the pvclock flags.
+ */
+ bool xen_pvclock_tsc_unstable =
+ ka->xen_hvm_config.flags & KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE;
+#endif
kernel_ns = 0;
host_tsc = 0;
@@ -3239,13 +3260,15 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
vcpu->hv_clock.flags = pvclock_flags;
if (vcpu->pv_time.active)
- kvm_setup_guest_pvclock(v, &vcpu->pv_time, 0);
+ kvm_setup_guest_pvclock(v, &vcpu->pv_time, 0, false);
#ifdef CONFIG_KVM_XEN
if (vcpu->xen.vcpu_info_cache.active)
kvm_setup_guest_pvclock(v, &vcpu->xen.vcpu_info_cache,
- offsetof(struct compat_vcpu_info, time));
+ offsetof(struct compat_vcpu_info, time),
+ xen_pvclock_tsc_unstable);
if (vcpu->xen.vcpu_time_info_cache.active)
- kvm_setup_guest_pvclock(v, &vcpu->xen.vcpu_time_info_cache, 0);
+ kvm_setup_guest_pvclock(v, &vcpu->xen.vcpu_time_info_cache, 0,
+ xen_pvclock_tsc_unstable);
#endif
kvm_hv_setup_tsc_page(v->kvm, &vcpu->hv_clock);
return 0;
@@ -4020,6 +4043,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
* the need to ignore the workaround.
*/
break;
+#ifdef CONFIG_KVM_HYPERV
case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
case HV_X64_MSR_SYNDBG_OPTIONS:
@@ -4032,6 +4056,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case HV_X64_MSR_TSC_INVARIANT_CONTROL:
return kvm_hv_set_msr_common(vcpu, msr, data,
msr_info->host_initiated);
+#endif
case MSR_IA32_BBL_CR_CTL3:
/* Drop writes to this legacy MSR -- see rdmsr
* counterpart for further detail.
@@ -4377,6 +4402,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
*/
msr_info->data = 0x20000000;
break;
+#ifdef CONFIG_KVM_HYPERV
case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER:
case HV_X64_MSR_SYNDBG_OPTIONS:
@@ -4390,6 +4416,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
return kvm_hv_get_msr_common(vcpu,
msr_info->index, &msr_info->data,
msr_info->host_initiated);
+#endif
case MSR_IA32_BBL_CR_CTL3:
/* This legacy MSR exists but isn't fully documented in current
* silicon. It is however accessed by winxp in very narrow
@@ -4527,6 +4554,7 @@ static inline bool kvm_can_mwait_in_guest(void)
boot_cpu_has(X86_FEATURE_ARAT);
}
+#ifdef CONFIG_KVM_HYPERV
static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu,
struct kvm_cpuid2 __user *cpuid_arg)
{
@@ -4547,6 +4575,14 @@ static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu,
return 0;
}
+#endif
+
+static bool kvm_is_vm_type_supported(unsigned long type)
+{
+ return type == KVM_X86_DEFAULT_VM ||
+ (type == KVM_X86_SW_PROTECTED_VM &&
+ IS_ENABLED(CONFIG_KVM_SW_PROTECTED_VM) && tdp_enabled);
+}
int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
{
@@ -4573,9 +4609,11 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_PIT_STATE2:
case KVM_CAP_SET_IDENTITY_MAP_ADDR:
case KVM_CAP_VCPU_EVENTS:
+#ifdef CONFIG_KVM_HYPERV
case KVM_CAP_HYPERV:
case KVM_CAP_HYPERV_VAPIC:
case KVM_CAP_HYPERV_SPIN:
+ case KVM_CAP_HYPERV_TIME:
case KVM_CAP_HYPERV_SYNIC:
case KVM_CAP_HYPERV_SYNIC2:
case KVM_CAP_HYPERV_VP_INDEX:
@@ -4585,6 +4623,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_HYPERV_CPUID:
case KVM_CAP_HYPERV_ENFORCE_CPUID:
case KVM_CAP_SYS_HYPERV_CPUID:
+#endif
case KVM_CAP_PCI_SEGMENT:
case KVM_CAP_DEBUGREGS:
case KVM_CAP_X86_ROBUST_SINGLESTEP:
@@ -4594,7 +4633,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_GET_TSC_KHZ:
case KVM_CAP_KVMCLOCK_CTRL:
case KVM_CAP_READONLY_MEM:
- case KVM_CAP_HYPERV_TIME:
case KVM_CAP_IOAPIC_POLARITY_IGNORED:
case KVM_CAP_TSC_DEADLINE_TIMER:
case KVM_CAP_DISABLE_QUIRKS:
@@ -4625,6 +4663,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_ENABLE_CAP:
case KVM_CAP_VM_DISABLE_NX_HUGE_PAGES:
case KVM_CAP_IRQFD_RESAMPLE:
+ case KVM_CAP_MEMORY_FAULT_INFO:
r = 1;
break;
case KVM_CAP_EXIT_HYPERCALL:
@@ -4638,7 +4677,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL |
KVM_XEN_HVM_CONFIG_SHARED_INFO |
KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL |
- KVM_XEN_HVM_CONFIG_EVTCHN_SEND;
+ KVM_XEN_HVM_CONFIG_EVTCHN_SEND |
+ KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE;
if (sched_info_on())
r |= KVM_XEN_HVM_CONFIG_RUNSTATE |
KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG;
@@ -4704,12 +4744,14 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
r = kvm_x86_ops.nested_ops->get_state ?
kvm_x86_ops.nested_ops->get_state(NULL, NULL, 0) : 0;
break;
+#ifdef CONFIG_KVM_HYPERV
case KVM_CAP_HYPERV_DIRECT_TLBFLUSH:
r = kvm_x86_ops.enable_l2_tlb_flush != NULL;
break;
case KVM_CAP_HYPERV_ENLIGHTENED_VMCS:
r = kvm_x86_ops.nested_ops->enable_evmcs != NULL;
break;
+#endif
case KVM_CAP_SMALLER_MAXPHYADDR:
r = (int) allow_smaller_maxphyaddr;
break;
@@ -4738,6 +4780,11 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_X86_NOTIFY_VMEXIT:
r = kvm_caps.has_notify_vmexit;
break;
+ case KVM_CAP_VM_TYPES:
+ r = BIT(KVM_X86_DEFAULT_VM);
+ if (kvm_is_vm_type_supported(KVM_X86_SW_PROTECTED_VM))
+ r |= BIT(KVM_X86_SW_PROTECTED_VM);
+ break;
default:
break;
}
@@ -4871,9 +4918,11 @@ long kvm_arch_dev_ioctl(struct file *filp,
case KVM_GET_MSRS:
r = msr_io(NULL, argp, do_get_msr_feature, 1);
break;
+#ifdef CONFIG_KVM_HYPERV
case KVM_GET_SUPPORTED_HV_CPUID:
r = kvm_ioctl_get_supported_hv_cpuid(NULL, argp);
break;
+#endif
case KVM_GET_DEVICE_ATTR: {
struct kvm_device_attr attr;
r = -EFAULT;
@@ -5699,14 +5748,11 @@ static int kvm_vcpu_ioctl_device_attr(struct kvm_vcpu *vcpu,
static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
struct kvm_enable_cap *cap)
{
- int r;
- uint16_t vmcs_version;
- void __user *user_ptr;
-
if (cap->flags)
return -EINVAL;
switch (cap->cap) {
+#ifdef CONFIG_KVM_HYPERV
case KVM_CAP_HYPERV_SYNIC2:
if (cap->args[0])
return -EINVAL;
@@ -5718,16 +5764,22 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
return kvm_hv_activate_synic(vcpu, cap->cap ==
KVM_CAP_HYPERV_SYNIC2);
case KVM_CAP_HYPERV_ENLIGHTENED_VMCS:
- if (!kvm_x86_ops.nested_ops->enable_evmcs)
- return -ENOTTY;
- r = kvm_x86_ops.nested_ops->enable_evmcs(vcpu, &vmcs_version);
- if (!r) {
- user_ptr = (void __user *)(uintptr_t)cap->args[0];
- if (copy_to_user(user_ptr, &vmcs_version,
- sizeof(vmcs_version)))
- r = -EFAULT;
+ {
+ int r;
+ uint16_t vmcs_version;
+ void __user *user_ptr;
+
+ if (!kvm_x86_ops.nested_ops->enable_evmcs)
+ return -ENOTTY;
+ r = kvm_x86_ops.nested_ops->enable_evmcs(vcpu, &vmcs_version);
+ if (!r) {
+ user_ptr = (void __user *)(uintptr_t)cap->args[0];
+ if (copy_to_user(user_ptr, &vmcs_version,
+ sizeof(vmcs_version)))
+ r = -EFAULT;
+ }
+ return r;
}
- return r;
case KVM_CAP_HYPERV_DIRECT_TLBFLUSH:
if (!kvm_x86_ops.enable_l2_tlb_flush)
return -ENOTTY;
@@ -5736,6 +5788,7 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
case KVM_CAP_HYPERV_ENFORCE_CPUID:
return kvm_hv_set_enforce_cpuid(vcpu, cap->args[0]);
+#endif
case KVM_CAP_ENFORCE_PV_FEATURE_CPUID:
vcpu->arch.pv_cpuid.enforce = cap->args[0];
@@ -6128,9 +6181,11 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
srcu_read_unlock(&vcpu->kvm->srcu, idx);
break;
}
+#ifdef CONFIG_KVM_HYPERV
case KVM_GET_SUPPORTED_HV_CPUID:
r = kvm_ioctl_get_supported_hv_cpuid(vcpu, argp);
break;
+#endif
#ifdef CONFIG_KVM_XEN
case KVM_XEN_VCPU_GET_ATTR: {
struct kvm_xen_vcpu_attr xva;
@@ -7188,6 +7243,7 @@ set_pit2_out:
r = static_call(kvm_x86_mem_enc_unregister_region)(kvm, &region);
break;
}
+#ifdef CONFIG_KVM_HYPERV
case KVM_HYPERV_EVENTFD: {
struct kvm_hyperv_eventfd hvevfd;
@@ -7197,6 +7253,7 @@ set_pit2_out:
r = kvm_vm_ioctl_hv_eventfd(kvm, &hvevfd);
break;
}
+#endif
case KVM_SET_PMU_EVENT_FILTER:
r = kvm_vm_ioctl_set_pmu_event_filter(kvm, argp);
break;
@@ -8432,6 +8489,15 @@ static void emulator_vm_bugged(struct x86_emulate_ctxt *ctxt)
kvm_vm_bugged(kvm);
}
+static gva_t emulator_get_untagged_addr(struct x86_emulate_ctxt *ctxt,
+ gva_t addr, unsigned int flags)
+{
+ if (!kvm_x86_ops.get_untagged_addr)
+ return addr;
+
+ return static_call(kvm_x86_get_untagged_addr)(emul_to_vcpu(ctxt), addr, flags);
+}
+
static const struct x86_emulate_ops emulate_ops = {
.vm_bugged = emulator_vm_bugged,
.read_gpr = emulator_read_gpr,
@@ -8476,6 +8542,7 @@ static const struct x86_emulate_ops emulate_ops = {
.leave_smm = emulator_leave_smm,
.triple_fault = emulator_triple_fault,
.set_xcr = emulator_set_xcr,
+ .get_untagged_addr = emulator_get_untagged_addr,
};
static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask)
@@ -10575,19 +10642,20 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
static void vcpu_load_eoi_exitmap(struct kvm_vcpu *vcpu)
{
- u64 eoi_exit_bitmap[4];
-
if (!kvm_apic_hw_enabled(vcpu->arch.apic))
return;
+#ifdef CONFIG_KVM_HYPERV
if (to_hv_vcpu(vcpu)) {
+ u64 eoi_exit_bitmap[4];
+
bitmap_or((ulong *)eoi_exit_bitmap,
vcpu->arch.ioapic_handled_vectors,
to_hv_synic(vcpu)->vec_bitmap, 256);
static_call_cond(kvm_x86_load_eoi_exitmap)(vcpu, eoi_exit_bitmap);
return;
}
-
+#endif
static_call_cond(kvm_x86_load_eoi_exitmap)(
vcpu, (u64 *)vcpu->arch.ioapic_handled_vectors);
}
@@ -10678,9 +10746,11 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
* the flushes are considered "remote" and not "local" because
* the requests can be initiated from other vCPUs.
*/
+#ifdef CONFIG_KVM_HYPERV
if (kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu) &&
kvm_hv_vcpu_flush_tlb(vcpu))
kvm_vcpu_flush_tlb_guest(vcpu);
+#endif
if (kvm_check_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu)) {
vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS;
@@ -10733,6 +10803,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
vcpu_load_eoi_exitmap(vcpu);
if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu))
kvm_vcpu_reload_apic_access_page(vcpu);
+#ifdef CONFIG_KVM_HYPERV
if (kvm_check_request(KVM_REQ_HV_CRASH, vcpu)) {
vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT;
vcpu->run->system_event.type = KVM_SYSTEM_EVENT_CRASH;
@@ -10763,6 +10834,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
*/
if (kvm_check_request(KVM_REQ_HV_STIMER, vcpu))
kvm_hv_process_stimers(vcpu);
+#endif
if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu))
kvm_vcpu_update_apicv(vcpu);
if (kvm_check_request(KVM_REQ_APF_READY, vcpu))
@@ -11081,6 +11153,7 @@ static int vcpu_run(struct kvm_vcpu *vcpu)
{
int r;
+ vcpu->run->exit_reason = KVM_EXIT_UNKNOWN;
vcpu->arch.l1tf_flush_l1d = true;
for (;;) {
@@ -11598,7 +11671,7 @@ static bool kvm_is_valid_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
*/
if (!(sregs->cr4 & X86_CR4_PAE) || !(sregs->efer & EFER_LMA))
return false;
- if (kvm_vcpu_is_illegal_gpa(vcpu, sregs->cr3))
+ if (!kvm_vcpu_is_legal_cr3(vcpu, sregs->cr3))
return false;
} else {
/*
@@ -12207,7 +12280,6 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
}
if (!init_event) {
- kvm_pmu_reset(vcpu);
vcpu->arch.smbase = 0x30000;
vcpu->arch.msr_misc_features_enables = 0;
@@ -12424,7 +12496,9 @@ void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu)
void kvm_arch_free_vm(struct kvm *kvm)
{
- kfree(to_kvm_hv(kvm)->hv_pa_pg);
+#if IS_ENABLED(CONFIG_HYPERV)
+ kfree(kvm->arch.hv_pa_pg);
+#endif
__kvm_arch_free_vm(kvm);
}
@@ -12434,9 +12508,11 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
int ret;
unsigned long flags;
- if (type)
+ if (!kvm_is_vm_type_supported(type))
return -EINVAL;
+ kvm->arch.vm_type = type;
+
ret = kvm_page_track_init(kvm);
if (ret)
goto out;
@@ -12575,8 +12651,8 @@ void __user * __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa,
hva = slot->userspace_addr;
}
- for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
- struct kvm_userspace_memory_region m;
+ for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
+ struct kvm_userspace_memory_region2 m;
m.slot = id | (i << 16);
m.flags = 0;
@@ -12726,6 +12802,10 @@ static int kvm_alloc_memslot_metadata(struct kvm *kvm,
}
}
+#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
+ kvm_mmu_init_memslot_memory_attributes(kvm, slot);
+#endif
+
if (kvm_page_track_create_memslot(kvm, slot, npages))
goto out_free;
@@ -13536,6 +13616,10 @@ int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva)
switch (type) {
case INVPCID_TYPE_INDIV_ADDR:
+ /*
+ * LAM doesn't apply to addresses that are inputs to TLB
+ * invalidation.
+ */
if ((!pcid_enabled && (operand.pcid != 0)) ||
is_noncanonical_address(operand.gla, vcpu)) {
kvm_inject_gp(vcpu, 0);
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 5184fde1dc54..2f7e19166658 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -530,6 +530,8 @@ bool kvm_msr_allowed(struct kvm_vcpu *vcpu, u32 index, u32 type);
__reserved_bits |= X86_CR4_VMXE; \
if (!__cpu_has(__c, X86_FEATURE_PCID)) \
__reserved_bits |= X86_CR4_PCIDE; \
+ if (!__cpu_has(__c, X86_FEATURE_LAM)) \
+ __reserved_bits |= X86_CR4_LAM_SUP; \
__reserved_bits; \
})
diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index 523bb6df5ac9..4b4e738c6f1b 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -1162,7 +1162,9 @@ int kvm_xen_hvm_config(struct kvm *kvm, struct kvm_xen_hvm_config *xhc)
{
/* Only some feature flags need to be *enabled* by userspace */
u32 permitted_flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL |
- KVM_XEN_HVM_CONFIG_EVTCHN_SEND;
+ KVM_XEN_HVM_CONFIG_EVTCHN_SEND |
+ KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE;
+ u32 old_flags;
if (xhc->flags & ~permitted_flags)
return -EINVAL;
@@ -1183,9 +1185,14 @@ int kvm_xen_hvm_config(struct kvm *kvm, struct kvm_xen_hvm_config *xhc)
else if (!xhc->msr && kvm->arch.xen_hvm_config.msr)
static_branch_slow_dec_deferred(&kvm_xen_enabled);
+ old_flags = kvm->arch.xen_hvm_config.flags;
memcpy(&kvm->arch.xen_hvm_config, xhc, sizeof(*xhc));
mutex_unlock(&kvm->arch.xen.xen_lock);
+
+ if ((old_flags ^ xhc->flags) & KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE)
+ kvm_make_all_cpus_request(kvm, KVM_REQ_CLOCK_UPDATE);
+
return 0;
}
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index ea2eb2ec90e2..55c4b07ec1f6 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -283,6 +283,9 @@ static int setup_mcfg_map(struct acpi_pci_root_info *ci)
info->mcfg_added = false;
seg = info->sd.domain;
+ dev_dbg(dev, "%s(%04x %pR ECAM %pa)\n", __func__, seg,
+ &root->secondary, &root->mcfg_addr);
+
/* return success if MMCFG is not in use */
if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg)
return 0;
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index 4b3efaa82ab7..0cc9520666ef 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * mmconfig-shared.c - Low-level direct PCI config space access via
- * MMCONFIG - common code between i386 and x86-64.
+ * Low-level direct PCI config space access via ECAM - common code between
+ * i386 and x86-64.
*
* This code does:
* - known chipset handling
@@ -11,6 +11,8 @@
* themselves.
*/
+#define pr_fmt(fmt) "PCI: " fmt
+
#include <linux/acpi.h>
#include <linux/efi.h>
#include <linux/pci.h>
@@ -24,9 +26,7 @@
#include <asm/pci_x86.h>
#include <asm/acpi.h>
-#define PREFIX "PCI: "
-
-/* Indicate if the mmcfg resources have been placed into the resource table. */
+/* Indicate if the ECAM resources have been placed into the resource table */
static bool pci_mmcfg_running_state;
static bool pci_mmcfg_arch_init_failed;
static DEFINE_MUTEX(pci_mmcfg_lock);
@@ -90,7 +90,7 @@ static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
- "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
+ "PCI ECAM %04x [bus %02x-%02x]", segment, start, end);
res->name = new->name;
return new;
@@ -102,16 +102,15 @@ struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
struct pci_mmcfg_region *new;
new = pci_mmconfig_alloc(segment, start, end, addr);
- if (new) {
- mutex_lock(&pci_mmcfg_lock);
- list_add_sorted(new);
- mutex_unlock(&pci_mmcfg_lock);
+ if (!new)
+ return NULL;
- pr_info(PREFIX
- "MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
- "(base %#lx)\n",
- segment, start, end, &new->res, (unsigned long)addr);
- }
+ mutex_lock(&pci_mmcfg_lock);
+ list_add_sorted(new);
+ mutex_unlock(&pci_mmcfg_lock);
+
+ pr_info("ECAM %pR (base %#lx) for domain %04x [bus %02x-%02x]\n",
+ &new->res, (unsigned long)addr, segment, start, end);
return new;
}
@@ -205,7 +204,7 @@ static const char *__init pci_mmcfg_amd_fam10h(void)
msr <<= 32;
msr |= low;
- /* mmconfig is not enable */
+ /* ECAM is not enabled */
if (!(msr & FAM10H_MMIO_CONF_ENABLE))
return NULL;
@@ -367,7 +366,7 @@ static int __init pci_mmcfg_check_hostbridge(void)
name = pci_mmcfg_probes[i].probe();
if (name)
- pr_info(PREFIX "%s with MMCONFIG support\n", name);
+ pr_info("%s with ECAM support\n", name);
}
/* some end_bus_number is crazy, fix it */
@@ -443,9 +442,11 @@ static bool is_acpi_reserved(u64 start, u64 end, enum e820_type not_used)
return mcfg_res.flags;
}
-static bool is_efi_mmio(u64 start, u64 end, enum e820_type not_used)
+static bool is_efi_mmio(struct resource *res)
{
#ifdef CONFIG_EFI
+ u64 start = res->start;
+ u64 end = res->start + resource_size(res);
efi_memory_desc_t *md;
u64 size, mmio_start, mmio_end;
@@ -455,11 +456,6 @@ static bool is_efi_mmio(u64 start, u64 end, enum e820_type not_used)
mmio_start = md->phys_addr;
mmio_end = mmio_start + size;
- /*
- * N.B. Caller supplies (start, start + size),
- * so to match, mmio_end is the first address
- * *past* the EFI_MEMORY_MAPPED_IO area.
- */
if (mmio_start <= start && end <= mmio_end)
return true;
}
@@ -490,11 +486,10 @@ static bool __ref is_mmconf_reserved(check_reserved_t is_reserved,
return false;
if (dev)
- dev_info(dev, "MMCONFIG at %pR reserved as %s\n",
+ dev_info(dev, "ECAM %pR reserved as %s\n",
&cfg->res, method);
else
- pr_info(PREFIX "MMCONFIG at %pR reserved as %s\n",
- &cfg->res, method);
+ pr_info("ECAM %pR reserved as %s\n", &cfg->res, method);
if (old_size != size) {
/* update end_bus */
@@ -503,47 +498,51 @@ static bool __ref is_mmconf_reserved(check_reserved_t is_reserved,
cfg->res.end = cfg->res.start +
PCI_MMCFG_BUS_OFFSET(num_buses) - 1;
snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN,
- "PCI MMCONFIG %04x [bus %02x-%02x]",
+ "PCI ECAM %04x [bus %02x-%02x]",
cfg->segment, cfg->start_bus, cfg->end_bus);
if (dev)
- dev_info(dev,
- "MMCONFIG "
- "at %pR (base %#lx) (size reduced!)\n",
- &cfg->res, (unsigned long) cfg->address);
+ dev_info(dev, "ECAM %pR (base %#lx) (size reduced!)\n",
+ &cfg->res, (unsigned long) cfg->address);
else
- pr_info(PREFIX
- "MMCONFIG for %04x [bus%02x-%02x] "
- "at %pR (base %#lx) (size reduced!)\n",
- cfg->segment, cfg->start_bus, cfg->end_bus,
- &cfg->res, (unsigned long) cfg->address);
+ pr_info("ECAM %pR (base %#lx) for %04x [bus%02x-%02x] (size reduced!)\n",
+ &cfg->res, (unsigned long) cfg->address,
+ cfg->segment, cfg->start_bus, cfg->end_bus);
}
return true;
}
-static bool __ref
-pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int early)
+static bool __ref pci_mmcfg_reserved(struct device *dev,
+ struct pci_mmcfg_region *cfg, int early)
{
+ struct resource *conflict;
+
if (!early && !acpi_disabled) {
if (is_mmconf_reserved(is_acpi_reserved, cfg, dev,
"ACPI motherboard resource"))
return true;
if (dev)
- dev_info(dev, FW_INFO
- "MMCONFIG at %pR not reserved in "
- "ACPI motherboard resources\n",
+ dev_info(dev, FW_INFO "ECAM %pR not reserved in ACPI motherboard resources\n",
&cfg->res);
else
- pr_info(FW_INFO PREFIX
- "MMCONFIG at %pR not reserved in "
- "ACPI motherboard resources\n",
- &cfg->res);
-
- if (is_mmconf_reserved(is_efi_mmio, cfg, dev,
- "EfiMemoryMappedIO"))
+ pr_info(FW_INFO "ECAM %pR not reserved in ACPI motherboard resources\n",
+ &cfg->res);
+
+ if (is_efi_mmio(&cfg->res)) {
+ pr_info("ECAM %pR is EfiMemoryMappedIO; assuming valid\n",
+ &cfg->res);
+ conflict = insert_resource_conflict(&iomem_resource,
+ &cfg->res);
+ if (conflict)
+ pr_warn("ECAM %pR conflicts with %s %pR\n",
+ &cfg->res, conflict->name, conflict);
+ else
+ pr_info("ECAM %pR reserved to work around lack of ACPI motherboard _CRS\n",
+ &cfg->res);
return true;
+ }
}
/*
@@ -569,30 +568,31 @@ static void __init pci_mmcfg_reject_broken(int early)
struct pci_mmcfg_region *cfg;
list_for_each_entry(cfg, &pci_mmcfg_list, list) {
- if (pci_mmcfg_check_reserved(NULL, cfg, early) == 0) {
- pr_info(PREFIX "not using MMCONFIG\n");
+ if (!pci_mmcfg_reserved(NULL, cfg, early)) {
+ pr_info("not using ECAM (%pR not reserved)\n",
+ &cfg->res);
free_all_mmcfg();
return;
}
}
}
-static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
- struct acpi_mcfg_allocation *cfg)
+static bool __init acpi_mcfg_valid_entry(struct acpi_table_mcfg *mcfg,
+ struct acpi_mcfg_allocation *cfg)
{
if (cfg->address < 0xFFFFFFFF)
- return 0;
+ return true;
if (!strncmp(mcfg->header.oem_id, "SGI", 3))
- return 0;
+ return true;
if ((mcfg->header.revision >= 1) && (dmi_get_bios_year() >= 2010))
- return 0;
+ return true;
- pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
- "is above 4GB, ignored\n", cfg->pci_segment,
- cfg->start_bus_number, cfg->end_bus_number, cfg->address);
- return -EINVAL;
+ pr_err("ECAM at %#llx for %04x [bus %02x-%02x] is above 4GB, ignored\n",
+ cfg->address, cfg->pci_segment, cfg->start_bus_number,
+ cfg->end_bus_number);
+ return false;
}
static int __init pci_parse_mcfg(struct acpi_table_header *header)
@@ -616,21 +616,21 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header)
i -= sizeof(struct acpi_mcfg_allocation);
}
if (entries == 0) {
- pr_err(PREFIX "MMCONFIG has no entries\n");
+ pr_err("MCFG has no entries\n");
return -ENODEV;
}
cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
for (i = 0; i < entries; i++) {
cfg = &cfg_table[i];
- if (acpi_mcfg_check_entry(mcfg, cfg)) {
+ if (!acpi_mcfg_valid_entry(mcfg, cfg)) {
free_all_mmcfg();
return -ENODEV;
}
if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
cfg->end_bus_number, cfg->address) == NULL) {
- pr_warn(PREFIX "no memory for MCFG entries\n");
+ pr_warn("no memory for MCFG entries\n");
free_all_mmcfg();
return -ENOMEM;
}
@@ -667,6 +667,8 @@ static int pci_mmcfg_for_each_region(int (*func)(__u64 start, __u64 size,
static void __init __pci_mmcfg_init(int early)
{
+ pr_debug("%s(%s)\n", __func__, early ? "early" : "late");
+
pci_mmcfg_reject_broken(early);
if (list_empty(&pci_mmcfg_list))
return;
@@ -693,6 +695,8 @@ static int __initdata known_bridge;
void __init pci_mmcfg_early_init(void)
{
+ pr_debug("%s() pci_probe %#x\n", __func__, pci_probe);
+
if (pci_probe & PCI_PROBE_MMCONF) {
if (pci_mmcfg_check_hostbridge())
known_bridge = 1;
@@ -706,14 +710,16 @@ void __init pci_mmcfg_early_init(void)
void __init pci_mmcfg_late_init(void)
{
- /* MMCONFIG disabled */
+ pr_debug("%s() pci_probe %#x\n", __func__, pci_probe);
+
+ /* ECAM disabled */
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
return;
if (known_bridge)
return;
- /* MMCONFIG hasn't been enabled yet, try again */
+ /* ECAM hasn't been enabled yet, try again */
if (pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF) {
acpi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
__pci_mmcfg_init(0);
@@ -726,7 +732,9 @@ static int __init pci_mmcfg_late_insert_resources(void)
pci_mmcfg_running_state = true;
- /* If we are not using MMCONFIG, don't insert the resources. */
+ pr_debug("%s() pci_probe %#x\n", __func__, pci_probe);
+
+ /* If we are not using ECAM, don't insert the resources. */
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
return 1;
@@ -735,21 +743,24 @@ static int __init pci_mmcfg_late_insert_resources(void)
* marked so it won't cause request errors when __request_region is
* called.
*/
- list_for_each_entry(cfg, &pci_mmcfg_list, list)
- if (!cfg->res.parent)
+ list_for_each_entry(cfg, &pci_mmcfg_list, list) {
+ if (!cfg->res.parent) {
+ pr_debug("%s() insert %pR\n", __func__, &cfg->res);
insert_resource(&iomem_resource, &cfg->res);
+ }
+ }
return 0;
}
/*
- * Perform MMCONFIG resource insertion after PCI initialization to allow for
+ * Perform ECAM resource insertion after PCI initialization to allow for
* misprogrammed MCFG tables that state larger sizes but actually conflict
* with other system resources.
*/
late_initcall(pci_mmcfg_late_insert_resources);
-/* Add MMCFG information for host bridges */
+/* Add ECAM information for host bridges */
int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
phys_addr_t addr)
{
@@ -757,6 +768,8 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
struct resource *tmp = NULL;
struct pci_mmcfg_region *cfg;
+ dev_dbg(dev, "%s(%04x [bus %02x-%02x])\n", __func__, seg, start, end);
+
if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed)
return -ENODEV;
@@ -767,15 +780,17 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
cfg = pci_mmconfig_lookup(seg, start);
if (cfg) {
if (cfg->end_bus < end)
- dev_info(dev, FW_INFO
- "MMCONFIG for "
- "domain %04x [bus %02x-%02x] "
- "only partially covers this bridge\n",
- cfg->segment, cfg->start_bus, cfg->end_bus);
+ dev_info(dev, FW_INFO "ECAM %pR for domain %04x [bus %02x-%02x] only partially covers this bridge\n",
+ &cfg->res, cfg->segment, cfg->start_bus,
+ cfg->end_bus);
mutex_unlock(&pci_mmcfg_lock);
return -EEXIST;
}
+ /*
+ * Don't move earlier; we must return -EEXIST, not -EINVAL, if
+ * pci_mmconfig_lookup() finds something
+ */
if (!addr) {
mutex_unlock(&pci_mmcfg_lock);
return -EINVAL;
@@ -784,10 +799,10 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
rc = -EBUSY;
cfg = pci_mmconfig_alloc(seg, start, end, addr);
if (cfg == NULL) {
- dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
+ dev_warn(dev, "fail to add ECAM (out of memory)\n");
rc = -ENOMEM;
- } else if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
- dev_warn(dev, FW_BUG "MMCONFIG %pR isn't reserved\n",
+ } else if (!pci_mmcfg_reserved(dev, cfg, 0)) {
+ dev_warn(dev, FW_BUG "ECAM %pR isn't reserved\n",
&cfg->res);
} else {
/* Insert resource if it's not in boot stage */
@@ -796,16 +811,13 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
&cfg->res);
if (tmp) {
- dev_warn(dev,
- "MMCONFIG %pR conflicts with "
- "%s %pR\n",
+ dev_warn(dev, "ECAM %pR conflicts with %s %pR\n",
&cfg->res, tmp->name, tmp);
} else if (pci_mmcfg_arch_map(cfg)) {
- dev_warn(dev, "fail to map MMCONFIG %pR.\n",
- &cfg->res);
+ dev_warn(dev, "fail to map ECAM %pR\n", &cfg->res);
} else {
list_add_sorted(cfg);
- dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
+ dev_info(dev, "ECAM %pR (base %#lx)\n",
&cfg->res, (unsigned long)addr);
cfg = NULL;
rc = 0;
@@ -823,7 +835,7 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
return rc;
}
-/* Delete MMCFG information for host bridges */
+/* Delete ECAM information for host bridges */
int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
{
struct pci_mmcfg_region *cfg;
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index bfa789875322..f9ef97c593cf 100644
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -131,7 +131,7 @@ const struct pci_raw_ops pci_mmcfg = {
int __init pci_mmcfg_arch_init(void)
{
- printk(KERN_INFO "PCI: Using MMCONFIG for extended config space\n");
+ printk(KERN_INFO "PCI: Using ECAM for extended config space\n");
raw_pci_ext_ops = &pci_mmcfg;
return 1;
}
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index 0c7b6e66c644..cb5aa79a759e 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -6,6 +6,8 @@
* space mapped. This allows lockless config space operation.
*/
+#define pr_fmt(fmt) "PCI: " fmt
+
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/acpi.h>
@@ -14,8 +16,6 @@
#include <asm/e820/api.h>
#include <asm/pci_x86.h>
-#define PREFIX "PCI: "
-
static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
{
struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
@@ -111,6 +111,25 @@ static void __iomem *mcfg_ioremap(struct pci_mmcfg_region *cfg)
return addr;
}
+int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
+{
+ cfg->virt = mcfg_ioremap(cfg);
+ if (!cfg->virt) {
+ pr_err("can't map ECAM at %pR\n", &cfg->res);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
+{
+ if (cfg && cfg->virt) {
+ iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
+ cfg->virt = NULL;
+ }
+}
+
int __init pci_mmcfg_arch_init(void)
{
struct pci_mmcfg_region *cfg;
@@ -133,22 +152,3 @@ void __init pci_mmcfg_arch_free(void)
list_for_each_entry(cfg, &pci_mmcfg_list, list)
pci_mmcfg_arch_unmap(cfg);
}
-
-int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
-{
- cfg->virt = mcfg_ioremap(cfg);
- if (!cfg->virt) {
- pr_err(PREFIX "can't map MMCONFIG at %pR\n", &cfg->res);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
-{
- if (cfg && cfg->virt) {
- iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
- cfg->virt = NULL;
- }
-}
diff --git a/arch/x86/pci/pcbios.c b/arch/x86/pci/pcbios.c
index 4f15280732ed..244c643bb0b5 100644
--- a/arch/x86/pci/pcbios.c
+++ b/arch/x86/pci/pcbios.c
@@ -3,6 +3,8 @@
* BIOS32 and PCI BIOS handling.
*/
+#include <linux/bits.h>
+#include <linux/bitfield.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -29,8 +31,19 @@
#define PCIBIOS_HW_TYPE1_SPEC 0x10
#define PCIBIOS_HW_TYPE2_SPEC 0x20
+/*
+ * Returned in EAX:
+ * - AH: return code
+ */
+#define PCIBIOS_RETURN_CODE GENMASK(15, 8)
+
int pcibios_enabled;
+static u8 pcibios_get_return_code(u32 eax)
+{
+ return FIELD_GET(PCIBIOS_RETURN_CODE, eax);
+}
+
/* According to the BIOS specification at:
* http://members.datafast.net.au/dft0802/specs/bios21.pdf, we could
* restrict the x zone to some pages and make it ro. But this may be
@@ -154,7 +167,7 @@ static int __init check_pcibios(void)
: "memory");
local_irq_restore(flags);
- status = (eax >> 8) & 0xff;
+ status = pcibios_get_return_code(eax);
hw_mech = eax & 0xff;
major_ver = (ebx >> 8) & 0xff;
minor_ver = ebx & 0xff;
@@ -227,7 +240,7 @@ static int pci_bios_read(unsigned int seg, unsigned int bus,
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
- return (int)((result & 0xff00) >> 8);
+ return pcibios_get_return_code(result);
}
static int pci_bios_write(unsigned int seg, unsigned int bus,
@@ -269,7 +282,7 @@ static int pci_bios_write(unsigned int seg, unsigned int bus,
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
- return (int)((result & 0xff00) >> 8);
+ return pcibios_get_return_code(result);
}
@@ -385,9 +398,10 @@ struct irq_routing_table * pcibios_get_irq_routing_table(void)
"m" (opt)
: "memory");
DBG("OK ret=%d, size=%d, map=%x\n", ret, opt.size, map);
- if (ret & 0xff00)
- printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
- else if (opt.size) {
+ ret = pcibios_get_return_code(ret);
+ if (ret) {
+ printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", ret);
+ } else if (opt.size) {
rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL);
if (rt) {
memset(rt, 0, sizeof(struct irq_routing_table));
@@ -415,7 +429,7 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq)
"b" ((dev->bus->number << 8) | dev->devfn),
"c" ((irq << 8) | (pin + 10)),
"S" (&pci_indirect));
- return !(ret & 0xff00);
+ return pcibios_get_return_code(ret) == PCIBIOS_SUCCESSFUL;
}
EXPORT_SYMBOL(pcibios_set_irq_routing);
diff --git a/arch/x86/um/asm/elf.h b/arch/x86/um/asm/elf.h
index 6523eb7c3bd1..6052200fe925 100644
--- a/arch/x86/um/asm/elf.h
+++ b/arch/x86/um/asm/elf.h
@@ -168,8 +168,8 @@ do { \
(pr_reg)[18] = (_regs)->regs.gp[18]; \
(pr_reg)[19] = (_regs)->regs.gp[19]; \
(pr_reg)[20] = (_regs)->regs.gp[20]; \
- (pr_reg)[21] = current->thread.arch.fs; \
- (pr_reg)[22] = 0; \
+ (pr_reg)[21] = (_regs)->regs.gp[21]; \
+ (pr_reg)[22] = (_regs)->regs.gp[22]; \
(pr_reg)[23] = 0; \
(pr_reg)[24] = 0; \
(pr_reg)[25] = 0; \
diff --git a/arch/x86/um/asm/processor_64.h b/arch/x86/um/asm/processor_64.h
index 1ef9c21877bc..f90159508936 100644
--- a/arch/x86/um/asm/processor_64.h
+++ b/arch/x86/um/asm/processor_64.h
@@ -10,13 +10,11 @@
struct arch_thread {
unsigned long debugregs[8];
int debugregs_seq;
- unsigned long fs;
struct faultinfo faultinfo;
};
#define INIT_ARCH_THREAD { .debugregs = { [ 0 ... 7 ] = 0 }, \
.debugregs_seq = 0, \
- .fs = 0, \
.faultinfo = { 0, 0, 0 } }
#define STACKSLOTS_PER_LINE 4
@@ -28,7 +26,6 @@ static inline void arch_flush_thread(struct arch_thread *thread)
static inline void arch_copy_thread(struct arch_thread *from,
struct arch_thread *to)
{
- to->fs = from->fs;
}
#define current_sp() ({ void *sp; __asm__("movq %%rsp, %0" : "=r" (sp) : ); sp; })
diff --git a/arch/x86/um/os-Linux/Makefile b/arch/x86/um/os-Linux/Makefile
index ae169125d03f..5249bbc30dcd 100644
--- a/arch/x86/um/os-Linux/Makefile
+++ b/arch/x86/um/os-Linux/Makefile
@@ -6,7 +6,6 @@
obj-y = registers.o task_size.o mcontext.o
obj-$(CONFIG_X86_32) += tls.o
-obj-$(CONFIG_64BIT) += prctl.o
USER_OBJS := $(obj-y)
diff --git a/arch/x86/um/os-Linux/prctl.c b/arch/x86/um/os-Linux/prctl.c
deleted file mode 100644
index 8431e87ac333..000000000000
--- a/arch/x86/um/os-Linux/prctl.c
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright (C) 2007 Jeff Dike (jdike@{addtoit.com,linux.intel.com})
- * Licensed under the GPL
- */
-
-#include <sys/ptrace.h>
-#include <asm/ptrace.h>
-
-int os_arch_prctl(int pid, int option, unsigned long *arg2)
-{
- return ptrace(PTRACE_ARCH_PRCTL, pid, (unsigned long) arg2, option);
-}
diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c
index 0bc4b73a9cde..7f1abde2c84b 100644
--- a/arch/x86/um/ptrace_32.c
+++ b/arch/x86/um/ptrace_32.c
@@ -25,30 +25,6 @@ void arch_switch_to(struct task_struct *to)
printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n");
}
-int is_syscall(unsigned long addr)
-{
- unsigned short instr;
- int n;
-
- n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
- if (n) {
- /* access_process_vm() grants access to vsyscall and stub,
- * while copy_from_user doesn't. Maybe access_process_vm is
- * slow, but that doesn't matter, since it will be called only
- * in case of singlestepping, if copy_from_user failed.
- */
- n = access_process_vm(current, addr, &instr, sizeof(instr),
- FOLL_FORCE);
- if (n != sizeof(instr)) {
- printk(KERN_ERR "is_syscall : failed to read "
- "instruction from 0x%lx\n", addr);
- return 1;
- }
- }
- /* int 0x80 or sysenter */
- return (instr == 0x80cd) || (instr == 0x340f);
-}
-
/* determines which flags the user has access to. */
/* 1 = access 0 = no access */
#define FLAG_MASK 0x00044dd5
diff --git a/arch/x86/um/ptrace_64.c b/arch/x86/um/ptrace_64.c
index 289d0159b041..aa68d83d3f44 100644
--- a/arch/x86/um/ptrace_64.c
+++ b/arch/x86/um/ptrace_64.c
@@ -188,32 +188,6 @@ int peek_user(struct task_struct *child, long addr, long data)
return put_user(tmp, (unsigned long *) data);
}
-/* XXX Mostly copied from sys-i386 */
-int is_syscall(unsigned long addr)
-{
- unsigned short instr;
- int n;
-
- n = copy_from_user(&instr, (void __user *) addr, sizeof(instr));
- if (n) {
- /*
- * access_process_vm() grants access to vsyscall and stub,
- * while copy_from_user doesn't. Maybe access_process_vm is
- * slow, but that doesn't matter, since it will be called only
- * in case of singlestepping, if copy_from_user failed.
- */
- n = access_process_vm(current, addr, &instr, sizeof(instr),
- FOLL_FORCE);
- if (n != sizeof(instr)) {
- printk("is_syscall : failed to read instruction from "
- "0x%lx\n", addr);
- return 1;
- }
- }
- /* sysenter */
- return instr == 0x050f;
-}
-
static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child)
{
int err, n, cpu = ((struct thread_info *) child->stack)->cpu;
diff --git a/arch/x86/um/shared/sysdep/ptrace_32.h b/arch/x86/um/shared/sysdep/ptrace_32.h
index db8478a83a09..0c4989842fbe 100644
--- a/arch/x86/um/shared/sysdep/ptrace_32.h
+++ b/arch/x86/um/shared/sysdep/ptrace_32.h
@@ -8,10 +8,6 @@
#define MAX_FP_NR HOST_FPX_SIZE
-void set_using_sysemu(int value);
-int get_using_sysemu(void);
-extern int sysemu_supported;
-
#define UPT_SYSCALL_ARG1(r) UPT_BX(r)
#define UPT_SYSCALL_ARG2(r) UPT_CX(r)
#define UPT_SYSCALL_ARG3(r) UPT_DX(r)
diff --git a/arch/x86/um/shared/sysdep/ptrace_user.h b/arch/x86/um/shared/sysdep/ptrace_user.h
index 44782bbad41e..1d1a824fa652 100644
--- a/arch/x86/um/shared/sysdep/ptrace_user.h
+++ b/arch/x86/um/shared/sysdep/ptrace_user.h
@@ -15,14 +15,12 @@
#define FP_SIZE ((HOST_FPX_SIZE > HOST_FP_SIZE) ? HOST_FPX_SIZE : HOST_FP_SIZE)
#else
#define FP_SIZE HOST_FP_SIZE
+#endif
/*
- * x86_64 FC3 doesn't define this in /usr/include/linux/ptrace.h even though
- * it's defined in the kernel's include/linux/ptrace.h. Additionally, use the
- * 2.4 name and value for 2.4 host compatibility.
+ * glibc before 2.27 does not include PTRACE_SYSEMU_SINGLESTEP in its enum,
+ * ensure we have a definition by (re-)defining it here.
*/
-#ifndef PTRACE_OLDSETOPTIONS
-#define PTRACE_OLDSETOPTIONS 21
-#endif
-
+#ifndef PTRACE_SYSEMU_SINGLESTEP
+#define PTRACE_SYSEMU_SINGLESTEP 32
#endif
diff --git a/arch/x86/um/shared/sysdep/stub_32.h b/arch/x86/um/shared/sysdep/stub_32.h
index 38fa894b65d0..ea8b5a2d67af 100644
--- a/arch/x86/um/shared/sysdep/stub_32.h
+++ b/arch/x86/um/shared/sysdep/stub_32.h
@@ -12,72 +12,79 @@
#define STUB_MMAP_NR __NR_mmap2
#define MMAP_OFFSET(o) ((o) >> UM_KERN_PAGE_SHIFT)
-static inline long stub_syscall0(long syscall)
+static __always_inline long stub_syscall0(long syscall)
{
long ret;
- __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall));
+ __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall)
+ : "memory");
return ret;
}
-static inline long stub_syscall1(long syscall, long arg1)
+static __always_inline long stub_syscall1(long syscall, long arg1)
{
long ret;
- __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1));
+ __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1)
+ : "memory");
return ret;
}
-static inline long stub_syscall2(long syscall, long arg1, long arg2)
+static __always_inline long stub_syscall2(long syscall, long arg1, long arg2)
{
long ret;
__asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1),
- "c" (arg2));
+ "c" (arg2)
+ : "memory");
return ret;
}
-static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
+static __always_inline long stub_syscall3(long syscall, long arg1, long arg2,
+ long arg3)
{
long ret;
__asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1),
- "c" (arg2), "d" (arg3));
+ "c" (arg2), "d" (arg3)
+ : "memory");
return ret;
}
-static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
- long arg4)
+static __always_inline long stub_syscall4(long syscall, long arg1, long arg2,
+ long arg3, long arg4)
{
long ret;
__asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1),
- "c" (arg2), "d" (arg3), "S" (arg4));
+ "c" (arg2), "d" (arg3), "S" (arg4)
+ : "memory");
return ret;
}
-static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3,
- long arg4, long arg5)
+static __always_inline long stub_syscall5(long syscall, long arg1, long arg2,
+ long arg3, long arg4, long arg5)
{
long ret;
__asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1),
- "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5));
+ "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5)
+ : "memory");
return ret;
}
-static inline void trap_myself(void)
+static __always_inline void trap_myself(void)
{
__asm("int3");
}
-static inline void remap_stack_and_trap(void)
+static __always_inline void remap_stack_and_trap(void)
{
__asm__ volatile (
"movl %%esp,%%ebx ;"
diff --git a/arch/x86/um/shared/sysdep/stub_64.h b/arch/x86/um/shared/sysdep/stub_64.h
index 2de1c8f88173..b24168ef0ac4 100644
--- a/arch/x86/um/shared/sysdep/stub_64.h
+++ b/arch/x86/um/shared/sysdep/stub_64.h
@@ -16,7 +16,7 @@
#define __syscall_clobber "r11","rcx","memory"
#define __syscall "syscall"
-static inline long stub_syscall0(long syscall)
+static __always_inline long stub_syscall0(long syscall)
{
long ret;
@@ -27,7 +27,7 @@ static inline long stub_syscall0(long syscall)
return ret;
}
-static inline long stub_syscall2(long syscall, long arg1, long arg2)
+static __always_inline long stub_syscall2(long syscall, long arg1, long arg2)
{
long ret;
@@ -38,7 +38,8 @@ static inline long stub_syscall2(long syscall, long arg1, long arg2)
return ret;
}
-static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
+static __always_inline long stub_syscall3(long syscall, long arg1, long arg2,
+ long arg3)
{
long ret;
@@ -50,7 +51,7 @@ static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
return ret;
}
-static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
+static __always_inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
long arg4)
{
long ret;
@@ -64,8 +65,8 @@ static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
return ret;
}
-static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3,
- long arg4, long arg5)
+static __always_inline long stub_syscall5(long syscall, long arg1, long arg2,
+ long arg3, long arg4, long arg5)
{
long ret;
@@ -78,12 +79,12 @@ static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3,
return ret;
}
-static inline void trap_myself(void)
+static __always_inline void trap_myself(void)
{
__asm("int3");
}
-static inline void remap_stack_and_trap(void)
+static __always_inline void remap_stack_and_trap(void)
{
__asm__ volatile (
"movq %0,%%rax ;"
diff --git a/arch/x86/um/syscalls_64.c b/arch/x86/um/syscalls_64.c
index 27b29ae6c471..6a00a28c9cca 100644
--- a/arch/x86/um/syscalls_64.c
+++ b/arch/x86/um/syscalls_64.c
@@ -16,60 +16,24 @@
long arch_prctl(struct task_struct *task, int option,
unsigned long __user *arg2)
{
- unsigned long *ptr = arg2, tmp;
- long ret;
- int pid = task->mm->context.id.u.pid;
-
- /*
- * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to
- * be safe), we need to call arch_prctl on the host because
- * setting %fs may result in something else happening (like a
- * GDT or thread.fs being set instead). So, we let the host
- * fiddle the registers and thread struct and restore the
- * registers afterwards.
- *
- * So, the saved registers are stored to the process (this
- * needed because a stub may have been the last thing to run),
- * arch_prctl is run on the host, then the registers are read
- * back.
- */
- switch (option) {
- case ARCH_SET_FS:
- case ARCH_SET_GS:
- ret = restore_pid_registers(pid, &current->thread.regs.regs);
- if (ret)
- return ret;
- break;
- case ARCH_GET_FS:
- case ARCH_GET_GS:
- /*
- * With these two, we read to a local pointer and
- * put_user it to the userspace pointer that we were
- * given. If addr isn't valid (because it hasn't been
- * faulted in or is just bogus), we want put_user to
- * fault it in (or return -EFAULT) instead of having
- * the host return -EFAULT.
- */
- ptr = &tmp;
- }
-
- ret = os_arch_prctl(pid, option, ptr);
- if (ret)
- return ret;
+ long ret = -EINVAL;
switch (option) {
case ARCH_SET_FS:
- current->thread.arch.fs = (unsigned long) ptr;
- ret = save_registers(pid, &current->thread.regs.regs);
+ current->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)] =
+ (unsigned long) arg2;
+ ret = 0;
break;
case ARCH_SET_GS:
- ret = save_registers(pid, &current->thread.regs.regs);
+ current->thread.regs.regs.gp[GS_BASE / sizeof(unsigned long)] =
+ (unsigned long) arg2;
+ ret = 0;
break;
case ARCH_GET_FS:
- ret = put_user(tmp, arg2);
+ ret = put_user(current->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)], arg2);
break;
case ARCH_GET_GS:
- ret = put_user(tmp, arg2);
+ ret = put_user(current->thread.regs.regs.gp[GS_BASE / sizeof(unsigned long)], arg2);
break;
}
@@ -83,10 +47,10 @@ SYSCALL_DEFINE2(arch_prctl, int, option, unsigned long, arg2)
void arch_switch_to(struct task_struct *to)
{
- if ((to->thread.arch.fs == 0) || (to->mm == NULL))
- return;
-
- arch_prctl(to, ARCH_SET_FS, (void __user *) to->thread.arch.fs);
+ /*
+ * Nothing needs to be done on x86_64.
+ * The FS_BASE/GS_BASE registers are saved in the ptrace register set.
+ */
}
SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
diff --git a/arch/x86/um/tls_64.c b/arch/x86/um/tls_64.c
index ebd3855d9b13..c51a613f6f5c 100644
--- a/arch/x86/um/tls_64.c
+++ b/arch/x86/um/tls_64.c
@@ -12,7 +12,7 @@ int arch_set_tls(struct task_struct *t, unsigned long tls)
* If CLONE_SETTLS is set, we need to save the thread id
* so it can be set during context switches.
*/
- t->thread.arch.fs = tls;
+ t->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)] = tls;
return 0;
}
diff --git a/arch/x86/virt/vmx/tdx/Makefile b/arch/x86/virt/vmx/tdx/Makefile
index 46ef8f73aebb..90da47eb85ee 100644
--- a/arch/x86/virt/vmx/tdx/Makefile
+++ b/arch/x86/virt/vmx/tdx/Makefile
@@ -1,2 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y += seamcall.o
+obj-y += seamcall.o tdx.o
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
new file mode 100644
index 000000000000..4d6826a76f78
--- /dev/null
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -0,0 +1,1492 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright(c) 2023 Intel Corporation.
+ *
+ * Intel Trusted Domain Extensions (TDX) support
+ */
+
+#define pr_fmt(fmt) "virt/tdx: " fmt
+
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/printk.h>
+#include <linux/cpu.h>
+#include <linux/spinlock.h>
+#include <linux/percpu-defs.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/memblock.h>
+#include <linux/memory.h>
+#include <linux/minmax.h>
+#include <linux/sizes.h>
+#include <linux/pfn.h>
+#include <linux/align.h>
+#include <linux/sort.h>
+#include <linux/log2.h>
+#include <linux/acpi.h>
+#include <linux/suspend.h>
+#include <linux/acpi.h>
+#include <asm/page.h>
+#include <asm/special_insns.h>
+#include <asm/msr-index.h>
+#include <asm/msr.h>
+#include <asm/cpufeature.h>
+#include <asm/tdx.h>
+#include <asm/intel-family.h>
+#include <asm/processor.h>
+#include <asm/mce.h>
+#include "tdx.h"
+
+static u32 tdx_global_keyid __ro_after_init;
+static u32 tdx_guest_keyid_start __ro_after_init;
+static u32 tdx_nr_guest_keyids __ro_after_init;
+
+static DEFINE_PER_CPU(bool, tdx_lp_initialized);
+
+static struct tdmr_info_list tdx_tdmr_list;
+
+static enum tdx_module_status_t tdx_module_status;
+static DEFINE_MUTEX(tdx_module_lock);
+
+/* All TDX-usable memory regions. Protected by mem_hotplug_lock. */
+static LIST_HEAD(tdx_memlist);
+
+typedef void (*sc_err_func_t)(u64 fn, u64 err, struct tdx_module_args *args);
+
+static inline void seamcall_err(u64 fn, u64 err, struct tdx_module_args *args)
+{
+ pr_err("SEAMCALL (0x%016llx) failed: 0x%016llx\n", fn, err);
+}
+
+static inline void seamcall_err_ret(u64 fn, u64 err,
+ struct tdx_module_args *args)
+{
+ seamcall_err(fn, err, args);
+ pr_err("RCX 0x%016llx RDX 0x%016llx R08 0x%016llx\n",
+ args->rcx, args->rdx, args->r8);
+ pr_err("R09 0x%016llx R10 0x%016llx R11 0x%016llx\n",
+ args->r9, args->r10, args->r11);
+}
+
+static inline int sc_retry_prerr(sc_func_t func, sc_err_func_t err_func,
+ u64 fn, struct tdx_module_args *args)
+{
+ u64 sret = sc_retry(func, fn, args);
+
+ if (sret == TDX_SUCCESS)
+ return 0;
+
+ if (sret == TDX_SEAMCALL_VMFAILINVALID)
+ return -ENODEV;
+
+ if (sret == TDX_SEAMCALL_GP)
+ return -EOPNOTSUPP;
+
+ if (sret == TDX_SEAMCALL_UD)
+ return -EACCES;
+
+ err_func(fn, sret, args);
+ return -EIO;
+}
+
+#define seamcall_prerr(__fn, __args) \
+ sc_retry_prerr(__seamcall, seamcall_err, (__fn), (__args))
+
+#define seamcall_prerr_ret(__fn, __args) \
+ sc_retry_prerr(__seamcall_ret, seamcall_err_ret, (__fn), (__args))
+
+/*
+ * Do the module global initialization once and return its result.
+ * It can be done on any cpu. It's always called with interrupts
+ * disabled.
+ */
+static int try_init_module_global(void)
+{
+ struct tdx_module_args args = {};
+ static DEFINE_RAW_SPINLOCK(sysinit_lock);
+ static bool sysinit_done;
+ static int sysinit_ret;
+
+ lockdep_assert_irqs_disabled();
+
+ raw_spin_lock(&sysinit_lock);
+
+ if (sysinit_done)
+ goto out;
+
+ /* RCX is module attributes and all bits are reserved */
+ args.rcx = 0;
+ sysinit_ret = seamcall_prerr(TDH_SYS_INIT, &args);
+
+ /*
+ * The first SEAMCALL also detects the TDX module, thus
+ * it can fail due to the TDX module is not loaded.
+ * Dump message to let the user know.
+ */
+ if (sysinit_ret == -ENODEV)
+ pr_err("module not loaded\n");
+
+ sysinit_done = true;
+out:
+ raw_spin_unlock(&sysinit_lock);
+ return sysinit_ret;
+}
+
+/**
+ * tdx_cpu_enable - Enable TDX on local cpu
+ *
+ * Do one-time TDX module per-cpu initialization SEAMCALL (and TDX module
+ * global initialization SEAMCALL if not done) on local cpu to make this
+ * cpu be ready to run any other SEAMCALLs.
+ *
+ * Always call this function via IPI function calls.
+ *
+ * Return 0 on success, otherwise errors.
+ */
+int tdx_cpu_enable(void)
+{
+ struct tdx_module_args args = {};
+ int ret;
+
+ if (!boot_cpu_has(X86_FEATURE_TDX_HOST_PLATFORM))
+ return -ENODEV;
+
+ lockdep_assert_irqs_disabled();
+
+ if (__this_cpu_read(tdx_lp_initialized))
+ return 0;
+
+ /*
+ * The TDX module global initialization is the very first step
+ * to enable TDX. Need to do it first (if hasn't been done)
+ * before the per-cpu initialization.
+ */
+ ret = try_init_module_global();
+ if (ret)
+ return ret;
+
+ ret = seamcall_prerr(TDH_SYS_LP_INIT, &args);
+ if (ret)
+ return ret;
+
+ __this_cpu_write(tdx_lp_initialized, true);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tdx_cpu_enable);
+
+/*
+ * Add a memory region as a TDX memory block. The caller must make sure
+ * all memory regions are added in address ascending order and don't
+ * overlap.
+ */
+static int add_tdx_memblock(struct list_head *tmb_list, unsigned long start_pfn,
+ unsigned long end_pfn, int nid)
+{
+ struct tdx_memblock *tmb;
+
+ tmb = kmalloc(sizeof(*tmb), GFP_KERNEL);
+ if (!tmb)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&tmb->list);
+ tmb->start_pfn = start_pfn;
+ tmb->end_pfn = end_pfn;
+ tmb->nid = nid;
+
+ /* @tmb_list is protected by mem_hotplug_lock */
+ list_add_tail(&tmb->list, tmb_list);
+ return 0;
+}
+
+static void free_tdx_memlist(struct list_head *tmb_list)
+{
+ /* @tmb_list is protected by mem_hotplug_lock */
+ while (!list_empty(tmb_list)) {
+ struct tdx_memblock *tmb = list_first_entry(tmb_list,
+ struct tdx_memblock, list);
+
+ list_del(&tmb->list);
+ kfree(tmb);
+ }
+}
+
+/*
+ * Ensure that all memblock memory regions are convertible to TDX
+ * memory. Once this has been established, stash the memblock
+ * ranges off in a secondary structure because memblock is modified
+ * in memory hotplug while TDX memory regions are fixed.
+ */
+static int build_tdx_memlist(struct list_head *tmb_list)
+{
+ unsigned long start_pfn, end_pfn;
+ int i, nid, ret;
+
+ for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid) {
+ /*
+ * The first 1MB is not reported as TDX convertible memory.
+ * Although the first 1MB is always reserved and won't end up
+ * to the page allocator, it is still in memblock's memory
+ * regions. Skip them manually to exclude them as TDX memory.
+ */
+ start_pfn = max(start_pfn, PHYS_PFN(SZ_1M));
+ if (start_pfn >= end_pfn)
+ continue;
+
+ /*
+ * Add the memory regions as TDX memory. The regions in
+ * memblock has already guaranteed they are in address
+ * ascending order and don't overlap.
+ */
+ ret = add_tdx_memblock(tmb_list, start_pfn, end_pfn, nid);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+err:
+ free_tdx_memlist(tmb_list);
+ return ret;
+}
+
+static int read_sys_metadata_field(u64 field_id, u64 *data)
+{
+ struct tdx_module_args args = {};
+ int ret;
+
+ /*
+ * TDH.SYS.RD -- reads one global metadata field
+ * - RDX (in): the field to read
+ * - R8 (out): the field data
+ */
+ args.rdx = field_id;
+ ret = seamcall_prerr_ret(TDH_SYS_RD, &args);
+ if (ret)
+ return ret;
+
+ *data = args.r8;
+
+ return 0;
+}
+
+static int read_sys_metadata_field16(u64 field_id,
+ int offset,
+ struct tdx_tdmr_sysinfo *ts)
+{
+ u16 *ts_member = ((void *)ts) + offset;
+ u64 tmp;
+ int ret;
+
+ if (WARN_ON_ONCE(MD_FIELD_ID_ELE_SIZE_CODE(field_id) !=
+ MD_FIELD_ID_ELE_SIZE_16BIT))
+ return -EINVAL;
+
+ ret = read_sys_metadata_field(field_id, &tmp);
+ if (ret)
+ return ret;
+
+ *ts_member = tmp;
+
+ return 0;
+}
+
+struct field_mapping {
+ u64 field_id;
+ int offset;
+};
+
+#define TD_SYSINFO_MAP(_field_id, _offset) \
+ { .field_id = MD_FIELD_ID_##_field_id, \
+ .offset = offsetof(struct tdx_tdmr_sysinfo, _offset) }
+
+/* Map TD_SYSINFO fields into 'struct tdx_tdmr_sysinfo': */
+static const struct field_mapping fields[] = {
+ TD_SYSINFO_MAP(MAX_TDMRS, max_tdmrs),
+ TD_SYSINFO_MAP(MAX_RESERVED_PER_TDMR, max_reserved_per_tdmr),
+ TD_SYSINFO_MAP(PAMT_4K_ENTRY_SIZE, pamt_entry_size[TDX_PS_4K]),
+ TD_SYSINFO_MAP(PAMT_2M_ENTRY_SIZE, pamt_entry_size[TDX_PS_2M]),
+ TD_SYSINFO_MAP(PAMT_1G_ENTRY_SIZE, pamt_entry_size[TDX_PS_1G]),
+};
+
+static int get_tdx_tdmr_sysinfo(struct tdx_tdmr_sysinfo *tdmr_sysinfo)
+{
+ int ret;
+ int i;
+
+ /* Populate 'tdmr_sysinfo' fields using the mapping structure above: */
+ for (i = 0; i < ARRAY_SIZE(fields); i++) {
+ ret = read_sys_metadata_field16(fields[i].field_id,
+ fields[i].offset,
+ tdmr_sysinfo);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Calculate the actual TDMR size */
+static int tdmr_size_single(u16 max_reserved_per_tdmr)
+{
+ int tdmr_sz;
+
+ /*
+ * The actual size of TDMR depends on the maximum
+ * number of reserved areas.
+ */
+ tdmr_sz = sizeof(struct tdmr_info);
+ tdmr_sz += sizeof(struct tdmr_reserved_area) * max_reserved_per_tdmr;
+
+ return ALIGN(tdmr_sz, TDMR_INFO_ALIGNMENT);
+}
+
+static int alloc_tdmr_list(struct tdmr_info_list *tdmr_list,
+ struct tdx_tdmr_sysinfo *tdmr_sysinfo)
+{
+ size_t tdmr_sz, tdmr_array_sz;
+ void *tdmr_array;
+
+ tdmr_sz = tdmr_size_single(tdmr_sysinfo->max_reserved_per_tdmr);
+ tdmr_array_sz = tdmr_sz * tdmr_sysinfo->max_tdmrs;
+
+ /*
+ * To keep things simple, allocate all TDMRs together.
+ * The buffer needs to be physically contiguous to make
+ * sure each TDMR is physically contiguous.
+ */
+ tdmr_array = alloc_pages_exact(tdmr_array_sz,
+ GFP_KERNEL | __GFP_ZERO);
+ if (!tdmr_array)
+ return -ENOMEM;
+
+ tdmr_list->tdmrs = tdmr_array;
+
+ /*
+ * Keep the size of TDMR to find the target TDMR
+ * at a given index in the TDMR list.
+ */
+ tdmr_list->tdmr_sz = tdmr_sz;
+ tdmr_list->max_tdmrs = tdmr_sysinfo->max_tdmrs;
+ tdmr_list->nr_consumed_tdmrs = 0;
+
+ return 0;
+}
+
+static void free_tdmr_list(struct tdmr_info_list *tdmr_list)
+{
+ free_pages_exact(tdmr_list->tdmrs,
+ tdmr_list->max_tdmrs * tdmr_list->tdmr_sz);
+}
+
+/* Get the TDMR from the list at the given index. */
+static struct tdmr_info *tdmr_entry(struct tdmr_info_list *tdmr_list,
+ int idx)
+{
+ int tdmr_info_offset = tdmr_list->tdmr_sz * idx;
+
+ return (void *)tdmr_list->tdmrs + tdmr_info_offset;
+}
+
+#define TDMR_ALIGNMENT SZ_1G
+#define TDMR_ALIGN_DOWN(_addr) ALIGN_DOWN((_addr), TDMR_ALIGNMENT)
+#define TDMR_ALIGN_UP(_addr) ALIGN((_addr), TDMR_ALIGNMENT)
+
+static inline u64 tdmr_end(struct tdmr_info *tdmr)
+{
+ return tdmr->base + tdmr->size;
+}
+
+/*
+ * Take the memory referenced in @tmb_list and populate the
+ * preallocated @tdmr_list, following all the special alignment
+ * and size rules for TDMR.
+ */
+static int fill_out_tdmrs(struct list_head *tmb_list,
+ struct tdmr_info_list *tdmr_list)
+{
+ struct tdx_memblock *tmb;
+ int tdmr_idx = 0;
+
+ /*
+ * Loop over TDX memory regions and fill out TDMRs to cover them.
+ * To keep it simple, always try to use one TDMR to cover one
+ * memory region.
+ *
+ * In practice TDX supports at least 64 TDMRs. A 2-socket system
+ * typically only consumes less than 10 of those. This code is
+ * dumb and simple and may use more TMDRs than is strictly
+ * required.
+ */
+ list_for_each_entry(tmb, tmb_list, list) {
+ struct tdmr_info *tdmr = tdmr_entry(tdmr_list, tdmr_idx);
+ u64 start, end;
+
+ start = TDMR_ALIGN_DOWN(PFN_PHYS(tmb->start_pfn));
+ end = TDMR_ALIGN_UP(PFN_PHYS(tmb->end_pfn));
+
+ /*
+ * A valid size indicates the current TDMR has already
+ * been filled out to cover the previous memory region(s).
+ */
+ if (tdmr->size) {
+ /*
+ * Loop to the next if the current memory region
+ * has already been fully covered.
+ */
+ if (end <= tdmr_end(tdmr))
+ continue;
+
+ /* Otherwise, skip the already covered part. */
+ if (start < tdmr_end(tdmr))
+ start = tdmr_end(tdmr);
+
+ /*
+ * Create a new TDMR to cover the current memory
+ * region, or the remaining part of it.
+ */
+ tdmr_idx++;
+ if (tdmr_idx >= tdmr_list->max_tdmrs) {
+ pr_warn("initialization failed: TDMRs exhausted.\n");
+ return -ENOSPC;
+ }
+
+ tdmr = tdmr_entry(tdmr_list, tdmr_idx);
+ }
+
+ tdmr->base = start;
+ tdmr->size = end - start;
+ }
+
+ /* @tdmr_idx is always the index of the last valid TDMR. */
+ tdmr_list->nr_consumed_tdmrs = tdmr_idx + 1;
+
+ /*
+ * Warn early that kernel is about to run out of TDMRs.
+ *
+ * This is an indication that TDMR allocation has to be
+ * reworked to be smarter to not run into an issue.
+ */
+ if (tdmr_list->max_tdmrs - tdmr_list->nr_consumed_tdmrs < TDMR_NR_WARN)
+ pr_warn("consumed TDMRs reaching limit: %d used out of %d\n",
+ tdmr_list->nr_consumed_tdmrs,
+ tdmr_list->max_tdmrs);
+
+ return 0;
+}
+
+/*
+ * Calculate PAMT size given a TDMR and a page size. The returned
+ * PAMT size is always aligned up to 4K page boundary.
+ */
+static unsigned long tdmr_get_pamt_sz(struct tdmr_info *tdmr, int pgsz,
+ u16 pamt_entry_size)
+{
+ unsigned long pamt_sz, nr_pamt_entries;
+
+ switch (pgsz) {
+ case TDX_PS_4K:
+ nr_pamt_entries = tdmr->size >> PAGE_SHIFT;
+ break;
+ case TDX_PS_2M:
+ nr_pamt_entries = tdmr->size >> PMD_SHIFT;
+ break;
+ case TDX_PS_1G:
+ nr_pamt_entries = tdmr->size >> PUD_SHIFT;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+
+ pamt_sz = nr_pamt_entries * pamt_entry_size;
+ /* TDX requires PAMT size must be 4K aligned */
+ pamt_sz = ALIGN(pamt_sz, PAGE_SIZE);
+
+ return pamt_sz;
+}
+
+/*
+ * Locate a NUMA node which should hold the allocation of the @tdmr
+ * PAMT. This node will have some memory covered by the TDMR. The
+ * relative amount of memory covered is not considered.
+ */
+static int tdmr_get_nid(struct tdmr_info *tdmr, struct list_head *tmb_list)
+{
+ struct tdx_memblock *tmb;
+
+ /*
+ * A TDMR must cover at least part of one TMB. That TMB will end
+ * after the TDMR begins. But, that TMB may have started before
+ * the TDMR. Find the next 'tmb' that _ends_ after this TDMR
+ * begins. Ignore 'tmb' start addresses. They are irrelevant.
+ */
+ list_for_each_entry(tmb, tmb_list, list) {
+ if (tmb->end_pfn > PHYS_PFN(tdmr->base))
+ return tmb->nid;
+ }
+
+ /*
+ * Fall back to allocating the TDMR's metadata from node 0 when
+ * no TDX memory block can be found. This should never happen
+ * since TDMRs originate from TDX memory blocks.
+ */
+ pr_warn("TDMR [0x%llx, 0x%llx): unable to find local NUMA node for PAMT allocation, fallback to use node 0.\n",
+ tdmr->base, tdmr_end(tdmr));
+ return 0;
+}
+
+/*
+ * Allocate PAMTs from the local NUMA node of some memory in @tmb_list
+ * within @tdmr, and set up PAMTs for @tdmr.
+ */
+static int tdmr_set_up_pamt(struct tdmr_info *tdmr,
+ struct list_head *tmb_list,
+ u16 pamt_entry_size[])
+{
+ unsigned long pamt_base[TDX_PS_NR];
+ unsigned long pamt_size[TDX_PS_NR];
+ unsigned long tdmr_pamt_base;
+ unsigned long tdmr_pamt_size;
+ struct page *pamt;
+ int pgsz, nid;
+
+ nid = tdmr_get_nid(tdmr, tmb_list);
+
+ /*
+ * Calculate the PAMT size for each TDX supported page size
+ * and the total PAMT size.
+ */
+ tdmr_pamt_size = 0;
+ for (pgsz = TDX_PS_4K; pgsz < TDX_PS_NR; pgsz++) {
+ pamt_size[pgsz] = tdmr_get_pamt_sz(tdmr, pgsz,
+ pamt_entry_size[pgsz]);
+ tdmr_pamt_size += pamt_size[pgsz];
+ }
+
+ /*
+ * Allocate one chunk of physically contiguous memory for all
+ * PAMTs. This helps minimize the PAMT's use of reserved areas
+ * in overlapped TDMRs.
+ */
+ pamt = alloc_contig_pages(tdmr_pamt_size >> PAGE_SHIFT, GFP_KERNEL,
+ nid, &node_online_map);
+ if (!pamt)
+ return -ENOMEM;
+
+ /*
+ * Break the contiguous allocation back up into the
+ * individual PAMTs for each page size.
+ */
+ tdmr_pamt_base = page_to_pfn(pamt) << PAGE_SHIFT;
+ for (pgsz = TDX_PS_4K; pgsz < TDX_PS_NR; pgsz++) {
+ pamt_base[pgsz] = tdmr_pamt_base;
+ tdmr_pamt_base += pamt_size[pgsz];
+ }
+
+ tdmr->pamt_4k_base = pamt_base[TDX_PS_4K];
+ tdmr->pamt_4k_size = pamt_size[TDX_PS_4K];
+ tdmr->pamt_2m_base = pamt_base[TDX_PS_2M];
+ tdmr->pamt_2m_size = pamt_size[TDX_PS_2M];
+ tdmr->pamt_1g_base = pamt_base[TDX_PS_1G];
+ tdmr->pamt_1g_size = pamt_size[TDX_PS_1G];
+
+ return 0;
+}
+
+static void tdmr_get_pamt(struct tdmr_info *tdmr, unsigned long *pamt_base,
+ unsigned long *pamt_size)
+{
+ unsigned long pamt_bs, pamt_sz;
+
+ /*
+ * The PAMT was allocated in one contiguous unit. The 4K PAMT
+ * should always point to the beginning of that allocation.
+ */
+ pamt_bs = tdmr->pamt_4k_base;
+ pamt_sz = tdmr->pamt_4k_size + tdmr->pamt_2m_size + tdmr->pamt_1g_size;
+
+ WARN_ON_ONCE((pamt_bs & ~PAGE_MASK) || (pamt_sz & ~PAGE_MASK));
+
+ *pamt_base = pamt_bs;
+ *pamt_size = pamt_sz;
+}
+
+static void tdmr_do_pamt_func(struct tdmr_info *tdmr,
+ void (*pamt_func)(unsigned long base, unsigned long size))
+{
+ unsigned long pamt_base, pamt_size;
+
+ tdmr_get_pamt(tdmr, &pamt_base, &pamt_size);
+
+ /* Do nothing if PAMT hasn't been allocated for this TDMR */
+ if (!pamt_size)
+ return;
+
+ if (WARN_ON_ONCE(!pamt_base))
+ return;
+
+ pamt_func(pamt_base, pamt_size);
+}
+
+static void free_pamt(unsigned long pamt_base, unsigned long pamt_size)
+{
+ free_contig_range(pamt_base >> PAGE_SHIFT, pamt_size >> PAGE_SHIFT);
+}
+
+static void tdmr_free_pamt(struct tdmr_info *tdmr)
+{
+ tdmr_do_pamt_func(tdmr, free_pamt);
+}
+
+static void tdmrs_free_pamt_all(struct tdmr_info_list *tdmr_list)
+{
+ int i;
+
+ for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++)
+ tdmr_free_pamt(tdmr_entry(tdmr_list, i));
+}
+
+/* Allocate and set up PAMTs for all TDMRs */
+static int tdmrs_set_up_pamt_all(struct tdmr_info_list *tdmr_list,
+ struct list_head *tmb_list,
+ u16 pamt_entry_size[])
+{
+ int i, ret = 0;
+
+ for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) {
+ ret = tdmr_set_up_pamt(tdmr_entry(tdmr_list, i), tmb_list,
+ pamt_entry_size);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+err:
+ tdmrs_free_pamt_all(tdmr_list);
+ return ret;
+}
+
+/*
+ * Convert TDX private pages back to normal by using MOVDIR64B to
+ * clear these pages. Note this function doesn't flush cache of
+ * these TDX private pages. The caller should make sure of that.
+ */
+static void reset_tdx_pages(unsigned long base, unsigned long size)
+{
+ const void *zero_page = (const void *)page_address(ZERO_PAGE(0));
+ unsigned long phys, end;
+
+ end = base + size;
+ for (phys = base; phys < end; phys += 64)
+ movdir64b(__va(phys), zero_page);
+
+ /*
+ * MOVDIR64B uses WC protocol. Use memory barrier to
+ * make sure any later user of these pages sees the
+ * updated data.
+ */
+ mb();
+}
+
+static void tdmr_reset_pamt(struct tdmr_info *tdmr)
+{
+ tdmr_do_pamt_func(tdmr, reset_tdx_pages);
+}
+
+static void tdmrs_reset_pamt_all(struct tdmr_info_list *tdmr_list)
+{
+ int i;
+
+ for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++)
+ tdmr_reset_pamt(tdmr_entry(tdmr_list, i));
+}
+
+static unsigned long tdmrs_count_pamt_kb(struct tdmr_info_list *tdmr_list)
+{
+ unsigned long pamt_size = 0;
+ int i;
+
+ for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) {
+ unsigned long base, size;
+
+ tdmr_get_pamt(tdmr_entry(tdmr_list, i), &base, &size);
+ pamt_size += size;
+ }
+
+ return pamt_size / 1024;
+}
+
+static int tdmr_add_rsvd_area(struct tdmr_info *tdmr, int *p_idx, u64 addr,
+ u64 size, u16 max_reserved_per_tdmr)
+{
+ struct tdmr_reserved_area *rsvd_areas = tdmr->reserved_areas;
+ int idx = *p_idx;
+
+ /* Reserved area must be 4K aligned in offset and size */
+ if (WARN_ON(addr & ~PAGE_MASK || size & ~PAGE_MASK))
+ return -EINVAL;
+
+ if (idx >= max_reserved_per_tdmr) {
+ pr_warn("initialization failed: TDMR [0x%llx, 0x%llx): reserved areas exhausted.\n",
+ tdmr->base, tdmr_end(tdmr));
+ return -ENOSPC;
+ }
+
+ /*
+ * Consume one reserved area per call. Make no effort to
+ * optimize or reduce the number of reserved areas which are
+ * consumed by contiguous reserved areas, for instance.
+ */
+ rsvd_areas[idx].offset = addr - tdmr->base;
+ rsvd_areas[idx].size = size;
+
+ *p_idx = idx + 1;
+
+ return 0;
+}
+
+/*
+ * Go through @tmb_list to find holes between memory areas. If any of
+ * those holes fall within @tdmr, set up a TDMR reserved area to cover
+ * the hole.
+ */
+static int tdmr_populate_rsvd_holes(struct list_head *tmb_list,
+ struct tdmr_info *tdmr,
+ int *rsvd_idx,
+ u16 max_reserved_per_tdmr)
+{
+ struct tdx_memblock *tmb;
+ u64 prev_end;
+ int ret;
+
+ /*
+ * Start looking for reserved blocks at the
+ * beginning of the TDMR.
+ */
+ prev_end = tdmr->base;
+ list_for_each_entry(tmb, tmb_list, list) {
+ u64 start, end;
+
+ start = PFN_PHYS(tmb->start_pfn);
+ end = PFN_PHYS(tmb->end_pfn);
+
+ /* Break if this region is after the TDMR */
+ if (start >= tdmr_end(tdmr))
+ break;
+
+ /* Exclude regions before this TDMR */
+ if (end < tdmr->base)
+ continue;
+
+ /*
+ * Skip over memory areas that
+ * have already been dealt with.
+ */
+ if (start <= prev_end) {
+ prev_end = end;
+ continue;
+ }
+
+ /* Add the hole before this region */
+ ret = tdmr_add_rsvd_area(tdmr, rsvd_idx, prev_end,
+ start - prev_end,
+ max_reserved_per_tdmr);
+ if (ret)
+ return ret;
+
+ prev_end = end;
+ }
+
+ /* Add the hole after the last region if it exists. */
+ if (prev_end < tdmr_end(tdmr)) {
+ ret = tdmr_add_rsvd_area(tdmr, rsvd_idx, prev_end,
+ tdmr_end(tdmr) - prev_end,
+ max_reserved_per_tdmr);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Go through @tdmr_list to find all PAMTs. If any of those PAMTs
+ * overlaps with @tdmr, set up a TDMR reserved area to cover the
+ * overlapping part.
+ */
+static int tdmr_populate_rsvd_pamts(struct tdmr_info_list *tdmr_list,
+ struct tdmr_info *tdmr,
+ int *rsvd_idx,
+ u16 max_reserved_per_tdmr)
+{
+ int i, ret;
+
+ for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) {
+ struct tdmr_info *tmp = tdmr_entry(tdmr_list, i);
+ unsigned long pamt_base, pamt_size, pamt_end;
+
+ tdmr_get_pamt(tmp, &pamt_base, &pamt_size);
+ /* Each TDMR must already have PAMT allocated */
+ WARN_ON_ONCE(!pamt_size || !pamt_base);
+
+ pamt_end = pamt_base + pamt_size;
+ /* Skip PAMTs outside of the given TDMR */
+ if ((pamt_end <= tdmr->base) ||
+ (pamt_base >= tdmr_end(tdmr)))
+ continue;
+
+ /* Only mark the part within the TDMR as reserved */
+ if (pamt_base < tdmr->base)
+ pamt_base = tdmr->base;
+ if (pamt_end > tdmr_end(tdmr))
+ pamt_end = tdmr_end(tdmr);
+
+ ret = tdmr_add_rsvd_area(tdmr, rsvd_idx, pamt_base,
+ pamt_end - pamt_base,
+ max_reserved_per_tdmr);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* Compare function called by sort() for TDMR reserved areas */
+static int rsvd_area_cmp_func(const void *a, const void *b)
+{
+ struct tdmr_reserved_area *r1 = (struct tdmr_reserved_area *)a;
+ struct tdmr_reserved_area *r2 = (struct tdmr_reserved_area *)b;
+
+ if (r1->offset + r1->size <= r2->offset)
+ return -1;
+ if (r1->offset >= r2->offset + r2->size)
+ return 1;
+
+ /* Reserved areas cannot overlap. The caller must guarantee. */
+ WARN_ON_ONCE(1);
+ return -1;
+}
+
+/*
+ * Populate reserved areas for the given @tdmr, including memory holes
+ * (via @tmb_list) and PAMTs (via @tdmr_list).
+ */
+static int tdmr_populate_rsvd_areas(struct tdmr_info *tdmr,
+ struct list_head *tmb_list,
+ struct tdmr_info_list *tdmr_list,
+ u16 max_reserved_per_tdmr)
+{
+ int ret, rsvd_idx = 0;
+
+ ret = tdmr_populate_rsvd_holes(tmb_list, tdmr, &rsvd_idx,
+ max_reserved_per_tdmr);
+ if (ret)
+ return ret;
+
+ ret = tdmr_populate_rsvd_pamts(tdmr_list, tdmr, &rsvd_idx,
+ max_reserved_per_tdmr);
+ if (ret)
+ return ret;
+
+ /* TDX requires reserved areas listed in address ascending order */
+ sort(tdmr->reserved_areas, rsvd_idx, sizeof(struct tdmr_reserved_area),
+ rsvd_area_cmp_func, NULL);
+
+ return 0;
+}
+
+/*
+ * Populate reserved areas for all TDMRs in @tdmr_list, including memory
+ * holes (via @tmb_list) and PAMTs.
+ */
+static int tdmrs_populate_rsvd_areas_all(struct tdmr_info_list *tdmr_list,
+ struct list_head *tmb_list,
+ u16 max_reserved_per_tdmr)
+{
+ int i;
+
+ for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) {
+ int ret;
+
+ ret = tdmr_populate_rsvd_areas(tdmr_entry(tdmr_list, i),
+ tmb_list, tdmr_list, max_reserved_per_tdmr);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Construct a list of TDMRs on the preallocated space in @tdmr_list
+ * to cover all TDX memory regions in @tmb_list based on the TDX module
+ * TDMR global information in @tdmr_sysinfo.
+ */
+static int construct_tdmrs(struct list_head *tmb_list,
+ struct tdmr_info_list *tdmr_list,
+ struct tdx_tdmr_sysinfo *tdmr_sysinfo)
+{
+ int ret;
+
+ ret = fill_out_tdmrs(tmb_list, tdmr_list);
+ if (ret)
+ return ret;
+
+ ret = tdmrs_set_up_pamt_all(tdmr_list, tmb_list,
+ tdmr_sysinfo->pamt_entry_size);
+ if (ret)
+ return ret;
+
+ ret = tdmrs_populate_rsvd_areas_all(tdmr_list, tmb_list,
+ tdmr_sysinfo->max_reserved_per_tdmr);
+ if (ret)
+ tdmrs_free_pamt_all(tdmr_list);
+
+ /*
+ * The tdmr_info_list is read-only from here on out.
+ * Ensure that these writes are seen by other CPUs.
+ * Pairs with a smp_rmb() in is_pamt_page().
+ */
+ smp_wmb();
+
+ return ret;
+}
+
+static int config_tdx_module(struct tdmr_info_list *tdmr_list, u64 global_keyid)
+{
+ struct tdx_module_args args = {};
+ u64 *tdmr_pa_array;
+ size_t array_sz;
+ int i, ret;
+
+ /*
+ * TDMRs are passed to the TDX module via an array of physical
+ * addresses of each TDMR. The array itself also has certain
+ * alignment requirement.
+ */
+ array_sz = tdmr_list->nr_consumed_tdmrs * sizeof(u64);
+ array_sz = roundup_pow_of_two(array_sz);
+ if (array_sz < TDMR_INFO_PA_ARRAY_ALIGNMENT)
+ array_sz = TDMR_INFO_PA_ARRAY_ALIGNMENT;
+
+ tdmr_pa_array = kzalloc(array_sz, GFP_KERNEL);
+ if (!tdmr_pa_array)
+ return -ENOMEM;
+
+ for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++)
+ tdmr_pa_array[i] = __pa(tdmr_entry(tdmr_list, i));
+
+ args.rcx = __pa(tdmr_pa_array);
+ args.rdx = tdmr_list->nr_consumed_tdmrs;
+ args.r8 = global_keyid;
+ ret = seamcall_prerr(TDH_SYS_CONFIG, &args);
+
+ /* Free the array as it is not required anymore. */
+ kfree(tdmr_pa_array);
+
+ return ret;
+}
+
+static int do_global_key_config(void *unused)
+{
+ struct tdx_module_args args = {};
+
+ return seamcall_prerr(TDH_SYS_KEY_CONFIG, &args);
+}
+
+/*
+ * Attempt to configure the global KeyID on all physical packages.
+ *
+ * This requires running code on at least one CPU in each package.
+ * TDMR initialization) will fail will fail if any package in the
+ * system has no online CPUs.
+ *
+ * This code takes no affirmative steps to online CPUs. Callers (aka.
+ * KVM) can ensure success by ensuring sufficient CPUs are online and
+ * can run SEAMCALLs.
+ */
+static int config_global_keyid(void)
+{
+ cpumask_var_t packages;
+ int cpu, ret = -EINVAL;
+
+ if (!zalloc_cpumask_var(&packages, GFP_KERNEL))
+ return -ENOMEM;
+
+ /*
+ * Hardware doesn't guarantee cache coherency across different
+ * KeyIDs. The kernel needs to flush PAMT's dirty cachelines
+ * (associated with KeyID 0) before the TDX module can use the
+ * global KeyID to access the PAMT. Given PAMTs are potentially
+ * large (~1/256th of system RAM), just use WBINVD.
+ */
+ wbinvd_on_all_cpus();
+
+ for_each_online_cpu(cpu) {
+ /*
+ * The key configuration only needs to be done once per
+ * package and will return an error if configured more
+ * than once. Avoid doing it multiple times per package.
+ */
+ if (cpumask_test_and_set_cpu(topology_physical_package_id(cpu),
+ packages))
+ continue;
+
+ /*
+ * TDH.SYS.KEY.CONFIG cannot run concurrently on
+ * different cpus. Do it one by one.
+ */
+ ret = smp_call_on_cpu(cpu, do_global_key_config, NULL, true);
+ if (ret)
+ break;
+ }
+
+ free_cpumask_var(packages);
+ return ret;
+}
+
+static int init_tdmr(struct tdmr_info *tdmr)
+{
+ u64 next;
+
+ /*
+ * Initializing a TDMR can be time consuming. To avoid long
+ * SEAMCALLs, the TDX module may only initialize a part of the
+ * TDMR in each call.
+ */
+ do {
+ struct tdx_module_args args = {
+ .rcx = tdmr->base,
+ };
+ int ret;
+
+ ret = seamcall_prerr_ret(TDH_SYS_TDMR_INIT, &args);
+ if (ret)
+ return ret;
+ /*
+ * RDX contains 'next-to-initialize' address if
+ * TDH.SYS.TDMR.INIT did not fully complete and
+ * should be retried.
+ */
+ next = args.rdx;
+ cond_resched();
+ /* Keep making SEAMCALLs until the TDMR is done */
+ } while (next < tdmr->base + tdmr->size);
+
+ return 0;
+}
+
+static int init_tdmrs(struct tdmr_info_list *tdmr_list)
+{
+ int i;
+
+ /*
+ * This operation is costly. It can be parallelized,
+ * but keep it simple for now.
+ */
+ for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) {
+ int ret;
+
+ ret = init_tdmr(tdmr_entry(tdmr_list, i));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int init_tdx_module(void)
+{
+ struct tdx_tdmr_sysinfo tdmr_sysinfo;
+ int ret;
+
+ /*
+ * To keep things simple, assume that all TDX-protected memory
+ * will come from the page allocator. Make sure all pages in the
+ * page allocator are TDX-usable memory.
+ *
+ * Build the list of "TDX-usable" memory regions which cover all
+ * pages in the page allocator to guarantee that. Do it while
+ * holding mem_hotplug_lock read-lock as the memory hotplug code
+ * path reads the @tdx_memlist to reject any new memory.
+ */
+ get_online_mems();
+
+ ret = build_tdx_memlist(&tdx_memlist);
+ if (ret)
+ goto out_put_tdxmem;
+
+ ret = get_tdx_tdmr_sysinfo(&tdmr_sysinfo);
+ if (ret)
+ goto err_free_tdxmem;
+
+ /* Allocate enough space for constructing TDMRs */
+ ret = alloc_tdmr_list(&tdx_tdmr_list, &tdmr_sysinfo);
+ if (ret)
+ goto err_free_tdxmem;
+
+ /* Cover all TDX-usable memory regions in TDMRs */
+ ret = construct_tdmrs(&tdx_memlist, &tdx_tdmr_list, &tdmr_sysinfo);
+ if (ret)
+ goto err_free_tdmrs;
+
+ /* Pass the TDMRs and the global KeyID to the TDX module */
+ ret = config_tdx_module(&tdx_tdmr_list, tdx_global_keyid);
+ if (ret)
+ goto err_free_pamts;
+
+ /* Config the key of global KeyID on all packages */
+ ret = config_global_keyid();
+ if (ret)
+ goto err_reset_pamts;
+
+ /* Initialize TDMRs to complete the TDX module initialization */
+ ret = init_tdmrs(&tdx_tdmr_list);
+ if (ret)
+ goto err_reset_pamts;
+
+ pr_info("%lu KB allocated for PAMT\n", tdmrs_count_pamt_kb(&tdx_tdmr_list));
+
+out_put_tdxmem:
+ /*
+ * @tdx_memlist is written here and read at memory hotplug time.
+ * Lock out memory hotplug code while building it.
+ */
+ put_online_mems();
+ return ret;
+
+err_reset_pamts:
+ /*
+ * Part of PAMTs may already have been initialized by the
+ * TDX module. Flush cache before returning PAMTs back
+ * to the kernel.
+ */
+ wbinvd_on_all_cpus();
+ /*
+ * According to the TDX hardware spec, if the platform
+ * doesn't have the "partial write machine check"
+ * erratum, any kernel read/write will never cause #MC
+ * in kernel space, thus it's OK to not convert PAMTs
+ * back to normal. But do the conversion anyway here
+ * as suggested by the TDX spec.
+ */
+ tdmrs_reset_pamt_all(&tdx_tdmr_list);
+err_free_pamts:
+ tdmrs_free_pamt_all(&tdx_tdmr_list);
+err_free_tdmrs:
+ free_tdmr_list(&tdx_tdmr_list);
+err_free_tdxmem:
+ free_tdx_memlist(&tdx_memlist);
+ goto out_put_tdxmem;
+}
+
+static int __tdx_enable(void)
+{
+ int ret;
+
+ ret = init_tdx_module();
+ if (ret) {
+ pr_err("module initialization failed (%d)\n", ret);
+ tdx_module_status = TDX_MODULE_ERROR;
+ return ret;
+ }
+
+ pr_info("module initialized\n");
+ tdx_module_status = TDX_MODULE_INITIALIZED;
+
+ return 0;
+}
+
+/**
+ * tdx_enable - Enable TDX module to make it ready to run TDX guests
+ *
+ * This function assumes the caller has: 1) held read lock of CPU hotplug
+ * lock to prevent any new cpu from becoming online; 2) done both VMXON
+ * and tdx_cpu_enable() on all online cpus.
+ *
+ * This function requires there's at least one online cpu for each CPU
+ * package to succeed.
+ *
+ * This function can be called in parallel by multiple callers.
+ *
+ * Return 0 if TDX is enabled successfully, otherwise error.
+ */
+int tdx_enable(void)
+{
+ int ret;
+
+ if (!boot_cpu_has(X86_FEATURE_TDX_HOST_PLATFORM))
+ return -ENODEV;
+
+ lockdep_assert_cpus_held();
+
+ mutex_lock(&tdx_module_lock);
+
+ switch (tdx_module_status) {
+ case TDX_MODULE_UNINITIALIZED:
+ ret = __tdx_enable();
+ break;
+ case TDX_MODULE_INITIALIZED:
+ /* Already initialized, great, tell the caller. */
+ ret = 0;
+ break;
+ default:
+ /* Failed to initialize in the previous attempts */
+ ret = -EINVAL;
+ break;
+ }
+
+ mutex_unlock(&tdx_module_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tdx_enable);
+
+static bool is_pamt_page(unsigned long phys)
+{
+ struct tdmr_info_list *tdmr_list = &tdx_tdmr_list;
+ int i;
+
+ /* Ensure that all remote 'tdmr_list' writes are visible: */
+ smp_rmb();
+
+ /*
+ * The TDX module is no longer returning TDX_SYS_NOT_READY and
+ * is initialized. The 'tdmr_list' was initialized long ago
+ * and is now read-only.
+ */
+ for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) {
+ unsigned long base, size;
+
+ tdmr_get_pamt(tdmr_entry(tdmr_list, i), &base, &size);
+
+ if (phys >= base && phys < (base + size))
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * Return whether the memory page at the given physical address is TDX
+ * private memory or not.
+ *
+ * This can be imprecise for two known reasons:
+ * 1. PAMTs are private memory and exist before the TDX module is
+ * ready and TDH_PHYMEM_PAGE_RDMD works. This is a relatively
+ * short window that occurs once per boot.
+ * 2. TDH_PHYMEM_PAGE_RDMD reflects the TDX module's knowledge of the
+ * page. However, the page can still cause #MC until it has been
+ * fully converted to shared using 64-byte writes like MOVDIR64B.
+ * Buggy hosts might still leave #MC-causing memory in place which
+ * this function can not detect.
+ */
+static bool paddr_is_tdx_private(unsigned long phys)
+{
+ struct tdx_module_args args = {
+ .rcx = phys & PAGE_MASK,
+ };
+ u64 sret;
+
+ if (!boot_cpu_has(X86_FEATURE_TDX_HOST_PLATFORM))
+ return false;
+
+ /* Get page type from the TDX module */
+ sret = __seamcall_ret(TDH_PHYMEM_PAGE_RDMD, &args);
+
+ /*
+ * The SEAMCALL will not return success unless there is a
+ * working, "ready" TDX module. Assume an absence of TDX
+ * private pages until SEAMCALL is working.
+ */
+ if (sret)
+ return false;
+
+ /*
+ * SEAMCALL was successful -- read page type (via RCX):
+ *
+ * - PT_NDA: Page is not used by the TDX module
+ * - PT_RSVD: Reserved for Non-TDX use
+ * - Others: Page is used by the TDX module
+ *
+ * Note PAMT pages are marked as PT_RSVD but they are also TDX
+ * private memory.
+ */
+ switch (args.rcx) {
+ case PT_NDA:
+ return false;
+ case PT_RSVD:
+ return is_pamt_page(phys);
+ default:
+ return true;
+ }
+}
+
+/*
+ * Some TDX-capable CPUs have an erratum. A write to TDX private
+ * memory poisons that memory, and a subsequent read of that memory
+ * triggers #MC.
+ *
+ * Help distinguish erratum-triggered #MCs from a normal hardware one.
+ * Just print additional message to show such #MC may be result of the
+ * erratum.
+ */
+const char *tdx_dump_mce_info(struct mce *m)
+{
+ if (!m || !mce_is_memory_error(m) || !mce_usable_address(m))
+ return NULL;
+
+ if (!paddr_is_tdx_private(m->addr))
+ return NULL;
+
+ return "TDX private memory error. Possible kernel bug.";
+}
+
+static __init int record_keyid_partitioning(u32 *tdx_keyid_start,
+ u32 *nr_tdx_keyids)
+{
+ u32 _nr_mktme_keyids, _tdx_keyid_start, _nr_tdx_keyids;
+ int ret;
+
+ /*
+ * IA32_MKTME_KEYID_PARTIONING:
+ * Bit [31:0]: Number of MKTME KeyIDs.
+ * Bit [63:32]: Number of TDX private KeyIDs.
+ */
+ ret = rdmsr_safe(MSR_IA32_MKTME_KEYID_PARTITIONING, &_nr_mktme_keyids,
+ &_nr_tdx_keyids);
+ if (ret || !_nr_tdx_keyids)
+ return -EINVAL;
+
+ /* TDX KeyIDs start after the last MKTME KeyID. */
+ _tdx_keyid_start = _nr_mktme_keyids + 1;
+
+ *tdx_keyid_start = _tdx_keyid_start;
+ *nr_tdx_keyids = _nr_tdx_keyids;
+
+ return 0;
+}
+
+static bool is_tdx_memory(unsigned long start_pfn, unsigned long end_pfn)
+{
+ struct tdx_memblock *tmb;
+
+ /*
+ * This check assumes that the start_pfn<->end_pfn range does not
+ * cross multiple @tdx_memlist entries. A single memory online
+ * event across multiple memblocks (from which @tdx_memlist
+ * entries are derived at the time of module initialization) is
+ * not possible. This is because memory offline/online is done
+ * on granularity of 'struct memory_block', and the hotpluggable
+ * memory region (one memblock) must be multiple of memory_block.
+ */
+ list_for_each_entry(tmb, &tdx_memlist, list) {
+ if (start_pfn >= tmb->start_pfn && end_pfn <= tmb->end_pfn)
+ return true;
+ }
+ return false;
+}
+
+static int tdx_memory_notifier(struct notifier_block *nb, unsigned long action,
+ void *v)
+{
+ struct memory_notify *mn = v;
+
+ if (action != MEM_GOING_ONLINE)
+ return NOTIFY_OK;
+
+ /*
+ * Empty list means TDX isn't enabled. Allow any memory
+ * to go online.
+ */
+ if (list_empty(&tdx_memlist))
+ return NOTIFY_OK;
+
+ /*
+ * The TDX memory configuration is static and can not be
+ * changed. Reject onlining any memory which is outside of
+ * the static configuration whether it supports TDX or not.
+ */
+ if (is_tdx_memory(mn->start_pfn, mn->start_pfn + mn->nr_pages))
+ return NOTIFY_OK;
+
+ return NOTIFY_BAD;
+}
+
+static struct notifier_block tdx_memory_nb = {
+ .notifier_call = tdx_memory_notifier,
+};
+
+static void __init check_tdx_erratum(void)
+{
+ /*
+ * These CPUs have an erratum. A partial write from non-TD
+ * software (e.g. via MOVNTI variants or UC/WC mapping) to TDX
+ * private memory poisons that memory, and a subsequent read of
+ * that memory triggers #MC.
+ */
+ switch (boot_cpu_data.x86_model) {
+ case INTEL_FAM6_SAPPHIRERAPIDS_X:
+ case INTEL_FAM6_EMERALDRAPIDS_X:
+ setup_force_cpu_bug(X86_BUG_TDX_PW_MCE);
+ }
+}
+
+void __init tdx_init(void)
+{
+ u32 tdx_keyid_start, nr_tdx_keyids;
+ int err;
+
+ err = record_keyid_partitioning(&tdx_keyid_start, &nr_tdx_keyids);
+ if (err)
+ return;
+
+ pr_info("BIOS enabled: private KeyID range [%u, %u)\n",
+ tdx_keyid_start, tdx_keyid_start + nr_tdx_keyids);
+
+ /*
+ * The TDX module itself requires one 'global KeyID' to protect
+ * its metadata. If there's only one TDX KeyID, there won't be
+ * any left for TDX guests thus there's no point to enable TDX
+ * at all.
+ */
+ if (nr_tdx_keyids < 2) {
+ pr_err("initialization failed: too few private KeyIDs available.\n");
+ return;
+ }
+
+ /*
+ * At this point, hibernation_available() indicates whether or
+ * not hibernation support has been permanently disabled.
+ */
+ if (hibernation_available()) {
+ pr_err("initialization failed: Hibernation support is enabled\n");
+ return;
+ }
+
+ err = register_memory_notifier(&tdx_memory_nb);
+ if (err) {
+ pr_err("initialization failed: register_memory_notifier() failed (%d)\n",
+ err);
+ return;
+ }
+
+#if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)
+ pr_info("Disable ACPI S3. Turn off TDX in the BIOS to use ACPI S3.\n");
+ acpi_suspend_lowlevel = NULL;
+#endif
+
+ /*
+ * Just use the first TDX KeyID as the 'global KeyID' and
+ * leave the rest for TDX guests.
+ */
+ tdx_global_keyid = tdx_keyid_start;
+ tdx_guest_keyid_start = tdx_keyid_start + 1;
+ tdx_nr_guest_keyids = nr_tdx_keyids - 1;
+
+ setup_force_cpu_cap(X86_FEATURE_TDX_HOST_PLATFORM);
+
+ check_tdx_erratum();
+}
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
new file mode 100644
index 000000000000..b701f69485d3
--- /dev/null
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _X86_VIRT_TDX_H
+#define _X86_VIRT_TDX_H
+
+#include <linux/bits.h>
+
+/*
+ * This file contains both macros and data structures defined by the TDX
+ * architecture and Linux defined software data structures and functions.
+ * The two should not be mixed together for better readability. The
+ * architectural definitions come first.
+ */
+
+/*
+ * TDX module SEAMCALL leaf functions
+ */
+#define TDH_PHYMEM_PAGE_RDMD 24
+#define TDH_SYS_KEY_CONFIG 31
+#define TDH_SYS_INIT 33
+#define TDH_SYS_RD 34
+#define TDH_SYS_LP_INIT 35
+#define TDH_SYS_TDMR_INIT 36
+#define TDH_SYS_CONFIG 45
+
+/* TDX page types */
+#define PT_NDA 0x0
+#define PT_RSVD 0x1
+
+/*
+ * Global scope metadata field ID.
+ *
+ * See Table "Global Scope Metadata", TDX module 1.5 ABI spec.
+ */
+#define MD_FIELD_ID_MAX_TDMRS 0x9100000100000008ULL
+#define MD_FIELD_ID_MAX_RESERVED_PER_TDMR 0x9100000100000009ULL
+#define MD_FIELD_ID_PAMT_4K_ENTRY_SIZE 0x9100000100000010ULL
+#define MD_FIELD_ID_PAMT_2M_ENTRY_SIZE 0x9100000100000011ULL
+#define MD_FIELD_ID_PAMT_1G_ENTRY_SIZE 0x9100000100000012ULL
+
+/*
+ * Sub-field definition of metadata field ID.
+ *
+ * See Table "MD_FIELD_ID (Metadata Field Identifier / Sequence Header)
+ * Definition", TDX module 1.5 ABI spec.
+ *
+ * - Bit 33:32: ELEMENT_SIZE_CODE -- size of a single element of metadata
+ *
+ * 0: 8 bits
+ * 1: 16 bits
+ * 2: 32 bits
+ * 3: 64 bits
+ */
+#define MD_FIELD_ID_ELE_SIZE_CODE(_field_id) \
+ (((_field_id) & GENMASK_ULL(33, 32)) >> 32)
+
+#define MD_FIELD_ID_ELE_SIZE_16BIT 1
+
+struct tdmr_reserved_area {
+ u64 offset;
+ u64 size;
+} __packed;
+
+#define TDMR_INFO_ALIGNMENT 512
+#define TDMR_INFO_PA_ARRAY_ALIGNMENT 512
+
+struct tdmr_info {
+ u64 base;
+ u64 size;
+ u64 pamt_1g_base;
+ u64 pamt_1g_size;
+ u64 pamt_2m_base;
+ u64 pamt_2m_size;
+ u64 pamt_4k_base;
+ u64 pamt_4k_size;
+ /*
+ * The actual number of reserved areas depends on the value of
+ * field MD_FIELD_ID_MAX_RESERVED_PER_TDMR in the TDX module
+ * global metadata.
+ */
+ DECLARE_FLEX_ARRAY(struct tdmr_reserved_area, reserved_areas);
+} __packed __aligned(TDMR_INFO_ALIGNMENT);
+
+/*
+ * Do not put any hardware-defined TDX structure representations below
+ * this comment!
+ */
+
+/* Kernel defined TDX module status during module initialization. */
+enum tdx_module_status_t {
+ TDX_MODULE_UNINITIALIZED,
+ TDX_MODULE_INITIALIZED,
+ TDX_MODULE_ERROR
+};
+
+struct tdx_memblock {
+ struct list_head list;
+ unsigned long start_pfn;
+ unsigned long end_pfn;
+ int nid;
+};
+
+/* "TDMR info" part of "Global Scope Metadata" for constructing TDMRs */
+struct tdx_tdmr_sysinfo {
+ u16 max_tdmrs;
+ u16 max_reserved_per_tdmr;
+ u16 pamt_entry_size[TDX_PS_NR];
+};
+
+/* Warn if kernel has less than TDMR_NR_WARN TDMRs after allocation */
+#define TDMR_NR_WARN 4
+
+struct tdmr_info_list {
+ void *tdmrs; /* Flexible array to hold 'tdmr_info's */
+ int nr_consumed_tdmrs; /* How many 'tdmr_info's are in use */
+
+ /* Metadata for finding target 'tdmr_info' and freeing @tdmrs */
+ int tdmr_sz; /* Size of one 'tdmr_info' */
+ int max_tdmrs; /* How many 'tdmr_info's are allocated */
+};
+
+#endif
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index e031eaf36c99..6f248d87e496 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -144,7 +144,7 @@ config XTENSA_VARIANT_CUSTOM_NAME
depends on XTENSA_VARIANT_CUSTOM
help
Provide the name of a custom Xtensa processor variant.
- This CORENAME selects arch/xtensa/variant/CORENAME.
+ This CORENAME selects arch/xtensa/variants/CORENAME.
Don't forget you have to select MMU if you have one.
config XTENSA_VARIANT_NAME
diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile
index bfd8e433ed62..4c14a02179eb 100644
--- a/arch/xtensa/Makefile
+++ b/arch/xtensa/Makefile
@@ -35,15 +35,19 @@ KBUILD_CFLAGS += -ffreestanding -D__linux__
KBUILD_CFLAGS += -pipe -mlongcalls -mtext-section-literals
KBUILD_CFLAGS += $(call cc-option,-mforce-no-pic,)
KBUILD_CFLAGS += $(call cc-option,-mno-serialize-volatile,)
+KBUILD_CFLAGS += $(call cc-option,-mno-fdpic,)
ifneq ($(CONFIG_KERNEL_ABI_CALL0),)
KBUILD_CFLAGS += -mabi=call0
KBUILD_AFLAGS += -mabi=call0
endif
KBUILD_AFLAGS += -mlongcalls -mtext-section-literals
+KBUILD_AFLAGS += $(call cc-option,-mno-fdpic,)
+
+KBUILD_LDFLAGS += -m elf32xtensa
ifneq ($(CONFIG_LD_NO_RELAX),)
-KBUILD_LDFLAGS := --no-relax
+KBUILD_LDFLAGS += --no-relax
endif
CHECKFLAGS += -D$(if $(CONFIG_CPU_BIG_ENDIAN),__XTENSA_EB__,__XTENSA_EL__)
diff --git a/arch/xtensa/include/asm/asmmacro.h b/arch/xtensa/include/asm/asmmacro.h
index 01bf7d9dbb19..a52d49a16ce7 100644
--- a/arch/xtensa/include/asm/asmmacro.h
+++ b/arch/xtensa/include/asm/asmmacro.h
@@ -11,7 +11,7 @@
#ifndef _XTENSA_ASMMACRO_H
#define _XTENSA_ASMMACRO_H
-#include <asm-generic/export.h>
+#include <linux/export.h>
#include <asm/core.h>
/*
diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h
index 785a00ce83c1..38bcecb0e457 100644
--- a/arch/xtensa/include/asm/cacheflush.h
+++ b/arch/xtensa/include/asm/cacheflush.h
@@ -116,8 +116,9 @@ void flush_cache_page(struct vm_area_struct*,
#define flush_cache_mm(mm) flush_cache_all()
#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
-#define flush_cache_vmap(start,end) flush_cache_all()
-#define flush_cache_vunmap(start,end) flush_cache_all()
+#define flush_cache_vmap(start,end) flush_cache_all()
+#define flush_cache_vmap_early(start,end) do { } while (0)
+#define flush_cache_vunmap(start,end) flush_cache_all()
void flush_dcache_folio(struct folio *folio);
#define flush_dcache_folio flush_dcache_folio
@@ -140,6 +141,7 @@ void local_flush_cache_page(struct vm_area_struct *vma,
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_vmap(start,end) do { } while (0)
+#define flush_cache_vmap_early(start,end) do { } while (0)
#define flush_cache_vunmap(start,end) do { } while (0)
#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
diff --git a/arch/xtensa/lib/pci-auto.c b/arch/xtensa/lib/pci-auto.c
index aa6752237985..05fc02f9e1c7 100644
--- a/arch/xtensa/lib/pci-auto.c
+++ b/arch/xtensa/lib/pci-auto.c
@@ -11,6 +11,7 @@
* Based on work from Matt Porter <[email protected]>
*/
+#include <linux/bitfield.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -222,10 +223,11 @@ pciauto_postscan_setup_bridge(struct pci_dev *dev, int current_bus, int sub_bus,
int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus)
{
- int sub_bus, pci_devfn, pci_class, cmdstat, found_multi=0;
+ int sub_bus, pci_devfn, pci_class, cmdstat;
unsigned short vid;
unsigned char header_type;
struct pci_dev *dev = &pciauto_dev;
+ bool found_multi = false;
pciauto_dev.bus = &pciauto_bus;
pciauto_dev.sysdata = pci_ctrl;
@@ -261,11 +263,11 @@ int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus)
continue;
if (!PCI_FUNC(pci_devfn))
- found_multi = header_type & 0x80;
+ found_multi = FIELD_GET(PCI_HEADER_TYPE_MFD, header_type);
pci_read_config_word(dev, PCI_VENDOR_ID, &vid);
if (vid == 0xffff || vid == 0x0000) {
- found_multi = 0;
+ found_multi = false;
continue;
}
diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c
index 7d1f8b398a46..8896e691c051 100644
--- a/arch/xtensa/platforms/iss/console.c
+++ b/arch/xtensa/platforms/iss/console.c
@@ -65,7 +65,7 @@ static void rs_poll(struct timer_list *unused)
struct tty_port *port = &serial_port;
int i = 0;
int rd = 1;
- unsigned char c;
+ u8 c;
while (simc_poll(0)) {
rd = simc_read(0, &c, 1);
diff --git a/drivers/Makefile b/drivers/Makefile
index d828329c268d..37fd6ce3bd7f 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -71,9 +71,8 @@ obj-y += gpu/
obj-$(CONFIG_CONNECTOR) += connector/
-# i810fb and intelfb depend on char/agp/
+# i810fb depends on char/agp/
obj-$(CONFIG_FB_I810) += video/fbdev/i810/
-obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/
obj-$(CONFIG_PARPORT) += parport/
obj-y += base/ block/ misc/ mfd/ nfc/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 6f2bfcf7645c..3c3f8037ebed 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -314,7 +314,6 @@ config ACPI_HOTPLUG_CPU
bool
depends on ACPI_PROCESSOR && HOTPLUG_CPU
select ACPI_CONTAINER
- default y
config ACPI_PROCESSOR_AGGREGATOR
tristate "Processor Aggregator"
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 0f5218e361df..4fe2ef54088c 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -184,24 +184,6 @@ static void __init acpi_pcc_cpufreq_init(void) {}
/* Initialization */
#ifdef CONFIG_ACPI_HOTPLUG_CPU
-int __weak acpi_map_cpu(acpi_handle handle,
- phys_cpuid_t physid, u32 acpi_id, int *pcpu)
-{
- return -ENODEV;
-}
-
-int __weak acpi_unmap_cpu(int cpu)
-{
- return -ENODEV;
-}
-
-int __weak arch_register_cpu(int cpu)
-{
- return -ENODEV;
-}
-
-void __weak arch_unregister_cpu(int cpu) {}
-
static int acpi_processor_hotadd_init(struct acpi_processor *pr)
{
unsigned long long sta;
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index ab2a82cb1b0b..7b7c605166e0 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/cper.h>
+#include <linux/cxl-event.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/ratelimit.h>
@@ -673,6 +674,78 @@ static void ghes_defer_non_standard_event(struct acpi_hest_generic_data *gdata,
schedule_work(&entry->work);
}
+/*
+ * Only a single callback can be registered for CXL CPER events.
+ */
+static DECLARE_RWSEM(cxl_cper_rw_sem);
+static cxl_cper_callback cper_callback;
+
+/* CXL Event record UUIDs are formatted as GUIDs and reported in section type */
+
+/*
+ * General Media Event Record
+ * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
+ */
+#define CPER_SEC_CXL_GEN_MEDIA_GUID \
+ GUID_INIT(0xfbcd0a77, 0xc260, 0x417f, \
+ 0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6)
+
+/*
+ * DRAM Event Record
+ * CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
+ */
+#define CPER_SEC_CXL_DRAM_GUID \
+ GUID_INIT(0x601dcbb3, 0x9c06, 0x4eab, \
+ 0xb8, 0xaf, 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24)
+
+/*
+ * Memory Module Event Record
+ * CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
+ */
+#define CPER_SEC_CXL_MEM_MODULE_GUID \
+ GUID_INIT(0xfe927475, 0xdd59, 0x4339, \
+ 0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74)
+
+static void cxl_cper_post_event(enum cxl_event_type event_type,
+ struct cxl_cper_event_rec *rec)
+{
+ if (rec->hdr.length <= sizeof(rec->hdr) ||
+ rec->hdr.length > sizeof(*rec)) {
+ pr_err(FW_WARN "CXL CPER Invalid section length (%u)\n",
+ rec->hdr.length);
+ return;
+ }
+
+ if (!(rec->hdr.validation_bits & CPER_CXL_COMP_EVENT_LOG_VALID)) {
+ pr_err(FW_WARN "CXL CPER invalid event\n");
+ return;
+ }
+
+ guard(rwsem_read)(&cxl_cper_rw_sem);
+ if (cper_callback)
+ cper_callback(event_type, rec);
+}
+
+int cxl_cper_register_callback(cxl_cper_callback callback)
+{
+ guard(rwsem_write)(&cxl_cper_rw_sem);
+ if (cper_callback)
+ return -EINVAL;
+ cper_callback = callback;
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_cper_register_callback, CXL);
+
+int cxl_cper_unregister_callback(cxl_cper_callback callback)
+{
+ guard(rwsem_write)(&cxl_cper_rw_sem);
+ if (callback != cper_callback)
+ return -EINVAL;
+ cper_callback = NULL;
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_callback, CXL);
+
static bool ghes_do_proc(struct ghes *ghes,
const struct acpi_hest_generic_status *estatus)
{
@@ -707,6 +780,22 @@ static bool ghes_do_proc(struct ghes *ghes,
}
else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
queued = ghes_handle_arm_hw_error(gdata, sev, sync);
+ } else if (guid_equal(sec_type, &CPER_SEC_CXL_GEN_MEDIA_GUID)) {
+ struct cxl_cper_event_rec *rec =
+ acpi_hest_get_payload(gdata);
+
+ cxl_cper_post_event(CXL_CPER_EVENT_GEN_MEDIA, rec);
+ } else if (guid_equal(sec_type, &CPER_SEC_CXL_DRAM_GUID)) {
+ struct cxl_cper_event_rec *rec =
+ acpi_hest_get_payload(gdata);
+
+ cxl_cper_post_event(CXL_CPER_EVENT_DRAM, rec);
+ } else if (guid_equal(sec_type,
+ &CPER_SEC_CXL_MEM_MODULE_GUID)) {
+ struct cxl_cper_event_rec *rec =
+ acpi_hest_get_payload(gdata);
+
+ cxl_cper_post_event(CXL_CPER_EVENT_MEM_MODULE, rec);
} else {
void *err = acpi_hest_get_payload(gdata);
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 992385537757..802f8a56d1fa 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -1186,7 +1186,7 @@ static ssize_t bus_dsm_mask_show(struct device *dev,
struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
- return sprintf(buf, "%#lx\n", acpi_desc->bus_dsm_mask);
+ return sysfs_emit(buf, "%#lx\n", acpi_desc->bus_dsm_mask);
}
static struct device_attribute dev_attr_bus_dsm_mask =
__ATTR(dsm_mask, 0444, bus_dsm_mask_show, NULL);
@@ -1198,7 +1198,7 @@ static ssize_t revision_show(struct device *dev,
struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
- return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision);
+ return sysfs_emit(buf, "%d\n", acpi_desc->acpi_header.revision);
}
static DEVICE_ATTR_RO(revision);
@@ -1209,7 +1209,7 @@ static ssize_t hw_error_scrub_show(struct device *dev,
struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
- return sprintf(buf, "%d\n", acpi_desc->scrub_mode);
+ return sysfs_emit(buf, "%d\n", acpi_desc->scrub_mode);
}
/*
@@ -1278,7 +1278,7 @@ static ssize_t scrub_show(struct device *dev,
mutex_lock(&acpi_desc->init_mutex);
busy = test_bit(ARS_BUSY, &acpi_desc->scrub_flags)
&& !test_bit(ARS_CANCEL, &acpi_desc->scrub_flags);
- rc = sprintf(buf, "%d%s", acpi_desc->scrub_count, busy ? "+\n" : "\n");
+ rc = sysfs_emit(buf, "%d%s", acpi_desc->scrub_count, busy ? "+\n" : "\n");
/* Allow an admin to poll the busy state at a higher rate */
if (busy && capable(CAP_SYS_RAWIO) && !test_and_set_bit(ARS_POLL,
&acpi_desc->scrub_flags)) {
@@ -1382,7 +1382,7 @@ static ssize_t handle_show(struct device *dev,
{
struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev);
- return sprintf(buf, "%#x\n", memdev->device_handle);
+ return sysfs_emit(buf, "%#x\n", memdev->device_handle);
}
static DEVICE_ATTR_RO(handle);
@@ -1391,7 +1391,7 @@ static ssize_t phys_id_show(struct device *dev,
{
struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev);
- return sprintf(buf, "%#x\n", memdev->physical_id);
+ return sysfs_emit(buf, "%#x\n", memdev->physical_id);
}
static DEVICE_ATTR_RO(phys_id);
@@ -1400,7 +1400,7 @@ static ssize_t vendor_show(struct device *dev,
{
struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
- return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->vendor_id));
+ return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(dcr->vendor_id));
}
static DEVICE_ATTR_RO(vendor);
@@ -1409,7 +1409,7 @@ static ssize_t rev_id_show(struct device *dev,
{
struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
- return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->revision_id));
+ return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(dcr->revision_id));
}
static DEVICE_ATTR_RO(rev_id);
@@ -1418,7 +1418,7 @@ static ssize_t device_show(struct device *dev,
{
struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
- return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->device_id));
+ return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(dcr->device_id));
}
static DEVICE_ATTR_RO(device);
@@ -1427,7 +1427,7 @@ static ssize_t subsystem_vendor_show(struct device *dev,
{
struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
- return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_vendor_id));
+ return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_vendor_id));
}
static DEVICE_ATTR_RO(subsystem_vendor);
@@ -1436,7 +1436,7 @@ static ssize_t subsystem_rev_id_show(struct device *dev,
{
struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
- return sprintf(buf, "0x%04x\n",
+ return sysfs_emit(buf, "0x%04x\n",
be16_to_cpu(dcr->subsystem_revision_id));
}
static DEVICE_ATTR_RO(subsystem_rev_id);
@@ -1446,7 +1446,7 @@ static ssize_t subsystem_device_show(struct device *dev,
{
struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
- return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_device_id));
+ return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_device_id));
}
static DEVICE_ATTR_RO(subsystem_device);
@@ -1465,7 +1465,7 @@ static ssize_t format_show(struct device *dev,
{
struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
- return sprintf(buf, "0x%04x\n", le16_to_cpu(dcr->code));
+ return sysfs_emit(buf, "0x%04x\n", le16_to_cpu(dcr->code));
}
static DEVICE_ATTR_RO(format);
@@ -1498,7 +1498,7 @@ static ssize_t format1_show(struct device *dev,
continue;
if (nfit_dcr->dcr->code == dcr->code)
continue;
- rc = sprintf(buf, "0x%04x\n",
+ rc = sysfs_emit(buf, "0x%04x\n",
le16_to_cpu(nfit_dcr->dcr->code));
break;
}
@@ -1515,7 +1515,7 @@ static ssize_t formats_show(struct device *dev,
{
struct nvdimm *nvdimm = to_nvdimm(dev);
- return sprintf(buf, "%d\n", num_nvdimm_formats(nvdimm));
+ return sysfs_emit(buf, "%d\n", num_nvdimm_formats(nvdimm));
}
static DEVICE_ATTR_RO(formats);
@@ -1524,7 +1524,7 @@ static ssize_t serial_show(struct device *dev,
{
struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev);
- return sprintf(buf, "0x%08x\n", be32_to_cpu(dcr->serial_number));
+ return sysfs_emit(buf, "0x%08x\n", be32_to_cpu(dcr->serial_number));
}
static DEVICE_ATTR_RO(serial);
@@ -1536,7 +1536,7 @@ static ssize_t family_show(struct device *dev,
if (nfit_mem->family < 0)
return -ENXIO;
- return sprintf(buf, "%d\n", nfit_mem->family);
+ return sysfs_emit(buf, "%d\n", nfit_mem->family);
}
static DEVICE_ATTR_RO(family);
@@ -1548,7 +1548,7 @@ static ssize_t dsm_mask_show(struct device *dev,
if (nfit_mem->family < 0)
return -ENXIO;
- return sprintf(buf, "%#lx\n", nfit_mem->dsm_mask);
+ return sysfs_emit(buf, "%#lx\n", nfit_mem->dsm_mask);
}
static DEVICE_ATTR_RO(dsm_mask);
@@ -1562,7 +1562,7 @@ static ssize_t flags_show(struct device *dev,
if (test_bit(NFIT_MEM_DIRTY, &nfit_mem->flags))
flags |= ACPI_NFIT_MEM_FLUSH_FAILED;
- return sprintf(buf, "%s%s%s%s%s%s%s\n",
+ return sysfs_emit(buf, "%s%s%s%s%s%s%s\n",
flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save_fail " : "",
flags & ACPI_NFIT_MEM_RESTORE_FAILED ? "restore_fail " : "",
flags & ACPI_NFIT_MEM_FLUSH_FAILED ? "flush_fail " : "",
@@ -1579,7 +1579,7 @@ static ssize_t id_show(struct device *dev,
struct nvdimm *nvdimm = to_nvdimm(dev);
struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
- return sprintf(buf, "%s\n", nfit_mem->id);
+ return sysfs_emit(buf, "%s\n", nfit_mem->id);
}
static DEVICE_ATTR_RO(id);
@@ -1589,7 +1589,7 @@ static ssize_t dirty_shutdown_show(struct device *dev,
struct nvdimm *nvdimm = to_nvdimm(dev);
struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
- return sprintf(buf, "%d\n", nfit_mem->dirty_shutdown);
+ return sysfs_emit(buf, "%d\n", nfit_mem->dirty_shutdown);
}
static DEVICE_ATTR_RO(dirty_shutdown);
@@ -2172,7 +2172,7 @@ static ssize_t range_index_show(struct device *dev,
struct nd_region *nd_region = to_nd_region(dev);
struct nfit_spa *nfit_spa = nd_region_provider_data(nd_region);
- return sprintf(buf, "%d\n", nfit_spa->spa->range_index);
+ return sysfs_emit(buf, "%d\n", nfit_spa->spa->range_index);
}
static DEVICE_ATTR_RO(range_index);
@@ -2257,26 +2257,23 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
struct nd_region_desc *ndr_desc,
struct acpi_nfit_system_address *spa)
{
+ u16 nr = ndr_desc->num_mappings;
+ struct nfit_set_info2 *info2 __free(kfree) =
+ kcalloc(nr, sizeof(*info2), GFP_KERNEL);
+ struct nfit_set_info *info __free(kfree) =
+ kcalloc(nr, sizeof(*info), GFP_KERNEL);
struct device *dev = acpi_desc->dev;
struct nd_interleave_set *nd_set;
- u16 nr = ndr_desc->num_mappings;
- struct nfit_set_info2 *info2;
- struct nfit_set_info *info;
int i;
+ if (!info || !info2)
+ return -ENOMEM;
+
nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL);
if (!nd_set)
return -ENOMEM;
import_guid(&nd_set->type_guid, spa->range_guid);
- info = devm_kcalloc(dev, nr, sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- info2 = devm_kcalloc(dev, nr, sizeof(*info2), GFP_KERNEL);
- if (!info2)
- return -ENOMEM;
-
for (i = 0; i < nr; i++) {
struct nd_mapping_desc *mapping = &ndr_desc->mapping[i];
struct nvdimm *nvdimm = mapping->nvdimm;
@@ -2337,8 +2334,6 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
}
ndr_desc->nd_set = nd_set;
- devm_kfree(dev, info);
- devm_kfree(dev, info2);
return 0;
}
diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c
index 9ef5f1bdcfdb..d6b85f0f6082 100644
--- a/drivers/acpi/numa/hmat.c
+++ b/drivers/acpi/numa/hmat.c
@@ -58,14 +58,22 @@ struct target_cache {
struct node_cache_attrs cache_attrs;
};
+enum {
+ NODE_ACCESS_CLASS_0 = 0,
+ NODE_ACCESS_CLASS_1,
+ NODE_ACCESS_CLASS_GENPORT_SINK,
+ NODE_ACCESS_CLASS_MAX,
+};
+
struct memory_target {
struct list_head node;
unsigned int memory_pxm;
unsigned int processor_pxm;
struct resource memregions;
- struct node_hmem_attrs hmem_attrs[2];
+ struct access_coordinate coord[NODE_ACCESS_CLASS_MAX];
struct list_head caches;
struct node_cache_attrs cache_attrs;
+ u8 gen_port_device_handle[ACPI_SRAT_DEVICE_HANDLE_SIZE];
bool registered;
};
@@ -100,6 +108,47 @@ static struct memory_target *find_mem_target(unsigned int mem_pxm)
return NULL;
}
+static struct memory_target *acpi_find_genport_target(u32 uid)
+{
+ struct memory_target *target;
+ u32 target_uid;
+ u8 *uid_ptr;
+
+ list_for_each_entry(target, &targets, node) {
+ uid_ptr = target->gen_port_device_handle + 8;
+ target_uid = *(u32 *)uid_ptr;
+ if (uid == target_uid)
+ return target;
+ }
+
+ return NULL;
+}
+
+/**
+ * acpi_get_genport_coordinates - Retrieve the access coordinates for a generic port
+ * @uid: ACPI unique id
+ * @coord: The access coordinates written back out for the generic port
+ *
+ * Return: 0 on success. Errno on failure.
+ *
+ * Only supports device handles that are ACPI. Assume ACPI0016 HID for CXL.
+ */
+int acpi_get_genport_coordinates(u32 uid,
+ struct access_coordinate *coord)
+{
+ struct memory_target *target;
+
+ guard(mutex)(&target_lock);
+ target = acpi_find_genport_target(uid);
+ if (!target)
+ return -ENOENT;
+
+ *coord = target->coord[NODE_ACCESS_CLASS_GENPORT_SINK];
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acpi_get_genport_coordinates, CXL);
+
static __init void alloc_memory_initiator(unsigned int cpu_pxm)
{
struct memory_initiator *initiator;
@@ -120,8 +169,7 @@ static __init void alloc_memory_initiator(unsigned int cpu_pxm)
list_add_tail(&initiator->node, &initiators);
}
-static __init void alloc_memory_target(unsigned int mem_pxm,
- resource_size_t start, resource_size_t len)
+static __init struct memory_target *alloc_target(unsigned int mem_pxm)
{
struct memory_target *target;
@@ -129,7 +177,7 @@ static __init void alloc_memory_target(unsigned int mem_pxm,
if (!target) {
target = kzalloc(sizeof(*target), GFP_KERNEL);
if (!target)
- return;
+ return NULL;
target->memory_pxm = mem_pxm;
target->processor_pxm = PXM_INVAL;
target->memregions = (struct resource) {
@@ -142,6 +190,19 @@ static __init void alloc_memory_target(unsigned int mem_pxm,
INIT_LIST_HEAD(&target->caches);
}
+ return target;
+}
+
+static __init void alloc_memory_target(unsigned int mem_pxm,
+ resource_size_t start,
+ resource_size_t len)
+{
+ struct memory_target *target;
+
+ target = alloc_target(mem_pxm);
+ if (!target)
+ return;
+
/*
* There are potentially multiple ranges per PXM, so record each
* in the per-target memregions resource tree.
@@ -152,6 +213,18 @@ static __init void alloc_memory_target(unsigned int mem_pxm,
start, start + len, mem_pxm);
}
+static __init void alloc_genport_target(unsigned int mem_pxm, u8 *handle)
+{
+ struct memory_target *target;
+
+ target = alloc_target(mem_pxm);
+ if (!target)
+ return;
+
+ memcpy(target->gen_port_device_handle, handle,
+ ACPI_SRAT_DEVICE_HANDLE_SIZE);
+}
+
static __init const char *hmat_data_type(u8 type)
{
switch (type) {
@@ -228,24 +301,24 @@ static void hmat_update_target_access(struct memory_target *target,
{
switch (type) {
case ACPI_HMAT_ACCESS_LATENCY:
- target->hmem_attrs[access].read_latency = value;
- target->hmem_attrs[access].write_latency = value;
+ target->coord[access].read_latency = value;
+ target->coord[access].write_latency = value;
break;
case ACPI_HMAT_READ_LATENCY:
- target->hmem_attrs[access].read_latency = value;
+ target->coord[access].read_latency = value;
break;
case ACPI_HMAT_WRITE_LATENCY:
- target->hmem_attrs[access].write_latency = value;
+ target->coord[access].write_latency = value;
break;
case ACPI_HMAT_ACCESS_BANDWIDTH:
- target->hmem_attrs[access].read_bandwidth = value;
- target->hmem_attrs[access].write_bandwidth = value;
+ target->coord[access].read_bandwidth = value;
+ target->coord[access].write_bandwidth = value;
break;
case ACPI_HMAT_READ_BANDWIDTH:
- target->hmem_attrs[access].read_bandwidth = value;
+ target->coord[access].read_bandwidth = value;
break;
case ACPI_HMAT_WRITE_BANDWIDTH:
- target->hmem_attrs[access].write_bandwidth = value;
+ target->coord[access].write_bandwidth = value;
break;
default:
break;
@@ -291,11 +364,28 @@ static __init void hmat_add_locality(struct acpi_hmat_locality *hmat_loc)
}
}
+static __init void hmat_update_target(unsigned int tgt_pxm, unsigned int init_pxm,
+ u8 mem_hier, u8 type, u32 value)
+{
+ struct memory_target *target = find_mem_target(tgt_pxm);
+
+ if (mem_hier != ACPI_HMAT_MEMORY)
+ return;
+
+ if (target && target->processor_pxm == init_pxm) {
+ hmat_update_target_access(target, type, value,
+ NODE_ACCESS_CLASS_0);
+ /* If the node has a CPU, update access 1 */
+ if (node_state(pxm_to_node(init_pxm), N_CPU))
+ hmat_update_target_access(target, type, value,
+ NODE_ACCESS_CLASS_1);
+ }
+}
+
static __init int hmat_parse_locality(union acpi_subtable_headers *header,
const unsigned long end)
{
struct acpi_hmat_locality *hmat_loc = (void *)header;
- struct memory_target *target;
unsigned int init, targ, total_size, ipds, tpds;
u32 *inits, *targs, value;
u16 *entries;
@@ -336,15 +426,8 @@ static __init int hmat_parse_locality(union acpi_subtable_headers *header,
inits[init], targs[targ], value,
hmat_data_type_suffix(type));
- if (mem_hier == ACPI_HMAT_MEMORY) {
- target = find_mem_target(targs[targ]);
- if (target && target->processor_pxm == inits[init]) {
- hmat_update_target_access(target, type, value, 0);
- /* If the node has a CPU, update access 1 */
- if (node_state(pxm_to_node(inits[init]), N_CPU))
- hmat_update_target_access(target, type, value, 1);
- }
- }
+ hmat_update_target(targs[targ], inits[init],
+ mem_hier, type, value);
}
}
@@ -491,6 +574,27 @@ static __init int srat_parse_mem_affinity(union acpi_subtable_headers *header,
return 0;
}
+static __init int srat_parse_genport_affinity(union acpi_subtable_headers *header,
+ const unsigned long end)
+{
+ struct acpi_srat_generic_affinity *ga = (void *)header;
+
+ if (!ga)
+ return -EINVAL;
+
+ if (!(ga->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED))
+ return 0;
+
+ /* Skip PCI device_handle for now */
+ if (ga->device_handle_type != 0)
+ return 0;
+
+ alloc_genport_target(ga->proximity_domain,
+ (u8 *)ga->device_handle);
+
+ return 0;
+}
+
static u32 hmat_initiator_perf(struct memory_target *target,
struct memory_initiator *initiator,
struct acpi_hmat_locality *hmat_loc)
@@ -592,6 +696,11 @@ static void hmat_update_target_attrs(struct memory_target *target,
u32 best = 0;
int i;
+ /* Don't update for generic port if there's no device handle */
+ if (access == NODE_ACCESS_CLASS_GENPORT_SINK &&
+ !(*(u16 *)target->gen_port_device_handle))
+ return;
+
bitmap_zero(p_nodes, MAX_NUMNODES);
/*
* If the Address Range Structure provides a local processor pxm, set
@@ -661,6 +770,14 @@ static void __hmat_register_target_initiators(struct memory_target *target,
}
}
+static void hmat_register_generic_target_initiators(struct memory_target *target)
+{
+ static DECLARE_BITMAP(p_nodes, MAX_NUMNODES);
+
+ __hmat_register_target_initiators(target, p_nodes,
+ NODE_ACCESS_CLASS_GENPORT_SINK);
+}
+
static void hmat_register_target_initiators(struct memory_target *target)
{
static DECLARE_BITMAP(p_nodes, MAX_NUMNODES);
@@ -681,7 +798,7 @@ static void hmat_register_target_cache(struct memory_target *target)
static void hmat_register_target_perf(struct memory_target *target, int access)
{
unsigned mem_nid = pxm_to_node(target->memory_pxm);
- node_set_perf_attrs(mem_nid, &target->hmem_attrs[access], access);
+ node_set_perf_attrs(mem_nid, &target->coord[access], access);
}
static void hmat_register_target_devices(struct memory_target *target)
@@ -713,6 +830,17 @@ static void hmat_register_target(struct memory_target *target)
hmat_register_target_devices(target);
/*
+ * Register generic port perf numbers. The nid may not be
+ * initialized and is still NUMA_NO_NODE.
+ */
+ mutex_lock(&target_lock);
+ if (*(u16 *)target->gen_port_device_handle) {
+ hmat_register_generic_target_initiators(target);
+ target->registered = true;
+ }
+ mutex_unlock(&target_lock);
+
+ /*
* Skip offline nodes. This can happen when memory
* marked EFI_MEMORY_SP, "specific purpose", is applied
* to all the memory in a proximity domain leading to
@@ -726,8 +854,8 @@ static void hmat_register_target(struct memory_target *target)
if (!target->registered) {
hmat_register_target_initiators(target);
hmat_register_target_cache(target);
- hmat_register_target_perf(target, 0);
- hmat_register_target_perf(target, 1);
+ hmat_register_target_perf(target, NODE_ACCESS_CLASS_0);
+ hmat_register_target_perf(target, NODE_ACCESS_CLASS_1);
target->registered = true;
}
mutex_unlock(&target_lock);
@@ -765,7 +893,7 @@ static int hmat_set_default_dram_perf(void)
int rc;
int nid, pxm;
struct memory_target *target;
- struct node_hmem_attrs *attrs;
+ struct access_coordinate *attrs;
if (!default_dram_type)
return -EIO;
@@ -775,7 +903,7 @@ static int hmat_set_default_dram_perf(void)
target = find_mem_target(pxm);
if (!target)
continue;
- attrs = &target->hmem_attrs[1];
+ attrs = &target->coord[1];
rc = mt_set_default_dram_perf(nid, attrs, "ACPI HMAT");
if (rc)
return rc;
@@ -789,7 +917,7 @@ static int hmat_calculate_adistance(struct notifier_block *self,
{
static DECLARE_BITMAP(p_nodes, MAX_NUMNODES);
struct memory_target *target;
- struct node_hmem_attrs *perf;
+ struct access_coordinate *perf;
int *adist = data;
int pxm;
@@ -802,7 +930,7 @@ static int hmat_calculate_adistance(struct notifier_block *self,
hmat_update_target_attrs(target, p_nodes, 1);
mutex_unlock(&target_lock);
- perf = &target->hmem_attrs[1];
+ perf = &target->coord[1];
if (mt_perf_to_adistance(perf, adist))
return NOTIFY_OK;
@@ -870,6 +998,13 @@ static __init int hmat_init(void)
ACPI_SRAT_TYPE_MEMORY_AFFINITY,
srat_parse_mem_affinity, 0) < 0)
goto out_put;
+
+ if (acpi_table_parse_entries(ACPI_SIG_SRAT,
+ sizeof(struct acpi_table_srat),
+ ACPI_SRAT_TYPE_GENERIC_PORT_AFFINITY,
+ srat_parse_genport_affinity, 0) < 0)
+ goto out_put;
+
acpi_put_table(tbl);
status = acpi_get_table(ACPI_SIG_HMAT, 0, &tbl);
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 07d76fb740b6..a6ead5204046 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -881,6 +881,7 @@ static struct fwnode_handle *acpi_parse_string_ref(const struct fwnode_handle *f
* @index: Index of the reference to return
* @num_args: Maximum number of arguments after each reference
* @args: Location to store the returned reference with optional arguments
+ * (may be NULL)
*
* Find property with @name, verifify that it is a package containing at least
* one object reference and if so, store the ACPI device object pointer to the
@@ -938,6 +939,9 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode,
if (!device)
return -EINVAL;
+ if (!args)
+ return 0;
+
args->fwnode = acpi_fwnode_handle(device);
args->nargs = 0;
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index 0e2c397b1399..dacad1d846c0 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -462,6 +462,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
},
},
{
+ /* Asus ExpertBook B1502CGA */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "B1502CGA"),
+ },
+ },
+ {
/* Asus ExpertBook B2402CBA */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
@@ -483,6 +490,20 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = {
},
},
{
+ /* Asus Vivobook E1504GA */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "E1504GA"),
+ },
+ },
+ {
+ /* Asus Vivobook E1504GAB */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "E1504GAB"),
+ },
+ },
+ {
/* LG Electronics 17U70P */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 0ba008773b00..e6ed1ba91e5c 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1561,8 +1561,7 @@ static inline const struct iommu_ops *acpi_iommu_fwspec_ops(struct device *dev)
return fwspec ? fwspec->ops : NULL;
}
-static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev,
- const u32 *id_in)
+static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in)
{
int err;
const struct iommu_ops *ops;
@@ -1576,7 +1575,7 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev,
ops = acpi_iommu_fwspec_ops(dev);
if (ops) {
mutex_unlock(&iommu_probe_device_lock);
- return ops;
+ return 0;
}
err = iort_iommu_configure_id(dev, id_in);
@@ -1593,12 +1592,14 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev,
/* Ignore all other errors apart from EPROBE_DEFER */
if (err == -EPROBE_DEFER) {
- return ERR_PTR(err);
+ return err;
} else if (err) {
dev_dbg(dev, "Adding to IOMMU failed: %d\n", err);
- return NULL;
+ return -ENODEV;
}
- return acpi_iommu_fwspec_ops(dev);
+ if (!acpi_iommu_fwspec_ops(dev))
+ return -ENODEV;
+ return 0;
}
#else /* !CONFIG_IOMMU_API */
@@ -1610,10 +1611,9 @@ int acpi_iommu_fwspec_init(struct device *dev, u32 id,
return -ENODEV;
}
-static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev,
- const u32 *id_in)
+static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in)
{
- return NULL;
+ return -ENODEV;
}
#endif /* !CONFIG_IOMMU_API */
@@ -1627,7 +1627,7 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev,
int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr,
const u32 *input_id)
{
- const struct iommu_ops *iommu;
+ int ret;
if (attr == DEV_DMA_NOT_SUPPORTED) {
set_dma_ops(dev, &dma_dummy_ops);
@@ -1636,12 +1636,16 @@ int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr,
acpi_arch_dma_setup(dev);
- iommu = acpi_iommu_configure_id(dev, input_id);
- if (PTR_ERR(iommu) == -EPROBE_DEFER)
+ ret = acpi_iommu_configure_id(dev, input_id);
+ if (ret == -EPROBE_DEFER)
return -EPROBE_DEFER;
- arch_setup_dma_ops(dev, 0, U64_MAX,
- iommu, attr == DEV_DMA_COHERENT);
+ /*
+ * Historically this routine doesn't fail driver probing due to errors
+ * in acpi_iommu_configure_id()
+ */
+
+ arch_setup_dma_ops(dev, 0, U64_MAX, attr == DEV_DMA_COHERENT);
return 0;
}
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index c1516337f668..b07f7d091d13 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -251,8 +251,9 @@ int __init_or_acpilib acpi_table_parse_entries_array(
return -ENODEV;
}
- count = acpi_parse_entries_array(id, table_size, table_header,
- proc, proc_num, max_entries);
+ count = acpi_parse_entries_array(id, table_size,
+ (union fw_table_header *)table_header,
+ proc, proc_num, max_entries);
acpi_put_table(table_header);
return count;
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 7658103ba760..8dd23b19e997 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2077,9 +2077,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
* Convert the address to an offset relative to
* the base of the transaction buffer.
*/
- fda_offset =
- (parent->buffer - (uintptr_t)buffer->user_data) +
- fda->parent_offset;
+ fda_offset = parent->buffer - buffer->user_data +
+ fda->parent_offset;
for (fd_index = 0; fd_index < fda->num_fds;
fd_index++) {
u32 fd;
@@ -2597,7 +2596,7 @@ static int binder_translate_fd_array(struct list_head *pf_head,
* Convert the address to an offset relative to
* the base of the transaction buffer.
*/
- fda_offset = (parent->buffer - (uintptr_t)t->buffer->user_data) +
+ fda_offset = parent->buffer - t->buffer->user_data +
fda->parent_offset;
sender_ufda_base = (void __user *)(uintptr_t)sender_uparent->buffer +
fda->parent_offset;
@@ -2672,8 +2671,9 @@ static int binder_fixup_parent(struct list_head *pf_head,
proc->pid, thread->pid);
return -EINVAL;
}
- buffer_offset = bp->parent_offset +
- (uintptr_t)parent->buffer - (uintptr_t)b->user_data;
+
+ buffer_offset = bp->parent_offset + parent->buffer - b->user_data;
+
return binder_add_fixup(pf_head, buffer_offset, bp->buffer, 0);
}
@@ -3225,7 +3225,7 @@ static void binder_transaction(struct binder_proc *proc,
t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
tr->offsets_size, extra_buffers_size,
- !reply && (t->flags & TF_ONE_WAY), current->tgid);
+ !reply && (t->flags & TF_ONE_WAY));
if (IS_ERR(t->buffer)) {
char *s;
@@ -3250,7 +3250,7 @@ static void binder_transaction(struct binder_proc *proc,
ALIGN(extra_buffers_size, sizeof(void *)) -
ALIGN(secctx_sz, sizeof(u64));
- t->security_ctx = (uintptr_t)t->buffer->user_data + buf_offset;
+ t->security_ctx = t->buffer->user_data + buf_offset;
err = binder_alloc_copy_to_buffer(&target_proc->alloc,
t->buffer, buf_offset,
secctx, secctx_sz);
@@ -3527,8 +3527,7 @@ static void binder_transaction(struct binder_proc *proc,
goto err_translate_failed;
}
/* Fixup buffer pointer to target proc address space */
- bp->buffer = (uintptr_t)
- t->buffer->user_data + sg_buf_offset;
+ bp->buffer = t->buffer->user_data + sg_buf_offset;
sg_buf_offset += ALIGN(bp->length, sizeof(u64));
num_valid = (buffer_offset - off_start_offset) /
@@ -4698,7 +4697,7 @@ retry:
}
trd->data_size = t->buffer->data_size;
trd->offsets_size = t->buffer->offsets_size;
- trd->data.ptr.buffer = (uintptr_t)t->buffer->user_data;
+ trd->data.ptr.buffer = t->buffer->user_data;
trd->data.ptr.offsets = trd->data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));
@@ -5030,7 +5029,7 @@ static __poll_t binder_poll(struct file *filp,
thread = binder_get_thread(proc);
if (!thread)
- return POLLERR;
+ return EPOLLERR;
binder_inner_proc_lock(thread->proc);
thread->looper |= BINDER_LOOPER_STATE_POLL;
@@ -5981,9 +5980,9 @@ static void print_binder_transaction_ilocked(struct seq_file *m,
}
if (buffer->target_node)
seq_printf(m, " node %d", buffer->target_node->debug_id);
- seq_printf(m, " size %zd:%zd data %pK\n",
+ seq_printf(m, " size %zd:%zd offset %lx\n",
buffer->data_size, buffer->offsets_size,
- buffer->user_data);
+ proc->alloc.buffer - buffer->user_data);
}
static void print_binder_work_ilocked(struct seq_file *m,
diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c
index f69d30c9f50f..e0e4dc38b692 100644
--- a/drivers/android/binder_alloc.c
+++ b/drivers/android/binder_alloc.c
@@ -26,7 +26,7 @@
#include "binder_alloc.h"
#include "binder_trace.h"
-struct list_lru binder_alloc_lru;
+struct list_lru binder_freelist;
static DEFINE_MUTEX(binder_alloc_mmap_lock);
@@ -125,23 +125,20 @@ static void binder_insert_allocated_buffer_locked(
static struct binder_buffer *binder_alloc_prepare_to_free_locked(
struct binder_alloc *alloc,
- uintptr_t user_ptr)
+ unsigned long user_ptr)
{
struct rb_node *n = alloc->allocated_buffers.rb_node;
struct binder_buffer *buffer;
- void __user *uptr;
-
- uptr = (void __user *)user_ptr;
while (n) {
buffer = rb_entry(n, struct binder_buffer, rb_node);
BUG_ON(buffer->free);
- if (uptr < buffer->user_data)
+ if (user_ptr < buffer->user_data) {
n = n->rb_left;
- else if (uptr > buffer->user_data)
+ } else if (user_ptr > buffer->user_data) {
n = n->rb_right;
- else {
+ } else {
/*
* Guard against user threads attempting to
* free the buffer when in use by kernel or
@@ -168,145 +165,168 @@ static struct binder_buffer *binder_alloc_prepare_to_free_locked(
* Return: Pointer to buffer or NULL
*/
struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc,
- uintptr_t user_ptr)
+ unsigned long user_ptr)
{
struct binder_buffer *buffer;
- mutex_lock(&alloc->mutex);
+ spin_lock(&alloc->lock);
buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr);
- mutex_unlock(&alloc->mutex);
+ spin_unlock(&alloc->lock);
return buffer;
}
-static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
- void __user *start, void __user *end)
+static inline void
+binder_set_installed_page(struct binder_lru_page *lru_page,
+ struct page *page)
+{
+ /* Pairs with acquire in binder_get_installed_page() */
+ smp_store_release(&lru_page->page_ptr, page);
+}
+
+static inline struct page *
+binder_get_installed_page(struct binder_lru_page *lru_page)
+{
+ /* Pairs with release in binder_set_installed_page() */
+ return smp_load_acquire(&lru_page->page_ptr);
+}
+
+static void binder_lru_freelist_add(struct binder_alloc *alloc,
+ unsigned long start, unsigned long end)
{
- void __user *page_addr;
- unsigned long user_page_addr;
struct binder_lru_page *page;
- struct vm_area_struct *vma = NULL;
- struct mm_struct *mm = NULL;
- bool need_mm = false;
+ unsigned long page_addr;
- binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: %s pages %pK-%pK\n", alloc->pid,
- allocate ? "allocate" : "free", start, end);
+ trace_binder_update_page_range(alloc, false, start, end);
- if (end <= start)
- return 0;
+ for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
+ size_t index;
+ int ret;
- trace_binder_update_page_range(alloc, allocate, start, end);
+ index = (page_addr - alloc->buffer) / PAGE_SIZE;
+ page = &alloc->pages[index];
- if (allocate == 0)
- goto free_range;
+ if (!binder_get_installed_page(page))
+ continue;
- for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
- page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE];
- if (!page->page_ptr) {
- need_mm = true;
- break;
- }
+ trace_binder_free_lru_start(alloc, index);
+
+ ret = list_lru_add_obj(&binder_freelist, &page->lru);
+ WARN_ON(!ret);
+
+ trace_binder_free_lru_end(alloc, index);
}
+}
+
+static int binder_install_single_page(struct binder_alloc *alloc,
+ struct binder_lru_page *lru_page,
+ unsigned long addr)
+{
+ struct page *page;
+ int ret = 0;
- if (need_mm && mmget_not_zero(alloc->mm))
- mm = alloc->mm;
+ if (!mmget_not_zero(alloc->mm))
+ return -ESRCH;
- if (mm) {
- mmap_write_lock(mm);
- vma = alloc->vma;
+ /*
+ * Protected with mmap_sem in write mode as multiple tasks
+ * might race to install the same page.
+ */
+ mmap_write_lock(alloc->mm);
+ if (binder_get_installed_page(lru_page))
+ goto out;
+
+ if (!alloc->vma) {
+ pr_err("%d: %s failed, no vma\n", alloc->pid, __func__);
+ ret = -ESRCH;
+ goto out;
}
- if (!vma && need_mm) {
- binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
- "%d: binder_alloc_buf failed to map pages in userspace, no vma\n",
- alloc->pid);
- goto err_no_vma;
+ page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
+ if (!page) {
+ pr_err("%d: failed to allocate page\n", alloc->pid);
+ ret = -ENOMEM;
+ goto out;
}
- for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
+ ret = vm_insert_page(alloc->vma, addr, page);
+ if (ret) {
+ pr_err("%d: %s failed to insert page at offset %lx with %d\n",
+ alloc->pid, __func__, addr - alloc->buffer, ret);
+ __free_page(page);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Mark page installation complete and safe to use */
+ binder_set_installed_page(lru_page, page);
+out:
+ mmap_write_unlock(alloc->mm);
+ mmput_async(alloc->mm);
+ return ret;
+}
+
+static int binder_install_buffer_pages(struct binder_alloc *alloc,
+ struct binder_buffer *buffer,
+ size_t size)
+{
+ struct binder_lru_page *page;
+ unsigned long start, final;
+ unsigned long page_addr;
+
+ start = buffer->user_data & PAGE_MASK;
+ final = PAGE_ALIGN(buffer->user_data + size);
+
+ for (page_addr = start; page_addr < final; page_addr += PAGE_SIZE) {
+ unsigned long index;
int ret;
- bool on_lru;
- size_t index;
index = (page_addr - alloc->buffer) / PAGE_SIZE;
page = &alloc->pages[index];
- if (page->page_ptr) {
- trace_binder_alloc_lru_start(alloc, index);
-
- on_lru = list_lru_del_obj(&binder_alloc_lru, &page->lru);
- WARN_ON(!on_lru);
-
- trace_binder_alloc_lru_end(alloc, index);
+ if (binder_get_installed_page(page))
continue;
- }
-
- if (WARN_ON(!vma))
- goto err_page_ptr_cleared;
trace_binder_alloc_page_start(alloc, index);
- page->page_ptr = alloc_page(GFP_KERNEL |
- __GFP_HIGHMEM |
- __GFP_ZERO);
- if (!page->page_ptr) {
- pr_err("%d: binder_alloc_buf failed for page at %pK\n",
- alloc->pid, page_addr);
- goto err_alloc_page_failed;
- }
- page->alloc = alloc;
- INIT_LIST_HEAD(&page->lru);
-
- user_page_addr = (uintptr_t)page_addr;
- ret = vm_insert_page(vma, user_page_addr, page[0].page_ptr);
- if (ret) {
- pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n",
- alloc->pid, user_page_addr);
- goto err_vm_insert_page_failed;
- }
- if (index + 1 > alloc->pages_high)
- alloc->pages_high = index + 1;
+ ret = binder_install_single_page(alloc, page, page_addr);
+ if (ret)
+ return ret;
trace_binder_alloc_page_end(alloc, index);
}
- if (mm) {
- mmap_write_unlock(mm);
- mmput(mm);
- }
+
return 0;
+}
-free_range:
- for (page_addr = end - PAGE_SIZE; 1; page_addr -= PAGE_SIZE) {
- bool ret;
- size_t index;
+/* The range of pages should exclude those shared with other buffers */
+static void binder_lru_freelist_del(struct binder_alloc *alloc,
+ unsigned long start, unsigned long end)
+{
+ struct binder_lru_page *page;
+ unsigned long page_addr;
+
+ trace_binder_update_page_range(alloc, true, start, end);
+
+ for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
+ unsigned long index;
+ bool on_lru;
index = (page_addr - alloc->buffer) / PAGE_SIZE;
page = &alloc->pages[index];
- trace_binder_free_lru_start(alloc, index);
+ if (page->page_ptr) {
+ trace_binder_alloc_lru_start(alloc, index);
- ret = list_lru_add_obj(&binder_alloc_lru, &page->lru);
- WARN_ON(!ret);
+ on_lru = list_lru_del_obj(&binder_freelist, &page->lru);
+ WARN_ON(!on_lru);
- trace_binder_free_lru_end(alloc, index);
- if (page_addr == start)
- break;
- continue;
-
-err_vm_insert_page_failed:
- __free_page(page->page_ptr);
- page->page_ptr = NULL;
-err_alloc_page_failed:
-err_page_ptr_cleared:
- if (page_addr == start)
- break;
- }
-err_no_vma:
- if (mm) {
- mmap_write_unlock(mm);
- mmput(mm);
+ trace_binder_alloc_lru_end(alloc, index);
+ continue;
+ }
+
+ if (index + 1 > alloc->pages_high)
+ alloc->pages_high = index + 1;
}
- return vma ? -ENOMEM : -ESRCH;
}
static inline void binder_alloc_set_vma(struct binder_alloc *alloc,
@@ -323,7 +343,44 @@ static inline struct vm_area_struct *binder_alloc_get_vma(
return smp_load_acquire(&alloc->vma);
}
-static bool debug_low_async_space_locked(struct binder_alloc *alloc, int pid)
+static void debug_no_space_locked(struct binder_alloc *alloc)
+{
+ size_t largest_alloc_size = 0;
+ struct binder_buffer *buffer;
+ size_t allocated_buffers = 0;
+ size_t largest_free_size = 0;
+ size_t total_alloc_size = 0;
+ size_t total_free_size = 0;
+ size_t free_buffers = 0;
+ size_t buffer_size;
+ struct rb_node *n;
+
+ for (n = rb_first(&alloc->allocated_buffers); n; n = rb_next(n)) {
+ buffer = rb_entry(n, struct binder_buffer, rb_node);
+ buffer_size = binder_alloc_buffer_size(alloc, buffer);
+ allocated_buffers++;
+ total_alloc_size += buffer_size;
+ if (buffer_size > largest_alloc_size)
+ largest_alloc_size = buffer_size;
+ }
+
+ for (n = rb_first(&alloc->free_buffers); n; n = rb_next(n)) {
+ buffer = rb_entry(n, struct binder_buffer, rb_node);
+ buffer_size = binder_alloc_buffer_size(alloc, buffer);
+ free_buffers++;
+ total_free_size += buffer_size;
+ if (buffer_size > largest_free_size)
+ largest_free_size = buffer_size;
+ }
+
+ binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
+ "allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n",
+ total_alloc_size, allocated_buffers,
+ largest_alloc_size, total_free_size,
+ free_buffers, largest_free_size);
+}
+
+static bool debug_low_async_space_locked(struct binder_alloc *alloc)
{
/*
* Find the amount and size of buffers allocated by the current caller;
@@ -332,10 +389,20 @@ static bool debug_low_async_space_locked(struct binder_alloc *alloc, int pid)
* and at some point we'll catch them in the act. This is more efficient
* than keeping a map per pid.
*/
- struct rb_node *n;
struct binder_buffer *buffer;
size_t total_alloc_size = 0;
+ int pid = current->tgid;
size_t num_buffers = 0;
+ struct rb_node *n;
+
+ /*
+ * Only start detecting spammers once we have less than 20% of async
+ * space left (which is less than 10% of total buffer size).
+ */
+ if (alloc->free_async_space >= alloc->buffer_size / 10) {
+ alloc->oneway_spam_detected = false;
+ return false;
+ }
for (n = rb_first(&alloc->allocated_buffers); n != NULL;
n = rb_next(n)) {
@@ -344,8 +411,7 @@ static bool debug_low_async_space_locked(struct binder_alloc *alloc, int pid)
continue;
if (!buffer->async_transaction)
continue;
- total_alloc_size += binder_alloc_buffer_size(alloc, buffer)
- + sizeof(struct binder_buffer);
+ total_alloc_size += binder_alloc_buffer_size(alloc, buffer);
num_buffers++;
}
@@ -366,58 +432,28 @@ static bool debug_low_async_space_locked(struct binder_alloc *alloc, int pid)
return false;
}
+/* Callers preallocate @new_buffer, it is freed by this function if unused */
static struct binder_buffer *binder_alloc_new_buf_locked(
struct binder_alloc *alloc,
- size_t data_size,
- size_t offsets_size,
- size_t extra_buffers_size,
- int is_async,
- int pid)
+ struct binder_buffer *new_buffer,
+ size_t size,
+ int is_async)
{
struct rb_node *n = alloc->free_buffers.rb_node;
+ struct rb_node *best_fit = NULL;
struct binder_buffer *buffer;
+ unsigned long next_used_page;
+ unsigned long curr_last_page;
size_t buffer_size;
- struct rb_node *best_fit = NULL;
- void __user *has_page_addr;
- void __user *end_page_addr;
- size_t size, data_offsets_size;
- int ret;
- /* Check binder_alloc is fully initialized */
- if (!binder_alloc_get_vma(alloc)) {
- binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
- "%d: binder_alloc_buf, no vma\n",
- alloc->pid);
- return ERR_PTR(-ESRCH);
- }
-
- data_offsets_size = ALIGN(data_size, sizeof(void *)) +
- ALIGN(offsets_size, sizeof(void *));
-
- if (data_offsets_size < data_size || data_offsets_size < offsets_size) {
- binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: got transaction with invalid size %zd-%zd\n",
- alloc->pid, data_size, offsets_size);
- return ERR_PTR(-EINVAL);
- }
- size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *));
- if (size < data_offsets_size || size < extra_buffers_size) {
- binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: got transaction with invalid extra_buffers_size %zd\n",
- alloc->pid, extra_buffers_size);
- return ERR_PTR(-EINVAL);
- }
- if (is_async &&
- alloc->free_async_space < size + sizeof(struct binder_buffer)) {
+ if (is_async && alloc->free_async_space < size) {
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: binder_alloc_buf size %zd failed, no async space left\n",
alloc->pid, size);
- return ERR_PTR(-ENOSPC);
+ buffer = ERR_PTR(-ENOSPC);
+ goto out;
}
- /* Pad 0-size buffers so they get assigned unique addresses */
- size = max(size, sizeof(void *));
-
while (n) {
buffer = rb_entry(n, struct binder_buffer, rb_node);
BUG_ON(!buffer->free);
@@ -426,121 +462,92 @@ static struct binder_buffer *binder_alloc_new_buf_locked(
if (size < buffer_size) {
best_fit = n;
n = n->rb_left;
- } else if (size > buffer_size)
+ } else if (size > buffer_size) {
n = n->rb_right;
- else {
+ } else {
best_fit = n;
break;
}
}
- if (best_fit == NULL) {
- size_t allocated_buffers = 0;
- size_t largest_alloc_size = 0;
- size_t total_alloc_size = 0;
- size_t free_buffers = 0;
- size_t largest_free_size = 0;
- size_t total_free_size = 0;
-
- for (n = rb_first(&alloc->allocated_buffers); n != NULL;
- n = rb_next(n)) {
- buffer = rb_entry(n, struct binder_buffer, rb_node);
- buffer_size = binder_alloc_buffer_size(alloc, buffer);
- allocated_buffers++;
- total_alloc_size += buffer_size;
- if (buffer_size > largest_alloc_size)
- largest_alloc_size = buffer_size;
- }
- for (n = rb_first(&alloc->free_buffers); n != NULL;
- n = rb_next(n)) {
- buffer = rb_entry(n, struct binder_buffer, rb_node);
- buffer_size = binder_alloc_buffer_size(alloc, buffer);
- free_buffers++;
- total_free_size += buffer_size;
- if (buffer_size > largest_free_size)
- largest_free_size = buffer_size;
- }
+
+ if (unlikely(!best_fit)) {
binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
"%d: binder_alloc_buf size %zd failed, no address space\n",
alloc->pid, size);
- binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
- "allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n",
- total_alloc_size, allocated_buffers,
- largest_alloc_size, total_free_size,
- free_buffers, largest_free_size);
- return ERR_PTR(-ENOSPC);
+ debug_no_space_locked(alloc);
+ buffer = ERR_PTR(-ENOSPC);
+ goto out;
}
- if (n == NULL) {
+
+ if (buffer_size != size) {
+ /* Found an oversized buffer and needs to be split */
buffer = rb_entry(best_fit, struct binder_buffer, rb_node);
buffer_size = binder_alloc_buffer_size(alloc, buffer);
+
+ WARN_ON(n || buffer_size == size);
+ new_buffer->user_data = buffer->user_data + size;
+ list_add(&new_buffer->entry, &buffer->entry);
+ new_buffer->free = 1;
+ binder_insert_free_buffer(alloc, new_buffer);
+ new_buffer = NULL;
}
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: binder_alloc_buf size %zd got buffer %pK size %zd\n",
alloc->pid, size, buffer, buffer_size);
- has_page_addr = (void __user *)
- (((uintptr_t)buffer->user_data + buffer_size) & PAGE_MASK);
- WARN_ON(n && buffer_size != size);
- end_page_addr =
- (void __user *)PAGE_ALIGN((uintptr_t)buffer->user_data + size);
- if (end_page_addr > has_page_addr)
- end_page_addr = has_page_addr;
- ret = binder_update_page_range(alloc, 1, (void __user *)
- PAGE_ALIGN((uintptr_t)buffer->user_data), end_page_addr);
- if (ret)
- return ERR_PTR(ret);
-
- if (buffer_size != size) {
- struct binder_buffer *new_buffer;
-
- new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
- if (!new_buffer) {
- pr_err("%s: %d failed to alloc new buffer struct\n",
- __func__, alloc->pid);
- goto err_alloc_buf_struct_failed;
- }
- new_buffer->user_data = (u8 __user *)buffer->user_data + size;
- list_add(&new_buffer->entry, &buffer->entry);
- new_buffer->free = 1;
- binder_insert_free_buffer(alloc, new_buffer);
- }
+ /*
+ * Now we remove the pages from the freelist. A clever calculation
+ * with buffer_size determines if the last page is shared with an
+ * adjacent in-use buffer. In such case, the page has been already
+ * removed from the freelist so we trim our range short.
+ */
+ next_used_page = (buffer->user_data + buffer_size) & PAGE_MASK;
+ curr_last_page = PAGE_ALIGN(buffer->user_data + size);
+ binder_lru_freelist_del(alloc, PAGE_ALIGN(buffer->user_data),
+ min(next_used_page, curr_last_page));
- rb_erase(best_fit, &alloc->free_buffers);
+ rb_erase(&buffer->rb_node, &alloc->free_buffers);
buffer->free = 0;
buffer->allow_user_free = 0;
binder_insert_allocated_buffer_locked(alloc, buffer);
- binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: binder_alloc_buf size %zd got %pK\n",
- alloc->pid, size, buffer);
- buffer->data_size = data_size;
- buffer->offsets_size = offsets_size;
buffer->async_transaction = is_async;
- buffer->extra_buffers_size = extra_buffers_size;
- buffer->pid = pid;
buffer->oneway_spam_suspect = false;
if (is_async) {
- alloc->free_async_space -= size + sizeof(struct binder_buffer);
+ alloc->free_async_space -= size;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
"%d: binder_alloc_buf size %zd async free %zd\n",
alloc->pid, size, alloc->free_async_space);
- if (alloc->free_async_space < alloc->buffer_size / 10) {
- /*
- * Start detecting spammers once we have less than 20%
- * of async space left (which is less than 10% of total
- * buffer size).
- */
- buffer->oneway_spam_suspect = debug_low_async_space_locked(alloc, pid);
- } else {
- alloc->oneway_spam_detected = false;
- }
+ if (debug_low_async_space_locked(alloc))
+ buffer->oneway_spam_suspect = true;
}
+
+out:
+ /* Discard possibly unused new_buffer */
+ kfree(new_buffer);
return buffer;
+}
-err_alloc_buf_struct_failed:
- binder_update_page_range(alloc, 0, (void __user *)
- PAGE_ALIGN((uintptr_t)buffer->user_data),
- end_page_addr);
- return ERR_PTR(-ENOMEM);
+/* Calculate the sanitized total size, returns 0 for invalid request */
+static inline size_t sanitized_size(size_t data_size,
+ size_t offsets_size,
+ size_t extra_buffers_size)
+{
+ size_t total, tmp;
+
+ /* Align to pointer size and check for overflows */
+ tmp = ALIGN(data_size, sizeof(void *)) +
+ ALIGN(offsets_size, sizeof(void *));
+ if (tmp < data_size || tmp < offsets_size)
+ return 0;
+ total = tmp + ALIGN(extra_buffers_size, sizeof(void *));
+ if (total < tmp || total < extra_buffers_size)
+ return 0;
+
+ /* Pad 0-sized buffers so they get a unique address */
+ total = max(total, sizeof(void *));
+
+ return total;
}
/**
@@ -550,87 +557,101 @@ err_alloc_buf_struct_failed:
* @offsets_size: user specified buffer offset
* @extra_buffers_size: size of extra space for meta-data (eg, security context)
* @is_async: buffer for async transaction
- * @pid: pid to attribute allocation to (used for debugging)
*
* Allocate a new buffer given the requested sizes. Returns
* the kernel version of the buffer pointer. The size allocated
* is the sum of the three given sizes (each rounded up to
* pointer-sized boundary)
*
- * Return: The allocated buffer or %NULL if error
+ * Return: The allocated buffer or %ERR_PTR(-errno) if error
*/
struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
size_t data_size,
size_t offsets_size,
size_t extra_buffers_size,
- int is_async,
- int pid)
+ int is_async)
{
- struct binder_buffer *buffer;
+ struct binder_buffer *buffer, *next;
+ size_t size;
+ int ret;
+
+ /* Check binder_alloc is fully initialized */
+ if (!binder_alloc_get_vma(alloc)) {
+ binder_alloc_debug(BINDER_DEBUG_USER_ERROR,
+ "%d: binder_alloc_buf, no vma\n",
+ alloc->pid);
+ return ERR_PTR(-ESRCH);
+ }
+
+ size = sanitized_size(data_size, offsets_size, extra_buffers_size);
+ if (unlikely(!size)) {
+ binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
+ "%d: got transaction with invalid size %zd-%zd-%zd\n",
+ alloc->pid, data_size, offsets_size,
+ extra_buffers_size);
+ return ERR_PTR(-EINVAL);
+ }
- mutex_lock(&alloc->mutex);
- buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size,
- extra_buffers_size, is_async, pid);
- mutex_unlock(&alloc->mutex);
+ /* Preallocate the next buffer */
+ next = kzalloc(sizeof(*next), GFP_KERNEL);
+ if (!next)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock(&alloc->lock);
+ buffer = binder_alloc_new_buf_locked(alloc, next, size, is_async);
+ if (IS_ERR(buffer)) {
+ spin_unlock(&alloc->lock);
+ goto out;
+ }
+
+ buffer->data_size = data_size;
+ buffer->offsets_size = offsets_size;
+ buffer->extra_buffers_size = extra_buffers_size;
+ buffer->pid = current->tgid;
+ spin_unlock(&alloc->lock);
+
+ ret = binder_install_buffer_pages(alloc, buffer, size);
+ if (ret) {
+ binder_alloc_free_buf(alloc, buffer);
+ buffer = ERR_PTR(ret);
+ }
+out:
return buffer;
}
-static void __user *buffer_start_page(struct binder_buffer *buffer)
+static unsigned long buffer_start_page(struct binder_buffer *buffer)
{
- return (void __user *)((uintptr_t)buffer->user_data & PAGE_MASK);
+ return buffer->user_data & PAGE_MASK;
}
-static void __user *prev_buffer_end_page(struct binder_buffer *buffer)
+static unsigned long prev_buffer_end_page(struct binder_buffer *buffer)
{
- return (void __user *)
- (((uintptr_t)(buffer->user_data) - 1) & PAGE_MASK);
+ return (buffer->user_data - 1) & PAGE_MASK;
}
static void binder_delete_free_buffer(struct binder_alloc *alloc,
struct binder_buffer *buffer)
{
- struct binder_buffer *prev, *next = NULL;
- bool to_free = true;
+ struct binder_buffer *prev, *next;
+
+ if (PAGE_ALIGNED(buffer->user_data))
+ goto skip_freelist;
BUG_ON(alloc->buffers.next == &buffer->entry);
prev = binder_buffer_prev(buffer);
BUG_ON(!prev->free);
- if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) {
- to_free = false;
- binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %pK share page with %pK\n",
- alloc->pid, buffer->user_data,
- prev->user_data);
- }
+ if (prev_buffer_end_page(prev) == buffer_start_page(buffer))
+ goto skip_freelist;
if (!list_is_last(&buffer->entry, &alloc->buffers)) {
next = binder_buffer_next(buffer);
- if (buffer_start_page(next) == buffer_start_page(buffer)) {
- to_free = false;
- binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %pK share page with %pK\n",
- alloc->pid,
- buffer->user_data,
- next->user_data);
- }
- }
-
- if (PAGE_ALIGNED(buffer->user_data)) {
- binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer start %pK is page aligned\n",
- alloc->pid, buffer->user_data);
- to_free = false;
+ if (buffer_start_page(next) == buffer_start_page(buffer))
+ goto skip_freelist;
}
- if (to_free) {
- binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %pK do not share page with %pK or %pK\n",
- alloc->pid, buffer->user_data,
- prev->user_data,
- next ? next->user_data : NULL);
- binder_update_page_range(alloc, 0, buffer_start_page(buffer),
- buffer_start_page(buffer) + PAGE_SIZE);
- }
+ binder_lru_freelist_add(alloc, buffer_start_page(buffer),
+ buffer_start_page(buffer) + PAGE_SIZE);
+skip_freelist:
list_del(&buffer->entry);
kfree(buffer);
}
@@ -657,17 +678,14 @@ static void binder_free_buf_locked(struct binder_alloc *alloc,
BUG_ON(buffer->user_data > alloc->buffer + alloc->buffer_size);
if (buffer->async_transaction) {
- alloc->free_async_space += buffer_size + sizeof(struct binder_buffer);
-
+ alloc->free_async_space += buffer_size;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC,
"%d: binder_free_buf size %zd async free %zd\n",
alloc->pid, size, alloc->free_async_space);
}
- binder_update_page_range(alloc, 0,
- (void __user *)PAGE_ALIGN((uintptr_t)buffer->user_data),
- (void __user *)(((uintptr_t)
- buffer->user_data + buffer_size) & PAGE_MASK));
+ binder_lru_freelist_add(alloc, PAGE_ALIGN(buffer->user_data),
+ (buffer->user_data + buffer_size) & PAGE_MASK);
rb_erase(&buffer->rb_node, &alloc->allocated_buffers);
buffer->free = 1;
@@ -691,8 +709,68 @@ static void binder_free_buf_locked(struct binder_alloc *alloc,
binder_insert_free_buffer(alloc, buffer);
}
+/**
+ * binder_alloc_get_page() - get kernel pointer for given buffer offset
+ * @alloc: binder_alloc for this proc
+ * @buffer: binder buffer to be accessed
+ * @buffer_offset: offset into @buffer data
+ * @pgoffp: address to copy final page offset to
+ *
+ * Lookup the struct page corresponding to the address
+ * at @buffer_offset into @buffer->user_data. If @pgoffp is not
+ * NULL, the byte-offset into the page is written there.
+ *
+ * The caller is responsible to ensure that the offset points
+ * to a valid address within the @buffer and that @buffer is
+ * not freeable by the user. Since it can't be freed, we are
+ * guaranteed that the corresponding elements of @alloc->pages[]
+ * cannot change.
+ *
+ * Return: struct page
+ */
+static struct page *binder_alloc_get_page(struct binder_alloc *alloc,
+ struct binder_buffer *buffer,
+ binder_size_t buffer_offset,
+ pgoff_t *pgoffp)
+{
+ binder_size_t buffer_space_offset = buffer_offset +
+ (buffer->user_data - alloc->buffer);
+ pgoff_t pgoff = buffer_space_offset & ~PAGE_MASK;
+ size_t index = buffer_space_offset >> PAGE_SHIFT;
+ struct binder_lru_page *lru_page;
+
+ lru_page = &alloc->pages[index];
+ *pgoffp = pgoff;
+ return lru_page->page_ptr;
+}
+
+/**
+ * binder_alloc_clear_buf() - zero out buffer
+ * @alloc: binder_alloc for this proc
+ * @buffer: binder buffer to be cleared
+ *
+ * memset the given buffer to 0
+ */
static void binder_alloc_clear_buf(struct binder_alloc *alloc,
- struct binder_buffer *buffer);
+ struct binder_buffer *buffer)
+{
+ size_t bytes = binder_alloc_buffer_size(alloc, buffer);
+ binder_size_t buffer_offset = 0;
+
+ while (bytes) {
+ unsigned long size;
+ struct page *page;
+ pgoff_t pgoff;
+
+ page = binder_alloc_get_page(alloc, buffer,
+ buffer_offset, &pgoff);
+ size = min_t(size_t, bytes, PAGE_SIZE - pgoff);
+ memset_page(page, pgoff, 0, size);
+ bytes -= size;
+ buffer_offset += size;
+ }
+}
+
/**
* binder_alloc_free_buf() - free a binder buffer
* @alloc: binder_alloc for this proc
@@ -706,18 +784,18 @@ void binder_alloc_free_buf(struct binder_alloc *alloc,
/*
* We could eliminate the call to binder_alloc_clear_buf()
* from binder_alloc_deferred_release() by moving this to
- * binder_alloc_free_buf_locked(). However, that could
- * increase contention for the alloc mutex if clear_on_free
- * is used frequently for large buffers. The mutex is not
+ * binder_free_buf_locked(). However, that could
+ * increase contention for the alloc->lock if clear_on_free
+ * is used frequently for large buffers. This lock is not
* needed for correctness here.
*/
if (buffer->clear_on_free) {
binder_alloc_clear_buf(alloc, buffer);
buffer->clear_on_free = false;
}
- mutex_lock(&alloc->mutex);
+ spin_lock(&alloc->lock);
binder_free_buf_locked(alloc, buffer);
- mutex_unlock(&alloc->mutex);
+ spin_unlock(&alloc->lock);
}
/**
@@ -736,9 +814,9 @@ void binder_alloc_free_buf(struct binder_alloc *alloc,
int binder_alloc_mmap_handler(struct binder_alloc *alloc,
struct vm_area_struct *vma)
{
- int ret;
- const char *failure_string;
struct binder_buffer *buffer;
+ const char *failure_string;
+ int ret, i;
if (unlikely(vma->vm_mm != alloc->mm)) {
ret = -EINVAL;
@@ -756,7 +834,7 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc,
SZ_4M);
mutex_unlock(&binder_alloc_mmap_lock);
- alloc->buffer = (void __user *)vma->vm_start;
+ alloc->buffer = vma->vm_start;
alloc->pages = kcalloc(alloc->buffer_size / PAGE_SIZE,
sizeof(alloc->pages[0]),
@@ -767,6 +845,11 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc,
goto err_alloc_pages_failed;
}
+ for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
+ alloc->pages[i].alloc = alloc;
+ INIT_LIST_HEAD(&alloc->pages[i].lru);
+ }
+
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
@@ -789,7 +872,7 @@ err_alloc_buf_struct_failed:
kfree(alloc->pages);
alloc->pages = NULL;
err_alloc_pages_failed:
- alloc->buffer = NULL;
+ alloc->buffer = 0;
mutex_lock(&binder_alloc_mmap_lock);
alloc->buffer_size = 0;
err_already_mapped:
@@ -810,7 +893,7 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
struct binder_buffer *buffer;
buffers = 0;
- mutex_lock(&alloc->mutex);
+ spin_lock(&alloc->lock);
BUG_ON(alloc->vma);
while ((n = rb_first(&alloc->allocated_buffers))) {
@@ -842,25 +925,25 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
int i;
for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) {
- void __user *page_addr;
+ unsigned long page_addr;
bool on_lru;
if (!alloc->pages[i].page_ptr)
continue;
- on_lru = list_lru_del_obj(&binder_alloc_lru,
- &alloc->pages[i].lru);
+ on_lru = list_lru_del_obj(&binder_freelist,
+ &alloc->pages[i].lru);
page_addr = alloc->buffer + i * PAGE_SIZE;
binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%s: %d: page %d at %pK %s\n",
- __func__, alloc->pid, i, page_addr,
+ "%s: %d: page %d %s\n",
+ __func__, alloc->pid, i,
on_lru ? "on lru" : "active");
__free_page(alloc->pages[i].page_ptr);
page_count++;
}
kfree(alloc->pages);
}
- mutex_unlock(&alloc->mutex);
+ spin_unlock(&alloc->lock);
if (alloc->mm)
mmdrop(alloc->mm);
@@ -869,16 +952,6 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc)
__func__, alloc->pid, buffers, page_count);
}
-static void print_binder_buffer(struct seq_file *m, const char *prefix,
- struct binder_buffer *buffer)
-{
- seq_printf(m, "%s %d: %pK size %zd:%zd:%zd %s\n",
- prefix, buffer->debug_id, buffer->user_data,
- buffer->data_size, buffer->offsets_size,
- buffer->extra_buffers_size,
- buffer->transaction ? "active" : "delivered");
-}
-
/**
* binder_alloc_print_allocated() - print buffer info
* @m: seq_file for output via seq_printf()
@@ -890,13 +963,20 @@ static void print_binder_buffer(struct seq_file *m, const char *prefix,
void binder_alloc_print_allocated(struct seq_file *m,
struct binder_alloc *alloc)
{
+ struct binder_buffer *buffer;
struct rb_node *n;
- mutex_lock(&alloc->mutex);
- for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n))
- print_binder_buffer(m, " buffer",
- rb_entry(n, struct binder_buffer, rb_node));
- mutex_unlock(&alloc->mutex);
+ spin_lock(&alloc->lock);
+ for (n = rb_first(&alloc->allocated_buffers); n; n = rb_next(n)) {
+ buffer = rb_entry(n, struct binder_buffer, rb_node);
+ seq_printf(m, " buffer %d: %lx size %zd:%zd:%zd %s\n",
+ buffer->debug_id,
+ buffer->user_data - alloc->buffer,
+ buffer->data_size, buffer->offsets_size,
+ buffer->extra_buffers_size,
+ buffer->transaction ? "active" : "delivered");
+ }
+ spin_unlock(&alloc->lock);
}
/**
@@ -913,7 +993,7 @@ void binder_alloc_print_pages(struct seq_file *m,
int lru = 0;
int free = 0;
- mutex_lock(&alloc->mutex);
+ spin_lock(&alloc->lock);
/*
* Make sure the binder_alloc is fully initialized, otherwise we might
* read inconsistent state.
@@ -929,7 +1009,7 @@ void binder_alloc_print_pages(struct seq_file *m,
lru++;
}
}
- mutex_unlock(&alloc->mutex);
+ spin_unlock(&alloc->lock);
seq_printf(m, " pages: %d:%d:%d\n", active, lru, free);
seq_printf(m, " pages high watermark: %zu\n", alloc->pages_high);
}
@@ -945,10 +1025,10 @@ int binder_alloc_get_allocated_count(struct binder_alloc *alloc)
struct rb_node *n;
int count = 0;
- mutex_lock(&alloc->mutex);
+ spin_lock(&alloc->lock);
for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n))
count++;
- mutex_unlock(&alloc->mutex);
+ spin_unlock(&alloc->lock);
return count;
}
@@ -981,33 +1061,39 @@ enum lru_status binder_alloc_free_page(struct list_head *item,
void *cb_arg)
__must_hold(lock)
{
- struct mm_struct *mm = NULL;
- struct binder_lru_page *page = container_of(item,
- struct binder_lru_page,
- lru);
- struct binder_alloc *alloc;
- uintptr_t page_addr;
- size_t index;
+ struct binder_lru_page *page = container_of(item, typeof(*page), lru);
+ struct binder_alloc *alloc = page->alloc;
+ struct mm_struct *mm = alloc->mm;
struct vm_area_struct *vma;
+ struct page *page_to_free;
+ unsigned long page_addr;
+ size_t index;
- alloc = page->alloc;
- if (!mutex_trylock(&alloc->mutex))
- goto err_get_alloc_mutex_failed;
-
+ if (!mmget_not_zero(mm))
+ goto err_mmget;
+ if (!mmap_read_trylock(mm))
+ goto err_mmap_read_lock_failed;
+ if (!spin_trylock(&alloc->lock))
+ goto err_get_alloc_lock_failed;
if (!page->page_ptr)
goto err_page_already_freed;
index = page - alloc->pages;
- page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE;
+ page_addr = alloc->buffer + index * PAGE_SIZE;
- mm = alloc->mm;
- if (!mmget_not_zero(mm))
- goto err_mmget;
- if (!mmap_read_trylock(mm))
- goto err_mmap_read_lock_failed;
- vma = binder_alloc_get_vma(alloc);
+ vma = vma_lookup(mm, page_addr);
+ if (vma && vma != binder_alloc_get_vma(alloc))
+ goto err_invalid_vma;
+
+ trace_binder_unmap_kernel_start(alloc, index);
+
+ page_to_free = page->page_ptr;
+ page->page_ptr = NULL;
+
+ trace_binder_unmap_kernel_end(alloc, index);
list_lru_isolate(lru, item);
+ spin_unlock(&alloc->lock);
spin_unlock(lock);
if (vma) {
@@ -1017,39 +1103,35 @@ enum lru_status binder_alloc_free_page(struct list_head *item,
trace_binder_unmap_user_end(alloc, index);
}
+
mmap_read_unlock(mm);
mmput_async(mm);
-
- trace_binder_unmap_kernel_start(alloc, index);
-
- __free_page(page->page_ptr);
- page->page_ptr = NULL;
-
- trace_binder_unmap_kernel_end(alloc, index);
+ __free_page(page_to_free);
spin_lock(lock);
- mutex_unlock(&alloc->mutex);
return LRU_REMOVED_RETRY;
+err_invalid_vma:
+err_page_already_freed:
+ spin_unlock(&alloc->lock);
+err_get_alloc_lock_failed:
+ mmap_read_unlock(mm);
err_mmap_read_lock_failed:
mmput_async(mm);
err_mmget:
-err_page_already_freed:
- mutex_unlock(&alloc->mutex);
-err_get_alloc_mutex_failed:
return LRU_SKIP;
}
static unsigned long
binder_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
{
- return list_lru_count(&binder_alloc_lru);
+ return list_lru_count(&binder_freelist);
}
static unsigned long
binder_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
{
- return list_lru_walk(&binder_alloc_lru, binder_alloc_free_page,
+ return list_lru_walk(&binder_freelist, binder_alloc_free_page,
NULL, sc->nr_to_scan);
}
@@ -1067,7 +1149,7 @@ void binder_alloc_init(struct binder_alloc *alloc)
alloc->pid = current->group_leader->pid;
alloc->mm = current->mm;
mmgrab(alloc->mm);
- mutex_init(&alloc->mutex);
+ spin_lock_init(&alloc->lock);
INIT_LIST_HEAD(&alloc->buffers);
}
@@ -1075,13 +1157,13 @@ int binder_alloc_shrinker_init(void)
{
int ret;
- ret = list_lru_init(&binder_alloc_lru);
+ ret = list_lru_init(&binder_freelist);
if (ret)
return ret;
binder_shrinker = shrinker_alloc(0, "android-binder");
if (!binder_shrinker) {
- list_lru_destroy(&binder_alloc_lru);
+ list_lru_destroy(&binder_freelist);
return -ENOMEM;
}
@@ -1096,7 +1178,7 @@ int binder_alloc_shrinker_init(void)
void binder_alloc_shrinker_exit(void)
{
shrinker_free(binder_shrinker);
- list_lru_destroy(&binder_alloc_lru);
+ list_lru_destroy(&binder_freelist);
}
/**
@@ -1132,68 +1214,6 @@ static inline bool check_buffer(struct binder_alloc *alloc,
}
/**
- * binder_alloc_get_page() - get kernel pointer for given buffer offset
- * @alloc: binder_alloc for this proc
- * @buffer: binder buffer to be accessed
- * @buffer_offset: offset into @buffer data
- * @pgoffp: address to copy final page offset to
- *
- * Lookup the struct page corresponding to the address
- * at @buffer_offset into @buffer->user_data. If @pgoffp is not
- * NULL, the byte-offset into the page is written there.
- *
- * The caller is responsible to ensure that the offset points
- * to a valid address within the @buffer and that @buffer is
- * not freeable by the user. Since it can't be freed, we are
- * guaranteed that the corresponding elements of @alloc->pages[]
- * cannot change.
- *
- * Return: struct page
- */
-static struct page *binder_alloc_get_page(struct binder_alloc *alloc,
- struct binder_buffer *buffer,
- binder_size_t buffer_offset,
- pgoff_t *pgoffp)
-{
- binder_size_t buffer_space_offset = buffer_offset +
- (buffer->user_data - alloc->buffer);
- pgoff_t pgoff = buffer_space_offset & ~PAGE_MASK;
- size_t index = buffer_space_offset >> PAGE_SHIFT;
- struct binder_lru_page *lru_page;
-
- lru_page = &alloc->pages[index];
- *pgoffp = pgoff;
- return lru_page->page_ptr;
-}
-
-/**
- * binder_alloc_clear_buf() - zero out buffer
- * @alloc: binder_alloc for this proc
- * @buffer: binder buffer to be cleared
- *
- * memset the given buffer to 0
- */
-static void binder_alloc_clear_buf(struct binder_alloc *alloc,
- struct binder_buffer *buffer)
-{
- size_t bytes = binder_alloc_buffer_size(alloc, buffer);
- binder_size_t buffer_offset = 0;
-
- while (bytes) {
- unsigned long size;
- struct page *page;
- pgoff_t pgoff;
-
- page = binder_alloc_get_page(alloc, buffer,
- buffer_offset, &pgoff);
- size = min_t(size_t, bytes, PAGE_SIZE - pgoff);
- memset_page(page, pgoff, 0, size);
- bytes -= size;
- buffer_offset += size;
- }
-}
-
-/**
* binder_alloc_copy_user_to_buffer() - copy src user to tgt user
* @alloc: binder_alloc for this proc
* @buffer: binder buffer to be accessed
diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h
index dc1e2b01dd64..70387234477e 100644
--- a/drivers/android/binder_alloc.h
+++ b/drivers/android/binder_alloc.h
@@ -9,13 +9,13 @@
#include <linux/rbtree.h>
#include <linux/list.h>
#include <linux/mm.h>
-#include <linux/rtmutex.h>
+#include <linux/spinlock.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/list_lru.h>
#include <uapi/linux/android/binder.h>
-extern struct list_lru binder_alloc_lru;
+extern struct list_lru binder_freelist;
struct binder_transaction;
/**
@@ -49,21 +49,19 @@ struct binder_buffer {
unsigned async_transaction:1;
unsigned oneway_spam_suspect:1;
unsigned debug_id:27;
-
struct binder_transaction *transaction;
-
struct binder_node *target_node;
size_t data_size;
size_t offsets_size;
size_t extra_buffers_size;
- void __user *user_data;
- int pid;
+ unsigned long user_data;
+ int pid;
};
/**
* struct binder_lru_page - page object used for binder shrinker
* @page_ptr: pointer to physical page in mmap'd space
- * @lru: entry in binder_alloc_lru
+ * @lru: entry in binder_freelist
* @alloc: binder_alloc for a proc
*/
struct binder_lru_page {
@@ -74,7 +72,7 @@ struct binder_lru_page {
/**
* struct binder_alloc - per-binder proc state for binder allocator
- * @mutex: protects binder_alloc fields
+ * @lock: protects binder_alloc fields
* @vma: vm_area_struct passed to mmap_handler
* (invariant after mmap)
* @mm: copy of task->mm (invariant after open)
@@ -98,10 +96,10 @@ struct binder_lru_page {
* struct binder_buffer objects used to track the user buffers
*/
struct binder_alloc {
- struct mutex mutex;
+ spinlock_t lock;
struct vm_area_struct *vma;
struct mm_struct *mm;
- void __user *buffer;
+ unsigned long buffer;
struct list_head buffers;
struct rb_root free_buffers;
struct rb_root allocated_buffers;
@@ -121,27 +119,26 @@ static inline void binder_selftest_alloc(struct binder_alloc *alloc) {}
enum lru_status binder_alloc_free_page(struct list_head *item,
struct list_lru_one *lru,
spinlock_t *lock, void *cb_arg);
-extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
- size_t data_size,
- size_t offsets_size,
- size_t extra_buffers_size,
- int is_async,
- int pid);
-extern void binder_alloc_init(struct binder_alloc *alloc);
-extern int binder_alloc_shrinker_init(void);
-extern void binder_alloc_shrinker_exit(void);
-extern void binder_alloc_vma_close(struct binder_alloc *alloc);
-extern struct binder_buffer *
+struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
+ size_t data_size,
+ size_t offsets_size,
+ size_t extra_buffers_size,
+ int is_async);
+void binder_alloc_init(struct binder_alloc *alloc);
+int binder_alloc_shrinker_init(void);
+void binder_alloc_shrinker_exit(void);
+void binder_alloc_vma_close(struct binder_alloc *alloc);
+struct binder_buffer *
binder_alloc_prepare_to_free(struct binder_alloc *alloc,
- uintptr_t user_ptr);
-extern void binder_alloc_free_buf(struct binder_alloc *alloc,
- struct binder_buffer *buffer);
-extern int binder_alloc_mmap_handler(struct binder_alloc *alloc,
- struct vm_area_struct *vma);
-extern void binder_alloc_deferred_release(struct binder_alloc *alloc);
-extern int binder_alloc_get_allocated_count(struct binder_alloc *alloc);
-extern void binder_alloc_print_allocated(struct seq_file *m,
- struct binder_alloc *alloc);
+ unsigned long user_ptr);
+void binder_alloc_free_buf(struct binder_alloc *alloc,
+ struct binder_buffer *buffer);
+int binder_alloc_mmap_handler(struct binder_alloc *alloc,
+ struct vm_area_struct *vma);
+void binder_alloc_deferred_release(struct binder_alloc *alloc);
+int binder_alloc_get_allocated_count(struct binder_alloc *alloc);
+void binder_alloc_print_allocated(struct seq_file *m,
+ struct binder_alloc *alloc);
void binder_alloc_print_pages(struct seq_file *m,
struct binder_alloc *alloc);
@@ -156,9 +153,9 @@ binder_alloc_get_free_async_space(struct binder_alloc *alloc)
{
size_t free_async_space;
- mutex_lock(&alloc->mutex);
+ spin_lock(&alloc->lock);
free_async_space = alloc->free_async_space;
- mutex_unlock(&alloc->mutex);
+ spin_unlock(&alloc->lock);
return free_async_space;
}
diff --git a/drivers/android/binder_alloc_selftest.c b/drivers/android/binder_alloc_selftest.c
index c2b323bc3b3a..81442fe20a69 100644
--- a/drivers/android/binder_alloc_selftest.c
+++ b/drivers/android/binder_alloc_selftest.c
@@ -72,6 +72,10 @@ enum buf_end_align_type {
* buf1 ]|[ buf2 | buf2 | buf2 ][ ...
*/
NEXT_NEXT_UNALIGNED,
+ /**
+ * @LOOP_END: The number of enum values in &buf_end_align_type.
+ * It is used for controlling loop termination.
+ */
LOOP_END,
};
@@ -93,11 +97,11 @@ static bool check_buffer_pages_allocated(struct binder_alloc *alloc,
struct binder_buffer *buffer,
size_t size)
{
- void __user *page_addr;
- void __user *end;
+ unsigned long page_addr;
+ unsigned long end;
int page_index;
- end = (void __user *)PAGE_ALIGN((uintptr_t)buffer->user_data + size);
+ end = PAGE_ALIGN(buffer->user_data + size);
page_addr = buffer->user_data;
for (; page_addr < end; page_addr += PAGE_SIZE) {
page_index = (page_addr - alloc->buffer) / PAGE_SIZE;
@@ -119,7 +123,7 @@ static void binder_selftest_alloc_buf(struct binder_alloc *alloc,
int i;
for (i = 0; i < BUFFER_NUM; i++) {
- buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0, 0);
+ buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0);
if (IS_ERR(buffers[i]) ||
!check_buffer_pages_allocated(alloc, buffers[i],
sizes[i])) {
@@ -158,8 +162,8 @@ static void binder_selftest_free_page(struct binder_alloc *alloc)
int i;
unsigned long count;
- while ((count = list_lru_count(&binder_alloc_lru))) {
- list_lru_walk(&binder_alloc_lru, binder_alloc_free_page,
+ while ((count = list_lru_count(&binder_freelist))) {
+ list_lru_walk(&binder_freelist, binder_alloc_free_page,
NULL, count);
}
@@ -183,7 +187,7 @@ static void binder_selftest_alloc_free(struct binder_alloc *alloc,
/* Allocate from lru. */
binder_selftest_alloc_buf(alloc, buffers, sizes, seq);
- if (list_lru_count(&binder_alloc_lru))
+ if (list_lru_count(&binder_freelist))
pr_err("lru list should be empty but is not\n");
binder_selftest_free_buf(alloc, buffers, sizes, seq, end);
diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h
index 8cc07e6a4273..fe38c6fc65d0 100644
--- a/drivers/android/binder_trace.h
+++ b/drivers/android/binder_trace.h
@@ -317,7 +317,7 @@ DEFINE_EVENT(binder_buffer_class, binder_transaction_update_buffer_release,
TRACE_EVENT(binder_update_page_range,
TP_PROTO(struct binder_alloc *alloc, bool allocate,
- void __user *start, void __user *end),
+ unsigned long start, unsigned long end),
TP_ARGS(alloc, allocate, start, end),
TP_STRUCT__entry(
__field(int, proc)
diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c
index 1224ab7aa070..3001d754ac36 100644
--- a/drivers/android/binderfs.c
+++ b/drivers/android/binderfs.c
@@ -29,7 +29,6 @@
#include <linux/uaccess.h>
#include <linux/user_namespace.h>
#include <linux/xarray.h>
-#include <uapi/asm-generic/errno-base.h>
#include <uapi/linux/android/binder.h>
#include <uapi/linux/android/binderfs.h>
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 5aaa0865625d..018ac202de34 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -219,20 +219,34 @@ static DECLARE_WORK(update_topology_flags_work, update_topology_flags_workfn);
static DEVICE_ATTR_RO(cpu_capacity);
-static int register_cpu_capacity_sysctl(void)
+static int cpu_capacity_sysctl_add(unsigned int cpu)
{
- int i;
- struct device *cpu;
+ struct device *cpu_dev = get_cpu_device(cpu);
- for_each_possible_cpu(i) {
- cpu = get_cpu_device(i);
- if (!cpu) {
- pr_err("%s: too early to get CPU%d device!\n",
- __func__, i);
- continue;
- }
- device_create_file(cpu, &dev_attr_cpu_capacity);
- }
+ if (!cpu_dev)
+ return -ENOENT;
+
+ device_create_file(cpu_dev, &dev_attr_cpu_capacity);
+
+ return 0;
+}
+
+static int cpu_capacity_sysctl_remove(unsigned int cpu)
+{
+ struct device *cpu_dev = get_cpu_device(cpu);
+
+ if (!cpu_dev)
+ return -ENOENT;
+
+ device_remove_file(cpu_dev, &dev_attr_cpu_capacity);
+
+ return 0;
+}
+
+static int register_cpu_capacity_sysctl(void)
+{
+ cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "topology/cpu-capacity",
+ cpu_capacity_sysctl_add, cpu_capacity_sysctl_remove);
return 0;
}
diff --git a/drivers/base/auxiliary.c b/drivers/base/auxiliary.c
index 4d4c2c8d26c4..d3a2c40c2f12 100644
--- a/drivers/base/auxiliary.c
+++ b/drivers/base/auxiliary.c
@@ -244,7 +244,7 @@ static void auxiliary_bus_shutdown(struct device *dev)
auxdrv->shutdown(auxdev);
}
-static struct bus_type auxiliary_bus_type = {
+static const struct bus_type auxiliary_bus_type = {
.name = "auxiliary",
.probe = auxiliary_bus_probe,
.remove = auxiliary_bus_remove,
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 84a21084d67d..daee55c9b2d9 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -1030,7 +1030,7 @@ static void device_insertion_sort_klist(struct device *a, struct list_head *list
list_move_tail(&a->p->knode_bus.n_node, list);
}
-void bus_sort_breadthfirst(struct bus_type *bus,
+void bus_sort_breadthfirst(const struct bus_type *bus,
int (*compare)(const struct device *a,
const struct device *b))
{
@@ -1194,7 +1194,7 @@ static void system_root_device_release(struct device *dev)
kfree(dev);
}
-static int subsys_register(struct bus_type *subsys,
+static int subsys_register(const struct bus_type *subsys,
const struct attribute_group **groups,
struct kobject *parent_of_root)
{
@@ -1264,7 +1264,7 @@ err_sp:
* directory itself and not some create fake root-device placed in
* /sys/devices/system/<name>.
*/
-int subsys_system_register(struct bus_type *subsys,
+int subsys_system_register(const struct bus_type *subsys,
const struct attribute_group **groups)
{
return subsys_register(subsys, groups, &system_kset->kobj);
@@ -1282,7 +1282,7 @@ EXPORT_SYMBOL_GPL(subsys_system_register);
* There's no restriction on device naming. This is for kernel software
* constructs which need sysfs interface.
*/
-int subsys_virtual_register(struct bus_type *subsys,
+int subsys_virtual_register(const struct bus_type *subsys,
const struct attribute_group **groups)
{
struct kobject *virtual_dir;
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 7e78aee0fd6c..7b38fdf8e1d7 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -213,6 +213,7 @@ int class_register(const struct class *cls)
return 0;
err_out:
+ lockdep_unregister_key(key);
kfree(cp);
return error;
}
diff --git a/drivers/base/container.c b/drivers/base/container.c
index 1ba42d2d3532..f40588ebc3f5 100644
--- a/drivers/base/container.c
+++ b/drivers/base/container.c
@@ -24,7 +24,7 @@ static int container_offline(struct device *dev)
return cdev->offline ? cdev->offline(cdev) : 0;
}
-struct bus_type container_subsys = {
+const struct bus_type container_subsys = {
.name = CONTAINER_BUS_NAME,
.dev_name = CONTAINER_BUS_NAME,
.online = trivial_online,
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 67ba592afc77..14d46af40f9a 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -298,7 +298,7 @@ static inline bool device_link_flag_is_sync_state_only(u32 flags)
* Check if @target depends on @dev or any device dependent on it (its child or
* its consumer etc). Return 1 if that is the case or 0 otherwise.
*/
-int device_is_dependent(struct device *dev, void *target)
+static int device_is_dependent(struct device *dev, void *target)
{
struct device_link *link;
int ret;
@@ -1641,7 +1641,7 @@ static void device_links_purge(struct device *dev)
#define FW_DEVLINK_FLAGS_RPM (FW_DEVLINK_FLAGS_ON | \
DL_FLAG_PM_RUNTIME)
-static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_ON;
+static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_RPM;
static int __init fw_devlink_setup(char *arg)
{
if (!arg)
@@ -4944,13 +4944,14 @@ define_dev_printk_level(_dev_info, KERN_INFO);
*
* return dev_err_probe(dev, err, ...);
*
- * Note that it is deemed acceptable to use this function for error
- * prints during probe even if the @err is known to never be -EPROBE_DEFER.
+ * Using this helper in your probe function is totally fine even if @err is
+ * known to never be -EPROBE_DEFER.
* The benefit compared to a normal dev_err() is the standardized format
- * of the error code and the fact that the error code is returned.
+ * of the error code, it being emitted symbolically (i.e. you get "EAGAIN"
+ * instead of "-35") and the fact that the error code is returned which allows
+ * more compact error paths.
*
* Returns @err.
- *
*/
int dev_err_probe(const struct device *dev, int err, const char *fmt, ...)
{
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 548491de818e..47de0f140ba6 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -525,19 +525,42 @@ bool cpu_is_hotpluggable(unsigned int cpu)
EXPORT_SYMBOL_GPL(cpu_is_hotpluggable);
#ifdef CONFIG_GENERIC_CPU_DEVICES
-static DEFINE_PER_CPU(struct cpu, cpu_devices);
-#endif
+DEFINE_PER_CPU(struct cpu, cpu_devices);
+
+bool __weak arch_cpu_is_hotpluggable(int cpu)
+{
+ return false;
+}
+
+int __weak arch_register_cpu(int cpu)
+{
+ struct cpu *c = &per_cpu(cpu_devices, cpu);
+
+ c->hotpluggable = arch_cpu_is_hotpluggable(cpu);
+
+ return register_cpu(c, cpu);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void __weak arch_unregister_cpu(int num)
+{
+ unregister_cpu(&per_cpu(cpu_devices, num));
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+#endif /* CONFIG_GENERIC_CPU_DEVICES */
static void __init cpu_dev_register_generic(void)
{
-#ifdef CONFIG_GENERIC_CPU_DEVICES
- int i;
+ int i, ret;
- for_each_possible_cpu(i) {
- if (register_cpu(&per_cpu(cpu_devices, i), i))
- panic("Failed to register CPU device");
+ if (!IS_ENABLED(CONFIG_GENERIC_CPU_DEVICES))
+ return;
+
+ for_each_present_cpu(i) {
+ ret = arch_register_cpu(i);
+ if (ret)
+ pr_warn("register_cpu %d failed (%d)\n", i, ret);
}
-#endif
}
#ifdef CONFIG_GENERIC_CPU_VULNERABILITIES
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 0c3725c3eefa..85152537dbf1 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -313,7 +313,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work)
mutex_lock(&deferred_probe_mutex);
list_for_each_entry(p, &deferred_probe_pending_list, deferred_probe)
- dev_info(p->device, "deferred probe pending\n");
+ dev_info(p->device, "deferred probe pending: %s", p->deferred_probe_reason ?: "(reason unknown)\n");
mutex_unlock(&deferred_probe_mutex);
fw_devlink_probing_done();
diff --git a/drivers/base/init.c b/drivers/base/init.c
index 397eb9880cec..c4954835128c 100644
--- a/drivers/base/init.c
+++ b/drivers/base/init.c
@@ -35,8 +35,8 @@ void __init driver_init(void)
of_core_init();
platform_bus_init();
auxiliary_bus_init();
- cpu_dev_init();
memory_dev_init();
node_dev_init();
+ cpu_dev_init();
container_dev_init();
}
diff --git a/drivers/base/isa.c b/drivers/base/isa.c
index 675ad3139224..e23d0b49a793 100644
--- a/drivers/base/isa.c
+++ b/drivers/base/isa.c
@@ -82,7 +82,7 @@ static int isa_bus_resume(struct device *dev)
return 0;
}
-static struct bus_type isa_bus_type = {
+static const struct bus_type isa_bus_type = {
.name = "isa",
.match = isa_bus_match,
.probe = isa_bus_probe,
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 8a13babd826c..14f964a7719b 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -68,7 +68,7 @@ static inline unsigned long phys_to_block_id(unsigned long phys)
static int memory_subsys_online(struct device *dev);
static int memory_subsys_offline(struct device *dev);
-static struct bus_type memory_subsys = {
+static const struct bus_type memory_subsys = {
.name = MEMORY_CLASS_NAME,
.dev_name = MEMORY_CLASS_NAME,
.online = memory_subsys_online,
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 493d533f8375..1c05640461dd 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -21,7 +21,7 @@
#include <linux/swap.h>
#include <linux/slab.h>
-static struct bus_type node_subsys = {
+static const struct bus_type node_subsys = {
.name = "node",
.dev_name = "node",
};
@@ -74,14 +74,14 @@ static BIN_ATTR_RO(cpulist, CPULIST_FILE_MAX_BYTES);
* @dev: Device for this memory access class
* @list_node: List element in the node's access list
* @access: The access class rank
- * @hmem_attrs: Heterogeneous memory performance attributes
+ * @coord: Heterogeneous memory performance coordinates
*/
struct node_access_nodes {
struct device dev;
struct list_head list_node;
unsigned int access;
#ifdef CONFIG_HMEM_REPORTING
- struct node_hmem_attrs hmem_attrs;
+ struct access_coordinate coord;
#endif
};
#define to_access_nodes(dev) container_of(dev, struct node_access_nodes, dev)
@@ -167,7 +167,7 @@ static ssize_t property##_show(struct device *dev, \
char *buf) \
{ \
return sysfs_emit(buf, "%u\n", \
- to_access_nodes(dev)->hmem_attrs.property); \
+ to_access_nodes(dev)->coord.property); \
} \
static DEVICE_ATTR_RO(property)
@@ -187,10 +187,10 @@ static struct attribute *access_attrs[] = {
/**
* node_set_perf_attrs - Set the performance values for given access class
* @nid: Node identifier to be set
- * @hmem_attrs: Heterogeneous memory performance attributes
+ * @coord: Heterogeneous memory performance coordinates
* @access: The access class the for the given attributes
*/
-void node_set_perf_attrs(unsigned int nid, struct node_hmem_attrs *hmem_attrs,
+void node_set_perf_attrs(unsigned int nid, struct access_coordinate *coord,
unsigned int access)
{
struct node_access_nodes *c;
@@ -205,7 +205,7 @@ void node_set_perf_attrs(unsigned int nid, struct node_hmem_attrs *hmem_attrs,
if (!c)
return;
- c->hmem_attrs = *hmem_attrs;
+ c->coord = *coord;
for (i = 0; access_attrs[i] != NULL; i++) {
if (sysfs_add_file_to_group(&c->dev.kobj, access_attrs[i],
"initiators")) {
@@ -868,11 +868,15 @@ int __register_one_node(int nid)
{
int error;
int cpu;
+ struct node *node;
- node_devices[nid] = kzalloc(sizeof(struct node), GFP_KERNEL);
- if (!node_devices[nid])
+ node = kzalloc(sizeof(struct node), GFP_KERNEL);
+ if (!node)
return -ENOMEM;
+ INIT_LIST_HEAD(&node->access_list);
+ node_devices[nid] = node;
+
error = register_node(node_devices[nid], nid);
/* link cpu under this node */
@@ -881,7 +885,6 @@ int __register_one_node(int nid)
register_cpu_under_node(cpu, nid);
}
- INIT_LIST_HEAD(&node_devices[nid]->access_list);
node_init_caches(nid);
return error;
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 8fdd0073eeeb..01f11629d241 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -2,7 +2,6 @@
obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o
obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o wakeup_stats.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
-obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o
obj-$(CONFIG_HAVE_CLK) += clock_ops.o
obj-$(CONFIG_PM_QOS_KUNIT_TEST) += qos-test.o
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index 4110c19c08dc..e18ba676cdf6 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -793,7 +793,7 @@ static int pm_clk_notify(struct notifier_block *nb,
* the remaining members of @clknb should be populated prior to calling this
* routine.
*/
-void pm_clk_add_notifier(struct bus_type *bus,
+void pm_clk_add_notifier(const struct bus_type *bus,
struct pm_clk_notifier_block *clknb)
{
if (!bus || !clknb)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 9c5a5f4dba5a..fadcd0379dc2 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -579,7 +579,7 @@ bool dev_pm_skip_resume(struct device *dev)
}
/**
- * __device_resume_noirq - Execute a "noirq resume" callback for given device.
+ * device_resume_noirq - Execute a "noirq resume" callback for given device.
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
* @async: If true, the device is being resumed asynchronously.
@@ -587,7 +587,7 @@ bool dev_pm_skip_resume(struct device *dev)
* The driver of @dev will not receive interrupts while this function is being
* executed.
*/
-static void __device_resume_noirq(struct device *dev, pm_message_t state, bool async)
+static void device_resume_noirq(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback = NULL;
const char *info = NULL;
@@ -674,16 +674,22 @@ static bool dpm_async_fn(struct device *dev, async_func_t func)
{
reinit_completion(&dev->power.completion);
- if (!is_async(dev))
- return false;
-
- get_device(dev);
+ if (is_async(dev)) {
+ dev->power.async_in_progress = true;
- if (async_schedule_dev_nocall(func, dev))
- return true;
+ get_device(dev);
- put_device(dev);
+ if (async_schedule_dev_nocall(func, dev))
+ return true;
+ put_device(dev);
+ }
+ /*
+ * Because async_schedule_dev_nocall() above has returned false or it
+ * has not been called at all, func() is not running and it is safe to
+ * update the async_in_progress flag without extra synchronization.
+ */
+ dev->power.async_in_progress = false;
return false;
}
@@ -691,18 +697,10 @@ static void async_resume_noirq(void *data, async_cookie_t cookie)
{
struct device *dev = data;
- __device_resume_noirq(dev, pm_transition, true);
+ device_resume_noirq(dev, pm_transition, true);
put_device(dev);
}
-static void device_resume_noirq(struct device *dev)
-{
- if (dpm_async_fn(dev, async_resume_noirq))
- return;
-
- __device_resume_noirq(dev, pm_transition, false);
-}
-
static void dpm_noirq_resume_devices(pm_message_t state)
{
struct device *dev;
@@ -712,18 +710,28 @@ static void dpm_noirq_resume_devices(pm_message_t state)
mutex_lock(&dpm_list_mtx);
pm_transition = state;
+ /*
+ * Trigger the resume of "async" devices upfront so they don't have to
+ * wait for the "non-async" ones they don't depend on.
+ */
+ list_for_each_entry(dev, &dpm_noirq_list, power.entry)
+ dpm_async_fn(dev, async_resume_noirq);
+
while (!list_empty(&dpm_noirq_list)) {
dev = to_device(dpm_noirq_list.next);
- get_device(dev);
list_move_tail(&dev->power.entry, &dpm_late_early_list);
- mutex_unlock(&dpm_list_mtx);
+ if (!dev->power.async_in_progress) {
+ get_device(dev);
- device_resume_noirq(dev);
+ mutex_unlock(&dpm_list_mtx);
- put_device(dev);
+ device_resume_noirq(dev, state, false);
- mutex_lock(&dpm_list_mtx);
+ put_device(dev);
+
+ mutex_lock(&dpm_list_mtx);
+ }
}
mutex_unlock(&dpm_list_mtx);
async_synchronize_full();
@@ -747,14 +755,14 @@ void dpm_resume_noirq(pm_message_t state)
}
/**
- * __device_resume_early - Execute an "early resume" callback for given device.
+ * device_resume_early - Execute an "early resume" callback for given device.
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
* @async: If true, the device is being resumed asynchronously.
*
* Runtime PM is disabled for @dev while this function is being executed.
*/
-static void __device_resume_early(struct device *dev, pm_message_t state, bool async)
+static void device_resume_early(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback = NULL;
const char *info = NULL;
@@ -820,18 +828,10 @@ static void async_resume_early(void *data, async_cookie_t cookie)
{
struct device *dev = data;
- __device_resume_early(dev, pm_transition, true);
+ device_resume_early(dev, pm_transition, true);
put_device(dev);
}
-static void device_resume_early(struct device *dev)
-{
- if (dpm_async_fn(dev, async_resume_early))
- return;
-
- __device_resume_early(dev, pm_transition, false);
-}
-
/**
* dpm_resume_early - Execute "early resume" callbacks for all devices.
* @state: PM transition of the system being carried out.
@@ -845,18 +845,28 @@ void dpm_resume_early(pm_message_t state)
mutex_lock(&dpm_list_mtx);
pm_transition = state;
+ /*
+ * Trigger the resume of "async" devices upfront so they don't have to
+ * wait for the "non-async" ones they don't depend on.
+ */
+ list_for_each_entry(dev, &dpm_late_early_list, power.entry)
+ dpm_async_fn(dev, async_resume_early);
+
while (!list_empty(&dpm_late_early_list)) {
dev = to_device(dpm_late_early_list.next);
- get_device(dev);
list_move_tail(&dev->power.entry, &dpm_suspended_list);
- mutex_unlock(&dpm_list_mtx);
+ if (!dev->power.async_in_progress) {
+ get_device(dev);
- device_resume_early(dev);
+ mutex_unlock(&dpm_list_mtx);
- put_device(dev);
+ device_resume_early(dev, state, false);
- mutex_lock(&dpm_list_mtx);
+ put_device(dev);
+
+ mutex_lock(&dpm_list_mtx);
+ }
}
mutex_unlock(&dpm_list_mtx);
async_synchronize_full();
@@ -876,12 +886,12 @@ void dpm_resume_start(pm_message_t state)
EXPORT_SYMBOL_GPL(dpm_resume_start);
/**
- * __device_resume - Execute "resume" callbacks for given device.
+ * device_resume - Execute "resume" callbacks for given device.
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
* @async: If true, the device is being resumed asynchronously.
*/
-static void __device_resume(struct device *dev, pm_message_t state, bool async)
+static void device_resume(struct device *dev, pm_message_t state, bool async)
{
pm_callback_t callback = NULL;
const char *info = NULL;
@@ -975,18 +985,10 @@ static void async_resume(void *data, async_cookie_t cookie)
{
struct device *dev = data;
- __device_resume(dev, pm_transition, true);
+ device_resume(dev, pm_transition, true);
put_device(dev);
}
-static void device_resume(struct device *dev)
-{
- if (dpm_async_fn(dev, async_resume))
- return;
-
- __device_resume(dev, pm_transition, false);
-}
-
/**
* dpm_resume - Execute "resume" callbacks for non-sysdev devices.
* @state: PM transition of the system being carried out.
@@ -1006,16 +1008,25 @@ void dpm_resume(pm_message_t state)
pm_transition = state;
async_error = 0;
+ /*
+ * Trigger the resume of "async" devices upfront so they don't have to
+ * wait for the "non-async" ones they don't depend on.
+ */
+ list_for_each_entry(dev, &dpm_suspended_list, power.entry)
+ dpm_async_fn(dev, async_resume);
+
while (!list_empty(&dpm_suspended_list)) {
dev = to_device(dpm_suspended_list.next);
get_device(dev);
- mutex_unlock(&dpm_list_mtx);
+ if (!dev->power.async_in_progress) {
+ mutex_unlock(&dpm_list_mtx);
- device_resume(dev);
+ device_resume(dev, state, false);
- mutex_lock(&dpm_list_mtx);
+ mutex_lock(&dpm_list_mtx);
+ }
if (!list_empty(&dev->power.entry))
list_move_tail(&dev->power.entry, &dpm_prepared_list);
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 8e93167f1783..bd77f6734f14 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -201,7 +201,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
if (!qos)
return -ENOMEM;
- n = kzalloc(3 * sizeof(*n), GFP_KERNEL);
+ n = kcalloc(3, sizeof(*n), GFP_KERNEL);
if (!n) {
kfree(qos);
return -ENOMEM;
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 8c40abed7852..a1b01ab42052 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -473,7 +473,7 @@ int fwnode_property_match_string(const struct fwnode_handle *fwnode,
const char **values;
int nval, ret;
- nval = fwnode_property_read_string_array(fwnode, propname, NULL, 0);
+ nval = fwnode_property_string_array_count(fwnode, propname);
if (nval < 0)
return nval;
@@ -499,6 +499,41 @@ out_free:
EXPORT_SYMBOL_GPL(fwnode_property_match_string);
/**
+ * fwnode_property_match_property_string - find a property string value in an array and return index
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property holding the string value
+ * @array: String array to search in
+ * @n: Size of the @array
+ *
+ * Find a property string value in a given @array and if it is found return
+ * the index back.
+ *
+ * Return: index, starting from %0, if the string value was found in the @array (success),
+ * %-ENOENT when the string value was not found in the @array,
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property is not a string,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_match_property_string(const struct fwnode_handle *fwnode,
+ const char *propname, const char * const *array, size_t n)
+{
+ const char *string;
+ int ret;
+
+ ret = fwnode_property_read_string(fwnode, propname, &string);
+ if (ret)
+ return ret;
+
+ ret = match_string(array, n, string);
+ if (ret < 0)
+ ret = -ENOENT;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_match_property_string);
+
+/**
* fwnode_property_get_reference_args() - Find a reference with arguments
* @fwnode: Firmware node where to look for the reference
* @prop: The name of the property
@@ -508,6 +543,7 @@ EXPORT_SYMBOL_GPL(fwnode_property_match_string);
* @nargs: Number of arguments. Ignored if @nargs_prop is non-NULL.
* @index: Index of the reference, from zero onwards.
* @args: Result structure with reference and integer arguments.
+ * May be NULL.
*
* Obtain a reference based on a named property in an fwnode, with
* integer arguments.
@@ -595,6 +631,34 @@ const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode)
}
/**
+ * fwnode_name_eq - Return true if node name is equal
+ * @fwnode: The firmware node
+ * @name: The name to which to compare the node name
+ *
+ * Compare the name provided as an argument to the name of the node, stopping
+ * the comparison at either NUL or '@' character, whichever comes first. This
+ * function is generally used for comparing node names while ignoring the
+ * possible unit address of the node.
+ *
+ * Return: true if the node name matches with the name provided in the @name
+ * argument, false otherwise.
+ */
+bool fwnode_name_eq(const struct fwnode_handle *fwnode, const char *name)
+{
+ const char *node_name;
+ ptrdiff_t len;
+
+ node_name = fwnode_get_name(fwnode);
+ if (!node_name)
+ return false;
+
+ len = strchrnul(node_name, '@') - node_name;
+
+ return str_has_prefix(node_name, name) == len;
+}
+EXPORT_SYMBOL_GPL(fwnode_name_eq);
+
+/**
* fwnode_get_parent - Return parent firwmare node
* @fwnode: Firmware whose parent is retrieved
*
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
index 8dec5228fde3..282c38aece0d 100644
--- a/drivers/base/soc.c
+++ b/drivers/base/soc.c
@@ -28,7 +28,7 @@ struct soc_device {
int soc_dev_num;
};
-static struct bus_type soc_bus_type = {
+static const struct bus_type soc_bus_type = {
.name = "soc",
};
static bool soc_bus_registered;
@@ -106,7 +106,7 @@ static void soc_release(struct device *dev)
{
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
- ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
+ ida_free(&soc_ida, soc_dev->soc_dev_num);
kfree(soc_dev->dev.groups);
kfree(soc_dev);
}
@@ -155,7 +155,7 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
soc_attr_groups[1] = soc_dev_attr->custom_attr_group;
/* Fetch a unique (reclaimable) SOC ID. */
- ret = ida_simple_get(&soc_ida, 0, 0, GFP_KERNEL);
+ ret = ida_alloc(&soc_ida, GFP_KERNEL);
if (ret < 0)
goto out3;
soc_dev->soc_dev_num = ret;
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index 1886995a0b3a..36512fb75a20 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -541,6 +541,9 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,
if (nargs > NR_FWNODE_REFERENCE_ARGS)
return -EINVAL;
+ if (!args)
+ return 0;
+
args->fwnode = software_node_get(refnode);
args->nargs = nargs;
@@ -747,10 +750,10 @@ static void software_node_release(struct kobject *kobj)
struct swnode *swnode = kobj_to_swnode(kobj);
if (swnode->parent) {
- ida_simple_remove(&swnode->parent->child_ids, swnode->id);
+ ida_free(&swnode->parent->child_ids, swnode->id);
list_del(&swnode->entry);
} else {
- ida_simple_remove(&swnode_root_ids, swnode->id);
+ ida_free(&swnode_root_ids, swnode->id);
}
if (swnode->allocated)
@@ -776,8 +779,8 @@ swnode_register(const struct software_node *node, struct swnode *parent,
if (!swnode)
return ERR_PTR(-ENOMEM);
- ret = ida_simple_get(parent ? &parent->child_ids : &swnode_root_ids,
- 0, 0, GFP_KERNEL);
+ ret = ida_alloc(parent ? &parent->child_ids : &swnode_root_ids,
+ GFP_KERNEL);
if (ret < 0) {
kfree(swnode);
return ERR_PTR(ret);
diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c
index 203a000a84e3..3c84fcbda01a 100644
--- a/drivers/bluetooth/btmtkuart.c
+++ b/drivers/bluetooth/btmtkuart.c
@@ -383,8 +383,8 @@ static void btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count)
}
}
-static int btmtkuart_receive_buf(struct serdev_device *serdev, const u8 *data,
- size_t count)
+static ssize_t btmtkuart_receive_buf(struct serdev_device *serdev,
+ const u8 *data, size_t count)
{
struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev);
diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
index b7c56be078f8..1d592ac413d1 100644
--- a/drivers/bluetooth/btnxpuart.c
+++ b/drivers/bluetooth/btnxpuart.c
@@ -1264,8 +1264,8 @@ static const struct h4_recv_pkt nxp_recv_pkts[] = {
{ NXP_RECV_FW_REQ_V3, .recv = nxp_recv_fw_req_v3 },
};
-static int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data,
- size_t count)
+static ssize_t btnxpuart_receive_buf(struct serdev_device *serdev,
+ const u8 *data, size_t count)
{
struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev);
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 7835170b1d66..d31edad7a056 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -4796,10 +4796,8 @@ static struct usb_driver btusb_driver = {
.disable_hub_initiated_lpm = 1,
#ifdef CONFIG_DEV_COREDUMP
- .drvwrap = {
- .driver = {
- .coredump = btusb_coredump,
- },
+ .driver = {
+ .coredump = btusb_coredump,
},
#endif
};
diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c
index f16fd79bc02b..39c8b567da3c 100644
--- a/drivers/bluetooth/hci_serdev.c
+++ b/drivers/bluetooth/hci_serdev.c
@@ -271,8 +271,8 @@ static void hci_uart_write_wakeup(struct serdev_device *serdev)
*
* Return: number of processed bytes
*/
-static int hci_uart_receive_buf(struct serdev_device *serdev, const u8 *data,
- size_t count)
+static ssize_t hci_uart_receive_buf(struct serdev_device *serdev,
+ const u8 *data, size_t count)
{
struct hci_uart *hu = serdev_device_get_drvdata(serdev);
diff --git a/drivers/bus/mhi/ep/internal.h b/drivers/bus/mhi/ep/internal.h
index a2125fa5fe2f..577965f95fda 100644
--- a/drivers/bus/mhi/ep/internal.h
+++ b/drivers/bus/mhi/ep/internal.h
@@ -126,6 +126,7 @@ struct mhi_ep_ring {
union mhi_ep_ring_ctx *ring_ctx;
struct mhi_ring_element *ring_cache;
enum mhi_ep_ring_type type;
+ struct delayed_work intmodt_work;
u64 rbase;
size_t rd_offset;
size_t wr_offset;
@@ -135,7 +136,9 @@ struct mhi_ep_ring {
u32 ch_id;
u32 er_index;
u32 irq_vector;
+ u32 intmodt;
bool started;
+ bool irq_pending;
};
struct mhi_ep_cmd {
@@ -159,6 +162,7 @@ struct mhi_ep_chan {
void (*xfer_cb)(struct mhi_ep_device *mhi_dev, struct mhi_result *result);
enum mhi_ch_state state;
enum dma_data_direction dir;
+ size_t rd_offset;
u64 tre_loc;
u32 tre_size;
u32 tre_bytes_left;
diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c
index 600881808982..65fc1d738bec 100644
--- a/drivers/bus/mhi/ep/main.c
+++ b/drivers/bus/mhi/ep/main.c
@@ -54,11 +54,27 @@ static int mhi_ep_send_event(struct mhi_ep_cntrl *mhi_cntrl, u32 ring_idx,
mutex_unlock(&mhi_cntrl->event_lock);
/*
- * Raise IRQ to host only if the BEI flag is not set in TRE. Host might
- * set this flag for interrupt moderation as per MHI protocol.
+ * As per the MHI specification, section 4.3, Interrupt moderation:
+ *
+ * 1. If BEI flag is not set, cancel any pending intmodt work if started
+ * for the event ring and raise IRQ immediately.
+ *
+ * 2. If both BEI and intmodt are set, and if no IRQ is pending for the
+ * same event ring, start the IRQ delayed work as per the value of
+ * intmodt. If previous IRQ is pending, then do nothing as the pending
+ * IRQ is enough for the host to process the current event ring element.
+ *
+ * 3. If BEI is set and intmodt is not set, no need to raise IRQ.
*/
- if (!bei)
+ if (!bei) {
+ if (READ_ONCE(ring->irq_pending))
+ cancel_delayed_work(&ring->intmodt_work);
+
mhi_cntrl->raise_irq(mhi_cntrl, ring->irq_vector);
+ } else if (ring->intmodt && !READ_ONCE(ring->irq_pending)) {
+ WRITE_ONCE(ring->irq_pending, true);
+ schedule_delayed_work(&ring->intmodt_work, msecs_to_jiffies(ring->intmodt));
+ }
return 0;
@@ -71,45 +87,77 @@ err_unlock:
static int mhi_ep_send_completion_event(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring,
struct mhi_ring_element *tre, u32 len, enum mhi_ev_ccs code)
{
- struct mhi_ring_element event = {};
+ struct mhi_ring_element *event;
+ int ret;
+
+ event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA);
+ if (!event)
+ return -ENOMEM;
- event.ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(*tre));
- event.dword[0] = MHI_TRE_EV_DWORD0(code, len);
- event.dword[1] = MHI_TRE_EV_DWORD1(ring->ch_id, MHI_PKT_TYPE_TX_EVENT);
+ event->ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(*tre));
+ event->dword[0] = MHI_TRE_EV_DWORD0(code, len);
+ event->dword[1] = MHI_TRE_EV_DWORD1(ring->ch_id, MHI_PKT_TYPE_TX_EVENT);
- return mhi_ep_send_event(mhi_cntrl, ring->er_index, &event, MHI_TRE_DATA_GET_BEI(tre));
+ ret = mhi_ep_send_event(mhi_cntrl, ring->er_index, event, MHI_TRE_DATA_GET_BEI(tre));
+ kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event);
+
+ return ret;
}
int mhi_ep_send_state_change_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state state)
{
- struct mhi_ring_element event = {};
+ struct mhi_ring_element *event;
+ int ret;
- event.dword[0] = MHI_SC_EV_DWORD0(state);
- event.dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_STATE_CHANGE_EVENT);
+ event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA);
+ if (!event)
+ return -ENOMEM;
- return mhi_ep_send_event(mhi_cntrl, 0, &event, 0);
+ event->dword[0] = MHI_SC_EV_DWORD0(state);
+ event->dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_STATE_CHANGE_EVENT);
+
+ ret = mhi_ep_send_event(mhi_cntrl, 0, event, 0);
+ kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event);
+
+ return ret;
}
int mhi_ep_send_ee_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_ee_type exec_env)
{
- struct mhi_ring_element event = {};
+ struct mhi_ring_element *event;
+ int ret;
- event.dword[0] = MHI_EE_EV_DWORD0(exec_env);
- event.dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_EE_EVENT);
+ event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA);
+ if (!event)
+ return -ENOMEM;
+
+ event->dword[0] = MHI_EE_EV_DWORD0(exec_env);
+ event->dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_EE_EVENT);
- return mhi_ep_send_event(mhi_cntrl, 0, &event, 0);
+ ret = mhi_ep_send_event(mhi_cntrl, 0, event, 0);
+ kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event);
+
+ return ret;
}
static int mhi_ep_send_cmd_comp_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_ev_ccs code)
{
struct mhi_ep_ring *ring = &mhi_cntrl->mhi_cmd->ring;
- struct mhi_ring_element event = {};
+ struct mhi_ring_element *event;
+ int ret;
+
+ event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA);
+ if (!event)
+ return -ENOMEM;
+
+ event->ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(struct mhi_ring_element));
+ event->dword[0] = MHI_CC_EV_DWORD0(code);
+ event->dword[1] = MHI_CC_EV_DWORD1(MHI_PKT_TYPE_CMD_COMPLETION_EVENT);
- event.ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(struct mhi_ring_element));
- event.dword[0] = MHI_CC_EV_DWORD0(code);
- event.dword[1] = MHI_CC_EV_DWORD1(MHI_PKT_TYPE_CMD_COMPLETION_EVENT);
+ ret = mhi_ep_send_event(mhi_cntrl, 0, event, 0);
+ kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event);
- return mhi_ep_send_event(mhi_cntrl, 0, &event, 0);
+ return ret;
}
static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_element *el)
@@ -151,6 +199,8 @@ static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_ele
goto err_unlock;
}
+
+ mhi_chan->rd_offset = ch_ring->rd_offset;
}
/* Set channel state to RUNNING */
@@ -280,22 +330,85 @@ bool mhi_ep_queue_is_empty(struct mhi_ep_device *mhi_dev, enum dma_data_directio
struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl;
struct mhi_ep_ring *ring = &mhi_cntrl->mhi_chan[mhi_chan->chan].ring;
- return !!(ring->rd_offset == ring->wr_offset);
+ return !!(mhi_chan->rd_offset == ring->wr_offset);
}
EXPORT_SYMBOL_GPL(mhi_ep_queue_is_empty);
+static void mhi_ep_read_completion(struct mhi_ep_buf_info *buf_info)
+{
+ struct mhi_ep_device *mhi_dev = buf_info->mhi_dev;
+ struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl;
+ struct mhi_ep_chan *mhi_chan = mhi_dev->ul_chan;
+ struct mhi_ep_ring *ring = &mhi_cntrl->mhi_chan[mhi_chan->chan].ring;
+ struct mhi_ring_element *el = &ring->ring_cache[ring->rd_offset];
+ struct mhi_result result = {};
+ int ret;
+
+ if (mhi_chan->xfer_cb) {
+ result.buf_addr = buf_info->cb_buf;
+ result.dir = mhi_chan->dir;
+ result.bytes_xferd = buf_info->size;
+
+ mhi_chan->xfer_cb(mhi_dev, &result);
+ }
+
+ /*
+ * The host will split the data packet into multiple TREs if it can't fit
+ * the packet in a single TRE. In that case, CHAIN flag will be set by the
+ * host for all TREs except the last one.
+ */
+ if (buf_info->code != MHI_EV_CC_OVERFLOW) {
+ if (MHI_TRE_DATA_GET_CHAIN(el)) {
+ /*
+ * IEOB (Interrupt on End of Block) flag will be set by the host if
+ * it expects the completion event for all TREs of a TD.
+ */
+ if (MHI_TRE_DATA_GET_IEOB(el)) {
+ ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el,
+ MHI_TRE_DATA_GET_LEN(el),
+ MHI_EV_CC_EOB);
+ if (ret < 0) {
+ dev_err(&mhi_chan->mhi_dev->dev,
+ "Error sending transfer compl. event\n");
+ goto err_free_tre_buf;
+ }
+ }
+ } else {
+ /*
+ * IEOT (Interrupt on End of Transfer) flag will be set by the host
+ * for the last TRE of the TD and expects the completion event for
+ * the same.
+ */
+ if (MHI_TRE_DATA_GET_IEOT(el)) {
+ ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el,
+ MHI_TRE_DATA_GET_LEN(el),
+ MHI_EV_CC_EOT);
+ if (ret < 0) {
+ dev_err(&mhi_chan->mhi_dev->dev,
+ "Error sending transfer compl. event\n");
+ goto err_free_tre_buf;
+ }
+ }
+ }
+ }
+
+ mhi_ep_ring_inc_index(ring);
+
+err_free_tre_buf:
+ kmem_cache_free(mhi_cntrl->tre_buf_cache, buf_info->cb_buf);
+}
+
static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
- struct mhi_ep_ring *ring,
- struct mhi_result *result,
- u32 len)
+ struct mhi_ep_ring *ring)
{
struct mhi_ep_chan *mhi_chan = &mhi_cntrl->mhi_chan[ring->ch_id];
struct device *dev = &mhi_cntrl->mhi_dev->dev;
size_t tr_len, read_offset, write_offset;
+ struct mhi_ep_buf_info buf_info = {};
+ u32 len = MHI_EP_DEFAULT_MTU;
struct mhi_ring_element *el;
bool tr_done = false;
- void *write_addr;
- u64 read_addr;
+ void *buf_addr;
u32 buf_left;
int ret;
@@ -308,7 +421,7 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
return -ENODEV;
}
- el = &ring->ring_cache[ring->rd_offset];
+ el = &ring->ring_cache[mhi_chan->rd_offset];
/* Check if there is data pending to be read from previous read operation */
if (mhi_chan->tre_bytes_left) {
@@ -324,81 +437,51 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl,
read_offset = mhi_chan->tre_size - mhi_chan->tre_bytes_left;
write_offset = len - buf_left;
- read_addr = mhi_chan->tre_loc + read_offset;
- write_addr = result->buf_addr + write_offset;
+
+ buf_addr = kmem_cache_zalloc(mhi_cntrl->tre_buf_cache, GFP_KERNEL | GFP_DMA);
+ if (!buf_addr)
+ return -ENOMEM;
+
+ buf_info.host_addr = mhi_chan->tre_loc + read_offset;
+ buf_info.dev_addr = buf_addr + write_offset;
+ buf_info.size = tr_len;
+ buf_info.cb = mhi_ep_read_completion;
+ buf_info.cb_buf = buf_addr;
+ buf_info.mhi_dev = mhi_chan->mhi_dev;
+
+ if (mhi_chan->tre_bytes_left - tr_len)
+ buf_info.code = MHI_EV_CC_OVERFLOW;
dev_dbg(dev, "Reading %zd bytes from channel (%u)\n", tr_len, ring->ch_id);
- ret = mhi_cntrl->read_from_host(mhi_cntrl, read_addr, write_addr, tr_len);
+ ret = mhi_cntrl->read_async(mhi_cntrl, &buf_info);
if (ret < 0) {
dev_err(&mhi_chan->mhi_dev->dev, "Error reading from channel\n");
- return ret;
+ goto err_free_buf_addr;
}
buf_left -= tr_len;
mhi_chan->tre_bytes_left -= tr_len;
- /*
- * Once the TRE (Transfer Ring Element) of a TD (Transfer Descriptor) has been
- * read completely:
- *
- * 1. Send completion event to the host based on the flags set in TRE.
- * 2. Increment the local read offset of the transfer ring.
- */
if (!mhi_chan->tre_bytes_left) {
- /*
- * The host will split the data packet into multiple TREs if it can't fit
- * the packet in a single TRE. In that case, CHAIN flag will be set by the
- * host for all TREs except the last one.
- */
- if (MHI_TRE_DATA_GET_CHAIN(el)) {
- /*
- * IEOB (Interrupt on End of Block) flag will be set by the host if
- * it expects the completion event for all TREs of a TD.
- */
- if (MHI_TRE_DATA_GET_IEOB(el)) {
- ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el,
- MHI_TRE_DATA_GET_LEN(el),
- MHI_EV_CC_EOB);
- if (ret < 0) {
- dev_err(&mhi_chan->mhi_dev->dev,
- "Error sending transfer compl. event\n");
- return ret;
- }
- }
- } else {
- /*
- * IEOT (Interrupt on End of Transfer) flag will be set by the host
- * for the last TRE of the TD and expects the completion event for
- * the same.
- */
- if (MHI_TRE_DATA_GET_IEOT(el)) {
- ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el,
- MHI_TRE_DATA_GET_LEN(el),
- MHI_EV_CC_EOT);
- if (ret < 0) {
- dev_err(&mhi_chan->mhi_dev->dev,
- "Error sending transfer compl. event\n");
- return ret;
- }
- }
-
+ if (MHI_TRE_DATA_GET_IEOT(el))
tr_done = true;
- }
- mhi_ep_ring_inc_index(ring);
+ mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size;
}
-
- result->bytes_xferd += tr_len;
} while (buf_left && !tr_done);
return 0;
+
+err_free_buf_addr:
+ kmem_cache_free(mhi_cntrl->tre_buf_cache, buf_addr);
+
+ return ret;
}
-static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring, struct mhi_ring_element *el)
+static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring)
{
struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
struct mhi_result result = {};
- u32 len = MHI_EP_DEFAULT_MTU;
struct mhi_ep_chan *mhi_chan;
int ret;
@@ -419,44 +502,59 @@ static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring, struct mhi_ring_elem
mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
} else {
/* UL channel */
- result.buf_addr = kzalloc(len, GFP_KERNEL);
- if (!result.buf_addr)
- return -ENOMEM;
-
do {
- ret = mhi_ep_read_channel(mhi_cntrl, ring, &result, len);
+ ret = mhi_ep_read_channel(mhi_cntrl, ring);
if (ret < 0) {
dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n");
- kfree(result.buf_addr);
return ret;
}
- result.dir = mhi_chan->dir;
- mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
- result.bytes_xferd = 0;
- memset(result.buf_addr, 0, len);
-
/* Read until the ring becomes empty */
} while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE));
-
- kfree(result.buf_addr);
}
return 0;
}
+static void mhi_ep_skb_completion(struct mhi_ep_buf_info *buf_info)
+{
+ struct mhi_ep_device *mhi_dev = buf_info->mhi_dev;
+ struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl;
+ struct mhi_ep_chan *mhi_chan = mhi_dev->dl_chan;
+ struct mhi_ep_ring *ring = &mhi_cntrl->mhi_chan[mhi_chan->chan].ring;
+ struct mhi_ring_element *el = &ring->ring_cache[ring->rd_offset];
+ struct device *dev = &mhi_dev->dev;
+ struct mhi_result result = {};
+ int ret;
+
+ if (mhi_chan->xfer_cb) {
+ result.buf_addr = buf_info->cb_buf;
+ result.dir = mhi_chan->dir;
+ result.bytes_xferd = buf_info->size;
+
+ mhi_chan->xfer_cb(mhi_dev, &result);
+ }
+
+ ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, buf_info->size,
+ buf_info->code);
+ if (ret) {
+ dev_err(dev, "Error sending transfer completion event\n");
+ return;
+ }
+
+ mhi_ep_ring_inc_index(ring);
+}
+
/* TODO: Handle partially formed TDs */
int mhi_ep_queue_skb(struct mhi_ep_device *mhi_dev, struct sk_buff *skb)
{
struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl;
struct mhi_ep_chan *mhi_chan = mhi_dev->dl_chan;
struct device *dev = &mhi_chan->mhi_dev->dev;
+ struct mhi_ep_buf_info buf_info = {};
struct mhi_ring_element *el;
u32 buf_left, read_offset;
struct mhi_ep_ring *ring;
- enum mhi_ev_ccs code;
- void *read_addr;
- u64 write_addr;
size_t tr_len;
u32 tre_len;
int ret;
@@ -480,40 +578,44 @@ int mhi_ep_queue_skb(struct mhi_ep_device *mhi_dev, struct sk_buff *skb)
goto err_exit;
}
- el = &ring->ring_cache[ring->rd_offset];
+ el = &ring->ring_cache[mhi_chan->rd_offset];
tre_len = MHI_TRE_DATA_GET_LEN(el);
tr_len = min(buf_left, tre_len);
read_offset = skb->len - buf_left;
- read_addr = skb->data + read_offset;
- write_addr = MHI_TRE_DATA_GET_PTR(el);
- dev_dbg(dev, "Writing %zd bytes to channel (%u)\n", tr_len, ring->ch_id);
- ret = mhi_cntrl->write_to_host(mhi_cntrl, read_addr, write_addr, tr_len);
- if (ret < 0) {
- dev_err(dev, "Error writing to the channel\n");
- goto err_exit;
- }
+ buf_info.dev_addr = skb->data + read_offset;
+ buf_info.host_addr = MHI_TRE_DATA_GET_PTR(el);
+ buf_info.size = tr_len;
+ buf_info.cb = mhi_ep_skb_completion;
+ buf_info.cb_buf = skb;
+ buf_info.mhi_dev = mhi_dev;
- buf_left -= tr_len;
/*
* For all TREs queued by the host for DL channel, only the EOT flag will be set.
* If the packet doesn't fit into a single TRE, send the OVERFLOW event to
* the host so that the host can adjust the packet boundary to next TREs. Else send
* the EOT event to the host indicating the packet boundary.
*/
- if (buf_left)
- code = MHI_EV_CC_OVERFLOW;
+ if (buf_left - tr_len)
+ buf_info.code = MHI_EV_CC_OVERFLOW;
else
- code = MHI_EV_CC_EOT;
+ buf_info.code = MHI_EV_CC_EOT;
- ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, tr_len, code);
- if (ret) {
- dev_err(dev, "Error sending transfer completion event\n");
+ dev_dbg(dev, "Writing %zd bytes to channel (%u)\n", tr_len, ring->ch_id);
+ ret = mhi_cntrl->write_async(mhi_cntrl, &buf_info);
+ if (ret < 0) {
+ dev_err(dev, "Error writing to the channel\n");
goto err_exit;
}
- mhi_ep_ring_inc_index(ring);
+ buf_left -= tr_len;
+
+ /*
+ * Update the read offset cached in mhi_chan. Actual read offset
+ * will be updated by the completion handler.
+ */
+ mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size;
} while (buf_left);
mutex_unlock(&mhi_chan->lock);
@@ -714,7 +816,6 @@ static void mhi_ep_ch_ring_worker(struct work_struct *work)
struct mhi_ep_cntrl *mhi_cntrl = container_of(work, struct mhi_ep_cntrl, ch_ring_work);
struct device *dev = &mhi_cntrl->mhi_dev->dev;
struct mhi_ep_ring_item *itr, *tmp;
- struct mhi_ring_element *el;
struct mhi_ep_ring *ring;
struct mhi_ep_chan *chan;
unsigned long flags;
@@ -748,31 +849,29 @@ static void mhi_ep_ch_ring_worker(struct work_struct *work)
if (ret) {
dev_err(dev, "Error updating write offset for ring\n");
mutex_unlock(&chan->lock);
- kfree(itr);
+ kmem_cache_free(mhi_cntrl->ring_item_cache, itr);
continue;
}
/* Sanity check to make sure there are elements in the ring */
- if (ring->rd_offset == ring->wr_offset) {
+ if (chan->rd_offset == ring->wr_offset) {
mutex_unlock(&chan->lock);
- kfree(itr);
+ kmem_cache_free(mhi_cntrl->ring_item_cache, itr);
continue;
}
- el = &ring->ring_cache[ring->rd_offset];
-
dev_dbg(dev, "Processing the ring for channel (%u)\n", ring->ch_id);
- ret = mhi_ep_process_ch_ring(ring, el);
+ ret = mhi_ep_process_ch_ring(ring);
if (ret) {
dev_err(dev, "Error processing ring for channel (%u): %d\n",
ring->ch_id, ret);
mutex_unlock(&chan->lock);
- kfree(itr);
+ kmem_cache_free(mhi_cntrl->ring_item_cache, itr);
continue;
}
mutex_unlock(&chan->lock);
- kfree(itr);
+ kmem_cache_free(mhi_cntrl->ring_item_cache, itr);
}
}
@@ -828,7 +927,7 @@ static void mhi_ep_queue_channel_db(struct mhi_ep_cntrl *mhi_cntrl, unsigned lon
u32 ch_id = ch_idx + i;
ring = &mhi_cntrl->mhi_chan[ch_id].ring;
- item = kzalloc(sizeof(*item), GFP_ATOMIC);
+ item = kmem_cache_zalloc(mhi_cntrl->ring_item_cache, GFP_ATOMIC);
if (!item)
return;
@@ -1365,6 +1464,10 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl,
if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->mmio || !mhi_cntrl->irq)
return -EINVAL;
+ if (!mhi_cntrl->read_sync || !mhi_cntrl->write_sync ||
+ !mhi_cntrl->read_async || !mhi_cntrl->write_async)
+ return -EINVAL;
+
ret = mhi_ep_chan_init(mhi_cntrl, config);
if (ret)
return ret;
@@ -1375,6 +1478,29 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl,
goto err_free_ch;
}
+ mhi_cntrl->ev_ring_el_cache = kmem_cache_create("mhi_ep_event_ring_el",
+ sizeof(struct mhi_ring_element), 0,
+ SLAB_CACHE_DMA, NULL);
+ if (!mhi_cntrl->ev_ring_el_cache) {
+ ret = -ENOMEM;
+ goto err_free_cmd;
+ }
+
+ mhi_cntrl->tre_buf_cache = kmem_cache_create("mhi_ep_tre_buf", MHI_EP_DEFAULT_MTU, 0,
+ SLAB_CACHE_DMA, NULL);
+ if (!mhi_cntrl->tre_buf_cache) {
+ ret = -ENOMEM;
+ goto err_destroy_ev_ring_el_cache;
+ }
+
+ mhi_cntrl->ring_item_cache = kmem_cache_create("mhi_ep_ring_item",
+ sizeof(struct mhi_ep_ring_item), 0,
+ 0, NULL);
+ if (!mhi_cntrl->ev_ring_el_cache) {
+ ret = -ENOMEM;
+ goto err_destroy_tre_buf_cache;
+ }
+
INIT_WORK(&mhi_cntrl->state_work, mhi_ep_state_worker);
INIT_WORK(&mhi_cntrl->reset_work, mhi_ep_reset_worker);
INIT_WORK(&mhi_cntrl->cmd_ring_work, mhi_ep_cmd_ring_worker);
@@ -1383,7 +1509,7 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl,
mhi_cntrl->wq = alloc_workqueue("mhi_ep_wq", 0, 0);
if (!mhi_cntrl->wq) {
ret = -ENOMEM;
- goto err_free_cmd;
+ goto err_destroy_ring_item_cache;
}
INIT_LIST_HEAD(&mhi_cntrl->st_transition_list);
@@ -1442,6 +1568,12 @@ err_ida_free:
ida_free(&mhi_ep_cntrl_ida, mhi_cntrl->index);
err_destroy_wq:
destroy_workqueue(mhi_cntrl->wq);
+err_destroy_ring_item_cache:
+ kmem_cache_destroy(mhi_cntrl->ring_item_cache);
+err_destroy_ev_ring_el_cache:
+ kmem_cache_destroy(mhi_cntrl->ev_ring_el_cache);
+err_destroy_tre_buf_cache:
+ kmem_cache_destroy(mhi_cntrl->tre_buf_cache);
err_free_cmd:
kfree(mhi_cntrl->mhi_cmd);
err_free_ch:
@@ -1463,6 +1595,9 @@ void mhi_ep_unregister_controller(struct mhi_ep_cntrl *mhi_cntrl)
free_irq(mhi_cntrl->irq, mhi_cntrl);
+ kmem_cache_destroy(mhi_cntrl->tre_buf_cache);
+ kmem_cache_destroy(mhi_cntrl->ev_ring_el_cache);
+ kmem_cache_destroy(mhi_cntrl->ring_item_cache);
kfree(mhi_cntrl->mhi_cmd);
kfree(mhi_cntrl->mhi_chan);
diff --git a/drivers/bus/mhi/ep/ring.c b/drivers/bus/mhi/ep/ring.c
index 115518ec76a4..aeb53b2c34a8 100644
--- a/drivers/bus/mhi/ep/ring.c
+++ b/drivers/bus/mhi/ep/ring.c
@@ -30,7 +30,8 @@ static int __mhi_ep_cache_ring(struct mhi_ep_ring *ring, size_t end)
{
struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
- size_t start, copy_size;
+ struct mhi_ep_buf_info buf_info = {};
+ size_t start;
int ret;
/* Don't proceed in the case of event ring. This happens during mhi_ep_ring_start(). */
@@ -43,30 +44,34 @@ static int __mhi_ep_cache_ring(struct mhi_ep_ring *ring, size_t end)
start = ring->wr_offset;
if (start < end) {
- copy_size = (end - start) * sizeof(struct mhi_ring_element);
- ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase +
- (start * sizeof(struct mhi_ring_element)),
- &ring->ring_cache[start], copy_size);
+ buf_info.size = (end - start) * sizeof(struct mhi_ring_element);
+ buf_info.host_addr = ring->rbase + (start * sizeof(struct mhi_ring_element));
+ buf_info.dev_addr = &ring->ring_cache[start];
+
+ ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info);
if (ret < 0)
return ret;
} else {
- copy_size = (ring->ring_size - start) * sizeof(struct mhi_ring_element);
- ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase +
- (start * sizeof(struct mhi_ring_element)),
- &ring->ring_cache[start], copy_size);
+ buf_info.size = (ring->ring_size - start) * sizeof(struct mhi_ring_element);
+ buf_info.host_addr = ring->rbase + (start * sizeof(struct mhi_ring_element));
+ buf_info.dev_addr = &ring->ring_cache[start];
+
+ ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info);
if (ret < 0)
return ret;
if (end) {
- ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase,
- &ring->ring_cache[0],
- end * sizeof(struct mhi_ring_element));
+ buf_info.host_addr = ring->rbase;
+ buf_info.dev_addr = &ring->ring_cache[0];
+ buf_info.size = end * sizeof(struct mhi_ring_element);
+
+ ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info);
if (ret < 0)
return ret;
}
}
- dev_dbg(dev, "Cached ring: start %zu end %zu size %zu\n", start, end, copy_size);
+ dev_dbg(dev, "Cached ring: start %zu end %zu size %zu\n", start, end, buf_info.size);
return 0;
}
@@ -102,6 +107,7 @@ int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *e
{
struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
+ struct mhi_ep_buf_info buf_info = {};
size_t old_offset = 0;
u32 num_free_elem;
__le64 rp;
@@ -133,12 +139,11 @@ int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *e
rp = cpu_to_le64(ring->rd_offset * sizeof(*el) + ring->rbase);
memcpy_toio((void __iomem *) &ring->ring_ctx->generic.rp, &rp, sizeof(u64));
- ret = mhi_cntrl->write_to_host(mhi_cntrl, el, ring->rbase + (old_offset * sizeof(*el)),
- sizeof(*el));
- if (ret < 0)
- return ret;
+ buf_info.host_addr = ring->rbase + (old_offset * sizeof(*el));
+ buf_info.dev_addr = el;
+ buf_info.size = sizeof(*el);
- return 0;
+ return mhi_cntrl->write_sync(mhi_cntrl, &buf_info);
}
void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32 id)
@@ -157,6 +162,15 @@ void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32
}
}
+static void mhi_ep_raise_irq(struct work_struct *work)
+{
+ struct mhi_ep_ring *ring = container_of(work, struct mhi_ep_ring, intmodt_work.work);
+ struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl;
+
+ mhi_cntrl->raise_irq(mhi_cntrl, ring->irq_vector);
+ WRITE_ONCE(ring->irq_pending, false);
+}
+
int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring,
union mhi_ep_ring_ctx *ctx)
{
@@ -173,8 +187,13 @@ int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring,
if (ring->type == RING_TYPE_CH)
ring->er_index = le32_to_cpu(ring->ring_ctx->ch.erindex);
- if (ring->type == RING_TYPE_ER)
+ if (ring->type == RING_TYPE_ER) {
ring->irq_vector = le32_to_cpu(ring->ring_ctx->ev.msivec);
+ ring->intmodt = FIELD_GET(EV_CTX_INTMODT_MASK,
+ le32_to_cpu(ring->ring_ctx->ev.intmod));
+
+ INIT_DELAYED_WORK(&ring->intmodt_work, mhi_ep_raise_irq);
+ }
/* During ring init, both rp and wp are equal */
memcpy_fromio(&val, (void __iomem *) &ring->ring_ctx->generic.rp, sizeof(u64));
@@ -201,6 +220,9 @@ int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring,
void mhi_ep_ring_reset(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring)
{
+ if (ring->type == RING_TYPE_ER)
+ cancel_delayed_work_sync(&ring->intmodt_work);
+
ring->started = false;
kfree(ring->ring_cache);
ring->ring_cache = NULL;
diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c
index f78aefd2d7a3..65ceac1837f9 100644
--- a/drivers/bus/mhi/host/init.c
+++ b/drivers/bus/mhi/host/init.c
@@ -881,6 +881,7 @@ static int parse_config(struct mhi_controller *mhi_cntrl,
if (!mhi_cntrl->timeout_ms)
mhi_cntrl->timeout_ms = MHI_TIMEOUT_MS;
+ mhi_cntrl->ready_timeout_ms = config->ready_timeout_ms;
mhi_cntrl->bounce_buf = config->use_bounce_buf;
mhi_cntrl->buffer_len = config->buf_len;
if (!mhi_cntrl->buffer_len)
diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h
index 2e139e76de4c..30ac415a3000 100644
--- a/drivers/bus/mhi/host/internal.h
+++ b/drivers/bus/mhi/host/internal.h
@@ -321,7 +321,7 @@ int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl,
u32 *out);
int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl,
void __iomem *base, u32 offset, u32 mask,
- u32 val, u32 delayus);
+ u32 val, u32 delayus, u32 timeout_ms);
void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base,
u32 offset, u32 val);
int __must_check mhi_write_reg_field(struct mhi_controller *mhi_cntrl,
diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c
index dcf627b36e82..abb561db9ae1 100644
--- a/drivers/bus/mhi/host/main.c
+++ b/drivers/bus/mhi/host/main.c
@@ -40,10 +40,11 @@ int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl,
int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl,
void __iomem *base, u32 offset,
- u32 mask, u32 val, u32 delayus)
+ u32 mask, u32 val, u32 delayus,
+ u32 timeout_ms)
{
int ret;
- u32 out, retry = (mhi_cntrl->timeout_ms * 1000) / delayus;
+ u32 out, retry = (timeout_ms * 1000) / delayus;
while (retry--) {
ret = mhi_read_reg_field(mhi_cntrl, base, offset, mask, &out);
@@ -268,7 +269,8 @@ static void mhi_del_ring_element(struct mhi_controller *mhi_cntrl,
static bool is_valid_ring_ptr(struct mhi_ring *ring, dma_addr_t addr)
{
- return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len;
+ return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len &&
+ !(addr & (sizeof(struct mhi_ring_element) - 1));
}
int mhi_destroy_device(struct device *dev, void *data)
@@ -642,6 +644,8 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
mhi_del_ring_element(mhi_cntrl, tre_ring);
local_rp = tre_ring->rp;
+ read_unlock_bh(&mhi_chan->lock);
+
/* notify client */
mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result);
@@ -667,6 +671,8 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl,
kfree(buf_info->cb_buf);
}
}
+
+ read_lock_bh(&mhi_chan->lock);
}
break;
} /* CC_EOT */
@@ -1122,17 +1128,15 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info,
if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)))
return -EIO;
- read_lock_irqsave(&mhi_cntrl->pm_lock, flags);
-
ret = mhi_is_ring_full(mhi_cntrl, tre_ring);
- if (unlikely(ret)) {
- ret = -EAGAIN;
- goto exit_unlock;
- }
+ if (unlikely(ret))
+ return -EAGAIN;
ret = mhi_gen_tre(mhi_cntrl, mhi_chan, buf_info, mflags);
if (unlikely(ret))
- goto exit_unlock;
+ return ret;
+
+ read_lock_irqsave(&mhi_cntrl->pm_lock, flags);
/* Packet is queued, take a usage ref to exit M3 if necessary
* for host->device buffer, balanced put is done on buffer completion
@@ -1152,7 +1156,6 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info,
if (dir == DMA_FROM_DEVICE)
mhi_cntrl->runtime_put(mhi_cntrl);
-exit_unlock:
read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags);
return ret;
@@ -1204,6 +1207,9 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
int eot, eob, chain, bei;
int ret;
+ /* Protect accesses for reading and incrementing WP */
+ write_lock_bh(&mhi_chan->lock);
+
buf_ring = &mhi_chan->buf_ring;
tre_ring = &mhi_chan->tre_ring;
@@ -1221,8 +1227,10 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
if (!info->pre_mapped) {
ret = mhi_cntrl->map_single(mhi_cntrl, buf_info);
- if (ret)
+ if (ret) {
+ write_unlock_bh(&mhi_chan->lock);
return ret;
+ }
}
eob = !!(flags & MHI_EOB);
@@ -1239,6 +1247,8 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
mhi_add_ring_element(mhi_cntrl, tre_ring);
mhi_add_ring_element(mhi_cntrl, buf_ring);
+ write_unlock_bh(&mhi_chan->lock);
+
return 0;
}
diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c
index 08f3f039dbdd..cd6cd14b3d29 100644
--- a/drivers/bus/mhi/host/pci_generic.c
+++ b/drivers/bus/mhi/host/pci_generic.c
@@ -269,6 +269,16 @@ static struct mhi_event_config modem_qcom_v1_mhi_events[] = {
MHI_EVENT_CONFIG_HW_DATA(5, 2048, 101)
};
+static const struct mhi_controller_config modem_qcom_v2_mhiv_config = {
+ .max_channels = 128,
+ .timeout_ms = 8000,
+ .ready_timeout_ms = 50000,
+ .num_channels = ARRAY_SIZE(modem_qcom_v1_mhi_channels),
+ .ch_cfg = modem_qcom_v1_mhi_channels,
+ .num_events = ARRAY_SIZE(modem_qcom_v1_mhi_events),
+ .event_cfg = modem_qcom_v1_mhi_events,
+};
+
static const struct mhi_controller_config modem_qcom_v1_mhiv_config = {
.max_channels = 128,
.timeout_ms = 8000,
@@ -278,6 +288,16 @@ static const struct mhi_controller_config modem_qcom_v1_mhiv_config = {
.event_cfg = modem_qcom_v1_mhi_events,
};
+static const struct mhi_pci_dev_info mhi_qcom_sdx75_info = {
+ .name = "qcom-sdx75m",
+ .fw = "qcom/sdx75m/xbl.elf",
+ .edl = "qcom/sdx75m/edl.mbn",
+ .config = &modem_qcom_v2_mhiv_config,
+ .bar_num = MHI_PCI_DEFAULT_BAR_NUM,
+ .dma_data_width = 32,
+ .sideband_wake = false,
+};
+
static const struct mhi_pci_dev_info mhi_qcom_sdx65_info = {
.name = "qcom-sdx65m",
.fw = "qcom/sdx65m/xbl.elf",
@@ -600,6 +620,8 @@ static const struct pci_device_id mhi_pci_id_table[] = {
.driver_data = (kernel_ulong_t) &mhi_telit_fn990_info },
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308),
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info },
+ { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0309),
+ .driver_data = (kernel_ulong_t) &mhi_qcom_sdx75_info },
{ PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1001), /* EM120R-GL (sdx24) */
.driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info },
{ PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1002), /* EM160R-GL (sdx24) */
diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c
index 8a4362d75fc4..a2f2feef1476 100644
--- a/drivers/bus/mhi/host/pm.c
+++ b/drivers/bus/mhi/host/pm.c
@@ -163,6 +163,7 @@ int mhi_ready_state_transition(struct mhi_controller *mhi_cntrl)
enum mhi_pm_state cur_state;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
u32 interval_us = 25000; /* poll register field every 25 milliseconds */
+ u32 timeout_ms;
int ret, i;
/* Check if device entered error state */
@@ -173,14 +174,18 @@ int mhi_ready_state_transition(struct mhi_controller *mhi_cntrl)
/* Wait for RESET to be cleared and READY bit to be set by the device */
ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
- MHICTRL_RESET_MASK, 0, interval_us);
+ MHICTRL_RESET_MASK, 0, interval_us,
+ mhi_cntrl->timeout_ms);
if (ret) {
dev_err(dev, "Device failed to clear MHI Reset\n");
return ret;
}
+ timeout_ms = mhi_cntrl->ready_timeout_ms ?
+ mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms;
ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHISTATUS,
- MHISTATUS_READY_MASK, 1, interval_us);
+ MHISTATUS_READY_MASK, 1, interval_us,
+ timeout_ms);
if (ret) {
dev_err(dev, "Device failed to enter MHI Ready\n");
return ret;
@@ -479,7 +484,7 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
/* Wait for the reset bit to be cleared by the device */
ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
- MHICTRL_RESET_MASK, 0, 25000);
+ MHICTRL_RESET_MASK, 0, 25000, mhi_cntrl->timeout_ms);
if (ret)
dev_err(dev, "Device failed to clear MHI Reset\n");
@@ -492,8 +497,8 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
if (!MHI_IN_PBL(mhi_get_exec_env(mhi_cntrl))) {
/* wait for ready to be set */
ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs,
- MHISTATUS,
- MHISTATUS_READY_MASK, 1, 25000);
+ MHISTATUS, MHISTATUS_READY_MASK,
+ 1, 25000, mhi_cntrl->timeout_ms);
if (ret)
dev_err(dev, "Device failed to enter READY state\n");
}
@@ -1111,7 +1116,8 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl)
if (state == MHI_STATE_SYS_ERR) {
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET);
ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL,
- MHICTRL_RESET_MASK, 0, interval_us);
+ MHICTRL_RESET_MASK, 0, interval_us,
+ mhi_cntrl->timeout_ms);
if (ret) {
dev_info(dev, "Failed to reset MHI due to syserr state\n");
goto error_exit;
@@ -1202,14 +1208,18 @@ EXPORT_SYMBOL_GPL(mhi_power_down);
int mhi_sync_power_up(struct mhi_controller *mhi_cntrl)
{
int ret = mhi_async_power_up(mhi_cntrl);
+ u32 timeout_ms;
if (ret)
return ret;
+ /* Some devices need more time to set ready during power up */
+ timeout_ms = mhi_cntrl->ready_timeout_ms ?
+ mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms;
wait_event_timeout(mhi_cntrl->state_event,
MHI_IN_MISSION_MODE(mhi_cntrl->ee) ||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
- msecs_to_jiffies(mhi_cntrl->timeout_ms));
+ msecs_to_jiffies(timeout_ms));
ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -ETIMEDOUT;
if (ret)
diff --git a/drivers/bus/moxtet.c b/drivers/bus/moxtet.c
index e384fbc6c1d9..641c1a6adc8a 100644
--- a/drivers/bus/moxtet.c
+++ b/drivers/bus/moxtet.c
@@ -102,7 +102,7 @@ static int moxtet_match(struct device *dev, struct device_driver *drv)
return 0;
}
-static struct bus_type moxtet_bus_type = {
+static const struct bus_type moxtet_bus_type = {
.name = "moxtet",
.dev_groups = moxtet_dev_groups,
.match = moxtet_match,
diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c
index 4461c6c9313f..b74d76afccb6 100644
--- a/drivers/cdx/cdx.c
+++ b/drivers/cdx/cdx.c
@@ -57,13 +57,17 @@
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/idr.h>
#include <linux/cdx/cdx_bus.h>
#include <linux/iommu.h>
#include <linux/dma-map-ops.h>
+#include <linux/debugfs.h>
#include "cdx.h"
/* Default DMA mask for devices on a CDX bus */
@@ -74,9 +78,13 @@
static DEFINE_IDA(cdx_controller_ida);
/* Lock to protect controller ops */
static DEFINE_MUTEX(cdx_controller_lock);
+/* Debugfs dir for cdx bus */
+static struct dentry *cdx_debugfs_dir;
static char *compat_node_name = "xlnx,versal-net-cdx";
+static void cdx_destroy_res_attr(struct cdx_device *cdx_dev, int num);
+
/**
* cdx_dev_reset - Reset a CDX device
* @dev: CDX device
@@ -145,6 +153,8 @@ static int cdx_unregister_device(struct device *dev,
if (cdx_dev->enabled && cdx->ops->bus_disable)
cdx->ops->bus_disable(cdx, cdx_dev->bus_num);
} else {
+ cdx_destroy_res_attr(cdx_dev, MAX_CDX_DEV_RESOURCES);
+ debugfs_remove_recursive(cdx_dev->debugfs_dir);
kfree(cdx_dev->driver_override);
cdx_dev->driver_override = NULL;
}
@@ -548,6 +558,31 @@ static const struct attribute_group *cdx_dev_groups[] = {
NULL,
};
+static int cdx_debug_resource_show(struct seq_file *s, void *data)
+{
+ struct cdx_device *cdx_dev = s->private;
+ int i;
+
+ for (i = 0; i < MAX_CDX_DEV_RESOURCES; i++) {
+ struct resource *res = &cdx_dev->res[i];
+
+ seq_printf(s, "%pr\n", res);
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(cdx_debug_resource);
+
+static void cdx_device_debugfs_init(struct cdx_device *cdx_dev)
+{
+ cdx_dev->debugfs_dir = debugfs_create_dir(dev_name(&cdx_dev->dev), cdx_debugfs_dir);
+ if (IS_ERR(cdx_dev->debugfs_dir))
+ return;
+
+ debugfs_create_file("resource", 0444, cdx_dev->debugfs_dir, cdx_dev,
+ &cdx_debug_resource_fops);
+}
+
static ssize_t rescan_store(const struct bus_type *bus,
const char *buf, size_t count)
{
@@ -569,12 +604,12 @@ static ssize_t rescan_store(const struct bus_type *bus,
/* Rescan all the devices */
for_each_compatible_node(np, NULL, compat_node_name) {
- if (!np)
- return -EINVAL;
-
pd = of_find_device_by_node(np);
- if (!pd)
- return -EINVAL;
+ if (!pd) {
+ of_node_put(np);
+ count = -EINVAL;
+ goto unlock;
+ }
cdx = platform_get_drvdata(pd);
if (cdx && cdx->controller_registered && cdx->ops->scan)
@@ -583,6 +618,7 @@ static ssize_t rescan_store(const struct bus_type *bus,
put_device(&pd->dev);
}
+unlock:
mutex_unlock(&cdx_controller_lock);
return count;
@@ -640,11 +676,105 @@ static void cdx_device_release(struct device *dev)
kfree(cdx_dev);
}
+static const struct vm_operations_struct cdx_phys_vm_ops = {
+#ifdef CONFIG_HAVE_IOREMAP_PROT
+ .access = generic_access_phys,
+#endif
+};
+
+/**
+ * cdx_mmap_resource - map a CDX resource into user memory space
+ * @fp: File pointer. Not used in this function, but required where
+ * this API is registered as a callback.
+ * @kobj: kobject for mapping
+ * @attr: struct bin_attribute for the file being mapped
+ * @vma: struct vm_area_struct passed into the mmap
+ *
+ * Use the regular CDX mapping routines to map a CDX resource into userspace.
+ *
+ * Return: true on success, false otherwise.
+ */
+static int cdx_mmap_resource(struct file *fp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ struct vm_area_struct *vma)
+{
+ struct cdx_device *cdx_dev = to_cdx_device(kobj_to_dev(kobj));
+ int num = (unsigned long)attr->private;
+ struct resource *res;
+ unsigned long size;
+
+ res = &cdx_dev->res[num];
+ if (iomem_is_exclusive(res->start))
+ return -EINVAL;
+
+ /* Make sure the caller is mapping a valid resource for this device */
+ size = ((cdx_resource_len(cdx_dev, num) - 1) >> PAGE_SHIFT) + 1;
+ if (vma->vm_pgoff + vma_pages(vma) > size)
+ return -EINVAL;
+
+ /*
+ * Map memory region and vm->vm_pgoff is expected to be an
+ * offset within that region.
+ */
+ vma->vm_page_prot = pgprot_device(vma->vm_page_prot);
+ vma->vm_pgoff += (cdx_resource_start(cdx_dev, num) >> PAGE_SHIFT);
+ vma->vm_ops = &cdx_phys_vm_ops;
+ return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+}
+
+static void cdx_destroy_res_attr(struct cdx_device *cdx_dev, int num)
+{
+ int i;
+
+ /* removing the bin attributes */
+ for (i = 0; i < num; i++) {
+ struct bin_attribute *res_attr;
+
+ res_attr = cdx_dev->res_attr[i];
+ if (res_attr) {
+ sysfs_remove_bin_file(&cdx_dev->dev.kobj, res_attr);
+ kfree(res_attr);
+ }
+ }
+}
+
+#define CDX_RES_ATTR_NAME_LEN 10
+static int cdx_create_res_attr(struct cdx_device *cdx_dev, int num)
+{
+ struct bin_attribute *res_attr;
+ char *res_attr_name;
+ int ret;
+
+ res_attr = kzalloc(sizeof(*res_attr) + CDX_RES_ATTR_NAME_LEN, GFP_ATOMIC);
+ if (!res_attr)
+ return -ENOMEM;
+
+ res_attr_name = (char *)(res_attr + 1);
+
+ sysfs_bin_attr_init(res_attr);
+
+ cdx_dev->res_attr[num] = res_attr;
+ sprintf(res_attr_name, "resource%d", num);
+
+ res_attr->mmap = cdx_mmap_resource;
+ res_attr->attr.name = res_attr_name;
+ res_attr->attr.mode = 0600;
+ res_attr->size = cdx_resource_len(cdx_dev, num);
+ res_attr->private = (void *)(unsigned long)num;
+ ret = sysfs_create_bin_file(&cdx_dev->dev.kobj, res_attr);
+ if (ret)
+ kfree(res_attr);
+
+ return ret;
+}
+
int cdx_device_add(struct cdx_dev_params *dev_params)
{
struct cdx_controller *cdx = dev_params->cdx;
struct cdx_device *cdx_dev;
- int ret;
+ int ret, i;
cdx_dev = kzalloc(sizeof(*cdx_dev), GFP_KERNEL);
if (!cdx_dev)
@@ -687,7 +817,28 @@ int cdx_device_add(struct cdx_dev_params *dev_params)
goto fail;
}
+ /* Create resource<N> attributes */
+ for (i = 0; i < MAX_CDX_DEV_RESOURCES; i++) {
+ if (cdx_resource_flags(cdx_dev, i) & IORESOURCE_MEM) {
+ /* skip empty resources */
+ if (!cdx_resource_len(cdx_dev, i))
+ continue;
+
+ ret = cdx_create_res_attr(cdx_dev, i);
+ if (ret != 0) {
+ dev_err(&cdx_dev->dev,
+ "cdx device resource<%d> file creation failed: %d", i, ret);
+ goto resource_create_fail;
+ }
+ }
+ }
+
+ cdx_device_debugfs_init(cdx_dev);
+
return 0;
+resource_create_fail:
+ cdx_destroy_res_attr(cdx_dev, i);
+ device_del(&cdx_dev->dev);
fail:
/*
* Do not free cdx_dev here as it would be freed in
@@ -788,6 +939,12 @@ EXPORT_SYMBOL_NS_GPL(cdx_unregister_controller, CDX_BUS_CONTROLLER);
static int __init cdx_bus_init(void)
{
- return bus_register(&cdx_bus_type);
+ int ret;
+
+ ret = bus_register(&cdx_bus_type);
+ if (!ret)
+ cdx_debugfs_dir = debugfs_create_dir(cdx_bus_type.name, NULL);
+
+ return ret;
}
postcore_initcall(cdx_bus_init);
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 4c188e9e477c..ee951b265213 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -299,7 +299,7 @@ static int register_device(int minor, struct pp_struct *pp)
goto err;
}
- index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL);
+ index = ida_alloc(&ida_index, GFP_KERNEL);
memset(&ppdev_cb, 0, sizeof(ppdev_cb));
ppdev_cb.irq_func = pp_irq;
ppdev_cb.flags = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
@@ -310,7 +310,7 @@ static int register_device(int minor, struct pp_struct *pp)
if (!pdev) {
pr_warn("%s: failed to register device!\n", name);
rc = -ENXIO;
- ida_simple_remove(&ida_index, index);
+ ida_free(&ida_index, index);
goto err;
}
@@ -750,7 +750,7 @@ static int pp_release(struct inode *inode, struct file *file)
if (pp->pdev) {
parport_unregister_device(pp->pdev);
- ida_simple_remove(&ida_index, pp->index);
+ ida_free(&ida_index, pp->index);
pp->pdev = NULL;
pr_debug(CHRDEV "%x: unregistered pardevice\n", minor);
}
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index 5af804c17a75..4c806a189ee5 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -40,7 +40,7 @@ static struct ttyprintk_port tpk_port;
static int tpk_curr;
-static char tpk_buffer[TPK_STR_SIZE + 4];
+static u8 tpk_buffer[TPK_STR_SIZE + 4];
static void tpk_flush(void)
{
@@ -51,9 +51,9 @@ static void tpk_flush(void)
}
}
-static int tpk_printk(const u8 *buf, int count)
+static int tpk_printk(const u8 *buf, size_t count)
{
- int i;
+ size_t i;
for (i = 0; i < count; i++) {
if (tpk_curr >= TPK_STR_SIZE) {
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 431e9e5bf9c1..035f89f1a251 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -230,9 +230,6 @@ struct port {
bool guest_connected;
};
-/* This is the very early arch-specified put chars function. */
-static int (*early_put_chars)(u32, const char *, int);
-
static struct port *find_port_by_vtermno(u32 vtermno)
{
struct port *port;
@@ -653,7 +650,7 @@ done:
* Give out the data that's requested from the buffer that we have
* queued up.
*/
-static ssize_t fill_readbuf(struct port *port, char __user *out_buf,
+static ssize_t fill_readbuf(struct port *port, u8 __user *out_buf,
size_t out_count, bool to_user)
{
struct port_buffer *buf;
@@ -672,7 +669,7 @@ static ssize_t fill_readbuf(struct port *port, char __user *out_buf,
if (ret)
return -EFAULT;
} else {
- memcpy((__force char *)out_buf, buf->buf + buf->offset,
+ memcpy((__force u8 *)out_buf, buf->buf + buf->offset,
out_count);
}
@@ -1107,16 +1104,13 @@ static const struct file_operations port_fops = {
* it to finish: inefficient in theory, but in practice
* implementations will do it immediately.
*/
-static int put_chars(u32 vtermno, const char *buf, int count)
+static ssize_t put_chars(u32 vtermno, const u8 *buf, size_t count)
{
struct port *port;
struct scatterlist sg[1];
void *data;
int ret;
- if (unlikely(early_put_chars))
- return early_put_chars(vtermno, buf, count);
-
port = find_port_by_vtermno(vtermno);
if (!port)
return -EPIPE;
@@ -1138,14 +1132,10 @@ static int put_chars(u32 vtermno, const char *buf, int count)
* We call out to fill_readbuf that gets us the required data from the
* buffers that are queued up.
*/
-static int get_chars(u32 vtermno, char *buf, int count)
+static ssize_t get_chars(u32 vtermno, u8 *buf, size_t count)
{
struct port *port;
- /* If we've not set up the port yet, we have no input to give. */
- if (unlikely(early_put_chars))
- return 0;
-
port = find_port_by_vtermno(vtermno);
if (!port)
return -EPIPE;
@@ -1153,7 +1143,7 @@ static int get_chars(u32 vtermno, char *buf, int count)
/* If we don't have an input queue yet, we can't get input. */
BUG_ON(!port->in_vq);
- return fill_readbuf(port, (__force char __user *)buf, count, false);
+ return fill_readbuf(port, (__force u8 __user *)buf, count, false);
}
static void resize_console(struct port *port)
@@ -1201,21 +1191,6 @@ static const struct hv_ops hv_ops = {
.notifier_hangup = notifier_del_vio,
};
-/*
- * Console drivers are initialized very early so boot messages can go
- * out, so we do things slightly differently from the generic virtio
- * initialization of the net and block drivers.
- *
- * At this stage, the console is output-only. It's too early to set
- * up a virtqueue, so we let the drivers do some boutique early-output
- * thing.
- */
-int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
-{
- early_put_chars = put_chars;
- return hvc_instantiate(0, 0, &hv_ops);
-}
-
static int init_port_console(struct port *port)
{
int ret;
@@ -1256,13 +1231,6 @@ static int init_port_console(struct port *port)
spin_unlock_irq(&pdrvdata_lock);
port->guest_connected = true;
- /*
- * Start using the new console output if this is the first
- * console to come up.
- */
- if (early_put_chars)
- early_put_chars = NULL;
-
/* Notify host of port being opened */
send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
@@ -1999,7 +1967,6 @@ static int virtcons_probe(struct virtio_device *vdev)
struct ports_device *portdev;
int err;
bool multiport;
- bool early = early_put_chars != NULL;
/* We only need a config space if features are offered */
if (!vdev->config->get &&
@@ -2010,9 +1977,6 @@ static int virtcons_probe(struct virtio_device *vdev)
return -EINVAL;
}
- /* Ensure to read early_put_chars now */
- barrier();
-
portdev = kmalloc(sizeof(*portdev), GFP_KERNEL);
if (!portdev) {
err = -ENOMEM;
@@ -2100,18 +2064,6 @@ static int virtcons_probe(struct virtio_device *vdev)
__send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
VIRTIO_CONSOLE_DEVICE_READY, 1);
- /*
- * If there was an early virtio console, assume that there are no
- * other consoles. We need to wait until the hvc_alloc matches the
- * hvc_instantiate, otherwise tty_open will complain, resulting in
- * a "Warning: unable to open an initial console" boot failure.
- * Without multiport this is done in add_port above. With multiport
- * this might take some host<->guest communication - thus we have to
- * wait.
- */
- if (multiport && early)
- wait_for_completion(&early_console_added);
-
return 0;
free_chrdev:
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c30d0d396f7a..50af5fc7f570 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -414,16 +414,6 @@ config COMMON_CLK_VC7
Renesas Versaclock7 is a family of configurable clock generator
and jitter attenuator ICs with fractional and integer dividers.
-config COMMON_CLK_STM32MP135
- def_bool COMMON_CLK && MACH_STM32MP13
- help
- Support for stm32mp135 SoC family clocks
-
-config COMMON_CLK_STM32MP157
- def_bool COMMON_CLK && MACH_STM32MP157
- help
- Support for stm32mp157 SoC family clocks
-
config COMMON_CLK_STM32F
def_bool COMMON_CLK && (MACH_STM32F429 || MACH_STM32F469 || MACH_STM32F746)
help
@@ -504,6 +494,7 @@ source "drivers/clk/starfive/Kconfig"
source "drivers/clk/sunxi/Kconfig"
source "drivers/clk/sunxi-ng/Kconfig"
source "drivers/clk/tegra/Kconfig"
+source "drivers/clk/stm32/Kconfig"
source "drivers/clk/ti/Kconfig"
source "drivers/clk/uniphier/Kconfig"
source "drivers/clk/visconti/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index ed71f2e0ee36..14fa8d4ecc1f 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -70,7 +70,6 @@ obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
obj-$(CONFIG_COMMON_CLK_SP7021) += clk-sp7021.o
obj-$(CONFIG_COMMON_CLK_STM32F) += clk-stm32f4.o
obj-$(CONFIG_COMMON_CLK_STM32H7) += clk-stm32h7.o
-obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o
obj-$(CONFIG_COMMON_CLK_TPS68470) += clk-tps68470.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
obj-$(CONFIG_CLK_TWL) += clk-twl.o
diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c
index 380245f635d6..53e21ac302e6 100644
--- a/drivers/clk/clk-renesas-pcie.c
+++ b/drivers/clk/clk-renesas-pcie.c
@@ -7,6 +7,7 @@
* Currently supported:
* - 9FGV0241
* - 9FGV0441
+ * - 9FGV0841
*
* Copyright (C) 2022 Marek Vasut <[email protected]>
*/
@@ -42,6 +43,7 @@
#define RS9_REG_DID 0x6
#define RS9_REG_BCP 0x7
+#define RS9_REG_VID_MASK GENMASK(3, 0)
#define RS9_REG_VID_IDT 0x01
#define RS9_REG_DID_TYPE_FGV (0x0 << RS9_REG_DID_TYPE_SHIFT)
@@ -49,16 +51,10 @@
#define RS9_REG_DID_TYPE_DMV (0x2 << RS9_REG_DID_TYPE_SHIFT)
#define RS9_REG_DID_TYPE_SHIFT 0x6
-/* Supported Renesas 9-series models. */
-enum rs9_model {
- RENESAS_9FGV0241,
- RENESAS_9FGV0441,
-};
-
/* Structure to describe features of a particular 9-series model */
struct rs9_chip_info {
- const enum rs9_model model;
unsigned int num_clks;
+ u8 outshift;
u8 did;
};
@@ -160,14 +156,12 @@ static const struct regmap_config rs9_regmap_config = {
static u8 rs9_calc_dif(const struct rs9_driver_data *rs9, int idx)
{
- enum rs9_model model = rs9->chip_info->model;
-
- if (model == RENESAS_9FGV0241)
- return BIT(idx) + 1;
- else if (model == RENESAS_9FGV0441)
- return BIT(idx);
-
- return 0;
+ /*
+ * On 9FGV0241, the DIF OE0 is BIT(1) and DIF OE(1) is BIT(2),
+ * on 9FGV0441 and 9FGV0841 the DIF OE0 is BIT(0) and so on.
+ * Increment the index in the 9FGV0241 special case here.
+ */
+ return BIT(idx + rs9->chip_info->outshift);
}
static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx)
@@ -333,6 +327,7 @@ static int rs9_probe(struct i2c_client *client)
if (ret < 0)
return ret;
+ vid &= RS9_REG_VID_MASK;
if (vid != RS9_REG_VID_IDT || did != rs9->chip_info->did)
return dev_err_probe(&client->dev, -ENODEV,
"Incorrect VID/DID: %#02x, %#02x. Expected %#02x, %#02x\n",
@@ -380,20 +375,27 @@ static int __maybe_unused rs9_resume(struct device *dev)
}
static const struct rs9_chip_info renesas_9fgv0241_info = {
- .model = RENESAS_9FGV0241,
.num_clks = 2,
+ .outshift = 1,
.did = RS9_REG_DID_TYPE_FGV | 0x02,
};
static const struct rs9_chip_info renesas_9fgv0441_info = {
- .model = RENESAS_9FGV0441,
.num_clks = 4,
+ .outshift = 0,
.did = RS9_REG_DID_TYPE_FGV | 0x04,
};
+static const struct rs9_chip_info renesas_9fgv0841_info = {
+ .num_clks = 8,
+ .outshift = 0,
+ .did = RS9_REG_DID_TYPE_FGV | 0x08,
+};
+
static const struct i2c_device_id rs9_id[] = {
{ "9fgv0241", .driver_data = (kernel_ulong_t)&renesas_9fgv0241_info },
{ "9fgv0441", .driver_data = (kernel_ulong_t)&renesas_9fgv0441_info },
+ { "9fgv0841", .driver_data = (kernel_ulong_t)&renesas_9fgv0841_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, rs9_id);
@@ -401,6 +403,7 @@ MODULE_DEVICE_TABLE(i2c, rs9_id);
static const struct of_device_id clk_rs9_of_match[] = {
{ .compatible = "renesas,9fgv0241", .data = &renesas_9fgv0241_info },
{ .compatible = "renesas,9fgv0441", .data = &renesas_9fgv0441_info },
+ { .compatible = "renesas,9fgv0841", .data = &renesas_9fgv0841_info },
{ }
};
MODULE_DEVICE_TABLE(of, clk_rs9_of_match);
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index 845b451511d2..6e8dd7387cfd 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -895,10 +895,8 @@ static int si5341_output_clk_set_rate(struct clk_hw *hw, unsigned long rate,
r[0] = r_div ? (r_div & 0xff) : 1;
r[1] = (r_div >> 8) & 0xff;
r[2] = (r_div >> 16) & 0xff;
- err = regmap_bulk_write(output->data->regmap,
+ return regmap_bulk_write(output->data->regmap,
SI5341_OUT_R_REG(output), r, 3);
-
- return 0;
}
static int si5341_output_reparent(struct clk_si5341_output *output, u8 index)
diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
index a9a0bc448a4b..4ce83c5265b8 100644
--- a/drivers/clk/clk-si5351.c
+++ b/drivers/clk/clk-si5351.c
@@ -506,6 +506,8 @@ static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct si5351_hw_data *hwdata =
container_of(hw, struct si5351_hw_data, hw);
+ struct si5351_platform_data *pdata =
+ hwdata->drvdata->client->dev.platform_data;
u8 reg = (hwdata->num == 0) ? SI5351_PLLA_PARAMETERS :
SI5351_PLLB_PARAMETERS;
@@ -518,9 +520,10 @@ static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate,
(hwdata->params.p2 == 0) ? SI5351_CLK_INTEGER_MODE : 0);
/* Do a pll soft reset on the affected pll */
- si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET,
- hwdata->num == 0 ? SI5351_PLL_RESET_A :
- SI5351_PLL_RESET_B);
+ if (pdata->pll_reset[hwdata->num])
+ si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET,
+ hwdata->num == 0 ? SI5351_PLL_RESET_A :
+ SI5351_PLL_RESET_B);
dev_dbg(&hwdata->drvdata->client->dev,
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
@@ -1222,6 +1225,44 @@ static int si5351_dt_parse(struct i2c_client *client,
}
}
+ /*
+ * Parse PLL reset mode. For compatibility with older device trees, the
+ * default is to always reset a PLL after setting its rate.
+ */
+ pdata->pll_reset[0] = true;
+ pdata->pll_reset[1] = true;
+
+ of_property_for_each_u32(np, "silabs,pll-reset-mode", prop, p, num) {
+ if (num >= 2) {
+ dev_err(&client->dev,
+ "invalid pll %d on pll-reset-mode prop\n", num);
+ return -EINVAL;
+ }
+
+ p = of_prop_next_u32(prop, p, &val);
+ if (!p) {
+ dev_err(&client->dev,
+ "missing pll-reset-mode for pll %d\n", num);
+ return -EINVAL;
+ }
+
+ switch (val) {
+ case 0:
+ /* Reset PLL whenever its rate is adjusted */
+ pdata->pll_reset[num] = true;
+ break;
+ case 1:
+ /* Don't reset PLL whenever its rate is adjusted */
+ pdata->pll_reset[num] = false;
+ break;
+ default:
+ dev_err(&client->dev,
+ "invalid pll-reset-mode %d for pll %d\n", val,
+ num);
+ return -EINVAL;
+ }
+ }
+
/* per clkout properties */
for_each_child_of_node(np, child) {
if (of_property_read_u32(child, "reg", &num)) {
diff --git a/drivers/clk/clk-sp7021.c b/drivers/clk/clk-sp7021.c
index 01d3c4c7b0b2..7cb7d501d7a6 100644
--- a/drivers/clk/clk-sp7021.c
+++ b/drivers/clk/clk-sp7021.c
@@ -604,14 +604,14 @@ static int sp7021_clk_probe(struct platform_device *pdev)
int i;
clk_base = devm_platform_ioremap_resource(pdev, 0);
- if (!clk_base)
- return -ENXIO;
+ if (IS_ERR(clk_base))
+ return PTR_ERR(clk_base);
pll_base = devm_platform_ioremap_resource(pdev, 1);
- if (!pll_base)
- return -ENXIO;
+ if (IS_ERR(pll_base))
+ return PTR_ERR(pll_base);
sys_base = devm_platform_ioremap_resource(pdev, 2);
- if (!sys_base)
- return -ENXIO;
+ if (IS_ERR(sys_base))
+ return PTR_ERR(sys_base);
/* enable default clks */
for (i = 0; i < ARRAY_SIZE(sp_clken); i++)
diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c
index 00930d7bca77..76d7ea1964c3 100644
--- a/drivers/clk/clk-versaclock3.c
+++ b/drivers/clk/clk-versaclock3.c
@@ -37,7 +37,7 @@
#define VC3_PLL1_M_DIV(n) ((n) & GENMASK(5, 0))
#define VC3_PLL1_VCO_N_DIVIDER 0x9
-#define VC3_PLL1_LOOP_FILTER_N_DIV_MSB 0x0a
+#define VC3_PLL1_LOOP_FILTER_N_DIV_MSB 0xa
#define VC3_OUT_DIV1_DIV2_CTRL 0xf
@@ -148,16 +148,16 @@ struct vc3_pfd_data {
};
struct vc3_pll_data {
+ unsigned long vco_min;
+ unsigned long vco_max;
u8 num;
u8 int_div_msb_offs;
u8 int_div_lsb_offs;
- unsigned long vco_min;
- unsigned long vco_max;
};
struct vc3_div_data {
- u8 offs;
const struct clk_div_table *table;
+ u8 offs;
u8 shift;
u8 width;
u8 flags;
@@ -210,7 +210,7 @@ static const struct clk_div_table div3_divs[] = {
static struct clk_hw *clk_out[6];
-static unsigned char vc3_pfd_mux_get_parent(struct clk_hw *hw)
+static u8 vc3_pfd_mux_get_parent(struct clk_hw *hw)
{
struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
const struct vc3_clk_data *pfd_mux = vc3->data;
@@ -226,9 +226,8 @@ static int vc3_pfd_mux_set_parent(struct clk_hw *hw, u8 index)
struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
const struct vc3_clk_data *pfd_mux = vc3->data;
- regmap_update_bits(vc3->regmap, pfd_mux->offs, pfd_mux->bitmsk,
- index ? pfd_mux->bitmsk : 0);
- return 0;
+ return regmap_update_bits(vc3->regmap, pfd_mux->offs, pfd_mux->bitmsk,
+ index ? pfd_mux->bitmsk : 0);
}
static const struct clk_ops vc3_pfd_mux_ops = {
@@ -440,7 +439,7 @@ static const struct clk_ops vc3_pll_ops = {
.set_rate = vc3_pll_set_rate,
};
-static unsigned char vc3_div_mux_get_parent(struct clk_hw *hw)
+static u8 vc3_div_mux_get_parent(struct clk_hw *hw)
{
struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
const struct vc3_clk_data *div_mux = vc3->data;
@@ -456,10 +455,8 @@ static int vc3_div_mux_set_parent(struct clk_hw *hw, u8 index)
struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
const struct vc3_clk_data *div_mux = vc3->data;
- regmap_update_bits(vc3->regmap, div_mux->offs, div_mux->bitmsk,
- index ? div_mux->bitmsk : 0);
-
- return 0;
+ return regmap_update_bits(vc3->regmap, div_mux->offs, div_mux->bitmsk,
+ index ? div_mux->bitmsk : 0);
}
static const struct clk_ops vc3_div_mux_ops = {
@@ -477,7 +474,7 @@ static unsigned int vc3_get_div(const struct clk_div_table *table,
if (clkt->val == val)
return clkt->div;
- return 0;
+ return 1;
}
static unsigned long vc3_div_recalc_rate(struct clk_hw *hw,
@@ -524,10 +521,9 @@ static int vc3_div_set_rate(struct clk_hw *hw, unsigned long rate,
value = divider_get_val(rate, parent_rate, div_data->table,
div_data->width, div_data->flags);
- regmap_update_bits(vc3->regmap, div_data->offs,
- VC3_DIV_MASK(div_data->width) << div_data->shift,
- value << div_data->shift);
- return 0;
+ return regmap_update_bits(vc3->regmap, div_data->offs,
+ VC3_DIV_MASK(div_data->width) << div_data->shift,
+ value << div_data->shift);
}
static const struct clk_ops vc3_div_ops = {
@@ -539,11 +535,9 @@ static const struct clk_ops vc3_div_ops = {
static int vc3_clk_mux_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
- int ret;
int frc;
- ret = clk_mux_determine_rate_flags(hw, req, CLK_SET_RATE_PARENT);
- if (ret) {
+ if (clk_mux_determine_rate_flags(hw, req, CLK_SET_RATE_PARENT)) {
/* The below check is equivalent to (best_parent_rate/rate) */
if (req->best_parent_rate >= req->rate) {
frc = DIV_ROUND_CLOSEST_ULL(req->best_parent_rate,
@@ -552,13 +546,12 @@ static int vc3_clk_mux_determine_rate(struct clk_hw *hw,
return clk_mux_determine_rate_flags(hw, req,
CLK_SET_RATE_PARENT);
}
- ret = 0;
}
- return ret;
+ return 0;
}
-static unsigned char vc3_clk_mux_get_parent(struct clk_hw *hw)
+static u8 vc3_clk_mux_get_parent(struct clk_hw *hw)
{
struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
const struct vc3_clk_data *clk_mux = vc3->data;
@@ -574,9 +567,8 @@ static int vc3_clk_mux_set_parent(struct clk_hw *hw, u8 index)
struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw);
const struct vc3_clk_data *clk_mux = vc3->data;
- regmap_update_bits(vc3->regmap, clk_mux->offs,
- clk_mux->bitmsk, index ? clk_mux->bitmsk : 0);
- return 0;
+ return regmap_update_bits(vc3->regmap, clk_mux->offs, clk_mux->bitmsk,
+ index ? clk_mux->bitmsk : 0);
}
static const struct clk_ops vc3_clk_mux_ops = {
@@ -605,7 +597,7 @@ static struct vc3_hw_data clk_pfd_mux[] = {
.offs = VC3_PLL_OP_CTRL,
.bitmsk = BIT(VC3_PLL_OP_CTRL_PLL2_REFIN_SEL)
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "pfd2_mux",
.ops = &vc3_pfd_mux_ops,
.parent_data = pfd_mux_parent_data,
@@ -618,7 +610,7 @@ static struct vc3_hw_data clk_pfd_mux[] = {
.offs = VC3_GENERAL_CTR,
.bitmsk = BIT(VC3_GENERAL_CTR_PLL3_REFIN_SEL)
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "pfd3_mux",
.ops = &vc3_pfd_mux_ops,
.parent_data = pfd_mux_parent_data,
@@ -636,7 +628,7 @@ static struct vc3_hw_data clk_pfd[] = {
.mdiv1_bitmsk = VC3_PLL1_M_DIV1,
.mdiv2_bitmsk = VC3_PLL1_M_DIV2
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "pfd1",
.ops = &vc3_pfd_ops,
.parent_data = &(const struct clk_parent_data) {
@@ -653,7 +645,7 @@ static struct vc3_hw_data clk_pfd[] = {
.mdiv1_bitmsk = VC3_PLL2_M_DIV1,
.mdiv2_bitmsk = VC3_PLL2_M_DIV2
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "pfd2",
.ops = &vc3_pfd_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -670,7 +662,7 @@ static struct vc3_hw_data clk_pfd[] = {
.mdiv1_bitmsk = VC3_PLL3_M_DIV1,
.mdiv2_bitmsk = VC3_PLL3_M_DIV2
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "pfd3",
.ops = &vc3_pfd_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -691,7 +683,7 @@ static struct vc3_hw_data clk_pll[] = {
.vco_min = VC3_PLL1_VCO_MIN,
.vco_max = VC3_PLL1_VCO_MAX
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "pll1",
.ops = &vc3_pll_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -709,7 +701,7 @@ static struct vc3_hw_data clk_pll[] = {
.vco_min = VC3_PLL2_VCO_MIN,
.vco_max = VC3_PLL2_VCO_MAX
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "pll2",
.ops = &vc3_pll_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -727,7 +719,7 @@ static struct vc3_hw_data clk_pll[] = {
.vco_min = VC3_PLL3_VCO_MIN,
.vco_max = VC3_PLL3_VCO_MAX
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "pll3",
.ops = &vc3_pll_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -760,7 +752,7 @@ static struct vc3_hw_data clk_div_mux[] = {
.offs = VC3_GENERAL_CTR,
.bitmsk = VC3_GENERAL_CTR_DIV1_SRC_SEL
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "div1_mux",
.ops = &vc3_div_mux_ops,
.parent_data = div_mux_parent_data[VC3_DIV1_MUX],
@@ -773,7 +765,7 @@ static struct vc3_hw_data clk_div_mux[] = {
.offs = VC3_PLL3_CHARGE_PUMP_CTRL,
.bitmsk = VC3_PLL3_CHARGE_PUMP_CTRL_OUTDIV3_SRC_SEL
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "div3_mux",
.ops = &vc3_div_mux_ops,
.parent_data = div_mux_parent_data[VC3_DIV3_MUX],
@@ -786,7 +778,7 @@ static struct vc3_hw_data clk_div_mux[] = {
.offs = VC3_OUTPUT_CTR,
.bitmsk = VC3_OUTPUT_CTR_DIV4_SRC_SEL
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "div4_mux",
.ops = &vc3_div_mux_ops,
.parent_data = div_mux_parent_data[VC3_DIV4_MUX],
@@ -805,7 +797,7 @@ static struct vc3_hw_data clk_div[] = {
.width = 4,
.flags = CLK_DIVIDER_READ_ONLY
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "div1",
.ops = &vc3_div_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -823,7 +815,7 @@ static struct vc3_hw_data clk_div[] = {
.width = 4,
.flags = CLK_DIVIDER_READ_ONLY
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "div2",
.ops = &vc3_div_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -841,7 +833,7 @@ static struct vc3_hw_data clk_div[] = {
.width = 4,
.flags = CLK_DIVIDER_READ_ONLY
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "div3",
.ops = &vc3_div_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -859,7 +851,7 @@ static struct vc3_hw_data clk_div[] = {
.width = 4,
.flags = CLK_DIVIDER_READ_ONLY
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "div4",
.ops = &vc3_div_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -877,7 +869,7 @@ static struct vc3_hw_data clk_div[] = {
.width = 4,
.flags = CLK_DIVIDER_READ_ONLY
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "div5",
.ops = &vc3_div_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -895,7 +887,7 @@ static struct vc3_hw_data clk_mux[] = {
.offs = VC3_SE1_DIV4_CTRL,
.bitmsk = VC3_SE1_DIV4_CTRL_SE1_CLK_SEL
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "se1_mux",
.ops = &vc3_clk_mux_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -911,7 +903,7 @@ static struct vc3_hw_data clk_mux[] = {
.offs = VC3_SE2_CTRL_REG0,
.bitmsk = VC3_SE2_CTRL_REG0_SE2_CLK_SEL
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "se2_mux",
.ops = &vc3_clk_mux_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -927,7 +919,7 @@ static struct vc3_hw_data clk_mux[] = {
.offs = VC3_SE3_DIFF1_CTRL_REG,
.bitmsk = VC3_SE3_DIFF1_CTRL_REG_SE3_CLK_SEL
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "se3_mux",
.ops = &vc3_clk_mux_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -943,7 +935,7 @@ static struct vc3_hw_data clk_mux[] = {
.offs = VC3_DIFF1_CTRL_REG,
.bitmsk = VC3_DIFF1_CTRL_REG_DIFF1_CLK_SEL
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "diff1_mux",
.ops = &vc3_clk_mux_ops,
.parent_hws = (const struct clk_hw *[]) {
@@ -959,7 +951,7 @@ static struct vc3_hw_data clk_mux[] = {
.offs = VC3_DIFF2_CTRL_REG,
.bitmsk = VC3_DIFF2_CTRL_REG_DIFF2_CLK_SEL
},
- .hw.init = &(struct clk_init_data){
+ .hw.init = &(struct clk_init_data) {
.name = "diff2_mux",
.ops = &vc3_clk_mux_ops,
.parent_hws = (const struct clk_hw *[]) {
diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c
index 2d7186905abd..5d0226530fdb 100644
--- a/drivers/clk/hisilicon/clk-hi3620.c
+++ b/drivers/clk/hisilicon/clk-hi3620.c
@@ -466,8 +466,10 @@ static void __init hi3620_mmc_clk_init(struct device_node *node)
return;
clk_data->clks = kcalloc(num, sizeof(*clk_data->clks), GFP_KERNEL);
- if (!clk_data->clks)
+ if (!clk_data->clks) {
+ kfree(clk_data);
return;
+ }
for (i = 0; i < num; i++) {
struct hisi_mmc_clock *mmc_clk = &hi3620_mmc_clks[i];
diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c
index 41f0a45aa162..7d8883916cac 100644
--- a/drivers/clk/imx/clk-imx8qxp.c
+++ b/drivers/clk/imx/clk-imx8qxp.c
@@ -66,6 +66,22 @@ static const char * const lcd_pxl_sels[] = {
"lcd_pxl_bypass_div_clk",
};
+static const char *const lvds0_sels[] = {
+ "clk_dummy",
+ "clk_dummy",
+ "clk_dummy",
+ "clk_dummy",
+ "mipi0_lvds_bypass_clk",
+};
+
+static const char *const lvds1_sels[] = {
+ "clk_dummy",
+ "clk_dummy",
+ "clk_dummy",
+ "clk_dummy",
+ "mipi1_lvds_bypass_clk",
+};
+
static const char * const mipi_sels[] = {
"clk_dummy",
"clk_dummy",
@@ -207,9 +223,9 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
/* MIPI-LVDS SS */
imx_clk_scu("mipi0_bypass_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_BYPASS);
imx_clk_scu("mipi0_pixel_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PER);
- imx_clk_scu("mipi0_lvds_pixel_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2);
imx_clk_scu("mipi0_lvds_bypass_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_BYPASS);
- imx_clk_scu("mipi0_lvds_phy_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3);
+ imx_clk_scu2("mipi0_lvds_pixel_clk", lvds0_sels, ARRAY_SIZE(lvds0_sels), IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu2("mipi0_lvds_phy_clk", lvds0_sels, ARRAY_SIZE(lvds0_sels), IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3);
imx_clk_scu2("mipi0_dsi_tx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_MST_BUS);
imx_clk_scu2("mipi0_dsi_rx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_SLV_BUS);
imx_clk_scu2("mipi0_dsi_phy_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PHY);
@@ -219,9 +235,9 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
imx_clk_scu("mipi1_bypass_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_BYPASS);
imx_clk_scu("mipi1_pixel_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PER);
- imx_clk_scu("mipi1_lvds_pixel_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2);
imx_clk_scu("mipi1_lvds_bypass_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_BYPASS);
- imx_clk_scu("mipi1_lvds_phy_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3);
+ imx_clk_scu2("mipi1_lvds_pixel_clk", lvds1_sels, ARRAY_SIZE(lvds1_sels), IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2);
+ imx_clk_scu2("mipi1_lvds_phy_clk", lvds1_sels, ARRAY_SIZE(lvds1_sels), IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3);
imx_clk_scu2("mipi1_dsi_tx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_MST_BUS);
imx_clk_scu2("mipi1_dsi_rx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_SLV_BUS);
diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
index 0d58d85c375e..d63564dbb12c 100644
--- a/drivers/clk/imx/clk-pll14xx.c
+++ b/drivers/clk/imx/clk-pll14xx.c
@@ -104,15 +104,15 @@ static const struct imx_pll14xx_rate_table *imx_get_pll_settings(
static long pll14xx_calc_rate(struct clk_pll14xx *pll, int mdiv, int pdiv,
int sdiv, int kdiv, unsigned long prate)
{
- u64 fvco = prate;
+ u64 fout = prate;
- /* fvco = (m * 65536 + k) * Fin / (p * 65536) */
- fvco *= (mdiv * 65536 + kdiv);
+ /* fout = (m * 65536 + k) * Fin / (p * 65536) / (1 << sdiv) */
+ fout *= (mdiv * 65536 + kdiv);
pdiv *= 65536;
- do_div(fvco, pdiv << sdiv);
+ do_div(fout, pdiv << sdiv);
- return fvco;
+ return fout;
}
static long pll1443x_calc_kdiv(int mdiv, int pdiv, int sdiv,
@@ -131,7 +131,7 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat
{
u32 pll_div_ctl0, pll_div_ctl1;
int mdiv, pdiv, sdiv, kdiv;
- long fvco, rate_min, rate_max, dist, best = LONG_MAX;
+ long fout, rate_min, rate_max, dist, best = LONG_MAX;
const struct imx_pll14xx_rate_table *tt;
/*
@@ -143,6 +143,7 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat
* d) -32768 <= k <= 32767
*
* fvco = (m * 65536 + k) * prate / (p * 65536)
+ * fout = (m * 65536 + k) * prate / (p * 65536) / (1 << sdiv)
*/
/* First try if we can get the desired rate from one of the static entries */
@@ -173,8 +174,8 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat
pr_debug("%s: in=%ld, want=%ld Only adjust kdiv %ld -> %d\n",
clk_hw_get_name(&pll->hw), prate, rate,
FIELD_GET(KDIV_MASK, pll_div_ctl1), kdiv);
- fvco = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate);
- t->rate = (unsigned int)fvco;
+ fout = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate);
+ t->rate = (unsigned int)fout;
t->mdiv = mdiv;
t->pdiv = pdiv;
t->sdiv = sdiv;
@@ -190,13 +191,13 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat
mdiv = clamp(mdiv, 64, 1023);
kdiv = pll1443x_calc_kdiv(mdiv, pdiv, sdiv, rate, prate);
- fvco = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate);
+ fout = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate);
/* best match */
- dist = abs((long)rate - (long)fvco);
+ dist = abs((long)rate - (long)fout);
if (dist < best) {
best = dist;
- t->rate = (unsigned int)fvco;
+ t->rate = (unsigned int)fout;
t->mdiv = mdiv;
t->pdiv = pdiv;
t->sdiv = sdiv;
diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c
index be89180dd19c..e48a904c0013 100644
--- a/drivers/clk/imx/clk-scu.c
+++ b/drivers/clk/imx/clk-scu.c
@@ -886,8 +886,10 @@ struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_na
return ERR_PTR(-EINVAL);
}
- if (!imx_clk_is_resource_owned(rsrc_id))
+ if (!imx_clk_is_resource_owned(rsrc_id)) {
+ kfree(clk_node);
return NULL;
+ }
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk) {
diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index 48b42d11111c..70a005e7e1b1 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -423,6 +423,15 @@ config COMMON_CLK_MT7986_ETHSYS
This driver adds support for clocks for Ethernet and SGMII
required on MediaTek MT7986 SoC.
+config COMMON_CLK_MT7988
+ tristate "Clock driver for MediaTek MT7988"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ select COMMON_CLK_MEDIATEK
+ default ARCH_MEDIATEK
+ help
+ This driver supports MediaTek MT7988 basic clocks and clocks
+ required for various periperals found on this SoC.
+
config COMMON_CLK_MT8135
tristate "Clock driver for MediaTek MT8135"
depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST
diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile
index dbeaa5b41177..eeccfa039896 100644
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -62,6 +62,11 @@ obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-apmixed.o
obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-topckgen.o
obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-infracfg.o
obj-$(CONFIG_COMMON_CLK_MT7986_ETHSYS) += clk-mt7986-eth.o
+obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-apmixed.o
+obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-topckgen.o
+obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-infracfg.o
+obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-eth.o
+obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-xfipll.o
obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135-apmixedsys.o clk-mt8135.o
obj-$(CONFIG_COMMON_CLK_MT8167) += clk-mt8167-apmixedsys.o clk-mt8167.o
obj-$(CONFIG_COMMON_CLK_MT8167_AUDSYS) += clk-mt8167-aud.o
diff --git a/drivers/clk/mediatek/clk-mt7988-apmixed.c b/drivers/clk/mediatek/clk-mt7988-apmixed.c
new file mode 100644
index 000000000000..baf9564351a3
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7988-apmixed.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ * Author: Sam Shih <[email protected]>
+ * Author: Xiufeng Li <[email protected]>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "clk-mtk.h"
+#include "clk-gate.h"
+#include "clk-mux.h"
+#include "clk-pll.h"
+#include <dt-bindings/clock/mediatek,mt7988-clk.h>
+
+#define MT7988_PLL_FMAX (2500UL * MHZ)
+#define MT7988_PCW_CHG_BIT 2
+
+#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask, _pcwbits, _pd_reg, \
+ _pd_shift, _tuner_reg, _tuner_en_reg, _tuner_en_bit, _pcw_reg, _pcw_shift, \
+ _pcw_chg_reg) \
+ { \
+ .id = _id, \
+ .name = _name, \
+ .reg = _reg, \
+ .pwr_reg = _pwr_reg, \
+ .en_mask = _en_mask, \
+ .flags = _flags, \
+ .rst_bar_mask = BIT(_rst_bar_mask), \
+ .fmax = MT7988_PLL_FMAX, \
+ .pcwbits = _pcwbits, \
+ .pd_reg = _pd_reg, \
+ .pd_shift = _pd_shift, \
+ .tuner_reg = _tuner_reg, \
+ .tuner_en_reg = _tuner_en_reg, \
+ .tuner_en_bit = _tuner_en_bit, \
+ .pcw_reg = _pcw_reg, \
+ .pcw_shift = _pcw_shift, \
+ .pcw_chg_reg = _pcw_chg_reg, \
+ .pcw_chg_bit = MT7988_PCW_CHG_BIT, \
+ .parent_name = "clkxtal", \
+ }
+
+static const struct mtk_pll_data plls[] = {
+ PLL(CLK_APMIXED_NETSYSPLL, "netsyspll", 0x0104, 0x0110, 0x00000001, 0, 0, 32, 0x0104, 4, 0,
+ 0, 0, 0x0108, 0, 0x0104),
+ PLL(CLK_APMIXED_MPLL, "mpll", 0x0114, 0x0120, 0xff000001, HAVE_RST_BAR, 23, 32, 0x0114, 4,
+ 0, 0, 0, 0x0118, 0, 0x0114),
+ PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0124, 0x0130, 0xff000001, HAVE_RST_BAR, 23, 32, 0x0124, 4,
+ 0, 0, 0, 0x0128, 0, 0x0124),
+ PLL(CLK_APMIXED_APLL2, "apll2", 0x0134, 0x0140, 0x00000001, 0, 0, 32, 0x0134, 4, 0x0704,
+ 0x0700, 1, 0x0138, 0, 0x0134),
+ PLL(CLK_APMIXED_NET1PLL, "net1pll", 0x0144, 0x0150, 0xff000001, HAVE_RST_BAR, 23, 32,
+ 0x0144, 4, 0, 0, 0, 0x0148, 0, 0x0144),
+ PLL(CLK_APMIXED_NET2PLL, "net2pll", 0x0154, 0x0160, 0xff000001, (HAVE_RST_BAR | PLL_AO), 23,
+ 32, 0x0154, 4, 0, 0, 0, 0x0158, 0, 0x0154),
+ PLL(CLK_APMIXED_WEDMCUPLL, "wedmcupll", 0x0164, 0x0170, 0x00000001, 0, 0, 32, 0x0164, 4, 0,
+ 0, 0, 0x0168, 0, 0x0164),
+ PLL(CLK_APMIXED_SGMPLL, "sgmpll", 0x0174, 0x0180, 0x00000001, 0, 0, 32, 0x0174, 4, 0, 0, 0,
+ 0x0178, 0, 0x0174),
+ PLL(CLK_APMIXED_ARM_B, "arm_b", 0x0204, 0x0210, 0xff000001, (HAVE_RST_BAR | PLL_AO), 23, 32,
+ 0x0204, 4, 0, 0, 0, 0x0208, 0, 0x0204),
+ PLL(CLK_APMIXED_CCIPLL2_B, "ccipll2_b", 0x0214, 0x0220, 0xff000001, HAVE_RST_BAR, 23, 32,
+ 0x0214, 4, 0, 0, 0, 0x0218, 0, 0x0214),
+ PLL(CLK_APMIXED_USXGMIIPLL, "usxgmiipll", 0x0304, 0x0310, 0xff000001, HAVE_RST_BAR, 23, 32,
+ 0x0304, 4, 0, 0, 0, 0x0308, 0, 0x0304),
+ PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0314, 0x0320, 0x00000001, 0, 0, 32, 0x0314, 4, 0, 0,
+ 0, 0x0318, 0, 0x0314),
+};
+
+static const struct of_device_id of_match_clk_mt7988_apmixed[] = {
+ { .compatible = "mediatek,mt7988-apmixedsys" },
+ { /* sentinel */ }
+};
+
+static int clk_mt7988_apmixed_probe(struct platform_device *pdev)
+{
+ struct clk_hw_onecell_data *clk_data;
+ struct device_node *node = pdev->dev.of_node;
+ int r;
+
+ clk_data = mtk_alloc_clk_data(ARRAY_SIZE(plls));
+ if (!clk_data)
+ return -ENOMEM;
+
+ r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
+ if (r)
+ goto free_apmixed_data;
+
+ r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+ if (r)
+ goto unregister_plls;
+
+ return r;
+
+unregister_plls:
+ mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data);
+free_apmixed_data:
+ mtk_free_clk_data(clk_data);
+ return r;
+}
+
+static struct platform_driver clk_mt7988_apmixed_drv = {
+ .probe = clk_mt7988_apmixed_probe,
+ .driver = {
+ .name = "clk-mt7988-apmixed",
+ .of_match_table = of_match_clk_mt7988_apmixed,
+ },
+};
+builtin_platform_driver(clk_mt7988_apmixed_drv);
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt7988-eth.c b/drivers/clk/mediatek/clk-mt7988-eth.c
new file mode 100644
index 000000000000..adf4a9d39b38
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7988-eth.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ * Author: Sam Shih <[email protected]>
+ * Author: Xiufeng Li <[email protected]>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "clk-mtk.h"
+#include "clk-gate.h"
+#include "reset.h"
+#include <dt-bindings/clock/mediatek,mt7988-clk.h>
+#include <dt-bindings/reset/mediatek,mt7988-resets.h>
+
+static const struct mtk_gate_regs ethdma_cg_regs = {
+ .set_ofs = 0x30,
+ .clr_ofs = 0x30,
+ .sta_ofs = 0x30,
+};
+
+#define GATE_ETHDMA(_id, _name, _parent, _shift) \
+ { \
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .regs = &ethdma_cg_regs, \
+ .shift = _shift, \
+ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
+ }
+
+static const struct mtk_gate ethdma_clks[] = {
+ GATE_ETHDMA(CLK_ETHDMA_XGP1_EN, "ethdma_xgp1_en", "top_xtal", 0),
+ GATE_ETHDMA(CLK_ETHDMA_XGP2_EN, "ethdma_xgp2_en", "top_xtal", 1),
+ GATE_ETHDMA(CLK_ETHDMA_XGP3_EN, "ethdma_xgp3_en", "top_xtal", 2),
+ GATE_ETHDMA(CLK_ETHDMA_FE_EN, "ethdma_fe_en", "netsys_2x_sel", 6),
+ GATE_ETHDMA(CLK_ETHDMA_GP2_EN, "ethdma_gp2_en", "top_xtal", 7),
+ GATE_ETHDMA(CLK_ETHDMA_GP1_EN, "ethdma_gp1_en", "top_xtal", 8),
+ GATE_ETHDMA(CLK_ETHDMA_GP3_EN, "ethdma_gp3_en", "top_xtal", 10),
+ GATE_ETHDMA(CLK_ETHDMA_ESW_EN, "ethdma_esw_en", "netsys_gsw_sel", 16),
+ GATE_ETHDMA(CLK_ETHDMA_CRYPT0_EN, "ethdma_crypt0_en", "eip197_sel", 29),
+};
+
+static const struct mtk_clk_desc ethdma_desc = {
+ .clks = ethdma_clks,
+ .num_clks = ARRAY_SIZE(ethdma_clks),
+};
+
+static const struct mtk_gate_regs sgmii_cg_regs = {
+ .set_ofs = 0xe4,
+ .clr_ofs = 0xe4,
+ .sta_ofs = 0xe4,
+};
+
+#define GATE_SGMII(_id, _name, _parent, _shift) \
+ { \
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .regs = &sgmii_cg_regs, \
+ .shift = _shift, \
+ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
+ }
+
+static const struct mtk_gate sgmii0_clks[] = {
+ GATE_SGMII(CLK_SGM0_TX_EN, "sgm0_tx_en", "top_xtal", 2),
+ GATE_SGMII(CLK_SGM0_RX_EN, "sgm0_rx_en", "top_xtal", 3),
+};
+
+static const struct mtk_clk_desc sgmii0_desc = {
+ .clks = sgmii0_clks,
+ .num_clks = ARRAY_SIZE(sgmii0_clks),
+};
+
+static const struct mtk_gate sgmii1_clks[] = {
+ GATE_SGMII(CLK_SGM1_TX_EN, "sgm1_tx_en", "top_xtal", 2),
+ GATE_SGMII(CLK_SGM1_RX_EN, "sgm1_rx_en", "top_xtal", 3),
+};
+
+static const struct mtk_clk_desc sgmii1_desc = {
+ .clks = sgmii1_clks,
+ .num_clks = ARRAY_SIZE(sgmii1_clks),
+};
+
+static const struct mtk_gate_regs ethwarp_cg_regs = {
+ .set_ofs = 0x14,
+ .clr_ofs = 0x14,
+ .sta_ofs = 0x14,
+};
+
+#define GATE_ETHWARP(_id, _name, _parent, _shift) \
+ { \
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .regs = &ethwarp_cg_regs, \
+ .shift = _shift, \
+ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
+ }
+
+static const struct mtk_gate ethwarp_clks[] = {
+ GATE_ETHWARP(CLK_ETHWARP_WOCPU2_EN, "ethwarp_wocpu2_en", "netsys_mcu_sel", 13),
+ GATE_ETHWARP(CLK_ETHWARP_WOCPU1_EN, "ethwarp_wocpu1_en", "netsys_mcu_sel", 14),
+ GATE_ETHWARP(CLK_ETHWARP_WOCPU0_EN, "ethwarp_wocpu0_en", "netsys_mcu_sel", 15),
+};
+
+static u16 ethwarp_rst_ofs[] = { 0x8 };
+
+static u16 ethwarp_idx_map[] = {
+ [MT7988_ETHWARP_RST_SWITCH] = 9,
+};
+
+static const struct mtk_clk_rst_desc ethwarp_rst_desc = {
+ .version = MTK_RST_SIMPLE,
+ .rst_bank_ofs = ethwarp_rst_ofs,
+ .rst_bank_nr = ARRAY_SIZE(ethwarp_rst_ofs),
+ .rst_idx_map = ethwarp_idx_map,
+ .rst_idx_map_nr = ARRAY_SIZE(ethwarp_idx_map),
+};
+
+static const struct mtk_clk_desc ethwarp_desc = {
+ .clks = ethwarp_clks,
+ .num_clks = ARRAY_SIZE(ethwarp_clks),
+ .rst_desc = &ethwarp_rst_desc,
+};
+
+static const struct of_device_id of_match_clk_mt7988_eth[] = {
+ { .compatible = "mediatek,mt7988-ethsys", .data = &ethdma_desc },
+ { .compatible = "mediatek,mt7988-sgmiisys0", .data = &sgmii0_desc },
+ { .compatible = "mediatek,mt7988-sgmiisys1", .data = &sgmii1_desc },
+ { .compatible = "mediatek,mt7988-ethwarp", .data = &ethwarp_desc },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_eth);
+
+static struct platform_driver clk_mt7988_eth_drv = {
+ .driver = {
+ .name = "clk-mt7988-eth",
+ .of_match_table = of_match_clk_mt7988_eth,
+ },
+ .probe = mtk_clk_simple_probe,
+ .remove_new = mtk_clk_simple_remove,
+};
+module_platform_driver(clk_mt7988_eth_drv);
+
+MODULE_DESCRIPTION("MediaTek MT7988 Ethernet clocks driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt7988-infracfg.c b/drivers/clk/mediatek/clk-mt7988-infracfg.c
new file mode 100644
index 000000000000..8011ef278bea
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7988-infracfg.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ * Author: Sam Shih <[email protected]>
+ * Author: Xiufeng Li <[email protected]>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "clk-mtk.h"
+#include "clk-gate.h"
+#include "clk-mux.h"
+#include <dt-bindings/clock/mediatek,mt7988-clk.h>
+
+static DEFINE_SPINLOCK(mt7988_clk_lock);
+
+static const char *const infra_mux_uart0_parents[] __initconst = { "csw_infra_f26m_sel",
+ "uart_sel" };
+
+static const char *const infra_mux_uart1_parents[] __initconst = { "csw_infra_f26m_sel",
+ "uart_sel" };
+
+static const char *const infra_mux_uart2_parents[] __initconst = { "csw_infra_f26m_sel",
+ "uart_sel" };
+
+static const char *const infra_mux_spi0_parents[] __initconst = { "i2c_sel", "spi_sel" };
+
+static const char *const infra_mux_spi1_parents[] __initconst = { "i2c_sel", "spim_mst_sel" };
+
+static const char *const infra_pwm_bck_parents[] __initconst = { "top_rtc_32p7k",
+ "csw_infra_f26m_sel", "sysaxi_sel",
+ "pwm_sel" };
+
+static const char *const infra_pcie_gfmux_tl_ck_o_p0_parents[] __initconst = {
+ "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", "pextp_tl_sel"
+};
+
+static const char *const infra_pcie_gfmux_tl_ck_o_p1_parents[] __initconst = {
+ "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", "pextp_tl_p1_sel"
+};
+
+static const char *const infra_pcie_gfmux_tl_ck_o_p2_parents[] __initconst = {
+ "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", "pextp_tl_p2_sel"
+};
+
+static const char *const infra_pcie_gfmux_tl_ck_o_p3_parents[] __initconst = {
+ "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", "pextp_tl_p3_sel"
+};
+
+static const struct mtk_mux infra_muxes[] = {
+ /* MODULE_CLK_SEL_0 */
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART0_SEL, "infra_mux_uart0_sel",
+ infra_mux_uart0_parents, 0x0018, 0x0010, 0x0014, 0, 1, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART1_SEL, "infra_mux_uart1_sel",
+ infra_mux_uart1_parents, 0x0018, 0x0010, 0x0014, 1, 1, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART2_SEL, "infra_mux_uart2_sel",
+ infra_mux_uart2_parents, 0x0018, 0x0010, 0x0014, 2, 1, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI0_SEL, "infra_mux_spi0_sel", infra_mux_spi0_parents,
+ 0x0018, 0x0010, 0x0014, 4, 1, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI1_SEL, "infra_mux_spi1_sel", infra_mux_spi1_parents,
+ 0x0018, 0x0010, 0x0014, 5, 1, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI2_SEL, "infra_mux_spi2_sel", infra_mux_spi0_parents,
+ 0x0018, 0x0010, 0x0014, 6, 1, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_SEL, "infra_pwm_sel", infra_pwm_bck_parents, 0x0018,
+ 0x0010, 0x0014, 14, 2, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK1_SEL, "infra_pwm_ck1_sel", infra_pwm_bck_parents,
+ 0x0018, 0x0010, 0x0014, 16, 2, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK2_SEL, "infra_pwm_ck2_sel", infra_pwm_bck_parents,
+ 0x0018, 0x0010, 0x0014, 18, 2, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK3_SEL, "infra_pwm_ck3_sel", infra_pwm_bck_parents,
+ 0x0018, 0x0010, 0x0014, 20, 2, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK4_SEL, "infra_pwm_ck4_sel", infra_pwm_bck_parents,
+ 0x0018, 0x0010, 0x0014, 22, 2, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK5_SEL, "infra_pwm_ck5_sel", infra_pwm_bck_parents,
+ 0x0018, 0x0010, 0x0014, 24, 2, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK6_SEL, "infra_pwm_ck6_sel", infra_pwm_bck_parents,
+ 0x0018, 0x0010, 0x0014, 26, 2, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK7_SEL, "infra_pwm_ck7_sel", infra_pwm_bck_parents,
+ 0x0018, 0x0010, 0x0014, 28, 2, -1, -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK8_SEL, "infra_pwm_ck8_sel", infra_pwm_bck_parents,
+ 0x0018, 0x0010, 0x0014, 30, 2, -1, -1, -1),
+ /* MODULE_CLK_SEL_1 */
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P0_SEL, "infra_pcie_gfmux_tl_o_p0_sel",
+ infra_pcie_gfmux_tl_ck_o_p0_parents, 0x0028, 0x0020, 0x0024, 0, 2, -1,
+ -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P1_SEL, "infra_pcie_gfmux_tl_o_p1_sel",
+ infra_pcie_gfmux_tl_ck_o_p1_parents, 0x0028, 0x0020, 0x0024, 2, 2, -1,
+ -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P2_SEL, "infra_pcie_gfmux_tl_o_p2_sel",
+ infra_pcie_gfmux_tl_ck_o_p2_parents, 0x0028, 0x0020, 0x0024, 4, 2, -1,
+ -1, -1),
+ MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P3_SEL, "infra_pcie_gfmux_tl_o_p3_sel",
+ infra_pcie_gfmux_tl_ck_o_p3_parents, 0x0028, 0x0020, 0x0024, 6, 2, -1,
+ -1, -1),
+};
+
+static const struct mtk_gate_regs infra0_cg_regs = {
+ .set_ofs = 0x10,
+ .clr_ofs = 0x14,
+ .sta_ofs = 0x18,
+};
+
+static const struct mtk_gate_regs infra1_cg_regs = {
+ .set_ofs = 0x40,
+ .clr_ofs = 0x44,
+ .sta_ofs = 0x48,
+};
+
+static const struct mtk_gate_regs infra2_cg_regs = {
+ .set_ofs = 0x50,
+ .clr_ofs = 0x54,
+ .sta_ofs = 0x58,
+};
+
+static const struct mtk_gate_regs infra3_cg_regs = {
+ .set_ofs = 0x60,
+ .clr_ofs = 0x64,
+ .sta_ofs = 0x68,
+};
+
+#define GATE_INFRA0_FLAGS(_id, _name, _parent, _shift, _flags) \
+ GATE_MTK_FLAGS(_id, _name, _parent, &infra0_cg_regs, _shift, &mtk_clk_gate_ops_setclr, \
+ _flags)
+
+#define GATE_INFRA1_FLAGS(_id, _name, _parent, _shift, _flags) \
+ GATE_MTK_FLAGS(_id, _name, _parent, &infra1_cg_regs, _shift, &mtk_clk_gate_ops_setclr, \
+ _flags)
+
+#define GATE_INFRA2_FLAGS(_id, _name, _parent, _shift, _flags) \
+ GATE_MTK_FLAGS(_id, _name, _parent, &infra2_cg_regs, _shift, &mtk_clk_gate_ops_setclr, \
+ _flags)
+
+#define GATE_INFRA3_FLAGS(_id, _name, _parent, _shift, _flags) \
+ GATE_MTK_FLAGS(_id, _name, _parent, &infra3_cg_regs, _shift, &mtk_clk_gate_ops_setclr, \
+ _flags)
+
+#define GATE_INFRA0(_id, _name, _parent, _shift) GATE_INFRA0_FLAGS(_id, _name, _parent, _shift, 0)
+
+#define GATE_INFRA1(_id, _name, _parent, _shift) GATE_INFRA1_FLAGS(_id, _name, _parent, _shift, 0)
+
+#define GATE_INFRA2(_id, _name, _parent, _shift) GATE_INFRA2_FLAGS(_id, _name, _parent, _shift, 0)
+
+#define GATE_INFRA3(_id, _name, _parent, _shift) GATE_INFRA3_FLAGS(_id, _name, _parent, _shift, 0)
+
+static const struct mtk_gate infra_clks[] = {
+ /* INFRA0 */
+ GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P0, "infra_pcie_peri_ck_26m_ck_p0",
+ "csw_infra_f26m_sel", 7),
+ GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P1, "infra_pcie_peri_ck_26m_ck_p1",
+ "csw_infra_f26m_sel", 8),
+ GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P2, "infra_pcie_peri_ck_26m_ck_p2",
+ "csw_infra_f26m_sel", 9),
+ GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P3, "infra_pcie_peri_ck_26m_ck_p3",
+ "csw_infra_f26m_sel", 10),
+ /* INFRA1 */
+ GATE_INFRA1(CLK_INFRA_66M_GPT_BCK, "infra_hf_66m_gpt_bck", "sysaxi_sel", 0),
+ GATE_INFRA1(CLK_INFRA_66M_PWM_HCK, "infra_hf_66m_pwm_hck", "sysaxi_sel", 1),
+ GATE_INFRA1(CLK_INFRA_66M_PWM_BCK, "infra_hf_66m_pwm_bck", "infra_pwm_sel", 2),
+ GATE_INFRA1(CLK_INFRA_66M_PWM_CK1, "infra_hf_66m_pwm_ck1", "infra_pwm_ck1_sel", 3),
+ GATE_INFRA1(CLK_INFRA_66M_PWM_CK2, "infra_hf_66m_pwm_ck2", "infra_pwm_ck2_sel", 4),
+ GATE_INFRA1(CLK_INFRA_66M_PWM_CK3, "infra_hf_66m_pwm_ck3", "infra_pwm_ck3_sel", 5),
+ GATE_INFRA1(CLK_INFRA_66M_PWM_CK4, "infra_hf_66m_pwm_ck4", "infra_pwm_ck4_sel", 6),
+ GATE_INFRA1(CLK_INFRA_66M_PWM_CK5, "infra_hf_66m_pwm_ck5", "infra_pwm_ck5_sel", 7),
+ GATE_INFRA1(CLK_INFRA_66M_PWM_CK6, "infra_hf_66m_pwm_ck6", "infra_pwm_ck6_sel", 8),
+ GATE_INFRA1(CLK_INFRA_66M_PWM_CK7, "infra_hf_66m_pwm_ck7", "infra_pwm_ck7_sel", 9),
+ GATE_INFRA1(CLK_INFRA_66M_PWM_CK8, "infra_hf_66m_pwm_ck8", "infra_pwm_ck8_sel", 10),
+ GATE_INFRA1(CLK_INFRA_133M_CQDMA_BCK, "infra_hf_133m_cqdma_bck", "sysaxi_sel", 12),
+ GATE_INFRA1(CLK_INFRA_66M_AUD_SLV_BCK, "infra_66m_aud_slv_bck", "sysaxi_sel", 13),
+ GATE_INFRA1(CLK_INFRA_AUD_26M, "infra_f_faud_26m", "csw_infra_f26m_sel", 14),
+ GATE_INFRA1(CLK_INFRA_AUD_L, "infra_f_faud_l", "aud_l_sel", 15),
+ GATE_INFRA1(CLK_INFRA_AUD_AUD, "infra_f_aud_aud", "a1sys_sel", 16),
+ GATE_INFRA1(CLK_INFRA_AUD_EG2, "infra_f_faud_eg2", "a_tuner_sel", 18),
+ GATE_INFRA1_FLAGS(CLK_INFRA_DRAMC_F26M, "infra_dramc_f26m", "csw_infra_f26m_sel", 19,
+ CLK_IS_CRITICAL),
+ /* JTAG */
+ GATE_INFRA1_FLAGS(CLK_INFRA_133M_DBG_ACKM, "infra_hf_133m_dbg_ackm", "sysaxi_sel", 20,
+ CLK_IS_CRITICAL),
+ GATE_INFRA1(CLK_INFRA_66M_AP_DMA_BCK, "infra_66m_ap_dma_bck", "sysaxi_sel", 21),
+ GATE_INFRA1(CLK_INFRA_66M_SEJ_BCK, "infra_hf_66m_sej_bck", "sysaxi_sel", 29),
+ GATE_INFRA1(CLK_INFRA_PRE_CK_SEJ_F13M, "infra_pre_ck_sej_f13m", "csw_infra_f26m_sel", 30),
+ /* INFRA2 */
+ GATE_INFRA2(CLK_INFRA_26M_THERM_SYSTEM, "infra_hf_26m_therm_system", "csw_infra_f26m_sel",
+ 0),
+ GATE_INFRA2(CLK_INFRA_I2C_BCK, "infra_i2c_bck", "i2c_sel", 1),
+ GATE_INFRA2(CLK_INFRA_52M_UART0_CK, "infra_f_52m_uart0", "infra_mux_uart0_sel", 3),
+ GATE_INFRA2(CLK_INFRA_52M_UART1_CK, "infra_f_52m_uart1", "infra_mux_uart1_sel", 4),
+ GATE_INFRA2(CLK_INFRA_52M_UART2_CK, "infra_f_52m_uart2", "infra_mux_uart2_sel", 5),
+ GATE_INFRA2(CLK_INFRA_NFI, "infra_f_fnfi", "nfi1x_sel", 9),
+ GATE_INFRA2(CLK_INFRA_SPINFI, "infra_f_fspinfi", "spinfi_sel", 10),
+ GATE_INFRA2_FLAGS(CLK_INFRA_66M_NFI_HCK, "infra_hf_66m_nfi_hck", "sysaxi_sel", 11,
+ CLK_IS_CRITICAL),
+ GATE_INFRA2_FLAGS(CLK_INFRA_104M_SPI0, "infra_hf_104m_spi0", "infra_mux_spi0_sel", 12,
+ CLK_IS_CRITICAL),
+ GATE_INFRA2(CLK_INFRA_104M_SPI1, "infra_hf_104m_spi1", "infra_mux_spi1_sel", 13),
+ GATE_INFRA2(CLK_INFRA_104M_SPI2_BCK, "infra_hf_104m_spi2_bck", "infra_mux_spi2_sel", 14),
+ GATE_INFRA2_FLAGS(CLK_INFRA_66M_SPI0_HCK, "infra_hf_66m_spi0_hck", "sysaxi_sel", 15,
+ CLK_IS_CRITICAL),
+ GATE_INFRA2(CLK_INFRA_66M_SPI1_HCK, "infra_hf_66m_spi1_hck", "sysaxi_sel", 16),
+ GATE_INFRA2(CLK_INFRA_66M_SPI2_HCK, "infra_hf_66m_spi2_hck", "sysaxi_sel", 17),
+ GATE_INFRA2(CLK_INFRA_66M_FLASHIF_AXI, "infra_hf_66m_flashif_axi", "sysaxi_sel", 18),
+ GATE_INFRA2_FLAGS(CLK_INFRA_RTC, "infra_f_frtc", "top_rtc_32k", 19, CLK_IS_CRITICAL),
+ GATE_INFRA2(CLK_INFRA_26M_ADC_BCK, "infra_f_26m_adc_bck", "csw_infra_f26m_sel", 20),
+ GATE_INFRA2(CLK_INFRA_RC_ADC, "infra_f_frc_adc", "infra_f_26m_adc_bck", 21),
+ GATE_INFRA2(CLK_INFRA_MSDC400, "infra_f_fmsdc400", "emmc_400m_sel", 22),
+ GATE_INFRA2(CLK_INFRA_MSDC2_HCK, "infra_f_fmsdc2_hck", "emmc_250m_sel", 23),
+ GATE_INFRA2(CLK_INFRA_133M_MSDC_0_HCK, "infra_hf_133m_msdc_0_hck", "sysaxi_sel", 24),
+ GATE_INFRA2(CLK_INFRA_66M_MSDC_0_HCK, "infra_66m_msdc_0_hck", "sysaxi_sel", 25),
+ GATE_INFRA2(CLK_INFRA_133M_CPUM_BCK, "infra_hf_133m_cpum_bck", "sysaxi_sel", 26),
+ GATE_INFRA2(CLK_INFRA_BIST2FPC, "infra_hf_fbist2fpc", "nfi1x_sel", 27),
+ GATE_INFRA2(CLK_INFRA_I2C_X16W_MCK_CK_P1, "infra_hf_i2c_x16w_mck_ck_p1", "sysaxi_sel", 29),
+ GATE_INFRA2(CLK_INFRA_I2C_X16W_PCK_CK_P1, "infra_hf_i2c_x16w_pck_ck_p1", "sysaxi_sel", 31),
+ /* INFRA3 */
+ GATE_INFRA3(CLK_INFRA_133M_USB_HCK, "infra_133m_usb_hck", "sysaxi_sel", 0),
+ GATE_INFRA3(CLK_INFRA_133M_USB_HCK_CK_P1, "infra_133m_usb_hck_ck_p1", "sysaxi_sel", 1),
+ GATE_INFRA3(CLK_INFRA_66M_USB_HCK, "infra_66m_usb_hck", "sysaxi_sel", 2),
+ GATE_INFRA3(CLK_INFRA_66M_USB_HCK_CK_P1, "infra_66m_usb_hck_ck_p1", "sysaxi_sel", 3),
+ GATE_INFRA3(CLK_INFRA_USB_SYS, "infra_usb_sys", "usb_sys_sel", 4),
+ GATE_INFRA3(CLK_INFRA_USB_SYS_CK_P1, "infra_usb_sys_ck_p1", "usb_sys_p1_sel", 5),
+ GATE_INFRA3(CLK_INFRA_USB_REF, "infra_usb_ref", "top_xtal", 6),
+ GATE_INFRA3(CLK_INFRA_USB_CK_P1, "infra_usb_ck_p1", "top_xtal", 7),
+ GATE_INFRA3_FLAGS(CLK_INFRA_USB_FRMCNT, "infra_usb_frmcnt", "usb_frmcnt_sel", 8,
+ CLK_IS_CRITICAL),
+ GATE_INFRA3_FLAGS(CLK_INFRA_USB_FRMCNT_CK_P1, "infra_usb_frmcnt_ck_p1", "usb_frmcnt_p1_sel",
+ 9, CLK_IS_CRITICAL),
+ GATE_INFRA3(CLK_INFRA_USB_PIPE, "infra_usb_pipe", "sspxtp_sel", 10),
+ GATE_INFRA3(CLK_INFRA_USB_PIPE_CK_P1, "infra_usb_pipe_ck_p1", "usb_phy_sel", 11),
+ GATE_INFRA3(CLK_INFRA_USB_UTMI, "infra_usb_utmi", "top_xtal", 12),
+ GATE_INFRA3(CLK_INFRA_USB_UTMI_CK_P1, "infra_usb_utmi_ck_p1", "top_xtal", 13),
+ GATE_INFRA3(CLK_INFRA_USB_XHCI, "infra_usb_xhci", "usb_xhci_sel", 14),
+ GATE_INFRA3(CLK_INFRA_USB_XHCI_CK_P1, "infra_usb_xhci_ck_p1", "usb_xhci_p1_sel", 15),
+ GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P0, "infra_pcie_gfmux_tl_ck_p0",
+ "infra_pcie_gfmux_tl_o_p0_sel", 20),
+ GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P1, "infra_pcie_gfmux_tl_ck_p1",
+ "infra_pcie_gfmux_tl_o_p1_sel", 21),
+ GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P2, "infra_pcie_gfmux_tl_ck_p2",
+ "infra_pcie_gfmux_tl_o_p2_sel", 22),
+ GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P3, "infra_pcie_gfmux_tl_ck_p3",
+ "infra_pcie_gfmux_tl_o_p3_sel", 23),
+ GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P0, "infra_pcie_pipe_ck_p0", "top_xtal", 24),
+ GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P1, "infra_pcie_pipe_ck_p1", "top_xtal", 25),
+ GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P2, "infra_pcie_pipe_ck_p2", "top_xtal", 26),
+ GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P3, "infra_pcie_pipe_ck_p3", "top_xtal", 27),
+ GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P0, "infra_133m_pcie_ck_p0", "sysaxi_sel", 28),
+ GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P1, "infra_133m_pcie_ck_p1", "sysaxi_sel", 29),
+ GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P2, "infra_133m_pcie_ck_p2", "sysaxi_sel", 30),
+ GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P3, "infra_133m_pcie_ck_p3", "sysaxi_sel", 31),
+};
+
+static const struct mtk_clk_desc infra_desc = {
+ .clks = infra_clks,
+ .num_clks = ARRAY_SIZE(infra_clks),
+ .mux_clks = infra_muxes,
+ .num_mux_clks = ARRAY_SIZE(infra_muxes),
+ .clk_lock = &mt7988_clk_lock,
+};
+
+static const struct of_device_id of_match_clk_mt7988_infracfg[] = {
+ { .compatible = "mediatek,mt7988-infracfg", .data = &infra_desc },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_infracfg);
+
+static struct platform_driver clk_mt7988_infracfg_drv = {
+ .driver = {
+ .name = "clk-mt7988-infracfg",
+ .of_match_table = of_match_clk_mt7988_infracfg,
+ },
+ .probe = mtk_clk_simple_probe,
+ .remove_new = mtk_clk_simple_remove,
+};
+module_platform_driver(clk_mt7988_infracfg_drv);
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt7988-topckgen.c b/drivers/clk/mediatek/clk-mt7988-topckgen.c
new file mode 100644
index 000000000000..760f8e0d2f26
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7988-topckgen.c
@@ -0,0 +1,325 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ * Author: Sam Shih <[email protected]>
+ * Author: Xiufeng Li <[email protected]>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "clk-mtk.h"
+#include "clk-gate.h"
+#include "clk-mux.h"
+#include <dt-bindings/clock/mediatek,mt7988-clk.h>
+
+static DEFINE_SPINLOCK(mt7988_clk_lock);
+
+static const struct mtk_fixed_clk top_fixed_clks[] = {
+ FIXED_CLK(CLK_TOP_XTAL, "top_xtal", "clkxtal", 40000000),
+};
+
+static const struct mtk_fixed_factor top_divs[] = {
+ FACTOR(CLK_TOP_XTAL_D2, "top_xtal_d2", "top_xtal", 1, 2),
+ FACTOR(CLK_TOP_RTC_32K, "top_rtc_32k", "top_xtal", 1, 1250),
+ FACTOR(CLK_TOP_RTC_32P7K, "top_rtc_32p7k", "top_xtal", 1, 1220),
+ FACTOR(CLK_TOP_MPLL_D2, "mpll_d2", "mpll", 1, 2),
+ FACTOR(CLK_TOP_MPLL_D3_D2, "mpll_d3_d2", "mpll", 1, 2),
+ FACTOR(CLK_TOP_MPLL_D4, "mpll_d4", "mpll", 1, 4),
+ FACTOR(CLK_TOP_MPLL_D8, "mpll_d8", "mpll", 1, 8),
+ FACTOR(CLK_TOP_MPLL_D8_D2, "mpll_d8_d2", "mpll", 1, 16),
+ FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2),
+ FACTOR(CLK_TOP_MMPLL_D3_D5, "mmpll_d3_d5", "mmpll", 1, 15),
+ FACTOR(CLK_TOP_MMPLL_D4, "mmpll_d4", "mmpll", 1, 4),
+ FACTOR(CLK_TOP_MMPLL_D6_D2, "mmpll_d6_d2", "mmpll", 1, 12),
+ FACTOR(CLK_TOP_MMPLL_D8, "mmpll_d8", "mmpll", 1, 8),
+ FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, 4),
+ FACTOR(CLK_TOP_NET1PLL_D4, "net1pll_d4", "net1pll", 1, 4),
+ FACTOR(CLK_TOP_NET1PLL_D5, "net1pll_d5", "net1pll", 1, 5),
+ FACTOR(CLK_TOP_NET1PLL_D5_D2, "net1pll_d5_d2", "net1pll", 1, 10),
+ FACTOR(CLK_TOP_NET1PLL_D5_D4, "net1pll_d5_d4", "net1pll", 1, 20),
+ FACTOR(CLK_TOP_NET1PLL_D8, "net1pll_d8", "net1pll", 1, 8),
+ FACTOR(CLK_TOP_NET1PLL_D8_D2, "net1pll_d8_d2", "net1pll", 1, 16),
+ FACTOR(CLK_TOP_NET1PLL_D8_D4, "net1pll_d8_d4", "net1pll", 1, 32),
+ FACTOR(CLK_TOP_NET1PLL_D8_D8, "net1pll_d8_d8", "net1pll", 1, 64),
+ FACTOR(CLK_TOP_NET1PLL_D8_D16, "net1pll_d8_d16", "net1pll", 1, 128),
+ FACTOR(CLK_TOP_NET2PLL_D2, "net2pll_d2", "net2pll", 1, 2),
+ FACTOR(CLK_TOP_NET2PLL_D4, "net2pll_d4", "net2pll", 1, 4),
+ FACTOR(CLK_TOP_NET2PLL_D4_D4, "net2pll_d4_d4", "net2pll", 1, 16),
+ FACTOR(CLK_TOP_NET2PLL_D4_D8, "net2pll_d4_d8", "net2pll", 1, 32),
+ FACTOR(CLK_TOP_NET2PLL_D6, "net2pll_d6", "net2pll", 1, 6),
+ FACTOR(CLK_TOP_NET2PLL_D8, "net2pll_d8", "net2pll", 1, 8),
+};
+
+static const char *const netsys_parents[] = { "top_xtal", "net2pll_d2", "mmpll_d2" };
+static const char *const netsys_500m_parents[] = { "top_xtal", "net1pll_d5", "net1pll_d5_d2" };
+static const char *const netsys_2x_parents[] = { "top_xtal", "net2pll", "mmpll" };
+static const char *const netsys_gsw_parents[] = { "top_xtal", "net1pll_d4", "net1pll_d5" };
+static const char *const eth_gmii_parents[] = { "top_xtal", "net1pll_d5_d4" };
+static const char *const netsys_mcu_parents[] = { "top_xtal", "net2pll", "mmpll",
+ "net1pll_d4", "net1pll_d5", "mpll" };
+static const char *const eip197_parents[] = { "top_xtal", "netsyspll", "net2pll",
+ "mmpll", "net1pll_d4", "net1pll_d5" };
+static const char *const axi_infra_parents[] = { "top_xtal", "net1pll_d8_d2" };
+static const char *const uart_parents[] = { "top_xtal", "mpll_d8", "mpll_d8_d2" };
+static const char *const emmc_250m_parents[] = { "top_xtal", "net1pll_d5_d2", "mmpll_d4" };
+static const char *const emmc_400m_parents[] = { "top_xtal", "msdcpll", "mmpll_d2",
+ "mpll_d2", "mmpll_d4", "net1pll_d8_d2" };
+static const char *const spi_parents[] = { "top_xtal", "mpll_d2", "mmpll_d4",
+ "net1pll_d8_d2", "net2pll_d6", "net1pll_d5_d4",
+ "mpll_d4", "net1pll_d8_d4" };
+static const char *const nfi1x_parents[] = { "top_xtal", "mmpll_d4", "net1pll_d8_d2", "net2pll_d6",
+ "mpll_d4", "mmpll_d8", "net1pll_d8_d4", "mpll_d8" };
+static const char *const spinfi_parents[] = { "top_xtal_d2", "top_xtal", "net1pll_d5_d4",
+ "mpll_d4", "mmpll_d8", "net1pll_d8_d4",
+ "mmpll_d6_d2", "mpll_d8" };
+static const char *const pwm_parents[] = { "top_xtal", "net1pll_d8_d2", "net1pll_d5_d4",
+ "mpll_d4", "mpll_d8_d2", "top_rtc_32k" };
+static const char *const i2c_parents[] = { "top_xtal", "net1pll_d5_d4", "mpll_d4",
+ "net1pll_d8_d4" };
+static const char *const pcie_mbist_250m_parents[] = { "top_xtal", "net1pll_d5_d2" };
+static const char *const pextp_tl_ck_parents[] = { "top_xtal", "net2pll_d6", "mmpll_d8",
+ "mpll_d8_d2", "top_rtc_32k" };
+static const char *const usb_frmcnt_parents[] = { "top_xtal", "mmpll_d3_d5" };
+static const char *const aud_parents[] = { "top_xtal", "apll2" };
+static const char *const a1sys_parents[] = { "top_xtal", "apll2_d4" };
+static const char *const aud_l_parents[] = { "top_xtal", "apll2", "mpll_d8_d2" };
+static const char *const sspxtp_parents[] = { "top_xtal_d2", "mpll_d8_d2" };
+static const char *const usxgmii_sbus_0_parents[] = { "top_xtal", "net1pll_d8_d4" };
+static const char *const sgm_0_parents[] = { "top_xtal", "sgmpll" };
+static const char *const sysapb_parents[] = { "top_xtal", "mpll_d3_d2" };
+static const char *const eth_refck_50m_parents[] = { "top_xtal", "net2pll_d4_d4" };
+static const char *const eth_sys_200m_parents[] = { "top_xtal", "net2pll_d4" };
+static const char *const eth_xgmii_parents[] = { "top_xtal_d2", "net1pll_d8_d8", "net1pll_d8_d16" };
+static const char *const bus_tops_parents[] = { "top_xtal", "net1pll_d5", "net2pll_d2" };
+static const char *const npu_tops_parents[] = { "top_xtal", "net2pll" };
+static const char *const dramc_md32_parents[] = { "top_xtal", "mpll_d2", "wedmcupll" };
+static const char *const da_xtp_glb_p0_parents[] = { "top_xtal", "net2pll_d8" };
+static const char *const mcusys_backup_625m_parents[] = { "top_xtal", "net1pll_d4" };
+static const char *const macsec_parents[] = { "top_xtal", "sgmpll", "net1pll_d8" };
+static const char *const netsys_tops_400m_parents[] = { "top_xtal", "net2pll_d2" };
+static const char *const eth_mii_parents[] = { "top_xtal_d2", "net2pll_d4_d8" };
+
+static const struct mtk_mux top_muxes[] = {
+ /* CLK_CFG_0 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_SEL, "netsys_sel", netsys_parents, 0x000, 0x004, 0x008,
+ 0, 2, 7, 0x1c0, 0),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_500M_SEL, "netsys_500m_sel", netsys_500m_parents, 0x000,
+ 0x004, 0x008, 8, 2, 15, 0x1C0, 1),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_2X_SEL, "netsys_2x_sel", netsys_2x_parents, 0x000,
+ 0x004, 0x008, 16, 2, 23, 0x1C0, 2),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_GSW_SEL, "netsys_gsw_sel", netsys_gsw_parents, 0x000,
+ 0x004, 0x008, 24, 2, 31, 0x1C0, 3),
+ /* CLK_CFG_1 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_GMII_SEL, "eth_gmii_sel", eth_gmii_parents, 0x010, 0x014,
+ 0x018, 0, 1, 7, 0x1C0, 4),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel", netsys_mcu_parents, 0x010,
+ 0x014, 0x018, 8, 3, 15, 0x1C0, 5),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_PAO_2X_SEL, "netsys_pao_2x_sel", netsys_mcu_parents,
+ 0x010, 0x014, 0x018, 16, 3, 23, 0x1C0, 6),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_EIP197_SEL, "eip197_sel", eip197_parents, 0x010, 0x014, 0x018,
+ 24, 3, 31, 0x1c0, 7),
+ /* CLK_CFG_2 */
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_AXI_INFRA_SEL, "axi_infra_sel", axi_infra_parents, 0x020,
+ 0x024, 0x028, 0, 1, 7, 0x1C0, 8, CLK_IS_CRITICAL),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x020, 0x024, 0x028, 8, 2,
+ 15, 0x1c0, 9),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_250M_SEL, "emmc_250m_sel", emmc_250m_parents, 0x020,
+ 0x024, 0x028, 16, 2, 23, 0x1C0, 10),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_400M_SEL, "emmc_400m_sel", emmc_400m_parents, 0x020,
+ 0x024, 0x028, 24, 3, 31, 0x1C0, 11),
+ /* CLK_CFG_3 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x030, 0x034, 0x038, 0, 3, 7,
+ 0x1c0, 12),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SPIM_MST_SEL, "spim_mst_sel", spi_parents, 0x030, 0x034, 0x038,
+ 8, 3, 15, 0x1c0, 13),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NFI1X_SEL, "nfi1x_sel", nfi1x_parents, 0x030, 0x034, 0x038, 16,
+ 3, 23, 0x1c0, 14),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SPINFI_SEL, "spinfi_sel", spinfi_parents, 0x030, 0x034, 0x038,
+ 24, 3, 31, 0x1c0, 15),
+ /* CLK_CFG_4 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x040, 0x044, 0x048, 0, 3, 7,
+ 0x1c0, 16),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_I2C_SEL, "i2c_sel", i2c_parents, 0x040, 0x044, 0x048, 8, 2, 15,
+ 0x1c0, 17),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PCIE_MBIST_250M_SEL, "pcie_mbist_250m_sel",
+ pcie_mbist_250m_parents, 0x040, 0x044, 0x048, 16, 1, 23, 0x1C0, 18),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_SEL, "pextp_tl_sel", pextp_tl_ck_parents, 0x040,
+ 0x044, 0x048, 24, 3, 31, 0x1C0, 19),
+ /* CLK_CFG_5 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_P1_SEL, "pextp_tl_p1_sel", pextp_tl_ck_parents, 0x050,
+ 0x054, 0x058, 0, 3, 7, 0x1C0, 20),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_P2_SEL, "pextp_tl_p2_sel", pextp_tl_ck_parents, 0x050,
+ 0x054, 0x058, 8, 3, 15, 0x1C0, 21),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_P3_SEL, "pextp_tl_p3_sel", pextp_tl_ck_parents, 0x050,
+ 0x054, 0x058, 16, 3, 23, 0x1C0, 22),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_SYS_SEL, "usb_sys_sel", eth_gmii_parents, 0x050, 0x054,
+ 0x058, 24, 1, 31, 0x1C0, 23),
+ /* CLK_CFG_6 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_SYS_P1_SEL, "usb_sys_p1_sel", eth_gmii_parents, 0x060,
+ 0x064, 0x068, 0, 1, 7, 0x1C0, 24),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_SEL, "usb_xhci_sel", eth_gmii_parents, 0x060, 0x064,
+ 0x068, 8, 1, 15, 0x1C0, 25),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P1_SEL, "usb_xhci_p1_sel", eth_gmii_parents, 0x060,
+ 0x064, 0x068, 16, 1, 23, 0x1C0, 26),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_FRMCNT_SEL, "usb_frmcnt_sel", usb_frmcnt_parents, 0x060,
+ 0x064, 0x068, 24, 1, 31, 0x1C0, 27),
+ /* CLK_CFG_7 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_FRMCNT_P1_SEL, "usb_frmcnt_p1_sel", usb_frmcnt_parents,
+ 0x070, 0x074, 0x078, 0, 1, 7, 0x1C0, 28),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_SEL, "aud_sel", aud_parents, 0x070, 0x074, 0x078, 8, 1, 15,
+ 0x1c0, 29),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents, 0x070, 0x074, 0x078, 16,
+ 1, 23, 0x1c0, 30),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents, 0x070, 0x074, 0x078, 24,
+ 2, 31, 0x1c4, 0),
+ /* CLK_CFG_8 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_A_TUNER_SEL, "a_tuner_sel", a1sys_parents, 0x080, 0x084, 0x088,
+ 0, 1, 7, 0x1c4, 1),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SSPXTP_SEL, "sspxtp_sel", sspxtp_parents, 0x080, 0x084, 0x088,
+ 8, 1, 15, 0x1c4, 2),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_PHY_SEL, "usb_phy_sel", sspxtp_parents, 0x080, 0x084,
+ 0x088, 16, 1, 23, 0x1c4, 3),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_USXGMII_SBUS_0_SEL, "usxgmii_sbus_0_sel",
+ usxgmii_sbus_0_parents, 0x080, 0x084, 0x088, 24, 1, 31, 0x1C4, 4),
+ /* CLK_CFG_9 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_USXGMII_SBUS_1_SEL, "usxgmii_sbus_1_sel",
+ usxgmii_sbus_0_parents, 0x090, 0x094, 0x098, 0, 1, 7, 0x1C4, 5),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_0_SEL, "sgm_0_sel", sgm_0_parents, 0x090, 0x094, 0x098, 8,
+ 1, 15, 0x1c4, 6),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_SBUS_0_SEL, "sgm_sbus_0_sel", usxgmii_sbus_0_parents,
+ 0x090, 0x094, 0x098, 16, 1, 23, 0x1C4, 7, CLK_IS_CRITICAL),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_1_SEL, "sgm_1_sel", sgm_0_parents, 0x090, 0x094, 0x098, 24,
+ 1, 31, 0x1c4, 8),
+ /* CLK_CFG_10 */
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_SBUS_1_SEL, "sgm_sbus_1_sel", usxgmii_sbus_0_parents,
+ 0x0a0, 0x0a4, 0x0a8, 0, 1, 7, 0x1C4, 9, CLK_IS_CRITICAL),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_XFI_PHY_0_XTAL_SEL, "xfi_phy_0_xtal_sel", sspxtp_parents,
+ 0x0a0, 0x0a4, 0x0a8, 8, 1, 15, 0x1C4, 10),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_XFI_PHY_1_XTAL_SEL, "xfi_phy_1_xtal_sel", sspxtp_parents,
+ 0x0a0, 0x0a4, 0x0a8, 16, 1, 23, 0x1C4, 11),
+ /* CLK_CFG_11 */
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAXI_SEL, "sysaxi_sel", axi_infra_parents, 0x0a0,
+ 0x0a4, 0x0a8, 24, 1, 31, 0x1C4, 12, CLK_IS_CRITICAL),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAPB_SEL, "sysapb_sel", sysapb_parents, 0x0b0, 0x0b4,
+ 0x0b8, 0, 1, 7, 0x1c4, 13, CLK_IS_CRITICAL),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_REFCK_50M_SEL, "eth_refck_50m_sel", eth_refck_50m_parents,
+ 0x0b0, 0x0b4, 0x0b8, 8, 1, 15, 0x1C4, 14),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_SYS_200M_SEL, "eth_sys_200m_sel", eth_sys_200m_parents,
+ 0x0b0, 0x0b4, 0x0b8, 16, 1, 23, 0x1C4, 15),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_SYS_SEL, "eth_sys_sel", pcie_mbist_250m_parents, 0x0b0,
+ 0x0b4, 0x0b8, 24, 1, 31, 0x1C4, 16),
+ /* CLK_CFG_12 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_XGMII_SEL, "eth_xgmii_sel", eth_xgmii_parents, 0x0c0,
+ 0x0c4, 0x0c8, 0, 2, 7, 0x1C4, 17),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_BUS_TOPS_SEL, "bus_tops_sel", bus_tops_parents, 0x0c0, 0x0c4,
+ 0x0c8, 8, 2, 15, 0x1C4, 18),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NPU_TOPS_SEL, "npu_tops_sel", npu_tops_parents, 0x0c0, 0x0c4,
+ 0x0c8, 16, 1, 23, 0x1C4, 19),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_SEL, "dramc_sel", sspxtp_parents, 0x0c0, 0x0c4,
+ 0x0c8, 24, 1, 31, 0x1C4, 20, CLK_IS_CRITICAL),
+ /* CLK_CFG_13 */
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel", dramc_md32_parents,
+ 0x0d0, 0x0d4, 0x0d8, 0, 2, 7, 0x1C4, 21, CLK_IS_CRITICAL),
+ MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_INFRA_F26M_SEL, "csw_infra_f26m_sel", sspxtp_parents,
+ 0x0d0, 0x0d4, 0x0d8, 8, 1, 15, 0x1C4, 22, CLK_IS_CRITICAL),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P0_SEL, "pextp_p0_sel", sspxtp_parents, 0x0d0, 0x0d4,
+ 0x0d8, 16, 1, 23, 0x1C4, 23),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P1_SEL, "pextp_p1_sel", sspxtp_parents, 0x0d0, 0x0d4,
+ 0x0d8, 24, 1, 31, 0x1C4, 24),
+ /* CLK_CFG_14 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P2_SEL, "pextp_p2_sel", sspxtp_parents, 0x0e0, 0x0e4,
+ 0x0e8, 0, 1, 7, 0x1C4, 25),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P3_SEL, "pextp_p3_sel", sspxtp_parents, 0x0e0, 0x0e4,
+ 0x0e8, 8, 1, 15, 0x1C4, 26),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P0_SEL, "da_xtp_glb_p0_sel", da_xtp_glb_p0_parents,
+ 0x0e0, 0x0e4, 0x0e8, 16, 1, 23, 0x1C4, 27),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P1_SEL, "da_xtp_glb_p1_sel", da_xtp_glb_p0_parents,
+ 0x0e0, 0x0e4, 0x0e8, 24, 1, 31, 0x1C4, 28),
+ /* CLK_CFG_15 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P2_SEL, "da_xtp_glb_p2_sel", da_xtp_glb_p0_parents,
+ 0x0f0, 0x0f4, 0x0f8, 0, 1, 7, 0x1C4, 29),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P3_SEL, "da_xtp_glb_p3_sel", da_xtp_glb_p0_parents,
+ 0x0f0, 0x0f4, 0x0f8, 8, 1, 15, 0x1C4, 30),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_CKM_SEL, "ckm_sel", sspxtp_parents, 0x0F0, 0x0f4, 0x0f8, 16, 1,
+ 23, 0x1c8, 0),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_SEL, "da_sel", sspxtp_parents, 0x0f0, 0x0f4, 0x0f8, 24, 1,
+ 31, 0x1C8, 1),
+ /* CLK_CFG_16 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_SEL, "pextp_sel", sspxtp_parents, 0x0100, 0x104, 0x108,
+ 0, 1, 7, 0x1c8, 2),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_TOPS_P2_26M_SEL, "tops_p2_26m_sel", sspxtp_parents, 0x0100,
+ 0x104, 0x108, 8, 1, 15, 0x1C8, 3),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_MCUSYS_BACKUP_625M_SEL, "mcusys_backup_625m_sel",
+ mcusys_backup_625m_parents, 0x0100, 0x104, 0x108, 16, 1, 23, 0x1C8, 4),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_SYNC_250M_SEL, "netsys_sync_250m_sel",
+ pcie_mbist_250m_parents, 0x0100, 0x104, 0x108, 24, 1, 31, 0x1c8, 5),
+ /* CLK_CFG_17 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_MACSEC_SEL, "macsec_sel", macsec_parents, 0x0110, 0x114, 0x118,
+ 0, 2, 7, 0x1c8, 6),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_TOPS_400M_SEL, "netsys_tops_400m_sel",
+ netsys_tops_400m_parents, 0x0110, 0x114, 0x118, 8, 1, 15, 0x1c8, 7),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_PPEFB_250M_SEL, "netsys_ppefb_250m_sel",
+ pcie_mbist_250m_parents, 0x0110, 0x114, 0x118, 16, 1, 23, 0x1c8, 8),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_WARP_SEL, "netsys_warp_sel", netsys_parents, 0x0110,
+ 0x114, 0x118, 24, 2, 31, 0x1C8, 9),
+ /* CLK_CFG_18 */
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_MII_SEL, "eth_mii_sel", eth_mii_parents, 0x0120, 0x124,
+ 0x128, 0, 1, 7, 0x1c8, 10),
+ MUX_GATE_CLR_SET_UPD(CLK_TOP_NPU_SEL, "ck_npu_sel", netsys_2x_parents, 0x0120, 0x124, 0x128,
+ 8, 2, 15, 0x1c8, 11),
+};
+
+static const struct mtk_composite top_aud_divs[] = {
+ DIV_GATE(CLK_TOP_AUD_I2S_M, "aud_i2s_m", "aud_sel", 0x0420, 0, 0x0420, 8, 8),
+};
+
+static const struct mtk_clk_desc topck_desc = {
+ .fixed_clks = top_fixed_clks,
+ .num_fixed_clks = ARRAY_SIZE(top_fixed_clks),
+ .factor_clks = top_divs,
+ .num_factor_clks = ARRAY_SIZE(top_divs),
+ .mux_clks = top_muxes,
+ .num_mux_clks = ARRAY_SIZE(top_muxes),
+ .composite_clks = top_aud_divs,
+ .num_composite_clks = ARRAY_SIZE(top_aud_divs),
+ .clk_lock = &mt7988_clk_lock,
+};
+
+static const char *const mcu_bus_div_parents[] = { "top_xtal", "ccipll2_b", "net1pll_d4" };
+
+static const char *const mcu_arm_div_parents[] = { "top_xtal", "arm_b", "net1pll_d4" };
+
+static struct mtk_composite mcu_muxes[] = {
+ /* bus_pll_divider_cfg */
+ MUX_GATE_FLAGS(CLK_MCU_BUS_DIV_SEL, "mcu_bus_div_sel", mcu_bus_div_parents, 0x7C0, 9, 2, -1,
+ CLK_IS_CRITICAL),
+ /* mp2_pll_divider_cfg */
+ MUX_GATE_FLAGS(CLK_MCU_ARM_DIV_SEL, "mcu_arm_div_sel", mcu_arm_div_parents, 0x7A8, 9, 2, -1,
+ CLK_IS_CRITICAL),
+};
+
+static const struct mtk_clk_desc mcusys_desc = {
+ .composite_clks = mcu_muxes,
+ .num_composite_clks = ARRAY_SIZE(mcu_muxes),
+};
+
+static const struct of_device_id of_match_clk_mt7988_topckgen[] = {
+ { .compatible = "mediatek,mt7988-topckgen", .data = &topck_desc },
+ { .compatible = "mediatek,mt7988-mcusys", .data = &mcusys_desc },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_topckgen);
+
+static struct platform_driver clk_mt7988_topckgen_drv = {
+ .probe = mtk_clk_simple_probe,
+ .remove_new = mtk_clk_simple_remove,
+ .driver = {
+ .name = "clk-mt7988-topckgen",
+ .of_match_table = of_match_clk_mt7988_topckgen,
+ },
+};
+module_platform_driver(clk_mt7988_topckgen_drv);
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt7988-xfipll.c b/drivers/clk/mediatek/clk-mt7988-xfipll.c
new file mode 100644
index 000000000000..9b9ca5471158
--- /dev/null
+++ b/drivers/clk/mediatek/clk-mt7988-xfipll.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023 Daniel Golle <[email protected]>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "clk-mtk.h"
+#include "clk-gate.h"
+#include <dt-bindings/clock/mediatek,mt7988-clk.h>
+
+/* Register to control USXGMII XFI PLL analog */
+#define XFI_PLL_ANA_GLB8 0x108
+#define RG_XFI_PLL_ANA_SWWA 0x02283248
+
+static const struct mtk_gate_regs xfipll_cg_regs = {
+ .set_ofs = 0x8,
+ .clr_ofs = 0x8,
+ .sta_ofs = 0x8,
+};
+
+#define GATE_XFIPLL(_id, _name, _parent, _shift) \
+ { \
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .regs = &xfipll_cg_regs, \
+ .shift = _shift, \
+ .ops = &mtk_clk_gate_ops_no_setclr_inv, \
+ }
+
+static const struct mtk_fixed_factor xfipll_divs[] = {
+ FACTOR(CLK_XFIPLL_PLL, "xfipll_pll", "top_xtal", 125, 32),
+};
+
+static const struct mtk_gate xfipll_clks[] = {
+ GATE_XFIPLL(CLK_XFIPLL_PLL_EN, "xfipll_pll_en", "xfipll_pll", 31),
+};
+
+static const struct mtk_clk_desc xfipll_desc = {
+ .clks = xfipll_clks,
+ .num_clks = ARRAY_SIZE(xfipll_clks),
+ .factor_clks = xfipll_divs,
+ .num_factor_clks = ARRAY_SIZE(xfipll_divs),
+};
+
+static int clk_mt7988_xfipll_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ void __iomem *base = of_iomap(node, 0);
+
+ if (!base)
+ return -ENOMEM;
+
+ /* Apply software workaround for USXGMII PLL TCL issue */
+ writel(RG_XFI_PLL_ANA_SWWA, base + XFI_PLL_ANA_GLB8);
+ iounmap(base);
+
+ return mtk_clk_simple_probe(pdev);
+};
+
+static const struct of_device_id of_match_clk_mt7988_xfipll[] = {
+ { .compatible = "mediatek,mt7988-xfi-pll", .data = &xfipll_desc },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_xfipll);
+
+static struct platform_driver clk_mt7988_xfipll_drv = {
+ .driver = {
+ .name = "clk-mt7988-xfipll",
+ .of_match_table = of_match_clk_mt7988_xfipll,
+ },
+ .probe = clk_mt7988_xfipll_probe,
+ .remove_new = mtk_clk_simple_remove,
+};
+module_platform_driver(clk_mt7988_xfipll_drv);
+
+MODULE_DESCRIPTION("MediaTek MT7988 XFI PLL clock driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/mediatek/clk-mt8188-topckgen.c b/drivers/clk/mediatek/clk-mt8188-topckgen.c
index e330a4f9a0c3..f7ec599b20af 100644
--- a/drivers/clk/mediatek/clk-mt8188-topckgen.c
+++ b/drivers/clk/mediatek/clk-mt8188-topckgen.c
@@ -475,29 +475,28 @@ static const char * const sspm_parents[] = {
"mainpll_d4_d2"
};
+/*
+ * Both DP/eDP can be parented to TVDPLL1 and TVDPLL2, but we force using
+ * TVDPLL1 on eDP and TVDPLL2 on DP to avoid changing the "other" PLL rate
+ * in dual output case, which would lead to corruption of functionality loss.
+ */
static const char * const dp_parents[] = {
"clk26m",
- "tvdpll1_d2",
"tvdpll2_d2",
- "tvdpll1_d4",
"tvdpll2_d4",
- "tvdpll1_d8",
"tvdpll2_d8",
- "tvdpll1_d16",
"tvdpll2_d16"
};
+static const u8 dp_parents_idx[] = { 0, 2, 4, 6, 8 };
static const char * const edp_parents[] = {
"clk26m",
"tvdpll1_d2",
- "tvdpll2_d2",
"tvdpll1_d4",
- "tvdpll2_d4",
"tvdpll1_d8",
- "tvdpll2_d8",
- "tvdpll1_d16",
- "tvdpll2_d16"
+ "tvdpll1_d16"
};
+static const u8 edp_parents_idx[] = { 0, 1, 3, 5, 7 };
static const char * const dpi_parents[] = {
"clk26m",
@@ -1038,10 +1037,12 @@ static const struct mtk_mux top_mtk_muxes[] = {
MUX_GATE_CLR_SET_UPD(CLK_TOP_SSPM, "top_sspm",
sspm_parents, 0x080, 0x084, 0x088, 24, 4, 31, 0x08, 3),
/* CLK_CFG_9 */
- MUX_GATE_CLR_SET_UPD(CLK_TOP_DP, "top_dp",
- dp_parents, 0x08C, 0x090, 0x094, 0, 4, 7, 0x08, 4),
- MUX_GATE_CLR_SET_UPD(CLK_TOP_EDP, "top_edp",
- edp_parents, 0x08C, 0x090, 0x094, 8, 4, 15, 0x08, 5),
+ MUX_GATE_CLR_SET_UPD_INDEXED(CLK_TOP_DP, "top_dp",
+ dp_parents, dp_parents_idx, 0x08C, 0x090, 0x094,
+ 0, 4, 7, 0x08, 4),
+ MUX_GATE_CLR_SET_UPD_INDEXED(CLK_TOP_EDP, "top_edp",
+ edp_parents, edp_parents_idx, 0x08C, 0x090, 0x094,
+ 8, 4, 15, 0x08, 5),
MUX_GATE_CLR_SET_UPD(CLK_TOP_DPI, "top_dpi",
dpi_parents, 0x08C, 0x090, 0x094, 16, 4, 23, 0x08, 6),
MUX_GATE_CLR_SET_UPD(CLK_TOP_DISP_PWM0, "top_disp_pwm0",
diff --git a/drivers/clk/mediatek/clk-mt8195-topckgen.c b/drivers/clk/mediatek/clk-mt8195-topckgen.c
index 5c426a1c94c7..8f713a3341a9 100644
--- a/drivers/clk/mediatek/clk-mt8195-topckgen.c
+++ b/drivers/clk/mediatek/clk-mt8195-topckgen.c
@@ -415,17 +415,28 @@ static const char * const pwrmcu_parents[] = {
"mainpll_d4_d2"
};
+/*
+ * Both DP/eDP can be parented to TVDPLL1 and TVDPLL2, but we force using
+ * TVDPLL1 on eDP and TVDPLL2 on DP to avoid changing the "other" PLL rate
+ * in dual output case, which would lead to corruption of functionality loss.
+ */
static const char * const dp_parents[] = {
"clk26m",
- "tvdpll1_d2",
"tvdpll2_d2",
- "tvdpll1_d4",
"tvdpll2_d4",
- "tvdpll1_d8",
"tvdpll2_d8",
- "tvdpll1_d16",
"tvdpll2_d16"
};
+static const u8 dp_parents_idx[] = { 0, 2, 4, 6, 8 };
+
+static const char * const edp_parents[] = {
+ "clk26m",
+ "tvdpll1_d2",
+ "tvdpll1_d4",
+ "tvdpll1_d8",
+ "tvdpll1_d16"
+};
+static const u8 edp_parents_idx[] = { 0, 1, 3, 5, 7 };
static const char * const disp_pwm_parents[] = {
"clk26m",
@@ -957,11 +968,11 @@ static const struct mtk_mux top_mtk_muxes[] = {
MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_PWRMCU, "top_pwrmcu",
pwrmcu_parents, 0x08C, 0x090, 0x094, 16, 3, 23, 0x08, 6,
CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
- MUX_GATE_CLR_SET_UPD(CLK_TOP_DP, "top_dp",
- dp_parents, 0x08C, 0x090, 0x094, 24, 4, 31, 0x08, 7),
+ MUX_GATE_CLR_SET_UPD_INDEXED(CLK_TOP_DP, "top_dp",
+ dp_parents, dp_parents_idx, 0x08C, 0x090, 0x094, 24, 4, 31, 0x08, 7),
/* CLK_CFG_10 */
- MUX_GATE_CLR_SET_UPD(CLK_TOP_EDP, "top_edp",
- dp_parents, 0x098, 0x09C, 0x0A0, 0, 4, 7, 0x08, 8),
+ MUX_GATE_CLR_SET_UPD_INDEXED(CLK_TOP_EDP, "top_edp",
+ edp_parents, edp_parents_idx, 0x098, 0x09C, 0x0A0, 0, 4, 7, 0x08, 8),
MUX_GATE_CLR_SET_UPD(CLK_TOP_DPI, "top_dpi",
dp_parents, 0x098, 0x09C, 0x0A0, 8, 4, 15, 0x08, 9),
MUX_GATE_CLR_SET_UPD(CLK_TOP_DISP_PWM0, "top_disp_pwm0",
diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c
index c93bc7f926e5..60990296450b 100644
--- a/drivers/clk/mediatek/clk-mux.c
+++ b/drivers/clk/mediatek/clk-mux.c
@@ -89,6 +89,17 @@ static u8 mtk_clk_mux_get_parent(struct clk_hw *hw)
regmap_read(mux->regmap, mux->data->mux_ofs, &val);
val = (val >> mux->data->mux_shift) & mask;
+ if (mux->data->parent_index) {
+ int i;
+
+ for (i = 0; i < mux->data->num_parents; i++)
+ if (mux->data->parent_index[i] == val)
+ return i;
+
+ /* Not found: return an impossible index to generate error */
+ return mux->data->num_parents + 1;
+ }
+
return val;
}
@@ -104,6 +115,9 @@ static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index)
else
__acquire(mux->lock);
+ if (mux->data->parent_index)
+ index = mux->data->parent_index[index];
+
regmap_read(mux->regmap, mux->data->mux_ofs, &orig);
val = (orig & ~(mask << mux->data->mux_shift))
| (index << mux->data->mux_shift);
diff --git a/drivers/clk/mediatek/clk-mux.h b/drivers/clk/mediatek/clk-mux.h
index 7ecb963b0ec6..943ad1d7ce4b 100644
--- a/drivers/clk/mediatek/clk-mux.h
+++ b/drivers/clk/mediatek/clk-mux.h
@@ -21,6 +21,7 @@ struct mtk_mux {
int id;
const char *name;
const char * const *parent_names;
+ const u8 *parent_index;
unsigned int flags;
u32 mux_ofs;
@@ -37,9 +38,10 @@ struct mtk_mux {
signed char num_parents;
};
-#define GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \
- _mux_set_ofs, _mux_clr_ofs, _shift, _width, \
- _gate, _upd_ofs, _upd, _flags, _ops) { \
+#define __GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _paridx, \
+ _num_parents, _mux_ofs, _mux_set_ofs, \
+ _mux_clr_ofs, _shift, _width, _gate, _upd_ofs, \
+ _upd, _flags, _ops) { \
.id = _id, \
.name = _name, \
.mux_ofs = _mux_ofs, \
@@ -51,11 +53,28 @@ struct mtk_mux {
.gate_shift = _gate, \
.upd_shift = _upd, \
.parent_names = _parents, \
- .num_parents = ARRAY_SIZE(_parents), \
+ .parent_index = _paridx, \
+ .num_parents = _num_parents, \
.flags = _flags, \
.ops = &_ops, \
}
+#define GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \
+ _mux_set_ofs, _mux_clr_ofs, _shift, _width, \
+ _gate, _upd_ofs, _upd, _flags, _ops) \
+ __GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, \
+ NULL, ARRAY_SIZE(_parents), _mux_ofs, \
+ _mux_set_ofs, _mux_clr_ofs, _shift, _width, \
+ _gate, _upd_ofs, _upd, _flags, _ops) \
+
+#define GATE_CLR_SET_UPD_FLAGS_INDEXED(_id, _name, _parents, _paridx, \
+ _mux_ofs, _mux_set_ofs, _mux_clr_ofs, _shift, \
+ _width, _gate, _upd_ofs, _upd, _flags, _ops) \
+ __GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, \
+ _paridx, ARRAY_SIZE(_paridx), _mux_ofs, \
+ _mux_set_ofs, _mux_clr_ofs, _shift, _width, \
+ _gate, _upd_ofs, _upd, _flags, _ops) \
+
extern const struct clk_ops mtk_mux_clr_set_upd_ops;
extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops;
@@ -67,6 +86,14 @@ extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops;
_gate, _upd_ofs, _upd, _flags, \
mtk_mux_gate_clr_set_upd_ops)
+#define MUX_GATE_CLR_SET_UPD_FLAGS_INDEXED(_id, _name, _parents, \
+ _paridx, _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \
+ _shift, _width, _gate, _upd_ofs, _upd, _flags) \
+ GATE_CLR_SET_UPD_FLAGS_INDEXED(_id, _name, _parents, \
+ _paridx, _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \
+ _shift, _width, _gate, _upd_ofs, _upd, _flags, \
+ mtk_mux_gate_clr_set_upd_ops)
+
#define MUX_GATE_CLR_SET_UPD(_id, _name, _parents, _mux_ofs, \
_mux_set_ofs, _mux_clr_ofs, _shift, _width, \
_gate, _upd_ofs, _upd) \
@@ -75,6 +102,14 @@ extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops;
_width, _gate, _upd_ofs, _upd, \
CLK_SET_RATE_PARENT)
+#define MUX_GATE_CLR_SET_UPD_INDEXED(_id, _name, _parents, _paridx, \
+ _mux_ofs, _mux_set_ofs, _mux_clr_ofs, _shift, \
+ _width, _gate, _upd_ofs, _upd) \
+ MUX_GATE_CLR_SET_UPD_FLAGS_INDEXED(_id, _name, \
+ _parents, _paridx, _mux_ofs, _mux_set_ofs, \
+ _mux_clr_ofs, _shift, _width, _gate, _upd_ofs, \
+ _upd, CLK_SET_RATE_PARENT)
+
#define MUX_CLR_SET_UPD(_id, _name, _parents, _mux_ofs, \
_mux_set_ofs, _mux_clr_ofs, _shift, _width, \
_upd_ofs, _upd) \
diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c
index 513ab6b1b322..ce453e1718e5 100644
--- a/drivers/clk/mediatek/clk-pll.c
+++ b/drivers/clk/mediatek/clk-pll.c
@@ -23,7 +23,7 @@
#define CON0_BASE_EN BIT(0)
#define CON0_PWR_ON BIT(0)
#define CON0_ISO_EN BIT(1)
-#define PCW_CHG_MASK BIT(31)
+#define PCW_CHG_BIT 31
#define AUDPLL_TUNER_EN BIT(31)
@@ -114,7 +114,8 @@ static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw,
pll->data->pcw_shift);
val |= pcw << pll->data->pcw_shift;
writel(val, pll->pcw_addr);
- chg = readl(pll->pcw_chg_addr) | PCW_CHG_MASK;
+ chg = readl(pll->pcw_chg_addr) |
+ BIT(pll->data->pcw_chg_bit ? : PCW_CHG_BIT);
writel(chg, pll->pcw_chg_addr);
if (pll->tuner_addr)
writel(val + 1, pll->tuner_addr);
diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h
index f17278ff15d7..285c8db958b3 100644
--- a/drivers/clk/mediatek/clk-pll.h
+++ b/drivers/clk/mediatek/clk-pll.h
@@ -48,6 +48,7 @@ struct mtk_pll_data {
const char *parent_name;
u32 en_reg;
u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */
+ u8 pcw_chg_bit;
};
/*
diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c
index f373a8d48b1d..90f4c6103014 100644
--- a/drivers/clk/meson/g12a.c
+++ b/drivers/clk/meson/g12a.c
@@ -3549,6 +3549,22 @@ static struct clk_regmap g12a_cts_encp_sel = {
},
};
+static struct clk_regmap g12a_cts_encl_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_VIID_CLK_DIV,
+ .mask = 0xf,
+ .shift = 12,
+ .table = mux_table_cts_sel,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cts_encl_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_hws = g12a_cts_parent_hws,
+ .num_parents = ARRAY_SIZE(g12a_cts_parent_hws),
+ .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+ },
+};
+
static struct clk_regmap g12a_cts_vdac_sel = {
.data = &(struct clk_regmap_mux_data){
.offset = HHI_VIID_CLK_DIV,
@@ -3628,6 +3644,22 @@ static struct clk_regmap g12a_cts_encp = {
},
};
+static struct clk_regmap g12a_cts_encl = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = HHI_VID_CLK_CNTL2,
+ .bit_idx = 3,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "cts_encl",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &g12a_cts_encl_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ },
+};
+
static struct clk_regmap g12a_cts_vdac = {
.data = &(struct clk_regmap_gate_data){
.offset = HHI_VID_CLK_CNTL2,
@@ -3722,6 +3754,66 @@ static struct clk_regmap g12a_mipi_dsi_pxclk = {
},
};
+/* MIPI ISP Clocks */
+
+static const struct clk_parent_data g12b_mipi_isp_parent_data[] = {
+ { .fw_name = "xtal", },
+ { .hw = &g12a_gp0_pll.hw },
+ { .hw = &g12a_hifi_pll.hw },
+ { .hw = &g12a_fclk_div2p5.hw },
+ { .hw = &g12a_fclk_div3.hw },
+ { .hw = &g12a_fclk_div4.hw },
+ { .hw = &g12a_fclk_div5.hw },
+ { .hw = &g12a_fclk_div7.hw },
+};
+
+static struct clk_regmap g12b_mipi_isp_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = HHI_ISP_CLK_CNTL,
+ .mask = 7,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "mipi_isp_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = g12b_mipi_isp_parent_data,
+ .num_parents = ARRAY_SIZE(g12b_mipi_isp_parent_data),
+ },
+};
+
+static struct clk_regmap g12b_mipi_isp_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = HHI_ISP_CLK_CNTL,
+ .shift = 0,
+ .width = 7,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "mipi_isp_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &g12b_mipi_isp_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap g12b_mipi_isp = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = HHI_ISP_CLK_CNTL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "mipi_isp",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &g12b_mipi_isp_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
/* HDMI Clocks */
static const struct clk_parent_data g12a_hdmi_parent_data[] = {
@@ -4214,9 +4306,12 @@ static MESON_GATE(g12a_htx_hdcp22, HHI_GCLK_MPEG2, 3);
static MESON_GATE(g12a_htx_pclk, HHI_GCLK_MPEG2, 4);
static MESON_GATE(g12a_bt656, HHI_GCLK_MPEG2, 6);
static MESON_GATE(g12a_usb1_to_ddr, HHI_GCLK_MPEG2, 8);
+static MESON_GATE(g12b_mipi_isp_gate, HHI_GCLK_MPEG2, 17);
static MESON_GATE(g12a_mmc_pclk, HHI_GCLK_MPEG2, 11);
static MESON_GATE(g12a_uart2, HHI_GCLK_MPEG2, 15);
static MESON_GATE(g12a_vpu_intr, HHI_GCLK_MPEG2, 25);
+static MESON_GATE(g12b_csi_phy1, HHI_GCLK_MPEG2, 28);
+static MESON_GATE(g12b_csi_phy0, HHI_GCLK_MPEG2, 29);
static MESON_GATE(g12a_gic, HHI_GCLK_MPEG2, 30);
static MESON_GATE(g12a_vclk2_venci0, HHI_GCLK_OTHER, 1);
@@ -4407,10 +4502,12 @@ static struct clk_hw *g12a_hw_clks[] = {
[CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw,
[CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw,
[CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw,
+ [CLKID_CTS_ENCL_SEL] = &g12a_cts_encl_sel.hw,
[CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw,
[CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw,
[CLKID_CTS_ENCI] = &g12a_cts_enci.hw,
[CLKID_CTS_ENCP] = &g12a_cts_encp.hw,
+ [CLKID_CTS_ENCL] = &g12a_cts_encl.hw,
[CLKID_CTS_VDAC] = &g12a_cts_vdac.hw,
[CLKID_HDMI_TX] = &g12a_hdmi_tx.hw,
[CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw,
@@ -4632,10 +4729,12 @@ static struct clk_hw *g12b_hw_clks[] = {
[CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw,
[CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw,
[CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw,
+ [CLKID_CTS_ENCL_SEL] = &g12a_cts_encl_sel.hw,
[CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw,
[CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw,
[CLKID_CTS_ENCI] = &g12a_cts_enci.hw,
[CLKID_CTS_ENCP] = &g12a_cts_encp.hw,
+ [CLKID_CTS_ENCL] = &g12a_cts_encl.hw,
[CLKID_CTS_VDAC] = &g12a_cts_vdac.hw,
[CLKID_HDMI_TX] = &g12a_hdmi_tx.hw,
[CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw,
@@ -4729,6 +4828,12 @@ static struct clk_hw *g12b_hw_clks[] = {
[CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw,
[CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw,
[CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw,
+ [CLKID_MIPI_ISP_SEL] = &g12b_mipi_isp_sel.hw,
+ [CLKID_MIPI_ISP_DIV] = &g12b_mipi_isp_div.hw,
+ [CLKID_MIPI_ISP] = &g12b_mipi_isp.hw,
+ [CLKID_MIPI_ISP_GATE] = &g12b_mipi_isp_gate.hw,
+ [CLKID_MIPI_ISP_CSI_PHY0] = &g12b_csi_phy0.hw,
+ [CLKID_MIPI_ISP_CSI_PHY1] = &g12b_csi_phy1.hw,
};
static struct clk_hw *sm1_hw_clks[] = {
@@ -4892,10 +4997,12 @@ static struct clk_hw *sm1_hw_clks[] = {
[CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw,
[CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw,
[CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw,
+ [CLKID_CTS_ENCL_SEL] = &g12a_cts_encl_sel.hw,
[CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw,
[CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw,
[CLKID_CTS_ENCI] = &g12a_cts_enci.hw,
[CLKID_CTS_ENCP] = &g12a_cts_encp.hw,
+ [CLKID_CTS_ENCL] = &g12a_cts_encl.hw,
[CLKID_CTS_VDAC] = &g12a_cts_vdac.hw,
[CLKID_HDMI_TX] = &g12a_hdmi_tx.hw,
[CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw,
@@ -5123,10 +5230,12 @@ static struct clk_regmap *const g12a_clk_regmaps[] = {
&g12a_vclk2_div12_en,
&g12a_cts_enci_sel,
&g12a_cts_encp_sel,
+ &g12a_cts_encl_sel,
&g12a_cts_vdac_sel,
&g12a_hdmi_tx_sel,
&g12a_cts_enci,
&g12a_cts_encp,
+ &g12a_cts_encl,
&g12a_cts_vdac,
&g12a_hdmi_tx,
&g12a_hdmi_sel,
@@ -5221,6 +5330,12 @@ static struct clk_regmap *const g12a_clk_regmaps[] = {
&g12a_mipi_dsi_pxclk_sel,
&g12a_mipi_dsi_pxclk_div,
&g12a_mipi_dsi_pxclk,
+ &g12b_mipi_isp_sel,
+ &g12b_mipi_isp_div,
+ &g12b_mipi_isp,
+ &g12b_mipi_isp_gate,
+ &g12b_csi_phy1,
+ &g12b_csi_phy0,
};
static const struct reg_sequence g12a_init_regs[] = {
diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h
index f11ee3c59849..27df99c4565a 100644
--- a/drivers/clk/meson/g12a.h
+++ b/drivers/clk/meson/g12a.h
@@ -70,6 +70,7 @@
#define HHI_MALI_CLK_CNTL 0x1b0
#define HHI_VPU_CLKC_CNTL 0x1b4
#define HHI_VPU_CLK_CNTL 0x1bC
+#define HHI_ISP_CLK_CNTL 0x1C0
#define HHI_NNA_CLK_CNTL 0x1C8
#define HHI_HDMI_CLK_CNTL 0x1CC
#define HHI_VDEC_CLK_CNTL 0x1E0
diff --git a/drivers/clk/microchip/clk-mpfs-ccc.c b/drivers/clk/microchip/clk-mpfs-ccc.c
index bce61c45e967..3a3ea2d142f8 100644
--- a/drivers/clk/microchip/clk-mpfs-ccc.c
+++ b/drivers/clk/microchip/clk-mpfs-ccc.c
@@ -4,8 +4,8 @@
*
* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries
*/
-#include "asm-generic/errno-base.h"
#include <linux/clk-provider.h>
+#include <linux/errno.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c
index fb0df64cf053..c5a7ba1deaa3 100644
--- a/drivers/clk/mmp/clk-of-pxa168.c
+++ b/drivers/clk/mmp/clk-of-pxa168.c
@@ -308,18 +308,21 @@ static void __init pxa168_clk_init(struct device_node *np)
pxa_unit->mpmu_base = of_iomap(np, 0);
if (!pxa_unit->mpmu_base) {
pr_err("failed to map mpmu registers\n");
+ kfree(pxa_unit);
return;
}
pxa_unit->apmu_base = of_iomap(np, 1);
if (!pxa_unit->apmu_base) {
pr_err("failed to map apmu registers\n");
+ kfree(pxa_unit);
return;
}
pxa_unit->apbc_base = of_iomap(np, 2);
if (!pxa_unit->apbc_base) {
pr_err("failed to map apbc registers\n");
+ kfree(pxa_unit);
return;
}
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index dbc3950c5960..2a9da0939377 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -20,6 +20,16 @@ menuconfig COMMON_CLK_QCOM
if COMMON_CLK_QCOM
+config CLK_X1E80100_GCC
+ tristate "X1E80100 Global Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ select QCOM_GDSC
+ help
+ Support for the global clock controller on Qualcomm Technologies, Inc
+ X1E80100 devices.
+ Say Y if you want to use peripheral devices such as UART, SPI, I2C,
+ USB, UFS, SD/eMMC, PCIe, etc.
+
config QCOM_A53PLL
tristate "MSM8916 A53 PLL"
help
@@ -427,6 +437,15 @@ config SC_CAMCC_7280
Say Y if you want to support camera devices and functionality such as
capturing pictures.
+config SC_CAMCC_8280XP
+ tristate "SC8280XP Camera Clock Controller"
+ select SC_GCC_8280XP
+ help
+ Support for the camera clock controller on Qualcomm Technologies, Inc
+ SC8280XP devices.
+ Say Y if you want to support camera devices and functionality such as
+ capturing pictures.
+
config SC_DISPCC_7180
tristate "SC7180 Display Clock Controller"
depends on ARM64 || COMPILE_TEST
@@ -668,6 +687,15 @@ config QDU_GCC_1000
QRU1000 devices. Say Y if you want to use peripheral
devices such as UART, SPI, I2C, USB, SD, PCIe, etc.
+config QDU_ECPRICC_1000
+ tristate "QDU1000/QRU1000 ECPRI Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ select QDU_GCC_1000
+ help
+ Support for the ECPRI clock controller on QDU1000 and
+ QRU1000 devices. Say Y if you want to support the ECPRI
+ clock controller functionality such as Ethernet.
+
config SDM_GCC_845
tristate "SDM845/SDM670 Global Clock Controller"
depends on ARM64 || COMPILE_TEST
@@ -843,6 +871,16 @@ config SM_DISPCC_8550
Say Y if you want to support display devices and functionality such as
splash screen.
+config SM_DISPCC_8650
+ tristate "SM8650 Display Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ select SM_GCC_8650
+ help
+ Support for the display clock controller on Qualcomm Technologies, Inc
+ SM8650 devices.
+ Say Y if you want to support display devices and functionality such as
+ splash screen.
+
config SM_GCC_4450
tristate "SM4450 Global Clock Controller"
depends on ARM64 || COMPILE_TEST
@@ -939,6 +977,15 @@ config SM_GCC_8550
Say Y if you want to use peripheral devices such as UART,
SPI, I2C, USB, SD/UFS, PCIe etc.
+config SM_GCC_8650
+ tristate "SM8650 Global Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ select QCOM_GDSC
+ help
+ Support for the global clock controller on SM8650 devices.
+ Say Y if you want to use peripheral devices such as UART,
+ SPI, I2C, USB, SD/UFS, PCIe etc.
+
config SM_GPUCC_6115
tristate "SM6115 Graphics Clock Controller"
select SM_GCC_6115
@@ -1020,6 +1067,14 @@ config SM_GPUCC_8550
Say Y if you want to support graphics controller devices and
functionality such as 3D graphics.
+config SM_GPUCC_8650
+ tristate "SM8650 Graphics Clock Controller"
+ select SM_GCC_8650
+ help
+ Support for the graphics clock controller on SM8650 devices.
+ Say Y if you want to support graphics controller devices and
+ functionality such as 3D graphics.
+
config SM_TCSRCC_8550
tristate "SM8550 TCSR Clock Controller"
depends on ARM64 || COMPILE_TEST
@@ -1028,6 +1083,14 @@ config SM_TCSRCC_8550
Support for the TCSR clock controller on SM8550 devices.
Say Y if you want to use peripheral devices such as SD/UFS.
+config SM_TCSRCC_8650
+ tristate "SM8650 TCSR Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ select QCOM_GDSC
+ help
+ Support for the TCSR clock controller on SM8650 devices.
+ Say Y if you want to use peripheral devices such as SD/UFS.
+
config SM_VIDEOCC_8150
tristate "SM8150 Video Clock Controller"
depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 17edd73f9839..582e06dc1d93 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -21,6 +21,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o
+obj-$(CONFIG_CLK_X1E80100_GCC) += gcc-x1e80100.o
obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o
obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o
obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o
@@ -65,9 +66,11 @@ obj-$(CONFIG_QCM_DISPCC_2290) += dispcc-qcm2290.o
obj-$(CONFIG_QCS_GCC_404) += gcc-qcs404.o
obj-$(CONFIG_QCS_Q6SSTOP_404) += q6sstop-qcs404.o
obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o
+obj-$(CONFIG_QDU_ECPRICC_1000) += ecpricc-qdu1000.o
obj-$(CONFIG_QDU_GCC_1000) += gcc-qdu1000.o
obj-$(CONFIG_SC_CAMCC_7180) += camcc-sc7180.o
obj-$(CONFIG_SC_CAMCC_7280) += camcc-sc7280.o
+obj-$(CONFIG_SC_CAMCC_8280XP) += camcc-sc8280xp.o
obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o
obj-$(CONFIG_SC_DISPCC_7280) += dispcc-sc7280.o
obj-$(CONFIG_SC_DISPCC_8280XP) += dispcc-sc8280xp.o
@@ -110,6 +113,7 @@ obj-$(CONFIG_SM_DISPCC_6375) += dispcc-sm6375.o
obj-$(CONFIG_SM_DISPCC_8250) += dispcc-sm8250.o
obj-$(CONFIG_SM_DISPCC_8450) += dispcc-sm8450.o
obj-$(CONFIG_SM_DISPCC_8550) += dispcc-sm8550.o
+obj-$(CONFIG_SM_DISPCC_8650) += dispcc-sm8650.o
obj-$(CONFIG_SM_GCC_4450) += gcc-sm4450.o
obj-$(CONFIG_SM_GCC_6115) += gcc-sm6115.o
obj-$(CONFIG_SM_GCC_6125) += gcc-sm6125.o
@@ -121,6 +125,7 @@ obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o
obj-$(CONFIG_SM_GCC_8350) += gcc-sm8350.o
obj-$(CONFIG_SM_GCC_8450) += gcc-sm8450.o
obj-$(CONFIG_SM_GCC_8550) += gcc-sm8550.o
+obj-$(CONFIG_SM_GCC_8650) += gcc-sm8650.o
obj-$(CONFIG_SM_GPUCC_6115) += gpucc-sm6115.o
obj-$(CONFIG_SM_GPUCC_6125) += gpucc-sm6125.o
obj-$(CONFIG_SM_GPUCC_6350) += gpucc-sm6350.o
@@ -130,7 +135,9 @@ obj-$(CONFIG_SM_GPUCC_8250) += gpucc-sm8250.o
obj-$(CONFIG_SM_GPUCC_8350) += gpucc-sm8350.o
obj-$(CONFIG_SM_GPUCC_8450) += gpucc-sm8450.o
obj-$(CONFIG_SM_GPUCC_8550) += gpucc-sm8550.o
+obj-$(CONFIG_SM_GPUCC_8650) += gpucc-sm8650.o
obj-$(CONFIG_SM_TCSRCC_8550) += tcsrcc-sm8550.o
+obj-$(CONFIG_SM_TCSRCC_8650) += tcsrcc-sm8650.o
obj-$(CONFIG_SM_VIDEOCC_8150) += videocc-sm8150.o
obj-$(CONFIG_SM_VIDEOCC_8250) += videocc-sm8250.o
obj-$(CONFIG_SM_VIDEOCC_8350) += videocc-sm8350.o
diff --git a/drivers/clk/qcom/apss-ipq-pll.c b/drivers/clk/qcom/apss-ipq-pll.c
index 41279e5437a6..678b805f13d4 100644
--- a/drivers/clk/qcom/apss-ipq-pll.c
+++ b/drivers/clk/qcom/apss-ipq-pll.c
@@ -73,6 +73,20 @@ static struct clk_alpha_pll ipq_pll_stromer_plus = {
},
};
+static const struct alpha_pll_config ipq5018_pll_config = {
+ .l = 0x32,
+ .config_ctl_val = 0x4001075b,
+ .config_ctl_hi_val = 0x304,
+ .main_output_mask = BIT(0),
+ .aux_output_mask = BIT(1),
+ .early_output_mask = BIT(3),
+ .alpha_en_mask = BIT(24),
+ .status_val = 0x3,
+ .status_mask = GENMASK(10, 8),
+ .lock_det = BIT(2),
+ .test_ctl_hi_val = 0x00400003,
+};
+
static const struct alpha_pll_config ipq5332_pll_config = {
.l = 0x2d,
.config_ctl_val = 0x4001075b,
@@ -129,6 +143,12 @@ struct apss_pll_data {
const struct alpha_pll_config *pll_config;
};
+static const struct apss_pll_data ipq5018_pll_data = {
+ .pll_type = CLK_ALPHA_PLL_TYPE_STROMER_PLUS,
+ .pll = &ipq_pll_stromer_plus,
+ .pll_config = &ipq5018_pll_config,
+};
+
static struct apss_pll_data ipq5332_pll_data = {
.pll_type = CLK_ALPHA_PLL_TYPE_STROMER_PLUS,
.pll = &ipq_pll_stromer_plus,
@@ -195,6 +215,7 @@ static int apss_ipq_pll_probe(struct platform_device *pdev)
}
static const struct of_device_id apss_ipq_pll_match_table[] = {
+ { .compatible = "qcom,ipq5018-a53pll", .data = &ipq5018_pll_data },
{ .compatible = "qcom,ipq5332-a53pll", .data = &ipq5332_pll_data },
{ .compatible = "qcom,ipq6018-a53pll", .data = &ipq6018_pll_data },
{ .compatible = "qcom,ipq8074-a53pll", .data = &ipq8074_pll_data },
diff --git a/drivers/clk/qcom/camcc-sc8280xp.c b/drivers/clk/qcom/camcc-sc8280xp.c
new file mode 100644
index 000000000000..3dcd79b01515
--- /dev/null
+++ b/drivers/clk/qcom/camcc-sc8280xp.c
@@ -0,0 +1,3045 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Linaro Ltd.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,sc8280xp-camcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+ DT_IFACE,
+ DT_BI_TCXO,
+ DT_BI_TCXO_AO,
+ DT_SLEEP_CLK,
+};
+
+enum {
+ P_BI_TCXO,
+ P_CAMCC_PLL0_OUT_EVEN,
+ P_CAMCC_PLL0_OUT_MAIN,
+ P_CAMCC_PLL0_OUT_ODD,
+ P_CAMCC_PLL1_OUT_EVEN,
+ P_CAMCC_PLL2_OUT_AUX,
+ P_CAMCC_PLL2_OUT_EARLY,
+ P_CAMCC_PLL3_OUT_EVEN,
+ P_CAMCC_PLL4_OUT_EVEN,
+ P_CAMCC_PLL5_OUT_EVEN,
+ P_CAMCC_PLL6_OUT_EVEN,
+ P_CAMCC_PLL7_OUT_EVEN,
+ P_CAMCC_PLL7_OUT_ODD,
+ P_SLEEP_CLK,
+};
+
+static struct pll_vco lucid_vco[] = {
+ { 249600000, 1800000000, 0 },
+};
+
+static struct pll_vco zonda_vco[] = {
+ { 595200000, 3600000000, 0 },
+};
+
+static struct alpha_pll_config camcc_pll0_config = {
+ .l = 0x3e,
+ .alpha = 0x8000,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x2a9a699c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000000,
+ .test_ctl_hi1_val = 0x01800000,
+ .user_ctl_val = 0x00003100,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll camcc_pll0 = {
+ .offset = 0x0,
+ .vco_table = lucid_vco,
+ .num_vco = ARRAY_SIZE(lucid_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll0",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_5lpe_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_camcc_pll0_out_even[] = {
+ { 0x1, 2 },
+};
+
+static struct clk_alpha_pll_postdiv camcc_pll0_out_even = {
+ .offset = 0x0,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_camcc_pll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_pll0_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static const struct clk_div_table post_div_table_camcc_pll0_out_odd[] = {
+ { 0x3, 3 },
+};
+
+static struct clk_alpha_pll_postdiv camcc_pll0_out_odd = {
+ .offset = 0x0,
+ .post_div_shift = 12,
+ .post_div_table = post_div_table_camcc_pll0_out_odd,
+ .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll0_out_odd),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_pll0_out_odd",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static struct alpha_pll_config camcc_pll1_config = {
+ .l = 0x21,
+ .alpha = 0x5555,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x2a9a699c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000000,
+ .test_ctl_hi1_val = 0x01800000,
+ .user_ctl_val = 0x00000100,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll camcc_pll1 = {
+ .offset = 0x1000,
+ .vco_table = lucid_vco,
+ .num_vco = ARRAY_SIZE(lucid_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll1",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_5lpe_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_camcc_pll1_out_even[] = {
+ { 0x1, 2 },
+};
+
+static struct clk_alpha_pll_postdiv camcc_pll1_out_even = {
+ .offset = 0x1000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_camcc_pll1_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll1_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_pll1_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll1.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static struct alpha_pll_config camcc_pll2_config = {
+ .l = 0x32,
+ .alpha = 0x0,
+ .config_ctl_val = 0x08200800,
+ .config_ctl_hi_val = 0x05028011,
+ .config_ctl_hi1_val = 0x08000000,
+};
+
+static struct clk_alpha_pll camcc_pll2 = {
+ .offset = 0x2000,
+ .vco_table = zonda_vco,
+ .num_vco = ARRAY_SIZE(zonda_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll2",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_zonda_ops,
+ },
+ },
+};
+
+static struct alpha_pll_config camcc_pll3_config = {
+ .l = 0x29,
+ .alpha = 0xaaaa,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x2a9a699c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000000,
+ .test_ctl_hi1_val = 0x01800000,
+ .user_ctl_val = 0x00000100,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll camcc_pll3 = {
+ .offset = 0x3000,
+ .vco_table = lucid_vco,
+ .num_vco = ARRAY_SIZE(lucid_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll3",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_5lpe_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_camcc_pll3_out_even[] = {
+ { 0x1, 2 },
+};
+
+static struct clk_alpha_pll_postdiv camcc_pll3_out_even = {
+ .offset = 0x3000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_camcc_pll3_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll3_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_pll3_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll3.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static struct alpha_pll_config camcc_pll4_config = {
+ .l = 0x29,
+ .alpha = 0xaaaa,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x2a9a699c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000000,
+ .test_ctl_hi1_val = 0x01800000,
+ .user_ctl_val = 0x00000100,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll camcc_pll4 = {
+ .offset = 0x4000,
+ .vco_table = lucid_vco,
+ .num_vco = ARRAY_SIZE(lucid_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll4",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_5lpe_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_camcc_pll4_out_even[] = {
+ { 0x1, 2 },
+};
+
+static struct clk_alpha_pll_postdiv camcc_pll4_out_even = {
+ .offset = 0x4000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_camcc_pll4_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll4_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_pll4_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll4.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static struct alpha_pll_config camcc_pll5_config = {
+ .l = 0x29,
+ .alpha = 0xaaaa,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x2a9a699c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000000,
+ .test_ctl_hi1_val = 0x01800000,
+ .user_ctl_val = 0x00000100,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll camcc_pll5 = {
+ .offset = 0x10000,
+ .vco_table = lucid_vco,
+ .num_vco = ARRAY_SIZE(lucid_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll5",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_5lpe_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_camcc_pll5_out_even[] = {
+ { 0x1, 2 },
+};
+
+static struct clk_alpha_pll_postdiv camcc_pll5_out_even = {
+ .offset = 0x10000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_camcc_pll5_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll5_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_pll5_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll5.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static struct alpha_pll_config camcc_pll6_config = {
+ .l = 0x29,
+ .alpha = 0xaaaa,
+ .config_ctl_val = 0x20486699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x2a9a699c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000000,
+ .test_ctl_hi1_val = 0x01800000,
+ .user_ctl_val = 0x00000100,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll camcc_pll6 = {
+ .offset = 0x11000,
+ .vco_table = lucid_vco,
+ .num_vco = ARRAY_SIZE(lucid_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll6",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_5lpe_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_camcc_pll6_out_even[] = {
+ { 0x1, 2 },
+};
+
+static struct clk_alpha_pll_postdiv camcc_pll6_out_even = {
+ .offset = 0x11000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_camcc_pll6_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll6_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_pll6_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll6.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static struct alpha_pll_config camcc_pll7_config = {
+ .l = 0x32,
+ .alpha = 0x0,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00002261,
+ .config_ctl_hi1_val = 0x2a9a699c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000000,
+ .test_ctl_hi1_val = 0x01800000,
+ .user_ctl_val = 0x00003100,
+ .user_ctl_hi_val = 0x00000805,
+ .user_ctl_hi1_val = 0x00000000,
+};
+
+static struct clk_alpha_pll camcc_pll7 = {
+ .offset = 0x12000,
+ .vco_table = lucid_vco,
+ .num_vco = ARRAY_SIZE(lucid_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_pll7",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_5lpe_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_camcc_pll7_out_even[] = {
+ { 0x1, 2 },
+};
+
+static struct clk_alpha_pll_postdiv camcc_pll7_out_even = {
+ .offset = 0x12000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_camcc_pll7_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll7_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_pll7_out_even",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll7.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static const struct clk_div_table post_div_table_camcc_pll7_out_odd[] = {
+ { 0x3, 3 },
+};
+
+static struct clk_alpha_pll_postdiv camcc_pll7_out_odd = {
+ .offset = 0x12000,
+ .post_div_shift = 12,
+ .post_div_table = post_div_table_camcc_pll7_out_odd,
+ .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll7_out_odd),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_pll7_out_odd",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_pll7.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ops,
+ },
+};
+
+static const struct parent_map camcc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL0_OUT_MAIN, 1 },
+ { P_CAMCC_PLL0_OUT_EVEN, 2 },
+ { P_CAMCC_PLL0_OUT_ODD, 3 },
+ { P_CAMCC_PLL7_OUT_EVEN, 5 },
+};
+
+static const struct clk_parent_data camcc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &camcc_pll0.clkr.hw },
+ { .hw = &camcc_pll0_out_even.clkr.hw },
+ { .hw = &camcc_pll0_out_odd.clkr.hw },
+ { .hw = &camcc_pll7_out_even.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL2_OUT_AUX, 2 },
+ { P_CAMCC_PLL2_OUT_EARLY, 5 },
+};
+
+static const struct clk_parent_data camcc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &camcc_pll2.clkr.hw },
+ { .hw = &camcc_pll2.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL0_OUT_MAIN, 1 },
+ { P_CAMCC_PLL0_OUT_EVEN, 2 },
+ { P_CAMCC_PLL0_OUT_ODD, 3 },
+ { P_CAMCC_PLL7_OUT_ODD, 4 },
+ { P_CAMCC_PLL7_OUT_EVEN, 5 },
+};
+
+static const struct clk_parent_data camcc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &camcc_pll0.clkr.hw },
+ { .hw = &camcc_pll0_out_even.clkr.hw },
+ { .hw = &camcc_pll0_out_odd.clkr.hw },
+ { .hw = &camcc_pll7_out_odd.clkr.hw },
+ { .hw = &camcc_pll7_out_even.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL0_OUT_MAIN, 1 },
+ { P_CAMCC_PLL0_OUT_EVEN, 2 },
+ { P_CAMCC_PLL0_OUT_ODD, 3 },
+ { P_CAMCC_PLL7_OUT_EVEN, 5 },
+ { P_CAMCC_PLL3_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data camcc_parent_data_3[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &camcc_pll0.clkr.hw },
+ { .hw = &camcc_pll0_out_even.clkr.hw },
+ { .hw = &camcc_pll0_out_odd.clkr.hw },
+ { .hw = &camcc_pll7_out_even.clkr.hw },
+ { .hw = &camcc_pll3_out_even.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL3_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data camcc_parent_data_4[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &camcc_pll3_out_even.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL4_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data camcc_parent_data_5[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &camcc_pll4_out_even.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_6[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL5_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data camcc_parent_data_6[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &camcc_pll5_out_even.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_7[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL6_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data camcc_parent_data_7[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &camcc_pll6_out_even.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_8[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAMCC_PLL1_OUT_EVEN, 4 },
+};
+
+static const struct clk_parent_data camcc_parent_data_8[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &camcc_pll1_out_even.clkr.hw },
+};
+
+static const struct parent_map camcc_parent_map_9[] = {
+ { P_SLEEP_CLK, 0 },
+};
+
+static const struct clk_parent_data camcc_parent_data_9[] = {
+ { .fw_name = "sleep_clk" },
+};
+
+static const struct parent_map camcc_parent_map_10[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data camcc_parent_data_10_ao[] = {
+ { .fw_name = "bi_tcxo_ao" },
+};
+
+static const struct freq_tbl ftbl_camcc_bps_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(200000000, P_CAMCC_PLL0_OUT_ODD, 2, 0, 0),
+ F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0),
+ F(760000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0),
+};
+
+static struct clk_rcg2 camcc_bps_clk_src = {
+ .cmd_rcgr = 0x7010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_3,
+ .freq_tbl = ftbl_camcc_bps_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_bps_clk_src",
+ .parent_data = camcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_camnoc_axi_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(150000000, P_CAMCC_PLL0_OUT_EVEN, 4, 0, 0),
+ F(266666667, P_CAMCC_PLL0_OUT_ODD, 1.5, 0, 0),
+ F(320000000, P_CAMCC_PLL7_OUT_ODD, 1, 0, 0),
+ F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0),
+};
+
+static struct clk_rcg2 camcc_camnoc_axi_clk_src = {
+ .cmd_rcgr = 0xc170,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_2,
+ .freq_tbl = ftbl_camcc_camnoc_axi_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_camnoc_axi_clk_src",
+ .parent_data = camcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_cci_0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(37500000, P_CAMCC_PLL0_OUT_EVEN, 16, 0, 0),
+};
+
+static struct clk_rcg2 camcc_cci_0_clk_src = {
+ .cmd_rcgr = 0xc108,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_cci_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_cci_0_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_cci_1_clk_src = {
+ .cmd_rcgr = 0xc124,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_cci_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_cci_1_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_cci_2_clk_src = {
+ .cmd_rcgr = 0xc204,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_cci_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_cci_2_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_cci_3_clk_src = {
+ .cmd_rcgr = 0xc220,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_cci_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_cci_3_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_cphy_rx_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(240000000, P_CAMCC_PLL0_OUT_EVEN, 2.5, 0, 0),
+ F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0),
+};
+
+static struct clk_rcg2 camcc_cphy_rx_clk_src = {
+ .cmd_rcgr = 0xa064,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_cphy_rx_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_cphy_rx_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_csi0phytimer_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(300000000, P_CAMCC_PLL0_OUT_EVEN, 2, 0, 0),
+};
+
+static struct clk_rcg2 camcc_csi0phytimer_clk_src = {
+ .cmd_rcgr = 0x6004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_csi0phytimer_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_csi1phytimer_clk_src = {
+ .cmd_rcgr = 0x6028,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_csi1phytimer_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_csi2phytimer_clk_src = {
+ .cmd_rcgr = 0x604c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_csi2phytimer_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_csi3phytimer_clk_src = {
+ .cmd_rcgr = 0x6074,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_csi0phytimer_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_csi3phytimer_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_fast_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(100000000, P_CAMCC_PLL0_OUT_EVEN, 6, 0, 0),
+ F(200000000, P_CAMCC_PLL0_OUT_EVEN, 3, 0, 0),
+ F(300000000, P_CAMCC_PLL0_OUT_MAIN, 4, 0, 0),
+ F(400000000, P_CAMCC_PLL0_OUT_MAIN, 3, 0, 0),
+};
+
+static struct clk_rcg2 camcc_fast_ahb_clk_src = {
+ .cmd_rcgr = 0x703c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_fast_ahb_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_fast_ahb_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_icp_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0),
+ F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0),
+};
+
+static struct clk_rcg2 camcc_icp_clk_src = {
+ .cmd_rcgr = 0xc0b8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_icp_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_icp_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_ife_0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(400000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(558000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(637000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(760000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0),
+};
+
+static struct clk_rcg2 camcc_ife_0_clk_src = {
+ .cmd_rcgr = 0xa010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_4,
+ .freq_tbl = ftbl_camcc_ife_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_clk_src",
+ .parent_data = camcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_ife_0_csid_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(75000000, P_CAMCC_PLL0_OUT_EVEN, 8, 0, 0),
+ F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0),
+};
+
+static struct clk_rcg2 camcc_ife_0_csid_clk_src = {
+ .cmd_rcgr = 0xa03c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_ife_0_csid_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_csid_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_ife_1_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(400000000, P_CAMCC_PLL4_OUT_EVEN, 1, 0, 0),
+ F(558000000, P_CAMCC_PLL4_OUT_EVEN, 1, 0, 0),
+ F(637000000, P_CAMCC_PLL4_OUT_EVEN, 1, 0, 0),
+ F(760000000, P_CAMCC_PLL4_OUT_EVEN, 1, 0, 0),
+};
+
+static struct clk_rcg2 camcc_ife_1_clk_src = {
+ .cmd_rcgr = 0xb010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_5,
+ .freq_tbl = ftbl_camcc_ife_1_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_clk_src",
+ .parent_data = camcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_1_csid_clk_src = {
+ .cmd_rcgr = 0xb03c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_ife_0_csid_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_csid_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_ife_2_clk_src[] = {
+ F(400000000, P_CAMCC_PLL5_OUT_EVEN, 1, 0, 0),
+ F(558000000, P_CAMCC_PLL5_OUT_EVEN, 1, 0, 0),
+ F(637000000, P_CAMCC_PLL5_OUT_EVEN, 1, 0, 0),
+ F(760000000, P_CAMCC_PLL5_OUT_EVEN, 1, 0, 0),
+};
+
+static struct clk_rcg2 camcc_ife_2_clk_src = {
+ .cmd_rcgr = 0xf010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_6,
+ .freq_tbl = ftbl_camcc_ife_2_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_clk_src",
+ .parent_data = camcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_6),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_ife_2_csid_clk_src[] = {
+ F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0),
+};
+
+static struct clk_rcg2 camcc_ife_2_csid_clk_src = {
+ .cmd_rcgr = 0xf03c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_ife_2_csid_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_csid_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_ife_3_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(400000000, P_CAMCC_PLL6_OUT_EVEN, 1, 0, 0),
+ F(558000000, P_CAMCC_PLL6_OUT_EVEN, 1, 0, 0),
+ F(637000000, P_CAMCC_PLL6_OUT_EVEN, 1, 0, 0),
+ F(760000000, P_CAMCC_PLL6_OUT_EVEN, 1, 0, 0),
+};
+
+static struct clk_rcg2 camcc_ife_3_clk_src = {
+ .cmd_rcgr = 0xf07c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_7,
+ .freq_tbl = ftbl_camcc_ife_3_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_3_clk_src",
+ .parent_data = camcc_parent_data_7,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_7),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_3_csid_clk_src = {
+ .cmd_rcgr = 0xf0a8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_ife_2_csid_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_3_csid_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_ife_lite_0_clk_src[] = {
+ F(320000000, P_CAMCC_PLL7_OUT_ODD, 1, 0, 0),
+ F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0),
+};
+
+static struct clk_rcg2 camcc_ife_lite_0_clk_src = {
+ .cmd_rcgr = 0xc004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_2,
+ .freq_tbl = ftbl_camcc_ife_lite_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_0_clk_src",
+ .parent_data = camcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_lite_0_csid_clk_src = {
+ .cmd_rcgr = 0xc020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_ife_2_csid_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_0_csid_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_lite_1_clk_src = {
+ .cmd_rcgr = 0xc048,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_2,
+ .freq_tbl = ftbl_camcc_ife_lite_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_1_clk_src",
+ .parent_data = camcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_lite_1_csid_clk_src = {
+ .cmd_rcgr = 0xc064,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_ife_2_csid_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_1_csid_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_lite_2_clk_src = {
+ .cmd_rcgr = 0xc240,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_2,
+ .freq_tbl = ftbl_camcc_ife_lite_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_2_clk_src",
+ .parent_data = camcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_lite_2_csid_clk_src = {
+ .cmd_rcgr = 0xc25c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_ife_2_csid_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_2_csid_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_lite_3_clk_src = {
+ .cmd_rcgr = 0xc284,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_2,
+ .freq_tbl = ftbl_camcc_ife_lite_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_3_clk_src",
+ .parent_data = camcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_ife_lite_3_csid_clk_src = {
+ .cmd_rcgr = 0xc2a0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_ife_2_csid_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_3_csid_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_ipe_0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(320000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(475000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(520000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0),
+};
+
+static struct clk_rcg2 camcc_ipe_0_clk_src = {
+ .cmd_rcgr = 0x8010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_8,
+ .freq_tbl = ftbl_camcc_ipe_0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_0_clk_src",
+ .parent_data = camcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_8),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_jpeg_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(200000000, P_CAMCC_PLL0_OUT_ODD, 2, 0, 0),
+ F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0),
+};
+
+static struct clk_rcg2 camcc_jpeg_clk_src = {
+ .cmd_rcgr = 0xc08c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_jpeg_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_jpeg_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_lrme_clk_src[] = {
+ F(240000000, P_CAMCC_PLL7_OUT_EVEN, 2, 0, 0),
+ F(300000000, P_CAMCC_PLL0_OUT_EVEN, 2, 0, 0),
+ F(320000000, P_CAMCC_PLL7_OUT_ODD, 1, 0, 0),
+ F(400000000, P_CAMCC_PLL0_OUT_MAIN, 3, 0, 0),
+};
+
+static struct clk_rcg2 camcc_lrme_clk_src = {
+ .cmd_rcgr = 0xc144,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_2,
+ .freq_tbl = ftbl_camcc_lrme_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_lrme_clk_src",
+ .parent_data = camcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_mclk0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(24000000, P_CAMCC_PLL2_OUT_EARLY, 10, 1, 4),
+ F(64000000, P_CAMCC_PLL2_OUT_EARLY, 15, 0, 0),
+};
+
+static struct clk_rcg2 camcc_mclk0_clk_src = {
+ .cmd_rcgr = 0x5004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk0_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_mclk1_clk_src = {
+ .cmd_rcgr = 0x5024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk1_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_mclk2_clk_src = {
+ .cmd_rcgr = 0x5044,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk2_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_mclk3_clk_src = {
+ .cmd_rcgr = 0x5064,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk3_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_mclk4_clk_src = {
+ .cmd_rcgr = 0x5084,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk4_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_mclk5_clk_src = {
+ .cmd_rcgr = 0x50a4,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk5_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_mclk6_clk_src = {
+ .cmd_rcgr = 0x50c4,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk6_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 camcc_mclk7_clk_src = {
+ .cmd_rcgr = 0x50e4,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_1,
+ .freq_tbl = ftbl_camcc_mclk0_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk7_clk_src",
+ .parent_data = camcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_sleep_clk_src[] = {
+ F(32000, P_SLEEP_CLK, 1, 0, 0),
+};
+
+static struct clk_rcg2 camcc_sleep_clk_src = {
+ .cmd_rcgr = 0xc1e8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_9,
+ .freq_tbl = ftbl_camcc_sleep_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_sleep_clk_src",
+ .parent_data = camcc_parent_data_9,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_9),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_slow_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(80000000, P_CAMCC_PLL7_OUT_EVEN, 6, 0, 0),
+};
+
+static struct clk_rcg2 camcc_slow_ahb_clk_src = {
+ .cmd_rcgr = 0x7058,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_0,
+ .freq_tbl = ftbl_camcc_slow_ahb_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_slow_ahb_clk_src",
+ .parent_data = camcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_camcc_xo_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+};
+
+static struct clk_rcg2 camcc_xo_clk_src = {
+ .cmd_rcgr = 0xc1cc,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = camcc_parent_map_10,
+ .freq_tbl = ftbl_camcc_xo_clk_src,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "camcc_xo_clk_src",
+ .parent_data = camcc_parent_data_10_ao,
+ .num_parents = ARRAY_SIZE(camcc_parent_data_10_ao),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_branch camcc_bps_ahb_clk = {
+ .halt_reg = 0x7070,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7070,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_bps_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_bps_areg_clk = {
+ .halt_reg = 0x7054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_bps_areg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_bps_axi_clk = {
+ .halt_reg = 0x7038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_bps_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_camnoc_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_bps_clk = {
+ .halt_reg = 0x7028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_bps_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_bps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_camnoc_axi_clk = {
+ .halt_reg = 0xc18c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc18c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_camnoc_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_camnoc_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_camnoc_dcd_xo_clk = {
+ .halt_reg = 0xc194,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc194,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_camnoc_dcd_xo_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_cci_0_clk = {
+ .halt_reg = 0xc120,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc120,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_cci_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cci_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_cci_1_clk = {
+ .halt_reg = 0xc13c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc13c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_cci_1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cci_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_cci_2_clk = {
+ .halt_reg = 0xc21c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc21c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_cci_2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cci_2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_cci_3_clk = {
+ .halt_reg = 0xc238,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc238,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_cci_3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cci_3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_core_ahb_clk = {
+ .halt_reg = 0xc1c8,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0xc1c8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_core_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_cpas_ahb_clk = {
+ .halt_reg = 0xc168,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc168,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_cpas_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csi0phytimer_clk = {
+ .halt_reg = 0x601c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x601c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csi0phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_csi0phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csi1phytimer_clk = {
+ .halt_reg = 0x6040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csi1phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_csi1phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csi2phytimer_clk = {
+ .halt_reg = 0x6064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6064,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csi2phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_csi2phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csi3phytimer_clk = {
+ .halt_reg = 0x608c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x608c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csi3phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_csi3phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csiphy0_clk = {
+ .halt_reg = 0x6020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csiphy0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csiphy1_clk = {
+ .halt_reg = 0x6044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6044,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csiphy1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csiphy2_clk = {
+ .halt_reg = 0x6068,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6068,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csiphy2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_csiphy3_clk = {
+ .halt_reg = 0x6090,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x6090,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_csiphy3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_gdsc_clk = {
+ .halt_reg = 0xc1e4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc1e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_gdsc_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_icp_ahb_clk = {
+ .halt_reg = 0xc0d8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc0d8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_icp_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_icp_clk = {
+ .halt_reg = 0xc0d0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc0d0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_icp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_icp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_0_axi_clk = {
+ .halt_reg = 0xa080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa080,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_camnoc_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_0_clk = {
+ .halt_reg = 0xa028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_0_cphy_rx_clk = {
+ .halt_reg = 0xa07c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa07c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_0_csid_clk = {
+ .halt_reg = 0xa054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_0_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_0_dsp_clk = {
+ .halt_reg = 0xa038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_0_dsp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_1_axi_clk = {
+ .halt_reg = 0xb068,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb068,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_camnoc_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_1_clk = {
+ .halt_reg = 0xb028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_1_cphy_rx_clk = {
+ .halt_reg = 0xb064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb064,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_1_csid_clk = {
+ .halt_reg = 0xb054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_1_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_1_dsp_clk = {
+ .halt_reg = 0xb038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xb038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_1_dsp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_2_axi_clk = {
+ .halt_reg = 0xf068,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf068,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_camnoc_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_2_clk = {
+ .halt_reg = 0xf028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_2_cphy_rx_clk = {
+ .halt_reg = 0xf064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf064,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_2_csid_clk = {
+ .halt_reg = 0xf054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf054,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_2_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_2_dsp_clk = {
+ .halt_reg = 0xf038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_2_dsp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_3_axi_clk = {
+ .halt_reg = 0xf0d4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf0d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_3_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_camnoc_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_3_clk = {
+ .halt_reg = 0xf094,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf094,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_3_cphy_rx_clk = {
+ .halt_reg = 0xf0d0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf0d0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_3_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_3_csid_clk = {
+ .halt_reg = 0xf0c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf0c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_3_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_3_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_3_dsp_clk = {
+ .halt_reg = 0xf0a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf0a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_3_dsp_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_0_clk = {
+ .halt_reg = 0xc01c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc01c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_lite_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_0_cphy_rx_clk = {
+ .halt_reg = 0xc040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_0_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_0_csid_clk = {
+ .halt_reg = 0xc038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_0_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_lite_0_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_1_clk = {
+ .halt_reg = 0xc060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc060,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_lite_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_1_cphy_rx_clk = {
+ .halt_reg = 0xc084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc084,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_1_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_1_csid_clk = {
+ .halt_reg = 0xc07c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc07c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_1_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_lite_1_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_2_clk = {
+ .halt_reg = 0xc258,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc258,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_lite_2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_2_cphy_rx_clk = {
+ .halt_reg = 0xc27c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc27c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_2_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_2_csid_clk = {
+ .halt_reg = 0xc274,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc274,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_2_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_lite_2_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_3_clk = {
+ .halt_reg = 0xc29c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc29c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_lite_3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_3_cphy_rx_clk = {
+ .halt_reg = 0xc2c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc2c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_3_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ife_lite_3_csid_clk = {
+ .halt_reg = 0xc2b8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc2b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ife_lite_3_csid_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ife_lite_3_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ipe_0_ahb_clk = {
+ .halt_reg = 0x8040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_0_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ipe_0_areg_clk = {
+ .halt_reg = 0x803c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x803c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_0_areg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ipe_0_axi_clk = {
+ .halt_reg = 0x8038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8038,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_0_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_camnoc_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ipe_0_clk = {
+ .halt_reg = 0x8028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ipe_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ipe_1_ahb_clk = {
+ .halt_reg = 0x9028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_1_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ipe_1_areg_clk = {
+ .halt_reg = 0x9024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_1_areg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ipe_1_axi_clk = {
+ .halt_reg = 0x9020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9020,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_1_axi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_camnoc_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_ipe_1_clk = {
+ .halt_reg = 0x9010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_ipe_1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_ipe_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_jpeg_clk = {
+ .halt_reg = 0xc0a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc0a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_jpeg_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_jpeg_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_lrme_clk = {
+ .halt_reg = 0xc15c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc15c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_lrme_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_lrme_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk0_clk = {
+ .halt_reg = 0x501c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x501c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk0_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk1_clk = {
+ .halt_reg = 0x503c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x503c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk1_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk2_clk = {
+ .halt_reg = 0x505c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x505c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk3_clk = {
+ .halt_reg = 0x507c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x507c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk3_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk4_clk = {
+ .halt_reg = 0x509c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x509c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk4_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk5_clk = {
+ .halt_reg = 0x50bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x50bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk5_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk6_clk = {
+ .halt_reg = 0x50dc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x50dc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk6_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_mclk7_clk = {
+ .halt_reg = 0x50fc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x50fc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_mclk7_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_mclk7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch camcc_sleep_clk = {
+ .halt_reg = 0xc200,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc200,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "camcc_sleep_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camcc_sleep_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc titan_top_gdsc;
+
+static struct gdsc bps_gdsc = {
+ .gdscr = 0x7004,
+ .pd = {
+ .name = "bps_gdsc",
+ },
+ .flags = HW_CTRL | RETAIN_FF_ENABLE,
+ .parent = &titan_top_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ife_0_gdsc = {
+ .gdscr = 0xa004,
+ .pd = {
+ .name = "ife_0_gdsc",
+ },
+ .flags = RETAIN_FF_ENABLE,
+ .parent = &titan_top_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ife_1_gdsc = {
+ .gdscr = 0xb004,
+ .pd = {
+ .name = "ife_1_gdsc",
+ },
+ .flags = RETAIN_FF_ENABLE,
+ .parent = &titan_top_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ife_2_gdsc = {
+ .gdscr = 0xf004,
+ .pd = {
+ .name = "ife_2_gdsc",
+ },
+ .flags = RETAIN_FF_ENABLE,
+ .parent = &titan_top_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ife_3_gdsc = {
+ .gdscr = 0xf070,
+ .pd = {
+ .name = "ife_3_gdsc",
+ },
+ .flags = RETAIN_FF_ENABLE,
+ .parent = &titan_top_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ipe_0_gdsc = {
+ .gdscr = 0x8004,
+ .pd = {
+ .name = "ipe_0_gdsc",
+ },
+ .flags = HW_CTRL | RETAIN_FF_ENABLE,
+ .parent = &titan_top_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc ipe_1_gdsc = {
+ .gdscr = 0x9004,
+ .pd = {
+ .name = "ipe_1_gdsc",
+ },
+ .flags = HW_CTRL | RETAIN_FF_ENABLE,
+ .parent = &titan_top_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct gdsc titan_top_gdsc = {
+ .gdscr = 0xc1bc,
+ .pd = {
+ .name = "titan_top_gdsc",
+ },
+ .flags = RETAIN_FF_ENABLE,
+ .pwrsts = PWRSTS_OFF_ON,
+};
+
+static struct clk_regmap *camcc_sc8280xp_clocks[] = {
+ [CAMCC_BPS_AHB_CLK] = &camcc_bps_ahb_clk.clkr,
+ [CAMCC_BPS_AREG_CLK] = &camcc_bps_areg_clk.clkr,
+ [CAMCC_BPS_AXI_CLK] = &camcc_bps_axi_clk.clkr,
+ [CAMCC_BPS_CLK] = &camcc_bps_clk.clkr,
+ [CAMCC_BPS_CLK_SRC] = &camcc_bps_clk_src.clkr,
+ [CAMCC_CAMNOC_AXI_CLK] = &camcc_camnoc_axi_clk.clkr,
+ [CAMCC_CAMNOC_AXI_CLK_SRC] = &camcc_camnoc_axi_clk_src.clkr,
+ [CAMCC_CAMNOC_DCD_XO_CLK] = &camcc_camnoc_dcd_xo_clk.clkr,
+ [CAMCC_CCI_0_CLK] = &camcc_cci_0_clk.clkr,
+ [CAMCC_CCI_0_CLK_SRC] = &camcc_cci_0_clk_src.clkr,
+ [CAMCC_CCI_1_CLK] = &camcc_cci_1_clk.clkr,
+ [CAMCC_CCI_1_CLK_SRC] = &camcc_cci_1_clk_src.clkr,
+ [CAMCC_CCI_2_CLK] = &camcc_cci_2_clk.clkr,
+ [CAMCC_CCI_2_CLK_SRC] = &camcc_cci_2_clk_src.clkr,
+ [CAMCC_CCI_3_CLK] = &camcc_cci_3_clk.clkr,
+ [CAMCC_CCI_3_CLK_SRC] = &camcc_cci_3_clk_src.clkr,
+ [CAMCC_CORE_AHB_CLK] = &camcc_core_ahb_clk.clkr,
+ [CAMCC_CPAS_AHB_CLK] = &camcc_cpas_ahb_clk.clkr,
+ [CAMCC_CPHY_RX_CLK_SRC] = &camcc_cphy_rx_clk_src.clkr,
+ [CAMCC_CSI0PHYTIMER_CLK] = &camcc_csi0phytimer_clk.clkr,
+ [CAMCC_CSI0PHYTIMER_CLK_SRC] = &camcc_csi0phytimer_clk_src.clkr,
+ [CAMCC_CSI1PHYTIMER_CLK] = &camcc_csi1phytimer_clk.clkr,
+ [CAMCC_CSI1PHYTIMER_CLK_SRC] = &camcc_csi1phytimer_clk_src.clkr,
+ [CAMCC_CSI2PHYTIMER_CLK] = &camcc_csi2phytimer_clk.clkr,
+ [CAMCC_CSI2PHYTIMER_CLK_SRC] = &camcc_csi2phytimer_clk_src.clkr,
+ [CAMCC_CSI3PHYTIMER_CLK] = &camcc_csi3phytimer_clk.clkr,
+ [CAMCC_CSI3PHYTIMER_CLK_SRC] = &camcc_csi3phytimer_clk_src.clkr,
+ [CAMCC_CSIPHY0_CLK] = &camcc_csiphy0_clk.clkr,
+ [CAMCC_CSIPHY1_CLK] = &camcc_csiphy1_clk.clkr,
+ [CAMCC_CSIPHY2_CLK] = &camcc_csiphy2_clk.clkr,
+ [CAMCC_CSIPHY3_CLK] = &camcc_csiphy3_clk.clkr,
+ [CAMCC_FAST_AHB_CLK_SRC] = &camcc_fast_ahb_clk_src.clkr,
+ [CAMCC_GDSC_CLK] = &camcc_gdsc_clk.clkr,
+ [CAMCC_ICP_AHB_CLK] = &camcc_icp_ahb_clk.clkr,
+ [CAMCC_ICP_CLK] = &camcc_icp_clk.clkr,
+ [CAMCC_ICP_CLK_SRC] = &camcc_icp_clk_src.clkr,
+ [CAMCC_IFE_0_AXI_CLK] = &camcc_ife_0_axi_clk.clkr,
+ [CAMCC_IFE_0_CLK] = &camcc_ife_0_clk.clkr,
+ [CAMCC_IFE_0_CLK_SRC] = &camcc_ife_0_clk_src.clkr,
+ [CAMCC_IFE_0_CPHY_RX_CLK] = &camcc_ife_0_cphy_rx_clk.clkr,
+ [CAMCC_IFE_0_CSID_CLK] = &camcc_ife_0_csid_clk.clkr,
+ [CAMCC_IFE_0_CSID_CLK_SRC] = &camcc_ife_0_csid_clk_src.clkr,
+ [CAMCC_IFE_0_DSP_CLK] = &camcc_ife_0_dsp_clk.clkr,
+ [CAMCC_IFE_1_AXI_CLK] = &camcc_ife_1_axi_clk.clkr,
+ [CAMCC_IFE_1_CLK] = &camcc_ife_1_clk.clkr,
+ [CAMCC_IFE_1_CLK_SRC] = &camcc_ife_1_clk_src.clkr,
+ [CAMCC_IFE_1_CPHY_RX_CLK] = &camcc_ife_1_cphy_rx_clk.clkr,
+ [CAMCC_IFE_1_CSID_CLK] = &camcc_ife_1_csid_clk.clkr,
+ [CAMCC_IFE_1_CSID_CLK_SRC] = &camcc_ife_1_csid_clk_src.clkr,
+ [CAMCC_IFE_1_DSP_CLK] = &camcc_ife_1_dsp_clk.clkr,
+ [CAMCC_IFE_2_AXI_CLK] = &camcc_ife_2_axi_clk.clkr,
+ [CAMCC_IFE_2_CLK] = &camcc_ife_2_clk.clkr,
+ [CAMCC_IFE_2_CLK_SRC] = &camcc_ife_2_clk_src.clkr,
+ [CAMCC_IFE_2_CPHY_RX_CLK] = &camcc_ife_2_cphy_rx_clk.clkr,
+ [CAMCC_IFE_2_CSID_CLK] = &camcc_ife_2_csid_clk.clkr,
+ [CAMCC_IFE_2_CSID_CLK_SRC] = &camcc_ife_2_csid_clk_src.clkr,
+ [CAMCC_IFE_2_DSP_CLK] = &camcc_ife_2_dsp_clk.clkr,
+ [CAMCC_IFE_3_AXI_CLK] = &camcc_ife_3_axi_clk.clkr,
+ [CAMCC_IFE_3_CLK] = &camcc_ife_3_clk.clkr,
+ [CAMCC_IFE_3_CLK_SRC] = &camcc_ife_3_clk_src.clkr,
+ [CAMCC_IFE_3_CPHY_RX_CLK] = &camcc_ife_3_cphy_rx_clk.clkr,
+ [CAMCC_IFE_3_CSID_CLK] = &camcc_ife_3_csid_clk.clkr,
+ [CAMCC_IFE_3_CSID_CLK_SRC] = &camcc_ife_3_csid_clk_src.clkr,
+ [CAMCC_IFE_3_DSP_CLK] = &camcc_ife_3_dsp_clk.clkr,
+ [CAMCC_IFE_LITE_0_CLK] = &camcc_ife_lite_0_clk.clkr,
+ [CAMCC_IFE_LITE_0_CLK_SRC] = &camcc_ife_lite_0_clk_src.clkr,
+ [CAMCC_IFE_LITE_0_CPHY_RX_CLK] = &camcc_ife_lite_0_cphy_rx_clk.clkr,
+ [CAMCC_IFE_LITE_0_CSID_CLK] = &camcc_ife_lite_0_csid_clk.clkr,
+ [CAMCC_IFE_LITE_0_CSID_CLK_SRC] = &camcc_ife_lite_0_csid_clk_src.clkr,
+ [CAMCC_IFE_LITE_1_CLK] = &camcc_ife_lite_1_clk.clkr,
+ [CAMCC_IFE_LITE_1_CLK_SRC] = &camcc_ife_lite_1_clk_src.clkr,
+ [CAMCC_IFE_LITE_1_CPHY_RX_CLK] = &camcc_ife_lite_1_cphy_rx_clk.clkr,
+ [CAMCC_IFE_LITE_1_CSID_CLK] = &camcc_ife_lite_1_csid_clk.clkr,
+ [CAMCC_IFE_LITE_1_CSID_CLK_SRC] = &camcc_ife_lite_1_csid_clk_src.clkr,
+ [CAMCC_IFE_LITE_2_CLK] = &camcc_ife_lite_2_clk.clkr,
+ [CAMCC_IFE_LITE_2_CLK_SRC] = &camcc_ife_lite_2_clk_src.clkr,
+ [CAMCC_IFE_LITE_2_CPHY_RX_CLK] = &camcc_ife_lite_2_cphy_rx_clk.clkr,
+ [CAMCC_IFE_LITE_2_CSID_CLK] = &camcc_ife_lite_2_csid_clk.clkr,
+ [CAMCC_IFE_LITE_2_CSID_CLK_SRC] = &camcc_ife_lite_2_csid_clk_src.clkr,
+ [CAMCC_IFE_LITE_3_CLK] = &camcc_ife_lite_3_clk.clkr,
+ [CAMCC_IFE_LITE_3_CLK_SRC] = &camcc_ife_lite_3_clk_src.clkr,
+ [CAMCC_IFE_LITE_3_CPHY_RX_CLK] = &camcc_ife_lite_3_cphy_rx_clk.clkr,
+ [CAMCC_IFE_LITE_3_CSID_CLK] = &camcc_ife_lite_3_csid_clk.clkr,
+ [CAMCC_IFE_LITE_3_CSID_CLK_SRC] = &camcc_ife_lite_3_csid_clk_src.clkr,
+ [CAMCC_IPE_0_AHB_CLK] = &camcc_ipe_0_ahb_clk.clkr,
+ [CAMCC_IPE_0_AREG_CLK] = &camcc_ipe_0_areg_clk.clkr,
+ [CAMCC_IPE_0_AXI_CLK] = &camcc_ipe_0_axi_clk.clkr,
+ [CAMCC_IPE_0_CLK] = &camcc_ipe_0_clk.clkr,
+ [CAMCC_IPE_0_CLK_SRC] = &camcc_ipe_0_clk_src.clkr,
+ [CAMCC_IPE_1_AHB_CLK] = &camcc_ipe_1_ahb_clk.clkr,
+ [CAMCC_IPE_1_AREG_CLK] = &camcc_ipe_1_areg_clk.clkr,
+ [CAMCC_IPE_1_AXI_CLK] = &camcc_ipe_1_axi_clk.clkr,
+ [CAMCC_IPE_1_CLK] = &camcc_ipe_1_clk.clkr,
+ [CAMCC_JPEG_CLK] = &camcc_jpeg_clk.clkr,
+ [CAMCC_JPEG_CLK_SRC] = &camcc_jpeg_clk_src.clkr,
+ [CAMCC_LRME_CLK] = &camcc_lrme_clk.clkr,
+ [CAMCC_LRME_CLK_SRC] = &camcc_lrme_clk_src.clkr,
+ [CAMCC_MCLK0_CLK] = &camcc_mclk0_clk.clkr,
+ [CAMCC_MCLK0_CLK_SRC] = &camcc_mclk0_clk_src.clkr,
+ [CAMCC_MCLK1_CLK] = &camcc_mclk1_clk.clkr,
+ [CAMCC_MCLK1_CLK_SRC] = &camcc_mclk1_clk_src.clkr,
+ [CAMCC_MCLK2_CLK] = &camcc_mclk2_clk.clkr,
+ [CAMCC_MCLK2_CLK_SRC] = &camcc_mclk2_clk_src.clkr,
+ [CAMCC_MCLK3_CLK] = &camcc_mclk3_clk.clkr,
+ [CAMCC_MCLK3_CLK_SRC] = &camcc_mclk3_clk_src.clkr,
+ [CAMCC_MCLK4_CLK] = &camcc_mclk4_clk.clkr,
+ [CAMCC_MCLK4_CLK_SRC] = &camcc_mclk4_clk_src.clkr,
+ [CAMCC_MCLK5_CLK] = &camcc_mclk5_clk.clkr,
+ [CAMCC_MCLK5_CLK_SRC] = &camcc_mclk5_clk_src.clkr,
+ [CAMCC_MCLK6_CLK] = &camcc_mclk6_clk.clkr,
+ [CAMCC_MCLK6_CLK_SRC] = &camcc_mclk6_clk_src.clkr,
+ [CAMCC_MCLK7_CLK] = &camcc_mclk7_clk.clkr,
+ [CAMCC_MCLK7_CLK_SRC] = &camcc_mclk7_clk_src.clkr,
+ [CAMCC_PLL0] = &camcc_pll0.clkr,
+ [CAMCC_PLL0_OUT_EVEN] = &camcc_pll0_out_even.clkr,
+ [CAMCC_PLL0_OUT_ODD] = &camcc_pll0_out_odd.clkr,
+ [CAMCC_PLL1] = &camcc_pll1.clkr,
+ [CAMCC_PLL1_OUT_EVEN] = &camcc_pll1_out_even.clkr,
+ [CAMCC_PLL2] = &camcc_pll2.clkr,
+ [CAMCC_PLL3] = &camcc_pll3.clkr,
+ [CAMCC_PLL3_OUT_EVEN] = &camcc_pll3_out_even.clkr,
+ [CAMCC_PLL4] = &camcc_pll4.clkr,
+ [CAMCC_PLL4_OUT_EVEN] = &camcc_pll4_out_even.clkr,
+ [CAMCC_PLL5] = &camcc_pll5.clkr,
+ [CAMCC_PLL5_OUT_EVEN] = &camcc_pll5_out_even.clkr,
+ [CAMCC_PLL6] = &camcc_pll6.clkr,
+ [CAMCC_PLL6_OUT_EVEN] = &camcc_pll6_out_even.clkr,
+ [CAMCC_PLL7] = &camcc_pll7.clkr,
+ [CAMCC_PLL7_OUT_EVEN] = &camcc_pll7_out_even.clkr,
+ [CAMCC_PLL7_OUT_ODD] = &camcc_pll7_out_odd.clkr,
+ [CAMCC_SLEEP_CLK] = &camcc_sleep_clk.clkr,
+ [CAMCC_SLEEP_CLK_SRC] = &camcc_sleep_clk_src.clkr,
+ [CAMCC_SLOW_AHB_CLK_SRC] = &camcc_slow_ahb_clk_src.clkr,
+ [CAMCC_XO_CLK_SRC] = &camcc_xo_clk_src.clkr,
+};
+
+static struct gdsc *camcc_sc8280xp_gdscs[] = {
+ [BPS_GDSC] = &bps_gdsc,
+ [IFE_0_GDSC] = &ife_0_gdsc,
+ [IFE_1_GDSC] = &ife_1_gdsc,
+ [IFE_2_GDSC] = &ife_2_gdsc,
+ [IFE_3_GDSC] = &ife_3_gdsc,
+ [IPE_0_GDSC] = &ipe_0_gdsc,
+ [IPE_1_GDSC] = &ipe_1_gdsc,
+ [TITAN_TOP_GDSC] = &titan_top_gdsc,
+};
+
+static const struct qcom_reset_map camcc_sc8280xp_resets[] = {
+ [CAMCC_BPS_BCR] = { 0x7000 },
+ [CAMCC_CAMNOC_BCR] = { 0xc16c },
+ [CAMCC_CCI_BCR] = { 0xc104 },
+ [CAMCC_CPAS_BCR] = { 0xc164 },
+ [CAMCC_CSI0PHY_BCR] = { 0x6000 },
+ [CAMCC_CSI1PHY_BCR] = { 0x6024 },
+ [CAMCC_CSI2PHY_BCR] = { 0x6048 },
+ [CAMCC_CSI3PHY_BCR] = { 0x6070 },
+ [CAMCC_ICP_BCR] = { 0xc0b4 },
+ [CAMCC_IFE_0_BCR] = { 0xa000 },
+ [CAMCC_IFE_1_BCR] = { 0xb000 },
+ [CAMCC_IFE_2_BCR] = { 0xf000 },
+ [CAMCC_IFE_3_BCR] = { 0xf06c },
+ [CAMCC_IFE_LITE_0_BCR] = { 0xc000 },
+ [CAMCC_IFE_LITE_1_BCR] = { 0xc044 },
+ [CAMCC_IFE_LITE_2_BCR] = { 0xc23c },
+ [CAMCC_IFE_LITE_3_BCR] = { 0xc280 },
+ [CAMCC_IPE_0_BCR] = { 0x8000 },
+ [CAMCC_IPE_1_BCR] = { 0x9000 },
+ [CAMCC_JPEG_BCR] = { 0xc088 },
+ [CAMCC_LRME_BCR] = { 0xc140 },
+};
+
+static const struct regmap_config camcc_sc8280xp_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x13020,
+ .fast_io = true,
+};
+
+static struct qcom_cc_desc camcc_sc8280xp_desc = {
+ .config = &camcc_sc8280xp_regmap_config,
+ .clks = camcc_sc8280xp_clocks,
+ .num_clks = ARRAY_SIZE(camcc_sc8280xp_clocks),
+ .resets = camcc_sc8280xp_resets,
+ .num_resets = ARRAY_SIZE(camcc_sc8280xp_resets),
+ .gdscs = camcc_sc8280xp_gdscs,
+ .num_gdscs = ARRAY_SIZE(camcc_sc8280xp_gdscs),
+};
+
+static const struct of_device_id camcc_sc8280xp_match_table[] = {
+ { .compatible = "qcom,sc8280xp-camcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, camcc_sc8280xp_match_table);
+
+static int camcc_sc8280xp_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ int ret;
+
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret)
+ return ret;
+
+ regmap = qcom_cc_map(pdev, &camcc_sc8280xp_desc);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ goto err_put_rpm;
+ }
+
+ clk_lucid_pll_configure(&camcc_pll0, regmap, &camcc_pll0_config);
+ clk_lucid_pll_configure(&camcc_pll1, regmap, &camcc_pll1_config);
+ clk_zonda_pll_configure(&camcc_pll2, regmap, &camcc_pll2_config);
+ clk_lucid_pll_configure(&camcc_pll3, regmap, &camcc_pll3_config);
+ clk_lucid_pll_configure(&camcc_pll4, regmap, &camcc_pll4_config);
+ clk_lucid_pll_configure(&camcc_pll5, regmap, &camcc_pll5_config);
+ clk_lucid_pll_configure(&camcc_pll6, regmap, &camcc_pll6_config);
+ clk_lucid_pll_configure(&camcc_pll7, regmap, &camcc_pll7_config);
+
+ /*
+ * Keep camcc_gdsc_clk always enabled:
+ */
+ regmap_update_bits(regmap, 0xc1e4, BIT(0), 1);
+
+ ret = qcom_cc_really_probe(pdev, &camcc_sc8280xp_desc, regmap);
+ if (ret)
+ goto err_disable;
+
+ pm_runtime_put(&pdev->dev);
+
+ return 0;
+
+err_disable:
+ regmap_update_bits(regmap, 0xc1e4, BIT(0), 0);
+err_put_rpm:
+ pm_runtime_put_sync(&pdev->dev);
+
+ return ret;
+}
+
+static struct platform_driver camcc_sc8280xp_driver = {
+ .probe = camcc_sc8280xp_probe,
+ .driver = {
+ .name = "camcc-sc8280xp",
+ .of_match_table = camcc_sc8280xp_match_table,
+ },
+};
+
+module_platform_driver(camcc_sc8280xp_driver);
+
+MODULE_DESCRIPTION("QCOM CAMCC SC8280XP Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index fc4735f74f0f..c1dba33ac31a 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/kernel.h>
@@ -134,6 +135,43 @@ static void clk_branch2_disable(struct clk_hw *hw)
clk_branch_toggle(hw, false, clk_branch2_check_halt);
}
+static int clk_branch2_mem_enable(struct clk_hw *hw)
+{
+ struct clk_mem_branch *mem_br = to_clk_mem_branch(hw);
+ struct clk_branch branch = mem_br->branch;
+ u32 val;
+ int ret;
+
+ regmap_update_bits(branch.clkr.regmap, mem_br->mem_enable_reg,
+ mem_br->mem_enable_ack_mask, mem_br->mem_enable_ack_mask);
+
+ ret = regmap_read_poll_timeout(branch.clkr.regmap, mem_br->mem_ack_reg,
+ val, val & mem_br->mem_enable_ack_mask, 0, 200);
+ if (ret) {
+ WARN(1, "%s mem enable failed\n", clk_hw_get_name(&branch.clkr.hw));
+ return ret;
+ }
+
+ return clk_branch2_enable(hw);
+}
+
+static void clk_branch2_mem_disable(struct clk_hw *hw)
+{
+ struct clk_mem_branch *mem_br = to_clk_mem_branch(hw);
+
+ regmap_update_bits(mem_br->branch.clkr.regmap, mem_br->mem_enable_reg,
+ mem_br->mem_enable_ack_mask, 0);
+
+ return clk_branch2_disable(hw);
+}
+
+const struct clk_ops clk_branch2_mem_ops = {
+ .enable = clk_branch2_mem_enable,
+ .disable = clk_branch2_mem_disable,
+ .is_enabled = clk_is_enabled_regmap,
+};
+EXPORT_SYMBOL_GPL(clk_branch2_mem_ops);
+
const struct clk_ops clk_branch2_ops = {
.enable = clk_branch2_enable,
.disable = clk_branch2_disable,
diff --git a/drivers/clk/qcom/clk-branch.h b/drivers/clk/qcom/clk-branch.h
index 0cf800b9d08d..8ffed603c050 100644
--- a/drivers/clk/qcom/clk-branch.h
+++ b/drivers/clk/qcom/clk-branch.h
@@ -38,6 +38,23 @@ struct clk_branch {
struct clk_regmap clkr;
};
+/**
+ * struct clk_mem_branch - gating clock which are associated with memories
+ *
+ * @mem_enable_reg: branch clock memory gating register
+ * @mem_ack_reg: branch clock memory ack register
+ * @mem_enable_ack_mask: branch clock memory enable and ack field in @mem_ack_reg
+ * @branch: branch clock gating handle
+ *
+ * Clock which can gate its memories.
+ */
+struct clk_mem_branch {
+ u32 mem_enable_reg;
+ u32 mem_ack_reg;
+ u32 mem_enable_ack_mask;
+ struct clk_branch branch;
+};
+
/* Branch clock common bits for HLOS-owned clocks */
#define CBCR_CLK_OFF BIT(31)
#define CBCR_NOC_FSM_STATUS GENMASK(30, 28)
@@ -85,8 +102,12 @@ extern const struct clk_ops clk_branch_ops;
extern const struct clk_ops clk_branch2_ops;
extern const struct clk_ops clk_branch_simple_ops;
extern const struct clk_ops clk_branch2_aon_ops;
+extern const struct clk_ops clk_branch2_mem_ops;
#define to_clk_branch(_hw) \
container_of(to_clk_regmap(_hw), struct clk_branch, clkr)
+#define to_clk_mem_branch(_hw) \
+ container_of(to_clk_branch(_hw), struct clk_mem_branch, branch)
+
#endif
diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c
index 5d853fd43294..bb82abeed88f 100644
--- a/drivers/clk/qcom/clk-rpmh.c
+++ b/drivers/clk/qcom/clk-rpmh.c
@@ -372,6 +372,9 @@ DEFINE_CLK_RPMH_VRM(clk3, _a1, "clka3", 1);
DEFINE_CLK_RPMH_VRM(clk4, _a1, "clka4", 1);
DEFINE_CLK_RPMH_VRM(clk5, _a1, "clka5", 1);
+DEFINE_CLK_RPMH_VRM(clk3, _a2, "clka3", 2);
+DEFINE_CLK_RPMH_VRM(clk4, _a2, "clka4", 2);
+DEFINE_CLK_RPMH_VRM(clk5, _a2, "clka5", 2);
DEFINE_CLK_RPMH_VRM(clk6, _a2, "clka6", 2);
DEFINE_CLK_RPMH_VRM(clk7, _a2, "clka7", 2);
DEFINE_CLK_RPMH_VRM(clk8, _a2, "clka8", 2);
@@ -630,6 +633,37 @@ static const struct clk_rpmh_desc clk_rpmh_sm8550 = {
.num_clks = ARRAY_SIZE(sm8550_rpmh_clocks),
};
+static struct clk_hw *sm8650_rpmh_clocks[] = {
+ [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div2.hw,
+ [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div2_ao.hw,
+ [RPMH_LN_BB_CLK1] = &clk_rpmh_clk6_a2.hw,
+ [RPMH_LN_BB_CLK1_A] = &clk_rpmh_clk6_a2_ao.hw,
+ [RPMH_LN_BB_CLK2] = &clk_rpmh_clk7_a2.hw,
+ [RPMH_LN_BB_CLK2_A] = &clk_rpmh_clk7_a2_ao.hw,
+ [RPMH_LN_BB_CLK3] = &clk_rpmh_clk8_a2.hw,
+ [RPMH_LN_BB_CLK3_A] = &clk_rpmh_clk8_a2_ao.hw,
+ [RPMH_RF_CLK1] = &clk_rpmh_clk1_a1.hw,
+ [RPMH_RF_CLK1_A] = &clk_rpmh_clk1_a1_ao.hw,
+ [RPMH_RF_CLK2] = &clk_rpmh_clk2_a1.hw,
+ [RPMH_RF_CLK2_A] = &clk_rpmh_clk2_a1_ao.hw,
+ /*
+ * The clka3 RPMh resource is missing in cmd-db
+ * for current platforms, while the clka3 exists
+ * on the PMK8550, the clock is unconnected and
+ * unused.
+ */
+ [RPMH_RF_CLK4] = &clk_rpmh_clk4_a2.hw,
+ [RPMH_RF_CLK4_A] = &clk_rpmh_clk4_a2_ao.hw,
+ [RPMH_RF_CLK5] = &clk_rpmh_clk5_a2.hw,
+ [RPMH_RF_CLK5_A] = &clk_rpmh_clk5_a2_ao.hw,
+ [RPMH_IPA_CLK] = &clk_rpmh_ipa.hw,
+};
+
+static const struct clk_rpmh_desc clk_rpmh_sm8650 = {
+ .clks = sm8650_rpmh_clocks,
+ .num_clks = ARRAY_SIZE(sm8650_rpmh_clocks),
+};
+
static struct clk_hw *sc7280_rpmh_clocks[] = {
[RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div4.hw,
[RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div4_ao.hw,
@@ -737,6 +771,28 @@ static const struct clk_rpmh_desc clk_rpmh_sm4450 = {
.num_clks = ARRAY_SIZE(sm4450_rpmh_clocks),
};
+static struct clk_hw *x1e80100_rpmh_clocks[] = {
+ [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div2.hw,
+ [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div2_ao.hw,
+ [RPMH_LN_BB_CLK1] = &clk_rpmh_clk6_a2.hw,
+ [RPMH_LN_BB_CLK1_A] = &clk_rpmh_clk6_a2_ao.hw,
+ [RPMH_LN_BB_CLK2] = &clk_rpmh_clk7_a2.hw,
+ [RPMH_LN_BB_CLK2_A] = &clk_rpmh_clk7_a2_ao.hw,
+ [RPMH_LN_BB_CLK3] = &clk_rpmh_clk8_a2.hw,
+ [RPMH_LN_BB_CLK3_A] = &clk_rpmh_clk8_a2_ao.hw,
+ [RPMH_RF_CLK3] = &clk_rpmh_clk3_a2.hw,
+ [RPMH_RF_CLK3_A] = &clk_rpmh_clk3_a2_ao.hw,
+ [RPMH_RF_CLK4] = &clk_rpmh_clk4_a2.hw,
+ [RPMH_RF_CLK4_A] = &clk_rpmh_clk4_a2_ao.hw,
+ [RPMH_RF_CLK5] = &clk_rpmh_clk5_a2.hw,
+ [RPMH_RF_CLK5_A] = &clk_rpmh_clk5_a2_ao.hw,
+};
+
+static const struct clk_rpmh_desc clk_rpmh_x1e80100 = {
+ .clks = x1e80100_rpmh_clocks,
+ .num_clks = ARRAY_SIZE(x1e80100_rpmh_clocks),
+};
+
static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec,
void *data)
{
@@ -837,7 +893,9 @@ static const struct of_device_id clk_rpmh_match_table[] = {
{ .compatible = "qcom,sm8350-rpmh-clk", .data = &clk_rpmh_sm8350},
{ .compatible = "qcom,sm8450-rpmh-clk", .data = &clk_rpmh_sm8450},
{ .compatible = "qcom,sm8550-rpmh-clk", .data = &clk_rpmh_sm8550},
+ { .compatible = "qcom,sm8650-rpmh-clk", .data = &clk_rpmh_sm8650},
{ .compatible = "qcom,sc7280-rpmh-clk", .data = &clk_rpmh_sc7280},
+ { .compatible = "qcom,x1e80100-rpmh-clk", .data = &clk_rpmh_x1e80100},
{ }
};
MODULE_DEVICE_TABLE(of, clk_rpmh_match_table);
diff --git a/drivers/clk/qcom/dispcc-sm8550.c b/drivers/clk/qcom/dispcc-sm8550.c
index aefa19f3c2c5..f96d8b81fd9a 100644
--- a/drivers/clk/qcom/dispcc-sm8550.c
+++ b/drivers/clk/qcom/dispcc-sm8550.c
@@ -81,6 +81,10 @@ static const struct alpha_pll_config disp_cc_pll0_config = {
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00182261,
.config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
.user_ctl_val = 0x00000000,
.user_ctl_hi_val = 0x00000005,
};
@@ -108,6 +112,10 @@ static const struct alpha_pll_config disp_cc_pll1_config = {
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00182261,
.config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
.user_ctl_val = 0x00000000,
.user_ctl_hi_val = 0x00000005,
};
@@ -1766,8 +1774,8 @@ static int disp_cc_sm8550_probe(struct platform_device *pdev)
goto err_put_rpm;
}
- clk_lucid_evo_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config);
- clk_lucid_evo_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config);
+ clk_lucid_ole_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config);
+ clk_lucid_ole_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config);
/* Enable clock gating for MDP clocks */
regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x10, 0x10);
diff --git a/drivers/clk/qcom/dispcc-sm8650.c b/drivers/clk/qcom/dispcc-sm8650.c
new file mode 100644
index 000000000000..f3b1d9d16bae
--- /dev/null
+++ b/drivers/clk/qcom/dispcc-sm8650.c
@@ -0,0 +1,1818 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved
+ * Copyright (c) 2023, Linaro Ltd.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,sm8650-dispcc.h>
+
+#include "common.h"
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "reset.h"
+#include "gdsc.h"
+
+/* Need to match the order of clocks in DT binding */
+enum {
+ DT_BI_TCXO,
+ DT_BI_TCXO_AO,
+ DT_AHB_CLK,
+ DT_SLEEP_CLK,
+
+ DT_DSI0_PHY_PLL_OUT_BYTECLK,
+ DT_DSI0_PHY_PLL_OUT_DSICLK,
+ DT_DSI1_PHY_PLL_OUT_BYTECLK,
+ DT_DSI1_PHY_PLL_OUT_DSICLK,
+
+ DT_DP0_PHY_PLL_LINK_CLK,
+ DT_DP0_PHY_PLL_VCO_DIV_CLK,
+ DT_DP1_PHY_PLL_LINK_CLK,
+ DT_DP1_PHY_PLL_VCO_DIV_CLK,
+ DT_DP2_PHY_PLL_LINK_CLK,
+ DT_DP2_PHY_PLL_VCO_DIV_CLK,
+ DT_DP3_PHY_PLL_LINK_CLK,
+ DT_DP3_PHY_PLL_VCO_DIV_CLK,
+};
+
+#define DISP_CC_MISC_CMD 0xF000
+
+enum {
+ P_BI_TCXO,
+ P_DISP_CC_PLL0_OUT_MAIN,
+ P_DISP_CC_PLL1_OUT_EVEN,
+ P_DISP_CC_PLL1_OUT_MAIN,
+ P_DP0_PHY_PLL_LINK_CLK,
+ P_DP0_PHY_PLL_VCO_DIV_CLK,
+ P_DP1_PHY_PLL_LINK_CLK,
+ P_DP1_PHY_PLL_VCO_DIV_CLK,
+ P_DP2_PHY_PLL_LINK_CLK,
+ P_DP2_PHY_PLL_VCO_DIV_CLK,
+ P_DP3_PHY_PLL_LINK_CLK,
+ P_DP3_PHY_PLL_VCO_DIV_CLK,
+ P_DSI0_PHY_PLL_OUT_BYTECLK,
+ P_DSI0_PHY_PLL_OUT_DSICLK,
+ P_DSI1_PHY_PLL_OUT_BYTECLK,
+ P_DSI1_PHY_PLL_OUT_DSICLK,
+ P_SLEEP_CLK,
+};
+
+static struct pll_vco lucid_ole_vco[] = {
+ { 249600000, 2100000000, 0 },
+};
+
+static const struct alpha_pll_config disp_cc_pll0_config = {
+ .l = 0xd,
+ .alpha = 0x6492,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll disp_cc_pll0 = {
+ .offset = 0x0,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_pll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_reset_lucid_ole_ops,
+ },
+ },
+};
+
+static const struct alpha_pll_config disp_cc_pll1_config = {
+ .l = 0x1f,
+ .alpha = 0x4000,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll disp_cc_pll1 = {
+ .offset = 0x1000,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_pll1",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_reset_lucid_ole_ops,
+ },
+ },
+};
+
+static const struct parent_map disp_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_0_ao[] = {
+ { .index = DT_BI_TCXO_AO },
+};
+
+static const struct parent_map disp_cc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_DP3_PHY_PLL_VCO_DIV_CLK, 3 },
+ { P_DP1_PHY_PLL_VCO_DIV_CLK, 4 },
+ { P_DP2_PHY_PLL_VCO_DIV_CLK, 6 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_DP3_PHY_PLL_VCO_DIV_CLK },
+ { .index = DT_DP1_PHY_PLL_VCO_DIV_CLK },
+ { .index = DT_DP2_PHY_PLL_VCO_DIV_CLK },
+};
+
+static const struct parent_map disp_cc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_DSI0_PHY_PLL_OUT_DSICLK, 1 },
+ { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 },
+ { P_DSI1_PHY_PLL_OUT_DSICLK, 3 },
+ { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_DSI0_PHY_PLL_OUT_DSICLK },
+ { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK },
+ { .index = DT_DSI1_PHY_PLL_OUT_DSICLK },
+ { .index = DT_DSI1_PHY_PLL_OUT_BYTECLK },
+};
+
+static const struct parent_map disp_cc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_DP1_PHY_PLL_LINK_CLK, 2 },
+ { P_DP2_PHY_PLL_LINK_CLK, 3 },
+ { P_DP3_PHY_PLL_LINK_CLK, 4 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_3[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_DP1_PHY_PLL_LINK_CLK },
+ { .index = DT_DP2_PHY_PLL_LINK_CLK },
+ { .index = DT_DP3_PHY_PLL_LINK_CLK },
+};
+
+static const struct parent_map disp_cc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_DP0_PHY_PLL_LINK_CLK, 1 },
+ { P_DP0_PHY_PLL_VCO_DIV_CLK, 2 },
+ { P_DP3_PHY_PLL_VCO_DIV_CLK, 3 },
+ { P_DP1_PHY_PLL_VCO_DIV_CLK, 4 },
+ { P_DP2_PHY_PLL_VCO_DIV_CLK, 6 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_4[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_DP0_PHY_PLL_LINK_CLK },
+ { .index = DT_DP0_PHY_PLL_VCO_DIV_CLK },
+ { .index = DT_DP3_PHY_PLL_VCO_DIV_CLK },
+ { .index = DT_DP1_PHY_PLL_VCO_DIV_CLK },
+ { .index = DT_DP2_PHY_PLL_VCO_DIV_CLK },
+};
+
+static const struct parent_map disp_cc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+ { P_DSI0_PHY_PLL_OUT_BYTECLK, 2 },
+ { P_DSI1_PHY_PLL_OUT_BYTECLK, 4 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_5[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_DSI0_PHY_PLL_OUT_BYTECLK },
+ { .index = DT_DSI1_PHY_PLL_OUT_BYTECLK },
+};
+
+static const struct parent_map disp_cc_parent_map_6[] = {
+ { P_BI_TCXO, 0 },
+ { P_DISP_CC_PLL1_OUT_MAIN, 4 },
+ { P_DISP_CC_PLL1_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_6[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &disp_cc_pll1.clkr.hw },
+ { .hw = &disp_cc_pll1.clkr.hw },
+};
+
+static const struct parent_map disp_cc_parent_map_7[] = {
+ { P_BI_TCXO, 0 },
+ { P_DP0_PHY_PLL_LINK_CLK, 1 },
+ { P_DP1_PHY_PLL_LINK_CLK, 2 },
+ { P_DP2_PHY_PLL_LINK_CLK, 3 },
+ { P_DP3_PHY_PLL_LINK_CLK, 4 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_7[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_DP0_PHY_PLL_LINK_CLK },
+ { .index = DT_DP1_PHY_PLL_LINK_CLK },
+ { .index = DT_DP2_PHY_PLL_LINK_CLK },
+ { .index = DT_DP3_PHY_PLL_LINK_CLK },
+};
+
+static const struct parent_map disp_cc_parent_map_8[] = {
+ { P_BI_TCXO, 0 },
+ { P_DISP_CC_PLL0_OUT_MAIN, 1 },
+ { P_DISP_CC_PLL1_OUT_MAIN, 4 },
+ { P_DISP_CC_PLL1_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_8[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &disp_cc_pll0.clkr.hw },
+ { .hw = &disp_cc_pll1.clkr.hw },
+ { .hw = &disp_cc_pll1.clkr.hw },
+};
+
+static const struct parent_map disp_cc_parent_map_9[] = {
+ { P_SLEEP_CLK, 0 },
+};
+
+static const struct clk_parent_data disp_cc_parent_data_9[] = {
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct freq_tbl ftbl_disp_cc_mdss_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(37500000, P_DISP_CC_PLL1_OUT_MAIN, 16, 0, 0),
+ F(75000000, P_DISP_CC_PLL1_OUT_MAIN, 8, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 disp_cc_mdss_ahb_clk_src = {
+ .cmd_rcgr = 0x82e8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_6,
+ .freq_tbl = ftbl_disp_cc_mdss_ahb_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_ahb_clk_src",
+ .parent_data = disp_cc_parent_data_6,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_6),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_disp_cc_mdss_byte0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = {
+ .cmd_rcgr = 0x8108,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_2,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_byte0_clk_src",
+ .parent_data = disp_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_byte2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_byte1_clk_src = {
+ .cmd_rcgr = 0x8124,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_2,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_byte1_clk_src",
+ .parent_data = disp_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_byte2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx0_aux_clk_src = {
+ .cmd_rcgr = 0x81bc,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_0,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_aux_clk_src",
+ .parent_data = disp_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_disp_cc_mdss_dptx0_link_clk_src[] = {
+ F(162000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
+ F(270000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
+ F(540000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
+ F(810000, P_DP0_PHY_PLL_LINK_CLK, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx0_link_clk_src = {
+ .cmd_rcgr = 0x8170,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_7,
+ .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_link_clk_src",
+ .parent_data = disp_cc_parent_data_7,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_7),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx0_pixel0_clk_src = {
+ .cmd_rcgr = 0x818c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_4,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_pixel0_clk_src",
+ .parent_data = disp_cc_parent_data_4,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx0_pixel1_clk_src = {
+ .cmd_rcgr = 0x81a4,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_4,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_pixel1_clk_src",
+ .parent_data = disp_cc_parent_data_4,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx1_aux_clk_src = {
+ .cmd_rcgr = 0x8220,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_0,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_aux_clk_src",
+ .parent_data = disp_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx1_link_clk_src = {
+ .cmd_rcgr = 0x8204,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_3,
+ .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_link_clk_src",
+ .parent_data = disp_cc_parent_data_3,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx1_pixel0_clk_src = {
+ .cmd_rcgr = 0x81d4,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_1,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_pixel0_clk_src",
+ .parent_data = disp_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx1_pixel1_clk_src = {
+ .cmd_rcgr = 0x81ec,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_1,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_pixel1_clk_src",
+ .parent_data = disp_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx2_aux_clk_src = {
+ .cmd_rcgr = 0x8284,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_0,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_aux_clk_src",
+ .parent_data = disp_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx2_link_clk_src = {
+ .cmd_rcgr = 0x8238,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_3,
+ .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_link_clk_src",
+ .parent_data = disp_cc_parent_data_3,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx2_pixel0_clk_src = {
+ .cmd_rcgr = 0x8254,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_1,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_pixel0_clk_src",
+ .parent_data = disp_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx2_pixel1_clk_src = {
+ .cmd_rcgr = 0x826c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_1,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_pixel1_clk_src",
+ .parent_data = disp_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx3_aux_clk_src = {
+ .cmd_rcgr = 0x82d0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_0,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_aux_clk_src",
+ .parent_data = disp_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx3_link_clk_src = {
+ .cmd_rcgr = 0x82b4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_3,
+ .freq_tbl = ftbl_disp_cc_mdss_dptx0_link_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_link_clk_src",
+ .parent_data = disp_cc_parent_data_3,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_dptx3_pixel0_clk_src = {
+ .cmd_rcgr = 0x829c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_1,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_pixel0_clk_src",
+ .parent_data = disp_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_dp_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = {
+ .cmd_rcgr = 0x8140,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_5,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_esc0_clk_src",
+ .parent_data = disp_cc_parent_data_5,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = {
+ .cmd_rcgr = 0x8158,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_5,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_esc1_clk_src",
+ .parent_data = disp_cc_parent_data_5,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(85714286, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(100000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(150000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(200000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(325000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(402000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(514000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = {
+ .cmd_rcgr = 0x80d8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_8,
+ .freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_mdp_clk_src",
+ .parent_data = disp_cc_parent_data_8,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_8),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = {
+ .cmd_rcgr = 0x80a8,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_2,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_pclk0_clk_src",
+ .parent_data = disp_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_pixel_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = {
+ .cmd_rcgr = 0x80c0,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_2,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_pclk1_clk_src",
+ .parent_data = disp_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_pixel_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = {
+ .cmd_rcgr = 0x80f0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_0,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_vsync_clk_src",
+ .parent_data = disp_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_disp_cc_sleep_clk_src[] = {
+ F(32000, P_SLEEP_CLK, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 disp_cc_sleep_clk_src = {
+ .cmd_rcgr = 0xe05c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_9,
+ .freq_tbl = ftbl_disp_cc_sleep_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_sleep_clk_src",
+ .parent_data = disp_cc_parent_data_9,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_9),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 disp_cc_xo_clk_src = {
+ .cmd_rcgr = 0xe03c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = disp_cc_parent_map_0,
+ .freq_tbl = ftbl_disp_cc_mdss_byte0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_xo_clk_src",
+ .parent_data = disp_cc_parent_data_0_ao,
+ .num_parents = ARRAY_SIZE(disp_cc_parent_data_0_ao),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = {
+ .reg = 0x8120,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_byte0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ },
+};
+
+static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = {
+ .reg = 0x813c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_byte1_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ },
+};
+
+static struct clk_regmap_div disp_cc_mdss_dptx0_link_div_clk_src = {
+ .reg = 0x8188,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_link_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div disp_cc_mdss_dptx1_link_div_clk_src = {
+ .reg = 0x821c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_link_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div disp_cc_mdss_dptx2_link_div_clk_src = {
+ .reg = 0x8250,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_link_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div disp_cc_mdss_dptx3_link_div_clk_src = {
+ .reg = 0x82cc,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_link_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch disp_cc_mdss_accu_clk = {
+ .halt_reg = 0xe058,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0xe058,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_accu_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_ahb1_clk = {
+ .halt_reg = 0xa020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_ahb1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_ahb_clk = {
+ .halt_reg = 0x80a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_byte0_clk = {
+ .halt_reg = 0x8028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_byte0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_byte0_intf_clk = {
+ .halt_reg = 0x802c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x802c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_byte0_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte0_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_byte1_clk = {
+ .halt_reg = 0x8030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_byte1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_byte1_intf_clk = {
+ .halt_reg = 0x8034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_byte1_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_byte1_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_aux_clk = {
+ .halt_reg = 0x8058,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8058,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_crypto_clk = {
+ .halt_reg = 0x804c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x804c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_crypto_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_link_clk = {
+ .halt_reg = 0x8040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8040,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_link_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_link_intf_clk = {
+ .halt_reg = 0x8048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8048,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_pixel0_clk = {
+ .halt_reg = 0x8050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8050,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_pixel0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_pixel0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_pixel1_clk = {
+ .halt_reg = 0x8054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8054,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_pixel1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_pixel1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx0_usb_router_link_intf_clk = {
+ .halt_reg = 0x8044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx0_usb_router_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx0_link_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_aux_clk = {
+ .halt_reg = 0x8074,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8074,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_crypto_clk = {
+ .halt_reg = 0x8070,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8070,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_crypto_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_link_clk = {
+ .halt_reg = 0x8064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_link_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_link_intf_clk = {
+ .halt_reg = 0x806c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x806c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_pixel0_clk = {
+ .halt_reg = 0x805c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x805c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_pixel0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_pixel0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_pixel1_clk = {
+ .halt_reg = 0x8060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_pixel1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_pixel1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx1_usb_router_link_intf_clk = {
+ .halt_reg = 0x8068,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx1_usb_router_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx1_link_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx2_aux_clk = {
+ .halt_reg = 0x808c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x808c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx2_crypto_clk = {
+ .halt_reg = 0x8088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8088,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_crypto_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx2_link_clk = {
+ .halt_reg = 0x8080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8080,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_link_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx2_link_intf_clk = {
+ .halt_reg = 0x8084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8084,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_link_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx2_pixel0_clk = {
+ .halt_reg = 0x8078,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8078,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_pixel0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_pixel0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx2_pixel1_clk = {
+ .halt_reg = 0x807c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x807c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx2_pixel1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx2_pixel1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx3_aux_clk = {
+ .halt_reg = 0x809c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x809c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx3_crypto_clk = {
+ .halt_reg = 0x80a0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80a0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_crypto_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx3_link_clk = {
+ .halt_reg = 0x8094,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8094,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_link_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_link_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx3_link_intf_clk = {
+ .halt_reg = 0x8098,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8098,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_link_intf_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_link_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_dptx3_pixel0_clk = {
+ .halt_reg = 0x8090,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8090,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_dptx3_pixel0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_dptx3_pixel0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_esc0_clk = {
+ .halt_reg = 0x8038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8038,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_esc0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_esc0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_esc1_clk = {
+ .halt_reg = 0x803c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x803c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_esc1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_esc1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_mdp1_clk = {
+ .halt_reg = 0xa004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_mdp1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_mdp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_mdp_clk = {
+ .halt_reg = 0x800c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x800c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_mdp_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_mdp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_mdp_lut1_clk = {
+ .halt_reg = 0xa010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_mdp_lut1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_mdp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_mdp_lut_clk = {
+ .halt_reg = 0x8018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x8018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_mdp_lut_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_mdp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_non_gdsc_ahb_clk = {
+ .halt_reg = 0xc004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0xc004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_non_gdsc_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_pclk0_clk = {
+ .halt_reg = 0x8004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_pclk0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_pclk0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_pclk1_clk = {
+ .halt_reg = 0x8008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_pclk1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_pclk1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_rscc_ahb_clk = {
+ .halt_reg = 0xc00c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_rscc_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_rscc_vsync_clk = {
+ .halt_reg = 0xc008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xc008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_rscc_vsync_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_vsync_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_vsync1_clk = {
+ .halt_reg = 0xa01c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa01c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_vsync1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_vsync_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_mdss_vsync_clk = {
+ .halt_reg = 0x8024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_mdss_vsync_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_mdss_vsync_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch disp_cc_sleep_clk = {
+ .halt_reg = 0xe074,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xe074,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "disp_cc_sleep_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &disp_cc_sleep_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc mdss_gdsc = {
+ .gdscr = 0x9000,
+ .pd = {
+ .name = "mdss_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = HW_CTRL | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc mdss_int2_gdsc = {
+ .gdscr = 0xb000,
+ .pd = {
+ .name = "mdss_int2_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = HW_CTRL | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *disp_cc_sm8650_clocks[] = {
+ [DISP_CC_MDSS_ACCU_CLK] = &disp_cc_mdss_accu_clk.clkr,
+ [DISP_CC_MDSS_AHB1_CLK] = &disp_cc_mdss_ahb1_clk.clkr,
+ [DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr,
+ [DISP_CC_MDSS_AHB_CLK_SRC] = &disp_cc_mdss_ahb_clk_src.clkr,
+ [DISP_CC_MDSS_BYTE0_CLK] = &disp_cc_mdss_byte0_clk.clkr,
+ [DISP_CC_MDSS_BYTE0_CLK_SRC] = &disp_cc_mdss_byte0_clk_src.clkr,
+ [DISP_CC_MDSS_BYTE0_DIV_CLK_SRC] = &disp_cc_mdss_byte0_div_clk_src.clkr,
+ [DISP_CC_MDSS_BYTE0_INTF_CLK] = &disp_cc_mdss_byte0_intf_clk.clkr,
+ [DISP_CC_MDSS_BYTE1_CLK] = &disp_cc_mdss_byte1_clk.clkr,
+ [DISP_CC_MDSS_BYTE1_CLK_SRC] = &disp_cc_mdss_byte1_clk_src.clkr,
+ [DISP_CC_MDSS_BYTE1_DIV_CLK_SRC] = &disp_cc_mdss_byte1_div_clk_src.clkr,
+ [DISP_CC_MDSS_BYTE1_INTF_CLK] = &disp_cc_mdss_byte1_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_AUX_CLK] = &disp_cc_mdss_dptx0_aux_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_AUX_CLK_SRC] = &disp_cc_mdss_dptx0_aux_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX0_CRYPTO_CLK] = &disp_cc_mdss_dptx0_crypto_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_LINK_CLK] = &disp_cc_mdss_dptx0_link_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_LINK_CLK_SRC] = &disp_cc_mdss_dptx0_link_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX0_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx0_link_div_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX0_LINK_INTF_CLK] = &disp_cc_mdss_dptx0_link_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_PIXEL0_CLK] = &disp_cc_mdss_dptx0_pixel0_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx0_pixel0_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX0_PIXEL1_CLK] = &disp_cc_mdss_dptx0_pixel1_clk.clkr,
+ [DISP_CC_MDSS_DPTX0_PIXEL1_CLK_SRC] = &disp_cc_mdss_dptx0_pixel1_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX0_USB_ROUTER_LINK_INTF_CLK] =
+ &disp_cc_mdss_dptx0_usb_router_link_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_AUX_CLK] = &disp_cc_mdss_dptx1_aux_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_AUX_CLK_SRC] = &disp_cc_mdss_dptx1_aux_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX1_CRYPTO_CLK] = &disp_cc_mdss_dptx1_crypto_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_LINK_CLK] = &disp_cc_mdss_dptx1_link_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_LINK_CLK_SRC] = &disp_cc_mdss_dptx1_link_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX1_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx1_link_div_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX1_LINK_INTF_CLK] = &disp_cc_mdss_dptx1_link_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_PIXEL0_CLK] = &disp_cc_mdss_dptx1_pixel0_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx1_pixel0_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX1_PIXEL1_CLK] = &disp_cc_mdss_dptx1_pixel1_clk.clkr,
+ [DISP_CC_MDSS_DPTX1_PIXEL1_CLK_SRC] = &disp_cc_mdss_dptx1_pixel1_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX1_USB_ROUTER_LINK_INTF_CLK] =
+ &disp_cc_mdss_dptx1_usb_router_link_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_AUX_CLK] = &disp_cc_mdss_dptx2_aux_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_AUX_CLK_SRC] = &disp_cc_mdss_dptx2_aux_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX2_CRYPTO_CLK] = &disp_cc_mdss_dptx2_crypto_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_LINK_CLK] = &disp_cc_mdss_dptx2_link_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_LINK_CLK_SRC] = &disp_cc_mdss_dptx2_link_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX2_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx2_link_div_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX2_LINK_INTF_CLK] = &disp_cc_mdss_dptx2_link_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_PIXEL0_CLK] = &disp_cc_mdss_dptx2_pixel0_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx2_pixel0_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX2_PIXEL1_CLK] = &disp_cc_mdss_dptx2_pixel1_clk.clkr,
+ [DISP_CC_MDSS_DPTX2_PIXEL1_CLK_SRC] = &disp_cc_mdss_dptx2_pixel1_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX3_AUX_CLK] = &disp_cc_mdss_dptx3_aux_clk.clkr,
+ [DISP_CC_MDSS_DPTX3_AUX_CLK_SRC] = &disp_cc_mdss_dptx3_aux_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX3_CRYPTO_CLK] = &disp_cc_mdss_dptx3_crypto_clk.clkr,
+ [DISP_CC_MDSS_DPTX3_LINK_CLK] = &disp_cc_mdss_dptx3_link_clk.clkr,
+ [DISP_CC_MDSS_DPTX3_LINK_CLK_SRC] = &disp_cc_mdss_dptx3_link_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX3_LINK_DIV_CLK_SRC] = &disp_cc_mdss_dptx3_link_div_clk_src.clkr,
+ [DISP_CC_MDSS_DPTX3_LINK_INTF_CLK] = &disp_cc_mdss_dptx3_link_intf_clk.clkr,
+ [DISP_CC_MDSS_DPTX3_PIXEL0_CLK] = &disp_cc_mdss_dptx3_pixel0_clk.clkr,
+ [DISP_CC_MDSS_DPTX3_PIXEL0_CLK_SRC] = &disp_cc_mdss_dptx3_pixel0_clk_src.clkr,
+ [DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr,
+ [DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr,
+ [DISP_CC_MDSS_ESC1_CLK] = &disp_cc_mdss_esc1_clk.clkr,
+ [DISP_CC_MDSS_ESC1_CLK_SRC] = &disp_cc_mdss_esc1_clk_src.clkr,
+ [DISP_CC_MDSS_MDP1_CLK] = &disp_cc_mdss_mdp1_clk.clkr,
+ [DISP_CC_MDSS_MDP_CLK] = &disp_cc_mdss_mdp_clk.clkr,
+ [DISP_CC_MDSS_MDP_CLK_SRC] = &disp_cc_mdss_mdp_clk_src.clkr,
+ [DISP_CC_MDSS_MDP_LUT1_CLK] = &disp_cc_mdss_mdp_lut1_clk.clkr,
+ [DISP_CC_MDSS_MDP_LUT_CLK] = &disp_cc_mdss_mdp_lut_clk.clkr,
+ [DISP_CC_MDSS_NON_GDSC_AHB_CLK] = &disp_cc_mdss_non_gdsc_ahb_clk.clkr,
+ [DISP_CC_MDSS_PCLK0_CLK] = &disp_cc_mdss_pclk0_clk.clkr,
+ [DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr,
+ [DISP_CC_MDSS_PCLK1_CLK] = &disp_cc_mdss_pclk1_clk.clkr,
+ [DISP_CC_MDSS_PCLK1_CLK_SRC] = &disp_cc_mdss_pclk1_clk_src.clkr,
+ [DISP_CC_MDSS_RSCC_AHB_CLK] = &disp_cc_mdss_rscc_ahb_clk.clkr,
+ [DISP_CC_MDSS_RSCC_VSYNC_CLK] = &disp_cc_mdss_rscc_vsync_clk.clkr,
+ [DISP_CC_MDSS_VSYNC1_CLK] = &disp_cc_mdss_vsync1_clk.clkr,
+ [DISP_CC_MDSS_VSYNC_CLK] = &disp_cc_mdss_vsync_clk.clkr,
+ [DISP_CC_MDSS_VSYNC_CLK_SRC] = &disp_cc_mdss_vsync_clk_src.clkr,
+ [DISP_CC_PLL0] = &disp_cc_pll0.clkr,
+ [DISP_CC_PLL1] = &disp_cc_pll1.clkr,
+ [DISP_CC_SLEEP_CLK] = &disp_cc_sleep_clk.clkr,
+ [DISP_CC_SLEEP_CLK_SRC] = &disp_cc_sleep_clk_src.clkr,
+ [DISP_CC_XO_CLK_SRC] = &disp_cc_xo_clk_src.clkr,
+};
+
+static const struct qcom_reset_map disp_cc_sm8650_resets[] = {
+ [DISP_CC_MDSS_CORE_BCR] = { 0x8000 },
+ [DISP_CC_MDSS_CORE_INT2_BCR] = { 0xa000 },
+ [DISP_CC_MDSS_RSCC_BCR] = { 0xc000 },
+};
+
+static struct gdsc *disp_cc_sm8650_gdscs[] = {
+ [MDSS_GDSC] = &mdss_gdsc,
+ [MDSS_INT2_GDSC] = &mdss_int2_gdsc,
+};
+
+static const struct regmap_config disp_cc_sm8650_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x11008,
+ .fast_io = true,
+};
+
+static struct qcom_cc_desc disp_cc_sm8650_desc = {
+ .config = &disp_cc_sm8650_regmap_config,
+ .clks = disp_cc_sm8650_clocks,
+ .num_clks = ARRAY_SIZE(disp_cc_sm8650_clocks),
+ .resets = disp_cc_sm8650_resets,
+ .num_resets = ARRAY_SIZE(disp_cc_sm8650_resets),
+ .gdscs = disp_cc_sm8650_gdscs,
+ .num_gdscs = ARRAY_SIZE(disp_cc_sm8650_gdscs),
+};
+
+static const struct of_device_id disp_cc_sm8650_match_table[] = {
+ { .compatible = "qcom,sm8650-dispcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, disp_cc_sm8650_match_table);
+
+static int disp_cc_sm8650_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ int ret;
+
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret)
+ return ret;
+
+ regmap = qcom_cc_map(pdev, &disp_cc_sm8650_desc);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ goto err_put_rpm;
+ }
+
+ clk_lucid_ole_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config);
+ clk_lucid_ole_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config);
+
+ /* Enable clock gating for MDP clocks */
+ regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x10, 0x10);
+
+ /* Keep clocks always enabled */
+ regmap_update_bits(regmap, 0xe054, BIT(0), BIT(0)); /* disp_cc_xo_clk */
+
+ ret = qcom_cc_really_probe(pdev, &disp_cc_sm8650_desc, regmap);
+ if (ret)
+ goto err_put_rpm;
+
+ pm_runtime_put(&pdev->dev);
+
+ return 0;
+
+err_put_rpm:
+ pm_runtime_put_sync(&pdev->dev);
+
+ return ret;
+}
+
+static struct platform_driver disp_cc_sm8650_driver = {
+ .probe = disp_cc_sm8650_probe,
+ .driver = {
+ .name = "disp_cc-sm8650",
+ .of_match_table = disp_cc_sm8650_match_table,
+ },
+};
+
+static int __init disp_cc_sm8650_init(void)
+{
+ return platform_driver_register(&disp_cc_sm8650_driver);
+}
+subsys_initcall(disp_cc_sm8650_init);
+
+static void __exit disp_cc_sm8650_exit(void)
+{
+ platform_driver_unregister(&disp_cc_sm8650_driver);
+}
+module_exit(disp_cc_sm8650_exit);
+
+MODULE_DESCRIPTION("QTI DISPCC SM8650 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/ecpricc-qdu1000.c b/drivers/clk/qcom/ecpricc-qdu1000.c
new file mode 100644
index 000000000000..c628054a7025
--- /dev/null
+++ b/drivers/clk/qcom/ecpricc-qdu1000.c
@@ -0,0 +1,2456 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,qdu1000-ecpricc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "common.h"
+#include "reset.h"
+
+enum {
+ DT_BI_TCXO,
+ DT_GCC_ECPRI_CC_GPLL0_OUT_MAIN,
+ DT_GCC_ECPRI_CC_GPLL1_OUT_EVEN,
+ DT_GCC_ECPRI_CC_GPLL2_OUT_MAIN,
+ DT_GCC_ECPRI_CC_GPLL3_OUT_MAIN,
+ DT_GCC_ECPRI_CC_GPLL4_OUT_MAIN,
+ DT_GCC_ECPRI_CC_GPLL5_OUT_EVEN,
+};
+
+enum {
+ P_BI_TCXO,
+ P_ECPRI_CC_PLL0_OUT_MAIN,
+ P_ECPRI_CC_PLL1_OUT_MAIN,
+ P_GCC_ECPRI_CC_GPLL0_OUT_MAIN,
+ P_GCC_ECPRI_CC_GPLL1_OUT_EVEN,
+ P_GCC_ECPRI_CC_GPLL2_OUT_MAIN,
+ P_GCC_ECPRI_CC_GPLL3_OUT_MAIN,
+ P_GCC_ECPRI_CC_GPLL4_OUT_MAIN,
+ P_GCC_ECPRI_CC_GPLL5_OUT_EVEN,
+};
+
+static const struct pll_vco lucid_evo_vco[] = {
+ { 249600000, 2020000000, 0 },
+};
+
+/* 700 MHz configuration */
+static const struct alpha_pll_config ecpri_cc_pll0_config = {
+ .l = 0x24,
+ .alpha = 0x7555,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x32aa299c,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000805,
+};
+
+static struct clk_alpha_pll ecpri_cc_pll0 = {
+ .offset = 0x0,
+ .vco_table = lucid_evo_vco,
+ .num_vco = ARRAY_SIZE(lucid_evo_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_pll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+/* 806 MHz configuration */
+static const struct alpha_pll_config ecpri_cc_pll1_config = {
+ .l = 0x29,
+ .alpha = 0xfaaa,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x32aa299c,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000805,
+};
+
+static struct clk_alpha_pll ecpri_cc_pll1 = {
+ .offset = 0x1000,
+ .vco_table = lucid_evo_vco,
+ .num_vco = ARRAY_SIZE(lucid_evo_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO],
+ .clkr = {
+ .enable_reg = 0x0,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_pll1",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct parent_map ecpri_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, 2 },
+ { P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 3 },
+ { P_ECPRI_CC_PLL1_OUT_MAIN, 4 },
+ { P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 5 },
+ { P_ECPRI_CC_PLL0_OUT_MAIN, 6 },
+};
+
+static const struct clk_parent_data ecpri_cc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_GCC_ECPRI_CC_GPLL0_OUT_MAIN },
+ { .index = DT_GCC_ECPRI_CC_GPLL2_OUT_MAIN },
+ { .index = DT_GCC_ECPRI_CC_GPLL5_OUT_EVEN },
+ { .hw = &ecpri_cc_pll1.clkr.hw },
+ { .index = DT_GCC_ECPRI_CC_GPLL4_OUT_MAIN },
+ { .hw = &ecpri_cc_pll0.clkr.hw },
+};
+
+static const struct parent_map ecpri_cc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_ECPRI_CC_GPLL1_OUT_EVEN, 2 },
+ { P_GCC_ECPRI_CC_GPLL3_OUT_MAIN, 3 },
+ { P_ECPRI_CC_PLL1_OUT_MAIN, 4 },
+ { P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 5 },
+ { P_ECPRI_CC_PLL0_OUT_MAIN, 6 },
+};
+
+static const struct clk_parent_data ecpri_cc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_GCC_ECPRI_CC_GPLL0_OUT_MAIN },
+ { .index = DT_GCC_ECPRI_CC_GPLL1_OUT_EVEN },
+ { .index = DT_GCC_ECPRI_CC_GPLL3_OUT_MAIN },
+ { .hw = &ecpri_cc_pll1.clkr.hw },
+ { .index = DT_GCC_ECPRI_CC_GPLL4_OUT_MAIN },
+ { .hw = &ecpri_cc_pll0.clkr.hw },
+};
+
+static const struct parent_map ecpri_cc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 3 },
+ { P_ECPRI_CC_PLL1_OUT_MAIN, 4 },
+ { P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 5 },
+ { P_ECPRI_CC_PLL0_OUT_MAIN, 6 },
+};
+
+static const struct clk_parent_data ecpri_cc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_GCC_ECPRI_CC_GPLL0_OUT_MAIN },
+ { .index = DT_GCC_ECPRI_CC_GPLL5_OUT_EVEN },
+ { .hw = &ecpri_cc_pll1.clkr.hw },
+ { .index = DT_GCC_ECPRI_CC_GPLL4_OUT_MAIN },
+ { .hw = &ecpri_cc_pll0.clkr.hw },
+};
+
+static const struct freq_tbl ftbl_ecpri_cc_ecpri_clk_src[] = {
+ F(466500000, P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ecpri_cc_ecpri_clk_src = {
+ .cmd_rcgr = 0x9034,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_2,
+ .freq_tbl = ftbl_ecpri_cc_ecpri_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_clk_src",
+ .parent_data = ecpri_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_ecpri_cc_ecpri_dma_clk_src[] = {
+ F(466500000, P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 1, 0, 0),
+ F(500000000, P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ecpri_cc_ecpri_dma_clk_src = {
+ .cmd_rcgr = 0x9080,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_0,
+ .freq_tbl = ftbl_ecpri_cc_ecpri_dma_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_dma_clk_src",
+ .parent_data = ecpri_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_ecpri_cc_ecpri_fast_clk_src[] = {
+ F(500000000, P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, 1, 0, 0),
+ F(600000000, P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ecpri_cc_ecpri_fast_clk_src = {
+ .cmd_rcgr = 0x904c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_0,
+ .freq_tbl = ftbl_ecpri_cc_ecpri_fast_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_fast_clk_src",
+ .parent_data = ecpri_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_ecpri_cc_ecpri_oran_clk_src[] = {
+ F(500000000, P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ecpri_cc_ecpri_oran_clk_src = {
+ .cmd_rcgr = 0x9064,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_0,
+ .freq_tbl = ftbl_ecpri_cc_ecpri_oran_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_oran_clk_src",
+ .parent_data = ecpri_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src[] = {
+ F(201500000, P_ECPRI_CC_PLL1_OUT_MAIN, 4, 0, 0),
+ F(403000000, P_ECPRI_CC_PLL1_OUT_MAIN, 2, 0, 0),
+ F(466500000, P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_c2c0_hm_ff_clk_src = {
+ .cmd_rcgr = 0x81b0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_0,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_c2c0_hm_ff_clk_src",
+ .parent_data = ecpri_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_ecpri_cc_eth_100g_c2c_hm_macsec_clk_src[] = {
+ F(100000000, P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(200000000, P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_c2c_hm_macsec_clk_src = {
+ .cmd_rcgr = 0x8150,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_0,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c_hm_macsec_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_c2c_hm_macsec_clk_src",
+ .parent_data = ecpri_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src = {
+ .cmd_rcgr = 0x81c8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_0,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src",
+ .parent_data = ecpri_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_fh0_hm_ff_clk_src = {
+ .cmd_rcgr = 0x8168,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_0,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh0_hm_ff_clk_src",
+ .parent_data = ecpri_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_fh0_macsec_clk_src = {
+ .cmd_rcgr = 0x8108,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_0,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c_hm_macsec_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh0_macsec_clk_src",
+ .parent_data = ecpri_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_fh1_hm_ff_clk_src = {
+ .cmd_rcgr = 0x8180,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_0,
+ .freq_tbl = ftbl_ecpri_cc_ecpri_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh1_hm_ff_clk_src",
+ .parent_data = ecpri_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_ecpri_cc_eth_100g_fh1_macsec_clk_src[] = {
+ F(200000000, P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_fh1_macsec_clk_src = {
+ .cmd_rcgr = 0x8120,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_0,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_fh1_macsec_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh1_macsec_clk_src",
+ .parent_data = ecpri_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_fh2_hm_ff_clk_src = {
+ .cmd_rcgr = 0x8198,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_0,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh2_hm_ff_clk_src",
+ .parent_data = ecpri_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_fh2_macsec_clk_src = {
+ .cmd_rcgr = 0x8138,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_0,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_fh1_macsec_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh2_macsec_clk_src",
+ .parent_data = ecpri_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src[] = {
+ F(533000000, P_GCC_ECPRI_CC_GPLL1_OUT_EVEN, 1, 0, 0),
+ F(700000000, P_GCC_ECPRI_CC_GPLL3_OUT_MAIN, 1, 0, 0),
+ F(806000000, P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src = {
+ .cmd_rcgr = 0x8228,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_1,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src",
+ .parent_data = ecpri_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk_src = {
+ .cmd_rcgr = 0x8240,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_1,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk_src",
+ .parent_data = ecpri_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_mac_fh0_hm_ref_clk_src = {
+ .cmd_rcgr = 0x81e0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_1,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_mac_fh0_hm_ref_clk_src",
+ .parent_data = ecpri_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_mac_fh1_hm_ref_clk_src = {
+ .cmd_rcgr = 0x81f8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_1,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_mac_fh1_hm_ref_clk_src",
+ .parent_data = ecpri_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 ecpri_cc_eth_100g_mac_fh2_hm_ref_clk_src = {
+ .cmd_rcgr = 0x8210,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_1,
+ .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_mac_fh2_hm_ref_clk_src",
+ .parent_data = ecpri_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_ecpri_cc_mss_emac_clk_src[] = {
+ F(403000000, P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 ecpri_cc_mss_emac_clk_src = {
+ .cmd_rcgr = 0xe00c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = ecpri_cc_parent_map_2,
+ .freq_tbl = ftbl_ecpri_cc_mss_emac_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_mss_emac_clk_src",
+ .parent_data = ecpri_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_2),
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_ecpri_fast_div2_clk_src = {
+ .reg = 0x907c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_fast_div2_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_fast_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_c2c_hm_ff_0_div_clk_src = {
+ .reg = 0x8290,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_c2c_hm_ff_0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_c2c0_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_c2c_hm_ff_1_div_clk_src = {
+ .reg = 0x8294,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_c2c_hm_ff_1_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_c2c0_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_div_clk_src = {
+ .reg = 0x8298,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_div_clk_src = {
+ .reg = 0x829c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_fh_0_hm_ff_0_div_clk_src = {
+ .reg = 0x8260,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_0_hm_ff_0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_fh_0_hm_ff_1_div_clk_src = {
+ .reg = 0x8264,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_0_hm_ff_1_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_fh_0_hm_ff_2_div_clk_src = {
+ .reg = 0x8268,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_0_hm_ff_2_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_fh_0_hm_ff_3_div_clk_src = {
+ .reg = 0x826c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_0_hm_ff_3_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_fh_1_hm_ff_0_div_clk_src = {
+ .reg = 0x8270,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_1_hm_ff_0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_fh_1_hm_ff_1_div_clk_src = {
+ .reg = 0x8274,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_1_hm_ff_1_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_fh_1_hm_ff_2_div_clk_src = {
+ .reg = 0x8278,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_1_hm_ff_2_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_fh_1_hm_ff_3_div_clk_src = {
+ .reg = 0x827c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_1_hm_ff_3_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_fh_2_hm_ff_0_div_clk_src = {
+ .reg = 0x8280,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_2_hm_ff_0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_fh_2_hm_ff_1_div_clk_src = {
+ .reg = 0x8284,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_2_hm_ff_1_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_fh_2_hm_ff_2_div_clk_src = {
+ .reg = 0x8288,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_2_hm_ff_2_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div ecpri_cc_eth_100g_fh_2_hm_ff_3_div_clk_src = {
+ .reg = 0x828c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_2_hm_ff_3_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch ecpri_cc_ecpri_cg_clk = {
+ .halt_reg = 0x900c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x900c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_cg_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_ecpri_dma_clk = {
+ .halt_reg = 0x902c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x902c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_dma_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_dma_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_ecpri_dma_noc_clk = {
+ .halt_reg = 0xf004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_dma_noc_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_dma_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_ecpri_fast_clk = {
+ .halt_reg = 0x9014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_fast_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_fast_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_ecpri_fast_div2_clk = {
+ .halt_reg = 0x901c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x901c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_fast_div2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_fast_div2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_ecpri_fast_div2_noc_clk = {
+ .halt_reg = 0xf008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xf008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_fast_div2_noc_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_fast_div2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_ecpri_fr_clk = {
+ .halt_reg = 0x9004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_fr_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_ecpri_oran_div2_clk = {
+ .halt_reg = 0x9024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_ecpri_oran_div2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_oran_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_eth_100g_c2c0_udp_fifo_clk = {
+ .halt_reg = 0x80cc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80cc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_c2c0_udp_fifo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_eth_100g_c2c1_udp_fifo_clk = {
+ .halt_reg = 0x80d0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80d0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_c2c1_udp_fifo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_c2c_0_hm_ff_0_clk = {
+ .mem_enable_reg = 0x8410,
+ .mem_ack_reg = 0x8424,
+ .mem_enable_ack_mask = BIT(0),
+ .branch = {
+ .halt_reg = 0x80b4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80b4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_c2c_0_hm_ff_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_c2c_hm_ff_0_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_c2c_0_hm_ff_1_clk = {
+ .mem_enable_reg = 0x8410,
+ .mem_ack_reg = 0x8424,
+ .mem_enable_ack_mask = BIT(1),
+ .branch = {
+ .halt_reg = 0x80bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_c2c_0_hm_ff_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_c2c_hm_ff_1_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_c2c_hm_macsec_clk = {
+ .mem_enable_reg = 0x8410,
+ .mem_ack_reg = 0x8424,
+ .mem_enable_ack_mask = BIT(4),
+ .branch = {
+ .halt_reg = 0x80ac,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80ac,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_c2c_hm_macsec_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_c2c_hm_macsec_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_clk = {
+ .mem_enable_reg = 0x8414,
+ .mem_ack_reg = 0x8428,
+ .mem_enable_ack_mask = BIT(0),
+ .branch = {
+ .halt_reg = 0x80d8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80d8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_clk = {
+ .mem_enable_reg = 0x8414,
+ .mem_ack_reg = 0x8428,
+ .mem_enable_ack_mask = BIT(1),
+ .branch = {
+ .halt_reg = 0x80e0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80e0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_eth_100g_dbg_c2c_udp_fifo_clk = {
+ .halt_reg = 0x80f0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80f0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_dbg_c2c_udp_fifo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_0_hm_ff_0_clk = {
+ .mem_enable_reg = 0x8404,
+ .mem_ack_reg = 0x8418,
+ .mem_enable_ack_mask = BIT(0),
+ .branch = {
+ .halt_reg = 0x800c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x800c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_0_hm_ff_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh_0_hm_ff_0_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_0_hm_ff_1_clk = {
+ .mem_enable_reg = 0x8404,
+ .mem_ack_reg = 0x8418,
+ .mem_enable_ack_mask = BIT(1),
+ .branch = {
+ .halt_reg = 0x8014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_0_hm_ff_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh_0_hm_ff_1_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_0_hm_ff_2_clk = {
+ .mem_enable_reg = 0x8404,
+ .mem_ack_reg = 0x8418,
+ .mem_enable_ack_mask = BIT(2),
+ .branch = {
+ .halt_reg = 0x801c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x801c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_0_hm_ff_2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh_0_hm_ff_2_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_0_hm_ff_3_clk = {
+ .mem_enable_reg = 0x8404,
+ .mem_ack_reg = 0x8418,
+ .mem_enable_ack_mask = BIT(3),
+ .branch = {
+ .halt_reg = 0x8024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_0_hm_ff_3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh_0_hm_ff_3_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_eth_100g_fh_0_udp_fifo_clk = {
+ .halt_reg = 0x8034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_0_udp_fifo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_1_hm_ff_0_clk = {
+ .mem_enable_reg = 0x8408,
+ .mem_ack_reg = 0x841c,
+ .mem_enable_ack_mask = BIT(0),
+ .branch = {
+ .halt_reg = 0x8044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_1_hm_ff_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh_1_hm_ff_0_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_1_hm_ff_1_clk = {
+ .mem_enable_reg = 0x8408,
+ .mem_ack_reg = 0x841c,
+ .mem_enable_ack_mask = BIT(1),
+ .branch = {
+ .halt_reg = 0x804c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x804c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_1_hm_ff_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh_1_hm_ff_1_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_1_hm_ff_2_clk = {
+ .mem_enable_reg = 0x8408,
+ .mem_ack_reg = 0x841c,
+ .mem_enable_ack_mask = BIT(2),
+ .branch = {
+ .halt_reg = 0x8054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8054,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_1_hm_ff_2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh_1_hm_ff_2_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_1_hm_ff_3_clk = {
+ .mem_enable_reg = 0x8408,
+ .mem_ack_reg = 0x841c,
+ .mem_enable_ack_mask = BIT(3),
+ .branch = {
+ .halt_reg = 0x805c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x805c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_1_hm_ff_3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh_1_hm_ff_3_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_eth_100g_fh_1_udp_fifo_clk = {
+ .halt_reg = 0x806c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x806c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_1_udp_fifo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_2_hm_ff_0_clk = {
+ .mem_enable_reg = 0x840c,
+ .mem_ack_reg = 0x8420,
+ .mem_enable_ack_mask = BIT(0),
+ .branch = {
+ .halt_reg = 0x807c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x807c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_2_hm_ff_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh_2_hm_ff_0_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_2_hm_ff_1_clk = {
+ .mem_enable_reg = 0x840c,
+ .mem_ack_reg = 0x8420,
+ .mem_enable_ack_mask = BIT(1),
+ .branch = {
+ .halt_reg = 0x8084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8084,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_2_hm_ff_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh_2_hm_ff_1_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_2_hm_ff_2_clk = {
+ .mem_enable_reg = 0x840c,
+ .mem_ack_reg = 0x8420,
+ .mem_enable_ack_mask = BIT(2),
+ .branch = {
+ .halt_reg = 0x808c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x808c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_2_hm_ff_2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh_2_hm_ff_2_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_2_hm_ff_3_clk = {
+ .mem_enable_reg = 0x840c,
+ .mem_ack_reg = 0x8420,
+ .mem_enable_ack_mask = BIT(3),
+ .branch = {
+ .halt_reg = 0x8094,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8094,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_2_hm_ff_3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh_2_hm_ff_3_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_eth_100g_fh_2_udp_fifo_clk = {
+ .halt_reg = 0x80a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_2_udp_fifo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_macsec_0_clk = {
+ .mem_enable_reg = 0x8404,
+ .mem_ack_reg = 0x8418,
+ .mem_enable_ack_mask = BIT(4),
+ .branch = {
+ .halt_reg = 0x8004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_macsec_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh0_macsec_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_macsec_1_clk = {
+ .mem_enable_reg = 0x8408,
+ .mem_ack_reg = 0x841c,
+ .mem_enable_ack_mask = BIT(4),
+ .branch = {
+ .halt_reg = 0x803c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x803c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_macsec_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh1_macsec_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_fh_macsec_2_clk = {
+ .mem_enable_reg = 0x840c,
+ .mem_ack_reg = 0x8420,
+ .mem_enable_ack_mask = BIT(4),
+ .branch = {
+ .halt_reg = 0x8074,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8074,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_fh_macsec_2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_fh2_macsec_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_mac_c2c_hm_ref_clk = {
+ .mem_enable_reg = 0x8410,
+ .mem_ack_reg = 0x8424,
+ .mem_enable_ack_mask = BIT(5),
+ .branch = {
+ .halt_reg = 0x80c4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80c4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_mac_c2c_hm_ref_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk = {
+ .mem_enable_reg = 0x8414,
+ .mem_ack_reg = 0x8428,
+ .mem_enable_ack_mask = BIT(5),
+ .branch = {
+ .halt_reg = 0x80e8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80e8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_mac_fh0_hm_ref_clk = {
+ .mem_enable_reg = 0x8404,
+ .mem_ack_reg = 0x8418,
+ .mem_enable_ack_mask = BIT(5),
+ .branch = {
+ .halt_reg = 0x802c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x802c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_mac_fh0_hm_ref_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_mac_fh0_hm_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_mac_fh1_hm_ref_clk = {
+ .mem_enable_reg = 0x8408,
+ .mem_ack_reg = 0x841c,
+ .mem_enable_ack_mask = BIT(5),
+ .branch = {
+ .halt_reg = 0x8064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_mac_fh1_hm_ref_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_mac_fh1_hm_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_100g_mac_fh2_hm_ref_clk = {
+ .mem_enable_reg = 0x840c,
+ .mem_ack_reg = 0x8420,
+ .mem_enable_ack_mask = BIT(5),
+ .branch = {
+ .halt_reg = 0x809c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x809c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_100g_mac_fh2_hm_ref_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_eth_100g_mac_fh2_hm_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_eth_dbg_nfapi_axi_clk = {
+ .halt_reg = 0x80f4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80f4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_dbg_nfapi_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_dma_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_eth_dbg_noc_axi_clk = {
+ .halt_reg = 0x80fc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x80fc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_dbg_noc_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_mss_emac_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_phy_0_ock_sram_clk = {
+ .mem_enable_reg = 0x8404,
+ .mem_ack_reg = 0x8418,
+ .mem_enable_ack_mask = BIT(6),
+ .branch = {
+ .halt_reg = 0xd140,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd140,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_phy_0_ock_sram_clk",
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_phy_1_ock_sram_clk = {
+ .mem_enable_reg = 0x8408,
+ .mem_ack_reg = 0x841C,
+ .mem_enable_ack_mask = BIT(6),
+ .branch = {
+ .halt_reg = 0xd148,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd148,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_phy_1_ock_sram_clk",
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_phy_2_ock_sram_clk = {
+ .mem_enable_reg = 0x840c,
+ .mem_ack_reg = 0x8420,
+ .mem_enable_ack_mask = BIT(6),
+ .branch = {
+ .halt_reg = 0xd150,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd150,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_phy_2_ock_sram_clk",
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_phy_3_ock_sram_clk = {
+ .mem_enable_reg = 0x8410,
+ .mem_ack_reg = 0x8424,
+ .mem_enable_ack_mask = BIT(6),
+ .branch = {
+ .halt_reg = 0xd158,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd158,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_phy_3_ock_sram_clk",
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_mem_branch ecpri_cc_eth_phy_4_ock_sram_clk = {
+ .mem_enable_reg = 0x8414,
+ .mem_ack_reg = 0x8428,
+ .mem_enable_ack_mask = BIT(6),
+ .branch = {
+ .halt_reg = 0xd160,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd160,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_eth_phy_4_ock_sram_clk",
+ .ops = &clk_branch2_mem_ops,
+ },
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_mss_emac_clk = {
+ .halt_reg = 0xe008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xe008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_mss_emac_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_mss_emac_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_mss_oran_clk = {
+ .halt_reg = 0xe004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xe004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_mss_oran_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &ecpri_cc_ecpri_oran_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy0_lane0_rx_clk = {
+ .halt_reg = 0xd000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy0_lane0_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy0_lane0_tx_clk = {
+ .halt_reg = 0xd050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd050,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy0_lane0_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy0_lane1_rx_clk = {
+ .halt_reg = 0xd004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy0_lane1_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy0_lane1_tx_clk = {
+ .halt_reg = 0xd054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd054,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy0_lane1_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy0_lane2_rx_clk = {
+ .halt_reg = 0xd008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy0_lane2_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy0_lane2_tx_clk = {
+ .halt_reg = 0xd058,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd058,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy0_lane2_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy0_lane3_rx_clk = {
+ .halt_reg = 0xd00c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy0_lane3_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy0_lane3_tx_clk = {
+ .halt_reg = 0xd05c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd05c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy0_lane3_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy1_lane0_rx_clk = {
+ .halt_reg = 0xd010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy1_lane0_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy1_lane0_tx_clk = {
+ .halt_reg = 0xd060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy1_lane0_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy1_lane1_rx_clk = {
+ .halt_reg = 0xd014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy1_lane1_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy1_lane1_tx_clk = {
+ .halt_reg = 0xd064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy1_lane1_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy1_lane2_rx_clk = {
+ .halt_reg = 0xd018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy1_lane2_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy1_lane2_tx_clk = {
+ .halt_reg = 0xd068,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy1_lane2_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy1_lane3_rx_clk = {
+ .halt_reg = 0xd01c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd01c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy1_lane3_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy1_lane3_tx_clk = {
+ .halt_reg = 0xd06c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd06c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy1_lane3_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy2_lane0_rx_clk = {
+ .halt_reg = 0xd020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy2_lane0_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy2_lane0_tx_clk = {
+ .halt_reg = 0xd070,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd070,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy2_lane0_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy2_lane1_rx_clk = {
+ .halt_reg = 0xd024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy2_lane1_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy2_lane1_tx_clk = {
+ .halt_reg = 0xd074,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd074,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy2_lane1_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy2_lane2_rx_clk = {
+ .halt_reg = 0xd028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy2_lane2_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy2_lane2_tx_clk = {
+ .halt_reg = 0xd078,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd078,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy2_lane2_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy2_lane3_rx_clk = {
+ .halt_reg = 0xd02c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd02c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy2_lane3_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy2_lane3_tx_clk = {
+ .halt_reg = 0xd07c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd07c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy2_lane3_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy3_lane0_rx_clk = {
+ .halt_reg = 0xd030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy3_lane0_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy3_lane0_tx_clk = {
+ .halt_reg = 0xd080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd080,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy3_lane0_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy3_lane1_rx_clk = {
+ .halt_reg = 0xd034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy3_lane1_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy3_lane1_tx_clk = {
+ .halt_reg = 0xd084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd084,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy3_lane1_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy3_lane2_rx_clk = {
+ .halt_reg = 0xd038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd038,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy3_lane2_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy3_lane2_tx_clk = {
+ .halt_reg = 0xd088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd088,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy3_lane2_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy3_lane3_rx_clk = {
+ .halt_reg = 0xd03c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd03c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy3_lane3_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy3_lane3_tx_clk = {
+ .halt_reg = 0xd08c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd08c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy3_lane3_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy4_lane0_rx_clk = {
+ .halt_reg = 0xd040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd040,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy4_lane0_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy4_lane0_tx_clk = {
+ .halt_reg = 0xd090,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd090,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy4_lane0_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy4_lane1_rx_clk = {
+ .halt_reg = 0xd044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy4_lane1_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy4_lane1_tx_clk = {
+ .halt_reg = 0xd094,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd094,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy4_lane1_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy4_lane2_rx_clk = {
+ .halt_reg = 0xd048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd048,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy4_lane2_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy4_lane2_tx_clk = {
+ .halt_reg = 0xd098,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd098,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy4_lane2_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy4_lane3_rx_clk = {
+ .halt_reg = 0xd04c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd04c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy4_lane3_rx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch ecpri_cc_phy4_lane3_tx_clk = {
+ .halt_reg = 0xd09c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xd09c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "ecpri_cc_phy4_lane3_tx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *ecpri_cc_qdu1000_clocks[] = {
+ [ECPRI_CC_ECPRI_CG_CLK] = &ecpri_cc_ecpri_cg_clk.clkr,
+ [ECPRI_CC_ECPRI_CLK_SRC] = &ecpri_cc_ecpri_clk_src.clkr,
+ [ECPRI_CC_ECPRI_DMA_CLK] = &ecpri_cc_ecpri_dma_clk.clkr,
+ [ECPRI_CC_ECPRI_DMA_CLK_SRC] = &ecpri_cc_ecpri_dma_clk_src.clkr,
+ [ECPRI_CC_ECPRI_DMA_NOC_CLK] = &ecpri_cc_ecpri_dma_noc_clk.clkr,
+ [ECPRI_CC_ECPRI_FAST_CLK] = &ecpri_cc_ecpri_fast_clk.clkr,
+ [ECPRI_CC_ECPRI_FAST_CLK_SRC] = &ecpri_cc_ecpri_fast_clk_src.clkr,
+ [ECPRI_CC_ECPRI_FAST_DIV2_CLK] = &ecpri_cc_ecpri_fast_div2_clk.clkr,
+ [ECPRI_CC_ECPRI_FAST_DIV2_CLK_SRC] = &ecpri_cc_ecpri_fast_div2_clk_src.clkr,
+ [ECPRI_CC_ECPRI_FAST_DIV2_NOC_CLK] = &ecpri_cc_ecpri_fast_div2_noc_clk.clkr,
+ [ECPRI_CC_ECPRI_FR_CLK] = &ecpri_cc_ecpri_fr_clk.clkr,
+ [ECPRI_CC_ECPRI_ORAN_CLK_SRC] = &ecpri_cc_ecpri_oran_clk_src.clkr,
+ [ECPRI_CC_ECPRI_ORAN_DIV2_CLK] = &ecpri_cc_ecpri_oran_div2_clk.clkr,
+ [ECPRI_CC_ETH_100G_C2C0_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_c2c0_hm_ff_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_C2C0_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_c2c0_udp_fifo_clk.clkr,
+ [ECPRI_CC_ETH_100G_C2C1_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_c2c1_udp_fifo_clk.clkr,
+ [ECPRI_CC_ETH_100G_C2C_0_HM_FF_0_CLK] = &ecpri_cc_eth_100g_c2c_0_hm_ff_0_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_C2C_0_HM_FF_1_CLK] = &ecpri_cc_eth_100g_c2c_0_hm_ff_1_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_C2C_HM_FF_0_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_c2c_hm_ff_0_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_C2C_HM_FF_1_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_c2c_hm_ff_1_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_C2C_HM_MACSEC_CLK] = &ecpri_cc_eth_100g_c2c_hm_macsec_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_C2C_HM_MACSEC_CLK_SRC] = &ecpri_cc_eth_100g_c2c_hm_macsec_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_0_CLK] =
+ &ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_0_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_1_CLK] =
+ &ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_1_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_DBG_C2C_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_dbg_c2c_udp_fifo_clk.clkr,
+ [ECPRI_CC_ETH_100G_FH0_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH0_MACSEC_CLK_SRC] = &ecpri_cc_eth_100g_fh0_macsec_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH1_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH1_MACSEC_CLK_SRC] = &ecpri_cc_eth_100g_fh1_macsec_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH2_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH2_MACSEC_CLK_SRC] = &ecpri_cc_eth_100g_fh2_macsec_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_0_HM_FF_0_CLK] = &ecpri_cc_eth_100g_fh_0_hm_ff_0_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_0_HM_FF_0_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_fh_0_hm_ff_0_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_0_HM_FF_1_CLK] = &ecpri_cc_eth_100g_fh_0_hm_ff_1_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_0_HM_FF_1_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_fh_0_hm_ff_1_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_0_HM_FF_2_CLK] = &ecpri_cc_eth_100g_fh_0_hm_ff_2_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_0_HM_FF_2_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_fh_0_hm_ff_2_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_0_HM_FF_3_CLK] = &ecpri_cc_eth_100g_fh_0_hm_ff_3_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_0_HM_FF_3_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_fh_0_hm_ff_3_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_0_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_fh_0_udp_fifo_clk.clkr,
+ [ECPRI_CC_ETH_100G_FH_1_HM_FF_0_CLK] = &ecpri_cc_eth_100g_fh_1_hm_ff_0_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_1_HM_FF_0_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_fh_1_hm_ff_0_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_1_HM_FF_1_CLK] = &ecpri_cc_eth_100g_fh_1_hm_ff_1_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_1_HM_FF_1_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_fh_1_hm_ff_1_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_1_HM_FF_2_CLK] = &ecpri_cc_eth_100g_fh_1_hm_ff_2_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_1_HM_FF_2_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_fh_1_hm_ff_2_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_1_HM_FF_3_CLK] = &ecpri_cc_eth_100g_fh_1_hm_ff_3_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_1_HM_FF_3_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_fh_1_hm_ff_3_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_1_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_fh_1_udp_fifo_clk.clkr,
+ [ECPRI_CC_ETH_100G_FH_2_HM_FF_0_CLK] = &ecpri_cc_eth_100g_fh_2_hm_ff_0_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_2_HM_FF_0_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_fh_2_hm_ff_0_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_2_HM_FF_1_CLK] = &ecpri_cc_eth_100g_fh_2_hm_ff_1_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_2_HM_FF_1_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_fh_2_hm_ff_1_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_2_HM_FF_2_CLK] = &ecpri_cc_eth_100g_fh_2_hm_ff_2_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_2_HM_FF_2_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_fh_2_hm_ff_2_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_2_HM_FF_3_CLK] = &ecpri_cc_eth_100g_fh_2_hm_ff_3_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_2_HM_FF_3_DIV_CLK_SRC] =
+ &ecpri_cc_eth_100g_fh_2_hm_ff_3_div_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_FH_2_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_fh_2_udp_fifo_clk.clkr,
+ [ECPRI_CC_ETH_100G_FH_MACSEC_0_CLK] = &ecpri_cc_eth_100g_fh_macsec_0_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_MACSEC_1_CLK] = &ecpri_cc_eth_100g_fh_macsec_1_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_FH_MACSEC_2_CLK] = &ecpri_cc_eth_100g_fh_macsec_2_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_MAC_C2C_HM_REF_CLK] = &ecpri_cc_eth_100g_mac_c2c_hm_ref_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_MAC_C2C_HM_REF_CLK_SRC] = &ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_MAC_DBG_C2C_HM_REF_CLK] =
+ &ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_MAC_DBG_C2C_HM_REF_CLK_SRC] =
+ &ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_MAC_FH0_HM_REF_CLK] = &ecpri_cc_eth_100g_mac_fh0_hm_ref_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_MAC_FH0_HM_REF_CLK_SRC] = &ecpri_cc_eth_100g_mac_fh0_hm_ref_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_MAC_FH1_HM_REF_CLK] = &ecpri_cc_eth_100g_mac_fh1_hm_ref_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_MAC_FH1_HM_REF_CLK_SRC] = &ecpri_cc_eth_100g_mac_fh1_hm_ref_clk_src.clkr,
+ [ECPRI_CC_ETH_100G_MAC_FH2_HM_REF_CLK] = &ecpri_cc_eth_100g_mac_fh2_hm_ref_clk.branch.clkr,
+ [ECPRI_CC_ETH_100G_MAC_FH2_HM_REF_CLK_SRC] = &ecpri_cc_eth_100g_mac_fh2_hm_ref_clk_src.clkr,
+ [ECPRI_CC_ETH_DBG_NFAPI_AXI_CLK] = &ecpri_cc_eth_dbg_nfapi_axi_clk.clkr,
+ [ECPRI_CC_ETH_DBG_NOC_AXI_CLK] = &ecpri_cc_eth_dbg_noc_axi_clk.clkr,
+ [ECPRI_CC_ETH_PHY_0_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_0_ock_sram_clk.branch.clkr,
+ [ECPRI_CC_ETH_PHY_1_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_1_ock_sram_clk.branch.clkr,
+ [ECPRI_CC_ETH_PHY_2_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_2_ock_sram_clk.branch.clkr,
+ [ECPRI_CC_ETH_PHY_3_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_3_ock_sram_clk.branch.clkr,
+ [ECPRI_CC_ETH_PHY_4_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_4_ock_sram_clk.branch.clkr,
+ [ECPRI_CC_MSS_EMAC_CLK] = &ecpri_cc_mss_emac_clk.clkr,
+ [ECPRI_CC_MSS_EMAC_CLK_SRC] = &ecpri_cc_mss_emac_clk_src.clkr,
+ [ECPRI_CC_MSS_ORAN_CLK] = &ecpri_cc_mss_oran_clk.clkr,
+ [ECPRI_CC_PHY0_LANE0_RX_CLK] = &ecpri_cc_phy0_lane0_rx_clk.clkr,
+ [ECPRI_CC_PHY0_LANE0_TX_CLK] = &ecpri_cc_phy0_lane0_tx_clk.clkr,
+ [ECPRI_CC_PHY0_LANE1_RX_CLK] = &ecpri_cc_phy0_lane1_rx_clk.clkr,
+ [ECPRI_CC_PHY0_LANE1_TX_CLK] = &ecpri_cc_phy0_lane1_tx_clk.clkr,
+ [ECPRI_CC_PHY0_LANE2_RX_CLK] = &ecpri_cc_phy0_lane2_rx_clk.clkr,
+ [ECPRI_CC_PHY0_LANE2_TX_CLK] = &ecpri_cc_phy0_lane2_tx_clk.clkr,
+ [ECPRI_CC_PHY0_LANE3_RX_CLK] = &ecpri_cc_phy0_lane3_rx_clk.clkr,
+ [ECPRI_CC_PHY0_LANE3_TX_CLK] = &ecpri_cc_phy0_lane3_tx_clk.clkr,
+ [ECPRI_CC_PHY1_LANE0_RX_CLK] = &ecpri_cc_phy1_lane0_rx_clk.clkr,
+ [ECPRI_CC_PHY1_LANE0_TX_CLK] = &ecpri_cc_phy1_lane0_tx_clk.clkr,
+ [ECPRI_CC_PHY1_LANE1_RX_CLK] = &ecpri_cc_phy1_lane1_rx_clk.clkr,
+ [ECPRI_CC_PHY1_LANE1_TX_CLK] = &ecpri_cc_phy1_lane1_tx_clk.clkr,
+ [ECPRI_CC_PHY1_LANE2_RX_CLK] = &ecpri_cc_phy1_lane2_rx_clk.clkr,
+ [ECPRI_CC_PHY1_LANE2_TX_CLK] = &ecpri_cc_phy1_lane2_tx_clk.clkr,
+ [ECPRI_CC_PHY1_LANE3_RX_CLK] = &ecpri_cc_phy1_lane3_rx_clk.clkr,
+ [ECPRI_CC_PHY1_LANE3_TX_CLK] = &ecpri_cc_phy1_lane3_tx_clk.clkr,
+ [ECPRI_CC_PHY2_LANE0_RX_CLK] = &ecpri_cc_phy2_lane0_rx_clk.clkr,
+ [ECPRI_CC_PHY2_LANE0_TX_CLK] = &ecpri_cc_phy2_lane0_tx_clk.clkr,
+ [ECPRI_CC_PHY2_LANE1_RX_CLK] = &ecpri_cc_phy2_lane1_rx_clk.clkr,
+ [ECPRI_CC_PHY2_LANE1_TX_CLK] = &ecpri_cc_phy2_lane1_tx_clk.clkr,
+ [ECPRI_CC_PHY2_LANE2_RX_CLK] = &ecpri_cc_phy2_lane2_rx_clk.clkr,
+ [ECPRI_CC_PHY2_LANE2_TX_CLK] = &ecpri_cc_phy2_lane2_tx_clk.clkr,
+ [ECPRI_CC_PHY2_LANE3_RX_CLK] = &ecpri_cc_phy2_lane3_rx_clk.clkr,
+ [ECPRI_CC_PHY2_LANE3_TX_CLK] = &ecpri_cc_phy2_lane3_tx_clk.clkr,
+ [ECPRI_CC_PHY3_LANE0_RX_CLK] = &ecpri_cc_phy3_lane0_rx_clk.clkr,
+ [ECPRI_CC_PHY3_LANE0_TX_CLK] = &ecpri_cc_phy3_lane0_tx_clk.clkr,
+ [ECPRI_CC_PHY3_LANE1_RX_CLK] = &ecpri_cc_phy3_lane1_rx_clk.clkr,
+ [ECPRI_CC_PHY3_LANE1_TX_CLK] = &ecpri_cc_phy3_lane1_tx_clk.clkr,
+ [ECPRI_CC_PHY3_LANE2_RX_CLK] = &ecpri_cc_phy3_lane2_rx_clk.clkr,
+ [ECPRI_CC_PHY3_LANE2_TX_CLK] = &ecpri_cc_phy3_lane2_tx_clk.clkr,
+ [ECPRI_CC_PHY3_LANE3_RX_CLK] = &ecpri_cc_phy3_lane3_rx_clk.clkr,
+ [ECPRI_CC_PHY3_LANE3_TX_CLK] = &ecpri_cc_phy3_lane3_tx_clk.clkr,
+ [ECPRI_CC_PHY4_LANE0_RX_CLK] = &ecpri_cc_phy4_lane0_rx_clk.clkr,
+ [ECPRI_CC_PHY4_LANE0_TX_CLK] = &ecpri_cc_phy4_lane0_tx_clk.clkr,
+ [ECPRI_CC_PHY4_LANE1_RX_CLK] = &ecpri_cc_phy4_lane1_rx_clk.clkr,
+ [ECPRI_CC_PHY4_LANE1_TX_CLK] = &ecpri_cc_phy4_lane1_tx_clk.clkr,
+ [ECPRI_CC_PHY4_LANE2_RX_CLK] = &ecpri_cc_phy4_lane2_rx_clk.clkr,
+ [ECPRI_CC_PHY4_LANE2_TX_CLK] = &ecpri_cc_phy4_lane2_tx_clk.clkr,
+ [ECPRI_CC_PHY4_LANE3_RX_CLK] = &ecpri_cc_phy4_lane3_rx_clk.clkr,
+ [ECPRI_CC_PHY4_LANE3_TX_CLK] = &ecpri_cc_phy4_lane3_tx_clk.clkr,
+ [ECPRI_CC_PLL0] = &ecpri_cc_pll0.clkr,
+ [ECPRI_CC_PLL1] = &ecpri_cc_pll1.clkr,
+};
+
+static const struct qcom_reset_map ecpri_cc_qdu1000_resets[] = {
+ [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ECPRI_SS_BCR] = { 0x9000 },
+ [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_C2C_BCR] = { 0x80a8 },
+ [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH0_BCR] = { 0x8000 },
+ [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH1_BCR] = { 0x8038 },
+ [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH2_BCR] = { 0x8070 },
+ [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_WRAPPER_TOP_BCR] = { 0x8104 },
+ [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_MODEM_BCR] = { 0xe000 },
+ [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_NOC_BCR] = { 0xf000 },
+};
+
+static const struct regmap_config ecpri_cc_qdu1000_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x31bf0,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc ecpri_cc_qdu1000_desc = {
+ .config = &ecpri_cc_qdu1000_regmap_config,
+ .clks = ecpri_cc_qdu1000_clocks,
+ .num_clks = ARRAY_SIZE(ecpri_cc_qdu1000_clocks),
+ .resets = ecpri_cc_qdu1000_resets,
+ .num_resets = ARRAY_SIZE(ecpri_cc_qdu1000_resets),
+};
+
+static const struct of_device_id ecpri_cc_qdu1000_match_table[] = {
+ { .compatible = "qcom,qdu1000-ecpricc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ecpri_cc_qdu1000_match_table);
+
+static int ecpri_cc_qdu1000_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &ecpri_cc_qdu1000_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ clk_lucid_evo_pll_configure(&ecpri_cc_pll0, regmap, &ecpri_cc_pll0_config);
+ clk_lucid_evo_pll_configure(&ecpri_cc_pll1, regmap, &ecpri_cc_pll1_config);
+
+ return qcom_cc_really_probe(pdev, &ecpri_cc_qdu1000_desc, regmap);
+}
+
+static struct platform_driver ecpri_cc_qdu1000_driver = {
+ .probe = ecpri_cc_qdu1000_probe,
+ .driver = {
+ .name = "ecpri_cc-qdu1000",
+ .of_match_table = ecpri_cc_qdu1000_match_table,
+ },
+};
+
+module_platform_driver(ecpri_cc_qdu1000_driver);
+
+MODULE_DESCRIPTION("QTI ECPRICC QDU1000 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/gcc-msm8939.c b/drivers/clk/qcom/gcc-msm8939.c
index b45f97c07eeb..7b9a3e99b589 100644
--- a/drivers/clk/qcom/gcc-msm8939.c
+++ b/drivers/clk/qcom/gcc-msm8939.c
@@ -696,7 +696,7 @@ static struct clk_rcg2 apss_ahb_clk_src = {
},
};
-static const struct freq_tbl ftbl_gcc_camss_csi0_1_clk[] = {
+static const struct freq_tbl ftbl_gcc_camss_csi0_1_2_clk[] = {
F(100000000, P_GPLL0, 8, 0, 0),
F(200000000, P_GPLL0, 4, 0, 0),
{ }
@@ -706,7 +706,7 @@ static struct clk_rcg2 csi0_clk_src = {
.cmd_rcgr = 0x4e020,
.hid_width = 5,
.parent_map = gcc_xo_gpll0_map,
- .freq_tbl = ftbl_gcc_camss_csi0_1_clk,
+ .freq_tbl = ftbl_gcc_camss_csi0_1_2_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "csi0_clk_src",
.parent_data = gcc_xo_gpll0_parent_data,
@@ -719,7 +719,7 @@ static struct clk_rcg2 csi1_clk_src = {
.cmd_rcgr = 0x4f020,
.hid_width = 5,
.parent_map = gcc_xo_gpll0_map,
- .freq_tbl = ftbl_gcc_camss_csi0_1_clk,
+ .freq_tbl = ftbl_gcc_camss_csi0_1_2_clk,
.clkr.hw.init = &(struct clk_init_data){
.name = "csi1_clk_src",
.parent_data = gcc_xo_gpll0_parent_data,
@@ -728,6 +728,19 @@ static struct clk_rcg2 csi1_clk_src = {
},
};
+static struct clk_rcg2 csi2_clk_src = {
+ .cmd_rcgr = 0x3c020,
+ .hid_width = 5,
+ .parent_map = gcc_xo_gpll0_map,
+ .freq_tbl = ftbl_gcc_camss_csi0_1_2_clk,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "csi2_clk_src",
+ .parent_data = gcc_xo_gpll0_parent_data,
+ .num_parents = ARRAY_SIZE(gcc_xo_gpll0_parent_data),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
static const struct freq_tbl ftbl_gcc_oxili_gfx3d_clk[] = {
F(19200000, P_XO, 1, 0, 0),
F(50000000, P_GPLL0, 16, 0, 0),
@@ -2385,6 +2398,91 @@ static struct clk_branch gcc_camss_csi1rdi_clk = {
},
};
+static struct clk_branch gcc_camss_csi2_ahb_clk = {
+ .halt_reg = 0x3c040,
+ .clkr = {
+ .enable_reg = 0x3c040,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &camss_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi2_clk = {
+ .halt_reg = 0x3c03c,
+ .clkr = {
+ .enable_reg = 0x3c03c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi2phy_clk = {
+ .halt_reg = 0x3c048,
+ .clkr = {
+ .enable_reg = 0x3c048,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2phy_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi2pix_clk = {
+ .halt_reg = 0x3c058,
+ .clkr = {
+ .enable_reg = 0x3c058,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2pix_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camss_csi2rdi_clk = {
+ .halt_reg = 0x3c050,
+ .clkr = {
+ .enable_reg = 0x3c050,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_camss_csi2rdi_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &csi2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_camss_csi_vfe0_clk = {
.halt_reg = 0x58050,
.clkr = {
@@ -3682,6 +3780,7 @@ static struct clk_regmap *gcc_msm8939_clocks[] = {
[APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr,
[CSI0_CLK_SRC] = &csi0_clk_src.clkr,
[CSI1_CLK_SRC] = &csi1_clk_src.clkr,
+ [CSI2_CLK_SRC] = &csi2_clk_src.clkr,
[GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr,
[VFE0_CLK_SRC] = &vfe0_clk_src.clkr,
[BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
@@ -3751,6 +3850,11 @@ static struct clk_regmap *gcc_msm8939_clocks[] = {
[GCC_CAMSS_CSI1PHY_CLK] = &gcc_camss_csi1phy_clk.clkr,
[GCC_CAMSS_CSI1PIX_CLK] = &gcc_camss_csi1pix_clk.clkr,
[GCC_CAMSS_CSI1RDI_CLK] = &gcc_camss_csi1rdi_clk.clkr,
+ [GCC_CAMSS_CSI2_AHB_CLK] = &gcc_camss_csi2_ahb_clk.clkr,
+ [GCC_CAMSS_CSI2_CLK] = &gcc_camss_csi2_clk.clkr,
+ [GCC_CAMSS_CSI2PHY_CLK] = &gcc_camss_csi2phy_clk.clkr,
+ [GCC_CAMSS_CSI2PIX_CLK] = &gcc_camss_csi2pix_clk.clkr,
+ [GCC_CAMSS_CSI2RDI_CLK] = &gcc_camss_csi2rdi_clk.clkr,
[GCC_CAMSS_CSI_VFE0_CLK] = &gcc_camss_csi_vfe0_clk.clkr,
[GCC_CAMSS_GP0_CLK] = &gcc_camss_gp0_clk.clkr,
[GCC_CAMSS_GP1_CLK] = &gcc_camss_gp1_clk.clkr,
diff --git a/drivers/clk/qcom/gcc-sm8550.c b/drivers/clk/qcom/gcc-sm8550.c
index 586126c4dd90..b883dffe5f7a 100644
--- a/drivers/clk/qcom/gcc-sm8550.c
+++ b/drivers/clk/qcom/gcc-sm8550.c
@@ -401,7 +401,7 @@ static struct clk_rcg2 gcc_gp1_clk_src = {
.parent_data = gcc_parent_data_1,
.num_parents = ARRAY_SIZE(gcc_parent_data_1),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -416,7 +416,7 @@ static struct clk_rcg2 gcc_gp2_clk_src = {
.parent_data = gcc_parent_data_1,
.num_parents = ARRAY_SIZE(gcc_parent_data_1),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -431,7 +431,7 @@ static struct clk_rcg2 gcc_gp3_clk_src = {
.parent_data = gcc_parent_data_1,
.num_parents = ARRAY_SIZE(gcc_parent_data_1),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -451,7 +451,7 @@ static struct clk_rcg2 gcc_pcie_0_aux_clk_src = {
.parent_data = gcc_parent_data_2,
.num_parents = ARRAY_SIZE(gcc_parent_data_2),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -471,7 +471,7 @@ static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -486,7 +486,7 @@ static struct clk_rcg2 gcc_pcie_1_aux_clk_src = {
.parent_data = gcc_parent_data_2,
.num_parents = ARRAY_SIZE(gcc_parent_data_2),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -501,7 +501,7 @@ static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -521,7 +521,7 @@ static struct clk_rcg2 gcc_pdm2_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -536,7 +536,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s0_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -551,7 +551,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s1_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -566,7 +566,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s2_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -581,7 +581,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s3_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -596,7 +596,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s4_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -611,7 +611,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s5_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -626,7 +626,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s6_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -641,7 +641,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s7_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -656,7 +656,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s8_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -671,7 +671,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s9_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -700,7 +700,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
@@ -717,7 +717,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
@@ -750,7 +750,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s2_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
@@ -767,7 +767,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
@@ -784,7 +784,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
@@ -801,7 +801,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
@@ -818,7 +818,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s6_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
@@ -835,7 +835,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s7_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
@@ -852,7 +852,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s0_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = {
@@ -869,7 +869,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s1_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = {
@@ -886,7 +886,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s2_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap2_s2_clk_src = {
@@ -903,7 +903,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s3_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap2_s3_clk_src = {
@@ -920,7 +920,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s4_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = {
@@ -937,7 +937,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s5_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap2_s5_clk_src = {
@@ -975,7 +975,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s6_clk_src_init = {
.parent_data = gcc_parent_data_8,
.num_parents = ARRAY_SIZE(gcc_parent_data_8),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap2_s6_clk_src = {
@@ -992,7 +992,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s7_clk_src_init = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
};
static struct clk_rcg2 gcc_qupv3_wrap2_s7_clk_src = {
@@ -1025,7 +1025,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
.parent_data = gcc_parent_data_9,
.num_parents = ARRAY_SIZE(gcc_parent_data_9),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -1048,7 +1048,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -1071,7 +1071,7 @@ static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -1093,7 +1093,7 @@ static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = {
.parent_data = gcc_parent_data_3,
.num_parents = ARRAY_SIZE(gcc_parent_data_3),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -1114,7 +1114,7 @@ static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = {
.parent_data = gcc_parent_data_4,
.num_parents = ARRAY_SIZE(gcc_parent_data_4),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -1136,7 +1136,7 @@ static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -1159,7 +1159,7 @@ static struct clk_rcg2 gcc_usb30_prim_master_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -1174,7 +1174,7 @@ static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = {
.parent_data = gcc_parent_data_0,
.num_parents = ARRAY_SIZE(gcc_parent_data_0),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -1189,7 +1189,7 @@ static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = {
.parent_data = gcc_parent_data_2,
.num_parents = ARRAY_SIZE(gcc_parent_data_2),
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_rcg2_shared_ops,
},
};
@@ -2998,38 +2998,46 @@ static struct clk_branch gcc_video_axi1_clk = {
static struct gdsc pcie_0_gdsc = {
.gdscr = 0x6b004,
+ .collapse_ctrl = 0x52020,
+ .collapse_mask = BIT(0),
.pd = {
.name = "pcie_0_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
- .flags = POLL_CFG_GDSCR,
+ .flags = VOTABLE | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
};
static struct gdsc pcie_0_phy_gdsc = {
.gdscr = 0x6c000,
+ .collapse_ctrl = 0x52020,
+ .collapse_mask = BIT(3),
.pd = {
.name = "pcie_0_phy_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
- .flags = POLL_CFG_GDSCR,
+ .flags = VOTABLE | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
};
static struct gdsc pcie_1_gdsc = {
.gdscr = 0x8d004,
+ .collapse_ctrl = 0x52020,
+ .collapse_mask = BIT(1),
.pd = {
.name = "pcie_1_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
- .flags = POLL_CFG_GDSCR,
+ .flags = VOTABLE | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
};
static struct gdsc pcie_1_phy_gdsc = {
.gdscr = 0x8e000,
+ .collapse_ctrl = 0x52020,
+ .collapse_mask = BIT(4),
.pd = {
.name = "pcie_1_phy_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
- .flags = POLL_CFG_GDSCR,
+ .flags = VOTABLE | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
};
static struct gdsc ufs_phy_gdsc = {
@@ -3038,7 +3046,7 @@ static struct gdsc ufs_phy_gdsc = {
.name = "ufs_phy_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
- .flags = POLL_CFG_GDSCR,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
};
static struct gdsc ufs_mem_phy_gdsc = {
@@ -3047,7 +3055,7 @@ static struct gdsc ufs_mem_phy_gdsc = {
.name = "ufs_mem_phy_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
- .flags = POLL_CFG_GDSCR,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
};
static struct gdsc usb30_prim_gdsc = {
@@ -3056,7 +3064,7 @@ static struct gdsc usb30_prim_gdsc = {
.name = "usb30_prim_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
- .flags = POLL_CFG_GDSCR,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
};
static struct gdsc usb3_phy_gdsc = {
@@ -3065,7 +3073,7 @@ static struct gdsc usb3_phy_gdsc = {
.name = "usb3_phy_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
- .flags = POLL_CFG_GDSCR,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
};
static struct clk_regmap *gcc_sm8550_clocks[] = {
diff --git a/drivers/clk/qcom/gcc-sm8650.c b/drivers/clk/qcom/gcc-sm8650.c
new file mode 100644
index 000000000000..9174dd82308c
--- /dev/null
+++ b/drivers/clk/qcom/gcc-sm8650.c
@@ -0,0 +1,3849 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,sm8650-gcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "clk-regmap-phy-mux.h"
+#include "gdsc.h"
+#include "reset.h"
+
+/* Need to match the order of clocks in DT binding */
+enum {
+ DT_BI_TCXO,
+ DT_BI_TCXO_AO,
+ DT_SLEEP_CLK,
+
+ DT_PCIE_0_PIPE,
+ DT_PCIE_1_PIPE,
+ DT_PCIE_1_PHY_AUX,
+
+ DT_UFS_PHY_RX_SYMBOL_0,
+ DT_UFS_PHY_RX_SYMBOL_1,
+ DT_UFS_PHY_TX_SYMBOL_0,
+
+ DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE,
+};
+
+enum {
+ P_BI_TCXO,
+ P_GCC_GPLL0_OUT_EVEN,
+ P_GCC_GPLL0_OUT_MAIN,
+ P_GCC_GPLL1_OUT_MAIN,
+ P_GCC_GPLL3_OUT_MAIN,
+ P_GCC_GPLL4_OUT_MAIN,
+ P_GCC_GPLL6_OUT_MAIN,
+ P_GCC_GPLL7_OUT_MAIN,
+ P_GCC_GPLL9_OUT_MAIN,
+ P_PCIE_0_PIPE_CLK,
+ P_PCIE_1_PHY_AUX_CLK,
+ P_PCIE_1_PIPE_CLK,
+ P_SLEEP_CLK,
+ P_UFS_PHY_RX_SYMBOL_0_CLK,
+ P_UFS_PHY_RX_SYMBOL_1_CLK,
+ P_UFS_PHY_TX_SYMBOL_0_CLK,
+ P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK,
+};
+
+static struct clk_alpha_pll gcc_gpll0 = {
+ .offset = 0x0,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll0_ao = {
+ .offset = 0x0,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x57020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll0_ao",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO_AO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = {
+ .offset = 0x0,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_gcc_gpll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll0_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+static struct clk_alpha_pll_postdiv gcc_gpll0_out_even_ao = {
+ .offset = 0x0,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_gcc_gpll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll0_out_even_ao",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0_ao.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll1 = {
+ .offset = 0x4000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll1",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll1_ao = {
+ .offset = 0x1000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x57020,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll1_ao",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO_AO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll3 = {
+ .offset = 0x3000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll3",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll3_ao = {
+ .offset = 0x3000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x57020,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll3_ao",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO_AO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll4 = {
+ .offset = 0x4000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll4",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll4_ao = {
+ .offset = 0x4000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x57020,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll4_ao",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO_AO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll6 = {
+ .offset = 0x6000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll6",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll6_ao = {
+ .offset = 0x6000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x57020,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll6_ao",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO_AO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll7 = {
+ .offset = 0x7000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll7",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll9 = {
+ .offset = 0x9000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll9",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static const struct parent_map gcc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_SLEEP_CLK, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .index = DT_SLEEP_CLK },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL1_OUT_MAIN, 4 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll1.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_3[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_4[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map gcc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data gcc_parent_data_5[] = {
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_8[] = {
+ { P_PCIE_1_PHY_AUX_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_8[] = {
+ { .index = DT_PCIE_1_PHY_AUX },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_10[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL7_OUT_MAIN, 2 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_10[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll7.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_11[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL9_OUT_MAIN, 2 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_11[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll9.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_12[] = {
+ { P_UFS_PHY_RX_SYMBOL_0_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_12[] = {
+ { .index = DT_UFS_PHY_RX_SYMBOL_0 },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_13[] = {
+ { P_UFS_PHY_RX_SYMBOL_1_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_13[] = {
+ { .index = DT_UFS_PHY_RX_SYMBOL_1 },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_14[] = {
+ { P_UFS_PHY_TX_SYMBOL_0_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_14[] = {
+ { .index = DT_UFS_PHY_TX_SYMBOL_0 },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_15[] = {
+ { P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_15[] = {
+ { .index = DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE },
+ { .index = DT_BI_TCXO },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_0_pipe_clk_src = {
+ .reg = 0x6b070,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_PCIE_0_PIPE,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_pcie_1_phy_aux_clk_src = {
+ .reg = 0x8d094,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_8,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_8),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_1_pipe_clk_src = {
+ .reg = 0x8d078,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_PCIE_1_PIPE,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_0_clk_src = {
+ .reg = 0x77064,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_12,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_rx_symbol_0_clk_src",
+ .parent_data = gcc_parent_data_12,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_12),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_1_clk_src = {
+ .reg = 0x770e0,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_13,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_rx_symbol_1_clk_src",
+ .parent_data = gcc_parent_data_13,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_13),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_ufs_phy_tx_symbol_0_clk_src = {
+ .reg = 0x77054,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_14,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_tx_symbol_0_clk_src",
+ .parent_data = gcc_parent_data_14,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_14),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = {
+ .reg = 0x3906c,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_15,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_pipe_clk_src",
+ .parent_data = gcc_parent_data_15,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_15),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = {
+ F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_gp1_clk_src = {
+ .cmd_rcgr = 0x64004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp1_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp2_clk_src = {
+ .cmd_rcgr = 0x65004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp2_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp3_clk_src = {
+ .cmd_rcgr = 0x66004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp3_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie_0_aux_clk_src = {
+ .cmd_rcgr = 0x6b074,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_aux_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = {
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x6b058,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_1_aux_clk_src = {
+ .cmd_rcgr = 0x8d07c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_aux_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x8d060,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = {
+ F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pdm2_clk_src = {
+ .cmd_rcgr = 0x33010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pdm2_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s0_clk_src = {
+ .cmd_rcgr = 0x17008,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s1_clk_src = {
+ .cmd_rcgr = 0x17024,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s2_clk_src = {
+ .cmd_rcgr = 0x17040,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s3_clk_src = {
+ .cmd_rcgr = 0x1705c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s4_clk_src = {
+ .cmd_rcgr = 0x17078,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s5_clk_src = {
+ .cmd_rcgr = 0x17094,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s6_clk_src = {
+ .cmd_rcgr = 0x170b0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s6_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s7_clk_src = {
+ .cmd_rcgr = 0x170cc,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s7_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s8_clk_src = {
+ .cmd_rcgr = 0x170e8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s8_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s9_clk_src = {
+ .cmd_rcgr = 0x17104,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s9_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap1_qspi_ref_clk_src[] = {
+ F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0),
+ F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_qspi_ref_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_qspi_ref_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_qspi_ref_clk_src = {
+ .cmd_rcgr = 0x188a0,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_qspi_ref_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_qspi_ref_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s0_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(102400000, P_GCC_GPLL0_OUT_EVEN, 1, 128, 375),
+ F(112000000, P_GCC_GPLL0_OUT_EVEN, 1, 28, 75),
+ F(117964800, P_GCC_GPLL0_OUT_EVEN, 1, 6144, 15625),
+ F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
+ .cmd_rcgr = 0x18010,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
+ .cmd_rcgr = 0x18148,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s3_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
+ .cmd_rcgr = 0x18290,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s4_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
+ .cmd_rcgr = 0x183c8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
+ .cmd_rcgr = 0x18500,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s6_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s6_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
+ .cmd_rcgr = 0x18638,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s7_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s7_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
+ .cmd_rcgr = 0x18770,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap2_ibi_ctrl_0_clk_src[] = {
+ F(37500000, P_GCC_GPLL0_OUT_EVEN, 8, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_ibi_ctrl_0_clk_src = {
+ .cmd_rcgr = 0x1e9d4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_qupv3_wrap2_ibi_ctrl_0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_ibi_ctrl_0_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = {
+ .cmd_rcgr = 0x1e010,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = {
+ .cmd_rcgr = 0x1e148,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s2_clk_src = {
+ .cmd_rcgr = 0x1e280,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s3_clk_src = {
+ .cmd_rcgr = 0x1e3b8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = {
+ .cmd_rcgr = 0x1e4f0,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s5_clk_src = {
+ .cmd_rcgr = 0x1e628,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s5_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap2_s6_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(128000000, P_GCC_GPLL0_OUT_MAIN, 1, 16, 75),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s6_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s6_clk_src",
+ .parent_data = gcc_parent_data_10,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_10),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s6_clk_src = {
+ .cmd_rcgr = 0x1e760,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_10,
+ .freq_tbl = ftbl_gcc_qupv3_wrap2_s6_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s6_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s7_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s7_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s7_clk_src = {
+ .cmd_rcgr = 0x1e898,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s7_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap3_qspi_ref_clk_src[] = {
+ F(300000000, P_GCC_GPLL0_OUT_EVEN, 1, 0, 0),
+ F(400000000, P_GCC_GPLL0_OUT_MAIN, 1.5, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap3_qspi_ref_clk_src_init = {
+ .name = "gcc_qupv3_wrap3_qspi_ref_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap3_qspi_ref_clk_src = {
+ .cmd_rcgr = 0x19018,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap3_qspi_ref_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap3_qspi_ref_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ F(202000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
+ .cmd_rcgr = 0x14018,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_11,
+ .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc2_apps_clk_src",
+ .parent_data = gcc_parent_data_11,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_11),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = {
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc4_apps_clk_src = {
+ .cmd_rcgr = 0x16018,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc4_apps_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = {
+ F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0),
+ F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = {
+ .cmd_rcgr = 0x77030,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_axi_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = {
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0),
+ F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = {
+ .cmd_rcgr = 0x77080,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_ice_core_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_phy_aux_clk_src[] = {
+ F(9600000, P_BI_TCXO, 2, 0, 0),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = {
+ .cmd_rcgr = 0x770b4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_ufs_phy_phy_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = {
+ .cmd_rcgr = 0x77098,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_unipro_core_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = {
+ F(66666667, P_GCC_GPLL0_OUT_EVEN, 4.5, 0, 0),
+ F(133333333, P_GCC_GPLL0_OUT_MAIN, 4.5, 0, 0),
+ F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb30_prim_master_clk_src = {
+ .cmd_rcgr = 0x3902c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x39044,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = {
+ .cmd_rcgr = 0x39070,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_qupv3_wrap1_s2_clk_src = {
+ .reg = 0x18280,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s2_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_qupv3_wrap3_s0_clk_src = {
+ .reg = 0x19010,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_s0_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap3_qspi_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = {
+ .reg = 0x3905c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch gcc_aggre_noc_pcie_axi_clk = {
+ .halt_reg = 0x10064,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x10064,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_noc_pcie_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_ufs_phy_axi_clk = {
+ .halt_reg = 0x770e4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x770e4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x770e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_ufs_phy_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_ufs_phy_axi_hw_ctl_clk = {
+ .halt_reg = 0x770e4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x770e4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x770e4,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_ufs_phy_axi_hw_ctl_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb3_prim_axi_clk = {
+ .halt_reg = 0x3908c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x3908c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3908c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+ .halt_reg = 0x38004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x38004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_hf_axi_clk = {
+ .halt_reg = 0x26010,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x26010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x26010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camera_hf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_sf_axi_clk = {
+ .halt_reg = 0x2601c,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x2601c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2601c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camera_sf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_pcie_anoc_ahb_clk = {
+ .halt_reg = 0x10050,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x10050,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_pcie_anoc_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = {
+ .halt_reg = 0x39088,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x39088,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x39088,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cnoc_pcie_sf_axi_clk = {
+ .halt_reg = 0x10058,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x10058,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cnoc_pcie_sf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ddrss_gpu_axi_clk = {
+ .halt_reg = 0x71154,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x71154,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x71154,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ddrss_gpu_axi_clk",
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ddrss_pcie_sf_qtb_clk = {
+ .halt_reg = 0x10074,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x10074,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(19),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ddrss_pcie_sf_qtb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_hf_axi_clk = {
+ .halt_reg = 0x2700c,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x2700c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2700c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_disp_hf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+ .halt_reg = 0x64000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x64000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+ .halt_reg = 0x65000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x65000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+ .halt_reg = 0x66000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x66000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_gpll0_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_div_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_gpll0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0_out_even.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_memnoc_gfx_clk = {
+ .halt_reg = 0x71010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x71010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x71010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_memnoc_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = {
+ .halt_reg = 0x71018,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x71018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_snoc_dvm_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_aux_clk = {
+ .halt_reg = 0x6b03c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_cfg_ahb_clk = {
+ .halt_reg = 0x6b038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6b038,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_mstr_axi_clk = {
+ .halt_reg = 0x6b02c,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x6b02c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_phy_rchng_clk = {
+ .halt_reg = 0x6b054,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_pipe_clk = {
+ .halt_reg = 0x6b048,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_slv_axi_clk = {
+ .halt_reg = 0x6b020,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6b020,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_slv_q2a_axi_clk = {
+ .halt_reg = 0x6b01c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_aux_clk = {
+ .halt_reg = 0x8d038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_cfg_ahb_clk = {
+ .halt_reg = 0x8d034,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x8d034,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_mstr_axi_clk = {
+ .halt_reg = 0x8d028,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x8d028,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_phy_aux_clk = {
+ .halt_reg = 0x8d044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_phy_rchng_clk = {
+ .halt_reg = 0x8d05c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_pipe_clk = {
+ .halt_reg = 0x8d050,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(30),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_slv_axi_clk = {
+ .halt_reg = 0x8d01c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x8d01c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_slv_q2a_axi_clk = {
+ .halt_reg = 0x8d018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+ .halt_reg = 0x3300c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3300c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pdm2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+ .halt_reg = 0x33004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x33004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x33004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_xo4_clk = {
+ .halt_reg = 0x33008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x33008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm_xo4_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = {
+ .halt_reg = 0x26008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x26008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x26008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_camera_nrt_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_camera_rt_ahb_clk = {
+ .halt_reg = 0x2600c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2600c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2600c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_camera_rt_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_disp_ahb_clk = {
+ .halt_reg = 0x27008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x27008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x27008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_disp_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_gpu_ahb_clk = {
+ .halt_reg = 0x71008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x71008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x71008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_gpu_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_pcie_ahb_clk = {
+ .halt_reg = 0x6b018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6b018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(11),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_pcie_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_cv_cpu_ahb_clk = {
+ .halt_reg = 0x32014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x32014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_video_cv_cpu_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_cvp_ahb_clk = {
+ .halt_reg = 0x32008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x32008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_video_cvp_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_v_cpu_ahb_clk = {
+ .halt_reg = 0x32010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x32010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_video_v_cpu_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = {
+ .halt_reg = 0x3200c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x3200c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3200c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_video_vcodec_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_core_clk = {
+ .halt_reg = 0x23004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s0_clk = {
+ .halt_reg = 0x17004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s1_clk = {
+ .halt_reg = 0x17020,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(11),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s2_clk = {
+ .halt_reg = 0x1703c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s3_clk = {
+ .halt_reg = 0x17058,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(13),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s4_clk = {
+ .halt_reg = 0x17074,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(14),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s5_clk = {
+ .halt_reg = 0x17090,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s6_clk = {
+ .halt_reg = 0x170ac,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s7_clk = {
+ .halt_reg = 0x170c8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(17),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s8_clk = {
+ .halt_reg = 0x170e4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(14),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s8_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s8_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s9_clk = {
+ .halt_reg = 0x17100,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s9_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s9_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s_ahb_clk = {
+ .halt_reg = 0x23000,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23000,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = {
+ .halt_reg = 0x23154,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(18),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_core_clk = {
+ .halt_reg = 0x23144,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(19),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_qspi_ref_clk = {
+ .halt_reg = 0x1889c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_qspi_ref_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s0_clk = {
+ .halt_reg = 0x18004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s1_clk = {
+ .halt_reg = 0x1813c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s2_clk = {
+ .halt_reg = 0x18274,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s3_clk = {
+ .halt_reg = 0x18284,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s4_clk = {
+ .halt_reg = 0x183bc,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s5_clk = {
+ .halt_reg = 0x184f4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s6_clk = {
+ .halt_reg = 0x1862c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s7_clk = {
+ .halt_reg = 0x18764,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_core_2x_clk = {
+ .halt_reg = 0x232a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_core_clk = {
+ .halt_reg = 0x23294,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_ibi_ctrl_2_clk = {
+ .halt_reg = 0x1e9cc,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1e9cc,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_ibi_ctrl_2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_ibi_ctrl_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_ibi_ctrl_3_clk = {
+ .halt_reg = 0x1e9d0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1e9d0,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_ibi_ctrl_3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_ibi_ctrl_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s0_clk = {
+ .halt_reg = 0x1e004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s1_clk = {
+ .halt_reg = 0x1e13c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s2_clk = {
+ .halt_reg = 0x1e274,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s3_clk = {
+ .halt_reg = 0x1e3ac,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s4_clk = {
+ .halt_reg = 0x1e4e4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s5_clk = {
+ .halt_reg = 0x1e61c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s6_clk = {
+ .halt_reg = 0x1e754,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s7_clk = {
+ .halt_reg = 0x1e88c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(17),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_core_2x_clk = {
+ .halt_reg = 0x233f4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_core_clk = {
+ .halt_reg = 0x233e4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_qspi_ref_clk = {
+ .halt_reg = 0x19014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_qspi_ref_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap3_qspi_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_s0_clk = {
+ .halt_reg = 0x19004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap3_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_1_m_ahb_clk = {
+ .halt_reg = 0x2313c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2313c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_1_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = {
+ .halt_reg = 0x23140,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23140,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(21),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_1_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_2_ibi_2_ahb_clk = {
+ .halt_reg = 0x1e9c4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1e9c4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_2_ibi_2_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_2_ibi_3_ahb_clk = {
+ .halt_reg = 0x1e9c8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1e9c8,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_2_ibi_3_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_2_m_ahb_clk = {
+ .halt_reg = 0x2328c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2328c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_2_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_2_s_ahb_clk = {
+ .halt_reg = 0x23290,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23290,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_2_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_3_m_ahb_clk = {
+ .halt_reg = 0x233dc,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x233dc,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(30),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_3_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_3_s_ahb_clk = {
+ .halt_reg = 0x233e0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x233e0,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(31),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_3_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+ .halt_reg = 0x14010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x14010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc2_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_apps_clk = {
+ .halt_reg = 0x14004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x14004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc2_apps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc2_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc4_ahb_clk = {
+ .halt_reg = 0x16010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x16010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc4_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc4_apps_clk = {
+ .halt_reg = 0x16004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x16004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc4_apps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc4_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ahb_clk = {
+ .halt_reg = 0x77024,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77024,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_axi_clk = {
+ .halt_reg = 0x77018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_axi_hw_ctl_clk = {
+ .halt_reg = 0x77018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77018,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_axi_hw_ctl_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ice_core_clk = {
+ .halt_reg = 0x77074,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77074,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77074,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_ice_core_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ice_core_hw_ctl_clk = {
+ .halt_reg = 0x77074,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77074,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77074,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_ice_core_hw_ctl_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_phy_aux_clk = {
+ .halt_reg = 0x770b0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x770b0,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x770b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_phy_aux_hw_ctl_clk = {
+ .halt_reg = 0x770b0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x770b0,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x770b0,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_phy_aux_hw_ctl_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = {
+ .halt_reg = 0x7702c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x7702c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_rx_symbol_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = {
+ .halt_reg = 0x770cc,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x770cc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_rx_symbol_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = {
+ .halt_reg = 0x77028,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x77028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_tx_symbol_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_tx_symbol_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_unipro_core_clk = {
+ .halt_reg = 0x77068,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77068,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_unipro_core_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_unipro_core_hw_ctl_clk = {
+ .halt_reg = 0x77068,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77068,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77068,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_unipro_core_hw_ctl_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_master_clk = {
+ .halt_reg = 0x39018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
+ .halt_reg = 0x39028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_sleep_clk = {
+ .halt_reg = 0x39024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_aux_clk = {
+ .halt_reg = 0x39060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = {
+ .halt_reg = 0x39064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_com_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_pipe_clk = {
+ .halt_reg = 0x39068,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x39068,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x39068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_axi0_clk = {
+ .halt_reg = 0x32018,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x32018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_video_axi0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_axi1_clk = {
+ .halt_reg = 0x32024,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x32024,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_video_axi1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc pcie_0_gdsc = {
+ .gdscr = 0x6b004,
+ .collapse_ctrl = 0x5214c,
+ .collapse_mask = BIT(0),
+ .pd = {
+ .name = "pcie_0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc pcie_0_phy_gdsc = {
+ .gdscr = 0x6c000,
+ .collapse_ctrl = 0x5214c,
+ .collapse_mask = BIT(3),
+ .pd = {
+ .name = "pcie_0_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc pcie_1_gdsc = {
+ .gdscr = 0x8d004,
+ .collapse_ctrl = 0x5214c,
+ .collapse_mask = BIT(1),
+ .pd = {
+ .name = "pcie_1_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc pcie_1_phy_gdsc = {
+ .gdscr = 0x8e000,
+ .collapse_ctrl = 0x5214c,
+ .collapse_mask = BIT(4),
+ .pd = {
+ .name = "pcie_1_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc ufs_phy_gdsc = {
+ .gdscr = 0x77004,
+ .pd = {
+ .name = "ufs_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc ufs_mem_phy_gdsc = {
+ .gdscr = 0x9e000,
+ .pd = {
+ .name = "ufs_mem_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc usb30_prim_gdsc = {
+ .gdscr = 0x39004,
+ .pd = {
+ .name = "usb30_prim_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc usb3_phy_gdsc = {
+ .gdscr = 0x50018,
+ .pd = {
+ .name = "usb3_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *gcc_sm8650_clocks[] = {
+ [GCC_AGGRE_NOC_PCIE_AXI_CLK] = &gcc_aggre_noc_pcie_axi_clk.clkr,
+ [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr,
+ [GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK] = &gcc_aggre_ufs_phy_axi_hw_ctl_clk.clkr,
+ [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_CAMERA_HF_AXI_CLK] = &gcc_camera_hf_axi_clk.clkr,
+ [GCC_CAMERA_SF_AXI_CLK] = &gcc_camera_sf_axi_clk.clkr,
+ [GCC_CFG_NOC_PCIE_ANOC_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_ahb_clk.clkr,
+ [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr,
+ [GCC_CNOC_PCIE_SF_AXI_CLK] = &gcc_cnoc_pcie_sf_axi_clk.clkr,
+ [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr,
+ [GCC_DDRSS_PCIE_SF_QTB_CLK] = &gcc_ddrss_pcie_sf_qtb_clk.clkr,
+ [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr,
+ [GCC_GPLL0] = &gcc_gpll0.clkr,
+ [GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr,
+ [GCC_GPLL1] = &gcc_gpll1.clkr,
+ [GCC_GPLL3] = &gcc_gpll3.clkr,
+ [GCC_GPLL4] = &gcc_gpll4.clkr,
+ [GCC_GPLL6] = &gcc_gpll6.clkr,
+ [GCC_GPLL7] = &gcc_gpll7.clkr,
+ [GCC_GPLL9] = &gcc_gpll9.clkr,
+ [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr,
+ [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr,
+ [GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr,
+ [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr,
+ [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr,
+ [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr,
+ [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr,
+ [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr,
+ [GCC_PCIE_0_PHY_RCHNG_CLK] = &gcc_pcie_0_phy_rchng_clk.clkr,
+ [GCC_PCIE_0_PHY_RCHNG_CLK_SRC] = &gcc_pcie_0_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr,
+ [GCC_PCIE_0_PIPE_CLK_SRC] = &gcc_pcie_0_pipe_clk_src.clkr,
+ [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr,
+ [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr,
+ [GCC_PCIE_1_AUX_CLK_SRC] = &gcc_pcie_1_aux_clk_src.clkr,
+ [GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr,
+ [GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr,
+ [GCC_PCIE_1_PHY_AUX_CLK] = &gcc_pcie_1_phy_aux_clk.clkr,
+ [GCC_PCIE_1_PHY_AUX_CLK_SRC] = &gcc_pcie_1_phy_aux_clk_src.clkr,
+ [GCC_PCIE_1_PHY_RCHNG_CLK] = &gcc_pcie_1_phy_rchng_clk.clkr,
+ [GCC_PCIE_1_PHY_RCHNG_CLK_SRC] = &gcc_pcie_1_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr,
+ [GCC_PCIE_1_PIPE_CLK_SRC] = &gcc_pcie_1_pipe_clk_src.clkr,
+ [GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr,
+ [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = &gcc_pcie_1_slv_q2a_axi_clk.clkr,
+ [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+ [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr,
+ [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+ [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr,
+ [GCC_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr,
+ [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr,
+ [GCC_QMIP_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr,
+ [GCC_QMIP_GPU_AHB_CLK] = &gcc_qmip_gpu_ahb_clk.clkr,
+ [GCC_QMIP_PCIE_AHB_CLK] = &gcc_qmip_pcie_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_CV_CPU_AHB_CLK] = &gcc_qmip_video_cv_cpu_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_CVP_AHB_CLK] = &gcc_qmip_video_cvp_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_V_CPU_AHB_CLK] = &gcc_qmip_video_v_cpu_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr,
+ [GCC_QUPV3_I2C_CORE_CLK] = &gcc_qupv3_i2c_core_clk.clkr,
+ [GCC_QUPV3_I2C_S0_CLK] = &gcc_qupv3_i2c_s0_clk.clkr,
+ [GCC_QUPV3_I2C_S0_CLK_SRC] = &gcc_qupv3_i2c_s0_clk_src.clkr,
+ [GCC_QUPV3_I2C_S1_CLK] = &gcc_qupv3_i2c_s1_clk.clkr,
+ [GCC_QUPV3_I2C_S1_CLK_SRC] = &gcc_qupv3_i2c_s1_clk_src.clkr,
+ [GCC_QUPV3_I2C_S2_CLK] = &gcc_qupv3_i2c_s2_clk.clkr,
+ [GCC_QUPV3_I2C_S2_CLK_SRC] = &gcc_qupv3_i2c_s2_clk_src.clkr,
+ [GCC_QUPV3_I2C_S3_CLK] = &gcc_qupv3_i2c_s3_clk.clkr,
+ [GCC_QUPV3_I2C_S3_CLK_SRC] = &gcc_qupv3_i2c_s3_clk_src.clkr,
+ [GCC_QUPV3_I2C_S4_CLK] = &gcc_qupv3_i2c_s4_clk.clkr,
+ [GCC_QUPV3_I2C_S4_CLK_SRC] = &gcc_qupv3_i2c_s4_clk_src.clkr,
+ [GCC_QUPV3_I2C_S5_CLK] = &gcc_qupv3_i2c_s5_clk.clkr,
+ [GCC_QUPV3_I2C_S5_CLK_SRC] = &gcc_qupv3_i2c_s5_clk_src.clkr,
+ [GCC_QUPV3_I2C_S6_CLK] = &gcc_qupv3_i2c_s6_clk.clkr,
+ [GCC_QUPV3_I2C_S6_CLK_SRC] = &gcc_qupv3_i2c_s6_clk_src.clkr,
+ [GCC_QUPV3_I2C_S7_CLK] = &gcc_qupv3_i2c_s7_clk.clkr,
+ [GCC_QUPV3_I2C_S7_CLK_SRC] = &gcc_qupv3_i2c_s7_clk_src.clkr,
+ [GCC_QUPV3_I2C_S8_CLK] = &gcc_qupv3_i2c_s8_clk.clkr,
+ [GCC_QUPV3_I2C_S8_CLK_SRC] = &gcc_qupv3_i2c_s8_clk_src.clkr,
+ [GCC_QUPV3_I2C_S9_CLK] = &gcc_qupv3_i2c_s9_clk.clkr,
+ [GCC_QUPV3_I2C_S9_CLK_SRC] = &gcc_qupv3_i2c_s9_clk_src.clkr,
+ [GCC_QUPV3_I2C_S_AHB_CLK] = &gcc_qupv3_i2c_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr,
+ [GCC_QUPV3_WRAP1_QSPI_REF_CLK] = &gcc_qupv3_wrap1_qspi_ref_clk.clkr,
+ [GCC_QUPV3_WRAP1_QSPI_REF_CLK_SRC] = &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr,
+ [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr,
+ [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr,
+ [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr,
+ [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr,
+ [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S5_CLK] = &gcc_qupv3_wrap1_s5_clk.clkr,
+ [GCC_QUPV3_WRAP1_S5_CLK_SRC] = &gcc_qupv3_wrap1_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S6_CLK] = &gcc_qupv3_wrap1_s6_clk.clkr,
+ [GCC_QUPV3_WRAP1_S6_CLK_SRC] = &gcc_qupv3_wrap1_s6_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S7_CLK] = &gcc_qupv3_wrap1_s7_clk.clkr,
+ [GCC_QUPV3_WRAP1_S7_CLK_SRC] = &gcc_qupv3_wrap1_s7_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_CORE_2X_CLK] = &gcc_qupv3_wrap2_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP2_CORE_CLK] = &gcc_qupv3_wrap2_core_clk.clkr,
+ [GCC_QUPV3_WRAP2_IBI_CTRL_0_CLK_SRC] = &gcc_qupv3_wrap2_ibi_ctrl_0_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_IBI_CTRL_2_CLK] = &gcc_qupv3_wrap2_ibi_ctrl_2_clk.clkr,
+ [GCC_QUPV3_WRAP2_IBI_CTRL_3_CLK] = &gcc_qupv3_wrap2_ibi_ctrl_3_clk.clkr,
+ [GCC_QUPV3_WRAP2_S0_CLK] = &gcc_qupv3_wrap2_s0_clk.clkr,
+ [GCC_QUPV3_WRAP2_S0_CLK_SRC] = &gcc_qupv3_wrap2_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S1_CLK] = &gcc_qupv3_wrap2_s1_clk.clkr,
+ [GCC_QUPV3_WRAP2_S1_CLK_SRC] = &gcc_qupv3_wrap2_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S2_CLK] = &gcc_qupv3_wrap2_s2_clk.clkr,
+ [GCC_QUPV3_WRAP2_S2_CLK_SRC] = &gcc_qupv3_wrap2_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S3_CLK] = &gcc_qupv3_wrap2_s3_clk.clkr,
+ [GCC_QUPV3_WRAP2_S3_CLK_SRC] = &gcc_qupv3_wrap2_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S4_CLK] = &gcc_qupv3_wrap2_s4_clk.clkr,
+ [GCC_QUPV3_WRAP2_S4_CLK_SRC] = &gcc_qupv3_wrap2_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S5_CLK] = &gcc_qupv3_wrap2_s5_clk.clkr,
+ [GCC_QUPV3_WRAP2_S5_CLK_SRC] = &gcc_qupv3_wrap2_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S6_CLK] = &gcc_qupv3_wrap2_s6_clk.clkr,
+ [GCC_QUPV3_WRAP2_S6_CLK_SRC] = &gcc_qupv3_wrap2_s6_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S7_CLK] = &gcc_qupv3_wrap2_s7_clk.clkr,
+ [GCC_QUPV3_WRAP2_S7_CLK_SRC] = &gcc_qupv3_wrap2_s7_clk_src.clkr,
+ [GCC_QUPV3_WRAP3_CORE_2X_CLK] = &gcc_qupv3_wrap3_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP3_CORE_CLK] = &gcc_qupv3_wrap3_core_clk.clkr,
+ [GCC_QUPV3_WRAP3_QSPI_REF_CLK] = &gcc_qupv3_wrap3_qspi_ref_clk.clkr,
+ [GCC_QUPV3_WRAP3_QSPI_REF_CLK_SRC] = &gcc_qupv3_wrap3_qspi_ref_clk_src.clkr,
+ [GCC_QUPV3_WRAP3_S0_CLK] = &gcc_qupv3_wrap3_s0_clk.clkr,
+ [GCC_QUPV3_WRAP3_S0_CLK_SRC] = &gcc_qupv3_wrap3_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_2_IBI_2_AHB_CLK] = &gcc_qupv3_wrap_2_ibi_2_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_2_IBI_3_AHB_CLK] = &gcc_qupv3_wrap_2_ibi_3_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_2_M_AHB_CLK] = &gcc_qupv3_wrap_2_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_2_S_AHB_CLK] = &gcc_qupv3_wrap_2_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_3_M_AHB_CLK] = &gcc_qupv3_wrap_3_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_3_S_AHB_CLK] = &gcc_qupv3_wrap_3_s_ahb_clk.clkr,
+ [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+ [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+ [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr,
+ [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr,
+ [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr,
+ [GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_clk_src.clkr,
+ [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr,
+ [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr,
+ [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr,
+ [GCC_UFS_PHY_AXI_HW_CTL_CLK] = &gcc_ufs_phy_axi_hw_ctl_clk.clkr,
+ [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr,
+ [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr,
+ [GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK] = &gcc_ufs_phy_ice_core_hw_ctl_clk.clkr,
+ [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr,
+ [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr,
+ [GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK] = &gcc_ufs_phy_phy_aux_hw_ctl_clk.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_rx_symbol_0_clk_src.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC] = &gcc_ufs_phy_rx_symbol_1_clk_src.clkr,
+ [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr,
+ [GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_tx_symbol_0_clk_src.clkr,
+ [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr,
+ [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_phy_unipro_core_clk_src.clkr,
+ [GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK] = &gcc_ufs_phy_unipro_core_hw_ctl_clk.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = &gcc_usb30_prim_mock_utmi_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr,
+ [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr,
+ [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr,
+ [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr,
+ [GCC_GPLL0_AO] = &gcc_gpll0_ao.clkr,
+ [GCC_GPLL0_OUT_EVEN_AO] = &gcc_gpll0_out_even_ao.clkr,
+ [GCC_GPLL1_AO] = &gcc_gpll1_ao.clkr,
+ [GCC_GPLL3_AO] = &gcc_gpll3_ao.clkr,
+ [GCC_GPLL4_AO] = &gcc_gpll4_ao.clkr,
+ [GCC_GPLL6_AO] = &gcc_gpll6_ao.clkr,
+};
+
+static const struct qcom_reset_map gcc_sm8650_resets[] = {
+ [GCC_CAMERA_BCR] = { 0x26000 },
+ [GCC_DISPLAY_BCR] = { 0x27000 },
+ [GCC_GPU_BCR] = { 0x71000 },
+ [GCC_PCIE_0_BCR] = { 0x6b000 },
+ [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x6c014 },
+ [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x6c020 },
+ [GCC_PCIE_0_PHY_BCR] = { 0x6c01c },
+ [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x6c028 },
+ [GCC_PCIE_1_BCR] = { 0x8d000 },
+ [GCC_PCIE_1_LINK_DOWN_BCR] = { 0x8e014 },
+ [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0x8e020 },
+ [GCC_PCIE_1_PHY_BCR] = { 0x8e01c },
+ [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0x8e024 },
+ [GCC_PCIE_PHY_BCR] = { 0x6f000 },
+ [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x6f00c },
+ [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 },
+ [GCC_PDM_BCR] = { 0x33000 },
+ [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 },
+ [GCC_QUPV3_WRAPPER_2_BCR] = { 0x1e000 },
+ [GCC_QUPV3_WRAPPER_3_BCR] = { 0x19000 },
+ [GCC_QUPV3_WRAPPER_I2C_BCR] = { 0x17000 },
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 },
+ [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 },
+ [GCC_SDCC2_BCR] = { 0x14000 },
+ [GCC_SDCC4_BCR] = { 0x16000 },
+ [GCC_UFS_PHY_BCR] = { 0x77000 },
+ [GCC_USB30_PRIM_BCR] = { 0x39000 },
+ [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 },
+ [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 },
+ [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 },
+ [GCC_USB3_PHY_SEC_BCR] = { 0x5000c },
+ [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 },
+ [GCC_USB3PHY_PHY_SEC_BCR] = { 0x50010 },
+ [GCC_VIDEO_AXI0_CLK_ARES] = { 0x32018, 2 },
+ [GCC_VIDEO_AXI1_CLK_ARES] = { 0x32024, 2 },
+ [GCC_VIDEO_BCR] = { 0x32000 },
+};
+
+static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = {
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_qspi_ref_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s6_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s7_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap3_qspi_ref_clk_src),
+};
+
+static struct gdsc *gcc_sm8650_gdscs[] = {
+ [PCIE_0_GDSC] = &pcie_0_gdsc,
+ [PCIE_0_PHY_GDSC] = &pcie_0_phy_gdsc,
+ [PCIE_1_GDSC] = &pcie_1_gdsc,
+ [PCIE_1_PHY_GDSC] = &pcie_1_phy_gdsc,
+ [UFS_PHY_GDSC] = &ufs_phy_gdsc,
+ [UFS_MEM_PHY_GDSC] = &ufs_mem_phy_gdsc,
+ [USB30_PRIM_GDSC] = &usb30_prim_gdsc,
+ [USB3_PHY_GDSC] = &usb3_phy_gdsc,
+};
+
+static const struct regmap_config gcc_sm8650_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x1f41f0,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gcc_sm8650_desc = {
+ .config = &gcc_sm8650_regmap_config,
+ .clks = gcc_sm8650_clocks,
+ .num_clks = ARRAY_SIZE(gcc_sm8650_clocks),
+ .resets = gcc_sm8650_resets,
+ .num_resets = ARRAY_SIZE(gcc_sm8650_resets),
+ .gdscs = gcc_sm8650_gdscs,
+ .num_gdscs = ARRAY_SIZE(gcc_sm8650_gdscs),
+};
+
+static const struct of_device_id gcc_sm8650_match_table[] = {
+ { .compatible = "qcom,sm8650-gcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_sm8650_match_table);
+
+static int gcc_sm8650_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ int ret;
+
+ regmap = qcom_cc_map(pdev, &gcc_sm8650_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks,
+ ARRAY_SIZE(gcc_dfs_clocks));
+ if (ret)
+ return ret;
+
+ /* Keep the critical clock always-On */
+ regmap_update_bits(regmap, 0x26004, BIT(0), BIT(0)); /* gcc_camera_ahb_clk */
+ regmap_update_bits(regmap, 0x26028, BIT(0), BIT(0)); /* gcc_camera_xo_clk */
+ regmap_update_bits(regmap, 0x27004, BIT(0), BIT(0)); /* gcc_disp_ahb_clk */
+ regmap_update_bits(regmap, 0x27018, BIT(0), BIT(0)); /* gcc_disp_xo_clk */
+ regmap_update_bits(regmap, 0x71004, BIT(0), BIT(0)); /* gcc_gpu_cfg_ahb_clk */
+ regmap_update_bits(regmap, 0x32004, BIT(0), BIT(0)); /* gcc_video_ahb_clk */
+ regmap_update_bits(regmap, 0x32030, BIT(0), BIT(0)); /* gcc_video_xo_clk */
+
+ qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true);
+
+ /* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */
+ regmap_write(regmap, 0x52150, 0x0);
+
+ return qcom_cc_really_probe(pdev, &gcc_sm8650_desc, regmap);
+}
+
+static struct platform_driver gcc_sm8650_driver = {
+ .probe = gcc_sm8650_probe,
+ .driver = {
+ .name = "gcc-sm8650",
+ .of_match_table = gcc_sm8650_match_table,
+ },
+};
+
+static int __init gcc_sm8650_init(void)
+{
+ return platform_driver_register(&gcc_sm8650_driver);
+}
+subsys_initcall(gcc_sm8650_init);
+
+static void __exit gcc_sm8650_exit(void)
+{
+ platform_driver_unregister(&gcc_sm8650_driver);
+}
+module_exit(gcc_sm8650_exit);
+
+MODULE_DESCRIPTION("QTI GCC SM8650 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c
new file mode 100644
index 000000000000..74db7fef237b
--- /dev/null
+++ b/drivers/clk/qcom/gcc-x1e80100.c
@@ -0,0 +1,6807 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,x1e80100-gcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "clk-regmap-phy-mux.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+ DT_BI_TCXO,
+ DT_SLEEP_CLK,
+ DT_PCIE_3_PIPE,
+ DT_PCIE_4_PIPE,
+ DT_PCIE_5_PIPE,
+ DT_PCIE_6A_PIPE,
+ DT_PCIE_6B_PIPE,
+ DT_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE,
+ DT_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE,
+ DT_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE,
+};
+
+enum {
+ P_BI_TCXO,
+ P_GCC_GPLL0_OUT_EVEN,
+ P_GCC_GPLL0_OUT_MAIN,
+ P_GCC_GPLL4_OUT_MAIN,
+ P_GCC_GPLL7_OUT_MAIN,
+ P_GCC_GPLL8_OUT_MAIN,
+ P_GCC_GPLL9_OUT_MAIN,
+ P_SLEEP_CLK,
+ P_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE_CLK,
+ P_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE_CLK,
+ P_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE_CLK,
+};
+
+static struct clk_alpha_pll gcc_gpll0 = {
+ .offset = 0x0,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x52030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = {
+ .offset = 0x0,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_gcc_gpll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll0_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll4 = {
+ .offset = 0x4000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x52030,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll4",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll7 = {
+ .offset = 0x7000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x52030,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll7",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll8 = {
+ .offset = 0x8000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x52030,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll8",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll9 = {
+ .offset = 0x9000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .enable_reg = 0x52030,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll9",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ole_ops,
+ },
+ },
+};
+
+static const struct parent_map gcc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_SLEEP_CLK, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .index = DT_SLEEP_CLK },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data gcc_parent_data_3[] = {
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL8_OUT_MAIN, 2 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_4[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll8.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL7_OUT_MAIN, 2 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_5[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll7.clkr.hw },
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map gcc_parent_map_6[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL7_OUT_MAIN, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_6[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll7.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_7[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_7[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_8[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL7_OUT_MAIN, 2 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_8[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll7.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_9[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL9_OUT_MAIN, 2 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_10[] = {
+ { .index = DT_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_10[] = {
+ { P_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_11[] = {
+ { .index = DT_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_11[] = {
+ { P_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_12[] = {
+ { .index = DT_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE },
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_12[] = {
+ { P_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE_CLK, 0 },
+ { P_BI_TCXO, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_9[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll9.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = {
+ F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_gp1_clk_src = {
+ .cmd_rcgr = 0x64004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp1_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp2_clk_src = {
+ .cmd_rcgr = 0x65004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp2_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp3_clk_src = {
+ .cmd_rcgr = 0x66004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp3_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie_0_aux_clk_src = {
+ .cmd_rcgr = 0xa0180,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_aux_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = {
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = {
+ .cmd_rcgr = 0xa0054,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_1_aux_clk_src = {
+ .cmd_rcgr = 0x2c180,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_aux_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x2c054,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_2_aux_clk_src = {
+ .cmd_rcgr = 0x13180,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_2_aux_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_2_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x13054,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_2_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_3_aux_clk_src = {
+ .cmd_rcgr = 0x5808c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_3_aux_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_3_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x58070,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_3_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_4_aux_clk_src = {
+ .cmd_rcgr = 0x6b080,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_4_aux_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_4_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x6b064,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_4_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_5_aux_clk_src = {
+ .cmd_rcgr = 0x2f080,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_5_aux_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_5_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x2f064,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_5_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_6a_aux_clk_src = {
+ .cmd_rcgr = 0x3108c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6a_aux_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_6a_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x31070,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6a_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_6b_aux_clk_src = {
+ .cmd_rcgr = 0x8d08c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6b_aux_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_6b_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x8d070,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6b_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_rscc_xo_clk_src = {
+ .cmd_rcgr = 0xa400c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_rscc_xo_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = {
+ F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pdm2_clk_src = {
+ .cmd_rcgr = 0x33010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pdm2_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = {
+ .cmd_rcgr = 0x42010,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = {
+ .cmd_rcgr = 0x42148,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s2_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0),
+ F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = {
+ .cmd_rcgr = 0x42288,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = {
+ .cmd_rcgr = 0x423c8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s4_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = {
+ .cmd_rcgr = 0x42500,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = {
+ .cmd_rcgr = 0x42638,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s6_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s6_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = {
+ .cmd_rcgr = 0x42770,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap0_s7_clk_src_init = {
+ .name = "gcc_qupv3_wrap0_s7_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = {
+ .cmd_rcgr = 0x428a8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
+ .cmd_rcgr = 0x18010,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
+ .cmd_rcgr = 0x18148,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = {
+ .cmd_rcgr = 0x18288,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
+ .cmd_rcgr = 0x183c8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
+ .cmd_rcgr = 0x18500,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
+ .cmd_rcgr = 0x18638,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s6_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s6_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
+ .cmd_rcgr = 0x18770,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s7_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s7_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
+ .cmd_rcgr = 0x188a8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = {
+ .cmd_rcgr = 0x1e010,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = {
+ .cmd_rcgr = 0x1e148,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s2_clk_src = {
+ .cmd_rcgr = 0x1e288,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s3_clk_src = {
+ .cmd_rcgr = 0x1e3c8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s2_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = {
+ .cmd_rcgr = 0x1e500,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s5_clk_src = {
+ .cmd_rcgr = 0x1e638,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s6_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s6_clk_src",
+ .parent_data = gcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_8),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s6_clk_src = {
+ .cmd_rcgr = 0x1e770,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_8,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s6_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s7_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s7_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s7_clk_src = {
+ .cmd_rcgr = 0x1e8a8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s7_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ F(202000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
+ .cmd_rcgr = 0x14018,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_9,
+ .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc2_apps_clk_src",
+ .parent_data = gcc_parent_data_9,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_9),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_floor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = {
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc4_apps_clk_src = {
+ .cmd_rcgr = 0x16018,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc4_apps_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_floor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = {
+ F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = {
+ .cmd_rcgr = 0x77030,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_axi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = {
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0),
+ F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = {
+ .cmd_rcgr = 0x77080,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_7,
+ .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_ice_core_clk_src",
+ .parent_data = gcc_parent_data_7,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_7),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = {
+ .cmd_rcgr = 0x770b4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = {
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(150000000, P_GCC_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(300000000, P_GCC_GPLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = {
+ .cmd_rcgr = 0x77098,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_ufs_phy_unipro_core_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_unipro_core_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb20_master_clk_src[] = {
+ F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0),
+ F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb20_master_clk_src = {
+ .cmd_rcgr = 0x2902c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb20_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb20_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x29158,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_mp_master_clk_src[] = {
+ F(66666667, P_GCC_GPLL0_OUT_EVEN, 4.5, 0, 0),
+ F(133333333, P_GCC_GPLL0_OUT_MAIN, 4.5, 0, 0),
+ F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb30_mp_master_clk_src = {
+ .cmd_rcgr = 0x1702c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_mp_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_mp_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x17158,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_mp_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_prim_master_clk_src = {
+ .cmd_rcgr = 0x3902c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x39044,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_sec_master_clk_src = {
+ .cmd_rcgr = 0xa102c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_sec_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_sec_mock_utmi_clk_src = {
+ .cmd_rcgr = 0xa1044,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_sec_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_tert_master_clk_src = {
+ .cmd_rcgr = 0xa202c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_tert_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_tert_mock_utmi_clk_src = {
+ .cmd_rcgr = 0xa2044,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_tert_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb3_mp_phy_aux_clk_src = {
+ .cmd_rcgr = 0x172a0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_mp_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = {
+ .cmd_rcgr = 0x39074,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb3_sec_phy_aux_clk_src = {
+ .cmd_rcgr = 0xa1074,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_sec_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb3_tert_phy_aux_clk_src = {
+ .cmd_rcgr = 0xa2074,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_tert_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb4_0_master_clk_src[] = {
+ F(85714286, P_GCC_GPLL0_OUT_EVEN, 3.5, 0, 0),
+ F(175000000, P_GCC_GPLL8_OUT_MAIN, 4, 0, 0),
+ F(350000000, P_GCC_GPLL8_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb4_0_master_clk_src = {
+ .cmd_rcgr = 0x9f024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_usb4_0_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_master_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(125000000, P_GCC_GPLL7_OUT_MAIN, 8, 0, 0),
+ F(250000000, P_GCC_GPLL7_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb4_0_phy_pcie_pipe_clk_src = {
+ .cmd_rcgr = 0x9f0e8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_phy_pcie_pipe_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb4_0_sb_if_clk_src = {
+ .cmd_rcgr = 0x9f08c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_sb_if_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb4_0_tmu_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(250000000, P_GCC_GPLL7_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb4_0_tmu_clk_src = {
+ .cmd_rcgr = 0x9f070,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_usb4_0_tmu_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_tmu_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb4_1_master_clk_src = {
+ .cmd_rcgr = 0x2b024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_usb4_0_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_master_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb4_1_phy_pcie_pipe_clk_src = {
+ .cmd_rcgr = 0x2b0e8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_phy_pcie_pipe_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb4_1_sb_if_clk_src = {
+ .cmd_rcgr = 0x2b08c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_sb_if_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb4_1_tmu_clk_src = {
+ .cmd_rcgr = 0x2b070,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_usb4_0_tmu_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_tmu_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb4_2_master_clk_src = {
+ .cmd_rcgr = 0x11024,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_usb4_0_master_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_master_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb4_2_phy_pcie_pipe_clk_src = {
+ .cmd_rcgr = 0x110e8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_phy_pcie_pipe_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb4_2_sb_if_clk_src = {
+ .cmd_rcgr = 0x1108c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_sb_if_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb4_2_tmu_clk_src = {
+ .cmd_rcgr = 0x11070,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_usb4_0_tmu_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_tmu_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_3_pipe_clk_src = {
+ .reg = 0x58088,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_3_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_PCIE_3_PIPE,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div gcc_pcie_3_pipe_div_clk_src = {
+ .reg = 0x5806c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_3_pipe_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_3_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_4_pipe_clk_src = {
+ .reg = 0x6b07c,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_4_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_PCIE_4_PIPE,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div gcc_pcie_4_pipe_div_clk_src = {
+ .reg = 0x6b060,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_4_pipe_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_4_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_5_pipe_clk_src = {
+ .reg = 0x2f07c,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_5_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_PCIE_5_PIPE,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div gcc_pcie_5_pipe_div_clk_src = {
+ .reg = 0x2f060,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_5_pipe_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_5_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_6a_pipe_clk_src = {
+ .reg = 0x31088,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_6a_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_PCIE_6A_PIPE,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div gcc_pcie_6a_pipe_div_clk_src = {
+ .reg = 0x3106c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6a_pipe_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_6a_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_6b_pipe_clk_src = {
+ .reg = 0x8d088,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_pcie_6b_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_PCIE_6B_PIPE,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_div gcc_pcie_6b_pipe_div_clk_src = {
+ .reg = 0x8d06c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6b_pipe_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_6b_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_qupv3_wrap0_s2_div_clk_src = {
+ .reg = 0x42284,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s2_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_qupv3_wrap0_s3_div_clk_src = {
+ .reg = 0x423c4,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s3_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_qupv3_wrap1_s2_div_clk_src = {
+ .reg = 0x18284,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s2_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_qupv3_wrap1_s3_div_clk_src = {
+ .reg = 0x183c4,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s3_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_qupv3_wrap2_s2_div_clk_src = {
+ .reg = 0x1e284,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s2_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_qupv3_wrap2_s3_div_clk_src = {
+ .reg = 0x1e3c4,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s3_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb20_mock_utmi_postdiv_clk_src = {
+ .reg = 0x29284,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb20_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb30_mp_mock_utmi_postdiv_clk_src = {
+ .reg = 0x17284,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_mp_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_mp_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = {
+ .reg = 0x3905c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb30_sec_mock_utmi_postdiv_clk_src = {
+ .reg = 0xa105c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_sec_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_sec_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb30_tert_mock_utmi_postdiv_clk_src = {
+ .reg = 0xa205c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_tert_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_tert_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch gcc_aggre_noc_usb_north_axi_clk = {
+ .halt_reg = 0x2d17c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2d17c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2d17c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_noc_usb_north_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_noc_usb_south_axi_clk = {
+ .halt_reg = 0x2d174,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2d174,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2d174,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_noc_usb_south_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_ufs_phy_axi_clk = {
+ .halt_reg = 0x770e4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x770e4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x770e4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_ufs_phy_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb2_prim_axi_clk = {
+ .halt_reg = 0x2928c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2928c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2928c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_usb2_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb20_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb3_mp_axi_clk = {
+ .halt_reg = 0x173d0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x173d0,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x173d0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_usb3_mp_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_mp_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb3_prim_axi_clk = {
+ .halt_reg = 0x39090,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x39090,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x39090,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb3_sec_axi_clk = {
+ .halt_reg = 0xa1090,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xa1090,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xa1090,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_usb3_sec_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_sec_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb3_tert_axi_clk = {
+ .halt_reg = 0xa2090,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xa2090,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xa2090,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_usb3_tert_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_tert_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb4_0_axi_clk = {
+ .halt_reg = 0x9f118,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x9f118,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x9f118,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_usb4_0_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb4_0_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb4_1_axi_clk = {
+ .halt_reg = 0x2b118,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2b118,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2b118,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_usb4_1_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb4_1_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb4_2_axi_clk = {
+ .halt_reg = 0x11118,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x11118,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x11118,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_usb4_2_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb4_2_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_usb_noc_axi_clk = {
+ .halt_reg = 0x2d034,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2d034,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2d034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_usb_noc_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_av1e_ahb_clk = {
+ .halt_reg = 0x4a004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x4a004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_av1e_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_av1e_axi_clk = {
+ .halt_reg = 0x4a008,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x4a008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4a008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_av1e_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_av1e_xo_clk = {
+ .halt_reg = 0x4a014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4a014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_av1e_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+ .halt_reg = 0x38004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x38004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_hf_axi_clk = {
+ .halt_reg = 0x26010,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x26010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x26010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camera_hf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_sf_axi_clk = {
+ .halt_reg = 0x2601c,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x2601c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2601c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camera_sf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_pcie_anoc_ahb_clk = {
+ .halt_reg = 0x10028,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x10028,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_pcie_anoc_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_pcie_anoc_north_ahb_clk = {
+ .halt_reg = 0x1002c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1002c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_pcie_anoc_north_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_pcie_anoc_south_ahb_clk = {
+ .halt_reg = 0x10030,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x10030,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_pcie_anoc_south_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb2_prim_axi_clk = {
+ .halt_reg = 0x29288,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x29288,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x29288,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb2_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb20_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_mp_axi_clk = {
+ .halt_reg = 0x173cc,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x173cc,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x173cc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb3_mp_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_mp_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = {
+ .halt_reg = 0x3908c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x3908c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3908c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_sec_axi_clk = {
+ .halt_reg = 0xa108c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xa108c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xa108c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb3_sec_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_sec_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_tert_axi_clk = {
+ .halt_reg = 0xa208c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xa208c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xa208c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb3_tert_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_tert_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb_anoc_ahb_clk = {
+ .halt_reg = 0x2d024,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2d024,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(21),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb_anoc_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb_anoc_north_ahb_clk = {
+ .halt_reg = 0x2d028,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2d028,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb_anoc_north_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb_anoc_south_ahb_clk = {
+ .halt_reg = 0x2d02c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2d02c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb_anoc_south_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cnoc_pcie1_tunnel_clk = {
+ .halt_reg = 0x2c2b4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(30),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cnoc_pcie1_tunnel_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cnoc_pcie2_tunnel_clk = {
+ .halt_reg = 0x132b4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(31),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cnoc_pcie2_tunnel_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cnoc_pcie_north_sf_axi_clk = {
+ .halt_reg = 0x10014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x10014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cnoc_pcie_north_sf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cnoc_pcie_south_sf_axi_clk = {
+ .halt_reg = 0x10018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x10018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cnoc_pcie_south_sf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cnoc_pcie_tunnel_clk = {
+ .halt_reg = 0xa02b4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xa02b4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cnoc_pcie_tunnel_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ddrss_gpu_axi_clk = {
+ .halt_reg = 0x7115c,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x7115c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7115c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ddrss_gpu_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_hf_axi_clk = {
+ .halt_reg = 0x2700c,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x2700c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2700c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_disp_hf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_disp_xo_clk = {
+ .halt_reg = 0x27018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x27018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_disp_xo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+ .halt_reg = 0x64000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x64000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+ .halt_reg = 0x65000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x65000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+ .halt_reg = 0x66000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x66000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_cfg_ahb_clk = {
+ .halt_reg = 0x71004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x71004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x71004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_cph_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_gpll0_cph_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_div_cph_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_gpll0_div_cph_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0_out_even.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_memnoc_gfx_clk = {
+ .halt_reg = 0x71010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x71010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x71010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_memnoc_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = {
+ .halt_reg = 0x71018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x71018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_snoc_dvm_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie0_phy_rchng_clk = {
+ .halt_reg = 0xa0050,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie0_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie1_phy_rchng_clk = {
+ .halt_reg = 0x2c050,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(31),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie1_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie2_phy_rchng_clk = {
+ .halt_reg = 0x13050,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie2_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_2_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_aux_clk = {
+ .halt_reg = 0xa0038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_cfg_ahb_clk = {
+ .halt_reg = 0xa0034,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xa0034,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_mstr_axi_clk = {
+ .halt_reg = 0xa0028,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0xa0028,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_pipe_clk = {
+ .halt_reg = 0xa0044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_slv_axi_clk = {
+ .halt_reg = 0xa001c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xa001c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(21),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_slv_q2a_axi_clk = {
+ .halt_reg = 0xa0018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_aux_clk = {
+ .halt_reg = 0x2c038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_cfg_ahb_clk = {
+ .halt_reg = 0x2c034,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2c034,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_mstr_axi_clk = {
+ .halt_reg = 0x2c028,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x2c028,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_pipe_clk = {
+ .halt_reg = 0x2c044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(30),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_slv_axi_clk = {
+ .halt_reg = 0x2c01c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2c01c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_slv_q2a_axi_clk = {
+ .halt_reg = 0x2c018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_2_aux_clk = {
+ .halt_reg = 0x13038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_2_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_2_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_2_cfg_ahb_clk = {
+ .halt_reg = 0x13034,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x13034,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(21),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_2_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_2_mstr_axi_clk = {
+ .halt_reg = 0x13028,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x13028,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_2_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_2_pipe_clk = {
+ .halt_reg = 0x13044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_2_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_2_slv_axi_clk = {
+ .halt_reg = 0x1301c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x1301c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(19),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_2_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_2_slv_q2a_axi_clk = {
+ .halt_reg = 0x13018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(18),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_2_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_3_aux_clk = {
+ .halt_reg = 0x58038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_3_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_3_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_3_cfg_ahb_clk = {
+ .halt_reg = 0x58034,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x58034,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_3_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_3_mstr_axi_clk = {
+ .halt_reg = 0x58028,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x58028,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(31),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_3_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_3_phy_aux_clk = {
+ .halt_reg = 0x58044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_3_phy_aux_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_3_phy_rchng_clk = {
+ .halt_reg = 0x5805c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_3_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_3_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_3_pipe_clk = {
+ .halt_reg = 0x58050,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_3_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_3_pipediv2_clk = {
+ .halt_reg = 0x58060,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_3_pipediv2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_3_pipe_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_3_slv_axi_clk = {
+ .halt_reg = 0x5801c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x5801c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(30),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_3_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_3_slv_q2a_axi_clk = {
+ .halt_reg = 0x58018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_3_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_4_aux_clk = {
+ .halt_reg = 0x6b038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_4_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_4_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_4_cfg_ahb_clk = {
+ .halt_reg = 0x6b034,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6b034,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_4_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_4_mstr_axi_clk = {
+ .halt_reg = 0x6b028,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x6b028,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_4_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_4_phy_rchng_clk = {
+ .halt_reg = 0x6b050,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_4_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_4_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_4_pipe_clk = {
+ .halt_reg = 0x6b044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_4_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_4_pipediv2_clk = {
+ .halt_reg = 0x6b054,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_4_pipediv2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_4_pipe_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_4_slv_axi_clk = {
+ .halt_reg = 0x6b01c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6b01c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_4_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_4_slv_q2a_axi_clk = {
+ .halt_reg = 0x6b018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_4_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_5_aux_clk = {
+ .halt_reg = 0x2f038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_5_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_5_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_5_cfg_ahb_clk = {
+ .halt_reg = 0x2f034,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2f034,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_5_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_5_mstr_axi_clk = {
+ .halt_reg = 0x2f028,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x2f028,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(14),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_5_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_5_phy_rchng_clk = {
+ .halt_reg = 0x2f050,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(18),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_5_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_5_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_5_pipe_clk = {
+ .halt_reg = 0x2f044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(17),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_5_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_5_pipediv2_clk = {
+ .halt_reg = 0x2f054,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(19),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_5_pipediv2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_5_pipe_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_5_slv_axi_clk = {
+ .halt_reg = 0x2f01c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2f01c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(13),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_5_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_5_slv_q2a_axi_clk = {
+ .halt_reg = 0x2f018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_5_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6a_aux_clk = {
+ .halt_reg = 0x31038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6a_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_6a_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6a_cfg_ahb_clk = {
+ .halt_reg = 0x31034,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x31034,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6a_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6a_mstr_axi_clk = {
+ .halt_reg = 0x31028,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x31028,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6a_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6a_phy_aux_clk = {
+ .halt_reg = 0x31044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6a_phy_aux_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6a_phy_rchng_clk = {
+ .halt_reg = 0x3105c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6a_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_6a_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6a_pipe_clk = {
+ .halt_reg = 0x31050,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6a_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6a_pipediv2_clk = {
+ .halt_reg = 0x31060,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6a_pipediv2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_6a_pipe_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6a_slv_axi_clk = {
+ .halt_reg = 0x3101c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x3101c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(21),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6a_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6a_slv_q2a_axi_clk = {
+ .halt_reg = 0x31018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6a_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6b_aux_clk = {
+ .halt_reg = 0x8d038,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6b_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_6b_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6b_cfg_ahb_clk = {
+ .halt_reg = 0x8d034,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x8d034,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6b_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6b_mstr_axi_clk = {
+ .halt_reg = 0x8d028,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x8d028,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6b_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6b_phy_aux_clk = {
+ .halt_reg = 0x8d044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6b_phy_aux_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6b_phy_rchng_clk = {
+ .halt_reg = 0x8d05c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6b_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_6b_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6b_pipe_clk = {
+ .halt_reg = 0x8d050,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(30),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6b_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6b_pipediv2_clk = {
+ .halt_reg = 0x8d060,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6b_pipediv2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_6b_pipe_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6b_slv_axi_clk = {
+ .halt_reg = 0x8d01c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x8d01c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6b_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_6b_slv_q2a_axi_clk = {
+ .halt_reg = 0x8d018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_6b_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_rscc_ahb_clk = {
+ .halt_reg = 0xa4008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xa4008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(18),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_rscc_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_rscc_xo_clk = {
+ .halt_reg = 0xa4004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(17),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_rscc_xo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_rscc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+ .halt_reg = 0x3300c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3300c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pdm2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+ .halt_reg = 0x33004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x33004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x33004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_xo4_clk = {
+ .halt_reg = 0x33008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x33008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm_xo4_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_av1e_ahb_clk = {
+ .halt_reg = 0x4a018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x4a018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x4a018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_av1e_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = {
+ .halt_reg = 0x26008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x26008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x26008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_camera_nrt_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_camera_rt_ahb_clk = {
+ .halt_reg = 0x2600c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2600c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2600c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_camera_rt_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_disp_ahb_clk = {
+ .halt_reg = 0x27008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x27008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x27008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_disp_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_gpu_ahb_clk = {
+ .halt_reg = 0x71008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x71008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x71008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_gpu_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_cv_cpu_ahb_clk = {
+ .halt_reg = 0x32014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x32014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_video_cv_cpu_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_cvp_ahb_clk = {
+ .halt_reg = 0x32008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x32008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_video_cvp_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_v_cpu_ahb_clk = {
+ .halt_reg = 0x32010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x32010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_video_v_cpu_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qmip_video_vcodec_ahb_clk = {
+ .halt_reg = 0x3200c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x3200c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x3200c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qmip_video_vcodec_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_core_2x_clk = {
+ .halt_reg = 0x23018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_core_clk = {
+ .halt_reg = 0x23008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_qspi_s2_clk = {
+ .halt_reg = 0x42280,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_qspi_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_qspi_s3_clk = {
+ .halt_reg = 0x423c0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_qspi_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s0_clk = {
+ .halt_reg = 0x42004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s1_clk = {
+ .halt_reg = 0x4213c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(11),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s2_clk = {
+ .halt_reg = 0x42274,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s2_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s3_clk = {
+ .halt_reg = 0x423b4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(13),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s3_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s4_clk = {
+ .halt_reg = 0x424f4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(14),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s5_clk = {
+ .halt_reg = 0x4262c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s6_clk = {
+ .halt_reg = 0x42764,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap0_s7_clk = {
+ .halt_reg = 0x4289c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(17),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap0_s7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap0_s7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = {
+ .halt_reg = 0x23168,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(18),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_core_clk = {
+ .halt_reg = 0x23158,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(19),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_qspi_s2_clk = {
+ .halt_reg = 0x18280,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_qspi_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_qspi_s3_clk = {
+ .halt_reg = 0x183c0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_qspi_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s0_clk = {
+ .halt_reg = 0x18004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s1_clk = {
+ .halt_reg = 0x1813c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s2_clk = {
+ .halt_reg = 0x18274,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s2_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s3_clk = {
+ .halt_reg = 0x183b4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s3_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s4_clk = {
+ .halt_reg = 0x184f4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s5_clk = {
+ .halt_reg = 0x1862c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s6_clk = {
+ .halt_reg = 0x18764,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s7_clk = {
+ .halt_reg = 0x1889c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_core_2x_clk = {
+ .halt_reg = 0x232b8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_core_clk = {
+ .halt_reg = 0x232a8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_qspi_s2_clk = {
+ .halt_reg = 0x1e280,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_qspi_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_qspi_s3_clk = {
+ .halt_reg = 0x1e3c0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_qspi_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s0_clk = {
+ .halt_reg = 0x1e004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s1_clk = {
+ .halt_reg = 0x1e13c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s2_clk = {
+ .halt_reg = 0x1e274,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s2_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s3_clk = {
+ .halt_reg = 0x1e3b4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s3_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s4_clk = {
+ .halt_reg = 0x1e4f4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s5_clk = {
+ .halt_reg = 0x1e62c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s6_clk = {
+ .halt_reg = 0x1e764,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s7_clk = {
+ .halt_reg = 0x1e89c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(17),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_0_m_ahb_clk = {
+ .halt_reg = 0x23000,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23000,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_0_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_0_s_ahb_clk = {
+ .halt_reg = 0x23004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_0_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_1_m_ahb_clk = {
+ .halt_reg = 0x23150,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23150,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_1_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = {
+ .halt_reg = 0x23154,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23154,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(21),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_1_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_2_m_ahb_clk = {
+ .halt_reg = 0x232a0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x232a0,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_2_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_2_s_ahb_clk = {
+ .halt_reg = 0x232a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x232a4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_2_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+ .halt_reg = 0x14010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x14010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc2_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_apps_clk = {
+ .halt_reg = 0x14004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x14004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc2_apps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc2_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc4_ahb_clk = {
+ .halt_reg = 0x16010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x16010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc4_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc4_apps_clk = {
+ .halt_reg = 0x16004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x16004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc4_apps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc4_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sys_noc_usb_axi_clk = {
+ .halt_reg = 0x2d014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2d014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2d014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sys_noc_usb_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ahb_clk = {
+ .halt_reg = 0x77024,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77024,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_axi_clk = {
+ .halt_reg = 0x77018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ice_core_clk = {
+ .halt_reg = 0x77074,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77074,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77074,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_ice_core_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_phy_aux_clk = {
+ .halt_reg = 0x770b0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x770b0,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x770b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = {
+ .halt_reg = 0x7702c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x7702c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_rx_symbol_0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = {
+ .halt_reg = 0x770cc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x770cc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_rx_symbol_1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = {
+ .halt_reg = 0x77028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x77028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_tx_symbol_0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_unipro_core_clk = {
+ .halt_reg = 0x77068,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77068,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_unipro_core_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_unipro_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_master_clk = {
+ .halt_reg = 0x29018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x29018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb20_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_mock_utmi_clk = {
+ .halt_reg = 0x29028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x29028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb20_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb20_sleep_clk = {
+ .halt_reg = 0x29024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x29024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb20_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_mp_master_clk = {
+ .halt_reg = 0x17018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_mp_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_mp_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_mp_mock_utmi_clk = {
+ .halt_reg = 0x17028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_mp_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_mp_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_mp_sleep_clk = {
+ .halt_reg = 0x17024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_mp_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_master_clk = {
+ .halt_reg = 0x39018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
+ .halt_reg = 0x39028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_sleep_clk = {
+ .halt_reg = 0x39024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_sec_master_clk = {
+ .halt_reg = 0xa1018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa1018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_sec_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_sec_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_sec_mock_utmi_clk = {
+ .halt_reg = 0xa1028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa1028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_sec_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_sec_sleep_clk = {
+ .halt_reg = 0xa1024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa1024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_sec_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_tert_master_clk = {
+ .halt_reg = 0xa2018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa2018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_tert_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_tert_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_tert_mock_utmi_clk = {
+ .halt_reg = 0xa2028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa2028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_tert_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_tert_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_tert_sleep_clk = {
+ .halt_reg = 0xa2024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa2024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_tert_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_mp_phy_aux_clk = {
+ .halt_reg = 0x17288,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17288,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_mp_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_mp_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_mp_phy_com_aux_clk = {
+ .halt_reg = 0x1728c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1728c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_mp_phy_com_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_mp_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_mp_phy_pipe_0_clk = {
+ .halt_reg = 0x17290,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17290,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_mp_phy_pipe_0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_mp_phy_pipe_1_clk = {
+ .halt_reg = 0x17298,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17298,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_mp_phy_pipe_1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_aux_clk = {
+ .halt_reg = 0x39060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = {
+ .halt_reg = 0x39064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_com_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = {
+ .reg = 0x3906c,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_10,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_prim_phy_pipe_clk_src",
+ .parent_data = gcc_parent_data_10,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_10),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_pipe_clk = {
+ .halt_reg = 0x39068,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x39068,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x39068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_sec_phy_aux_clk = {
+ .halt_reg = 0xa1060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa1060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_sec_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_sec_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_sec_phy_com_aux_clk = {
+ .halt_reg = 0xa1064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa1064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_sec_phy_com_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_sec_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_usb3_sec_phy_pipe_clk_src = {
+ .reg = 0xa106c,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_11,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_sec_phy_pipe_clk_src",
+ .parent_data = gcc_parent_data_11,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_11),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_sec_phy_pipe_clk = {
+ .halt_reg = 0xa1068,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xa1068,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xa1068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_sec_phy_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_sec_phy_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_tert_phy_aux_clk = {
+ .halt_reg = 0xa2060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa2060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_tert_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_tert_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_tert_phy_com_aux_clk = {
+ .halt_reg = 0xa2064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0xa2064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_tert_phy_com_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_tert_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap_mux gcc_usb3_tert_phy_pipe_clk_src = {
+ .reg = 0xa206c,
+ .shift = 0,
+ .width = 2,
+ .parent_map = gcc_parent_map_12,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_usb3_tert_phy_pipe_clk_src",
+ .parent_data = gcc_parent_data_12,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_12),
+ .ops = &clk_regmap_mux_closest_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_tert_phy_pipe_clk = {
+ .halt_reg = 0xa2068,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0xa2068,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0xa2068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_tert_phy_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_tert_phy_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_0_cfg_ahb_clk = {
+ .halt_reg = 0x9f0a8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x9f0a8,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x9f0a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_0_dp0_clk = {
+ .halt_reg = 0x9f060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9f060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_dp0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_0_dp1_clk = {
+ .halt_reg = 0x9f108,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9f108,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_dp1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_0_master_clk = {
+ .halt_reg = 0x9f018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9f018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb4_0_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_0_phy_p2rr2p_pipe_clk = {
+ .halt_reg = 0x9f0d8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9f0d8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_phy_p2rr2p_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_0_phy_pcie_pipe_clk = {
+ .halt_reg = 0x9f048,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(19),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_phy_pcie_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_0_phy_rx0_clk = {
+ .halt_reg = 0x9f0b0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9f0b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_phy_rx0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_0_phy_rx1_clk = {
+ .halt_reg = 0x9f0c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9f0c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_phy_rx1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_0_phy_usb_pipe_clk = {
+ .halt_reg = 0x9f0a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x9f0a4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x9f0a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_phy_usb_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_0_sb_if_clk = {
+ .halt_reg = 0x9f044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9f044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_sb_if_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb4_0_sb_if_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_0_sys_clk = {
+ .halt_reg = 0x9f054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9f054,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_sys_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_0_tmu_clk = {
+ .halt_reg = 0x9f088,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x9f088,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x9f088,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_0_tmu_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb4_0_tmu_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_1_cfg_ahb_clk = {
+ .halt_reg = 0x2b0a8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2b0a8,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2b0a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_1_dp0_clk = {
+ .halt_reg = 0x2b060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_dp0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_1_dp1_clk = {
+ .halt_reg = 0x2b108,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b108,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_dp1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_1_master_clk = {
+ .halt_reg = 0x2b018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb4_1_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_1_phy_p2rr2p_pipe_clk = {
+ .halt_reg = 0x2b0d8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b0d8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_phy_p2rr2p_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_1_phy_pcie_pipe_clk = {
+ .halt_reg = 0x2b048,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_phy_pcie_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_1_phy_rx0_clk = {
+ .halt_reg = 0x2b0b0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b0b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_phy_rx0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_1_phy_rx1_clk = {
+ .halt_reg = 0x2b0c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b0c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_phy_rx1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_1_phy_usb_pipe_clk = {
+ .halt_reg = 0x2b0a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2b0a4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2b0a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_phy_usb_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_1_sb_if_clk = {
+ .halt_reg = 0x2b044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_sb_if_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb4_1_sb_if_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_1_sys_clk = {
+ .halt_reg = 0x2b054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b054,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_sys_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_1_tmu_clk = {
+ .halt_reg = 0x2b088,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2b088,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2b088,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_1_tmu_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb4_1_tmu_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_2_cfg_ahb_clk = {
+ .halt_reg = 0x110a8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x110a8,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x110a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_2_dp0_clk = {
+ .halt_reg = 0x11060,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11060,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_dp0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_2_dp1_clk = {
+ .halt_reg = 0x11108,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11108,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_dp1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_2_master_clk = {
+ .halt_reg = 0x11018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb4_2_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_2_phy_p2rr2p_pipe_clk = {
+ .halt_reg = 0x110d8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x110d8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_phy_p2rr2p_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_2_phy_pcie_pipe_clk = {
+ .halt_reg = 0x11048,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_phy_pcie_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_2_phy_rx0_clk = {
+ .halt_reg = 0x110b0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x110b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_phy_rx0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_2_phy_rx1_clk = {
+ .halt_reg = 0x110c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x110c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_phy_rx1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_2_phy_usb_pipe_clk = {
+ .halt_reg = 0x110a4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x110a4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x110a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_phy_usb_pipe_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_2_sb_if_clk = {
+ .halt_reg = 0x11044,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_sb_if_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb4_2_sb_if_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_2_sys_clk = {
+ .halt_reg = 0x11054,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11054,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_sys_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb4_2_tmu_clk = {
+ .halt_reg = 0x11088,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x11088,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x11088,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb4_2_tmu_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb4_2_tmu_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_axi0_clk = {
+ .halt_reg = 0x32018,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x32018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_video_axi0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_axi1_clk = {
+ .halt_reg = 0x32024,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x32024,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_video_axi1_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc gcc_pcie_0_tunnel_gdsc = {
+ .gdscr = 0xa0004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_pcie_0_tunnel_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_1_tunnel_gdsc = {
+ .gdscr = 0x2c004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_pcie_1_tunnel_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_2_tunnel_gdsc = {
+ .gdscr = 0x13004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_pcie_2_tunnel_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_3_gdsc = {
+ .gdscr = 0x58004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_pcie_3_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_3_phy_gdsc = {
+ .gdscr = 0x3e000,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_pcie_3_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_4_gdsc = {
+ .gdscr = 0x6b004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_pcie_4_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_4_phy_gdsc = {
+ .gdscr = 0x6c000,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_pcie_4_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_5_gdsc = {
+ .gdscr = 0x2f004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_pcie_5_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_5_phy_gdsc = {
+ .gdscr = 0x30000,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_pcie_5_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_6_phy_gdsc = {
+ .gdscr = 0x8e000,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_pcie_6_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_6a_gdsc = {
+ .gdscr = 0x31004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_pcie_6a_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_6b_gdsc = {
+ .gdscr = 0x8d004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_pcie_6b_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_ufs_mem_phy_gdsc = {
+ .gdscr = 0x9e000,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_ufs_mem_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_ufs_phy_gdsc = {
+ .gdscr = 0x77004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_ufs_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb20_prim_gdsc = {
+ .gdscr = 0x29004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_usb20_prim_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb30_mp_gdsc = {
+ .gdscr = 0x17004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_usb30_mp_gdsc",
+ },
+ .pwrsts = PWRSTS_RET_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb30_prim_gdsc = {
+ .gdscr = 0x39004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_usb30_prim_gdsc",
+ },
+ .pwrsts = PWRSTS_RET_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb30_sec_gdsc = {
+ .gdscr = 0xa1004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_usb30_sec_gdsc",
+ },
+ .pwrsts = PWRSTS_RET_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb30_tert_gdsc = {
+ .gdscr = 0xa2004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_usb30_tert_gdsc",
+ },
+ .pwrsts = PWRSTS_RET_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb3_mp_ss0_phy_gdsc = {
+ .gdscr = 0x1900c,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_usb3_mp_ss0_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_RET_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb3_mp_ss1_phy_gdsc = {
+ .gdscr = 0x5400c,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_usb3_mp_ss1_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb4_0_gdsc = {
+ .gdscr = 0x9f004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_usb4_0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb4_1_gdsc = {
+ .gdscr = 0x2b004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_usb4_1_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb4_2_gdsc = {
+ .gdscr = 0x11004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_usb4_2_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb_0_phy_gdsc = {
+ .gdscr = 0x50024,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_usb_0_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb_1_phy_gdsc = {
+ .gdscr = 0x2a024,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_usb_1_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb_2_phy_gdsc = {
+ .gdscr = 0xa3024,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_usb_2_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_RET_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *gcc_x1e80100_clocks[] = {
+ [GCC_AGGRE_NOC_USB_NORTH_AXI_CLK] = &gcc_aggre_noc_usb_north_axi_clk.clkr,
+ [GCC_AGGRE_NOC_USB_SOUTH_AXI_CLK] = &gcc_aggre_noc_usb_south_axi_clk.clkr,
+ [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr,
+ [GCC_AGGRE_USB2_PRIM_AXI_CLK] = &gcc_aggre_usb2_prim_axi_clk.clkr,
+ [GCC_AGGRE_USB3_MP_AXI_CLK] = &gcc_aggre_usb3_mp_axi_clk.clkr,
+ [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr,
+ [GCC_AGGRE_USB3_SEC_AXI_CLK] = &gcc_aggre_usb3_sec_axi_clk.clkr,
+ [GCC_AGGRE_USB3_TERT_AXI_CLK] = &gcc_aggre_usb3_tert_axi_clk.clkr,
+ [GCC_AGGRE_USB4_0_AXI_CLK] = &gcc_aggre_usb4_0_axi_clk.clkr,
+ [GCC_AGGRE_USB4_1_AXI_CLK] = &gcc_aggre_usb4_1_axi_clk.clkr,
+ [GCC_AGGRE_USB4_2_AXI_CLK] = &gcc_aggre_usb4_2_axi_clk.clkr,
+ [GCC_AGGRE_USB_NOC_AXI_CLK] = &gcc_aggre_usb_noc_axi_clk.clkr,
+ [GCC_AV1E_AHB_CLK] = &gcc_av1e_ahb_clk.clkr,
+ [GCC_AV1E_AXI_CLK] = &gcc_av1e_axi_clk.clkr,
+ [GCC_AV1E_XO_CLK] = &gcc_av1e_xo_clk.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_CAMERA_HF_AXI_CLK] = &gcc_camera_hf_axi_clk.clkr,
+ [GCC_CAMERA_SF_AXI_CLK] = &gcc_camera_sf_axi_clk.clkr,
+ [GCC_CFG_NOC_PCIE_ANOC_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_ahb_clk.clkr,
+ [GCC_CFG_NOC_PCIE_ANOC_NORTH_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_north_ahb_clk.clkr,
+ [GCC_CFG_NOC_PCIE_ANOC_SOUTH_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_south_ahb_clk.clkr,
+ [GCC_CFG_NOC_USB2_PRIM_AXI_CLK] = &gcc_cfg_noc_usb2_prim_axi_clk.clkr,
+ [GCC_CFG_NOC_USB3_MP_AXI_CLK] = &gcc_cfg_noc_usb3_mp_axi_clk.clkr,
+ [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr,
+ [GCC_CFG_NOC_USB3_SEC_AXI_CLK] = &gcc_cfg_noc_usb3_sec_axi_clk.clkr,
+ [GCC_CFG_NOC_USB3_TERT_AXI_CLK] = &gcc_cfg_noc_usb3_tert_axi_clk.clkr,
+ [GCC_CFG_NOC_USB_ANOC_AHB_CLK] = &gcc_cfg_noc_usb_anoc_ahb_clk.clkr,
+ [GCC_CFG_NOC_USB_ANOC_NORTH_AHB_CLK] = &gcc_cfg_noc_usb_anoc_north_ahb_clk.clkr,
+ [GCC_CFG_NOC_USB_ANOC_SOUTH_AHB_CLK] = &gcc_cfg_noc_usb_anoc_south_ahb_clk.clkr,
+ [GCC_CNOC_PCIE1_TUNNEL_CLK] = &gcc_cnoc_pcie1_tunnel_clk.clkr,
+ [GCC_CNOC_PCIE2_TUNNEL_CLK] = &gcc_cnoc_pcie2_tunnel_clk.clkr,
+ [GCC_CNOC_PCIE_NORTH_SF_AXI_CLK] = &gcc_cnoc_pcie_north_sf_axi_clk.clkr,
+ [GCC_CNOC_PCIE_SOUTH_SF_AXI_CLK] = &gcc_cnoc_pcie_south_sf_axi_clk.clkr,
+ [GCC_CNOC_PCIE_TUNNEL_CLK] = &gcc_cnoc_pcie_tunnel_clk.clkr,
+ [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr,
+ [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr,
+ [GCC_DISP_XO_CLK] = &gcc_disp_xo_clk.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr,
+ [GCC_GPLL0] = &gcc_gpll0.clkr,
+ [GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr,
+ [GCC_GPLL4] = &gcc_gpll4.clkr,
+ [GCC_GPLL7] = &gcc_gpll7.clkr,
+ [GCC_GPLL8] = &gcc_gpll8.clkr,
+ [GCC_GPLL9] = &gcc_gpll9.clkr,
+ [GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr,
+ [GCC_GPU_GPLL0_CPH_CLK_SRC] = &gcc_gpu_gpll0_cph_clk_src.clkr,
+ [GCC_GPU_GPLL0_DIV_CPH_CLK_SRC] = &gcc_gpu_gpll0_div_cph_clk_src.clkr,
+ [GCC_GPU_MEMNOC_GFX_CLK] = &gcc_gpu_memnoc_gfx_clk.clkr,
+ [GCC_GPU_SNOC_DVM_GFX_CLK] = &gcc_gpu_snoc_dvm_gfx_clk.clkr,
+ [GCC_PCIE0_PHY_RCHNG_CLK] = &gcc_pcie0_phy_rchng_clk.clkr,
+ [GCC_PCIE1_PHY_RCHNG_CLK] = &gcc_pcie1_phy_rchng_clk.clkr,
+ [GCC_PCIE2_PHY_RCHNG_CLK] = &gcc_pcie2_phy_rchng_clk.clkr,
+ [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr,
+ [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr,
+ [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr,
+ [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr,
+ [GCC_PCIE_0_PHY_RCHNG_CLK_SRC] = &gcc_pcie_0_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr,
+ [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr,
+ [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr,
+ [GCC_PCIE_1_AUX_CLK_SRC] = &gcc_pcie_1_aux_clk_src.clkr,
+ [GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr,
+ [GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr,
+ [GCC_PCIE_1_PHY_RCHNG_CLK_SRC] = &gcc_pcie_1_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr,
+ [GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr,
+ [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = &gcc_pcie_1_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_2_AUX_CLK] = &gcc_pcie_2_aux_clk.clkr,
+ [GCC_PCIE_2_AUX_CLK_SRC] = &gcc_pcie_2_aux_clk_src.clkr,
+ [GCC_PCIE_2_CFG_AHB_CLK] = &gcc_pcie_2_cfg_ahb_clk.clkr,
+ [GCC_PCIE_2_MSTR_AXI_CLK] = &gcc_pcie_2_mstr_axi_clk.clkr,
+ [GCC_PCIE_2_PHY_RCHNG_CLK_SRC] = &gcc_pcie_2_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_2_PIPE_CLK] = &gcc_pcie_2_pipe_clk.clkr,
+ [GCC_PCIE_2_SLV_AXI_CLK] = &gcc_pcie_2_slv_axi_clk.clkr,
+ [GCC_PCIE_2_SLV_Q2A_AXI_CLK] = &gcc_pcie_2_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_3_AUX_CLK] = &gcc_pcie_3_aux_clk.clkr,
+ [GCC_PCIE_3_AUX_CLK_SRC] = &gcc_pcie_3_aux_clk_src.clkr,
+ [GCC_PCIE_3_CFG_AHB_CLK] = &gcc_pcie_3_cfg_ahb_clk.clkr,
+ [GCC_PCIE_3_MSTR_AXI_CLK] = &gcc_pcie_3_mstr_axi_clk.clkr,
+ [GCC_PCIE_3_PHY_AUX_CLK] = &gcc_pcie_3_phy_aux_clk.clkr,
+ [GCC_PCIE_3_PHY_RCHNG_CLK] = &gcc_pcie_3_phy_rchng_clk.clkr,
+ [GCC_PCIE_3_PHY_RCHNG_CLK_SRC] = &gcc_pcie_3_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_3_PIPE_CLK] = &gcc_pcie_3_pipe_clk.clkr,
+ [GCC_PCIE_3_PIPE_CLK_SRC] = &gcc_pcie_3_pipe_clk_src.clkr,
+ [GCC_PCIE_3_PIPE_DIV_CLK_SRC] = &gcc_pcie_3_pipe_div_clk_src.clkr,
+ [GCC_PCIE_3_PIPEDIV2_CLK] = &gcc_pcie_3_pipediv2_clk.clkr,
+ [GCC_PCIE_3_SLV_AXI_CLK] = &gcc_pcie_3_slv_axi_clk.clkr,
+ [GCC_PCIE_3_SLV_Q2A_AXI_CLK] = &gcc_pcie_3_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_4_AUX_CLK] = &gcc_pcie_4_aux_clk.clkr,
+ [GCC_PCIE_4_AUX_CLK_SRC] = &gcc_pcie_4_aux_clk_src.clkr,
+ [GCC_PCIE_4_CFG_AHB_CLK] = &gcc_pcie_4_cfg_ahb_clk.clkr,
+ [GCC_PCIE_4_MSTR_AXI_CLK] = &gcc_pcie_4_mstr_axi_clk.clkr,
+ [GCC_PCIE_4_PHY_RCHNG_CLK] = &gcc_pcie_4_phy_rchng_clk.clkr,
+ [GCC_PCIE_4_PHY_RCHNG_CLK_SRC] = &gcc_pcie_4_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_4_PIPE_CLK] = &gcc_pcie_4_pipe_clk.clkr,
+ [GCC_PCIE_4_PIPE_CLK_SRC] = &gcc_pcie_4_pipe_clk_src.clkr,
+ [GCC_PCIE_4_PIPE_DIV_CLK_SRC] = &gcc_pcie_4_pipe_div_clk_src.clkr,
+ [GCC_PCIE_4_PIPEDIV2_CLK] = &gcc_pcie_4_pipediv2_clk.clkr,
+ [GCC_PCIE_4_SLV_AXI_CLK] = &gcc_pcie_4_slv_axi_clk.clkr,
+ [GCC_PCIE_4_SLV_Q2A_AXI_CLK] = &gcc_pcie_4_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_5_AUX_CLK] = &gcc_pcie_5_aux_clk.clkr,
+ [GCC_PCIE_5_AUX_CLK_SRC] = &gcc_pcie_5_aux_clk_src.clkr,
+ [GCC_PCIE_5_CFG_AHB_CLK] = &gcc_pcie_5_cfg_ahb_clk.clkr,
+ [GCC_PCIE_5_MSTR_AXI_CLK] = &gcc_pcie_5_mstr_axi_clk.clkr,
+ [GCC_PCIE_5_PHY_RCHNG_CLK] = &gcc_pcie_5_phy_rchng_clk.clkr,
+ [GCC_PCIE_5_PHY_RCHNG_CLK_SRC] = &gcc_pcie_5_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_5_PIPE_CLK] = &gcc_pcie_5_pipe_clk.clkr,
+ [GCC_PCIE_5_PIPE_CLK_SRC] = &gcc_pcie_5_pipe_clk_src.clkr,
+ [GCC_PCIE_5_PIPE_DIV_CLK_SRC] = &gcc_pcie_5_pipe_div_clk_src.clkr,
+ [GCC_PCIE_5_PIPEDIV2_CLK] = &gcc_pcie_5_pipediv2_clk.clkr,
+ [GCC_PCIE_5_SLV_AXI_CLK] = &gcc_pcie_5_slv_axi_clk.clkr,
+ [GCC_PCIE_5_SLV_Q2A_AXI_CLK] = &gcc_pcie_5_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_6A_AUX_CLK] = &gcc_pcie_6a_aux_clk.clkr,
+ [GCC_PCIE_6A_AUX_CLK_SRC] = &gcc_pcie_6a_aux_clk_src.clkr,
+ [GCC_PCIE_6A_CFG_AHB_CLK] = &gcc_pcie_6a_cfg_ahb_clk.clkr,
+ [GCC_PCIE_6A_MSTR_AXI_CLK] = &gcc_pcie_6a_mstr_axi_clk.clkr,
+ [GCC_PCIE_6A_PHY_AUX_CLK] = &gcc_pcie_6a_phy_aux_clk.clkr,
+ [GCC_PCIE_6A_PHY_RCHNG_CLK] = &gcc_pcie_6a_phy_rchng_clk.clkr,
+ [GCC_PCIE_6A_PHY_RCHNG_CLK_SRC] = &gcc_pcie_6a_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_6A_PIPE_CLK] = &gcc_pcie_6a_pipe_clk.clkr,
+ [GCC_PCIE_6A_PIPE_CLK_SRC] = &gcc_pcie_6a_pipe_clk_src.clkr,
+ [GCC_PCIE_6A_PIPE_DIV_CLK_SRC] = &gcc_pcie_6a_pipe_div_clk_src.clkr,
+ [GCC_PCIE_6A_PIPEDIV2_CLK] = &gcc_pcie_6a_pipediv2_clk.clkr,
+ [GCC_PCIE_6A_SLV_AXI_CLK] = &gcc_pcie_6a_slv_axi_clk.clkr,
+ [GCC_PCIE_6A_SLV_Q2A_AXI_CLK] = &gcc_pcie_6a_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_6B_AUX_CLK] = &gcc_pcie_6b_aux_clk.clkr,
+ [GCC_PCIE_6B_AUX_CLK_SRC] = &gcc_pcie_6b_aux_clk_src.clkr,
+ [GCC_PCIE_6B_CFG_AHB_CLK] = &gcc_pcie_6b_cfg_ahb_clk.clkr,
+ [GCC_PCIE_6B_MSTR_AXI_CLK] = &gcc_pcie_6b_mstr_axi_clk.clkr,
+ [GCC_PCIE_6B_PHY_AUX_CLK] = &gcc_pcie_6b_phy_aux_clk.clkr,
+ [GCC_PCIE_6B_PHY_RCHNG_CLK] = &gcc_pcie_6b_phy_rchng_clk.clkr,
+ [GCC_PCIE_6B_PHY_RCHNG_CLK_SRC] = &gcc_pcie_6b_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_6B_PIPE_CLK] = &gcc_pcie_6b_pipe_clk.clkr,
+ [GCC_PCIE_6B_PIPE_CLK_SRC] = &gcc_pcie_6b_pipe_clk_src.clkr,
+ [GCC_PCIE_6B_PIPE_DIV_CLK_SRC] = &gcc_pcie_6b_pipe_div_clk_src.clkr,
+ [GCC_PCIE_6B_PIPEDIV2_CLK] = &gcc_pcie_6b_pipediv2_clk.clkr,
+ [GCC_PCIE_6B_SLV_AXI_CLK] = &gcc_pcie_6b_slv_axi_clk.clkr,
+ [GCC_PCIE_6B_SLV_Q2A_AXI_CLK] = &gcc_pcie_6b_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_RSCC_AHB_CLK] = &gcc_pcie_rscc_ahb_clk.clkr,
+ [GCC_PCIE_RSCC_XO_CLK] = &gcc_pcie_rscc_xo_clk.clkr,
+ [GCC_PCIE_RSCC_XO_CLK_SRC] = &gcc_pcie_rscc_xo_clk_src.clkr,
+ [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+ [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr,
+ [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+ [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr,
+ [GCC_QMIP_AV1E_AHB_CLK] = &gcc_qmip_av1e_ahb_clk.clkr,
+ [GCC_QMIP_CAMERA_NRT_AHB_CLK] = &gcc_qmip_camera_nrt_ahb_clk.clkr,
+ [GCC_QMIP_CAMERA_RT_AHB_CLK] = &gcc_qmip_camera_rt_ahb_clk.clkr,
+ [GCC_QMIP_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr,
+ [GCC_QMIP_GPU_AHB_CLK] = &gcc_qmip_gpu_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_CV_CPU_AHB_CLK] = &gcc_qmip_video_cv_cpu_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_CVP_AHB_CLK] = &gcc_qmip_video_cvp_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_V_CPU_AHB_CLK] = &gcc_qmip_video_v_cpu_ahb_clk.clkr,
+ [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP0_CORE_2X_CLK] = &gcc_qupv3_wrap0_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP0_CORE_CLK] = &gcc_qupv3_wrap0_core_clk.clkr,
+ [GCC_QUPV3_WRAP0_QSPI_S2_CLK] = &gcc_qupv3_wrap0_qspi_s2_clk.clkr,
+ [GCC_QUPV3_WRAP0_QSPI_S3_CLK] = &gcc_qupv3_wrap0_qspi_s3_clk.clkr,
+ [GCC_QUPV3_WRAP0_S0_CLK] = &gcc_qupv3_wrap0_s0_clk.clkr,
+ [GCC_QUPV3_WRAP0_S0_CLK_SRC] = &gcc_qupv3_wrap0_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S1_CLK] = &gcc_qupv3_wrap0_s1_clk.clkr,
+ [GCC_QUPV3_WRAP0_S1_CLK_SRC] = &gcc_qupv3_wrap0_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S2_CLK] = &gcc_qupv3_wrap0_s2_clk.clkr,
+ [GCC_QUPV3_WRAP0_S2_CLK_SRC] = &gcc_qupv3_wrap0_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S2_DIV_CLK_SRC] = &gcc_qupv3_wrap0_s2_div_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S3_CLK] = &gcc_qupv3_wrap0_s3_clk.clkr,
+ [GCC_QUPV3_WRAP0_S3_CLK_SRC] = &gcc_qupv3_wrap0_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S3_DIV_CLK_SRC] = &gcc_qupv3_wrap0_s3_div_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S4_CLK] = &gcc_qupv3_wrap0_s4_clk.clkr,
+ [GCC_QUPV3_WRAP0_S4_CLK_SRC] = &gcc_qupv3_wrap0_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S5_CLK] = &gcc_qupv3_wrap0_s5_clk.clkr,
+ [GCC_QUPV3_WRAP0_S5_CLK_SRC] = &gcc_qupv3_wrap0_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S6_CLK] = &gcc_qupv3_wrap0_s6_clk.clkr,
+ [GCC_QUPV3_WRAP0_S6_CLK_SRC] = &gcc_qupv3_wrap0_s6_clk_src.clkr,
+ [GCC_QUPV3_WRAP0_S7_CLK] = &gcc_qupv3_wrap0_s7_clk.clkr,
+ [GCC_QUPV3_WRAP0_S7_CLK_SRC] = &gcc_qupv3_wrap0_s7_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr,
+ [GCC_QUPV3_WRAP1_QSPI_S2_CLK] = &gcc_qupv3_wrap1_qspi_s2_clk.clkr,
+ [GCC_QUPV3_WRAP1_QSPI_S3_CLK] = &gcc_qupv3_wrap1_qspi_s3_clk.clkr,
+ [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr,
+ [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr,
+ [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr,
+ [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S2_DIV_CLK_SRC] = &gcc_qupv3_wrap1_s2_div_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr,
+ [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S3_DIV_CLK_SRC] = &gcc_qupv3_wrap1_s3_div_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr,
+ [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S5_CLK] = &gcc_qupv3_wrap1_s5_clk.clkr,
+ [GCC_QUPV3_WRAP1_S5_CLK_SRC] = &gcc_qupv3_wrap1_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S6_CLK] = &gcc_qupv3_wrap1_s6_clk.clkr,
+ [GCC_QUPV3_WRAP1_S6_CLK_SRC] = &gcc_qupv3_wrap1_s6_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S7_CLK] = &gcc_qupv3_wrap1_s7_clk.clkr,
+ [GCC_QUPV3_WRAP1_S7_CLK_SRC] = &gcc_qupv3_wrap1_s7_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_CORE_2X_CLK] = &gcc_qupv3_wrap2_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP2_CORE_CLK] = &gcc_qupv3_wrap2_core_clk.clkr,
+ [GCC_QUPV3_WRAP2_QSPI_S2_CLK] = &gcc_qupv3_wrap2_qspi_s2_clk.clkr,
+ [GCC_QUPV3_WRAP2_QSPI_S3_CLK] = &gcc_qupv3_wrap2_qspi_s3_clk.clkr,
+ [GCC_QUPV3_WRAP2_S0_CLK] = &gcc_qupv3_wrap2_s0_clk.clkr,
+ [GCC_QUPV3_WRAP2_S0_CLK_SRC] = &gcc_qupv3_wrap2_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S1_CLK] = &gcc_qupv3_wrap2_s1_clk.clkr,
+ [GCC_QUPV3_WRAP2_S1_CLK_SRC] = &gcc_qupv3_wrap2_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S2_CLK] = &gcc_qupv3_wrap2_s2_clk.clkr,
+ [GCC_QUPV3_WRAP2_S2_CLK_SRC] = &gcc_qupv3_wrap2_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S2_DIV_CLK_SRC] = &gcc_qupv3_wrap2_s2_div_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S3_CLK] = &gcc_qupv3_wrap2_s3_clk.clkr,
+ [GCC_QUPV3_WRAP2_S3_CLK_SRC] = &gcc_qupv3_wrap2_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S3_DIV_CLK_SRC] = &gcc_qupv3_wrap2_s3_div_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S4_CLK] = &gcc_qupv3_wrap2_s4_clk.clkr,
+ [GCC_QUPV3_WRAP2_S4_CLK_SRC] = &gcc_qupv3_wrap2_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S5_CLK] = &gcc_qupv3_wrap2_s5_clk.clkr,
+ [GCC_QUPV3_WRAP2_S5_CLK_SRC] = &gcc_qupv3_wrap2_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S6_CLK] = &gcc_qupv3_wrap2_s6_clk.clkr,
+ [GCC_QUPV3_WRAP2_S6_CLK_SRC] = &gcc_qupv3_wrap2_s6_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S7_CLK] = &gcc_qupv3_wrap2_s7_clk.clkr,
+ [GCC_QUPV3_WRAP2_S7_CLK_SRC] = &gcc_qupv3_wrap2_s7_clk_src.clkr,
+ [GCC_QUPV3_WRAP_0_M_AHB_CLK] = &gcc_qupv3_wrap_0_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_0_S_AHB_CLK] = &gcc_qupv3_wrap_0_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_1_M_AHB_CLK] = &gcc_qupv3_wrap_1_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_2_M_AHB_CLK] = &gcc_qupv3_wrap_2_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_2_S_AHB_CLK] = &gcc_qupv3_wrap_2_s_ahb_clk.clkr,
+ [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+ [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+ [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr,
+ [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr,
+ [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr,
+ [GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_clk_src.clkr,
+ [GCC_SYS_NOC_USB_AXI_CLK] = &gcc_sys_noc_usb_axi_clk.clkr,
+ [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr,
+ [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr,
+ [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr,
+ [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr,
+ [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr,
+ [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr,
+ [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr,
+ [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr,
+ [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr,
+ [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_phy_unipro_core_clk_src.clkr,
+ [GCC_USB20_MASTER_CLK] = &gcc_usb20_master_clk.clkr,
+ [GCC_USB20_MASTER_CLK_SRC] = &gcc_usb20_master_clk_src.clkr,
+ [GCC_USB20_MOCK_UTMI_CLK] = &gcc_usb20_mock_utmi_clk.clkr,
+ [GCC_USB20_MOCK_UTMI_CLK_SRC] = &gcc_usb20_mock_utmi_clk_src.clkr,
+ [GCC_USB20_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb20_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB20_SLEEP_CLK] = &gcc_usb20_sleep_clk.clkr,
+ [GCC_USB30_MP_MASTER_CLK] = &gcc_usb30_mp_master_clk.clkr,
+ [GCC_USB30_MP_MASTER_CLK_SRC] = &gcc_usb30_mp_master_clk_src.clkr,
+ [GCC_USB30_MP_MOCK_UTMI_CLK] = &gcc_usb30_mp_mock_utmi_clk.clkr,
+ [GCC_USB30_MP_MOCK_UTMI_CLK_SRC] = &gcc_usb30_mp_mock_utmi_clk_src.clkr,
+ [GCC_USB30_MP_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_mp_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB30_MP_SLEEP_CLK] = &gcc_usb30_mp_sleep_clk.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = &gcc_usb30_prim_mock_utmi_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr,
+ [GCC_USB30_SEC_MASTER_CLK] = &gcc_usb30_sec_master_clk.clkr,
+ [GCC_USB30_SEC_MASTER_CLK_SRC] = &gcc_usb30_sec_master_clk_src.clkr,
+ [GCC_USB30_SEC_MOCK_UTMI_CLK] = &gcc_usb30_sec_mock_utmi_clk.clkr,
+ [GCC_USB30_SEC_MOCK_UTMI_CLK_SRC] = &gcc_usb30_sec_mock_utmi_clk_src.clkr,
+ [GCC_USB30_SEC_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_sec_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB30_SEC_SLEEP_CLK] = &gcc_usb30_sec_sleep_clk.clkr,
+ [GCC_USB30_TERT_MASTER_CLK] = &gcc_usb30_tert_master_clk.clkr,
+ [GCC_USB30_TERT_MASTER_CLK_SRC] = &gcc_usb30_tert_master_clk_src.clkr,
+ [GCC_USB30_TERT_MOCK_UTMI_CLK] = &gcc_usb30_tert_mock_utmi_clk.clkr,
+ [GCC_USB30_TERT_MOCK_UTMI_CLK_SRC] = &gcc_usb30_tert_mock_utmi_clk_src.clkr,
+ [GCC_USB30_TERT_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_tert_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB30_TERT_SLEEP_CLK] = &gcc_usb30_tert_sleep_clk.clkr,
+ [GCC_USB3_MP_PHY_AUX_CLK] = &gcc_usb3_mp_phy_aux_clk.clkr,
+ [GCC_USB3_MP_PHY_AUX_CLK_SRC] = &gcc_usb3_mp_phy_aux_clk_src.clkr,
+ [GCC_USB3_MP_PHY_COM_AUX_CLK] = &gcc_usb3_mp_phy_com_aux_clk.clkr,
+ [GCC_USB3_MP_PHY_PIPE_0_CLK] = &gcc_usb3_mp_phy_pipe_0_clk.clkr,
+ [GCC_USB3_MP_PHY_PIPE_1_CLK] = &gcc_usb3_mp_phy_pipe_1_clk.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr,
+ [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr,
+ [GCC_USB3_SEC_PHY_AUX_CLK] = &gcc_usb3_sec_phy_aux_clk.clkr,
+ [GCC_USB3_SEC_PHY_AUX_CLK_SRC] = &gcc_usb3_sec_phy_aux_clk_src.clkr,
+ [GCC_USB3_SEC_PHY_COM_AUX_CLK] = &gcc_usb3_sec_phy_com_aux_clk.clkr,
+ [GCC_USB3_SEC_PHY_PIPE_CLK] = &gcc_usb3_sec_phy_pipe_clk.clkr,
+ [GCC_USB3_SEC_PHY_PIPE_CLK_SRC] = &gcc_usb3_sec_phy_pipe_clk_src.clkr,
+ [GCC_USB3_TERT_PHY_AUX_CLK] = &gcc_usb3_tert_phy_aux_clk.clkr,
+ [GCC_USB3_TERT_PHY_AUX_CLK_SRC] = &gcc_usb3_tert_phy_aux_clk_src.clkr,
+ [GCC_USB3_TERT_PHY_COM_AUX_CLK] = &gcc_usb3_tert_phy_com_aux_clk.clkr,
+ [GCC_USB3_TERT_PHY_PIPE_CLK] = &gcc_usb3_tert_phy_pipe_clk.clkr,
+ [GCC_USB3_TERT_PHY_PIPE_CLK_SRC] = &gcc_usb3_tert_phy_pipe_clk_src.clkr,
+ [GCC_USB4_0_CFG_AHB_CLK] = &gcc_usb4_0_cfg_ahb_clk.clkr,
+ [GCC_USB4_0_DP0_CLK] = &gcc_usb4_0_dp0_clk.clkr,
+ [GCC_USB4_0_DP1_CLK] = &gcc_usb4_0_dp1_clk.clkr,
+ [GCC_USB4_0_MASTER_CLK] = &gcc_usb4_0_master_clk.clkr,
+ [GCC_USB4_0_MASTER_CLK_SRC] = &gcc_usb4_0_master_clk_src.clkr,
+ [GCC_USB4_0_PHY_P2RR2P_PIPE_CLK] = &gcc_usb4_0_phy_p2rr2p_pipe_clk.clkr,
+ [GCC_USB4_0_PHY_PCIE_PIPE_CLK] = &gcc_usb4_0_phy_pcie_pipe_clk.clkr,
+ [GCC_USB4_0_PHY_PCIE_PIPE_CLK_SRC] = &gcc_usb4_0_phy_pcie_pipe_clk_src.clkr,
+ [GCC_USB4_0_PHY_RX0_CLK] = &gcc_usb4_0_phy_rx0_clk.clkr,
+ [GCC_USB4_0_PHY_RX1_CLK] = &gcc_usb4_0_phy_rx1_clk.clkr,
+ [GCC_USB4_0_PHY_USB_PIPE_CLK] = &gcc_usb4_0_phy_usb_pipe_clk.clkr,
+ [GCC_USB4_0_SB_IF_CLK] = &gcc_usb4_0_sb_if_clk.clkr,
+ [GCC_USB4_0_SB_IF_CLK_SRC] = &gcc_usb4_0_sb_if_clk_src.clkr,
+ [GCC_USB4_0_SYS_CLK] = &gcc_usb4_0_sys_clk.clkr,
+ [GCC_USB4_0_TMU_CLK] = &gcc_usb4_0_tmu_clk.clkr,
+ [GCC_USB4_0_TMU_CLK_SRC] = &gcc_usb4_0_tmu_clk_src.clkr,
+ [GCC_USB4_1_CFG_AHB_CLK] = &gcc_usb4_1_cfg_ahb_clk.clkr,
+ [GCC_USB4_1_DP0_CLK] = &gcc_usb4_1_dp0_clk.clkr,
+ [GCC_USB4_1_DP1_CLK] = &gcc_usb4_1_dp1_clk.clkr,
+ [GCC_USB4_1_MASTER_CLK] = &gcc_usb4_1_master_clk.clkr,
+ [GCC_USB4_1_MASTER_CLK_SRC] = &gcc_usb4_1_master_clk_src.clkr,
+ [GCC_USB4_1_PHY_P2RR2P_PIPE_CLK] = &gcc_usb4_1_phy_p2rr2p_pipe_clk.clkr,
+ [GCC_USB4_1_PHY_PCIE_PIPE_CLK] = &gcc_usb4_1_phy_pcie_pipe_clk.clkr,
+ [GCC_USB4_1_PHY_PCIE_PIPE_CLK_SRC] = &gcc_usb4_1_phy_pcie_pipe_clk_src.clkr,
+ [GCC_USB4_1_PHY_RX0_CLK] = &gcc_usb4_1_phy_rx0_clk.clkr,
+ [GCC_USB4_1_PHY_RX1_CLK] = &gcc_usb4_1_phy_rx1_clk.clkr,
+ [GCC_USB4_1_PHY_USB_PIPE_CLK] = &gcc_usb4_1_phy_usb_pipe_clk.clkr,
+ [GCC_USB4_1_SB_IF_CLK] = &gcc_usb4_1_sb_if_clk.clkr,
+ [GCC_USB4_1_SB_IF_CLK_SRC] = &gcc_usb4_1_sb_if_clk_src.clkr,
+ [GCC_USB4_1_SYS_CLK] = &gcc_usb4_1_sys_clk.clkr,
+ [GCC_USB4_1_TMU_CLK] = &gcc_usb4_1_tmu_clk.clkr,
+ [GCC_USB4_1_TMU_CLK_SRC] = &gcc_usb4_1_tmu_clk_src.clkr,
+ [GCC_USB4_2_CFG_AHB_CLK] = &gcc_usb4_2_cfg_ahb_clk.clkr,
+ [GCC_USB4_2_DP0_CLK] = &gcc_usb4_2_dp0_clk.clkr,
+ [GCC_USB4_2_DP1_CLK] = &gcc_usb4_2_dp1_clk.clkr,
+ [GCC_USB4_2_MASTER_CLK] = &gcc_usb4_2_master_clk.clkr,
+ [GCC_USB4_2_MASTER_CLK_SRC] = &gcc_usb4_2_master_clk_src.clkr,
+ [GCC_USB4_2_PHY_P2RR2P_PIPE_CLK] = &gcc_usb4_2_phy_p2rr2p_pipe_clk.clkr,
+ [GCC_USB4_2_PHY_PCIE_PIPE_CLK] = &gcc_usb4_2_phy_pcie_pipe_clk.clkr,
+ [GCC_USB4_2_PHY_PCIE_PIPE_CLK_SRC] = &gcc_usb4_2_phy_pcie_pipe_clk_src.clkr,
+ [GCC_USB4_2_PHY_RX0_CLK] = &gcc_usb4_2_phy_rx0_clk.clkr,
+ [GCC_USB4_2_PHY_RX1_CLK] = &gcc_usb4_2_phy_rx1_clk.clkr,
+ [GCC_USB4_2_PHY_USB_PIPE_CLK] = &gcc_usb4_2_phy_usb_pipe_clk.clkr,
+ [GCC_USB4_2_SB_IF_CLK] = &gcc_usb4_2_sb_if_clk.clkr,
+ [GCC_USB4_2_SB_IF_CLK_SRC] = &gcc_usb4_2_sb_if_clk_src.clkr,
+ [GCC_USB4_2_SYS_CLK] = &gcc_usb4_2_sys_clk.clkr,
+ [GCC_USB4_2_TMU_CLK] = &gcc_usb4_2_tmu_clk.clkr,
+ [GCC_USB4_2_TMU_CLK_SRC] = &gcc_usb4_2_tmu_clk_src.clkr,
+ [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr,
+ [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr,
+};
+
+static struct gdsc *gcc_x1e80100_gdscs[] = {
+ [GCC_PCIE_0_TUNNEL_GDSC] = &gcc_pcie_0_tunnel_gdsc,
+ [GCC_PCIE_1_TUNNEL_GDSC] = &gcc_pcie_1_tunnel_gdsc,
+ [GCC_PCIE_2_TUNNEL_GDSC] = &gcc_pcie_2_tunnel_gdsc,
+ [GCC_PCIE_3_GDSC] = &gcc_pcie_3_gdsc,
+ [GCC_PCIE_3_PHY_GDSC] = &gcc_pcie_3_phy_gdsc,
+ [GCC_PCIE_4_GDSC] = &gcc_pcie_4_gdsc,
+ [GCC_PCIE_4_PHY_GDSC] = &gcc_pcie_4_phy_gdsc,
+ [GCC_PCIE_5_GDSC] = &gcc_pcie_5_gdsc,
+ [GCC_PCIE_5_PHY_GDSC] = &gcc_pcie_5_phy_gdsc,
+ [GCC_PCIE_6_PHY_GDSC] = &gcc_pcie_6_phy_gdsc,
+ [GCC_PCIE_6A_GDSC] = &gcc_pcie_6a_gdsc,
+ [GCC_PCIE_6B_GDSC] = &gcc_pcie_6b_gdsc,
+ [GCC_UFS_MEM_PHY_GDSC] = &gcc_ufs_mem_phy_gdsc,
+ [GCC_UFS_PHY_GDSC] = &gcc_ufs_phy_gdsc,
+ [GCC_USB20_PRIM_GDSC] = &gcc_usb20_prim_gdsc,
+ [GCC_USB30_MP_GDSC] = &gcc_usb30_mp_gdsc,
+ [GCC_USB30_PRIM_GDSC] = &gcc_usb30_prim_gdsc,
+ [GCC_USB30_SEC_GDSC] = &gcc_usb30_sec_gdsc,
+ [GCC_USB30_TERT_GDSC] = &gcc_usb30_tert_gdsc,
+ [GCC_USB3_MP_SS0_PHY_GDSC] = &gcc_usb3_mp_ss0_phy_gdsc,
+ [GCC_USB3_MP_SS1_PHY_GDSC] = &gcc_usb3_mp_ss1_phy_gdsc,
+ [GCC_USB4_0_GDSC] = &gcc_usb4_0_gdsc,
+ [GCC_USB4_1_GDSC] = &gcc_usb4_1_gdsc,
+ [GCC_USB4_2_GDSC] = &gcc_usb4_2_gdsc,
+ [GCC_USB_0_PHY_GDSC] = &gcc_usb_0_phy_gdsc,
+ [GCC_USB_1_PHY_GDSC] = &gcc_usb_1_phy_gdsc,
+ [GCC_USB_2_PHY_GDSC] = &gcc_usb_2_phy_gdsc,
+};
+
+static const struct qcom_reset_map gcc_x1e80100_resets[] = {
+ [GCC_AV1E_BCR] = { 0x4a000 },
+ [GCC_CAMERA_BCR] = { 0x26000 },
+ [GCC_DISPLAY_BCR] = { 0x27000 },
+ [GCC_GPU_BCR] = { 0x71000 },
+ [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x6c014 },
+ [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x6c020 },
+ [GCC_PCIE_0_PHY_BCR] = { 0x6c01c },
+ [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x6c028 },
+ [GCC_PCIE_0_TUNNEL_BCR] = { 0xa0000 },
+ [GCC_PCIE_1_LINK_DOWN_BCR] = { 0x8e014 },
+ [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0x8e020 },
+ [GCC_PCIE_1_PHY_BCR] = { 0x8e01c },
+ [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0x8e024 },
+ [GCC_PCIE_1_TUNNEL_BCR] = { 0x2c000 },
+ [GCC_PCIE_2_LINK_DOWN_BCR] = { 0xa5014 },
+ [GCC_PCIE_2_NOCSR_COM_PHY_BCR] = { 0xa5020 },
+ [GCC_PCIE_2_PHY_BCR] = { 0xa501c },
+ [GCC_PCIE_2_PHY_NOCSR_COM_PHY_BCR] = { 0xa5028 },
+ [GCC_PCIE_2_TUNNEL_BCR] = { 0x13000 },
+ [GCC_PCIE_3_BCR] = { 0x58000 },
+ [GCC_PCIE_3_LINK_DOWN_BCR] = { 0xab014 },
+ [GCC_PCIE_3_NOCSR_COM_PHY_BCR] = { 0xab020 },
+ [GCC_PCIE_3_PHY_BCR] = { 0xab01c },
+ [GCC_PCIE_3_PHY_NOCSR_COM_PHY_BCR] = { 0xab024 },
+ [GCC_PCIE_4_BCR] = { 0x6b000 },
+ [GCC_PCIE_4_LINK_DOWN_BCR] = { 0xb3014 },
+ [GCC_PCIE_4_NOCSR_COM_PHY_BCR] = { 0xb3020 },
+ [GCC_PCIE_4_PHY_BCR] = { 0xb301c },
+ [GCC_PCIE_4_PHY_NOCSR_COM_PHY_BCR] = { 0xb3028 },
+ [GCC_PCIE_5_BCR] = { 0x2f000 },
+ [GCC_PCIE_5_LINK_DOWN_BCR] = { 0xaa014 },
+ [GCC_PCIE_5_NOCSR_COM_PHY_BCR] = { 0xaa020 },
+ [GCC_PCIE_5_PHY_BCR] = { 0xaa01c },
+ [GCC_PCIE_5_PHY_NOCSR_COM_PHY_BCR] = { 0xaa028 },
+ [GCC_PCIE_6A_BCR] = { 0x31000 },
+ [GCC_PCIE_6A_LINK_DOWN_BCR] = { 0xac014 },
+ [GCC_PCIE_6A_NOCSR_COM_PHY_BCR] = { 0xac020 },
+ [GCC_PCIE_6A_PHY_BCR] = { 0xac01c },
+ [GCC_PCIE_6A_PHY_NOCSR_COM_PHY_BCR] = { 0xac024 },
+ [GCC_PCIE_6B_BCR] = { 0x8d000 },
+ [GCC_PCIE_6B_LINK_DOWN_BCR] = { 0xb5014 },
+ [GCC_PCIE_6B_NOCSR_COM_PHY_BCR] = { 0xb5020 },
+ [GCC_PCIE_6B_PHY_BCR] = { 0xb501c },
+ [GCC_PCIE_6B_PHY_NOCSR_COM_PHY_BCR] = { 0xb5024 },
+ [GCC_PCIE_PHY_BCR] = { 0x6f000 },
+ [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x6f00c },
+ [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 },
+ [GCC_PCIE_RSCC_BCR] = { 0xa4000 },
+ [GCC_PDM_BCR] = { 0x33000 },
+ [GCC_QUPV3_WRAPPER_0_BCR] = { 0x42000 },
+ [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 },
+ [GCC_QUPV3_WRAPPER_2_BCR] = { 0x1e000 },
+ [GCC_QUSB2PHY_HS0_MP_BCR] = { 0x1200c },
+ [GCC_QUSB2PHY_HS1_MP_BCR] = { 0x12010 },
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 },
+ [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 },
+ [GCC_QUSB2PHY_TERT_BCR] = { 0x12008 },
+ [GCC_QUSB2PHY_USB20_HS_BCR] = { 0x12014 },
+ [GCC_SDCC2_BCR] = { 0x14000 },
+ [GCC_SDCC4_BCR] = { 0x16000 },
+ [GCC_UFS_PHY_BCR] = { 0x77000 },
+ [GCC_USB20_PRIM_BCR] = { 0x29000 },
+ [GCC_USB30_MP_BCR] = { 0x17000 },
+ [GCC_USB30_PRIM_BCR] = { 0x39000 },
+ [GCC_USB30_SEC_BCR] = { 0xa1000 },
+ [GCC_USB30_TERT_BCR] = { 0xa2000 },
+ [GCC_USB3_MP_SS0_PHY_BCR] = { 0x19008 },
+ [GCC_USB3_MP_SS1_PHY_BCR] = { 0x54008 },
+ [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 },
+ [GCC_USB3_PHY_SEC_BCR] = { 0x2a000 },
+ [GCC_USB3_PHY_TERT_BCR] = { 0xa3000 },
+ [GCC_USB3_UNIPHY_MP0_BCR] = { 0x19000 },
+ [GCC_USB3_UNIPHY_MP1_BCR] = { 0x54000 },
+ [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 },
+ [GCC_USB3PHY_PHY_SEC_BCR] = { 0x2a004 },
+ [GCC_USB3PHY_PHY_TERT_BCR] = { 0xa3004 },
+ [GCC_USB3UNIPHY_PHY_MP0_BCR] = { 0x19004 },
+ [GCC_USB3UNIPHY_PHY_MP1_BCR] = { 0x54004 },
+ [GCC_USB4_0_BCR] = { 0x9f000 },
+ [GCC_USB4_0_DP0_PHY_PRIM_BCR] = { 0x50010 },
+ [GCC_USB4_1_DP0_PHY_SEC_BCR] = { 0x2a010 },
+ [GCC_USB4_2_DP0_PHY_TERT_BCR] = { 0xa3010 },
+ [GCC_USB4_1_BCR] = { 0x2b000 },
+ [GCC_USB4_2_BCR] = { 0x11000 },
+ [GCC_USB_0_PHY_BCR] = { 0x50020 },
+ [GCC_USB_1_PHY_BCR] = { 0x2a020 },
+ [GCC_USB_2_PHY_BCR] = { 0xa3020 },
+ [GCC_VIDEO_BCR] = { 0x32000 },
+};
+
+static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = {
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s6_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s7_clk_src),
+};
+
+static const struct regmap_config gcc_x1e80100_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x1f41f0,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gcc_x1e80100_desc = {
+ .config = &gcc_x1e80100_regmap_config,
+ .clks = gcc_x1e80100_clocks,
+ .num_clks = ARRAY_SIZE(gcc_x1e80100_clocks),
+ .resets = gcc_x1e80100_resets,
+ .num_resets = ARRAY_SIZE(gcc_x1e80100_resets),
+ .gdscs = gcc_x1e80100_gdscs,
+ .num_gdscs = ARRAY_SIZE(gcc_x1e80100_gdscs),
+};
+
+static const struct of_device_id gcc_x1e80100_match_table[] = {
+ { .compatible = "qcom,x1e80100-gcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_x1e80100_match_table);
+
+static int gcc_x1e80100_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+ int ret;
+
+ regmap = qcom_cc_map(pdev, &gcc_x1e80100_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks,
+ ARRAY_SIZE(gcc_dfs_clocks));
+ if (ret)
+ return ret;
+
+ /* Keep the critical clock always-On */
+ regmap_update_bits(regmap, 0x26004, BIT(0), BIT(0)); /* gcc_camera_ahb_clk */
+ regmap_update_bits(regmap, 0x26028, BIT(0), BIT(0)); /* gcc_camera_xo_clk */
+ regmap_update_bits(regmap, 0x27004, BIT(0), BIT(0)); /* gcc_disp_ahb_clk */
+ regmap_update_bits(regmap, 0x27018, BIT(0), BIT(0)); /* gcc_disp_xo_clk */
+ regmap_update_bits(regmap, 0x32004, BIT(0), BIT(0)); /* gcc_video_ahb_clk */
+ regmap_update_bits(regmap, 0x32030, BIT(0), BIT(0)); /* gcc_video_xo_clk */
+ regmap_update_bits(regmap, 0x71004, BIT(0), BIT(0)); /* gcc_gpu_cfg_ahb_clk */
+
+ /* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */
+ regmap_write(regmap, 0x52224, 0x0);
+
+ return qcom_cc_really_probe(pdev, &gcc_x1e80100_desc, regmap);
+}
+
+static struct platform_driver gcc_x1e80100_driver = {
+ .probe = gcc_x1e80100_probe,
+ .driver = {
+ .name = "gcc-x1e80100",
+ .of_match_table = gcc_x1e80100_match_table,
+ },
+};
+
+static int __init gcc_x1e80100_init(void)
+{
+ return platform_driver_register(&gcc_x1e80100_driver);
+}
+subsys_initcall(gcc_x1e80100_init);
+
+static void __exit gcc_x1e80100_exit(void)
+{
+ platform_driver_unregister(&gcc_x1e80100_driver);
+}
+module_exit(gcc_x1e80100_exit);
+
+MODULE_DESCRIPTION("QTI GCC X1E80100 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/gpucc-sm8150.c b/drivers/clk/qcom/gpucc-sm8150.c
index 8422fd047493..c89a5b59ddb7 100644
--- a/drivers/clk/qcom/gpucc-sm8150.c
+++ b/drivers/clk/qcom/gpucc-sm8150.c
@@ -37,8 +37,8 @@ static struct alpha_pll_config gpu_cc_pll1_config = {
.config_ctl_hi_val = 0x00002267,
.config_ctl_hi1_val = 0x00000024,
.test_ctl_val = 0x00000000,
- .test_ctl_hi_val = 0x00000002,
- .test_ctl_hi1_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000000,
+ .test_ctl_hi1_val = 0x00000020,
.user_ctl_val = 0x00000000,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x000000d0,
diff --git a/drivers/clk/qcom/gpucc-sm8550.c b/drivers/clk/qcom/gpucc-sm8550.c
index 420dcb27b47d..2fa8673424d7 100644
--- a/drivers/clk/qcom/gpucc-sm8550.c
+++ b/drivers/clk/qcom/gpucc-sm8550.c
@@ -35,12 +35,12 @@ enum {
};
static const struct pll_vco lucid_ole_vco[] = {
- { 249600000, 2300000000, 0 },
+ { 249600000, 2000000000, 0 },
};
static const struct alpha_pll_config gpu_cc_pll0_config = {
- .l = 0x0d,
- .alpha = 0x0,
+ .l = 0x1e,
+ .alpha = 0xbaaa,
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00182261,
.config_ctl_hi1_val = 0x82aa299c,
diff --git a/drivers/clk/qcom/gpucc-sm8650.c b/drivers/clk/qcom/gpucc-sm8650.c
new file mode 100644
index 000000000000..03307e482aca
--- /dev/null
+++ b/drivers/clk/qcom/gpucc-sm8650.c
@@ -0,0 +1,663 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,sm8650-gpucc.h>
+#include <dt-bindings/reset/qcom,sm8650-gpucc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "clk-regmap-phy-mux.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+ DT_BI_TCXO,
+ DT_GPLL0_OUT_MAIN,
+ DT_GPLL0_OUT_MAIN_DIV,
+};
+
+enum {
+ P_BI_TCXO,
+ P_GPLL0_OUT_MAIN,
+ P_GPLL0_OUT_MAIN_DIV,
+ P_GPU_CC_PLL0_OUT_MAIN,
+ P_GPU_CC_PLL1_OUT_MAIN,
+};
+
+static struct pll_vco lucid_ole_vco[] = {
+ { 249600000, 2100000000, 0 },
+};
+
+static const struct alpha_pll_config gpu_cc_pll0_config = {
+ .l = 0x20,
+ .alpha = 0x4aaa,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll gpu_cc_pll0 = {
+ .offset = 0x0,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_pll0",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct alpha_pll_config gpu_cc_pll1_config = {
+ .l = 0x1b,
+ .alpha = 0x1555,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll gpu_cc_pll1 = {
+ .offset = 0x1000,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_pll1",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct parent_map gpu_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+};
+
+static const struct clk_parent_data gpu_cc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_GPLL0_OUT_MAIN },
+ { .index = DT_GPLL0_OUT_MAIN_DIV },
+};
+
+static const struct parent_map gpu_cc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPU_CC_PLL0_OUT_MAIN, 1 },
+ { P_GPU_CC_PLL1_OUT_MAIN, 3 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+};
+
+static const struct clk_parent_data gpu_cc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpu_cc_pll0.clkr.hw },
+ { .hw = &gpu_cc_pll1.clkr.hw },
+ { .index = DT_GPLL0_OUT_MAIN },
+ { .index = DT_GPLL0_OUT_MAIN_DIV },
+};
+
+static const struct parent_map gpu_cc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_GPU_CC_PLL1_OUT_MAIN, 3 },
+ { P_GPLL0_OUT_MAIN, 5 },
+ { P_GPLL0_OUT_MAIN_DIV, 6 },
+};
+
+static const struct clk_parent_data gpu_cc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gpu_cc_pll1.clkr.hw },
+ { .index = DT_GPLL0_OUT_MAIN },
+ { .index = DT_GPLL0_OUT_MAIN_DIV },
+};
+
+static const struct freq_tbl ftbl_gpu_cc_ff_clk_src[] = {
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gpu_cc_ff_clk_src = {
+ .cmd_rcgr = 0x9474,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gpu_cc_parent_map_0,
+ .freq_tbl = ftbl_gpu_cc_ff_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_ff_clk_src",
+ .parent_data = gpu_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(260000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0),
+ F(625000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gpu_cc_gmu_clk_src = {
+ .cmd_rcgr = 0x9318,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gpu_cc_parent_map_1,
+ .freq_tbl = ftbl_gpu_cc_gmu_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gmu_clk_src",
+ .parent_data = gpu_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gpu_cc_hub_clk_src[] = {
+ F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gpu_cc_hub_clk_src = {
+ .cmd_rcgr = 0x93ec,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gpu_cc_parent_map_2,
+ .freq_tbl = ftbl_gpu_cc_hub_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_hub_clk_src",
+ .parent_data = gpu_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gpu_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_regmap_div gpu_cc_hub_div_clk_src = {
+ .reg = 0x942c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpu_cc_hub_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpu_cc_hub_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch gpu_cc_ahb_clk = {
+ .halt_reg = 0x911c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x911c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpu_cc_hub_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_crc_ahb_clk = {
+ .halt_reg = 0x9120,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x9120,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_crc_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpu_cc_hub_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_accu_shift_clk = {
+ .halt_reg = 0x9160,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x9160,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gpu_cc_cx_accu_shift_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_ff_clk = {
+ .halt_reg = 0x914c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x914c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cx_ff_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpu_cc_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cx_gmu_clk = {
+ .halt_reg = 0x913c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x913c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cx_gmu_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpu_cc_gmu_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cxo_aon_clk = {
+ .halt_reg = 0x9004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x9004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cxo_aon_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_cxo_clk = {
+ .halt_reg = 0x9144,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9144,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_cxo_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_demet_clk = {
+ .halt_reg = 0x900c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x900c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_demet_clk",
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_freq_measure_clk = {
+ .halt_reg = 0x9008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9008,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_freq_measure_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_gx_gfx3d_clk = {
+ .halt_reg = 0x90a8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x90a8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gx_gfx3d_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_gx_gfx3d_rdvm_clk = {
+ .halt_reg = 0x90c8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x90c8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gx_gfx3d_rdvm_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_gx_gmu_clk = {
+ .halt_reg = 0x90bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x90bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gx_gmu_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpu_cc_gmu_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_gx_vsense_clk = {
+ .halt_reg = 0x90b0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x90b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_gx_vsense_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_gx_accu_shift_clk = {
+ .halt_reg = 0x90d0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x90d0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gpu_cc_gx_accu_shift_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_gx_ff_clk = {
+ .halt_reg = 0x90c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x90c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gpu_cc_gx_ff_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpu_cc_ff_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = {
+ .halt_reg = 0x7000,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_hlos1_vote_gpu_smmu_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_hub_aon_clk = {
+ .halt_reg = 0x93e8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x93e8,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_hub_aon_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpu_cc_hub_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_hub_cx_int_clk = {
+ .halt_reg = 0x9148,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x9148,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_hub_cx_int_clk",
+ .parent_hws = (const struct clk_hw*[]){
+ &gpu_cc_hub_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_aon_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_memnoc_gfx_clk = {
+ .halt_reg = 0x9150,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x9150,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_memnoc_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_sleep_clk = {
+ .halt_reg = 0x9134,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x9134,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gpu_cc_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gpu_cc_dpm_clk = {
+ .halt_reg = 0x9164,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x9164,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data){
+ .name = "gpu_cc_dpm_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc gpu_cx_gdsc = {
+ .gdscr = 0x9108,
+ .gds_hw_ctrl = 0x9168,
+ .clk_dis_wait_val = 8,
+ .pd = {
+ .name = "gpu_cx_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gpu_gx_gdsc = {
+ .gdscr = 0x905c,
+ .clamp_io_ctrl = 0x9504,
+ .resets = (unsigned int []){ GPUCC_GPU_CC_GX_BCR,
+ GPUCC_GPU_CC_ACD_BCR,
+ GPUCC_GPU_CC_GX_ACD_IROOT_BCR },
+ .reset_count = 3,
+ .pd = {
+ .name = "gpu_gx_gdsc",
+ .power_on = gdsc_gx_do_nothing_enable,
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = CLAMP_IO | AON_RESET | SW_RESET | POLL_CFG_GDSCR,
+};
+
+static struct clk_regmap *gpu_cc_sm8650_clocks[] = {
+ [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr,
+ [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr,
+ [GPU_CC_CX_ACCU_SHIFT_CLK] = &gpu_cc_cx_accu_shift_clk.clkr,
+ [GPU_CC_CX_FF_CLK] = &gpu_cc_cx_ff_clk.clkr,
+ [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr,
+ [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr,
+ [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr,
+ [GPU_CC_DEMET_CLK] = &gpu_cc_demet_clk.clkr,
+ [GPU_CC_DPM_CLK] = &gpu_cc_dpm_clk.clkr,
+ [GPU_CC_FF_CLK_SRC] = &gpu_cc_ff_clk_src.clkr,
+ [GPU_CC_FREQ_MEASURE_CLK] = &gpu_cc_freq_measure_clk.clkr,
+ [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr,
+ [GPU_CC_GX_ACCU_SHIFT_CLK] = &gpu_cc_gx_accu_shift_clk.clkr,
+ [GPU_CC_GX_FF_CLK] = &gpu_cc_gx_ff_clk.clkr,
+ [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr,
+ [GPU_CC_GX_GFX3D_RDVM_CLK] = &gpu_cc_gx_gfx3d_rdvm_clk.clkr,
+ [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr,
+ [GPU_CC_GX_VSENSE_CLK] = &gpu_cc_gx_vsense_clk.clkr,
+ [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr,
+ [GPU_CC_HUB_AON_CLK] = &gpu_cc_hub_aon_clk.clkr,
+ [GPU_CC_HUB_CLK_SRC] = &gpu_cc_hub_clk_src.clkr,
+ [GPU_CC_HUB_CX_INT_CLK] = &gpu_cc_hub_cx_int_clk.clkr,
+ [GPU_CC_HUB_DIV_CLK_SRC] = &gpu_cc_hub_div_clk_src.clkr,
+ [GPU_CC_MEMNOC_GFX_CLK] = &gpu_cc_memnoc_gfx_clk.clkr,
+ [GPU_CC_PLL0] = &gpu_cc_pll0.clkr,
+ [GPU_CC_PLL1] = &gpu_cc_pll1.clkr,
+ [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr,
+};
+
+static const struct qcom_reset_map gpu_cc_sm8650_resets[] = {
+ [GPUCC_GPU_CC_XO_BCR] = { 0x9000 },
+ [GPUCC_GPU_CC_GX_BCR] = { 0x9058 },
+ [GPUCC_GPU_CC_CX_BCR] = { 0x9104 },
+ [GPUCC_GPU_CC_GFX3D_AON_BCR] = { 0x9198 },
+ [GPUCC_GPU_CC_ACD_BCR] = { 0x9358 },
+ [GPUCC_GPU_CC_FAST_HUB_BCR] = { 0x93e4 },
+ [GPUCC_GPU_CC_FF_BCR] = { 0x9470 },
+ [GPUCC_GPU_CC_GMU_BCR] = { 0x9314 },
+ [GPUCC_GPU_CC_GX_ACD_IROOT_BCR] = { 0x958c },
+};
+
+static struct gdsc *gpu_cc_sm8650_gdscs[] = {
+ [GPU_CX_GDSC] = &gpu_cx_gdsc,
+ [GPU_GX_GDSC] = &gpu_gx_gdsc,
+};
+
+static const struct regmap_config gpu_cc_sm8650_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xa000,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc gpu_cc_sm8650_desc = {
+ .config = &gpu_cc_sm8650_regmap_config,
+ .clks = gpu_cc_sm8650_clocks,
+ .num_clks = ARRAY_SIZE(gpu_cc_sm8650_clocks),
+ .resets = gpu_cc_sm8650_resets,
+ .num_resets = ARRAY_SIZE(gpu_cc_sm8650_resets),
+ .gdscs = gpu_cc_sm8650_gdscs,
+ .num_gdscs = ARRAY_SIZE(gpu_cc_sm8650_gdscs),
+};
+
+static const struct of_device_id gpu_cc_sm8650_match_table[] = {
+ { .compatible = "qcom,sm8650-gpucc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gpu_cc_sm8650_match_table);
+
+static int gpu_cc_sm8650_probe(struct platform_device *pdev)
+{
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &gpu_cc_sm8650_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ clk_lucid_ole_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config);
+ clk_lucid_ole_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config);
+
+ return qcom_cc_really_probe(pdev, &gpu_cc_sm8650_desc, regmap);
+}
+
+static struct platform_driver gpu_cc_sm8650_driver = {
+ .probe = gpu_cc_sm8650_probe,
+ .driver = {
+ .name = "sm8650-gpucc",
+ .of_match_table = gpu_cc_sm8650_match_table,
+ },
+};
+module_platform_driver(gpu_cc_sm8650_driver);
+
+MODULE_DESCRIPTION("QTI GPU_CC SM8650 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/tcsrcc-sm8650.c b/drivers/clk/qcom/tcsrcc-sm8650.c
new file mode 100644
index 000000000000..11c7d6df48c7
--- /dev/null
+++ b/drivers/clk/qcom/tcsrcc-sm8650.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,sm8650-tcsr.h>
+
+#include "clk-branch.h"
+#include "clk-regmap.h"
+#include "common.h"
+#include "reset.h"
+
+enum {
+ DT_BI_TCXO_PAD,
+};
+
+static struct clk_branch tcsr_pcie_0_clkref_en = {
+ .halt_reg = 0x31100,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x31100,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "tcsr_pcie_0_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_pcie_1_clkref_en = {
+ .halt_reg = 0x31114,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x31114,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "tcsr_pcie_1_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_ufs_clkref_en = {
+ .halt_reg = 0x31110,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x31110,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "tcsr_ufs_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_ufs_pad_clkref_en = {
+ .halt_reg = 0x31104,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x31104,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "tcsr_ufs_pad_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_usb2_clkref_en = {
+ .halt_reg = 0x31118,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x31118,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "tcsr_usb2_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_usb3_clkref_en = {
+ .halt_reg = 0x31108,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x31108,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "tcsr_usb3_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *tcsr_cc_sm8650_clocks[] = {
+ [TCSR_PCIE_0_CLKREF_EN] = &tcsr_pcie_0_clkref_en.clkr,
+ [TCSR_PCIE_1_CLKREF_EN] = &tcsr_pcie_1_clkref_en.clkr,
+ [TCSR_UFS_CLKREF_EN] = &tcsr_ufs_clkref_en.clkr,
+ [TCSR_UFS_PAD_CLKREF_EN] = &tcsr_ufs_pad_clkref_en.clkr,
+ [TCSR_USB2_CLKREF_EN] = &tcsr_usb2_clkref_en.clkr,
+ [TCSR_USB3_CLKREF_EN] = &tcsr_usb3_clkref_en.clkr,
+};
+
+static const struct regmap_config tcsr_cc_sm8650_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x3b000,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc tcsr_cc_sm8650_desc = {
+ .config = &tcsr_cc_sm8650_regmap_config,
+ .clks = tcsr_cc_sm8650_clocks,
+ .num_clks = ARRAY_SIZE(tcsr_cc_sm8650_clocks),
+};
+
+static const struct of_device_id tcsr_cc_sm8650_match_table[] = {
+ { .compatible = "qcom,sm8650-tcsr" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tcsr_cc_sm8650_match_table);
+
+static int tcsr_cc_sm8650_probe(struct platform_device *pdev)
+{
+ return qcom_cc_probe(pdev, &tcsr_cc_sm8650_desc);
+}
+
+static struct platform_driver tcsr_cc_sm8650_driver = {
+ .probe = tcsr_cc_sm8650_probe,
+ .driver = {
+ .name = "tcsr_cc-sm8650",
+ .of_match_table = tcsr_cc_sm8650_match_table,
+ },
+};
+
+static int __init tcsr_cc_sm8650_init(void)
+{
+ return platform_driver_register(&tcsr_cc_sm8650_driver);
+}
+subsys_initcall(tcsr_cc_sm8650_init);
+
+static void __exit tcsr_cc_sm8650_exit(void)
+{
+ platform_driver_unregister(&tcsr_cc_sm8650_driver);
+}
+module_exit(tcsr_cc_sm8650_exit);
+
+MODULE_DESCRIPTION("QTI TCSRCC SM8650 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/videocc-sm8150.c b/drivers/clk/qcom/videocc-sm8150.c
index 1afdbe4a249d..f1456eaa87c4 100644
--- a/drivers/clk/qcom/videocc-sm8150.c
+++ b/drivers/clk/qcom/videocc-sm8150.c
@@ -6,6 +6,7 @@
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <dt-bindings/clock/qcom,videocc-sm8150.h>
@@ -33,6 +34,7 @@ static struct alpha_pll_config video_pll0_config = {
.config_ctl_val = 0x20485699,
.config_ctl_hi_val = 0x00002267,
.config_ctl_hi1_val = 0x00000024,
+ .test_ctl_hi1_val = 0x00000020,
.user_ctl_val = 0x00000000,
.user_ctl_hi_val = 0x00000805,
.user_ctl_hi1_val = 0x000000D0,
@@ -214,6 +216,10 @@ static const struct regmap_config video_cc_sm8150_regmap_config = {
static const struct qcom_reset_map video_cc_sm8150_resets[] = {
[VIDEO_CC_MVSC_CORE_CLK_BCR] = { 0x850, 2 },
+ [VIDEO_CC_INTERFACE_BCR] = { 0x8f0 },
+ [VIDEO_CC_MVS0_BCR] = { 0x870 },
+ [VIDEO_CC_MVS1_BCR] = { 0x8b0 },
+ [VIDEO_CC_MVSC_BCR] = { 0x810 },
};
static const struct qcom_cc_desc video_cc_sm8150_desc = {
@@ -235,17 +241,32 @@ MODULE_DEVICE_TABLE(of, video_cc_sm8150_match_table);
static int video_cc_sm8150_probe(struct platform_device *pdev)
{
struct regmap *regmap;
+ int ret;
+
+ ret = devm_pm_runtime_enable(&pdev->dev);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret)
+ return ret;
regmap = qcom_cc_map(pdev, &video_cc_sm8150_desc);
- if (IS_ERR(regmap))
+ if (IS_ERR(regmap)) {
+ pm_runtime_put_sync(&pdev->dev);
return PTR_ERR(regmap);
+ }
clk_trion_pll_configure(&video_pll0, regmap, &video_pll0_config);
/* Keep VIDEO_CC_XO_CLK ALWAYS-ON */
regmap_update_bits(regmap, 0x984, 0x1, 0x1);
- return qcom_cc_really_probe(pdev, &video_cc_sm8150_desc, regmap);
+ ret = qcom_cc_really_probe(pdev, &video_cc_sm8150_desc, regmap);
+
+ pm_runtime_put_sync(&pdev->dev);
+
+ return ret;
}
static struct platform_driver video_cc_sm8150_driver = {
diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c
index 7cc580d67362..5974adcef3ed 100644
--- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c
@@ -192,6 +192,8 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
DEF_MOD("msi3", 621, R8A779G0_CLK_MSO),
DEF_MOD("msi4", 622, R8A779G0_CLK_MSO),
DEF_MOD("msi5", 623, R8A779G0_CLK_MSO),
+ DEF_MOD("pciec0", 624, R8A779G0_CLK_S0D2_HSC),
+ DEF_MOD("pscie1", 625, R8A779G0_CLK_S0D2_HSC),
DEF_MOD("pwm", 628, R8A779G0_CLK_SASYNCPERD4),
DEF_MOD("rpc-if", 629, R8A779G0_CLK_RPCD2),
DEF_MOD("scif0", 702, R8A779G0_CLK_SASYNCPERD4),
@@ -235,6 +237,7 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
DEF_MOD("pfc2", 917, R8A779G0_CLK_CL16M),
DEF_MOD("pfc3", 918, R8A779G0_CLK_CL16M),
DEF_MOD("tsc", 919, R8A779G0_CLK_CL16M),
+ DEF_MOD("tsn", 2723, R8A779G0_CLK_S0D4_HSC),
DEF_MOD("ssiu", 2926, R8A779G0_CLK_S0D6_PER),
DEF_MOD("ssi", 2927, R8A779G0_CLK_S0D6_PER),
};
diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c
index 4394cb241d99..2582ba95256e 100644
--- a/drivers/clk/renesas/r9a08g045-cpg.c
+++ b/drivers/clk/renesas/r9a08g045-cpg.c
@@ -181,13 +181,16 @@ static const struct cpg_core_clk r9a08g045_core_clks[] __initconst = {
DEF_G3S_DIV("P3", R9A08G045_CLK_P3, CLK_PLL3_DIV2_4, DIVPL3C, G3S_DIVPL3C_STS,
dtable_1_32, 0, 0, 0, NULL),
DEF_FIXED("P3_DIV2", CLK_P3_DIV2, R9A08G045_CLK_P3, 1, 2),
+ DEF_FIXED("ZT", R9A08G045_CLK_ZT, CLK_PLL3_DIV2_8, 1, 1),
DEF_FIXED("S0", R9A08G045_CLK_S0, CLK_SEL_PLL4, 1, 2),
DEF_FIXED("OSC", R9A08G045_OSCCLK, CLK_EXTAL, 1, 1),
DEF_FIXED("OSC2", R9A08G045_OSCCLK2, CLK_EXTAL, 1, 3),
+ DEF_FIXED("HP", R9A08G045_CLK_HP, CLK_PLL6, 1, 2),
};
static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = {
DEF_MOD("gic_gicclk", R9A08G045_GIC600_GICCLK, R9A08G045_CLK_P1, 0x514, 0),
+ DEF_MOD("ia55_pclk", R9A08G045_IA55_PCLK, R9A08G045_CLK_P2, 0x518, 0),
DEF_MOD("ia55_clk", R9A08G045_IA55_CLK, R9A08G045_CLK_P1, 0x518, 1),
DEF_MOD("dmac_aclk", R9A08G045_DMAC_ACLK, R9A08G045_CLK_P3, 0x52c, 0),
DEF_MOD("sdhi0_imclk", R9A08G045_SDHI0_IMCLK, CLK_SD0_DIV4, 0x554, 0),
@@ -202,6 +205,12 @@ static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = {
DEF_MOD("sdhi2_imclk2", R9A08G045_SDHI2_IMCLK2, CLK_SD2_DIV4, 0x554, 9),
DEF_MOD("sdhi2_clk_hs", R9A08G045_SDHI2_CLK_HS, R9A08G045_CLK_SD2, 0x554, 10),
DEF_MOD("sdhi2_aclk", R9A08G045_SDHI2_ACLK, R9A08G045_CLK_P1, 0x554, 11),
+ DEF_COUPLED("eth0_axi", R9A08G045_ETH0_CLK_AXI, R9A08G045_CLK_M0, 0x57c, 0),
+ DEF_COUPLED("eth0_chi", R9A08G045_ETH0_CLK_CHI, R9A08G045_CLK_ZT, 0x57c, 0),
+ DEF_MOD("eth0_refclk", R9A08G045_ETH0_REFCLK, R9A08G045_CLK_HP, 0x57c, 8),
+ DEF_COUPLED("eth1_axi", R9A08G045_ETH1_CLK_AXI, R9A08G045_CLK_M0, 0x57c, 1),
+ DEF_COUPLED("eth1_chi", R9A08G045_ETH1_CLK_CHI, R9A08G045_CLK_ZT, 0x57c, 1),
+ DEF_MOD("eth1_refclk", R9A08G045_ETH1_REFCLK, R9A08G045_CLK_HP, 0x57c, 9),
DEF_MOD("scif0_clk_pck", R9A08G045_SCIF0_CLK_PCK, R9A08G045_CLK_P0, 0x584, 0),
DEF_MOD("gpio_hclk", R9A08G045_GPIO_HCLK, R9A08G045_OSCCLK, 0x598, 0),
};
@@ -209,9 +218,12 @@ static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = {
static const struct rzg2l_reset r9a08g045_resets[] = {
DEF_RST(R9A08G045_GIC600_GICRESET_N, 0x814, 0),
DEF_RST(R9A08G045_GIC600_DBG_GICRESET_N, 0x814, 1),
+ DEF_RST(R9A08G045_IA55_RESETN, 0x818, 0),
DEF_RST(R9A08G045_SDHI0_IXRST, 0x854, 0),
DEF_RST(R9A08G045_SDHI1_IXRST, 0x854, 1),
DEF_RST(R9A08G045_SDHI2_IXRST, 0x854, 2),
+ DEF_RST(R9A08G045_ETH0_RST_HW_N, 0x87c, 0),
+ DEF_RST(R9A08G045_ETH1_RST_HW_N, 0x87c, 1),
DEF_RST(R9A08G045_SCIF0_RST_SYSTEM_N, 0x884, 0),
DEF_RST(R9A08G045_GPIO_RSTN, 0x898, 0),
DEF_RST(R9A08G045_GPIO_PORT_RESETN, 0x898, 1),
@@ -220,6 +232,7 @@ static const struct rzg2l_reset r9a08g045_resets[] = {
static const unsigned int r9a08g045_crit_mod_clks[] __initconst = {
MOD_CLK_BASE + R9A08G045_GIC600_GICCLK,
+ MOD_CLK_BASE + R9A08G045_IA55_PCLK,
MOD_CLK_BASE + R9A08G045_IA55_CLK,
MOD_CLK_BASE + R9A08G045_DMAC_ACLK,
};
diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c
index 764bd72cf059..3d2daa4ba2a4 100644
--- a/drivers/clk/renesas/rzg2l-cpg.c
+++ b/drivers/clk/renesas/rzg2l-cpg.c
@@ -1410,41 +1410,33 @@ fail:
#define rcdev_to_priv(x) container_of(x, struct rzg2l_cpg_priv, rcdev)
-static int rzg2l_cpg_reset(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev);
- const struct rzg2l_cpg_info *info = priv->info;
- unsigned int reg = info->resets[id].off;
- u32 dis = BIT(info->resets[id].bit);
- u32 we = dis << 16;
-
- dev_dbg(rcdev->dev, "reset id:%ld offset:0x%x\n", id, CLK_RST_R(reg));
-
- /* Reset module */
- writel(we, priv->base + CLK_RST_R(reg));
-
- /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */
- udelay(35);
-
- /* Release module from reset state */
- writel(we | dis, priv->base + CLK_RST_R(reg));
-
- return 0;
-}
-
static int rzg2l_cpg_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev);
const struct rzg2l_cpg_info *info = priv->info;
unsigned int reg = info->resets[id].off;
- u32 value = BIT(info->resets[id].bit) << 16;
+ u32 mask = BIT(info->resets[id].bit);
+ s8 monbit = info->resets[id].monbit;
+ u32 value = mask << 16;
dev_dbg(rcdev->dev, "assert id:%ld offset:0x%x\n", id, CLK_RST_R(reg));
writel(value, priv->base + CLK_RST_R(reg));
- return 0;
+
+ if (info->has_clk_mon_regs) {
+ reg = CLK_MRST_R(reg);
+ } else if (monbit >= 0) {
+ reg = CPG_RST_MON;
+ mask = BIT(monbit);
+ } else {
+ /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */
+ udelay(35);
+ return 0;
+ }
+
+ return readl_poll_timeout_atomic(priv->base + reg, value,
+ value & mask, 10, 200);
}
static int rzg2l_cpg_deassert(struct reset_controller_dev *rcdev,
@@ -1453,14 +1445,40 @@ static int rzg2l_cpg_deassert(struct reset_controller_dev *rcdev,
struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev);
const struct rzg2l_cpg_info *info = priv->info;
unsigned int reg = info->resets[id].off;
- u32 dis = BIT(info->resets[id].bit);
- u32 value = (dis << 16) | dis;
+ u32 mask = BIT(info->resets[id].bit);
+ s8 monbit = info->resets[id].monbit;
+ u32 value = (mask << 16) | mask;
dev_dbg(rcdev->dev, "deassert id:%ld offset:0x%x\n", id,
CLK_RST_R(reg));
writel(value, priv->base + CLK_RST_R(reg));
- return 0;
+
+ if (info->has_clk_mon_regs) {
+ reg = CLK_MRST_R(reg);
+ } else if (monbit >= 0) {
+ reg = CPG_RST_MON;
+ mask = BIT(monbit);
+ } else {
+ /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */
+ udelay(35);
+ return 0;
+ }
+
+ return readl_poll_timeout_atomic(priv->base + reg, value,
+ !(value & mask), 10, 200);
+}
+
+static int rzg2l_cpg_reset(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ int ret;
+
+ ret = rzg2l_cpg_assert(rcdev, id);
+ if (ret)
+ return ret;
+
+ return rzg2l_cpg_deassert(rcdev, id);
}
static int rzg2l_cpg_status(struct reset_controller_dev *rcdev,
@@ -1468,18 +1486,21 @@ static int rzg2l_cpg_status(struct reset_controller_dev *rcdev,
{
struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev);
const struct rzg2l_cpg_info *info = priv->info;
- unsigned int reg = info->resets[id].off;
- u32 bitmask = BIT(info->resets[id].bit);
s8 monbit = info->resets[id].monbit;
+ unsigned int reg;
+ u32 bitmask;
if (info->has_clk_mon_regs) {
- return !!(readl(priv->base + CLK_MRST_R(reg)) & bitmask);
+ reg = CLK_MRST_R(info->resets[id].off);
+ bitmask = BIT(info->resets[id].bit);
} else if (monbit >= 0) {
- u32 monbitmask = BIT(monbit);
-
- return !!(readl(priv->base + CPG_RST_MON) & monbitmask);
+ reg = CPG_RST_MON;
+ bitmask = BIT(monbit);
+ } else {
+ return -ENOTSUPP;
}
- return -ENOTSUPP;
+
+ return !!(readl(priv->base + reg) & bitmask);
}
static const struct reset_control_ops rzg2l_cpg_reset_ops = {
diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c
index db713e1526cd..b786ddc9af2a 100644
--- a/drivers/clk/rockchip/clk-rk3568.c
+++ b/drivers/clk/rockchip/clk-rk3568.c
@@ -78,7 +78,9 @@ static struct rockchip_pll_rate_table rk3568_pll_rates[] = {
RK3036_PLL_RATE(200000000, 1, 100, 3, 4, 1, 0),
RK3036_PLL_RATE(148500000, 1, 99, 4, 4, 1, 0),
RK3036_PLL_RATE(135000000, 2, 45, 4, 1, 1, 0),
+ RK3036_PLL_RATE(126400000, 1, 79, 5, 3, 1, 0),
RK3036_PLL_RATE(119000000, 3, 119, 4, 2, 1, 0),
+ RK3036_PLL_RATE(115200000, 1, 24, 5, 1, 1, 0),
RK3036_PLL_RATE(108000000, 2, 45, 5, 1, 1, 0),
RK3036_PLL_RATE(101000000, 1, 101, 6, 4, 1, 0),
RK3036_PLL_RATE(100000000, 1, 150, 6, 6, 1, 0),
@@ -1593,6 +1595,7 @@ static const char *const rk3568_cru_critical_clocks[] __initconst = {
"hclk_php",
"pclk_php",
"hclk_usb",
+ "pclk_usb",
"hclk_vo",
};
diff --git a/drivers/clk/samsung/clk-cpu.h b/drivers/clk/samsung/clk-cpu.h
index fc9f67a3b22e..0164bd9ad021 100644
--- a/drivers/clk/samsung/clk-cpu.h
+++ b/drivers/clk/samsung/clk-cpu.h
@@ -11,10 +11,10 @@
#include "clk.h"
/**
- * struct exynos_cpuclk_data: config data to setup cpu clocks.
- * @prate: frequency of the primary parent clock (in KHz).
- * @div0: value to be programmed in the div_cpu0 register.
- * @div1: value to be programmed in the div_cpu1 register.
+ * struct exynos_cpuclk_cfg_data - config data to setup cpu clocks
+ * @prate: frequency of the primary parent clock (in KHz)
+ * @div0: value to be programmed in the div_cpu0 register
+ * @div1: value to be programmed in the div_cpu1 register
*
* This structure holds the divider configuration data for dividers in the CPU
* clock domain. The parent frequency at which these divider values are valid is
@@ -29,17 +29,17 @@ struct exynos_cpuclk_cfg_data {
};
/**
- * struct exynos_cpuclk: information about clock supplied to a CPU core.
- * @hw: handle between CCF and CPU clock.
- * @alt_parent: alternate parent clock to use when switching the speed
- * of the primary parent clock.
- * @ctrl_base: base address of the clock controller.
- * @lock: cpu clock domain register access lock.
- * @cfg: cpu clock rate configuration data.
- * @num_cfgs: number of array elements in @cfg array.
- * @clk_nb: clock notifier registered for changes in clock speed of the
- * primary parent clock.
- * @flags: configuration flags for the CPU clock.
+ * struct exynos_cpuclk - information about clock supplied to a CPU core
+ * @hw: handle between CCF and CPU clock
+ * @alt_parent: alternate parent clock to use when switching the speed
+ * of the primary parent clock
+ * @ctrl_base: base address of the clock controller
+ * @lock: cpu clock domain register access lock
+ * @cfg: cpu clock rate configuration data
+ * @num_cfgs: number of array elements in @cfg array
+ * @clk_nb: clock notifier registered for changes in clock speed of the
+ * primary parent clock
+ * @flags: configuration flags for the CPU clock
*
* This structure holds information required for programming the CPU clock for
* various clock speeds.
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index ab9c3d7a25b3..516b716407e5 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -14,11 +14,11 @@
#include "clk-pll.h"
/**
- * struct samsung_clk_provider: information about clock provider
- * @reg_base: virtual address for the register base.
- * @dev: clock provider device needed for runtime PM.
- * @lock: maintains exclusion between callbacks for a given clock-provider.
- * @clk_data: holds clock related data like clk_hw* and number of clocks.
+ * struct samsung_clk_provider - information about clock provider
+ * @reg_base: virtual address for the register base
+ * @dev: clock provider device needed for runtime PM
+ * @lock: maintains exclusion between callbacks for a given clock-provider
+ * @clk_data: holds clock related data like clk_hw* and number of clocks
*/
struct samsung_clk_provider {
void __iomem *reg_base;
@@ -29,10 +29,10 @@ struct samsung_clk_provider {
};
/**
- * struct samsung_clock_alias: information about mux clock
- * @id: platform specific id of the clock.
- * @dev_name: name of the device to which this clock belongs.
- * @alias: optional clock alias name to be assigned to this clock.
+ * struct samsung_clock_alias - information about mux clock
+ * @id: platform specific id of the clock
+ * @dev_name: name of the device to which this clock belongs
+ * @alias: optional clock alias name to be assigned to this clock
*/
struct samsung_clock_alias {
unsigned int id;
@@ -50,12 +50,12 @@ struct samsung_clock_alias {
#define MHZ (1000 * 1000)
/**
- * struct samsung_fixed_rate_clock: information about fixed-rate clock
- * @id: platform specific id of the clock.
- * @name: name of this fixed-rate clock.
- * @parent_name: optional parent clock name.
- * @flags: optional fixed-rate clock flags.
- * @fixed-rate: fixed clock rate of this clock.
+ * struct samsung_fixed_rate_clock - information about fixed-rate clock
+ * @id: platform specific id of the clock
+ * @name: name of this fixed-rate clock
+ * @parent_name: optional parent clock name
+ * @flags: optional fixed-rate clock flags
+ * @fixed_rate: fixed clock rate of this clock
*/
struct samsung_fixed_rate_clock {
unsigned int id;
@@ -74,14 +74,14 @@ struct samsung_fixed_rate_clock {
.fixed_rate = frate, \
}
-/*
- * struct samsung_fixed_factor_clock: information about fixed-factor clock
- * @id: platform specific id of the clock.
- * @name: name of this fixed-factor clock.
- * @parent_name: parent clock name.
- * @mult: fixed multiplication factor.
- * @div: fixed division factor.
- * @flags: optional fixed-factor clock flags.
+/**
+ * struct samsung_fixed_factor_clock - information about fixed-factor clock
+ * @id: platform specific id of the clock
+ * @name: name of this fixed-factor clock
+ * @parent_name: parent clock name
+ * @mult: fixed multiplication factor
+ * @div: fixed division factor
+ * @flags: optional fixed-factor clock flags
*/
struct samsung_fixed_factor_clock {
unsigned int id;
@@ -103,16 +103,16 @@ struct samsung_fixed_factor_clock {
}
/**
- * struct samsung_mux_clock: information about mux clock
- * @id: platform specific id of the clock.
- * @name: name of this mux clock.
- * @parent_names: array of pointer to parent clock names.
- * @num_parents: number of parents listed in @parent_names.
- * @flags: optional flags for basic clock.
- * @offset: offset of the register for configuring the mux.
- * @shift: starting bit location of the mux control bit-field in @reg.
- * @width: width of the mux control bit-field in @reg.
- * @mux_flags: flags for mux-type clock.
+ * struct samsung_mux_clock - information about mux clock
+ * @id: platform specific id of the clock
+ * @name: name of this mux clock
+ * @parent_names: array of pointer to parent clock names
+ * @num_parents: number of parents listed in @parent_names
+ * @flags: optional flags for basic clock
+ * @offset: offset of the register for configuring the mux
+ * @shift: starting bit location of the mux control bit-field in @reg
+ * @width: width of the mux control bit-field in @reg
+ * @mux_flags: flags for mux-type clock
*/
struct samsung_mux_clock {
unsigned int id;
@@ -146,14 +146,16 @@ struct samsung_mux_clock {
__MUX(_id, cname, pnames, o, s, w, f, mf)
/**
- * @id: platform specific id of the clock.
- * struct samsung_div_clock: information about div clock
- * @name: name of this div clock.
- * @parent_name: name of the parent clock.
- * @flags: optional flags for basic clock.
- * @offset: offset of the register for configuring the div.
- * @shift: starting bit location of the div control bit-field in @reg.
- * @div_flags: flags for div-type clock.
+ * struct samsung_div_clock - information about div clock
+ * @id: platform specific id of the clock
+ * @name: name of this div clock
+ * @parent_name: name of the parent clock
+ * @flags: optional flags for basic clock
+ * @offset: offset of the register for configuring the div
+ * @shift: starting bit location of the div control bit-field in @reg
+ * @width: width of the bitfield
+ * @div_flags: flags for div-type clock
+ * @table: array of divider/value pairs ending with a div set to 0
*/
struct samsung_div_clock {
unsigned int id;
@@ -190,14 +192,14 @@ struct samsung_div_clock {
__DIV(_id, cname, pname, o, s, w, 0, 0, t)
/**
- * struct samsung_gate_clock: information about gate clock
- * @id: platform specific id of the clock.
- * @name: name of this gate clock.
- * @parent_name: name of the parent clock.
- * @flags: optional flags for basic clock.
- * @offset: offset of the register for configuring the gate.
- * @bit_idx: bit index of the gate control bit-field in @reg.
- * @gate_flags: flags for gate-type clock.
+ * struct samsung_gate_clock - information about gate clock
+ * @id: platform specific id of the clock
+ * @name: name of this gate clock
+ * @parent_name: name of the parent clock
+ * @flags: optional flags for basic clock
+ * @offset: offset of the register for configuring the gate
+ * @bit_idx: bit index of the gate control bit-field in @reg
+ * @gate_flags: flags for gate-type clock
*/
struct samsung_gate_clock {
unsigned int id;
@@ -226,9 +228,9 @@ struct samsung_gate_clock {
#define PNAME(x) static const char * const x[] __initconst
/**
- * struct samsung_clk_reg_dump: register dump of clock controller registers.
- * @offset: clock register offset from the controller base address.
- * @value: the value to be register at offset.
+ * struct samsung_clk_reg_dump - register dump of clock controller registers
+ * @offset: clock register offset from the controller base address
+ * @value: the value to be register at offset
*/
struct samsung_clk_reg_dump {
u32 offset;
@@ -236,14 +238,15 @@ struct samsung_clk_reg_dump {
};
/**
- * struct samsung_pll_clock: information about pll clock
- * @id: platform specific id of the clock.
- * @name: name of this pll clock.
- * @parent_name: name of the parent clock.
- * @flags: optional flags for basic clock.
- * @con_offset: offset of the register for configuring the PLL.
- * @lock_offset: offset of the register for locking the PLL.
- * @type: Type of PLL to be registered.
+ * struct samsung_pll_clock - information about pll clock
+ * @id: platform specific id of the clock
+ * @name: name of this pll clock
+ * @parent_name: name of the parent clock
+ * @flags: optional flags for basic clock
+ * @con_offset: offset of the register for configuring the PLL
+ * @lock_offset: offset of the register for locking the PLL
+ * @type: type of PLL to be registered
+ * @rate_table: array of PLL settings for possible PLL rates
*/
struct samsung_pll_clock {
unsigned int id;
@@ -302,39 +305,51 @@ struct samsung_clock_reg_cache {
unsigned int rsuspend_num;
};
+/**
+ * struct samsung_cmu_info - all clocks information needed for CMU registration
+ * @pll_clks: list of PLL clocks
+ * @nr_pll_clks: count of clocks in @pll_clks
+ * @mux_clks: list of mux clocks
+ * @nr_mux_clks: count of clocks in @mux_clks
+ * @div_clks: list of div clocks
+ * @nr_div_clks: count of clocks in @div_clks
+ * @gate_clks: list of gate clocks
+ * @nr_gate_clks: count of clocks in @gate_clks
+ * @fixed_clks: list of fixed clocks
+ * @nr_fixed_clks: count clocks in @fixed_clks
+ * @fixed_factor_clks: list of fixed factor clocks
+ * @nr_fixed_factor_clks: count of clocks in @fixed_factor_clks
+ * @nr_clk_ids: total number of clocks with IDs assigned
+ * @cpu_clks: list of CPU clocks
+ * @nr_cpu_clks: count of clocks in @cpu_clks
+ * @clk_regs: list of clock registers
+ * @nr_clk_regs: count of clock registers in @clk_regs
+ * @suspend_regs: list of clock registers to set before suspend
+ * @nr_suspend_regs: count of clock registers in @suspend_regs
+ * @clk_name: name of the parent clock needed for CMU register access
+ */
struct samsung_cmu_info {
- /* list of pll clocks and respective count */
const struct samsung_pll_clock *pll_clks;
unsigned int nr_pll_clks;
- /* list of mux clocks and respective count */
const struct samsung_mux_clock *mux_clks;
unsigned int nr_mux_clks;
- /* list of div clocks and respective count */
const struct samsung_div_clock *div_clks;
unsigned int nr_div_clks;
- /* list of gate clocks and respective count */
const struct samsung_gate_clock *gate_clks;
unsigned int nr_gate_clks;
- /* list of fixed clocks and respective count */
const struct samsung_fixed_rate_clock *fixed_clks;
unsigned int nr_fixed_clks;
- /* list of fixed factor clocks and respective count */
const struct samsung_fixed_factor_clock *fixed_factor_clks;
unsigned int nr_fixed_factor_clks;
- /* total number of clocks with IDs assigned*/
unsigned int nr_clk_ids;
- /* list of cpu clocks and respective count */
const struct samsung_cpu_clock *cpu_clks;
unsigned int nr_cpu_clks;
- /* list and number of clocks registers */
const unsigned long *clk_regs;
unsigned int nr_clk_regs;
- /* list and number of clocks registers to set before suspend */
const struct samsung_clk_reg_dump *suspend_regs;
unsigned int nr_suspend_regs;
- /* name of the parent clock needed for CMU register access */
const char *clk_name;
};
diff --git a/drivers/clk/starfive/clk-starfive-jh7100-audio.c b/drivers/clk/starfive/clk-starfive-jh7100-audio.c
index ee4bda14a40e..1fcf4e62f347 100644
--- a/drivers/clk/starfive/clk-starfive-jh7100-audio.c
+++ b/drivers/clk/starfive/clk-starfive-jh7100-audio.c
@@ -79,7 +79,7 @@ static const struct jh71x0_clk_data jh7100_audclk_data[] = {
JH71X0_GDIV(JH7100_AUDCLK_USB_LPM, "usb_lpm", CLK_IGNORE_UNUSED, 4, JH7100_AUDCLK_USB_APB),
JH71X0_GDIV(JH7100_AUDCLK_USB_STB, "usb_stb", CLK_IGNORE_UNUSED, 3, JH7100_AUDCLK_USB_APB),
JH71X0__DIV(JH7100_AUDCLK_APB_EN, "apb_en", 8, JH7100_AUDCLK_DOM7AHB_BUS),
- JH71X0__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 2,
+ JH71X0__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 0, 2,
JH7100_AUDCLK_VAD_INTMEM,
JH7100_AUDCLK_AUDIO_12288),
};
diff --git a/drivers/clk/starfive/clk-starfive-jh7100.c b/drivers/clk/starfive/clk-starfive-jh7100.c
index 69cc11ea7e33..03f6f26a15d8 100644
--- a/drivers/clk/starfive/clk-starfive-jh7100.c
+++ b/drivers/clk/starfive/clk-starfive-jh7100.c
@@ -24,48 +24,48 @@
#define JH7100_CLK_GMAC_GR_MII_RX (JH7100_CLK_END + 3)
static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = {
- JH71X0__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 4,
+ JH71X0__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 0, 4,
JH7100_CLK_OSC_SYS,
JH7100_CLK_PLL0_OUT,
JH7100_CLK_PLL1_OUT,
JH7100_CLK_PLL2_OUT),
- JH71X0__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 3,
+ JH71X0__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 0, 3,
JH7100_CLK_OSC_SYS,
JH7100_CLK_PLL1_OUT,
JH7100_CLK_PLL2_OUT),
- JH71X0__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 4,
+ JH71X0__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 0, 4,
JH7100_CLK_OSC_SYS,
JH7100_CLK_PLL0_OUT,
JH7100_CLK_PLL1_OUT,
JH7100_CLK_PLL2_OUT),
- JH71X0__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 3,
+ JH71X0__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 0, 3,
JH7100_CLK_OSC_SYS,
JH7100_CLK_PLL0_OUT,
JH7100_CLK_PLL2_OUT),
- JH71X0__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 2,
+ JH71X0__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 0, 2,
JH7100_CLK_OSC_SYS,
JH7100_CLK_PLL0_OUT),
- JH71X0__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 2,
+ JH71X0__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 0, 2,
JH7100_CLK_OSC_SYS,
JH7100_CLK_PLL2_OUT),
- JH71X0__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 3,
+ JH71X0__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 0, 3,
JH7100_CLK_OSC_SYS,
JH7100_CLK_PLL1_OUT,
JH7100_CLK_PLL2_OUT),
- JH71X0__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 3,
+ JH71X0__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 0, 3,
JH7100_CLK_OSC_AUD,
JH7100_CLK_PLL0_OUT,
JH7100_CLK_PLL2_OUT),
JH71X0_GDIV(JH7100_CLK_AUDIO_ROOT, "audio_root", 0, 8, JH7100_CLK_PLL0_OUT),
- JH71X0__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 3,
+ JH71X0__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 0, 3,
JH7100_CLK_OSC_SYS,
JH7100_CLK_PLL1_OUT,
JH7100_CLK_PLL2_OUT),
- JH71X0__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 3,
+ JH71X0__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 0, 3,
JH7100_CLK_OSC_SYS,
JH7100_CLK_PLL0_OUT,
JH7100_CLK_PLL1_OUT),
- JH71X0__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 3,
+ JH71X0__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 0, 3,
JH7100_CLK_OSC_AUD,
JH7100_CLK_PLL0_OUT,
JH7100_CLK_PLL2_OUT),
@@ -76,7 +76,7 @@ static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = {
JH71X0_GDIV(JH7100_CLK_PLL0_TESTOUT, "pll0_testout", 0, 31, JH7100_CLK_PERH0_SRC),
JH71X0_GDIV(JH7100_CLK_PLL1_TESTOUT, "pll1_testout", 0, 31, JH7100_CLK_DLA_ROOT),
JH71X0_GDIV(JH7100_CLK_PLL2_TESTOUT, "pll2_testout", 0, 31, JH7100_CLK_PERH1_SRC),
- JH71X0__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 2,
+ JH71X0__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 0, 2,
JH7100_CLK_OSC_SYS,
JH7100_CLK_OSC_AUD),
JH71X0__DIV(JH7100_CLK_CPU_CORE, "cpu_core", 8, JH7100_CLK_CPUNBUS_ROOT_DIV),
@@ -142,7 +142,7 @@ static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = {
JH71X0__DIV(JH7100_CLK_NOC_COG, "noc_cog", 8, JH7100_CLK_DLA_ROOT),
JH71X0_GATE(JH7100_CLK_NNE_AHB, "nne_ahb", 0, JH7100_CLK_AHB_BUS),
JH71X0__DIV(JH7100_CLK_NNEBUS_SRC1, "nnebus_src1", 4, JH7100_CLK_DSP_ROOT),
- JH71X0__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 2,
+ JH71X0__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 0, 2,
JH7100_CLK_CPU_AXI,
JH7100_CLK_NNEBUS_SRC1),
JH71X0_GATE(JH7100_CLK_NNE_AXI, "nne_axi", 0, JH7100_CLK_NNE_BUS),
@@ -166,7 +166,7 @@ static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = {
JH71X0_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", 0, 8, JH7100_CLK_USBPHY_ROOTDIV),
JH71X0_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", 0, 32,
JH7100_CLK_USBPHY_ROOTDIV),
- JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 2,
+ JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 0, 2,
JH7100_CLK_OSC_SYS,
JH7100_CLK_USBPHY_PLLDIV25M),
JH71X0_FDIV(JH7100_CLK_AUDIO_DIV, "audio_div", JH7100_CLK_AUDIO_ROOT),
@@ -200,12 +200,12 @@ static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = {
JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV),
JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF),
JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF),
- JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 3,
+ JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 3,
JH7100_CLK_GMAC_GTX,
JH7100_CLK_GMAC_TX_INV,
JH7100_CLK_GMAC_RMII_TX),
JH71X0__INV(JH7100_CLK_GMAC_TX_INV, "gmac_tx_inv", JH7100_CLK_GMAC_TX),
- JH71X0__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 2,
+ JH71X0__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 0, 2,
JH7100_CLK_GMAC_GR_MII_RX,
JH7100_CLK_GMAC_RMII_RX),
JH71X0__INV(JH7100_CLK_GMAC_RX_INV, "gmac_rx_inv", JH7100_CLK_GMAC_RX_PRE),
diff --git a/drivers/clk/starfive/clk-starfive-jh7110-aon.c b/drivers/clk/starfive/clk-starfive-jh7110-aon.c
index 62954eb7b50a..418efdad719b 100644
--- a/drivers/clk/starfive/clk-starfive-jh7110-aon.c
+++ b/drivers/clk/starfive/clk-starfive-jh7110-aon.c
@@ -26,7 +26,7 @@
static const struct jh71x0_clk_data jh7110_aonclk_data[] = {
/* source */
JH71X0__DIV(JH7110_AONCLK_OSC_DIV4, "osc_div4", 4, JH7110_AONCLK_OSC),
- JH71X0__MUX(JH7110_AONCLK_APB_FUNC, "apb_func", 2,
+ JH71X0__MUX(JH7110_AONCLK_APB_FUNC, "apb_func", 0, 2,
JH7110_AONCLK_OSC_DIV4,
JH7110_AONCLK_OSC),
/* gmac0 */
@@ -39,7 +39,7 @@ static const struct jh71x0_clk_data jh7110_aonclk_data[] = {
JH7110_AONCLK_GMAC0_GTXCLK,
JH7110_AONCLK_GMAC0_RMII_RTX),
JH71X0__INV(JH7110_AONCLK_GMAC0_TX_INV, "gmac0_tx_inv", JH7110_AONCLK_GMAC0_TX),
- JH71X0__MUX(JH7110_AONCLK_GMAC0_RX, "gmac0_rx", 2,
+ JH71X0__MUX(JH7110_AONCLK_GMAC0_RX, "gmac0_rx", 0, 2,
JH7110_AONCLK_GMAC0_RGMII_RXIN,
JH7110_AONCLK_GMAC0_RMII_RTX),
JH71X0__INV(JH7110_AONCLK_GMAC0_RX_INV, "gmac0_rx_inv", JH7110_AONCLK_GMAC0_RX),
@@ -48,7 +48,7 @@ static const struct jh71x0_clk_data jh7110_aonclk_data[] = {
/* rtc */
JH71X0_GATE(JH7110_AONCLK_RTC_APB, "rtc_apb", 0, JH7110_AONCLK_APB_BUS),
JH71X0__DIV(JH7110_AONCLK_RTC_INTERNAL, "rtc_internal", 1022, JH7110_AONCLK_OSC),
- JH71X0__MUX(JH7110_AONCLK_RTC_32K, "rtc_32k", 2,
+ JH71X0__MUX(JH7110_AONCLK_RTC_32K, "rtc_32k", 0, 2,
JH7110_AONCLK_RTC_OSC,
JH7110_AONCLK_RTC_INTERNAL),
JH71X0_GATE(JH7110_AONCLK_RTC_CAL, "rtc_cal", 0, JH7110_AONCLK_OSC),
diff --git a/drivers/clk/starfive/clk-starfive-jh7110-isp.c b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
index ce034ed28532..929b8788279e 100644
--- a/drivers/clk/starfive/clk-starfive-jh7110-isp.c
+++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c
@@ -53,7 +53,7 @@ static const struct jh71x0_clk_data jh7110_ispclk_data[] = {
JH7110_ISPCLK_MIPI_RX0_PXL),
JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_IF3, "vin_pixel_if3", 0,
JH7110_ISPCLK_MIPI_RX0_PXL),
- JH71X0__MUX(JH7110_ISPCLK_VIN_P_AXI_WR, "vin_p_axi_wr", 2,
+ JH71X0__MUX(JH7110_ISPCLK_VIN_P_AXI_WR, "vin_p_axi_wr", 0, 2,
JH7110_ISPCLK_MIPI_RX0_PXL,
JH7110_ISPCLK_DVP_INV),
/* ispv2_top_wrapper */
diff --git a/drivers/clk/starfive/clk-starfive-jh7110-sys.c b/drivers/clk/starfive/clk-starfive-jh7110-sys.c
index 3884eff9fe93..8f5e5abfa178 100644
--- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c
+++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c
@@ -36,18 +36,18 @@
static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
/* root */
- JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 2,
+ JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 0, 2,
JH7110_SYSCLK_OSC,
JH7110_SYSCLK_PLL0_OUT),
JH71X0__DIV(JH7110_SYSCLK_CPU_CORE, "cpu_core", 7, JH7110_SYSCLK_CPU_ROOT),
JH71X0__DIV(JH7110_SYSCLK_CPU_BUS, "cpu_bus", 2, JH7110_SYSCLK_CPU_CORE),
- JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 2,
+ JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 0, 2,
JH7110_SYSCLK_PLL2_OUT,
JH7110_SYSCLK_PLL1_OUT),
JH71X0_MDIV(JH7110_SYSCLK_PERH_ROOT, "perh_root", 2, 2,
JH7110_SYSCLK_PLL0_OUT,
JH7110_SYSCLK_PLL2_OUT),
- JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 2,
+ JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 0, 2,
JH7110_SYSCLK_OSC,
JH7110_SYSCLK_PLL2_OUT),
JH71X0__DIV(JH7110_SYSCLK_NOCSTG_BUS, "nocstg_bus", 3, JH7110_SYSCLK_BUS_ROOT),
@@ -62,7 +62,7 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0__DIV(JH7110_SYSCLK_PLL2_DIV2, "pll2_div2", 2, JH7110_SYSCLK_PLL2_OUT),
JH71X0__DIV(JH7110_SYSCLK_AUDIO_ROOT, "audio_root", 8, JH7110_SYSCLK_PLL2_OUT),
JH71X0__DIV(JH7110_SYSCLK_MCLK_INNER, "mclk_inner", 64, JH7110_SYSCLK_AUDIO_ROOT),
- JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 2,
+ JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 0, 2,
JH7110_SYSCLK_MCLK_INNER,
JH7110_SYSCLK_MCLK_EXT),
JH71X0_GATE(JH7110_SYSCLK_MCLK_OUT, "mclk_out", 0, JH7110_SYSCLK_MCLK_INNER),
@@ -96,7 +96,7 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0__DIV(JH7110_SYSCLK_OSC_DIV2, "osc_div2", 2, JH7110_SYSCLK_OSC),
JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV4, "pll1_div4", 2, JH7110_SYSCLK_PLL1_DIV2),
JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV8, "pll1_div8", 2, JH7110_SYSCLK_PLL1_DIV4),
- JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 4,
+ JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 0, 4,
JH7110_SYSCLK_OSC_DIV2,
JH7110_SYSCLK_PLL1_DIV2,
JH7110_SYSCLK_PLL1_DIV4,
@@ -186,7 +186,7 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0__DIV(JH7110_SYSCLK_GMAC1_RMII_RTX, "gmac1_rmii_rtx", 30,
JH7110_SYSCLK_GMAC1_RMII_REFIN),
JH71X0_GDIV(JH7110_SYSCLK_GMAC1_PTP, "gmac1_ptp", 0, 31, JH7110_SYSCLK_GMAC_SRC),
- JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 2,
+ JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 0, 2,
JH7110_SYSCLK_GMAC1_RGMII_RXIN,
JH7110_SYSCLK_GMAC1_RMII_RTX),
JH71X0__INV(JH7110_SYSCLK_GMAC1_RX_INV, "gmac1_rx_inv", JH7110_SYSCLK_GMAC1_RX),
@@ -270,11 +270,11 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0_MDIV(JH7110_SYSCLK_I2STX0_LRCK_MST, "i2stx0_lrck_mst", 64, 2,
JH7110_SYSCLK_I2STX0_BCLK_MST_INV,
JH7110_SYSCLK_I2STX0_BCLK_MST),
- JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 2,
+ JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 0, 2,
JH7110_SYSCLK_I2STX0_BCLK_MST,
JH7110_SYSCLK_I2STX_BCLK_EXT),
JH71X0__INV(JH7110_SYSCLK_I2STX0_BCLK_INV, "i2stx0_bclk_inv", JH7110_SYSCLK_I2STX0_BCLK),
- JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 2,
+ JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 0, 2,
JH7110_SYSCLK_I2STX0_LRCK_MST,
JH7110_SYSCLK_I2STX_LRCK_EXT),
/* i2stx1 */
@@ -285,11 +285,11 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0_MDIV(JH7110_SYSCLK_I2STX1_LRCK_MST, "i2stx1_lrck_mst", 64, 2,
JH7110_SYSCLK_I2STX1_BCLK_MST_INV,
JH7110_SYSCLK_I2STX1_BCLK_MST),
- JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 2,
+ JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 0, 2,
JH7110_SYSCLK_I2STX1_BCLK_MST,
JH7110_SYSCLK_I2STX_BCLK_EXT),
JH71X0__INV(JH7110_SYSCLK_I2STX1_BCLK_INV, "i2stx1_bclk_inv", JH7110_SYSCLK_I2STX1_BCLK),
- JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 2,
+ JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 0, 2,
JH7110_SYSCLK_I2STX1_LRCK_MST,
JH7110_SYSCLK_I2STX_LRCK_EXT),
/* i2srx */
@@ -300,11 +300,11 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0_MDIV(JH7110_SYSCLK_I2SRX_LRCK_MST, "i2srx_lrck_mst", 64, 2,
JH7110_SYSCLK_I2SRX_BCLK_MST_INV,
JH7110_SYSCLK_I2SRX_BCLK_MST),
- JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 2,
+ JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 0, 2,
JH7110_SYSCLK_I2SRX_BCLK_MST,
JH7110_SYSCLK_I2SRX_BCLK_EXT),
JH71X0__INV(JH7110_SYSCLK_I2SRX_BCLK_INV, "i2srx_bclk_inv", JH7110_SYSCLK_I2SRX_BCLK),
- JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 2,
+ JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 0, 2,
JH7110_SYSCLK_I2SRX_LRCK_MST,
JH7110_SYSCLK_I2SRX_LRCK_EXT),
/* pdm */
@@ -314,7 +314,7 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = {
JH71X0_GATE(JH7110_SYSCLK_TDM_AHB, "tdm_ahb", 0, JH7110_SYSCLK_AHB0),
JH71X0_GATE(JH7110_SYSCLK_TDM_APB, "tdm_apb", 0, JH7110_SYSCLK_APB0),
JH71X0_GDIV(JH7110_SYSCLK_TDM_INTERNAL, "tdm_internal", 0, 64, JH7110_SYSCLK_MCLK),
- JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 2,
+ JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 0, 2,
JH7110_SYSCLK_TDM_INTERNAL,
JH7110_SYSCLK_TDM_EXT),
JH71X0__INV(JH7110_SYSCLK_TDM_TDM_INV, "tdm_tdm_inv", JH7110_SYSCLK_TDM_TDM),
diff --git a/drivers/clk/starfive/clk-starfive-jh71x0.h b/drivers/clk/starfive/clk-starfive-jh71x0.h
index 34bb11c72eb7..23e052fc1549 100644
--- a/drivers/clk/starfive/clk-starfive-jh71x0.h
+++ b/drivers/clk/starfive/clk-starfive-jh71x0.h
@@ -61,10 +61,10 @@ struct jh71x0_clk_data {
.parents = { [0] = _parent }, \
}
-#define JH71X0__MUX(_idx, _name, _nparents, ...) \
+#define JH71X0__MUX(_idx, _name, _flags, _nparents, ...) \
[_idx] = { \
.name = _name, \
- .flags = 0, \
+ .flags = _flags, \
.max = ((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT, \
.parents = { __VA_ARGS__ }, \
}
diff --git a/drivers/clk/stm32/Kconfig b/drivers/clk/stm32/Kconfig
new file mode 100644
index 000000000000..3c8493a94a11
--- /dev/null
+++ b/drivers/clk/stm32/Kconfig
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# common clock support for STMicroelectronics SoC family.
+
+menuconfig COMMON_CLK_STM32MP
+ bool "Clock support for common STM32MP clocks"
+ depends on ARCH_STM32 || COMPILE_TEST
+ default y
+ select RESET_CONTROLLER
+ help
+ Support for STM32MP SoC family clocks.
+
+if COMMON_CLK_STM32MP
+
+config COMMON_CLK_STM32MP135
+ bool "Clock driver for stm32mp13x clocks"
+ depends on ARM || COMPILE_TEST
+ default y
+ help
+ Support for stm32mp13x SoC family clocks.
+
+config COMMON_CLK_STM32MP157
+ bool "Clock driver for stm32mp15x clocks"
+ depends on ARM || COMPILE_TEST
+ default y
+ help
+ Support for stm32mp15x SoC family clocks.
+
+endif
+
diff --git a/drivers/clk/stm32/Makefile b/drivers/clk/stm32/Makefile
index 95bd2230bba0..5ced7fe3ddec 100644
--- a/drivers/clk/stm32/Makefile
+++ b/drivers/clk/stm32/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_COMMON_CLK_STM32MP135) += clk-stm32mp13.o clk-stm32-core.o reset-stm32.o
+obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o reset-stm32.o
diff --git a/drivers/clk/stm32/clk-stm32-core.c b/drivers/clk/stm32/clk-stm32-core.c
index 067b918a8894..58705fcad334 100644
--- a/drivers/clk/stm32/clk-stm32-core.c
+++ b/drivers/clk/stm32/clk-stm32-core.c
@@ -70,6 +70,7 @@ static int stm32_rcc_clock_init(struct device *dev,
int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data,
void __iomem *base)
{
+ const struct stm32_rcc_match_data *rcc_match_data;
const struct of_device_id *match;
int err;
@@ -79,8 +80,10 @@ int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data,
return -ENODEV;
}
+ rcc_match_data = match->data;
+
/* RCC Reset Configuration */
- err = stm32_rcc_reset_init(dev, match, base);
+ err = stm32_rcc_reset_init(dev, rcc_match_data->reset_data, base);
if (err) {
pr_err("stm32 reset failed to initialize\n");
return err;
diff --git a/drivers/clk/stm32/clk-stm32-core.h b/drivers/clk/stm32/clk-stm32-core.h
index 76cffda02308..bb5aa19a792d 100644
--- a/drivers/clk/stm32/clk-stm32-core.h
+++ b/drivers/clk/stm32/clk-stm32-core.h
@@ -70,15 +70,12 @@ struct stm32_rcc_match_data {
const struct clock_config *tab_clocks;
unsigned int maxbinding;
struct clk_stm32_clock_data *clock_data;
- u32 clear_offset;
+ struct clk_stm32_reset_data *reset_data;
int (*check_security)(void __iomem *base,
const struct clock_config *cfg);
int (*multi_mux)(void __iomem *base, const struct clock_config *cfg);
};
-int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match,
- void __iomem *base);
-
int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data,
void __iomem *base);
diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/stm32/clk-stm32mp1.c
index 939779f66867..7e2337297402 100644
--- a/drivers/clk/clk-stm32mp1.c
+++ b/drivers/clk/stm32/clk-stm32mp1.c
@@ -20,6 +20,10 @@
#include <dt-bindings/clock/stm32mp1-clks.h>
+#include "reset-stm32.h"
+
+#define STM32MP1_RESET_ID_MASK GENMASK(15, 0)
+
static DEFINE_SPINLOCK(rlock);
#define RCC_OCENSETR 0x0C
@@ -2137,22 +2141,27 @@ struct stm32_rcc_match_data {
const struct clock_config *cfg;
unsigned int num;
unsigned int maxbinding;
- u32 clear_offset;
+ struct clk_stm32_reset_data *reset_data;
bool (*check_security)(const struct clock_config *cfg);
};
+static struct clk_stm32_reset_data stm32mp1_reset_data = {
+ .nr_lines = STM32MP1_RESET_ID_MASK,
+ .clear_offset = RCC_CLR,
+};
+
static struct stm32_rcc_match_data stm32mp1_data = {
.cfg = stm32mp1_clock_cfg,
.num = ARRAY_SIZE(stm32mp1_clock_cfg),
.maxbinding = STM32MP1_LAST_CLK,
- .clear_offset = RCC_CLR,
+ .reset_data = &stm32mp1_reset_data,
};
static struct stm32_rcc_match_data stm32mp1_data_secure = {
.cfg = stm32mp1_clock_cfg,
.num = ARRAY_SIZE(stm32mp1_clock_cfg),
.maxbinding = STM32MP1_LAST_CLK,
- .clear_offset = RCC_CLR,
+ .reset_data = &stm32mp1_reset_data,
.check_security = &stm32_check_security
};
@@ -2193,113 +2202,6 @@ static int stm32_register_hw_clk(struct device *dev,
return 0;
}
-#define STM32_RESET_ID_MASK GENMASK(15, 0)
-
-struct stm32_reset_data {
- /* reset lock */
- spinlock_t lock;
- struct reset_controller_dev rcdev;
- void __iomem *membase;
- u32 clear_offset;
-};
-
-static inline struct stm32_reset_data *
-to_stm32_reset_data(struct reset_controller_dev *rcdev)
-{
- return container_of(rcdev, struct stm32_reset_data, rcdev);
-}
-
-static int stm32_reset_update(struct reset_controller_dev *rcdev,
- unsigned long id, bool assert)
-{
- struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
- int reg_width = sizeof(u32);
- int bank = id / (reg_width * BITS_PER_BYTE);
- int offset = id % (reg_width * BITS_PER_BYTE);
-
- if (data->clear_offset) {
- void __iomem *addr;
-
- addr = data->membase + (bank * reg_width);
- if (!assert)
- addr += data->clear_offset;
-
- writel(BIT(offset), addr);
-
- } else {
- unsigned long flags;
- u32 reg;
-
- spin_lock_irqsave(&data->lock, flags);
-
- reg = readl(data->membase + (bank * reg_width));
-
- if (assert)
- reg |= BIT(offset);
- else
- reg &= ~BIT(offset);
-
- writel(reg, data->membase + (bank * reg_width));
-
- spin_unlock_irqrestore(&data->lock, flags);
- }
-
- return 0;
-}
-
-static int stm32_reset_assert(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- return stm32_reset_update(rcdev, id, true);
-}
-
-static int stm32_reset_deassert(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- return stm32_reset_update(rcdev, id, false);
-}
-
-static int stm32_reset_status(struct reset_controller_dev *rcdev,
- unsigned long id)
-{
- struct stm32_reset_data *data = to_stm32_reset_data(rcdev);
- int reg_width = sizeof(u32);
- int bank = id / (reg_width * BITS_PER_BYTE);
- int offset = id % (reg_width * BITS_PER_BYTE);
- u32 reg;
-
- reg = readl(data->membase + (bank * reg_width));
-
- return !!(reg & BIT(offset));
-}
-
-static const struct reset_control_ops stm32_reset_ops = {
- .assert = stm32_reset_assert,
- .deassert = stm32_reset_deassert,
- .status = stm32_reset_status,
-};
-
-static int stm32_rcc_reset_init(struct device *dev, void __iomem *base,
- const struct of_device_id *match)
-{
- const struct stm32_rcc_match_data *data = match->data;
- struct stm32_reset_data *reset_data = NULL;
-
- reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
- if (!reset_data)
- return -ENOMEM;
-
- spin_lock_init(&reset_data->lock);
- reset_data->membase = base;
- reset_data->rcdev.owner = THIS_MODULE;
- reset_data->rcdev.ops = &stm32_reset_ops;
- reset_data->rcdev.of_node = dev_of_node(dev);
- reset_data->rcdev.nr_resets = STM32_RESET_ID_MASK;
- reset_data->clear_offset = data->clear_offset;
-
- return reset_controller_register(&reset_data->rcdev);
-}
-
static int stm32_rcc_clock_init(struct device *dev, void __iomem *base,
const struct of_device_id *match)
{
@@ -2342,6 +2244,7 @@ static int stm32_rcc_clock_init(struct device *dev, void __iomem *base,
static int stm32_rcc_init(struct device *dev, void __iomem *base,
const struct of_device_id *match_data)
{
+ const struct stm32_rcc_match_data *rcc_match_data;
const struct of_device_id *match;
int err;
@@ -2351,8 +2254,10 @@ static int stm32_rcc_init(struct device *dev, void __iomem *base,
return -ENODEV;
}
+ rcc_match_data = match->data;
+
/* RCC Reset Configuration */
- err = stm32_rcc_reset_init(dev, base, match);
+ err = stm32_rcc_reset_init(dev, rcc_match_data->reset_data, base);
if (err) {
pr_err("stm32mp1 reset failed to initialize\n");
return err;
diff --git a/drivers/clk/stm32/clk-stm32mp13.c b/drivers/clk/stm32/clk-stm32mp13.c
index c4a737482fe5..d4ecb3c34a1b 100644
--- a/drivers/clk/stm32/clk-stm32mp13.c
+++ b/drivers/clk/stm32/clk-stm32mp13.c
@@ -10,8 +10,10 @@
#include <linux/platform_device.h>
#include <dt-bindings/clock/stm32mp13-clks.h>
#include "clk-stm32-core.h"
+#include "reset-stm32.h"
#include "stm32mp13_rcc.h"
+#define STM32MP1_RESET_ID_MASK GENMASK(15, 0)
#define RCC_CLR_OFFSET 0x4
/* STM32 Gates definition */
@@ -1511,13 +1513,18 @@ static struct clk_stm32_clock_data stm32mp13_clock_data = {
.is_multi_mux = stm32mp13_is_multi_mux,
};
+static struct clk_stm32_reset_data stm32mp13_reset_data = {
+ .nr_lines = STM32MP1_RESET_ID_MASK,
+ .clear_offset = RCC_CLR_OFFSET,
+};
+
static const struct stm32_rcc_match_data stm32mp13_data = {
.tab_clocks = stm32mp13_clock_cfg,
.num_clocks = ARRAY_SIZE(stm32mp13_clock_cfg),
.clock_data = &stm32mp13_clock_data,
.check_security = &stm32mp13_clock_is_provided_by_secure,
.maxbinding = STM32MP1_LAST_CLK,
- .clear_offset = RCC_CLR_OFFSET,
+ .reset_data = &stm32mp13_reset_data,
};
static const struct of_device_id stm32mp13_match_data[] = {
diff --git a/drivers/clk/stm32/reset-stm32.c b/drivers/clk/stm32/reset-stm32.c
index e89381528af9..14c2ee1eebee 100644
--- a/drivers/clk/stm32/reset-stm32.c
+++ b/drivers/clk/stm32/reset-stm32.c
@@ -11,9 +11,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include "clk-stm32-core.h"
-
-#define STM32_RESET_ID_MASK GENMASK(15, 0)
+#include "reset-stm32.h"
struct stm32_reset_data {
/* reset lock */
@@ -99,24 +97,22 @@ static const struct reset_control_ops stm32_reset_ops = {
.status = stm32_reset_status,
};
-int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match,
+int stm32_rcc_reset_init(struct device *dev, struct clk_stm32_reset_data *data,
void __iomem *base)
{
- const struct stm32_rcc_match_data *data = match->data;
- struct stm32_reset_data *reset_data = NULL;
-
- data = match->data;
+ struct stm32_reset_data *reset_data;
reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
if (!reset_data)
return -ENOMEM;
spin_lock_init(&reset_data->lock);
+
reset_data->membase = base;
reset_data->rcdev.owner = THIS_MODULE;
reset_data->rcdev.ops = &stm32_reset_ops;
reset_data->rcdev.of_node = dev_of_node(dev);
- reset_data->rcdev.nr_resets = STM32_RESET_ID_MASK;
+ reset_data->rcdev.nr_resets = data->nr_lines;
reset_data->clear_offset = data->clear_offset;
return reset_controller_register(&reset_data->rcdev);
diff --git a/drivers/clk/stm32/reset-stm32.h b/drivers/clk/stm32/reset-stm32.h
index 6eb6ea4b55ab..8cf1cc9be480 100644
--- a/drivers/clk/stm32/reset-stm32.h
+++ b/drivers/clk/stm32/reset-stm32.h
@@ -4,5 +4,11 @@
* Author: Gabriel Fernandez <[email protected]> for STMicroelectronics.
*/
-int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match,
+struct clk_stm32_reset_data {
+ const struct reset_control_ops *ops;
+ unsigned int nr_lines;
+ u32 clear_offset;
+};
+
+int stm32_rcc_reset_init(struct device *dev, struct clk_stm32_reset_data *data,
void __iomem *base);
diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c
index eed64547ad42..853f84398e2b 100644
--- a/drivers/clk/sunxi-ng/ccu_nkm.c
+++ b/drivers/clk/sunxi-ng/ccu_nkm.c
@@ -21,17 +21,16 @@ static unsigned long ccu_nkm_find_best_with_parent_adj(struct ccu_common *common
unsigned long *parent, unsigned long rate,
struct _ccu_nkm *nkm)
{
- unsigned long best_rate = 0, best_parent_rate = *parent, tmp_parent = *parent;
+ unsigned long best_rate = 0, best_parent_rate = *parent;
unsigned long best_n = 0, best_k = 0, best_m = 0;
unsigned long _n, _k, _m;
for (_k = nkm->min_k; _k <= nkm->max_k; _k++) {
for (_n = nkm->min_n; _n <= nkm->max_n; _n++) {
for (_m = nkm->min_m; _m <= nkm->max_m; _m++) {
- unsigned long tmp_rate;
+ unsigned long tmp_rate, tmp_parent;
tmp_parent = clk_hw_round_rate(parent_hw, rate * _m / (_n * _k));
-
tmp_rate = tmp_parent * _n * _k / _m;
if (ccu_is_better_rate(common, rate, tmp_rate, best_rate) ||
diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
index d56822ce6126..6a6e5d9292e8 100644
--- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
+++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c
@@ -23,15 +23,41 @@
#define WZRD_NUM_OUTPUTS 7
#define WZRD_ACLK_MAX_FREQ 250000000UL
-#define WZRD_CLK_CFG_REG(n) (0x200 + 4 * (n))
+#define WZRD_CLK_CFG_REG(v, n) (0x200 + 0x130 * (v) + 4 * (n))
#define WZRD_CLKOUT0_FRAC_EN BIT(18)
-#define WZRD_CLKFBOUT_FRAC_EN BIT(26)
+#define WZRD_CLKFBOUT_1 0
+#define WZRD_CLKFBOUT_2 1
+#define WZRD_CLKOUT0_1 2
+#define WZRD_CLKOUT0_2 3
+#define WZRD_DESKEW_2 20
+#define WZRD_DIVCLK 21
+#define WZRD_CLKFBOUT_4 51
+#define WZRD_CLKFBOUT_3 48
+#define WZRD_DUTY_CYCLE 2
+#define WZRD_O_DIV 4
+
+#define WZRD_CLKFBOUT_FRAC_EN BIT(1)
+#define WZRD_CLKFBOUT_PREDIV2 (BIT(11) | BIT(12) | BIT(9))
+#define WZRD_MULT_PREDIV2 (BIT(10) | BIT(9) | BIT(12))
+#define WZRD_CLKFBOUT_EDGE BIT(8)
+#define WZRD_P5EN BIT(13)
+#define WZRD_P5EN_SHIFT 13
+#define WZRD_P5FEDGE BIT(15)
+#define WZRD_DIVCLK_EDGE BIT(10)
+#define WZRD_P5FEDGE_SHIFT 15
+#define WZRD_CLKOUT0_PREDIV2 BIT(11)
+#define WZRD_EDGE_SHIFT 8
#define WZRD_CLKFBOUT_MULT_SHIFT 8
#define WZRD_CLKFBOUT_MULT_MASK (0xff << WZRD_CLKFBOUT_MULT_SHIFT)
+#define WZRD_CLKFBOUT_L_SHIFT 0
+#define WZRD_CLKFBOUT_H_SHIFT 8
+#define WZRD_CLKFBOUT_L_MASK GENMASK(7, 0)
+#define WZRD_CLKFBOUT_H_MASK GENMASK(15, 8)
#define WZRD_CLKFBOUT_FRAC_SHIFT 16
#define WZRD_CLKFBOUT_FRAC_MASK (0x3ff << WZRD_CLKFBOUT_FRAC_SHIFT)
+#define WZRD_VERSAL_FRAC_MASK GENMASK(5, 0)
#define WZRD_DIVCLK_DIVIDE_SHIFT 0
#define WZRD_DIVCLK_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT)
#define WZRD_CLKOUT_DIVIDE_SHIFT 0
@@ -45,6 +71,7 @@
#define WZRD_DR_STATUS_REG_OFFSET 0x04
#define WZRD_DR_LOCK_BIT_MASK 0x00000001
#define WZRD_DR_INIT_REG_OFFSET 0x25C
+#define WZRD_DR_INIT_VERSAL_OFFSET 0x14
#define WZRD_DR_DIV_TO_PHASE_OFFSET 4
#define WZRD_DR_BEGIN_DYNA_RECONF 0x03
#define WZRD_DR_BEGIN_DYNA_RECONF_5_2 0x07
@@ -52,6 +79,8 @@
#define WZRD_USEC_POLL 10
#define WZRD_TIMEOUT_POLL 1000
+#define WZRD_FRAC_GRADIENT 64
+#define PREDIV2_MULT 2
/* Divider limits, from UG572 Table 3-4 for Ultrascale+ */
#define DIV_O 0x01
@@ -65,6 +94,14 @@
#define WZRD_VCO_MAX 1600000000
#define WZRD_O_MIN 1
#define WZRD_O_MAX 128
+#define VER_WZRD_M_MIN 4
+#define VER_WZRD_M_MAX 432
+#define VER_WZRD_D_MIN 1
+#define VER_WZRD_D_MAX 123
+#define VER_WZRD_VCO_MIN 2160000000ULL
+#define VER_WZRD_VCO_MAX 4320000000ULL
+#define VER_WZRD_O_MIN 2
+#define VER_WZRD_O_MAX 511
#define WZRD_MIN_ERR 20000
#define WZRD_FRAC_POINTS 1000
@@ -135,6 +172,10 @@ struct clk_wzrd_divider {
spinlock_t *lock; /* divider lock */
};
+struct versal_clk_data {
+ bool is_versal;
+};
+
#define to_clk_wzrd(_nb) container_of(_nb, struct clk_wzrd, nb)
/* maximum frequencies for input/output clocks per speed grade */
@@ -147,6 +188,31 @@ static const unsigned long clk_wzrd_max_freq[] = {
/* spin lock variable for clk_wzrd */
static DEFINE_SPINLOCK(clkwzrd_lock);
+static unsigned long clk_wzrd_recalc_rate_ver(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
+ void __iomem *div_addr = divider->base + divider->offset;
+ u32 div, p5en, edge, prediv2, all;
+ unsigned int vall, valh;
+
+ edge = !!(readl(div_addr) & WZRD_CLKFBOUT_EDGE);
+ p5en = !!(readl(div_addr) & WZRD_P5EN);
+ prediv2 = !!(readl(div_addr) & WZRD_CLKOUT0_PREDIV2);
+ vall = readl(div_addr + 4) & WZRD_CLKFBOUT_L_MASK;
+ valh = readl(div_addr + 4) >> WZRD_CLKFBOUT_H_SHIFT;
+ all = valh + vall + edge;
+ if (!all)
+ all = 1;
+
+ if (prediv2)
+ div = 2 * all + prediv2 * p5en;
+ else
+ div = all;
+
+ return DIV_ROUND_UP_ULL((u64)parent_rate, div);
+}
+
static unsigned long clk_wzrd_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -161,19 +227,64 @@ static unsigned long clk_wzrd_recalc_rate(struct clk_hw *hw,
divider->flags, divider->width);
}
+static int clk_wzrd_ver_dynamic_reconfig(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
+ void __iomem *div_addr = divider->base + divider->offset;
+ u32 value, regh, edged, p5en, p5fedge, regval, regval1;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(divider->lock, flags);
+
+ value = DIV_ROUND_CLOSEST(parent_rate, rate);
+
+ regh = (value / 4);
+ regval1 = readl(div_addr);
+ regval1 |= WZRD_CLKFBOUT_PREDIV2;
+ regval1 = regval1 & ~(WZRD_CLKFBOUT_EDGE | WZRD_P5EN | WZRD_P5FEDGE);
+ if (value % 4 > 1) {
+ edged = 1;
+ regval1 |= (edged << WZRD_EDGE_SHIFT);
+ }
+ p5fedge = value % 2;
+ p5en = value % 2;
+ regval1 = regval1 | p5en << WZRD_P5EN_SHIFT | p5fedge << WZRD_P5FEDGE_SHIFT;
+ writel(regval1, div_addr);
+
+ regval = regh | regh << WZRD_CLKFBOUT_H_SHIFT;
+ writel(regval, div_addr + 4);
+ /* Check status register */
+ err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET,
+ value, value & WZRD_DR_LOCK_BIT_MASK,
+ WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);
+ if (err)
+ goto err_reconfig;
+
+ /* Initiate reconfiguration */
+ writel(WZRD_DR_BEGIN_DYNA_RECONF,
+ divider->base + WZRD_DR_INIT_VERSAL_OFFSET);
+
+ /* Check status register */
+ err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET,
+ value, value & WZRD_DR_LOCK_BIT_MASK,
+ WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);
+err_reconfig:
+ spin_unlock_irqrestore(divider->lock, flags);
+ return err;
+}
+
static int clk_wzrd_dynamic_reconfig(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
- int err;
- u32 value;
- unsigned long flags = 0;
struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
void __iomem *div_addr = divider->base + divider->offset;
+ unsigned long flags;
+ u32 value;
+ int err;
- if (divider->lock)
- spin_lock_irqsave(divider->lock, flags);
- else
- __acquire(divider->lock);
+ spin_lock_irqsave(divider->lock, flags);
value = DIV_ROUND_CLOSEST(parent_rate, rate);
@@ -185,9 +296,9 @@ static int clk_wzrd_dynamic_reconfig(struct clk_hw *hw, unsigned long rate,
writel(0x00, div_addr + WZRD_DR_DIV_TO_PHASE_OFFSET);
/* Check status register */
- err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET,
- value, value & WZRD_DR_LOCK_BIT_MASK,
- WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);
+ err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET,
+ value, value & WZRD_DR_LOCK_BIT_MASK,
+ WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);
if (err)
goto err_reconfig;
@@ -198,14 +309,11 @@ static int clk_wzrd_dynamic_reconfig(struct clk_hw *hw, unsigned long rate,
divider->base + WZRD_DR_INIT_REG_OFFSET);
/* Check status register */
- err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET,
- value, value & WZRD_DR_LOCK_BIT_MASK,
- WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);
+ err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET,
+ value, value & WZRD_DR_LOCK_BIT_MASK,
+ WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);
err_reconfig:
- if (divider->lock)
- spin_unlock_irqrestore(divider->lock, flags);
- else
- __release(divider->lock);
+ spin_unlock_irqrestore(divider->lock, flags);
return err;
}
@@ -223,18 +331,66 @@ static long clk_wzrd_round_rate(struct clk_hw *hw, unsigned long rate,
return *prate / div;
}
+static int clk_wzrd_get_divisors_ver(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
+ u64 vco_freq, freq, diff, vcomin, vcomax;
+ u32 m, d, o;
+ u32 mmin, mmax, dmin, dmax, omin, omax;
+
+ mmin = VER_WZRD_M_MIN;
+ mmax = VER_WZRD_M_MAX;
+ dmin = VER_WZRD_D_MIN;
+ dmax = VER_WZRD_D_MAX;
+ omin = VER_WZRD_O_MIN;
+ omax = VER_WZRD_O_MAX;
+ vcomin = VER_WZRD_VCO_MIN;
+ vcomax = VER_WZRD_VCO_MAX;
+
+ for (m = mmin; m <= mmax; m++) {
+ for (d = dmin; d <= dmax; d++) {
+ vco_freq = DIV_ROUND_CLOSEST((parent_rate * m), d);
+ if (vco_freq >= vcomin && vco_freq <= vcomax) {
+ for (o = omin; o <= omax; o++) {
+ freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o);
+ diff = abs(freq - rate);
+
+ if (diff < WZRD_MIN_ERR) {
+ divider->m = m;
+ divider->d = d;
+ divider->o = o;
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ return -EBUSY;
+}
+
static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
- unsigned long vco_freq, freq, diff;
+ u64 vco_freq, freq, diff, vcomin, vcomax;
u32 m, d, o;
-
- for (m = WZRD_M_MIN; m <= WZRD_M_MAX; m++) {
- for (d = WZRD_D_MIN; d <= WZRD_D_MAX; d++) {
+ u32 mmin, mmax, dmin, dmax, omin, omax;
+
+ mmin = WZRD_M_MIN;
+ mmax = WZRD_M_MAX;
+ dmin = WZRD_D_MIN;
+ dmax = WZRD_D_MAX;
+ omin = WZRD_O_MIN;
+ omax = WZRD_O_MAX;
+ vcomin = WZRD_VCO_MIN;
+ vcomax = WZRD_VCO_MAX;
+
+ for (m = mmin; m <= mmax; m++) {
+ for (d = dmin; d <= dmax; d++) {
vco_freq = DIV_ROUND_CLOSEST((parent_rate * m), d);
- if (vco_freq >= WZRD_VCO_MIN && vco_freq <= WZRD_VCO_MAX) {
- for (o = WZRD_O_MIN; o <= WZRD_O_MAX; o++) {
+ if (vco_freq >= vcomin && vco_freq <= vcomax) {
+ for (o = omin; o <= omax; o++) {
freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o);
diff = abs(freq - rate);
@@ -251,12 +407,99 @@ static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate,
return -EBUSY;
}
+static int clk_wzrd_reconfig(struct clk_wzrd_divider *divider, void __iomem *div_addr)
+{
+ u32 value;
+ int err;
+
+ /* Check status register */
+ err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, value,
+ value & WZRD_DR_LOCK_BIT_MASK,
+ WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);
+ if (err)
+ return -ETIMEDOUT;
+
+ /* Initiate reconfiguration */
+ writel(WZRD_DR_BEGIN_DYNA_RECONF, div_addr);
+ /* Check status register */
+ return readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, value,
+ value & WZRD_DR_LOCK_BIT_MASK,
+ WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);
+}
+
+static int clk_wzrd_dynamic_ver_all_nolock(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ u32 regh, edged, p5en, p5fedge, value2, m, regval, regval1, value;
+ struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
+ void __iomem *div_addr;
+ int err;
+
+ err = clk_wzrd_get_divisors_ver(hw, rate, parent_rate);
+ if (err)
+ return err;
+
+ writel(0, divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_4));
+
+ m = divider->m;
+ edged = m % WZRD_DUTY_CYCLE;
+ regh = m / WZRD_DUTY_CYCLE;
+ regval1 = readl(divider->base + WZRD_CLK_CFG_REG(1,
+ WZRD_CLKFBOUT_1));
+ regval1 |= WZRD_MULT_PREDIV2;
+ if (edged)
+ regval1 = regval1 | WZRD_CLKFBOUT_EDGE;
+ else
+ regval1 = regval1 & ~WZRD_CLKFBOUT_EDGE;
+
+ writel(regval1, divider->base + WZRD_CLK_CFG_REG(1,
+ WZRD_CLKFBOUT_1));
+ regval1 = regh | regh << WZRD_CLKFBOUT_H_SHIFT;
+ writel(regval1, divider->base + WZRD_CLK_CFG_REG(1,
+ WZRD_CLKFBOUT_2));
+
+ value2 = divider->d;
+ edged = value2 % WZRD_DUTY_CYCLE;
+ regh = (value2 / WZRD_DUTY_CYCLE);
+ regval1 = FIELD_PREP(WZRD_DIVCLK_EDGE, edged);
+ writel(regval1, divider->base + WZRD_CLK_CFG_REG(1,
+ WZRD_DESKEW_2));
+ regval1 = regh | regh << WZRD_CLKFBOUT_H_SHIFT;
+ writel(regval1, divider->base + WZRD_CLK_CFG_REG(1, WZRD_DIVCLK));
+
+ value = divider->o;
+ regh = value / WZRD_O_DIV;
+ regval1 = readl(divider->base + WZRD_CLK_CFG_REG(1,
+ WZRD_CLKOUT0_1));
+ regval1 |= WZRD_CLKFBOUT_PREDIV2;
+ regval1 = regval1 & ~(WZRD_CLKFBOUT_EDGE | WZRD_P5EN | WZRD_P5FEDGE);
+
+ if (value % WZRD_O_DIV > 1) {
+ edged = 1;
+ regval1 |= edged << WZRD_CLKFBOUT_H_SHIFT;
+ }
+
+ p5fedge = value % WZRD_DUTY_CYCLE;
+ p5en = value % WZRD_DUTY_CYCLE;
+
+ regval1 = regval1 | FIELD_PREP(WZRD_P5EN, p5en) | FIELD_PREP(WZRD_P5FEDGE, p5fedge);
+ writel(regval1, divider->base + WZRD_CLK_CFG_REG(1,
+ WZRD_CLKOUT0_1));
+ regval = regh | regh << WZRD_CLKFBOUT_H_SHIFT;
+ writel(regval, divider->base + WZRD_CLK_CFG_REG(1,
+ WZRD_CLKOUT0_2));
+ div_addr = divider->base + WZRD_DR_INIT_VERSAL_OFFSET;
+
+ return clk_wzrd_reconfig(divider, div_addr);
+}
+
static int clk_wzrd_dynamic_all_nolock(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
unsigned long vco_freq, rate_div, clockout0_div;
- u32 reg, pre, value, f;
+ void __iomem *div_addr = divider->base;
+ u32 reg, pre, f;
int err;
err = clk_wzrd_get_divisors(hw, rate, parent_rate);
@@ -275,35 +518,22 @@ static int clk_wzrd_dynamic_all_nolock(struct clk_hw *hw, unsigned long rate,
reg = FIELD_PREP(WZRD_CLKOUT_DIVIDE_MASK, clockout0_div) |
FIELD_PREP(WZRD_CLKOUT0_FRAC_MASK, f);
- writel(reg, divider->base + WZRD_CLK_CFG_REG(2));
+ writel(reg, divider->base + WZRD_CLK_CFG_REG(0, 2));
/* Set divisor and clear phase offset */
reg = FIELD_PREP(WZRD_CLKFBOUT_MULT_MASK, divider->m) |
FIELD_PREP(WZRD_DIVCLK_DIVIDE_MASK, divider->d);
- writel(reg, divider->base + WZRD_CLK_CFG_REG(0));
- writel(divider->o, divider->base + WZRD_CLK_CFG_REG(2));
- writel(0, divider->base + WZRD_CLK_CFG_REG(3));
- /* Check status register */
- err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value,
- value & WZRD_DR_LOCK_BIT_MASK,
- WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);
- if (err)
- return -ETIMEDOUT;
-
- /* Initiate reconfiguration */
- writel(WZRD_DR_BEGIN_DYNA_RECONF,
- divider->base + WZRD_DR_INIT_REG_OFFSET);
-
- /* Check status register */
- return readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value,
- value & WZRD_DR_LOCK_BIT_MASK,
- WZRD_USEC_POLL, WZRD_TIMEOUT_POLL);
+ writel(reg, divider->base + WZRD_CLK_CFG_REG(0, 0));
+ writel(divider->o, divider->base + WZRD_CLK_CFG_REG(0, 2));
+ writel(0, divider->base + WZRD_CLK_CFG_REG(0, 3));
+ div_addr = divider->base + WZRD_DR_INIT_REG_OFFSET;
+ return clk_wzrd_reconfig(divider, div_addr);
}
static int clk_wzrd_dynamic_all(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
- unsigned long flags = 0;
+ unsigned long flags;
int ret;
spin_lock_irqsave(divider->lock, flags);
@@ -315,21 +545,103 @@ static int clk_wzrd_dynamic_all(struct clk_hw *hw, unsigned long rate,
return ret;
}
+static int clk_wzrd_dynamic_all_ver(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(divider->lock, flags);
+
+ ret = clk_wzrd_dynamic_ver_all_nolock(hw, rate, parent_rate);
+
+ spin_unlock_irqrestore(divider->lock, flags);
+
+ return ret;
+}
+
static unsigned long clk_wzrd_recalc_rate_all(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
u32 m, d, o, div, reg, f;
- reg = readl(divider->base + WZRD_CLK_CFG_REG(0));
+ reg = readl(divider->base + WZRD_CLK_CFG_REG(0, 0));
d = FIELD_GET(WZRD_DIVCLK_DIVIDE_MASK, reg);
m = FIELD_GET(WZRD_CLKFBOUT_MULT_MASK, reg);
- reg = readl(divider->base + WZRD_CLK_CFG_REG(2));
+ reg = readl(divider->base + WZRD_CLK_CFG_REG(0, 2));
o = FIELD_GET(WZRD_DIVCLK_DIVIDE_MASK, reg);
f = FIELD_GET(WZRD_CLKOUT0_FRAC_MASK, reg);
div = DIV_ROUND_CLOSEST(d * (WZRD_FRAC_POINTS * o + f), WZRD_FRAC_POINTS);
return divider_recalc_rate(hw, parent_rate * m, div, divider->table,
+ divider->flags, divider->width);
+}
+
+static unsigned long clk_wzrd_recalc_rate_all_ver(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw);
+ u32 edged, div2, p5en, edge, prediv2, all, regl, regh, mult;
+ u32 div, reg;
+
+ edge = !!(readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_1)) &
+ WZRD_CLKFBOUT_EDGE);
+
+ reg = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_2));
+ regl = FIELD_GET(WZRD_CLKFBOUT_L_MASK, reg);
+ regh = FIELD_GET(WZRD_CLKFBOUT_H_MASK, reg);
+
+ mult = regl + regh + edge;
+ if (!mult)
+ mult = 1;
+
+ regl = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_4)) &
+ WZRD_CLKFBOUT_FRAC_EN;
+ if (regl) {
+ regl = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_3))
+ & WZRD_VERSAL_FRAC_MASK;
+ mult = mult * WZRD_FRAC_GRADIENT + regl;
+ parent_rate = DIV_ROUND_CLOSEST((parent_rate * mult), WZRD_FRAC_GRADIENT);
+ } else {
+ parent_rate = parent_rate * mult;
+ }
+
+ /* O Calculation */
+ reg = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKOUT0_1));
+ edged = FIELD_GET(WZRD_CLKFBOUT_EDGE, reg);
+ p5en = FIELD_GET(WZRD_P5EN, reg);
+ prediv2 = FIELD_GET(WZRD_CLKOUT0_PREDIV2, reg);
+
+ reg = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKOUT0_2));
+ /* Low time */
+ regl = FIELD_GET(WZRD_CLKFBOUT_L_MASK, reg);
+ /* High time */
+ regh = FIELD_GET(WZRD_CLKFBOUT_H_MASK, reg);
+ all = regh + regl + edged;
+ if (!all)
+ all = 1;
+
+ if (prediv2)
+ div2 = PREDIV2_MULT * all + p5en;
+ else
+ div2 = all;
+
+ /* D calculation */
+ edged = !!(readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_DESKEW_2)) &
+ WZRD_DIVCLK_EDGE);
+ reg = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_DIVCLK));
+ /* Low time */
+ regl = FIELD_GET(WZRD_CLKFBOUT_L_MASK, reg);
+ /* High time */
+ regh = FIELD_GET(WZRD_CLKFBOUT_H_MASK, reg);
+ div = regl + regh + edged;
+ if (!div)
+ div = 1;
+
+ div = div * div2;
+ return divider_recalc_rate(hw, parent_rate, div, divider->table,
divider->flags, divider->width);
}
@@ -360,6 +672,18 @@ static long clk_wzrd_round_rate_all(struct clk_hw *hw, unsigned long rate,
return rate;
}
+static const struct clk_ops clk_wzrd_ver_divider_ops = {
+ .round_rate = clk_wzrd_round_rate,
+ .set_rate = clk_wzrd_ver_dynamic_reconfig,
+ .recalc_rate = clk_wzrd_recalc_rate_ver,
+};
+
+static const struct clk_ops clk_wzrd_ver_div_all_ops = {
+ .round_rate = clk_wzrd_round_rate_all,
+ .set_rate = clk_wzrd_dynamic_all_ver,
+ .recalc_rate = clk_wzrd_recalc_rate_all_ver,
+};
+
static const struct clk_ops clk_wzrd_clk_divider_ops = {
.round_rate = clk_wzrd_round_rate,
.set_rate = clk_wzrd_dynamic_reconfig,
@@ -484,6 +808,53 @@ static struct clk *clk_wzrd_register_divf(struct device *dev,
return hw->clk;
}
+static struct clk *clk_wzrd_ver_register_divider(struct device *dev,
+ const char *name,
+ const char *parent_name,
+ unsigned long flags,
+ void __iomem *base,
+ u16 offset,
+ u8 shift, u8 width,
+ u8 clk_divider_flags,
+ u32 div_type,
+ spinlock_t *lock)
+{
+ struct clk_wzrd_divider *div;
+ struct clk_hw *hw;
+ struct clk_init_data init;
+ int ret;
+
+ div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
+ init.ops = &clk_divider_ro_ops;
+ else if (div_type == DIV_O)
+ init.ops = &clk_wzrd_ver_divider_ops;
+ else
+ init.ops = &clk_wzrd_ver_div_all_ops;
+ init.flags = flags;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ div->base = base;
+ div->offset = offset;
+ div->shift = shift;
+ div->width = width;
+ div->flags = clk_divider_flags;
+ div->lock = lock;
+ div->hw.init = &init;
+
+ hw = &div->hw;
+ ret = devm_clk_hw_register(dev, hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return hw->clk;
+}
+
static struct clk *clk_wzrd_register_divider(struct device *dev,
const char *name,
const char *parent_name,
@@ -588,18 +959,24 @@ static int __maybe_unused clk_wzrd_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(clk_wzrd_dev_pm_ops, clk_wzrd_suspend,
clk_wzrd_resume);
+static const struct versal_clk_data versal_data = {
+ .is_versal = true,
+};
+
static int clk_wzrd_probe(struct platform_device *pdev)
{
- int i, ret;
+ const char *clkout_name, *clk_name, *clk_mul_name;
+ u32 regl, regh, edge, regld, reghd, edged, div;
+ struct device_node *np = pdev->dev.of_node;
+ const struct versal_clk_data *data;
+ struct clk_wzrd *clk_wzrd;
+ unsigned long flags = 0;
+ void __iomem *ctrl_reg;
u32 reg, reg_f, mult;
+ bool is_versal = false;
unsigned long rate;
- const char *clk_name;
- void __iomem *ctrl_reg;
- struct clk_wzrd *clk_wzrd;
- const char *clkout_name;
- struct device_node *np = pdev->dev.of_node;
int nr_outputs;
- unsigned long flags = 0;
+ int i, ret;
clk_wzrd = devm_kzalloc(&pdev->dev, sizeof(*clk_wzrd), GFP_KERNEL);
if (!clk_wzrd)
@@ -641,6 +1018,10 @@ static int clk_wzrd_probe(struct platform_device *pdev)
goto err_disable_clk;
}
+ data = device_get_match_data(&pdev->dev);
+ if (data)
+ is_versal = data->is_versal;
+
ret = of_property_read_u32(np, "xlnx,nr-outputs", &nr_outputs);
if (ret || nr_outputs > WZRD_NUM_OUTPUTS) {
ret = -EINVAL;
@@ -653,26 +1034,61 @@ static int clk_wzrd_probe(struct platform_device *pdev)
goto err_disable_clk;
}
- if (nr_outputs == 1) {
- clk_wzrd->clkout[0] = clk_wzrd_register_divider
+ if (is_versal) {
+ if (nr_outputs == 1) {
+ clk_wzrd->clkout[0] = clk_wzrd_ver_register_divider
(&pdev->dev, clkout_name,
__clk_get_name(clk_wzrd->clk_in1), 0,
- clk_wzrd->base, WZRD_CLK_CFG_REG(3),
+ clk_wzrd->base, WZRD_CLK_CFG_REG(is_versal, 3),
WZRD_CLKOUT_DIVIDE_SHIFT,
WZRD_CLKOUT_DIVIDE_WIDTH,
CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
DIV_ALL, &clkwzrd_lock);
- goto out;
- }
-
- reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0));
- reg_f = reg & WZRD_CLKFBOUT_FRAC_MASK;
- reg_f = reg_f >> WZRD_CLKFBOUT_FRAC_SHIFT;
+ goto out;
+ }
+ /* register multiplier */
+ edge = !!(readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 0)) &
+ BIT(8));
+ regl = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 1)) &
+ WZRD_CLKFBOUT_L_MASK) >> WZRD_CLKFBOUT_L_SHIFT;
+ regh = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 1)) &
+ WZRD_CLKFBOUT_H_MASK) >> WZRD_CLKFBOUT_H_SHIFT;
+ mult = regl + regh + edge;
+ if (!mult)
+ mult = 1;
+ mult = mult * WZRD_FRAC_GRADIENT;
+
+ regl = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 51)) &
+ WZRD_CLKFBOUT_FRAC_EN;
+ if (regl) {
+ regl = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 48)) &
+ WZRD_VERSAL_FRAC_MASK;
+ mult = mult + regl;
+ }
+ div = 64;
+ } else {
+ if (nr_outputs == 1) {
+ clk_wzrd->clkout[0] = clk_wzrd_register_divider
+ (&pdev->dev, clkout_name,
+ __clk_get_name(clk_wzrd->clk_in1), 0,
+ clk_wzrd->base, WZRD_CLK_CFG_REG(is_versal, 3),
+ WZRD_CLKOUT_DIVIDE_SHIFT,
+ WZRD_CLKOUT_DIVIDE_WIDTH,
+ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ DIV_ALL, &clkwzrd_lock);
- reg = reg & WZRD_CLKFBOUT_MULT_MASK;
- reg = reg >> WZRD_CLKFBOUT_MULT_SHIFT;
- mult = (reg * 1000) + reg_f;
+ goto out;
+ }
+ reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 0));
+ reg_f = reg & WZRD_CLKFBOUT_FRAC_MASK;
+ reg_f = reg_f >> WZRD_CLKFBOUT_FRAC_SHIFT;
+
+ reg = reg & WZRD_CLKFBOUT_MULT_MASK;
+ reg = reg >> WZRD_CLKFBOUT_MULT_SHIFT;
+ mult = (reg * 1000) + reg_f;
+ div = 1000;
+ }
clk_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_mul", dev_name(&pdev->dev));
if (!clk_name) {
ret = -ENOMEM;
@@ -681,7 +1097,7 @@ static int clk_wzrd_probe(struct platform_device *pdev)
clk_wzrd->clks_internal[wzrd_clk_mul] = clk_register_fixed_factor
(&pdev->dev, clk_name,
__clk_get_name(clk_wzrd->clk_in1),
- 0, mult, 1000);
+ 0, mult, div);
if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul])) {
dev_err(&pdev->dev, "unable to register fixed-factor clock\n");
ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul]);
@@ -694,13 +1110,29 @@ static int clk_wzrd_probe(struct platform_device *pdev)
goto err_rm_int_clk;
}
- ctrl_reg = clk_wzrd->base + WZRD_CLK_CFG_REG(0);
- /* register div */
- clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_divider
+ if (is_versal) {
+ edged = !!(readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 20)) &
+ BIT(10));
+ regld = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 21)) &
+ WZRD_CLKFBOUT_L_MASK) >> WZRD_CLKFBOUT_L_SHIFT;
+ reghd = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 21)) &
+ WZRD_CLKFBOUT_H_MASK) >> WZRD_CLKFBOUT_H_SHIFT;
+ div = (regld + reghd + edged);
+ if (!div)
+ div = 1;
+
+ clk_mul_name = __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]);
+ clk_wzrd->clks_internal[wzrd_clk_mul_div] =
+ clk_register_fixed_factor(&pdev->dev, clk_name,
+ clk_mul_name, 0, 1, div);
+ } else {
+ ctrl_reg = clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 0);
+ clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_divider
(&pdev->dev, clk_name,
__clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]),
flags, ctrl_reg, 0, 8, CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ALLOW_ZERO, &clkwzrd_lock);
+ }
if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div])) {
dev_err(&pdev->dev, "unable to register divider clock\n");
ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div]);
@@ -716,24 +1148,35 @@ static int clk_wzrd_probe(struct platform_device *pdev)
goto err_rm_int_clk;
}
- if (!i)
- clk_wzrd->clkout[i] = clk_wzrd_register_divf
- (&pdev->dev, clkout_name,
- clk_name, flags,
- clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12),
- WZRD_CLKOUT_DIVIDE_SHIFT,
- WZRD_CLKOUT_DIVIDE_WIDTH,
- CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
- DIV_O, &clkwzrd_lock);
- else
- clk_wzrd->clkout[i] = clk_wzrd_register_divider
- (&pdev->dev, clkout_name,
- clk_name, 0,
- clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12),
- WZRD_CLKOUT_DIVIDE_SHIFT,
- WZRD_CLKOUT_DIVIDE_WIDTH,
- CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
- DIV_O, &clkwzrd_lock);
+ if (is_versal) {
+ clk_wzrd->clkout[i] = clk_wzrd_ver_register_divider
+ (&pdev->dev,
+ clkout_name, clk_name, 0,
+ clk_wzrd->base,
+ (WZRD_CLK_CFG_REG(is_versal, 3) + i * 8),
+ WZRD_CLKOUT_DIVIDE_SHIFT,
+ WZRD_CLKOUT_DIVIDE_WIDTH,
+ CLK_DIVIDER_ONE_BASED |
+ CLK_DIVIDER_ALLOW_ZERO,
+ DIV_O, &clkwzrd_lock);
+ } else {
+ if (!i)
+ clk_wzrd->clkout[i] = clk_wzrd_register_divf
+ (&pdev->dev, clkout_name, clk_name, flags, clk_wzrd->base,
+ (WZRD_CLK_CFG_REG(is_versal, 2) + i * 12),
+ WZRD_CLKOUT_DIVIDE_SHIFT,
+ WZRD_CLKOUT_DIVIDE_WIDTH,
+ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ DIV_O, &clkwzrd_lock);
+ else
+ clk_wzrd->clkout[i] = clk_wzrd_register_divider
+ (&pdev->dev, clkout_name, clk_name, 0, clk_wzrd->base,
+ (WZRD_CLK_CFG_REG(is_versal, 2) + i * 12),
+ WZRD_CLKOUT_DIVIDE_SHIFT,
+ WZRD_CLKOUT_DIVIDE_WIDTH,
+ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ DIV_O, &clkwzrd_lock);
+ }
if (IS_ERR(clk_wzrd->clkout[i])) {
int j;
@@ -799,9 +1242,10 @@ static void clk_wzrd_remove(struct platform_device *pdev)
}
static const struct of_device_id clk_wzrd_ids[] = {
- { .compatible = "xlnx,clocking-wizard" },
- { .compatible = "xlnx,clocking-wizard-v5.2" },
- { .compatible = "xlnx,clocking-wizard-v6.0" },
+ { .compatible = "xlnx,versal-clk-wizard", .data = &versal_data },
+ { .compatible = "xlnx,clocking-wizard" },
+ { .compatible = "xlnx,clocking-wizard-v5.2" },
+ { .compatible = "xlnx,clocking-wizard-v6.0" },
{ },
};
MODULE_DEVICE_TABLE(of, clk_wzrd_ids);
diff --git a/drivers/clk/zynqmp/clk-mux-zynqmp.c b/drivers/clk/zynqmp/clk-mux-zynqmp.c
index 60359333f26d..9b5d3050b742 100644
--- a/drivers/clk/zynqmp/clk-mux-zynqmp.c
+++ b/drivers/clk/zynqmp/clk-mux-zynqmp.c
@@ -89,7 +89,7 @@ static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index)
static const struct clk_ops zynqmp_clk_mux_ops = {
.get_parent = zynqmp_clk_mux_get_parent,
.set_parent = zynqmp_clk_mux_set_parent,
- .determine_rate = __clk_mux_determine_rate,
+ .determine_rate = __clk_mux_determine_rate_closest,
};
static const struct clk_ops zynqmp_clk_mux_ro_ops = {
diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c
index 33a3b2a22659..5a00487ae408 100644
--- a/drivers/clk/zynqmp/divider.c
+++ b/drivers/clk/zynqmp/divider.c
@@ -110,52 +110,6 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw,
return DIV_ROUND_UP_ULL(parent_rate, value);
}
-static void zynqmp_get_divider2_val(struct clk_hw *hw,
- unsigned long rate,
- struct zynqmp_clk_divider *divider,
- u32 *bestdiv)
-{
- int div1;
- int div2;
- long error = LONG_MAX;
- unsigned long div1_prate;
- struct clk_hw *div1_parent_hw;
- struct zynqmp_clk_divider *pdivider;
- struct clk_hw *div2_parent_hw = clk_hw_get_parent(hw);
-
- if (!div2_parent_hw)
- return;
-
- pdivider = to_zynqmp_clk_divider(div2_parent_hw);
- if (!pdivider)
- return;
-
- div1_parent_hw = clk_hw_get_parent(div2_parent_hw);
- if (!div1_parent_hw)
- return;
-
- div1_prate = clk_hw_get_rate(div1_parent_hw);
- *bestdiv = 1;
- for (div1 = 1; div1 <= pdivider->max_div;) {
- for (div2 = 1; div2 <= divider->max_div;) {
- long new_error = ((div1_prate / div1) / div2) - rate;
-
- if (abs(new_error) < abs(error)) {
- *bestdiv = div2;
- error = new_error;
- }
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
- div2 = div2 << 1;
- else
- div2++;
- }
- if (pdivider->flags & CLK_DIVIDER_POWER_OF_TWO)
- div1 = div1 << 1;
- else
- div1++;
- }
-}
-
/**
* zynqmp_clk_divider_round_rate() - Round rate of divider clock
* @hw: handle between common and hardware-specific interfaces
@@ -174,6 +128,7 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw,
u32 div_type = divider->div_type;
u32 bestdiv;
int ret;
+ u8 width;
/* if read only, just return current value */
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
@@ -193,23 +148,12 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw,
return DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
}
- bestdiv = zynqmp_divider_get_val(*prate, rate, divider->flags);
-
- /*
- * In case of two divisors, compute best divider values and return
- * divider2 value based on compute value. div1 will be automatically
- * set to optimum based on required total divider value.
- */
- if (div_type == TYPE_DIV2 &&
- (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
- zynqmp_get_divider2_val(hw, rate, divider, &bestdiv);
- }
+ width = fls(divider->max_div);
- if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && divider->is_frac)
- bestdiv = rate % *prate ? 1 : bestdiv;
+ rate = divider_round_rate(hw, rate, prate, NULL, width, divider->flags);
- bestdiv = min_t(u32, bestdiv, divider->max_div);
- *prate = rate * bestdiv;
+ if (divider->is_frac && (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && (rate % *prate))
+ *prate = rate;
return rate;
}
diff --git a/drivers/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c
index 1548dea15df1..1b481731df96 100644
--- a/drivers/comedi/comedi_fops.c
+++ b/drivers/comedi/comedi_fops.c
@@ -1714,8 +1714,8 @@ static int __comedi_get_user_chanlist(struct comedi_device *dev,
lockdep_assert_held(&dev->mutex);
cmd->chanlist = NULL;
- chanlist = memdup_user(user_chanlist,
- cmd->chanlist_len * sizeof(unsigned int));
+ chanlist = memdup_array_user(user_chanlist,
+ cmd->chanlist_len, sizeof(unsigned int));
if (IS_ERR(chanlist))
return PTR_ERR(chanlist);
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 3c69040920b8..2ca70b0b5fdc 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -302,7 +302,10 @@ static bool hwp_forced __read_mostly;
static struct cpufreq_driver *intel_pstate_driver __read_mostly;
-#define HYBRID_SCALING_FACTOR 78741
+#define HYBRID_SCALING_FACTOR 78741
+#define HYBRID_SCALING_FACTOR_MTL 80000
+
+static int hybrid_scaling_factor = HYBRID_SCALING_FACTOR;
static inline int core_get_scaling(void)
{
@@ -422,7 +425,7 @@ static int intel_pstate_cppc_get_scaling(int cpu)
*/
if (!ret && cppc_perf.nominal_perf && cppc_perf.nominal_freq &&
cppc_perf.nominal_perf * 100 != cppc_perf.nominal_freq)
- return HYBRID_SCALING_FACTOR;
+ return hybrid_scaling_factor;
return core_get_scaling();
}
@@ -1968,7 +1971,7 @@ static int hwp_get_cpu_scaling(int cpu)
smp_call_function_single(cpu, hybrid_get_type, &cpu_type, 1);
/* P-cores have a smaller perf level-to-freqency scaling factor. */
if (cpu_type == 0x40)
- return HYBRID_SCALING_FACTOR;
+ return hybrid_scaling_factor;
/* Use default core scaling for E-cores */
if (cpu_type == 0x20)
@@ -3399,6 +3402,11 @@ static const struct x86_cpu_id intel_epp_balance_perf[] = {
{}
};
+static const struct x86_cpu_id intel_hybrid_scaling_factor[] = {
+ X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L, HYBRID_SCALING_FACTOR_MTL),
+ {}
+};
+
static int __init intel_pstate_init(void)
{
static struct cpudata **_all_cpu_data;
@@ -3489,9 +3497,16 @@ hwp_cpu_matched:
if (hwp_active) {
const struct x86_cpu_id *id = x86_match_cpu(intel_epp_balance_perf);
+ const struct x86_cpu_id *hybrid_id = x86_match_cpu(intel_hybrid_scaling_factor);
if (id)
epp_values[EPP_INDEX_BALANCE_PERFORMANCE] = id->driver_data;
+
+ if (hybrid_id) {
+ hybrid_scaling_factor = hybrid_id->driver_data;
+ pr_debug("hybrid scaling factor: %d\n", hybrid_scaling_factor);
+ }
+
}
mutex_lock(&intel_pstate_driver_lock);
diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 8ea1d340e438..67998dbd1d46 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -5,6 +5,7 @@ menuconfig CXL_BUS
select FW_LOADER
select FW_UPLOAD
select PCI_DOE
+ select FIRMWARE_TABLE
help
CXL is a bus that is electrically compatible with PCI Express, but
layers three protocols on that signalling (CXL.io, CXL.cache, and
@@ -54,8 +55,10 @@ config CXL_MEM_RAW_COMMANDS
config CXL_ACPI
tristate "CXL ACPI: Platform Support"
depends on ACPI
+ depends on ACPI_NUMA
default CXL_BUS
select ACPI_TABLE_LIB
+ select ACPI_HMAT
help
Enable support for host managed device memory (HDM) resources
published by a platform's ACPI CXL memory layout description. See
diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index 2034eb4ce83f..dcf2b39e1048 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -6,6 +6,7 @@
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/pci.h>
+#include <linux/node.h>
#include <asm/div64.h>
#include "cxlpci.h"
#include "cxl.h"
@@ -17,6 +18,10 @@ struct cxl_cxims_data {
u64 xormaps[] __counted_by(nr_maps);
};
+static const guid_t acpi_cxl_qtg_id_guid =
+ GUID_INIT(0xF365F9A6, 0xA7DE, 0x4071,
+ 0xA6, 0x6A, 0xB4, 0x0C, 0x0B, 0x4F, 0x8E, 0x52);
+
/*
* Find a targets entry (n) in the host bridge interleave list.
* CXL Specification 3.0 Table 9-22
@@ -194,6 +199,123 @@ struct cxl_cfmws_context {
int id;
};
+/**
+ * cxl_acpi_evaluate_qtg_dsm - Retrieve QTG ids via ACPI _DSM
+ * @handle: ACPI handle
+ * @coord: performance access coordinates
+ * @entries: number of QTG IDs to return
+ * @qos_class: int array provided by caller to return QTG IDs
+ *
+ * Return: number of QTG IDs returned, or -errno for errors
+ *
+ * Issue QTG _DSM with accompanied bandwidth and latency data in order to get
+ * the QTG IDs that are suitable for the performance point in order of most
+ * suitable to least suitable. Write back array of QTG IDs and return the
+ * actual number of QTG IDs written back.
+ */
+static int
+cxl_acpi_evaluate_qtg_dsm(acpi_handle handle, struct access_coordinate *coord,
+ int entries, int *qos_class)
+{
+ union acpi_object *out_obj, *out_buf, *obj;
+ union acpi_object in_array[4] = {
+ [0].integer = { ACPI_TYPE_INTEGER, coord->read_latency },
+ [1].integer = { ACPI_TYPE_INTEGER, coord->write_latency },
+ [2].integer = { ACPI_TYPE_INTEGER, coord->read_bandwidth },
+ [3].integer = { ACPI_TYPE_INTEGER, coord->write_bandwidth },
+ };
+ union acpi_object in_obj = {
+ .package = {
+ .type = ACPI_TYPE_PACKAGE,
+ .count = 4,
+ .elements = in_array,
+ },
+ };
+ int count, pkg_entries, i;
+ u16 max_qtg;
+ int rc;
+
+ if (!entries)
+ return -EINVAL;
+
+ out_obj = acpi_evaluate_dsm(handle, &acpi_cxl_qtg_id_guid, 1, 1, &in_obj);
+ if (!out_obj)
+ return -ENXIO;
+
+ if (out_obj->type != ACPI_TYPE_PACKAGE) {
+ rc = -ENXIO;
+ goto out;
+ }
+
+ /* Check Max QTG ID */
+ obj = &out_obj->package.elements[0];
+ if (obj->type != ACPI_TYPE_INTEGER) {
+ rc = -ENXIO;
+ goto out;
+ }
+
+ max_qtg = obj->integer.value;
+
+ /* It's legal to have 0 QTG entries */
+ pkg_entries = out_obj->package.count;
+ if (pkg_entries <= 1) {
+ rc = 0;
+ goto out;
+ }
+
+ /* Retrieve QTG IDs package */
+ obj = &out_obj->package.elements[1];
+ if (obj->type != ACPI_TYPE_PACKAGE) {
+ rc = -ENXIO;
+ goto out;
+ }
+
+ pkg_entries = obj->package.count;
+ count = min(entries, pkg_entries);
+ for (i = 0; i < count; i++) {
+ u16 qtg_id;
+
+ out_buf = &obj->package.elements[i];
+ if (out_buf->type != ACPI_TYPE_INTEGER) {
+ rc = -ENXIO;
+ goto out;
+ }
+
+ qtg_id = out_buf->integer.value;
+ if (qtg_id > max_qtg)
+ pr_warn("QTG ID %u greater than MAX %u\n",
+ qtg_id, max_qtg);
+
+ qos_class[i] = qtg_id;
+ }
+ rc = count;
+
+out:
+ ACPI_FREE(out_obj);
+ return rc;
+}
+
+static int cxl_acpi_qos_class(struct cxl_root *cxl_root,
+ struct access_coordinate *coord, int entries,
+ int *qos_class)
+{
+ struct device *dev = cxl_root->port.uport_dev;
+ acpi_handle handle;
+
+ if (!dev_is_platform(dev))
+ return -ENODEV;
+
+ handle = ACPI_HANDLE(dev);
+ if (!handle)
+ return -ENODEV;
+
+ return cxl_acpi_evaluate_qtg_dsm(handle, coord, entries, qos_class);
+}
+
+static const struct cxl_root_ops acpi_root_ops = {
+ .qos_class = cxl_acpi_qos_class,
+};
+
static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
const unsigned long end)
{
@@ -389,8 +511,29 @@ static int cxl_get_chbs(struct device *dev, struct acpi_device *hb,
return 0;
}
+static int get_genport_coordinates(struct device *dev, struct cxl_dport *dport)
+{
+ struct acpi_device *hb = to_cxl_host_bridge(NULL, dev);
+ u32 uid;
+ int rc;
+
+ if (kstrtou32(acpi_device_uid(hb), 0, &uid))
+ return -EINVAL;
+
+ rc = acpi_get_genport_coordinates(uid, &dport->hb_coord);
+ if (rc < 0)
+ return rc;
+
+ /* Adjust back to picoseconds from nanoseconds */
+ dport->hb_coord.read_latency *= 1000;
+ dport->hb_coord.write_latency *= 1000;
+
+ return 0;
+}
+
static int add_host_bridge_dport(struct device *match, void *arg)
{
+ int ret;
acpi_status rc;
struct device *bridge;
struct cxl_dport *dport;
@@ -440,6 +583,10 @@ static int add_host_bridge_dport(struct device *match, void *arg)
if (IS_ERR(dport))
return PTR_ERR(dport);
+ ret = get_genport_coordinates(match, dport);
+ if (ret)
+ dev_dbg(match, "Failed to get generic port perf coordinates.\n");
+
return 0;
}
@@ -656,6 +803,7 @@ static int cxl_acpi_probe(struct platform_device *pdev)
{
int rc;
struct resource *cxl_res;
+ struct cxl_root *cxl_root;
struct cxl_port *root_port;
struct device *host = &pdev->dev;
struct acpi_device *adev = ACPI_COMPANION(host);
@@ -675,9 +823,10 @@ static int cxl_acpi_probe(struct platform_device *pdev)
cxl_res->end = -1;
cxl_res->flags = IORESOURCE_MEM;
- root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL);
- if (IS_ERR(root_port))
- return PTR_ERR(root_port);
+ cxl_root = devm_cxl_add_root(host, &acpi_root_ops);
+ if (IS_ERR(cxl_root))
+ return PTR_ERR(cxl_root);
+ root_port = &cxl_root->port;
rc = bus_for_each_dev(adev->dev.bus, NULL, root_port,
add_host_bridge_dport);
diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile
index 1f66b5d4d935..9259bcc6773c 100644
--- a/drivers/cxl/core/Makefile
+++ b/drivers/cxl/core/Makefile
@@ -13,5 +13,6 @@ cxl_core-y += mbox.o
cxl_core-y += pci.o
cxl_core-y += hdm.o
cxl_core-y += pmu.o
+cxl_core-y += cdat.o
cxl_core-$(CONFIG_TRACING) += trace.o
cxl_core-$(CONFIG_CXL_REGION) += region.o
diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
new file mode 100644
index 000000000000..6fe11546889f
--- /dev/null
+++ b/drivers/cxl/core/cdat.c
@@ -0,0 +1,521 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2023 Intel Corporation. All rights reserved. */
+#include <linux/acpi.h>
+#include <linux/xarray.h>
+#include <linux/fw_table.h>
+#include <linux/node.h>
+#include <linux/overflow.h>
+#include "cxlpci.h"
+#include "cxlmem.h"
+#include "core.h"
+#include "cxl.h"
+
+struct dsmas_entry {
+ struct range dpa_range;
+ u8 handle;
+ struct access_coordinate coord;
+
+ int entries;
+ int qos_class;
+};
+
+static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg,
+ const unsigned long end)
+{
+ struct acpi_cdat_header *hdr = &header->cdat;
+ struct acpi_cdat_dsmas *dsmas;
+ int size = sizeof(*hdr) + sizeof(*dsmas);
+ struct xarray *dsmas_xa = arg;
+ struct dsmas_entry *dent;
+ u16 len;
+ int rc;
+
+ len = le16_to_cpu((__force __le16)hdr->length);
+ if (len != size || (unsigned long)hdr + len > end) {
+ pr_warn("Malformed DSMAS table length: (%u:%u)\n", size, len);
+ return -EINVAL;
+ }
+
+ /* Skip common header */
+ dsmas = (struct acpi_cdat_dsmas *)(hdr + 1);
+
+ dent = kzalloc(sizeof(*dent), GFP_KERNEL);
+ if (!dent)
+ return -ENOMEM;
+
+ dent->handle = dsmas->dsmad_handle;
+ dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address);
+ dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) +
+ le64_to_cpu((__force __le64)dsmas->dpa_length) - 1;
+
+ rc = xa_insert(dsmas_xa, dent->handle, dent, GFP_KERNEL);
+ if (rc) {
+ kfree(dent);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void cxl_access_coordinate_set(struct access_coordinate *coord,
+ int access, unsigned int val)
+{
+ switch (access) {
+ case ACPI_HMAT_ACCESS_LATENCY:
+ coord->read_latency = val;
+ coord->write_latency = val;
+ break;
+ case ACPI_HMAT_READ_LATENCY:
+ coord->read_latency = val;
+ break;
+ case ACPI_HMAT_WRITE_LATENCY:
+ coord->write_latency = val;
+ break;
+ case ACPI_HMAT_ACCESS_BANDWIDTH:
+ coord->read_bandwidth = val;
+ coord->write_bandwidth = val;
+ break;
+ case ACPI_HMAT_READ_BANDWIDTH:
+ coord->read_bandwidth = val;
+ break;
+ case ACPI_HMAT_WRITE_BANDWIDTH:
+ coord->write_bandwidth = val;
+ break;
+ }
+}
+
+static int cdat_dslbis_handler(union acpi_subtable_headers *header, void *arg,
+ const unsigned long end)
+{
+ struct acpi_cdat_header *hdr = &header->cdat;
+ struct acpi_cdat_dslbis *dslbis;
+ int size = sizeof(*hdr) + sizeof(*dslbis);
+ struct xarray *dsmas_xa = arg;
+ struct dsmas_entry *dent;
+ __le64 le_base;
+ __le16 le_val;
+ u64 val;
+ u16 len;
+ int rc;
+
+ len = le16_to_cpu((__force __le16)hdr->length);
+ if (len != size || (unsigned long)hdr + len > end) {
+ pr_warn("Malformed DSLBIS table length: (%u:%u)\n", size, len);
+ return -EINVAL;
+ }
+
+ /* Skip common header */
+ dslbis = (struct acpi_cdat_dslbis *)(hdr + 1);
+
+ /* Skip unrecognized data type */
+ if (dslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH)
+ return 0;
+
+ /* Not a memory type, skip */
+ if ((dslbis->flags & ACPI_HMAT_MEMORY_HIERARCHY) != ACPI_HMAT_MEMORY)
+ return 0;
+
+ dent = xa_load(dsmas_xa, dslbis->handle);
+ if (!dent) {
+ pr_warn("No matching DSMAS entry for DSLBIS entry.\n");
+ return 0;
+ }
+
+ le_base = (__force __le64)dslbis->entry_base_unit;
+ le_val = (__force __le16)dslbis->entry[0];
+ rc = check_mul_overflow(le64_to_cpu(le_base),
+ le16_to_cpu(le_val), &val);
+ if (rc)
+ pr_warn("DSLBIS value overflowed.\n");
+
+ cxl_access_coordinate_set(&dent->coord, dslbis->data_type, val);
+
+ return 0;
+}
+
+static int cdat_table_parse_output(int rc)
+{
+ if (rc < 0)
+ return rc;
+ if (rc == 0)
+ return -ENOENT;
+
+ return 0;
+}
+
+static int cxl_cdat_endpoint_process(struct cxl_port *port,
+ struct xarray *dsmas_xa)
+{
+ int rc;
+
+ rc = cdat_table_parse(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler,
+ dsmas_xa, port->cdat.table);
+ rc = cdat_table_parse_output(rc);
+ if (rc)
+ return rc;
+
+ rc = cdat_table_parse(ACPI_CDAT_TYPE_DSLBIS, cdat_dslbis_handler,
+ dsmas_xa, port->cdat.table);
+ return cdat_table_parse_output(rc);
+}
+
+static int cxl_port_perf_data_calculate(struct cxl_port *port,
+ struct xarray *dsmas_xa)
+{
+ struct access_coordinate c;
+ struct dsmas_entry *dent;
+ int valid_entries = 0;
+ unsigned long index;
+ int rc;
+
+ rc = cxl_endpoint_get_perf_coordinates(port, &c);
+ if (rc) {
+ dev_dbg(&port->dev, "Failed to retrieve perf coordinates.\n");
+ return rc;
+ }
+
+ struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
+
+ if (!cxl_root)
+ return -ENODEV;
+
+ if (!cxl_root->ops || !cxl_root->ops->qos_class)
+ return -EOPNOTSUPP;
+
+ xa_for_each(dsmas_xa, index, dent) {
+ int qos_class;
+
+ dent->coord.read_latency = dent->coord.read_latency +
+ c.read_latency;
+ dent->coord.write_latency = dent->coord.write_latency +
+ c.write_latency;
+ dent->coord.read_bandwidth = min_t(int, c.read_bandwidth,
+ dent->coord.read_bandwidth);
+ dent->coord.write_bandwidth = min_t(int, c.write_bandwidth,
+ dent->coord.write_bandwidth);
+
+ dent->entries = 1;
+ rc = cxl_root->ops->qos_class(cxl_root, &dent->coord, 1,
+ &qos_class);
+ if (rc != 1)
+ continue;
+
+ valid_entries++;
+ dent->qos_class = qos_class;
+ }
+
+ if (!valid_entries)
+ return -ENOENT;
+
+ return 0;
+}
+
+static void add_perf_entry(struct device *dev, struct dsmas_entry *dent,
+ struct list_head *list)
+{
+ struct cxl_dpa_perf *dpa_perf;
+
+ dpa_perf = kzalloc(sizeof(*dpa_perf), GFP_KERNEL);
+ if (!dpa_perf)
+ return;
+
+ dpa_perf->dpa_range = dent->dpa_range;
+ dpa_perf->coord = dent->coord;
+ dpa_perf->qos_class = dent->qos_class;
+ list_add_tail(&dpa_perf->list, list);
+ dev_dbg(dev,
+ "DSMAS: dpa: %#llx qos: %d read_bw: %d write_bw %d read_lat: %d write_lat: %d\n",
+ dent->dpa_range.start, dpa_perf->qos_class,
+ dent->coord.read_bandwidth, dent->coord.write_bandwidth,
+ dent->coord.read_latency, dent->coord.write_latency);
+}
+
+static void free_perf_ents(void *data)
+{
+ struct cxl_memdev_state *mds = data;
+ struct cxl_dpa_perf *dpa_perf, *n;
+ LIST_HEAD(discard);
+
+ list_splice_tail_init(&mds->ram_perf_list, &discard);
+ list_splice_tail_init(&mds->pmem_perf_list, &discard);
+ list_for_each_entry_safe(dpa_perf, n, &discard, list) {
+ list_del(&dpa_perf->list);
+ kfree(dpa_perf);
+ }
+}
+
+static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds,
+ struct xarray *dsmas_xa)
+{
+ struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
+ struct device *dev = cxlds->dev;
+ struct range pmem_range = {
+ .start = cxlds->pmem_res.start,
+ .end = cxlds->pmem_res.end,
+ };
+ struct range ram_range = {
+ .start = cxlds->ram_res.start,
+ .end = cxlds->ram_res.end,
+ };
+ struct dsmas_entry *dent;
+ unsigned long index;
+
+ xa_for_each(dsmas_xa, index, dent) {
+ if (resource_size(&cxlds->ram_res) &&
+ range_contains(&ram_range, &dent->dpa_range))
+ add_perf_entry(dev, dent, &mds->ram_perf_list);
+ else if (resource_size(&cxlds->pmem_res) &&
+ range_contains(&pmem_range, &dent->dpa_range))
+ add_perf_entry(dev, dent, &mds->pmem_perf_list);
+ else
+ dev_dbg(dev, "no partition for dsmas dpa: %#llx\n",
+ dent->dpa_range.start);
+ }
+
+ devm_add_action_or_reset(&cxlds->cxlmd->dev, free_perf_ents, mds);
+}
+
+static int match_cxlrd_qos_class(struct device *dev, void *data)
+{
+ int dev_qos_class = *(int *)data;
+ struct cxl_root_decoder *cxlrd;
+
+ if (!is_root_decoder(dev))
+ return 0;
+
+ cxlrd = to_cxl_root_decoder(dev);
+ if (cxlrd->qos_class == CXL_QOS_CLASS_INVALID)
+ return 0;
+
+ if (cxlrd->qos_class == dev_qos_class)
+ return 1;
+
+ return 0;
+}
+
+static void cxl_qos_match(struct cxl_port *root_port,
+ struct list_head *work_list,
+ struct list_head *discard_list)
+{
+ struct cxl_dpa_perf *dpa_perf, *n;
+
+ list_for_each_entry_safe(dpa_perf, n, work_list, list) {
+ int rc;
+
+ if (dpa_perf->qos_class == CXL_QOS_CLASS_INVALID)
+ return;
+
+ rc = device_for_each_child(&root_port->dev,
+ (void *)&dpa_perf->qos_class,
+ match_cxlrd_qos_class);
+ if (!rc)
+ list_move_tail(&dpa_perf->list, discard_list);
+ }
+}
+
+static int match_cxlrd_hb(struct device *dev, void *data)
+{
+ struct device *host_bridge = data;
+ struct cxl_switch_decoder *cxlsd;
+ struct cxl_root_decoder *cxlrd;
+
+ if (!is_root_decoder(dev))
+ return 0;
+
+ cxlrd = to_cxl_root_decoder(dev);
+ cxlsd = &cxlrd->cxlsd;
+
+ guard(rwsem_read)(&cxl_region_rwsem);
+ for (int i = 0; i < cxlsd->nr_targets; i++) {
+ if (host_bridge == cxlsd->target[i]->dport_dev)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void discard_dpa_perf(struct list_head *list)
+{
+ struct cxl_dpa_perf *dpa_perf, *n;
+
+ list_for_each_entry_safe(dpa_perf, n, list, list) {
+ list_del(&dpa_perf->list);
+ kfree(dpa_perf);
+ }
+}
+DEFINE_FREE(dpa_perf, struct list_head *, if (!list_empty(_T)) discard_dpa_perf(_T))
+
+static int cxl_qos_class_verify(struct cxl_memdev *cxlmd)
+{
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
+ LIST_HEAD(__discard);
+ struct list_head *discard __free(dpa_perf) = &__discard;
+ struct cxl_port *root_port;
+ int rc;
+
+ struct cxl_root *cxl_root __free(put_cxl_root) =
+ find_cxl_root(cxlmd->endpoint);
+
+ if (!cxl_root)
+ return -ENODEV;
+
+ root_port = &cxl_root->port;
+
+ /* Check that the QTG IDs are all sane between end device and root decoders */
+ cxl_qos_match(root_port, &mds->ram_perf_list, discard);
+ cxl_qos_match(root_port, &mds->pmem_perf_list, discard);
+
+ /* Check to make sure that the device's host bridge is under a root decoder */
+ rc = device_for_each_child(&root_port->dev,
+ (void *)cxlmd->endpoint->host_bridge,
+ match_cxlrd_hb);
+ if (!rc) {
+ list_splice_tail_init(&mds->ram_perf_list, discard);
+ list_splice_tail_init(&mds->pmem_perf_list, discard);
+ }
+
+ return rc;
+}
+
+static void discard_dsmas(struct xarray *xa)
+{
+ unsigned long index;
+ void *ent;
+
+ xa_for_each(xa, index, ent) {
+ xa_erase(xa, index);
+ kfree(ent);
+ }
+ xa_destroy(xa);
+}
+DEFINE_FREE(dsmas, struct xarray *, if (_T) discard_dsmas(_T))
+
+void cxl_endpoint_parse_cdat(struct cxl_port *port)
+{
+ struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct xarray __dsmas_xa;
+ struct xarray *dsmas_xa __free(dsmas) = &__dsmas_xa;
+ int rc;
+
+ xa_init(&__dsmas_xa);
+ if (!port->cdat.table)
+ return;
+
+ rc = cxl_cdat_endpoint_process(port, dsmas_xa);
+ if (rc < 0) {
+ dev_dbg(&port->dev, "Failed to parse CDAT: %d\n", rc);
+ return;
+ }
+
+ rc = cxl_port_perf_data_calculate(port, dsmas_xa);
+ if (rc) {
+ dev_dbg(&port->dev, "Failed to do perf coord calculations.\n");
+ return;
+ }
+
+ cxl_memdev_set_qos_class(cxlds, dsmas_xa);
+ cxl_qos_class_verify(cxlmd);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_endpoint_parse_cdat, CXL);
+
+static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg,
+ const unsigned long end)
+{
+ struct acpi_cdat_sslbis *sslbis;
+ int size = sizeof(header->cdat) + sizeof(*sslbis);
+ struct cxl_port *port = arg;
+ struct device *dev = &port->dev;
+ struct acpi_cdat_sslbe *entry;
+ int remain, entries, i;
+ u16 len;
+
+ len = le16_to_cpu((__force __le16)header->cdat.length);
+ remain = len - size;
+ if (!remain || remain % sizeof(*entry) ||
+ (unsigned long)header + len > end) {
+ dev_warn(dev, "Malformed SSLBIS table length: (%u)\n", len);
+ return -EINVAL;
+ }
+
+ /* Skip common header */
+ sslbis = (struct acpi_cdat_sslbis *)((unsigned long)header +
+ sizeof(header->cdat));
+
+ /* Unrecognized data type, we can skip */
+ if (sslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH)
+ return 0;
+
+ entries = remain / sizeof(*entry);
+ entry = (struct acpi_cdat_sslbe *)((unsigned long)header + sizeof(*sslbis));
+
+ for (i = 0; i < entries; i++) {
+ u16 x = le16_to_cpu((__force __le16)entry->portx_id);
+ u16 y = le16_to_cpu((__force __le16)entry->porty_id);
+ __le64 le_base;
+ __le16 le_val;
+ struct cxl_dport *dport;
+ unsigned long index;
+ u16 dsp_id;
+ u64 val;
+
+ switch (x) {
+ case ACPI_CDAT_SSLBIS_US_PORT:
+ dsp_id = y;
+ break;
+ case ACPI_CDAT_SSLBIS_ANY_PORT:
+ switch (y) {
+ case ACPI_CDAT_SSLBIS_US_PORT:
+ dsp_id = x;
+ break;
+ case ACPI_CDAT_SSLBIS_ANY_PORT:
+ dsp_id = ACPI_CDAT_SSLBIS_ANY_PORT;
+ break;
+ default:
+ dsp_id = y;
+ break;
+ }
+ break;
+ default:
+ dsp_id = x;
+ break;
+ }
+
+ le_base = (__force __le64)sslbis->entry_base_unit;
+ le_val = (__force __le16)entry->latency_or_bandwidth;
+
+ if (check_mul_overflow(le64_to_cpu(le_base),
+ le16_to_cpu(le_val), &val))
+ dev_warn(dev, "SSLBIS value overflowed!\n");
+
+ xa_for_each(&port->dports, index, dport) {
+ if (dsp_id == ACPI_CDAT_SSLBIS_ANY_PORT ||
+ dsp_id == dport->port_id)
+ cxl_access_coordinate_set(&dport->sw_coord,
+ sslbis->data_type,
+ val);
+ }
+
+ entry++;
+ }
+
+ return 0;
+}
+
+void cxl_switch_parse_cdat(struct cxl_port *port)
+{
+ int rc;
+
+ if (!port->cdat.table)
+ return;
+
+ rc = cdat_table_parse(ACPI_CDAT_TYPE_SSLBIS, cdat_sslbis_handler,
+ port, port->cdat.table);
+ rc = cdat_table_parse_output(rc);
+ if (rc)
+ dev_dbg(&port->dev, "Failed to parse SSLBIS: %d\n", rc);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_switch_parse_cdat, CXL);
+
+MODULE_IMPORT_NS(CXL);
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 86d7ba23235e..3b64fb1b9ed0 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -88,4 +88,6 @@ enum cxl_poison_trace_type {
CXL_POISON_TRACE_CLEAR,
};
+long cxl_pci_get_latency(struct pci_dev *pdev);
+
#endif /* __CXL_CORE_H__ */
diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index 36270dcfb42e..27166a411705 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -63,6 +63,7 @@ static struct cxl_mem_command cxl_mem_commands[CXL_MEM_COMMAND_ID_MAX] = {
CXL_CMD(GET_SHUTDOWN_STATE, 0, 0x1, 0),
CXL_CMD(SET_SHUTDOWN_STATE, 0x1, 0, 0),
CXL_CMD(GET_SCAN_MEDIA_CAPS, 0x10, 0x4, 0),
+ CXL_CMD(GET_TIMESTAMP, 0, 0x8, 0),
};
/*
@@ -836,54 +837,37 @@ out:
}
EXPORT_SYMBOL_NS_GPL(cxl_enumerate_cmds, CXL);
-/*
- * General Media Event Record
- * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
- */
-static const uuid_t gen_media_event_uuid =
- UUID_INIT(0xfbcd0a77, 0xc260, 0x417f,
- 0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6);
-
-/*
- * DRAM Event Record
- * CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
- */
-static const uuid_t dram_event_uuid =
- UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab,
- 0xb8, 0xaf, 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24);
-
-/*
- * Memory Module Event Record
- * CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
- */
-static const uuid_t mem_mod_event_uuid =
- UUID_INIT(0xfe927475, 0xdd59, 0x4339,
- 0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74);
-
-static void cxl_event_trace_record(const struct cxl_memdev *cxlmd,
- enum cxl_event_log_type type,
- struct cxl_event_record_raw *record)
+void cxl_event_trace_record(const struct cxl_memdev *cxlmd,
+ enum cxl_event_log_type type,
+ enum cxl_event_type event_type,
+ const uuid_t *uuid, union cxl_event *evt)
{
- uuid_t *id = &record->hdr.id;
-
- if (uuid_equal(id, &gen_media_event_uuid)) {
- struct cxl_event_gen_media *rec =
- (struct cxl_event_gen_media *)record;
+ if (event_type == CXL_CPER_EVENT_GEN_MEDIA)
+ trace_cxl_general_media(cxlmd, type, &evt->gen_media);
+ else if (event_type == CXL_CPER_EVENT_DRAM)
+ trace_cxl_dram(cxlmd, type, &evt->dram);
+ else if (event_type == CXL_CPER_EVENT_MEM_MODULE)
+ trace_cxl_memory_module(cxlmd, type, &evt->mem_module);
+ else
+ trace_cxl_generic_event(cxlmd, type, uuid, &evt->generic);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_event_trace_record, CXL);
- trace_cxl_general_media(cxlmd, type, rec);
- } else if (uuid_equal(id, &dram_event_uuid)) {
- struct cxl_event_dram *rec = (struct cxl_event_dram *)record;
+static void __cxl_event_trace_record(const struct cxl_memdev *cxlmd,
+ enum cxl_event_log_type type,
+ struct cxl_event_record_raw *record)
+{
+ enum cxl_event_type ev_type = CXL_CPER_EVENT_GENERIC;
+ const uuid_t *uuid = &record->id;
- trace_cxl_dram(cxlmd, type, rec);
- } else if (uuid_equal(id, &mem_mod_event_uuid)) {
- struct cxl_event_mem_module *rec =
- (struct cxl_event_mem_module *)record;
+ if (uuid_equal(uuid, &CXL_EVENT_GEN_MEDIA_UUID))
+ ev_type = CXL_CPER_EVENT_GEN_MEDIA;
+ else if (uuid_equal(uuid, &CXL_EVENT_DRAM_UUID))
+ ev_type = CXL_CPER_EVENT_DRAM;
+ else if (uuid_equal(uuid, &CXL_EVENT_MEM_MODULE_UUID))
+ ev_type = CXL_CPER_EVENT_MEM_MODULE;
- trace_cxl_memory_module(cxlmd, type, rec);
- } else {
- /* For unknown record types print just the header */
- trace_cxl_generic_event(cxlmd, type, record);
- }
+ cxl_event_trace_record(cxlmd, type, ev_type, uuid, &record->event);
}
static int cxl_clear_event_record(struct cxl_memdev_state *mds,
@@ -926,7 +910,10 @@ static int cxl_clear_event_record(struct cxl_memdev_state *mds,
*/
i = 0;
for (cnt = 0; cnt < total; cnt++) {
- payload->handles[i++] = get_pl->records[cnt].hdr.handle;
+ struct cxl_event_record_raw *raw = &get_pl->records[cnt];
+ struct cxl_event_generic *gen = &raw->event.generic;
+
+ payload->handles[i++] = gen->hdr.handle;
dev_dbg(mds->cxlds.dev, "Event log '%d': Clearing %u\n", log,
le16_to_cpu(payload->handles[i]));
@@ -991,8 +978,8 @@ static void cxl_mem_get_records_log(struct cxl_memdev_state *mds,
break;
for (i = 0; i < nr_rec; i++)
- cxl_event_trace_record(cxlmd, type,
- &payload->records[i]);
+ __cxl_event_trace_record(cxlmd, type,
+ &payload->records[i]);
if (payload->flags & CXL_GET_EVENT_FLAG_OVERFLOW)
trace_cxl_overflow(cxlmd, type, payload);
@@ -1404,6 +1391,8 @@ struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev)
mds->cxlds.reg_map.host = dev;
mds->cxlds.reg_map.resource = CXL_RESOURCE_NONE;
mds->cxlds.type = CXL_DEVTYPE_CLASSMEM;
+ INIT_LIST_HEAD(&mds->ram_perf_list);
+ INIT_LIST_HEAD(&mds->pmem_perf_list);
return mds;
}
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 2f43d368ba07..dae8802ecdb0 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -114,7 +114,7 @@ static DEVICE_ATTR_RO(serial);
static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
- return sprintf(buf, "%d\n", dev_to_node(dev));
+ return sysfs_emit(buf, "%d\n", dev_to_node(dev));
}
static DEVICE_ATTR_RO(numa_node);
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 37e1652afbc7..6c9c8d92f8f7 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright(c) 2021 Intel Corporation. All rights reserved. */
+#include <linux/units.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/device.h>
#include <linux/delay.h>
@@ -979,3 +980,38 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
return PCI_ERS_RESULT_NEED_RESET;
}
EXPORT_SYMBOL_NS_GPL(cxl_error_detected, CXL);
+
+static int cxl_flit_size(struct pci_dev *pdev)
+{
+ if (cxl_pci_flit_256(pdev))
+ return 256;
+
+ return 68;
+}
+
+/**
+ * cxl_pci_get_latency - calculate the link latency for the PCIe link
+ * @pdev: PCI device
+ *
+ * return: calculated latency or 0 for no latency
+ *
+ * CXL Memory Device SW Guide v1.0 2.11.4 Link latency calculation
+ * Link latency = LinkPropagationLatency + FlitLatency + RetimerLatency
+ * LinkProgationLatency is negligible, so 0 will be used
+ * RetimerLatency is assumed to be negligible and 0 will be used
+ * FlitLatency = FlitSize / LinkBandwidth
+ * FlitSize is defined by spec. CXL rev3.0 4.2.1.
+ * 68B flit is used up to 32GT/s. >32GT/s, 256B flit size is used.
+ * The FlitLatency is converted to picoseconds.
+ */
+long cxl_pci_get_latency(struct pci_dev *pdev)
+{
+ long bw;
+
+ bw = pcie_link_speed_mbps(pdev);
+ if (bw < 0)
+ return 0;
+ bw /= BITS_PER_BYTE;
+
+ return cxl_flit_size(pdev) * MEGA / bw;
+}
diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c
index fc94f5240327..e69625a8d6a1 100644
--- a/drivers/cxl/core/pmem.c
+++ b/drivers/cxl/core/pmem.c
@@ -64,14 +64,14 @@ static int match_nvdimm_bridge(struct device *dev, void *data)
struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd)
{
- struct cxl_port *port = find_cxl_root(cxlmd->endpoint);
+ struct cxl_root *cxl_root __free(put_cxl_root) =
+ find_cxl_root(cxlmd->endpoint);
struct device *dev;
- if (!port)
+ if (!cxl_root)
return NULL;
- dev = device_find_child(&port->dev, NULL, match_nvdimm_bridge);
- put_device(&port->dev);
+ dev = device_find_child(&cxl_root->port.dev, NULL, match_nvdimm_bridge);
if (!dev)
return NULL;
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index b7c93bb18f6e..e59d9d37aa65 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -9,6 +9,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/idr.h>
+#include <linux/node.h>
#include <cxlmem.h>
#include <cxlpci.h>
#include <cxl.h>
@@ -172,14 +173,10 @@ static ssize_t target_list_show(struct device *dev,
{
struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev);
ssize_t offset;
- unsigned int seq;
int rc;
- do {
- seq = read_seqbegin(&cxlsd->target_lock);
- rc = emit_target_list(cxlsd, buf);
- } while (read_seqretry(&cxlsd->target_lock, seq));
-
+ guard(rwsem_read)(&cxl_region_rwsem);
+ rc = emit_target_list(cxlsd, buf);
if (rc < 0)
return rc;
offset = rc;
@@ -541,7 +538,10 @@ static void cxl_port_release(struct device *dev)
xa_destroy(&port->dports);
xa_destroy(&port->regions);
ida_free(&cxl_port_ida, port->id);
- kfree(port);
+ if (is_cxl_root(port))
+ kfree(to_cxl_root(port));
+ else
+ kfree(port);
}
static ssize_t decoders_committed_show(struct device *dev,
@@ -669,17 +669,31 @@ static struct lock_class_key cxl_port_key;
static struct cxl_port *cxl_port_alloc(struct device *uport_dev,
struct cxl_dport *parent_dport)
{
- struct cxl_port *port;
+ struct cxl_root *cxl_root __free(kfree) = NULL;
+ struct cxl_port *port, *_port __free(kfree) = NULL;
struct device *dev;
int rc;
- port = kzalloc(sizeof(*port), GFP_KERNEL);
- if (!port)
- return ERR_PTR(-ENOMEM);
+ /* No parent_dport, root cxl_port */
+ if (!parent_dport) {
+ cxl_root = kzalloc(sizeof(*cxl_root), GFP_KERNEL);
+ if (!cxl_root)
+ return ERR_PTR(-ENOMEM);
+ } else {
+ _port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!_port)
+ return ERR_PTR(-ENOMEM);
+ }
rc = ida_alloc(&cxl_port_ida, GFP_KERNEL);
if (rc < 0)
- goto err;
+ return ERR_PTR(rc);
+
+ if (cxl_root)
+ port = &no_free_ptr(cxl_root)->port;
+ else
+ port = no_free_ptr(_port);
+
port->id = rc;
port->uport_dev = uport_dev;
@@ -731,10 +745,6 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev,
dev->type = &cxl_port_type;
return port;
-
-err:
- kfree(port);
- return ERR_PTR(rc);
}
static int cxl_setup_comp_regs(struct device *host, struct cxl_register_map *map,
@@ -841,6 +851,9 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host,
if (rc)
return ERR_PTR(rc);
+ if (parent_dport && dev_is_pci(uport_dev))
+ port->pci_latency = cxl_pci_get_latency(to_pci_dev(uport_dev));
+
return port;
err:
@@ -884,6 +897,22 @@ struct cxl_port *devm_cxl_add_port(struct device *host,
}
EXPORT_SYMBOL_NS_GPL(devm_cxl_add_port, CXL);
+struct cxl_root *devm_cxl_add_root(struct device *host,
+ const struct cxl_root_ops *ops)
+{
+ struct cxl_root *cxl_root;
+ struct cxl_port *port;
+
+ port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL);
+ if (IS_ERR(port))
+ return (struct cxl_root *)port;
+
+ cxl_root = to_cxl_root(port);
+ cxl_root->ops = ops;
+ return cxl_root;
+}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_add_root, CXL);
+
struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port)
{
/* There is no pci_bus associated with a CXL platform-root port */
@@ -939,7 +968,7 @@ static bool dev_is_cxl_root_child(struct device *dev)
return false;
}
-struct cxl_port *find_cxl_root(struct cxl_port *port)
+struct cxl_root *find_cxl_root(struct cxl_port *port)
{
struct cxl_port *iter = port;
@@ -949,10 +978,19 @@ struct cxl_port *find_cxl_root(struct cxl_port *port)
if (!iter)
return NULL;
get_device(&iter->dev);
- return iter;
+ return to_cxl_root(iter);
}
EXPORT_SYMBOL_NS_GPL(find_cxl_root, CXL);
+void put_cxl_root(struct cxl_root *cxl_root)
+{
+ if (!cxl_root)
+ return;
+
+ put_device(&cxl_root->port.dev);
+}
+EXPORT_SYMBOL_NS_GPL(put_cxl_root, CXL);
+
static struct cxl_dport *find_dport(struct cxl_port *port, int id)
{
struct cxl_dport *dport;
@@ -1108,6 +1146,9 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev,
if (rc)
return ERR_PTR(rc);
+ if (dev_is_pci(dport_dev))
+ dport->link_latency = cxl_pci_get_latency(to_pci_dev(dport_dev));
+
return dport;
}
@@ -1633,7 +1674,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_mem_find_port, CXL);
static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd,
struct cxl_port *port, int *target_map)
{
- int i, rc = 0;
+ int i;
if (!target_map)
return 0;
@@ -1643,19 +1684,16 @@ static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd,
if (xa_empty(&port->dports))
return -EINVAL;
- write_seqlock(&cxlsd->target_lock);
- for (i = 0; i < cxlsd->nr_targets; i++) {
+ guard(rwsem_write)(&cxl_region_rwsem);
+ for (i = 0; i < cxlsd->cxld.interleave_ways; i++) {
struct cxl_dport *dport = find_dport(port, target_map[i]);
- if (!dport) {
- rc = -ENXIO;
- break;
- }
+ if (!dport)
+ return -ENXIO;
cxlsd->target[i] = dport;
}
- write_sequnlock(&cxlsd->target_lock);
- return rc;
+ return 0;
}
struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos)
@@ -1725,7 +1763,6 @@ static int cxl_switch_decoder_init(struct cxl_port *port,
return -EINVAL;
cxlsd->nr_targets = nr_targets;
- seqlock_init(&cxlsd->target_lock);
return cxl_decoder_init(port, &cxlsd->cxld);
}
@@ -2059,6 +2096,80 @@ bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd)
}
EXPORT_SYMBOL_NS_GPL(schedule_cxl_memdev_detach, CXL);
+static void combine_coordinates(struct access_coordinate *c1,
+ struct access_coordinate *c2)
+{
+ if (c2->write_bandwidth)
+ c1->write_bandwidth = min(c1->write_bandwidth,
+ c2->write_bandwidth);
+ c1->write_latency += c2->write_latency;
+
+ if (c2->read_bandwidth)
+ c1->read_bandwidth = min(c1->read_bandwidth,
+ c2->read_bandwidth);
+ c1->read_latency += c2->read_latency;
+}
+
+/**
+ * cxl_endpoint_get_perf_coordinates - Retrieve performance numbers stored in dports
+ * of CXL path
+ * @port: endpoint cxl_port
+ * @coord: output performance data
+ *
+ * Return: errno on failure, 0 on success.
+ */
+int cxl_endpoint_get_perf_coordinates(struct cxl_port *port,
+ struct access_coordinate *coord)
+{
+ struct access_coordinate c = {
+ .read_bandwidth = UINT_MAX,
+ .write_bandwidth = UINT_MAX,
+ };
+ struct cxl_port *iter = port;
+ struct cxl_dport *dport;
+ struct pci_dev *pdev;
+ unsigned int bw;
+
+ if (!is_cxl_endpoint(port))
+ return -EINVAL;
+
+ dport = iter->parent_dport;
+
+ /*
+ * Exit the loop when the parent port of the current port is cxl root.
+ * The iterative loop starts at the endpoint and gathers the
+ * latency of the CXL link from the current iter to the next downstream
+ * port each iteration. If the parent is cxl root then there is
+ * nothing to gather.
+ */
+ while (iter && !is_cxl_root(to_cxl_port(iter->dev.parent))) {
+ combine_coordinates(&c, &dport->sw_coord);
+ c.write_latency += dport->link_latency;
+ c.read_latency += dport->link_latency;
+
+ iter = to_cxl_port(iter->dev.parent);
+ dport = iter->parent_dport;
+ }
+
+ /* Augment with the generic port (host bridge) perf data */
+ combine_coordinates(&c, &dport->hb_coord);
+
+ /* Get the calculated PCI paths bandwidth */
+ pdev = to_pci_dev(port->uport_dev->parent);
+ bw = pcie_bandwidth_available(pdev, NULL, NULL, NULL);
+ if (bw == 0)
+ return -ENXIO;
+ bw /= BITS_PER_BYTE;
+
+ c.write_bandwidth = min(c.write_bandwidth, bw);
+ c.read_bandwidth = min(c.read_bandwidth, bw);
+
+ *coord = c;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_endpoint_get_perf_coordinates, CXL);
+
/* for user tooling to ensure port disable work has completed */
static ssize_t flush_store(const struct bus_type *bus, const char *buf, size_t count)
{
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 3e817a6f94c6..0f05692bfec3 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -397,7 +397,7 @@ static ssize_t interleave_ways_store(struct device *dev,
return rc;
/*
- * Even for x3, x9, and x12 interleaves the region interleave must be a
+ * Even for x3, x6, and x12 interleaves the region interleave must be a
* power of 2 multiple of the host bridge interleave.
*/
if (!is_power_of_2(val / cxld->interleave_ways) ||
@@ -552,8 +552,9 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size)
res = alloc_free_mem_region(cxlrd->res, size, SZ_256M,
dev_name(&cxlr->dev));
if (IS_ERR(res)) {
- dev_dbg(&cxlr->dev, "failed to allocate HPA: %ld\n",
- PTR_ERR(res));
+ dev_dbg(&cxlr->dev,
+ "HPA allocation error (%ld) for size:%pap in %s %pr\n",
+ PTR_ERR(res), &size, cxlrd->res->name, cxlrd->res);
return PTR_ERR(res);
}
@@ -2083,13 +2084,13 @@ static struct cxl_region *to_cxl_region(struct device *dev)
return container_of(dev, struct cxl_region, dev);
}
-static void unregister_region(void *dev)
+static void unregister_region(void *_cxlr)
{
- struct cxl_region *cxlr = to_cxl_region(dev);
+ struct cxl_region *cxlr = _cxlr;
struct cxl_region_params *p = &cxlr->params;
int i;
- device_del(dev);
+ device_del(&cxlr->dev);
/*
* Now that region sysfs is shutdown, the parameter block is now
@@ -2100,7 +2101,7 @@ static void unregister_region(void *dev)
detach_target(cxlr, i);
cxl_region_iomem_release(cxlr);
- put_device(dev);
+ put_device(&cxlr->dev);
}
static struct lock_class_key cxl_region_key;
diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h
index a0b5819bc70b..89445435303a 100644
--- a/drivers/cxl/core/trace.h
+++ b/drivers/cxl/core/trace.h
@@ -181,6 +181,7 @@ TRACE_EVENT(cxl_overflow,
* 1) Add CXL_EVT_TP_entry to TP_STRUCT__entry
* 2) Use CXL_EVT_TP_fast_assign within TP_fast_assign;
* pass the dev, log, and CXL event header
+ * NOTE: The uuid must be assigned by the specific trace event
* 3) Use CXL_EVT_TP_printk() instead of TP_printk()
*
* See the generic_event tracepoint as an example.
@@ -203,7 +204,6 @@ TRACE_EVENT(cxl_overflow,
__assign_str(host, dev_name((cxlmd)->dev.parent)); \
__entry->log = (l); \
__entry->serial = (cxlmd)->cxlds->serial; \
- memcpy(&__entry->hdr_uuid, &(hdr).id, sizeof(uuid_t)); \
__entry->hdr_length = (hdr).length; \
__entry->hdr_flags = get_unaligned_le24((hdr).flags); \
__entry->hdr_handle = le16_to_cpu((hdr).handle); \
@@ -225,9 +225,9 @@ TRACE_EVENT(cxl_overflow,
TRACE_EVENT(cxl_generic_event,
TP_PROTO(const struct cxl_memdev *cxlmd, enum cxl_event_log_type log,
- struct cxl_event_record_raw *rec),
+ const uuid_t *uuid, struct cxl_event_generic *gen_rec),
- TP_ARGS(cxlmd, log, rec),
+ TP_ARGS(cxlmd, log, uuid, gen_rec),
TP_STRUCT__entry(
CXL_EVT_TP_entry
@@ -235,8 +235,9 @@ TRACE_EVENT(cxl_generic_event,
),
TP_fast_assign(
- CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
- memcpy(__entry->data, &rec->data, CXL_EVENT_RECORD_DATA_LENGTH);
+ CXL_EVT_TP_fast_assign(cxlmd, log, gen_rec->hdr);
+ memcpy(&__entry->hdr_uuid, uuid, sizeof(uuid_t));
+ memcpy(__entry->data, gen_rec->data, CXL_EVENT_RECORD_DATA_LENGTH);
),
CXL_EVT_TP_printk("%s",
@@ -337,6 +338,7 @@ TRACE_EVENT(cxl_general_media,
TP_fast_assign(
CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
+ memcpy(&__entry->hdr_uuid, &CXL_EVENT_GEN_MEDIA_UUID, sizeof(uuid_t));
/* General Media */
__entry->dpa = le64_to_cpu(rec->phys_addr);
@@ -423,6 +425,7 @@ TRACE_EVENT(cxl_dram,
TP_fast_assign(
CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
+ memcpy(&__entry->hdr_uuid, &CXL_EVENT_DRAM_UUID, sizeof(uuid_t));
/* DRAM */
__entry->dpa = le64_to_cpu(rec->phys_addr);
@@ -570,6 +573,7 @@ TRACE_EVENT(cxl_memory_module,
TP_fast_assign(
CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr);
+ memcpy(&__entry->hdr_uuid, &CXL_EVENT_MEM_MODULE_UUID, sizeof(uuid_t));
/* Memory Module Event */
__entry->event_type = rec->event_type;
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 687043ece101..b6017c0c57b4 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -8,6 +8,7 @@
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/log2.h>
+#include <linux/node.h>
#include <linux/io.h>
/**
@@ -412,7 +413,6 @@ struct cxl_endpoint_decoder {
/**
* struct cxl_switch_decoder - Switch specific CXL HDM Decoder
* @cxld: base cxl_decoder object
- * @target_lock: coordinate coherent reads of the target list
* @nr_targets: number of elements in @target
* @target: active ordered target list in current decoder configuration
*
@@ -424,7 +424,6 @@ struct cxl_endpoint_decoder {
*/
struct cxl_switch_decoder {
struct cxl_decoder cxld;
- seqlock_t target_lock;
int nr_targets;
struct cxl_dport *target[];
};
@@ -590,6 +589,7 @@ struct cxl_dax_region {
* @depth: How deep this port is relative to the root. depth 0 is the root.
* @cdat: Cached CDAT data
* @cdat_available: Should a CDAT attribute be available in sysfs
+ * @pci_latency: Upstream latency in picoseconds
*/
struct cxl_port {
struct device dev;
@@ -612,6 +612,30 @@ struct cxl_port {
size_t length;
} cdat;
bool cdat_available;
+ long pci_latency;
+};
+
+/**
+ * struct cxl_root - logical collection of root cxl_port items
+ *
+ * @port: cxl_port member
+ * @ops: cxl root operations
+ */
+struct cxl_root {
+ struct cxl_port port;
+ const struct cxl_root_ops *ops;
+};
+
+static inline struct cxl_root *
+to_cxl_root(const struct cxl_port *port)
+{
+ return container_of(port, struct cxl_root, port);
+}
+
+struct cxl_root_ops {
+ int (*qos_class)(struct cxl_root *cxl_root,
+ struct access_coordinate *coord, int entries,
+ int *qos_class);
};
static inline struct cxl_dport *
@@ -634,6 +658,9 @@ struct cxl_rcrb_info {
* @rch: Indicate whether this dport was enumerated in RCH or VH mode
* @port: reference to cxl_port that contains this downstream port
* @regs: Dport parsed register blocks
+ * @sw_coord: access coordinates (performance) for switch from CDAT
+ * @hb_coord: access coordinates (performance) from ACPI generic port (host bridge)
+ * @link_latency: calculated PCIe downstream latency
*/
struct cxl_dport {
struct device *dport_dev;
@@ -643,6 +670,9 @@ struct cxl_dport {
bool rch;
struct cxl_port *port;
struct cxl_regs regs;
+ struct access_coordinate sw_coord;
+ struct access_coordinate hb_coord;
+ long link_latency;
};
/**
@@ -700,7 +730,12 @@ struct cxl_port *devm_cxl_add_port(struct device *host,
struct device *uport_dev,
resource_size_t component_reg_phys,
struct cxl_dport *parent_dport);
-struct cxl_port *find_cxl_root(struct cxl_port *port);
+struct cxl_root *devm_cxl_add_root(struct device *host,
+ const struct cxl_root_ops *ops);
+struct cxl_root *find_cxl_root(struct cxl_port *port);
+void put_cxl_root(struct cxl_root *cxl_root);
+DEFINE_FREE(put_cxl_root, struct cxl_root *, if (_T) put_cxl_root(_T))
+
int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
void cxl_bus_rescan(void);
void cxl_bus_drain(void);
@@ -839,6 +874,12 @@ static inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
}
#endif
+void cxl_endpoint_parse_cdat(struct cxl_port *port);
+void cxl_switch_parse_cdat(struct cxl_port *port);
+
+int cxl_endpoint_get_perf_coordinates(struct cxl_port *port,
+ struct access_coordinate *coord);
+
/*
* Unit test builds overrides this to __weak, find the 'strong' version
* of these symbols in tools/testing/cxl/.
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index a2fcbca253f3..5303d6942b88 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -6,6 +6,8 @@
#include <linux/cdev.h>
#include <linux/uuid.h>
#include <linux/rcuwait.h>
+#include <linux/cxl-event.h>
+#include <linux/node.h>
#include "cxl.h"
/* CXL 2.0 8.2.8.5.1.1 Memory Device Status Register */
@@ -392,6 +394,20 @@ enum cxl_devtype {
};
/**
+ * struct cxl_dpa_perf - DPA performance property entry
+ * @list - list entry
+ * @dpa_range - range for DPA address
+ * @coord - QoS performance data (i.e. latency, bandwidth)
+ * @qos_class - QoS Class cookies
+ */
+struct cxl_dpa_perf {
+ struct list_head list;
+ struct range dpa_range;
+ struct access_coordinate coord;
+ int qos_class;
+};
+
+/**
* struct cxl_dev_state - The driver device state
*
* cxl_dev_state represents the CXL driver/device state. It provides an
@@ -455,6 +471,8 @@ struct cxl_dev_state {
* @security: security driver state info
* @fw: firmware upload / activation state
* @mbox_send: @dev specific transport for transmitting mailbox commands
+ * @ram_perf_list: performance data entries matched to RAM
+ * @pmem_perf_list: performance data entries matched to PMEM
*
* See CXL 3.0 8.2.9.8.2 Capacity Configuration and Label Storage for
* details on capacity parameters.
@@ -475,6 +493,10 @@ struct cxl_memdev_state {
u64 active_persistent_bytes;
u64 next_volatile_bytes;
u64 next_persistent_bytes;
+
+ struct list_head ram_perf_list;
+ struct list_head pmem_perf_list;
+
struct cxl_event_state event;
struct cxl_poison_state poison;
struct cxl_security_state security;
@@ -503,6 +525,7 @@ enum cxl_opcode {
CXL_MBOX_OP_GET_FW_INFO = 0x0200,
CXL_MBOX_OP_TRANSFER_FW = 0x0201,
CXL_MBOX_OP_ACTIVATE_FW = 0x0202,
+ CXL_MBOX_OP_GET_TIMESTAMP = 0x0300,
CXL_MBOX_OP_SET_TIMESTAMP = 0x0301,
CXL_MBOX_OP_GET_SUPPORTED_LOGS = 0x0400,
CXL_MBOX_OP_GET_LOG = 0x0401,
@@ -580,25 +603,28 @@ struct cxl_mbox_identify {
} __packed;
/*
- * Common Event Record Format
- * CXL rev 3.0 section 8.2.9.2.1; Table 8-42
+ * General Media Event Record UUID
+ * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
*/
-struct cxl_event_record_hdr {
- uuid_t id;
- u8 length;
- u8 flags[3];
- __le16 handle;
- __le16 related_handle;
- __le64 timestamp;
- u8 maint_op_class;
- u8 reserved[15];
-} __packed;
+#define CXL_EVENT_GEN_MEDIA_UUID \
+ UUID_INIT(0xfbcd0a77, 0xc260, 0x417f, 0x85, 0xa9, 0x08, 0x8b, 0x16, \
+ 0x21, 0xeb, 0xa6)
-#define CXL_EVENT_RECORD_DATA_LENGTH 0x50
-struct cxl_event_record_raw {
- struct cxl_event_record_hdr hdr;
- u8 data[CXL_EVENT_RECORD_DATA_LENGTH];
-} __packed;
+/*
+ * DRAM Event Record UUID
+ * CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44
+ */
+#define CXL_EVENT_DRAM_UUID \
+ UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab, 0xb8, 0xaf, 0x4e, 0x9b, 0xfb, \
+ 0x5c, 0x96, 0x24)
+
+/*
+ * Memory Module Event Record UUID
+ * CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
+ */
+#define CXL_EVENT_MEM_MODULE_UUID \
+ UUID_INIT(0xfe927475, 0xdd59, 0x4339, 0xa5, 0x86, 0x79, 0xba, 0xb1, \
+ 0x13, 0xb7, 0x74)
/*
* Get Event Records output payload
@@ -641,74 +667,6 @@ struct cxl_mbox_clear_event_payload {
} __packed;
#define CXL_CLEAR_EVENT_MAX_HANDLES U8_MAX
-/*
- * General Media Event Record
- * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
- */
-#define CXL_EVENT_GEN_MED_COMP_ID_SIZE 0x10
-struct cxl_event_gen_media {
- struct cxl_event_record_hdr hdr;
- __le64 phys_addr;
- u8 descriptor;
- u8 type;
- u8 transaction_type;
- u8 validity_flags[2];
- u8 channel;
- u8 rank;
- u8 device[3];
- u8 component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE];
- u8 reserved[46];
-} __packed;
-
-/*
- * DRAM Event Record - DER
- * CXL rev 3.0 section 8.2.9.2.1.2; Table 3-44
- */
-#define CXL_EVENT_DER_CORRECTION_MASK_SIZE 0x20
-struct cxl_event_dram {
- struct cxl_event_record_hdr hdr;
- __le64 phys_addr;
- u8 descriptor;
- u8 type;
- u8 transaction_type;
- u8 validity_flags[2];
- u8 channel;
- u8 rank;
- u8 nibble_mask[3];
- u8 bank_group;
- u8 bank;
- u8 row[3];
- u8 column[2];
- u8 correction_mask[CXL_EVENT_DER_CORRECTION_MASK_SIZE];
- u8 reserved[0x17];
-} __packed;
-
-/*
- * Get Health Info Record
- * CXL rev 3.0 section 8.2.9.8.3.1; Table 8-100
- */
-struct cxl_get_health_info {
- u8 health_status;
- u8 media_status;
- u8 add_status;
- u8 life_used;
- u8 device_temp[2];
- u8 dirty_shutdown_cnt[4];
- u8 cor_vol_err_cnt[4];
- u8 cor_per_err_cnt[4];
-} __packed;
-
-/*
- * Memory Module Event Record
- * CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
- */
-struct cxl_event_mem_module {
- struct cxl_event_record_hdr hdr;
- u8 event_type;
- struct cxl_get_health_info info;
- u8 reserved[0x3d];
-} __packed;
-
struct cxl_mbox_get_partition_info {
__le64 active_volatile_cap;
__le64 active_persistent_cap;
@@ -866,6 +824,10 @@ void set_exclusive_cxl_commands(struct cxl_memdev_state *mds,
void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds,
unsigned long *cmds);
void cxl_mem_get_event_records(struct cxl_memdev_state *mds, u32 status);
+void cxl_event_trace_record(const struct cxl_memdev *cxlmd,
+ enum cxl_event_log_type type,
+ enum cxl_event_type event_type,
+ const uuid_t *uuid, union cxl_event *evt);
int cxl_set_timestamp(struct cxl_memdev_state *mds);
int cxl_poison_state_init(struct cxl_memdev_state *mds);
int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len,
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 0fa4799ea316..711b05d9a370 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -85,6 +85,19 @@ struct cdat_entry_header {
__le16 length;
} __packed;
+/*
+ * CXL v3.0 6.2.3 Table 6-4
+ * The table indicates that if PCIe Flit Mode is set, then CXL is in 256B flits
+ * mode, otherwise it's 68B flits mode.
+ */
+static inline bool cxl_pci_flit_256(struct pci_dev *pdev)
+{
+ u16 lnksta2;
+
+ pcie_capability_read_word(pdev, PCI_EXP_LNKSTA2, &lnksta2);
+ return lnksta2 & PCI_EXP_LNKSTA2_FLIT;
+}
+
int devm_cxl_port_enumerate_dports(struct cxl_port *port);
struct cxl_dev_state;
int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index e087febf9af0..c5c9d8e0d88d 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -215,23 +215,78 @@ static ssize_t trigger_poison_list_store(struct device *dev,
}
static DEVICE_ATTR_WO(trigger_poison_list);
+static ssize_t ram_qos_class_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
+ struct cxl_dpa_perf *dpa_perf;
+
+ if (!dev->driver)
+ return -ENOENT;
+
+ if (list_empty(&mds->ram_perf_list))
+ return -ENOENT;
+
+ dpa_perf = list_first_entry(&mds->ram_perf_list, struct cxl_dpa_perf,
+ list);
+
+ return sysfs_emit(buf, "%d\n", dpa_perf->qos_class);
+}
+
+static struct device_attribute dev_attr_ram_qos_class =
+ __ATTR(qos_class, 0444, ram_qos_class_show, NULL);
+
+static ssize_t pmem_qos_class_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+ struct cxl_dev_state *cxlds = cxlmd->cxlds;
+ struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
+ struct cxl_dpa_perf *dpa_perf;
+
+ if (!dev->driver)
+ return -ENOENT;
+
+ if (list_empty(&mds->pmem_perf_list))
+ return -ENOENT;
+
+ dpa_perf = list_first_entry(&mds->pmem_perf_list, struct cxl_dpa_perf,
+ list);
+
+ return sysfs_emit(buf, "%d\n", dpa_perf->qos_class);
+}
+
+static struct device_attribute dev_attr_pmem_qos_class =
+ __ATTR(qos_class, 0444, pmem_qos_class_show, NULL);
+
static umode_t cxl_mem_visible(struct kobject *kobj, struct attribute *a, int n)
{
- if (a == &dev_attr_trigger_poison_list.attr) {
- struct device *dev = kobj_to_dev(kobj);
- struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
- struct cxl_memdev_state *mds =
- to_cxl_memdev_state(cxlmd->cxlds);
+ struct device *dev = kobj_to_dev(kobj);
+ struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
+ struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds);
+ if (a == &dev_attr_trigger_poison_list.attr)
if (!test_bit(CXL_POISON_ENABLED_LIST,
mds->poison.enabled_cmds))
return 0;
- }
+
+ if (a == &dev_attr_pmem_qos_class.attr)
+ if (list_empty(&mds->pmem_perf_list))
+ return 0;
+
+ if (a == &dev_attr_ram_qos_class.attr)
+ if (list_empty(&mds->ram_perf_list))
+ return 0;
+
return a->mode;
}
static struct attribute *cxl_mem_attrs[] = {
&dev_attr_trigger_poison_list.attr,
+ &dev_attr_ram_qos_class.attr,
+ &dev_attr_pmem_qos_class.attr,
NULL
};
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 0155fb66b580..4fd1f207c84e 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright(c) 2020 Intel Corporation. All rights reserved. */
+#include <asm-generic/unaligned.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/moduleparam.h>
#include <linux/module.h>
@@ -969,6 +970,61 @@ static struct pci_driver cxl_pci_driver = {
},
};
+#define CXL_EVENT_HDR_FLAGS_REC_SEVERITY GENMASK(1, 0)
+static void cxl_cper_event_call(enum cxl_event_type ev_type,
+ struct cxl_cper_event_rec *rec)
+{
+ struct cper_cxl_event_devid *device_id = &rec->hdr.device_id;
+ struct pci_dev *pdev __free(pci_dev_put) = NULL;
+ enum cxl_event_log_type log_type;
+ struct cxl_dev_state *cxlds;
+ unsigned int devfn;
+ u32 hdr_flags;
+
+ devfn = PCI_DEVFN(device_id->device_num, device_id->func_num);
+ pdev = pci_get_domain_bus_and_slot(device_id->segment_num,
+ device_id->bus_num, devfn);
+ if (!pdev)
+ return;
+
+ guard(pci_dev)(pdev);
+ if (pdev->driver != &cxl_pci_driver)
+ return;
+
+ cxlds = pci_get_drvdata(pdev);
+ if (!cxlds)
+ return;
+
+ /* Fabricate a log type */
+ hdr_flags = get_unaligned_le24(rec->event.generic.hdr.flags);
+ log_type = FIELD_GET(CXL_EVENT_HDR_FLAGS_REC_SEVERITY, hdr_flags);
+
+ cxl_event_trace_record(cxlds->cxlmd, log_type, ev_type,
+ &uuid_null, &rec->event);
+}
+
+static int __init cxl_pci_driver_init(void)
+{
+ int rc;
+
+ rc = cxl_cper_register_callback(cxl_cper_event_call);
+ if (rc)
+ return rc;
+
+ rc = pci_register_driver(&cxl_pci_driver);
+ if (rc)
+ cxl_cper_unregister_callback(cxl_cper_event_call);
+
+ return rc;
+}
+
+static void __exit cxl_pci_driver_exit(void)
+{
+ pci_unregister_driver(&cxl_pci_driver);
+ cxl_cper_unregister_callback(cxl_cper_event_call);
+}
+
+module_init(cxl_pci_driver_init);
+module_exit(cxl_pci_driver_exit);
MODULE_LICENSE("GPL v2");
-module_pci_driver(cxl_pci_driver);
MODULE_IMPORT_NS(CXL);
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 47bc8e0b8590..97c21566677a 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -69,6 +69,8 @@ static int cxl_switch_port_probe(struct cxl_port *port)
if (rc < 0)
return rc;
+ cxl_switch_parse_cdat(port);
+
cxlhdm = devm_cxl_setup_hdm(port, NULL);
if (!IS_ERR(cxlhdm))
return devm_cxl_enumerate_decoders(cxlhdm, NULL);
@@ -109,6 +111,7 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
/* Cache the data early to ensure is_visible() works */
read_cdat_data(port);
+ cxl_endpoint_parse_cdat(port);
get_device(&cxlmd->dev);
rc = devm_add_action_or_reset(&port->dev, schedule_detach, cxlmd);
@@ -127,14 +130,15 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
* This can't fail in practice as CXL root exit unregisters all
* descendant ports and that in turn synchronizes with cxl_port_probe()
*/
- root = find_cxl_root(port);
+ struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port);
+
+ root = &cxl_root->port;
/*
* Now that all endpoint decoders are successfully enumerated, try to
* assemble regions from committed decoders
*/
device_for_each_child(&port->dev, root, discover_region);
- put_device(&root->dev);
return 0;
}
diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
index fa4d4142a68a..88547a23825b 100644
--- a/drivers/dma/tegra186-gpc-dma.c
+++ b/drivers/dma/tegra186-gpc-dma.c
@@ -1348,8 +1348,8 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
static int tegra_dma_probe(struct platform_device *pdev)
{
const struct tegra_dma_chip_data *cdata = NULL;
- struct iommu_fwspec *iommu_spec;
- unsigned int stream_id, i;
+ unsigned int i;
+ u32 stream_id;
struct tegra_dma *tdma;
int ret;
@@ -1378,12 +1378,10 @@ static int tegra_dma_probe(struct platform_device *pdev)
tdma->dma_dev.dev = &pdev->dev;
- iommu_spec = dev_iommu_fwspec_get(&pdev->dev);
- if (!iommu_spec) {
+ if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) {
dev_err(&pdev->dev, "Missing iommu stream-id\n");
return -EINVAL;
}
- stream_id = iommu_spec->ids[0] & 0xffff;
ret = device_property_read_u32(&pdev->dev, "dma-channel-mask",
&tdma->chan_mask);
diff --git a/drivers/edac/edac_device.h b/drivers/edac/edac_device.h
index 3f44e6b9d387..7db22a4c83ef 100644
--- a/drivers/edac/edac_device.h
+++ b/drivers/edac/edac_device.h
@@ -176,7 +176,7 @@ struct edac_device_ctl_info {
struct edac_dev_sysfs_attribute *sysfs_attributes;
/* pointer to main 'edac' subsys in sysfs */
- struct bus_type *edac_subsys;
+ const struct bus_type *edac_subsys;
/* the internal state of this controller instance */
int op_state;
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
index 010c26be5846..237a542e045a 100644
--- a/drivers/edac/edac_device_sysfs.c
+++ b/drivers/edac/edac_device_sysfs.c
@@ -229,7 +229,7 @@ static struct kobj_type ktype_device_ctrl = {
int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
{
struct device *dev_root;
- struct bus_type *edac_subsys;
+ const struct bus_type *edac_subsys;
int err = -ENODEV;
edac_dbg(1, "\n");
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
index 32a931d0cb71..1c9f62382666 100644
--- a/drivers/edac/edac_module.c
+++ b/drivers/edac/edac_module.c
@@ -67,7 +67,7 @@ char *edac_op_state_to_string(int opstate)
* sysfs object: /sys/devices/system/edac
* need to export to other files
*/
-static struct bus_type edac_subsys = {
+static const struct bus_type edac_subsys = {
.name = "edac",
.dev_name = "edac",
};
@@ -90,7 +90,7 @@ static void edac_subsys_exit(void)
}
/* return pointer to the 'edac' node in sysfs */
-struct bus_type *edac_get_sysfs_subsys(void)
+const struct bus_type *edac_get_sysfs_subsys(void)
{
return &edac_subsys;
}
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
index 901d4cd3ca38..7b44afcf48db 100644
--- a/drivers/edac/edac_pci_sysfs.c
+++ b/drivers/edac/edac_pci_sysfs.c
@@ -338,7 +338,7 @@ static struct kobj_type ktype_edac_pci_main_kobj = {
static int edac_pci_main_kobj_setup(void)
{
int err = -ENODEV;
- struct bus_type *edac_subsys;
+ const struct bus_type *edac_subsys;
struct device *dev_root;
edac_dbg(0, "\n");
diff --git a/drivers/edac/versal_edac.c b/drivers/edac/versal_edac.c
index 8625de20fc71..62caf454b567 100644
--- a/drivers/edac/versal_edac.c
+++ b/drivers/edac/versal_edac.c
@@ -1005,7 +1005,7 @@ static int mc_probe(struct platform_device *pdev)
goto free_edac_mc;
}
- rc = xlnx_register_event(PM_NOTIFY_CB, EVENT_ERROR_PMC_ERR1,
+ rc = xlnx_register_event(PM_NOTIFY_CB, VERSAL_EVENT_ERROR_PMC_ERR1,
XPM_EVENT_ERROR_MASK_DDRMC_CR | XPM_EVENT_ERROR_MASK_DDRMC_NCR |
XPM_EVENT_ERROR_MASK_NOC_CR | XPM_EVENT_ERROR_MASK_NOC_NCR,
false, err_callback, mci);
@@ -1042,7 +1042,7 @@ static int mc_remove(struct platform_device *pdev)
debugfs_remove_recursive(priv->debugfs);
#endif
- xlnx_unregister_event(PM_NOTIFY_CB, EVENT_ERROR_PMC_ERR1,
+ xlnx_unregister_event(PM_NOTIFY_CB, VERSAL_EVENT_ERROR_PMC_ERR1,
XPM_EVENT_ERROR_MASK_DDRMC_CR |
XPM_EVENT_ERROR_MASK_NOC_CR |
XPM_EVENT_ERROR_MASK_NOC_NCR |
diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c
index f72e90ceca53..53de581a393a 100644
--- a/drivers/extcon/extcon-qcom-spmi-misc.c
+++ b/drivers/extcon/extcon-qcom-spmi-misc.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* extcon-qcom-spmi-misc.c - Qualcomm USB extcon driver to support USB ID
* and VBUS detection based on extcon-usb-gpio.c.
*
diff --git a/drivers/extcon/extcon-usbc-tusb320.c b/drivers/extcon/extcon-usbc-tusb320.c
index 4d08c2123e59..2eab341de6b7 100644
--- a/drivers/extcon/extcon-usbc-tusb320.c
+++ b/drivers/extcon/extcon-usbc-tusb320.c
@@ -17,6 +17,7 @@
#include <linux/usb/typec.h>
#include <linux/usb/typec_altmode.h>
#include <linux/usb/role.h>
+#include <linux/irq.h>
#define TUSB320_REG8 0x8
#define TUSB320_REG8_CURRENT_MODE_ADVERTISE GENMASK(7, 6)
@@ -515,6 +516,8 @@ static int tusb320_probe(struct i2c_client *client)
const void *match_data;
unsigned int revision;
int ret;
+ u32 irq_trigger_type = IRQF_TRIGGER_FALLING;
+ struct irq_data *irq_d;
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -568,9 +571,13 @@ static int tusb320_probe(struct i2c_client *client)
*/
tusb320_state_update_handler(priv, true);
+ irq_d = irq_get_irq_data(client->irq);
+ if (irq_d)
+ irq_trigger_type = irqd_get_trigger_type(irq_d);
+
ret = devm_request_threaded_irq(priv->dev, client->irq, NULL,
tusb320_irq_handler,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ IRQF_ONESHOT | irq_trigger_type,
client->name, priv);
if (ret)
tusb320_typec_remove(priv);
diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c
index 6f7a60d2ed91..e7f55c021e56 100644
--- a/drivers/extcon/extcon.c
+++ b/drivers/extcon/extcon.c
@@ -1280,8 +1280,6 @@ int extcon_dev_register(struct extcon_dev *edev)
edev->id = ret;
- dev_set_name(&edev->dev, "extcon%d", edev->id);
-
ret = extcon_alloc_cables(edev);
if (ret < 0)
goto err_alloc_cables;
@@ -1310,6 +1308,7 @@ int extcon_dev_register(struct extcon_dev *edev)
RAW_INIT_NOTIFIER_HEAD(&edev->nh_all);
dev_set_drvdata(&edev->dev, edev);
+ dev_set_name(&edev->dev, "extcon%d", edev->id);
edev->state = 0;
ret = device_register(&edev->dev);
diff --git a/drivers/firewire/.kunitconfig b/drivers/firewire/.kunitconfig
index 1599e069395f..76444a2d5e12 100644
--- a/drivers/firewire/.kunitconfig
+++ b/drivers/firewire/.kunitconfig
@@ -2,3 +2,4 @@ CONFIG_KUNIT=y
CONFIG_PCI=y
CONFIG_FIREWIRE=y
CONFIG_FIREWIRE_KUNIT_UAPI_TEST=y
+CONFIG_FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST=y
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index 0a6596b027db..552a39df8cbd 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -34,6 +34,22 @@ config FIREWIRE_KUNIT_UAPI_TEST
For more information on KUnit and unit tests in general, refer
to the KUnit documentation in Documentation/dev-tools/kunit/.
+config FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST
+ tristate "KUnit tests for device attributes" if !KUNIT_ALL_TESTS
+ depends on FIREWIRE && KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ This builds the KUnit tests for device attribute for node and
+ unit.
+
+ KUnit tests run during boot and output the results to the debug
+ log in TAP format (https://testanything.org/). Only useful for
+ kernel devs running KUnit test harness and are not for inclusion
+ into a production build.
+
+ For more information on KUnit and unit tests in general, refer
+ to the KUnit documentation in Documentation/dev-tools/kunit/.
+
config FIREWIRE_OHCI
tristate "OHCI-1394 controllers"
depends on PCI && FIREWIRE && MMU
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 2828e9573e90..0547253d16fe 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -31,6 +31,8 @@
#include "core.h"
+#define ROOT_DIR_OFFSET 5
+
void fw_csr_iterator_init(struct fw_csr_iterator *ci, const u32 *p)
{
ci->p = p + 1;
@@ -47,6 +49,22 @@ int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value)
}
EXPORT_SYMBOL(fw_csr_iterator_next);
+static const u32 *search_directory(const u32 *directory, int search_key)
+{
+ struct fw_csr_iterator ci;
+ int key, value;
+
+ search_key |= CSR_DIRECTORY;
+
+ fw_csr_iterator_init(&ci, directory);
+ while (fw_csr_iterator_next(&ci, &key, &value)) {
+ if (key == search_key)
+ return ci.p - 1 + value;
+ }
+
+ return NULL;
+}
+
static const u32 *search_leaf(const u32 *directory, int search_key)
{
struct fw_csr_iterator ci;
@@ -135,8 +153,25 @@ static void get_ids(const u32 *directory, int *id)
static void get_modalias_ids(const struct fw_unit *unit, int *id)
{
- get_ids(&fw_parent_device(unit)->config_rom[5], id);
- get_ids(unit->directory, id);
+ const u32 *root_directory = &fw_parent_device(unit)->config_rom[ROOT_DIR_OFFSET];
+ const u32 *directories[] = {NULL, NULL, NULL};
+ const u32 *vendor_directory;
+ int i;
+
+ directories[0] = root_directory;
+
+ // Legacy layout of configuration ROM described in Annex 1 of 'Configuration ROM for AV/C
+ // Devices 1.0 (December 12, 2000, 1394 Trading Association, TA Document 1999027)'.
+ vendor_directory = search_directory(root_directory, CSR_VENDOR);
+ if (!vendor_directory) {
+ directories[1] = unit->directory;
+ } else {
+ directories[1] = vendor_directory;
+ directories[2] = unit->directory;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(directories) && !!directories[i]; ++i)
+ get_ids(directories[i], id);
}
static bool match_ids(const struct ieee1394_device_id *id_table, int *id)
@@ -171,7 +206,7 @@ static const struct ieee1394_device_id *unit_match(struct device *dev,
return NULL;
}
-static bool is_fw_unit(struct device *dev);
+static bool is_fw_unit(const struct device *dev);
static int fw_unit_match(struct device *dev, struct device_driver *drv)
{
@@ -219,7 +254,7 @@ static int fw_unit_uevent(const struct device *dev, struct kobj_uevent_env *env)
return 0;
}
-struct bus_type fw_bus_type = {
+const struct bus_type fw_bus_type = {
.name = "firewire",
.match = fw_unit_match,
.probe = fw_unit_probe,
@@ -251,27 +286,44 @@ static ssize_t show_immediate(struct device *dev,
struct config_rom_attribute *attr =
container_of(dattr, struct config_rom_attribute, attr);
struct fw_csr_iterator ci;
- const u32 *dir;
- int key, value, ret = -ENOENT;
+ const u32 *directories[] = {NULL, NULL};
+ int i, value = -1;
down_read(&fw_device_rwsem);
- if (is_fw_unit(dev))
- dir = fw_unit(dev)->directory;
- else
- dir = fw_device(dev)->config_rom + 5;
+ if (is_fw_unit(dev)) {
+ directories[0] = fw_unit(dev)->directory;
+ } else {
+ const u32 *root_directory = fw_device(dev)->config_rom + ROOT_DIR_OFFSET;
+ const u32 *vendor_directory = search_directory(root_directory, CSR_VENDOR);
+
+ if (!vendor_directory) {
+ directories[0] = root_directory;
+ } else {
+ // Legacy layout of configuration ROM described in Annex 1 of
+ // 'Configuration ROM for AV/C Devices 1.0 (December 12, 2000, 1394 Trading
+ // Association, TA Document 1999027)'.
+ directories[0] = vendor_directory;
+ directories[1] = root_directory;
+ }
+ }
- fw_csr_iterator_init(&ci, dir);
- while (fw_csr_iterator_next(&ci, &key, &value))
- if (attr->key == key) {
- ret = snprintf(buf, buf ? PAGE_SIZE : 0,
- "0x%06x\n", value);
- break;
+ for (i = 0; i < ARRAY_SIZE(directories) && !!directories[i]; ++i) {
+ int key, val;
+
+ fw_csr_iterator_init(&ci, directories[i]);
+ while (fw_csr_iterator_next(&ci, &key, &val)) {
+ if (attr->key == key)
+ value = val;
}
+ }
up_read(&fw_device_rwsem);
- return ret;
+ if (value < 0)
+ return -ENOENT;
+
+ return snprintf(buf, buf ? PAGE_SIZE : 0, "0x%06x\n", value);
}
#define IMMEDIATE_ATTR(name, key) \
@@ -282,17 +334,29 @@ static ssize_t show_text_leaf(struct device *dev,
{
struct config_rom_attribute *attr =
container_of(dattr, struct config_rom_attribute, attr);
- const u32 *dir;
+ const u32 *directories[] = {NULL, NULL};
size_t bufsize;
char dummy_buf[2];
- int ret;
+ int i, ret = -ENOENT;
down_read(&fw_device_rwsem);
- if (is_fw_unit(dev))
- dir = fw_unit(dev)->directory;
- else
- dir = fw_device(dev)->config_rom + 5;
+ if (is_fw_unit(dev)) {
+ directories[0] = fw_unit(dev)->directory;
+ } else {
+ const u32 *root_directory = fw_device(dev)->config_rom + ROOT_DIR_OFFSET;
+ const u32 *vendor_directory = search_directory(root_directory, CSR_VENDOR);
+
+ if (!vendor_directory) {
+ directories[0] = root_directory;
+ } else {
+ // Legacy layout of configuration ROM described in Annex 1 of
+ // 'Configuration ROM for AV/C Devices 1.0 (December 12, 2000, 1394
+ // Trading Association, TA Document 1999027)'.
+ directories[0] = root_directory;
+ directories[1] = vendor_directory;
+ }
+ }
if (buf) {
bufsize = PAGE_SIZE - 1;
@@ -301,7 +365,12 @@ static ssize_t show_text_leaf(struct device *dev,
bufsize = 1;
}
- ret = fw_csr_string(dir, attr->key, buf, bufsize);
+ for (i = 0; i < ARRAY_SIZE(directories) && !!directories[i]; ++i) {
+ int result = fw_csr_string(directories[i], attr->key, buf, bufsize);
+ // Detected.
+ if (result >= 0)
+ ret = result;
+ }
if (ret >= 0) {
/* Strip trailing whitespace and add newline. */
@@ -446,7 +515,7 @@ static ssize_t units_show(struct device *dev,
int key, value, i = 0;
down_read(&fw_device_rwsem);
- fw_csr_iterator_init(&ci, &device->config_rom[5]);
+ fw_csr_iterator_init(&ci, &device->config_rom[ROOT_DIR_OFFSET]);
while (fw_csr_iterator_next(&ci, &key, &value)) {
if (key != (CSR_UNIT | CSR_DIRECTORY))
continue;
@@ -679,7 +748,7 @@ static struct device_type fw_unit_type = {
.release = fw_unit_release,
};
-static bool is_fw_unit(struct device *dev)
+static bool is_fw_unit(const struct device *dev)
{
return dev->type == &fw_unit_type;
}
@@ -691,7 +760,7 @@ static void create_units(struct fw_device *device)
int key, value, i;
i = 0;
- fw_csr_iterator_init(&ci, &device->config_rom[5]);
+ fw_csr_iterator_init(&ci, &device->config_rom[ROOT_DIR_OFFSET]);
while (fw_csr_iterator_next(&ci, &key, &value)) {
if (key != (CSR_UNIT | CSR_DIRECTORY))
continue;
@@ -835,7 +904,7 @@ static struct device_type fw_device_type = {
.release = fw_device_release,
};
-static bool is_fw_device(struct device *dev)
+static bool is_fw_device(const struct device *dev)
{
return dev->type == &fw_device_type;
}
@@ -1308,3 +1377,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
break;
}
}
+
+#ifdef CONFIG_FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST
+#include "device-attribute-test.c"
+#endif
diff --git a/drivers/firewire/device-attribute-test.c b/drivers/firewire/device-attribute-test.c
new file mode 100644
index 000000000000..2f123c6b0a16
--- /dev/null
+++ b/drivers/firewire/device-attribute-test.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// device-attribute-test.c - An application of Kunit to test implementation for device attributes.
+//
+// Copyright (c) 2023 Takashi Sakamoto
+//
+// This file can not be built independently since it is intentionally included in core-device.c.
+
+#include <kunit/test.h>
+
+// Configuration ROM for AV/C Devices 1.0 (Dec. 12, 2000, 1394 Trading Association)
+// Annex C:Configuration ROM example(informative)
+// C.1 Simple AV/C device
+//
+// Copied from the documentation.
+static const u32 simple_avc_config_rom[] = {
+ 0x0404eabf,
+ 0x31333934,
+ 0xe0646102,
+ 0xffffffff,
+ 0xffffffff,
+ 0x00063287, // root directory.
+ 0x03ffffff,
+ 0x8100000a,
+ 0x17ffffff,
+ 0x8100000e,
+ 0x0c0083c0,
+ 0xd1000001,
+ 0x0004442d, // unit 0 directory.
+ 0x1200a02d,
+ 0x13010001,
+ 0x17ffffff,
+ 0x81000007,
+ 0x0005c915, // leaf for textual descriptor.
+ 0x00000000,
+ 0x00000000,
+ 0x56656e64,
+ 0x6f72204e,
+ 0x616d6500,
+ 0x00057f16, // leaf for textual descriptor.
+ 0x00000000,
+ 0x00000000,
+ 0x4d6f6465,
+ 0x6c204e61,
+ 0x6d650000,
+};
+
+// Ibid.
+// Annex A:Consideration for configuration ROM reader design (informative)
+// A.1 Vendor directory
+//
+// Written by hand.
+static const u32 legacy_avc_config_rom[] = {
+ 0x04199fe7,
+ 0x31333934,
+ 0xe0644000,
+ 0x00112233,
+ 0x44556677,
+ 0x0005dace, // root directory.
+ 0x03012345,
+ 0x0c0083c0,
+ 0x8d000009,
+ 0xd1000002,
+ 0xc3000004,
+ 0x0002e107, // unit 0 directory.
+ 0x12abcdef,
+ 0x13543210,
+ 0x0002cb73, // vendor directory.
+ 0x17fedcba,
+ 0x81000004,
+ 0x00026dc1, // leaf for EUI-64.
+ 0x00112233,
+ 0x44556677,
+ 0x00050e84, // leaf for textual descriptor.
+ 0x00000000,
+ 0x00000000,
+ 0x41424344,
+ 0x45464748,
+ 0x494a0000,
+};
+
+static void device_attr_simple_avc(struct kunit *test)
+{
+ static const struct fw_device node = {
+ .device = {
+ .type = &fw_device_type,
+ },
+ .config_rom = simple_avc_config_rom,
+ .config_rom_length = sizeof(simple_avc_config_rom),
+ };
+ static const struct fw_unit unit0 = {
+ .device = {
+ .type = &fw_unit_type,
+ .parent = (struct device *)&node.device,
+ },
+ .directory = &simple_avc_config_rom[12],
+ };
+ struct device *node_dev = (struct device *)&node.device;
+ struct device *unit0_dev = (struct device *)&unit0.device;
+ static const int unit0_expected_ids[] = {0x00ffffff, 0x00ffffff, 0x0000a02d, 0x00010001};
+ char *buf = kunit_kzalloc(test, PAGE_SIZE, GFP_KERNEL);
+ int ids[4] = {0, 0, 0, 0};
+
+ // Ensure associations for node and unit devices.
+
+ KUNIT_ASSERT_TRUE(test, is_fw_device(node_dev));
+ KUNIT_ASSERT_FALSE(test, is_fw_unit(node_dev));
+ KUNIT_ASSERT_PTR_EQ(test, fw_device(node_dev), &node);
+
+ KUNIT_ASSERT_FALSE(test, is_fw_device(unit0_dev));
+ KUNIT_ASSERT_TRUE(test, is_fw_unit(unit0_dev));
+ KUNIT_ASSERT_PTR_EQ(test, fw_parent_device((&unit0)), &node);
+ KUNIT_ASSERT_PTR_EQ(test, fw_unit(unit0_dev), &unit0);
+
+ // For entries in root directory.
+
+ // Vendor immediate entry is found.
+ KUNIT_EXPECT_GT(test, show_immediate(node_dev, &config_rom_attributes[0].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "0xffffff\n");
+
+ // Model immediate entry is found.
+ KUNIT_EXPECT_GT(test, show_immediate(node_dev, &config_rom_attributes[4].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "0xffffff\n");
+
+ // Descriptor leaf entry for vendor is found.
+ KUNIT_EXPECT_GT(test, show_text_leaf(node_dev, &config_rom_attributes[5].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "Vendor Name\n");
+
+ // Descriptor leaf entry for model is found.
+ KUNIT_EXPECT_GT(test, show_text_leaf(node_dev, &config_rom_attributes[6].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "Model Name\n");
+
+ // For entries in unit 0 directory.
+
+ // Vendor immediate entry is not found.
+ KUNIT_EXPECT_LT(test, show_immediate(unit0_dev, &config_rom_attributes[0].attr, buf), 0);
+
+ // Model immediate entry is found.
+ KUNIT_EXPECT_GT(test, show_immediate(unit0_dev, &config_rom_attributes[4].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "0xffffff\n");
+
+ // Descriptor leaf entry for vendor is not found.
+ KUNIT_EXPECT_LT(test, show_text_leaf(unit0_dev, &config_rom_attributes[5].attr, buf), 0);
+
+ // Descriptor leaf entry for model is found.
+ KUNIT_EXPECT_GT(test, show_text_leaf(unit0_dev, &config_rom_attributes[6].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "Model Name\n");
+
+ // Specifier_ID immediate entry is found.
+ KUNIT_EXPECT_GT(test, show_immediate(unit0_dev, &config_rom_attributes[2].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "0x00a02d\n");
+
+ // Version immediate entry is found.
+ KUNIT_EXPECT_GT(test, show_immediate(unit0_dev, &config_rom_attributes[3].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "0x010001\n");
+
+ kunit_kfree(test, buf);
+
+ get_modalias_ids(&unit0, ids);
+ KUNIT_EXPECT_MEMEQ(test, ids, unit0_expected_ids, sizeof(ids));
+}
+
+static void device_attr_legacy_avc(struct kunit *test)
+{
+ static const struct fw_device node = {
+ .device = {
+ .type = &fw_device_type,
+ },
+ .config_rom = legacy_avc_config_rom,
+ .config_rom_length = sizeof(legacy_avc_config_rom),
+ };
+ static const struct fw_unit unit0 = {
+ .device = {
+ .type = &fw_unit_type,
+ .parent = (struct device *)&node.device,
+ },
+ .directory = &legacy_avc_config_rom[11],
+ };
+ struct device *node_dev = (struct device *)&node.device;
+ struct device *unit0_dev = (struct device *)&unit0.device;
+ static const int unit0_expected_ids[] = {0x00012345, 0x00fedcba, 0x00abcdef, 0x00543210};
+ char *buf = kunit_kzalloc(test, PAGE_SIZE, GFP_KERNEL);
+ int ids[4] = {0, 0, 0, 0};
+
+ // Ensure associations for node and unit devices.
+
+ KUNIT_ASSERT_TRUE(test, is_fw_device(node_dev));
+ KUNIT_ASSERT_FALSE(test, is_fw_unit(node_dev));
+ KUNIT_ASSERT_PTR_EQ(test, fw_device((node_dev)), &node);
+
+ KUNIT_ASSERT_FALSE(test, is_fw_device(unit0_dev));
+ KUNIT_ASSERT_TRUE(test, is_fw_unit(unit0_dev));
+ KUNIT_ASSERT_PTR_EQ(test, fw_parent_device((&unit0)), &node);
+ KUNIT_ASSERT_PTR_EQ(test, fw_unit(unit0_dev), &unit0);
+
+ // For entries in root directory.
+
+ // Vendor immediate entry is found.
+ KUNIT_EXPECT_GT(test, show_immediate(node_dev, &config_rom_attributes[0].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "0x012345\n");
+
+ // Model immediate entry is found.
+ KUNIT_EXPECT_GT(test, show_immediate(node_dev, &config_rom_attributes[4].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "0xfedcba\n");
+
+ // Descriptor leaf entry for vendor is not found.
+ KUNIT_EXPECT_LT(test, show_text_leaf(node_dev, &config_rom_attributes[5].attr, buf), 0);
+
+ // Descriptor leaf entry for model is found.
+ KUNIT_EXPECT_GT(test, show_text_leaf(node_dev, &config_rom_attributes[6].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "ABCDEFGHIJ\n");
+
+ // For entries in unit 0 directory.
+
+ // Vendor immediate entry is not found.
+ KUNIT_EXPECT_LT(test, show_immediate(unit0_dev, &config_rom_attributes[0].attr, buf), 0);
+
+ // Model immediate entry is not found.
+ KUNIT_EXPECT_LT(test, show_immediate(unit0_dev, &config_rom_attributes[4].attr, buf), 0);
+
+ // Descriptor leaf entry for vendor is not found.
+ KUNIT_EXPECT_LT(test, show_text_leaf(unit0_dev, &config_rom_attributes[5].attr, buf), 0);
+
+ // Descriptor leaf entry for model is not found.
+ KUNIT_EXPECT_LT(test, show_text_leaf(unit0_dev, &config_rom_attributes[6].attr, buf), 0);
+
+ // Specifier_ID immediate entry is found.
+ KUNIT_EXPECT_GT(test, show_immediate(unit0_dev, &config_rom_attributes[2].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "0xabcdef\n");
+
+ // Version immediate entry is found.
+ KUNIT_EXPECT_GT(test, show_immediate(unit0_dev, &config_rom_attributes[3].attr, buf), 0);
+ KUNIT_EXPECT_STREQ(test, buf, "0x543210\n");
+
+ kunit_kfree(test, buf);
+
+ get_modalias_ids(&unit0, ids);
+ KUNIT_EXPECT_MEMEQ(test, ids, unit0_expected_ids, sizeof(ids));
+}
+
+static struct kunit_case device_attr_test_cases[] = {
+ KUNIT_CASE(device_attr_simple_avc),
+ KUNIT_CASE(device_attr_legacy_avc),
+ {}
+};
+
+static struct kunit_suite device_attr_test_suite = {
+ .name = "firewire-device-attribute",
+ .test_cases = device_attr_test_cases,
+};
+kunit_test_suite(device_attr_test_suite);
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 61eba7646edc..afd38539b92e 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -28,15 +28,6 @@ config ARM_SCPI_PROTOCOL
This protocol library provides interface for all the client drivers
making use of the features offered by the SCP.
-config ARM_SCPI_POWER_DOMAIN
- tristate "SCPI power domain driver"
- depends on ARM_SCPI_PROTOCOL || (COMPILE_TEST && OF)
- default y
- select PM_GENERIC_DOMAINS if PM
- help
- This enables support for the SCPI power domains which can be
- enabled or disabled via the SCP firmware
-
config ARM_SDE_INTERFACE
bool "ARM Software Delegated Exception Interface (SDEI)"
depends on ARM64
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index d305d66bc820..7a8d486e718f 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -3,7 +3,6 @@
# Makefile for the linux kernel.
#
obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o
-obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o
obj-$(CONFIG_ARM_SDE_INTERFACE) += arm_sdei.o
obj-$(CONFIG_DMI) += dmi_scan.o
obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o
diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig
index 706d1264d038..aa5842be19b2 100644
--- a/drivers/firmware/arm_scmi/Kconfig
+++ b/drivers/firmware/arm_scmi/Kconfig
@@ -168,31 +168,6 @@ config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE
endif #ARM_SCMI_PROTOCOL
-config ARM_SCMI_POWER_DOMAIN
- tristate "SCMI power domain driver"
- depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
- default y
- select PM_GENERIC_DOMAINS if PM
- help
- This enables support for the SCMI power domains which can be
- enabled or disabled via the SCP firmware
-
- This driver can also be built as a module. If so, the module
- will be called scmi_pm_domain. Note this may needed early in boot
- before rootfs may be available.
-
-config ARM_SCMI_PERF_DOMAIN
- tristate "SCMI performance domain driver"
- depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
- default y
- select PM_GENERIC_DOMAINS if PM
- help
- This enables support for the SCMI performance domains which can be
- enabled or disabled via the SCP firmware.
-
- This driver can also be built as a module. If so, the module will be
- called scmi_perf_domain.
-
config ARM_SCMI_POWER_CONTROL
tristate "SCMI system power control driver"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index a9f70e6e58ac..3ea64b22cf0d 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -2834,7 +2834,7 @@ clear_ida:
return ret;
}
-static int scmi_remove(struct platform_device *pdev)
+static void scmi_remove(struct platform_device *pdev)
{
int id;
struct scmi_info *info = platform_get_drvdata(pdev);
@@ -2868,8 +2868,6 @@ static int scmi_remove(struct platform_device *pdev)
scmi_cleanup_txrx_channels(info);
ida_free(&scmi_id, info->id);
-
- return 0;
}
static ssize_t protocol_version_show(struct device *dev,
@@ -2947,7 +2945,7 @@ static struct platform_driver scmi_driver = {
.dev_groups = versions_groups,
},
.probe = scmi_probe,
- .remove = scmi_remove,
+ .remove_new = scmi_remove,
};
/**
diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
index 3f123f592cb4..94a6b4e667de 100644
--- a/drivers/firmware/arm_scpi.c
+++ b/drivers/firmware/arm_scpi.c
@@ -863,7 +863,7 @@ static void scpi_free_channels(void *data)
mbox_free_channel(info->channels[i].chan);
}
-static int scpi_remove(struct platform_device *pdev)
+static void scpi_remove(struct platform_device *pdev)
{
int i;
struct scpi_drvinfo *info = platform_get_drvdata(pdev);
@@ -874,8 +874,6 @@ static int scpi_remove(struct platform_device *pdev)
kfree(info->dvfs[i]->opps);
kfree(info->dvfs[i]);
}
-
- return 0;
}
#define MAX_SCPI_XFERS 10
@@ -1048,7 +1046,7 @@ static struct platform_driver scpi_driver = {
.dev_groups = versions_groups,
},
.probe = scpi_probe,
- .remove = scpi_remove,
+ .remove_new = scpi_remove,
};
module_platform_driver(scpi_driver);
diff --git a/drivers/firmware/imx/imx-dsp.c b/drivers/firmware/imx/imx-dsp.c
index a48a58e0c61f..01c8ef14eaec 100644
--- a/drivers/firmware/imx/imx-dsp.c
+++ b/drivers/firmware/imx/imx-dsp.c
@@ -160,7 +160,7 @@ static int imx_dsp_probe(struct platform_device *pdev)
return 0;
}
-static int imx_dsp_remove(struct platform_device *pdev)
+static void imx_dsp_remove(struct platform_device *pdev)
{
struct imx_dsp_chan *dsp_chan;
struct imx_dsp_ipc *dsp_ipc;
@@ -173,8 +173,6 @@ static int imx_dsp_remove(struct platform_device *pdev)
mbox_free_channel(dsp_chan->ch);
kfree(dsp_chan->name);
}
-
- return 0;
}
static struct platform_driver imx_dsp_driver = {
@@ -182,7 +180,7 @@ static struct platform_driver imx_dsp_driver = {
.name = "imx-dsp",
},
.probe = imx_dsp_probe,
- .remove = imx_dsp_remove,
+ .remove_new = imx_dsp_remove,
};
builtin_platform_driver(imx_dsp_driver);
diff --git a/drivers/firmware/mtk-adsp-ipc.c b/drivers/firmware/mtk-adsp-ipc.c
index 85e94ddc7204..a762302978de 100644
--- a/drivers/firmware/mtk-adsp-ipc.c
+++ b/drivers/firmware/mtk-adsp-ipc.c
@@ -116,7 +116,7 @@ static int mtk_adsp_ipc_probe(struct platform_device *pdev)
return 0;
}
-static int mtk_adsp_ipc_remove(struct platform_device *pdev)
+static void mtk_adsp_ipc_remove(struct platform_device *pdev)
{
struct mtk_adsp_ipc *adsp_ipc = dev_get_drvdata(&pdev->dev);
struct mtk_adsp_chan *adsp_chan;
@@ -126,8 +126,6 @@ static int mtk_adsp_ipc_remove(struct platform_device *pdev)
adsp_chan = &adsp_ipc->chans[i];
mbox_free_channel(adsp_chan->ch);
}
-
- return 0;
}
static struct platform_driver mtk_adsp_ipc_driver = {
@@ -135,7 +133,7 @@ static struct platform_driver mtk_adsp_ipc_driver = {
.name = "mtk-adsp-ipc",
},
.probe = mtk_adsp_ipc_probe,
- .remove = mtk_adsp_ipc_remove,
+ .remove_new = mtk_adsp_ipc_remove,
};
builtin_platform_driver(mtk_adsp_ipc_driver);
diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 1448f61173b3..03da9a4354f8 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -731,7 +731,7 @@ err_sel:
return err;
}
-static int fw_cfg_sysfs_remove(struct platform_device *pdev)
+static void fw_cfg_sysfs_remove(struct platform_device *pdev)
{
pr_debug("fw_cfg: unloading.\n");
fw_cfg_sysfs_cache_cleanup();
@@ -739,7 +739,6 @@ static int fw_cfg_sysfs_remove(struct platform_device *pdev)
fw_cfg_io_cleanup();
fw_cfg_kset_unregister_recursive(fw_cfg_fname_kset);
fw_cfg_kobj_cleanup(fw_cfg_sel_ko);
- return 0;
}
static const struct of_device_id fw_cfg_sysfs_mmio_match[] = {
@@ -758,7 +757,7 @@ MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match);
static struct platform_driver fw_cfg_sysfs_driver = {
.probe = fw_cfg_sysfs_probe,
- .remove = fw_cfg_sysfs_remove,
+ .remove_new = fw_cfg_sysfs_remove,
.driver = {
.name = "fw_cfg",
.of_match_table = fw_cfg_sysfs_mmio_match,
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
index 4cd290a60fba..322aada20f74 100644
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -317,7 +317,7 @@ static void rpi_firmware_shutdown(struct platform_device *pdev)
rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_REBOOT, NULL, 0);
}
-static int rpi_firmware_remove(struct platform_device *pdev)
+static void rpi_firmware_remove(struct platform_device *pdev)
{
struct rpi_firmware *fw = platform_get_drvdata(pdev);
@@ -327,8 +327,6 @@ static int rpi_firmware_remove(struct platform_device *pdev)
rpi_clk = NULL;
rpi_firmware_put(fw);
-
- return 0;
}
static const struct of_device_id rpi_firmware_of_match[] = {
@@ -406,7 +404,7 @@ static struct platform_driver rpi_firmware_driver = {
},
.probe = rpi_firmware_probe,
.shutdown = rpi_firmware_shutdown,
- .remove = rpi_firmware_remove,
+ .remove_new = rpi_firmware_remove,
};
module_platform_driver(rpi_firmware_driver);
diff --git a/drivers/firmware/stratix10-rsu.c b/drivers/firmware/stratix10-rsu.c
index 4f7a7abada48..e20cee9c2d32 100644
--- a/drivers/firmware/stratix10-rsu.c
+++ b/drivers/firmware/stratix10-rsu.c
@@ -793,17 +793,16 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
return ret;
}
-static int stratix10_rsu_remove(struct platform_device *pdev)
+static void stratix10_rsu_remove(struct platform_device *pdev)
{
struct stratix10_rsu_priv *priv = platform_get_drvdata(pdev);
stratix10_svc_free_channel(priv->chan);
- return 0;
}
static struct platform_driver stratix10_rsu_driver = {
.probe = stratix10_rsu_probe,
- .remove = stratix10_rsu_remove,
+ .remove_new = stratix10_rsu_remove,
.driver = {
.name = "stratix10-rsu",
.dev_groups = rsu_groups,
diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c
index c693da60e9a9..528f37417aea 100644
--- a/drivers/firmware/stratix10-svc.c
+++ b/drivers/firmware/stratix10-svc.c
@@ -1251,7 +1251,7 @@ err_destroy_pool:
return ret;
}
-static int stratix10_svc_drv_remove(struct platform_device *pdev)
+static void stratix10_svc_drv_remove(struct platform_device *pdev)
{
struct stratix10_svc *svc = dev_get_drvdata(&pdev->dev);
struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev);
@@ -1267,13 +1267,11 @@ static int stratix10_svc_drv_remove(struct platform_device *pdev)
if (ctrl->genpool)
gen_pool_destroy(ctrl->genpool);
list_del(&ctrl->node);
-
- return 0;
}
static struct platform_driver stratix10_svc_driver = {
.probe = stratix10_svc_drv_probe,
- .remove = stratix10_svc_drv_remove,
+ .remove_new = stratix10_svc_drv_remove,
.driver = {
.name = "stratix10-svc",
.of_match_table = stratix10_svc_drv_match,
diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c
index 82fcfd29bc4d..19706bd2642a 100644
--- a/drivers/firmware/sysfb.c
+++ b/drivers/firmware/sysfb.c
@@ -71,7 +71,7 @@ EXPORT_SYMBOL_GPL(sysfb_disable);
static __init int sysfb_init(void)
{
- struct screen_info *si = &screen_info;
+ const struct screen_info *si = &screen_info;
struct simplefb_platform_data mode;
const char *name;
bool compatible;
@@ -119,6 +119,18 @@ static __init int sysfb_init(void)
if (ret)
goto err;
+ /*
+ * The firmware framebuffer is now maintained by the created
+ * device. Disable screen_info after we've consumed it. Prevents
+ * invalid access during kexec reboots.
+ *
+ * TODO: Vgacon still relies on the global screen_info. Make
+ * vgacon work with the platform device, so we can clear
+ * the screen_info unconditionally.
+ */
+ if (strcmp(name, "platform-framebuffer"))
+ screen_info.orig_video_isVGA = 0;
+
goto unlock_mutex;
err:
platform_device_put(pd);
diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c
index 2de0fb139ce1..31d962cdd6eb 100644
--- a/drivers/firmware/turris-mox-rwtm.c
+++ b/drivers/firmware/turris-mox-rwtm.c
@@ -554,7 +554,7 @@ put_kobj:
return ret;
}
-static int turris_mox_rwtm_remove(struct platform_device *pdev)
+static void turris_mox_rwtm_remove(struct platform_device *pdev)
{
struct mox_rwtm *rwtm = platform_get_drvdata(pdev);
@@ -562,8 +562,6 @@ static int turris_mox_rwtm_remove(struct platform_device *pdev)
sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs);
kobject_put(rwtm_to_kobj(rwtm));
mbox_free_channel(rwtm->mbox);
-
- return 0;
}
static const struct of_device_id turris_mox_rwtm_match[] = {
@@ -576,7 +574,7 @@ MODULE_DEVICE_TABLE(of, turris_mox_rwtm_match);
static struct platform_driver turris_mox_rwtm_driver = {
.probe = turris_mox_rwtm_probe,
- .remove = turris_mox_rwtm_remove,
+ .remove_new = turris_mox_rwtm_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = turris_mox_rwtm_match,
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
index b0d22d4455d9..79789f0563f6 100644
--- a/drivers/firmware/xilinx/zynqmp.c
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -92,6 +92,8 @@ static int zynqmp_pm_ret_code(u32 ret_status)
return 0;
case XST_PM_NO_FEATURE:
return -ENOTSUPP;
+ case XST_PM_INVALID_VERSION:
+ return -EOPNOTSUPP;
case XST_PM_NO_ACCESS:
return -EACCES;
case XST_PM_ABORT_SUSPEND:
@@ -101,13 +103,13 @@ static int zynqmp_pm_ret_code(u32 ret_status)
case XST_PM_INTERNAL:
case XST_PM_CONFLICT:
case XST_PM_INVALID_NODE:
+ case XST_PM_INVALID_CRC:
default:
return -EINVAL;
}
}
-static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2,
- u32 *ret_payload)
+static noinline int do_fw_call_fail(u32 *ret_payload, u32 num_args, ...)
{
return -ENODEV;
}
@@ -116,25 +118,35 @@ static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2,
* PM function call wrapper
* Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration
*/
-static int (*do_fw_call)(u64, u64, u64, u32 *ret_payload) = do_fw_call_fail;
+static int (*do_fw_call)(u32 *ret_payload, u32, ...) = do_fw_call_fail;
/**
* do_fw_call_smc() - Call system-level platform management layer (SMC)
- * @arg0: Argument 0 to SMC call
- * @arg1: Argument 1 to SMC call
- * @arg2: Argument 2 to SMC call
+ * @num_args: Number of variable arguments should be <= 8
* @ret_payload: Returned value array
*
* Invoke platform management function via SMC call (no hypervisor present).
*
* Return: Returns status, either success or error+reason
*/
-static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2,
- u32 *ret_payload)
+static noinline int do_fw_call_smc(u32 *ret_payload, u32 num_args, ...)
{
struct arm_smccc_res res;
+ u64 args[8] = {0};
+ va_list arg_list;
+ u8 i;
- arm_smccc_smc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
+ if (num_args > 8)
+ return -EINVAL;
+
+ va_start(arg_list, num_args);
+
+ for (i = 0; i < num_args; i++)
+ args[i] = va_arg(arg_list, u64);
+
+ va_end(arg_list);
+
+ arm_smccc_smc(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], &res);
if (ret_payload) {
ret_payload[0] = lower_32_bits(res.a0);
@@ -148,9 +160,7 @@ static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2,
/**
* do_fw_call_hvc() - Call system-level platform management layer (HVC)
- * @arg0: Argument 0 to HVC call
- * @arg1: Argument 1 to HVC call
- * @arg2: Argument 2 to HVC call
+ * @num_args: Number of variable arguments should be <= 8
* @ret_payload: Returned value array
*
* Invoke platform management function via HVC
@@ -159,12 +169,24 @@ static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2,
*
* Return: Returns status, either success or error+reason
*/
-static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2,
- u32 *ret_payload)
+static noinline int do_fw_call_hvc(u32 *ret_payload, u32 num_args, ...)
{
struct arm_smccc_res res;
+ u64 args[8] = {0};
+ va_list arg_list;
+ u8 i;
+
+ if (num_args > 8)
+ return -EINVAL;
+
+ va_start(arg_list, num_args);
+
+ for (i = 0; i < num_args; i++)
+ args[i] = va_arg(arg_list, u64);
+
+ va_end(arg_list);
- arm_smccc_hvc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
+ arm_smccc_hvc(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], &res);
if (ret_payload) {
ret_payload[0] = lower_32_bits(res.a0);
@@ -180,11 +202,31 @@ static int __do_feature_check_call(const u32 api_id, u32 *ret_payload)
{
int ret;
u64 smc_arg[2];
+ u32 module_id;
+ u32 feature_check_api_id;
- smc_arg[0] = PM_SIP_SVC | PM_FEATURE_CHECK;
- smc_arg[1] = api_id;
+ module_id = FIELD_GET(MODULE_ID_MASK, api_id);
- ret = do_fw_call(smc_arg[0], smc_arg[1], 0, ret_payload);
+ /*
+ * Feature check of APIs belonging to PM, XSEM, and TF-A are handled by calling
+ * PM_FEATURE_CHECK API. For other modules, call PM_API_FEATURES API.
+ */
+ if (module_id == PM_MODULE_ID || module_id == XSEM_MODULE_ID || module_id == TF_A_MODULE_ID)
+ feature_check_api_id = PM_FEATURE_CHECK;
+ else
+ feature_check_api_id = PM_API_FEATURES;
+
+ /*
+ * Feature check of TF-A APIs is done in the TF-A layer and it expects for
+ * MODULE_ID_MASK bits of SMC's arg[0] to be the same as PM_MODULE_ID.
+ */
+ if (module_id == TF_A_MODULE_ID)
+ module_id = PM_MODULE_ID;
+
+ smc_arg[0] = PM_SIP_SVC | FIELD_PREP(MODULE_ID_MASK, module_id) | feature_check_api_id;
+ smc_arg[1] = (api_id & API_ID_MASK);
+
+ ret = do_fw_call(ret_payload, 2, smc_arg[0], smc_arg[1]);
if (ret)
ret = -EOPNOTSUPP;
else
@@ -295,11 +337,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_is_function_supported);
* zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer
* caller function depending on the configuration
* @pm_api_id: Requested PM-API call
- * @arg0: Argument 0 to requested PM-API call
- * @arg1: Argument 1 to requested PM-API call
- * @arg2: Argument 2 to requested PM-API call
- * @arg3: Argument 3 to requested PM-API call
* @ret_payload: Returned value array
+ * @num_args: Number of arguments to requested PM-API call
*
* Invoke platform management function for SMC or HVC call, depending on
* configuration.
@@ -316,26 +355,38 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_is_function_supported);
*
* Return: Returns status, either success or error+reason
*/
-int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1,
- u32 arg2, u32 arg3, u32 *ret_payload)
+int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...)
{
/*
* Added SIP service call Function Identifier
* Make sure to stay in x0 register
*/
- u64 smc_arg[4];
- int ret;
+ u64 smc_arg[8];
+ int ret, i;
+ va_list arg_list;
+ u32 args[14] = {0};
+
+ if (num_args > 14)
+ return -EINVAL;
+
+ va_start(arg_list, num_args);
/* Check if feature is supported or not */
ret = zynqmp_pm_feature(pm_api_id);
if (ret < 0)
return ret;
+ for (i = 0; i < num_args; i++)
+ args[i] = va_arg(arg_list, u32);
+
+ va_end(arg_list);
+
smc_arg[0] = PM_SIP_SVC | pm_api_id;
- smc_arg[1] = ((u64)arg1 << 32) | arg0;
- smc_arg[2] = ((u64)arg3 << 32) | arg2;
+ for (i = 0; i < 7; i++)
+ smc_arg[i + 1] = ((u64)args[(i * 2) + 1] << 32) | args[i * 2];
- return do_fw_call(smc_arg[0], smc_arg[1], smc_arg[2], ret_payload);
+ return do_fw_call(ret_payload, 8, smc_arg[0], smc_arg[1], smc_arg[2], smc_arg[3],
+ smc_arg[4], smc_arg[5], smc_arg[6], smc_arg[7]);
}
static u32 pm_api_version;
@@ -347,14 +398,12 @@ int zynqmp_pm_register_sgi(u32 sgi_num, u32 reset)
{
int ret;
- ret = zynqmp_pm_invoke_fn(TF_A_PM_REGISTER_SGI, sgi_num, reset, 0, 0,
- NULL);
- if (!ret)
+ ret = zynqmp_pm_invoke_fn(TF_A_PM_REGISTER_SGI, NULL, 2, sgi_num, reset);
+ if (ret != -EOPNOTSUPP && !ret)
return ret;
/* try old implementation as fallback strategy if above fails */
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_REGISTER_SGI, sgi_num,
- reset, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, IOCTL_REGISTER_SGI, sgi_num, reset);
}
/**
@@ -376,7 +425,7 @@ int zynqmp_pm_get_api_version(u32 *version)
*version = pm_api_version;
return 0;
}
- ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, 0, 0, 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, ret_payload, 0);
*version = ret_payload[1];
return ret;
@@ -399,7 +448,7 @@ int zynqmp_pm_get_chipid(u32 *idcode, u32 *version)
if (!idcode || !version)
return -EINVAL;
- ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, ret_payload, 0);
*idcode = ret_payload[1];
*version = ret_payload[2];
@@ -414,7 +463,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_chipid);
*
* Return: Returns status, either success or error+reason
*/
-static int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily)
+int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily)
{
u32 ret_payload[PAYLOAD_ARG_CNT];
u32 idcode;
@@ -427,7 +476,7 @@ static int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily)
return 0;
}
- ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, ret_payload, 0);
if (ret < 0)
return ret;
@@ -439,6 +488,7 @@ static int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily)
return 0;
}
+EXPORT_SYMBOL_GPL(zynqmp_pm_get_family_info);
/**
* zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version
@@ -459,8 +509,7 @@ static int zynqmp_pm_get_trustzone_version(u32 *version)
*version = pm_tz_version;
return 0;
}
- ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, 0, 0,
- 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, ret_payload, 0);
*version = ret_payload[1];
return ret;
@@ -507,8 +556,8 @@ int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)
{
int ret;
- ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1,
- qdata.arg2, qdata.arg3, out);
+ ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, out, 4, qdata.qid, qdata.arg1, qdata.arg2,
+ qdata.arg3);
/*
* For clock name query, all bytes in SMC response are clock name
@@ -530,7 +579,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_query_data);
*/
int zynqmp_pm_clock_enable(u32 clock_id)
{
- return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, clock_id, 0, 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, NULL, 1, clock_id);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_clock_enable);
@@ -545,7 +594,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_clock_enable);
*/
int zynqmp_pm_clock_disable(u32 clock_id)
{
- return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, clock_id, 0, 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, NULL, 1, clock_id);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_clock_disable);
@@ -564,8 +613,7 @@ int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state)
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
- ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, clock_id, 0,
- 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, ret_payload, 1, clock_id);
*state = ret_payload[1];
return ret;
@@ -584,8 +632,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getstate);
*/
int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider)
{
- return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, clock_id, divider,
- 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, NULL, 2, clock_id, divider);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setdivider);
@@ -604,8 +651,7 @@ int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
- ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, clock_id, 0,
- 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, ret_payload, 1, clock_id);
*divider = ret_payload[1];
return ret;
@@ -613,47 +659,6 @@ int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)
EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getdivider);
/**
- * zynqmp_pm_clock_setrate() - Set the clock rate for given id
- * @clock_id: ID of the clock
- * @rate: rate value in hz
- *
- * This function is used by master to set rate for any clock.
- *
- * Return: Returns status, either success or error+reason
- */
-int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate)
-{
- return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE, clock_id,
- lower_32_bits(rate),
- upper_32_bits(rate),
- 0, NULL);
-}
-EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setrate);
-
-/**
- * zynqmp_pm_clock_getrate() - Get the clock rate for given id
- * @clock_id: ID of the clock
- * @rate: rate value in hz
- *
- * This function is used by master to get rate
- * for any clock.
- *
- * Return: Returns status, either success or error+reason
- */
-int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate)
-{
- u32 ret_payload[PAYLOAD_ARG_CNT];
- int ret;
-
- ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE, clock_id, 0,
- 0, 0, ret_payload);
- *rate = ((u64)ret_payload[2] << 32) | ret_payload[1];
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getrate);
-
-/**
* zynqmp_pm_clock_setparent() - Set the clock parent for given id
* @clock_id: ID of the clock
* @parent_id: parent id
@@ -664,8 +669,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getrate);
*/
int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id)
{
- return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, clock_id,
- parent_id, 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, NULL, 2, clock_id, parent_id);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setparent);
@@ -684,8 +688,7 @@ int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id)
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
- ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, clock_id, 0,
- 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, ret_payload, 1, clock_id);
*parent_id = ret_payload[1];
return ret;
@@ -704,8 +707,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getparent);
*/
int zynqmp_pm_set_pll_frac_mode(u32 clk_id, u32 mode)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_PLL_FRAC_MODE,
- clk_id, mode, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_PLL_FRAC_MODE, clk_id, mode);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_mode);
@@ -721,8 +723,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_mode);
*/
int zynqmp_pm_get_pll_frac_mode(u32 clk_id, u32 *mode)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_MODE,
- clk_id, 0, mode);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, mode, 3, 0, IOCTL_GET_PLL_FRAC_MODE, clk_id);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_mode);
@@ -739,8 +740,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_mode);
*/
int zynqmp_pm_set_pll_frac_data(u32 clk_id, u32 data)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_PLL_FRAC_DATA,
- clk_id, data, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_PLL_FRAC_DATA, clk_id, data);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_data);
@@ -756,8 +756,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_data);
*/
int zynqmp_pm_get_pll_frac_data(u32 clk_id, u32 *data)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_DATA,
- clk_id, 0, data);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, data, 3, 0, IOCTL_GET_PLL_FRAC_DATA, clk_id);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_data);
@@ -778,9 +777,8 @@ int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value)
u32 mask = (node_id == NODE_SD_0) ? GENMASK(15, 0) : GENMASK(31, 16);
if (value) {
- return zynqmp_pm_invoke_fn(PM_IOCTL, node_id,
- IOCTL_SET_SD_TAPDELAY,
- type, value, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, node_id, IOCTL_SET_SD_TAPDELAY, type,
+ value);
}
/*
@@ -798,7 +796,7 @@ int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value)
* Use PM_MMIO_READ/PM_MMIO_WRITE to re-implement the missing counter
* part of IOCTL_SET_SD_TAPDELAY which clears SDx_ITAPDLYENA bits.
*/
- return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, reg, mask, 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, NULL, 2, reg, mask);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay);
@@ -814,8 +812,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay);
*/
int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, IOCTL_SD_DLL_RESET,
- type, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, node_id, IOCTL_SD_DLL_RESET, type);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset);
@@ -831,8 +828,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset);
*/
int zynqmp_pm_ospi_mux_select(u32 dev_id, u32 select)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, dev_id, IOCTL_OSPI_MUX_SELECT,
- select, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, dev_id, IOCTL_OSPI_MUX_SELECT, select);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_ospi_mux_select);
@@ -847,8 +843,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_ospi_mux_select);
*/
int zynqmp_pm_write_ggs(u32 index, u32 value)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_GGS,
- index, value, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_WRITE_GGS, index, value);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs);
@@ -863,8 +858,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs);
*/
int zynqmp_pm_read_ggs(u32 index, u32 *value)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_GGS,
- index, 0, value);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, value, 3, 0, IOCTL_READ_GGS, index);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs);
@@ -880,8 +874,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs);
*/
int zynqmp_pm_write_pggs(u32 index, u32 value)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_PGGS, index, value,
- NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_WRITE_PGGS, index, value);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs);
@@ -897,15 +890,13 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs);
*/
int zynqmp_pm_read_pggs(u32 index, u32 *value)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_PGGS, index, 0,
- value);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, value, 3, 0, IOCTL_READ_PGGS, index);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs);
int zynqmp_pm_set_tapdelay_bypass(u32 index, u32 value)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_TAPDELAY_BYPASS,
- index, value, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_TAPDELAY_BYPASS, index, value);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_tapdelay_bypass);
@@ -920,8 +911,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_tapdelay_bypass);
*/
int zynqmp_pm_set_boot_health_status(u32 value)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_BOOT_HEALTH_STATUS,
- value, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, 0, IOCTL_SET_BOOT_HEALTH_STATUS, value);
}
/**
@@ -935,8 +925,7 @@ int zynqmp_pm_set_boot_health_status(u32 value)
int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset,
const enum zynqmp_pm_reset_action assert_flag)
{
- return zynqmp_pm_invoke_fn(PM_RESET_ASSERT, reset, assert_flag,
- 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_RESET_ASSERT, NULL, 2, reset, assert_flag);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_reset_assert);
@@ -955,8 +944,7 @@ int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset, u32 *status)
if (!status)
return -EINVAL;
- ret = zynqmp_pm_invoke_fn(PM_RESET_GET_STATUS, reset, 0,
- 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_RESET_GET_STATUS, ret_payload, 1, reset);
*status = ret_payload[1];
return ret;
@@ -981,9 +969,8 @@ int zynqmp_pm_fpga_load(const u64 address, const u32 size, const u32 flags)
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
- ret = zynqmp_pm_invoke_fn(PM_FPGA_LOAD, lower_32_bits(address),
- upper_32_bits(address), size, flags,
- ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_FPGA_LOAD, ret_payload, 4, lower_32_bits(address),
+ upper_32_bits(address), size, flags);
if (ret_payload[0])
return -ret_payload[0];
@@ -1008,7 +995,7 @@ int zynqmp_pm_fpga_get_status(u32 *value)
if (!value)
return -EINVAL;
- ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, ret_payload, 0);
*value = ret_payload[1];
return ret;
@@ -1036,11 +1023,9 @@ int zynqmp_pm_fpga_get_config_status(u32 *value)
lower_addr = lower_32_bits((u64)&buf);
upper_addr = upper_32_bits((u64)&buf);
- ret = zynqmp_pm_invoke_fn(PM_FPGA_READ,
- XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET,
- lower_addr, upper_addr,
- XILINX_ZYNQMP_PM_FPGA_READ_CONFIG_REG,
- ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_FPGA_READ, ret_payload, 4,
+ XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET, lower_addr, upper_addr,
+ XILINX_ZYNQMP_PM_FPGA_READ_CONFIG_REG);
*value = ret_payload[1];
@@ -1058,7 +1043,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_get_config_status);
*/
int zynqmp_pm_pinctrl_request(const u32 pin)
{
- return zynqmp_pm_invoke_fn(PM_PINCTRL_REQUEST, pin, 0, 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_PINCTRL_REQUEST, NULL, 1, pin);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_request);
@@ -1072,36 +1057,11 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_request);
*/
int zynqmp_pm_pinctrl_release(const u32 pin)
{
- return zynqmp_pm_invoke_fn(PM_PINCTRL_RELEASE, pin, 0, 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_PINCTRL_RELEASE, NULL, 1, pin);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_release);
/**
- * zynqmp_pm_pinctrl_get_function - Read function id set for the given pin
- * @pin: Pin number
- * @id: Buffer to store function ID
- *
- * This function provides the function currently set for the given pin.
- *
- * Return: Returns status, either success or error+reason
- */
-int zynqmp_pm_pinctrl_get_function(const u32 pin, u32 *id)
-{
- u32 ret_payload[PAYLOAD_ARG_CNT];
- int ret;
-
- if (!id)
- return -EINVAL;
-
- ret = zynqmp_pm_invoke_fn(PM_PINCTRL_GET_FUNCTION, pin, 0,
- 0, 0, ret_payload);
- *id = ret_payload[1];
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_get_function);
-
-/**
* zynqmp_pm_pinctrl_set_function - Set requested function for the pin
* @pin: Pin number
* @id: Function ID to set
@@ -1112,8 +1072,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_get_function);
*/
int zynqmp_pm_pinctrl_set_function(const u32 pin, const u32 id)
{
- return zynqmp_pm_invoke_fn(PM_PINCTRL_SET_FUNCTION, pin, id,
- 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_PINCTRL_SET_FUNCTION, NULL, 2, pin, id);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_set_function);
@@ -1136,8 +1095,7 @@ int zynqmp_pm_pinctrl_get_config(const u32 pin, const u32 param,
if (!value)
return -EINVAL;
- ret = zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_GET, pin, param,
- 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_GET, ret_payload, 2, pin, param);
*value = ret_payload[1];
return ret;
@@ -1166,8 +1124,7 @@ int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param,
return -EOPNOTSUPP;
}
- return zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_SET, pin,
- param, value, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_SET, NULL, 3, pin, param, value);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_set_config);
@@ -1185,8 +1142,7 @@ unsigned int zynqmp_pm_bootmode_read(u32 *ps_mode)
unsigned int ret;
u32 ret_payload[PAYLOAD_ARG_CNT];
- ret = zynqmp_pm_invoke_fn(PM_MMIO_READ, CRL_APB_BOOT_PIN_CTRL, 0,
- 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_MMIO_READ, ret_payload, 1, CRL_APB_BOOT_PIN_CTRL);
*ps_mode = ret_payload[1];
@@ -1205,8 +1161,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_read);
*/
int zynqmp_pm_bootmode_write(u32 ps_mode)
{
- return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, CRL_APB_BOOT_PIN_CTRL,
- CRL_APB_BOOTPIN_CTRL_MASK, ps_mode, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, NULL, 3, CRL_APB_BOOT_PIN_CTRL,
+ CRL_APB_BOOTPIN_CTRL_MASK, ps_mode);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_write);
@@ -1221,7 +1177,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_write);
*/
int zynqmp_pm_init_finalize(void)
{
- return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, 0, 0, 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, NULL, 0);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_init_finalize);
@@ -1235,7 +1191,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_init_finalize);
*/
int zynqmp_pm_set_suspend_mode(u32 mode)
{
- return zynqmp_pm_invoke_fn(PM_SET_SUSPEND_MODE, mode, 0, 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_SET_SUSPEND_MODE, NULL, 1, mode);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_suspend_mode);
@@ -1254,8 +1210,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_suspend_mode);
int zynqmp_pm_request_node(const u32 node, const u32 capabilities,
const u32 qos, const enum zynqmp_pm_request_ack ack)
{
- return zynqmp_pm_invoke_fn(PM_REQUEST_NODE, node, capabilities,
- qos, ack, NULL);
+ return zynqmp_pm_invoke_fn(PM_REQUEST_NODE, NULL, 4, node, capabilities, qos, ack);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_request_node);
@@ -1271,7 +1226,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_request_node);
*/
int zynqmp_pm_release_node(const u32 node)
{
- return zynqmp_pm_invoke_fn(PM_RELEASE_NODE, node, 0, 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_RELEASE_NODE, NULL, 1, node);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_release_node);
@@ -1290,8 +1245,7 @@ int zynqmp_pm_get_rpu_mode(u32 node_id, enum rpu_oper_mode *rpu_mode)
u32 ret_payload[PAYLOAD_ARG_CNT];
int ret;
- ret = zynqmp_pm_invoke_fn(PM_IOCTL, node_id,
- IOCTL_GET_RPU_OPER_MODE, 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_IOCTL, ret_payload, 2, node_id, IOCTL_GET_RPU_OPER_MODE);
/* only set rpu_mode if no error */
if (ret == XST_PM_SUCCESS)
@@ -1313,9 +1267,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_rpu_mode);
*/
int zynqmp_pm_set_rpu_mode(u32 node_id, enum rpu_oper_mode rpu_mode)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, node_id,
- IOCTL_SET_RPU_OPER_MODE, (u32)rpu_mode,
- 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, node_id, IOCTL_SET_RPU_OPER_MODE,
+ (u32)rpu_mode);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_rpu_mode);
@@ -1331,9 +1284,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_rpu_mode);
*/
int zynqmp_pm_set_tcm_config(u32 node_id, enum rpu_tcm_comb tcm_mode)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, node_id,
- IOCTL_TCM_COMB_CONFIG, (u32)tcm_mode, 0,
- NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, node_id, IOCTL_TCM_COMB_CONFIG,
+ (u32)tcm_mode);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_tcm_config);
@@ -1348,7 +1300,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_tcm_config);
int zynqmp_pm_force_pwrdwn(const u32 node,
const enum zynqmp_pm_request_ack ack)
{
- return zynqmp_pm_invoke_fn(PM_FORCE_POWERDOWN, node, ack, 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_FORCE_POWERDOWN, NULL, 2, node, ack);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_force_pwrdwn);
@@ -1367,8 +1319,8 @@ int zynqmp_pm_request_wake(const u32 node,
const enum zynqmp_pm_request_ack ack)
{
/* set_addr flag is encoded into 1st bit of address */
- return zynqmp_pm_invoke_fn(PM_REQUEST_WAKEUP, node, address | set_addr,
- address >> 32, ack, NULL);
+ return zynqmp_pm_invoke_fn(PM_REQUEST_WAKEUP, NULL, 4, node, address | set_addr,
+ address >> 32, ack);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_request_wake);
@@ -1388,15 +1340,14 @@ int zynqmp_pm_set_requirement(const u32 node, const u32 capabilities,
const u32 qos,
const enum zynqmp_pm_request_ack ack)
{
- return zynqmp_pm_invoke_fn(PM_SET_REQUIREMENT, node, capabilities,
- qos, ack, NULL);
+ return zynqmp_pm_invoke_fn(PM_SET_REQUIREMENT, NULL, 4, node, capabilities, qos, ack);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_requirement);
/**
* zynqmp_pm_load_pdi - Load and process PDI
- * @src: Source device where PDI is located
- * @address: PDI src address
+ * @src: Source device where PDI is located
+ * @address: PDI src address
*
* This function provides support to load PDI from linux
*
@@ -1404,9 +1355,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_requirement);
*/
int zynqmp_pm_load_pdi(const u32 src, const u64 address)
{
- return zynqmp_pm_invoke_fn(PM_LOAD_PDI, src,
- lower_32_bits(address),
- upper_32_bits(address), 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_LOAD_PDI, NULL, 3, src, lower_32_bits(address),
+ upper_32_bits(address));
}
EXPORT_SYMBOL_GPL(zynqmp_pm_load_pdi);
@@ -1426,9 +1376,8 @@ int zynqmp_pm_aes_engine(const u64 address, u32 *out)
if (!out)
return -EINVAL;
- ret = zynqmp_pm_invoke_fn(PM_SECURE_AES, upper_32_bits(address),
- lower_32_bits(address),
- 0, 0, ret_payload);
+ ret = zynqmp_pm_invoke_fn(PM_SECURE_AES, ret_payload, 2, upper_32_bits(address),
+ lower_32_bits(address));
*out = ret_payload[1];
return ret;
@@ -1456,8 +1405,7 @@ int zynqmp_pm_sha_hash(const u64 address, const u32 size, const u32 flags)
u32 lower_addr = lower_32_bits(address);
u32 upper_addr = upper_32_bits(address);
- return zynqmp_pm_invoke_fn(PM_SECURE_SHA, upper_addr, lower_addr,
- size, flags, NULL);
+ return zynqmp_pm_invoke_fn(PM_SECURE_SHA, NULL, 4, upper_addr, lower_addr, size, flags);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_sha_hash);
@@ -1479,8 +1427,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_sha_hash);
int zynqmp_pm_register_notifier(const u32 node, const u32 event,
const u32 wake, const u32 enable)
{
- return zynqmp_pm_invoke_fn(PM_REGISTER_NOTIFIER, node, event,
- wake, enable, NULL);
+ return zynqmp_pm_invoke_fn(PM_REGISTER_NOTIFIER, NULL, 4, node, event, wake, enable);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_register_notifier);
@@ -1493,8 +1440,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_register_notifier);
*/
int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype)
{
- return zynqmp_pm_invoke_fn(PM_SYSTEM_SHUTDOWN, type, subtype,
- 0, 0, NULL);
+ return zynqmp_pm_invoke_fn(PM_SYSTEM_SHUTDOWN, NULL, 2, type, subtype);
}
/**
@@ -1506,8 +1452,7 @@ int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype)
*/
int zynqmp_pm_set_feature_config(enum pm_feature_config_id id, u32 value)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_FEATURE_CONFIG,
- id, value, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_FEATURE_CONFIG, id, value);
}
/**
@@ -1520,8 +1465,7 @@ int zynqmp_pm_set_feature_config(enum pm_feature_config_id id, u32 value)
int zynqmp_pm_get_feature_config(enum pm_feature_config_id id,
u32 *payload)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_GET_FEATURE_CONFIG,
- id, 0, payload);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, payload, 3, 0, IOCTL_GET_FEATURE_CONFIG, id);
}
/**
@@ -1534,8 +1478,7 @@ int zynqmp_pm_get_feature_config(enum pm_feature_config_id id,
*/
int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, node, IOCTL_SET_SD_CONFIG,
- config, value, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, node, IOCTL_SET_SD_CONFIG, config, value);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_config);
@@ -1550,8 +1493,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_config);
int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config,
u32 value)
{
- return zynqmp_pm_invoke_fn(PM_IOCTL, node, IOCTL_SET_GEM_CONFIG,
- config, value, NULL);
+ return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, node, IOCTL_SET_GEM_CONFIG, config, value);
}
EXPORT_SYMBOL_GPL(zynqmp_pm_set_gem_config);
@@ -1916,7 +1858,6 @@ ATTRIBUTE_GROUPS(zynqmp_firmware);
static int zynqmp_firmware_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *np;
struct zynqmp_devinfo *devinfo;
int ret;
@@ -1924,22 +1865,9 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
if (ret)
return ret;
- np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
- if (!np) {
- np = of_find_compatible_node(NULL, NULL, "xlnx,versal");
- if (!np)
- return 0;
-
+ ret = do_feature_check_call(PM_FEATURE_CHECK);
+ if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_1))
feature_check_enabled = true;
- }
-
- if (!feature_check_enabled) {
- ret = do_feature_check_call(PM_FEATURE_CHECK);
- if (ret >= 0)
- feature_check_enabled = true;
- }
-
- of_node_put(np);
devinfo = devm_kzalloc(dev, sizeof(*devinfo), GFP_KERNEL);
if (!devinfo)
@@ -1992,19 +1920,17 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
zynqmp_pm_api_debugfs_init();
- np = of_find_compatible_node(NULL, NULL, "xlnx,versal");
- if (np) {
+ if (pm_family_code == VERSAL_FAMILY_CODE) {
em_dev = platform_device_register_data(&pdev->dev, "xlnx_event_manager",
-1, NULL, 0);
if (IS_ERR(em_dev))
dev_err_probe(&pdev->dev, PTR_ERR(em_dev), "EM register fail with error\n");
}
- of_node_put(np);
return of_platform_populate(dev->of_node, NULL, NULL, dev);
}
-static int zynqmp_firmware_remove(struct platform_device *pdev)
+static void zynqmp_firmware_remove(struct platform_device *pdev)
{
struct pm_api_feature_data *feature_data;
struct hlist_node *tmp;
@@ -2019,8 +1945,6 @@ static int zynqmp_firmware_remove(struct platform_device *pdev)
}
platform_device_unregister(em_dev);
-
- return 0;
}
static const struct of_device_id zynqmp_firmware_of_match[] = {
@@ -2037,6 +1961,6 @@ static struct platform_driver zynqmp_firmware_driver = {
.dev_groups = zynqmp_firmware_groups,
},
.probe = zynqmp_firmware_probe,
- .remove = zynqmp_firmware_remove,
+ .remove_new = zynqmp_firmware_remove,
};
module_platform_driver(zynqmp_firmware_driver);
diff --git a/drivers/fpga/altera-fpga2sdram.c b/drivers/fpga/altera-fpga2sdram.c
index 1fa2ccc321ab..6b60ca004345 100644
--- a/drivers/fpga/altera-fpga2sdram.c
+++ b/drivers/fpga/altera-fpga2sdram.c
@@ -147,20 +147,18 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev)
return ret;
}
-static int alt_fpga_bridge_remove(struct platform_device *pdev)
+static void alt_fpga_bridge_remove(struct platform_device *pdev)
{
struct fpga_bridge *br = platform_get_drvdata(pdev);
fpga_bridge_unregister(br);
-
- return 0;
}
MODULE_DEVICE_TABLE(of, altera_fpga_of_match);
static struct platform_driver altera_fpga_driver = {
.probe = alt_fpga_bridge_probe,
- .remove = alt_fpga_bridge_remove,
+ .remove_new = alt_fpga_bridge_remove,
.driver = {
.name = "altera_fpga2sdram_bridge",
.of_match_table = of_match_ptr(altera_fpga_of_match),
diff --git a/drivers/fpga/altera-freeze-bridge.c b/drivers/fpga/altera-freeze-bridge.c
index 0c3fb8226908..44061cb16f87 100644
--- a/drivers/fpga/altera-freeze-bridge.c
+++ b/drivers/fpga/altera-freeze-bridge.c
@@ -253,18 +253,16 @@ static int altera_freeze_br_probe(struct platform_device *pdev)
return 0;
}
-static int altera_freeze_br_remove(struct platform_device *pdev)
+static void altera_freeze_br_remove(struct platform_device *pdev)
{
struct fpga_bridge *br = platform_get_drvdata(pdev);
fpga_bridge_unregister(br);
-
- return 0;
}
static struct platform_driver altera_freeze_br_driver = {
.probe = altera_freeze_br_probe,
- .remove = altera_freeze_br_remove,
+ .remove_new = altera_freeze_br_remove,
.driver = {
.name = "altera_freeze_br",
.of_match_table = altera_freeze_br_of_match,
diff --git a/drivers/fpga/altera-hps2fpga.c b/drivers/fpga/altera-hps2fpga.c
index 578663503297..6f8e24be19c6 100644
--- a/drivers/fpga/altera-hps2fpga.c
+++ b/drivers/fpga/altera-hps2fpga.c
@@ -191,7 +191,7 @@ err:
return ret;
}
-static int alt_fpga_bridge_remove(struct platform_device *pdev)
+static void alt_fpga_bridge_remove(struct platform_device *pdev)
{
struct fpga_bridge *bridge = platform_get_drvdata(pdev);
struct altera_hps2fpga_data *priv = bridge->priv;
@@ -199,15 +199,13 @@ static int alt_fpga_bridge_remove(struct platform_device *pdev)
fpga_bridge_unregister(bridge);
clk_disable_unprepare(priv->clk);
-
- return 0;
}
MODULE_DEVICE_TABLE(of, altera_fpga_of_match);
static struct platform_driver alt_fpga_bridge_driver = {
.probe = alt_fpga_bridge_probe,
- .remove = alt_fpga_bridge_remove,
+ .remove_new = alt_fpga_bridge_remove,
.driver = {
.name = "altera_hps2fpga_bridge",
.of_match_table = of_match_ptr(altera_fpga_of_match),
diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c
index 7f621e96d3b8..c0a75ca360d6 100644
--- a/drivers/fpga/dfl-afu-main.c
+++ b/drivers/fpga/dfl-afu-main.c
@@ -932,15 +932,13 @@ exit:
return ret;
}
-static int afu_remove(struct platform_device *pdev)
+static void afu_remove(struct platform_device *pdev)
{
dev_dbg(&pdev->dev, "%s\n", __func__);
dfl_fpga_dev_ops_unregister(pdev);
dfl_fpga_dev_feature_uinit(pdev);
afu_dev_destroy(pdev);
-
- return 0;
}
static const struct attribute_group *afu_dev_groups[] = {
@@ -956,7 +954,7 @@ static struct platform_driver afu_driver = {
.dev_groups = afu_dev_groups,
},
.probe = afu_probe,
- .remove = afu_remove,
+ .remove_new = afu_remove,
};
static int __init afu_init(void)
diff --git a/drivers/fpga/dfl-fme-br.c b/drivers/fpga/dfl-fme-br.c
index 808d1f4d76df..0b01b3895277 100644
--- a/drivers/fpga/dfl-fme-br.c
+++ b/drivers/fpga/dfl-fme-br.c
@@ -78,7 +78,7 @@ static int fme_br_probe(struct platform_device *pdev)
return 0;
}
-static int fme_br_remove(struct platform_device *pdev)
+static void fme_br_remove(struct platform_device *pdev)
{
struct fpga_bridge *br = platform_get_drvdata(pdev);
struct fme_br_priv *priv = br->priv;
@@ -89,8 +89,6 @@ static int fme_br_remove(struct platform_device *pdev)
put_device(&priv->port_pdev->dev);
if (priv->port_ops)
dfl_fpga_port_ops_put(priv->port_ops);
-
- return 0;
}
static struct platform_driver fme_br_driver = {
@@ -98,7 +96,7 @@ static struct platform_driver fme_br_driver = {
.name = DFL_FPGA_FME_BRIDGE,
},
.probe = fme_br_probe,
- .remove = fme_br_remove,
+ .remove_new = fme_br_remove,
};
module_platform_driver(fme_br_driver);
diff --git a/drivers/fpga/dfl-fme-main.c b/drivers/fpga/dfl-fme-main.c
index 3dcf990bd261..a2b5da0093da 100644
--- a/drivers/fpga/dfl-fme-main.c
+++ b/drivers/fpga/dfl-fme-main.c
@@ -730,13 +730,11 @@ exit:
return ret;
}
-static int fme_remove(struct platform_device *pdev)
+static void fme_remove(struct platform_device *pdev)
{
dfl_fpga_dev_ops_unregister(pdev);
dfl_fpga_dev_feature_uinit(pdev);
fme_dev_destroy(pdev);
-
- return 0;
}
static const struct attribute_group *fme_dev_groups[] = {
@@ -751,7 +749,7 @@ static struct platform_driver fme_driver = {
.dev_groups = fme_dev_groups,
},
.probe = fme_probe,
- .remove = fme_remove,
+ .remove_new = fme_remove,
};
module_platform_driver(fme_driver);
diff --git a/drivers/fpga/dfl-fme-region.c b/drivers/fpga/dfl-fme-region.c
index 4aebde0a7f1c..71616f8b4982 100644
--- a/drivers/fpga/dfl-fme-region.c
+++ b/drivers/fpga/dfl-fme-region.c
@@ -61,15 +61,13 @@ eprobe_mgr_put:
return ret;
}
-static int fme_region_remove(struct platform_device *pdev)
+static void fme_region_remove(struct platform_device *pdev)
{
struct fpga_region *region = platform_get_drvdata(pdev);
struct fpga_manager *mgr = region->mgr;
fpga_region_unregister(region);
fpga_mgr_put(mgr);
-
- return 0;
}
static struct platform_driver fme_region_driver = {
@@ -77,7 +75,7 @@ static struct platform_driver fme_region_driver = {
.name = DFL_FPGA_FME_REGION,
},
.probe = fme_region_probe,
- .remove = fme_region_remove,
+ .remove_new = fme_region_remove,
};
module_platform_driver(fme_region_driver);
diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c
index e73f88050f08..e6d12fbab653 100644
--- a/drivers/fpga/dfl.c
+++ b/drivers/fpga/dfl.c
@@ -2008,8 +2008,8 @@ long dfl_feature_ioctl_set_irq(struct platform_device *pdev,
(hdr.start + hdr.count < hdr.start))
return -EINVAL;
- fds = memdup_user((void __user *)(arg + sizeof(hdr)),
- array_size(hdr.count, sizeof(s32)));
+ fds = memdup_array_user((void __user *)(arg + sizeof(hdr)),
+ hdr.count, sizeof(s32));
if (IS_ERR(fds))
return PTR_ERR(fds);
diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c
index 31af2e08c825..89851b133709 100644
--- a/drivers/fpga/intel-m10-bmc-sec-update.c
+++ b/drivers/fpga/intel-m10-bmc-sec-update.c
@@ -730,15 +730,13 @@ fw_name_fail:
return ret;
}
-static int m10bmc_sec_remove(struct platform_device *pdev)
+static void m10bmc_sec_remove(struct platform_device *pdev)
{
struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);
firmware_upload_unregister(sec->fwl);
kfree(sec->fw_name);
xa_erase(&fw_upload_xa, sec->fw_name_id);
-
- return 0;
}
static const struct platform_device_id intel_m10bmc_sec_ids[] = {
@@ -760,7 +758,7 @@ MODULE_DEVICE_TABLE(platform, intel_m10bmc_sec_ids);
static struct platform_driver intel_m10bmc_sec_driver = {
.probe = m10bmc_sec_probe,
- .remove = m10bmc_sec_remove,
+ .remove_new = m10bmc_sec_remove,
.driver = {
.name = "intel-m10bmc-sec-update",
.dev_groups = m10bmc_sec_attr_groups,
diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c
index a6affd83f275..8526a5a86f0c 100644
--- a/drivers/fpga/of-fpga-region.c
+++ b/drivers/fpga/of-fpga-region.c
@@ -425,20 +425,18 @@ eprobe_mgr_put:
return ret;
}
-static int of_fpga_region_remove(struct platform_device *pdev)
+static void of_fpga_region_remove(struct platform_device *pdev)
{
struct fpga_region *region = platform_get_drvdata(pdev);
struct fpga_manager *mgr = region->mgr;
fpga_region_unregister(region);
fpga_mgr_put(mgr);
-
- return 0;
}
static struct platform_driver of_fpga_region_driver = {
.probe = of_fpga_region_probe,
- .remove = of_fpga_region_remove,
+ .remove_new = of_fpga_region_remove,
.driver = {
.name = "of-fpga-region",
.of_match_table = of_match_ptr(fpga_region_of_match),
diff --git a/drivers/fpga/socfpga-a10.c b/drivers/fpga/socfpga-a10.c
index cc4861e345c9..4c03513b8f03 100644
--- a/drivers/fpga/socfpga-a10.c
+++ b/drivers/fpga/socfpga-a10.c
@@ -517,15 +517,13 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev)
return 0;
}
-static int socfpga_a10_fpga_remove(struct platform_device *pdev)
+static void socfpga_a10_fpga_remove(struct platform_device *pdev)
{
struct fpga_manager *mgr = platform_get_drvdata(pdev);
struct a10_fpga_priv *priv = mgr->priv;
fpga_mgr_unregister(mgr);
clk_disable_unprepare(priv->clk);
-
- return 0;
}
static const struct of_device_id socfpga_a10_fpga_of_match[] = {
@@ -537,7 +535,7 @@ MODULE_DEVICE_TABLE(of, socfpga_a10_fpga_of_match);
static struct platform_driver socfpga_a10_fpga_driver = {
.probe = socfpga_a10_fpga_probe,
- .remove = socfpga_a10_fpga_remove,
+ .remove_new = socfpga_a10_fpga_remove,
.driver = {
.name = "socfpga_a10_fpga_manager",
.of_match_table = socfpga_a10_fpga_of_match,
diff --git a/drivers/fpga/stratix10-soc.c b/drivers/fpga/stratix10-soc.c
index cacb9cc5757e..2c0def7d7cbb 100644
--- a/drivers/fpga/stratix10-soc.c
+++ b/drivers/fpga/stratix10-soc.c
@@ -436,15 +436,13 @@ probe_err:
return ret;
}
-static int s10_remove(struct platform_device *pdev)
+static void s10_remove(struct platform_device *pdev)
{
struct fpga_manager *mgr = platform_get_drvdata(pdev);
struct s10_priv *priv = mgr->priv;
fpga_mgr_unregister(mgr);
stratix10_svc_free_channel(priv->chan);
-
- return 0;
}
static const struct of_device_id s10_of_match[] = {
@@ -457,7 +455,7 @@ MODULE_DEVICE_TABLE(of, s10_of_match);
static struct platform_driver s10_driver = {
.probe = s10_probe,
- .remove = s10_remove,
+ .remove_new = s10_remove,
.driver = {
.name = "Stratix10 SoC FPGA manager",
.of_match_table = of_match_ptr(s10_of_match),
diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c
index 68835896f180..788dd2f63a65 100644
--- a/drivers/fpga/xilinx-pr-decoupler.c
+++ b/drivers/fpga/xilinx-pr-decoupler.c
@@ -150,7 +150,7 @@ err_clk:
return err;
}
-static int xlnx_pr_decoupler_remove(struct platform_device *pdev)
+static void xlnx_pr_decoupler_remove(struct platform_device *pdev)
{
struct fpga_bridge *bridge = platform_get_drvdata(pdev);
struct xlnx_pr_decoupler_data *p = bridge->priv;
@@ -158,13 +158,11 @@ static int xlnx_pr_decoupler_remove(struct platform_device *pdev)
fpga_bridge_unregister(bridge);
clk_unprepare(p->clk);
-
- return 0;
}
static struct platform_driver xlnx_pr_decoupler_driver = {
.probe = xlnx_pr_decoupler_probe,
- .remove = xlnx_pr_decoupler_remove,
+ .remove_new = xlnx_pr_decoupler_remove,
.driver = {
.name = "xlnx_pr_decoupler",
.of_match_table = xlnx_pr_decoupler_of_match,
diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c
index 96611d424a10..0ac93183d201 100644
--- a/drivers/fpga/zynq-fpga.c
+++ b/drivers/fpga/zynq-fpga.c
@@ -618,7 +618,7 @@ static int zynq_fpga_probe(struct platform_device *pdev)
return 0;
}
-static int zynq_fpga_remove(struct platform_device *pdev)
+static void zynq_fpga_remove(struct platform_device *pdev)
{
struct zynq_fpga_priv *priv;
struct fpga_manager *mgr;
@@ -629,8 +629,6 @@ static int zynq_fpga_remove(struct platform_device *pdev)
fpga_mgr_unregister(mgr);
clk_unprepare(priv->clk);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -644,7 +642,7 @@ MODULE_DEVICE_TABLE(of, zynq_fpga_of_match);
static struct platform_driver zynq_fpga_driver = {
.probe = zynq_fpga_probe,
- .remove = zynq_fpga_remove,
+ .remove_new = zynq_fpga_remove,
.driver = {
.name = "zynq_fpga_manager",
.of_match_table = of_match_ptr(zynq_fpga_of_match),
diff --git a/drivers/gnss/serial.c b/drivers/gnss/serial.c
index 5d8e9bfb24d0..baa956494e79 100644
--- a/drivers/gnss/serial.c
+++ b/drivers/gnss/serial.c
@@ -80,8 +80,8 @@ static const struct gnss_operations gnss_serial_gnss_ops = {
.write_raw = gnss_serial_write_raw,
};
-static int gnss_serial_receive_buf(struct serdev_device *serdev,
- const unsigned char *buf, size_t count)
+static ssize_t gnss_serial_receive_buf(struct serdev_device *serdev,
+ const u8 *buf, size_t count)
{
struct gnss_serial *gserial = serdev_device_get_drvdata(serdev);
struct gnss_device *gdev = gserial->gdev;
diff --git a/drivers/gnss/sirf.c b/drivers/gnss/sirf.c
index bcb53ccfee4d..6801a8fb2040 100644
--- a/drivers/gnss/sirf.c
+++ b/drivers/gnss/sirf.c
@@ -160,8 +160,8 @@ static const struct gnss_operations sirf_gnss_ops = {
.write_raw = sirf_write_raw,
};
-static int sirf_receive_buf(struct serdev_device *serdev,
- const unsigned char *buf, size_t count)
+static ssize_t sirf_receive_buf(struct serdev_device *serdev,
+ const u8 *buf, size_t count)
{
struct sirf_data *data = serdev_device_get_drvdata(serdev);
struct gnss_device *gdev = data->gdev;
diff --git a/drivers/gnss/ubx.c b/drivers/gnss/ubx.c
index c951be202ca2..92402f6082c4 100644
--- a/drivers/gnss/ubx.c
+++ b/drivers/gnss/ubx.c
@@ -7,6 +7,7 @@
#include <linux/errno.h>
#include <linux/gnss.h>
+#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -17,7 +18,6 @@
#include "serial.h"
struct ubx_data {
- struct regulator *v_bckp;
struct regulator *vcc;
};
@@ -66,6 +66,7 @@ static const struct gnss_serial_ops ubx_gserial_ops = {
static int ubx_probe(struct serdev_device *serdev)
{
struct gnss_serial *gserial;
+ struct gpio_desc *reset;
struct ubx_data *data;
int ret;
@@ -87,30 +88,23 @@ static int ubx_probe(struct serdev_device *serdev)
goto err_free_gserial;
}
- data->v_bckp = devm_regulator_get_optional(&serdev->dev, "v-bckp");
- if (IS_ERR(data->v_bckp)) {
- ret = PTR_ERR(data->v_bckp);
- if (ret == -ENODEV)
- data->v_bckp = NULL;
- else
- goto err_free_gserial;
- }
+ ret = devm_regulator_get_enable_optional(&serdev->dev, "v-bckp");
+ if (ret < 0 && ret != -ENODEV)
+ goto err_free_gserial;
- if (data->v_bckp) {
- ret = regulator_enable(data->v_bckp);
- if (ret)
- goto err_free_gserial;
+ /* Deassert reset */
+ reset = devm_gpiod_get_optional(&serdev->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(reset)) {
+ ret = PTR_ERR(reset);
+ goto err_free_gserial;
}
ret = gnss_serial_register(gserial);
if (ret)
- goto err_disable_v_bckp;
+ goto err_free_gserial;
return 0;
-err_disable_v_bckp:
- if (data->v_bckp)
- regulator_disable(data->v_bckp);
err_free_gserial:
gnss_serial_free(gserial);
@@ -120,11 +114,8 @@ err_free_gserial:
static void ubx_remove(struct serdev_device *serdev)
{
struct gnss_serial *gserial = serdev_device_get_drvdata(serdev);
- struct ubx_data *data = gnss_serial_get_drvdata(gserial);
gnss_serial_deregister(gserial);
- if (data->v_bckp)
- regulator_disable(data->v_bckp);
gnss_serial_free(gserial);
}
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 402f7d99b0c1..e7770eedd146 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -184,7 +184,7 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np,
const char *propname;
bool active_high;
} gpios[] = {
-#if !IS_ENABLED(CONFIG_LCD_HX8357)
+#if IS_ENABLED(CONFIG_LCD_HX8357)
/*
* Himax LCD controllers used incorrectly named
* "gpios-reset" property and also specified wrong
@@ -478,7 +478,7 @@ static struct gpio_desc *of_find_gpio_rename(struct device_node *np,
*/
const char *compatible;
} gpios[] = {
-#if !IS_ENABLED(CONFIG_LCD_HX8357)
+#if IS_ENABLED(CONFIG_LCD_HX8357)
/* Himax LCD controllers used "gpios-reset" */
{ "reset", "gpios-reset", "himax,hx8357" },
{ "reset", "gpios-reset", "himax,hx8369" },
diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c
index d511d17c5bdf..cff85086f2d6 100644
--- a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c
+++ b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c
@@ -7,7 +7,6 @@
#include <linux/hyperv.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/screen_info.h>
#include <drm/drm_aperture.h>
#include <drm/drm_atomic_helper.h>
@@ -73,11 +72,6 @@ static int hyperv_setup_vram(struct hyperv_drm_device *hv,
struct drm_device *dev = &hv->dev;
int ret;
- if (IS_ENABLED(CONFIG_SYSFB))
- drm_aperture_remove_conflicting_framebuffers(screen_info.lfb_base,
- screen_info.lfb_size,
- &hyperv_driver);
-
hv->fb_size = (unsigned long)hv->mmio_megabytes * 1024 * 1024;
ret = vmbus_allocate_mmio(&hv->mem, hdev, 0, -1, hv->fb_size, 0x100000,
@@ -130,6 +124,8 @@ static int hyperv_vmbus_probe(struct hv_device *hdev,
goto err_hv_set_drv_data;
}
+ drm_aperture_remove_framebuffers(&hyperv_driver);
+
ret = hyperv_setup_vram(hv, hdev);
if (ret)
goto err_vmbus_close;
diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c
index 612d4cd9dacb..3f3cd944a1c5 100644
--- a/drivers/gpu/drm/i915/display/intel_backlight.c
+++ b/drivers/gpu/drm/i915/display/intel_backlight.c
@@ -275,7 +275,7 @@ static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state,
struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;
pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
+ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state);
}
static void
@@ -428,7 +428,7 @@ static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn
intel_backlight_set_pwm_level(old_conn_state, level);
panel->backlight.pwm_state.enabled = false;
- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
+ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state);
}
void intel_backlight_disable(const struct drm_connector_state *old_conn_state)
@@ -750,7 +750,7 @@ static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
panel->backlight.pwm_state.enabled = true;
- pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
+ pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state);
}
static void __intel_backlight_enable(const struct intel_crtc_state *crtc_state,
diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
index 884a1da36089..6b25e195232f 100644
--- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c
+++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c
@@ -3067,24 +3067,29 @@ static void intel_c20pll_state_verify(const struct intel_crtc_state *state,
{
struct drm_i915_private *i915 = to_i915(crtc->base.dev);
const struct intel_c20pll_state *mpll_sw_state = &state->cx0pll_state.c20;
- bool use_mplla;
+ bool sw_use_mpllb = mpll_sw_state->tx[0] & C20_PHY_USE_MPLLB;
+ bool hw_use_mpllb = mpll_hw_state->tx[0] & C20_PHY_USE_MPLLB;
int i;
- use_mplla = intel_c20_use_mplla(mpll_hw_state->clock);
- if (use_mplla) {
- for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mplla); i++) {
- I915_STATE_WARN(i915, mpll_hw_state->mplla[i] != mpll_sw_state->mplla[i],
- "[CRTC:%d:%s] mismatch in C20MPLLA: Register[%d] (expected 0x%04x, found 0x%04x)",
- crtc->base.base.id, crtc->base.name, i,
- mpll_sw_state->mplla[i], mpll_hw_state->mplla[i]);
- }
- } else {
+ I915_STATE_WARN(i915, sw_use_mpllb != hw_use_mpllb,
+ "[CRTC:%d:%s] mismatch in C20: Register MPLLB selection (expected %d, found %d)",
+ crtc->base.base.id, crtc->base.name,
+ sw_use_mpllb, hw_use_mpllb);
+
+ if (hw_use_mpllb) {
for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mpllb); i++) {
I915_STATE_WARN(i915, mpll_hw_state->mpllb[i] != mpll_sw_state->mpllb[i],
"[CRTC:%d:%s] mismatch in C20MPLLB: Register[%d] (expected 0x%04x, found 0x%04x)",
crtc->base.base.id, crtc->base.name, i,
mpll_sw_state->mpllb[i], mpll_hw_state->mpllb[i]);
}
+ } else {
+ for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mplla); i++) {
+ I915_STATE_WARN(i915, mpll_hw_state->mplla[i] != mpll_sw_state->mplla[i],
+ "[CRTC:%d:%s] mismatch in C20MPLLA: Register[%d] (expected 0x%04x, found 0x%04x)",
+ crtc->base.base.id, crtc->base.name, i,
+ mpll_sw_state->mplla[i], mpll_hw_state->mplla[i]);
+ }
}
for (i = 0; i < ARRAY_SIZE(mpll_sw_state->tx); i++) {
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index 5f091502719b..6fd4fa52253a 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -405,8 +405,8 @@ print_async_put_domains_state(struct i915_power_domains *power_domains)
struct drm_i915_private,
display.power.domains);
- drm_dbg(&i915->drm, "async_put_wakeref %lu\n",
- power_domains->async_put_wakeref);
+ drm_dbg(&i915->drm, "async_put_wakeref: %s\n",
+ str_yes_no(power_domains->async_put_wakeref));
print_power_domains(power_domains, "async_put_domains[0]",
&power_domains->async_put_domains[0]);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 7d2b8ce48fda..f5ef95da5534 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -2101,7 +2101,7 @@ static int intel_dp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp,
}
}
- dsc_max_bpc = intel_dp_dsc_min_src_input_bpc(i915);
+ dsc_max_bpc = intel_dp_dsc_max_src_input_bpc(i915);
if (!dsc_max_bpc)
return -EINVAL;
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index b6e2e70e1290..8f702c3fc62d 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -3319,11 +3319,11 @@ void intel_psr_connector_debugfs_add(struct intel_connector *connector)
struct drm_i915_private *i915 = to_i915(connector->base.dev);
struct dentry *root = connector->base.debugfs_entry;
- if (connector->base.connector_type != DRM_MODE_CONNECTOR_eDP) {
- if (!(HAS_DP20(i915) &&
- connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort))
- return;
- }
+ /* TODO: Add support for MST connectors as well. */
+ if ((connector->base.connector_type != DRM_MODE_CONNECTOR_eDP &&
+ connector->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort) ||
+ connector->mst_port)
+ return;
debugfs_create_file("i915_psr_sink_status", 0444, root,
connector, &i915_psr_sink_status_fops);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index c573c067779f..03bc7f9d191b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -412,9 +412,9 @@ struct i915_gem_context {
/** @stale: tracks stale engines to be destroyed */
struct {
- /** @lock: guards engines */
+ /** @stale.lock: guards engines */
spinlock_t lock;
- /** @engines: list of stale engines */
+ /** @stale.engines: list of stale engines */
struct list_head engines;
} stale;
};
diff --git a/drivers/gpu/drm/i915/gt/intel_gsc.h b/drivers/gpu/drm/i915/gt/intel_gsc.h
index 7ab3ca0f9f26..013c64251448 100644
--- a/drivers/gpu/drm/i915/gt/intel_gsc.h
+++ b/drivers/gpu/drm/i915/gt/intel_gsc.h
@@ -21,8 +21,11 @@ struct mei_aux_device;
/**
* struct intel_gsc - graphics security controller
*
- * @gem_obj: scratch memory GSC operations
- * @intf : gsc interface
+ * @intf: gsc interface
+ * @intf.adev: MEI aux. device for this @intf
+ * @intf.gem_obj: scratch memory GSC operations
+ * @intf.irq: IRQ for this device (%-1 for no IRQ)
+ * @intf.id: this interface's id number/index
*/
struct intel_gsc {
struct intel_gsc_intf {
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
index e22c12ce245a..813cc888e6fa 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
@@ -105,61 +105,67 @@ struct intel_guc {
*/
struct {
/**
- * @lock: protects everything in submission_state,
- * ce->guc_id.id, and ce->guc_id.ref when transitioning in and
- * out of zero
+ * @submission_state.lock: protects everything in
+ * submission_state, ce->guc_id.id, and ce->guc_id.ref
+ * when transitioning in and out of zero
*/
spinlock_t lock;
/**
- * @guc_ids: used to allocate new guc_ids, single-lrc
+ * @submission_state.guc_ids: used to allocate new
+ * guc_ids, single-lrc
*/
struct ida guc_ids;
/**
- * @num_guc_ids: Number of guc_ids, selftest feature to be able
- * to reduce this number while testing.
+ * @submission_state.num_guc_ids: Number of guc_ids, selftest
+ * feature to be able to reduce this number while testing.
*/
int num_guc_ids;
/**
- * @guc_ids_bitmap: used to allocate new guc_ids, multi-lrc
+ * @submission_state.guc_ids_bitmap: used to allocate
+ * new guc_ids, multi-lrc
*/
unsigned long *guc_ids_bitmap;
/**
- * @guc_id_list: list of intel_context with valid guc_ids but no
- * refs
+ * @submission_state.guc_id_list: list of intel_context
+ * with valid guc_ids but no refs
*/
struct list_head guc_id_list;
/**
- * @guc_ids_in_use: Number single-lrc guc_ids in use
+ * @submission_state.guc_ids_in_use: Number single-lrc
+ * guc_ids in use
*/
unsigned int guc_ids_in_use;
/**
- * @destroyed_contexts: list of contexts waiting to be destroyed
- * (deregistered with the GuC)
+ * @submission_state.destroyed_contexts: list of contexts
+ * waiting to be destroyed (deregistered with the GuC)
*/
struct list_head destroyed_contexts;
/**
- * @destroyed_worker: worker to deregister contexts, need as we
- * need to take a GT PM reference and can't from destroy
- * function as it might be in an atomic context (no sleeping)
+ * @submission_state.destroyed_worker: worker to deregister
+ * contexts, need as we need to take a GT PM reference and
+ * can't from destroy function as it might be in an atomic
+ * context (no sleeping)
*/
struct work_struct destroyed_worker;
/**
- * @reset_fail_worker: worker to trigger a GT reset after an
- * engine reset fails
+ * @submission_state.reset_fail_worker: worker to trigger
+ * a GT reset after an engine reset fails
*/
struct work_struct reset_fail_worker;
/**
- * @reset_fail_mask: mask of engines that failed to reset
+ * @submission_state.reset_fail_mask: mask of engines that
+ * failed to reset
*/
intel_engine_mask_t reset_fail_mask;
/**
- * @sched_disable_delay_ms: schedule disable delay, in ms, for
- * contexts
+ * @submission_state.sched_disable_delay_ms: schedule
+ * disable delay, in ms, for contexts
*/
unsigned int sched_disable_delay_ms;
/**
- * @sched_disable_gucid_threshold: threshold of min remaining available
- * guc_ids before we start bypassing the schedule disable delay
+ * @submission_state.sched_disable_gucid_threshold:
+ * threshold of min remaining available guc_ids before
+ * we start bypassing the schedule disable delay
*/
unsigned int sched_disable_gucid_threshold;
} submission_state;
@@ -243,37 +249,40 @@ struct intel_guc {
*/
struct {
/**
- * @lock: Lock protecting the below fields and the engine stats.
+ * @timestamp.lock: Lock protecting the below fields and
+ * the engine stats.
*/
spinlock_t lock;
/**
- * @gt_stamp: 64 bit extended value of the GT timestamp.
+ * @timestamp.gt_stamp: 64-bit extended value of the GT
+ * timestamp.
*/
u64 gt_stamp;
/**
- * @ping_delay: Period for polling the GT timestamp for
- * overflow.
+ * @timestamp.ping_delay: Period for polling the GT
+ * timestamp for overflow.
*/
unsigned long ping_delay;
/**
- * @work: Periodic work to adjust GT timestamp, engine and
- * context usage for overflows.
+ * @timestamp.work: Periodic work to adjust GT timestamp,
+ * engine and context usage for overflows.
*/
struct delayed_work work;
/**
- * @shift: Right shift value for the gpm timestamp
+ * @timestamp.shift: Right shift value for the gpm timestamp
*/
u32 shift;
/**
- * @last_stat_jiffies: jiffies at last actual stats collection time
- * We use this timestamp to ensure we don't oversample the
- * stats because runtime power management events can trigger
- * stats collection at much higher rates than required.
+ * @timestamp.last_stat_jiffies: jiffies at last actual
+ * stats collection time. We use this timestamp to ensure
+ * we don't oversample the stats because runtime power
+ * management events can trigger stats collection at much
+ * higher rates than required.
*/
unsigned long last_stat_jiffies;
} timestamp;
diff --git a/drivers/gpu/drm/i915/i915_perf_types.h b/drivers/gpu/drm/i915/i915_perf_types.h
index 13b1ae9b96c7..46445248d193 100644
--- a/drivers/gpu/drm/i915/i915_perf_types.h
+++ b/drivers/gpu/drm/i915/i915_perf_types.h
@@ -291,7 +291,8 @@ struct i915_perf_stream {
int size_exponent;
/**
- * @ptr_lock: Locks reads and writes to all head/tail state
+ * @oa_buffer.ptr_lock: Locks reads and writes to all
+ * head/tail state
*
* Consider: the head and tail pointer state needs to be read
* consistently from a hrtimer callback (atomic context) and
@@ -313,7 +314,8 @@ struct i915_perf_stream {
spinlock_t ptr_lock;
/**
- * @head: Although we can always read back the head pointer register,
+ * @oa_buffer.head: Although we can always read back
+ * the head pointer register,
* we prefer to avoid trusting the HW state, just to avoid any
* risk that some hardware condition could * somehow bump the
* head pointer unpredictably and cause us to forward the wrong
@@ -322,7 +324,8 @@ struct i915_perf_stream {
u32 head;
/**
- * @tail: The last verified tail that can be read by userspace.
+ * @oa_buffer.tail: The last verified tail that can be
+ * read by userspace.
*/
u32 tail;
} oa_buffer;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c
index c8ce7ff18713..e74493a4569e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c
@@ -550,6 +550,10 @@ ga100_fifo_nonstall_ctor(struct nvkm_fifo *fifo)
struct nvkm_engn *engn = list_first_entry(&runl->engns, typeof(*engn), head);
runl->nonstall.vector = engn->func->nonstall(engn);
+
+ /* if no nonstall vector just keep going */
+ if (runl->nonstall.vector == -1)
+ continue;
if (runl->nonstall.vector < 0) {
RUNL_ERROR(runl, "nonstall %d", runl->nonstall.vector);
return runl->nonstall.vector;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c
index b903785056b5..3454c7d29502 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c
@@ -351,7 +351,7 @@ r535_engn_nonstall(struct nvkm_engn *engn)
int ret;
ret = nvkm_gsp_intr_nonstall(subdev->device->gsp, subdev->type, subdev->inst);
- WARN_ON(ret < 0);
+ WARN_ON(ret == -ENOENT);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c
index 04bceaa28a19..da1bebb896f7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c
@@ -25,12 +25,8 @@ int
nvkm_gsp_intr_nonstall(struct nvkm_gsp *gsp, enum nvkm_subdev_type type, int inst)
{
for (int i = 0; i < gsp->intr_nr; i++) {
- if (gsp->intr[i].type == type && gsp->intr[i].inst == inst) {
- if (gsp->intr[i].nonstall != ~0)
- return gsp->intr[i].nonstall;
-
- return -EINVAL;
- }
+ if (gsp->intr[i].type == type && gsp->intr[i].inst == inst)
+ return gsp->intr[i].nonstall;
}
return -ENOENT;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c
index e7e8fdf3adab..29682722b0b3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c
@@ -28,19 +28,14 @@ static void
gp10b_ltc_init(struct nvkm_ltc *ltc)
{
struct nvkm_device *device = ltc->subdev.device;
- struct iommu_fwspec *spec;
+ u32 sid;
nvkm_wr32(device, 0x17e27c, ltc->ltc_nr);
nvkm_wr32(device, 0x17e000, ltc->ltc_nr);
nvkm_wr32(device, 0x100800, ltc->ltc_nr);
- spec = dev_iommu_fwspec_get(device->dev);
- if (spec) {
- u32 sid = spec->ids[0] & 0xffff;
-
- /* stream ID */
+ if (tegra_dev_iommu_get_stream_id(device->dev, &sid))
nvkm_wr32(device, 0x160000, sid << 2);
- }
}
static const struct nvkm_ltc_func
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 574103fc79f9..85b3b4871a1d 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -35,7 +35,6 @@
#include "rockchip_drm_drv.h"
#include "rockchip_drm_gem.h"
-#include "rockchip_drm_fb.h"
#include "rockchip_drm_vop2.h"
#include "rockchip_rgb.h"
@@ -1681,7 +1680,6 @@ static unsigned long rk3588_calc_cru_cfg(struct vop2_video_port *vp, int id,
unsigned long dclk_core_rate = v_pixclk >> 2;
unsigned long dclk_rate = v_pixclk;
unsigned long dclk_out_rate;
- unsigned long if_dclk_rate;
unsigned long if_pixclk_rate;
int K = 1;
@@ -1696,8 +1694,8 @@ static unsigned long rk3588_calc_cru_cfg(struct vop2_video_port *vp, int id,
}
if_pixclk_rate = (dclk_core_rate << 1) / K;
- if_dclk_rate = dclk_core_rate / K;
/*
+ * if_dclk_rate = dclk_core_rate / K;
* *if_pixclk_div = dclk_rate / if_pixclk_rate;
* *if_dclk_div = dclk_rate / if_dclk_rate;
*/
diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
index bef293922b98..3d0e093a7e6e 100644
--- a/drivers/gpu/drm/solomon/ssd130x.c
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -319,7 +319,7 @@ static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x)
pwm_init_state(ssd130x->pwm, &pwmstate);
pwm_set_relative_duty_cycle(&pwmstate, 50, 100);
- pwm_apply_state(ssd130x->pwm, &pwmstate);
+ pwm_apply_might_sleep(ssd130x->pwm, &pwmstate);
/* Enable the PWM */
pwm_enable(ssd130x->pwm);
diff --git a/drivers/gpu/drm/v3d/v3d_debugfs.c b/drivers/gpu/drm/v3d/v3d_debugfs.c
index f843a50d5dce..94eafcecc65b 100644
--- a/drivers/gpu/drm/v3d/v3d_debugfs.c
+++ b/drivers/gpu/drm/v3d/v3d_debugfs.c
@@ -62,9 +62,9 @@ static const struct v3d_reg_def v3d_core_reg_defs[] = {
REGDEF(33, 71, V3D_PTB_BPCA),
REGDEF(33, 71, V3D_PTB_BPCS),
- REGDEF(33, 41, V3D_GMP_STATUS(33)),
- REGDEF(33, 41, V3D_GMP_CFG(33)),
- REGDEF(33, 41, V3D_GMP_VIO_ADDR(33)),
+ REGDEF(33, 42, V3D_GMP_STATUS(33)),
+ REGDEF(33, 42, V3D_GMP_CFG(33)),
+ REGDEF(33, 42, V3D_GMP_VIO_ADDR(33)),
REGDEF(33, 71, V3D_ERR_FDBGO),
REGDEF(33, 71, V3D_ERR_FDBGB),
@@ -74,13 +74,13 @@ static const struct v3d_reg_def v3d_core_reg_defs[] = {
static const struct v3d_reg_def v3d_csd_reg_defs[] = {
REGDEF(41, 71, V3D_CSD_STATUS),
- REGDEF(41, 41, V3D_CSD_CURRENT_CFG0(41)),
- REGDEF(41, 41, V3D_CSD_CURRENT_CFG1(41)),
- REGDEF(41, 41, V3D_CSD_CURRENT_CFG2(41)),
- REGDEF(41, 41, V3D_CSD_CURRENT_CFG3(41)),
- REGDEF(41, 41, V3D_CSD_CURRENT_CFG4(41)),
- REGDEF(41, 41, V3D_CSD_CURRENT_CFG5(41)),
- REGDEF(41, 41, V3D_CSD_CURRENT_CFG6(41)),
+ REGDEF(41, 42, V3D_CSD_CURRENT_CFG0(41)),
+ REGDEF(41, 42, V3D_CSD_CURRENT_CFG1(41)),
+ REGDEF(41, 42, V3D_CSD_CURRENT_CFG2(41)),
+ REGDEF(41, 42, V3D_CSD_CURRENT_CFG3(41)),
+ REGDEF(41, 42, V3D_CSD_CURRENT_CFG4(41)),
+ REGDEF(41, 42, V3D_CSD_CURRENT_CFG5(41)),
+ REGDEF(41, 42, V3D_CSD_CURRENT_CFG6(41)),
REGDEF(71, 71, V3D_CSD_CURRENT_CFG0(71)),
REGDEF(71, 71, V3D_CSD_CURRENT_CFG1(71)),
REGDEF(71, 71, V3D_CSD_CURRENT_CFG2(71)),
diff --git a/drivers/greybus/gb-beagleplay.c b/drivers/greybus/gb-beagleplay.c
index 43318c1993ba..c3e90025064b 100644
--- a/drivers/greybus/gb-beagleplay.c
+++ b/drivers/greybus/gb-beagleplay.c
@@ -85,17 +85,31 @@ struct hdlc_payload {
void *buf;
};
+/**
+ * struct hdlc_greybus_frame - Structure to represent greybus HDLC frame payload
+ *
+ * @cport: cport id
+ * @hdr: greybus operation header
+ * @payload: greybus message payload
+ *
+ * The HDLC payload sent over UART for greybus address has cport preappended to greybus message
+ */
+struct hdlc_greybus_frame {
+ __le16 cport;
+ struct gb_operation_msg_hdr hdr;
+ u8 payload[];
+} __packed;
+
static void hdlc_rx_greybus_frame(struct gb_beagleplay *bg, u8 *buf, u16 len)
{
- u16 cport_id;
- struct gb_operation_msg_hdr *hdr = (struct gb_operation_msg_hdr *)buf;
-
- memcpy(&cport_id, hdr->pad, sizeof(cport_id));
+ struct hdlc_greybus_frame *gb_frame = (struct hdlc_greybus_frame *)buf;
+ u16 cport_id = le16_to_cpu(gb_frame->cport);
+ u16 gb_msg_len = le16_to_cpu(gb_frame->hdr.size);
dev_dbg(&bg->sd->dev, "Greybus Operation %u type %X cport %u status %u received",
- hdr->operation_id, hdr->type, cport_id, hdr->result);
+ gb_frame->hdr.operation_id, gb_frame->hdr.type, cport_id, gb_frame->hdr.result);
- greybus_data_rcvd(bg->gb_hd, cport_id, buf, len);
+ greybus_data_rcvd(bg->gb_hd, cport_id, (u8 *)&gb_frame->hdr, gb_msg_len);
}
static void hdlc_rx_dbg_frame(const struct gb_beagleplay *bg, const char *buf, u16 len)
@@ -257,7 +271,7 @@ static void hdlc_rx_frame(struct gb_beagleplay *bg)
}
}
-static int hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count)
+static ssize_t hdlc_rx(struct gb_beagleplay *bg, const u8 *data, size_t count)
{
size_t i;
u8 c;
@@ -317,7 +331,8 @@ static void hdlc_deinit(struct gb_beagleplay *bg)
flush_work(&bg->tx_work);
}
-static int gb_tty_receive(struct serdev_device *sd, const unsigned char *data, size_t count)
+static ssize_t gb_tty_receive(struct serdev_device *sd, const u8 *data,
+ size_t count)
{
struct gb_beagleplay *bg = serdev_device_get_drvdata(sd);
@@ -336,25 +351,39 @@ static struct serdev_device_ops gb_beagleplay_ops = {
.write_wakeup = gb_tty_wakeup,
};
+/**
+ * gb_message_send() - Send greybus message using HDLC over UART
+ *
+ * @hd: pointer to greybus host device
+ * @cport: AP cport where message originates
+ * @msg: greybus message to send
+ * @mask: gfp mask
+ *
+ * Greybus HDLC frame has the following payload:
+ * 1. le16 cport
+ * 2. gb_operation_msg_hdr msg_header
+ * 3. u8 *msg_payload
+ */
static int gb_message_send(struct gb_host_device *hd, u16 cport, struct gb_message *msg, gfp_t mask)
{
struct gb_beagleplay *bg = dev_get_drvdata(&hd->dev);
- struct hdlc_payload payloads[2];
+ struct hdlc_payload payloads[3];
+ __le16 cport_id = cpu_to_le16(cport);
dev_dbg(&hd->dev, "Sending greybus message with Operation %u, Type: %X on Cport %u",
msg->header->operation_id, msg->header->type, cport);
- if (msg->header->size > RX_HDLC_PAYLOAD)
+ if (le16_to_cpu(msg->header->size) > RX_HDLC_PAYLOAD)
return dev_err_probe(&hd->dev, -E2BIG, "Greybus message too big");
- memcpy(msg->header->pad, &cport, sizeof(cport));
-
- payloads[0].buf = msg->header;
- payloads[0].len = sizeof(*msg->header);
- payloads[1].buf = msg->payload;
- payloads[1].len = msg->payload_size;
+ payloads[0].buf = &cport_id;
+ payloads[0].len = sizeof(cport_id);
+ payloads[1].buf = msg->header;
+ payloads[1].len = sizeof(*msg->header);
+ payloads[2].buf = msg->payload;
+ payloads[2].len = msg->payload_size;
- hdlc_tx_frames(bg, ADDRESS_GREYBUS, 0x03, payloads, 2);
+ hdlc_tx_frames(bg, ADDRESS_GREYBUS, 0x03, payloads, 3);
greybus_message_sent(bg->gb_hd, msg, 0);
return 0;
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 4ce74af79657..4c682c650704 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -761,14 +761,15 @@ config HID_MULTITOUCH
module will be called hid-multitouch.
config HID_NINTENDO
- tristate "Nintendo Joy-Con and Pro Controller support"
+ tristate "Nintendo Joy-Con, NSO, and Pro Controller support"
depends on NEW_LEDS
depends on LEDS_CLASS
select POWER_SUPPLY
help
- Adds support for the Nintendo Switch Joy-Cons and Pro Controller.
+ Adds support for the Nintendo Switch Joy-Cons, NSO, Pro Controller.
All controllers support bluetooth, and the Pro Controller also supports
- its USB mode.
+ its USB mode. This also includes support for the Nintendo Switch Online
+ Controllers which include the Genesis, SNES, and N64 controllers.
To compile this driver as a module, choose M here: the
module will be called hid-nintendo.
@@ -779,9 +780,9 @@ config NINTENDO_FF
select INPUT_FF_MEMLESS
help
Say Y here if you have a Nintendo Switch controller and want to enable
- force feedback support for it. This works for both joy-cons and the pro
- controller. For the pro controller, both rumble motors can be controlled
- individually.
+ force feedback support for it. This works for both joy-cons, the pro
+ controller, and the NSO N64 controller. For the pro controller, both
+ rumble motors can be controlled individually.
config HID_NTI
tristate "NTI keyboard adapters"
@@ -1296,6 +1297,15 @@ config HID_ALPS
Say Y here if you have a Alps touchpads over i2c-hid or usbhid
and want support for its special functionalities.
+config HID_MCP2200
+ tristate "Microchip MCP2200 HID USB-to-GPIO bridge"
+ depends on USB_HID && GPIOLIB
+ help
+ Provides GPIO functionality over USB-HID through MCP2200 device.
+
+ To compile this driver as a module, choose M here: the module
+ will be called hid-mcp2200.ko.
+
config HID_MCP2221
tristate "Microchip MCP2221 HID USB-to-I2C/SMbus host support"
depends on USB_HID && I2C
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 8a06d0f840bc..082a728eac60 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o
obj-$(CONFIG_HID_MACALLY) += hid-macally.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MALTRON) += hid-maltron.o
+obj-$(CONFIG_HID_MCP2200) += hid-mcp2200.o
obj-$(CONFIG_HID_MCP2221) += hid-mcp2221.o
obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o
obj-$(CONFIG_HID_MEGAWORLD_FF) += hid-megaworld.o
diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_common.h b/drivers/hid/amd-sfh-hid/amd_sfh_common.h
index 2643bb14fee2..a1950bc6e6ce 100644
--- a/drivers/hid/amd-sfh-hid/amd_sfh_common.h
+++ b/drivers/hid/amd-sfh-hid/amd_sfh_common.h
@@ -37,6 +37,11 @@ struct amd_mp2_sensor_info {
dma_addr_t dma_address;
};
+struct sfh_dev_status {
+ bool is_hpd_present;
+ bool is_als_present;
+};
+
struct amd_mp2_dev {
struct pci_dev *pdev;
struct amdtp_cl_data *cl_data;
@@ -47,6 +52,7 @@ struct amd_mp2_dev {
struct amd_input_data in_data;
/* mp2 active control status */
u32 mp2_acs;
+ struct sfh_dev_status dev_en;
};
struct amd_mp2_ops {
diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c
index 8a037de08e92..33fbdde8aff0 100644
--- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c
+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c
@@ -132,7 +132,7 @@ static void get_common_inputs(struct common_input_property *common, int report_i
common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM;
}
-static int float_to_int(u32 flt32_val)
+int amd_sfh_float_to_int(u32 flt32_val)
{
int fraction, shift, mantissa, sign, exp, zeropre;
@@ -201,9 +201,9 @@ static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id,
OFFSET_SENSOR_DATA_DEFAULT;
memcpy_fromio(&accel_data, sensoraddr, sizeof(struct sfh_accel_data));
get_common_inputs(&acc_input.common_property, report_id);
- acc_input.in_accel_x_value = float_to_int(accel_data.acceldata.x) / 100;
- acc_input.in_accel_y_value = float_to_int(accel_data.acceldata.y) / 100;
- acc_input.in_accel_z_value = float_to_int(accel_data.acceldata.z) / 100;
+ acc_input.in_accel_x_value = amd_sfh_float_to_int(accel_data.acceldata.x) / 100;
+ acc_input.in_accel_y_value = amd_sfh_float_to_int(accel_data.acceldata.y) / 100;
+ acc_input.in_accel_z_value = amd_sfh_float_to_int(accel_data.acceldata.z) / 100;
memcpy(input_report, &acc_input, sizeof(acc_input));
report_size = sizeof(acc_input);
break;
@@ -212,9 +212,9 @@ static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id,
OFFSET_SENSOR_DATA_DEFAULT;
memcpy_fromio(&gyro_data, sensoraddr, sizeof(struct sfh_gyro_data));
get_common_inputs(&gyro_input.common_property, report_id);
- gyro_input.in_angel_x_value = float_to_int(gyro_data.gyrodata.x) / 1000;
- gyro_input.in_angel_y_value = float_to_int(gyro_data.gyrodata.y) / 1000;
- gyro_input.in_angel_z_value = float_to_int(gyro_data.gyrodata.z) / 1000;
+ gyro_input.in_angel_x_value = amd_sfh_float_to_int(gyro_data.gyrodata.x) / 1000;
+ gyro_input.in_angel_y_value = amd_sfh_float_to_int(gyro_data.gyrodata.y) / 1000;
+ gyro_input.in_angel_z_value = amd_sfh_float_to_int(gyro_data.gyrodata.z) / 1000;
memcpy(input_report, &gyro_input, sizeof(gyro_input));
report_size = sizeof(gyro_input);
break;
@@ -223,9 +223,9 @@ static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id,
OFFSET_SENSOR_DATA_DEFAULT;
memcpy_fromio(&mag_data, sensoraddr, sizeof(struct sfh_mag_data));
get_common_inputs(&magno_input.common_property, report_id);
- magno_input.in_magno_x = float_to_int(mag_data.magdata.x) / 100;
- magno_input.in_magno_y = float_to_int(mag_data.magdata.y) / 100;
- magno_input.in_magno_z = float_to_int(mag_data.magdata.z) / 100;
+ magno_input.in_magno_x = amd_sfh_float_to_int(mag_data.magdata.x) / 100;
+ magno_input.in_magno_y = amd_sfh_float_to_int(mag_data.magdata.y) / 100;
+ magno_input.in_magno_z = amd_sfh_float_to_int(mag_data.magdata.z) / 100;
magno_input.in_magno_accuracy = mag_data.accuracy / 100;
memcpy(input_report, &magno_input, sizeof(magno_input));
report_size = sizeof(magno_input);
@@ -235,13 +235,15 @@ static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id,
OFFSET_SENSOR_DATA_DEFAULT;
memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data));
get_common_inputs(&als_input.common_property, report_id);
- als_input.illuminance_value = float_to_int(als_data.lux);
+ als_input.illuminance_value = amd_sfh_float_to_int(als_data.lux);
memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info));
if (binfo.sbase.s_prop[ALS_IDX].sf.feat & 0x2) {
als_input.light_color_temp = als_data.light_color_temp;
- als_input.chromaticity_x_value = float_to_int(als_data.chromaticity_x);
- als_input.chromaticity_y_value = float_to_int(als_data.chromaticity_y);
+ als_input.chromaticity_x_value =
+ amd_sfh_float_to_int(als_data.chromaticity_x);
+ als_input.chromaticity_y_value =
+ amd_sfh_float_to_int(als_data.chromaticity_y);
}
report_size = sizeof(als_input);
diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c
index e9c6413af24a..9dbe6f4cb294 100644
--- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c
+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c
@@ -73,6 +73,15 @@ static int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata)
int i, status;
for (i = 0; i < cl_data->num_hid_devices; i++) {
+ switch (cl_data->sensor_idx[i]) {
+ case HPD_IDX:
+ privdata->dev_en.is_hpd_present = false;
+ break;
+ case ALS_IDX:
+ privdata->dev_en.is_als_present = false;
+ break;
+ }
+
if (cl_data->sensor_sts[i] == SENSOR_ENABLED) {
privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]);
status = amd_sfh_wait_for_response
@@ -178,6 +187,14 @@ static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata)
rc = amdtp_hid_probe(i, cl_data);
if (rc)
goto cleanup;
+ switch (cl_data->sensor_idx[i]) {
+ case HPD_IDX:
+ privdata->dev_en.is_hpd_present = true;
+ break;
+ case ALS_IDX:
+ privdata->dev_en.is_als_present = true;
+ break;
+ }
}
dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n",
cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]),
@@ -259,6 +276,7 @@ static void amd_mp2_pci_remove(void *privdata)
{
struct amd_mp2_dev *mp2 = privdata;
+ sfh_deinit_emp2();
amd_sfh_hid_client_deinit(privdata);
mp2->mp2_ops->stop_all(mp2);
pci_intx(mp2->pdev, false);
@@ -311,12 +329,14 @@ int amd_sfh1_1_init(struct amd_mp2_dev *mp2)
rc = amd_sfh_irq_init(mp2);
if (rc) {
+ sfh_deinit_emp2();
dev_err(dev, "amd_sfh_irq_init failed\n");
return rc;
}
rc = amd_sfh1_1_hid_client_init(mp2);
if (rc) {
+ sfh_deinit_emp2();
dev_err(dev, "amd_sfh1_1_hid_client_init failed\n");
return rc;
}
diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
index 4f81ef2d4f56..ae36312bc236 100644
--- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
@@ -7,11 +7,14 @@
*
* Author: Basavaraj Natikar <[email protected]>
*/
+#include <linux/amd-pmf-io.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/iopoll.h>
#include "amd_sfh_interface.h"
+static struct amd_mp2_dev *emp2;
+
static int amd_sfh_wait_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id)
{
struct sfh_cmd_response cmd_resp;
@@ -73,7 +76,63 @@ static struct amd_mp2_ops amd_sfh_ops = {
.response = amd_sfh_wait_response,
};
+void sfh_deinit_emp2(void)
+{
+ emp2 = NULL;
+}
+
void sfh_interface_init(struct amd_mp2_dev *mp2)
{
mp2->mp2_ops = &amd_sfh_ops;
+ emp2 = mp2;
+}
+
+static int amd_sfh_hpd_info(u8 *user_present)
+{
+ struct hpd_status hpdstatus;
+
+ if (!user_present)
+ return -EINVAL;
+
+ if (!emp2 || !emp2->dev_en.is_hpd_present)
+ return -ENODEV;
+
+ hpdstatus.val = readl(emp2->mmio + AMD_C2P_MSG(4));
+ *user_present = hpdstatus.shpd.presence;
+
+ return 0;
+}
+
+static int amd_sfh_als_info(u32 *ambient_light)
+{
+ struct sfh_als_data als_data;
+ void __iomem *sensoraddr;
+
+ if (!ambient_light)
+ return -EINVAL;
+
+ if (!emp2 || !emp2->dev_en.is_als_present)
+ return -ENODEV;
+
+ sensoraddr = emp2->vsbase +
+ (ALS_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) +
+ OFFSET_SENSOR_DATA_DEFAULT;
+ memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data));
+ *ambient_light = amd_sfh_float_to_int(als_data.lux);
+
+ return 0;
+}
+
+int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op)
+{
+ if (sfh_info) {
+ switch (op) {
+ case MT_HPD:
+ return amd_sfh_hpd_info(&sfh_info->user_present);
+ case MT_ALS:
+ return amd_sfh_als_info(&sfh_info->ambient_light);
+ }
+ }
+ return -EINVAL;
}
+EXPORT_SYMBOL_GPL(amd_get_sfh_info);
diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h
index 656c3e95ef8c..2c211d28764d 100644
--- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h
+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h
@@ -165,5 +165,7 @@ struct hpd_status {
};
void sfh_interface_init(struct amd_mp2_dev *mp2);
+void sfh_deinit_emp2(void);
void amd_sfh1_1_set_desc_ops(struct amd_mp2_ops *mp2_ops);
+int amd_sfh_float_to_int(u32 flt32_val);
#endif
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index e0181218ad85..de7a477d6665 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -2749,7 +2749,7 @@ static int hid_uevent(const struct device *dev, struct kobj_uevent_env *env)
return 0;
}
-struct bus_type hid_bus_type = {
+const struct bus_type hid_bus_type = {
.name = "hid",
.dev_groups = hid_dev_groups,
.drv_groups = hid_drv_groups,
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 72046039d1be..fb30e228d35f 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -916,6 +916,7 @@
#define USB_DEVICE_ID_PICK16F1454 0x0042
#define USB_DEVICE_ID_PICK16F1454_V2 0xf2f7
#define USB_DEVICE_ID_LUXAFOR 0xf372
+#define USB_DEVICE_ID_MCP2200 0x00df
#define USB_DEVICE_ID_MCP2221 0x00dd
#define USB_VENDOR_ID_MICROSOFT 0x045e
@@ -987,7 +988,10 @@
#define USB_DEVICE_ID_NINTENDO_JOYCONL 0x2006
#define USB_DEVICE_ID_NINTENDO_JOYCONR 0x2007
#define USB_DEVICE_ID_NINTENDO_PROCON 0x2009
-#define USB_DEVICE_ID_NINTENDO_CHRGGRIP 0x200E
+#define USB_DEVICE_ID_NINTENDO_CHRGGRIP 0x200e
+#define USB_DEVICE_ID_NINTENDO_SNESCON 0x2017
+#define USB_DEVICE_ID_NINTENDO_GENCON 0x201e
+#define USB_DEVICE_ID_NINTENDO_N64CON 0x2019
#define USB_VENDOR_ID_NOVATEK 0x0603
#define USB_DEVICE_ID_NOVATEK_PCT 0x0600
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index c9c968d4b36a..a46ff4e8b99f 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -120,6 +120,9 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie
* @scroll_jiffies: Time of last scroll motion.
* @touches: Most recent data for a touch, indexed by tracking ID.
* @tracking_ids: Mapping of current touch input data to @touches.
+ * @hdev: Pointer to the underlying HID device.
+ * @work: Workqueue to handle initialization retry for quirky devices.
+ * @battery_timer: Timer for obtaining battery level information.
*/
struct magicmouse_sc {
struct input_dev *input;
diff --git a/drivers/hid/hid-mcp2200.c b/drivers/hid/hid-mcp2200.c
new file mode 100644
index 000000000000..bf57f7f6caa0
--- /dev/null
+++ b/drivers/hid/hid-mcp2200.c
@@ -0,0 +1,392 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MCP2200 - Microchip USB to GPIO bridge
+ *
+ * Copyright (c) 2023, Johannes Roith <[email protected]>
+ *
+ * Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/22228A.pdf
+ * App Note for HID: https://ww1.microchip.com/downloads/en/DeviceDoc/93066A.pdf
+ */
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/hid.h>
+#include <linux/hidraw.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include "hid-ids.h"
+
+/* Commands codes in a raw output report */
+#define SET_CLEAR_OUTPUTS 0x08
+#define CONFIGURE 0x10
+#define READ_EE 0x20
+#define WRITE_EE 0x40
+#define READ_ALL 0x80
+
+/* MCP GPIO direction encoding */
+enum MCP_IO_DIR {
+ MCP2200_DIR_OUT = 0x00,
+ MCP2200_DIR_IN = 0x01,
+};
+
+/* Altternative pin assignments */
+#define TXLED 2
+#define RXLED 3
+#define USBCFG 6
+#define SSPND 7
+#define MCP_NGPIO 8
+
+/* CMD to set or clear a GPIO output */
+struct mcp_set_clear_outputs {
+ u8 cmd;
+ u8 dummys1[10];
+ u8 set_bmap;
+ u8 clear_bmap;
+ u8 dummys2[3];
+} __packed;
+
+/* CMD to configure the IOs */
+struct mcp_configure {
+ u8 cmd;
+ u8 dummys1[3];
+ u8 io_bmap;
+ u8 config_alt_pins;
+ u8 io_default_val_bmap;
+ u8 config_alt_options;
+ u8 baud_h;
+ u8 baud_l;
+ u8 dummys2[6];
+} __packed;
+
+/* CMD to read all parameters */
+struct mcp_read_all {
+ u8 cmd;
+ u8 dummys[15];
+} __packed;
+
+/* Response to the read all cmd */
+struct mcp_read_all_resp {
+ u8 cmd;
+ u8 eep_addr;
+ u8 dummy;
+ u8 eep_val;
+ u8 io_bmap;
+ u8 config_alt_pins;
+ u8 io_default_val_bmap;
+ u8 config_alt_options;
+ u8 baud_h;
+ u8 baud_l;
+ u8 io_port_val_bmap;
+ u8 dummys[5];
+} __packed;
+
+struct mcp2200 {
+ struct hid_device *hdev;
+ struct mutex lock;
+ struct completion wait_in_report;
+ u8 gpio_dir;
+ u8 gpio_val;
+ u8 gpio_inval;
+ u8 baud_h;
+ u8 baud_l;
+ u8 config_alt_pins;
+ u8 gpio_reset_val;
+ u8 config_alt_options;
+ int status;
+ struct gpio_chip gc;
+ u8 hid_report[16];
+};
+
+/* this executes the READ_ALL cmd */
+static int mcp_cmd_read_all(struct mcp2200 *mcp)
+{
+ struct mcp_read_all *read_all;
+ int len, t;
+
+ reinit_completion(&mcp->wait_in_report);
+
+ mutex_lock(&mcp->lock);
+
+ read_all = (struct mcp_read_all *) mcp->hid_report;
+ read_all->cmd = READ_ALL;
+ len = hid_hw_output_report(mcp->hdev, (u8 *) read_all,
+ sizeof(struct mcp_read_all));
+
+ mutex_unlock(&mcp->lock);
+
+ if (len != sizeof(struct mcp_read_all))
+ return -EINVAL;
+
+ t = wait_for_completion_timeout(&mcp->wait_in_report,
+ msecs_to_jiffies(4000));
+ if (!t)
+ return -ETIMEDOUT;
+
+ /* return status, negative value if wrong response was received */
+ return mcp->status;
+}
+
+static void mcp_set_multiple(struct gpio_chip *gc, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct mcp2200 *mcp = gpiochip_get_data(gc);
+ u8 value;
+ int status;
+ struct mcp_set_clear_outputs *cmd;
+
+ mutex_lock(&mcp->lock);
+ cmd = (struct mcp_set_clear_outputs *) mcp->hid_report;
+
+ value = mcp->gpio_val & ~*mask;
+ value |= (*mask & *bits);
+
+ cmd->cmd = SET_CLEAR_OUTPUTS;
+ cmd->set_bmap = value;
+ cmd->clear_bmap = ~(value);
+
+ status = hid_hw_output_report(mcp->hdev, (u8 *) cmd,
+ sizeof(struct mcp_set_clear_outputs));
+
+ if (status == sizeof(struct mcp_set_clear_outputs))
+ mcp->gpio_val = value;
+
+ mutex_unlock(&mcp->lock);
+}
+
+static void mcp_set(struct gpio_chip *gc, unsigned int gpio_nr, int value)
+{
+ unsigned long mask = 1 << gpio_nr;
+ unsigned long bmap_value = value << gpio_nr;
+
+ mcp_set_multiple(gc, &mask, &bmap_value);
+}
+
+static int mcp_get_multiple(struct gpio_chip *gc, unsigned long *mask,
+ unsigned long *bits)
+{
+ u32 val;
+ struct mcp2200 *mcp = gpiochip_get_data(gc);
+ int status;
+
+ status = mcp_cmd_read_all(mcp);
+ if (status)
+ return status;
+
+ val = mcp->gpio_inval;
+ *bits = (val & *mask);
+ return 0;
+}
+
+static int mcp_get(struct gpio_chip *gc, unsigned int gpio_nr)
+{
+ unsigned long mask = 0, bits = 0;
+
+ mask = (1 << gpio_nr);
+ mcp_get_multiple(gc, &mask, &bits);
+ return bits > 0;
+}
+
+static int mcp_get_direction(struct gpio_chip *gc, unsigned int gpio_nr)
+{
+ struct mcp2200 *mcp = gpiochip_get_data(gc);
+
+ return (mcp->gpio_dir & (MCP2200_DIR_IN << gpio_nr))
+ ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
+}
+
+static int mcp_set_direction(struct gpio_chip *gc, unsigned int gpio_nr,
+ enum MCP_IO_DIR io_direction)
+{
+ struct mcp2200 *mcp = gpiochip_get_data(gc);
+ struct mcp_configure *conf;
+ int status;
+ /* after the configure cmd we will need to set the outputs again */
+ unsigned long mask = ~(mcp->gpio_dir); /* only set outputs */
+ unsigned long bits = mcp->gpio_val;
+ /* Offsets of alternative pins in config_alt_pins, 0 is not used */
+ u8 alt_pin_conf[8] = {SSPND, USBCFG, 0, 0, 0, 0, RXLED, TXLED};
+ u8 config_alt_pins = mcp->config_alt_pins;
+
+ /* Read in the reset baudrate first, we need it later */
+ status = mcp_cmd_read_all(mcp);
+ if (status != 0)
+ return status;
+
+ mutex_lock(&mcp->lock);
+ conf = (struct mcp_configure *) mcp->hid_report;
+
+ /* configure will reset the chip! */
+ conf->cmd = CONFIGURE;
+ conf->io_bmap = (mcp->gpio_dir & ~(1 << gpio_nr))
+ | (io_direction << gpio_nr);
+ /* Don't overwrite the reset parameters */
+ conf->baud_h = mcp->baud_h;
+ conf->baud_l = mcp->baud_l;
+ conf->config_alt_options = mcp->config_alt_options;
+ conf->io_default_val_bmap = mcp->gpio_reset_val;
+ /* Adjust alt. func if necessary */
+ if (alt_pin_conf[gpio_nr])
+ config_alt_pins &= ~(1 << alt_pin_conf[gpio_nr]);
+ conf->config_alt_pins = config_alt_pins;
+
+ status = hid_hw_output_report(mcp->hdev, (u8 *) conf,
+ sizeof(struct mcp_set_clear_outputs));
+
+ if (status == sizeof(struct mcp_set_clear_outputs)) {
+ mcp->gpio_dir = conf->io_bmap;
+ mcp->config_alt_pins = config_alt_pins;
+ } else {
+ mutex_unlock(&mcp->lock);
+ return -EIO;
+ }
+
+ mutex_unlock(&mcp->lock);
+
+ /* Configure CMD will clear all IOs -> rewrite them */
+ mcp_set_multiple(gc, &mask, &bits);
+ return 0;
+}
+
+static int mcp_direction_input(struct gpio_chip *gc, unsigned int gpio_nr)
+{
+ return mcp_set_direction(gc, gpio_nr, MCP2200_DIR_IN);
+}
+
+static int mcp_direction_output(struct gpio_chip *gc, unsigned int gpio_nr,
+ int value)
+{
+ int ret;
+ unsigned long mask, bmap_value;
+
+ mask = 1 << gpio_nr;
+ bmap_value = value << gpio_nr;
+
+ ret = mcp_set_direction(gc, gpio_nr, MCP2200_DIR_OUT);
+ if (!ret)
+ mcp_set_multiple(gc, &mask, &bmap_value);
+ return ret;
+}
+
+static const struct gpio_chip template_chip = {
+ .label = "mcp2200",
+ .owner = THIS_MODULE,
+ .get_direction = mcp_get_direction,
+ .direction_input = mcp_direction_input,
+ .direction_output = mcp_direction_output,
+ .set = mcp_set,
+ .set_multiple = mcp_set_multiple,
+ .get = mcp_get,
+ .get_multiple = mcp_get_multiple,
+ .base = -1,
+ .ngpio = MCP_NGPIO,
+ .can_sleep = true,
+};
+
+/*
+ * MCP2200 uses interrupt endpoint for input reports. This function
+ * is called by HID layer when it receives i/p report from mcp2200,
+ * which is actually a response to the previously sent command.
+ */
+static int mcp2200_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *data, int size)
+{
+ struct mcp2200 *mcp = hid_get_drvdata(hdev);
+ struct mcp_read_all_resp *all_resp;
+
+ switch (data[0]) {
+ case READ_ALL:
+ all_resp = (struct mcp_read_all_resp *) data;
+ mcp->status = 0;
+ mcp->gpio_inval = all_resp->io_port_val_bmap;
+ mcp->baud_h = all_resp->baud_h;
+ mcp->baud_l = all_resp->baud_l;
+ mcp->gpio_reset_val = all_resp->io_default_val_bmap;
+ mcp->config_alt_pins = all_resp->config_alt_pins;
+ mcp->config_alt_options = all_resp->config_alt_options;
+ break;
+ default:
+ mcp->status = -EIO;
+ break;
+ }
+
+ complete(&mcp->wait_in_report);
+ return 0;
+}
+
+static int mcp2200_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+ struct mcp2200 *mcp;
+
+ mcp = devm_kzalloc(&hdev->dev, sizeof(*mcp), GFP_KERNEL);
+ if (!mcp)
+ return -ENOMEM;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "can't parse reports\n");
+ return ret;
+ }
+
+ ret = hid_hw_start(hdev, 0);
+ if (ret) {
+ hid_err(hdev, "can't start hardware\n");
+ return ret;
+ }
+
+ hid_info(hdev, "USB HID v%x.%02x Device [%s] on %s\n", hdev->version >> 8,
+ hdev->version & 0xff, hdev->name, hdev->phys);
+
+ ret = hid_hw_open(hdev);
+ if (ret) {
+ hid_err(hdev, "can't open device\n");
+ hid_hw_stop(hdev);
+ return ret;
+ }
+
+ mutex_init(&mcp->lock);
+ init_completion(&mcp->wait_in_report);
+ hid_set_drvdata(hdev, mcp);
+ mcp->hdev = hdev;
+
+ mcp->gc = template_chip;
+ mcp->gc.parent = &hdev->dev;
+
+ ret = devm_gpiochip_add_data(&hdev->dev, &mcp->gc, mcp);
+ if (ret < 0) {
+ hid_err(hdev, "Unable to register gpiochip\n");
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mcp2200_remove(struct hid_device *hdev)
+{
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
+}
+
+static const struct hid_device_id mcp2200_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_MCP2200) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, mcp2200_devices);
+
+static struct hid_driver mcp2200_driver = {
+ .name = "mcp2200",
+ .id_table = mcp2200_devices,
+ .probe = mcp2200_probe,
+ .remove = mcp2200_remove,
+ .raw_event = mcp2200_raw_event,
+};
+
+/* Register with HID core */
+module_hid_driver(mcp2200_driver);
+
+MODULE_AUTHOR("Johannes Roith <[email protected]>");
+MODULE_DESCRIPTION("MCP2200 Microchip HID USB to GPIO bridge");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
index aef0785c91cc..f9cceaeffd08 100644
--- a/drivers/hid/hid-mcp2221.c
+++ b/drivers/hid/hid-mcp2221.c
@@ -49,6 +49,7 @@ enum {
MCP2221_I2C_MASK_ADDR_NACK = 0x40,
MCP2221_I2C_WRADDRL_SEND = 0x21,
MCP2221_I2C_ADDR_NACK = 0x25,
+ MCP2221_I2C_READ_PARTIAL = 0x54,
MCP2221_I2C_READ_COMPL = 0x55,
MCP2221_ALT_F_NOT_GPIOV = 0xEE,
MCP2221_ALT_F_NOT_GPIOD = 0xEF,
@@ -187,6 +188,25 @@ static int mcp_cancel_last_cmd(struct mcp2221 *mcp)
return mcp_send_data_req_status(mcp, mcp->txbuf, 8);
}
+/* Check if the last command succeeded or failed and return the result.
+ * If the command did fail, cancel that command which will free the i2c bus.
+ */
+static int mcp_chk_last_cmd_status_free_bus(struct mcp2221 *mcp)
+{
+ int ret;
+
+ ret = mcp_chk_last_cmd_status(mcp);
+ if (ret) {
+ /* The last command was a failure.
+ * Send a cancel which will also free the bus.
+ */
+ usleep_range(980, 1000);
+ mcp_cancel_last_cmd(mcp);
+ }
+
+ return ret;
+}
+
static int mcp_set_i2c_speed(struct mcp2221 *mcp)
{
int ret;
@@ -241,7 +261,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp,
usleep_range(980, 1000);
if (last_status) {
- ret = mcp_chk_last_cmd_status(mcp);
+ ret = mcp_chk_last_cmd_status_free_bus(mcp);
if (ret)
return ret;
}
@@ -278,6 +298,7 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
{
int ret;
u16 total_len;
+ int retries = 0;
mcp->txbuf[0] = type;
if (msg) {
@@ -301,20 +322,31 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
mcp->rxbuf_idx = 0;
do {
+ /* Wait for the data to be read by the device */
+ usleep_range(980, 1000);
+
memset(mcp->txbuf, 0, 4);
mcp->txbuf[0] = MCP2221_I2C_GET_DATA;
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
- if (ret)
- return ret;
-
- ret = mcp_chk_last_cmd_status(mcp);
- if (ret)
- return ret;
-
- usleep_range(980, 1000);
+ if (ret) {
+ if (retries < 5) {
+ /* The data wasn't ready to read.
+ * Wait a bit longer and try again.
+ */
+ usleep_range(90, 100);
+ retries++;
+ } else {
+ return ret;
+ }
+ } else {
+ retries = 0;
+ }
} while (mcp->rxbuf_idx < total_len);
+ usleep_range(980, 1000);
+ ret = mcp_chk_last_cmd_status_free_bus(mcp);
+
return ret;
}
@@ -328,11 +360,6 @@ static int mcp_i2c_xfer(struct i2c_adapter *adapter,
mutex_lock(&mcp->lock);
- /* Setting speed before every transaction is required for mcp2221 */
- ret = mcp_set_i2c_speed(mcp);
- if (ret)
- goto exit;
-
if (num == 1) {
if (msgs->flags & I2C_M_RD) {
ret = mcp_i2c_smbus_read(mcp, msgs, MCP2221_I2C_RD_DATA,
@@ -417,9 +444,7 @@ static int mcp_smbus_write(struct mcp2221 *mcp, u16 addr,
if (last_status) {
usleep_range(980, 1000);
- ret = mcp_chk_last_cmd_status(mcp);
- if (ret)
- return ret;
+ ret = mcp_chk_last_cmd_status_free_bus(mcp);
}
return ret;
@@ -437,10 +462,6 @@ static int mcp_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
mutex_lock(&mcp->lock);
- ret = mcp_set_i2c_speed(mcp);
- if (ret)
- goto exit;
-
switch (size) {
case I2C_SMBUS_QUICK:
@@ -791,7 +812,8 @@ static int mcp2221_raw_event(struct hid_device *hdev,
mcp->status = -EIO;
break;
}
- if (data[2] == MCP2221_I2C_READ_COMPL) {
+ if (data[2] == MCP2221_I2C_READ_COMPL ||
+ data[2] == MCP2221_I2C_READ_PARTIAL) {
buf = mcp->rxbuf;
memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]);
mcp->rxbuf_idx = mcp->rxbuf_idx + data[3];
@@ -1150,12 +1172,18 @@ static int mcp2221_probe(struct hid_device *hdev,
if (i2c_clk_freq < 50)
i2c_clk_freq = 50;
mcp->cur_i2c_clk_div = (12000000 / (i2c_clk_freq * 1000)) - 3;
+ ret = mcp_set_i2c_speed(mcp);
+ if (ret) {
+ hid_err(hdev, "can't set i2c speed: %d\n", ret);
+ return ret;
+ }
mcp->adapter.owner = THIS_MODULE;
mcp->adapter.class = I2C_CLASS_HWMON;
mcp->adapter.algo = &mcp_i2c_algo;
mcp->adapter.retries = 1;
mcp->adapter.dev.parent = &hdev->dev;
+ ACPI_COMPANION_SET(&mcp->adapter.dev, ACPI_COMPANION(hdev->dev.parent));
snprintf(mcp->adapter.name, sizeof(mcp->adapter.name),
"MCP2221 usb-i2c bridge");
diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c
index 997c3a1adaca..ccc4032fb2b0 100644
--- a/drivers/hid/hid-nintendo.c
+++ b/drivers/hid/hid-nintendo.c
@@ -3,6 +3,9 @@
* HID driver for Nintendo Switch Joy-Cons and Pro Controllers
*
* Copyright (c) 2019-2021 Daniel J. Ogorchock <[email protected]>
+ * Portions Copyright (c) 2020 Nadia Holmquist Pedersen <[email protected]>
+ * Copyright (c) 2022 Emily Strickland <[email protected]>
+ * Copyright (c) 2023 Ryan McClelland <[email protected]>
*
* The following resources/projects were referenced for this driver:
* https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering
@@ -17,6 +20,9 @@
* This driver supports the Nintendo Switch Joy-Cons and Pro Controllers. The
* Pro Controllers can either be used over USB or Bluetooth.
*
+ * This driver also incorporates support for Nintendo Switch Online controllers
+ * for the NES, SNES, Sega Genesis, and N64.
+ *
* The driver will retrieve the factory calibration info from the controllers,
* so little to no user calibration should be required.
*
@@ -305,9 +311,14 @@ enum joycon_ctlr_state {
/* Controller type received as part of device info */
enum joycon_ctlr_type {
- JOYCON_CTLR_TYPE_JCL = 0x01,
- JOYCON_CTLR_TYPE_JCR = 0x02,
- JOYCON_CTLR_TYPE_PRO = 0x03,
+ JOYCON_CTLR_TYPE_JCL = 0x01,
+ JOYCON_CTLR_TYPE_JCR = 0x02,
+ JOYCON_CTLR_TYPE_PRO = 0x03,
+ JOYCON_CTLR_TYPE_NESL = 0x09,
+ JOYCON_CTLR_TYPE_NESR = 0x0A,
+ JOYCON_CTLR_TYPE_SNES = 0x0B,
+ JOYCON_CTLR_TYPE_GEN = 0x0D,
+ JOYCON_CTLR_TYPE_N64 = 0x0C,
};
struct joycon_stick_cal {
@@ -348,6 +359,137 @@ struct joycon_imu_cal {
#define JC_BTN_L BIT(22)
#define JC_BTN_ZL BIT(23)
+struct joycon_ctlr_button_mapping {
+ u32 code;
+ u32 bit;
+};
+
+/*
+ * D-pad is configured as buttons for the left Joy-Con only!
+ */
+static const struct joycon_ctlr_button_mapping left_joycon_button_mappings[] = {
+ { BTN_TL, JC_BTN_L, },
+ { BTN_TL2, JC_BTN_ZL, },
+ { BTN_SELECT, JC_BTN_MINUS, },
+ { BTN_THUMBL, JC_BTN_LSTICK, },
+ { BTN_DPAD_UP, JC_BTN_UP, },
+ { BTN_DPAD_DOWN, JC_BTN_DOWN, },
+ { BTN_DPAD_LEFT, JC_BTN_LEFT, },
+ { BTN_DPAD_RIGHT, JC_BTN_RIGHT, },
+ { BTN_Z, JC_BTN_CAP, },
+ { /* sentinel */ },
+};
+
+/*
+ * The unused *right*-side triggers become the SL/SR triggers for the *left*
+ * Joy-Con, if and only if we're not using a charging grip.
+ */
+static const struct joycon_ctlr_button_mapping left_joycon_s_button_mappings[] = {
+ { BTN_TR, JC_BTN_SL_L, },
+ { BTN_TR2, JC_BTN_SR_L, },
+ { /* sentinel */ },
+};
+
+static const struct joycon_ctlr_button_mapping right_joycon_button_mappings[] = {
+ { BTN_EAST, JC_BTN_A, },
+ { BTN_SOUTH, JC_BTN_B, },
+ { BTN_NORTH, JC_BTN_X, },
+ { BTN_WEST, JC_BTN_Y, },
+ { BTN_TR, JC_BTN_R, },
+ { BTN_TR2, JC_BTN_ZR, },
+ { BTN_START, JC_BTN_PLUS, },
+ { BTN_THUMBR, JC_BTN_RSTICK, },
+ { BTN_MODE, JC_BTN_HOME, },
+ { /* sentinel */ },
+};
+
+/*
+ * The unused *left*-side triggers become the SL/SR triggers for the *right*
+ * Joy-Con, if and only if we're not using a charging grip.
+ */
+static const struct joycon_ctlr_button_mapping right_joycon_s_button_mappings[] = {
+ { BTN_TL, JC_BTN_SL_R, },
+ { BTN_TL2, JC_BTN_SR_R, },
+ { /* sentinel */ },
+};
+
+static const struct joycon_ctlr_button_mapping procon_button_mappings[] = {
+ { BTN_EAST, JC_BTN_A, },
+ { BTN_SOUTH, JC_BTN_B, },
+ { BTN_NORTH, JC_BTN_X, },
+ { BTN_WEST, JC_BTN_Y, },
+ { BTN_TL, JC_BTN_L, },
+ { BTN_TR, JC_BTN_R, },
+ { BTN_TL2, JC_BTN_ZL, },
+ { BTN_TR2, JC_BTN_ZR, },
+ { BTN_SELECT, JC_BTN_MINUS, },
+ { BTN_START, JC_BTN_PLUS, },
+ { BTN_THUMBL, JC_BTN_LSTICK, },
+ { BTN_THUMBR, JC_BTN_RSTICK, },
+ { BTN_MODE, JC_BTN_HOME, },
+ { BTN_Z, JC_BTN_CAP, },
+ { /* sentinel */ },
+};
+
+static const struct joycon_ctlr_button_mapping nescon_button_mappings[] = {
+ { BTN_SOUTH, JC_BTN_A, },
+ { BTN_EAST, JC_BTN_B, },
+ { BTN_TL, JC_BTN_L, },
+ { BTN_TR, JC_BTN_R, },
+ { BTN_SELECT, JC_BTN_MINUS, },
+ { BTN_START, JC_BTN_PLUS, },
+ { /* sentinel */ },
+};
+
+static const struct joycon_ctlr_button_mapping snescon_button_mappings[] = {
+ { BTN_EAST, JC_BTN_A, },
+ { BTN_SOUTH, JC_BTN_B, },
+ { BTN_NORTH, JC_BTN_X, },
+ { BTN_WEST, JC_BTN_Y, },
+ { BTN_TL, JC_BTN_L, },
+ { BTN_TR, JC_BTN_R, },
+ { BTN_TL2, JC_BTN_ZL, },
+ { BTN_TR2, JC_BTN_ZR, },
+ { BTN_SELECT, JC_BTN_MINUS, },
+ { BTN_START, JC_BTN_PLUS, },
+ { /* sentinel */ },
+};
+
+/*
+ * "A", "B", and "C" are mapped positionally, rather than by label (e.g., "A"
+ * gets assigned to BTN_EAST instead of BTN_A).
+ */
+static const struct joycon_ctlr_button_mapping gencon_button_mappings[] = {
+ { BTN_SOUTH, JC_BTN_A, },
+ { BTN_EAST, JC_BTN_B, },
+ { BTN_WEST, JC_BTN_R, },
+ { BTN_SELECT, JC_BTN_ZR, },
+ { BTN_START, JC_BTN_PLUS, },
+ { BTN_MODE, JC_BTN_HOME, },
+ { BTN_Z, JC_BTN_CAP, },
+ { /* sentinel */ },
+};
+
+/*
+ * N64's C buttons get assigned to d-pad directions and registered as buttons.
+ */
+static const struct joycon_ctlr_button_mapping n64con_button_mappings[] = {
+ { BTN_A, JC_BTN_A, },
+ { BTN_B, JC_BTN_B, },
+ { BTN_TL2, JC_BTN_ZL, }, /* Z */
+ { BTN_TL, JC_BTN_L, },
+ { BTN_TR, JC_BTN_R, },
+ { BTN_TR2, JC_BTN_LSTICK, }, /* ZR */
+ { BTN_START, JC_BTN_PLUS, },
+ { BTN_FORWARD, JC_BTN_Y, }, /* C UP */
+ { BTN_BACK, JC_BTN_ZR, }, /* C DOWN */
+ { BTN_LEFT, JC_BTN_X, }, /* C LEFT */
+ { BTN_RIGHT, JC_BTN_MINUS, }, /* C RIGHT */
+ { BTN_MODE, JC_BTN_HOME, },
+ { BTN_Z, JC_BTN_CAP, },
+ { /* sentinel */ },
+};
+
enum joycon_msg_type {
JOYCON_MSG_TYPE_NONE,
JOYCON_MSG_TYPE_USB,
@@ -506,13 +648,182 @@ struct joycon_ctlr {
/* Does this controller have inputs associated with left joycon? */
#define jc_type_has_left(ctlr) \
(ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCL || \
- ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO)
+ ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO || \
+ ctlr->ctlr_type == JOYCON_CTLR_TYPE_N64)
/* Does this controller have inputs associated with right joycon? */
#define jc_type_has_right(ctlr) \
(ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCR || \
ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO)
+
+/*
+ * Controller device helpers
+ *
+ * These look at the device ID known to the HID subsystem to identify a device,
+ * but take caution: some NSO devices lie about themselves (NES Joy-Cons and
+ * Sega Genesis controller). See type helpers below.
+ *
+ * These helpers are most useful early during the HID probe or in conjunction
+ * with the capability helpers below.
+ */
+static inline bool joycon_device_is_left_joycon(struct joycon_ctlr *ctlr)
+{
+ return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONL;
+}
+
+static inline bool joycon_device_is_right_joycon(struct joycon_ctlr *ctlr)
+{
+ return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONR;
+}
+
+static inline bool joycon_device_is_procon(struct joycon_ctlr *ctlr)
+{
+ return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_PROCON;
+}
+
+static inline bool joycon_device_is_chrggrip(struct joycon_ctlr *ctlr)
+{
+ return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_CHRGGRIP;
+}
+
+static inline bool joycon_device_is_snescon(struct joycon_ctlr *ctlr)
+{
+ return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_SNESCON;
+}
+
+static inline bool joycon_device_is_gencon(struct joycon_ctlr *ctlr)
+{
+ return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_GENCON;
+}
+
+static inline bool joycon_device_is_n64con(struct joycon_ctlr *ctlr)
+{
+ return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_N64CON;
+}
+
+static inline bool joycon_device_has_usb(struct joycon_ctlr *ctlr)
+{
+ return joycon_device_is_procon(ctlr) ||
+ joycon_device_is_chrggrip(ctlr) ||
+ joycon_device_is_snescon(ctlr) ||
+ joycon_device_is_gencon(ctlr) ||
+ joycon_device_is_n64con(ctlr);
+}
+
+/*
+ * Controller type helpers
+ *
+ * These are slightly different than the device-ID-based helpers above. They are
+ * generally more reliable, since they can distinguish between, e.g., Genesis
+ * versus SNES, or NES Joy-Cons versus regular Switch Joy-Cons. They're most
+ * useful for reporting available inputs. For other kinds of distinctions, see
+ * the capability helpers below.
+ *
+ * They have two major drawbacks: (1) they're not available until after we set
+ * the reporting method and then request the device info; (2) they can't
+ * distinguish all controllers (like the Charging Grip from the Pro controller.)
+ */
+static inline bool joycon_type_is_left_joycon(struct joycon_ctlr *ctlr)
+{
+ return ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCL;
+}
+
+static inline bool joycon_type_is_right_joycon(struct joycon_ctlr *ctlr)
+{
+ return ctlr->ctlr_type == JOYCON_CTLR_TYPE_JCR;
+}
+
+static inline bool joycon_type_is_procon(struct joycon_ctlr *ctlr)
+{
+ return ctlr->ctlr_type == JOYCON_CTLR_TYPE_PRO;
+}
+
+static inline bool joycon_type_is_snescon(struct joycon_ctlr *ctlr)
+{
+ return ctlr->ctlr_type == JOYCON_CTLR_TYPE_SNES;
+}
+
+static inline bool joycon_type_is_gencon(struct joycon_ctlr *ctlr)
+{
+ return ctlr->ctlr_type == JOYCON_CTLR_TYPE_GEN;
+}
+
+static inline bool joycon_type_is_n64con(struct joycon_ctlr *ctlr)
+{
+ return ctlr->ctlr_type == JOYCON_CTLR_TYPE_N64;
+}
+
+static inline bool joycon_type_is_left_nescon(struct joycon_ctlr *ctlr)
+{
+ return ctlr->ctlr_type == JOYCON_CTLR_TYPE_NESL;
+}
+
+static inline bool joycon_type_is_right_nescon(struct joycon_ctlr *ctlr)
+{
+ return ctlr->ctlr_type == JOYCON_CTLR_TYPE_NESR;
+}
+
+static inline bool joycon_type_has_left_controls(struct joycon_ctlr *ctlr)
+{
+ return joycon_type_is_left_joycon(ctlr) ||
+ joycon_type_is_procon(ctlr);
+}
+
+static inline bool joycon_type_has_right_controls(struct joycon_ctlr *ctlr)
+{
+ return joycon_type_is_right_joycon(ctlr) ||
+ joycon_type_is_procon(ctlr);
+}
+
+static inline bool joycon_type_is_any_joycon(struct joycon_ctlr *ctlr)
+{
+ return joycon_type_is_left_joycon(ctlr) ||
+ joycon_type_is_right_joycon(ctlr) ||
+ joycon_device_is_chrggrip(ctlr);
+}
+
+static inline bool joycon_type_is_any_nescon(struct joycon_ctlr *ctlr)
+{
+ return joycon_type_is_left_nescon(ctlr) ||
+ joycon_type_is_right_nescon(ctlr);
+}
+
+/*
+ * Controller capability helpers
+ *
+ * These helpers combine the use of the helpers above to detect certain
+ * capabilities during initialization. They are always accurate but (since they
+ * use type helpers) cannot be used early in the HID probe.
+ */
+static inline bool joycon_has_imu(struct joycon_ctlr *ctlr)
+{
+ return joycon_device_is_chrggrip(ctlr) ||
+ joycon_type_is_any_joycon(ctlr) ||
+ joycon_type_is_procon(ctlr);
+}
+
+static inline bool joycon_has_joysticks(struct joycon_ctlr *ctlr)
+{
+ return joycon_device_is_chrggrip(ctlr) ||
+ joycon_type_is_any_joycon(ctlr) ||
+ joycon_type_is_procon(ctlr) ||
+ joycon_type_is_n64con(ctlr);
+}
+
+static inline bool joycon_has_rumble(struct joycon_ctlr *ctlr)
+{
+ return joycon_device_is_chrggrip(ctlr) ||
+ joycon_type_is_any_joycon(ctlr) ||
+ joycon_type_is_procon(ctlr) ||
+ joycon_type_is_n64con(ctlr);
+}
+
+static inline bool joycon_using_usb(struct joycon_ctlr *ctlr)
+{
+ return ctlr->hdev->bus == BUS_USB;
+}
+
static int __joycon_hid_send(struct hid_device *hdev, u8 *data, size_t len)
{
u8 *buf;
@@ -1296,15 +1607,10 @@ static void joycon_parse_imu_report(struct joycon_ctlr *ctlr,
}
}
-static void joycon_parse_report(struct joycon_ctlr *ctlr,
- struct joycon_input_report *rep)
+static void joycon_handle_rumble_report(struct joycon_ctlr *ctlr, struct joycon_input_report *rep)
{
- struct input_dev *dev = ctlr->input;
unsigned long flags;
- u8 tmp;
- u32 btns;
unsigned long msecs = jiffies_to_msecs(jiffies);
- unsigned long report_delta_ms = msecs - ctlr->last_input_report_msecs;
spin_lock_irqsave(&ctlr->lock, flags);
if (IS_ENABLED(CONFIG_NINTENDO_FF) && rep->vibrator_report &&
@@ -1323,11 +1629,21 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
queue_work(ctlr->rumble_queue, &ctlr->rumble_worker);
}
- /* Parse the battery status */
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+}
+
+static void joycon_parse_battery_status(struct joycon_ctlr *ctlr, struct joycon_input_report *rep)
+{
+ u8 tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+
tmp = rep->bat_con;
ctlr->host_powered = tmp & BIT(0);
ctlr->battery_charging = tmp & BIT(4);
tmp = tmp >> 5;
+
switch (tmp) {
case 0: /* empty */
ctlr->battery_capacity = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
@@ -1349,102 +1665,121 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
hid_warn(ctlr->hdev, "Invalid battery status\n");
break;
}
+
spin_unlock_irqrestore(&ctlr->lock, flags);
+}
- /* Parse the buttons and sticks */
- btns = hid_field_extract(ctlr->hdev, rep->button_status, 0, 24);
-
- if (jc_type_has_left(ctlr)) {
- u16 raw_x;
- u16 raw_y;
- s32 x;
- s32 y;
-
- /* get raw stick values */
- raw_x = hid_field_extract(ctlr->hdev, rep->left_stick, 0, 12);
- raw_y = hid_field_extract(ctlr->hdev,
- rep->left_stick + 1, 4, 12);
- /* map the stick values */
- x = joycon_map_stick_val(&ctlr->left_stick_cal_x, raw_x);
- y = -joycon_map_stick_val(&ctlr->left_stick_cal_y, raw_y);
- /* report sticks */
- input_report_abs(dev, ABS_X, x);
- input_report_abs(dev, ABS_Y, y);
-
- /* report buttons */
- input_report_key(dev, BTN_TL, btns & JC_BTN_L);
- input_report_key(dev, BTN_TL2, btns & JC_BTN_ZL);
- input_report_key(dev, BTN_SELECT, btns & JC_BTN_MINUS);
- input_report_key(dev, BTN_THUMBL, btns & JC_BTN_LSTICK);
- input_report_key(dev, BTN_Z, btns & JC_BTN_CAP);
-
- if (jc_type_is_joycon(ctlr)) {
- /* Report the S buttons as the non-existent triggers */
- input_report_key(dev, BTN_TR, btns & JC_BTN_SL_L);
- input_report_key(dev, BTN_TR2, btns & JC_BTN_SR_L);
-
- /* Report d-pad as digital buttons for the joy-cons */
- input_report_key(dev, BTN_DPAD_DOWN,
- btns & JC_BTN_DOWN);
- input_report_key(dev, BTN_DPAD_UP, btns & JC_BTN_UP);
- input_report_key(dev, BTN_DPAD_RIGHT,
- btns & JC_BTN_RIGHT);
- input_report_key(dev, BTN_DPAD_LEFT,
- btns & JC_BTN_LEFT);
- } else {
- int hatx = 0;
- int haty = 0;
-
- /* d-pad x */
- if (btns & JC_BTN_LEFT)
- hatx = -1;
- else if (btns & JC_BTN_RIGHT)
- hatx = 1;
- input_report_abs(dev, ABS_HAT0X, hatx);
-
- /* d-pad y */
- if (btns & JC_BTN_UP)
- haty = -1;
- else if (btns & JC_BTN_DOWN)
- haty = 1;
- input_report_abs(dev, ABS_HAT0Y, haty);
- }
- }
- if (jc_type_has_right(ctlr)) {
- u16 raw_x;
- u16 raw_y;
- s32 x;
- s32 y;
-
- /* get raw stick values */
- raw_x = hid_field_extract(ctlr->hdev, rep->right_stick, 0, 12);
- raw_y = hid_field_extract(ctlr->hdev,
- rep->right_stick + 1, 4, 12);
- /* map stick values */
- x = joycon_map_stick_val(&ctlr->right_stick_cal_x, raw_x);
- y = -joycon_map_stick_val(&ctlr->right_stick_cal_y, raw_y);
- /* report sticks */
- input_report_abs(dev, ABS_RX, x);
- input_report_abs(dev, ABS_RY, y);
-
- /* report buttons */
- input_report_key(dev, BTN_TR, btns & JC_BTN_R);
- input_report_key(dev, BTN_TR2, btns & JC_BTN_ZR);
- if (jc_type_is_joycon(ctlr)) {
- /* Report the S buttons as the non-existent triggers */
- input_report_key(dev, BTN_TL, btns & JC_BTN_SL_R);
- input_report_key(dev, BTN_TL2, btns & JC_BTN_SR_R);
- }
- input_report_key(dev, BTN_START, btns & JC_BTN_PLUS);
- input_report_key(dev, BTN_THUMBR, btns & JC_BTN_RSTICK);
- input_report_key(dev, BTN_MODE, btns & JC_BTN_HOME);
- input_report_key(dev, BTN_WEST, btns & JC_BTN_Y);
- input_report_key(dev, BTN_NORTH, btns & JC_BTN_X);
- input_report_key(dev, BTN_EAST, btns & JC_BTN_A);
- input_report_key(dev, BTN_SOUTH, btns & JC_BTN_B);
+static void joycon_report_left_stick(struct joycon_ctlr *ctlr,
+ struct joycon_input_report *rep)
+{
+ u16 raw_x;
+ u16 raw_y;
+ s32 x;
+ s32 y;
+
+ raw_x = hid_field_extract(ctlr->hdev, rep->left_stick, 0, 12);
+ raw_y = hid_field_extract(ctlr->hdev, rep->left_stick + 1, 4, 12);
+
+ x = joycon_map_stick_val(&ctlr->left_stick_cal_x, raw_x);
+ y = -joycon_map_stick_val(&ctlr->left_stick_cal_y, raw_y);
+
+ input_report_abs(ctlr->input, ABS_X, x);
+ input_report_abs(ctlr->input, ABS_Y, y);
+}
+
+static void joycon_report_right_stick(struct joycon_ctlr *ctlr,
+ struct joycon_input_report *rep)
+{
+ u16 raw_x;
+ u16 raw_y;
+ s32 x;
+ s32 y;
+
+ raw_x = hid_field_extract(ctlr->hdev, rep->right_stick, 0, 12);
+ raw_y = hid_field_extract(ctlr->hdev, rep->right_stick + 1, 4, 12);
+
+ x = joycon_map_stick_val(&ctlr->right_stick_cal_x, raw_x);
+ y = -joycon_map_stick_val(&ctlr->right_stick_cal_y, raw_y);
+
+ input_report_abs(ctlr->input, ABS_RX, x);
+ input_report_abs(ctlr->input, ABS_RY, y);
+}
+
+static void joycon_report_dpad(struct joycon_ctlr *ctlr,
+ struct joycon_input_report *rep)
+{
+ int hatx = 0;
+ int haty = 0;
+ u32 btns = hid_field_extract(ctlr->hdev, rep->button_status, 0, 24);
+
+ if (btns & JC_BTN_LEFT)
+ hatx = -1;
+ else if (btns & JC_BTN_RIGHT)
+ hatx = 1;
+
+ if (btns & JC_BTN_UP)
+ haty = -1;
+ else if (btns & JC_BTN_DOWN)
+ haty = 1;
+
+ input_report_abs(ctlr->input, ABS_HAT0X, hatx);
+ input_report_abs(ctlr->input, ABS_HAT0Y, haty);
+}
+
+static void joycon_report_buttons(struct joycon_ctlr *ctlr,
+ struct joycon_input_report *rep,
+ const struct joycon_ctlr_button_mapping button_mappings[])
+{
+ const struct joycon_ctlr_button_mapping *button;
+ u32 status = hid_field_extract(ctlr->hdev, rep->button_status, 0, 24);
+
+ for (button = button_mappings; button->code; button++)
+ input_report_key(ctlr->input, button->code, status & button->bit);
+}
+
+static void joycon_parse_report(struct joycon_ctlr *ctlr,
+ struct joycon_input_report *rep)
+{
+ unsigned long flags;
+ unsigned long msecs = jiffies_to_msecs(jiffies);
+ unsigned long report_delta_ms = msecs - ctlr->last_input_report_msecs;
+
+ if (joycon_has_rumble(ctlr))
+ joycon_handle_rumble_report(ctlr, rep);
+
+ joycon_parse_battery_status(ctlr, rep);
+
+ if (joycon_type_is_left_joycon(ctlr)) {
+ joycon_report_left_stick(ctlr, rep);
+ joycon_report_buttons(ctlr, rep, left_joycon_button_mappings);
+ if (!joycon_device_is_chrggrip(ctlr))
+ joycon_report_buttons(ctlr, rep, left_joycon_s_button_mappings);
+ } else if (joycon_type_is_right_joycon(ctlr)) {
+ joycon_report_right_stick(ctlr, rep);
+ joycon_report_buttons(ctlr, rep, right_joycon_button_mappings);
+ if (!joycon_device_is_chrggrip(ctlr))
+ joycon_report_buttons(ctlr, rep, right_joycon_s_button_mappings);
+ } else if (joycon_type_is_procon(ctlr)) {
+ joycon_report_left_stick(ctlr, rep);
+ joycon_report_right_stick(ctlr, rep);
+ joycon_report_dpad(ctlr, rep);
+ joycon_report_buttons(ctlr, rep, procon_button_mappings);
+ } else if (joycon_type_is_any_nescon(ctlr)) {
+ joycon_report_dpad(ctlr, rep);
+ joycon_report_buttons(ctlr, rep, nescon_button_mappings);
+ } else if (joycon_type_is_snescon(ctlr)) {
+ joycon_report_dpad(ctlr, rep);
+ joycon_report_buttons(ctlr, rep, snescon_button_mappings);
+ } else if (joycon_type_is_gencon(ctlr)) {
+ joycon_report_dpad(ctlr, rep);
+ joycon_report_buttons(ctlr, rep, gencon_button_mappings);
+ } else if (joycon_type_is_n64con(ctlr)) {
+ joycon_report_left_stick(ctlr, rep);
+ joycon_report_dpad(ctlr, rep);
+ joycon_report_buttons(ctlr, rep, n64con_button_mappings);
}
- input_sync(dev);
+ input_sync(ctlr->input);
spin_lock_irqsave(&ctlr->lock, flags);
ctlr->last_input_report_msecs = msecs;
@@ -1484,7 +1819,7 @@ static void joycon_parse_report(struct joycon_ctlr *ctlr,
}
/* parse IMU data if present */
- if (rep->id == JC_INPUT_IMU_DATA)
+ if ((rep->id == JC_INPUT_IMU_DATA) && joycon_has_imu(ctlr))
joycon_parse_imu_report(ctlr, rep);
}
@@ -1697,123 +2032,65 @@ static int joycon_play_effect(struct input_dev *dev, void *data,
}
#endif /* IS_ENABLED(CONFIG_NINTENDO_FF) */
-static const unsigned int joycon_button_inputs_l[] = {
- BTN_SELECT, BTN_Z, BTN_THUMBL,
- BTN_TL, BTN_TL2,
- 0 /* 0 signals end of array */
-};
-
-static const unsigned int joycon_button_inputs_r[] = {
- BTN_START, BTN_MODE, BTN_THUMBR,
- BTN_SOUTH, BTN_EAST, BTN_NORTH, BTN_WEST,
- BTN_TR, BTN_TR2,
- 0 /* 0 signals end of array */
-};
-
-/* We report joy-con d-pad inputs as buttons and pro controller as a hat. */
-static const unsigned int joycon_dpad_inputs_jc[] = {
- BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT,
- 0 /* 0 signals end of array */
-};
-
-static int joycon_input_create(struct joycon_ctlr *ctlr)
+static void joycon_config_left_stick(struct input_dev *idev)
{
- struct hid_device *hdev;
- const char *name;
- const char *imu_name;
- int ret;
- int i;
-
- hdev = ctlr->hdev;
+ input_set_abs_params(idev,
+ ABS_X,
+ -JC_MAX_STICK_MAG,
+ JC_MAX_STICK_MAG,
+ JC_STICK_FUZZ,
+ JC_STICK_FLAT);
+ input_set_abs_params(idev,
+ ABS_Y,
+ -JC_MAX_STICK_MAG,
+ JC_MAX_STICK_MAG,
+ JC_STICK_FUZZ,
+ JC_STICK_FLAT);
+}
- switch (hdev->product) {
- case USB_DEVICE_ID_NINTENDO_PROCON:
- name = "Nintendo Switch Pro Controller";
- imu_name = "Nintendo Switch Pro Controller IMU";
- break;
- case USB_DEVICE_ID_NINTENDO_CHRGGRIP:
- if (jc_type_has_left(ctlr)) {
- name = "Nintendo Switch Left Joy-Con (Grip)";
- imu_name = "Nintendo Switch Left Joy-Con IMU (Grip)";
- } else {
- name = "Nintendo Switch Right Joy-Con (Grip)";
- imu_name = "Nintendo Switch Right Joy-Con IMU (Grip)";
- }
- break;
- case USB_DEVICE_ID_NINTENDO_JOYCONL:
- name = "Nintendo Switch Left Joy-Con";
- imu_name = "Nintendo Switch Left Joy-Con IMU";
- break;
- case USB_DEVICE_ID_NINTENDO_JOYCONR:
- name = "Nintendo Switch Right Joy-Con";
- imu_name = "Nintendo Switch Right Joy-Con IMU";
- break;
- default: /* Should be impossible */
- hid_err(hdev, "Invalid hid product\n");
- return -EINVAL;
- }
+static void joycon_config_right_stick(struct input_dev *idev)
+{
+ input_set_abs_params(idev,
+ ABS_RX,
+ -JC_MAX_STICK_MAG,
+ JC_MAX_STICK_MAG,
+ JC_STICK_FUZZ,
+ JC_STICK_FLAT);
+ input_set_abs_params(idev,
+ ABS_RY,
+ -JC_MAX_STICK_MAG,
+ JC_MAX_STICK_MAG,
+ JC_STICK_FUZZ,
+ JC_STICK_FLAT);
+}
- ctlr->input = devm_input_allocate_device(&hdev->dev);
- if (!ctlr->input)
- return -ENOMEM;
- ctlr->input->id.bustype = hdev->bus;
- ctlr->input->id.vendor = hdev->vendor;
- ctlr->input->id.product = hdev->product;
- ctlr->input->id.version = hdev->version;
- ctlr->input->uniq = ctlr->mac_addr_str;
- ctlr->input->name = name;
- ctlr->input->phys = hdev->phys;
- input_set_drvdata(ctlr->input, ctlr);
+static void joycon_config_dpad(struct input_dev *idev)
+{
+ input_set_abs_params(idev,
+ ABS_HAT0X,
+ -JC_MAX_DPAD_MAG,
+ JC_MAX_DPAD_MAG,
+ JC_DPAD_FUZZ,
+ JC_DPAD_FLAT);
+ input_set_abs_params(idev,
+ ABS_HAT0Y,
+ -JC_MAX_DPAD_MAG,
+ JC_MAX_DPAD_MAG,
+ JC_DPAD_FUZZ,
+ JC_DPAD_FLAT);
+}
- /* set up sticks and buttons */
- if (jc_type_has_left(ctlr)) {
- input_set_abs_params(ctlr->input, ABS_X,
- -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG,
- JC_STICK_FUZZ, JC_STICK_FLAT);
- input_set_abs_params(ctlr->input, ABS_Y,
- -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG,
- JC_STICK_FUZZ, JC_STICK_FLAT);
-
- for (i = 0; joycon_button_inputs_l[i] > 0; i++)
- input_set_capability(ctlr->input, EV_KEY,
- joycon_button_inputs_l[i]);
-
- /* configure d-pad differently for joy-con vs pro controller */
- if (hdev->product != USB_DEVICE_ID_NINTENDO_PROCON) {
- for (i = 0; joycon_dpad_inputs_jc[i] > 0; i++)
- input_set_capability(ctlr->input, EV_KEY,
- joycon_dpad_inputs_jc[i]);
- } else {
- input_set_abs_params(ctlr->input, ABS_HAT0X,
- -JC_MAX_DPAD_MAG, JC_MAX_DPAD_MAG,
- JC_DPAD_FUZZ, JC_DPAD_FLAT);
- input_set_abs_params(ctlr->input, ABS_HAT0Y,
- -JC_MAX_DPAD_MAG, JC_MAX_DPAD_MAG,
- JC_DPAD_FUZZ, JC_DPAD_FLAT);
- }
- }
- if (jc_type_has_right(ctlr)) {
- input_set_abs_params(ctlr->input, ABS_RX,
- -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG,
- JC_STICK_FUZZ, JC_STICK_FLAT);
- input_set_abs_params(ctlr->input, ABS_RY,
- -JC_MAX_STICK_MAG, JC_MAX_STICK_MAG,
- JC_STICK_FUZZ, JC_STICK_FLAT);
-
- for (i = 0; joycon_button_inputs_r[i] > 0; i++)
- input_set_capability(ctlr->input, EV_KEY,
- joycon_button_inputs_r[i]);
- }
+static void joycon_config_buttons(struct input_dev *idev,
+ const struct joycon_ctlr_button_mapping button_mappings[])
+{
+ const struct joycon_ctlr_button_mapping *button;
- /* Let's report joy-con S triggers separately */
- if (hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONL) {
- input_set_capability(ctlr->input, EV_KEY, BTN_TR);
- input_set_capability(ctlr->input, EV_KEY, BTN_TR2);
- } else if (hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONR) {
- input_set_capability(ctlr->input, EV_KEY, BTN_TL);
- input_set_capability(ctlr->input, EV_KEY, BTN_TL2);
- }
+ for (button = button_mappings; button->code; button++)
+ input_set_capability(idev, EV_KEY, button->code);
+}
+static void joycon_config_rumble(struct joycon_ctlr *ctlr)
+{
#if IS_ENABLED(CONFIG_NINTENDO_FF)
/* set up rumble */
input_set_capability(ctlr->input, EV_FF, FF_RUMBLE);
@@ -1826,10 +2103,15 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
joycon_set_rumble(ctlr, 0, 0, false);
ctlr->rumble_msecs = jiffies_to_msecs(jiffies);
#endif
+}
- ret = input_register_device(ctlr->input);
- if (ret)
- return ret;
+static int joycon_imu_input_create(struct joycon_ctlr *ctlr)
+{
+ struct hid_device *hdev;
+ const char *imu_name;
+ int ret;
+
+ hdev = ctlr->hdev;
/* configure the imu input device */
ctlr->imu_input = devm_input_allocate_device(&hdev->dev);
@@ -1841,8 +2123,14 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
ctlr->imu_input->id.product = hdev->product;
ctlr->imu_input->id.version = hdev->version;
ctlr->imu_input->uniq = ctlr->mac_addr_str;
- ctlr->imu_input->name = imu_name;
ctlr->imu_input->phys = hdev->phys;
+
+ imu_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s (IMU)", ctlr->input->name);
+ if (!imu_name)
+ return -ENOMEM;
+
+ ctlr->imu_input->name = imu_name;
+
input_set_drvdata(ctlr->imu_input, ctlr);
/* configure imu axes */
@@ -1884,6 +2172,71 @@ static int joycon_input_create(struct joycon_ctlr *ctlr)
return 0;
}
+static int joycon_input_create(struct joycon_ctlr *ctlr)
+{
+ struct hid_device *hdev;
+ int ret;
+
+ hdev = ctlr->hdev;
+
+ ctlr->input = devm_input_allocate_device(&hdev->dev);
+ if (!ctlr->input)
+ return -ENOMEM;
+ ctlr->input->id.bustype = hdev->bus;
+ ctlr->input->id.vendor = hdev->vendor;
+ ctlr->input->id.product = hdev->product;
+ ctlr->input->id.version = hdev->version;
+ ctlr->input->uniq = ctlr->mac_addr_str;
+ ctlr->input->name = hdev->name;
+ ctlr->input->phys = hdev->phys;
+ input_set_drvdata(ctlr->input, ctlr);
+
+ ret = input_register_device(ctlr->input);
+ if (ret)
+ return ret;
+
+ if (joycon_type_is_right_joycon(ctlr)) {
+ joycon_config_right_stick(ctlr->input);
+ joycon_config_buttons(ctlr->input, right_joycon_button_mappings);
+ if (!joycon_device_is_chrggrip(ctlr))
+ joycon_config_buttons(ctlr->input, right_joycon_s_button_mappings);
+ } else if (joycon_type_is_left_joycon(ctlr)) {
+ joycon_config_left_stick(ctlr->input);
+ joycon_config_buttons(ctlr->input, left_joycon_button_mappings);
+ if (!joycon_device_is_chrggrip(ctlr))
+ joycon_config_buttons(ctlr->input, left_joycon_s_button_mappings);
+ } else if (joycon_type_is_procon(ctlr)) {
+ joycon_config_left_stick(ctlr->input);
+ joycon_config_right_stick(ctlr->input);
+ joycon_config_dpad(ctlr->input);
+ joycon_config_buttons(ctlr->input, procon_button_mappings);
+ } else if (joycon_type_is_any_nescon(ctlr)) {
+ joycon_config_dpad(ctlr->input);
+ joycon_config_buttons(ctlr->input, nescon_button_mappings);
+ } else if (joycon_type_is_snescon(ctlr)) {
+ joycon_config_dpad(ctlr->input);
+ joycon_config_buttons(ctlr->input, snescon_button_mappings);
+ } else if (joycon_type_is_gencon(ctlr)) {
+ joycon_config_dpad(ctlr->input);
+ joycon_config_buttons(ctlr->input, gencon_button_mappings);
+ } else if (joycon_type_is_n64con(ctlr)) {
+ joycon_config_dpad(ctlr->input);
+ joycon_config_left_stick(ctlr->input);
+ joycon_config_buttons(ctlr->input, n64con_button_mappings);
+ }
+
+ if (joycon_has_imu(ctlr)) {
+ ret = joycon_imu_input_create(ctlr);
+ if (ret)
+ return ret;
+ }
+
+ if (joycon_has_rumble(ctlr))
+ joycon_config_rumble(ctlr);
+
+ return 0;
+}
+
/* Because the subcommand sets all the leds at once, the brightness argument is ignored */
static int joycon_player_led_brightness_set(struct led_classdev *led,
enum led_brightness brightness)
@@ -2120,9 +2473,7 @@ static int joycon_read_info(struct joycon_ctlr *ctlr)
struct joycon_input_report *report;
req.subcmd_id = JC_SUBCMD_REQ_DEV_INFO;
- mutex_lock(&ctlr->output_mutex);
ret = joycon_send_subcmd(ctlr, &req, 0, HZ);
- mutex_unlock(&ctlr->output_mutex);
if (ret) {
hid_err(ctlr->hdev, "Failed to get joycon info; ret=%d\n", ret);
return ret;
@@ -2145,8 +2496,17 @@ static int joycon_read_info(struct joycon_ctlr *ctlr)
return -ENOMEM;
hid_info(ctlr->hdev, "controller MAC = %s\n", ctlr->mac_addr_str);
- /* Retrieve the type so we can distinguish for charging grip */
+ /*
+ * Retrieve the type so we can distinguish the controller type
+ * Unfortantly the hdev->product can't always be used due to a ?bug?
+ * with the NSO Genesis controller. Over USB, it will report the
+ * PID as 0x201E, but over bluetooth it will report the PID as 0x2017
+ * which is the same as the NSO SNES controller. This is different from
+ * the rest of the controllers which will report the same PID over USB
+ * and bluetooth.
+ */
ctlr->ctlr_type = report->subcmd_reply.data[2];
+ hid_dbg(ctlr->hdev, "controller type = 0x%02X\n", ctlr->ctlr_type);
return 0;
}
@@ -2158,8 +2518,7 @@ static int joycon_init(struct hid_device *hdev)
mutex_lock(&ctlr->output_mutex);
/* if handshake command fails, assume ble pro controller */
- if ((jc_type_is_procon(ctlr) || jc_type_is_chrggrip(ctlr)) &&
- !joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ)) {
+ if (joycon_using_usb(ctlr) && !joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ)) {
hid_dbg(hdev, "detected USB controller\n");
/* set baudrate for improved latency */
ret = joycon_send_usb(ctlr, JC_USB_CMD_BAUDRATE_3M, HZ);
@@ -2184,24 +2543,43 @@ static int joycon_init(struct hid_device *hdev)
goto out_unlock;
}
- /* get controller calibration data, and parse it */
- ret = joycon_request_calibration(ctlr);
+ /* needed to retrieve the controller type */
+ ret = joycon_read_info(ctlr);
if (ret) {
- /*
- * We can function with default calibration, but it may be
- * inaccurate. Provide a warning, and continue on.
- */
- hid_warn(hdev, "Analog stick positions may be inaccurate\n");
+ hid_err(hdev, "Failed to retrieve controller info; ret=%d\n",
+ ret);
+ goto out_unlock;
}
- /* get IMU calibration data, and parse it */
- ret = joycon_request_imu_calibration(ctlr);
- if (ret) {
- /*
- * We can function with default calibration, but it may be
- * inaccurate. Provide a warning, and continue on.
- */
- hid_warn(hdev, "Unable to read IMU calibration data\n");
+ if (joycon_has_joysticks(ctlr)) {
+ /* get controller calibration data, and parse it */
+ ret = joycon_request_calibration(ctlr);
+ if (ret) {
+ /*
+ * We can function with default calibration, but it may be
+ * inaccurate. Provide a warning, and continue on.
+ */
+ hid_warn(hdev, "Analog stick positions may be inaccurate\n");
+ }
+ }
+
+ if (joycon_has_imu(ctlr)) {
+ /* get IMU calibration data, and parse it */
+ ret = joycon_request_imu_calibration(ctlr);
+ if (ret) {
+ /*
+ * We can function with default calibration, but it may be
+ * inaccurate. Provide a warning, and continue on.
+ */
+ hid_warn(hdev, "Unable to read IMU calibration data\n");
+ }
+
+ /* Enable the IMU */
+ ret = joycon_enable_imu(ctlr);
+ if (ret) {
+ hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret);
+ goto out_unlock;
+ }
}
/* Set the reporting mode to 0x30, which is the full report mode */
@@ -2211,18 +2589,13 @@ static int joycon_init(struct hid_device *hdev)
goto out_unlock;
}
- /* Enable rumble */
- ret = joycon_enable_rumble(ctlr);
- if (ret) {
- hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret);
- goto out_unlock;
- }
-
- /* Enable the IMU */
- ret = joycon_enable_imu(ctlr);
- if (ret) {
- hid_err(hdev, "Failed to enable the IMU; ret=%d\n", ret);
- goto out_unlock;
+ if (joycon_has_rumble(ctlr)) {
+ /* Enable rumble */
+ ret = joycon_enable_rumble(ctlr);
+ if (ret) {
+ hid_err(hdev, "Failed to enable rumble; ret=%d\n", ret);
+ goto out_unlock;
+ }
}
out_unlock:
@@ -2367,13 +2740,6 @@ static int nintendo_hid_probe(struct hid_device *hdev,
goto err_close;
}
- ret = joycon_read_info(ctlr);
- if (ret) {
- hid_err(hdev, "Failed to retrieve controller info; ret=%d\n",
- ret);
- goto err_close;
- }
-
/* Initialize the leds */
ret = joycon_leds_create(ctlr);
if (ret) {
@@ -2445,6 +2811,12 @@ static int nintendo_hid_resume(struct hid_device *hdev)
static const struct hid_device_id nintendo_hid_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_PROCON) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
+ USB_DEVICE_ID_NINTENDO_SNESCON) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
+ USB_DEVICE_ID_NINTENDO_GENCON) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
+ USB_DEVICE_ID_NINTENDO_N64CON) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_PROCON) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NINTENDO,
@@ -2453,6 +2825,12 @@ static const struct hid_device_id nintendo_hid_devices[] = {
USB_DEVICE_ID_NINTENDO_JOYCONL) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_JOYCONR) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
+ USB_DEVICE_ID_NINTENDO_SNESCON) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
+ USB_DEVICE_ID_NINTENDO_GENCON) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
+ USB_DEVICE_ID_NINTENDO_N64CON) },
{ }
};
MODULE_DEVICE_TABLE(hid, nintendo_hid_devices);
@@ -2471,6 +2849,7 @@ static struct hid_driver nintendo_hid_driver = {
module_hid_driver(nintendo_hid_driver);
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ryan McClelland <[email protected]>");
+MODULE_AUTHOR("Emily Strickland <[email protected]>");
MODULE_AUTHOR("Daniel J. Ogorchock <[email protected]>");
MODULE_DESCRIPTION("Driver for Nintendo Switch Controllers");
-
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 2eba152e8b90..26e93a331a51 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -632,7 +632,7 @@ static int sensor_hub_probe(struct hid_device *hdev,
}
INIT_LIST_HEAD(&hdev->inputs);
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | HID_CONNECT_DRIVER);
if (ret) {
hid_err(hdev, "hw start failed\n");
return ret;
diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c
index b110818fc945..b3c4e50e248a 100644
--- a/drivers/hid/hid-steam.c
+++ b/drivers/hid/hid-steam.c
@@ -71,60 +71,222 @@ static LIST_HEAD(steam_devices);
/*
* Commands that can be sent in a feature report.
- * Thanks to Valve for some valuable hints.
+ * Thanks to Valve and SDL for the names.
*/
-#define STEAM_CMD_SET_MAPPINGS 0x80
-#define STEAM_CMD_CLEAR_MAPPINGS 0x81
-#define STEAM_CMD_GET_MAPPINGS 0x82
-#define STEAM_CMD_GET_ATTRIB 0x83
-#define STEAM_CMD_GET_ATTRIB_LABEL 0x84
-#define STEAM_CMD_DEFAULT_MAPPINGS 0x85
-#define STEAM_CMD_FACTORY_RESET 0x86
-#define STEAM_CMD_WRITE_REGISTER 0x87
-#define STEAM_CMD_CLEAR_REGISTER 0x88
-#define STEAM_CMD_READ_REGISTER 0x89
-#define STEAM_CMD_GET_REGISTER_LABEL 0x8a
-#define STEAM_CMD_GET_REGISTER_MAX 0x8b
-#define STEAM_CMD_GET_REGISTER_DEFAULT 0x8c
-#define STEAM_CMD_SET_MODE 0x8d
-#define STEAM_CMD_DEFAULT_MOUSE 0x8e
-#define STEAM_CMD_FORCEFEEDBAK 0x8f
-#define STEAM_CMD_REQUEST_COMM_STATUS 0xb4
-#define STEAM_CMD_GET_SERIAL 0xae
-#define STEAM_CMD_HAPTIC_RUMBLE 0xeb
-
-/* Some useful register ids */
-#define STEAM_REG_LPAD_MODE 0x07
-#define STEAM_REG_RPAD_MODE 0x08
-#define STEAM_REG_RPAD_MARGIN 0x18
-#define STEAM_REG_LED 0x2d
-#define STEAM_REG_GYRO_MODE 0x30
-#define STEAM_REG_LPAD_CLICK_PRESSURE 0x34
-#define STEAM_REG_RPAD_CLICK_PRESSURE 0x35
-
-/* Raw event identifiers */
-#define STEAM_EV_INPUT_DATA 0x01
-#define STEAM_EV_CONNECT 0x03
-#define STEAM_EV_BATTERY 0x04
-#define STEAM_EV_DECK_INPUT_DATA 0x09
+enum {
+ ID_SET_DIGITAL_MAPPINGS = 0x80,
+ ID_CLEAR_DIGITAL_MAPPINGS = 0x81,
+ ID_GET_DIGITAL_MAPPINGS = 0x82,
+ ID_GET_ATTRIBUTES_VALUES = 0x83,
+ ID_GET_ATTRIBUTE_LABEL = 0x84,
+ ID_SET_DEFAULT_DIGITAL_MAPPINGS = 0x85,
+ ID_FACTORY_RESET = 0x86,
+ ID_SET_SETTINGS_VALUES = 0x87,
+ ID_CLEAR_SETTINGS_VALUES = 0x88,
+ ID_GET_SETTINGS_VALUES = 0x89,
+ ID_GET_SETTING_LABEL = 0x8A,
+ ID_GET_SETTINGS_MAXS = 0x8B,
+ ID_GET_SETTINGS_DEFAULTS = 0x8C,
+ ID_SET_CONTROLLER_MODE = 0x8D,
+ ID_LOAD_DEFAULT_SETTINGS = 0x8E,
+ ID_TRIGGER_HAPTIC_PULSE = 0x8F,
+ ID_TURN_OFF_CONTROLLER = 0x9F,
+
+ ID_GET_DEVICE_INFO = 0xA1,
+
+ ID_CALIBRATE_TRACKPADS = 0xA7,
+ ID_RESERVED_0 = 0xA8,
+ ID_SET_SERIAL_NUMBER = 0xA9,
+ ID_GET_TRACKPAD_CALIBRATION = 0xAA,
+ ID_GET_TRACKPAD_FACTORY_CALIBRATION = 0xAB,
+ ID_GET_TRACKPAD_RAW_DATA = 0xAC,
+ ID_ENABLE_PAIRING = 0xAD,
+ ID_GET_STRING_ATTRIBUTE = 0xAE,
+ ID_RADIO_ERASE_RECORDS = 0xAF,
+ ID_RADIO_WRITE_RECORD = 0xB0,
+ ID_SET_DONGLE_SETTING = 0xB1,
+ ID_DONGLE_DISCONNECT_DEVICE = 0xB2,
+ ID_DONGLE_COMMIT_DEVICE = 0xB3,
+ ID_DONGLE_GET_WIRELESS_STATE = 0xB4,
+ ID_CALIBRATE_GYRO = 0xB5,
+ ID_PLAY_AUDIO = 0xB6,
+ ID_AUDIO_UPDATE_START = 0xB7,
+ ID_AUDIO_UPDATE_DATA = 0xB8,
+ ID_AUDIO_UPDATE_COMPLETE = 0xB9,
+ ID_GET_CHIPID = 0xBA,
+
+ ID_CALIBRATE_JOYSTICK = 0xBF,
+ ID_CALIBRATE_ANALOG_TRIGGERS = 0xC0,
+ ID_SET_AUDIO_MAPPING = 0xC1,
+ ID_CHECK_GYRO_FW_LOAD = 0xC2,
+ ID_CALIBRATE_ANALOG = 0xC3,
+ ID_DONGLE_GET_CONNECTED_SLOTS = 0xC4,
+
+ ID_RESET_IMU = 0xCE,
+
+ ID_TRIGGER_HAPTIC_CMD = 0xEA,
+ ID_TRIGGER_RUMBLE_CMD = 0xEB,
+};
+
+/* Settings IDs */
+enum {
+ /* 0 */
+ SETTING_MOUSE_SENSITIVITY,
+ SETTING_MOUSE_ACCELERATION,
+ SETTING_TRACKBALL_ROTATION_ANGLE,
+ SETTING_HAPTIC_INTENSITY_UNUSED,
+ SETTING_LEFT_GAMEPAD_STICK_ENABLED,
+ SETTING_RIGHT_GAMEPAD_STICK_ENABLED,
+ SETTING_USB_DEBUG_MODE,
+ SETTING_LEFT_TRACKPAD_MODE,
+ SETTING_RIGHT_TRACKPAD_MODE,
+ SETTING_MOUSE_POINTER_ENABLED,
+
+ /* 10 */
+ SETTING_DPAD_DEADZONE,
+ SETTING_MINIMUM_MOMENTUM_VEL,
+ SETTING_MOMENTUM_DECAY_AMMOUNT,
+ SETTING_TRACKPAD_RELATIVE_MODE_TICKS_PER_PIXEL,
+ SETTING_HAPTIC_INCREMENT,
+ SETTING_DPAD_ANGLE_SIN,
+ SETTING_DPAD_ANGLE_COS,
+ SETTING_MOMENTUM_VERTICAL_DIVISOR,
+ SETTING_MOMENTUM_MAXIMUM_VELOCITY,
+ SETTING_TRACKPAD_Z_ON,
+
+ /* 20 */
+ SETTING_TRACKPAD_Z_OFF,
+ SETTING_SENSITIVY_SCALE_AMMOUNT,
+ SETTING_LEFT_TRACKPAD_SECONDARY_MODE,
+ SETTING_RIGHT_TRACKPAD_SECONDARY_MODE,
+ SETTING_SMOOTH_ABSOLUTE_MOUSE,
+ SETTING_STEAMBUTTON_POWEROFF_TIME,
+ SETTING_UNUSED_1,
+ SETTING_TRACKPAD_OUTER_RADIUS,
+ SETTING_TRACKPAD_Z_ON_LEFT,
+ SETTING_TRACKPAD_Z_OFF_LEFT,
+
+ /* 30 */
+ SETTING_TRACKPAD_OUTER_SPIN_VEL,
+ SETTING_TRACKPAD_OUTER_SPIN_RADIUS,
+ SETTING_TRACKPAD_OUTER_SPIN_HORIZONTAL_ONLY,
+ SETTING_TRACKPAD_RELATIVE_MODE_DEADZONE,
+ SETTING_TRACKPAD_RELATIVE_MODE_MAX_VEL,
+ SETTING_TRACKPAD_RELATIVE_MODE_INVERT_Y,
+ SETTING_TRACKPAD_DOUBLE_TAP_BEEP_ENABLED,
+ SETTING_TRACKPAD_DOUBLE_TAP_BEEP_PERIOD,
+ SETTING_TRACKPAD_DOUBLE_TAP_BEEP_COUNT,
+ SETTING_TRACKPAD_OUTER_RADIUS_RELEASE_ON_TRANSITION,
+
+ /* 40 */
+ SETTING_RADIAL_MODE_ANGLE,
+ SETTING_HAPTIC_INTENSITY_MOUSE_MODE,
+ SETTING_LEFT_DPAD_REQUIRES_CLICK,
+ SETTING_RIGHT_DPAD_REQUIRES_CLICK,
+ SETTING_LED_BASELINE_BRIGHTNESS,
+ SETTING_LED_USER_BRIGHTNESS,
+ SETTING_ENABLE_RAW_JOYSTICK,
+ SETTING_ENABLE_FAST_SCAN,
+ SETTING_IMU_MODE,
+ SETTING_WIRELESS_PACKET_VERSION,
+
+ /* 50 */
+ SETTING_SLEEP_INACTIVITY_TIMEOUT,
+ SETTING_TRACKPAD_NOISE_THRESHOLD,
+ SETTING_LEFT_TRACKPAD_CLICK_PRESSURE,
+ SETTING_RIGHT_TRACKPAD_CLICK_PRESSURE,
+ SETTING_LEFT_BUMPER_CLICK_PRESSURE,
+ SETTING_RIGHT_BUMPER_CLICK_PRESSURE,
+ SETTING_LEFT_GRIP_CLICK_PRESSURE,
+ SETTING_RIGHT_GRIP_CLICK_PRESSURE,
+ SETTING_LEFT_GRIP2_CLICK_PRESSURE,
+ SETTING_RIGHT_GRIP2_CLICK_PRESSURE,
+
+ /* 60 */
+ SETTING_PRESSURE_MODE,
+ SETTING_CONTROLLER_TEST_MODE,
+ SETTING_TRIGGER_MODE,
+ SETTING_TRACKPAD_Z_THRESHOLD,
+ SETTING_FRAME_RATE,
+ SETTING_TRACKPAD_FILT_CTRL,
+ SETTING_TRACKPAD_CLIP,
+ SETTING_DEBUG_OUTPUT_SELECT,
+ SETTING_TRIGGER_THRESHOLD_PERCENT,
+ SETTING_TRACKPAD_FREQUENCY_HOPPING,
+
+ /* 70 */
+ SETTING_HAPTICS_ENABLED,
+ SETTING_STEAM_WATCHDOG_ENABLE,
+ SETTING_TIMP_TOUCH_THRESHOLD_ON,
+ SETTING_TIMP_TOUCH_THRESHOLD_OFF,
+ SETTING_FREQ_HOPPING,
+ SETTING_TEST_CONTROL,
+ SETTING_HAPTIC_MASTER_GAIN_DB,
+ SETTING_THUMB_TOUCH_THRESH,
+ SETTING_DEVICE_POWER_STATUS,
+ SETTING_HAPTIC_INTENSITY,
+
+ /* 80 */
+ SETTING_STABILIZER_ENABLED,
+ SETTING_TIMP_MODE_MTE,
+};
+
+/* Input report identifiers */
+enum
+{
+ ID_CONTROLLER_STATE = 1,
+ ID_CONTROLLER_DEBUG = 2,
+ ID_CONTROLLER_WIRELESS = 3,
+ ID_CONTROLLER_STATUS = 4,
+ ID_CONTROLLER_DEBUG2 = 5,
+ ID_CONTROLLER_SECONDARY_STATE = 6,
+ ID_CONTROLLER_BLE_STATE = 7,
+ ID_CONTROLLER_DECK_STATE = 9
+};
+
+/* String attribute idenitifiers */
+enum {
+ ATTRIB_STR_BOARD_SERIAL,
+ ATTRIB_STR_UNIT_SERIAL,
+};
/* Values for GYRO_MODE (bitmask) */
-#define STEAM_GYRO_MODE_OFF 0x0000
-#define STEAM_GYRO_MODE_STEERING 0x0001
-#define STEAM_GYRO_MODE_TILT 0x0002
-#define STEAM_GYRO_MODE_SEND_ORIENTATION 0x0004
-#define STEAM_GYRO_MODE_SEND_RAW_ACCEL 0x0008
-#define STEAM_GYRO_MODE_SEND_RAW_GYRO 0x0010
+enum {
+ SETTING_GYRO_MODE_OFF = 0,
+ SETTING_GYRO_MODE_STEERING = BIT(0),
+ SETTING_GYRO_MODE_TILT = BIT(1),
+ SETTING_GYRO_MODE_SEND_ORIENTATION = BIT(2),
+ SETTING_GYRO_MODE_SEND_RAW_ACCEL = BIT(3),
+ SETTING_GYRO_MODE_SEND_RAW_GYRO = BIT(4),
+};
+
+/* Trackpad modes */
+enum {
+ TRACKPAD_ABSOLUTE_MOUSE,
+ TRACKPAD_RELATIVE_MOUSE,
+ TRACKPAD_DPAD_FOUR_WAY_DISCRETE,
+ TRACKPAD_DPAD_FOUR_WAY_OVERLAP,
+ TRACKPAD_DPAD_EIGHT_WAY,
+ TRACKPAD_RADIAL_MODE,
+ TRACKPAD_ABSOLUTE_DPAD,
+ TRACKPAD_NONE,
+ TRACKPAD_GESTURE_KEYBOARD,
+};
+
+/* Pad identifiers for the deck */
+#define STEAM_PAD_LEFT 0
+#define STEAM_PAD_RIGHT 1
+#define STEAM_PAD_BOTH 2
/* Other random constants */
-#define STEAM_SERIAL_LEN 10
+#define STEAM_SERIAL_LEN 0x15
struct steam_device {
struct list_head list;
spinlock_t lock;
struct hid_device *hdev, *client_hdev;
- struct mutex mutex;
- bool client_opened;
+ struct mutex report_mutex;
+ unsigned long client_opened;
struct input_dev __rcu *input;
unsigned long quirks;
struct work_struct work_connect;
@@ -134,7 +296,9 @@ struct steam_device {
struct power_supply __rcu *battery;
u8 battery_charge;
u16 voltage;
- struct delayed_work heartbeat;
+ struct delayed_work mode_switch;
+ bool did_mode_switch;
+ bool gamepad_mode;
struct work_struct rumble_work;
u16 rumble_left;
u16 rumble_right;
@@ -226,13 +390,13 @@ static inline int steam_send_report_byte(struct steam_device *steam, u8 cmd)
return steam_send_report(steam, &cmd, 1);
}
-static int steam_write_registers(struct steam_device *steam,
+static int steam_write_settings(struct steam_device *steam,
/* u8 reg, u16 val */...)
{
/* Send: 0x87 len (reg valLo valHi)* */
u8 reg;
u16 val;
- u8 cmd[64] = {STEAM_CMD_WRITE_REGISTER, 0x00};
+ u8 cmd[64] = {ID_SET_SETTINGS_VALUES, 0x00};
int ret;
va_list args;
@@ -265,23 +429,29 @@ static int steam_get_serial(struct steam_device *steam)
{
/*
* Send: 0xae 0x15 0x01
- * Recv: 0xae 0x15 0x01 serialnumber (10 chars)
+ * Recv: 0xae 0x15 0x01 serialnumber
*/
- int ret;
- u8 cmd[] = {STEAM_CMD_GET_SERIAL, 0x15, 0x01};
+ int ret = 0;
+ u8 cmd[] = {ID_GET_STRING_ATTRIBUTE, sizeof(steam->serial_no), ATTRIB_STR_UNIT_SERIAL};
u8 reply[3 + STEAM_SERIAL_LEN + 1];
+ mutex_lock(&steam->report_mutex);
ret = steam_send_report(steam, cmd, sizeof(cmd));
if (ret < 0)
- return ret;
+ goto out;
ret = steam_recv_report(steam, reply, sizeof(reply));
if (ret < 0)
- return ret;
- if (reply[0] != 0xae || reply[1] != 0x15 || reply[2] != 0x01)
- return -EIO;
+ goto out;
+ if (reply[0] != ID_GET_STRING_ATTRIBUTE || reply[1] < 1 ||
+ reply[1] > sizeof(steam->serial_no) || reply[2] != ATTRIB_STR_UNIT_SERIAL) {
+ ret = -EIO;
+ goto out;
+ }
reply[3 + STEAM_SERIAL_LEN] = 0;
- strscpy(steam->serial_no, reply + 3, sizeof(steam->serial_no));
- return 0;
+ strscpy(steam->serial_no, reply + 3, reply[1]);
+out:
+ mutex_unlock(&steam->report_mutex);
+ return ret;
}
/*
@@ -291,14 +461,50 @@ static int steam_get_serial(struct steam_device *steam)
*/
static inline int steam_request_conn_status(struct steam_device *steam)
{
- return steam_send_report_byte(steam, STEAM_CMD_REQUEST_COMM_STATUS);
+ int ret;
+ mutex_lock(&steam->report_mutex);
+ ret = steam_send_report_byte(steam, ID_DONGLE_GET_WIRELESS_STATE);
+ mutex_unlock(&steam->report_mutex);
+ return ret;
+}
+
+/*
+ * Send a haptic pulse to the trackpads
+ * Duration and interval are measured in microseconds, count is the number
+ * of pulses to send for duration time with interval microseconds between them
+ * and gain is measured in decibels, ranging from -24 to +6
+ */
+static inline int steam_haptic_pulse(struct steam_device *steam, u8 pad,
+ u16 duration, u16 interval, u16 count, u8 gain)
+{
+ int ret;
+ u8 report[10] = {ID_TRIGGER_HAPTIC_PULSE, 8};
+
+ /* Left and right are swapped on this report for legacy reasons */
+ if (pad < STEAM_PAD_BOTH)
+ pad ^= 1;
+
+ report[2] = pad;
+ report[3] = duration & 0xFF;
+ report[4] = duration >> 8;
+ report[5] = interval & 0xFF;
+ report[6] = interval >> 8;
+ report[7] = count & 0xFF;
+ report[8] = count >> 8;
+ report[9] = gain;
+
+ mutex_lock(&steam->report_mutex);
+ ret = steam_send_report(steam, report, sizeof(report));
+ mutex_unlock(&steam->report_mutex);
+ return ret;
}
static inline int steam_haptic_rumble(struct steam_device *steam,
u16 intensity, u16 left_speed, u16 right_speed,
u8 left_gain, u8 right_gain)
{
- u8 report[11] = {STEAM_CMD_HAPTIC_RUMBLE, 9};
+ int ret;
+ u8 report[11] = {ID_TRIGGER_RUMBLE_CMD, 9};
report[3] = intensity & 0xFF;
report[4] = intensity >> 8;
@@ -309,7 +515,10 @@ static inline int steam_haptic_rumble(struct steam_device *steam,
report[9] = left_gain;
report[10] = right_gain;
- return steam_send_report(steam, report, sizeof(report));
+ mutex_lock(&steam->report_mutex);
+ ret = steam_send_report(steam, report, sizeof(report));
+ mutex_unlock(&steam->report_mutex);
+ return ret;
}
static void steam_haptic_rumble_cb(struct work_struct *work)
@@ -335,40 +544,36 @@ static int steam_play_effect(struct input_dev *dev, void *data,
static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
{
+ if (steam->gamepad_mode)
+ enable = false;
+
if (enable) {
+ mutex_lock(&steam->report_mutex);
/* enable esc, enter, cursors */
- steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MAPPINGS);
- /* enable mouse */
- steam_send_report_byte(steam, STEAM_CMD_DEFAULT_MOUSE);
- steam_write_registers(steam,
- STEAM_REG_RPAD_MARGIN, 0x01, /* enable margin */
- 0);
-
- cancel_delayed_work_sync(&steam->heartbeat);
+ steam_send_report_byte(steam, ID_SET_DEFAULT_DIGITAL_MAPPINGS);
+ /* reset settings */
+ steam_send_report_byte(steam, ID_LOAD_DEFAULT_SETTINGS);
+ mutex_unlock(&steam->report_mutex);
} else {
+ mutex_lock(&steam->report_mutex);
/* disable esc, enter, cursor */
- steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS);
+ steam_send_report_byte(steam, ID_CLEAR_DIGITAL_MAPPINGS);
if (steam->quirks & STEAM_QUIRK_DECK) {
- steam_write_registers(steam,
- STEAM_REG_RPAD_MARGIN, 0x00, /* disable margin */
- STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */
- STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */
- STEAM_REG_LPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */
- STEAM_REG_RPAD_CLICK_PRESSURE, 0xFFFF, /* disable clicky pad */
+ steam_write_settings(steam,
+ SETTING_LEFT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */
+ SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */
+ SETTING_LEFT_TRACKPAD_CLICK_PRESSURE, 0xFFFF, /* disable haptic click */
+ SETTING_RIGHT_TRACKPAD_CLICK_PRESSURE, 0xFFFF, /* disable haptic click */
+ SETTING_STEAM_WATCHDOG_ENABLE, 0, /* disable watchdog that tests if Steam is active */
0);
- /*
- * The Steam Deck has a watchdog that automatically enables
- * lizard mode if it doesn't see any traffic for too long
- */
- if (!work_busy(&steam->heartbeat.work))
- schedule_delayed_work(&steam->heartbeat, 5 * HZ);
+ mutex_unlock(&steam->report_mutex);
} else {
- steam_write_registers(steam,
- STEAM_REG_RPAD_MARGIN, 0x00, /* disable margin */
- STEAM_REG_LPAD_MODE, 0x07, /* disable mouse */
- STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */
+ steam_write_settings(steam,
+ SETTING_LEFT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */
+ SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_NONE, /* disable mouse */
0);
+ mutex_unlock(&steam->report_mutex);
}
}
}
@@ -376,22 +581,38 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable)
static int steam_input_open(struct input_dev *dev)
{
struct steam_device *steam = input_get_drvdata(dev);
+ unsigned long flags;
+ bool set_lizard_mode;
+
+ /*
+ * Disabling lizard mode automatically is only done on the Steam
+ * Controller. On the Steam Deck, this is toggled manually by holding
+ * the options button instead, handled by steam_mode_switch_cb.
+ */
+ if (!(steam->quirks & STEAM_QUIRK_DECK)) {
+ spin_lock_irqsave(&steam->lock, flags);
+ set_lizard_mode = !steam->client_opened && lizard_mode;
+ spin_unlock_irqrestore(&steam->lock, flags);
+ if (set_lizard_mode)
+ steam_set_lizard_mode(steam, false);
+ }
- mutex_lock(&steam->mutex);
- if (!steam->client_opened && lizard_mode)
- steam_set_lizard_mode(steam, false);
- mutex_unlock(&steam->mutex);
return 0;
}
static void steam_input_close(struct input_dev *dev)
{
struct steam_device *steam = input_get_drvdata(dev);
+ unsigned long flags;
+ bool set_lizard_mode;
- mutex_lock(&steam->mutex);
- if (!steam->client_opened && lizard_mode)
- steam_set_lizard_mode(steam, true);
- mutex_unlock(&steam->mutex);
+ if (!(steam->quirks & STEAM_QUIRK_DECK)) {
+ spin_lock_irqsave(&steam->lock, flags);
+ set_lizard_mode = !steam->client_opened && lizard_mode;
+ spin_unlock_irqrestore(&steam->lock, flags);
+ if (set_lizard_mode)
+ steam_set_lizard_mode(steam, true);
+ }
}
static enum power_supply_property steam_battery_props[] = {
@@ -635,7 +856,8 @@ static void steam_battery_unregister(struct steam_device *steam)
static int steam_register(struct steam_device *steam)
{
int ret;
- bool client_opened;
+ unsigned long client_opened;
+ unsigned long flags;
/*
* This function can be called several times in a row with the
@@ -648,11 +870,9 @@ static int steam_register(struct steam_device *steam)
* Unlikely, but getting the serial could fail, and it is not so
* important, so make up a serial number and go on.
*/
- mutex_lock(&steam->mutex);
if (steam_get_serial(steam) < 0)
strscpy(steam->serial_no, "XXXXXXXXXX",
sizeof(steam->serial_no));
- mutex_unlock(&steam->mutex);
hid_info(steam->hdev, "Steam Controller '%s' connected",
steam->serial_no);
@@ -667,15 +887,13 @@ static int steam_register(struct steam_device *steam)
mutex_unlock(&steam_devices_lock);
}
- mutex_lock(&steam->mutex);
+ spin_lock_irqsave(&steam->lock, flags);
client_opened = steam->client_opened;
- if (!client_opened)
+ spin_unlock_irqrestore(&steam->lock, flags);
+ if (!client_opened) {
steam_set_lizard_mode(steam, lizard_mode);
- mutex_unlock(&steam->mutex);
-
- if (!client_opened)
ret = steam_input_register(steam);
- else
+ } else
ret = 0;
return ret;
@@ -719,6 +937,34 @@ static void steam_work_connect_cb(struct work_struct *work)
}
}
+static void steam_mode_switch_cb(struct work_struct *work)
+{
+ struct steam_device *steam = container_of(to_delayed_work(work),
+ struct steam_device, mode_switch);
+ unsigned long flags;
+ bool client_opened;
+ steam->gamepad_mode = !steam->gamepad_mode;
+ if (!lizard_mode)
+ return;
+
+ if (steam->gamepad_mode)
+ steam_set_lizard_mode(steam, false);
+ else {
+ spin_lock_irqsave(&steam->lock, flags);
+ client_opened = steam->client_opened;
+ spin_unlock_irqrestore(&steam->lock, flags);
+ if (!client_opened)
+ steam_set_lizard_mode(steam, lizard_mode);
+ }
+
+ steam_haptic_pulse(steam, STEAM_PAD_RIGHT, 0x190, 0, 1, 0);
+ if (steam->gamepad_mode) {
+ steam_haptic_pulse(steam, STEAM_PAD_LEFT, 0x14D, 0x14D, 0x2D, 0);
+ } else {
+ steam_haptic_pulse(steam, STEAM_PAD_LEFT, 0x1F4, 0x1F4, 0x1E, 0);
+ }
+}
+
static bool steam_is_valve_interface(struct hid_device *hdev)
{
struct hid_report_enum *rep_enum;
@@ -738,22 +984,6 @@ static bool steam_is_valve_interface(struct hid_device *hdev)
return !list_empty(&rep_enum->report_list);
}
-static void steam_lizard_mode_heartbeat(struct work_struct *work)
-{
- struct steam_device *steam = container_of(work, struct steam_device,
- heartbeat.work);
-
- mutex_lock(&steam->mutex);
- if (!steam->client_opened && steam->client_hdev) {
- steam_send_report_byte(steam, STEAM_CMD_CLEAR_MAPPINGS);
- steam_write_registers(steam,
- STEAM_REG_RPAD_MODE, 0x07, /* disable mouse */
- 0);
- schedule_delayed_work(&steam->heartbeat, 5 * HZ);
- }
- mutex_unlock(&steam->mutex);
-}
-
static int steam_client_ll_parse(struct hid_device *hdev)
{
struct steam_device *steam = hdev->driver_data;
@@ -774,10 +1004,11 @@ static void steam_client_ll_stop(struct hid_device *hdev)
static int steam_client_ll_open(struct hid_device *hdev)
{
struct steam_device *steam = hdev->driver_data;
+ unsigned long flags;
- mutex_lock(&steam->mutex);
- steam->client_opened = true;
- mutex_unlock(&steam->mutex);
+ spin_lock_irqsave(&steam->lock, flags);
+ steam->client_opened++;
+ spin_unlock_irqrestore(&steam->lock, flags);
steam_input_unregister(steam);
@@ -792,17 +1023,14 @@ static void steam_client_ll_close(struct hid_device *hdev)
bool connected;
spin_lock_irqsave(&steam->lock, flags);
- connected = steam->connected;
+ steam->client_opened--;
+ connected = steam->connected && !steam->client_opened;
spin_unlock_irqrestore(&steam->lock, flags);
- mutex_lock(&steam->mutex);
- steam->client_opened = false;
- if (connected)
+ if (connected) {
steam_set_lizard_mode(steam, lizard_mode);
- mutex_unlock(&steam->mutex);
-
- if (connected)
steam_input_register(steam);
+ }
}
static int steam_client_ll_raw_request(struct hid_device *hdev,
@@ -888,20 +1116,13 @@ static int steam_probe(struct hid_device *hdev,
steam->hdev = hdev;
hid_set_drvdata(hdev, steam);
spin_lock_init(&steam->lock);
- mutex_init(&steam->mutex);
+ mutex_init(&steam->report_mutex);
steam->quirks = id->driver_data;
INIT_WORK(&steam->work_connect, steam_work_connect_cb);
+ INIT_DELAYED_WORK(&steam->mode_switch, steam_mode_switch_cb);
INIT_LIST_HEAD(&steam->list);
- INIT_DEFERRABLE_WORK(&steam->heartbeat, steam_lizard_mode_heartbeat);
INIT_WORK(&steam->rumble_work, steam_haptic_rumble_cb);
- steam->client_hdev = steam_create_client_hid(hdev);
- if (IS_ERR(steam->client_hdev)) {
- ret = PTR_ERR(steam->client_hdev);
- goto client_hdev_fail;
- }
- steam->client_hdev->driver_data = steam;
-
/*
* With the real steam controller interface, do not connect hidraw.
* Instead, create the client_hid and connect that.
@@ -910,10 +1131,6 @@ static int steam_probe(struct hid_device *hdev,
if (ret)
goto hid_hw_start_fail;
- ret = hid_add_device(steam->client_hdev);
- if (ret)
- goto client_hdev_add_fail;
-
ret = hid_hw_open(hdev);
if (ret) {
hid_err(hdev,
@@ -939,17 +1156,28 @@ static int steam_probe(struct hid_device *hdev,
}
}
+ steam->client_hdev = steam_create_client_hid(hdev);
+ if (IS_ERR(steam->client_hdev)) {
+ ret = PTR_ERR(steam->client_hdev);
+ goto client_hdev_fail;
+ }
+ steam->client_hdev->driver_data = steam;
+
+ ret = hid_add_device(steam->client_hdev);
+ if (ret)
+ goto client_hdev_add_fail;
+
return 0;
-input_register_fail:
-hid_hw_open_fail:
client_hdev_add_fail:
hid_hw_stop(hdev);
-hid_hw_start_fail:
- hid_destroy_device(steam->client_hdev);
client_hdev_fail:
+ hid_destroy_device(steam->client_hdev);
+input_register_fail:
+hid_hw_open_fail:
+hid_hw_start_fail:
cancel_work_sync(&steam->work_connect);
- cancel_delayed_work_sync(&steam->heartbeat);
+ cancel_delayed_work_sync(&steam->mode_switch);
cancel_work_sync(&steam->rumble_work);
steam_alloc_fail:
hid_err(hdev, "%s: failed with error %d\n",
@@ -966,13 +1194,11 @@ static void steam_remove(struct hid_device *hdev)
return;
}
+ cancel_delayed_work_sync(&steam->mode_switch);
+ cancel_work_sync(&steam->work_connect);
hid_destroy_device(steam->client_hdev);
- mutex_lock(&steam->mutex);
steam->client_hdev = NULL;
- steam->client_opened = false;
- cancel_delayed_work_sync(&steam->heartbeat);
- mutex_unlock(&steam->mutex);
- cancel_work_sync(&steam->work_connect);
+ steam->client_opened = 0;
if (steam->quirks & STEAM_QUIRK_WIRELESS) {
hid_info(hdev, "Steam wireless receiver disconnected");
}
@@ -1254,6 +1480,17 @@ static void steam_do_deck_input_event(struct steam_device *steam,
b13 = data[13];
b14 = data[14];
+ if (!(b9 & BIT(6)) && steam->did_mode_switch) {
+ steam->did_mode_switch = false;
+ cancel_delayed_work_sync(&steam->mode_switch);
+ } else if (!steam->client_opened && (b9 & BIT(6)) && !steam->did_mode_switch) {
+ steam->did_mode_switch = true;
+ schedule_delayed_work(&steam->mode_switch, 45 * HZ / 100);
+ }
+
+ if (!steam->gamepad_mode)
+ return;
+
lpad_touched = b10 & BIT(3);
rpad_touched = b10 & BIT(4);
@@ -1375,7 +1612,7 @@ static int steam_raw_event(struct hid_device *hdev,
return 0;
switch (data[2]) {
- case STEAM_EV_INPUT_DATA:
+ case ID_CONTROLLER_STATE:
if (steam->client_opened)
return 0;
rcu_read_lock();
@@ -1384,7 +1621,7 @@ static int steam_raw_event(struct hid_device *hdev,
steam_do_input_event(steam, input, data);
rcu_read_unlock();
break;
- case STEAM_EV_DECK_INPUT_DATA:
+ case ID_CONTROLLER_DECK_STATE:
if (steam->client_opened)
return 0;
rcu_read_lock();
@@ -1393,7 +1630,7 @@ static int steam_raw_event(struct hid_device *hdev,
steam_do_deck_input_event(steam, input, data);
rcu_read_unlock();
break;
- case STEAM_EV_CONNECT:
+ case ID_CONTROLLER_WIRELESS:
/*
* The payload of this event is a single byte:
* 0x01: disconnected.
@@ -1408,7 +1645,7 @@ static int steam_raw_event(struct hid_device *hdev,
break;
}
break;
- case STEAM_EV_BATTERY:
+ case ID_CONTROLLER_STATUS:
if (steam->quirks & STEAM_QUIRK_WIRELESS) {
rcu_read_lock();
battery = rcu_dereference(steam->battery);
@@ -1439,10 +1676,8 @@ static int steam_param_set_lizard_mode(const char *val,
mutex_lock(&steam_devices_lock);
list_for_each_entry(steam, &steam_devices, list) {
- mutex_lock(&steam->mutex);
if (!steam->client_opened)
steam_set_lizard_mode(steam, lizard_mode);
- mutex_unlock(&steam->mutex);
}
mutex_unlock(&steam_devices_lock);
return 0;
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index 2735cd585af0..90f316ae9819 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -44,12 +44,11 @@
#include "i2c-hid.h"
/* quirks to control the device */
-#define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0)
-#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1)
-#define I2C_HID_QUIRK_BOGUS_IRQ BIT(4)
-#define I2C_HID_QUIRK_RESET_ON_RESUME BIT(5)
-#define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(6)
-#define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(7)
+#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(0)
+#define I2C_HID_QUIRK_BOGUS_IRQ BIT(1)
+#define I2C_HID_QUIRK_RESET_ON_RESUME BIT(2)
+#define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(3)
+#define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(4)
/* Command opcodes */
#define I2C_HID_OPCODE_RESET 0x01
@@ -120,8 +119,6 @@ static const struct i2c_hid_quirks {
__u16 idProduct;
__u32 quirks;
} i2c_hid_quirks[] = {
- { USB_VENDOR_ID_WEIDA, HID_ANY_ID,
- I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
{ I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET },
{ I2C_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_VOYO_WINPAD_A15,
@@ -395,8 +392,7 @@ static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state)
* The call will get a return value (EREMOTEIO) but device will be
* triggered and activated. After that, it goes like a normal device.
*/
- if (power_state == I2C_HID_PWR_ON &&
- ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) {
+ if (power_state == I2C_HID_PWR_ON) {
ret = i2c_hid_set_power_command(ihid, I2C_HID_PWR_ON);
/* Device was already activated */
@@ -426,12 +422,23 @@ set_pwr_exit:
return ret;
}
-static int i2c_hid_execute_reset(struct i2c_hid *ihid)
+static int i2c_hid_start_hwreset(struct i2c_hid *ihid)
{
size_t length = 0;
int ret;
- i2c_hid_dbg(ihid, "resetting...\n");
+ i2c_hid_dbg(ihid, "%s\n", __func__);
+
+ /*
+ * This prevents sending feature reports while the device is
+ * being reset. Otherwise we may lose the reset complete
+ * interrupt.
+ */
+ lockdep_assert_held(&ihid->reset_lock);
+
+ ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
+ if (ret)
+ return ret;
/* Prepare reset command. Command register goes first. */
*(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
@@ -444,60 +451,40 @@ static int i2c_hid_execute_reset(struct i2c_hid *ihid)
ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
if (ret) {
- dev_err(&ihid->client->dev, "failed to reset device.\n");
- goto out;
- }
-
- if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) {
- msleep(100);
- goto out;
+ dev_err(&ihid->client->dev,
+ "failed to reset device: %d\n", ret);
+ goto err_clear_reset;
}
- i2c_hid_dbg(ihid, "%s: waiting...\n", __func__);
- if (!wait_event_timeout(ihid->wait,
- !test_bit(I2C_HID_RESET_PENDING, &ihid->flags),
- msecs_to_jiffies(5000))) {
- ret = -ENODATA;
- goto out;
- }
- i2c_hid_dbg(ihid, "%s: finished.\n", __func__);
+ return 0;
-out:
+err_clear_reset:
clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
+ i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
return ret;
}
-static int i2c_hid_hwreset(struct i2c_hid *ihid)
+static int i2c_hid_finish_hwreset(struct i2c_hid *ihid)
{
- int ret;
+ int ret = 0;
- i2c_hid_dbg(ihid, "%s\n", __func__);
-
- /*
- * This prevents sending feature reports while the device is
- * being reset. Otherwise we may lose the reset complete
- * interrupt.
- */
- mutex_lock(&ihid->reset_lock);
-
- ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
- if (ret)
- goto out_unlock;
+ i2c_hid_dbg(ihid, "%s: waiting...\n", __func__);
- ret = i2c_hid_execute_reset(ihid);
- if (ret) {
- dev_err(&ihid->client->dev,
- "failed to reset device: %d\n", ret);
- i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
- goto out_unlock;
+ if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) {
+ msleep(100);
+ clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
+ } else if (!wait_event_timeout(ihid->wait,
+ !test_bit(I2C_HID_RESET_PENDING, &ihid->flags),
+ msecs_to_jiffies(1000))) {
+ dev_warn(&ihid->client->dev, "device did not ack reset within 1000 ms\n");
+ clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
}
+ i2c_hid_dbg(ihid, "%s: finished.\n", __func__);
/* At least some SIS devices need this after reset */
if (!(ihid->quirks & I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET))
ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
-out_unlock:
- mutex_unlock(&ihid->reset_lock);
return ret;
}
@@ -729,11 +716,10 @@ static int i2c_hid_parse(struct hid_device *hid)
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
struct i2c_hid_desc *hdesc = &ihid->hdesc;
+ char *rdesc = NULL, *use_override = NULL;
unsigned int rsize;
- char *rdesc;
int ret;
int tries = 3;
- char *use_override;
i2c_hid_dbg(ihid, "entering %s\n", __func__);
@@ -743,14 +729,15 @@ static int i2c_hid_parse(struct hid_device *hid)
return -EINVAL;
}
+ mutex_lock(&ihid->reset_lock);
do {
- ret = i2c_hid_hwreset(ihid);
+ ret = i2c_hid_start_hwreset(ihid);
if (ret)
msleep(1000);
} while (tries-- > 0 && ret);
if (ret)
- return ret;
+ goto abort_reset;
use_override = i2c_hid_get_dmi_hid_report_desc_override(client->name,
&rsize);
@@ -762,8 +749,8 @@ static int i2c_hid_parse(struct hid_device *hid)
rdesc = kzalloc(rsize, GFP_KERNEL);
if (!rdesc) {
- dbg_hid("couldn't allocate rdesc memory\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto abort_reset;
}
i2c_hid_dbg(ihid, "asking HID report descriptor\n");
@@ -773,23 +760,34 @@ static int i2c_hid_parse(struct hid_device *hid)
rdesc, rsize);
if (ret) {
hid_err(hid, "reading report descriptor failed\n");
- kfree(rdesc);
- return -EIO;
+ goto abort_reset;
}
}
+ /*
+ * Windows directly reads the report-descriptor after sending reset
+ * and then waits for resets completion afterwards. Some touchpads
+ * actually wait for the report-descriptor to be read before signalling
+ * reset completion.
+ */
+ ret = i2c_hid_finish_hwreset(ihid);
+abort_reset:
+ clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
+ mutex_unlock(&ihid->reset_lock);
+ if (ret)
+ goto out;
+
i2c_hid_dbg(ihid, "Report Descriptor: %*ph\n", rsize, rdesc);
ret = hid_parse_report(hid, rdesc, rsize);
+ if (ret)
+ dbg_hid("parsing report descriptor failed\n");
+
+out:
if (!use_override)
kfree(rdesc);
- if (ret) {
- dbg_hid("parsing report descriptor failed\n");
- return ret;
- }
-
- return 0;
+ return ret;
}
static int i2c_hid_start(struct hid_device *hid)
@@ -987,10 +985,15 @@ static int i2c_hid_core_resume(struct i2c_hid *ihid)
* However some ALPS touchpads generate IRQ storm without reset, so
* let's still reset them here.
*/
- if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME)
- ret = i2c_hid_hwreset(ihid);
- else
+ if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME) {
+ mutex_lock(&ihid->reset_lock);
+ ret = i2c_hid_start_hwreset(ihid);
+ if (ret == 0)
+ ret = i2c_hid_finish_hwreset(ihid);
+ mutex_unlock(&ihid->reset_lock);
+ } else {
ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
+ }
if (ret)
return ret;
diff --git a/drivers/hid/i2c-hid/i2c-hid-of-elan.c b/drivers/hid/i2c-hid/i2c-hid-of-elan.c
index 31abab57ad44..5b91fb106cfc 100644
--- a/drivers/hid/i2c-hid/i2c-hid-of-elan.c
+++ b/drivers/hid/i2c-hid/i2c-hid-of-elan.c
@@ -130,9 +130,17 @@ static const struct elan_i2c_hid_chip_data ilitek_ili9882t_chip_data = {
.main_supply_name = NULL,
};
+static const struct elan_i2c_hid_chip_data ilitek_ili2901_chip_data = {
+ .post_power_delay_ms = 10,
+ .post_gpio_reset_on_delay_ms = 100,
+ .hid_descriptor_address = 0x0001,
+ .main_supply_name = "vcc33",
+};
+
static const struct of_device_id elan_i2c_hid_of_match[] = {
{ .compatible = "elan,ekth6915", .data = &elan_ekth6915_chip_data },
{ .compatible = "ilitek,ili9882t", .data = &ilitek_ili9882t_chip_data },
+ { .compatible = "ilitek,ili2901", .data = &ilitek_ili2901_chip_data },
{ }
};
MODULE_DEVICE_TABLE(of, elan_i2c_hid_of_match);
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
index 710fda5f19e1..65e7eeb2fa64 100644
--- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
@@ -119,50 +119,6 @@ static inline bool ish_should_leave_d0i3(struct pci_dev *pdev)
return !pm_resume_via_firmware() || pdev->device == CHV_DEVICE_ID;
}
-static int enable_gpe(struct device *dev)
-{
-#ifdef CONFIG_ACPI
- acpi_status acpi_sts;
- struct acpi_device *adev;
- struct acpi_device_wakeup *wakeup;
-
- adev = ACPI_COMPANION(dev);
- if (!adev) {
- dev_err(dev, "get acpi handle failed\n");
- return -ENODEV;
- }
- wakeup = &adev->wakeup;
-
- /*
- * Call acpi_disable_gpe(), so that reference count
- * gpe_event_info->runtime_count doesn't overflow.
- * When gpe_event_info->runtime_count = 0, the call
- * to acpi_disable_gpe() simply return.
- */
- acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number);
-
- acpi_sts = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number);
- if (ACPI_FAILURE(acpi_sts)) {
- dev_err(dev, "enable ose_gpe failed\n");
- return -EIO;
- }
-
- return 0;
-#else
- return -ENODEV;
-#endif
-}
-
-static void enable_pme_wake(struct pci_dev *pdev)
-{
- if ((pci_pme_capable(pdev, PCI_D0) ||
- pci_pme_capable(pdev, PCI_D3hot) ||
- pci_pme_capable(pdev, PCI_D3cold)) && !enable_gpe(&pdev->dev)) {
- pci_pme_active(pdev, true);
- dev_dbg(&pdev->dev, "ish ipc driver pme wake enabled\n");
- }
-}
-
/**
* ish_probe() - PCI driver probe callback
* @pdev: pci device
@@ -233,7 +189,7 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Enable PME for EHL */
if (pdev->device == EHL_Ax_DEVICE_ID)
- enable_pme_wake(pdev);
+ device_init_wakeup(dev, true);
ret = ish_init(ishtp);
if (ret)
@@ -256,6 +212,19 @@ static void ish_remove(struct pci_dev *pdev)
ish_device_disable(ishtp_dev);
}
+
+/**
+ * ish_shutdown() - PCI driver shutdown callback
+ * @pdev: pci device
+ *
+ * This function sets up wakeup for S5
+ */
+static void ish_shutdown(struct pci_dev *pdev)
+{
+ if (pdev->device == EHL_Ax_DEVICE_ID)
+ pci_prepare_to_sleep(pdev);
+}
+
static struct device __maybe_unused *ish_resume_device;
/* 50ms to get resume response */
@@ -378,13 +347,6 @@ static int __maybe_unused ish_resume(struct device *device)
struct pci_dev *pdev = to_pci_dev(device);
struct ishtp_device *dev = pci_get_drvdata(pdev);
- /* add this to finish power flow for EHL */
- if (dev->pdev->device == EHL_Ax_DEVICE_ID) {
- pci_set_power_state(pdev, PCI_D0);
- enable_pme_wake(pdev);
- dev_dbg(dev->devc, "set power state to D0 for ehl\n");
- }
-
ish_resume_device = device;
dev->resume_flag = 1;
@@ -400,6 +362,7 @@ static struct pci_driver ish_driver = {
.id_table = ish_pci_tbl,
.probe = ish_probe,
.remove = ish_remove,
+ .shutdown = ish_shutdown,
.driver.pm = &ish_pm_ops,
};
diff --git a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
index 16aa030af845..e157863a8b25 100644
--- a/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
+++ b/drivers/hid/intel-ish-hid/ishtp-fw-loader.c
@@ -840,43 +840,22 @@ static void load_fw_from_host_handler(struct work_struct *work)
*
* Return: 0 for success, negative error code for failure
*/
-static int loader_init(struct ishtp_cl *loader_ishtp_cl, int reset)
+static int loader_init(struct ishtp_cl *loader_ishtp_cl, bool reset)
{
int rv;
- struct ishtp_fw_client *fw_client;
struct ishtp_cl_data *client_data =
ishtp_get_client_data(loader_ishtp_cl);
dev_dbg(cl_data_to_dev(client_data), "reset flag: %d\n", reset);
- rv = ishtp_cl_link(loader_ishtp_cl);
- if (rv < 0) {
- dev_err(cl_data_to_dev(client_data), "ishtp_cl_link failed\n");
- return rv;
- }
-
- /* Connect to firmware client */
- ishtp_set_tx_ring_size(loader_ishtp_cl, LOADER_CL_TX_RING_SIZE);
- ishtp_set_rx_ring_size(loader_ishtp_cl, LOADER_CL_RX_RING_SIZE);
-
- fw_client =
- ishtp_fw_cl_get_client(ishtp_get_ishtp_device(loader_ishtp_cl),
- &loader_ishtp_id_table[0].guid);
- if (!fw_client) {
- dev_err(cl_data_to_dev(client_data),
- "ISH client uuid not found\n");
- rv = -ENOENT;
- goto err_cl_unlink;
- }
-
- ishtp_cl_set_fw_client_id(loader_ishtp_cl,
- ishtp_get_fw_client_id(fw_client));
- ishtp_set_connection_state(loader_ishtp_cl, ISHTP_CL_CONNECTING);
-
- rv = ishtp_cl_connect(loader_ishtp_cl);
+ rv = ishtp_cl_establish_connection(loader_ishtp_cl,
+ &loader_ishtp_id_table[0].guid,
+ LOADER_CL_TX_RING_SIZE,
+ LOADER_CL_RX_RING_SIZE,
+ reset);
if (rv < 0) {
dev_err(cl_data_to_dev(client_data), "Client connect fail\n");
- goto err_cl_unlink;
+ goto err_cl_disconnect;
}
dev_dbg(cl_data_to_dev(client_data), "Client connected\n");
@@ -885,17 +864,14 @@ static int loader_init(struct ishtp_cl *loader_ishtp_cl, int reset)
return 0;
-err_cl_unlink:
- ishtp_cl_unlink(loader_ishtp_cl);
+err_cl_disconnect:
+ ishtp_cl_destroy_connection(loader_ishtp_cl, reset);
return rv;
}
static void loader_deinit(struct ishtp_cl *loader_ishtp_cl)
{
- ishtp_set_connection_state(loader_ishtp_cl, ISHTP_CL_DISCONNECTING);
- ishtp_cl_disconnect(loader_ishtp_cl);
- ishtp_cl_unlink(loader_ishtp_cl);
- ishtp_cl_flush_queues(loader_ishtp_cl);
+ ishtp_cl_destroy_connection(loader_ishtp_cl, false);
/* Disband and free all Tx and Rx client-level rings */
ishtp_cl_free(loader_ishtp_cl);
@@ -914,19 +890,7 @@ static void reset_handler(struct work_struct *work)
loader_ishtp_cl = client_data->loader_ishtp_cl;
cl_device = client_data->cl_device;
- /* Unlink, flush queues & start again */
- ishtp_cl_unlink(loader_ishtp_cl);
- ishtp_cl_flush_queues(loader_ishtp_cl);
- ishtp_cl_free(loader_ishtp_cl);
-
- loader_ishtp_cl = ishtp_cl_allocate(cl_device);
- if (!loader_ishtp_cl)
- return;
-
- ishtp_set_drvdata(cl_device, loader_ishtp_cl);
- ishtp_set_client_data(loader_ishtp_cl, client_data);
- client_data->loader_ishtp_cl = loader_ishtp_cl;
- client_data->cl_device = cl_device;
+ ishtp_cl_destroy_connection(loader_ishtp_cl, true);
rv = loader_init(loader_ishtp_cl, 1);
if (rv < 0) {
@@ -974,7 +938,7 @@ static int loader_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
INIT_WORK(&client_data->work_fw_load,
load_fw_from_host_handler);
- rv = loader_init(loader_ishtp_cl, 0);
+ rv = loader_init(loader_ishtp_cl, false);
if (rv < 0) {
ishtp_cl_free(loader_ishtp_cl);
return rv;
diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
index e3d70c5460e9..fbd4f8ea1951 100644
--- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c
+++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c
@@ -639,47 +639,26 @@ static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl,
*
* Return: 0 on success, non zero on error
*/
-static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
+static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, bool reset)
{
- struct ishtp_device *dev;
struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
- struct ishtp_fw_client *fw_client;
int i;
int rv;
dev_dbg(cl_data_to_dev(client_data), "%s\n", __func__);
hid_ishtp_trace(client_data, "%s reset flag: %d\n", __func__, reset);
- rv = ishtp_cl_link(hid_ishtp_cl);
- if (rv) {
- dev_err(cl_data_to_dev(client_data),
- "ishtp_cl_link failed\n");
- return -ENOMEM;
- }
-
client_data->init_done = 0;
- dev = ishtp_get_ishtp_device(hid_ishtp_cl);
-
- /* Connect to FW client */
- ishtp_set_tx_ring_size(hid_ishtp_cl, HID_CL_TX_RING_SIZE);
- ishtp_set_rx_ring_size(hid_ishtp_cl, HID_CL_RX_RING_SIZE);
-
- fw_client = ishtp_fw_cl_get_client(dev, &hid_ishtp_id_table[0].guid);
- if (!fw_client) {
- dev_err(cl_data_to_dev(client_data),
- "ish client uuid not found\n");
- return -ENOENT;
- }
- ishtp_cl_set_fw_client_id(hid_ishtp_cl,
- ishtp_get_fw_client_id(fw_client));
- ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_CONNECTING);
-
- rv = ishtp_cl_connect(hid_ishtp_cl);
+ rv = ishtp_cl_establish_connection(hid_ishtp_cl,
+ &hid_ishtp_id_table[0].guid,
+ HID_CL_TX_RING_SIZE,
+ HID_CL_RX_RING_SIZE,
+ reset);
if (rv) {
dev_err(cl_data_to_dev(client_data),
"client connect fail\n");
- goto err_cl_unlink;
+ goto err_cl_disconnect;
}
hid_ishtp_trace(client_data, "%s client connected\n", __func__);
@@ -723,10 +702,7 @@ static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
return 0;
err_cl_disconnect:
- ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_DISCONNECTING);
- ishtp_cl_disconnect(hid_ishtp_cl);
-err_cl_unlink:
- ishtp_cl_unlink(hid_ishtp_cl);
+ ishtp_cl_destroy_connection(hid_ishtp_cl, reset);
return rv;
}
@@ -738,8 +714,7 @@ err_cl_unlink:
*/
static void hid_ishtp_cl_deinit(struct ishtp_cl *hid_ishtp_cl)
{
- ishtp_cl_unlink(hid_ishtp_cl);
- ishtp_cl_flush_queues(hid_ishtp_cl);
+ ishtp_cl_destroy_connection(hid_ishtp_cl, false);
/* disband and free all Tx and Rx client-level rings */
ishtp_cl_free(hid_ishtp_cl);
@@ -749,33 +724,23 @@ static void hid_ishtp_cl_reset_handler(struct work_struct *work)
{
struct ishtp_cl_data *client_data;
struct ishtp_cl *hid_ishtp_cl;
- struct ishtp_cl_device *cl_device;
int retry;
int rv;
client_data = container_of(work, struct ishtp_cl_data, work);
hid_ishtp_cl = client_data->hid_ishtp_cl;
- cl_device = client_data->cl_device;
hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
hid_ishtp_cl);
dev_dbg(ishtp_device(client_data->cl_device), "%s\n", __func__);
- hid_ishtp_cl_deinit(hid_ishtp_cl);
-
- hid_ishtp_cl = ishtp_cl_allocate(cl_device);
- if (!hid_ishtp_cl)
- return;
-
- ishtp_set_drvdata(cl_device, hid_ishtp_cl);
- ishtp_set_client_data(hid_ishtp_cl, client_data);
- client_data->hid_ishtp_cl = hid_ishtp_cl;
+ ishtp_cl_destroy_connection(hid_ishtp_cl, true);
client_data->num_hid_devices = 0;
for (retry = 0; retry < 3; ++retry) {
- rv = hid_ishtp_cl_init(hid_ishtp_cl, 1);
+ rv = hid_ishtp_cl_init(hid_ishtp_cl, true);
if (!rv)
break;
dev_err(cl_data_to_dev(client_data), "Retry reset init\n");
@@ -841,7 +806,7 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
ishtp_hid_print_trace = ishtp_trace_callback(cl_device);
- rv = hid_ishtp_cl_init(hid_ishtp_cl, 0);
+ rv = hid_ishtp_cl_init(hid_ishtp_cl, false);
if (rv) {
ishtp_cl_free(hid_ishtp_cl);
return rv;
@@ -868,11 +833,9 @@ static void hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
hid_ishtp_cl);
dev_dbg(ishtp_device(cl_device), "%s\n", __func__);
- ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_DISCONNECTING);
- ishtp_cl_disconnect(hid_ishtp_cl);
+ hid_ishtp_cl_deinit(hid_ishtp_cl);
ishtp_put_device(cl_device);
ishtp_hid_remove(client_data);
- hid_ishtp_cl_deinit(hid_ishtp_cl);
hid_ishtp_cl = NULL;
diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c
index 7fc738a22375..aa6cb033bb06 100644
--- a/drivers/hid/intel-ish-hid/ishtp/bus.c
+++ b/drivers/hid/intel-ish-hid/ishtp/bus.c
@@ -378,7 +378,7 @@ static const struct dev_pm_ops ishtp_cl_bus_dev_pm_ops = {
.restore = ishtp_cl_device_resume,
};
-static struct bus_type ishtp_cl_bus_type = {
+static const struct bus_type ishtp_cl_bus_type = {
.name = "ishtp",
.dev_groups = ishtp_cl_dev_groups,
.probe = ishtp_cl_device_probe,
diff --git a/drivers/hid/intel-ish-hid/ishtp/client.c b/drivers/hid/intel-ish-hid/ishtp/client.c
index 2d92fc129ce4..82c907f01bd3 100644
--- a/drivers/hid/intel-ish-hid/ishtp/client.c
+++ b/drivers/hid/intel-ish-hid/ishtp/client.c
@@ -339,16 +339,17 @@ static bool ishtp_cl_is_other_connecting(struct ishtp_cl *cl)
}
/**
- * ishtp_cl_connect() - Send connect request to firmware
+ * ishtp_cl_connect_to_fw() - Send connect request to firmware
* @cl: client device instance
*
- * Send a connect request for a client to firmware. If successful it will
- * RX and TX ring buffers
+ * Send a connect request to the firmware and wait for firmware response.
+ * If there is successful connection response from the firmware, change
+ * client state to ISHTP_CL_CONNECTED, and bind client to related
+ * firmware client_id.
*
- * Return: 0 if successful connect response from the firmware and able
- * to bind and allocate ring buffers or error code on failure
+ * Return: 0 for success and error code on failure
*/
-int ishtp_cl_connect(struct ishtp_cl *cl)
+static int ishtp_cl_connect_to_fw(struct ishtp_cl *cl)
{
struct ishtp_device *dev;
int rets;
@@ -358,8 +359,6 @@ int ishtp_cl_connect(struct ishtp_cl *cl)
dev = cl->dev;
- dev->print_log(dev, "%s() current_state = %d\n", __func__, cl->state);
-
if (ishtp_cl_is_other_connecting(cl)) {
dev->print_log(dev, "%s() Busy\n", __func__);
return -EBUSY;
@@ -405,6 +404,38 @@ int ishtp_cl_connect(struct ishtp_cl *cl)
return rets;
}
+ return rets;
+}
+
+/**
+ * ishtp_cl_connect() - Build connection with firmware
+ * @cl: client device instance
+ *
+ * Call ishtp_cl_connect_to_fw() to connect and bind to firmware. If successful,
+ * allocate RX and TX ring buffers, and start flow control with firmware to
+ * start communication.
+ *
+ * Return: 0 if there is successful connection to the firmware, allocate
+ * ring buffers.
+ */
+int ishtp_cl_connect(struct ishtp_cl *cl)
+{
+ struct ishtp_device *dev;
+ int rets;
+
+ if (!cl || !cl->dev)
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ dev->print_log(dev, "%s() current_state = %d\n", __func__, cl->state);
+
+ rets = ishtp_cl_connect_to_fw(cl);
+ if (rets) {
+ dev->print_log(dev, "%s() Connect to fw failed\n", __func__);
+ return rets;
+ }
+
rets = ishtp_cl_alloc_rx_ring(cl);
if (rets) {
dev->print_log(dev, "%s() Alloc RX ring failed\n", __func__);
@@ -422,16 +453,148 @@ int ishtp_cl_connect(struct ishtp_cl *cl)
return rets;
}
- /* Upon successful connection and allocation, emit flow-control */
+ /*
+ * Upon successful connection and allocation, start flow-control.
+ */
rets = ishtp_cl_read_start(cl);
- dev->print_log(dev, "%s() successful\n", __func__);
-
return rets;
}
EXPORT_SYMBOL(ishtp_cl_connect);
/**
+ * ishtp_cl_establish_connection() - Establish connection with the firmware
+ * @cl: client device instance
+ * @uuid: uuid of the client to search
+ * @tx_size: TX ring buffer size
+ * @rx_size: RX ring buffer size
+ * @reset: true if called for reset connection, otherwise for first connection
+ *
+ * This is a helper function for client driver to build connection with firmware.
+ * If it's first time connecting to the firmware, set reset to false, this
+ * function will link client to bus, find client id and send connect request to
+ * the firmware.
+ *
+ * If it's called for reset handler where client lost connection after
+ * firmware reset, set reset to true, this function will reinit client state and
+ * establish connection again. In this case, this function reuses current client
+ * structure and ring buffers to avoid allocation failure and memory fragments.
+ *
+ * Return: 0 for successful connection with the firmware,
+ * or error code on failure
+ */
+int ishtp_cl_establish_connection(struct ishtp_cl *cl, const guid_t *uuid,
+ int tx_size, int rx_size, bool reset)
+{
+ struct ishtp_device *dev;
+ struct ishtp_fw_client *fw_client;
+ int rets;
+
+ if (!cl || !cl->dev)
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ ishtp_set_connection_state(cl, ISHTP_CL_INITIALIZING);
+
+ /* reinit ishtp_cl structure if call for reset */
+ if (reset) {
+ cl->host_client_id = 0;
+ cl->fw_client_id = 0;
+ cl->ishtp_flow_ctrl_creds = 0;
+ cl->out_flow_ctrl_creds = 0;
+
+ cl->last_tx_path = CL_TX_PATH_IPC;
+ cl->last_dma_acked = 1;
+ cl->last_dma_addr = NULL;
+ cl->last_ipc_acked = 1;
+
+ cl->sending = 0;
+ cl->err_send_msg = 0;
+ cl->err_send_fc = 0;
+
+ cl->send_msg_cnt_ipc = 0;
+ cl->send_msg_cnt_dma = 0;
+ cl->recv_msg_cnt_ipc = 0;
+ cl->recv_msg_cnt_dma = 0;
+ cl->recv_msg_num_frags = 0;
+ cl->ishtp_flow_ctrl_cnt = 0;
+ cl->out_flow_ctrl_cnt = 0;
+ }
+
+ /* link to bus */
+ rets = ishtp_cl_link(cl);
+ if (rets) {
+ dev->print_log(dev, "%s() ishtp_cl_link failed\n", __func__);
+ return rets;
+ }
+
+ /* find firmware client */
+ fw_client = ishtp_fw_cl_get_client(dev, uuid);
+ if (!fw_client) {
+ dev->print_log(dev,
+ "%s() ish client uuid not found\n", __func__);
+ return -ENOENT;
+ }
+
+ ishtp_set_tx_ring_size(cl, tx_size);
+ ishtp_set_rx_ring_size(cl, rx_size);
+
+ ishtp_cl_set_fw_client_id(cl, ishtp_get_fw_client_id(fw_client));
+
+ ishtp_set_connection_state(cl, ISHTP_CL_CONNECTING);
+
+ /*
+ * For reset case, not allocate tx/rx ring buffer which are already
+ * done in ishtp_cl_connect() during first connection.
+ */
+ if (reset) {
+ rets = ishtp_cl_connect_to_fw(cl);
+ if (!rets)
+ rets = ishtp_cl_read_start(cl);
+ else
+ dev->print_log(dev,
+ "%s() connect to fw failed\n", __func__);
+ } else {
+ rets = ishtp_cl_connect(cl);
+ }
+
+ return rets;
+}
+EXPORT_SYMBOL(ishtp_cl_establish_connection);
+
+/**
+ * ishtp_cl_destroy_connection() - Disconnect with the firmware
+ * @cl: client device instance
+ * @reset: true if called for firmware reset, false for normal disconnection
+ *
+ * This is a helper function for client driver to disconnect with firmware,
+ * unlink to bus and flush message queue.
+ */
+void ishtp_cl_destroy_connection(struct ishtp_cl *cl, bool reset)
+{
+ if (!cl)
+ return;
+
+ if (reset) {
+ /*
+ * For reset case, connection is already lost during fw reset.
+ * Just set state to DISCONNECTED is enough.
+ */
+ ishtp_set_connection_state(cl, ISHTP_CL_DISCONNECTED);
+ } else {
+ if (cl->state != ISHTP_CL_DISCONNECTED) {
+ ishtp_set_connection_state(cl, ISHTP_CL_DISCONNECTING);
+ ishtp_cl_disconnect(cl);
+ }
+ }
+
+ ishtp_cl_unlink(cl);
+ ishtp_cl_flush_queues(cl);
+}
+EXPORT_SYMBOL(ishtp_cl_destroy_connection);
+
+/**
* ishtp_cl_read_start() - Prepare to read client message
* @cl: client device instance
*
diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h
index 166a76c9bcad..77c5fb26cd14 100644
--- a/drivers/hid/wacom.h
+++ b/drivers/hid/wacom.h
@@ -164,6 +164,7 @@ struct wacom {
struct work_struct battery_work;
struct work_struct remote_work;
struct delayed_work init_work;
+ struct delayed_work aes_battery_work;
struct wacom_remote *remote;
struct work_struct mode_change_work;
struct timer_list idleprox_timer;
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 3f704b8072e8..b613f11ed949 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -1813,6 +1813,13 @@ static void wacom_destroy_battery(struct wacom *wacom)
}
}
+static void wacom_aes_battery_handler(struct work_struct *work)
+{
+ struct wacom *wacom = container_of(work, struct wacom, aes_battery_work.work);
+
+ wacom_destroy_battery(wacom);
+}
+
static ssize_t wacom_show_speed(struct device *dev,
struct device_attribute
*attr, char *buf)
@@ -2794,6 +2801,7 @@ static int wacom_probe(struct hid_device *hdev,
mutex_init(&wacom->lock);
INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work);
+ INIT_DELAYED_WORK(&wacom->aes_battery_work, wacom_aes_battery_handler);
INIT_WORK(&wacom->wireless_work, wacom_wireless_work);
INIT_WORK(&wacom->battery_work, wacom_battery_work);
INIT_WORK(&wacom->remote_work, wacom_remote_work);
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 471db78dbbf0..da8a01fedd39 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -2528,11 +2528,12 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
struct input_dev *input = wacom_wac->pen_input;
bool range = wacom_wac->hid_data.inrange_state;
bool sense = wacom_wac->hid_data.sense_state;
+ bool entering_range = !wacom_wac->tool[0] && range;
if (wacom_wac->is_invalid_bt_frame)
return;
- if (!wacom_wac->tool[0] && range) { /* first in range */
+ if (entering_range) { /* first in range */
/* Going into range select tool */
if (wacom_wac->hid_data.invert_state)
wacom_wac->tool[0] = BTN_TOOL_RUBBER;
@@ -2583,6 +2584,15 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
input_sync(input);
}
+ /* Handle AES battery timeout behavior */
+ if (wacom_wac->features.quirks & WACOM_QUIRK_AESPEN) {
+ if (entering_range)
+ cancel_delayed_work(&wacom->aes_battery_work);
+ if (!sense)
+ schedule_delayed_work(&wacom->aes_battery_work,
+ msecs_to_jiffies(WACOM_AES_BATTERY_TIMEOUT));
+ }
+
if (!sense) {
wacom_wac->tool[0] = 0;
wacom_wac->id[0] = 0;
@@ -2649,8 +2659,8 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
{
struct hid_data *hid_data = &wacom_wac->hid_data;
bool mt = wacom_wac->features.touch_max > 1;
- bool prox = hid_data->tipswitch &&
- report_touch_events(wacom_wac);
+ bool touch_down = hid_data->tipswitch && hid_data->confidence;
+ bool prox = touch_down && report_touch_events(wacom_wac);
if (touch_is_muted(wacom_wac)) {
if (!wacom_wac->shared->touch_down)
@@ -2700,24 +2710,6 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
}
}
-static bool wacom_wac_slot_is_active(struct input_dev *dev, int key)
-{
- struct input_mt *mt = dev->mt;
- struct input_mt_slot *s;
-
- if (!mt)
- return false;
-
- for (s = mt->slots; s != mt->slots + mt->num_slots; s++) {
- if (s->key == key &&
- input_mt_get_value(s, ABS_MT_TRACKING_ID) >= 0) {
- return true;
- }
- }
-
- return false;
-}
-
static void wacom_wac_finger_event(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage, __s32 value)
{
@@ -2768,14 +2760,8 @@ static void wacom_wac_finger_event(struct hid_device *hdev,
}
if (usage->usage_index + 1 == field->report_count) {
- if (equivalent_usage == wacom_wac->hid_data.last_slot_field) {
- bool touch_removed = wacom_wac_slot_is_active(wacom_wac->touch_input,
- wacom_wac->hid_data.id) && !wacom_wac->hid_data.tipswitch;
-
- if (wacom_wac->hid_data.confidence || touch_removed) {
- wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
- }
- }
+ if (equivalent_usage == wacom_wac->hid_data.last_slot_field)
+ wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
}
}
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 57e185f18d53..e63b1e806e34 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -14,6 +14,7 @@
#define WACOM_MAX_REMOTES 5
#define WACOM_STATUS_UNKNOWN 255
#define WACOM_REMOTE_BATTERY_TIMEOUT 21000000000ll
+#define WACOM_AES_BATTERY_TIMEOUT 1800000
/* packet length for individual models */
#define WACOM_PKGLEN_BBFUN 9
diff --git a/drivers/hsi/controllers/omap_ssi_core.c b/drivers/hsi/controllers/omap_ssi_core.c
index 4c1a00f9929e..6802efb4d6cd 100644
--- a/drivers/hsi/controllers/omap_ssi_core.c
+++ b/drivers/hsi/controllers/omap_ssi_core.c
@@ -355,7 +355,7 @@ static int ssi_add_controller(struct hsi_controller *ssi,
if (!omap_ssi)
return -ENOMEM;
- err = ida_simple_get(&platform_omap_ssi_ida, 0, 0, GFP_KERNEL);
+ err = ida_alloc(&platform_omap_ssi_ida, GFP_KERNEL);
if (err < 0)
return err;
ssi->id = err;
@@ -417,7 +417,7 @@ static int ssi_add_controller(struct hsi_controller *ssi,
return 0;
out_err:
- ida_simple_remove(&platform_omap_ssi_ida, ssi->id);
+ ida_free(&platform_omap_ssi_ida, ssi->id);
return err;
}
@@ -451,7 +451,7 @@ static void ssi_remove_controller(struct hsi_controller *ssi)
tasklet_kill(&omap_ssi->gdd_tasklet);
hsi_unregister_controller(ssi);
clk_notifier_unregister(omap_ssi->fck, &omap_ssi->fck_nb);
- ida_simple_remove(&platform_omap_ssi_ida, id);
+ ida_free(&platform_omap_ssi_ida, id);
}
static inline int ssi_of_get_available_ports_count(const struct device_node *np)
diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c
index 4372f5d146ab..0285a74363b3 100644
--- a/drivers/hv/hv_common.c
+++ b/drivers/hv/hv_common.c
@@ -488,7 +488,7 @@ void hv_setup_dma_ops(struct device *dev, bool coherent)
* Hyper-V does not offer a vIOMMU in the guest
* VM, so pass 0/NULL for the IOMMU settings
*/
- arch_setup_dma_ops(dev, 0, 0, NULL, coherent);
+ arch_setup_dma_ops(dev, 0, 0, coherent);
}
EXPORT_SYMBOL_GPL(hv_setup_dma_ops);
diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c
index d9733da8ea34..904816abb7c4 100644
--- a/drivers/hwmon/npcm750-pwm-fan.c
+++ b/drivers/hwmon/npcm750-pwm-fan.c
@@ -195,6 +195,7 @@ struct npcm7xx_cooling_device {
struct npcm7xx_pwm_fan_data {
void __iomem *pwm_base;
void __iomem *fan_base;
+ int pwm_modules;
unsigned long pwm_clk_freq;
unsigned long fan_clk_freq;
struct clk *pwm_clk;
@@ -710,7 +711,7 @@ static u32 npcm7xx_pwm_init(struct npcm7xx_pwm_fan_data *data)
/* Setting PWM Prescale Register value register to both modules */
prescale_val |= (prescale_val << NPCM7XX_PWM_PRESCALE_SHIFT_CH01);
- for (m = 0; m < NPCM7XX_PWM_MAX_MODULES ; m++) {
+ for (m = 0; m < data->pwm_modules; m++) {
iowrite32(prescale_val, NPCM7XX_PWM_REG_PR(data->pwm_base, m));
iowrite32(NPCM7XX_PWM_PRESCALE2_DEFAULT,
NPCM7XX_PWM_REG_CSR(data->pwm_base, m));
@@ -946,6 +947,8 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev)
if (!data->info)
return -EINVAL;
+ data->pwm_modules = data->info->pwm_max_channel / NPCM7XX_PWM_MAX_CHN_NUM_IN_A_MODULE;
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm");
if (!res) {
dev_err(dev, "pwm resource not found\n");
@@ -983,7 +986,7 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev)
output_freq = npcm7xx_pwm_init(data);
npcm7xx_fan_init(data);
- for (cnt = 0; cnt < NPCM7XX_PWM_MAX_MODULES ; cnt++)
+ for (cnt = 0; cnt < data->pwm_modules; cnt++)
mutex_init(&data->pwm_lock[cnt]);
for (i = 0; i < NPCM7XX_FAN_MAX_MODULE; i++) {
diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
index 6e4516c2ab89..b67bc9e833c0 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -151,7 +151,7 @@ static int pwm_fan_power_on(struct pwm_fan_ctx *ctx)
}
state->enabled = true;
- ret = pwm_apply_state(ctx->pwm, state);
+ ret = pwm_apply_might_sleep(ctx->pwm, state);
if (ret) {
dev_err(ctx->dev, "failed to enable PWM\n");
goto disable_regulator;
@@ -181,7 +181,7 @@ static int pwm_fan_power_off(struct pwm_fan_ctx *ctx)
state->enabled = false;
state->duty_cycle = 0;
- ret = pwm_apply_state(ctx->pwm, state);
+ ret = pwm_apply_might_sleep(ctx->pwm, state);
if (ret) {
dev_err(ctx->dev, "failed to disable PWM\n");
return ret;
@@ -207,7 +207,7 @@ static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm)
period = state->period;
state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM);
- ret = pwm_apply_state(ctx->pwm, state);
+ ret = pwm_apply_might_sleep(ctx->pwm, state);
if (ret)
return ret;
ret = pwm_fan_power_on(ctx);
@@ -278,7 +278,7 @@ static int pwm_fan_update_enable(struct pwm_fan_ctx *ctx, long val)
state,
&enable_regulator);
- pwm_apply_state(ctx->pwm, state);
+ pwm_apply_might_sleep(ctx->pwm, state);
pwm_fan_switch_power(ctx, enable_regulator);
pwm_fan_update_state(ctx, 0);
}
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index ada694ba9f95..0c0a932c00f3 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -84,8 +84,9 @@ static DEFINE_MUTEX(hwspinlock_tree_lock);
* should decide between spin_trylock, spin_trylock_irq and
* spin_trylock_irqsave.
*
- * Returns 0 if we successfully locked the hwspinlock or -EBUSY if
+ * Returns: %0 if we successfully locked the hwspinlock or -EBUSY if
* the hwspinlock was already taken.
+ *
* This function will never sleep.
*/
int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
@@ -171,7 +172,7 @@ EXPORT_SYMBOL_GPL(__hwspin_trylock);
/**
* __hwspin_lock_timeout() - lock an hwspinlock with timeout limit
* @hwlock: the hwspinlock to be locked
- * @timeout: timeout value in msecs
+ * @to: timeout value in msecs
* @mode: mode which controls whether local interrupts are disabled or not
* @flags: a pointer to where the caller's interrupt state will be saved at (if
* requested)
@@ -199,9 +200,11 @@ EXPORT_SYMBOL_GPL(__hwspin_trylock);
* to choose the appropriate @mode of operation, exactly the same way users
* should decide between spin_lock, spin_lock_irq and spin_lock_irqsave.
*
- * Returns 0 when the @hwlock was successfully taken, and an appropriate
+ * Returns: %0 when the @hwlock was successfully taken, and an appropriate
* error code otherwise (most notably -ETIMEDOUT if the @hwlock is still
- * busy after @timeout msecs). The function will never sleep.
+ * busy after @timeout msecs).
+ *
+ * The function will never sleep.
*/
int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to,
int mode, unsigned long *flags)
@@ -304,13 +307,12 @@ EXPORT_SYMBOL_GPL(__hwspin_unlock);
/**
* of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id
- * @bank: the hwspinlock device bank
* @hwlock_spec: hwlock specifier as found in the device tree
*
* This is a simple translation function, suitable for hwspinlock platform
* drivers that only has a lock specifier length of 1.
*
- * Returns a relative index of the lock within a specified bank on success,
+ * Returns: a relative index of the lock within a specified bank on success,
* or -EINVAL on invalid specifier cell count.
*/
static inline int
@@ -332,9 +334,10 @@ of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec)
* hwspinlock device, so that it can be requested using the normal
* hwspin_lock_request_specific() API.
*
- * Returns the global lock id number on success, -EPROBE_DEFER if the hwspinlock
- * device is not yet registered, -EINVAL on invalid args specifier value or an
- * appropriate error as returned from the OF parsing of the DT client node.
+ * Returns: the global lock id number on success, -EPROBE_DEFER if the
+ * hwspinlock device is not yet registered, -EINVAL on invalid args
+ * specifier value or an appropriate error as returned from the OF parsing
+ * of the DT client node.
*/
int of_hwspin_lock_get_id(struct device_node *np, int index)
{
@@ -399,9 +402,10 @@ EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id);
* the hwspinlock device, so that it can be requested using the normal
* hwspin_lock_request_specific() API.
*
- * Returns the global lock id number on success, -EPROBE_DEFER if the hwspinlock
- * device is not yet registered, -EINVAL on invalid args specifier value or an
- * appropriate error as returned from the OF parsing of the DT client node.
+ * Returns: the global lock id number on success, -EPROBE_DEFER if the
+ * hwspinlock device is not yet registered, -EINVAL on invalid args
+ * specifier value or an appropriate error as returned from the OF parsing
+ * of the DT client node.
*/
int of_hwspin_lock_get_id_byname(struct device_node *np, const char *name)
{
@@ -481,7 +485,7 @@ out:
*
* Should be called from a process context (might sleep)
*
- * Returns 0 on success, or an appropriate error code on failure
+ * Returns: %0 on success, or an appropriate error code on failure
*/
int hwspin_lock_register(struct hwspinlock_device *bank, struct device *dev,
const struct hwspinlock_ops *ops, int base_id, int num_locks)
@@ -529,7 +533,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_register);
*
* Should be called from a process context (might sleep)
*
- * Returns 0 on success, or an appropriate error code on failure
+ * Returns: %0 on success, or an appropriate error code on failure
*/
int hwspin_lock_unregister(struct hwspinlock_device *bank)
{
@@ -578,7 +582,7 @@ static int devm_hwspin_lock_device_match(struct device *dev, void *res,
*
* Should be called from a process context (might sleep)
*
- * Returns 0 on success, or an appropriate error code on failure
+ * Returns: %0 on success, or an appropriate error code on failure
*/
int devm_hwspin_lock_unregister(struct device *dev,
struct hwspinlock_device *bank)
@@ -607,7 +611,7 @@ EXPORT_SYMBOL_GPL(devm_hwspin_lock_unregister);
*
* Should be called from a process context (might sleep)
*
- * Returns 0 on success, or an appropriate error code on failure
+ * Returns: %0 on success, or an appropriate error code on failure
*/
int devm_hwspin_lock_register(struct device *dev,
struct hwspinlock_device *bank,
@@ -635,12 +639,13 @@ EXPORT_SYMBOL_GPL(devm_hwspin_lock_register);
/**
* __hwspin_lock_request() - tag an hwspinlock as used and power it up
+ * @hwlock: the target hwspinlock
*
* This is an internal function that prepares an hwspinlock instance
* before it is given to the user. The function assumes that
* hwspinlock_tree_lock is taken.
*
- * Returns 0 or positive to indicate success, and a negative value to
+ * Returns: %0 or positive to indicate success, and a negative value to
* indicate an error (with the appropriate error code)
*/
static int __hwspin_lock_request(struct hwspinlock *hwlock)
@@ -680,7 +685,7 @@ static int __hwspin_lock_request(struct hwspinlock *hwlock)
* hwspin_lock_get_id() - retrieve id number of a given hwspinlock
* @hwlock: a valid hwspinlock instance
*
- * Returns the id number of a given @hwlock, or -EINVAL if @hwlock is invalid.
+ * Returns: the id number of a given @hwlock, or -EINVAL if @hwlock is invalid.
*/
int hwspin_lock_get_id(struct hwspinlock *hwlock)
{
@@ -704,7 +709,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_get_id);
*
* Should be called from a process context (might sleep)
*
- * Returns the address of the assigned hwspinlock, or NULL on error
+ * Returns: the address of the assigned hwspinlock, or %NULL on error
*/
struct hwspinlock *hwspin_lock_request(void)
{
@@ -747,7 +752,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_request);
*
* Should be called from a process context (might sleep)
*
- * Returns the address of the assigned hwspinlock, or NULL on error
+ * Returns: the address of the assigned hwspinlock, or %NULL on error
*/
struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
{
@@ -795,7 +800,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_request_specific);
*
* Should be called from a process context (might sleep)
*
- * Returns 0 on success, or an appropriate error code on failure
+ * Returns: %0 on success, or an appropriate error code on failure
*/
int hwspin_lock_free(struct hwspinlock *hwlock)
{
@@ -865,7 +870,7 @@ static void devm_hwspin_lock_release(struct device *dev, void *res)
*
* Should be called from a process context (might sleep)
*
- * Returns 0 on success, or an appropriate error code on failure
+ * Returns: %0 on success, or an appropriate error code on failure
*/
int devm_hwspin_lock_free(struct device *dev, struct hwspinlock *hwlock)
{
@@ -891,7 +896,7 @@ EXPORT_SYMBOL_GPL(devm_hwspin_lock_free);
*
* Should be called from a process context (might sleep)
*
- * Returns the address of the assigned hwspinlock, or NULL on error
+ * Returns: the address of the assigned hwspinlock, or %NULL on error
*/
struct hwspinlock *devm_hwspin_lock_request(struct device *dev)
{
@@ -926,7 +931,7 @@ EXPORT_SYMBOL_GPL(devm_hwspin_lock_request);
*
* Should be called from a process context (might sleep)
*
- * Returns the address of the assigned hwspinlock, or NULL on error
+ * Returns: the address of the assigned hwspinlock, or %NULL on error
*/
struct hwspinlock *devm_hwspin_lock_request_specific(struct device *dev,
unsigned int id)
diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c
index a0fd67fd2934..814dfe8697bf 100644
--- a/drivers/hwspinlock/qcom_hwspinlock.c
+++ b/drivers/hwspinlock/qcom_hwspinlock.c
@@ -115,7 +115,6 @@ static const struct of_device_id qcom_hwspinlock_of_match[] = {
{ .compatible = "qcom,sfpb-mutex", .data = &of_sfpb_mutex },
{ .compatible = "qcom,tcsr-mutex", .data = &of_tcsr_mutex },
{ .compatible = "qcom,apq8084-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
- { .compatible = "qcom,ipq6018-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
{ .compatible = "qcom,msm8226-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
{ .compatible = "qcom,msm8974-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
{ .compatible = "qcom,msm8994-tcsr-mutex", .data = &of_msm8226_tcsr_mutex },
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 9fabe00a40d6..d7f0e231feb9 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -1093,6 +1093,7 @@ static int coresight_validate_source(struct coresight_device *csdev,
if (subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_PROC &&
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE &&
+ subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM &&
subtype != CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS) {
dev_err(&csdev->dev, "wrong device subtype in %s\n", function);
return -EINVAL;
@@ -1162,6 +1163,7 @@ int coresight_enable(struct coresight_device *csdev)
per_cpu(tracer_path, cpu) = path;
break;
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
+ case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
/*
* Use the hash of source's device name as ID
@@ -1212,6 +1214,7 @@ void coresight_disable(struct coresight_device *csdev)
per_cpu(tracer_path, cpu) = NULL;
break;
case CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE:
+ case CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM:
case CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS:
hash = hashlen_hash(hashlen_string(NULL, dev_name(&csdev->dev)));
/* Find the path by the hash. */
diff --git a/drivers/hwtracing/coresight/coresight-dummy.c b/drivers/hwtracing/coresight/coresight-dummy.c
index e4deafae7bc2..ac70c0b491be 100644
--- a/drivers/hwtracing/coresight/coresight-dummy.c
+++ b/drivers/hwtracing/coresight/coresight-dummy.c
@@ -122,14 +122,13 @@ static int dummy_probe(struct platform_device *pdev)
return 0;
}
-static int dummy_remove(struct platform_device *pdev)
+static void dummy_remove(struct platform_device *pdev)
{
struct dummy_drvdata *drvdata = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
pm_runtime_disable(dev);
coresight_unregister(drvdata->csdev);
- return 0;
}
static const struct of_device_id dummy_match[] = {
@@ -140,7 +139,7 @@ static const struct of_device_id dummy_match[] = {
static struct platform_driver dummy_driver = {
.probe = dummy_probe,
- .remove = dummy_remove,
+ .remove_new = dummy_remove,
.driver = {
.name = "coresight-dummy",
.of_match_table = dummy_match,
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index 89e8ed214ea4..a52cfcce25d6 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -68,6 +68,7 @@ PMU_FORMAT_ATTR(preset, "config:0-3");
PMU_FORMAT_ATTR(sinkid, "config2:0-31");
/* config ID - set if a system configuration is selected */
PMU_FORMAT_ATTR(configid, "config2:32-63");
+PMU_FORMAT_ATTR(cc_threshold, "config3:0-11");
/*
@@ -101,6 +102,7 @@ static struct attribute *etm_config_formats_attr[] = {
&format_attr_preset.attr,
&format_attr_configid.attr,
&format_attr_branch_broadcast.attr,
+ &format_attr_cc_threshold.attr,
NULL,
};
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 34aee59dd147..ce1995a2827f 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -644,7 +644,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
struct etmv4_config *config = &drvdata->config;
struct perf_event_attr *attr = &event->attr;
unsigned long cfg_hash;
- int preset;
+ int preset, cc_threshold;
/* Clear configuration from previous run */
memset(config, 0, sizeof(struct etmv4_config));
@@ -667,7 +667,12 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
if (attr->config & BIT(ETM_OPT_CYCACC)) {
config->cfg |= TRCCONFIGR_CCI;
/* TRM: Must program this for cycacc to work */
- config->ccctlr = ETM_CYC_THRESHOLD_DEFAULT;
+ cc_threshold = attr->config3 & ETM_CYC_THRESHOLD_MASK;
+ if (!cc_threshold)
+ cc_threshold = ETM_CYC_THRESHOLD_DEFAULT;
+ if (cc_threshold < drvdata->ccitmin)
+ cc_threshold = drvdata->ccitmin;
+ config->ccctlr = cc_threshold;
}
if (attr->config & BIT(ETM_OPT_TS)) {
/*
@@ -1150,6 +1155,41 @@ static void cpu_detect_trace_filtering(struct etmv4_drvdata *drvdata)
drvdata->trfcr = trfcr;
}
+/*
+ * The following errata on applicable cpu ranges, affect the CCITMIN filed
+ * in TCRIDR3 register. Software read for the field returns 0x100 limiting
+ * the cycle threshold granularity, whereas the right value should have
+ * been 0x4, which is well supported in the hardware.
+ */
+static struct midr_range etm_wrong_ccitmin_cpus[] = {
+ /* Erratum #1490853 - Cortex-A76 */
+ MIDR_RANGE(MIDR_CORTEX_A76, 0, 0, 4, 0),
+ /* Erratum #1490853 - Neoverse-N1 */
+ MIDR_RANGE(MIDR_NEOVERSE_N1, 0, 0, 4, 0),
+ /* Erratum #1491015 - Cortex-A77 */
+ MIDR_RANGE(MIDR_CORTEX_A77, 0, 0, 1, 0),
+ /* Erratum #1502854 - Cortex-X1 */
+ MIDR_REV(MIDR_CORTEX_X1, 0, 0),
+ /* Erratum #1619801 - Neoverse-V1 */
+ MIDR_REV(MIDR_NEOVERSE_V1, 0, 0),
+ {},
+};
+
+static void etm4_fixup_wrong_ccitmin(struct etmv4_drvdata *drvdata)
+{
+ /*
+ * Erratum affected cpus will read 256 as the minimum
+ * instruction trace cycle counting threshold whereas
+ * the correct value should be 4 instead. Override the
+ * recorded value for 'drvdata->ccitmin' to workaround
+ * this problem.
+ */
+ if (is_midr_in_range_list(read_cpuid_id(), etm_wrong_ccitmin_cpus)) {
+ if (drvdata->ccitmin == 256)
+ drvdata->ccitmin = 4;
+ }
+}
+
static void etm4_init_arch_data(void *info)
{
u32 etmidr0;
@@ -1214,6 +1254,8 @@ static void etm4_init_arch_data(void *info)
etmidr3 = etm4x_relaxed_read32(csa, TRCIDR3);
/* CCITMIN, bits[11:0] minimum threshold value that can be programmed */
drvdata->ccitmin = FIELD_GET(TRCIDR3_CCITMIN_MASK, etmidr3);
+ etm4_fixup_wrong_ccitmin(drvdata);
+
/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
drvdata->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
drvdata->config.s_ex_level = drvdata->s_ex_level;
@@ -2261,7 +2303,7 @@ static void etm4_remove_amba(struct amba_device *adev)
etm4_remove_dev(drvdata);
}
-static int etm4_remove_platform_dev(struct platform_device *pdev)
+static void etm4_remove_platform_dev(struct platform_device *pdev)
{
struct etmv4_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
@@ -2271,8 +2313,6 @@ static int etm4_remove_platform_dev(struct platform_device *pdev)
if (drvdata && !IS_ERR_OR_NULL(drvdata->pclk))
clk_put(drvdata->pclk);
-
- return 0;
}
static const struct amba_id etm4_ids[] = {
@@ -2358,7 +2398,7 @@ MODULE_DEVICE_TABLE(acpi, etm4x_acpi_ids);
static struct platform_driver etm4_platform_driver = {
.probe = etm4_probe_platform_dev,
- .remove = etm4_remove_platform_dev,
+ .remove_new = etm4_remove_platform_dev,
.driver = {
.name = "coresight-etm4x",
.of_match_table = etm4_sysreg_match,
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 20e2e4cb7614..da17b6c49b0f 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -1036,7 +1036,7 @@ struct etmv4_drvdata {
u8 ctxid_size;
u8 vmid_size;
u8 ccsize;
- u8 ccitmin;
+ u16 ccitmin;
u8 s_ex_level;
u8 ns_ex_level;
u8 q_support;
diff --git a/drivers/hwtracing/coresight/coresight-funnel.c b/drivers/hwtracing/coresight/coresight-funnel.c
index b8e150e45b27..a5b1fc787766 100644
--- a/drivers/hwtracing/coresight/coresight-funnel.c
+++ b/drivers/hwtracing/coresight/coresight-funnel.c
@@ -335,11 +335,10 @@ static int static_funnel_probe(struct platform_device *pdev)
return ret;
}
-static int static_funnel_remove(struct platform_device *pdev)
+static void static_funnel_remove(struct platform_device *pdev)
{
funnel_remove(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- return 0;
}
static const struct of_device_id static_funnel_match[] = {
@@ -360,7 +359,7 @@ MODULE_DEVICE_TABLE(acpi, static_funnel_ids);
static struct platform_driver static_funnel_driver = {
.probe = static_funnel_probe,
- .remove = static_funnel_remove,
+ .remove_new = static_funnel_remove,
.driver = {
.name = "coresight-static-funnel",
/* THIS_MODULE is taken care of by platform_driver_register() */
diff --git a/drivers/hwtracing/coresight/coresight-replicator.c b/drivers/hwtracing/coresight/coresight-replicator.c
index b6be73034996..91d93060dda5 100644
--- a/drivers/hwtracing/coresight/coresight-replicator.c
+++ b/drivers/hwtracing/coresight/coresight-replicator.c
@@ -320,11 +320,10 @@ static int static_replicator_probe(struct platform_device *pdev)
return ret;
}
-static int static_replicator_remove(struct platform_device *pdev)
+static void static_replicator_remove(struct platform_device *pdev)
{
replicator_remove(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- return 0;
}
#ifdef CONFIG_PM
@@ -373,7 +372,7 @@ MODULE_DEVICE_TABLE(acpi, static_replicator_acpi_ids);
static struct platform_driver static_replicator_driver = {
.probe = static_replicator_probe,
- .remove = static_replicator_remove,
+ .remove_new = static_replicator_remove,
.driver = {
.name = "coresight-static-replicator",
/* THIS_MODULE is taken care of by platform_driver_register() */
diff --git a/drivers/hwtracing/coresight/coresight-tmc-core.c b/drivers/hwtracing/coresight/coresight-tmc-core.c
index c106d142e632..7ec5365e2b64 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-core.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-core.c
@@ -10,6 +10,7 @@
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/io.h>
+#include <linux/iommu.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
@@ -344,7 +345,14 @@ static const struct attribute_group coresight_tmc_mgmt_group = {
.name = "mgmt",
};
-static const struct attribute_group *coresight_tmc_groups[] = {
+static const struct attribute_group *coresight_etf_groups[] = {
+ &coresight_tmc_group,
+ &coresight_tmc_mgmt_group,
+ NULL,
+};
+
+static const struct attribute_group *coresight_etr_groups[] = {
+ &coresight_etr_group,
&coresight_tmc_group,
&coresight_tmc_mgmt_group,
NULL,
@@ -465,6 +473,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
drvdata->memwidth = tmc_get_memwidth(devid);
/* This device is not associated with a session */
drvdata->pid = -1;
+ drvdata->etr_mode = ETR_MODE_AUTO;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
drvdata->size = tmc_etr_get_default_buffer_size(dev);
@@ -474,16 +483,17 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
}
desc.dev = dev;
- desc.groups = coresight_tmc_groups;
switch (drvdata->config_type) {
case TMC_CONFIG_TYPE_ETB:
+ desc.groups = coresight_etf_groups;
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.ops = &tmc_etb_cs_ops;
dev_list = &etb_devs;
break;
case TMC_CONFIG_TYPE_ETR:
+ desc.groups = coresight_etr_groups;
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM;
desc.ops = &tmc_etr_cs_ops;
@@ -496,6 +506,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
dev_list = &etr_devs;
break;
case TMC_CONFIG_TYPE_ETF:
+ desc.groups = coresight_etf_groups;
desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c
index 8311e1028ddb..af02ba5d5f15 100644
--- a/drivers/hwtracing/coresight/coresight-tmc-etr.c
+++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c
@@ -26,6 +26,12 @@ struct etr_flat_buf {
size_t size;
};
+struct etr_buf_hw {
+ bool has_iommu;
+ bool has_etr_sg;
+ bool has_catu;
+};
+
/*
* etr_perf_buffer - Perf buffer used for ETR
* @drvdata - The ETR drvdaga this buffer has been allocated for.
@@ -830,6 +836,22 @@ static inline int tmc_etr_mode_alloc_buf(int mode,
}
}
+static void get_etr_buf_hw(struct device *dev, struct etr_buf_hw *buf_hw)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ buf_hw->has_iommu = iommu_get_domain_for_dev(dev->parent);
+ buf_hw->has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
+ buf_hw->has_catu = !!tmc_etr_get_catu_device(drvdata);
+}
+
+static bool etr_can_use_flat_mode(struct etr_buf_hw *buf_hw, ssize_t etr_buf_size)
+{
+ bool has_sg = buf_hw->has_catu || buf_hw->has_etr_sg;
+
+ return !has_sg || buf_hw->has_iommu || etr_buf_size < SZ_1M;
+}
+
/*
* tmc_alloc_etr_buf: Allocate a buffer use by ETR.
* @drvdata : ETR device details.
@@ -843,23 +865,22 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
int node, void **pages)
{
int rc = -ENOMEM;
- bool has_etr_sg, has_iommu;
- bool has_sg, has_catu;
struct etr_buf *etr_buf;
+ struct etr_buf_hw buf_hw;
struct device *dev = &drvdata->csdev->dev;
- has_etr_sg = tmc_etr_has_cap(drvdata, TMC_ETR_SG);
- has_iommu = iommu_get_domain_for_dev(dev->parent);
- has_catu = !!tmc_etr_get_catu_device(drvdata);
-
- has_sg = has_catu || has_etr_sg;
-
+ get_etr_buf_hw(dev, &buf_hw);
etr_buf = kzalloc(sizeof(*etr_buf), GFP_KERNEL);
if (!etr_buf)
return ERR_PTR(-ENOMEM);
etr_buf->size = size;
+ /* If there is user directive for buffer mode, try that first */
+ if (drvdata->etr_mode != ETR_MODE_AUTO)
+ rc = tmc_etr_mode_alloc_buf(drvdata->etr_mode, drvdata,
+ etr_buf, node, pages);
+
/*
* If we have to use an existing list of pages, we cannot reliably
* use a contiguous DMA memory (even if we have an IOMMU). Otherwise,
@@ -872,14 +893,13 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata,
* Fallback to available mechanisms.
*
*/
- if (!pages &&
- (!has_sg || has_iommu || size < SZ_1M))
+ if (rc && !pages && etr_can_use_flat_mode(&buf_hw, size))
rc = tmc_etr_mode_alloc_buf(ETR_MODE_FLAT, drvdata,
etr_buf, node, pages);
- if (rc && has_etr_sg)
+ if (rc && buf_hw.has_etr_sg)
rc = tmc_etr_mode_alloc_buf(ETR_MODE_ETR_SG, drvdata,
etr_buf, node, pages);
- if (rc && has_catu)
+ if (rc && buf_hw.has_catu)
rc = tmc_etr_mode_alloc_buf(ETR_MODE_CATU, drvdata,
etr_buf, node, pages);
if (rc) {
@@ -1804,3 +1824,70 @@ int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata)
return 0;
}
+
+static const char *const buf_modes_str[] = {
+ [ETR_MODE_FLAT] = "flat",
+ [ETR_MODE_ETR_SG] = "tmc-sg",
+ [ETR_MODE_CATU] = "catu",
+ [ETR_MODE_AUTO] = "auto",
+};
+
+static ssize_t buf_modes_available_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct etr_buf_hw buf_hw;
+ ssize_t size = 0;
+
+ get_etr_buf_hw(dev, &buf_hw);
+ size += sysfs_emit(buf, "%s ", buf_modes_str[ETR_MODE_AUTO]);
+ size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_FLAT]);
+ if (buf_hw.has_etr_sg)
+ size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_ETR_SG]);
+
+ if (buf_hw.has_catu)
+ size += sysfs_emit_at(buf, size, "%s ", buf_modes_str[ETR_MODE_CATU]);
+
+ size += sysfs_emit_at(buf, size, "\n");
+ return size;
+}
+static DEVICE_ATTR_RO(buf_modes_available);
+
+static ssize_t buf_mode_preferred_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%s\n", buf_modes_str[drvdata->etr_mode]);
+}
+
+static ssize_t buf_mode_preferred_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct etr_buf_hw buf_hw;
+
+ get_etr_buf_hw(dev, &buf_hw);
+ if (sysfs_streq(buf, buf_modes_str[ETR_MODE_FLAT]))
+ drvdata->etr_mode = ETR_MODE_FLAT;
+ else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_ETR_SG]) && buf_hw.has_etr_sg)
+ drvdata->etr_mode = ETR_MODE_ETR_SG;
+ else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_CATU]) && buf_hw.has_catu)
+ drvdata->etr_mode = ETR_MODE_CATU;
+ else if (sysfs_streq(buf, buf_modes_str[ETR_MODE_AUTO]))
+ drvdata->etr_mode = ETR_MODE_AUTO;
+ else
+ return -EINVAL;
+ return size;
+}
+static DEVICE_ATTR_RW(buf_mode_preferred);
+
+static struct attribute *coresight_etr_attrs[] = {
+ &dev_attr_buf_modes_available.attr,
+ &dev_attr_buf_mode_preferred.attr,
+ NULL,
+};
+
+const struct attribute_group coresight_etr_group = {
+ .attrs = coresight_etr_attrs,
+};
diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h
index 0ee48c5ba764..8dcb426ac3e7 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.h
+++ b/drivers/hwtracing/coresight/coresight-tmc.h
@@ -135,6 +135,7 @@ enum etr_mode {
ETR_MODE_FLAT, /* Uses contiguous flat buffer */
ETR_MODE_ETR_SG, /* Uses in-built TMC ETR SG mechanism */
ETR_MODE_CATU, /* Use SG mechanism in CATU */
+ ETR_MODE_AUTO, /* Use the default mechanism */
};
struct etr_buf_operations;
@@ -207,6 +208,7 @@ struct tmc_drvdata {
enum tmc_mem_intf_width memwidth;
u32 trigger_cntr;
u32 etr_caps;
+ enum etr_mode etr_mode;
struct idr idr;
struct mutex idr_mutex;
struct etr_buf *sysfs_buf;
@@ -334,5 +336,6 @@ void tmc_etr_set_catu_ops(const struct etr_buf_operations *catu);
void tmc_etr_remove_catu_ops(void);
struct etr_buf *tmc_etr_get_buffer(struct coresight_device *csdev,
enum cs_mode mode, void *data);
+extern const struct attribute_group coresight_etr_group;
#endif
diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c
index 8d2b9d29237d..5f82737c37bb 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.c
+++ b/drivers/hwtracing/coresight/coresight-tpda.c
@@ -21,6 +21,80 @@
DEFINE_CORESIGHT_DEVLIST(tpda_devs, "tpda");
+static bool coresight_device_is_tpdm(struct coresight_device *csdev)
+{
+ return (csdev->type == CORESIGHT_DEV_TYPE_SOURCE) &&
+ (csdev->subtype.source_subtype ==
+ CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM);
+}
+
+/*
+ * Read the DSB element size from the TPDM device
+ * Returns
+ * The dsb element size read from the devicetree if available.
+ * 0 - Otherwise, with a warning once.
+ */
+static int tpdm_read_dsb_element_size(struct coresight_device *csdev)
+{
+ int rc = 0;
+ u8 size = 0;
+
+ rc = fwnode_property_read_u8(dev_fwnode(csdev->dev.parent),
+ "qcom,dsb-element-size", &size);
+ if (rc)
+ dev_warn_once(&csdev->dev,
+ "Failed to read TPDM DSB Element size: %d\n", rc);
+
+ return size;
+}
+
+/*
+ * Search and read element data size from the TPDM node in
+ * the devicetree. Each input port of TPDA is connected to
+ * a TPDM. Different TPDM supports different types of dataset,
+ * and some may support more than one type of dataset.
+ * Parameter "inport" is used to pass in the input port number
+ * of TPDA, and it is set to -1 in the recursize call.
+ */
+static int tpda_get_element_size(struct coresight_device *csdev,
+ int inport)
+{
+ int dsb_size = -ENOENT;
+ int i, size;
+ struct coresight_device *in;
+
+ for (i = 0; i < csdev->pdata->nr_inconns; i++) {
+ in = csdev->pdata->in_conns[i]->src_dev;
+ if (!in)
+ continue;
+
+ /* Ignore the paths that do not match port */
+ if (inport > 0 &&
+ csdev->pdata->in_conns[i]->dest_port != inport)
+ continue;
+
+ if (coresight_device_is_tpdm(in)) {
+ size = tpdm_read_dsb_element_size(in);
+ } else {
+ /* Recurse down the path */
+ size = tpda_get_element_size(in, -1);
+ }
+
+ if (size < 0)
+ return size;
+
+ if (dsb_size < 0) {
+ /* Found a size, save it. */
+ dsb_size = size;
+ } else {
+ /* Found duplicate TPDMs */
+ return -EEXIST;
+ }
+ }
+
+ return dsb_size;
+}
+
/* Settings pre enabling port control register */
static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
{
@@ -32,26 +106,55 @@ static void tpda_enable_pre_port(struct tpda_drvdata *drvdata)
writel_relaxed(val, drvdata->base + TPDA_CR);
}
-static void tpda_enable_port(struct tpda_drvdata *drvdata, int port)
+static int tpda_enable_port(struct tpda_drvdata *drvdata, int port)
{
u32 val;
+ int size;
val = readl_relaxed(drvdata->base + TPDA_Pn_CR(port));
+ /*
+ * Configure aggregator port n DSB data set element size
+ * Set the bit to 0 if the size is 32
+ * Set the bit to 1 if the size is 64
+ */
+ size = tpda_get_element_size(drvdata->csdev, port);
+ switch (size) {
+ case 32:
+ val &= ~TPDA_Pn_CR_DSBSIZE;
+ break;
+ case 64:
+ val |= TPDA_Pn_CR_DSBSIZE;
+ break;
+ case 0:
+ return -EEXIST;
+ case -EEXIST:
+ dev_warn_once(&drvdata->csdev->dev,
+ "Detected multiple TPDMs on port %d", -EEXIST);
+ return -EEXIST;
+ default:
+ return -EINVAL;
+ }
+
/* Enable the port */
val |= TPDA_Pn_CR_ENA;
writel_relaxed(val, drvdata->base + TPDA_Pn_CR(port));
+
+ return 0;
}
-static void __tpda_enable(struct tpda_drvdata *drvdata, int port)
+static int __tpda_enable(struct tpda_drvdata *drvdata, int port)
{
+ int ret;
+
CS_UNLOCK(drvdata->base);
if (!drvdata->csdev->enable)
tpda_enable_pre_port(drvdata);
- tpda_enable_port(drvdata, port);
-
+ ret = tpda_enable_port(drvdata, port);
CS_LOCK(drvdata->base);
+
+ return ret;
}
static int tpda_enable(struct coresight_device *csdev,
@@ -59,16 +162,19 @@ static int tpda_enable(struct coresight_device *csdev,
struct coresight_connection *out)
{
struct tpda_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ int ret = 0;
spin_lock(&drvdata->spinlock);
- if (atomic_read(&in->dest_refcnt) == 0)
- __tpda_enable(drvdata, in->dest_port);
+ if (atomic_read(&in->dest_refcnt) == 0) {
+ ret = __tpda_enable(drvdata, in->dest_port);
+ if (!ret) {
+ atomic_inc(&in->dest_refcnt);
+ dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
+ }
+ }
- atomic_inc(&in->dest_refcnt);
spin_unlock(&drvdata->spinlock);
-
- dev_dbg(drvdata->dev, "TPDA inport %d enabled.\n", in->dest_port);
- return 0;
+ return ret;
}
static void __tpda_disable(struct tpda_drvdata *drvdata, int port)
diff --git a/drivers/hwtracing/coresight/coresight-tpda.h b/drivers/hwtracing/coresight/coresight-tpda.h
index 0399678df312..b3b38fd41b64 100644
--- a/drivers/hwtracing/coresight/coresight-tpda.h
+++ b/drivers/hwtracing/coresight/coresight-tpda.h
@@ -10,6 +10,8 @@
#define TPDA_Pn_CR(n) (0x004 + (n * 4))
/* Aggregator port enable bit */
#define TPDA_Pn_CR_ENA BIT(0)
+/* Aggregator port DSB data set element size bit */
+#define TPDA_Pn_CR_DSBSIZE BIT(8)
#define TPDA_MAX_INPORTS 32
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c
index f4854af0431e..97654aa4b772 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.c
+++ b/drivers/hwtracing/coresight/coresight-tpdm.c
@@ -4,6 +4,7 @@
*/
#include <linux/amba/bus.h>
+#include <linux/bitfield.h>
#include <linux/bitmap.h>
#include <linux/coresight.h>
#include <linux/coresight-pmu.h>
@@ -20,23 +21,265 @@
DEFINE_CORESIGHT_DEVLIST(tpdm_devs, "tpdm");
-static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
+/* Read dataset array member with the index number */
+static ssize_t tpdm_simple_dataset_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct tpdm_dataset_attribute *tpdm_attr =
+ container_of(attr, struct tpdm_dataset_attribute, attr);
+
+ switch (tpdm_attr->mem) {
+ case DSB_EDGE_CTRL:
+ if (tpdm_attr->idx >= TPDM_DSB_MAX_EDCR)
+ return -EINVAL;
+ return sysfs_emit(buf, "0x%x\n",
+ drvdata->dsb->edge_ctrl[tpdm_attr->idx]);
+ case DSB_EDGE_CTRL_MASK:
+ if (tpdm_attr->idx >= TPDM_DSB_MAX_EDCMR)
+ return -EINVAL;
+ return sysfs_emit(buf, "0x%x\n",
+ drvdata->dsb->edge_ctrl_mask[tpdm_attr->idx]);
+ case DSB_TRIG_PATT:
+ if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)
+ return -EINVAL;
+ return sysfs_emit(buf, "0x%x\n",
+ drvdata->dsb->trig_patt[tpdm_attr->idx]);
+ case DSB_TRIG_PATT_MASK:
+ if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)
+ return -EINVAL;
+ return sysfs_emit(buf, "0x%x\n",
+ drvdata->dsb->trig_patt_mask[tpdm_attr->idx]);
+ case DSB_PATT:
+ if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)
+ return -EINVAL;
+ return sysfs_emit(buf, "0x%x\n",
+ drvdata->dsb->patt_val[tpdm_attr->idx]);
+ case DSB_PATT_MASK:
+ if (tpdm_attr->idx >= TPDM_DSB_MAX_PATT)
+ return -EINVAL;
+ return sysfs_emit(buf, "0x%x\n",
+ drvdata->dsb->patt_mask[tpdm_attr->idx]);
+ case DSB_MSR:
+ if (tpdm_attr->idx >= drvdata->dsb_msr_num)
+ return -EINVAL;
+ return sysfs_emit(buf, "0x%x\n",
+ drvdata->dsb->msr[tpdm_attr->idx]);
+ }
+ return -EINVAL;
+}
+
+/* Write dataset array member with the index number */
+static ssize_t tpdm_simple_dataset_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ unsigned long val;
+ ssize_t ret = size;
+
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct tpdm_dataset_attribute *tpdm_attr =
+ container_of(attr, struct tpdm_dataset_attribute, attr);
+
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ switch (tpdm_attr->mem) {
+ case DSB_TRIG_PATT:
+ if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
+ drvdata->dsb->trig_patt[tpdm_attr->idx] = val;
+ else
+ ret = -EINVAL;
+ break;
+ case DSB_TRIG_PATT_MASK:
+ if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
+ drvdata->dsb->trig_patt_mask[tpdm_attr->idx] = val;
+ else
+ ret = -EINVAL;
+ break;
+ case DSB_PATT:
+ if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
+ drvdata->dsb->patt_val[tpdm_attr->idx] = val;
+ else
+ ret = -EINVAL;
+ break;
+ case DSB_PATT_MASK:
+ if (tpdm_attr->idx < TPDM_DSB_MAX_PATT)
+ drvdata->dsb->patt_mask[tpdm_attr->idx] = val;
+ else
+ ret = -EINVAL;
+ break;
+ case DSB_MSR:
+ if (tpdm_attr->idx < drvdata->dsb_msr_num)
+ drvdata->dsb->msr[tpdm_attr->idx] = val;
+ else
+ ret = -EINVAL;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ spin_unlock(&drvdata->spinlock);
+
+ return ret;
+}
+
+static bool tpdm_has_dsb_dataset(struct tpdm_drvdata *drvdata)
+{
+ return (drvdata->datasets & TPDM_PIDR0_DS_DSB);
+}
+
+static umode_t tpdm_dsb_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ if (drvdata && tpdm_has_dsb_dataset(drvdata))
+ return attr->mode;
+
+ return 0;
+}
+
+static umode_t tpdm_dsb_msr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ struct device_attribute *dev_attr =
+ container_of(attr, struct device_attribute, attr);
+ struct tpdm_dataset_attribute *tpdm_attr =
+ container_of(dev_attr, struct tpdm_dataset_attribute, attr);
+
+ if (tpdm_attr->idx < drvdata->dsb_msr_num)
+ return attr->mode;
+
+ return 0;
+}
+
+static void tpdm_reset_datasets(struct tpdm_drvdata *drvdata)
+{
+ if (tpdm_has_dsb_dataset(drvdata)) {
+ memset(drvdata->dsb, 0, sizeof(struct dsb_dataset));
+
+ drvdata->dsb->trig_ts = true;
+ drvdata->dsb->trig_type = false;
+ }
+}
+
+static void set_dsb_mode(struct tpdm_drvdata *drvdata, u32 *val)
+{
+ u32 mode;
+
+ /* Set the test accurate mode */
+ mode = TPDM_DSB_MODE_TEST(drvdata->dsb->mode);
+ *val &= ~TPDM_DSB_CR_TEST_MODE;
+ *val |= FIELD_PREP(TPDM_DSB_CR_TEST_MODE, mode);
+
+ /* Set the byte lane for high-performance mode */
+ mode = TPDM_DSB_MODE_HPBYTESEL(drvdata->dsb->mode);
+ *val &= ~TPDM_DSB_CR_HPSEL;
+ *val |= FIELD_PREP(TPDM_DSB_CR_HPSEL, mode);
+
+ /* Set the performance mode */
+ if (drvdata->dsb->mode & TPDM_DSB_MODE_PERF)
+ *val |= TPDM_DSB_CR_MODE;
+ else
+ *val &= ~TPDM_DSB_CR_MODE;
+}
+
+static void set_dsb_tier(struct tpdm_drvdata *drvdata)
{
u32 val;
- /* Set the enable bit of DSB control register to 1 */
+ val = readl_relaxed(drvdata->base + TPDM_DSB_TIER);
+
+ /* Clear all relevant fields */
+ val &= ~(TPDM_DSB_TIER_PATT_TSENAB | TPDM_DSB_TIER_PATT_TYPE |
+ TPDM_DSB_TIER_XTRIG_TSENAB);
+
+ /* Set pattern timestamp type and enablement */
+ if (drvdata->dsb->patt_ts) {
+ val |= TPDM_DSB_TIER_PATT_TSENAB;
+ if (drvdata->dsb->patt_type)
+ val |= TPDM_DSB_TIER_PATT_TYPE;
+ else
+ val &= ~TPDM_DSB_TIER_PATT_TYPE;
+ } else {
+ val &= ~TPDM_DSB_TIER_PATT_TSENAB;
+ }
+
+ /* Set trigger timestamp */
+ if (drvdata->dsb->trig_ts)
+ val |= TPDM_DSB_TIER_XTRIG_TSENAB;
+ else
+ val &= ~TPDM_DSB_TIER_XTRIG_TSENAB;
+
+ writel_relaxed(val, drvdata->base + TPDM_DSB_TIER);
+}
+
+static void set_dsb_msr(struct tpdm_drvdata *drvdata)
+{
+ int i;
+
+ for (i = 0; i < drvdata->dsb_msr_num; i++)
+ writel_relaxed(drvdata->dsb->msr[i],
+ drvdata->base + TPDM_DSB_MSR(i));
+}
+
+static void tpdm_enable_dsb(struct tpdm_drvdata *drvdata)
+{
+ u32 val, i;
+
+ for (i = 0; i < TPDM_DSB_MAX_EDCR; i++)
+ writel_relaxed(drvdata->dsb->edge_ctrl[i],
+ drvdata->base + TPDM_DSB_EDCR(i));
+ for (i = 0; i < TPDM_DSB_MAX_EDCMR; i++)
+ writel_relaxed(drvdata->dsb->edge_ctrl_mask[i],
+ drvdata->base + TPDM_DSB_EDCMR(i));
+ for (i = 0; i < TPDM_DSB_MAX_PATT; i++) {
+ writel_relaxed(drvdata->dsb->patt_val[i],
+ drvdata->base + TPDM_DSB_TPR(i));
+ writel_relaxed(drvdata->dsb->patt_mask[i],
+ drvdata->base + TPDM_DSB_TPMR(i));
+ writel_relaxed(drvdata->dsb->trig_patt[i],
+ drvdata->base + TPDM_DSB_XPR(i));
+ writel_relaxed(drvdata->dsb->trig_patt_mask[i],
+ drvdata->base + TPDM_DSB_XPMR(i));
+ }
+
+ set_dsb_tier(drvdata);
+
+ set_dsb_msr(drvdata);
+
val = readl_relaxed(drvdata->base + TPDM_DSB_CR);
+ /* Set the mode of DSB dataset */
+ set_dsb_mode(drvdata, &val);
+ /* Set trigger type */
+ if (drvdata->dsb->trig_type)
+ val |= TPDM_DSB_CR_TRIG_TYPE;
+ else
+ val &= ~TPDM_DSB_CR_TRIG_TYPE;
+ /* Set the enable bit of DSB control register to 1 */
val |= TPDM_DSB_CR_ENA;
writel_relaxed(val, drvdata->base + TPDM_DSB_CR);
}
-/* TPDM enable operations */
+/*
+ * TPDM enable operations
+ * The TPDM or Monitor serves as data collection component for various
+ * dataset types. It covers Basic Counts(BC), Tenure Counts(TC),
+ * Continuous Multi-Bit(CMB), Multi-lane CMB(MCMB) and Discrete Single
+ * Bit(DSB). This function will initialize the configuration according
+ * to the dataset type supported by the TPDM.
+ */
static void __tpdm_enable(struct tpdm_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
- /* Check if DSB datasets is present for TPDM. */
- if (drvdata->datasets & TPDM_PIDR0_DS_DSB)
+ if (tpdm_has_dsb_dataset(drvdata))
tpdm_enable_dsb(drvdata);
CS_LOCK(drvdata->base);
@@ -76,8 +319,7 @@ static void __tpdm_disable(struct tpdm_drvdata *drvdata)
{
CS_UNLOCK(drvdata->base);
- /* Check if DSB datasets is present for TPDM. */
- if (drvdata->datasets & TPDM_PIDR0_DS_DSB)
+ if (tpdm_has_dsb_dataset(drvdata))
tpdm_disable_dsb(drvdata);
CS_LOCK(drvdata->base);
@@ -110,16 +352,45 @@ static const struct coresight_ops tpdm_cs_ops = {
.source_ops = &tpdm_source_ops,
};
-static void tpdm_init_default_data(struct tpdm_drvdata *drvdata)
+static int tpdm_datasets_setup(struct tpdm_drvdata *drvdata)
{
u32 pidr;
- CS_UNLOCK(drvdata->base);
/* Get the datasets present on the TPDM. */
pidr = readl_relaxed(drvdata->base + CORESIGHT_PERIPHIDR0);
drvdata->datasets |= pidr & GENMASK(TPDM_DATASETS - 1, 0);
- CS_LOCK(drvdata->base);
+
+ if (tpdm_has_dsb_dataset(drvdata) && (!drvdata->dsb)) {
+ drvdata->dsb = devm_kzalloc(drvdata->dev,
+ sizeof(*drvdata->dsb), GFP_KERNEL);
+ if (!drvdata->dsb)
+ return -ENOMEM;
+ }
+ tpdm_reset_datasets(drvdata);
+
+ return 0;
+}
+
+static ssize_t reset_dataset_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ int ret = 0;
+ unsigned long val;
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret || val != 1)
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ tpdm_reset_datasets(drvdata);
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
}
+static DEVICE_ATTR_WO(reset_dataset);
/*
* value 1: 64 bits test data
@@ -161,6 +432,7 @@ static ssize_t integration_test_store(struct device *dev,
static DEVICE_ATTR_WO(integration_test);
static struct attribute *tpdm_attrs[] = {
+ &dev_attr_reset_dataset.attr,
&dev_attr_integration_test.attr,
NULL,
};
@@ -169,8 +441,421 @@ static struct attribute_group tpdm_attr_grp = {
.attrs = tpdm_attrs,
};
+static ssize_t dsb_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%x\n", drvdata->dsb->mode);
+}
+
+static ssize_t dsb_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if ((kstrtoul(buf, 0, &val)) || (val < 0) ||
+ (val & ~TPDM_DSB_MODE_MASK))
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ drvdata->dsb->mode = val & TPDM_DSB_MODE_MASK;
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR_RW(dsb_mode);
+
+static ssize_t ctrl_idx_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%u\n",
+ (unsigned int)drvdata->dsb->edge_ctrl_idx);
+}
+
+/*
+ * The EDCR registers can include up to 16 32-bit registers, and each
+ * one can be configured to control up to 16 edge detections(2 bits
+ * control one edge detection). So a total 256 edge detections can be
+ * configured. This function provides a way to set the index number of
+ * the edge detection which needs to be configured.
+ */
+static ssize_t ctrl_idx_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if ((kstrtoul(buf, 0, &val)) || (val >= TPDM_DSB_MAX_LINES))
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ drvdata->dsb->edge_ctrl_idx = val;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_RW(ctrl_idx);
+
+/*
+ * This function is used to control the edge detection according
+ * to the index number that has been set.
+ * "edge_ctrl" should be one of the following values.
+ * 0 - Rising edge detection
+ * 1 - Falling edge detection
+ * 2 - Rising and falling edge detection (toggle detection)
+ */
+static ssize_t ctrl_val_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val, edge_ctrl;
+ int reg;
+
+ if ((kstrtoul(buf, 0, &edge_ctrl)) || (edge_ctrl > 0x2))
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ /*
+ * There are 2 bit per DSB Edge Control line.
+ * Thus we have 16 lines in a 32bit word.
+ */
+ reg = EDCR_TO_WORD_IDX(drvdata->dsb->edge_ctrl_idx);
+ val = drvdata->dsb->edge_ctrl[reg];
+ val &= ~EDCR_TO_WORD_MASK(drvdata->dsb->edge_ctrl_idx);
+ val |= EDCR_TO_WORD_VAL(edge_ctrl, drvdata->dsb->edge_ctrl_idx);
+ drvdata->dsb->edge_ctrl[reg] = val;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_WO(ctrl_val);
+
+static ssize_t ctrl_mask_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+ u32 set;
+ int reg;
+
+ if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ /*
+ * There is 1 bit per DSB Edge Control Mark line.
+ * Thus we have 32 lines in a 32bit word.
+ */
+ reg = EDCMR_TO_WORD_IDX(drvdata->dsb->edge_ctrl_idx);
+ set = drvdata->dsb->edge_ctrl_mask[reg];
+ if (val)
+ set |= BIT(EDCMR_TO_WORD_SHIFT(drvdata->dsb->edge_ctrl_idx));
+ else
+ set &= ~BIT(EDCMR_TO_WORD_SHIFT(drvdata->dsb->edge_ctrl_idx));
+ drvdata->dsb->edge_ctrl_mask[reg] = set;
+ spin_unlock(&drvdata->spinlock);
+
+ return size;
+}
+static DEVICE_ATTR_WO(ctrl_mask);
+
+static ssize_t enable_ts_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%u\n",
+ (unsigned int)drvdata->dsb->patt_ts);
+}
+
+/*
+ * value 1: Enable/Disable DSB pattern timestamp
+ */
+static ssize_t enable_ts_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ drvdata->dsb->patt_ts = !!val;
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR_RW(enable_ts);
+
+static ssize_t set_type_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%u\n",
+ (unsigned int)drvdata->dsb->patt_type);
+}
+
+/*
+ * value 1: Set DSB pattern type
+ */
+static ssize_t set_type_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ drvdata->dsb->patt_type = val;
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR_RW(set_type);
+
+static ssize_t dsb_trig_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%u\n",
+ (unsigned int)drvdata->dsb->trig_type);
+}
+
+/*
+ * Trigger type (boolean):
+ * false - Disable trigger type.
+ * true - Enable trigger type.
+ */
+static ssize_t dsb_trig_type_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ if (val)
+ drvdata->dsb->trig_type = true;
+ else
+ drvdata->dsb->trig_type = false;
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR_RW(dsb_trig_type);
+
+static ssize_t dsb_trig_ts_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+
+ return sysfs_emit(buf, "%u\n",
+ (unsigned int)drvdata->dsb->trig_ts);
+}
+
+/*
+ * Trigger timestamp (boolean):
+ * false - Disable trigger timestamp.
+ * true - Enable trigger timestamp.
+ */
+static ssize_t dsb_trig_ts_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t size)
+{
+ struct tpdm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ unsigned long val;
+
+ if ((kstrtoul(buf, 0, &val)) || (val & ~1UL))
+ return -EINVAL;
+
+ spin_lock(&drvdata->spinlock);
+ if (val)
+ drvdata->dsb->trig_ts = true;
+ else
+ drvdata->dsb->trig_ts = false;
+ spin_unlock(&drvdata->spinlock);
+ return size;
+}
+static DEVICE_ATTR_RW(dsb_trig_ts);
+
+static struct attribute *tpdm_dsb_edge_attrs[] = {
+ &dev_attr_ctrl_idx.attr,
+ &dev_attr_ctrl_val.attr,
+ &dev_attr_ctrl_mask.attr,
+ DSB_EDGE_CTRL_ATTR(0),
+ DSB_EDGE_CTRL_ATTR(1),
+ DSB_EDGE_CTRL_ATTR(2),
+ DSB_EDGE_CTRL_ATTR(3),
+ DSB_EDGE_CTRL_ATTR(4),
+ DSB_EDGE_CTRL_ATTR(5),
+ DSB_EDGE_CTRL_ATTR(6),
+ DSB_EDGE_CTRL_ATTR(7),
+ DSB_EDGE_CTRL_ATTR(8),
+ DSB_EDGE_CTRL_ATTR(9),
+ DSB_EDGE_CTRL_ATTR(10),
+ DSB_EDGE_CTRL_ATTR(11),
+ DSB_EDGE_CTRL_ATTR(12),
+ DSB_EDGE_CTRL_ATTR(13),
+ DSB_EDGE_CTRL_ATTR(14),
+ DSB_EDGE_CTRL_ATTR(15),
+ DSB_EDGE_CTRL_MASK_ATTR(0),
+ DSB_EDGE_CTRL_MASK_ATTR(1),
+ DSB_EDGE_CTRL_MASK_ATTR(2),
+ DSB_EDGE_CTRL_MASK_ATTR(3),
+ DSB_EDGE_CTRL_MASK_ATTR(4),
+ DSB_EDGE_CTRL_MASK_ATTR(5),
+ DSB_EDGE_CTRL_MASK_ATTR(6),
+ DSB_EDGE_CTRL_MASK_ATTR(7),
+ NULL,
+};
+
+static struct attribute *tpdm_dsb_trig_patt_attrs[] = {
+ DSB_TRIG_PATT_ATTR(0),
+ DSB_TRIG_PATT_ATTR(1),
+ DSB_TRIG_PATT_ATTR(2),
+ DSB_TRIG_PATT_ATTR(3),
+ DSB_TRIG_PATT_ATTR(4),
+ DSB_TRIG_PATT_ATTR(5),
+ DSB_TRIG_PATT_ATTR(6),
+ DSB_TRIG_PATT_ATTR(7),
+ DSB_TRIG_PATT_MASK_ATTR(0),
+ DSB_TRIG_PATT_MASK_ATTR(1),
+ DSB_TRIG_PATT_MASK_ATTR(2),
+ DSB_TRIG_PATT_MASK_ATTR(3),
+ DSB_TRIG_PATT_MASK_ATTR(4),
+ DSB_TRIG_PATT_MASK_ATTR(5),
+ DSB_TRIG_PATT_MASK_ATTR(6),
+ DSB_TRIG_PATT_MASK_ATTR(7),
+ NULL,
+};
+
+static struct attribute *tpdm_dsb_patt_attrs[] = {
+ DSB_PATT_ATTR(0),
+ DSB_PATT_ATTR(1),
+ DSB_PATT_ATTR(2),
+ DSB_PATT_ATTR(3),
+ DSB_PATT_ATTR(4),
+ DSB_PATT_ATTR(5),
+ DSB_PATT_ATTR(6),
+ DSB_PATT_ATTR(7),
+ DSB_PATT_MASK_ATTR(0),
+ DSB_PATT_MASK_ATTR(1),
+ DSB_PATT_MASK_ATTR(2),
+ DSB_PATT_MASK_ATTR(3),
+ DSB_PATT_MASK_ATTR(4),
+ DSB_PATT_MASK_ATTR(5),
+ DSB_PATT_MASK_ATTR(6),
+ DSB_PATT_MASK_ATTR(7),
+ &dev_attr_enable_ts.attr,
+ &dev_attr_set_type.attr,
+ NULL,
+};
+
+static struct attribute *tpdm_dsb_msr_attrs[] = {
+ DSB_MSR_ATTR(0),
+ DSB_MSR_ATTR(1),
+ DSB_MSR_ATTR(2),
+ DSB_MSR_ATTR(3),
+ DSB_MSR_ATTR(4),
+ DSB_MSR_ATTR(5),
+ DSB_MSR_ATTR(6),
+ DSB_MSR_ATTR(7),
+ DSB_MSR_ATTR(8),
+ DSB_MSR_ATTR(9),
+ DSB_MSR_ATTR(10),
+ DSB_MSR_ATTR(11),
+ DSB_MSR_ATTR(12),
+ DSB_MSR_ATTR(13),
+ DSB_MSR_ATTR(14),
+ DSB_MSR_ATTR(15),
+ DSB_MSR_ATTR(16),
+ DSB_MSR_ATTR(17),
+ DSB_MSR_ATTR(18),
+ DSB_MSR_ATTR(19),
+ DSB_MSR_ATTR(20),
+ DSB_MSR_ATTR(21),
+ DSB_MSR_ATTR(22),
+ DSB_MSR_ATTR(23),
+ DSB_MSR_ATTR(24),
+ DSB_MSR_ATTR(25),
+ DSB_MSR_ATTR(26),
+ DSB_MSR_ATTR(27),
+ DSB_MSR_ATTR(28),
+ DSB_MSR_ATTR(29),
+ DSB_MSR_ATTR(30),
+ DSB_MSR_ATTR(31),
+ NULL,
+};
+
+static struct attribute *tpdm_dsb_attrs[] = {
+ &dev_attr_dsb_mode.attr,
+ &dev_attr_dsb_trig_ts.attr,
+ &dev_attr_dsb_trig_type.attr,
+ NULL,
+};
+
+static struct attribute_group tpdm_dsb_attr_grp = {
+ .attrs = tpdm_dsb_attrs,
+ .is_visible = tpdm_dsb_is_visible,
+};
+
+static struct attribute_group tpdm_dsb_edge_grp = {
+ .attrs = tpdm_dsb_edge_attrs,
+ .is_visible = tpdm_dsb_is_visible,
+ .name = "dsb_edge",
+};
+
+static struct attribute_group tpdm_dsb_trig_patt_grp = {
+ .attrs = tpdm_dsb_trig_patt_attrs,
+ .is_visible = tpdm_dsb_is_visible,
+ .name = "dsb_trig_patt",
+};
+
+static struct attribute_group tpdm_dsb_patt_grp = {
+ .attrs = tpdm_dsb_patt_attrs,
+ .is_visible = tpdm_dsb_is_visible,
+ .name = "dsb_patt",
+};
+
+static struct attribute_group tpdm_dsb_msr_grp = {
+ .attrs = tpdm_dsb_msr_attrs,
+ .is_visible = tpdm_dsb_msr_is_visible,
+ .name = "dsb_msr",
+};
+
static const struct attribute_group *tpdm_attr_grps[] = {
&tpdm_attr_grp,
+ &tpdm_dsb_attr_grp,
+ &tpdm_dsb_edge_grp,
+ &tpdm_dsb_trig_patt_grp,
+ &tpdm_dsb_patt_grp,
+ &tpdm_dsb_msr_grp,
NULL,
};
@@ -181,6 +866,7 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
struct coresight_platform_data *pdata;
struct tpdm_drvdata *drvdata;
struct coresight_desc desc = { 0 };
+ int ret;
pdata = coresight_get_platform_data(dev);
if (IS_ERR(pdata))
@@ -200,12 +886,20 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
drvdata->base = base;
+ ret = tpdm_datasets_setup(drvdata);
+ if (ret)
+ return ret;
+
+ if (drvdata && tpdm_has_dsb_dataset(drvdata))
+ of_property_read_u32(drvdata->dev->of_node,
+ "qcom,dsb-msrs-num", &drvdata->dsb_msr_num);
+
/* Set up coresight component description */
desc.name = coresight_alloc_device_name(&tpdm_devs, dev);
if (!desc.name)
return -ENOMEM;
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
- desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS;
+ desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM;
desc.ops = &tpdm_cs_ops;
desc.pdata = adev->dev.platform_data;
desc.dev = &adev->dev;
@@ -216,7 +910,7 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id)
return PTR_ERR(drvdata->csdev);
spin_lock_init(&drvdata->spinlock);
- tpdm_init_default_data(drvdata);
+
/* Decrease pm refcount when probe is done.*/
pm_runtime_put(&adev->dev);
diff --git a/drivers/hwtracing/coresight/coresight-tpdm.h b/drivers/hwtracing/coresight/coresight-tpdm.h
index 543854043a2d..4115b2a17b8d 100644
--- a/drivers/hwtracing/coresight/coresight-tpdm.h
+++ b/drivers/hwtracing/coresight/coresight-tpdm.h
@@ -11,8 +11,52 @@
/* DSB Subunit Registers */
#define TPDM_DSB_CR (0x780)
+#define TPDM_DSB_TIER (0x784)
+#define TPDM_DSB_TPR(n) (0x788 + (n * 4))
+#define TPDM_DSB_TPMR(n) (0x7A8 + (n * 4))
+#define TPDM_DSB_XPR(n) (0x7C8 + (n * 4))
+#define TPDM_DSB_XPMR(n) (0x7E8 + (n * 4))
+#define TPDM_DSB_EDCR(n) (0x808 + (n * 4))
+#define TPDM_DSB_EDCMR(n) (0x848 + (n * 4))
+#define TPDM_DSB_MSR(n) (0x980 + (n * 4))
+
/* Enable bit for DSB subunit */
#define TPDM_DSB_CR_ENA BIT(0)
+/* Enable bit for DSB subunit perfmance mode */
+#define TPDM_DSB_CR_MODE BIT(1)
+/* Enable bit for DSB subunit trigger type */
+#define TPDM_DSB_CR_TRIG_TYPE BIT(12)
+/* Data bits for DSB high performace mode */
+#define TPDM_DSB_CR_HPSEL GENMASK(6, 2)
+/* Data bits for DSB test mode */
+#define TPDM_DSB_CR_TEST_MODE GENMASK(10, 9)
+
+/* Enable bit for DSB subunit pattern timestamp */
+#define TPDM_DSB_TIER_PATT_TSENAB BIT(0)
+/* Enable bit for DSB subunit trigger timestamp */
+#define TPDM_DSB_TIER_XTRIG_TSENAB BIT(1)
+/* Bit for DSB subunit pattern type */
+#define TPDM_DSB_TIER_PATT_TYPE BIT(2)
+
+/* DSB programming modes */
+/* DSB mode bits mask */
+#define TPDM_DSB_MODE_MASK GENMASK(8, 0)
+/* Test mode control bit*/
+#define TPDM_DSB_MODE_TEST(val) (val & GENMASK(1, 0))
+/* Performance mode */
+#define TPDM_DSB_MODE_PERF BIT(3)
+/* High performance mode */
+#define TPDM_DSB_MODE_HPBYTESEL(val) (val & GENMASK(8, 4))
+
+#define EDCRS_PER_WORD 16
+#define EDCR_TO_WORD_IDX(r) ((r) / EDCRS_PER_WORD)
+#define EDCR_TO_WORD_SHIFT(r) ((r % EDCRS_PER_WORD) * 2)
+#define EDCR_TO_WORD_VAL(val, r) (val << EDCR_TO_WORD_SHIFT(r))
+#define EDCR_TO_WORD_MASK(r) EDCR_TO_WORD_VAL(0x3, r)
+
+#define EDCMRS_PER_WORD 32
+#define EDCMR_TO_WORD_IDX(r) ((r) / EDCMRS_PER_WORD)
+#define EDCMR_TO_WORD_SHIFT(r) ((r) % EDCMRS_PER_WORD)
/* TPDM integration test registers */
#define TPDM_ITATBCNTRL (0xEF0)
@@ -40,6 +84,95 @@
#define TPDM_PIDR0_DS_IMPDEF BIT(0)
#define TPDM_PIDR0_DS_DSB BIT(1)
+#define TPDM_DSB_MAX_LINES 256
+/* MAX number of EDCR registers */
+#define TPDM_DSB_MAX_EDCR 16
+/* MAX number of EDCMR registers */
+#define TPDM_DSB_MAX_EDCMR 8
+/* MAX number of DSB pattern */
+#define TPDM_DSB_MAX_PATT 8
+/* MAX number of DSB MSR */
+#define TPDM_DSB_MAX_MSR 32
+
+#define tpdm_simple_dataset_ro(name, mem, idx) \
+ (&((struct tpdm_dataset_attribute[]) { \
+ { \
+ __ATTR(name, 0444, tpdm_simple_dataset_show, NULL), \
+ mem, \
+ idx, \
+ } \
+ })[0].attr.attr)
+
+#define tpdm_simple_dataset_rw(name, mem, idx) \
+ (&((struct tpdm_dataset_attribute[]) { \
+ { \
+ __ATTR(name, 0644, tpdm_simple_dataset_show, \
+ tpdm_simple_dataset_store), \
+ mem, \
+ idx, \
+ } \
+ })[0].attr.attr)
+
+#define DSB_EDGE_CTRL_ATTR(nr) \
+ tpdm_simple_dataset_ro(edcr##nr, \
+ DSB_EDGE_CTRL, nr)
+
+#define DSB_EDGE_CTRL_MASK_ATTR(nr) \
+ tpdm_simple_dataset_ro(edcmr##nr, \
+ DSB_EDGE_CTRL_MASK, nr)
+
+#define DSB_TRIG_PATT_ATTR(nr) \
+ tpdm_simple_dataset_rw(xpr##nr, \
+ DSB_TRIG_PATT, nr)
+
+#define DSB_TRIG_PATT_MASK_ATTR(nr) \
+ tpdm_simple_dataset_rw(xpmr##nr, \
+ DSB_TRIG_PATT_MASK, nr)
+
+#define DSB_PATT_ATTR(nr) \
+ tpdm_simple_dataset_rw(tpr##nr, \
+ DSB_PATT, nr)
+
+#define DSB_PATT_MASK_ATTR(nr) \
+ tpdm_simple_dataset_rw(tpmr##nr, \
+ DSB_PATT_MASK, nr)
+
+#define DSB_MSR_ATTR(nr) \
+ tpdm_simple_dataset_rw(msr##nr, \
+ DSB_MSR, nr)
+
+/**
+ * struct dsb_dataset - specifics associated to dsb dataset
+ * @mode: DSB programming mode
+ * @edge_ctrl_idx Index number of the edge control
+ * @edge_ctrl: Save value for edge control
+ * @edge_ctrl_mask: Save value for edge control mask
+ * @patt_val: Save value for pattern
+ * @patt_mask: Save value for pattern mask
+ * @trig_patt: Save value for trigger pattern
+ * @trig_patt_mask: Save value for trigger pattern mask
+ * @msr Save value for MSR
+ * @patt_ts: Enable/Disable pattern timestamp
+ * @patt_type: Set pattern type
+ * @trig_ts: Enable/Disable trigger timestamp.
+ * @trig_type: Enable/Disable trigger type.
+ */
+struct dsb_dataset {
+ u32 mode;
+ u32 edge_ctrl_idx;
+ u32 edge_ctrl[TPDM_DSB_MAX_EDCR];
+ u32 edge_ctrl_mask[TPDM_DSB_MAX_EDCMR];
+ u32 patt_val[TPDM_DSB_MAX_PATT];
+ u32 patt_mask[TPDM_DSB_MAX_PATT];
+ u32 trig_patt[TPDM_DSB_MAX_PATT];
+ u32 trig_patt_mask[TPDM_DSB_MAX_PATT];
+ u32 msr[TPDM_DSB_MAX_MSR];
+ bool patt_ts;
+ bool patt_type;
+ bool trig_ts;
+ bool trig_type;
+};
+
/**
* struct tpdm_drvdata - specifics associated to an TPDM component
* @base: memory mapped base address for this component.
@@ -48,6 +181,8 @@
* @spinlock: lock for the drvdata value.
* @enable: enable status of the component.
* @datasets: The datasets types present of the TPDM.
+ * @dsb Specifics associated to TPDM DSB.
+ * @dsb_msr_num Number of MSR supported by DSB TPDM
*/
struct tpdm_drvdata {
@@ -57,6 +192,32 @@ struct tpdm_drvdata {
spinlock_t spinlock;
bool enable;
unsigned long datasets;
+ struct dsb_dataset *dsb;
+ u32 dsb_msr_num;
+};
+
+/* Enumerate members of various datasets */
+enum dataset_mem {
+ DSB_EDGE_CTRL,
+ DSB_EDGE_CTRL_MASK,
+ DSB_TRIG_PATT,
+ DSB_TRIG_PATT_MASK,
+ DSB_PATT,
+ DSB_PATT_MASK,
+ DSB_MSR,
+};
+
+/**
+ * struct tpdm_dataset_attribute - Record the member variables and
+ * index number of datasets that need to be operated by sysfs file
+ * @attr: The device attribute
+ * @mem: The member in the dataset data structure
+ * @idx: The index number of the array data
+ */
+struct tpdm_dataset_attribute {
+ struct device_attribute attr;
+ enum dataset_mem mem;
+ u32 idx;
};
#endif /* _CORESIGHT_CORESIGHT_TPDM_H */
diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index e20c1c6acc73..6136776482e6 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -1253,8 +1253,18 @@ static void arm_trbe_register_coresight_cpu(struct trbe_drvdata *drvdata, int cp
desc.name = devm_kasprintf(dev, GFP_KERNEL, "trbe%d", cpu);
if (!desc.name)
goto cpu_clear;
-
- desc.pdata = coresight_get_platform_data(dev);
+ /*
+ * TRBE coresight devices do not need regular connections
+ * information, as the paths get built between all percpu
+ * source and their respective percpu sink devices. Though
+ * coresight_register() expect device connections via the
+ * platform_data, which TRBE devices do not have. As they
+ * are not real ACPI devices, coresight_get_platform_data()
+ * ends up failing. Instead let's allocate a dummy zeroed
+ * coresight_platform_data structure and assign that back
+ * into the device for that purpose.
+ */
+ desc.pdata = devm_kzalloc(dev, sizeof(*desc.pdata), GFP_KERNEL);
if (IS_ERR(desc.pdata))
goto cpu_clear;
@@ -1520,14 +1530,13 @@ probe_failed:
return ret;
}
-static int arm_trbe_device_remove(struct platform_device *pdev)
+static void arm_trbe_device_remove(struct platform_device *pdev)
{
struct trbe_drvdata *drvdata = platform_get_drvdata(pdev);
arm_trbe_remove_cpuhp(drvdata);
arm_trbe_remove_coresight(drvdata);
arm_trbe_remove_irq(drvdata);
- return 0;
}
static const struct of_device_id arm_trbe_of_match[] = {
@@ -1536,14 +1545,23 @@ static const struct of_device_id arm_trbe_of_match[] = {
};
MODULE_DEVICE_TABLE(of, arm_trbe_of_match);
+#ifdef CONFIG_ACPI
+static const struct platform_device_id arm_trbe_acpi_match[] = {
+ { ARMV8_TRBE_PDEV_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, arm_trbe_acpi_match);
+#endif
+
static struct platform_driver arm_trbe_driver = {
+ .id_table = ACPI_PTR(arm_trbe_acpi_match),
.driver = {
.name = DRVNAME,
.of_match_table = of_match_ptr(arm_trbe_of_match),
.suppress_bind_attrs = true,
},
.probe = arm_trbe_device_probe,
- .remove = arm_trbe_device_remove,
+ .remove_new = arm_trbe_device_remove,
};
static int __init arm_trbe_init(void)
diff --git a/drivers/hwtracing/coresight/coresight-trbe.h b/drivers/hwtracing/coresight/coresight-trbe.h
index e915e749be55..45202c48acce 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.h
+++ b/drivers/hwtracing/coresight/coresight-trbe.h
@@ -7,11 +7,13 @@
*
* Author: Anshuman Khandual <[email protected]>
*/
+#include <linux/acpi.h>
#include <linux/coresight.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/of.h>
+#include <linux/perf/arm_pmu.h>
#include <linux/platform_device.h>
#include <linux/smp.h>
diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c
index 6e32d31a95fe..10e886455b8b 100644
--- a/drivers/hwtracing/coresight/ultrasoc-smb.c
+++ b/drivers/hwtracing/coresight/ultrasoc-smb.c
@@ -97,27 +97,19 @@ static int smb_open(struct inode *inode, struct file *file)
{
struct smb_drv_data *drvdata = container_of(file->private_data,
struct smb_drv_data, miscdev);
- int ret = 0;
- spin_lock(&drvdata->spinlock);
+ guard(spinlock)(&drvdata->spinlock);
- if (drvdata->reading) {
- ret = -EBUSY;
- goto out;
- }
+ if (drvdata->reading)
+ return -EBUSY;
- if (atomic_read(&drvdata->csdev->refcnt)) {
- ret = -EBUSY;
- goto out;
- }
+ if (atomic_read(&drvdata->csdev->refcnt))
+ return -EBUSY;
smb_update_data_size(drvdata);
-
drvdata->reading = true;
-out:
- spin_unlock(&drvdata->spinlock);
- return ret;
+ return 0;
}
static ssize_t smb_read(struct file *file, char __user *data, size_t len,
@@ -160,9 +152,8 @@ static int smb_release(struct inode *inode, struct file *file)
struct smb_drv_data *drvdata = container_of(file->private_data,
struct smb_drv_data, miscdev);
- spin_lock(&drvdata->spinlock);
+ guard(spinlock)(&drvdata->spinlock);
drvdata->reading = false;
- spin_unlock(&drvdata->spinlock);
return 0;
}
@@ -255,19 +246,15 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret = 0;
- spin_lock(&drvdata->spinlock);
+ guard(spinlock)(&drvdata->spinlock);
/* Do nothing, the trace data is reading by other interface now */
- if (drvdata->reading) {
- ret = -EBUSY;
- goto out;
- }
+ if (drvdata->reading)
+ return -EBUSY;
/* Do nothing, the SMB is already enabled as other mode */
- if (drvdata->mode != CS_MODE_DISABLED && drvdata->mode != mode) {
- ret = -EBUSY;
- goto out;
- }
+ if (drvdata->mode != CS_MODE_DISABLED && drvdata->mode != mode)
+ return -EBUSY;
switch (mode) {
case CS_MODE_SYSFS:
@@ -281,13 +268,10 @@ static int smb_enable(struct coresight_device *csdev, enum cs_mode mode,
}
if (ret)
- goto out;
+ return ret;
atomic_inc(&csdev->refcnt);
-
dev_dbg(&csdev->dev, "Ultrasoc SMB enabled\n");
-out:
- spin_unlock(&drvdata->spinlock);
return ret;
}
@@ -295,19 +279,14 @@ out:
static int smb_disable(struct coresight_device *csdev)
{
struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
- int ret = 0;
- spin_lock(&drvdata->spinlock);
+ guard(spinlock)(&drvdata->spinlock);
- if (drvdata->reading) {
- ret = -EBUSY;
- goto out;
- }
+ if (drvdata->reading)
+ return -EBUSY;
- if (atomic_dec_return(&csdev->refcnt)) {
- ret = -EBUSY;
- goto out;
- }
+ if (atomic_dec_return(&csdev->refcnt))
+ return -EBUSY;
/* Complain if we (somehow) got out of sync */
WARN_ON_ONCE(drvdata->mode == CS_MODE_DISABLED);
@@ -317,12 +296,9 @@ static int smb_disable(struct coresight_device *csdev)
/* Dissociate from the target process. */
drvdata->pid = -1;
drvdata->mode = CS_MODE_DISABLED;
-
dev_dbg(&csdev->dev, "Ultrasoc SMB disabled\n");
-out:
- spin_unlock(&drvdata->spinlock);
- return ret;
+ return 0;
}
static void *smb_alloc_buffer(struct coresight_device *csdev,
@@ -395,17 +371,17 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev,
struct smb_drv_data *drvdata = dev_get_drvdata(csdev->dev.parent);
struct smb_data_buffer *sdb = &drvdata->sdb;
struct cs_buffers *buf = sink_config;
- unsigned long data_size = 0;
+ unsigned long data_size;
bool lost = false;
if (!buf)
return 0;
- spin_lock(&drvdata->spinlock);
+ guard(spinlock)(&drvdata->spinlock);
/* Don't do anything if another tracer is using this sink. */
if (atomic_read(&csdev->refcnt) != 1)
- goto out;
+ return 0;
smb_disable_hw(drvdata);
smb_update_data_size(drvdata);
@@ -424,8 +400,6 @@ static unsigned long smb_update_buffer(struct coresight_device *csdev,
smb_sync_perf_buffer(drvdata, buf, handle->head);
if (!buf->snapshot && lost)
perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED);
-out:
- spin_unlock(&drvdata->spinlock);
return data_size;
}
@@ -601,15 +575,13 @@ static int smb_probe(struct platform_device *pdev)
return 0;
}
-static int smb_remove(struct platform_device *pdev)
+static void smb_remove(struct platform_device *pdev)
{
struct smb_drv_data *drvdata = platform_get_drvdata(pdev);
smb_unregister_sink(drvdata);
smb_config_inport(&pdev->dev, false);
-
- return 0;
}
#ifdef CONFIG_ACPI
@@ -627,7 +599,7 @@ static struct platform_driver smb_driver = {
.suppress_bind_attrs = true,
},
.probe = smb_probe,
- .remove = smb_remove,
+ .remove_new = smb_remove,
};
module_platform_driver(smb_driver);
diff --git a/drivers/hwtracing/ptt/hisi_ptt.c b/drivers/hwtracing/ptt/hisi_ptt.c
index a991ecb7515a..c1b5fd2b8974 100644
--- a/drivers/hwtracing/ptt/hisi_ptt.c
+++ b/drivers/hwtracing/ptt/hisi_ptt.c
@@ -183,6 +183,10 @@ static void hisi_ptt_wait_dma_reset_done(struct hisi_ptt *hisi_ptt)
static void hisi_ptt_trace_end(struct hisi_ptt *hisi_ptt)
{
writel(0, hisi_ptt->iobase + HISI_PTT_TRACE_CTRL);
+
+ /* Mask the interrupt on the end */
+ writel(HISI_PTT_TRACE_INT_MASK_ALL, hisi_ptt->iobase + HISI_PTT_TRACE_INT_MASK);
+
hisi_ptt->trace_ctrl.started = false;
}
@@ -270,15 +274,14 @@ static int hisi_ptt_update_aux(struct hisi_ptt *hisi_ptt, int index, bool stop)
buf->pos += size;
/*
- * Just commit the traced data if we're going to stop. Otherwise if the
- * resident AUX buffer cannot contain the data of next trace buffer,
- * apply a new one.
+ * Always commit the data to the AUX buffer in time to make sure
+ * userspace got enough time to consume the data.
+ *
+ * If we're not going to stop, apply a new one and check whether
+ * there's enough room for the next trace.
*/
- if (stop) {
- perf_aux_output_end(handle, buf->pos);
- } else if (buf->length - buf->pos < HISI_PTT_TRACE_BUF_SIZE) {
- perf_aux_output_end(handle, buf->pos);
-
+ perf_aux_output_end(handle, size);
+ if (!stop) {
buf = perf_aux_output_begin(handle, event);
if (!buf)
return -EINVAL;
diff --git a/drivers/hwtracing/ptt/hisi_ptt.h b/drivers/hwtracing/ptt/hisi_ptt.h
index e17f045d7e72..46030aa88081 100644
--- a/drivers/hwtracing/ptt/hisi_ptt.h
+++ b/drivers/hwtracing/ptt/hisi_ptt.h
@@ -47,6 +47,7 @@
#define HISI_PTT_TRACE_INT_STAT 0x0890
#define HISI_PTT_TRACE_INT_STAT_MASK GENMASK(3, 0)
#define HISI_PTT_TRACE_INT_MASK 0x0894
+#define HISI_PTT_TRACE_INT_MASK_ALL GENMASK(3, 0)
#define HISI_PTT_TUNING_INT_STAT 0x0898
#define HISI_PTT_TUNING_INT_STAT_MASK BIT(0)
#define HISI_PTT_TRACE_WR_STS 0x08a0
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 95caa162706f..3afa530c5e32 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -557,6 +557,88 @@ static ssize_t i2c_scl_frequency_show(struct device *dev,
}
static DEVICE_ATTR_RO(i2c_scl_frequency);
+static int i3c_set_hotjoin(struct i3c_master_controller *master, bool enable)
+{
+ int ret;
+
+ if (!master || !master->ops)
+ return -EINVAL;
+
+ if (!master->ops->enable_hotjoin || !master->ops->disable_hotjoin)
+ return -EINVAL;
+
+ i3c_bus_normaluse_lock(&master->bus);
+
+ if (enable)
+ ret = master->ops->enable_hotjoin(master);
+ else
+ ret = master->ops->disable_hotjoin(master);
+
+ master->hotjoin = enable;
+
+ i3c_bus_normaluse_unlock(&master->bus);
+
+ return ret;
+}
+
+static ssize_t hotjoin_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
+ int ret;
+ bool res;
+
+ if (!i3cbus->cur_master)
+ return -EINVAL;
+
+ if (kstrtobool(buf, &res))
+ return -EINVAL;
+
+ ret = i3c_set_hotjoin(i3cbus->cur_master->common.master, res);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+/*
+ * i3c_master_enable_hotjoin - Enable hotjoin
+ * @master: I3C master object
+ *
+ * Return: a 0 in case of success, an negative error code otherwise.
+ */
+int i3c_master_enable_hotjoin(struct i3c_master_controller *master)
+{
+ return i3c_set_hotjoin(master, true);
+}
+EXPORT_SYMBOL_GPL(i3c_master_enable_hotjoin);
+
+/*
+ * i3c_master_disable_hotjoin - Disable hotjoin
+ * @master: I3C master object
+ *
+ * Return: a 0 in case of success, an negative error code otherwise.
+ */
+int i3c_master_disable_hotjoin(struct i3c_master_controller *master)
+{
+ return i3c_set_hotjoin(master, false);
+}
+EXPORT_SYMBOL_GPL(i3c_master_disable_hotjoin);
+
+static ssize_t hotjoin_show(struct device *dev, struct device_attribute *da, char *buf)
+{
+ struct i3c_bus *i3cbus = dev_to_i3cbus(dev);
+ ssize_t ret;
+
+ i3c_bus_normaluse_lock(i3cbus);
+ ret = sysfs_emit(buf, "%d\n", i3cbus->cur_master->common.master->hotjoin);
+ i3c_bus_normaluse_unlock(i3cbus);
+
+ return ret;
+}
+
+static DEVICE_ATTR_RW(hotjoin);
+
static struct attribute *i3c_masterdev_attrs[] = {
&dev_attr_mode.attr,
&dev_attr_current_master.attr,
@@ -567,6 +649,7 @@ static struct attribute *i3c_masterdev_attrs[] = {
&dev_attr_pid.attr,
&dev_attr_dynamic_address.attr,
&dev_attr_hdrcap.attr,
+ &dev_attr_hotjoin.attr,
NULL,
};
ATTRIBUTE_GROUPS(i3c_masterdev);
@@ -1130,8 +1213,16 @@ static int i3c_master_getmxds_locked(struct i3c_master_controller *master,
i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETMXDS, &dest, 1);
ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
- if (ret)
- goto out;
+ if (ret) {
+ /*
+ * Retry when the device does not support max read turnaround
+ * while expecting shorter length from this CCC command.
+ */
+ dest.payload.len -= 3;
+ ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+ if (ret)
+ goto out;
+ }
if (dest.payload.len != 2 && dest.payload.len != 5) {
ret = -EIO;
diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
index bcbe8f914149..c1627f3552ce 100644
--- a/drivers/i3c/master/i3c-master-cdns.c
+++ b/drivers/i3c/master/i3c-master-cdns.c
@@ -76,7 +76,8 @@
#define PRESCL_CTRL0 0x14
#define PRESCL_CTRL0_I2C(x) ((x) << 16)
#define PRESCL_CTRL0_I3C(x) (x)
-#define PRESCL_CTRL0_MAX GENMASK(9, 0)
+#define PRESCL_CTRL0_I3C_MAX GENMASK(9, 0)
+#define PRESCL_CTRL0_I2C_MAX GENMASK(15, 0)
#define PRESCL_CTRL1 0x18
#define PRESCL_CTRL1_PP_LOW_MASK GENMASK(15, 8)
@@ -1233,7 +1234,7 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
return -EINVAL;
pres = DIV_ROUND_UP(sysclk_rate, (bus->scl_rate.i3c * 4)) - 1;
- if (pres > PRESCL_CTRL0_MAX)
+ if (pres > PRESCL_CTRL0_I3C_MAX)
return -ERANGE;
bus->scl_rate.i3c = sysclk_rate / ((pres + 1) * 4);
@@ -1246,7 +1247,7 @@ static int cdns_i3c_master_bus_init(struct i3c_master_controller *m)
max_i2cfreq = bus->scl_rate.i2c;
pres = (sysclk_rate / (max_i2cfreq * 5)) - 1;
- if (pres > PRESCL_CTRL0_MAX)
+ if (pres > PRESCL_CTRL0_I2C_MAX)
return -ERANGE;
bus->scl_rate.i2c = sysclk_rate / ((pres + 1) * 5);
diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
index 2b2323aa6714..638b054d6c92 100644
--- a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
+++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
@@ -298,7 +298,7 @@ static int hci_cmd_v1_daa(struct i3c_hci *hci)
unsigned int dcr, bcr;
DECLARE_COMPLETION_ONSTACK(done);
- xfer = hci_alloc_xfer(2);
+ xfer = hci_alloc_xfer(1);
if (!xfer)
return -ENOMEM;
@@ -339,12 +339,13 @@ static int hci_cmd_v1_daa(struct i3c_hci *hci)
ret = -ETIME;
break;
}
- if (RESP_STATUS(xfer[0].response) == RESP_ERR_NACK &&
+ if ((RESP_STATUS(xfer->response) == RESP_ERR_ADDR_HEADER ||
+ RESP_STATUS(xfer->response) == RESP_ERR_NACK) &&
RESP_DATA_LENGTH(xfer->response) == 1) {
ret = 0; /* no more devices to be assigned */
break;
}
- if (RESP_STATUS(xfer[0].response) != RESP_SUCCESS) {
+ if (RESP_STATUS(xfer->response) != RESP_SUCCESS) {
ret = -EIO;
break;
}
diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 1ae56a5699c6..d7e966a25583 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -245,7 +245,14 @@ static int i3c_hci_send_ccc_cmd(struct i3c_master_controller *m,
if (ccc->rnw)
ccc->dests[i - prefixed].payload.len =
RESP_DATA_LENGTH(xfer[i].response);
- if (RESP_STATUS(xfer[i].response) != RESP_SUCCESS) {
+ switch (RESP_STATUS(xfer[i].response)) {
+ case RESP_SUCCESS:
+ continue;
+ case RESP_ERR_ADDR_HEADER:
+ case RESP_ERR_NACK:
+ ccc->err = I3C_ERROR_M2;
+ fallthrough;
+ default:
ret = -EIO;
goto out;
}
@@ -269,6 +276,34 @@ static int i3c_hci_daa(struct i3c_master_controller *m)
return hci->cmd->perform_daa(hci);
}
+static int i3c_hci_alloc_safe_xfer_buf(struct i3c_hci *hci,
+ struct hci_xfer *xfer)
+{
+ if (hci->io != &mipi_i3c_hci_dma ||
+ xfer->data == NULL || !is_vmalloc_addr(xfer->data))
+ return 0;
+
+ if (xfer->rnw)
+ xfer->bounce_buf = kzalloc(xfer->data_len, GFP_KERNEL);
+ else
+ xfer->bounce_buf = kmemdup(xfer->data,
+ xfer->data_len, GFP_KERNEL);
+
+ return xfer->bounce_buf == NULL ? -ENOMEM : 0;
+}
+
+static void i3c_hci_free_safe_xfer_buf(struct i3c_hci *hci,
+ struct hci_xfer *xfer)
+{
+ if (hci->io != &mipi_i3c_hci_dma || xfer->bounce_buf == NULL)
+ return;
+
+ if (xfer->rnw)
+ memcpy(xfer->data, xfer->bounce_buf, xfer->data_len);
+
+ kfree(xfer->bounce_buf);
+}
+
static int i3c_hci_priv_xfers(struct i3c_dev_desc *dev,
struct i3c_priv_xfer *i3c_xfers,
int nxfers)
@@ -302,6 +337,9 @@ static int i3c_hci_priv_xfers(struct i3c_dev_desc *dev,
}
hci->cmd->prep_i3c_xfer(hci, dev, &xfer[i]);
xfer[i].cmd_desc[0] |= CMD_0_ROC;
+ ret = i3c_hci_alloc_safe_xfer_buf(hci, &xfer[i]);
+ if (ret)
+ goto out;
}
last = i - 1;
xfer[last].cmd_desc[0] |= CMD_0_TOC;
@@ -325,6 +363,9 @@ static int i3c_hci_priv_xfers(struct i3c_dev_desc *dev,
}
out:
+ for (i = 0; i < nxfers; i++)
+ i3c_hci_free_safe_xfer_buf(hci, &xfer[i]);
+
hci_free_xfer(xfer, nxfers);
return ret;
}
@@ -350,6 +391,9 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
xfer[i].rnw = i2c_xfers[i].flags & I2C_M_RD;
hci->cmd->prep_i2c_xfer(hci, dev, &xfer[i]);
xfer[i].cmd_desc[0] |= CMD_0_ROC;
+ ret = i3c_hci_alloc_safe_xfer_buf(hci, &xfer[i]);
+ if (ret)
+ goto out;
}
last = i - 1;
xfer[last].cmd_desc[0] |= CMD_0_TOC;
@@ -371,6 +415,9 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
}
out:
+ for (i = 0; i < nxfers; i++)
+ i3c_hci_free_safe_xfer_buf(hci, &xfer[i]);
+
hci_free_xfer(xfer, nxfers);
return ret;
}
diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index c805a8497319..4e01a95cc4d0 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -362,6 +362,7 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
struct hci_rh_data *rh;
unsigned int i, ring, enqueue_ptr;
u32 op1_val, op2_val;
+ void *buf;
/* For now we only use ring 0 */
ring = 0;
@@ -390,9 +391,10 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
/* 2nd and 3rd words of Data Buffer Descriptor Structure */
if (xfer->data) {
+ buf = xfer->bounce_buf ? xfer->bounce_buf : xfer->data;
xfer->data_dma =
dma_map_single(&hci->master.dev,
- xfer->data,
+ buf,
xfer->data_len,
xfer->rnw ?
DMA_FROM_DEVICE :
diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h
index f109923f6c3f..f94d95e024be 100644
--- a/drivers/i3c/master/mipi-i3c-hci/hci.h
+++ b/drivers/i3c/master/mipi-i3c-hci/hci.h
@@ -90,6 +90,7 @@ struct hci_xfer {
struct {
/* DMA specific */
dma_addr_t data_dma;
+ void *bounce_buf;
int ring_number;
int ring_entry;
};
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index cf703c00f633..5ee4db68988e 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -128,13 +128,17 @@
/* This parameter depends on the implementation and may be tuned */
#define SVC_I3C_FIFO_SIZE 16
+#define SVC_I3C_EVENT_IBI BIT(0)
+#define SVC_I3C_EVENT_HOTJOIN BIT(1)
+
struct svc_i3c_cmd {
u8 addr;
bool rnw;
u8 *in;
const void *out;
unsigned int len;
- unsigned int read_len;
+ unsigned int actual_len;
+ struct i3c_priv_xfer *xfer;
bool continued;
};
@@ -177,6 +181,7 @@ struct svc_i3c_regs_save {
* @ibi.tbq_slot: To be queued IBI slot
* @ibi.lock: IBI lock
* @lock: Transfer lock, protect between IBI work thread and callbacks from master
+ * @enabled_events: Bit masks for enable events (IBI, HotJoin).
*/
struct svc_i3c_master {
struct i3c_master_controller base;
@@ -206,6 +211,7 @@ struct svc_i3c_master {
spinlock_t lock;
} ibi;
struct mutex lock;
+ int enabled_events;
};
/**
@@ -220,6 +226,11 @@ struct svc_i3c_i2c_dev_data {
struct i3c_generic_ibi_pool *ibi_pool;
};
+static inline bool is_events_enabled(struct svc_i3c_master *master, u32 mask)
+{
+ return !!(master->enabled_events & mask);
+}
+
static bool svc_i3c_master_error(struct svc_i3c_master *master)
{
u32 mstatus, merrwarn;
@@ -429,13 +440,16 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
switch (ibitype) {
case SVC_I3C_MSTATUS_IBITYPE_IBI:
dev = svc_i3c_master_dev_from_addr(master, ibiaddr);
- if (!dev)
+ if (!dev || !is_events_enabled(master, SVC_I3C_EVENT_IBI))
svc_i3c_master_nack_ibi(master);
else
svc_i3c_master_handle_ibi(master, dev);
break;
case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
- svc_i3c_master_ack_ibi(master, false);
+ if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN))
+ svc_i3c_master_ack_ibi(master, false);
+ else
+ svc_i3c_master_nack_ibi(master);
break;
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
svc_i3c_master_nack_ibi(master);
@@ -472,7 +486,9 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
svc_i3c_master_emit_stop(master);
break;
case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
- queue_work(master->base.wq, &master->hj_work);
+ svc_i3c_master_emit_stop(master);
+ if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN))
+ queue_work(master->base.wq, &master->hj_work);
break;
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
default:
@@ -1024,7 +1040,7 @@ static int svc_i3c_master_write(struct svc_i3c_master *master,
static int svc_i3c_master_xfer(struct svc_i3c_master *master,
bool rnw, unsigned int xfer_type, u8 addr,
u8 *in, const u8 *out, unsigned int xfer_len,
- unsigned int *read_len, bool continued)
+ unsigned int *actual_len, bool continued)
{
u32 reg;
int ret;
@@ -1037,7 +1053,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
SVC_I3C_MCTRL_IBIRESP_NACK |
SVC_I3C_MCTRL_DIR(rnw) |
SVC_I3C_MCTRL_ADDR(addr) |
- SVC_I3C_MCTRL_RDTERM(*read_len),
+ SVC_I3C_MCTRL_RDTERM(*actual_len),
master->regs + SVC_I3C_MCTRL);
ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
@@ -1047,6 +1063,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
if (readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_NACK) {
ret = -ENXIO;
+ *actual_len = 0;
goto emit_stop;
}
@@ -1064,6 +1081,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
*/
if (SVC_I3C_MSTATUS_IBIWON(reg)) {
ret = -ENXIO;
+ *actual_len = 0;
goto emit_stop;
}
@@ -1075,7 +1093,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
goto emit_stop;
if (rnw)
- *read_len = ret;
+ *actual_len = ret;
ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
SVC_I3C_MSTATUS_COMPLETE(reg), 0, 1000);
@@ -1157,8 +1175,12 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
ret = svc_i3c_master_xfer(master, cmd->rnw, xfer->type,
cmd->addr, cmd->in, cmd->out,
- cmd->len, &cmd->read_len,
+ cmd->len, &cmd->actual_len,
cmd->continued);
+ /* cmd->xfer is NULL if I2C or CCC transfer */
+ if (cmd->xfer)
+ cmd->xfer->actual_len = cmd->actual_len;
+
if (ret)
break;
}
@@ -1243,7 +1265,7 @@ static int svc_i3c_master_send_bdcast_ccc_cmd(struct svc_i3c_master *master,
cmd->in = NULL;
cmd->out = buf;
cmd->len = xfer_len;
- cmd->read_len = 0;
+ cmd->actual_len = 0;
cmd->continued = false;
mutex_lock(&master->lock);
@@ -1263,7 +1285,7 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master,
struct i3c_ccc_cmd *ccc)
{
unsigned int xfer_len = ccc->dests[0].payload.len;
- unsigned int read_len = ccc->rnw ? xfer_len : 0;
+ unsigned int actual_len = ccc->rnw ? xfer_len : 0;
struct svc_i3c_xfer *xfer;
struct svc_i3c_cmd *cmd;
int ret;
@@ -1281,7 +1303,7 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master,
cmd->in = NULL;
cmd->out = &ccc->id;
cmd->len = 1;
- cmd->read_len = 0;
+ cmd->actual_len = 0;
cmd->continued = true;
/* Directed message */
@@ -1291,7 +1313,7 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master,
cmd->in = ccc->rnw ? ccc->dests[0].payload.data : NULL;
cmd->out = ccc->rnw ? NULL : ccc->dests[0].payload.data,
cmd->len = xfer_len;
- cmd->read_len = read_len;
+ cmd->actual_len = actual_len;
cmd->continued = false;
mutex_lock(&master->lock);
@@ -1300,8 +1322,8 @@ static int svc_i3c_master_send_direct_ccc_cmd(struct svc_i3c_master *master,
svc_i3c_master_dequeue_xfer(master, xfer);
mutex_unlock(&master->lock);
- if (cmd->read_len != xfer_len)
- ccc->dests[0].payload.len = cmd->read_len;
+ if (cmd->actual_len != xfer_len)
+ ccc->dests[0].payload.len = cmd->actual_len;
ret = xfer->ret;
svc_i3c_master_free_xfer(xfer);
@@ -1346,12 +1368,13 @@ static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
for (i = 0; i < nxfers; i++) {
struct svc_i3c_cmd *cmd = &xfer->cmds[i];
+ cmd->xfer = &xfers[i];
cmd->addr = master->addrs[data->index];
cmd->rnw = xfers[i].rnw;
cmd->in = xfers[i].rnw ? xfers[i].data.in : NULL;
cmd->out = xfers[i].rnw ? NULL : xfers[i].data.out;
cmd->len = xfers[i].len;
- cmd->read_len = xfers[i].rnw ? xfers[i].len : 0;
+ cmd->actual_len = xfers[i].rnw ? xfers[i].len : 0;
cmd->continued = (i + 1) < nxfers;
}
@@ -1391,7 +1414,7 @@ static int svc_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
cmd->in = cmd->rnw ? xfers[i].buf : NULL;
cmd->out = cmd->rnw ? NULL : xfers[i].buf;
cmd->len = xfers[i].len;
- cmd->read_len = cmd->rnw ? xfers[i].len : 0;
+ cmd->actual_len = cmd->rnw ? xfers[i].len : 0;
cmd->continued = (i + 1 < nxfers);
}
@@ -1472,6 +1495,7 @@ static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
return ret;
}
+ master->enabled_events |= SVC_I3C_EVENT_IBI;
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
@@ -1483,7 +1507,9 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
struct svc_i3c_master *master = to_svc_i3c_master(m);
int ret;
- svc_i3c_master_disable_interrupts(master);
+ master->enabled_events &= ~SVC_I3C_EVENT_IBI;
+ if (!master->enabled_events)
+ svc_i3c_master_disable_interrupts(master);
ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
@@ -1493,6 +1519,39 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
return ret;
}
+static int svc_i3c_master_enable_hotjoin(struct i3c_master_controller *m)
+{
+ struct svc_i3c_master *master = to_svc_i3c_master(m);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(master->dev);
+ if (ret < 0) {
+ dev_err(master->dev, "<%s> Cannot get runtime PM.\n", __func__);
+ return ret;
+ }
+
+ master->enabled_events |= SVC_I3C_EVENT_HOTJOIN;
+
+ svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
+
+ return 0;
+}
+
+static int svc_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
+{
+ struct svc_i3c_master *master = to_svc_i3c_master(m);
+
+ master->enabled_events &= ~SVC_I3C_EVENT_HOTJOIN;
+
+ if (!master->enabled_events)
+ svc_i3c_master_disable_interrupts(master);
+
+ pm_runtime_mark_last_busy(master->dev);
+ pm_runtime_put_autosuspend(master->dev);
+
+ return 0;
+}
+
static void svc_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev,
struct i3c_ibi_slot *slot)
{
@@ -1519,6 +1578,8 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
.recycle_ibi_slot = svc_i3c_master_recycle_ibi_slot,
.enable_ibi = svc_i3c_master_enable_ibi,
.disable_ibi = svc_i3c_master_disable_ibi,
+ .enable_hotjoin = svc_i3c_master_enable_hotjoin,
+ .disable_hotjoin = svc_i3c_master_disable_hotjoin,
};
static int svc_i3c_master_prepare_clks(struct svc_i3c_master *master)
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index f113dae59048..91adcac875a4 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -260,10 +260,11 @@ config BMI088_ACCEL
select REGMAP
select BMI088_ACCEL_SPI
help
- Say yes here to build support for the Bosch BMI088 accelerometer.
+ Say yes here to build support for the following Bosch accelerometers:
+ BMI088, BMI085, BMI090L. Note that all of these are combo module that
+ include both accelerometer and gyroscope.
- This is a combo module with both accelerometer and gyroscope. This
- driver only implements the accelerometer part, which has its own
+ This driver only implements the accelerometer part, which has its own
address and register map. BMG160 provides the gyroscope driver.
config BMI088_ACCEL_SPI
diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c
index 84edcc78d796..4d989708e6c3 100644
--- a/drivers/iio/accel/bmi088-accel-core.c
+++ b/drivers/iio/accel/bmi088-accel-core.c
@@ -2,6 +2,8 @@
/*
* 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
* - BMI088
+ * - BMI085
+ * - BMI090L
*
* Copyright (c) 2018-2021, Topic Embedded Products
*/
diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c
index ee540edd8412..7b419a7b2478 100644
--- a/drivers/iio/accel/bmi088-accel-spi.c
+++ b/drivers/iio/accel/bmi088-accel-spi.c
@@ -2,6 +2,8 @@
/*
* 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
* - BMI088
+ * - BMI085
+ * - BMI090L
*
* Copyright (c) 2018-2020, Topic Embedded Products
*/
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 35f9867da12c..3b73c509bd68 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -36,13 +36,29 @@ config AD4130
To compile this driver as a module, choose M here: the module will be
called ad4130.
+config AD7091R
+ tristate
+
config AD7091R5
tristate "Analog Devices AD7091R5 ADC Driver"
depends on I2C
+ select AD7091R
select REGMAP_I2C
help
Say yes here to build support for Analog Devices AD7091R-5 ADC.
+config AD7091R8
+ tristate "Analog Devices AD7091R8 ADC Driver"
+ depends on SPI
+ select AD7091R
+ select REGMAP_SPI
+ help
+ Say yes here to build support for Analog Devices AD7091R-2, AD7091R-4,
+ and AD7091R-8 ADC.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad7091r8.
+
config AD7124
tristate "Analog Devices AD7124 and similar sigma-delta ADCs driver"
depends on SPI_MASTER
@@ -292,7 +308,7 @@ config ADI_AXI_ADC
select IIO_BUFFER
select IIO_BUFFER_HW_CONSUMER
select IIO_BUFFER_DMAENGINE
- depends on HAS_IOMEM
+ select REGMAP_MMIO
depends on OF
help
Say yes here to build support for Analog Devices Generic
@@ -745,6 +761,17 @@ config MAX1363
To compile this driver as a module, choose M here: the module will be
called max1363.
+config MAX34408
+ tristate "Maxim max34408/max344089 ADC driver"
+ depends on I2C
+ help
+ Say yes here to build support for Maxim max34408/max34409 current sense
+ monitor with 8-bits ADC interface with overcurrent delay/threshold and
+ shutdown delay.
+
+ To compile this driver as a module, choose M here: the module will be
+ called max34408.
+
config MAX77541_ADC
tristate "Analog Devices MAX77541 ADC driver"
depends on MFD_MAX77541
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index bee11d442af4..d2fda54a3259 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -7,7 +7,9 @@
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD4130) += ad4130.o
-obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o
+obj-$(CONFIG_AD7091R) += ad7091r-base.o
+obj-$(CONFIG_AD7091R5) += ad7091r5.o
+obj-$(CONFIG_AD7091R8) += ad7091r8.o
obj-$(CONFIG_AD7124) += ad7124.o
obj-$(CONFIG_AD7192) += ad7192.o
obj-$(CONFIG_AD7266) += ad7266.o
@@ -68,6 +70,7 @@ obj-$(CONFIG_MAX11205) += max11205.o
obj-$(CONFIG_MAX11410) += max11410.o
obj-$(CONFIG_MAX1241) += max1241.o
obj-$(CONFIG_MAX1363) += max1363.o
+obj-$(CONFIG_MAX34408) += max34408.o
obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o
obj-$(CONFIG_MAX9611) += max9611.o
obj-$(CONFIG_MCP320X) += mcp320x.o
diff --git a/drivers/iio/adc/ad7091r-base.c b/drivers/iio/adc/ad7091r-base.c
index 8e252cde735b..f4255b91acfc 100644
--- a/drivers/iio/adc/ad7091r-base.c
+++ b/drivers/iio/adc/ad7091r-base.c
@@ -6,6 +6,7 @@
*/
#include <linux/bitops.h>
+#include <linux/bitfield.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
@@ -15,67 +16,26 @@
#include "ad7091r-base.h"
-#define AD7091R_REG_RESULT 0
-#define AD7091R_REG_CHANNEL 1
-#define AD7091R_REG_CONF 2
-#define AD7091R_REG_ALERT 3
-#define AD7091R_REG_CH_LOW_LIMIT(ch) ((ch) * 3 + 4)
-#define AD7091R_REG_CH_HIGH_LIMIT(ch) ((ch) * 3 + 5)
-#define AD7091R_REG_CH_HYSTERESIS(ch) ((ch) * 3 + 6)
-
-/* AD7091R_REG_RESULT */
-#define AD7091R_REG_RESULT_CH_ID(x) (((x) >> 13) & 0x3)
-#define AD7091R_REG_RESULT_CONV_RESULT(x) ((x) & 0xfff)
-
-/* AD7091R_REG_CONF */
-#define AD7091R_REG_CONF_AUTO BIT(8)
-#define AD7091R_REG_CONF_CMD BIT(10)
-
-#define AD7091R_REG_CONF_MODE_MASK \
- (AD7091R_REG_CONF_AUTO | AD7091R_REG_CONF_CMD)
-
-enum ad7091r_mode {
- AD7091R_MODE_SAMPLE,
- AD7091R_MODE_COMMAND,
- AD7091R_MODE_AUTOCYCLE,
+const struct iio_event_spec ad7091r_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
+ },
};
-
-struct ad7091r_state {
- struct device *dev;
- struct regmap *map;
- struct regulator *vref;
- const struct ad7091r_chip_info *chip_info;
- enum ad7091r_mode mode;
- struct mutex lock; /*lock to prevent concurent reads */
-};
-
-static int ad7091r_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode)
-{
- int ret, conf;
-
- switch (mode) {
- case AD7091R_MODE_SAMPLE:
- conf = 0;
- break;
- case AD7091R_MODE_COMMAND:
- conf = AD7091R_REG_CONF_CMD;
- break;
- case AD7091R_MODE_AUTOCYCLE:
- conf = AD7091R_REG_CONF_AUTO;
- break;
- default:
- return -EINVAL;
- }
-
- ret = regmap_update_bits(st->map, AD7091R_REG_CONF,
- AD7091R_REG_CONF_MODE_MASK, conf);
- if (ret)
- return ret;
-
- st->mode = mode;
-
- return 0;
-}
+EXPORT_SYMBOL_NS_GPL(ad7091r_events, IIO_AD7091R);
static int ad7091r_set_channel(struct ad7091r_state *st, unsigned int channel)
{
@@ -110,7 +70,7 @@ static int ad7091r_read_one(struct iio_dev *iio_dev,
if (ret)
return ret;
- if (AD7091R_REG_RESULT_CH_ID(val) != channel)
+ if (st->chip_info->reg_result_chan_id(val) != channel)
return -EIO;
*read_val = AD7091R_REG_RESULT_CONV_RESULT(val);
@@ -168,14 +128,148 @@ unlock:
return ret;
}
+static int ad7091r_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct ad7091r_state *st = iio_priv(indio_dev);
+ int val, ret;
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ ret = regmap_read(st->map,
+ AD7091R_REG_CH_HIGH_LIMIT(chan->channel),
+ &val);
+ if (ret)
+ return ret;
+ return val != AD7091R_HIGH_LIMIT;
+ case IIO_EV_DIR_FALLING:
+ ret = regmap_read(st->map,
+ AD7091R_REG_CH_LOW_LIMIT(chan->channel),
+ &val);
+ if (ret)
+ return ret;
+ return val != AD7091R_LOW_LIMIT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad7091r_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir, int state)
+{
+ struct ad7091r_state *st = iio_priv(indio_dev);
+
+ if (state) {
+ return regmap_set_bits(st->map, AD7091R_REG_CONF,
+ AD7091R_REG_CONF_ALERT_EN);
+ } else {
+ /*
+ * Set thresholds either to 0 or to 2^12 - 1 as appropriate to
+ * prevent alerts and thus disable event generation.
+ */
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ return regmap_write(st->map,
+ AD7091R_REG_CH_HIGH_LIMIT(chan->channel),
+ AD7091R_HIGH_LIMIT);
+ case IIO_EV_DIR_FALLING:
+ return regmap_write(st->map,
+ AD7091R_REG_CH_LOW_LIMIT(chan->channel),
+ AD7091R_LOW_LIMIT);
+ default:
+ return -EINVAL;
+ }
+ }
+}
+
+static int ad7091r_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int *val, int *val2)
+{
+ struct ad7091r_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ ret = regmap_read(st->map,
+ AD7091R_REG_CH_HIGH_LIMIT(chan->channel),
+ val);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_EV_DIR_FALLING:
+ ret = regmap_read(st->map,
+ AD7091R_REG_CH_LOW_LIMIT(chan->channel),
+ val);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_INFO_HYSTERESIS:
+ ret = regmap_read(st->map,
+ AD7091R_REG_CH_HYSTERESIS(chan->channel),
+ val);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad7091r_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int val, int val2)
+{
+ struct ad7091r_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ return regmap_write(st->map,
+ AD7091R_REG_CH_HIGH_LIMIT(chan->channel),
+ val);
+ case IIO_EV_DIR_FALLING:
+ return regmap_write(st->map,
+ AD7091R_REG_CH_LOW_LIMIT(chan->channel),
+ val);
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_INFO_HYSTERESIS:
+ return regmap_write(st->map,
+ AD7091R_REG_CH_HYSTERESIS(chan->channel),
+ val);
+ default:
+ return -EINVAL;
+ }
+}
+
static const struct iio_info ad7091r_info = {
.read_raw = ad7091r_read_raw,
+ .read_event_config = &ad7091r_read_event_config,
+ .write_event_config = &ad7091r_write_event_config,
+ .read_event_value = &ad7091r_read_event_value,
+ .write_event_value = &ad7091r_write_event_value,
};
static irqreturn_t ad7091r_event_handler(int irq, void *private)
{
- struct ad7091r_state *st = (struct ad7091r_state *) private;
- struct iio_dev *iio_dev = dev_get_drvdata(st->dev);
+ struct iio_dev *iio_dev = private;
+ struct ad7091r_state *st = iio_priv(iio_dev);
unsigned int i, read_val;
int ret;
s64 timestamp = iio_get_time_ns(iio_dev);
@@ -207,9 +301,8 @@ static void ad7091r_remove(void *data)
regulator_disable(st->vref);
}
-int ad7091r_probe(struct device *dev, const char *name,
- const struct ad7091r_chip_info *chip_info,
- struct regmap *map, int irq)
+int ad7091r_probe(struct device *dev, const struct ad7091r_init_info *init_info,
+ int irq)
{
struct iio_dev *iio_dev;
struct ad7091r_state *st;
@@ -221,29 +314,54 @@ int ad7091r_probe(struct device *dev, const char *name,
st = iio_priv(iio_dev);
st->dev = dev;
- st->chip_info = chip_info;
- st->map = map;
+ init_info->init_adc_regmap(st, init_info->regmap_config);
+ if (IS_ERR(st->map))
+ return dev_err_probe(st->dev, PTR_ERR(st->map),
+ "Error initializing regmap\n");
- iio_dev->name = name;
iio_dev->info = &ad7091r_info;
iio_dev->modes = INDIO_DIRECT_MODE;
- iio_dev->num_channels = chip_info->num_channels;
- iio_dev->channels = chip_info->channels;
+ if (init_info->setup) {
+ ret = init_info->setup(st);
+ if (ret < 0)
+ return ret;
+ }
if (irq) {
+ st->chip_info = init_info->info_irq;
+ ret = regmap_update_bits(st->map, AD7091R_REG_CONF,
+ AD7091R_REG_CONF_ALERT_EN, BIT(4));
+ if (ret)
+ return ret;
+
ret = devm_request_threaded_irq(dev, irq, NULL,
- ad7091r_event_handler,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT, name, st);
+ ad7091r_event_handler,
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ st->chip_info->name, iio_dev);
if (ret)
return ret;
+ } else {
+ st->chip_info = init_info->info_no_irq;
}
+ iio_dev->name = st->chip_info->name;
+ iio_dev->num_channels = st->chip_info->num_channels;
+ iio_dev->channels = st->chip_info->channels;
+
st->vref = devm_regulator_get_optional(dev, "vref");
if (IS_ERR(st->vref)) {
if (PTR_ERR(st->vref) == -EPROBE_DEFER)
return -EPROBE_DEFER;
+
st->vref = NULL;
+ /* Enable internal vref */
+ ret = regmap_set_bits(st->map, AD7091R_REG_CONF,
+ AD7091R_REG_CONF_INT_VREF);
+ if (ret)
+ return dev_err_probe(st->dev, ret,
+ "Error on enable internal reference\n");
} else {
ret = regulator_enable(st->vref);
if (ret)
@@ -254,7 +372,7 @@ int ad7091r_probe(struct device *dev, const char *name,
}
/* Use command mode by default to convert only desired channels*/
- ret = ad7091r_set_mode(st, AD7091R_MODE_COMMAND);
+ ret = st->chip_info->set_mode(st, AD7091R_MODE_COMMAND);
if (ret)
return ret;
@@ -262,7 +380,7 @@ int ad7091r_probe(struct device *dev, const char *name,
}
EXPORT_SYMBOL_NS_GPL(ad7091r_probe, IIO_AD7091R);
-static bool ad7091r_writeable_reg(struct device *dev, unsigned int reg)
+bool ad7091r_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case AD7091R_REG_RESULT:
@@ -272,8 +390,9 @@ static bool ad7091r_writeable_reg(struct device *dev, unsigned int reg)
return true;
}
}
+EXPORT_SYMBOL_NS_GPL(ad7091r_writeable_reg, IIO_AD7091R);
-static bool ad7091r_volatile_reg(struct device *dev, unsigned int reg)
+bool ad7091r_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case AD7091R_REG_RESULT:
@@ -283,14 +402,7 @@ static bool ad7091r_volatile_reg(struct device *dev, unsigned int reg)
return false;
}
}
-
-const struct regmap_config ad7091r_regmap_config = {
- .reg_bits = 8,
- .val_bits = 16,
- .writeable_reg = ad7091r_writeable_reg,
- .volatile_reg = ad7091r_volatile_reg,
-};
-EXPORT_SYMBOL_NS_GPL(ad7091r_regmap_config, IIO_AD7091R);
+EXPORT_SYMBOL_NS_GPL(ad7091r_volatile_reg, IIO_AD7091R);
MODULE_AUTHOR("Beniamin Bia <[email protected]>");
MODULE_DESCRIPTION("Analog Devices AD7091Rx multi-channel converters");
diff --git a/drivers/iio/adc/ad7091r-base.h b/drivers/iio/adc/ad7091r-base.h
index 509748aef9b1..696bf7a897bb 100644
--- a/drivers/iio/adc/ad7091r-base.h
+++ b/drivers/iio/adc/ad7091r-base.h
@@ -8,19 +8,92 @@
#ifndef __DRIVERS_IIO_ADC_AD7091R_BASE_H__
#define __DRIVERS_IIO_ADC_AD7091R_BASE_H__
+#include <linux/regmap.h>
+
+#define AD7091R_REG_RESULT 0
+#define AD7091R_REG_CHANNEL 1
+#define AD7091R_REG_CONF 2
+#define AD7091R_REG_ALERT 3
+#define AD7091R_REG_CH_LOW_LIMIT(ch) ((ch) * 3 + 4)
+#define AD7091R_REG_CH_HIGH_LIMIT(ch) ((ch) * 3 + 5)
+#define AD7091R_REG_CH_HYSTERESIS(ch) ((ch) * 3 + 6)
+
+/* AD7091R_REG_RESULT */
+#define AD7091R5_REG_RESULT_CH_ID(x) (((x) >> 13) & 0x3)
+#define AD7091R8_REG_RESULT_CH_ID(x) (((x) >> 13) & 0x7)
+#define AD7091R_REG_RESULT_CONV_RESULT(x) ((x) & 0xfff)
+
+/* AD7091R_REG_CONF */
+#define AD7091R_REG_CONF_INT_VREF BIT(0)
+#define AD7091R_REG_CONF_ALERT_EN BIT(4)
+#define AD7091R_REG_CONF_AUTO BIT(8)
+#define AD7091R_REG_CONF_CMD BIT(10)
+
+#define AD7091R_REG_CONF_MODE_MASK \
+ (AD7091R_REG_CONF_AUTO | AD7091R_REG_CONF_CMD)
+
+/* AD7091R_REG_CH_LIMIT */
+#define AD7091R_HIGH_LIMIT 0xFFF
+#define AD7091R_LOW_LIMIT 0x0
+
+#define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \
+ .type = IIO_VOLTAGE, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .indexed = 1, \
+ .channel = idx, \
+ .event_spec = ev, \
+ .num_event_specs = num_ev, \
+ .scan_type.storagebits = 16, \
+ .scan_type.realbits = bits, \
+}
+
struct device;
-struct ad7091r_state;
+struct gpio_desc;
+
+enum ad7091r_mode {
+ AD7091R_MODE_SAMPLE,
+ AD7091R_MODE_COMMAND,
+ AD7091R_MODE_AUTOCYCLE,
+};
+
+struct ad7091r_state {
+ struct device *dev;
+ struct regmap *map;
+ struct gpio_desc *convst_gpio;
+ struct gpio_desc *reset_gpio;
+ struct regulator *vref;
+ const struct ad7091r_chip_info *chip_info;
+ enum ad7091r_mode mode;
+ struct mutex lock; /*lock to prevent concurent reads */
+ __be16 tx_buf __aligned(IIO_DMA_MINALIGN);
+ __be16 rx_buf;
+};
struct ad7091r_chip_info {
+ const char *name;
unsigned int num_channels;
const struct iio_chan_spec *channels;
unsigned int vref_mV;
+ unsigned int (*reg_result_chan_id)(unsigned int val);
+ int (*set_mode)(struct ad7091r_state *st, enum ad7091r_mode mode);
};
-extern const struct regmap_config ad7091r_regmap_config;
+struct ad7091r_init_info {
+ const struct ad7091r_chip_info *info_irq;
+ const struct ad7091r_chip_info *info_no_irq;
+ const struct regmap_config *regmap_config;
+ void (*init_adc_regmap)(struct ad7091r_state *st,
+ const struct regmap_config *regmap_conf);
+ int (*setup)(struct ad7091r_state *st);
+};
+
+extern const struct iio_event_spec ad7091r_events[3];
+
+int ad7091r_probe(struct device *dev, const struct ad7091r_init_info *init_info,
+ int irq);
-int ad7091r_probe(struct device *dev, const char *name,
- const struct ad7091r_chip_info *chip_info,
- struct regmap *map, int irq);
+bool ad7091r_volatile_reg(struct device *dev, unsigned int reg);
+bool ad7091r_writeable_reg(struct device *dev, unsigned int reg);
#endif /* __DRIVERS_IIO_ADC_AD7091R_BASE_H__ */
diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c
index 2f048527b7b7..a75837334157 100644
--- a/drivers/iio/adc/ad7091r5.c
+++ b/drivers/iio/adc/ad7091r5.c
@@ -12,42 +12,11 @@
#include "ad7091r-base.h"
-static const struct iio_event_spec ad7091r5_events[] = {
- {
- .type = IIO_EV_TYPE_THRESH,
- .dir = IIO_EV_DIR_RISING,
- .mask_separate = BIT(IIO_EV_INFO_VALUE) |
- BIT(IIO_EV_INFO_ENABLE),
- },
- {
- .type = IIO_EV_TYPE_THRESH,
- .dir = IIO_EV_DIR_FALLING,
- .mask_separate = BIT(IIO_EV_INFO_VALUE) |
- BIT(IIO_EV_INFO_ENABLE),
- },
- {
- .type = IIO_EV_TYPE_THRESH,
- .dir = IIO_EV_DIR_EITHER,
- .mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
- },
-};
-
-#define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \
- .type = IIO_VOLTAGE, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- .indexed = 1, \
- .channel = idx, \
- .event_spec = ev, \
- .num_event_specs = num_ev, \
- .scan_type.storagebits = 16, \
- .scan_type.realbits = bits, \
-}
static const struct iio_chan_spec ad7091r5_channels_irq[] = {
- AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
- AD7091R_CHANNEL(1, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
- AD7091R_CHANNEL(2, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
- AD7091R_CHANNEL(3, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
+ AD7091R_CHANNEL(0, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(1, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(2, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(3, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
};
static const struct iio_chan_spec ad7091r5_channels_noirq[] = {
@@ -57,43 +26,98 @@ static const struct iio_chan_spec ad7091r5_channels_noirq[] = {
AD7091R_CHANNEL(3, 12, NULL, 0),
};
+static int ad7091r5_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode)
+{
+ int ret, conf;
+
+ switch (mode) {
+ case AD7091R_MODE_SAMPLE:
+ conf = 0;
+ break;
+ case AD7091R_MODE_COMMAND:
+ conf = AD7091R_REG_CONF_CMD;
+ break;
+ case AD7091R_MODE_AUTOCYCLE:
+ conf = AD7091R_REG_CONF_AUTO;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(st->map, AD7091R_REG_CONF,
+ AD7091R_REG_CONF_MODE_MASK, conf);
+ if (ret)
+ return ret;
+
+ st->mode = mode;
+
+ return 0;
+}
+
+static unsigned int ad7091r5_reg_result_chan_id(unsigned int val)
+{
+ return AD7091R5_REG_RESULT_CH_ID(val);
+}
+
static const struct ad7091r_chip_info ad7091r5_chip_info_irq = {
+ .name = "ad7091r-5",
.channels = ad7091r5_channels_irq,
.num_channels = ARRAY_SIZE(ad7091r5_channels_irq),
.vref_mV = 2500,
+ .reg_result_chan_id = &ad7091r5_reg_result_chan_id,
+ .set_mode = &ad7091r5_set_mode,
};
static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = {
+ .name = "ad7091r-5",
.channels = ad7091r5_channels_noirq,
.num_channels = ARRAY_SIZE(ad7091r5_channels_noirq),
.vref_mV = 2500,
+ .reg_result_chan_id = &ad7091r5_reg_result_chan_id,
+ .set_mode = &ad7091r5_set_mode,
};
-static int ad7091r5_i2c_probe(struct i2c_client *i2c)
+static const struct regmap_config ad7091r_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .writeable_reg = ad7091r_writeable_reg,
+ .volatile_reg = ad7091r_volatile_reg,
+};
+
+static void ad7091r5_regmap_init(struct ad7091r_state *st,
+ const struct regmap_config *regmap_conf)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
- const struct ad7091r_chip_info *chip_info;
- struct regmap *map = devm_regmap_init_i2c(i2c, &ad7091r_regmap_config);
+ struct i2c_client *i2c = container_of(st->dev, struct i2c_client, dev);
- if (IS_ERR(map))
- return PTR_ERR(map);
+ st->map = devm_regmap_init_i2c(i2c, regmap_conf);
+}
+
+static struct ad7091r_init_info ad7091r5_init_info = {
+ .info_irq = &ad7091r5_chip_info_irq,
+ .info_no_irq = &ad7091r5_chip_info_noirq,
+ .regmap_config = &ad7091r_regmap_config,
+ .init_adc_regmap = &ad7091r5_regmap_init
+};
+
+static int ad7091r5_i2c_probe(struct i2c_client *i2c)
+{
+ const struct ad7091r_init_info *init_info;
- if (i2c->irq)
- chip_info = &ad7091r5_chip_info_irq;
- else
- chip_info = &ad7091r5_chip_info_noirq;
+ init_info = i2c_get_match_data(i2c);
+ if (!init_info)
+ return -EINVAL;
- return ad7091r_probe(&i2c->dev, id->name, chip_info, map, i2c->irq);
+ return ad7091r_probe(&i2c->dev, init_info, i2c->irq);
}
static const struct of_device_id ad7091r5_dt_ids[] = {
- { .compatible = "adi,ad7091r5" },
+ { .compatible = "adi,ad7091r5", .data = &ad7091r5_init_info },
{},
};
MODULE_DEVICE_TABLE(of, ad7091r5_dt_ids);
static const struct i2c_device_id ad7091r5_i2c_ids[] = {
- {"ad7091r5", 0},
+ {"ad7091r5", (kernel_ulong_t)&ad7091r5_init_info },
{}
};
MODULE_DEVICE_TABLE(i2c, ad7091r5_i2c_ids);
diff --git a/drivers/iio/adc/ad7091r8.c b/drivers/iio/adc/ad7091r8.c
new file mode 100644
index 000000000000..57700f124803
--- /dev/null
+++ b/drivers/iio/adc/ad7091r8.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Analog Devices AD7091R8 12-bit SAR ADC driver
+ *
+ * Copyright 2023 Analog Devices Inc.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
+#include <linux/spi/spi.h>
+
+#include "ad7091r-base.h"
+
+#define AD7091R8_REG_ADDR_MSK GENMASK(15, 11)
+#define AD7091R8_RD_WR_FLAG_MSK BIT(10)
+#define AD7091R8_REG_DATA_MSK GENMASK(9, 0)
+
+#define AD7091R_SPI_REGMAP_CONFIG(n) { \
+ .reg_bits = 8, \
+ .val_bits = 16, \
+ .volatile_reg = ad7091r_volatile_reg, \
+ .writeable_reg = ad7091r_writeable_reg, \
+ .max_register = AD7091R_REG_CH_HYSTERESIS(n), \
+}
+
+static int ad7091r8_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode)
+{
+ /* AD7091R-2/-4/-8 don't set sample/command/autocycle mode in conf reg */
+ st->mode = mode;
+ return 0;
+}
+
+static unsigned int ad7091r8_reg_result_chan_id(unsigned int val)
+{
+ return AD7091R8_REG_RESULT_CH_ID(val);
+}
+
+#define AD7091R_SPI_CHIP_INFO(_n, _name) { \
+ .name = _name, \
+ .channels = ad7091r##_n##_channels, \
+ .num_channels = ARRAY_SIZE(ad7091r##_n##_channels), \
+ .vref_mV = 2500, \
+ .reg_result_chan_id = &ad7091r8_reg_result_chan_id, \
+ .set_mode = &ad7091r8_set_mode, \
+}
+
+#define AD7091R_SPI_CHIP_INFO_IRQ(_n, _name) { \
+ .name = _name, \
+ .channels = ad7091r##_n##_channels_irq, \
+ .num_channels = ARRAY_SIZE(ad7091r##_n##_channels_irq), \
+ .vref_mV = 2500, \
+ .reg_result_chan_id = &ad7091r8_reg_result_chan_id, \
+ .set_mode = &ad7091r8_set_mode, \
+}
+
+enum ad7091r8_info_ids {
+ AD7091R2_INFO,
+ AD7091R4_INFO,
+ AD7091R4_INFO_IRQ,
+ AD7091R8_INFO,
+ AD7091R8_INFO_IRQ,
+};
+
+static const struct iio_chan_spec ad7091r2_channels[] = {
+ AD7091R_CHANNEL(0, 12, NULL, 0),
+ AD7091R_CHANNEL(1, 12, NULL, 0),
+};
+
+static const struct iio_chan_spec ad7091r4_channels[] = {
+ AD7091R_CHANNEL(0, 12, NULL, 0),
+ AD7091R_CHANNEL(1, 12, NULL, 0),
+ AD7091R_CHANNEL(2, 12, NULL, 0),
+ AD7091R_CHANNEL(3, 12, NULL, 0),
+};
+
+static const struct iio_chan_spec ad7091r4_channels_irq[] = {
+ AD7091R_CHANNEL(0, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(1, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(2, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(3, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+};
+
+static const struct iio_chan_spec ad7091r8_channels[] = {
+ AD7091R_CHANNEL(0, 12, NULL, 0),
+ AD7091R_CHANNEL(1, 12, NULL, 0),
+ AD7091R_CHANNEL(2, 12, NULL, 0),
+ AD7091R_CHANNEL(3, 12, NULL, 0),
+ AD7091R_CHANNEL(4, 12, NULL, 0),
+ AD7091R_CHANNEL(5, 12, NULL, 0),
+ AD7091R_CHANNEL(6, 12, NULL, 0),
+ AD7091R_CHANNEL(7, 12, NULL, 0),
+};
+
+static const struct iio_chan_spec ad7091r8_channels_irq[] = {
+ AD7091R_CHANNEL(0, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(1, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(2, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(3, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(4, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(5, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(6, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+ AD7091R_CHANNEL(7, 12, ad7091r_events, ARRAY_SIZE(ad7091r_events)),
+};
+
+static void ad7091r_pulse_convst(struct ad7091r_state *st)
+{
+ gpiod_set_value_cansleep(st->convst_gpio, 1);
+ gpiod_set_value_cansleep(st->convst_gpio, 0);
+}
+
+static int ad7091r_regmap_bus_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct ad7091r_state *st = context;
+ struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
+ int ret;
+
+ struct spi_transfer t[] = {
+ {
+ .tx_buf = &st->tx_buf,
+ .len = 2,
+ .cs_change = 1,
+ }, {
+ .rx_buf = &st->rx_buf,
+ .len = 2,
+ }
+ };
+
+ if (reg == AD7091R_REG_RESULT)
+ ad7091r_pulse_convst(st);
+
+ st->tx_buf = cpu_to_be16(reg << 11);
+
+ ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t));
+ if (ret < 0)
+ return ret;
+
+ *val = be16_to_cpu(st->rx_buf);
+ return 0;
+}
+
+static int ad7091r_regmap_bus_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct ad7091r_state *st = context;
+ struct spi_device *spi = container_of(st->dev, struct spi_device, dev);
+
+ /*
+ * AD7091R-2/-4/-8 protocol (datasheet page 31) is to do a single SPI
+ * transfer with reg address set in bits B15:B11 and value set in B9:B0.
+ */
+ st->tx_buf = cpu_to_be16(FIELD_PREP(AD7091R8_REG_DATA_MSK, val) |
+ FIELD_PREP(AD7091R8_RD_WR_FLAG_MSK, 1) |
+ FIELD_PREP(AD7091R8_REG_ADDR_MSK, reg));
+
+ return spi_write(spi, &st->tx_buf, 2);
+}
+
+static struct regmap_bus ad7091r8_regmap_bus = {
+ .reg_read = ad7091r_regmap_bus_reg_read,
+ .reg_write = ad7091r_regmap_bus_reg_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_BIG,
+ .val_format_endian_default = REGMAP_ENDIAN_BIG,
+};
+
+static const struct ad7091r_chip_info ad7091r8_infos[] = {
+ [AD7091R2_INFO] = AD7091R_SPI_CHIP_INFO(2, "ad7091r-2"),
+ [AD7091R4_INFO] = AD7091R_SPI_CHIP_INFO(4, "ad7091r-4"),
+ [AD7091R4_INFO_IRQ] = AD7091R_SPI_CHIP_INFO_IRQ(4, "ad7091r-4"),
+ [AD7091R8_INFO] = AD7091R_SPI_CHIP_INFO(8, "ad7091r-8"),
+ [AD7091R8_INFO_IRQ] = AD7091R_SPI_CHIP_INFO_IRQ(8, "ad7091r-8")
+};
+
+static const struct regmap_config ad7091r2_reg_conf = AD7091R_SPI_REGMAP_CONFIG(2);
+static const struct regmap_config ad7091r4_reg_conf = AD7091R_SPI_REGMAP_CONFIG(4);
+static const struct regmap_config ad7091r8_reg_conf = AD7091R_SPI_REGMAP_CONFIG(8);
+
+static void ad7091r8_regmap_init(struct ad7091r_state *st,
+ const struct regmap_config *regmap_conf)
+{
+ st->map = devm_regmap_init(st->dev, &ad7091r8_regmap_bus, st,
+ regmap_conf);
+}
+
+static int ad7091r8_gpio_setup(struct ad7091r_state *st)
+{
+ st->convst_gpio = devm_gpiod_get(st->dev, "convst", GPIOD_OUT_LOW);
+ if (IS_ERR(st->convst_gpio))
+ return dev_err_probe(st->dev, PTR_ERR(st->convst_gpio),
+ "Error getting convst GPIO\n");
+
+ st->reset_gpio = devm_gpiod_get_optional(st->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(st->reset_gpio))
+ return dev_err_probe(st->dev, PTR_ERR(st->convst_gpio),
+ "Error on requesting reset GPIO\n");
+
+ if (st->reset_gpio) {
+ fsleep(20);
+ gpiod_set_value_cansleep(st->reset_gpio, 0);
+ }
+
+ return 0;
+}
+
+static struct ad7091r_init_info ad7091r2_init_info = {
+ .info_no_irq = &ad7091r8_infos[AD7091R2_INFO],
+ .regmap_config = &ad7091r2_reg_conf,
+ .init_adc_regmap = &ad7091r8_regmap_init,
+ .setup = &ad7091r8_gpio_setup
+};
+
+static struct ad7091r_init_info ad7091r4_init_info = {
+ .info_no_irq = &ad7091r8_infos[AD7091R4_INFO],
+ .info_irq = &ad7091r8_infos[AD7091R4_INFO_IRQ],
+ .regmap_config = &ad7091r4_reg_conf,
+ .init_adc_regmap = &ad7091r8_regmap_init,
+ .setup = &ad7091r8_gpio_setup
+};
+
+static struct ad7091r_init_info ad7091r8_init_info = {
+ .info_no_irq = &ad7091r8_infos[AD7091R8_INFO],
+ .info_irq = &ad7091r8_infos[AD7091R8_INFO_IRQ],
+ .regmap_config = &ad7091r8_reg_conf,
+ .init_adc_regmap = &ad7091r8_regmap_init,
+ .setup = &ad7091r8_gpio_setup
+};
+
+static int ad7091r8_spi_probe(struct spi_device *spi)
+{
+ const struct ad7091r_init_info *init_info;
+
+ init_info = spi_get_device_match_data(spi);
+ if (!init_info)
+ return -EINVAL;
+
+ return ad7091r_probe(&spi->dev, init_info, spi->irq);
+}
+
+static const struct of_device_id ad7091r8_of_match[] = {
+ { .compatible = "adi,ad7091r2", .data = &ad7091r2_init_info },
+ { .compatible = "adi,ad7091r4", .data = &ad7091r4_init_info },
+ { .compatible = "adi,ad7091r8", .data = &ad7091r8_init_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad7091r8_of_match);
+
+static const struct spi_device_id ad7091r8_spi_id[] = {
+ { "ad7091r2", (kernel_ulong_t)&ad7091r2_init_info },
+ { "ad7091r4", (kernel_ulong_t)&ad7091r4_init_info },
+ { "ad7091r8", (kernel_ulong_t)&ad7091r8_init_info },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad7091r8_spi_id);
+
+static struct spi_driver ad7091r8_driver = {
+ .driver = {
+ .name = "ad7091r8",
+ .of_match_table = ad7091r8_of_match,
+ },
+ .probe = ad7091r8_spi_probe,
+ .id_table = ad7091r8_spi_id,
+};
+module_spi_driver(ad7091r8_driver);
+
+MODULE_AUTHOR("Marcelo Schmitt <[email protected]>");
+MODULE_DESCRIPTION("Analog Devices AD7091R8 ADC driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_AD7091R);
diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c
index 39eccc28debe..6581fce4ba95 100644
--- a/drivers/iio/adc/ad9467.c
+++ b/drivers/iio/adc/ad9467.c
@@ -4,8 +4,9 @@
*
* Copyright 2012-2020 Analog Devices Inc.
*/
-
+#include <linux/cleanup.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -100,12 +101,6 @@
#define AD9467_DEF_OUTPUT_MODE 0x08
#define AD9467_REG_VREF_MASK 0x0F
-enum {
- ID_AD9265,
- ID_AD9434,
- ID_AD9467,
-};
-
struct ad9467_chip_info {
struct adi_axi_adc_chip_info axi_adc_info;
unsigned int default_output_mode;
@@ -119,9 +114,11 @@ struct ad9467_state {
struct spi_device *spi;
struct clk *clk;
unsigned int output_mode;
+ unsigned int (*scales)[2];
struct gpio_desc *pwrdown_gpio;
- struct gpio_desc *reset_gpio;
+ /* ensure consistent state obtained on multiple related accesses */
+ struct mutex lock;
};
static int ad9467_spi_read(struct spi_device *spi, unsigned int reg)
@@ -161,11 +158,13 @@ static int ad9467_reg_access(struct adi_axi_adc_conv *conv, unsigned int reg,
struct spi_device *spi = st->spi;
int ret;
- if (readval == NULL) {
+ if (!readval) {
+ guard(mutex)(&st->lock);
ret = ad9467_spi_write(spi, reg, writeval);
- ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER,
- AN877_ADC_TRANSFER_SYNC);
- return ret;
+ if (ret)
+ return ret;
+ return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER,
+ AN877_ADC_TRANSFER_SYNC);
}
ret = ad9467_spi_read(spi, reg);
@@ -212,6 +211,7 @@ static void __ad9467_get_scale(struct adi_axi_adc_conv *conv, int index,
.channel = _chan, \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = _si, \
.scan_type = { \
.sign = _sign, \
@@ -228,43 +228,46 @@ static const struct iio_chan_spec ad9467_channels[] = {
AD9467_CHAN(0, 0, 16, 'S'),
};
-static const struct ad9467_chip_info ad9467_chip_tbl[] = {
- [ID_AD9265] = {
- .axi_adc_info = {
- .id = CHIPID_AD9265,
- .max_rate = 125000000UL,
- .scale_table = ad9265_scale_table,
- .num_scales = ARRAY_SIZE(ad9265_scale_table),
- .channels = ad9467_channels,
- .num_channels = ARRAY_SIZE(ad9467_channels),
- },
- .default_output_mode = AD9265_DEF_OUTPUT_MODE,
- .vref_mask = AD9265_REG_VREF_MASK,
+static const struct ad9467_chip_info ad9467_chip_tbl = {
+ .axi_adc_info = {
+ .name = "ad9467",
+ .id = CHIPID_AD9467,
+ .max_rate = 250000000UL,
+ .scale_table = ad9467_scale_table,
+ .num_scales = ARRAY_SIZE(ad9467_scale_table),
+ .channels = ad9467_channels,
+ .num_channels = ARRAY_SIZE(ad9467_channels),
},
- [ID_AD9434] = {
- .axi_adc_info = {
- .id = CHIPID_AD9434,
- .max_rate = 500000000UL,
- .scale_table = ad9434_scale_table,
- .num_scales = ARRAY_SIZE(ad9434_scale_table),
- .channels = ad9434_channels,
- .num_channels = ARRAY_SIZE(ad9434_channels),
- },
- .default_output_mode = AD9434_DEF_OUTPUT_MODE,
- .vref_mask = AD9434_REG_VREF_MASK,
+ .default_output_mode = AD9467_DEF_OUTPUT_MODE,
+ .vref_mask = AD9467_REG_VREF_MASK,
+};
+
+static const struct ad9467_chip_info ad9434_chip_tbl = {
+ .axi_adc_info = {
+ .name = "ad9434",
+ .id = CHIPID_AD9434,
+ .max_rate = 500000000UL,
+ .scale_table = ad9434_scale_table,
+ .num_scales = ARRAY_SIZE(ad9434_scale_table),
+ .channels = ad9434_channels,
+ .num_channels = ARRAY_SIZE(ad9434_channels),
},
- [ID_AD9467] = {
- .axi_adc_info = {
- .id = CHIPID_AD9467,
- .max_rate = 250000000UL,
- .scale_table = ad9467_scale_table,
- .num_scales = ARRAY_SIZE(ad9467_scale_table),
- .channels = ad9467_channels,
- .num_channels = ARRAY_SIZE(ad9467_channels),
- },
- .default_output_mode = AD9467_DEF_OUTPUT_MODE,
- .vref_mask = AD9467_REG_VREF_MASK,
+ .default_output_mode = AD9434_DEF_OUTPUT_MODE,
+ .vref_mask = AD9434_REG_VREF_MASK,
+};
+
+static const struct ad9467_chip_info ad9265_chip_tbl = {
+ .axi_adc_info = {
+ .name = "ad9265",
+ .id = CHIPID_AD9265,
+ .max_rate = 125000000UL,
+ .scale_table = ad9265_scale_table,
+ .num_scales = ARRAY_SIZE(ad9265_scale_table),
+ .channels = ad9467_channels,
+ .num_channels = ARRAY_SIZE(ad9467_channels),
},
+ .default_output_mode = AD9265_DEF_OUTPUT_MODE,
+ .vref_mask = AD9265_REG_VREF_MASK,
};
static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2)
@@ -273,10 +276,13 @@ static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2)
const struct ad9467_chip_info *info1 = to_ad9467_chip_info(info);
struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
unsigned int i, vref_val;
+ int ret;
- vref_val = ad9467_spi_read(st->spi, AN877_ADC_REG_VREF);
+ ret = ad9467_spi_read(st->spi, AN877_ADC_REG_VREF);
+ if (ret < 0)
+ return ret;
- vref_val &= info1->vref_mask;
+ vref_val = ret & info1->vref_mask;
for (i = 0; i < info->num_scales; i++) {
if (vref_val == info->scale_table[i][1])
@@ -297,6 +303,7 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2)
struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
unsigned int scale_val[2];
unsigned int i;
+ int ret;
if (val != 0)
return -EINVAL;
@@ -306,11 +313,14 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2)
if (scale_val[0] != val || scale_val[1] != val2)
continue;
- ad9467_spi_write(st->spi, AN877_ADC_REG_VREF,
- info->scale_table[i][1]);
- ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
- AN877_ADC_TRANSFER_SYNC);
- return 0;
+ guard(mutex)(&st->lock);
+ ret = ad9467_spi_write(st->spi, AN877_ADC_REG_VREF,
+ info->scale_table[i][1]);
+ if (ret < 0)
+ return ret;
+
+ return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
+ AN877_ADC_TRANSFER_SYNC);
}
return -EINVAL;
@@ -359,6 +369,26 @@ static int ad9467_write_raw(struct adi_axi_adc_conv *conv,
}
}
+static int ad9467_read_avail(struct adi_axi_adc_conv *conv,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ const struct adi_axi_adc_chip_info *info = conv->chip_info;
+ struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (const int *)st->scales;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ /* Values are stored in a 2D matrix */
+ *length = info->num_scales * 2;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode)
{
int ret;
@@ -371,6 +401,26 @@ static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode)
AN877_ADC_TRANSFER_SYNC);
}
+static int ad9467_scale_fill(struct adi_axi_adc_conv *conv)
+{
+ const struct adi_axi_adc_chip_info *info = conv->chip_info;
+ struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+ unsigned int i, val1, val2;
+
+ st->scales = devm_kmalloc_array(&st->spi->dev, info->num_scales,
+ sizeof(*st->scales), GFP_KERNEL);
+ if (!st->scales)
+ return -ENOMEM;
+
+ for (i = 0; i < info->num_scales; i++) {
+ __ad9467_get_scale(conv, i, &val1, &val2);
+ st->scales[i][0] = val1;
+ st->scales[i][1] = val2;
+ }
+
+ return 0;
+}
+
static int ad9467_preenable_setup(struct adi_axi_adc_conv *conv)
{
struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
@@ -378,6 +428,21 @@ static int ad9467_preenable_setup(struct adi_axi_adc_conv *conv)
return ad9467_outputmode_set(st->spi, st->output_mode);
}
+static int ad9467_reset(struct device *dev)
+{
+ struct gpio_desc *gpio;
+
+ gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR_OR_NULL(gpio))
+ return PTR_ERR_OR_ZERO(gpio);
+
+ fsleep(1);
+ gpiod_set_value_cansleep(gpio, 0);
+ fsleep(10 * USEC_PER_MSEC);
+
+ return 0;
+}
+
static int ad9467_probe(struct spi_device *spi)
{
const struct ad9467_chip_info *info;
@@ -386,9 +451,7 @@ static int ad9467_probe(struct spi_device *spi)
unsigned int id;
int ret;
- info = of_device_get_match_data(&spi->dev);
- if (!info)
- info = (void *)spi_get_device_id(spi)->driver_data;
+ info = spi_get_device_match_data(spi);
if (!info)
return -ENODEV;
@@ -408,21 +471,16 @@ static int ad9467_probe(struct spi_device *spi)
if (IS_ERR(st->pwrdown_gpio))
return PTR_ERR(st->pwrdown_gpio);
- st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
- GPIOD_OUT_LOW);
- if (IS_ERR(st->reset_gpio))
- return PTR_ERR(st->reset_gpio);
-
- if (st->reset_gpio) {
- udelay(1);
- ret = gpiod_direction_output(st->reset_gpio, 1);
- if (ret)
- return ret;
- mdelay(10);
- }
+ ret = ad9467_reset(&spi->dev);
+ if (ret)
+ return ret;
conv->chip_info = &info->axi_adc_info;
+ ret = ad9467_scale_fill(conv);
+ if (ret)
+ return ret;
+
id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID);
if (id != conv->chip_info->id) {
dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n",
@@ -433,6 +491,7 @@ static int ad9467_probe(struct spi_device *spi)
conv->reg_access = ad9467_reg_access;
conv->write_raw = ad9467_write_raw;
conv->read_raw = ad9467_read_raw;
+ conv->read_avail = ad9467_read_avail;
conv->preenable_setup = ad9467_preenable_setup;
st->output_mode = info->default_output_mode |
@@ -442,17 +501,17 @@ static int ad9467_probe(struct spi_device *spi)
}
static const struct of_device_id ad9467_of_match[] = {
- { .compatible = "adi,ad9265", .data = &ad9467_chip_tbl[ID_AD9265], },
- { .compatible = "adi,ad9434", .data = &ad9467_chip_tbl[ID_AD9434], },
- { .compatible = "adi,ad9467", .data = &ad9467_chip_tbl[ID_AD9467], },
+ { .compatible = "adi,ad9265", .data = &ad9265_chip_tbl, },
+ { .compatible = "adi,ad9434", .data = &ad9434_chip_tbl, },
+ { .compatible = "adi,ad9467", .data = &ad9467_chip_tbl, },
{}
};
MODULE_DEVICE_TABLE(of, ad9467_of_match);
static const struct spi_device_id ad9467_ids[] = {
- { "ad9265", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9265] },
- { "ad9434", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9434] },
- { "ad9467", (kernel_ulong_t)&ad9467_chip_tbl[ID_AD9467] },
+ { "ad9265", (kernel_ulong_t)&ad9265_chip_tbl },
+ { "ad9434", (kernel_ulong_t)&ad9434_chip_tbl },
+ { "ad9467", (kernel_ulong_t)&ad9467_chip_tbl },
{}
};
MODULE_DEVICE_TABLE(spi, ad9467_ids);
diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c
index aff0532a974a..c247ff1541d2 100644
--- a/drivers/iio/adc/adi-axi-adc.c
+++ b/drivers/iio/adc/adi-axi-adc.c
@@ -14,6 +14,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
@@ -62,7 +63,7 @@ struct adi_axi_adc_state {
struct mutex lock;
struct adi_axi_adc_client *client;
- void __iomem *regs;
+ struct regmap *regmap;
};
struct adi_axi_adc_client {
@@ -90,19 +91,6 @@ void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv)
}
EXPORT_SYMBOL_NS_GPL(adi_axi_adc_conv_priv, IIO_ADI_AXI);
-static void adi_axi_adc_write(struct adi_axi_adc_state *st,
- unsigned int reg,
- unsigned int val)
-{
- iowrite32(val, st->regs + reg);
-}
-
-static unsigned int adi_axi_adc_read(struct adi_axi_adc_state *st,
- unsigned int reg)
-{
- return ioread32(st->regs + reg);
-}
-
static int adi_axi_adc_config_dma_buffer(struct device *dev,
struct iio_dev *indio_dev)
{
@@ -144,22 +132,39 @@ static int adi_axi_adc_write_raw(struct iio_dev *indio_dev,
return conv->write_raw(conv, chan, val, val2, mask);
}
+static int adi_axi_adc_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ struct adi_axi_adc_state *st = iio_priv(indio_dev);
+ struct adi_axi_adc_conv *conv = &st->client->conv;
+
+ if (!conv->read_avail)
+ return -EOPNOTSUPP;
+
+ return conv->read_avail(conv, chan, vals, type, length, mask);
+}
+
static int adi_axi_adc_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct adi_axi_adc_state *st = iio_priv(indio_dev);
struct adi_axi_adc_conv *conv = &st->client->conv;
- unsigned int i, ctrl;
+ unsigned int i;
+ int ret;
for (i = 0; i < conv->chip_info->num_channels; i++) {
- ctrl = adi_axi_adc_read(st, ADI_AXI_REG_CHAN_CTRL(i));
-
if (test_bit(i, scan_mask))
- ctrl |= ADI_AXI_REG_CHAN_CTRL_ENABLE;
+ ret = regmap_set_bits(st->regmap,
+ ADI_AXI_REG_CHAN_CTRL(i),
+ ADI_AXI_REG_CHAN_CTRL_ENABLE);
else
- ctrl &= ~ADI_AXI_REG_CHAN_CTRL_ENABLE;
-
- adi_axi_adc_write(st, ADI_AXI_REG_CHAN_CTRL(i), ctrl);
+ ret = regmap_clear_bits(st->regmap,
+ ADI_AXI_REG_CHAN_CTRL(i),
+ ADI_AXI_REG_CHAN_CTRL_ENABLE);
+ if (ret)
+ return ret;
}
return 0;
@@ -228,69 +233,11 @@ struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev,
}
EXPORT_SYMBOL_NS_GPL(devm_adi_axi_adc_conv_register, IIO_ADI_AXI);
-static ssize_t in_voltage_scale_available_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct adi_axi_adc_state *st = iio_priv(indio_dev);
- struct adi_axi_adc_conv *conv = &st->client->conv;
- size_t len = 0;
- int i;
-
- for (i = 0; i < conv->chip_info->num_scales; i++) {
- const unsigned int *s = conv->chip_info->scale_table[i];
-
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "%u.%06u ", s[0], s[1]);
- }
- buf[len - 1] = '\n';
-
- return len;
-}
-
-static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0);
-
-enum {
- ADI_AXI_ATTR_SCALE_AVAIL,
-};
-
-#define ADI_AXI_ATTR(_en_, _file_) \
- [ADI_AXI_ATTR_##_en_] = &iio_dev_attr_##_file_.dev_attr.attr
-
-static struct attribute *adi_axi_adc_attributes[] = {
- ADI_AXI_ATTR(SCALE_AVAIL, in_voltage_scale_available),
- NULL
-};
-
-static umode_t axi_adc_attr_is_visible(struct kobject *kobj,
- struct attribute *attr, int n)
-{
- struct device *dev = kobj_to_dev(kobj);
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct adi_axi_adc_state *st = iio_priv(indio_dev);
- struct adi_axi_adc_conv *conv = &st->client->conv;
-
- switch (n) {
- case ADI_AXI_ATTR_SCALE_AVAIL:
- if (!conv->chip_info->num_scales)
- return 0;
- return attr->mode;
- default:
- return attr->mode;
- }
-}
-
-static const struct attribute_group adi_axi_adc_attribute_group = {
- .attrs = adi_axi_adc_attributes,
- .is_visible = axi_adc_attr_is_visible,
-};
-
static const struct iio_info adi_axi_adc_info = {
.read_raw = &adi_axi_adc_read_raw,
.write_raw = &adi_axi_adc_write_raw,
- .attrs = &adi_axi_adc_attribute_group,
.update_scan_mode = &adi_axi_adc_update_scan_mode,
+ .read_avail = &adi_axi_adc_read_avail,
};
static const struct adi_axi_adc_core_info adi_axi_adc_10_0_a_info = {
@@ -354,21 +301,32 @@ static int adi_axi_adc_setup_channels(struct device *dev,
}
for (i = 0; i < conv->chip_info->num_channels; i++) {
- adi_axi_adc_write(st, ADI_AXI_REG_CHAN_CTRL(i),
- ADI_AXI_REG_CHAN_CTRL_DEFAULTS);
+ ret = regmap_write(st->regmap, ADI_AXI_REG_CHAN_CTRL(i),
+ ADI_AXI_REG_CHAN_CTRL_DEFAULTS);
+ if (ret)
+ return ret;
}
return 0;
}
-static void axi_adc_reset(struct adi_axi_adc_state *st)
+static int axi_adc_reset(struct adi_axi_adc_state *st)
{
- adi_axi_adc_write(st, ADI_AXI_REG_RSTN, 0);
+ int ret;
+
+ ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN, 0);
+ if (ret)
+ return ret;
+
mdelay(10);
- adi_axi_adc_write(st, ADI_AXI_REG_RSTN, ADI_AXI_REG_RSTN_MMCM_RSTN);
+ ret = regmap_write(st->regmap, ADI_AXI_REG_RSTN,
+ ADI_AXI_REG_RSTN_MMCM_RSTN);
+ if (ret)
+ return ret;
+
mdelay(10);
- adi_axi_adc_write(st, ADI_AXI_REG_RSTN,
- ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN);
+ return regmap_write(st->regmap, ADI_AXI_REG_RSTN,
+ ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN);
}
static void adi_axi_adc_cleanup(void *data)
@@ -379,12 +337,20 @@ static void adi_axi_adc_cleanup(void *data)
module_put(cl->dev->driver->owner);
}
+static const struct regmap_config axi_adc_regmap_config = {
+ .val_bits = 32,
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x0800,
+};
+
static int adi_axi_adc_probe(struct platform_device *pdev)
{
struct adi_axi_adc_conv *conv;
struct iio_dev *indio_dev;
struct adi_axi_adc_client *cl;
struct adi_axi_adc_state *st;
+ void __iomem *base;
unsigned int ver;
int ret;
@@ -405,15 +371,24 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
cl->state = st;
mutex_init(&st->lock);
- st->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(st->regs))
- return PTR_ERR(st->regs);
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ st->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &axi_adc_regmap_config);
+ if (IS_ERR(st->regmap))
+ return PTR_ERR(st->regmap);
conv = &st->client->conv;
- axi_adc_reset(st);
+ ret = axi_adc_reset(st);
+ if (ret)
+ return ret;
- ver = adi_axi_adc_read(st, ADI_AXI_REG_VERSION);
+ ret = regmap_read(st->regmap, ADI_AXI_REG_VERSION, &ver);
+ if (ret)
+ return ret;
if (cl->info->version > ver) {
dev_err(&pdev->dev,
diff --git a/drivers/iio/adc/max34408.c b/drivers/iio/adc/max34408.c
new file mode 100644
index 000000000000..6c2ea2bc52c6
--- /dev/null
+++ b/drivers/iio/adc/max34408.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IIO driver for Maxim MAX34409/34408 ADC, 4-Channels/2-Channels, 8bits, I2C
+ *
+ * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX34408-MAX34409.pdf
+ *
+ * TODO: ALERT interrupt, Overcurrent delay, Shutdown delay
+ */
+
+#include <linux/bitfield.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/types.h>
+
+#define MAX34408_STATUS_REG 0x0
+#define MAX34408_CONTROL_REG 0x1
+#define MAX34408_OCDELAY_REG 0x2
+#define MAX34408_SDDELAY_REG 0x3
+
+#define MAX34408_ADC1_REG 0x4
+#define MAX34408_ADC2_REG 0x5
+/* ADC3 & ADC4 always returns 0x0 on 34408 */
+#define MAX34409_ADC3_REG 0x6
+#define MAX34409_ADC4_REG 0x7
+
+#define MAX34408_OCT1_REG 0x8
+#define MAX34408_OCT2_REG 0x9
+#define MAX34409_OCT3_REG 0xA
+#define MAX34409_OCT4_REG 0xB
+
+#define MAX34408_DID_REG 0xC
+#define MAX34408_DCYY_REG 0xD
+#define MAX34408_DCWW_REG 0xE
+
+/* Bit masks for status register */
+#define MAX34408_STATUS_OC_MSK GENMASK(1, 0)
+#define MAX34409_STATUS_OC_MSK GENMASK(3, 0)
+#define MAX34408_STATUS_SHTDN BIT(4)
+#define MAX34408_STATUS_ENA BIT(5)
+
+/* Bit masks for control register */
+#define MAX34408_CONTROL_AVG0 BIT(0)
+#define MAX34408_CONTROL_AVG1 BIT(1)
+#define MAX34408_CONTROL_AVG2 BIT(2)
+#define MAX34408_CONTROL_ALERT BIT(3)
+
+#define MAX34408_DEFAULT_AVG 0x4
+
+/* Bit masks for over current delay */
+#define MAX34408_OCDELAY_OCD_MSK GENMASK(6, 0)
+#define MAX34408_OCDELAY_RESET BIT(7)
+
+/* Bit masks for shutdown delay */
+#define MAX34408_SDDELAY_SHD_MSK GENMASK(6, 0)
+#define MAX34408_SDDELAY_RESET BIT(7)
+
+#define MAX34408_DEFAULT_RSENSE 1000
+
+/**
+ * struct max34408_data - max34408/max34409 specific data.
+ * @regmap: device register map.
+ * @dev: max34408 device.
+ * @lock: lock for protecting access to device hardware registers, mostly
+ * for read modify write cycles for control registers.
+ * @input_rsense: Rsense values in uOhm, will be overwritten by
+ * values from channel nodes.
+ */
+struct max34408_data {
+ struct regmap *regmap;
+ struct device *dev;
+ struct mutex lock;
+ u32 input_rsense[4];
+};
+
+static const struct regmap_config max34408_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MAX34408_DCWW_REG,
+};
+
+struct max34408_adc_model_data {
+ const char *model_name;
+ const struct iio_chan_spec *channels;
+ const int num_channels;
+};
+
+#define MAX34008_CHANNEL(_index, _address) \
+ { \
+ .type = IIO_CURRENT, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+ .channel = (_index), \
+ .address = (_address), \
+ .indexed = 1, \
+ }
+
+static const struct iio_chan_spec max34408_channels[] = {
+ MAX34008_CHANNEL(0, MAX34408_ADC1_REG),
+ MAX34008_CHANNEL(1, MAX34408_ADC2_REG),
+};
+
+static const struct iio_chan_spec max34409_channels[] = {
+ MAX34008_CHANNEL(0, MAX34408_ADC1_REG),
+ MAX34008_CHANNEL(1, MAX34408_ADC2_REG),
+ MAX34008_CHANNEL(2, MAX34409_ADC3_REG),
+ MAX34008_CHANNEL(3, MAX34409_ADC4_REG),
+};
+
+static int max34408_read_adc_avg(struct max34408_data *max34408,
+ const struct iio_chan_spec *chan, int *val)
+{
+ unsigned int ctrl;
+ int rc;
+
+ guard(mutex)(&max34408->lock);
+ rc = regmap_read(max34408->regmap, MAX34408_CONTROL_REG, (u32 *)&ctrl);
+ if (rc)
+ return rc;
+
+ /* set averaging (0b100) default values*/
+ rc = regmap_write(max34408->regmap, MAX34408_CONTROL_REG,
+ MAX34408_DEFAULT_AVG);
+ if (rc) {
+ dev_err(max34408->dev,
+ "Error (%d) writing control register\n", rc);
+ return rc;
+ }
+
+ rc = regmap_read(max34408->regmap, chan->address, val);
+ if (rc)
+ return rc;
+
+ /* back to old values */
+ rc = regmap_write(max34408->regmap, MAX34408_CONTROL_REG, ctrl);
+ if (rc)
+ dev_err(max34408->dev,
+ "Error (%d) writing control register\n", rc);
+
+ return rc;
+}
+
+static int max34408_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct max34408_data *max34408 = iio_priv(indio_dev);
+ int rc;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ rc = max34408_read_adc_avg(max34408, chan, val);
+ if (rc)
+ return rc;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ /*
+ * calcluate current for 8bit ADC with Rsense
+ * value.
+ * 10 mV * 1000 / Rsense uOhm = max current
+ * (max current * adc val * 1000) / (2^8 - 1) mA
+ */
+ *val = 10000 / max34408->input_rsense[chan->channel];
+ *val2 = 8;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info max34408_info = {
+ .read_raw = max34408_read_raw,
+};
+
+static const struct max34408_adc_model_data max34408_model_data = {
+ .model_name = "max34408",
+ .channels = max34408_channels,
+ .num_channels = 2,
+};
+
+static const struct max34408_adc_model_data max34409_model_data = {
+ .model_name = "max34409",
+ .channels = max34409_channels,
+ .num_channels = 4,
+};
+
+static int max34408_probe(struct i2c_client *client)
+{
+ const struct max34408_adc_model_data *model_data;
+ struct device *dev = &client->dev;
+ struct max34408_data *max34408;
+ struct fwnode_handle *node;
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ int rc, i = 0;
+
+ model_data = i2c_get_match_data(client);
+ if (!model_data)
+ return -EINVAL;
+
+ regmap = devm_regmap_init_i2c(client, &max34408_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err_probe(dev, PTR_ERR(regmap),
+ "regmap_init failed\n");
+ return PTR_ERR(regmap);
+ }
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*max34408));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ max34408 = iio_priv(indio_dev);
+ max34408->regmap = regmap;
+ max34408->dev = dev;
+ mutex_init(&max34408->lock);
+
+ device_for_each_child_node(dev, node) {
+ fwnode_property_read_u32(node, "maxim,rsense-val-micro-ohms",
+ &max34408->input_rsense[i]);
+ i++;
+ }
+
+ /* disable ALERT and averaging */
+ rc = regmap_write(max34408->regmap, MAX34408_CONTROL_REG, 0x0);
+ if (rc)
+ return rc;
+
+ indio_dev->channels = model_data->channels;
+ indio_dev->num_channels = model_data->num_channels;
+ indio_dev->name = model_data->model_name;
+
+ indio_dev->info = &max34408_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id max34408_of_match[] = {
+ {
+ .compatible = "maxim,max34408",
+ .data = &max34408_model_data,
+ },
+ {
+ .compatible = "maxim,max34409",
+ .data = &max34409_model_data,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, max34408_of_match);
+
+static const struct i2c_device_id max34408_id[] = {
+ { "max34408", (kernel_ulong_t)&max34408_model_data },
+ { "max34409", (kernel_ulong_t)&max34409_model_data },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, max34408_id);
+
+static struct i2c_driver max34408_driver = {
+ .driver = {
+ .name = "max34408",
+ .of_match_table = max34408_of_match,
+ },
+ .probe = max34408_probe,
+ .id_table = max34408_id,
+};
+module_i2c_driver(max34408_driver);
+
+MODULE_AUTHOR("Ivan Mikhaylov <[email protected]>");
+MODULE_DESCRIPTION("Maxim MAX34408/34409 ADC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c
index d864558bc087..7a32e7a1be9d 100644
--- a/drivers/iio/adc/mcp3911.c
+++ b/drivers/iio/adc/mcp3911.c
@@ -7,6 +7,7 @@
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -316,47 +317,37 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct mcp3911 *adc = iio_priv(indio_dev);
- int ret = -EINVAL;
+ int ret;
- mutex_lock(&adc->lock);
+ guard(mutex)(&adc->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = mcp3911_read(adc,
MCP3911_CHANNEL(channel->channel), val, 3);
if (ret)
- goto out;
+ return ret;
*val = sign_extend32(*val, 23);
-
- ret = IIO_VAL_INT;
- break;
-
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
-
ret = adc->chip->get_offset(adc, channel->channel, val);
if (ret)
- goto out;
+ return ret;
- ret = IIO_VAL_INT;
- break;
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
ret = adc->chip->get_osr(adc, val);
if (ret)
- goto out;
-
- ret = IIO_VAL_INT;
- break;
+ return ret;
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = mcp3911_scale_table[ilog2(adc->gain[channel->channel])][0];
*val2 = mcp3911_scale_table[ilog2(adc->gain[channel->channel])][1];
- ret = IIO_VAL_INT_PLUS_NANO;
- break;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
}
-
-out:
- mutex_unlock(&adc->lock);
- return ret;
}
static int mcp3911_write_raw(struct iio_dev *indio_dev,
@@ -364,9 +355,8 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev,
int val2, long mask)
{
struct mcp3911 *adc = iio_priv(indio_dev);
- int ret = -EINVAL;
- mutex_lock(&adc->lock);
+ guard(mutex)(&adc->lock);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
for (int i = 0; i < MCP3911_NUM_SCALES; i++) {
@@ -374,32 +364,25 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev,
val2 == mcp3911_scale_table[i][1]) {
adc->gain[channel->channel] = BIT(i);
- ret = adc->chip->set_scale(adc, channel->channel, i);
+ return adc->chip->set_scale(adc, channel->channel, i);
}
}
- break;
+ return -EINVAL;
case IIO_CHAN_INFO_OFFSET:
- if (val2 != 0) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = adc->chip->set_offset(adc, channel->channel, val);
- break;
+ if (val2 != 0)
+ return -EINVAL;
+ return adc->chip->set_offset(adc, channel->channel, val);
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
for (int i = 0; i < ARRAY_SIZE(mcp3911_osr_table); i++) {
if (val == mcp3911_osr_table[i]) {
- ret = adc->chip->set_osr(adc, i);
- break;
+ return adc->chip->set_osr(adc, i);
}
}
- break;
+ return -EINVAL;
+ default:
+ return -EINVAL;
}
-
-out:
- mutex_unlock(&adc->lock);
- return ret;
}
static int mcp3911_calc_scale_table(struct mcp3911 *adc)
@@ -532,7 +515,7 @@ static irqreturn_t mcp3911_trigger_handler(int irq, void *p)
int i = 0;
int ret;
- mutex_lock(&adc->lock);
+ guard(mutex)(&adc->lock);
adc->tx_buf = MCP3911_REG_READ(MCP3911_CHANNEL(0), adc->dev_addr);
ret = spi_sync_transfer(adc->spi, xfer, ARRAY_SIZE(xfer));
if (ret < 0) {
@@ -549,7 +532,6 @@ static irqreturn_t mcp3911_trigger_handler(int irq, void *p)
iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan,
iio_get_time_ns(indio_dev));
out:
- mutex_unlock(&adc->lock);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c
index e87d35d50a95..ed4d72922696 100644
--- a/drivers/iio/amplifiers/hmc425a.c
+++ b/drivers/iio/amplifiers/hmc425a.c
@@ -5,6 +5,7 @@
* Copyright 2020 Analog Devices Inc.
*/
+#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
@@ -22,6 +23,7 @@
enum hmc425a_type {
ID_HMC425A,
ID_HMC540S,
+ ID_ADRF5740
};
struct hmc425a_chip_info {
@@ -74,6 +76,10 @@ static int hmc425a_read_raw(struct iio_dev *indio_dev,
case ID_HMC540S:
gain = ~code * -1000;
break;
+ case ID_ADRF5740:
+ code = code & BIT(3) ? code & ~BIT(2) : code;
+ gain = code * -2000;
+ break;
}
*val = gain / 1000;
@@ -113,6 +119,10 @@ static int hmc425a_write_raw(struct iio_dev *indio_dev,
case ID_HMC540S:
code = ~((abs(gain) / 1000) & 0xF);
break;
+ case ID_ADRF5740:
+ code = (abs(gain) / 2000) & 0xF;
+ code = code & BIT(3) ? code | BIT(2) : code;
+ break;
}
mutex_lock(&st->lock);
@@ -165,6 +175,7 @@ static const struct iio_chan_spec hmc425a_channels[] = {
static const struct of_device_id hmc425a_of_match[] = {
{ .compatible = "adi,hmc425a", .data = (void *)ID_HMC425A },
{ .compatible = "adi,hmc540s", .data = (void *)ID_HMC540S },
+ { .compatible = "adi,adrf5740", .data = (void *)ID_ADRF5740 },
{},
};
MODULE_DEVICE_TABLE(of, hmc425a_of_match);
@@ -188,6 +199,15 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
.gain_max = 0,
.default_gain = -0x10, /* set default gain -15.0db*/
},
+ [ID_ADRF5740] = {
+ .name = "adrf5740",
+ .channels = hmc425a_channels,
+ .num_channels = ARRAY_SIZE(hmc425a_channels),
+ .num_gpios = 4,
+ .gain_min = -22000,
+ .gain_max = 0,
+ .default_gain = 0xF, /* set default gain -22.0db*/
+ },
};
static int hmc425a_probe(struct platform_device *pdev)
@@ -229,6 +249,9 @@ static int hmc425a_probe(struct platform_device *pdev)
indio_dev->info = &hmc425a_info;
indio_dev->modes = INDIO_DIRECT_MODE;
+ /* Set default gain */
+ hmc425a_write(indio_dev, st->gain);
+
return devm_iio_device_register(&pdev->dev, indio_dev);
}
diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c
index d348af8b9705..5610ba67925e 100644
--- a/drivers/iio/buffer/industrialio-buffer-dma.c
+++ b/drivers/iio/buffer/industrialio-buffer-dma.c
@@ -179,7 +179,7 @@ static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block(
}
block->size = size;
- block->state = IIO_BLOCK_STATE_DEQUEUED;
+ block->state = IIO_BLOCK_STATE_DONE;
block->queue = queue;
INIT_LIST_HEAD(&block->head);
kref_init(&block->kref);
@@ -191,16 +191,8 @@ static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block(
static void _iio_dma_buffer_block_done(struct iio_dma_buffer_block *block)
{
- struct iio_dma_buffer_queue *queue = block->queue;
-
- /*
- * The buffer has already been freed by the application, just drop the
- * reference.
- */
- if (block->state != IIO_BLOCK_STATE_DEAD) {
+ if (block->state != IIO_BLOCK_STATE_DEAD)
block->state = IIO_BLOCK_STATE_DONE;
- list_add_tail(&block->head, &queue->outgoing);
- }
}
/**
@@ -261,7 +253,6 @@ static bool iio_dma_block_reusable(struct iio_dma_buffer_block *block)
* not support abort and has not given back the block yet.
*/
switch (block->state) {
- case IIO_BLOCK_STATE_DEQUEUED:
case IIO_BLOCK_STATE_QUEUED:
case IIO_BLOCK_STATE_DONE:
return true;
@@ -317,7 +308,6 @@ int iio_dma_buffer_request_update(struct iio_buffer *buffer)
* dead. This means we can reset the lists without having to fear
* corrution.
*/
- INIT_LIST_HEAD(&queue->outgoing);
spin_unlock_irq(&queue->list_lock);
INIT_LIST_HEAD(&queue->incoming);
@@ -356,6 +346,29 @@ out_unlock:
}
EXPORT_SYMBOL_GPL(iio_dma_buffer_request_update);
+static void iio_dma_buffer_fileio_free(struct iio_dma_buffer_queue *queue)
+{
+ unsigned int i;
+
+ spin_lock_irq(&queue->list_lock);
+ for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
+ if (!queue->fileio.blocks[i])
+ continue;
+ queue->fileio.blocks[i]->state = IIO_BLOCK_STATE_DEAD;
+ }
+ spin_unlock_irq(&queue->list_lock);
+
+ INIT_LIST_HEAD(&queue->incoming);
+
+ for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
+ if (!queue->fileio.blocks[i])
+ continue;
+ iio_buffer_block_put(queue->fileio.blocks[i]);
+ queue->fileio.blocks[i] = NULL;
+ }
+ queue->fileio.active_block = NULL;
+}
+
static void iio_dma_buffer_submit_block(struct iio_dma_buffer_queue *queue,
struct iio_dma_buffer_block *block)
{
@@ -456,14 +469,20 @@ static struct iio_dma_buffer_block *iio_dma_buffer_dequeue(
struct iio_dma_buffer_queue *queue)
{
struct iio_dma_buffer_block *block;
+ unsigned int idx;
spin_lock_irq(&queue->list_lock);
- block = list_first_entry_or_null(&queue->outgoing, struct
- iio_dma_buffer_block, head);
- if (block != NULL) {
- list_del(&block->head);
- block->state = IIO_BLOCK_STATE_DEQUEUED;
+
+ idx = queue->fileio.next_dequeue;
+ block = queue->fileio.blocks[idx];
+
+ if (block->state == IIO_BLOCK_STATE_DONE) {
+ idx = (idx + 1) % ARRAY_SIZE(queue->fileio.blocks);
+ queue->fileio.next_dequeue = idx;
+ } else {
+ block = NULL;
}
+
spin_unlock_irq(&queue->list_lock);
return block;
@@ -539,6 +558,7 @@ size_t iio_dma_buffer_data_available(struct iio_buffer *buf)
struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buf);
struct iio_dma_buffer_block *block;
size_t data_available = 0;
+ unsigned int i;
/*
* For counting the available bytes we'll use the size of the block not
@@ -552,8 +572,15 @@ size_t iio_dma_buffer_data_available(struct iio_buffer *buf)
data_available += queue->fileio.active_block->size;
spin_lock_irq(&queue->list_lock);
- list_for_each_entry(block, &queue->outgoing, head)
- data_available += block->size;
+
+ for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
+ block = queue->fileio.blocks[i];
+
+ if (block != queue->fileio.active_block
+ && block->state == IIO_BLOCK_STATE_DONE)
+ data_available += block->size;
+ }
+
spin_unlock_irq(&queue->list_lock);
mutex_unlock(&queue->lock);
@@ -617,7 +644,6 @@ int iio_dma_buffer_init(struct iio_dma_buffer_queue *queue,
queue->ops = ops;
INIT_LIST_HEAD(&queue->incoming);
- INIT_LIST_HEAD(&queue->outgoing);
mutex_init(&queue->lock);
spin_lock_init(&queue->list_lock);
@@ -635,28 +661,9 @@ EXPORT_SYMBOL_GPL(iio_dma_buffer_init);
*/
void iio_dma_buffer_exit(struct iio_dma_buffer_queue *queue)
{
- unsigned int i;
-
mutex_lock(&queue->lock);
- spin_lock_irq(&queue->list_lock);
- for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
- if (!queue->fileio.blocks[i])
- continue;
- queue->fileio.blocks[i]->state = IIO_BLOCK_STATE_DEAD;
- }
- INIT_LIST_HEAD(&queue->outgoing);
- spin_unlock_irq(&queue->list_lock);
-
- INIT_LIST_HEAD(&queue->incoming);
-
- for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
- if (!queue->fileio.blocks[i])
- continue;
- iio_buffer_block_put(queue->fileio.blocks[i]);
- queue->fileio.blocks[i] = NULL;
- }
- queue->fileio.active_block = NULL;
+ iio_dma_buffer_fileio_free(queue);
queue->ops = NULL;
mutex_unlock(&queue->lock);
diff --git a/drivers/iio/chemical/Kconfig b/drivers/iio/chemical/Kconfig
index c30657e10ee1..02649ab81b3c 100644
--- a/drivers/iio/chemical/Kconfig
+++ b/drivers/iio/chemical/Kconfig
@@ -5,6 +5,17 @@
menu "Chemical Sensors"
+config AOSONG_AGS02MA
+ tristate "Aosong AGS02MA TVOC sensor driver"
+ depends on I2C
+ select CRC8
+ help
+ Say Y here to build support for Aosong AGS02MA TVOC (Total Volatile
+ Organic Compounds) sensor.
+
+ To compile this driver as module, choose M here: the module will be
+ called ags02ma.
+
config ATLAS_PH_SENSOR
tristate "Atlas Scientific OEM SM sensors"
depends on I2C
diff --git a/drivers/iio/chemical/Makefile b/drivers/iio/chemical/Makefile
index a11e777a7a00..2f3dee8bb779 100644
--- a/drivers/iio/chemical/Makefile
+++ b/drivers/iio/chemical/Makefile
@@ -4,6 +4,7 @@
#
# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_AOSONG_AGS02MA) += ags02ma.o
obj-$(CONFIG_ATLAS_PH_SENSOR) += atlas-sensor.o
obj-$(CONFIG_ATLAS_EZO_SENSOR) += atlas-ezo-sensor.o
obj-$(CONFIG_BME680) += bme680_core.o
diff --git a/drivers/iio/chemical/ags02ma.c b/drivers/iio/chemical/ags02ma.c
new file mode 100644
index 000000000000..8fcd80946543
--- /dev/null
+++ b/drivers/iio/chemical/ags02ma.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2023 Anshul Dalal <[email protected]>
+ *
+ * Driver for Aosong AGS02MA
+ *
+ * Datasheet:
+ * https://asairsensors.com/wp-content/uploads/2021/09/AGS02MA.pdf
+ * Product Page:
+ * http://www.aosong.com/m/en/products-33.html
+ */
+
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+
+#define AGS02MA_TVOC_READ_REG 0x00
+#define AGS02MA_VERSION_REG 0x11
+
+#define AGS02MA_VERSION_PROCESSING_DELAY 30
+#define AGS02MA_TVOC_READ_PROCESSING_DELAY 1500
+
+#define AGS02MA_CRC8_INIT 0xff
+#define AGS02MA_CRC8_POLYNOMIAL 0x31
+
+DECLARE_CRC8_TABLE(ags02ma_crc8_table);
+
+struct ags02ma_data {
+ struct i2c_client *client;
+};
+
+struct ags02ma_reading {
+ __be32 data;
+ u8 crc;
+} __packed;
+
+static int ags02ma_register_read(struct i2c_client *client, u8 reg, u16 delay,
+ u32 *val)
+{
+ int ret;
+ u8 crc;
+ struct ags02ma_reading read_buffer;
+
+ ret = i2c_master_send(client, &reg, sizeof(reg));
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "Failed to send data to register 0x%x: %d", reg, ret);
+ return ret;
+ }
+
+ /* Processing Delay, Check Table 7.7 in the datasheet */
+ msleep_interruptible(delay);
+
+ ret = i2c_master_recv(client, (u8 *)&read_buffer, sizeof(read_buffer));
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "Failed to receive from register 0x%x: %d", reg, ret);
+ return ret;
+ }
+
+ crc = crc8(ags02ma_crc8_table, (u8 *)&read_buffer.data,
+ sizeof(read_buffer.data), AGS02MA_CRC8_INIT);
+ if (crc != read_buffer.crc) {
+ dev_err(&client->dev, "CRC error\n");
+ return -EIO;
+ }
+
+ *val = be32_to_cpu(read_buffer.data);
+ return 0;
+}
+
+static int ags02ma_read_raw(struct iio_dev *iio_device,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ int ret;
+ struct ags02ma_data *data = iio_priv(iio_device);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = ags02ma_register_read(data->client, AGS02MA_TVOC_READ_REG,
+ AGS02MA_TVOC_READ_PROCESSING_DELAY,
+ val);
+ if (ret < 0)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ /* The sensor reads data as ppb */
+ *val = 0;
+ *val2 = 100;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info ags02ma_info = {
+ .read_raw = ags02ma_read_raw,
+};
+
+static const struct iio_chan_spec ags02ma_channel = {
+ .type = IIO_CONCENTRATION,
+ .channel2 = IIO_MOD_VOC,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+};
+
+static int ags02ma_probe(struct i2c_client *client)
+{
+ int ret;
+ struct ags02ma_data *data;
+ struct iio_dev *indio_dev;
+ u32 version;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ crc8_populate_msb(ags02ma_crc8_table, AGS02MA_CRC8_POLYNOMIAL);
+
+ ret = ags02ma_register_read(client, AGS02MA_VERSION_REG,
+ AGS02MA_VERSION_PROCESSING_DELAY, &version);
+ if (ret < 0)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to read device version\n");
+ dev_dbg(&client->dev, "Aosong AGS02MA, Version: 0x%x", version);
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+ indio_dev->info = &ags02ma_info;
+ indio_dev->channels = &ags02ma_channel;
+ indio_dev->num_channels = 1;
+ indio_dev->name = "ags02ma";
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id ags02ma_id_table[] = {
+ { "ags02ma" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, ags02ma_id_table);
+
+static const struct of_device_id ags02ma_of_table[] = {
+ { .compatible = "aosong,ags02ma" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ags02ma_of_table);
+
+static struct i2c_driver ags02ma_driver = {
+ .driver = {
+ .name = "ags02ma",
+ .of_match_table = ags02ma_of_table,
+ },
+ .id_table = ags02ma_id_table,
+ .probe = ags02ma_probe,
+};
+module_i2c_driver(ags02ma_driver);
+
+MODULE_AUTHOR("Anshul Dalal <[email protected]>");
+MODULE_DESCRIPTION("Aosong AGS02MA TVOC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/chemical/pms7003.c b/drivers/iio/chemical/pms7003.c
index e9857d93b307..b5cf15a515d2 100644
--- a/drivers/iio/chemical/pms7003.c
+++ b/drivers/iio/chemical/pms7003.c
@@ -211,13 +211,13 @@ static bool pms7003_frame_is_okay(struct pms7003_frame *frame)
return checksum == pms7003_calc_checksum(frame);
}
-static int pms7003_receive_buf(struct serdev_device *serdev,
- const unsigned char *buf, size_t size)
+static ssize_t pms7003_receive_buf(struct serdev_device *serdev, const u8 *buf,
+ size_t size)
{
struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
struct pms7003_state *state = iio_priv(indio_dev);
struct pms7003_frame *frame = &state->frame;
- int num;
+ size_t num;
if (!frame->expected_length) {
u16 magic;
diff --git a/drivers/iio/chemical/scd30_serial.c b/drivers/iio/chemical/scd30_serial.c
index 3c519103d30b..a47654591e55 100644
--- a/drivers/iio/chemical/scd30_serial.c
+++ b/drivers/iio/chemical/scd30_serial.c
@@ -174,13 +174,13 @@ static int scd30_serdev_command(struct scd30_state *state, enum scd30_cmd cmd, u
return 0;
}
-static int scd30_serdev_receive_buf(struct serdev_device *serdev,
- const unsigned char *buf, size_t size)
+static ssize_t scd30_serdev_receive_buf(struct serdev_device *serdev,
+ const u8 *buf, size_t size)
{
struct iio_dev *indio_dev = serdev_device_get_drvdata(serdev);
struct scd30_serdev_priv *priv;
struct scd30_state *state;
- int num;
+ size_t num;
if (!indio_dev)
return 0;
diff --git a/drivers/iio/chemical/sps30_serial.c b/drivers/iio/chemical/sps30_serial.c
index 164f4b3e025c..3afa89f8acc3 100644
--- a/drivers/iio/chemical/sps30_serial.c
+++ b/drivers/iio/chemical/sps30_serial.c
@@ -74,8 +74,8 @@ static int sps30_serial_xfer(struct sps30_state *state, const unsigned char *buf
}
static const struct {
- unsigned char byte;
- unsigned char byte2;
+ u8 byte;
+ u8 byte2;
} sps30_serial_bytes[] = {
{ 0x11, 0x31 },
{ 0x13, 0x33 },
@@ -83,7 +83,7 @@ static const struct {
{ 0x7d, 0x5d },
};
-static int sps30_serial_put_byte(unsigned char *buf, unsigned char byte)
+static int sps30_serial_put_byte(u8 *buf, u8 byte)
{
int i;
@@ -102,7 +102,7 @@ static int sps30_serial_put_byte(unsigned char *buf, unsigned char byte)
return 1;
}
-static char sps30_serial_get_byte(bool escaped, unsigned char byte2)
+static u8 sps30_serial_get_byte(bool escaped, u8 byte2)
{
int i;
@@ -130,8 +130,8 @@ static unsigned char sps30_serial_calc_chksum(const unsigned char *buf, size_t n
return ~chksum;
}
-static int sps30_serial_prep_frame(unsigned char *buf, unsigned char cmd,
- const unsigned char *arg, size_t arg_size)
+static int sps30_serial_prep_frame(u8 *buf, u8 cmd, const u8 *arg,
+ size_t arg_size)
{
unsigned char chksum;
int num = 0;
@@ -210,14 +210,14 @@ static int sps30_serial_command(struct sps30_state *state, unsigned char cmd,
return rsp_size;
}
-static int sps30_serial_receive_buf(struct serdev_device *serdev,
- const unsigned char *buf, size_t size)
+static ssize_t sps30_serial_receive_buf(struct serdev_device *serdev,
+ const u8 *buf, size_t size)
{
struct iio_dev *indio_dev = dev_get_drvdata(&serdev->dev);
struct sps30_serial_priv *priv;
struct sps30_state *state;
- unsigned char byte;
size_t i;
+ u8 byte;
if (!indio_dev)
return 0;
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 93b8be183de6..34eb40bb9529 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -400,6 +400,16 @@ config MCP4728
To compile this driver as a module, choose M here: the module
will be called mcp4728.
+config MCP4821
+ tristate "MCP4801/02/11/12/21/22 DAC driver"
+ depends on SPI
+ help
+ Say yes here to build the driver for the Microchip MCP4801
+ MCP4802, MCP4811, MCP4812, MCP4821 and MCP4822 DAC devices.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mcp4821.
+
config MCP4922
tristate "MCP4902, MCP4912, MCP4922 DAC driver"
depends on SPI
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index 5b2bac900d5a..55bf89739d14 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_MAX5522) += max5522.o
obj-$(CONFIG_MAX5821) += max5821.o
obj-$(CONFIG_MCP4725) += mcp4725.o
obj-$(CONFIG_MCP4728) += mcp4728.o
+obj-$(CONFIG_MCP4821) += mcp4821.o
obj-$(CONFIG_MCP4922) += mcp4922.o
obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
obj-$(CONFIG_STM32_DAC) += stm32-dac.o
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c
index a4167454da81..75b549827e15 100644
--- a/drivers/iio/dac/ad5791.c
+++ b/drivers/iio/dac/ad5791.c
@@ -345,6 +345,7 @@ static int ad5791_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
struct ad5791_state *st;
int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
+ bool use_rbuf_gain2;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (!indio_dev)
@@ -379,6 +380,12 @@ static int ad5791_probe(struct spi_device *spi)
st->pwr_down = true;
st->spi = spi;
+ if (pdata)
+ use_rbuf_gain2 = pdata->use_rbuf_gain2;
+ else
+ use_rbuf_gain2 = device_property_read_bool(&spi->dev,
+ "adi,rbuf-gain2-en");
+
if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) {
st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000;
st->vref_neg_mv = neg_voltage_uv / 1000;
@@ -398,7 +405,7 @@ static int ad5791_probe(struct spi_device *spi)
st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv))
- | ((pdata && pdata->use_rbuf_gain2) ? 0 : AD5791_CTRL_RBUF) |
+ | (use_rbuf_gain2 ? 0 : AD5791_CTRL_RBUF) |
AD5791_CTRL_BIN2SC;
ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl |
diff --git a/drivers/iio/dac/mcp4821.c b/drivers/iio/dac/mcp4821.c
new file mode 100644
index 000000000000..8a0480d33845
--- /dev/null
+++ b/drivers/iio/dac/mcp4821.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2023 Anshul Dalal <[email protected]>
+ *
+ * Driver for Microchip MCP4801, MCP4802, MCP4811, MCP4812, MCP4821 and MCP4822
+ *
+ * Based on the work of:
+ * Michael Welling (MCP4922 Driver)
+ *
+ * Datasheet:
+ * MCP48x1: https://ww1.microchip.com/downloads/en/DeviceDoc/22244B.pdf
+ * MCP48x2: https://ww1.microchip.com/downloads/en/DeviceDoc/20002249B.pdf
+ *
+ * TODO:
+ * - Configurable gain
+ * - Regulator control
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/types.h>
+
+#include <asm/unaligned.h>
+
+#define MCP4821_ACTIVE_MODE BIT(12)
+#define MCP4802_SECOND_CHAN BIT(15)
+
+/* DAC uses an internal Voltage reference of 4.096V at a gain of 2x */
+#define MCP4821_2X_GAIN_VREF_MV 4096
+
+enum mcp4821_supported_drvice_ids {
+ ID_MCP4801,
+ ID_MCP4802,
+ ID_MCP4811,
+ ID_MCP4812,
+ ID_MCP4821,
+ ID_MCP4822,
+};
+
+struct mcp4821_state {
+ struct spi_device *spi;
+ u16 dac_value[2];
+};
+
+struct mcp4821_chip_info {
+ const char *name;
+ int num_channels;
+ const struct iio_chan_spec channels[2];
+};
+
+#define MCP4821_CHAN(channel_id, resolution) \
+ { \
+ .type = IIO_VOLTAGE, .output = 1, .indexed = 1, \
+ .channel = (channel_id), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_type = { \
+ .realbits = (resolution), \
+ .shift = 12 - (resolution), \
+ }, \
+ }
+
+static const struct mcp4821_chip_info mcp4821_chip_info_table[6] = {
+ [ID_MCP4801] = {
+ .name = "mcp4801",
+ .num_channels = 1,
+ .channels = {
+ MCP4821_CHAN(0, 8),
+ },
+ },
+ [ID_MCP4802] = {
+ .name = "mcp4802",
+ .num_channels = 2,
+ .channels = {
+ MCP4821_CHAN(0, 8),
+ MCP4821_CHAN(1, 8),
+ },
+ },
+ [ID_MCP4811] = {
+ .name = "mcp4811",
+ .num_channels = 1,
+ .channels = {
+ MCP4821_CHAN(0, 10),
+ },
+ },
+ [ID_MCP4812] = {
+ .name = "mcp4812",
+ .num_channels = 2,
+ .channels = {
+ MCP4821_CHAN(0, 10),
+ MCP4821_CHAN(1, 10),
+ },
+ },
+ [ID_MCP4821] = {
+ .name = "mcp4821",
+ .num_channels = 1,
+ .channels = {
+ MCP4821_CHAN(0, 12),
+ },
+ },
+ [ID_MCP4822] = {
+ .name = "mcp4822",
+ .num_channels = 2,
+ .channels = {
+ MCP4821_CHAN(0, 12),
+ MCP4821_CHAN(1, 12),
+ },
+ },
+};
+
+static int mcp4821_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct mcp4821_state *state;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ state = iio_priv(indio_dev);
+ *val = state->dac_value[chan->channel];
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = MCP4821_2X_GAIN_VREF_MV;
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mcp4821_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct mcp4821_state *state = iio_priv(indio_dev);
+ u16 write_val;
+ __be16 write_buffer;
+ int ret;
+
+ if (val2 != 0)
+ return -EINVAL;
+
+ if (val < 0 || val >= BIT(chan->scan_type.realbits))
+ return -EINVAL;
+
+ if (mask != IIO_CHAN_INFO_RAW)
+ return -EINVAL;
+
+ write_val = MCP4821_ACTIVE_MODE | val << chan->scan_type.shift;
+ if (chan->channel)
+ write_val |= MCP4802_SECOND_CHAN;
+
+ write_buffer = cpu_to_be16(write_val);
+ ret = spi_write(state->spi, &write_buffer, sizeof(write_buffer));
+ if (ret) {
+ dev_err(&state->spi->dev, "Failed to write to device: %d", ret);
+ return ret;
+ }
+
+ state->dac_value[chan->channel] = val;
+
+ return 0;
+}
+
+static const struct iio_info mcp4821_info = {
+ .read_raw = &mcp4821_read_raw,
+ .write_raw = &mcp4821_write_raw,
+};
+
+static int mcp4821_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct mcp4821_state *state;
+ const struct mcp4821_chip_info *info;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ state = iio_priv(indio_dev);
+ state->spi = spi;
+
+ info = spi_get_device_match_data(spi);
+ indio_dev->name = info->name;
+ indio_dev->info = &mcp4821_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = info->channels;
+ indio_dev->num_channels = info->num_channels;
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+#define MCP4821_COMPATIBLE(of_compatible, id) \
+ { \
+ .compatible = of_compatible, \
+ .data = &mcp4821_chip_info_table[id] \
+ }
+
+static const struct of_device_id mcp4821_of_table[] = {
+ MCP4821_COMPATIBLE("microchip,mcp4801", ID_MCP4801),
+ MCP4821_COMPATIBLE("microchip,mcp4802", ID_MCP4802),
+ MCP4821_COMPATIBLE("microchip,mcp4811", ID_MCP4811),
+ MCP4821_COMPATIBLE("microchip,mcp4812", ID_MCP4812),
+ MCP4821_COMPATIBLE("microchip,mcp4821", ID_MCP4821),
+ MCP4821_COMPATIBLE("microchip,mcp4822", ID_MCP4822),
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mcp4821_of_table);
+
+static const struct spi_device_id mcp4821_id_table[] = {
+ { "mcp4801", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4801]},
+ { "mcp4802", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4802]},
+ { "mcp4811", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4811]},
+ { "mcp4812", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4812]},
+ { "mcp4821", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4821]},
+ { "mcp4822", (kernel_ulong_t)&mcp4821_chip_info_table[ID_MCP4822]},
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, mcp4821_id_table);
+
+static struct spi_driver mcp4821_driver = {
+ .driver = {
+ .name = "mcp4821",
+ .of_match_table = mcp4821_of_table,
+ },
+ .probe = mcp4821_probe,
+ .id_table = mcp4821_id_table,
+};
+module_spi_driver(mcp4821_driver);
+
+MODULE_AUTHOR("Anshul Dalal <[email protected]>");
+MODULE_DESCRIPTION("Microchip MCP4821 DAC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/frequency/adf4377.c b/drivers/iio/frequency/adf4377.c
index 26abecbd51e0..9284c13f1abb 100644
--- a/drivers/iio/frequency/adf4377.c
+++ b/drivers/iio/frequency/adf4377.c
@@ -870,7 +870,6 @@ static const struct iio_chan_spec adf4377_channels[] = {
static int adf4377_properties_parse(struct adf4377_state *st)
{
struct spi_device *spi = st->spi;
- const char *str;
int ret;
st->clkin = devm_clk_get_enabled(&spi->dev, "ref_in");
@@ -896,16 +895,13 @@ static int adf4377_properties_parse(struct adf4377_state *st)
return dev_err_probe(&spi->dev, PTR_ERR(st->gpio_enclk2),
"failed to get the CE GPIO\n");
- ret = device_property_read_string(&spi->dev, "adi,muxout-select", &str);
- if (ret) {
- st->muxout_select = ADF4377_MUXOUT_HIGH_Z;
- } else {
- ret = match_string(adf4377_muxout_modes, ARRAY_SIZE(adf4377_muxout_modes), str);
- if (ret < 0)
- return ret;
-
+ ret = device_property_match_property_string(&spi->dev, "adi,muxout-select",
+ adf4377_muxout_modes,
+ ARRAY_SIZE(adf4377_muxout_modes));
+ if (ret >= 0)
st->muxout_select = ret;
- }
+ else
+ st->muxout_select = ADF4377_MUXOUT_HIGH_Z;
return 0;
}
diff --git a/drivers/iio/frequency/admv1014.c b/drivers/iio/frequency/admv1014.c
index bb5e1feef42b..b46b73b89eb7 100644
--- a/drivers/iio/frequency/admv1014.c
+++ b/drivers/iio/frequency/admv1014.c
@@ -710,7 +710,6 @@ static int admv1014_init(struct admv1014_state *st)
static int admv1014_properties_parse(struct admv1014_state *st)
{
- const char *str;
unsigned int i;
struct spi_device *spi = st->spi;
int ret;
@@ -719,27 +718,21 @@ static int admv1014_properties_parse(struct admv1014_state *st)
st->p1db_comp = device_property_read_bool(&spi->dev, "adi,p1db-compensation-enable");
- ret = device_property_read_string(&spi->dev, "adi,input-mode", &str);
- if (ret) {
- st->input_mode = ADMV1014_IQ_MODE;
- } else {
- ret = match_string(input_mode_names, ARRAY_SIZE(input_mode_names), str);
- if (ret < 0)
- return ret;
-
+ ret = device_property_match_property_string(&spi->dev, "adi,input-mode",
+ input_mode_names,
+ ARRAY_SIZE(input_mode_names));
+ if (ret >= 0)
st->input_mode = ret;
- }
-
- ret = device_property_read_string(&spi->dev, "adi,quad-se-mode", &str);
- if (ret) {
- st->quad_se_mode = ADMV1014_SE_MODE_POS;
- } else {
- ret = match_string(quad_se_mode_names, ARRAY_SIZE(quad_se_mode_names), str);
- if (ret < 0)
- return ret;
+ else
+ st->input_mode = ADMV1014_IQ_MODE;
+ ret = device_property_match_property_string(&spi->dev, "adi,quad-se-mode",
+ quad_se_mode_names,
+ ARRAY_SIZE(quad_se_mode_names));
+ if (ret >= 0)
st->quad_se_mode = ADMV1014_SE_MODE_POS + (ret * 3);
- }
+ else
+ st->quad_se_mode = ADMV1014_SE_MODE_POS;
for (i = 0; i < ADMV1014_NUM_REGULATORS; ++i)
st->regulators[i].supply = admv1014_reg_name[i];
diff --git a/drivers/iio/humidity/hdc3020.c b/drivers/iio/humidity/hdc3020.c
new file mode 100644
index 000000000000..4e3311170725
--- /dev/null
+++ b/drivers/iio/humidity/hdc3020.c
@@ -0,0 +1,473 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * hdc3020.c - Support for the TI HDC3020,HDC3021 and HDC3022
+ * temperature + relative humidity sensors
+ *
+ * Copyright (C) 2023
+ *
+ * Datasheet: https://www.ti.com/lit/ds/symlink/hdc3020.pdf
+ */
+
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+#include <asm/unaligned.h>
+
+#include <linux/iio/iio.h>
+
+#define HDC3020_HEATER_CMD_MSB 0x30 /* shared by all heater commands */
+#define HDC3020_HEATER_ENABLE 0x6D
+#define HDC3020_HEATER_DISABLE 0x66
+#define HDC3020_HEATER_CONFIG 0x6E
+
+#define HDC3020_READ_RETRY_TIMES 10
+#define HDC3020_BUSY_DELAY_MS 10
+
+#define HDC3020_CRC8_POLYNOMIAL 0x31
+
+static const u8 HDC3020_S_AUTO_10HZ_MOD0[2] = { 0x27, 0x37 };
+
+static const u8 HDC3020_EXIT_AUTO[2] = { 0x30, 0x93 };
+
+static const u8 HDC3020_R_T_RH_AUTO[2] = { 0xE0, 0x00 };
+static const u8 HDC3020_R_T_LOW_AUTO[2] = { 0xE0, 0x02 };
+static const u8 HDC3020_R_T_HIGH_AUTO[2] = { 0xE0, 0x03 };
+static const u8 HDC3020_R_RH_LOW_AUTO[2] = { 0xE0, 0x04 };
+static const u8 HDC3020_R_RH_HIGH_AUTO[2] = { 0xE0, 0x05 };
+
+struct hdc3020_data {
+ struct i2c_client *client;
+ /*
+ * Ensure that the sensor configuration (currently only heater is
+ * supported) will not be changed during the process of reading
+ * sensor data (this driver will try HDC3020_READ_RETRY_TIMES times
+ * if the device does not respond).
+ */
+ struct mutex lock;
+};
+
+static const int hdc3020_heater_vals[] = {0, 1, 0x3FFF};
+
+static const struct iio_chan_spec hdc3020_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) |
+ BIT(IIO_CHAN_INFO_TROUGH) | BIT(IIO_CHAN_INFO_OFFSET),
+ },
+ {
+ .type = IIO_HUMIDITYRELATIVE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) |
+ BIT(IIO_CHAN_INFO_TROUGH),
+ },
+ {
+ /*
+ * For setting the internal heater, which can be switched on to
+ * prevent or remove any condensation that may develop when the
+ * ambient environment approaches its dew point temperature.
+ */
+ .type = IIO_CURRENT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
+ .output = 1,
+ },
+};
+
+DECLARE_CRC8_TABLE(hdc3020_crc8_table);
+
+static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len)
+{
+ struct i2c_client *client = data->client;
+ struct i2c_msg msg;
+ int ret, cnt;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.buf = (char *)buf;
+ msg.len = len;
+
+ /*
+ * During the measurement process, HDC3020 will not return data.
+ * So wait for a while and try again
+ */
+ for (cnt = 0; cnt < HDC3020_READ_RETRY_TIMES; cnt++) {
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret == 1)
+ return 0;
+
+ mdelay(HDC3020_BUSY_DELAY_MS);
+ }
+ dev_err(&client->dev, "Could not write sensor command\n");
+
+ return -ETIMEDOUT;
+}
+
+static int hdc3020_read_bytes(struct hdc3020_data *data, const u8 *buf,
+ void *val, int len)
+{
+ int ret, cnt;
+ struct i2c_client *client = data->client;
+ struct i2c_msg msg[2] = {
+ [0] = {
+ .addr = client->addr,
+ .flags = 0,
+ .buf = (char *)buf,
+ .len = 2,
+ },
+ [1] = {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .buf = val,
+ .len = len,
+ },
+ };
+
+ /*
+ * During the measurement process, HDC3020 will not return data.
+ * So wait for a while and try again
+ */
+ for (cnt = 0; cnt < HDC3020_READ_RETRY_TIMES; cnt++) {
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret == 2)
+ return 0;
+
+ mdelay(HDC3020_BUSY_DELAY_MS);
+ }
+ dev_err(&client->dev, "Could not read sensor data\n");
+
+ return -ETIMEDOUT;
+}
+
+static int hdc3020_read_measurement(struct hdc3020_data *data,
+ enum iio_chan_type type, int *val)
+{
+ u8 crc, buf[6];
+ int ret;
+
+ ret = hdc3020_read_bytes(data, HDC3020_R_T_RH_AUTO, buf, 6);
+ if (ret < 0)
+ return ret;
+
+ /* CRC check of the temperature measurement */
+ crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
+ if (crc != buf[2])
+ return -EINVAL;
+
+ /* CRC check of the relative humidity measurement */
+ crc = crc8(hdc3020_crc8_table, buf + 3, 2, CRC8_INIT_VALUE);
+ if (crc != buf[5])
+ return -EINVAL;
+
+ if (type == IIO_TEMP)
+ *val = get_unaligned_be16(buf);
+ else if (type == IIO_HUMIDITYRELATIVE)
+ *val = get_unaligned_be16(&buf[3]);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+/*
+ * After exiting the automatic measurement mode or resetting, the peak
+ * value will be reset to the default value
+ * This method is used to get the highest temp measured during automatic
+ * measurement
+ */
+static int hdc3020_read_high_peak_t(struct hdc3020_data *data, int *val)
+{
+ u8 crc, buf[3];
+ int ret;
+
+ ret = hdc3020_read_bytes(data, HDC3020_R_T_HIGH_AUTO, buf, 3);
+ if (ret < 0)
+ return ret;
+
+ crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
+ if (crc != buf[2])
+ return -EINVAL;
+
+ *val = get_unaligned_be16(buf);
+
+ return 0;
+}
+
+/*
+ * This method is used to get the lowest temp measured during automatic
+ * measurement
+ */
+static int hdc3020_read_low_peak_t(struct hdc3020_data *data, int *val)
+{
+ u8 crc, buf[3];
+ int ret;
+
+ ret = hdc3020_read_bytes(data, HDC3020_R_T_LOW_AUTO, buf, 3);
+ if (ret < 0)
+ return ret;
+
+ crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
+ if (crc != buf[2])
+ return -EINVAL;
+
+ *val = get_unaligned_be16(buf);
+
+ return 0;
+}
+
+/*
+ * This method is used to get the highest humidity measured during automatic
+ * measurement
+ */
+static int hdc3020_read_high_peak_rh(struct hdc3020_data *data, int *val)
+{
+ u8 crc, buf[3];
+ int ret;
+
+ ret = hdc3020_read_bytes(data, HDC3020_R_RH_HIGH_AUTO, buf, 3);
+ if (ret < 0)
+ return ret;
+
+ crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
+ if (crc != buf[2])
+ return -EINVAL;
+
+ *val = get_unaligned_be16(buf);
+
+ return 0;
+}
+
+/*
+ * This method is used to get the lowest humidity measured during automatic
+ * measurement
+ */
+static int hdc3020_read_low_peak_rh(struct hdc3020_data *data, int *val)
+{
+ u8 crc, buf[3];
+ int ret;
+
+ ret = hdc3020_read_bytes(data, HDC3020_R_RH_LOW_AUTO, buf, 3);
+ if (ret < 0)
+ return ret;
+
+ crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
+ if (crc != buf[2])
+ return -EINVAL;
+
+ *val = get_unaligned_be16(buf);
+
+ return 0;
+}
+
+static int hdc3020_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct hdc3020_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (chan->type != IIO_TEMP && chan->type != IIO_HUMIDITYRELATIVE)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW: {
+ guard(mutex)(&data->lock);
+ ret = hdc3020_read_measurement(data, chan->type, val);
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_PEAK: {
+ guard(mutex)(&data->lock);
+ if (chan->type == IIO_TEMP) {
+ ret = hdc3020_read_high_peak_t(data, val);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = hdc3020_read_high_peak_rh(data, val);
+ if (ret < 0)
+ return ret;
+ }
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_TROUGH: {
+ guard(mutex)(&data->lock);
+ if (chan->type == IIO_TEMP) {
+ ret = hdc3020_read_low_peak_t(data, val);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = hdc3020_read_low_peak_rh(data, val);
+ if (ret < 0)
+ return ret;
+ }
+ return IIO_VAL_INT;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ *val2 = 65536;
+ if (chan->type == IIO_TEMP)
+ *val = 175;
+ else
+ *val = 100;
+ return IIO_VAL_FRACTIONAL;
+
+ case IIO_CHAN_INFO_OFFSET:
+ if (chan->type != IIO_TEMP)
+ return -EINVAL;
+
+ *val = 16852;
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int hdc3020_read_available(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals,
+ int *type, int *length, long mask)
+{
+ if (mask != IIO_CHAN_INFO_RAW || chan->type != IIO_CURRENT)
+ return -EINVAL;
+
+ *vals = hdc3020_heater_vals;
+ *type = IIO_VAL_INT;
+
+ return IIO_AVAIL_RANGE;
+}
+
+static int hdc3020_update_heater(struct hdc3020_data *data, int val)
+{
+ u8 buf[5];
+ int ret;
+
+ if (val < hdc3020_heater_vals[0] || val > hdc3020_heater_vals[2])
+ return -EINVAL;
+
+ buf[0] = HDC3020_HEATER_CMD_MSB;
+
+ if (!val) {
+ buf[1] = HDC3020_HEATER_DISABLE;
+ return hdc3020_write_bytes(data, buf, 2);
+ }
+
+ buf[1] = HDC3020_HEATER_CONFIG;
+ put_unaligned_be16(val & GENMASK(13, 0), &buf[2]);
+ buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE);
+ ret = hdc3020_write_bytes(data, buf, 5);
+ if (ret < 0)
+ return ret;
+
+ buf[1] = HDC3020_HEATER_ENABLE;
+
+ return hdc3020_write_bytes(data, buf, 2);
+}
+
+static int hdc3020_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct hdc3020_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (chan->type != IIO_CURRENT)
+ return -EINVAL;
+
+ guard(mutex)(&data->lock);
+ return hdc3020_update_heater(data, val);
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info hdc3020_info = {
+ .read_raw = hdc3020_read_raw,
+ .write_raw = hdc3020_write_raw,
+ .read_avail = hdc3020_read_available,
+};
+
+static void hdc3020_stop(void *data)
+{
+ hdc3020_write_bytes((struct hdc3020_data *)data, HDC3020_EXIT_AUTO, 2);
+}
+
+static int hdc3020_probe(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev;
+ struct hdc3020_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -EOPNOTSUPP;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+ mutex_init(&data->lock);
+
+ crc8_populate_msb(hdc3020_crc8_table, HDC3020_CRC8_POLYNOMIAL);
+
+ indio_dev->name = "hdc3020";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &hdc3020_info;
+ indio_dev->channels = hdc3020_channels;
+ indio_dev->num_channels = ARRAY_SIZE(hdc3020_channels);
+
+ ret = hdc3020_write_bytes(data, HDC3020_S_AUTO_10HZ_MOD0, 2);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Unable to set up measurement\n");
+
+ ret = devm_add_action_or_reset(&data->client->dev, hdc3020_stop, data);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_device_register(&data->client->dev, indio_dev);
+ if (ret)
+ return dev_err_probe(&client->dev, ret, "Failed to add device");
+
+ return 0;
+}
+
+static const struct i2c_device_id hdc3020_id[] = {
+ { "hdc3020" },
+ { "hdc3021" },
+ { "hdc3022" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, hdc3020_id);
+
+static const struct of_device_id hdc3020_dt_ids[] = {
+ { .compatible = "ti,hdc3020" },
+ { .compatible = "ti,hdc3021" },
+ { .compatible = "ti,hdc3022" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hdc3020_dt_ids);
+
+static struct i2c_driver hdc3020_driver = {
+ .driver = {
+ .name = "hdc3020",
+ .of_match_table = hdc3020_dt_ids,
+ },
+ .probe = hdc3020_probe,
+ .id_table = hdc3020_id,
+};
+module_i2c_driver(hdc3020_driver);
+
+MODULE_AUTHOR("Javier Carrasco <[email protected]>");
+MODULE_AUTHOR("Li peiyu <[email protected]>");
+MODULE_DESCRIPTION("TI HDC3020 humidity and temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index c2f97629e9cd..52a155ff3250 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -53,6 +53,7 @@ config ADIS16480
ADIS16485, ADIS16488 inertial sensors.
source "drivers/iio/imu/bmi160/Kconfig"
+source "drivers/iio/imu/bmi323/Kconfig"
source "drivers/iio/imu/bno055/Kconfig"
config FXOS8700
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 6eb612034722..7e2d7d5c3b7b 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -15,6 +15,7 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
obj-y += bmi160/
+obj-y += bmi323/
obj-y += bno055/
obj-$(CONFIG_FXOS8700) += fxos8700_core.o
diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
index bc40240b29e2..495caf4ce87a 100644
--- a/drivers/iio/imu/adis.c
+++ b/drivers/iio/imu/adis.c
@@ -44,8 +44,6 @@ int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int value,
.cs_change = 1,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
- .cs_change_delay.value = adis->data->cs_change_delay,
- .cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 2,
.bits_per_word = 8,
@@ -53,8 +51,6 @@ int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int value,
.cs_change = 1,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
- .cs_change_delay.value = adis->data->cs_change_delay,
- .cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 4,
.bits_per_word = 8,
@@ -62,8 +58,6 @@ int __adis_write_reg(struct adis *adis, unsigned int reg, unsigned int value,
.cs_change = 1,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
- .cs_change_delay.value = adis->data->cs_change_delay,
- .cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 6,
.bits_per_word = 8,
@@ -144,8 +138,6 @@ int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val,
.cs_change = 1,
.delay.value = adis->data->write_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
- .cs_change_delay.value = adis->data->cs_change_delay,
- .cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 2,
.bits_per_word = 8,
@@ -153,8 +145,6 @@ int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val,
.cs_change = 1,
.delay.value = adis->data->read_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
- .cs_change_delay.value = adis->data->cs_change_delay,
- .cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 4,
.rx_buf = adis->rx,
@@ -163,8 +153,6 @@ int __adis_read_reg(struct adis *adis, unsigned int reg, unsigned int *val,
.cs_change = 1,
.delay.value = adis->data->read_delay,
.delay.unit = SPI_DELAY_UNIT_USECS,
- .cs_change_delay.value = adis->data->cs_change_delay,
- .cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
}, {
.rx_buf = adis->rx + 2,
.bits_per_word = 8,
@@ -524,6 +512,12 @@ int adis_init(struct adis *adis, struct iio_dev *indio_dev,
}
mutex_init(&adis->state_lock);
+
+ if (!spi->cs_inactive.value) {
+ spi->cs_inactive.value = data->cs_change_delay;
+ spi->cs_inactive.unit = SPI_DELAY_UNIT_USECS;
+ }
+
adis->spi = spi;
adis->data = data;
iio_device_set_drvdata(indio_dev, adis);
diff --git a/drivers/iio/imu/bmi323/Kconfig b/drivers/iio/imu/bmi323/Kconfig
new file mode 100644
index 000000000000..ab37b285393c
--- /dev/null
+++ b/drivers/iio/imu/bmi323/Kconfig
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# BMI323 IMU driver
+#
+
+config BMI323
+ tristate
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+
+config BMI323_I2C
+ tristate "Bosch BMI323 I2C driver"
+ depends on I2C
+ select BMI323
+ select REGMAP_I2C
+ help
+ Enable support for the Bosch BMI323 6-Axis IMU connected to I2C
+ interface.
+
+ This driver can also be built as a module. If so, the module will be
+ called bmi323_i2c.
+
+config BMI323_SPI
+ tristate "Bosch BMI323 SPI driver"
+ depends on SPI
+ select BMI323
+ select REGMAP_SPI
+ help
+ Enable support for the Bosch BMI323 6-Axis IMU connected to SPI
+ interface.
+
+ This driver can also be built as a module. If so, the module will be
+ called bmi323_spi.
diff --git a/drivers/iio/imu/bmi323/Makefile b/drivers/iio/imu/bmi323/Makefile
new file mode 100644
index 000000000000..a6a6dc0207c9
--- /dev/null
+++ b/drivers/iio/imu/bmi323/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for Bosch BMI323 IMU
+#
+obj-$(CONFIG_BMI323) += bmi323_core.o
+obj-$(CONFIG_BMI323_I2C) += bmi323_i2c.o
+obj-$(CONFIG_BMI323_SPI) += bmi323_spi.o
diff --git a/drivers/iio/imu/bmi323/bmi323.h b/drivers/iio/imu/bmi323/bmi323.h
new file mode 100644
index 000000000000..dff126d41658
--- /dev/null
+++ b/drivers/iio/imu/bmi323/bmi323.h
@@ -0,0 +1,209 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * IIO driver for Bosch BMI323 6-Axis IMU
+ *
+ * Copyright (C) 2023, Jagath Jog J <[email protected]>
+ */
+
+#ifndef _BMI323_H_
+#define _BMI323_H_
+
+#include <linux/bits.h>
+#include <linux/regmap.h>
+#include <linux/units.h>
+
+#define BMI323_I2C_DUMMY 2
+#define BMI323_SPI_DUMMY 1
+
+/* Register map */
+
+#define BMI323_CHIP_ID_REG 0x00
+#define BMI323_CHIP_ID_VAL 0x0043
+#define BMI323_CHIP_ID_MSK GENMASK(7, 0)
+#define BMI323_ERR_REG 0x01
+#define BMI323_STATUS_REG 0x02
+#define BMI323_STATUS_POR_MSK BIT(0)
+
+/* Accelero/Gyro/Temp data registers */
+#define BMI323_ACCEL_X_REG 0x03
+#define BMI323_GYRO_X_REG 0x06
+#define BMI323_TEMP_REG 0x09
+#define BMI323_ALL_CHAN_MSK GENMASK(5, 0)
+
+/* Status registers */
+#define BMI323_STATUS_INT1_REG 0x0D
+#define BMI323_STATUS_INT2_REG 0x0E
+#define BMI323_STATUS_NOMOTION_MSK BIT(0)
+#define BMI323_STATUS_MOTION_MSK BIT(1)
+#define BMI323_STATUS_STP_WTR_MSK BIT(5)
+#define BMI323_STATUS_TAP_MSK BIT(8)
+#define BMI323_STATUS_ERROR_MSK BIT(10)
+#define BMI323_STATUS_TMP_DRDY_MSK BIT(11)
+#define BMI323_STATUS_GYR_DRDY_MSK BIT(12)
+#define BMI323_STATUS_ACC_DRDY_MSK BIT(13)
+#define BMI323_STATUS_ACC_GYR_DRDY_MSK GENMASK(13, 12)
+#define BMI323_STATUS_FIFO_WTRMRK_MSK BIT(14)
+#define BMI323_STATUS_FIFO_FULL_MSK BIT(15)
+
+/* Feature registers */
+#define BMI323_FEAT_IO0_REG 0x10
+#define BMI323_FEAT_IO0_XYZ_NOMOTION_MSK GENMASK(2, 0)
+#define BMI323_FEAT_IO0_XYZ_MOTION_MSK GENMASK(5, 3)
+#define BMI323_FEAT_XYZ_MSK GENMASK(2, 0)
+#define BMI323_FEAT_IO0_STP_CNT_MSK BIT(9)
+#define BMI323_FEAT_IO0_S_TAP_MSK BIT(12)
+#define BMI323_FEAT_IO0_D_TAP_MSK BIT(13)
+#define BMI323_FEAT_IO1_REG 0x11
+#define BMI323_FEAT_IO1_ERR_MSK GENMASK(3, 0)
+#define BMI323_FEAT_IO2_REG 0x12
+#define BMI323_FEAT_IO_STATUS_REG 0x14
+#define BMI323_FEAT_IO_STATUS_MSK BIT(0)
+#define BMI323_FEAT_ENG_POLL 2000
+#define BMI323_FEAT_ENG_TIMEOUT 10000
+
+/* FIFO registers */
+#define BMI323_FIFO_FILL_LEVEL_REG 0x15
+#define BMI323_FIFO_DATA_REG 0x16
+
+/* Accelero/Gyro config registers */
+#define BMI323_ACC_CONF_REG 0x20
+#define BMI323_GYRO_CONF_REG 0x21
+#define BMI323_ACC_GYRO_CONF_MODE_MSK GENMASK(14, 12)
+#define BMI323_ACC_GYRO_CONF_ODR_MSK GENMASK(3, 0)
+#define BMI323_ACC_GYRO_CONF_SCL_MSK GENMASK(6, 4)
+#define BMI323_ACC_GYRO_CONF_BW_MSK BIT(7)
+#define BMI323_ACC_GYRO_CONF_AVG_MSK GENMASK(10, 8)
+
+/* FIFO registers */
+#define BMI323_FIFO_WTRMRK_REG 0x35
+#define BMI323_FIFO_CONF_REG 0x36
+#define BMI323_FIFO_CONF_STP_FUL_MSK BIT(0)
+#define BMI323_FIFO_CONF_ACC_GYR_EN_MSK GENMASK(10, 9)
+#define BMI323_FIFO_ACC_GYR_MSK GENMASK(1, 0)
+#define BMI323_FIFO_CTRL_REG 0x37
+#define BMI323_FIFO_FLUSH_MSK BIT(0)
+
+/* Interrupt pin config registers */
+#define BMI323_IO_INT_CTR_REG 0x38
+#define BMI323_IO_INT1_LVL_MSK BIT(0)
+#define BMI323_IO_INT1_OD_MSK BIT(1)
+#define BMI323_IO_INT1_OP_EN_MSK BIT(2)
+#define BMI323_IO_INT1_LVL_OD_OP_MSK GENMASK(2, 0)
+#define BMI323_IO_INT2_LVL_MSK BIT(8)
+#define BMI323_IO_INT2_OD_MSK BIT(9)
+#define BMI323_IO_INT2_OP_EN_MSK BIT(10)
+#define BMI323_IO_INT2_LVL_OD_OP_MSK GENMASK(10, 8)
+#define BMI323_IO_INT_CONF_REG 0x39
+#define BMI323_IO_INT_LTCH_MSK BIT(0)
+#define BMI323_INT_MAP1_REG 0x3A
+#define BMI323_INT_MAP2_REG 0x3B
+#define BMI323_NOMOTION_MSK GENMASK(1, 0)
+#define BMI323_MOTION_MSK GENMASK(3, 2)
+#define BMI323_STEP_CNT_MSK GENMASK(11, 10)
+#define BMI323_TAP_MSK GENMASK(1, 0)
+#define BMI323_TMP_DRDY_MSK GENMASK(7, 6)
+#define BMI323_GYR_DRDY_MSK GENMASK(9, 8)
+#define BMI323_ACC_DRDY_MSK GENMASK(11, 10)
+#define BMI323_FIFO_WTRMRK_MSK GENMASK(13, 12)
+#define BMI323_FIFO_FULL_MSK GENMASK(15, 14)
+
+/* Feature registers */
+#define BMI323_FEAT_CTRL_REG 0x40
+#define BMI323_FEAT_ENG_EN_MSK BIT(0)
+#define BMI323_FEAT_DATA_ADDR 0x41
+#define BMI323_FEAT_DATA_TX 0x42
+#define BMI323_FEAT_DATA_STATUS 0x43
+#define BMI323_FEAT_DATA_TX_RDY_MSK BIT(1)
+#define BMI323_FEAT_EVNT_EXT_REG 0x47
+#define BMI323_FEAT_EVNT_EXT_S_MSK BIT(3)
+#define BMI323_FEAT_EVNT_EXT_D_MSK BIT(4)
+
+#define BMI323_CMD_REG 0x7E
+#define BMI323_RST_VAL 0xDEAF
+#define BMI323_CFG_RES_REG 0x7F
+
+/* Extended registers */
+#define BMI323_GEN_SET1_REG 0x02
+#define BMI323_GEN_SET1_MODE_MSK BIT(0)
+#define BMI323_GEN_HOLD_DUR_MSK GENMASK(4, 1)
+
+/* Any Motion/No Motion config registers */
+#define BMI323_ANYMO1_REG 0x05
+#define BMI323_NOMO1_REG 0x08
+#define BMI323_MO2_OFFSET 0x01
+#define BMI323_MO3_OFFSET 0x02
+#define BMI323_MO1_REF_UP_MSK BIT(12)
+#define BMI323_MO1_SLOPE_TH_MSK GENMASK(11, 0)
+#define BMI323_MO2_HYSTR_MSK GENMASK(9, 0)
+#define BMI323_MO3_DURA_MSK GENMASK(12, 0)
+
+/* Step counter config registers */
+#define BMI323_STEP_SC1_REG 0x10
+#define BMI323_STEP_SC1_WTRMRK_MSK GENMASK(9, 0)
+#define BMI323_STEP_SC1_RST_CNT_MSK BIT(10)
+#define BMI323_STEP_SC1_REG 0x10
+#define BMI323_STEP_LEN 2
+
+/* Tap gesture config registers */
+#define BMI323_TAP1_REG 0x1E
+#define BMI323_TAP1_AXIS_SEL_MSK GENMASK(1, 0)
+#define BMI323_AXIS_XYZ_MSK GENMASK(1, 0)
+#define BMI323_TAP1_TIMOUT_MSK BIT(2)
+#define BMI323_TAP1_MAX_PEAKS_MSK GENMASK(5, 3)
+#define BMI323_TAP1_MODE_MSK GENMASK(7, 6)
+#define BMI323_TAP2_REG 0x1F
+#define BMI323_TAP2_THRES_MSK GENMASK(9, 0)
+#define BMI323_TAP2_MAX_DUR_MSK GENMASK(15, 10)
+#define BMI323_TAP3_REG 0x20
+#define BMI323_TAP3_QUIET_TIM_MSK GENMASK(15, 12)
+#define BMI323_TAP3_QT_BW_TAP_MSK GENMASK(11, 8)
+#define BMI323_TAP3_QT_AFT_GES_MSK GENMASK(15, 12)
+
+#define BMI323_MOTION_THRES_SCALE 512
+#define BMI323_MOTION_HYSTR_SCALE 512
+#define BMI323_MOTION_DURAT_SCALE 50
+#define BMI323_TAP_THRES_SCALE 512
+#define BMI323_DUR_BW_TAP_SCALE 200
+#define BMI323_QUITE_TIM_GES_SCALE 25
+#define BMI323_MAX_GES_DUR_SCALE 25
+
+/*
+ * The formula to calculate temperature in C.
+ * See datasheet section 6.1.1, Register Map Overview
+ *
+ * T_C = (temp_raw / 512) + 23
+ */
+#define BMI323_TEMP_OFFSET 11776
+#define BMI323_TEMP_SCALE 1953125
+
+/*
+ * The BMI323 features a FIFO with a capacity of 2048 bytes. Each frame
+ * consists of accelerometer (X, Y, Z) data and gyroscope (X, Y, Z) data,
+ * totaling 6 words or 12 bytes. The FIFO buffer can hold a total of
+ * 170 frames.
+ *
+ * If a watermark interrupt is configured for 170 frames, the interrupt will
+ * trigger when the FIFO reaches 169 frames, so limit the maximum watermark
+ * level to 169 frames. In terms of data, 169 frames would equal 1014 bytes,
+ * which is approximately 2 frames before the FIFO reaches its full capacity.
+ * See datasheet section 5.7.3 FIFO Buffer Interrupts
+ */
+#define BMI323_BYTES_PER_SAMPLE 2
+#define BMI323_FIFO_LENGTH_IN_BYTES 2048
+#define BMI323_FIFO_FRAME_LENGTH 6
+#define BMI323_FIFO_FULL_IN_FRAMES \
+ ((BMI323_FIFO_LENGTH_IN_BYTES / \
+ (BMI323_BYTES_PER_SAMPLE * BMI323_FIFO_FRAME_LENGTH)) - 1)
+#define BMI323_FIFO_FULL_IN_WORDS \
+ (BMI323_FIFO_FULL_IN_FRAMES * BMI323_FIFO_FRAME_LENGTH)
+
+#define BMI323_INT_MICRO_TO_RAW(val, val2, scale) ((val) * (scale) + \
+ ((val2) * (scale)) / MEGA)
+
+#define BMI323_RAW_TO_MICRO(raw, scale) ((((raw) % (scale)) * MEGA) / scale)
+
+struct device;
+int bmi323_core_probe(struct device *dev);
+extern const struct regmap_config bmi323_regmap_config;
+
+#endif
diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c
new file mode 100644
index 000000000000..183af482828f
--- /dev/null
+++ b/drivers/iio/imu/bmi323/bmi323_core.c
@@ -0,0 +1,2139 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IIO core driver for Bosch BMI323 6-Axis IMU.
+ *
+ * Copyright (C) 2023, Jagath Jog J <[email protected]>
+ *
+ * Datasheet: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi323-ds000.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/units.h>
+
+#include <asm/unaligned.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include "bmi323.h"
+
+enum bmi323_sensor_type {
+ BMI323_ACCEL,
+ BMI323_GYRO,
+ BMI323_SENSORS_CNT,
+};
+
+enum bmi323_opr_mode {
+ ACC_GYRO_MODE_DISABLE = 0x00,
+ GYRO_DRIVE_MODE_ENABLED = 0x01,
+ ACC_GYRO_MODE_DUTYCYCLE = 0x03,
+ ACC_GYRO_MODE_CONTINOUS = 0x04,
+ ACC_GYRO_MODE_HIGH_PERF = 0x07,
+};
+
+enum bmi323_state {
+ BMI323_IDLE,
+ BMI323_BUFFER_DRDY_TRIGGERED,
+ BMI323_BUFFER_FIFO,
+};
+
+enum bmi323_irq_pin {
+ BMI323_IRQ_DISABLED,
+ BMI323_IRQ_INT1,
+ BMI323_IRQ_INT2,
+};
+
+enum bmi323_3db_bw {
+ BMI323_BW_ODR_BY_2,
+ BMI323_BW_ODR_BY_4,
+};
+
+enum bmi323_scan {
+ BMI323_ACCEL_X,
+ BMI323_ACCEL_Y,
+ BMI323_ACCEL_Z,
+ BMI323_GYRO_X,
+ BMI323_GYRO_Y,
+ BMI323_GYRO_Z,
+ BMI323_CHAN_MAX
+};
+
+struct bmi323_hw {
+ u8 data;
+ u8 config;
+ const int (*scale_table)[2];
+ int scale_table_len;
+};
+
+/*
+ * The accelerometer supports +-2G/4G/8G/16G ranges, and the resolution of
+ * each sample is 16 bits, signed.
+ * At +-8G the scale can calculated by
+ * ((8 + 8) * 9.80665 / (2^16 - 1)) * 10^6 = 2394.23819 scale in micro
+ *
+ */
+static const int bmi323_accel_scale[][2] = {
+ { 0, 598 },
+ { 0, 1197 },
+ { 0, 2394 },
+ { 0, 4788 },
+};
+
+static const int bmi323_gyro_scale[][2] = {
+ { 0, 66 },
+ { 0, 133 },
+ { 0, 266 },
+ { 0, 532 },
+ { 0, 1065 },
+};
+
+static const int bmi323_accel_gyro_avrg[] = {0, 2, 4, 8, 16, 32, 64};
+
+static const struct bmi323_hw bmi323_hw[2] = {
+ [BMI323_ACCEL] = {
+ .data = BMI323_ACCEL_X_REG,
+ .config = BMI323_ACC_CONF_REG,
+ .scale_table = bmi323_accel_scale,
+ .scale_table_len = ARRAY_SIZE(bmi323_accel_scale),
+ },
+ [BMI323_GYRO] = {
+ .data = BMI323_GYRO_X_REG,
+ .config = BMI323_GYRO_CONF_REG,
+ .scale_table = bmi323_gyro_scale,
+ .scale_table_len = ARRAY_SIZE(bmi323_gyro_scale),
+ },
+};
+
+struct bmi323_data {
+ struct device *dev;
+ struct regmap *regmap;
+ struct iio_mount_matrix orientation;
+ enum bmi323_irq_pin irq_pin;
+ struct iio_trigger *trig;
+ bool drdy_trigger_enabled;
+ enum bmi323_state state;
+ s64 fifo_tstamp, old_fifo_tstamp;
+ u32 odrns[BMI323_SENSORS_CNT];
+ u32 odrhz[BMI323_SENSORS_CNT];
+ unsigned int feature_events;
+
+ /*
+ * Lock to protect the members of device's private data from concurrent
+ * access and also to serialize the access of extended registers.
+ * See bmi323_write_ext_reg(..) for more info.
+ */
+ struct mutex mutex;
+ int watermark;
+ __le16 fifo_buff[BMI323_FIFO_FULL_IN_WORDS] __aligned(IIO_DMA_MINALIGN);
+ struct {
+ __le16 channels[BMI323_CHAN_MAX];
+ s64 ts __aligned(8);
+ } buffer;
+ __le16 steps_count[BMI323_STEP_LEN];
+};
+
+static const struct iio_mount_matrix *
+bmi323_get_mount_matrix(const struct iio_dev *idev,
+ const struct iio_chan_spec *chan)
+{
+ struct bmi323_data *data = iio_priv(idev);
+
+ return &data->orientation;
+}
+
+static const struct iio_chan_spec_ext_info bmi323_ext_info[] = {
+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, bmi323_get_mount_matrix),
+ { }
+};
+
+static const struct iio_event_spec bmi323_step_wtrmrk_event = {
+ .type = IIO_EV_TYPE_CHANGE,
+ .dir = IIO_EV_DIR_NONE,
+ .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE),
+};
+
+static const struct iio_event_spec bmi323_accel_event[] = {
+ {
+ .type = IIO_EV_TYPE_MAG,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_PERIOD) |
+ BIT(IIO_EV_INFO_HYSTERESIS) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+ {
+ .type = IIO_EV_TYPE_MAG,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_PERIOD) |
+ BIT(IIO_EV_INFO_HYSTERESIS) |
+ BIT(IIO_EV_INFO_ENABLE),
+ },
+ {
+ .type = IIO_EV_TYPE_GESTURE,
+ .dir = IIO_EV_DIR_SINGLETAP,
+ .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_RESET_TIMEOUT),
+ },
+ {
+ .type = IIO_EV_TYPE_GESTURE,
+ .dir = IIO_EV_DIR_DOUBLETAP,
+ .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_RESET_TIMEOUT) |
+ BIT(IIO_EV_INFO_TAP2_MIN_DELAY),
+ },
+};
+
+#define BMI323_ACCEL_CHANNEL(_type, _axis, _index) { \
+ .type = _type, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##_axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_LE, \
+ }, \
+ .ext_info = bmi323_ext_info, \
+ .event_spec = bmi323_accel_event, \
+ .num_event_specs = ARRAY_SIZE(bmi323_accel_event), \
+}
+
+#define BMI323_GYRO_CHANNEL(_type, _axis, _index) { \
+ .type = _type, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##_axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_LE, \
+ }, \
+ .ext_info = bmi323_ext_info, \
+}
+
+static const struct iio_chan_spec bmi323_channels[] = {
+ BMI323_ACCEL_CHANNEL(IIO_ACCEL, X, BMI323_ACCEL_X),
+ BMI323_ACCEL_CHANNEL(IIO_ACCEL, Y, BMI323_ACCEL_Y),
+ BMI323_ACCEL_CHANNEL(IIO_ACCEL, Z, BMI323_ACCEL_Z),
+ BMI323_GYRO_CHANNEL(IIO_ANGL_VEL, X, BMI323_GYRO_X),
+ BMI323_GYRO_CHANNEL(IIO_ANGL_VEL, Y, BMI323_GYRO_Y),
+ BMI323_GYRO_CHANNEL(IIO_ANGL_VEL, Z, BMI323_GYRO_Z),
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = -1,
+ },
+ {
+ .type = IIO_STEPS,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+ BIT(IIO_CHAN_INFO_ENABLE),
+ .scan_index = -1,
+ .event_spec = &bmi323_step_wtrmrk_event,
+ .num_event_specs = 1,
+
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(BMI323_CHAN_MAX),
+};
+
+static const int bmi323_acc_gyro_odr[][2] = {
+ { 0, 781250 },
+ { 1, 562500 },
+ { 3, 125000 },
+ { 6, 250000 },
+ { 12, 500000 },
+ { 25, 0 },
+ { 50, 0 },
+ { 100, 0 },
+ { 200, 0 },
+ { 400, 0 },
+ { 800, 0 },
+};
+
+static const int bmi323_acc_gyro_odrns[] = {
+ 1280 * MEGA,
+ 640 * MEGA,
+ 320 * MEGA,
+ 160 * MEGA,
+ 80 * MEGA,
+ 40 * MEGA,
+ 20 * MEGA,
+ 10 * MEGA,
+ 5 * MEGA,
+ 2500 * KILO,
+ 1250 * KILO,
+};
+
+static enum bmi323_sensor_type bmi323_iio_to_sensor(enum iio_chan_type iio_type)
+{
+ switch (iio_type) {
+ case IIO_ACCEL:
+ return BMI323_ACCEL;
+ case IIO_ANGL_VEL:
+ return BMI323_GYRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bmi323_set_mode(struct bmi323_data *data,
+ enum bmi323_sensor_type sensor,
+ enum bmi323_opr_mode mode)
+{
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config,
+ BMI323_ACC_GYRO_CONF_MODE_MSK,
+ FIELD_PREP(BMI323_ACC_GYRO_CONF_MODE_MSK,
+ mode));
+}
+
+/*
+ * When writing data to extended register there must be no communication to
+ * any other register before write transaction is complete.
+ * See datasheet section 6.2 Extended Register Map Description.
+ */
+static int bmi323_write_ext_reg(struct bmi323_data *data, unsigned int ext_addr,
+ unsigned int ext_data)
+{
+ int ret, feature_status;
+
+ ret = regmap_read(data->regmap, BMI323_FEAT_DATA_STATUS,
+ &feature_status);
+ if (ret)
+ return ret;
+
+ if (!FIELD_GET(BMI323_FEAT_DATA_TX_RDY_MSK, feature_status))
+ return -EBUSY;
+
+ ret = regmap_write(data->regmap, BMI323_FEAT_DATA_ADDR, ext_addr);
+ if (ret)
+ return ret;
+
+ return regmap_write(data->regmap, BMI323_FEAT_DATA_TX, ext_data);
+}
+
+/*
+ * When reading data from extended register there must be no communication to
+ * any other register before read transaction is complete.
+ * See datasheet section 6.2 Extended Register Map Description.
+ */
+static int bmi323_read_ext_reg(struct bmi323_data *data, unsigned int ext_addr,
+ unsigned int *ext_data)
+{
+ int ret, feature_status;
+
+ ret = regmap_read(data->regmap, BMI323_FEAT_DATA_STATUS,
+ &feature_status);
+ if (ret)
+ return ret;
+
+ if (!FIELD_GET(BMI323_FEAT_DATA_TX_RDY_MSK, feature_status))
+ return -EBUSY;
+
+ ret = regmap_write(data->regmap, BMI323_FEAT_DATA_ADDR, ext_addr);
+ if (ret)
+ return ret;
+
+ return regmap_read(data->regmap, BMI323_FEAT_DATA_TX, ext_data);
+}
+
+static int bmi323_update_ext_reg(struct bmi323_data *data,
+ unsigned int ext_addr,
+ unsigned int mask, unsigned int ext_data)
+{
+ unsigned int value;
+ int ret;
+
+ ret = bmi323_read_ext_reg(data, ext_addr, &value);
+ if (ret)
+ return ret;
+
+ set_mask_bits(&value, mask, ext_data);
+
+ return bmi323_write_ext_reg(data, ext_addr, value);
+}
+
+static int bmi323_get_error_status(struct bmi323_data *data)
+{
+ int error, ret;
+
+ guard(mutex)(&data->mutex);
+ ret = regmap_read(data->regmap, BMI323_ERR_REG, &error);
+ if (ret)
+ return ret;
+
+ if (error)
+ dev_err(data->dev, "Sensor error 0x%x\n", error);
+
+ return error;
+}
+
+static int bmi323_feature_engine_events(struct bmi323_data *data,
+ const unsigned int event_mask,
+ bool state)
+{
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(data->regmap, BMI323_FEAT_IO0_REG, &value);
+ if (ret)
+ return ret;
+
+ /* Register must be cleared before changing an active config */
+ ret = regmap_write(data->regmap, BMI323_FEAT_IO0_REG, 0);
+ if (ret)
+ return ret;
+
+ if (state)
+ value |= event_mask;
+ else
+ value &= ~event_mask;
+
+ ret = regmap_write(data->regmap, BMI323_FEAT_IO0_REG, value);
+ if (ret)
+ return ret;
+
+ return regmap_write(data->regmap, BMI323_FEAT_IO_STATUS_REG,
+ BMI323_FEAT_IO_STATUS_MSK);
+}
+
+static int bmi323_step_wtrmrk_en(struct bmi323_data *data, int state)
+{
+ enum bmi323_irq_pin step_irq;
+ int ret;
+
+ guard(mutex)(&data->mutex);
+ if (!FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, data->feature_events))
+ return -EINVAL;
+
+ if (state)
+ step_irq = data->irq_pin;
+ else
+ step_irq = BMI323_IRQ_DISABLED;
+
+ ret = bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG,
+ BMI323_STEP_SC1_WTRMRK_MSK,
+ FIELD_PREP(BMI323_STEP_SC1_WTRMRK_MSK,
+ state ? 1 : 0));
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(data->regmap, BMI323_INT_MAP1_REG,
+ BMI323_STEP_CNT_MSK,
+ FIELD_PREP(BMI323_STEP_CNT_MSK, step_irq));
+}
+
+static int bmi323_motion_config_reg(enum iio_event_direction dir)
+{
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ return BMI323_ANYMO1_REG;
+ case IIO_EV_DIR_FALLING:
+ return BMI323_NOMO1_REG;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bmi323_motion_event_en(struct bmi323_data *data,
+ enum iio_event_direction dir, int state)
+{
+ unsigned int state_value = state ? BMI323_FEAT_XYZ_MSK : 0;
+ int config, ret, msk, raw, field_value;
+ enum bmi323_irq_pin motion_irq;
+ int irq_msk, irq_field_val;
+
+ if (state)
+ motion_irq = data->irq_pin;
+ else
+ motion_irq = BMI323_IRQ_DISABLED;
+
+ switch (dir) {
+ case IIO_EV_DIR_RISING:
+ msk = BMI323_FEAT_IO0_XYZ_MOTION_MSK;
+ raw = 512;
+ config = BMI323_ANYMO1_REG;
+ irq_msk = BMI323_MOTION_MSK;
+ irq_field_val = FIELD_PREP(BMI323_MOTION_MSK, motion_irq);
+ field_value = FIELD_PREP(BMI323_FEAT_IO0_XYZ_MOTION_MSK,
+ state_value);
+ break;
+ case IIO_EV_DIR_FALLING:
+ msk = BMI323_FEAT_IO0_XYZ_NOMOTION_MSK;
+ raw = 0;
+ config = BMI323_NOMO1_REG;
+ irq_msk = BMI323_NOMOTION_MSK;
+ irq_field_val = FIELD_PREP(BMI323_NOMOTION_MSK, motion_irq);
+ field_value = FIELD_PREP(BMI323_FEAT_IO0_XYZ_NOMOTION_MSK,
+ state_value);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ guard(mutex)(&data->mutex);
+ ret = bmi323_feature_engine_events(data, msk, state);
+ if (ret)
+ return ret;
+
+ ret = bmi323_update_ext_reg(data, config,
+ BMI323_MO1_REF_UP_MSK,
+ FIELD_PREP(BMI323_MO1_REF_UP_MSK, 0));
+ if (ret)
+ return ret;
+
+ /* Set initial value to avoid interrupts while enabling*/
+ ret = bmi323_update_ext_reg(data, config,
+ BMI323_MO1_SLOPE_TH_MSK,
+ FIELD_PREP(BMI323_MO1_SLOPE_TH_MSK, raw));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP1_REG, irq_msk,
+ irq_field_val);
+ if (ret)
+ return ret;
+
+ set_mask_bits(&data->feature_events, msk, field_value);
+
+ return 0;
+}
+
+static int bmi323_tap_event_en(struct bmi323_data *data,
+ enum iio_event_direction dir, int state)
+{
+ enum bmi323_irq_pin tap_irq;
+ int ret, tap_enabled;
+
+ guard(mutex)(&data->mutex);
+
+ if (data->odrhz[BMI323_ACCEL] < 200) {
+ dev_err(data->dev, "Invalid accelerometer parameter\n");
+ return -EINVAL;
+ }
+
+ switch (dir) {
+ case IIO_EV_DIR_SINGLETAP:
+ ret = bmi323_feature_engine_events(data,
+ BMI323_FEAT_IO0_S_TAP_MSK,
+ state);
+ if (ret)
+ return ret;
+
+ set_mask_bits(&data->feature_events, BMI323_FEAT_IO0_S_TAP_MSK,
+ FIELD_PREP(BMI323_FEAT_IO0_S_TAP_MSK, state));
+ break;
+ case IIO_EV_DIR_DOUBLETAP:
+ ret = bmi323_feature_engine_events(data,
+ BMI323_FEAT_IO0_D_TAP_MSK,
+ state);
+ if (ret)
+ return ret;
+
+ set_mask_bits(&data->feature_events, BMI323_FEAT_IO0_D_TAP_MSK,
+ FIELD_PREP(BMI323_FEAT_IO0_D_TAP_MSK, state));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ tap_enabled = FIELD_GET(BMI323_FEAT_IO0_S_TAP_MSK |
+ BMI323_FEAT_IO0_D_TAP_MSK,
+ data->feature_events);
+
+ if (tap_enabled)
+ tap_irq = data->irq_pin;
+ else
+ tap_irq = BMI323_IRQ_DISABLED;
+
+ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG,
+ BMI323_TAP_MSK,
+ FIELD_PREP(BMI323_TAP_MSK, tap_irq));
+ if (ret)
+ return ret;
+
+ if (!state)
+ return 0;
+
+ ret = bmi323_update_ext_reg(data, BMI323_TAP1_REG,
+ BMI323_TAP1_MAX_PEAKS_MSK,
+ FIELD_PREP(BMI323_TAP1_MAX_PEAKS_MSK,
+ 0x04));
+ if (ret)
+ return ret;
+
+ ret = bmi323_update_ext_reg(data, BMI323_TAP1_REG,
+ BMI323_TAP1_AXIS_SEL_MSK,
+ FIELD_PREP(BMI323_TAP1_AXIS_SEL_MSK,
+ BMI323_AXIS_XYZ_MSK));
+ if (ret)
+ return ret;
+
+ return bmi323_update_ext_reg(data, BMI323_TAP1_REG,
+ BMI323_TAP1_TIMOUT_MSK,
+ FIELD_PREP(BMI323_TAP1_TIMOUT_MSK,
+ 0));
+}
+
+static ssize_t in_accel_gesture_tap_wait_dur_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct bmi323_data *data = iio_priv(indio_dev);
+ unsigned int reg_value, raw;
+ int ret, val[2];
+
+ scoped_guard(mutex, &data->mutex) {
+ ret = bmi323_read_ext_reg(data, BMI323_TAP2_REG, &reg_value);
+ if (ret)
+ return ret;
+ }
+
+ raw = FIELD_GET(BMI323_TAP2_MAX_DUR_MSK, reg_value);
+ val[0] = raw / BMI323_MAX_GES_DUR_SCALE;
+ val[1] = BMI323_RAW_TO_MICRO(raw, BMI323_MAX_GES_DUR_SCALE);
+
+ return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, ARRAY_SIZE(val),
+ val);
+}
+
+static ssize_t in_accel_gesture_tap_wait_dur_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct bmi323_data *data = iio_priv(indio_dev);
+ int ret, val_int, val_fract, raw;
+
+ ret = iio_str_to_fixpoint(buf, 100000, &val_int, &val_fract);
+ if (ret)
+ return ret;
+
+ raw = BMI323_INT_MICRO_TO_RAW(val_int, val_fract,
+ BMI323_MAX_GES_DUR_SCALE);
+ if (!in_range(raw, 0, 64))
+ return -EINVAL;
+
+ guard(mutex)(&data->mutex);
+ ret = bmi323_update_ext_reg(data, BMI323_TAP2_REG,
+ BMI323_TAP2_MAX_DUR_MSK,
+ FIELD_PREP(BMI323_TAP2_MAX_DUR_MSK, raw));
+ if (ret)
+ return ret;
+
+ return len;
+}
+
+/*
+ * Maximum duration from first tap within the second tap is expected to happen.
+ * This timeout is applicable only if gesture_tap_wait_timeout is enabled.
+ */
+static IIO_DEVICE_ATTR_RW(in_accel_gesture_tap_wait_dur, 0);
+
+static ssize_t in_accel_gesture_tap_wait_timeout_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct bmi323_data *data = iio_priv(indio_dev);
+ unsigned int reg_value, raw;
+ int ret;
+
+ scoped_guard(mutex, &data->mutex) {
+ ret = bmi323_read_ext_reg(data, BMI323_TAP1_REG, &reg_value);
+ if (ret)
+ return ret;
+ }
+
+ raw = FIELD_GET(BMI323_TAP1_TIMOUT_MSK, reg_value);
+
+ return iio_format_value(buf, IIO_VAL_INT, 1, &raw);
+}
+
+static ssize_t in_accel_gesture_tap_wait_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct bmi323_data *data = iio_priv(indio_dev);
+ bool val;
+ int ret;
+
+ ret = kstrtobool(buf, &val);
+ if (ret)
+ return ret;
+
+ guard(mutex)(&data->mutex);
+ ret = bmi323_update_ext_reg(data, BMI323_TAP1_REG,
+ BMI323_TAP1_TIMOUT_MSK,
+ FIELD_PREP(BMI323_TAP1_TIMOUT_MSK, val));
+ if (ret)
+ return ret;
+
+ return len;
+}
+
+/* Enable/disable gesture confirmation with wait time */
+static IIO_DEVICE_ATTR_RW(in_accel_gesture_tap_wait_timeout, 0);
+
+static IIO_CONST_ATTR(in_accel_gesture_tap_wait_dur_available,
+ "[0.0 0.04 2.52]");
+
+static IIO_CONST_ATTR(in_accel_gesture_doubletap_tap2_min_delay_available,
+ "[0.005 0.005 0.075]");
+
+static IIO_CONST_ATTR(in_accel_gesture_tap_reset_timeout_available,
+ "[0.04 0.04 0.6]");
+
+static IIO_CONST_ATTR(in_accel_gesture_tap_value_available, "[0.0 0.002 1.99]");
+
+static IIO_CONST_ATTR(in_accel_mag_value_available, "[0.0 0.002 7.99]");
+
+static IIO_CONST_ATTR(in_accel_mag_period_available, "[0.0 0.02 162.0]");
+
+static IIO_CONST_ATTR(in_accel_mag_hysteresis_available, "[0.0 0.002 1.99]");
+
+static struct attribute *bmi323_event_attributes[] = {
+ &iio_const_attr_in_accel_gesture_tap_value_available.dev_attr.attr,
+ &iio_const_attr_in_accel_gesture_tap_reset_timeout_available.dev_attr.attr,
+ &iio_const_attr_in_accel_gesture_doubletap_tap2_min_delay_available.dev_attr.attr,
+ &iio_const_attr_in_accel_gesture_tap_wait_dur_available.dev_attr.attr,
+ &iio_dev_attr_in_accel_gesture_tap_wait_timeout.dev_attr.attr,
+ &iio_dev_attr_in_accel_gesture_tap_wait_dur.dev_attr.attr,
+ &iio_const_attr_in_accel_mag_value_available.dev_attr.attr,
+ &iio_const_attr_in_accel_mag_period_available.dev_attr.attr,
+ &iio_const_attr_in_accel_mag_hysteresis_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group bmi323_event_attribute_group = {
+ .attrs = bmi323_event_attributes,
+};
+
+static int bmi323_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir, int state)
+{
+ struct bmi323_data *data = iio_priv(indio_dev);
+
+ switch (type) {
+ case IIO_EV_TYPE_MAG:
+ return bmi323_motion_event_en(data, dir, state);
+ case IIO_EV_TYPE_GESTURE:
+ return bmi323_tap_event_en(data, dir, state);
+ case IIO_EV_TYPE_CHANGE:
+ return bmi323_step_wtrmrk_en(data, state);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bmi323_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct bmi323_data *data = iio_priv(indio_dev);
+ int ret, value, reg_val;
+
+ guard(mutex)(&data->mutex);
+
+ switch (chan->type) {
+ case IIO_ACCEL:
+ switch (dir) {
+ case IIO_EV_DIR_SINGLETAP:
+ ret = FIELD_GET(BMI323_FEAT_IO0_S_TAP_MSK,
+ data->feature_events);
+ break;
+ case IIO_EV_DIR_DOUBLETAP:
+ ret = FIELD_GET(BMI323_FEAT_IO0_D_TAP_MSK,
+ data->feature_events);
+ break;
+ case IIO_EV_DIR_RISING:
+ value = FIELD_GET(BMI323_FEAT_IO0_XYZ_MOTION_MSK,
+ data->feature_events);
+ ret = value ? 1 : 0;
+ break;
+ case IIO_EV_DIR_FALLING:
+ value = FIELD_GET(BMI323_FEAT_IO0_XYZ_NOMOTION_MSK,
+ data->feature_events);
+ ret = value ? 1 : 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+ case IIO_STEPS:
+ ret = regmap_read(data->regmap, BMI323_INT_MAP1_REG, &reg_val);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(BMI323_STEP_CNT_MSK, reg_val) ? 1 : 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bmi323_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct bmi323_data *data = iio_priv(indio_dev);
+ unsigned int raw;
+ int reg;
+
+ guard(mutex)(&data->mutex);
+
+ switch (type) {
+ case IIO_EV_TYPE_GESTURE:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ if (!in_range(val, 0, 2))
+ return -EINVAL;
+
+ raw = BMI323_INT_MICRO_TO_RAW(val, val2,
+ BMI323_TAP_THRES_SCALE);
+
+ return bmi323_update_ext_reg(data, BMI323_TAP2_REG,
+ BMI323_TAP2_THRES_MSK,
+ FIELD_PREP(BMI323_TAP2_THRES_MSK,
+ raw));
+ case IIO_EV_INFO_RESET_TIMEOUT:
+ if (val || !in_range(val2, 40000, 560001))
+ return -EINVAL;
+
+ raw = BMI323_INT_MICRO_TO_RAW(val, val2,
+ BMI323_QUITE_TIM_GES_SCALE);
+
+ return bmi323_update_ext_reg(data, BMI323_TAP3_REG,
+ BMI323_TAP3_QT_AFT_GES_MSK,
+ FIELD_PREP(BMI323_TAP3_QT_AFT_GES_MSK,
+ raw));
+ case IIO_EV_INFO_TAP2_MIN_DELAY:
+ if (val || !in_range(val2, 5000, 70001))
+ return -EINVAL;
+
+ raw = BMI323_INT_MICRO_TO_RAW(val, val2,
+ BMI323_DUR_BW_TAP_SCALE);
+
+ return bmi323_update_ext_reg(data, BMI323_TAP3_REG,
+ BMI323_TAP3_QT_BW_TAP_MSK,
+ FIELD_PREP(BMI323_TAP3_QT_BW_TAP_MSK,
+ raw));
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_TYPE_MAG:
+ reg = bmi323_motion_config_reg(dir);
+ if (reg < 0)
+ return -EINVAL;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ if (!in_range(val, 0, 8))
+ return -EINVAL;
+
+ raw = BMI323_INT_MICRO_TO_RAW(val, val2,
+ BMI323_MOTION_THRES_SCALE);
+
+ return bmi323_update_ext_reg(data, reg,
+ BMI323_MO1_SLOPE_TH_MSK,
+ FIELD_PREP(BMI323_MO1_SLOPE_TH_MSK,
+ raw));
+ case IIO_EV_INFO_PERIOD:
+ if (!in_range(val, 0, 163))
+ return -EINVAL;
+
+ raw = BMI323_INT_MICRO_TO_RAW(val, val2,
+ BMI323_MOTION_DURAT_SCALE);
+
+ return bmi323_update_ext_reg(data,
+ reg + BMI323_MO3_OFFSET,
+ BMI323_MO3_DURA_MSK,
+ FIELD_PREP(BMI323_MO3_DURA_MSK,
+ raw));
+ case IIO_EV_INFO_HYSTERESIS:
+ if (!in_range(val, 0, 2))
+ return -EINVAL;
+
+ raw = BMI323_INT_MICRO_TO_RAW(val, val2,
+ BMI323_MOTION_HYSTR_SCALE);
+
+ return bmi323_update_ext_reg(data,
+ reg + BMI323_MO2_OFFSET,
+ BMI323_MO2_HYSTR_MSK,
+ FIELD_PREP(BMI323_MO2_HYSTR_MSK,
+ raw));
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_TYPE_CHANGE:
+ if (!in_range(val, 0, 20461))
+ return -EINVAL;
+
+ raw = val / 20;
+ return bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG,
+ BMI323_STEP_SC1_WTRMRK_MSK,
+ FIELD_PREP(BMI323_STEP_SC1_WTRMRK_MSK,
+ raw));
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bmi323_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct bmi323_data *data = iio_priv(indio_dev);
+ unsigned int raw, reg_value;
+ int ret, reg;
+
+ guard(mutex)(&data->mutex);
+
+ switch (type) {
+ case IIO_EV_TYPE_GESTURE:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ ret = bmi323_read_ext_reg(data, BMI323_TAP2_REG,
+ &reg_value);
+ if (ret)
+ return ret;
+
+ raw = FIELD_GET(BMI323_TAP2_THRES_MSK, reg_value);
+ *val = raw / BMI323_TAP_THRES_SCALE;
+ *val2 = BMI323_RAW_TO_MICRO(raw, BMI323_TAP_THRES_SCALE);
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_EV_INFO_RESET_TIMEOUT:
+ ret = bmi323_read_ext_reg(data, BMI323_TAP3_REG,
+ &reg_value);
+ if (ret)
+ return ret;
+
+ raw = FIELD_GET(BMI323_TAP3_QT_AFT_GES_MSK, reg_value);
+ *val = 0;
+ *val2 = BMI323_RAW_TO_MICRO(raw,
+ BMI323_QUITE_TIM_GES_SCALE);
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_EV_INFO_TAP2_MIN_DELAY:
+ ret = bmi323_read_ext_reg(data, BMI323_TAP3_REG,
+ &reg_value);
+ if (ret)
+ return ret;
+
+ raw = FIELD_GET(BMI323_TAP3_QT_BW_TAP_MSK, reg_value);
+ *val = 0;
+ *val2 = BMI323_RAW_TO_MICRO(raw,
+ BMI323_DUR_BW_TAP_SCALE);
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_TYPE_MAG:
+ reg = bmi323_motion_config_reg(dir);
+ if (reg < 0)
+ return -EINVAL;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ ret = bmi323_read_ext_reg(data, reg, &reg_value);
+ if (ret)
+ return ret;
+
+ raw = FIELD_GET(BMI323_MO1_SLOPE_TH_MSK, reg_value);
+ *val = raw / BMI323_MOTION_THRES_SCALE;
+ *val2 = BMI323_RAW_TO_MICRO(raw,
+ BMI323_MOTION_THRES_SCALE);
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_EV_INFO_PERIOD:
+ ret = bmi323_read_ext_reg(data,
+ reg + BMI323_MO3_OFFSET,
+ &reg_value);
+ if (ret)
+ return ret;
+
+ raw = FIELD_GET(BMI323_MO3_DURA_MSK, reg_value);
+ *val = raw / BMI323_MOTION_DURAT_SCALE;
+ *val2 = BMI323_RAW_TO_MICRO(raw,
+ BMI323_MOTION_DURAT_SCALE);
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_EV_INFO_HYSTERESIS:
+ ret = bmi323_read_ext_reg(data,
+ reg + BMI323_MO2_OFFSET,
+ &reg_value);
+ if (ret)
+ return ret;
+
+ raw = FIELD_GET(BMI323_MO2_HYSTR_MSK, reg_value);
+ *val = raw / BMI323_MOTION_HYSTR_SCALE;
+ *val2 = BMI323_RAW_TO_MICRO(raw,
+ BMI323_MOTION_HYSTR_SCALE);
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_TYPE_CHANGE:
+ ret = bmi323_read_ext_reg(data, BMI323_STEP_SC1_REG,
+ &reg_value);
+ if (ret)
+ return ret;
+
+ raw = FIELD_GET(BMI323_STEP_SC1_WTRMRK_MSK, reg_value);
+ *val = raw * 20;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int __bmi323_fifo_flush(struct iio_dev *indio_dev)
+{
+ struct bmi323_data *data = iio_priv(indio_dev);
+ int i, ret, fifo_lvl, frame_count, bit, index;
+ __le16 *frame, *pchannels;
+ u64 sample_period;
+ s64 tstamp;
+
+ guard(mutex)(&data->mutex);
+ ret = regmap_read(data->regmap, BMI323_FIFO_FILL_LEVEL_REG, &fifo_lvl);
+ if (ret)
+ return ret;
+
+ fifo_lvl = min(fifo_lvl, BMI323_FIFO_FULL_IN_WORDS);
+
+ frame_count = fifo_lvl / BMI323_FIFO_FRAME_LENGTH;
+ if (!frame_count)
+ return -EINVAL;
+
+ if (fifo_lvl % BMI323_FIFO_FRAME_LENGTH)
+ dev_warn(data->dev, "Bad FIFO alignment\n");
+
+ /*
+ * Approximate timestamps for each of the sample based on the sampling
+ * frequency, timestamp for last sample and number of samples.
+ */
+ if (data->old_fifo_tstamp) {
+ sample_period = data->fifo_tstamp - data->old_fifo_tstamp;
+ do_div(sample_period, frame_count);
+ } else {
+ sample_period = data->odrns[BMI323_ACCEL];
+ }
+
+ tstamp = data->fifo_tstamp - (frame_count - 1) * sample_period;
+
+ ret = regmap_noinc_read(data->regmap, BMI323_FIFO_DATA_REG,
+ &data->fifo_buff[0],
+ fifo_lvl * BMI323_BYTES_PER_SAMPLE);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < frame_count; i++) {
+ frame = &data->fifo_buff[i * BMI323_FIFO_FRAME_LENGTH];
+ pchannels = &data->buffer.channels[0];
+
+ index = 0;
+ for_each_set_bit(bit, indio_dev->active_scan_mask,
+ BMI323_CHAN_MAX)
+ pchannels[index++] = frame[bit];
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
+ tstamp);
+
+ tstamp += sample_period;
+ }
+
+ return frame_count;
+}
+
+static int bmi323_set_watermark(struct iio_dev *indio_dev, unsigned int val)
+{
+ struct bmi323_data *data = iio_priv(indio_dev);
+
+ val = min(val, (u32)BMI323_FIFO_FULL_IN_FRAMES);
+
+ guard(mutex)(&data->mutex);
+ data->watermark = val;
+
+ return 0;
+}
+
+static int bmi323_fifo_disable(struct bmi323_data *data)
+{
+ int ret;
+
+ guard(mutex)(&data->mutex);
+ ret = regmap_write(data->regmap, BMI323_FIFO_CONF_REG, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG,
+ BMI323_FIFO_WTRMRK_MSK,
+ FIELD_PREP(BMI323_FIFO_WTRMRK_MSK, 0));
+ if (ret)
+ return ret;
+
+ data->fifo_tstamp = 0;
+ data->state = BMI323_IDLE;
+
+ return 0;
+}
+
+static int bmi323_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct bmi323_data *data = iio_priv(indio_dev);
+
+ if (iio_device_get_current_mode(indio_dev) == INDIO_BUFFER_TRIGGERED)
+ return 0;
+
+ return bmi323_fifo_disable(data);
+}
+
+static int bmi323_update_watermark(struct bmi323_data *data)
+{
+ int wtrmrk;
+
+ wtrmrk = data->watermark * BMI323_FIFO_FRAME_LENGTH;
+
+ return regmap_write(data->regmap, BMI323_FIFO_WTRMRK_REG, wtrmrk);
+}
+
+static int bmi323_fifo_enable(struct bmi323_data *data)
+{
+ int ret;
+
+ guard(mutex)(&data->mutex);
+ ret = regmap_update_bits(data->regmap, BMI323_FIFO_CONF_REG,
+ BMI323_FIFO_CONF_ACC_GYR_EN_MSK,
+ FIELD_PREP(BMI323_FIFO_CONF_ACC_GYR_EN_MSK,
+ BMI323_FIFO_ACC_GYR_MSK));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG,
+ BMI323_FIFO_WTRMRK_MSK,
+ FIELD_PREP(BMI323_FIFO_WTRMRK_MSK,
+ data->irq_pin));
+ if (ret)
+ return ret;
+
+ ret = bmi323_update_watermark(data);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap, BMI323_FIFO_CTRL_REG,
+ BMI323_FIFO_FLUSH_MSK);
+ if (ret)
+ return ret;
+
+ data->state = BMI323_BUFFER_FIFO;
+
+ return 0;
+}
+
+static int bmi323_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct bmi323_data *data = iio_priv(indio_dev);
+
+ guard(mutex)(&data->mutex);
+ /*
+ * When the ODR of the accelerometer and gyroscope do not match, the
+ * maximum ODR value between the accelerometer and gyroscope is used
+ * for FIFO and the signal with lower ODR will insert dummy frame.
+ * So allow buffer read only when ODR's of accelero and gyro are equal.
+ * See datasheet section 5.7 "FIFO Data Buffering".
+ */
+ if (data->odrns[BMI323_ACCEL] != data->odrns[BMI323_GYRO]) {
+ dev_err(data->dev, "Accelero and Gyro ODR doesn't match\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int bmi323_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct bmi323_data *data = iio_priv(indio_dev);
+
+ if (iio_device_get_current_mode(indio_dev) == INDIO_BUFFER_TRIGGERED)
+ return 0;
+
+ return bmi323_fifo_enable(data);
+}
+
+static ssize_t hwfifo_watermark_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct bmi323_data *data = iio_priv(indio_dev);
+ int wm;
+
+ scoped_guard(mutex, &data->mutex)
+ wm = data->watermark;
+
+ return sysfs_emit(buf, "%d\n", wm);
+}
+static IIO_DEVICE_ATTR_RO(hwfifo_watermark, 0);
+
+static ssize_t hwfifo_enabled_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct bmi323_data *data = iio_priv(indio_dev);
+ bool state;
+
+ scoped_guard(mutex, &data->mutex)
+ state = data->state == BMI323_BUFFER_FIFO;
+
+ return sysfs_emit(buf, "%d\n", state);
+}
+static IIO_DEVICE_ATTR_RO(hwfifo_enabled, 0);
+
+static const struct iio_dev_attr *bmi323_fifo_attributes[] = {
+ &iio_dev_attr_hwfifo_watermark,
+ &iio_dev_attr_hwfifo_enabled,
+ NULL
+};
+
+static const struct iio_buffer_setup_ops bmi323_buffer_ops = {
+ .preenable = bmi323_buffer_preenable,
+ .postenable = bmi323_buffer_postenable,
+ .predisable = bmi323_buffer_predisable,
+};
+
+static irqreturn_t bmi323_irq_thread_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct bmi323_data *data = iio_priv(indio_dev);
+ unsigned int status_addr, status, feature_event;
+ s64 timestamp = iio_get_time_ns(indio_dev);
+ int ret;
+
+ if (data->irq_pin == BMI323_IRQ_INT1)
+ status_addr = BMI323_STATUS_INT1_REG;
+ else
+ status_addr = BMI323_STATUS_INT2_REG;
+
+ scoped_guard(mutex, &data->mutex) {
+ ret = regmap_read(data->regmap, status_addr, &status);
+ if (ret)
+ return IRQ_NONE;
+ }
+
+ if (!status || FIELD_GET(BMI323_STATUS_ERROR_MSK, status))
+ return IRQ_NONE;
+
+ if (FIELD_GET(BMI323_STATUS_FIFO_WTRMRK_MSK, status)) {
+ data->old_fifo_tstamp = data->fifo_tstamp;
+ data->fifo_tstamp = iio_get_time_ns(indio_dev);
+ ret = __bmi323_fifo_flush(indio_dev);
+ if (ret < 0)
+ return IRQ_NONE;
+ }
+
+ if (FIELD_GET(BMI323_STATUS_ACC_GYR_DRDY_MSK, status))
+ iio_trigger_poll_nested(data->trig);
+
+ if (FIELD_GET(BMI323_STATUS_MOTION_MSK, status))
+ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
+ IIO_MOD_X_OR_Y_OR_Z,
+ IIO_EV_TYPE_MAG,
+ IIO_EV_DIR_RISING),
+ timestamp);
+
+ if (FIELD_GET(BMI323_STATUS_NOMOTION_MSK, status))
+ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
+ IIO_MOD_X_OR_Y_OR_Z,
+ IIO_EV_TYPE_MAG,
+ IIO_EV_DIR_FALLING),
+ timestamp);
+
+ if (FIELD_GET(BMI323_STATUS_STP_WTR_MSK, status))
+ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_STEPS, 0,
+ IIO_NO_MOD,
+ IIO_EV_TYPE_CHANGE,
+ IIO_EV_DIR_NONE),
+ timestamp);
+
+ if (FIELD_GET(BMI323_STATUS_TAP_MSK, status)) {
+ scoped_guard(mutex, &data->mutex) {
+ ret = regmap_read(data->regmap,
+ BMI323_FEAT_EVNT_EXT_REG,
+ &feature_event);
+ if (ret)
+ return IRQ_NONE;
+ }
+
+ if (FIELD_GET(BMI323_FEAT_EVNT_EXT_S_MSK, feature_event)) {
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
+ IIO_MOD_X_OR_Y_OR_Z,
+ IIO_EV_TYPE_GESTURE,
+ IIO_EV_DIR_SINGLETAP),
+ timestamp);
+ }
+
+ if (FIELD_GET(BMI323_FEAT_EVNT_EXT_D_MSK, feature_event))
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
+ IIO_MOD_X_OR_Y_OR_Z,
+ IIO_EV_TYPE_GESTURE,
+ IIO_EV_DIR_DOUBLETAP),
+ timestamp);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int bmi323_set_drdy_irq(struct bmi323_data *data,
+ enum bmi323_irq_pin irq_pin)
+{
+ int ret;
+
+ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG,
+ BMI323_GYR_DRDY_MSK,
+ FIELD_PREP(BMI323_GYR_DRDY_MSK, irq_pin));
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG,
+ BMI323_ACC_DRDY_MSK,
+ FIELD_PREP(BMI323_ACC_DRDY_MSK, irq_pin));
+}
+
+static int bmi323_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct bmi323_data *data = iio_trigger_get_drvdata(trig);
+ enum bmi323_irq_pin irq_pin;
+
+ guard(mutex)(&data->mutex);
+
+ if (data->state == BMI323_BUFFER_FIFO) {
+ dev_warn(data->dev, "Can't set trigger when FIFO enabled\n");
+ return -EBUSY;
+ }
+
+ if (state) {
+ data->state = BMI323_BUFFER_DRDY_TRIGGERED;
+ irq_pin = data->irq_pin;
+ } else {
+ data->state = BMI323_IDLE;
+ irq_pin = BMI323_IRQ_DISABLED;
+ }
+
+ return bmi323_set_drdy_irq(data, irq_pin);
+}
+
+static const struct iio_trigger_ops bmi323_trigger_ops = {
+ .set_trigger_state = &bmi323_data_rdy_trigger_set_state,
+};
+
+static irqreturn_t bmi323_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct bmi323_data *data = iio_priv(indio_dev);
+ int ret, bit, index = 0;
+
+ /* Lock to protect the data->buffer */
+ guard(mutex)(&data->mutex);
+
+ if (*indio_dev->active_scan_mask == BMI323_ALL_CHAN_MSK) {
+ ret = regmap_bulk_read(data->regmap, BMI323_ACCEL_X_REG,
+ &data->buffer.channels,
+ ARRAY_SIZE(data->buffer.channels));
+ if (ret)
+ return IRQ_NONE;
+ } else {
+ for_each_set_bit(bit, indio_dev->active_scan_mask,
+ BMI323_CHAN_MAX) {
+ ret = regmap_raw_read(data->regmap,
+ BMI323_ACCEL_X_REG + bit,
+ &data->buffer.channels[index++],
+ BMI323_BYTES_PER_SAMPLE);
+ if (ret)
+ return IRQ_NONE;
+ }
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
+ iio_get_time_ns(indio_dev));
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int bmi323_set_average(struct bmi323_data *data,
+ enum bmi323_sensor_type sensor, int avg)
+{
+ int raw = ARRAY_SIZE(bmi323_accel_gyro_avrg);
+
+ while (raw--)
+ if (avg == bmi323_accel_gyro_avrg[raw])
+ break;
+ if (raw < 0)
+ return -EINVAL;
+
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config,
+ BMI323_ACC_GYRO_CONF_AVG_MSK,
+ FIELD_PREP(BMI323_ACC_GYRO_CONF_AVG_MSK,
+ raw));
+}
+
+static int bmi323_get_average(struct bmi323_data *data,
+ enum bmi323_sensor_type sensor, int *avg)
+{
+ int ret, value, raw;
+
+ scoped_guard(mutex, &data->mutex) {
+ ret = regmap_read(data->regmap, bmi323_hw[sensor].config, &value);
+ if (ret)
+ return ret;
+ }
+
+ raw = FIELD_GET(BMI323_ACC_GYRO_CONF_AVG_MSK, value);
+ *avg = bmi323_accel_gyro_avrg[raw];
+
+ return IIO_VAL_INT;
+}
+
+static int bmi323_enable_steps(struct bmi323_data *data, int val)
+{
+ int ret;
+
+ guard(mutex)(&data->mutex);
+ if (data->odrhz[BMI323_ACCEL] < 200) {
+ dev_err(data->dev, "Invalid accelerometer parameter\n");
+ return -EINVAL;
+ }
+
+ ret = bmi323_feature_engine_events(data, BMI323_FEAT_IO0_STP_CNT_MSK,
+ val ? 1 : 0);
+ if (ret)
+ return ret;
+
+ set_mask_bits(&data->feature_events, BMI323_FEAT_IO0_STP_CNT_MSK,
+ FIELD_PREP(BMI323_FEAT_IO0_STP_CNT_MSK, val ? 1 : 0));
+
+ return 0;
+}
+
+static int bmi323_read_steps(struct bmi323_data *data, int *val)
+{
+ int ret;
+
+ guard(mutex)(&data->mutex);
+ if (!FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, data->feature_events))
+ return -EINVAL;
+
+ ret = regmap_bulk_read(data->regmap, BMI323_FEAT_IO2_REG,
+ data->steps_count,
+ ARRAY_SIZE(data->steps_count));
+ if (ret)
+ return ret;
+
+ *val = get_unaligned_le32(data->steps_count);
+
+ return IIO_VAL_INT;
+}
+
+static int bmi323_read_axis(struct bmi323_data *data,
+ struct iio_chan_spec const *chan, int *val)
+{
+ enum bmi323_sensor_type sensor;
+ unsigned int value;
+ u8 addr;
+ int ret;
+
+ ret = bmi323_get_error_status(data);
+ if (ret)
+ return -EINVAL;
+
+ sensor = bmi323_iio_to_sensor(chan->type);
+ addr = bmi323_hw[sensor].data + (chan->channel2 - IIO_MOD_X);
+
+ scoped_guard(mutex, &data->mutex) {
+ ret = regmap_read(data->regmap, addr, &value);
+ if (ret)
+ return ret;
+ }
+
+ *val = sign_extend32(value, chan->scan_type.realbits - 1);
+
+ return IIO_VAL_INT;
+}
+
+static int bmi323_get_temp_data(struct bmi323_data *data, int *val)
+{
+ unsigned int value;
+ int ret;
+
+ ret = bmi323_get_error_status(data);
+ if (ret)
+ return -EINVAL;
+
+ scoped_guard(mutex, &data->mutex) {
+ ret = regmap_read(data->regmap, BMI323_TEMP_REG, &value);
+ if (ret)
+ return ret;
+ }
+
+ *val = sign_extend32(value, 15);
+
+ return IIO_VAL_INT;
+}
+
+static int bmi323_get_odr(struct bmi323_data *data,
+ enum bmi323_sensor_type sensor, int *odr, int *uodr)
+{
+ int ret, value, odr_raw;
+
+ scoped_guard(mutex, &data->mutex) {
+ ret = regmap_read(data->regmap, bmi323_hw[sensor].config, &value);
+ if (ret)
+ return ret;
+ }
+
+ odr_raw = FIELD_GET(BMI323_ACC_GYRO_CONF_ODR_MSK, value);
+ *odr = bmi323_acc_gyro_odr[odr_raw - 1][0];
+ *uodr = bmi323_acc_gyro_odr[odr_raw - 1][1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int bmi323_configure_power_mode(struct bmi323_data *data,
+ enum bmi323_sensor_type sensor,
+ int odr_index)
+{
+ enum bmi323_opr_mode mode;
+
+ if (bmi323_acc_gyro_odr[odr_index][0] > 25)
+ mode = ACC_GYRO_MODE_CONTINOUS;
+ else
+ mode = ACC_GYRO_MODE_DUTYCYCLE;
+
+ return bmi323_set_mode(data, sensor, mode);
+}
+
+static int bmi323_set_odr(struct bmi323_data *data,
+ enum bmi323_sensor_type sensor, int odr, int uodr)
+{
+ int odr_raw, ret;
+
+ odr_raw = ARRAY_SIZE(bmi323_acc_gyro_odr);
+
+ while (odr_raw--)
+ if (odr == bmi323_acc_gyro_odr[odr_raw][0] &&
+ uodr == bmi323_acc_gyro_odr[odr_raw][1])
+ break;
+ if (odr_raw < 0)
+ return -EINVAL;
+
+ ret = bmi323_configure_power_mode(data, sensor, odr_raw);
+ if (ret)
+ return -EINVAL;
+
+ guard(mutex)(&data->mutex);
+ data->odrhz[sensor] = bmi323_acc_gyro_odr[odr_raw][0];
+ data->odrns[sensor] = bmi323_acc_gyro_odrns[odr_raw];
+
+ odr_raw++;
+
+ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config,
+ BMI323_ACC_GYRO_CONF_ODR_MSK,
+ FIELD_PREP(BMI323_ACC_GYRO_CONF_ODR_MSK,
+ odr_raw));
+}
+
+static int bmi323_get_scale(struct bmi323_data *data,
+ enum bmi323_sensor_type sensor, int *val2)
+{
+ int ret, value, scale_raw;
+
+ scoped_guard(mutex, &data->mutex) {
+ ret = regmap_read(data->regmap, bmi323_hw[sensor].config,
+ &value);
+ if (ret)
+ return ret;
+ }
+
+ scale_raw = FIELD_GET(BMI323_ACC_GYRO_CONF_SCL_MSK, value);
+ *val2 = bmi323_hw[sensor].scale_table[scale_raw][1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int bmi323_set_scale(struct bmi323_data *data,
+ enum bmi323_sensor_type sensor, int val, int val2)
+{
+ int scale_raw;
+
+ scale_raw = bmi323_hw[sensor].scale_table_len;
+
+ while (scale_raw--)
+ if (val == bmi323_hw[sensor].scale_table[scale_raw][0] &&
+ val2 == bmi323_hw[sensor].scale_table[scale_raw][1])
+ break;
+ if (scale_raw < 0)
+ return -EINVAL;
+
+ guard(mutex)(&data->mutex);
+ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config,
+ BMI323_ACC_GYRO_CONF_SCL_MSK,
+ FIELD_PREP(BMI323_ACC_GYRO_CONF_SCL_MSK,
+ scale_raw));
+}
+
+static int bmi323_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ enum bmi323_sensor_type sensor;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *vals = (const int *)bmi323_acc_gyro_odr;
+ *length = ARRAY_SIZE(bmi323_acc_gyro_odr) * 2;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ sensor = bmi323_iio_to_sensor(chan->type);
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *vals = (const int *)bmi323_hw[sensor].scale_table;
+ *length = bmi323_hw[sensor].scale_table_len * 2;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *type = IIO_VAL_INT;
+ *vals = (const int *)bmi323_accel_gyro_avrg;
+ *length = ARRAY_SIZE(bmi323_accel_gyro_avrg);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bmi323_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ struct bmi323_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = bmi323_set_odr(data, bmi323_iio_to_sensor(chan->type),
+ val, val2);
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
+ case IIO_CHAN_INFO_SCALE:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = bmi323_set_scale(data, bmi323_iio_to_sensor(chan->type),
+ val, val2);
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = bmi323_set_average(data, bmi323_iio_to_sensor(chan->type),
+ val);
+
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
+ case IIO_CHAN_INFO_ENABLE:
+ return bmi323_enable_steps(data, val);
+ case IIO_CHAN_INFO_PROCESSED:
+ scoped_guard(mutex, &data->mutex) {
+ if (val || !FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK,
+ data->feature_events))
+ return -EINVAL;
+
+ /* Clear step counter value */
+ ret = bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG,
+ BMI323_STEP_SC1_RST_CNT_MSK,
+ FIELD_PREP(BMI323_STEP_SC1_RST_CNT_MSK,
+ 1));
+ }
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int bmi323_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct bmi323_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ return bmi323_read_steps(data, val);
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_ACCEL:
+ case IIO_ANGL_VEL:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = bmi323_read_axis(data, chan, val);
+
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
+ case IIO_TEMP:
+ return bmi323_get_temp_data(data, val);
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return bmi323_get_odr(data, bmi323_iio_to_sensor(chan->type),
+ val, val2);
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ACCEL:
+ case IIO_ANGL_VEL:
+ *val = 0;
+ return bmi323_get_scale(data,
+ bmi323_iio_to_sensor(chan->type),
+ val2);
+ case IIO_TEMP:
+ *val = BMI323_TEMP_SCALE / MEGA;
+ *val2 = BMI323_TEMP_SCALE % MEGA;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ return bmi323_get_average(data,
+ bmi323_iio_to_sensor(chan->type),
+ val);
+ case IIO_CHAN_INFO_OFFSET:
+ switch (chan->type) {
+ case IIO_TEMP:
+ *val = BMI323_TEMP_OFFSET;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_ENABLE:
+ scoped_guard(mutex, &data->mutex)
+ *val = FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK,
+ data->feature_events);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info bmi323_info = {
+ .read_raw = bmi323_read_raw,
+ .write_raw = bmi323_write_raw,
+ .read_avail = bmi323_read_avail,
+ .hwfifo_set_watermark = bmi323_set_watermark,
+ .write_event_config = bmi323_write_event_config,
+ .read_event_config = bmi323_read_event_config,
+ .write_event_value = bmi323_write_event_value,
+ .read_event_value = bmi323_read_event_value,
+ .event_attrs = &bmi323_event_attribute_group,
+};
+
+#define BMI323_SCAN_MASK_ACCEL_3AXIS \
+ (BIT(BMI323_ACCEL_X) | BIT(BMI323_ACCEL_Y) | BIT(BMI323_ACCEL_Z))
+
+#define BMI323_SCAN_MASK_GYRO_3AXIS \
+ (BIT(BMI323_GYRO_X) | BIT(BMI323_GYRO_Y) | BIT(BMI323_GYRO_Z))
+
+static const unsigned long bmi323_avail_scan_masks[] = {
+ /* 3-axis accel */
+ BMI323_SCAN_MASK_ACCEL_3AXIS,
+ /* 3-axis gyro */
+ BMI323_SCAN_MASK_GYRO_3AXIS,
+ /* 3-axis accel + 3-axis gyro */
+ BMI323_SCAN_MASK_ACCEL_3AXIS | BMI323_SCAN_MASK_GYRO_3AXIS,
+ 0
+};
+
+static int bmi323_int_pin_config(struct bmi323_data *data,
+ enum bmi323_irq_pin irq_pin,
+ bool active_high, bool open_drain, bool latch)
+{
+ unsigned int mask, field_value;
+ int ret;
+
+ ret = regmap_update_bits(data->regmap, BMI323_IO_INT_CONF_REG,
+ BMI323_IO_INT_LTCH_MSK,
+ FIELD_PREP(BMI323_IO_INT_LTCH_MSK, latch));
+ if (ret)
+ return ret;
+
+ ret = bmi323_update_ext_reg(data, BMI323_GEN_SET1_REG,
+ BMI323_GEN_HOLD_DUR_MSK,
+ FIELD_PREP(BMI323_GEN_HOLD_DUR_MSK, 0));
+ if (ret)
+ return ret;
+
+ switch (irq_pin) {
+ case BMI323_IRQ_INT1:
+ mask = BMI323_IO_INT1_LVL_OD_OP_MSK;
+
+ field_value = FIELD_PREP(BMI323_IO_INT1_LVL_MSK, active_high) |
+ FIELD_PREP(BMI323_IO_INT1_OD_MSK, open_drain) |
+ FIELD_PREP(BMI323_IO_INT1_OP_EN_MSK, 1);
+ break;
+ case BMI323_IRQ_INT2:
+ mask = BMI323_IO_INT2_LVL_OD_OP_MSK;
+
+ field_value = FIELD_PREP(BMI323_IO_INT2_LVL_MSK, active_high) |
+ FIELD_PREP(BMI323_IO_INT2_OD_MSK, open_drain) |
+ FIELD_PREP(BMI323_IO_INT2_OP_EN_MSK, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return regmap_update_bits(data->regmap, BMI323_IO_INT_CTR_REG, mask,
+ field_value);
+}
+
+static int bmi323_trigger_probe(struct bmi323_data *data,
+ struct iio_dev *indio_dev)
+{
+ bool open_drain, active_high, latch;
+ struct fwnode_handle *fwnode;
+ enum bmi323_irq_pin irq_pin;
+ int ret, irq, irq_type;
+ struct irq_data *desc;
+
+ fwnode = dev_fwnode(data->dev);
+ if (!fwnode)
+ return -ENODEV;
+
+ irq = fwnode_irq_get_byname(fwnode, "INT1");
+ if (irq > 0) {
+ irq_pin = BMI323_IRQ_INT1;
+ } else {
+ irq = fwnode_irq_get_byname(fwnode, "INT2");
+ if (irq < 0)
+ return 0;
+
+ irq_pin = BMI323_IRQ_INT2;
+ }
+
+ desc = irq_get_irq_data(irq);
+ if (!desc)
+ return dev_err_probe(data->dev, -EINVAL,
+ "Could not find IRQ %d\n", irq);
+
+ irq_type = irqd_get_trigger_type(desc);
+ switch (irq_type) {
+ case IRQF_TRIGGER_RISING:
+ latch = false;
+ active_high = true;
+ break;
+ case IRQF_TRIGGER_HIGH:
+ latch = true;
+ active_high = true;
+ break;
+ case IRQF_TRIGGER_FALLING:
+ latch = false;
+ active_high = false;
+ break;
+ case IRQF_TRIGGER_LOW:
+ latch = true;
+ active_high = false;
+ break;
+ default:
+ return dev_err_probe(data->dev, -EINVAL,
+ "Invalid interrupt type 0x%x specified\n",
+ irq_type);
+ }
+
+ open_drain = fwnode_property_read_bool(fwnode, "drive-open-drain");
+
+ ret = bmi323_int_pin_config(data, irq_pin, active_high, open_drain,
+ latch);
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "Failed to configure irq line\n");
+
+ data->trig = devm_iio_trigger_alloc(data->dev, "%s-trig-%d",
+ indio_dev->name, irq_pin);
+ if (!data->trig)
+ return -ENOMEM;
+
+ data->trig->ops = &bmi323_trigger_ops;
+ iio_trigger_set_drvdata(data->trig, data);
+
+ ret = devm_request_threaded_irq(data->dev, irq, NULL,
+ bmi323_irq_thread_handler,
+ IRQF_ONESHOT, "bmi323-int", indio_dev);
+ if (ret)
+ return dev_err_probe(data->dev, ret, "Failed to request IRQ\n");
+
+ ret = devm_iio_trigger_register(data->dev, data->trig);
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "Trigger registration failed\n");
+
+ data->irq_pin = irq_pin;
+
+ return 0;
+}
+
+static int bmi323_feature_engine_enable(struct bmi323_data *data, bool en)
+{
+ unsigned int feature_status;
+ int ret;
+
+ if (!en)
+ return regmap_write(data->regmap, BMI323_FEAT_CTRL_REG, 0);
+
+ ret = regmap_write(data->regmap, BMI323_FEAT_IO2_REG, 0x012c);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap, BMI323_FEAT_IO_STATUS_REG,
+ BMI323_FEAT_IO_STATUS_MSK);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(data->regmap, BMI323_FEAT_CTRL_REG,
+ BMI323_FEAT_ENG_EN_MSK);
+ if (ret)
+ return ret;
+
+ /*
+ * It takes around 4 msec to enable the Feature engine, so check
+ * the status of the feature engine every 2 msec for a maximum
+ * of 5 trials.
+ */
+ ret = regmap_read_poll_timeout(data->regmap, BMI323_FEAT_IO1_REG,
+ feature_status,
+ FIELD_GET(BMI323_FEAT_IO1_ERR_MSK,
+ feature_status) == 1,
+ BMI323_FEAT_ENG_POLL,
+ BMI323_FEAT_ENG_TIMEOUT);
+ if (ret)
+ return dev_err_probe(data->dev, -EINVAL,
+ "Failed to enable feature engine\n");
+
+ return 0;
+}
+
+static void bmi323_disable(void *data_ptr)
+{
+ struct bmi323_data *data = data_ptr;
+
+ bmi323_set_mode(data, BMI323_ACCEL, ACC_GYRO_MODE_DISABLE);
+ bmi323_set_mode(data, BMI323_GYRO, ACC_GYRO_MODE_DISABLE);
+}
+
+static int bmi323_set_bw(struct bmi323_data *data,
+ enum bmi323_sensor_type sensor, enum bmi323_3db_bw bw)
+{
+ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config,
+ BMI323_ACC_GYRO_CONF_BW_MSK,
+ FIELD_PREP(BMI323_ACC_GYRO_CONF_BW_MSK, bw));
+}
+
+static int bmi323_init(struct bmi323_data *data)
+{
+ int ret, val;
+
+ /*
+ * Perform soft reset to make sure the device is in a known state after
+ * start up. A delay of 1.5 ms is required after reset.
+ * See datasheet section 5.17 "Soft Reset".
+ */
+ ret = regmap_write(data->regmap, BMI323_CMD_REG, BMI323_RST_VAL);
+ if (ret)
+ return ret;
+
+ usleep_range(1500, 2000);
+
+ /*
+ * Dummy read is required to enable SPI interface after reset.
+ * See datasheet section 7.2.1 "Protocol Selection".
+ */
+ regmap_read(data->regmap, BMI323_CHIP_ID_REG, &val);
+
+ ret = regmap_read(data->regmap, BMI323_STATUS_REG, &val);
+ if (ret)
+ return ret;
+
+ if (!FIELD_GET(BMI323_STATUS_POR_MSK, val))
+ return dev_err_probe(data->dev, -EINVAL,
+ "Sensor initialization error\n");
+
+ ret = regmap_read(data->regmap, BMI323_CHIP_ID_REG, &val);
+ if (ret)
+ return ret;
+
+ if (FIELD_GET(BMI323_CHIP_ID_MSK, val) != BMI323_CHIP_ID_VAL)
+ return dev_err_probe(data->dev, -EINVAL, "Chip ID mismatch\n");
+
+ ret = bmi323_feature_engine_enable(data, true);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(data->regmap, BMI323_ERR_REG, &val);
+ if (ret)
+ return ret;
+
+ if (val)
+ return dev_err_probe(data->dev, -EINVAL,
+ "Sensor power error = 0x%x\n", val);
+
+ /*
+ * Set the Bandwidth coefficient which defines the 3 dB cutoff
+ * frequency in relation to the ODR.
+ */
+ ret = bmi323_set_bw(data, BMI323_ACCEL, BMI323_BW_ODR_BY_2);
+ if (ret)
+ return ret;
+
+ ret = bmi323_set_bw(data, BMI323_GYRO, BMI323_BW_ODR_BY_2);
+ if (ret)
+ return ret;
+
+ ret = bmi323_set_odr(data, BMI323_ACCEL, 25, 0);
+ if (ret)
+ return ret;
+
+ ret = bmi323_set_odr(data, BMI323_GYRO, 25, 0);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(data->dev, bmi323_disable, data);
+}
+
+int bmi323_core_probe(struct device *dev)
+{
+ static const char * const regulator_names[] = { "vdd", "vddio" };
+ struct iio_dev *indio_dev;
+ struct bmi323_data *data;
+ struct regmap *regmap;
+ int ret;
+
+ regmap = dev_get_regmap(dev, NULL);
+ if (!regmap)
+ return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return dev_err_probe(dev, -ENOMEM,
+ "Failed to allocate device\n");
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names),
+ regulator_names);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable regulators\n");
+
+ data = iio_priv(indio_dev);
+ data->dev = dev;
+ data->regmap = regmap;
+ mutex_init(&data->mutex);
+
+ ret = bmi323_init(data);
+ if (ret)
+ return -EINVAL;
+
+ ret = iio_read_mount_matrix(dev, &data->orientation);
+ if (ret)
+ return ret;
+
+ indio_dev->name = "bmi323-imu";
+ indio_dev->info = &bmi323_info;
+ indio_dev->channels = bmi323_channels;
+ indio_dev->num_channels = ARRAY_SIZE(bmi323_channels);
+ indio_dev->available_scan_masks = bmi323_avail_scan_masks;
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+ dev_set_drvdata(data->dev, indio_dev);
+
+ ret = bmi323_trigger_probe(data, indio_dev);
+ if (ret)
+ return -EINVAL;
+
+ ret = devm_iio_triggered_buffer_setup_ext(data->dev, indio_dev,
+ &iio_pollfunc_store_time,
+ bmi323_trigger_handler,
+ IIO_BUFFER_DIRECTION_IN,
+ &bmi323_buffer_ops,
+ bmi323_fifo_attributes);
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "Failed to setup trigger buffer\n");
+
+ ret = devm_iio_device_register(data->dev, indio_dev);
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "Unable to register iio device\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(bmi323_core_probe, IIO_BMI323);
+
+MODULE_DESCRIPTION("Bosch BMI323 IMU driver");
+MODULE_AUTHOR("Jagath Jog J <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c
new file mode 100644
index 000000000000..20a8001b9956
--- /dev/null
+++ b/drivers/iio/imu/bmi323/bmi323_i2c.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * I2C driver for Bosch BMI323 6-Axis IMU.
+ *
+ * Copyright (C) 2023, Jagath Jog J <[email protected]>
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "bmi323.h"
+
+struct bmi323_i2c_priv {
+ struct i2c_client *i2c;
+ u8 i2c_rx_buffer[BMI323_FIFO_LENGTH_IN_BYTES + BMI323_I2C_DUMMY];
+};
+
+/*
+ * From BMI323 datasheet section 4: Notes on the Serial Interface Support.
+ * Each I2C register read operation requires to read two dummy bytes before
+ * the actual payload.
+ */
+static int bmi323_regmap_i2c_read(void *context, const void *reg_buf,
+ size_t reg_size, void *val_buf,
+ size_t val_size)
+{
+ struct bmi323_i2c_priv *priv = context;
+ struct i2c_msg msgs[2];
+ int ret;
+
+ msgs[0].addr = priv->i2c->addr;
+ msgs[0].flags = priv->i2c->flags;
+ msgs[0].len = reg_size;
+ msgs[0].buf = (u8 *)reg_buf;
+
+ msgs[1].addr = priv->i2c->addr;
+ msgs[1].len = val_size + BMI323_I2C_DUMMY;
+ msgs[1].buf = priv->i2c_rx_buffer;
+ msgs[1].flags = priv->i2c->flags | I2C_M_RD;
+
+ ret = i2c_transfer(priv->i2c->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret < 0)
+ return -EIO;
+
+ memcpy(val_buf, priv->i2c_rx_buffer + BMI323_I2C_DUMMY, val_size);
+
+ return 0;
+}
+
+static int bmi323_regmap_i2c_write(void *context, const void *data,
+ size_t count)
+{
+ struct bmi323_i2c_priv *priv = context;
+ u8 reg;
+
+ reg = *(u8 *)data;
+ return i2c_smbus_write_i2c_block_data(priv->i2c, reg,
+ count - sizeof(u8),
+ data + sizeof(u8));
+}
+
+static struct regmap_bus bmi323_regmap_bus = {
+ .read = bmi323_regmap_i2c_read,
+ .write = bmi323_regmap_i2c_write,
+};
+
+static const struct regmap_config bmi323_i2c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = BMI323_CFG_RES_REG,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+static int bmi323_i2c_probe(struct i2c_client *i2c)
+{
+ struct device *dev = &i2c->dev;
+ struct bmi323_i2c_priv *priv;
+ struct regmap *regmap;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->i2c = i2c;
+ regmap = devm_regmap_init(dev, &bmi323_regmap_bus, priv,
+ &bmi323_i2c_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to initialize I2C Regmap\n");
+
+ return bmi323_core_probe(dev);
+}
+
+static const struct i2c_device_id bmi323_i2c_ids[] = {
+ { "bmi323" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bmi323_i2c_ids);
+
+static const struct of_device_id bmi323_of_i2c_match[] = {
+ { .compatible = "bosch,bmi323" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, bmi323_of_i2c_match);
+
+static struct i2c_driver bmi323_i2c_driver = {
+ .driver = {
+ .name = "bmi323",
+ .of_match_table = bmi323_of_i2c_match,
+ },
+ .probe = bmi323_i2c_probe,
+ .id_table = bmi323_i2c_ids,
+};
+module_i2c_driver(bmi323_i2c_driver);
+
+MODULE_DESCRIPTION("Bosch BMI323 IMU driver");
+MODULE_AUTHOR("Jagath Jog J <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_BMI323);
diff --git a/drivers/iio/imu/bmi323/bmi323_spi.c b/drivers/iio/imu/bmi323/bmi323_spi.c
new file mode 100644
index 000000000000..7b1e8127d0dd
--- /dev/null
+++ b/drivers/iio/imu/bmi323/bmi323_spi.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SPI driver for Bosch BMI323 6-Axis IMU.
+ *
+ * Copyright (C) 2023, Jagath Jog J <[email protected]>
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "bmi323.h"
+
+/*
+ * From BMI323 datasheet section 4: Notes on the Serial Interface Support.
+ * Each SPI register read operation requires to read one dummy byte before
+ * the actual payload.
+ */
+static int bmi323_regmap_spi_read(void *context, const void *reg_buf,
+ size_t reg_size, void *val_buf,
+ size_t val_size)
+{
+ struct spi_device *spi = context;
+
+ return spi_write_then_read(spi, reg_buf, reg_size, val_buf, val_size);
+}
+
+static int bmi323_regmap_spi_write(void *context, const void *data,
+ size_t count)
+{
+ struct spi_device *spi = context;
+ u8 *data_buff = (u8 *)data;
+
+ data_buff[1] = data_buff[0];
+ return spi_write(spi, data_buff + 1, count - 1);
+}
+
+static struct regmap_bus bmi323_regmap_bus = {
+ .read = bmi323_regmap_spi_read,
+ .write = bmi323_regmap_spi_write,
+};
+
+static const struct regmap_config bmi323_spi_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .pad_bits = 8,
+ .read_flag_mask = BIT(7),
+ .max_register = BMI323_CFG_RES_REG,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+static int bmi323_spi_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init(dev, &bmi323_regmap_bus, dev,
+ &bmi323_spi_regmap_config);
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "Failed to initialize SPI Regmap\n");
+
+ return bmi323_core_probe(dev);
+}
+
+static const struct spi_device_id bmi323_spi_ids[] = {
+ { "bmi323" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, bmi323_spi_ids);
+
+static const struct of_device_id bmi323_of_spi_match[] = {
+ { .compatible = "bosch,bmi323" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, bmi323_of_spi_match);
+
+static struct spi_driver bmi323_spi_driver = {
+ .driver = {
+ .name = "bmi323",
+ .of_match_table = bmi323_of_spi_match,
+ },
+ .probe = bmi323_spi_probe,
+ .id_table = bmi323_spi_ids,
+};
+module_spi_driver(bmi323_spi_driver);
+
+MODULE_DESCRIPTION("Bosch BMI323 IMU driver");
+MODULE_AUTHOR("Jagath Jog J <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_BMI323);
diff --git a/drivers/iio/imu/bno055/bno055_ser_core.c b/drivers/iio/imu/bno055/bno055_ser_core.c
index 57728a568471..5677bdf4f846 100644
--- a/drivers/iio/imu/bno055/bno055_ser_core.c
+++ b/drivers/iio/imu/bno055/bno055_ser_core.c
@@ -378,12 +378,12 @@ static void bno055_ser_handle_rx(struct bno055_ser_priv *priv, int status)
* Also, we assume to RX one pkt per time (i.e. the HW doesn't send anything
* unless we require to AND we don't queue more than one request per time).
*/
-static int bno055_ser_receive_buf(struct serdev_device *serdev,
- const unsigned char *buf, size_t size)
+static ssize_t bno055_ser_receive_buf(struct serdev_device *serdev,
+ const u8 *buf, size_t size)
{
int status;
struct bno055_ser_priv *priv = serdev_device_get_drvdata(serdev);
- int remaining = size;
+ size_t remaining = size;
if (size == 0)
return 0;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
index b1e4fde27d25..f67bd5a39beb 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
@@ -137,10 +137,7 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev,
out_unlock:
mutex_unlock(&st->lock);
/* sleep maximum required time */
- if (sleep_accel > sleep_temp)
- sleep = sleep_accel;
- else
- sleep = sleep_temp;
+ sleep = max(sleep_accel, sleep_temp);
if (sleep)
msleep(sleep);
return ret;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
index 6ef1df9d60b7..b52f328fd26c 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
@@ -424,10 +424,7 @@ out_unlock:
mutex_unlock(&st->lock);
/* sleep maximum required time */
- if (sleep_sensor > sleep_temp)
- sleep = sleep_sensor;
- else
- sleep = sleep_temp;
+ sleep = max(sleep_sensor, sleep_temp);
if (sleep)
msleep(sleep);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
index 3bf946e56e1d..3df0a715e885 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
@@ -137,10 +137,7 @@ static int inv_icm42600_gyro_update_scan_mode(struct iio_dev *indio_dev,
out_unlock:
mutex_unlock(&st->lock);
/* sleep maximum required time */
- if (sleep_gyro > sleep_temp)
- sleep = sleep_gyro;
- else
- sleep = sleep_temp;
+ sleep = max(sleep_gyro, sleep_temp);
if (sleep)
msleep(sleep);
return ret;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 6b034dccc3b1..0e94e5335e93 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -567,15 +567,12 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
static int inv_mpu6050_sensor_set(struct inv_mpu6050_state *st, int reg,
int axis, int val)
{
- int ind, result;
+ int ind;
__be16 d = cpu_to_be16(val);
ind = (axis - IIO_MOD_X) * 2;
- result = regmap_bulk_write(st->map, reg + ind, &d, sizeof(d));
- if (result)
- return -EINVAL;
- return 0;
+ return regmap_bulk_write(st->map, reg + ind, &d, sizeof(d));
}
static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg,
@@ -587,7 +584,7 @@ static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg,
ind = (axis - IIO_MOD_X) * 2;
result = regmap_bulk_read(st->map, reg + ind, &d, sizeof(d));
if (result)
- return -EINVAL;
+ return result;
*val = (short)be16_to_cpup(&d);
return IIO_VAL_INT;
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 176d31d9f9d8..b581a7e80566 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -413,6 +413,22 @@ static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
{
if (bitmap_empty(mask, masklength))
return NULL;
+ /*
+ * The condition here do not handle multi-long masks correctly.
+ * It only checks the first long to be zero, and will use such mask
+ * as a terminator even if there was bits set after the first long.
+ *
+ * Correct check would require using:
+ * while (!bitmap_empty(av_masks, masklength))
+ * instead. This is potentially hazardous because the
+ * avaliable_scan_masks is a zero terminated array of longs - and
+ * using the proper bitmap_empty() check for multi-long wide masks
+ * would require the array to be terminated with multiple zero longs -
+ * which is not such an usual pattern.
+ *
+ * As writing of this no multi-long wide masks were found in-tree, so
+ * the simple while (*av_masks) check is working.
+ */
while (*av_masks) {
if (strict) {
if (bitmap_equal(mask, av_masks, masklength))
@@ -600,7 +616,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
&iio_show_fixed_type,
NULL,
0,
- 0,
+ IIO_SEPARATE,
&indio_dev->dev,
buffer,
&buffer->buffer_attr_list);
@@ -613,7 +629,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
&iio_scan_el_show,
&iio_scan_el_store,
chan->scan_index,
- 0,
+ IIO_SEPARATE,
&indio_dev->dev,
buffer,
&buffer->buffer_attr_list);
@@ -623,7 +639,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
&iio_scan_el_ts_show,
&iio_scan_el_ts_store,
chan->scan_index,
- 0,
+ IIO_SEPARATE,
&indio_dev->dev,
buffer,
&buffer->buffer_attr_list);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index c77745b594bd..9a85752124dd 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -117,6 +117,8 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_LIGHT_GREEN] = "green",
[IIO_MOD_LIGHT_BLUE] = "blue",
[IIO_MOD_LIGHT_UV] = "uv",
+ [IIO_MOD_LIGHT_UVA] = "uva",
+ [IIO_MOD_LIGHT_UVB] = "uvb",
[IIO_MOD_LIGHT_DUV] = "duv",
[IIO_MOD_QUATERNION] = "quaternion",
[IIO_MOD_TEMP_AMBIENT] = "ambient",
@@ -182,6 +184,7 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_THERMOCOUPLE_TYPE] = "thermocouple_type",
[IIO_CHAN_INFO_CALIBAMBIENT] = "calibambient",
[IIO_CHAN_INFO_ZEROPOINT] = "zeropoint",
+ [IIO_CHAN_INFO_TROUGH] = "trough_raw",
};
/**
* iio_device_id() - query the unique ID for the device
@@ -1896,6 +1899,66 @@ static int iio_check_extended_name(const struct iio_dev *indio_dev)
static const struct iio_buffer_setup_ops noop_ring_setup_ops;
+static void iio_sanity_check_avail_scan_masks(struct iio_dev *indio_dev)
+{
+ unsigned int num_masks, masklength, longs_per_mask;
+ const unsigned long *av_masks;
+ int i;
+
+ av_masks = indio_dev->available_scan_masks;
+ masklength = indio_dev->masklength;
+ longs_per_mask = BITS_TO_LONGS(masklength);
+
+ /*
+ * The code determining how many available_scan_masks is in the array
+ * will be assuming the end of masks when first long with all bits
+ * zeroed is encountered. This is incorrect for masks where mask
+ * consists of more than one long, and where some of the available masks
+ * has long worth of bits zeroed (but has subsequent bit(s) set). This
+ * is a safety measure against bug where array of masks is terminated by
+ * a single zero while mask width is greater than width of a long.
+ */
+ if (longs_per_mask > 1)
+ dev_warn(indio_dev->dev.parent,
+ "multi long available scan masks not fully supported\n");
+
+ if (bitmap_empty(av_masks, masklength))
+ dev_warn(indio_dev->dev.parent, "empty scan mask\n");
+
+ for (num_masks = 0; *av_masks; num_masks++)
+ av_masks += longs_per_mask;
+
+ if (num_masks < 2)
+ return;
+
+ av_masks = indio_dev->available_scan_masks;
+
+ /*
+ * Go through all the masks from first to one before the last, and see
+ * that no mask found later from the available_scan_masks array is a
+ * subset of mask found earlier. If this happens, then the mask found
+ * later will never get used because scanning the array is stopped when
+ * the first suitable mask is found. Drivers should order the array of
+ * available masks in the order of preference (presumably the least
+ * costy to access masks first).
+ */
+ for (i = 0; i < num_masks - 1; i++) {
+ const unsigned long *mask1;
+ int j;
+
+ mask1 = av_masks + i * longs_per_mask;
+ for (j = i + 1; j < num_masks; j++) {
+ const unsigned long *mask2;
+
+ mask2 = av_masks + j * longs_per_mask;
+ if (bitmap_subset(mask2, mask1, masklength))
+ dev_warn(indio_dev->dev.parent,
+ "available_scan_mask %d subset of %d. Never used\n",
+ j, i);
+ }
+ }
+}
+
int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
{
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
@@ -1934,6 +1997,9 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
goto error_unreg_debugfs;
}
+ if (indio_dev->available_scan_masks)
+ iio_sanity_check_avail_scan_masks(indio_dev);
+
ret = iio_device_register_sysfs(indio_dev);
if (ret) {
dev_err(indio_dev->dev.parent,
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 45edba797e4c..143003232d1c 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -252,6 +252,21 @@ config ISL29125
To compile this driver as a module, choose M here: the module will be
called isl29125.
+config ISL76682
+ tristate "Intersil ISL76682 Light Sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Say Y here if you want to build a driver for the Intersil ISL76682
+ Ambient Light Sensor and IR Intensity sensor. This driver provides
+ the readouts via standard IIO sysfs and device interface. Both ALS
+ illuminance and IR illuminance are provided raw with separate scale
+ setting which can be configured via sysfs, the default scale is 1000
+ lux, other options are 4000/16000/64000 lux.
+
+ To compile this driver as a module, choose M here: the module will be
+ called isl76682.
+
config HID_SENSOR_ALS
depends on HID_SENSOR_HUB
select IIO_BUFFER
@@ -347,6 +362,17 @@ config SENSORS_LM3533
changes. The ALS-control output values can be set per zone for the
three current output channels.
+config LTR390
+ tristate "LTR-390UV-01 ambient light and UV sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the Lite-On LTR-390UV-01
+ ambient light and UV sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called ltr390.
+
config LTR501
tristate "LTR-501ALS-01 light sensor"
depends on I2C
@@ -637,6 +663,17 @@ config VEML6070
To compile this driver as a module, choose M here: the
module will be called veml6070.
+config VEML6075
+ tristate "VEML6075 UVA and UVB light sensor"
+ select REGMAP_I2C
+ depends on I2C
+ help
+ Say Y here if you want to build a driver for the Vishay VEML6075 UVA
+ and UVB light sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called veml6075.
+
config VL6180
tristate "VL6180 ALS, range and proximity sensor"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index c0db4c4c36ec..2e5fdb33e0e9 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -28,8 +28,10 @@ obj-$(CONFIG_IQS621_ALS) += iqs621-als.o
obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o
obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
obj-$(CONFIG_ISL29125) += isl29125.o
+obj-$(CONFIG_ISL76682) += isl76682.o
obj-$(CONFIG_JSA1212) += jsa1212.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
+obj-$(CONFIG_LTR390) += ltr390.o
obj-$(CONFIG_LTR501) += ltr501.o
obj-$(CONFIG_LTRF216A) += ltrf216a.o
obj-$(CONFIG_LV0104CS) += lv0104cs.o
@@ -60,5 +62,6 @@ obj-$(CONFIG_VCNL4000) += vcnl4000.o
obj-$(CONFIG_VCNL4035) += vcnl4035.o
obj-$(CONFIG_VEML6030) += veml6030.o
obj-$(CONFIG_VEML6070) += veml6070.o
+obj-$(CONFIG_VEML6075) += veml6075.o
obj-$(CONFIG_VL6180) += vl6180.o
obj-$(CONFIG_ZOPT2201) += zopt2201.o
diff --git a/drivers/iio/light/isl76682.c b/drivers/iio/light/isl76682.c
new file mode 100644
index 000000000000..cf6ddee44ffc
--- /dev/null
+++ b/drivers/iio/light/isl76682.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * IIO driver for the light sensor ISL76682.
+ * ISL76682 is Ambient Light Sensor
+ *
+ * Copyright (c) 2023 Marek Vasut <[email protected]>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include <linux/iio/iio.h>
+
+#define ISL76682_REG_COMMAND 0x00
+
+#define ISL76682_COMMAND_EN BIT(7)
+#define ISL76682_COMMAND_MODE_CONTINUOUS BIT(6)
+#define ISL76682_COMMAND_LIGHT_IR BIT(5)
+
+#define ISL76682_COMMAND_RANGE_LUX_1K 0x0
+#define ISL76682_COMMAND_RANGE_LUX_4K 0x1
+#define ISL76682_COMMAND_RANGE_LUX_16K 0x2
+#define ISL76682_COMMAND_RANGE_LUX_64K 0x3
+#define ISL76682_COMMAND_RANGE_LUX_MASK GENMASK(1, 0)
+
+#define ISL76682_REG_ALSIR_L 0x01
+
+#define ISL76682_REG_ALSIR_U 0x02
+
+#define ISL76682_NUM_REGS (ISL76682_REG_ALSIR_U + 1)
+
+#define ISL76682_CONV_TIME_MS 100
+#define ISL76682_INT_TIME_US 90000
+
+#define ISL76682_ADC_MAX (BIT(16) - 1)
+
+struct isl76682_chip {
+ /*
+ * Lock to synchronize access to device command register
+ * and the content of range variable below.
+ */
+ struct mutex lock;
+ struct regmap *regmap;
+ u8 range;
+ u8 command;
+};
+
+struct isl76682_range {
+ u8 range;
+ u32 als;
+ u32 ir;
+};
+
+static struct isl76682_range isl76682_range_table[] = {
+ { ISL76682_COMMAND_RANGE_LUX_1K, 15000, 10500 },
+ { ISL76682_COMMAND_RANGE_LUX_4K, 60000, 42000 },
+ { ISL76682_COMMAND_RANGE_LUX_16K, 240000, 168000 },
+ { ISL76682_COMMAND_RANGE_LUX_64K, 960000, 673000 }
+};
+
+static int isl76682_get(struct isl76682_chip *chip, bool mode_ir, int *data)
+{
+ u8 command;
+ int ret;
+
+ command = ISL76682_COMMAND_EN | ISL76682_COMMAND_MODE_CONTINUOUS |
+ chip->range;
+
+ if (mode_ir)
+ command |= ISL76682_COMMAND_LIGHT_IR;
+
+ if (command != chip->command) {
+ ret = regmap_write(chip->regmap, ISL76682_REG_COMMAND, command);
+ if (ret)
+ return ret;
+
+ /* Need to wait for conversion time if ALS/IR mode enabled */
+ msleep(ISL76682_CONV_TIME_MS);
+
+ chip->command = command;
+ }
+
+ ret = regmap_bulk_read(chip->regmap, ISL76682_REG_ALSIR_L, data, 2);
+ *data &= ISL76682_ADC_MAX;
+ return ret;
+}
+
+static int isl76682_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct isl76682_chip *chip = iio_priv(indio_dev);
+ int i;
+
+ if (mask != IIO_CHAN_INFO_SCALE)
+ return -EINVAL;
+
+ if (val != 0)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(isl76682_range_table); i++) {
+ if (chan->type == IIO_LIGHT && val2 != isl76682_range_table[i].als)
+ continue;
+ if (chan->type == IIO_INTENSITY && val2 != isl76682_range_table[i].ir)
+ continue;
+
+ scoped_guard(mutex, &chip->lock)
+ chip->range = isl76682_range_table[i].range;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int isl76682_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct isl76682_chip *chip = iio_priv(indio_dev);
+ int ret;
+ int i;
+
+ guard(mutex)(&chip->lock);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_LIGHT:
+ ret = isl76682_get(chip, false, val);
+ return (ret < 0) ? ret : IIO_VAL_INT;
+ case IIO_INTENSITY:
+ ret = isl76682_get(chip, true, val);
+ return (ret < 0) ? ret : IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ for (i = 0; i < ARRAY_SIZE(isl76682_range_table); i++) {
+ if (chip->range != isl76682_range_table[i].range)
+ continue;
+
+ *val = 0;
+ switch (chan->type) {
+ case IIO_LIGHT:
+ *val2 = isl76682_range_table[i].als;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_INTENSITY:
+ *val2 = isl76682_range_table[i].ir;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ }
+ return -EINVAL;
+ case IIO_CHAN_INFO_INT_TIME:
+ *val = 0;
+ *val2 = ISL76682_INT_TIME_US;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int illuminance_scale_available[] = {
+ 0, 15000,
+ 0, 60000,
+ 0, 240000,
+ 0, 960000,
+};
+
+static int intensity_scale_available[] = {
+ 0, 10500,
+ 0, 42000,
+ 0, 168000,
+ 0, 673000,
+};
+
+static int isl76682_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type,
+ int *length, long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_LIGHT:
+ *vals = illuminance_scale_available;
+ *length = ARRAY_SIZE(illuminance_scale_available);
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ case IIO_INTENSITY:
+ *vals = intensity_scale_available;
+ *length = ARRAY_SIZE(intensity_scale_available);
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec isl76682_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+ }, {
+ .type = IIO_INTENSITY,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+ }
+};
+
+static const struct iio_info isl76682_info = {
+ .read_avail = isl76682_read_avail,
+ .read_raw = isl76682_read_raw,
+ .write_raw = isl76682_write_raw,
+};
+
+static int isl76682_clear_configure_reg(struct isl76682_chip *chip)
+{
+ struct device *dev = regmap_get_device(chip->regmap);
+ int ret;
+
+ ret = regmap_write(chip->regmap, ISL76682_REG_COMMAND, 0x0);
+ if (ret < 0)
+ dev_err(dev, "Error %d clearing the CONFIGURE register\n", ret);
+
+ /*
+ * In the success case, the command register was zeroed out.
+ *
+ * In the error case, we do not know in which state the command
+ * register is, so we assume it is zeroed out, so that it would
+ * be reprogrammed at the next data read out, and at that time
+ * we hope it would be reprogrammed successfully. That is very
+ * much a best effort approach.
+ */
+ chip->command = 0;
+
+ return ret;
+}
+
+static void isl76682_reset_action(void *chip)
+{
+ isl76682_clear_configure_reg(chip);
+}
+
+static bool isl76682_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ISL76682_REG_ALSIR_L:
+ case ISL76682_REG_ALSIR_U:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config isl76682_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_reg = isl76682_is_volatile_reg,
+ .max_register = ISL76682_NUM_REGS - 1,
+ .num_reg_defaults_raw = ISL76682_NUM_REGS,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static int isl76682_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct isl76682_chip *chip;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ chip = iio_priv(indio_dev);
+
+ mutex_init(&chip->lock);
+
+ chip->regmap = devm_regmap_init_i2c(client, &isl76682_regmap_config);
+ ret = PTR_ERR_OR_ZERO(chip->regmap);
+ if (ret)
+ return dev_err_probe(dev, ret, "Error initializing regmap\n");
+
+ chip->range = ISL76682_COMMAND_RANGE_LUX_1K;
+
+ ret = isl76682_clear_configure_reg(chip);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, isl76682_reset_action, chip);
+ if (ret)
+ return ret;
+
+ indio_dev->info = &isl76682_info;
+ indio_dev->channels = isl76682_channels;
+ indio_dev->num_channels = ARRAY_SIZE(isl76682_channels);
+ indio_dev->name = "isl76682";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct i2c_device_id isl76682_id[] = {
+ { "isl76682" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, isl76682_id);
+
+static const struct of_device_id isl76682_of_match[] = {
+ { .compatible = "isil,isl76682" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, isl76682_of_match);
+
+static struct i2c_driver isl76682_driver = {
+ .driver = {
+ .name = "isl76682",
+ .of_match_table = isl76682_of_match,
+ },
+ .probe = isl76682_probe,
+ .id_table = isl76682_id,
+};
+module_i2c_driver(isl76682_driver);
+
+MODULE_DESCRIPTION("ISL76682 Ambient Light Sensor driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marek Vasut <[email protected]>");
diff --git a/drivers/iio/light/ltr390.c b/drivers/iio/light/ltr390.c
new file mode 100644
index 000000000000..fff1e899097d
--- /dev/null
+++ b/drivers/iio/light/ltr390.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * IIO driver for Lite-On LTR390 ALS and UV sensor
+ * (7-bit I2C slave address 0x53)
+ *
+ * Based on the work of:
+ * Shreeya Patel and Shi Zhigang (LTRF216 Driver)
+ *
+ * Copyright (C) 2023 Anshul Dalal <[email protected]>
+ *
+ * Datasheet:
+ * https://optoelectronics.liteon.com/upload/download/DS86-2015-0004/LTR-390UV_Final_%20DS_V1%201.pdf
+ *
+ * TODO:
+ * - Support for configurable gain and resolution
+ * - Sensor suspend/resume support
+ * - Add support for reading the ALS
+ * - Interrupt support
+ */
+
+#include <linux/i2c.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+
+#include <asm/unaligned.h>
+
+#define LTR390_MAIN_CTRL 0x00
+#define LTR390_PART_ID 0x06
+#define LTR390_UVS_DATA 0x10
+
+#define LTR390_SW_RESET BIT(4)
+#define LTR390_UVS_MODE BIT(3)
+#define LTR390_SENSOR_ENABLE BIT(1)
+
+#define LTR390_PART_NUMBER_ID 0xb
+
+/*
+ * At 20-bit resolution (integration time: 400ms) and 18x gain, 2300 counts of
+ * the sensor are equal to 1 UV Index [Datasheet Page#8].
+ *
+ * For the default resolution of 18-bit (integration time: 100ms) and default
+ * gain of 3x, the counts/uvi are calculated as follows:
+ * 2300 / ((3/18) * (100/400)) = 95.83
+ */
+#define LTR390_COUNTS_PER_UVI 96
+
+/*
+ * Window Factor is needed when the device is under Window glass with coated
+ * tinted ink. This is to compensate for the light loss due to the lower
+ * transmission rate of the window glass and helps * in calculating lux.
+ */
+#define LTR390_WINDOW_FACTOR 1
+
+struct ltr390_data {
+ struct regmap *regmap;
+ struct i2c_client *client;
+ /* Protects device from simulataneous reads */
+ struct mutex lock;
+};
+
+static const struct regmap_config ltr390_regmap_config = {
+ .name = "ltr390",
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+};
+
+static int ltr390_register_read(struct ltr390_data *data, u8 register_address)
+{
+ struct device *dev = &data->client->dev;
+ int ret;
+ u8 recieve_buffer[3];
+
+ guard(mutex)(&data->lock);
+
+ ret = regmap_bulk_read(data->regmap, register_address, recieve_buffer,
+ sizeof(recieve_buffer));
+ if (ret) {
+ dev_err(dev, "failed to read measurement data");
+ return ret;
+ }
+
+ return get_unaligned_le24(recieve_buffer);
+}
+
+static int ltr390_read_raw(struct iio_dev *iio_device,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ int ret;
+ struct ltr390_data *data = iio_priv(iio_device);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = ltr390_register_read(data, LTR390_UVS_DATA);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = LTR390_WINDOW_FACTOR;
+ *val2 = LTR390_COUNTS_PER_UVI;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info ltr390_info = {
+ .read_raw = ltr390_read_raw,
+};
+
+static const struct iio_chan_spec ltr390_channel = {
+ .type = IIO_UVINDEX,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE)
+};
+
+static int ltr390_probe(struct i2c_client *client)
+{
+ struct ltr390_data *data;
+ struct iio_dev *indio_dev;
+ struct device *dev;
+ int ret, part_number;
+
+ dev = &client->dev;
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+
+ data->regmap = devm_regmap_init_i2c(client, &ltr390_regmap_config);
+ if (IS_ERR(data->regmap))
+ return dev_err_probe(dev, PTR_ERR(data->regmap),
+ "regmap initialization failed\n");
+
+ data->client = client;
+ mutex_init(&data->lock);
+
+ indio_dev->info = &ltr390_info;
+ indio_dev->channels = &ltr390_channel;
+ indio_dev->num_channels = 1;
+ indio_dev->name = "ltr390";
+
+ ret = regmap_read(data->regmap, LTR390_PART_ID, &part_number);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to get sensor's part id\n");
+ /* Lower 4 bits of `part_number` change with hardware revisions */
+ if (part_number >> 4 != LTR390_PART_NUMBER_ID)
+ dev_info(dev, "received invalid product id: 0x%x", part_number);
+ dev_dbg(dev, "LTR390, product id: 0x%x\n", part_number);
+
+ /* reset sensor, chip fails to respond to this, so ignore any errors */
+ regmap_set_bits(data->regmap, LTR390_MAIN_CTRL, LTR390_SW_RESET);
+
+ /* Wait for the registers to reset before proceeding */
+ usleep_range(1000, 2000);
+
+ ret = regmap_set_bits(data->regmap, LTR390_MAIN_CTRL,
+ LTR390_SENSOR_ENABLE | LTR390_UVS_MODE);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable the sensor\n");
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct i2c_device_id ltr390_id[] = {
+ { "ltr390" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, ltr390_id);
+
+static const struct of_device_id ltr390_of_table[] = {
+ { .compatible = "liteon,ltr390" },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ltr390_of_table);
+
+static struct i2c_driver ltr390_driver = {
+ .driver = {
+ .name = "ltr390",
+ .of_match_table = ltr390_of_table,
+ },
+ .probe = ltr390_probe,
+ .id_table = ltr390_id,
+};
+module_i2c_driver(ltr390_driver);
+
+MODULE_AUTHOR("Anshul Dalal <[email protected]>");
+MODULE_DESCRIPTION("Lite-On LTR390 ALS and UV sensor Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/ltrf216a.c b/drivers/iio/light/ltrf216a.c
index 8de4dd849936..68dc48420a88 100644
--- a/drivers/iio/light/ltrf216a.c
+++ b/drivers/iio/light/ltrf216a.c
@@ -234,7 +234,7 @@ static int ltrf216a_read_data(struct ltrf216a_data *data, u8 addr)
static int ltrf216a_get_lux(struct ltrf216a_data *data)
{
int ret, greendata;
- u64 lux, div;
+ u64 lux;
ret = ltrf216a_set_power_state(data, true);
if (ret)
@@ -246,10 +246,9 @@ static int ltrf216a_get_lux(struct ltrf216a_data *data)
ltrf216a_set_power_state(data, false);
- lux = greendata * 45 * LTRF216A_WIN_FAC * 100;
- div = data->als_gain_fac * data->int_time_fac * 100;
+ lux = greendata * 45 * LTRF216A_WIN_FAC;
- return div_u64(lux, div);
+ return lux;
}
static int ltrf216a_read_raw(struct iio_dev *indio_dev,
@@ -279,7 +278,8 @@ static int ltrf216a_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
*val = ret;
- return IIO_VAL_INT;
+ *val2 = data->als_gain_fac * data->int_time_fac;
+ return IIO_VAL_FRACTIONAL;
case IIO_CHAN_INFO_INT_TIME:
mutex_lock(&data->lock);
ret = ltrf216a_get_int_time(data, val, val2);
diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c
index ed241598aefb..636432c45651 100644
--- a/drivers/iio/light/pa12203001.c
+++ b/drivers/iio/light/pa12203001.c
@@ -472,7 +472,7 @@ static struct i2c_driver pa12203001_driver = {
.driver = {
.name = PA12203001_DRIVER_NAME,
.pm = &pa12203001_pm_ops,
- .acpi_match_table = ACPI_PTR(pa12203001_acpi_match),
+ .acpi_match_table = pa12203001_acpi_match,
},
.probe = pa12203001_probe,
.remove = pa12203001_remove,
diff --git a/drivers/iio/light/rohm-bu27008.c b/drivers/iio/light/rohm-bu27008.c
index 6a6d77805091..0f010eff1981 100644
--- a/drivers/iio/light/rohm-bu27008.c
+++ b/drivers/iio/light/rohm-bu27008.c
@@ -130,6 +130,7 @@
* @BU27008_BLUE: Blue channel. Via data2 (when used).
* @BU27008_CLEAR: Clear channel. Via data2 or data3 (when used).
* @BU27008_IR: IR channel. Via data3 (when used).
+ * @BU27008_LUX: Illuminance channel, computed using RGB and IR.
* @BU27008_NUM_CHANS: Number of channel types.
*/
enum bu27008_chan_type {
@@ -138,6 +139,7 @@ enum bu27008_chan_type {
BU27008_BLUE,
BU27008_CLEAR,
BU27008_IR,
+ BU27008_LUX,
BU27008_NUM_CHANS
};
@@ -172,6 +174,8 @@ static const unsigned long bu27008_scan_masks[] = {
ALWAYS_SCANNABLE | BIT(BU27008_CLEAR) | BIT(BU27008_IR),
/* buffer is R, G, B, IR */
ALWAYS_SCANNABLE | BIT(BU27008_BLUE) | BIT(BU27008_IR),
+ /* buffer is R, G, B, IR, LUX */
+ ALWAYS_SCANNABLE | BIT(BU27008_BLUE) | BIT(BU27008_IR) | BIT(BU27008_LUX),
0
};
@@ -331,6 +335,19 @@ static const struct iio_chan_spec bu27008_channels[] = {
* Hence we don't advertise available ones either.
*/
BU27008_CHAN(IR, DATA3, 0),
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .channel = BU27008_LUX,
+ .scan_index = BU27008_LUX,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 64,
+ .storagebits = 64,
+ .endianness = IIO_CPU,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(BU27008_NUM_CHANS),
};
@@ -1004,6 +1021,169 @@ static int bu27008_read_one(struct bu27008_data *data, struct iio_dev *idev,
return ret;
}
+#define BU27008_LUX_DATA_RED 0
+#define BU27008_LUX_DATA_GREEN 1
+#define BU27008_LUX_DATA_BLUE 2
+#define BU27008_LUX_DATA_IR 3
+#define LUX_DATA_SIZE (BU27008_NUM_HW_CHANS * sizeof(__le16))
+
+static int bu27008_read_lux_chans(struct bu27008_data *data, unsigned int time,
+ __le16 *chan_data)
+{
+ int ret, chan_sel, tmpret, valid;
+
+ chan_sel = BU27008_BLUE2_IR3 << (ffs(data->cd->chan_sel_mask) - 1);
+
+ ret = regmap_update_bits(data->regmap, data->cd->chan_sel_reg,
+ data->cd->chan_sel_mask, chan_sel);
+ if (ret)
+ return ret;
+
+ ret = bu27008_meas_set(data, true);
+ if (ret)
+ return ret;
+
+ msleep(time / USEC_PER_MSEC);
+
+ ret = regmap_read_poll_timeout(data->regmap, data->cd->valid_reg,
+ valid, (valid & BU27008_MASK_VALID),
+ BU27008_VALID_RESULT_WAIT_QUANTA_US,
+ BU27008_MAX_VALID_RESULT_WAIT_US);
+ if (ret)
+ goto out;
+
+ ret = regmap_bulk_read(data->regmap, BU27008_REG_DATA0_LO, chan_data,
+ LUX_DATA_SIZE);
+ if (ret)
+ goto out;
+out:
+ tmpret = bu27008_meas_set(data, false);
+ if (tmpret)
+ dev_warn(data->dev, "Stopping measurement failed\n");
+
+ return ret;
+}
+
+/*
+ * Following equation for computing lux out of register values was given by
+ * ROHM HW colleagues;
+ *
+ * Red = RedData*1024 / Gain * 20 / meas_mode
+ * Green = GreenData* 1024 / Gain * 20 / meas_mode
+ * Blue = BlueData* 1024 / Gain * 20 / meas_mode
+ * IR = IrData* 1024 / Gain * 20 / meas_mode
+ *
+ * where meas_mode is the integration time in mS / 10
+ *
+ * IRratio = (IR > 0.18 * Green) ? 0 : 1
+ *
+ * Lx = max(c1*Red + c2*Green + c3*Blue,0)
+ *
+ * for
+ * IRratio 0: c1 = -0.00002237, c2 = 0.0003219, c3 = -0.000120371
+ * IRratio 1: c1 = -0.00001074, c2 = 0.000305415, c3 = -0.000129367
+ */
+
+/*
+ * The max chan data is 0xffff. When we multiply it by 1024 * 20, we'll get
+ * 0x4FFFB000 which still fits in 32-bit integer. This won't overflow.
+ */
+#define NORM_CHAN_DATA_FOR_LX_CALC(chan, gain, time) (le16_to_cpu(chan) * \
+ 1024 * 20 / (gain) / (time))
+static u64 bu27008_calc_nlux(struct bu27008_data *data, __le16 *lux_data,
+ unsigned int gain, unsigned int gain_ir, unsigned int time)
+{
+ unsigned int red, green, blue, ir;
+ s64 c1, c2, c3, nlux;
+
+ time /= 10000;
+ ir = NORM_CHAN_DATA_FOR_LX_CALC(lux_data[BU27008_LUX_DATA_IR], gain_ir, time);
+ red = NORM_CHAN_DATA_FOR_LX_CALC(lux_data[BU27008_LUX_DATA_RED], gain, time);
+ green = NORM_CHAN_DATA_FOR_LX_CALC(lux_data[BU27008_LUX_DATA_GREEN], gain, time);
+ blue = NORM_CHAN_DATA_FOR_LX_CALC(lux_data[BU27008_LUX_DATA_BLUE], gain, time);
+
+ if ((u64)ir * 100LLU > (u64)green * 18LLU) {
+ c1 = -22370;
+ c2 = 321900;
+ c3 = -120371;
+ } else {
+ c1 = -10740;
+ c2 = 305415;
+ c3 = -129367;
+ }
+ nlux = c1 * red + c2 * green + c3 * blue;
+
+ return max_t(s64, 0, nlux);
+}
+
+static int bu27008_get_time_n_gains(struct bu27008_data *data,
+ unsigned int *gain, unsigned int *gain_ir, unsigned int *time)
+{
+ int ret;
+
+ ret = bu27008_get_gain(data, &data->gts, gain);
+ if (ret < 0)
+ return ret;
+
+ ret = bu27008_get_gain(data, &data->gts_ir, gain_ir);
+ if (ret < 0)
+ return ret;
+
+ ret = bu27008_get_int_time_us(data);
+ if (ret < 0)
+ return ret;
+
+ /* Max integration time is 400000. Fits in signed int. */
+ *time = ret;
+
+ return 0;
+}
+
+struct bu27008_buf {
+ __le16 chan[BU27008_NUM_HW_CHANS];
+ u64 lux __aligned(8);
+ s64 ts __aligned(8);
+};
+
+static int bu27008_buffer_fill_lux(struct bu27008_data *data,
+ struct bu27008_buf *raw)
+{
+ unsigned int gain, gain_ir, time;
+ int ret;
+
+ ret = bu27008_get_time_n_gains(data, &gain, &gain_ir, &time);
+ if (ret)
+ return ret;
+
+ raw->lux = bu27008_calc_nlux(data, raw->chan, gain, gain_ir, time);
+
+ return 0;
+}
+
+static int bu27008_read_lux(struct bu27008_data *data, struct iio_dev *idev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2)
+{
+ __le16 lux_data[BU27008_NUM_HW_CHANS];
+ unsigned int gain, gain_ir, time;
+ u64 nlux;
+ int ret;
+
+ ret = bu27008_get_time_n_gains(data, &gain, &gain_ir, &time);
+ if (ret)
+ return ret;
+
+ ret = bu27008_read_lux_chans(data, time, lux_data);
+ if (ret)
+ return ret;
+
+ nlux = bu27008_calc_nlux(data, lux_data, gain, gain_ir, time);
+ *val = (int)nlux;
+ *val2 = nlux >> 32LLU;
+
+ return IIO_VAL_INT_64;
+}
+
static int bu27008_read_raw(struct iio_dev *idev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -1018,7 +1198,10 @@ static int bu27008_read_raw(struct iio_dev *idev,
return -EBUSY;
mutex_lock(&data->mutex);
- ret = bu27008_read_one(data, idev, chan, val, val2);
+ if (chan->type == IIO_LIGHT)
+ ret = bu27008_read_lux(data, idev, chan, val, val2);
+ else
+ ret = bu27008_read_one(data, idev, chan, val, val2);
mutex_unlock(&data->mutex);
iio_device_release_direct_mode(idev);
@@ -1026,6 +1209,11 @@ static int bu27008_read_raw(struct iio_dev *idev,
return ret;
case IIO_CHAN_INFO_SCALE:
+ if (chan->type == IIO_LIGHT) {
+ *val = 0;
+ *val2 = 1;
+ return IIO_VAL_INT_PLUS_NANO;
+ }
ret = bu27008_get_scale(data, chan->scan_index == BU27008_IR,
val, val2);
if (ret)
@@ -1236,10 +1424,7 @@ static irqreturn_t bu27008_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *idev = pf->indio_dev;
struct bu27008_data *data = iio_priv(idev);
- struct {
- __le16 chan[BU27008_NUM_HW_CHANS];
- s64 ts __aligned(8);
- } raw;
+ struct bu27008_buf raw;
int ret, dummy;
memset(&raw, 0, sizeof(raw));
@@ -1257,6 +1442,12 @@ static irqreturn_t bu27008_trigger_handler(int irq, void *p)
if (ret < 0)
goto err_read;
+ if (test_bit(BU27008_LUX, idev->active_scan_mask)) {
+ ret = bu27008_buffer_fill_lux(data, &raw);
+ if (ret)
+ goto err_read;
+ }
+
iio_push_to_buffers_with_timestamp(idev, &raw, pf->timestamp);
err_read:
iio_trigger_notify_done(idev->trig);
diff --git a/drivers/iio/light/veml6075.c b/drivers/iio/light/veml6075.c
new file mode 100644
index 000000000000..05d4c0e9015d
--- /dev/null
+++ b/drivers/iio/light/veml6075.c
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Vishay VEML6075 UVA and UVB light sensor
+ *
+ * Copyright 2023 Javier Carrasco <[email protected]>
+ *
+ * 7-bit I2C slave, address 0x10
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+
+#define VEML6075_CMD_CONF 0x00 /* configuration register */
+#define VEML6075_CMD_UVA 0x07 /* UVA channel */
+#define VEML6075_CMD_UVB 0x09 /* UVB channel */
+#define VEML6075_CMD_COMP1 0x0A /* visible light compensation */
+#define VEML6075_CMD_COMP2 0x0B /* infrarred light compensation */
+#define VEML6075_CMD_ID 0x0C /* device ID */
+
+#define VEML6075_CONF_IT GENMASK(6, 4) /* intregration time */
+#define VEML6075_CONF_HD BIT(3) /* dynamic setting */
+#define VEML6075_CONF_TRIG BIT(2) /* trigger */
+#define VEML6075_CONF_AF BIT(1) /* active force enable */
+#define VEML6075_CONF_SD BIT(0) /* shutdown */
+
+#define VEML6075_IT_50_MS 0x00
+#define VEML6075_IT_100_MS 0x01
+#define VEML6075_IT_200_MS 0x02
+#define VEML6075_IT_400_MS 0x03
+#define VEML6075_IT_800_MS 0x04
+
+#define VEML6075_AF_DISABLE 0x00
+#define VEML6075_AF_ENABLE 0x01
+
+#define VEML6075_SD_DISABLE 0x00
+#define VEML6075_SD_ENABLE 0x01
+
+/* Open-air coefficients and responsivity */
+#define VEML6075_A_COEF 2220
+#define VEML6075_B_COEF 1330
+#define VEML6075_C_COEF 2950
+#define VEML6075_D_COEF 1740
+#define VEML6075_UVA_RESP 1461
+#define VEML6075_UVB_RESP 2591
+
+static const int veml6075_it_ms[] = { 50, 100, 200, 400, 800 };
+
+struct veml6075_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ /*
+ * prevent integration time modification and triggering
+ * measurements while a measurement is underway.
+ */
+ struct mutex lock;
+};
+
+/* channel number */
+enum veml6075_chan {
+ CH_UVA,
+ CH_UVB,
+};
+
+static const struct iio_chan_spec veml6075_channels[] = {
+ {
+ .type = IIO_INTENSITY,
+ .channel = CH_UVA,
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_UVA,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
+ },
+ {
+ .type = IIO_INTENSITY,
+ .channel = CH_UVB,
+ .modified = 1,
+ .channel2 = IIO_MOD_LIGHT_UVB,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
+ },
+ {
+ .type = IIO_UVINDEX,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_INT_TIME),
+ },
+};
+
+static int veml6075_request_measurement(struct veml6075_data *data)
+{
+ int ret, conf, int_time;
+
+ ret = regmap_read(data->regmap, VEML6075_CMD_CONF, &conf);
+ if (ret < 0)
+ return ret;
+
+ /* disable shutdown and trigger measurement */
+ ret = regmap_write(data->regmap, VEML6075_CMD_CONF,
+ (conf | VEML6075_CONF_TRIG) & ~VEML6075_CONF_SD);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * A measurement requires between 1.30 and 1.40 times the integration
+ * time for all possible configurations. Using a 1.50 factor simplifies
+ * operations and ensures reliability under all circumstances.
+ */
+ int_time = veml6075_it_ms[FIELD_GET(VEML6075_CONF_IT, conf)];
+ msleep(int_time + (int_time / 2));
+
+ /* shutdown again, data registers are still accessible */
+ return regmap_update_bits(data->regmap, VEML6075_CMD_CONF,
+ VEML6075_CONF_SD, VEML6075_CONF_SD);
+}
+
+static int veml6075_uva_comp(int raw_uva, int comp1, int comp2)
+{
+ int comp1a_c, comp2a_c, uva_comp;
+
+ comp1a_c = (comp1 * VEML6075_A_COEF) / 1000U;
+ comp2a_c = (comp2 * VEML6075_B_COEF) / 1000U;
+ uva_comp = raw_uva - comp1a_c - comp2a_c;
+
+ return clamp_val(uva_comp, 0, U16_MAX);
+}
+
+static int veml6075_uvb_comp(int raw_uvb, int comp1, int comp2)
+{
+ int comp1b_c, comp2b_c, uvb_comp;
+
+ comp1b_c = (comp1 * VEML6075_C_COEF) / 1000U;
+ comp2b_c = (comp2 * VEML6075_D_COEF) / 1000U;
+ uvb_comp = raw_uvb - comp1b_c - comp2b_c;
+
+ return clamp_val(uvb_comp, 0, U16_MAX);
+}
+
+static int veml6075_read_comp(struct veml6075_data *data, int *c1, int *c2)
+{
+ int ret;
+
+ ret = regmap_read(data->regmap, VEML6075_CMD_COMP1, c1);
+ if (ret < 0)
+ return ret;
+
+ return regmap_read(data->regmap, VEML6075_CMD_COMP2, c2);
+}
+
+static int veml6075_read_uv_direct(struct veml6075_data *data, int chan,
+ int *val)
+{
+ int c1, c2, ret;
+
+ guard(mutex)(&data->lock);
+
+ ret = veml6075_request_measurement(data);
+ if (ret < 0)
+ return ret;
+
+ ret = veml6075_read_comp(data, &c1, &c2);
+ if (ret < 0)
+ return ret;
+
+ switch (chan) {
+ case CH_UVA:
+ ret = regmap_read(data->regmap, VEML6075_CMD_UVA, val);
+ if (ret < 0)
+ return ret;
+
+ *val = veml6075_uva_comp(*val, c1, c2);
+ return IIO_VAL_INT;
+ case CH_UVB:
+ ret = regmap_read(data->regmap, VEML6075_CMD_UVB, val);
+ if (ret < 0)
+ return ret;
+
+ *val = veml6075_uvb_comp(*val, c1, c2);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int veml6075_read_int_time_index(struct veml6075_data *data)
+{
+ int ret, conf;
+
+ ret = regmap_read(data->regmap, VEML6075_CMD_CONF, &conf);
+ if (ret < 0)
+ return ret;
+
+ return FIELD_GET(VEML6075_CONF_IT, conf);
+}
+
+static int veml6075_read_int_time_ms(struct veml6075_data *data, int *val)
+{
+ int int_index;
+
+ guard(mutex)(&data->lock);
+ int_index = veml6075_read_int_time_index(data);
+ if (int_index < 0)
+ return int_index;
+
+ *val = veml6075_it_ms[int_index];
+
+ return IIO_VAL_INT;
+}
+
+static int veml6075_get_uvi_micro(struct veml6075_data *data, int uva_comp,
+ int uvb_comp)
+{
+ int uvia_micro = uva_comp * VEML6075_UVA_RESP;
+ int uvib_micro = uvb_comp * VEML6075_UVB_RESP;
+ int int_index;
+
+ int_index = veml6075_read_int_time_index(data);
+ if (int_index < 0)
+ return int_index;
+
+ switch (int_index) {
+ case VEML6075_IT_50_MS:
+ return uvia_micro + uvib_micro;
+ case VEML6075_IT_100_MS:
+ case VEML6075_IT_200_MS:
+ case VEML6075_IT_400_MS:
+ case VEML6075_IT_800_MS:
+ return (uvia_micro + uvib_micro) / (2 << int_index);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int veml6075_read_uvi(struct veml6075_data *data, int *val, int *val2)
+{
+ int ret, c1, c2, uva, uvb, uvi_micro;
+
+ guard(mutex)(&data->lock);
+
+ ret = veml6075_request_measurement(data);
+ if (ret < 0)
+ return ret;
+
+ ret = veml6075_read_comp(data, &c1, &c2);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(data->regmap, VEML6075_CMD_UVA, &uva);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(data->regmap, VEML6075_CMD_UVB, &uvb);
+ if (ret < 0)
+ return ret;
+
+ uvi_micro = veml6075_get_uvi_micro(data, veml6075_uva_comp(uva, c1, c2),
+ veml6075_uvb_comp(uvb, c1, c2));
+ if (uvi_micro < 0)
+ return uvi_micro;
+
+ *val = uvi_micro / MICRO;
+ *val2 = uvi_micro % MICRO;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int veml6075_read_responsivity(int chan, int *val, int *val2)
+{
+ /* scale = 1 / resp */
+ switch (chan) {
+ case CH_UVA:
+ /* resp = 0.93 c/uW/cm2: scale = 1.75268817 */
+ *val = 1;
+ *val2 = 75268817;
+ return IIO_VAL_INT_PLUS_NANO;
+ case CH_UVB:
+ /* resp = 2.1 c/uW/cm2: scale = 0.476190476 */
+ *val = 0;
+ *val2 = 476190476;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int veml6075_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_INT_TIME:
+ *length = ARRAY_SIZE(veml6075_it_ms);
+ *vals = veml6075_it_ms;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int veml6075_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct veml6075_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return veml6075_read_uv_direct(data, chan->channel, val);
+ case IIO_CHAN_INFO_PROCESSED:
+ return veml6075_read_uvi(data, val, val2);
+ case IIO_CHAN_INFO_INT_TIME:
+ return veml6075_read_int_time_ms(data, val);
+ case IIO_CHAN_INFO_SCALE:
+ return veml6075_read_responsivity(chan->channel, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int veml6075_write_int_time_ms(struct veml6075_data *data, int val)
+{
+ int i = ARRAY_SIZE(veml6075_it_ms);
+
+ guard(mutex)(&data->lock);
+
+ while (i-- > 0) {
+ if (val == veml6075_it_ms[i])
+ break;
+ }
+ if (i < 0)
+ return -EINVAL;
+
+ return regmap_update_bits(data->regmap, VEML6075_CMD_CONF,
+ VEML6075_CONF_IT,
+ FIELD_PREP(VEML6075_CONF_IT, i));
+}
+
+static int veml6075_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct veml6075_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_INT_TIME:
+ return veml6075_write_int_time_ms(data, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info veml6075_info = {
+ .read_avail = veml6075_read_avail,
+ .read_raw = veml6075_read_raw,
+ .write_raw = veml6075_write_raw,
+};
+
+static bool veml6075_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case VEML6075_CMD_CONF:
+ case VEML6075_CMD_UVA:
+ case VEML6075_CMD_UVB:
+ case VEML6075_CMD_COMP1:
+ case VEML6075_CMD_COMP2:
+ case VEML6075_CMD_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool veml6075_writable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case VEML6075_CMD_CONF:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config veml6075_regmap_config = {
+ .name = "veml6075",
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = VEML6075_CMD_ID,
+ .readable_reg = veml6075_readable_reg,
+ .writeable_reg = veml6075_writable_reg,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+static int veml6075_probe(struct i2c_client *client)
+{
+ struct veml6075_data *data;
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ int config, ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(client, &veml6075_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+ data->regmap = regmap;
+
+ mutex_init(&data->lock);
+
+ indio_dev->name = "veml6075";
+ indio_dev->info = &veml6075_info;
+ indio_dev->channels = veml6075_channels;
+ indio_dev->num_channels = ARRAY_SIZE(veml6075_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = devm_regulator_get_enable(&client->dev, "vdd");
+ if (ret < 0)
+ return ret;
+
+ /* default: 100ms integration time, active force enable, shutdown */
+ config = FIELD_PREP(VEML6075_CONF_IT, VEML6075_IT_100_MS) |
+ FIELD_PREP(VEML6075_CONF_AF, VEML6075_AF_ENABLE) |
+ FIELD_PREP(VEML6075_CONF_SD, VEML6075_SD_ENABLE);
+ ret = regmap_write(data->regmap, VEML6075_CMD_CONF, config);
+ if (ret < 0)
+ return ret;
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id veml6075_id[] = {
+ { "veml6075" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, veml6075_id);
+
+static const struct of_device_id veml6075_of_match[] = {
+ { .compatible = "vishay,veml6075" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, veml6075_of_match);
+
+static struct i2c_driver veml6075_driver = {
+ .driver = {
+ .name = "veml6075",
+ .of_match_table = veml6075_of_match,
+ },
+ .probe = veml6075_probe,
+ .id_table = veml6075_id,
+};
+
+module_i2c_driver(veml6075_driver);
+
+MODULE_AUTHOR("Javier Carrasco <[email protected]>");
+MODULE_DESCRIPTION("Vishay VEML6075 UVA and UVB light sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/magnetometer/tmag5273.c b/drivers/iio/magnetometer/tmag5273.c
index e8c4ca142d21..218b1ce076c1 100644
--- a/drivers/iio/magnetometer/tmag5273.c
+++ b/drivers/iio/magnetometer/tmag5273.c
@@ -497,17 +497,13 @@ static int tmag5273_set_operating_mode(struct tmag5273_data *data,
static void tmag5273_read_device_property(struct tmag5273_data *data)
{
struct device *dev = data->dev;
- const char *str;
int ret;
data->angle_measurement = TMAG5273_ANGLE_EN_X_Y;
- ret = device_property_read_string(dev, "ti,angle-measurement", &str);
- if (ret)
- return;
-
- ret = match_string(tmag5273_angle_names,
- ARRAY_SIZE(tmag5273_angle_names), str);
+ ret = device_property_match_property_string(dev, "ti,angle-measurement",
+ tmag5273_angle_names,
+ ARRAY_SIZE(tmag5273_angle_names));
if (ret >= 0)
data->angle_measurement = ret;
}
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index 95efa32e4289..79adfd059c3a 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -109,6 +109,28 @@ config HP03
To compile this driver as a module, choose M here: the module
will be called hp03.
+config HSC030PA
+ tristate "Honeywell HSC/SSC TruStability pressure sensor series"
+ depends on (I2C || SPI_MASTER)
+ select HSC030PA_I2C if I2C
+ select HSC030PA_SPI if SPI_MASTER
+ help
+ Say Y here to build support for the Honeywell TruStability
+ HSC and SSC pressure and temperature sensor series.
+
+ To compile this driver as a module, choose M here: the module
+ will be called hsc030pa.
+
+config HSC030PA_I2C
+ tristate
+ depends on HSC030PA
+ depends on I2C
+
+config HSC030PA_SPI
+ tristate
+ depends on HSC030PA
+ depends on SPI_MASTER
+
config ICP10100
tristate "InvenSense ICP-101xx pressure and temperature sensor"
depends on I2C
diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile
index 436aec7e65f3..b0f8b94662f2 100644
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -15,6 +15,9 @@ obj-$(CONFIG_DPS310) += dps310.o
obj-$(CONFIG_IIO_CROS_EC_BARO) += cros_ec_baro.o
obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o
obj-$(CONFIG_HP03) += hp03.o
+obj-$(CONFIG_HSC030PA) += hsc030pa.o
+obj-$(CONFIG_HSC030PA_I2C) += hsc030pa_i2c.o
+obj-$(CONFIG_HSC030PA_SPI) += hsc030pa_spi.o
obj-$(CONFIG_ICP10100) += icp10100.o
obj-$(CONFIG_MPL115) += mpl115.o
obj-$(CONFIG_MPL115_I2C) += mpl115_i2c.o
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index a2ef1373a274..fe8734468ed3 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -13,6 +13,7 @@
* https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf
* https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme280-ds002.pdf
* https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp388-ds001.pdf
+ * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp390-ds002.pdf
* https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp581-ds004.pdf
*
* Notice:
@@ -794,10 +795,12 @@ static int bmp280_chip_config(struct bmp280_data *data)
}
static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 };
+static const u8 bmp280_chip_ids[] = { BMP280_CHIP_ID };
const struct bmp280_chip_info bmp280_chip_info = {
.id_reg = BMP280_REG_ID,
- .chip_id = BMP280_CHIP_ID,
+ .chip_id = bmp280_chip_ids,
+ .num_chip_id = ARRAY_SIZE(bmp280_chip_ids),
.regmap_config = &bmp280_regmap_config,
.start_up_time = 2000,
.channels = bmp280_channels,
@@ -846,9 +849,12 @@ static int bme280_chip_config(struct bmp280_data *data)
return bmp280_chip_config(data);
}
+static const u8 bme280_chip_ids[] = { BME280_CHIP_ID };
+
const struct bmp280_chip_info bme280_chip_info = {
.id_reg = BMP280_REG_ID,
- .chip_id = BME280_CHIP_ID,
+ .chip_id = bme280_chip_ids,
+ .num_chip_id = ARRAY_SIZE(bme280_chip_ids),
.regmap_config = &bmp280_regmap_config,
.start_up_time = 2000,
.channels = bmp280_channels,
@@ -920,7 +926,7 @@ static int bmp380_cmd(struct bmp280_data *data, u8 cmd)
}
/*
- * Returns temperature in Celsius dregrees, resolution is 0.01º C. Output value of
+ * Returns temperature in Celsius degrees, resolution is 0.01º C. Output value of
* "5123" equals 51.2º C. t_fine carries fine temperature as global value.
*
* Taken from datasheet, Section Appendix 9, "Compensation formula" and repo
@@ -1220,10 +1226,12 @@ static int bmp380_chip_config(struct bmp280_data *data)
static const int bmp380_oversampling_avail[] = { 1, 2, 4, 8, 16, 32 };
static const int bmp380_iir_filter_coeffs_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128};
+static const u8 bmp380_chip_ids[] = { BMP380_CHIP_ID, BMP390_CHIP_ID };
const struct bmp280_chip_info bmp380_chip_info = {
.id_reg = BMP380_REG_ID,
- .chip_id = BMP380_CHIP_ID,
+ .chip_id = bmp380_chip_ids,
+ .num_chip_id = ARRAY_SIZE(bmp380_chip_ids),
.regmap_config = &bmp380_regmap_config,
.start_up_time = 2000,
.channels = bmp380_channels,
@@ -1385,7 +1393,7 @@ static int bmp580_read_temp(struct bmp280_data *data, int *val, int *val2)
/*
* Temperature is returned in Celsius degrees in fractional
- * form down 2^16. We reescale by x1000 to return milli Celsius
+ * form down 2^16. We rescale by x1000 to return milli Celsius
* to respect IIO ABI.
*/
*val = raw_temp * 1000;
@@ -1412,7 +1420,7 @@ static int bmp580_read_press(struct bmp280_data *data, int *val, int *val2)
}
/*
* Pressure is returned in Pascals in fractional form down 2^16.
- * We reescale /1000 to convert to kilopascal to respect IIO ABI.
+ * We rescale /1000 to convert to kilopascal to respect IIO ABI.
*/
*val = raw_press;
*val2 = 64000; /* 2^6 * 1000 */
@@ -1720,10 +1728,12 @@ static int bmp580_chip_config(struct bmp280_data *data)
}
static const int bmp580_oversampling_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
+static const u8 bmp580_chip_ids[] = { BMP580_CHIP_ID, BMP580_CHIP_ID_ALT };
const struct bmp280_chip_info bmp580_chip_info = {
.id_reg = BMP580_REG_CHIP_ID,
- .chip_id = BMP580_CHIP_ID,
+ .chip_id = bmp580_chip_ids,
+ .num_chip_id = ARRAY_SIZE(bmp580_chip_ids),
.regmap_config = &bmp580_regmap_config,
.start_up_time = 2000,
.channels = bmp380_channels,
@@ -1983,10 +1993,12 @@ static int bmp180_chip_config(struct bmp280_data *data)
static const int bmp180_oversampling_temp_avail[] = { 1 };
static const int bmp180_oversampling_press_avail[] = { 1, 2, 4, 8 };
+static const u8 bmp180_chip_ids[] = { BMP180_CHIP_ID };
const struct bmp280_chip_info bmp180_chip_info = {
.id_reg = BMP280_REG_ID,
- .chip_id = BMP180_CHIP_ID,
+ .chip_id = bmp180_chip_ids,
+ .num_chip_id = ARRAY_SIZE(bmp180_chip_ids),
.regmap_config = &bmp180_regmap_config,
.start_up_time = 2000,
.channels = bmp280_channels,
@@ -2077,6 +2089,7 @@ int bmp280_common_probe(struct device *dev,
struct bmp280_data *data;
struct gpio_desc *gpiod;
unsigned int chip_id;
+ unsigned int i;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
@@ -2142,12 +2155,17 @@ int bmp280_common_probe(struct device *dev,
ret = regmap_read(regmap, data->chip_info->id_reg, &chip_id);
if (ret < 0)
return ret;
- if (chip_id != data->chip_info->chip_id) {
- dev_err(dev, "bad chip id: expected %x got %x\n",
- data->chip_info->chip_id, chip_id);
- return -EINVAL;
+
+ for (i = 0; i < data->chip_info->num_chip_id; i++) {
+ if (chip_id == data->chip_info->chip_id[i]) {
+ dev_info(dev, "0x%x is a known chip id for %s\n", chip_id, name);
+ break;
+ }
}
+ if (i == data->chip_info->num_chip_id)
+ dev_warn(dev, "bad chip id: 0x%x is not a known chip id\n", chip_id);
+
if (data->chip_info->preinit) {
ret = data->chip_info->preinit(data);
if (ret)
diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c
index dbe630ad05b5..34e3bc758493 100644
--- a/drivers/iio/pressure/bmp280-i2c.c
+++ b/drivers/iio/pressure/bmp280-i2c.c
@@ -7,13 +7,11 @@
static int bmp280_i2c_probe(struct i2c_client *client)
{
- struct regmap *regmap;
- const struct bmp280_chip_info *chip_info;
const struct i2c_device_id *id = i2c_client_get_device_id(client);
+ const struct bmp280_chip_info *chip_info;
+ struct regmap *regmap;
- chip_info = device_get_match_data(&client->dev);
- if (!chip_info)
- chip_info = (const struct bmp280_chip_info *) id->driver_data;
+ chip_info = i2c_get_match_data(client);
regmap = devm_regmap_init_i2c(client, chip_info->regmap_config);
if (IS_ERR(regmap)) {
diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c
index 1dff9bb7c4e9..433d6fac83c4 100644
--- a/drivers/iio/pressure/bmp280-spi.c
+++ b/drivers/iio/pressure/bmp280-spi.c
@@ -14,8 +14,7 @@
static int bmp280_regmap_spi_write(void *context, const void *data,
size_t count)
{
- struct device *dev = context;
- struct spi_device *spi = to_spi_device(dev);
+ struct spi_device *spi = to_spi_device(context);
u8 buf[2];
memcpy(buf, data, 2);
@@ -31,8 +30,7 @@ static int bmp280_regmap_spi_write(void *context, const void *data,
static int bmp280_regmap_spi_read(void *context, const void *reg,
size_t reg_size, void *val, size_t val_size)
{
- struct device *dev = context;
- struct spi_device *spi = to_spi_device(dev);
+ struct spi_device *spi = to_spi_device(context);
return spi_write_then_read(spi, reg, reg_size, val, val_size);
}
@@ -58,9 +56,7 @@ static int bmp280_spi_probe(struct spi_device *spi)
return ret;
}
- chip_info = device_get_match_data(&spi->dev);
- if (!chip_info)
- chip_info = (const struct bmp280_chip_info *) id->driver_data;
+ chip_info = spi_get_device_match_data(spi);
regmap = devm_regmap_init(&spi->dev,
&bmp280_regmap_bus,
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index 5c0563ce7572..4012387d7956 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -292,6 +292,7 @@
#define BMP580_CHIP_ID_ALT 0x51
#define BMP180_CHIP_ID 0x55
#define BMP280_CHIP_ID 0x58
+#define BMP390_CHIP_ID 0x60
#define BME280_CHIP_ID 0x60
#define BMP280_SOFT_RESET_VAL 0xB6
@@ -410,7 +411,7 @@ struct bmp280_data {
__le16 bmp280_cal_buf[BMP280_CONTIGUOUS_CALIB_REGS / 2];
__be16 bmp180_cal_buf[BMP180_REG_CALIB_COUNT / 2];
u8 bmp380_cal_buf[BMP380_CALIB_REG_COUNT];
- /* Miscellaneous, endianess-aware data buffers */
+ /* Miscellaneous, endianness-aware data buffers */
__le16 le16;
__be16 be16;
} __aligned(IIO_DMA_MINALIGN);
@@ -418,7 +419,8 @@ struct bmp280_data {
struct bmp280_chip_info {
unsigned int id_reg;
- const unsigned int chip_id;
+ const u8 *chip_id;
+ int num_chip_id;
const struct regmap_config *regmap_config;
diff --git a/drivers/iio/pressure/hsc030pa.c b/drivers/iio/pressure/hsc030pa.c
new file mode 100644
index 000000000000..d6a51f0c335f
--- /dev/null
+++ b/drivers/iio/pressure/hsc030pa.c
@@ -0,0 +1,494 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Honeywell TruStability HSC Series pressure/temperature sensor
+ *
+ * Copyright (c) 2023 Petre Rodan <[email protected]>
+ *
+ * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/init.h>
+#include <linux/math64.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include <asm/unaligned.h>
+
+#include "hsc030pa.h"
+
+/*
+ * HSC_PRESSURE_TRIPLET_LEN - length for the string that defines the
+ * pressure range, measurement unit and type as per the part nomenclature.
+ * Consult honeywell,pressure-triplet in the bindings file for details.
+ */
+#define HSC_PRESSURE_TRIPLET_LEN 6
+#define HSC_STATUS_MASK GENMASK(7, 6)
+#define HSC_TEMPERATURE_MASK GENMASK(15, 5)
+#define HSC_PRESSURE_MASK GENMASK(29, 16)
+
+struct hsc_func_spec {
+ u32 output_min;
+ u32 output_max;
+};
+
+/*
+ * function A: 10% - 90% of 2^14
+ * function B: 5% - 95% of 2^14
+ * function C: 5% - 85% of 2^14
+ * function F: 4% - 94% of 2^14
+ */
+static const struct hsc_func_spec hsc_func_spec[] = {
+ [HSC_FUNCTION_A] = { .output_min = 1638, .output_max = 14746 },
+ [HSC_FUNCTION_B] = { .output_min = 819, .output_max = 15565 },
+ [HSC_FUNCTION_C] = { .output_min = 819, .output_max = 13926 },
+ [HSC_FUNCTION_F] = { .output_min = 655, .output_max = 15401 },
+};
+
+enum hsc_variants {
+ HSC001BA = 0x00, HSC1_6BA = 0x01, HSC2_5BA = 0x02, HSC004BA = 0x03,
+ HSC006BA = 0x04, HSC010BA = 0x05, HSC1_6MD = 0x06, HSC2_5MD = 0x07,
+ HSC004MD = 0x08, HSC006MD = 0x09, HSC010MD = 0x0a, HSC016MD = 0x0b,
+ HSC025MD = 0x0c, HSC040MD = 0x0d, HSC060MD = 0x0e, HSC100MD = 0x0f,
+ HSC160MD = 0x10, HSC250MD = 0x11, HSC400MD = 0x12, HSC600MD = 0x13,
+ HSC001BD = 0x14, HSC1_6BD = 0x15, HSC2_5BD = 0x16, HSC004BD = 0x17,
+ HSC2_5MG = 0x18, HSC004MG = 0x19, HSC006MG = 0x1a, HSC010MG = 0x1b,
+ HSC016MG = 0x1c, HSC025MG = 0x1d, HSC040MG = 0x1e, HSC060MG = 0x1f,
+ HSC100MG = 0x20, HSC160MG = 0x21, HSC250MG = 0x22, HSC400MG = 0x23,
+ HSC600MG = 0x24, HSC001BG = 0x25, HSC1_6BG = 0x26, HSC2_5BG = 0x27,
+ HSC004BG = 0x28, HSC006BG = 0x29, HSC010BG = 0x2a, HSC100KA = 0x2b,
+ HSC160KA = 0x2c, HSC250KA = 0x2d, HSC400KA = 0x2e, HSC600KA = 0x2f,
+ HSC001GA = 0x30, HSC160LD = 0x31, HSC250LD = 0x32, HSC400LD = 0x33,
+ HSC600LD = 0x34, HSC001KD = 0x35, HSC1_6KD = 0x36, HSC2_5KD = 0x37,
+ HSC004KD = 0x38, HSC006KD = 0x39, HSC010KD = 0x3a, HSC016KD = 0x3b,
+ HSC025KD = 0x3c, HSC040KD = 0x3d, HSC060KD = 0x3e, HSC100KD = 0x3f,
+ HSC160KD = 0x40, HSC250KD = 0x41, HSC400KD = 0x42, HSC250LG = 0x43,
+ HSC400LG = 0x44, HSC600LG = 0x45, HSC001KG = 0x46, HSC1_6KG = 0x47,
+ HSC2_5KG = 0x48, HSC004KG = 0x49, HSC006KG = 0x4a, HSC010KG = 0x4b,
+ HSC016KG = 0x4c, HSC025KG = 0x4d, HSC040KG = 0x4e, HSC060KG = 0x4f,
+ HSC100KG = 0x50, HSC160KG = 0x51, HSC250KG = 0x52, HSC400KG = 0x53,
+ HSC600KG = 0x54, HSC001GG = 0x55, HSC015PA = 0x56, HSC030PA = 0x57,
+ HSC060PA = 0x58, HSC100PA = 0x59, HSC150PA = 0x5a, HSC0_5ND = 0x5b,
+ HSC001ND = 0x5c, HSC002ND = 0x5d, HSC004ND = 0x5e, HSC005ND = 0x5f,
+ HSC010ND = 0x60, HSC020ND = 0x61, HSC030ND = 0x62, HSC001PD = 0x63,
+ HSC005PD = 0x64, HSC015PD = 0x65, HSC030PD = 0x66, HSC060PD = 0x67,
+ HSC001NG = 0x68, HSC002NG = 0x69, HSC004NG = 0x6a, HSC005NG = 0x6b,
+ HSC010NG = 0x6c, HSC020NG = 0x6d, HSC030NG = 0x6e, HSC001PG = 0x6f,
+ HSC005PG = 0x70, HSC015PG = 0x71, HSC030PG = 0x72, HSC060PG = 0x73,
+ HSC100PG = 0x74, HSC150PG = 0x75, HSC_VARIANTS_MAX
+};
+
+static const char * const hsc_triplet_variants[HSC_VARIANTS_MAX] = {
+ [HSC001BA] = "001BA", [HSC1_6BA] = "1.6BA", [HSC2_5BA] = "2.5BA",
+ [HSC004BA] = "004BA", [HSC006BA] = "006BA", [HSC010BA] = "010BA",
+ [HSC1_6MD] = "1.6MD", [HSC2_5MD] = "2.5MD", [HSC004MD] = "004MD",
+ [HSC006MD] = "006MD", [HSC010MD] = "010MD", [HSC016MD] = "016MD",
+ [HSC025MD] = "025MD", [HSC040MD] = "040MD", [HSC060MD] = "060MD",
+ [HSC100MD] = "100MD", [HSC160MD] = "160MD", [HSC250MD] = "250MD",
+ [HSC400MD] = "400MD", [HSC600MD] = "600MD", [HSC001BD] = "001BD",
+ [HSC1_6BD] = "1.6BD", [HSC2_5BD] = "2.5BD", [HSC004BD] = "004BD",
+ [HSC2_5MG] = "2.5MG", [HSC004MG] = "004MG", [HSC006MG] = "006MG",
+ [HSC010MG] = "010MG", [HSC016MG] = "016MG", [HSC025MG] = "025MG",
+ [HSC040MG] = "040MG", [HSC060MG] = "060MG", [HSC100MG] = "100MG",
+ [HSC160MG] = "160MG", [HSC250MG] = "250MG", [HSC400MG] = "400MG",
+ [HSC600MG] = "600MG", [HSC001BG] = "001BG", [HSC1_6BG] = "1.6BG",
+ [HSC2_5BG] = "2.5BG", [HSC004BG] = "004BG", [HSC006BG] = "006BG",
+ [HSC010BG] = "010BG", [HSC100KA] = "100KA", [HSC160KA] = "160KA",
+ [HSC250KA] = "250KA", [HSC400KA] = "400KA", [HSC600KA] = "600KA",
+ [HSC001GA] = "001GA", [HSC160LD] = "160LD", [HSC250LD] = "250LD",
+ [HSC400LD] = "400LD", [HSC600LD] = "600LD", [HSC001KD] = "001KD",
+ [HSC1_6KD] = "1.6KD", [HSC2_5KD] = "2.5KD", [HSC004KD] = "004KD",
+ [HSC006KD] = "006KD", [HSC010KD] = "010KD", [HSC016KD] = "016KD",
+ [HSC025KD] = "025KD", [HSC040KD] = "040KD", [HSC060KD] = "060KD",
+ [HSC100KD] = "100KD", [HSC160KD] = "160KD", [HSC250KD] = "250KD",
+ [HSC400KD] = "400KD", [HSC250LG] = "250LG", [HSC400LG] = "400LG",
+ [HSC600LG] = "600LG", [HSC001KG] = "001KG", [HSC1_6KG] = "1.6KG",
+ [HSC2_5KG] = "2.5KG", [HSC004KG] = "004KG", [HSC006KG] = "006KG",
+ [HSC010KG] = "010KG", [HSC016KG] = "016KG", [HSC025KG] = "025KG",
+ [HSC040KG] = "040KG", [HSC060KG] = "060KG", [HSC100KG] = "100KG",
+ [HSC160KG] = "160KG", [HSC250KG] = "250KG", [HSC400KG] = "400KG",
+ [HSC600KG] = "600KG", [HSC001GG] = "001GG", [HSC015PA] = "015PA",
+ [HSC030PA] = "030PA", [HSC060PA] = "060PA", [HSC100PA] = "100PA",
+ [HSC150PA] = "150PA", [HSC0_5ND] = "0.5ND", [HSC001ND] = "001ND",
+ [HSC002ND] = "002ND", [HSC004ND] = "004ND", [HSC005ND] = "005ND",
+ [HSC010ND] = "010ND", [HSC020ND] = "020ND", [HSC030ND] = "030ND",
+ [HSC001PD] = "001PD", [HSC005PD] = "005PD", [HSC015PD] = "015PD",
+ [HSC030PD] = "030PD", [HSC060PD] = "060PD", [HSC001NG] = "001NG",
+ [HSC002NG] = "002NG", [HSC004NG] = "004NG", [HSC005NG] = "005NG",
+ [HSC010NG] = "010NG", [HSC020NG] = "020NG", [HSC030NG] = "030NG",
+ [HSC001PG] = "001PG", [HSC005PG] = "005PG", [HSC015PG] = "015PG",
+ [HSC030PG] = "030PG", [HSC060PG] = "060PG", [HSC100PG] = "100PG",
+ [HSC150PG] = "150PG",
+};
+
+/**
+ * struct hsc_range_config - list of pressure ranges based on nomenclature
+ * @pmin: lowest pressure that can be measured
+ * @pmax: highest pressure that can be measured
+ */
+struct hsc_range_config {
+ const s32 pmin;
+ const s32 pmax;
+};
+
+/* All min max limits have been converted to pascals */
+static const struct hsc_range_config hsc_range_config[HSC_VARIANTS_MAX] = {
+ [HSC001BA] = { .pmin = 0, .pmax = 100000 },
+ [HSC1_6BA] = { .pmin = 0, .pmax = 160000 },
+ [HSC2_5BA] = { .pmin = 0, .pmax = 250000 },
+ [HSC004BA] = { .pmin = 0, .pmax = 400000 },
+ [HSC006BA] = { .pmin = 0, .pmax = 600000 },
+ [HSC010BA] = { .pmin = 0, .pmax = 1000000 },
+ [HSC1_6MD] = { .pmin = -160, .pmax = 160 },
+ [HSC2_5MD] = { .pmin = -250, .pmax = 250 },
+ [HSC004MD] = { .pmin = -400, .pmax = 400 },
+ [HSC006MD] = { .pmin = -600, .pmax = 600 },
+ [HSC010MD] = { .pmin = -1000, .pmax = 1000 },
+ [HSC016MD] = { .pmin = -1600, .pmax = 1600 },
+ [HSC025MD] = { .pmin = -2500, .pmax = 2500 },
+ [HSC040MD] = { .pmin = -4000, .pmax = 4000 },
+ [HSC060MD] = { .pmin = -6000, .pmax = 6000 },
+ [HSC100MD] = { .pmin = -10000, .pmax = 10000 },
+ [HSC160MD] = { .pmin = -16000, .pmax = 16000 },
+ [HSC250MD] = { .pmin = -25000, .pmax = 25000 },
+ [HSC400MD] = { .pmin = -40000, .pmax = 40000 },
+ [HSC600MD] = { .pmin = -60000, .pmax = 60000 },
+ [HSC001BD] = { .pmin = -100000, .pmax = 100000 },
+ [HSC1_6BD] = { .pmin = -160000, .pmax = 160000 },
+ [HSC2_5BD] = { .pmin = -250000, .pmax = 250000 },
+ [HSC004BD] = { .pmin = -400000, .pmax = 400000 },
+ [HSC2_5MG] = { .pmin = 0, .pmax = 250 },
+ [HSC004MG] = { .pmin = 0, .pmax = 400 },
+ [HSC006MG] = { .pmin = 0, .pmax = 600 },
+ [HSC010MG] = { .pmin = 0, .pmax = 1000 },
+ [HSC016MG] = { .pmin = 0, .pmax = 1600 },
+ [HSC025MG] = { .pmin = 0, .pmax = 2500 },
+ [HSC040MG] = { .pmin = 0, .pmax = 4000 },
+ [HSC060MG] = { .pmin = 0, .pmax = 6000 },
+ [HSC100MG] = { .pmin = 0, .pmax = 10000 },
+ [HSC160MG] = { .pmin = 0, .pmax = 16000 },
+ [HSC250MG] = { .pmin = 0, .pmax = 25000 },
+ [HSC400MG] = { .pmin = 0, .pmax = 40000 },
+ [HSC600MG] = { .pmin = 0, .pmax = 60000 },
+ [HSC001BG] = { .pmin = 0, .pmax = 100000 },
+ [HSC1_6BG] = { .pmin = 0, .pmax = 160000 },
+ [HSC2_5BG] = { .pmin = 0, .pmax = 250000 },
+ [HSC004BG] = { .pmin = 0, .pmax = 400000 },
+ [HSC006BG] = { .pmin = 0, .pmax = 600000 },
+ [HSC010BG] = { .pmin = 0, .pmax = 1000000 },
+ [HSC100KA] = { .pmin = 0, .pmax = 100000 },
+ [HSC160KA] = { .pmin = 0, .pmax = 160000 },
+ [HSC250KA] = { .pmin = 0, .pmax = 250000 },
+ [HSC400KA] = { .pmin = 0, .pmax = 400000 },
+ [HSC600KA] = { .pmin = 0, .pmax = 600000 },
+ [HSC001GA] = { .pmin = 0, .pmax = 1000000 },
+ [HSC160LD] = { .pmin = -160, .pmax = 160 },
+ [HSC250LD] = { .pmin = -250, .pmax = 250 },
+ [HSC400LD] = { .pmin = -400, .pmax = 400 },
+ [HSC600LD] = { .pmin = -600, .pmax = 600 },
+ [HSC001KD] = { .pmin = -1000, .pmax = 1000 },
+ [HSC1_6KD] = { .pmin = -1600, .pmax = 1600 },
+ [HSC2_5KD] = { .pmin = -2500, .pmax = 2500 },
+ [HSC004KD] = { .pmin = -4000, .pmax = 4000 },
+ [HSC006KD] = { .pmin = -6000, .pmax = 6000 },
+ [HSC010KD] = { .pmin = -10000, .pmax = 10000 },
+ [HSC016KD] = { .pmin = -16000, .pmax = 16000 },
+ [HSC025KD] = { .pmin = -25000, .pmax = 25000 },
+ [HSC040KD] = { .pmin = -40000, .pmax = 40000 },
+ [HSC060KD] = { .pmin = -60000, .pmax = 60000 },
+ [HSC100KD] = { .pmin = -100000, .pmax = 100000 },
+ [HSC160KD] = { .pmin = -160000, .pmax = 160000 },
+ [HSC250KD] = { .pmin = -250000, .pmax = 250000 },
+ [HSC400KD] = { .pmin = -400000, .pmax = 400000 },
+ [HSC250LG] = { .pmin = 0, .pmax = 250 },
+ [HSC400LG] = { .pmin = 0, .pmax = 400 },
+ [HSC600LG] = { .pmin = 0, .pmax = 600 },
+ [HSC001KG] = { .pmin = 0, .pmax = 1000 },
+ [HSC1_6KG] = { .pmin = 0, .pmax = 1600 },
+ [HSC2_5KG] = { .pmin = 0, .pmax = 2500 },
+ [HSC004KG] = { .pmin = 0, .pmax = 4000 },
+ [HSC006KG] = { .pmin = 0, .pmax = 6000 },
+ [HSC010KG] = { .pmin = 0, .pmax = 10000 },
+ [HSC016KG] = { .pmin = 0, .pmax = 16000 },
+ [HSC025KG] = { .pmin = 0, .pmax = 25000 },
+ [HSC040KG] = { .pmin = 0, .pmax = 40000 },
+ [HSC060KG] = { .pmin = 0, .pmax = 60000 },
+ [HSC100KG] = { .pmin = 0, .pmax = 100000 },
+ [HSC160KG] = { .pmin = 0, .pmax = 160000 },
+ [HSC250KG] = { .pmin = 0, .pmax = 250000 },
+ [HSC400KG] = { .pmin = 0, .pmax = 400000 },
+ [HSC600KG] = { .pmin = 0, .pmax = 600000 },
+ [HSC001GG] = { .pmin = 0, .pmax = 1000000 },
+ [HSC015PA] = { .pmin = 0, .pmax = 103421 },
+ [HSC030PA] = { .pmin = 0, .pmax = 206843 },
+ [HSC060PA] = { .pmin = 0, .pmax = 413685 },
+ [HSC100PA] = { .pmin = 0, .pmax = 689476 },
+ [HSC150PA] = { .pmin = 0, .pmax = 1034214 },
+ [HSC0_5ND] = { .pmin = -125, .pmax = 125 },
+ [HSC001ND] = { .pmin = -249, .pmax = 249 },
+ [HSC002ND] = { .pmin = -498, .pmax = 498 },
+ [HSC004ND] = { .pmin = -996, .pmax = 996 },
+ [HSC005ND] = { .pmin = -1245, .pmax = 1245 },
+ [HSC010ND] = { .pmin = -2491, .pmax = 2491 },
+ [HSC020ND] = { .pmin = -4982, .pmax = 4982 },
+ [HSC030ND] = { .pmin = -7473, .pmax = 7473 },
+ [HSC001PD] = { .pmin = -6895, .pmax = 6895 },
+ [HSC005PD] = { .pmin = -34474, .pmax = 34474 },
+ [HSC015PD] = { .pmin = -103421, .pmax = 103421 },
+ [HSC030PD] = { .pmin = -206843, .pmax = 206843 },
+ [HSC060PD] = { .pmin = -413685, .pmax = 413685 },
+ [HSC001NG] = { .pmin = 0, .pmax = 249 },
+ [HSC002NG] = { .pmin = 0, .pmax = 498 },
+ [HSC004NG] = { .pmin = 0, .pmax = 996 },
+ [HSC005NG] = { .pmin = 0, .pmax = 1245 },
+ [HSC010NG] = { .pmin = 0, .pmax = 2491 },
+ [HSC020NG] = { .pmin = 0, .pmax = 4982 },
+ [HSC030NG] = { .pmin = 0, .pmax = 7473 },
+ [HSC001PG] = { .pmin = 0, .pmax = 6895 },
+ [HSC005PG] = { .pmin = 0, .pmax = 34474 },
+ [HSC015PG] = { .pmin = 0, .pmax = 103421 },
+ [HSC030PG] = { .pmin = 0, .pmax = 206843 },
+ [HSC060PG] = { .pmin = 0, .pmax = 413685 },
+ [HSC100PG] = { .pmin = 0, .pmax = 689476 },
+ [HSC150PG] = { .pmin = 0, .pmax = 1034214 },
+};
+
+/**
+ * hsc_measurement_is_valid() - validate last conversion via status bits
+ * @data: structure containing instantiated sensor data
+ * Return: true only if both status bits are zero
+ *
+ * the two MSB from the first transfered byte contain a status code
+ * 00 - normal operation, valid data
+ * 01 - device in factory programming mode
+ * 10 - stale data
+ * 11 - diagnostic condition
+ */
+static bool hsc_measurement_is_valid(struct hsc_data *data)
+{
+ return !(data->buffer[0] & HSC_STATUS_MASK);
+}
+
+static int hsc_get_measurement(struct hsc_data *data)
+{
+ const struct hsc_chip_data *chip = data->chip;
+ int ret;
+
+ ret = data->recv_cb(data);
+ if (ret < 0)
+ return ret;
+
+ data->is_valid = chip->valid(data);
+ if (!data->is_valid)
+ return -EAGAIN;
+
+ return 0;
+}
+
+/*
+ * IIO ABI expects
+ * value = (conv + offset) * scale
+ *
+ * datasheet provides the following formula for determining the temperature
+ * temp[C] = conv * a + b
+ * where a = 200/2047; b = -50
+ *
+ * temp[C] = (conv + (b/a)) * a * (1000)
+ * =>
+ * scale = a * 1000 = .097703957 * 1000 = 97.703957
+ * offset = b/a = -50 / .097703957 = -50000000 / 97704
+ *
+ * based on the datasheet
+ * pressure = (conv - Omin) * Q + Pmin =
+ * ((conv - Omin) + Pmin/Q) * Q
+ * =>
+ * scale = Q = (Pmax - Pmin) / (Omax - Omin)
+ * offset = Pmin/Q - Omin = Pmin * (Omax - Omin) / (Pmax - Pmin) - Omin
+ */
+static int hsc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ struct hsc_data *data = iio_priv(indio_dev);
+ int ret;
+ u32 recvd;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = hsc_get_measurement(data);
+ if (ret)
+ return ret;
+
+ recvd = get_unaligned_be32(data->buffer);
+ switch (channel->type) {
+ case IIO_PRESSURE:
+ *val = FIELD_GET(HSC_PRESSURE_MASK, recvd);
+ return IIO_VAL_INT;
+ case IIO_TEMP:
+ *val = FIELD_GET(HSC_TEMPERATURE_MASK, recvd);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+
+ case IIO_CHAN_INFO_SCALE:
+ switch (channel->type) {
+ case IIO_TEMP:
+ *val = 97;
+ *val2 = 703957;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_PRESSURE:
+ *val = data->p_scale;
+ *val2 = data->p_scale_dec;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+
+ case IIO_CHAN_INFO_OFFSET:
+ switch (channel->type) {
+ case IIO_TEMP:
+ *val = -50000000;
+ *val2 = 97704;
+ return IIO_VAL_FRACTIONAL;
+ case IIO_PRESSURE:
+ *val = data->p_offset;
+ *val2 = data->p_offset_dec;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec hsc_channels[] = {
+ {
+ .type = IIO_PRESSURE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ },
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ },
+};
+
+static const struct iio_info hsc_info = {
+ .read_raw = hsc_read_raw,
+};
+
+static const struct hsc_chip_data hsc_chip = {
+ .valid = hsc_measurement_is_valid,
+ .channels = hsc_channels,
+ .num_channels = ARRAY_SIZE(hsc_channels),
+};
+
+int hsc_common_probe(struct device *dev, hsc_recv_fn recv)
+{
+ struct hsc_data *hsc;
+ struct iio_dev *indio_dev;
+ const char *triplet;
+ u64 tmp;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*hsc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ hsc = iio_priv(indio_dev);
+
+ hsc->chip = &hsc_chip;
+ hsc->recv_cb = recv;
+ hsc->dev = dev;
+
+ ret = device_property_read_u32(dev, "honeywell,transfer-function",
+ &hsc->function);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "honeywell,transfer-function could not be read\n");
+ if (hsc->function > HSC_FUNCTION_F)
+ return dev_err_probe(dev, -EINVAL,
+ "honeywell,transfer-function %d invalid\n",
+ hsc->function);
+
+ ret = device_property_read_string(dev, "honeywell,pressure-triplet",
+ &triplet);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "honeywell,pressure-triplet could not be read\n");
+
+ if (str_has_prefix(triplet, "NA")) {
+ ret = device_property_read_u32(dev, "honeywell,pmin-pascal",
+ &hsc->pmin);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "honeywell,pmin-pascal could not be read\n");
+
+ ret = device_property_read_u32(dev, "honeywell,pmax-pascal",
+ &hsc->pmax);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "honeywell,pmax-pascal could not be read\n");
+ } else {
+ ret = device_property_match_property_string(dev,
+ "honeywell,pressure-triplet",
+ hsc_triplet_variants,
+ HSC_VARIANTS_MAX);
+ if (ret < 0)
+ return dev_err_probe(dev, -EINVAL,
+ "honeywell,pressure-triplet is invalid\n");
+
+ hsc->pmin = hsc_range_config[ret].pmin;
+ hsc->pmax = hsc_range_config[ret].pmax;
+ }
+
+ if (hsc->pmin >= hsc->pmax)
+ return dev_err_probe(dev, -EINVAL,
+ "pressure limits are invalid\n");
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret, "can't get vdd supply\n");
+
+ hsc->outmin = hsc_func_spec[hsc->function].output_min;
+ hsc->outmax = hsc_func_spec[hsc->function].output_max;
+
+ tmp = div_s64(((s64)(hsc->pmax - hsc->pmin)) * MICRO,
+ hsc->outmax - hsc->outmin);
+ hsc->p_scale = div_s64_rem(tmp, NANO, &hsc->p_scale_dec);
+ tmp = div_s64(((s64)hsc->pmin * (s64)(hsc->outmax - hsc->outmin)) * MICRO,
+ hsc->pmax - hsc->pmin);
+ tmp -= (s64)hsc->outmin * MICRO;
+ hsc->p_offset = div_s64_rem(tmp, MICRO, &hsc->p_offset_dec);
+
+ indio_dev->name = "hsc030pa";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &hsc_info;
+ indio_dev->channels = hsc->chip->channels;
+ indio_dev->num_channels = hsc->chip->num_channels;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+EXPORT_SYMBOL_NS(hsc_common_probe, IIO_HONEYWELL_HSC030PA);
+
+MODULE_AUTHOR("Petre Rodan <[email protected]>");
+MODULE_DESCRIPTION("Honeywell HSC and SSC pressure sensor core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/pressure/hsc030pa.h b/drivers/iio/pressure/hsc030pa.h
new file mode 100644
index 000000000000..d20420dba4f6
--- /dev/null
+++ b/drivers/iio/pressure/hsc030pa.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Honeywell TruStability HSC Series pressure/temperature sensor
+ *
+ * Copyright (c) 2023 Petre Rodan <[email protected]>
+ */
+
+#ifndef _HSC030PA_H
+#define _HSC030PA_H
+
+#include <linux/types.h>
+
+#define HSC_REG_MEASUREMENT_RD_SIZE 4
+
+struct device;
+
+struct iio_chan_spec;
+struct iio_dev;
+
+struct hsc_data;
+struct hsc_chip_data;
+
+typedef int (*hsc_recv_fn)(struct hsc_data *);
+
+/**
+ * struct hsc_data
+ * @dev: current device structure
+ * @chip: structure containing chip's channel properties
+ * @recv_cb: function that implements the chip reads
+ * @is_valid: true if last transfer has been validated
+ * @pmin: minimum measurable pressure limit
+ * @pmax: maximum measurable pressure limit
+ * @outmin: minimum raw pressure in counts (based on transfer function)
+ * @outmax: maximum raw pressure in counts (based on transfer function)
+ * @function: transfer function
+ * @p_scale: pressure scale
+ * @p_scale_dec: pressure scale, decimal places
+ * @p_offset: pressure offset
+ * @p_offset_dec: pressure offset, decimal places
+ * @buffer: raw conversion data
+ */
+struct hsc_data {
+ struct device *dev;
+ const struct hsc_chip_data *chip;
+ hsc_recv_fn recv_cb;
+ bool is_valid;
+ s32 pmin;
+ s32 pmax;
+ u32 outmin;
+ u32 outmax;
+ u32 function;
+ s64 p_scale;
+ s32 p_scale_dec;
+ s64 p_offset;
+ s32 p_offset_dec;
+ u8 buffer[HSC_REG_MEASUREMENT_RD_SIZE] __aligned(IIO_DMA_MINALIGN);
+};
+
+struct hsc_chip_data {
+ bool (*valid)(struct hsc_data *data);
+ const struct iio_chan_spec *channels;
+ u8 num_channels;
+};
+
+enum hsc_func_id {
+ HSC_FUNCTION_A,
+ HSC_FUNCTION_B,
+ HSC_FUNCTION_C,
+ HSC_FUNCTION_F,
+};
+
+int hsc_common_probe(struct device *dev, hsc_recv_fn recv);
+
+#endif
diff --git a/drivers/iio/pressure/hsc030pa_i2c.c b/drivers/iio/pressure/hsc030pa_i2c.c
new file mode 100644
index 000000000000..e2b524b36417
--- /dev/null
+++ b/drivers/iio/pressure/hsc030pa_i2c.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Honeywell TruStability HSC Series pressure/temperature sensor
+ *
+ * Copyright (c) 2023 Petre Rodan <[email protected]>
+ *
+ * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf [hsc]
+ * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/common/documents/sps-siot-i2c-comms-digital-output-pressure-sensors-tn-008201-3-en-ciid-45841.pdf [i2c related]
+ */
+
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+
+#include "hsc030pa.h"
+
+static int hsc_i2c_recv(struct hsc_data *data)
+{
+ struct i2c_client *client = to_i2c_client(data->dev);
+ struct i2c_msg msg;
+ int ret;
+
+ msg.addr = client->addr;
+ msg.flags = client->flags | I2C_M_RD;
+ msg.len = HSC_REG_MEASUREMENT_RD_SIZE;
+ msg.buf = data->buffer;
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ return (ret == 2) ? 0 : ret;
+}
+
+static int hsc_i2c_probe(struct i2c_client *client)
+{
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -EOPNOTSUPP;
+
+ return hsc_common_probe(&client->dev, hsc_i2c_recv);
+}
+
+static const struct of_device_id hsc_i2c_match[] = {
+ { .compatible = "honeywell,hsc030pa" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, hsc_i2c_match);
+
+static const struct i2c_device_id hsc_i2c_id[] = {
+ { "hsc030pa" },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, hsc_i2c_id);
+
+static struct i2c_driver hsc_i2c_driver = {
+ .driver = {
+ .name = "hsc030pa",
+ .of_match_table = hsc_i2c_match,
+ },
+ .probe = hsc_i2c_probe,
+ .id_table = hsc_i2c_id,
+};
+module_i2c_driver(hsc_i2c_driver);
+
+MODULE_AUTHOR("Petre Rodan <[email protected]>");
+MODULE_DESCRIPTION("Honeywell HSC and SSC pressure sensor i2c driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HONEYWELL_HSC030PA);
diff --git a/drivers/iio/pressure/hsc030pa_spi.c b/drivers/iio/pressure/hsc030pa_spi.c
new file mode 100644
index 000000000000..a719bade8326
--- /dev/null
+++ b/drivers/iio/pressure/hsc030pa_spi.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Honeywell TruStability HSC Series pressure/temperature sensor
+ *
+ * Copyright (c) 2023 Petre Rodan <[email protected]>
+ *
+ * Datasheet: https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/stddef.h>
+
+#include <linux/iio/iio.h>
+
+#include "hsc030pa.h"
+
+static int hsc_spi_recv(struct hsc_data *data)
+{
+ struct spi_device *spi = to_spi_device(data->dev);
+ struct spi_transfer xfer = {
+ .tx_buf = NULL,
+ .rx_buf = data->buffer,
+ .len = HSC_REG_MEASUREMENT_RD_SIZE,
+ };
+
+ return spi_sync_transfer(spi, &xfer, 1);
+}
+
+static int hsc_spi_probe(struct spi_device *spi)
+{
+ return hsc_common_probe(&spi->dev, hsc_spi_recv);
+}
+
+static const struct of_device_id hsc_spi_match[] = {
+ { .compatible = "honeywell,hsc030pa" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, hsc_spi_match);
+
+static const struct spi_device_id hsc_spi_id[] = {
+ { "hsc030pa" },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, hsc_spi_id);
+
+static struct spi_driver hsc_spi_driver = {
+ .driver = {
+ .name = "hsc030pa",
+ .of_match_table = hsc_spi_match,
+ },
+ .probe = hsc_spi_probe,
+ .id_table = hsc_spi_id,
+};
+module_spi_driver(hsc_spi_driver);
+
+MODULE_AUTHOR("Petre Rodan <[email protected]>");
+MODULE_DESCRIPTION("Honeywell HSC and SSC pressure sensor spi driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(IIO_HONEYWELL_HSC030PA);
diff --git a/drivers/iio/proximity/irsd200.c b/drivers/iio/proximity/irsd200.c
index bdff91f6b1a3..323ac6dac90e 100644
--- a/drivers/iio/proximity/irsd200.c
+++ b/drivers/iio/proximity/irsd200.c
@@ -7,7 +7,6 @@
#include <asm/unaligned.h>
#include <linux/bitfield.h>
-#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c
index 438f9c9aba6e..ac2ed2da21cc 100644
--- a/drivers/iio/proximity/sx9324.c
+++ b/drivers/iio/proximity/sx9324.c
@@ -888,7 +888,6 @@ sx9324_get_default_reg(struct device *dev, int idx,
char prop[] = SX9324_PROXRAW_DEF;
u32 start = 0, raw = 0, pos = 0;
int ret, count, ph, pin;
- const char *res;
memcpy(reg_def, &sx9324_default_regs[idx], sizeof(*reg_def));
@@ -915,24 +914,21 @@ sx9324_get_default_reg(struct device *dev, int idx,
reg_def->def = raw;
break;
case SX9324_REG_AFE_CTRL0:
- ret = device_property_read_string(dev,
- "semtech,cs-idle-sleep", &res);
- if (!ret)
- ret = match_string(sx9324_csidle, ARRAY_SIZE(sx9324_csidle), res);
+ ret = device_property_match_property_string(dev, "semtech,cs-idle-sleep",
+ sx9324_csidle,
+ ARRAY_SIZE(sx9324_csidle));
if (ret >= 0) {
reg_def->def &= ~SX9324_REG_AFE_CTRL0_CSIDLE_MASK;
reg_def->def |= ret << SX9324_REG_AFE_CTRL0_CSIDLE_SHIFT;
}
- ret = device_property_read_string(dev,
- "semtech,int-comp-resistor", &res);
- if (ret)
- break;
- ret = match_string(sx9324_rints, ARRAY_SIZE(sx9324_rints), res);
- if (ret < 0)
- break;
- reg_def->def &= ~SX9324_REG_AFE_CTRL0_RINT_MASK;
- reg_def->def |= ret << SX9324_REG_AFE_CTRL0_RINT_SHIFT;
+ ret = device_property_match_property_string(dev, "semtech,int-comp-resistor",
+ sx9324_rints,
+ ARRAY_SIZE(sx9324_rints));
+ if (ret >= 0) {
+ reg_def->def &= ~SX9324_REG_AFE_CTRL0_RINT_MASK;
+ reg_def->def |= ret << SX9324_REG_AFE_CTRL0_RINT_SHIFT;
+ }
break;
case SX9324_REG_AFE_CTRL4:
case SX9324_REG_AFE_CTRL7:
diff --git a/drivers/iio/resolver/ad2s1210.c b/drivers/iio/resolver/ad2s1210.c
index 1bd1b950e7cc..a414eef12e5e 100644
--- a/drivers/iio/resolver/ad2s1210.c
+++ b/drivers/iio/resolver/ad2s1210.c
@@ -141,7 +141,7 @@ struct ad2s1210_state {
struct spi_device *sdev;
/** GPIO pin connected to SAMPLE line. */
struct gpio_desc *sample_gpio;
- /** GPIO pins connected to A0 and A1 lines. */
+ /** GPIO pins connected to A0 and A1 lines (optional). */
struct gpio_descs *mode_gpios;
/** Used to access config registers. */
struct regmap *regmap;
@@ -149,6 +149,8 @@ struct ad2s1210_state {
unsigned long clkin_hz;
/** Available raw hysteresis values based on resolution. */
int hysteresis_available[2];
+ /* adi,fixed-mode property - only valid when mode_gpios == NULL. */
+ enum ad2s1210_mode fixed_mode;
/** The selected resolution */
enum ad2s1210_resolution resolution;
/** Copy of fault register from the previous read. */
@@ -175,6 +177,9 @@ static int ad2s1210_set_mode(struct ad2s1210_state *st, enum ad2s1210_mode mode)
struct gpio_descs *gpios = st->mode_gpios;
DECLARE_BITMAP(bitmap, 2);
+ if (!gpios)
+ return mode == st->fixed_mode ? 0 : -EOPNOTSUPP;
+
bitmap[0] = mode;
return gpiod_set_array_value(gpios->ndescs, gpios->desc, gpios->info,
@@ -276,7 +281,8 @@ static int ad2s1210_regmap_reg_read(void *context, unsigned int reg,
* parity error. The fault register is read-only and the D7 bit means
* something else there.
*/
- if (reg != AD2S1210_REG_FAULT && st->rx[1] & AD2S1210_ADDRESS_DATA)
+ if ((reg > AD2S1210_REG_VELOCITY_LSB && reg != AD2S1210_REG_FAULT)
+ && st->rx[1] & AD2S1210_ADDRESS_DATA)
return -EBADMSG;
*val = st->rx[1];
@@ -450,21 +456,53 @@ static int ad2s1210_single_conversion(struct iio_dev *indio_dev,
ad2s1210_toggle_sample_line(st);
timestamp = iio_get_time_ns(indio_dev);
- switch (chan->type) {
- case IIO_ANGL:
- ret = ad2s1210_set_mode(st, MOD_POS);
- break;
- case IIO_ANGL_VEL:
- ret = ad2s1210_set_mode(st, MOD_VEL);
- break;
- default:
- return -EINVAL;
+ if (st->fixed_mode == MOD_CONFIG) {
+ unsigned int reg_val;
+
+ switch (chan->type) {
+ case IIO_ANGL:
+ ret = regmap_bulk_read(st->regmap,
+ AD2S1210_REG_POSITION_MSB,
+ &st->sample.raw, 2);
+ if (ret < 0)
+ return ret;
+
+ break;
+ case IIO_ANGL_VEL:
+ ret = regmap_bulk_read(st->regmap,
+ AD2S1210_REG_VELOCITY_MSB,
+ &st->sample.raw, 2);
+ if (ret < 0)
+ return ret;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &reg_val);
+ if (ret < 0)
+ return ret;
+
+ st->sample.fault = reg_val;
+ } else {
+ switch (chan->type) {
+ case IIO_ANGL:
+ ret = ad2s1210_set_mode(st, MOD_POS);
+ break;
+ case IIO_ANGL_VEL:
+ ret = ad2s1210_set_mode(st, MOD_VEL);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (ret < 0)
+ return ret;
+
+ ret = spi_read(st->sdev, &st->sample, 3);
+ if (ret < 0)
+ return ret;
}
- if (ret < 0)
- return ret;
- ret = spi_read(st->sdev, &st->sample, 3);
- if (ret < 0)
- return ret;
switch (chan->type) {
case IIO_ANGL:
@@ -1252,27 +1290,53 @@ static irqreturn_t ad2s1210_trigger_handler(int irq, void *p)
ad2s1210_toggle_sample_line(st);
if (test_bit(0, indio_dev->active_scan_mask)) {
- ret = ad2s1210_set_mode(st, MOD_POS);
- if (ret < 0)
- goto error_ret;
-
- ret = spi_read(st->sdev, &st->sample, 3);
- if (ret < 0)
- goto error_ret;
+ if (st->fixed_mode == MOD_CONFIG) {
+ ret = regmap_bulk_read(st->regmap,
+ AD2S1210_REG_POSITION_MSB,
+ &st->sample.raw, 2);
+ if (ret < 0)
+ goto error_ret;
+ } else {
+ ret = ad2s1210_set_mode(st, MOD_POS);
+ if (ret < 0)
+ goto error_ret;
+
+ ret = spi_read(st->sdev, &st->sample, 3);
+ if (ret < 0)
+ goto error_ret;
+ }
memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
}
if (test_bit(1, indio_dev->active_scan_mask)) {
- ret = ad2s1210_set_mode(st, MOD_VEL);
- if (ret < 0)
- goto error_ret;
+ if (st->fixed_mode == MOD_CONFIG) {
+ ret = regmap_bulk_read(st->regmap,
+ AD2S1210_REG_VELOCITY_MSB,
+ &st->sample.raw, 2);
+ if (ret < 0)
+ goto error_ret;
+ } else {
+ ret = ad2s1210_set_mode(st, MOD_VEL);
+ if (ret < 0)
+ goto error_ret;
+
+ ret = spi_read(st->sdev, &st->sample, 3);
+ if (ret < 0)
+ goto error_ret;
+ }
- ret = spi_read(st->sdev, &st->sample, 3);
+ memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
+ }
+
+ if (st->fixed_mode == MOD_CONFIG) {
+ unsigned int reg_val;
+
+ ret = regmap_read(st->regmap, AD2S1210_REG_FAULT, &reg_val);
if (ret < 0)
- goto error_ret;
+ return ret;
- memcpy(&st->scan.chan[chan++], &st->sample.raw, 2);
+ st->sample.fault = reg_val;
}
ad2s1210_push_events(indio_dev, st->sample.fault, pf->timestamp);
@@ -1299,9 +1363,24 @@ static const struct iio_info ad2s1210_info = {
static int ad2s1210_setup_properties(struct ad2s1210_state *st)
{
struct device *dev = &st->sdev->dev;
+ const char *str_val;
u32 val;
int ret;
+ ret = device_property_read_string(dev, "adi,fixed-mode", &str_val);
+ if (ret == -EINVAL)
+ st->fixed_mode = -1;
+ else if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to read adi,fixed-mode property\n");
+ else {
+ if (strcmp(str_val, "config"))
+ return dev_err_probe(dev, -EINVAL,
+ "only adi,fixed-mode=\"config\" is supported\n");
+
+ st->fixed_mode = MOD_CONFIG;
+ }
+
ret = device_property_read_u32(dev, "assigned-resolution-bits", &val);
if (ret < 0)
return dev_err_probe(dev, ret,
@@ -1347,6 +1426,7 @@ static int ad2s1210_setup_gpios(struct ad2s1210_state *st)
{
struct device *dev = &st->sdev->dev;
struct gpio_descs *resolution_gpios;
+ struct gpio_desc *reset_gpio;
DECLARE_BITMAP(bitmap, 2);
int ret;
@@ -1357,12 +1437,21 @@ static int ad2s1210_setup_gpios(struct ad2s1210_state *st)
"failed to request sample GPIO\n");
/* both pins high means that we start in config mode */
- st->mode_gpios = devm_gpiod_get_array(dev, "mode", GPIOD_OUT_HIGH);
+ st->mode_gpios = devm_gpiod_get_array_optional(dev, "mode",
+ GPIOD_OUT_HIGH);
if (IS_ERR(st->mode_gpios))
return dev_err_probe(dev, PTR_ERR(st->mode_gpios),
"failed to request mode GPIOs\n");
- if (st->mode_gpios->ndescs != 2)
+ if (!st->mode_gpios && st->fixed_mode == -1)
+ return dev_err_probe(dev, -EINVAL,
+ "must specify either adi,fixed-mode or mode-gpios\n");
+
+ if (st->mode_gpios && st->fixed_mode != -1)
+ return dev_err_probe(dev, -EINVAL,
+ "must specify only one of adi,fixed-mode or mode-gpios\n");
+
+ if (st->mode_gpios && st->mode_gpios->ndescs != 2)
return dev_err_probe(dev, -EINVAL,
"requires exactly 2 mode-gpios\n");
@@ -1393,6 +1482,17 @@ static int ad2s1210_setup_gpios(struct ad2s1210_state *st)
"failed to set resolution gpios\n");
}
+ /* If the optional reset GPIO is present, toggle it to do a hard reset. */
+ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(reset_gpio),
+ "failed to request reset GPIO\n");
+
+ if (reset_gpio) {
+ udelay(10);
+ gpiod_set_value(reset_gpio, 0);
+ }
+
return 0;
}
diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
index ed384f33e0c7..ed0e4963362f 100644
--- a/drivers/iio/temperature/Kconfig
+++ b/drivers/iio/temperature/Kconfig
@@ -76,6 +76,18 @@ config MLX90632
This driver can also be built as a module. If so, the module will
be called mlx90632.
+config MLX90635
+ tristate "MLX90635 contact-less infrared sensor with medical accuracy"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the Melexis
+ MLX90635 contact-less infrared sensor with medical accuracy
+ connected with I2C.
+
+ This driver can also be built as a module. If so, the module will
+ be called mlx90635.
+
config TMP006
tristate "TMP006 infrared thermopile sensor"
depends on I2C
@@ -158,4 +170,14 @@ config MAX31865
This driver can also be build as a module. If so, the module
will be called max31865.
+config MCP9600
+ tristate "MCP9600 thermocouple EMF converter"
+ depends on I2C
+ help
+ If you say yes here you get support for MCP9600
+ thermocouple EMF converter connected via I2C.
+
+ This driver can also be built as a module. If so, the module
+ will be called mcp9600.
+
endmenu
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
index dfec8c6d3019..07d6e65709f7 100644
--- a/drivers/iio/temperature/Makefile
+++ b/drivers/iio/temperature/Makefile
@@ -10,8 +10,10 @@ obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
obj-$(CONFIG_MAX30208) += max30208.o
obj-$(CONFIG_MAX31856) += max31856.o
obj-$(CONFIG_MAX31865) += max31865.o
+obj-$(CONFIG_MCP9600) += mcp9600.o
obj-$(CONFIG_MLX90614) += mlx90614.o
obj-$(CONFIG_MLX90632) += mlx90632.o
+obj-$(CONFIG_MLX90632) += mlx90635.o
obj-$(CONFIG_TMP006) += tmp006.o
obj-$(CONFIG_TMP007) += tmp007.o
obj-$(CONFIG_TMP117) += tmp117.o
diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c
new file mode 100644
index 000000000000..46845804292b
--- /dev/null
+++ b/drivers/iio/temperature/mcp9600.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * mcp9600.c - Support for Microchip MCP9600 thermocouple EMF converter
+ *
+ * Copyright (c) 2022 Andrew Hepp
+ * Author: <[email protected]>
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+
+/* MCP9600 registers */
+#define MCP9600_HOT_JUNCTION 0x0
+#define MCP9600_COLD_JUNCTION 0x2
+#define MCP9600_DEVICE_ID 0x20
+
+/* MCP9600 device id value */
+#define MCP9600_DEVICE_ID_MCP9600 0x40
+
+static const struct iio_chan_spec mcp9600_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .address = MCP9600_HOT_JUNCTION,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ },
+ {
+ .type = IIO_TEMP,
+ .address = MCP9600_COLD_JUNCTION,
+ .channel2 = IIO_MOD_TEMP_AMBIENT,
+ .modified = 1,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+struct mcp9600_data {
+ struct i2c_client *client;
+};
+
+static int mcp9600_read(struct mcp9600_data *data,
+ struct iio_chan_spec const *chan, int *val)
+{
+ int ret;
+
+ ret = i2c_smbus_read_word_swapped(data->client, chan->address);
+
+ if (ret < 0)
+ return ret;
+ *val = ret;
+
+ return 0;
+}
+
+static int mcp9600_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct mcp9600_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = mcp9600_read(data, chan, val);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 62;
+ *val2 = 500000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info mcp9600_info = {
+ .read_raw = mcp9600_read_raw,
+};
+
+static int mcp9600_probe(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev;
+ struct mcp9600_data *data;
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, MCP9600_DEVICE_ID);
+ if (ret < 0)
+ return dev_err_probe(&client->dev, ret, "Failed to read device ID\n");
+ if (ret != MCP9600_DEVICE_ID_MCP9600)
+ dev_warn(&client->dev, "Expected ID %x, got %x\n",
+ MCP9600_DEVICE_ID_MCP9600, ret);
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+
+ indio_dev->info = &mcp9600_info;
+ indio_dev->name = "mcp9600";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = mcp9600_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mcp9600_channels);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id mcp9600_id[] = {
+ { "mcp9600" },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, mcp9600_id);
+
+static const struct of_device_id mcp9600_of_match[] = {
+ { .compatible = "microchip,mcp9600" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, mcp9600_of_match);
+
+static struct i2c_driver mcp9600_driver = {
+ .driver = {
+ .name = "mcp9600",
+ .of_match_table = mcp9600_of_match,
+ },
+ .probe = mcp9600_probe,
+ .id_table = mcp9600_id
+};
+module_i2c_driver(mcp9600_driver);
+
+MODULE_AUTHOR("Andrew Hepp <[email protected]>");
+MODULE_DESCRIPTION("Microchip MCP9600 thermocouple EMF converter driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/temperature/mlx90635.c b/drivers/iio/temperature/mlx90635.c
new file mode 100644
index 000000000000..1f5c962c1818
--- /dev/null
+++ b/drivers/iio/temperature/mlx90635.c
@@ -0,0 +1,1097 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * mlx90635.c - Melexis MLX90635 contactless IR temperature sensor
+ *
+ * Copyright (c) 2023 Melexis <[email protected]>
+ *
+ * Driver for the Melexis MLX90635 I2C 16-bit IR thermopile sensor
+ */
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/iopoll.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/math64.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+
+/* Memory sections addresses */
+#define MLX90635_ADDR_RAM 0x0000 /* Start address of ram */
+#define MLX90635_ADDR_EEPROM 0x0018 /* Start address of user eeprom */
+
+/* EEPROM addresses - used at startup */
+#define MLX90635_EE_I2C_CFG 0x0018 /* I2C address register initial value */
+#define MLX90635_EE_CTRL1 0x001A /* Control register1 initial value */
+#define MLX90635_EE_CTRL2 0x001C /* Control register2 initial value */
+
+#define MLX90635_EE_Ha 0x001E /* Ha customer calib value reg 16bit */
+#define MLX90635_EE_Hb 0x0020 /* Hb customer calib value reg 16bit */
+#define MLX90635_EE_Fa 0x0026 /* Fa calibration register 32bit */
+#define MLX90635_EE_FASCALE 0x002A /* Scaling coefficient for Fa register 16bit */
+#define MLX90635_EE_Ga 0x002C /* Ga calibration register 16bit */
+#define MLX90635_EE_Fb 0x002E /* Fb calibration register 16bit */
+#define MLX90635_EE_Ea 0x0030 /* Ea calibration register 32bit */
+#define MLX90635_EE_Eb 0x0034 /* Eb calibration register 32bit */
+#define MLX90635_EE_P_G 0x0038 /* P_G calibration register 16bit */
+#define MLX90635_EE_P_O 0x003A /* P_O calibration register 16bit */
+#define MLX90635_EE_Aa 0x003C /* Aa calibration register 16bit */
+#define MLX90635_EE_VERSION 0x003E /* Version bits 4:7 and 12:15 */
+#define MLX90635_EE_Gb 0x0040 /* Gb calibration register 16bit */
+
+/* Device status register - volatile */
+#define MLX90635_REG_STATUS 0x0000
+#define MLX90635_STAT_BUSY BIT(6) /* Device busy indicator */
+#define MLX90635_STAT_BRST BIT(5) /* Brown out reset indicator */
+#define MLX90635_STAT_CYCLE_POS GENMASK(4, 2) /* Data position */
+#define MLX90635_STAT_END_CONV BIT(1) /* End of conversion indicator */
+#define MLX90635_STAT_DATA_RDY BIT(0) /* Data ready indicator */
+
+/* EEPROM control register address - volatile */
+#define MLX90635_REG_EE 0x000C
+#define MLX90635_EE_ACTIVE BIT(4) /* Power-on EEPROM */
+#define MLX90635_EE_BUSY_MASK BIT(15)
+
+#define MLX90635_REG_CMD 0x0010 /* Command register address */
+
+/* Control register1 address - volatile */
+#define MLX90635_REG_CTRL1 0x0014
+#define MLX90635_CTRL1_REFRESH_RATE_MASK GENMASK(2, 0)
+#define MLX90635_CTRL1_RES_CTRL_MASK GENMASK(4, 3)
+#define MLX90635_CTRL1_TABLE_MASK BIT(15) /* Table select */
+
+/* Control register2 address - volatile */
+#define MLX90635_REG_CTRL2 0x0016
+#define MLX90635_CTRL2_BURST_CNT_MASK GENMASK(10, 6) /* Burst count */
+#define MLX90635_CTRL2_MODE_MASK GENMASK(12, 11) /* Power mode */
+#define MLX90635_CTRL2_SOB_MASK BIT(15)
+
+/* PowerModes statuses */
+#define MLX90635_PWR_STATUS_HALT 0
+#define MLX90635_PWR_STATUS_SLEEP_STEP 1
+#define MLX90635_PWR_STATUS_STEP 2
+#define MLX90635_PWR_STATUS_CONTINUOUS 3
+
+/* Measurement data addresses */
+#define MLX90635_RESULT_1 0x0002
+#define MLX90635_RESULT_2 0x0004
+#define MLX90635_RESULT_3 0x0006
+#define MLX90635_RESULT_4 0x0008
+#define MLX90635_RESULT_5 0x000A
+
+/* Timings (ms) */
+#define MLX90635_TIMING_RST_MIN 200 /* Minimum time after addressed reset command */
+#define MLX90635_TIMING_RST_MAX 250 /* Maximum time after addressed reset command */
+#define MLX90635_TIMING_POLLING 10000 /* Time between bit polling*/
+#define MLX90635_TIMING_EE_ACTIVE_MIN 100 /* Minimum time after activating the EEPROM for read */
+#define MLX90635_TIMING_EE_ACTIVE_MAX 150 /* Maximum time after activating the EEPROM for read */
+
+/* Magic constants */
+#define MLX90635_ID_DSPv1 0x01 /* EEPROM DSP version */
+#define MLX90635_RESET_CMD 0x0006 /* Reset sensor (address or global) */
+#define MLX90635_MAX_MEAS_NUM 31 /* Maximum number of measurements in list */
+#define MLX90635_PTAT_DIV 12 /* Used to divide the PTAT value in pre-processing */
+#define MLX90635_IR_DIV 24 /* Used to divide the IR value in pre-processing */
+#define MLX90635_SLEEP_DELAY_MS 6000 /* Autosleep delay */
+#define MLX90635_MEAS_MAX_TIME 2000 /* Max measurement time in ms for the lowest refresh rate */
+#define MLX90635_READ_RETRIES 100 /* Number of read retries before quitting with timeout error */
+#define MLX90635_VERSION_MASK (GENMASK(15, 12) | GENMASK(7, 4))
+#define MLX90635_DSP_VERSION(reg) (((reg & GENMASK(14, 12)) >> 9) | ((reg & GENMASK(6, 4)) >> 4))
+#define MLX90635_DSP_FIXED BIT(15)
+
+
+/**
+ * struct mlx90635_data - private data for the MLX90635 device
+ * @client: I2C client of the device
+ * @lock: Internal mutex because multiple reads are needed for single triggered
+ * measurement to ensure data consistency
+ * @regmap: Regmap of the device registers
+ * @regmap_ee: Regmap of the device EEPROM which can be cached
+ * @emissivity: Object emissivity from 0 to 1000 where 1000 = 1
+ * @regulator: Regulator of the device
+ * @powerstatus: Current POWER status of the device
+ * @interaction_ts: Timestamp of the last temperature read that is used
+ * for power management in jiffies
+ */
+struct mlx90635_data {
+ struct i2c_client *client;
+ struct mutex lock;
+ struct regmap *regmap;
+ struct regmap *regmap_ee;
+ u16 emissivity;
+ struct regulator *regulator;
+ int powerstatus;
+ unsigned long interaction_ts;
+};
+
+static const struct regmap_range mlx90635_volatile_reg_range[] = {
+ regmap_reg_range(MLX90635_REG_STATUS, MLX90635_REG_STATUS),
+ regmap_reg_range(MLX90635_RESULT_1, MLX90635_RESULT_5),
+ regmap_reg_range(MLX90635_REG_EE, MLX90635_REG_EE),
+ regmap_reg_range(MLX90635_REG_CMD, MLX90635_REG_CMD),
+ regmap_reg_range(MLX90635_REG_CTRL1, MLX90635_REG_CTRL2),
+};
+
+static const struct regmap_access_table mlx90635_volatile_regs_tbl = {
+ .yes_ranges = mlx90635_volatile_reg_range,
+ .n_yes_ranges = ARRAY_SIZE(mlx90635_volatile_reg_range),
+};
+
+static const struct regmap_range mlx90635_read_reg_range[] = {
+ regmap_reg_range(MLX90635_REG_STATUS, MLX90635_REG_STATUS),
+ regmap_reg_range(MLX90635_RESULT_1, MLX90635_RESULT_5),
+ regmap_reg_range(MLX90635_REG_EE, MLX90635_REG_EE),
+ regmap_reg_range(MLX90635_REG_CMD, MLX90635_REG_CMD),
+ regmap_reg_range(MLX90635_REG_CTRL1, MLX90635_REG_CTRL2),
+};
+
+static const struct regmap_access_table mlx90635_readable_regs_tbl = {
+ .yes_ranges = mlx90635_read_reg_range,
+ .n_yes_ranges = ARRAY_SIZE(mlx90635_read_reg_range),
+};
+
+static const struct regmap_range mlx90635_no_write_reg_range[] = {
+ regmap_reg_range(MLX90635_RESULT_1, MLX90635_RESULT_5),
+};
+
+static const struct regmap_access_table mlx90635_writeable_regs_tbl = {
+ .no_ranges = mlx90635_no_write_reg_range,
+ .n_no_ranges = ARRAY_SIZE(mlx90635_no_write_reg_range),
+};
+
+static const struct regmap_config mlx90635_regmap = {
+ .name = "mlx90635-registers",
+ .reg_stride = 1,
+ .reg_bits = 16,
+ .val_bits = 16,
+
+ .volatile_table = &mlx90635_volatile_regs_tbl,
+ .rd_table = &mlx90635_readable_regs_tbl,
+ .wr_table = &mlx90635_writeable_regs_tbl,
+
+ .use_single_read = true,
+ .use_single_write = true,
+ .can_multi_write = false,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct regmap_range mlx90635_read_ee_range[] = {
+ regmap_reg_range(MLX90635_EE_I2C_CFG, MLX90635_EE_CTRL2),
+ regmap_reg_range(MLX90635_EE_Ha, MLX90635_EE_Gb),
+};
+
+static const struct regmap_access_table mlx90635_readable_ees_tbl = {
+ .yes_ranges = mlx90635_read_ee_range,
+ .n_yes_ranges = ARRAY_SIZE(mlx90635_read_ee_range),
+};
+
+static const struct regmap_range mlx90635_no_write_ee_range[] = {
+ regmap_reg_range(MLX90635_ADDR_EEPROM, MLX90635_EE_Gb),
+};
+
+static const struct regmap_access_table mlx90635_writeable_ees_tbl = {
+ .no_ranges = mlx90635_no_write_ee_range,
+ .n_no_ranges = ARRAY_SIZE(mlx90635_no_write_ee_range),
+};
+
+static const struct regmap_config mlx90635_regmap_ee = {
+ .name = "mlx90635-eeprom",
+ .reg_stride = 1,
+ .reg_bits = 16,
+ .val_bits = 16,
+
+ .volatile_table = NULL,
+ .rd_table = &mlx90635_readable_ees_tbl,
+ .wr_table = &mlx90635_writeable_ees_tbl,
+
+ .use_single_read = true,
+ .use_single_write = true,
+ .can_multi_write = false,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .val_format_endian = REGMAP_ENDIAN_BIG,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+/**
+ * mlx90635_reset_delay() - Give the mlx90635 some time to reset properly
+ * If this is not done, the following I2C command(s) will not be accepted.
+ */
+static void mlx90635_reset_delay(void)
+{
+ usleep_range(MLX90635_TIMING_RST_MIN, MLX90635_TIMING_RST_MAX);
+}
+
+static int mlx90635_pwr_sleep_step(struct mlx90635_data *data)
+{
+ int ret;
+
+ if (data->powerstatus == MLX90635_PWR_STATUS_SLEEP_STEP)
+ return 0;
+
+ ret = regmap_write_bits(data->regmap, MLX90635_REG_CTRL2, MLX90635_CTRL2_MODE_MASK,
+ FIELD_PREP(MLX90635_CTRL2_MODE_MASK, MLX90635_PWR_STATUS_SLEEP_STEP));
+ if (ret < 0)
+ return ret;
+
+ data->powerstatus = MLX90635_PWR_STATUS_SLEEP_STEP;
+ return 0;
+}
+
+static int mlx90635_pwr_continuous(struct mlx90635_data *data)
+{
+ int ret;
+
+ if (data->powerstatus == MLX90635_PWR_STATUS_CONTINUOUS)
+ return 0;
+
+ ret = regmap_write_bits(data->regmap, MLX90635_REG_CTRL2, MLX90635_CTRL2_MODE_MASK,
+ FIELD_PREP(MLX90635_CTRL2_MODE_MASK, MLX90635_PWR_STATUS_CONTINUOUS));
+ if (ret < 0)
+ return ret;
+
+ data->powerstatus = MLX90635_PWR_STATUS_CONTINUOUS;
+ return 0;
+}
+
+static int mlx90635_read_ee_register(struct regmap *regmap, u16 reg_lsb,
+ s32 *reg_value)
+{
+ unsigned int read;
+ u32 value;
+ int ret;
+
+ ret = regmap_read(regmap, reg_lsb + 2, &read);
+ if (ret < 0)
+ return ret;
+
+ value = read;
+
+ ret = regmap_read(regmap, reg_lsb, &read);
+ if (ret < 0)
+ return ret;
+
+ *reg_value = (read << 16) | (value & 0xffff);
+
+ return 0;
+}
+
+static int mlx90635_read_ee_ambient(struct regmap *regmap, s16 *PG, s16 *PO, s16 *Gb)
+{
+ unsigned int read_tmp;
+ int ret;
+
+ ret = regmap_read(regmap, MLX90635_EE_P_O, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *PO = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90635_EE_P_G, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *PG = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90635_EE_Gb, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *Gb = (u16)read_tmp;
+
+ return 0;
+}
+
+static int mlx90635_read_ee_object(struct regmap *regmap, u32 *Ea, u32 *Eb, u32 *Fa, s16 *Fb,
+ s16 *Ga, s16 *Gb, s16 *Ha, s16 *Hb, u16 *Fa_scale)
+{
+ unsigned int read_tmp;
+ int ret;
+
+ ret = mlx90635_read_ee_register(regmap, MLX90635_EE_Ea, Ea);
+ if (ret < 0)
+ return ret;
+
+ ret = mlx90635_read_ee_register(regmap, MLX90635_EE_Eb, Eb);
+ if (ret < 0)
+ return ret;
+
+ ret = mlx90635_read_ee_register(regmap, MLX90635_EE_Fa, Fa);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(regmap, MLX90635_EE_Ha, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *Ha = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90635_EE_Hb, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *Hb = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90635_EE_Ga, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *Ga = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90635_EE_Gb, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *Gb = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90635_EE_Fb, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *Fb = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90635_EE_FASCALE, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *Fa_scale = (u16)read_tmp;
+
+ return 0;
+}
+
+static int mlx90635_calculate_dataset_ready_time(struct mlx90635_data *data, int *refresh_time)
+{
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(data->regmap, MLX90635_REG_CTRL1, &reg);
+ if (ret < 0)
+ return ret;
+
+ *refresh_time = 2 * (MLX90635_MEAS_MAX_TIME >> FIELD_GET(MLX90635_CTRL1_REFRESH_RATE_MASK, reg)) + 80;
+
+ return 0;
+}
+
+static int mlx90635_perform_measurement_burst(struct mlx90635_data *data)
+{
+ unsigned int reg_status;
+ int refresh_time;
+ int ret;
+
+ ret = regmap_write_bits(data->regmap, MLX90635_REG_STATUS,
+ MLX90635_STAT_END_CONV, MLX90635_STAT_END_CONV);
+ if (ret < 0)
+ return ret;
+
+ ret = mlx90635_calculate_dataset_ready_time(data, &refresh_time);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write_bits(data->regmap, MLX90635_REG_CTRL2,
+ FIELD_PREP(MLX90635_CTRL2_SOB_MASK, 1),
+ FIELD_PREP(MLX90635_CTRL2_SOB_MASK, 1));
+ if (ret < 0)
+ return ret;
+
+ msleep(refresh_time); /* Wait minimum time for dataset to be ready */
+
+ ret = regmap_read_poll_timeout(data->regmap, MLX90635_REG_STATUS, reg_status,
+ (!(reg_status & MLX90635_STAT_END_CONV)) == 0,
+ MLX90635_TIMING_POLLING, MLX90635_READ_RETRIES * 10000);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "data not ready");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int mlx90635_read_ambient_raw(struct regmap *regmap,
+ s16 *ambient_new_raw, s16 *ambient_old_raw)
+{
+ unsigned int read_tmp;
+ int ret;
+
+ ret = regmap_read(regmap, MLX90635_RESULT_2, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *ambient_new_raw = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90635_RESULT_3, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *ambient_old_raw = (s16)read_tmp;
+
+ return 0;
+}
+
+static int mlx90635_read_object_raw(struct regmap *regmap, s16 *object_raw)
+{
+ unsigned int read_tmp;
+ s16 read;
+ int ret;
+
+ ret = regmap_read(regmap, MLX90635_RESULT_1, &read_tmp);
+ if (ret < 0)
+ return ret;
+
+ read = (s16)read_tmp;
+
+ ret = regmap_read(regmap, MLX90635_RESULT_4, &read_tmp);
+ if (ret < 0)
+ return ret;
+ *object_raw = (read - (s16)read_tmp) / 2;
+
+ return 0;
+}
+
+static int mlx90635_read_all_channel(struct mlx90635_data *data,
+ s16 *ambient_new_raw, s16 *ambient_old_raw,
+ s16 *object_raw)
+{
+ int ret;
+
+ mutex_lock(&data->lock);
+ if (data->powerstatus == MLX90635_PWR_STATUS_SLEEP_STEP) {
+ /* Trigger measurement in Sleep Step mode */
+ ret = mlx90635_perform_measurement_burst(data);
+ if (ret < 0)
+ goto read_unlock;
+ }
+
+ ret = mlx90635_read_ambient_raw(data->regmap, ambient_new_raw,
+ ambient_old_raw);
+ if (ret < 0)
+ goto read_unlock;
+
+ ret = mlx90635_read_object_raw(data->regmap, object_raw);
+read_unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static s64 mlx90635_preprocess_temp_amb(s16 ambient_new_raw,
+ s16 ambient_old_raw, s16 Gb)
+{
+ s64 VR_Ta, kGb, tmp;
+
+ kGb = ((s64)Gb * 1000LL) >> 10ULL;
+ VR_Ta = (s64)ambient_old_raw * 1000000LL +
+ kGb * div64_s64(((s64)ambient_new_raw * 1000LL),
+ (MLX90635_PTAT_DIV));
+ tmp = div64_s64(
+ div64_s64(((s64)ambient_new_raw * 1000000000000LL),
+ (MLX90635_PTAT_DIV)), VR_Ta);
+ return div64_s64(tmp << 19ULL, 1000LL);
+}
+
+static s64 mlx90635_preprocess_temp_obj(s16 object_raw,
+ s16 ambient_new_raw,
+ s16 ambient_old_raw, s16 Gb)
+{
+ s64 VR_IR, kGb, tmp;
+
+ kGb = ((s64)Gb * 1000LL) >> 10ULL;
+ VR_IR = (s64)ambient_old_raw * 1000000LL +
+ kGb * (div64_s64((s64)ambient_new_raw * 1000LL,
+ MLX90635_PTAT_DIV));
+ tmp = div64_s64(
+ div64_s64((s64)(object_raw * 1000000LL),
+ MLX90635_IR_DIV) * 1000000LL,
+ VR_IR);
+ return div64_s64((tmp << 19ULL), 1000LL);
+}
+
+static s32 mlx90635_calc_temp_ambient(s16 ambient_new_raw, s16 ambient_old_raw,
+ u16 P_G, u16 P_O, s16 Gb)
+{
+ s64 kPG, kPO, AMB;
+
+ AMB = mlx90635_preprocess_temp_amb(ambient_new_raw, ambient_old_raw,
+ Gb);
+ kPG = ((s64)P_G * 1000000LL) >> 9ULL;
+ kPO = AMB - (((s64)P_O * 1000LL) >> 1ULL);
+
+ return 30 * 1000LL + div64_s64(kPO * 1000000LL, kPG);
+}
+
+static s32 mlx90635_calc_temp_object_iteration(s32 prev_object_temp, s64 object,
+ s64 TAdut, s64 TAdut4, s16 Ga,
+ u32 Fa, u16 Fa_scale, s16 Fb,
+ s16 Ha, s16 Hb, u16 emissivity)
+{
+ s64 calcedGa, calcedGb, calcedFa, Alpha_corr;
+ s64 Ha_customer, Hb_customer;
+
+ Ha_customer = ((s64)Ha * 1000000LL) >> 14ULL;
+ Hb_customer = ((s64)Hb * 100) >> 10ULL;
+
+ calcedGa = ((s64)((s64)Ga * (prev_object_temp - 35 * 1000LL)
+ * 1000LL)) >> 24LL;
+ calcedGb = ((s64)(Fb * (TAdut - 30 * 1000000LL))) >> 24LL;
+
+ Alpha_corr = ((s64)((s64)Fa * Ha_customer * 10000LL) >> Fa_scale);
+ Alpha_corr *= ((s64)(1 * 1000000LL + calcedGa + calcedGb));
+
+ Alpha_corr = div64_s64(Alpha_corr, 1000LL);
+ Alpha_corr *= emissivity;
+ Alpha_corr = div64_s64(Alpha_corr, 100LL);
+ calcedFa = div64_s64((s64)object * 100000000000LL, Alpha_corr);
+
+ return (int_sqrt64(int_sqrt64(calcedFa * 100000000LL + TAdut4))
+ - 27315 - Hb_customer) * 10;
+}
+
+static s64 mlx90635_calc_ta4(s64 TAdut, s64 scale)
+{
+ return (div64_s64(TAdut, scale) + 27315) *
+ (div64_s64(TAdut, scale) + 27315) *
+ (div64_s64(TAdut, scale) + 27315) *
+ (div64_s64(TAdut, scale) + 27315);
+}
+
+static s32 mlx90635_calc_temp_object(s64 object, s64 ambient, u32 Ea, u32 Eb,
+ s16 Ga, u32 Fa, u16 Fa_scale, s16 Fb, s16 Ha, s16 Hb,
+ u16 tmp_emi)
+{
+ s64 kTA, kTA0, TAdut, TAdut4;
+ s64 temp = 35000;
+ s8 i;
+
+ kTA = (Ea * 1000LL) >> 16LL;
+ kTA0 = (Eb * 1000LL) >> 8LL;
+ TAdut = div64_s64(((ambient - kTA0) * 1000000LL), kTA) + 30 * 1000000LL;
+ TAdut4 = mlx90635_calc_ta4(TAdut, 10000LL);
+
+ /* Iterations of calculation as described in datasheet */
+ for (i = 0; i < 5; ++i) {
+ temp = mlx90635_calc_temp_object_iteration(temp, object, TAdut, TAdut4,
+ Ga, Fa, Fa_scale, Fb, Ha, Hb,
+ tmp_emi);
+ }
+ return temp;
+}
+
+static int mlx90635_calc_object(struct mlx90635_data *data, int *val)
+{
+ s16 ambient_new_raw, ambient_old_raw, object_raw;
+ s16 Fb, Ga, Gb, Ha, Hb;
+ s64 object, ambient;
+ u32 Ea, Eb, Fa;
+ u16 Fa_scale;
+ int ret;
+
+ ret = mlx90635_read_ee_object(data->regmap_ee, &Ea, &Eb, &Fa, &Fb, &Ga, &Gb, &Ha, &Hb, &Fa_scale);
+ if (ret < 0)
+ return ret;
+
+ ret = mlx90635_read_all_channel(data,
+ &ambient_new_raw, &ambient_old_raw,
+ &object_raw);
+ if (ret < 0)
+ return ret;
+
+ ambient = mlx90635_preprocess_temp_amb(ambient_new_raw,
+ ambient_old_raw, Gb);
+ object = mlx90635_preprocess_temp_obj(object_raw,
+ ambient_new_raw,
+ ambient_old_raw, Gb);
+
+ *val = mlx90635_calc_temp_object(object, ambient, Ea, Eb, Ga, Fa, Fa_scale, Fb,
+ Ha, Hb, data->emissivity);
+ return 0;
+}
+
+static int mlx90635_calc_ambient(struct mlx90635_data *data, int *val)
+{
+ s16 ambient_new_raw, ambient_old_raw;
+ s16 PG, PO, Gb;
+ int ret;
+
+ ret = mlx90635_read_ee_ambient(data->regmap_ee, &PG, &PO, &Gb);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&data->lock);
+ if (data->powerstatus == MLX90635_PWR_STATUS_SLEEP_STEP) {
+ ret = mlx90635_perform_measurement_burst(data);
+ if (ret < 0)
+ goto read_ambient_unlock;
+ }
+
+ ret = mlx90635_read_ambient_raw(data->regmap, &ambient_new_raw,
+ &ambient_old_raw);
+read_ambient_unlock:
+ mutex_unlock(&data->lock);
+ if (ret < 0)
+ return ret;
+
+ *val = mlx90635_calc_temp_ambient(ambient_new_raw, ambient_old_raw,
+ PG, PO, Gb);
+ return ret;
+}
+
+static int mlx90635_get_refresh_rate(struct mlx90635_data *data,
+ unsigned int *refresh_rate)
+{
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(data->regmap, MLX90635_REG_CTRL1, &reg);
+ if (ret < 0)
+ return ret;
+
+ *refresh_rate = FIELD_GET(MLX90635_CTRL1_REFRESH_RATE_MASK, reg);
+
+ return 0;
+}
+
+static const struct {
+ int val;
+ int val2;
+} mlx90635_freqs[] = {
+ { 0, 200000 },
+ { 0, 500000 },
+ { 0, 900000 },
+ { 1, 700000 },
+ { 3, 0 },
+ { 4, 800000 },
+ { 6, 900000 },
+ { 8, 900000 }
+};
+
+/**
+ * mlx90635_pm_interaction_wakeup() - Measure time between user interactions to change powermode
+ * @data: pointer to mlx90635_data object containing interaction_ts information
+ *
+ * Switch to continuous mode when interaction is faster than MLX90635_MEAS_MAX_TIME. Update the
+ * interaction_ts for each function call with the jiffies to enable measurement between function
+ * calls. Initial value of the interaction_ts needs to be set before this function call.
+ */
+static int mlx90635_pm_interaction_wakeup(struct mlx90635_data *data)
+{
+ unsigned long now;
+ int ret;
+
+ now = jiffies;
+ if (time_in_range(now, data->interaction_ts,
+ data->interaction_ts +
+ msecs_to_jiffies(MLX90635_MEAS_MAX_TIME + 100))) {
+ ret = mlx90635_pwr_continuous(data);
+ if (ret < 0)
+ return ret;
+ }
+
+ data->interaction_ts = now;
+
+ return 0;
+}
+
+static int mlx90635_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ struct mlx90635_data *data = iio_priv(indio_dev);
+ int ret;
+ int cr;
+
+ pm_runtime_get_sync(&data->client->dev);
+ ret = mlx90635_pm_interaction_wakeup(data);
+ if (ret < 0)
+ goto mlx90635_read_raw_pm;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (channel->channel2) {
+ case IIO_MOD_TEMP_AMBIENT:
+ ret = mlx90635_calc_ambient(data, val);
+ if (ret < 0)
+ goto mlx90635_read_raw_pm;
+
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_MOD_TEMP_OBJECT:
+ ret = mlx90635_calc_object(data, val);
+ if (ret < 0)
+ goto mlx90635_read_raw_pm;
+
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ case IIO_CHAN_INFO_CALIBEMISSIVITY:
+ if (data->emissivity == 1000) {
+ *val = 1;
+ *val2 = 0;
+ } else {
+ *val = 0;
+ *val2 = data->emissivity * 1000;
+ }
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = mlx90635_get_refresh_rate(data, &cr);
+ if (ret < 0)
+ goto mlx90635_read_raw_pm;
+
+ *val = mlx90635_freqs[cr].val;
+ *val2 = mlx90635_freqs[cr].val2;
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+mlx90635_read_raw_pm:
+ pm_runtime_mark_last_busy(&data->client->dev);
+ pm_runtime_put_autosuspend(&data->client->dev);
+ return ret;
+}
+
+static int mlx90635_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int val,
+ int val2, long mask)
+{
+ struct mlx90635_data *data = iio_priv(indio_dev);
+ int ret;
+ int i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_CALIBEMISSIVITY:
+ /* Confirm we are within 0 and 1.0 */
+ if (val < 0 || val2 < 0 || val > 1 ||
+ (val == 1 && val2 != 0))
+ return -EINVAL;
+ data->emissivity = val * 1000 + val2 / 1000;
+ return 0;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ for (i = 0; i < ARRAY_SIZE(mlx90635_freqs); i++) {
+ if (val == mlx90635_freqs[i].val &&
+ val2 == mlx90635_freqs[i].val2)
+ break;
+ }
+ if (i == ARRAY_SIZE(mlx90635_freqs))
+ return -EINVAL;
+
+ ret = regmap_write_bits(data->regmap, MLX90635_REG_CTRL1,
+ MLX90635_CTRL1_REFRESH_RATE_MASK, i);
+
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mlx90635_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = (int *)mlx90635_freqs;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ *length = 2 * ARRAY_SIZE(mlx90635_freqs);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_chan_spec mlx90635_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .modified = 1,
+ .channel2 = IIO_MOD_TEMP_AMBIENT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ },
+ {
+ .type = IIO_TEMP,
+ .modified = 1,
+ .channel2 = IIO_MOD_TEMP_OBJECT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+ BIT(IIO_CHAN_INFO_CALIBEMISSIVITY),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ },
+};
+
+static const struct iio_info mlx90635_info = {
+ .read_raw = mlx90635_read_raw,
+ .write_raw = mlx90635_write_raw,
+ .read_avail = mlx90635_read_avail,
+};
+
+static void mlx90635_sleep(void *_data)
+{
+ struct mlx90635_data *data = _data;
+
+ mlx90635_pwr_sleep_step(data);
+}
+
+static int mlx90635_suspend(struct mlx90635_data *data)
+{
+ return mlx90635_pwr_sleep_step(data);
+}
+
+static int mlx90635_wakeup(struct mlx90635_data *data)
+{
+ s16 Fb, Ga, Gb, Ha, Hb, PG, PO;
+ unsigned int dsp_version;
+ u32 Ea, Eb, Fa;
+ u16 Fa_scale;
+ int ret;
+
+ regcache_cache_bypass(data->regmap_ee, false);
+ regcache_cache_only(data->regmap_ee, false);
+ regcache_cache_only(data->regmap, false);
+
+ ret = mlx90635_pwr_continuous(data);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Switch to continuous mode failed\n");
+ return ret;
+ }
+ ret = regmap_write_bits(data->regmap, MLX90635_REG_EE,
+ MLX90635_EE_ACTIVE, MLX90635_EE_ACTIVE);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Powering EEPROM failed\n");
+ return ret;
+ }
+ usleep_range(MLX90635_TIMING_EE_ACTIVE_MIN, MLX90635_TIMING_EE_ACTIVE_MAX);
+
+ regcache_mark_dirty(data->regmap_ee);
+
+ ret = regcache_sync(data->regmap_ee);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "Failed to sync cache: %d\n", ret);
+ return ret;
+ }
+
+ ret = mlx90635_read_ee_ambient(data->regmap_ee, &PG, &PO, &Gb);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "Failed to read to cache Ambient coefficients EEPROM region: %d\n", ret);
+ return ret;
+ }
+
+ ret = mlx90635_read_ee_object(data->regmap_ee, &Ea, &Eb, &Fa, &Fb, &Ga, &Gb, &Ha, &Hb, &Fa_scale);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "Failed to read to cache Object coefficients EEPROM region: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(data->regmap_ee, MLX90635_EE_VERSION, &dsp_version);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "Failed to read to cache of EEPROM version: %d\n", ret);
+ return ret;
+ }
+
+ regcache_cache_only(data->regmap_ee, true);
+
+ return ret;
+}
+
+static void mlx90635_disable_regulator(void *_data)
+{
+ struct mlx90635_data *data = _data;
+ int ret;
+
+ ret = regulator_disable(data->regulator);
+ if (ret < 0)
+ dev_err(regmap_get_device(data->regmap),
+ "Failed to disable power regulator: %d\n", ret);
+}
+
+static int mlx90635_enable_regulator(struct mlx90635_data *data)
+{
+ int ret;
+
+ ret = regulator_enable(data->regulator);
+ if (ret < 0) {
+ dev_err(regmap_get_device(data->regmap), "Failed to enable power regulator!\n");
+ return ret;
+ }
+
+ mlx90635_reset_delay();
+
+ return ret;
+}
+
+static int mlx90635_probe(struct i2c_client *client)
+{
+ struct mlx90635_data *mlx90635;
+ struct iio_dev *indio_dev;
+ unsigned int dsp_version;
+ struct regmap *regmap;
+ struct regmap *regmap_ee;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mlx90635));
+ if (!indio_dev)
+ return dev_err_probe(&client->dev, -ENOMEM, "failed to allocate device\n");
+
+ regmap = devm_regmap_init_i2c(client, &mlx90635_regmap);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(regmap),
+ "failed to allocate regmap\n");
+
+ regmap_ee = devm_regmap_init_i2c(client, &mlx90635_regmap_ee);
+ if (IS_ERR(regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(regmap),
+ "failed to allocate regmap\n");
+
+ mlx90635 = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ mlx90635->client = client;
+ mlx90635->regmap = regmap;
+ mlx90635->regmap_ee = regmap_ee;
+ mlx90635->powerstatus = MLX90635_PWR_STATUS_SLEEP_STEP;
+
+ mutex_init(&mlx90635->lock);
+ indio_dev->name = "mlx90635";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &mlx90635_info;
+ indio_dev->channels = mlx90635_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mlx90635_channels);
+
+ mlx90635->regulator = devm_regulator_get(&client->dev, "vdd");
+ if (IS_ERR(mlx90635->regulator))
+ return dev_err_probe(&client->dev, PTR_ERR(mlx90635->regulator),
+ "failed to get vdd regulator");
+
+ ret = mlx90635_enable_regulator(mlx90635);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_add_action_or_reset(&client->dev, mlx90635_disable_regulator,
+ mlx90635);
+ if (ret < 0)
+ return dev_err_probe(&client->dev, ret,
+ "failed to setup regulator cleanup action\n");
+
+ ret = mlx90635_wakeup(mlx90635);
+ if (ret < 0)
+ return dev_err_probe(&client->dev, ret, "wakeup failed\n");
+
+ ret = devm_add_action_or_reset(&client->dev, mlx90635_sleep, mlx90635);
+ if (ret < 0)
+ return dev_err_probe(&client->dev, ret,
+ "failed to setup low power cleanup\n");
+
+ ret = regmap_read(mlx90635->regmap_ee, MLX90635_EE_VERSION, &dsp_version);
+ if (ret < 0)
+ return dev_err_probe(&client->dev, ret, "read of version failed\n");
+
+ dsp_version = dsp_version & MLX90635_VERSION_MASK;
+
+ if (FIELD_GET(MLX90635_DSP_FIXED, dsp_version)) {
+ if (MLX90635_DSP_VERSION(dsp_version) == MLX90635_ID_DSPv1) {
+ dev_dbg(&client->dev,
+ "Detected DSP v1 calibration %x\n", dsp_version);
+ } else {
+ dev_dbg(&client->dev,
+ "Detected Unknown EEPROM calibration %lx\n",
+ MLX90635_DSP_VERSION(dsp_version));
+ }
+ } else {
+ return dev_err_probe(&client->dev, -EPROTONOSUPPORT,
+ "Wrong fixed top bit %x (expected 0x8X0X)\n",
+ dsp_version);
+ }
+
+ mlx90635->emissivity = 1000;
+ mlx90635->interaction_ts = jiffies; /* Set initial value */
+
+ pm_runtime_get_noresume(&client->dev);
+ pm_runtime_set_active(&client->dev);
+
+ ret = devm_pm_runtime_enable(&client->dev);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "failed to enable powermanagement\n");
+
+ pm_runtime_set_autosuspend_delay(&client->dev, MLX90635_SLEEP_DELAY_MS);
+ pm_runtime_use_autosuspend(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id mlx90635_id[] = {
+ { "mlx90635" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mlx90635_id);
+
+static const struct of_device_id mlx90635_of_match[] = {
+ { .compatible = "melexis,mlx90635" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mlx90635_of_match);
+
+static int mlx90635_pm_suspend(struct device *dev)
+{
+ struct mlx90635_data *data = iio_priv(dev_get_drvdata(dev));
+ int ret;
+
+ ret = mlx90635_suspend(data);
+ if (ret < 0)
+ return ret;
+
+ ret = regulator_disable(data->regulator);
+ if (ret < 0)
+ dev_err(regmap_get_device(data->regmap),
+ "Failed to disable power regulator: %d\n", ret);
+
+ return ret;
+}
+
+static int mlx90635_pm_resume(struct device *dev)
+{
+ struct mlx90635_data *data = iio_priv(dev_get_drvdata(dev));
+ int ret;
+
+ ret = mlx90635_enable_regulator(data);
+ if (ret < 0)
+ return ret;
+
+ return mlx90635_wakeup(data);
+}
+
+static int mlx90635_pm_runtime_suspend(struct device *dev)
+{
+ struct mlx90635_data *data = iio_priv(dev_get_drvdata(dev));
+
+ return mlx90635_pwr_sleep_step(data);
+}
+
+static const struct dev_pm_ops mlx90635_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(mlx90635_pm_suspend, mlx90635_pm_resume)
+ RUNTIME_PM_OPS(mlx90635_pm_runtime_suspend, NULL, NULL)
+};
+
+static struct i2c_driver mlx90635_driver = {
+ .driver = {
+ .name = "mlx90635",
+ .of_match_table = mlx90635_of_match,
+ .pm = pm_ptr(&mlx90635_pm_ops),
+ },
+ .probe = mlx90635_probe,
+ .id_table = mlx90635_id,
+};
+module_i2c_driver(mlx90635_driver);
+
+MODULE_AUTHOR("Crt Mori <[email protected]>");
+MODULE_DESCRIPTION("Melexis MLX90635 contactless Infra Red temperature sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h
index 9fd9849ebdd1..9dca451ed522 100644
--- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h
+++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h
@@ -41,6 +41,7 @@
#define __BNXT_RE_H__
#include <rdma/uverbs_ioctl.h>
#include "hw_counters.h"
+#include <linux/hashtable.h>
#define ROCE_DRV_MODULE_NAME "bnxt_re"
#define BNXT_RE_DESC "Broadcom NetXtreme-C/E RoCE Driver"
@@ -135,6 +136,7 @@ struct bnxt_re_pacing {
#define BNXT_RE_DB_FIFO_ROOM_SHIFT 15
#define BNXT_RE_GRC_FIFO_REG_BASE 0x2000
+#define MAX_CQ_HASH_BITS (16)
struct bnxt_re_dev {
struct ib_device ibdev;
struct list_head list;
@@ -189,6 +191,7 @@ struct bnxt_re_dev {
struct bnxt_re_pacing pacing;
struct work_struct dbq_fifo_check_work;
struct delayed_work dbq_pacing_work;
+ DECLARE_HASHTABLE(cq_hash, MAX_CQ_HASH_BITS);
};
#define to_bnxt_re_dev(ptr, member) \
diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.c b/drivers/infiniband/hw/bnxt_re/hw_counters.c
index 93572405d6fa..128651c01595 100644
--- a/drivers/infiniband/hw/bnxt_re/hw_counters.c
+++ b/drivers/infiniband/hw/bnxt_re/hw_counters.c
@@ -371,7 +371,7 @@ int bnxt_re_ib_get_hw_stats(struct ib_device *ibdev,
}
done:
- return bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ?
+ return bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx) ?
BNXT_RE_NUM_EXT_COUNTERS : BNXT_RE_NUM_STD_COUNTERS;
}
@@ -381,7 +381,7 @@ struct rdma_hw_stats *bnxt_re_ib_alloc_hw_port_stats(struct ib_device *ibdev,
struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev);
int num_counters = 0;
- if (bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx))
+ if (bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))
num_counters = BNXT_RE_NUM_EXT_COUNTERS;
else
num_counters = BNXT_RE_NUM_STD_COUNTERS;
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index faa88d12ee86..824349659d69 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -50,6 +50,7 @@
#include <rdma/ib_mad.h>
#include <rdma/ib_cache.h>
#include <rdma/uverbs_ioctl.h>
+#include <linux/hashtable.h>
#include "bnxt_ulp.h"
@@ -567,6 +568,7 @@ bnxt_re_mmap_entry_insert(struct bnxt_re_ucontext *uctx, u64 mem_offset,
case BNXT_RE_MMAP_WC_DB:
case BNXT_RE_MMAP_DBR_BAR:
case BNXT_RE_MMAP_DBR_PAGE:
+ case BNXT_RE_MMAP_TOGGLE_PAGE:
ret = rdma_user_mmap_entry_insert(&uctx->ib_uctx,
&entry->rdma_entry, PAGE_SIZE);
break;
@@ -1023,7 +1025,7 @@ static int bnxt_re_init_user_qp(struct bnxt_re_dev *rdev, struct bnxt_re_pd *pd,
bytes = (qplib_qp->sq.max_wqe * qplib_qp->sq.wqe_size);
/* Consider mapping PSN search memory only for RC QPs. */
if (qplib_qp->type == CMDQ_CREATE_QP_TYPE_RC) {
- psn_sz = bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ?
+ psn_sz = bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx) ?
sizeof(struct sq_psn_search_ext) :
sizeof(struct sq_psn_search);
psn_nume = (qplib_qp->wqe_mode == BNXT_QPLIB_WQE_MODE_STATIC) ?
@@ -1184,7 +1186,8 @@ fail:
}
static int bnxt_re_init_rq_attr(struct bnxt_re_qp *qp,
- struct ib_qp_init_attr *init_attr)
+ struct ib_qp_init_attr *init_attr,
+ struct bnxt_re_ucontext *uctx)
{
struct bnxt_qplib_dev_attr *dev_attr;
struct bnxt_qplib_qp *qplqp;
@@ -1213,7 +1216,7 @@ static int bnxt_re_init_rq_attr(struct bnxt_re_qp *qp,
/* Allocate 1 more than what's provided so posting max doesn't
* mean empty.
*/
- entries = roundup_pow_of_two(init_attr->cap.max_recv_wr + 1);
+ entries = bnxt_re_init_depth(init_attr->cap.max_recv_wr + 1, uctx);
rq->max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + 1);
rq->q_full_delta = 0;
rq->sg_info.pgsize = PAGE_SIZE;
@@ -1233,7 +1236,7 @@ static void bnxt_re_adjust_gsi_rq_attr(struct bnxt_re_qp *qp)
qplqp = &qp->qplib_qp;
dev_attr = &rdev->dev_attr;
- if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) {
+ if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) {
qplqp->rq.max_sge = dev_attr->max_qp_sges;
if (qplqp->rq.max_sge > dev_attr->max_qp_sges)
qplqp->rq.max_sge = dev_attr->max_qp_sges;
@@ -1243,7 +1246,7 @@ static void bnxt_re_adjust_gsi_rq_attr(struct bnxt_re_qp *qp)
static int bnxt_re_init_sq_attr(struct bnxt_re_qp *qp,
struct ib_qp_init_attr *init_attr,
- struct ib_udata *udata)
+ struct bnxt_re_ucontext *uctx)
{
struct bnxt_qplib_dev_attr *dev_attr;
struct bnxt_qplib_qp *qplqp;
@@ -1272,7 +1275,7 @@ static int bnxt_re_init_sq_attr(struct bnxt_re_qp *qp,
/* Allocate 128 + 1 more than what's provided */
diff = (qplqp->wqe_mode == BNXT_QPLIB_WQE_MODE_VARIABLE) ?
0 : BNXT_QPLIB_RESERVED_QP_WRS;
- entries = roundup_pow_of_two(entries + diff + 1);
+ entries = bnxt_re_init_depth(entries + diff + 1, uctx);
sq->max_wqe = min_t(u32, entries, dev_attr->max_qp_wqes + diff + 1);
sq->q_full_delta = diff + 1;
/*
@@ -1288,7 +1291,8 @@ static int bnxt_re_init_sq_attr(struct bnxt_re_qp *qp,
}
static void bnxt_re_adjust_gsi_sq_attr(struct bnxt_re_qp *qp,
- struct ib_qp_init_attr *init_attr)
+ struct ib_qp_init_attr *init_attr,
+ struct bnxt_re_ucontext *uctx)
{
struct bnxt_qplib_dev_attr *dev_attr;
struct bnxt_qplib_qp *qplqp;
@@ -1299,8 +1303,8 @@ static void bnxt_re_adjust_gsi_sq_attr(struct bnxt_re_qp *qp,
qplqp = &qp->qplib_qp;
dev_attr = &rdev->dev_attr;
- if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) {
- entries = roundup_pow_of_two(init_attr->cap.max_send_wr + 1);
+ if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) {
+ entries = bnxt_re_init_depth(init_attr->cap.max_send_wr + 1, uctx);
qplqp->sq.max_wqe = min_t(u32, entries,
dev_attr->max_qp_wqes + 1);
qplqp->sq.q_full_delta = qplqp->sq.max_wqe -
@@ -1326,7 +1330,7 @@ static int bnxt_re_init_qp_type(struct bnxt_re_dev *rdev,
goto out;
}
- if (bnxt_qplib_is_chip_gen_p5(chip_ctx) &&
+ if (bnxt_qplib_is_chip_gen_p5_p7(chip_ctx) &&
init_attr->qp_type == IB_QPT_GSI)
qptype = CMDQ_CREATE_QP_TYPE_GSI;
out:
@@ -1338,6 +1342,7 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd,
struct ib_udata *udata)
{
struct bnxt_qplib_dev_attr *dev_attr;
+ struct bnxt_re_ucontext *uctx;
struct bnxt_qplib_qp *qplqp;
struct bnxt_re_dev *rdev;
struct bnxt_re_cq *cq;
@@ -1347,6 +1352,7 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd,
qplqp = &qp->qplib_qp;
dev_attr = &rdev->dev_attr;
+ uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx);
/* Setup misc params */
ether_addr_copy(qplqp->smac, rdev->netdev->dev_addr);
qplqp->pd = &pd->qplib_pd;
@@ -1388,18 +1394,18 @@ static int bnxt_re_init_qp_attr(struct bnxt_re_qp *qp, struct bnxt_re_pd *pd,
}
/* Setup RQ/SRQ */
- rc = bnxt_re_init_rq_attr(qp, init_attr);
+ rc = bnxt_re_init_rq_attr(qp, init_attr, uctx);
if (rc)
goto out;
if (init_attr->qp_type == IB_QPT_GSI)
bnxt_re_adjust_gsi_rq_attr(qp);
/* Setup SQ */
- rc = bnxt_re_init_sq_attr(qp, init_attr, udata);
+ rc = bnxt_re_init_sq_attr(qp, init_attr, uctx);
if (rc)
goto out;
if (init_attr->qp_type == IB_QPT_GSI)
- bnxt_re_adjust_gsi_sq_attr(qp, init_attr);
+ bnxt_re_adjust_gsi_sq_attr(qp, init_attr, uctx);
if (udata) /* This will update DPI and qp_handle */
rc = bnxt_re_init_user_qp(rdev, pd, qp, udata);
@@ -1523,7 +1529,7 @@ int bnxt_re_create_qp(struct ib_qp *ib_qp, struct ib_qp_init_attr *qp_init_attr,
goto fail;
if (qp_init_attr->qp_type == IB_QPT_GSI &&
- !(bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx))) {
+ !(bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))) {
rc = bnxt_re_create_gsi_qp(qp, pd, qp_init_attr);
if (rc == -ENODEV)
goto qp_destroy;
@@ -1715,6 +1721,7 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq,
{
struct bnxt_qplib_dev_attr *dev_attr;
struct bnxt_qplib_nq *nq = NULL;
+ struct bnxt_re_ucontext *uctx;
struct bnxt_re_dev *rdev;
struct bnxt_re_srq *srq;
struct bnxt_re_pd *pd;
@@ -1739,13 +1746,14 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq,
goto exit;
}
+ uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx);
srq->rdev = rdev;
srq->qplib_srq.pd = &pd->qplib_pd;
srq->qplib_srq.dpi = &rdev->dpi_privileged;
/* Allocate 1 more than what's provided so posting max doesn't
* mean empty
*/
- entries = roundup_pow_of_two(srq_init_attr->attr.max_wr + 1);
+ entries = bnxt_re_init_depth(srq_init_attr->attr.max_wr + 1, uctx);
if (entries > dev_attr->max_srq_wqes + 1)
entries = dev_attr->max_srq_wqes + 1;
srq->qplib_srq.max_wqe = entries;
@@ -2103,6 +2111,9 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
qp->qplib_qp.max_dest_rd_atomic = qp_attr->max_dest_rd_atomic;
}
if (qp_attr_mask & IB_QP_CAP) {
+ struct bnxt_re_ucontext *uctx =
+ rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx);
+
qp->qplib_qp.modify_flags |=
CMDQ_MODIFY_QP_MODIFY_MASK_SQ_SIZE |
CMDQ_MODIFY_QP_MODIFY_MASK_RQ_SIZE |
@@ -2119,7 +2130,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
"Create QP failed - max exceeded");
return -EINVAL;
}
- entries = roundup_pow_of_two(qp_attr->cap.max_send_wr);
+ entries = bnxt_re_init_depth(qp_attr->cap.max_send_wr, uctx);
qp->qplib_qp.sq.max_wqe = min_t(u32, entries,
dev_attr->max_qp_wqes + 1);
qp->qplib_qp.sq.q_full_delta = qp->qplib_qp.sq.max_wqe -
@@ -2132,7 +2143,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
qp->qplib_qp.sq.q_full_delta -= 1;
qp->qplib_qp.sq.max_sge = qp_attr->cap.max_send_sge;
if (qp->qplib_qp.rq.max_wqe) {
- entries = roundup_pow_of_two(qp_attr->cap.max_recv_wr);
+ entries = bnxt_re_init_depth(qp_attr->cap.max_recv_wr, uctx);
qp->qplib_qp.rq.max_wqe =
min_t(u32, entries, dev_attr->max_qp_wqes + 1);
qp->qplib_qp.rq.q_full_delta = qp->qplib_qp.rq.max_wqe -
@@ -2900,14 +2911,20 @@ int bnxt_re_post_recv(struct ib_qp *ib_qp, const struct ib_recv_wr *wr,
/* Completion Queues */
int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
{
- struct bnxt_re_cq *cq;
+ struct bnxt_qplib_chip_ctx *cctx;
struct bnxt_qplib_nq *nq;
struct bnxt_re_dev *rdev;
+ struct bnxt_re_cq *cq;
cq = container_of(ib_cq, struct bnxt_re_cq, ib_cq);
rdev = cq->rdev;
nq = cq->qplib_cq.nq;
+ cctx = rdev->chip_ctx;
+ if (cctx->modes.toggle_bits & BNXT_QPLIB_CQ_TOGGLE_BIT) {
+ free_page((unsigned long)cq->uctx_cq_page);
+ hash_del(&cq->hash_entry);
+ }
bnxt_qplib_destroy_cq(&rdev->qplib_res, &cq->qplib_cq);
ib_umem_release(cq->umem);
@@ -2920,13 +2937,16 @@ int bnxt_re_destroy_cq(struct ib_cq *ib_cq, struct ib_udata *udata)
int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
struct ib_udata *udata)
{
+ struct bnxt_re_cq *cq = container_of(ibcq, struct bnxt_re_cq, ib_cq);
struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibcq->device, ibdev);
+ struct bnxt_re_ucontext *uctx =
+ rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx);
struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr;
- struct bnxt_re_cq *cq = container_of(ibcq, struct bnxt_re_cq, ib_cq);
- int rc, entries;
- int cqe = attr->cqe;
+ struct bnxt_qplib_chip_ctx *cctx;
struct bnxt_qplib_nq *nq = NULL;
unsigned int nq_alloc_cnt;
+ int cqe = attr->cqe;
+ int rc, entries;
u32 active_cqs;
if (attr->flags)
@@ -2939,9 +2959,10 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
}
cq->rdev = rdev;
+ cctx = rdev->chip_ctx;
cq->qplib_cq.cq_handle = (u64)(unsigned long)(&cq->qplib_cq);
- entries = roundup_pow_of_two(cqe + 1);
+ entries = bnxt_re_init_depth(cqe + 1, uctx);
if (entries > dev_attr->max_cq_wqes + 1)
entries = dev_attr->max_cq_wqes + 1;
@@ -2949,8 +2970,6 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
cq->qplib_cq.sg_info.pgshft = PAGE_SHIFT;
if (udata) {
struct bnxt_re_cq_req req;
- struct bnxt_re_ucontext *uctx = rdma_udata_to_drv_context(
- udata, struct bnxt_re_ucontext, ib_uctx);
if (ib_copy_from_udata(&req, udata, sizeof(req))) {
rc = -EFAULT;
goto fail;
@@ -3002,22 +3021,34 @@ int bnxt_re_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
spin_lock_init(&cq->cq_lock);
if (udata) {
- struct bnxt_re_cq_resp resp;
+ struct bnxt_re_cq_resp resp = {};
+ if (cctx->modes.toggle_bits & BNXT_QPLIB_CQ_TOGGLE_BIT) {
+ hash_add(rdev->cq_hash, &cq->hash_entry, cq->qplib_cq.id);
+ /* Allocate a page */
+ cq->uctx_cq_page = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!cq->uctx_cq_page) {
+ rc = -ENOMEM;
+ goto c2fail;
+ }
+ resp.comp_mask |= BNXT_RE_CQ_TOGGLE_PAGE_SUPPORT;
+ }
resp.cqid = cq->qplib_cq.id;
resp.tail = cq->qplib_cq.hwq.cons;
resp.phase = cq->qplib_cq.period;
resp.rsvd = 0;
- rc = ib_copy_to_udata(udata, &resp, sizeof(resp));
+ rc = ib_copy_to_udata(udata, &resp, min(sizeof(resp), udata->outlen));
if (rc) {
ibdev_err(&rdev->ibdev, "Failed to copy CQ udata");
bnxt_qplib_destroy_cq(&rdev->qplib_res, &cq->qplib_cq);
- goto c2fail;
+ goto free_mem;
}
}
return 0;
+free_mem:
+ free_page((unsigned long)cq->uctx_cq_page);
c2fail:
ib_umem_release(cq->umem);
fail:
@@ -3072,12 +3103,11 @@ int bnxt_re_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
return -EINVAL;
}
- entries = roundup_pow_of_two(cqe + 1);
+ uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext, ib_uctx);
+ entries = bnxt_re_init_depth(cqe + 1, uctx);
if (entries > dev_attr->max_cq_wqes + 1)
entries = dev_attr->max_cq_wqes + 1;
- uctx = rdma_udata_to_drv_context(udata, struct bnxt_re_ucontext,
- ib_uctx);
/* uverbs consumer */
if (ib_copy_from_udata(&req, udata, sizeof(req))) {
rc = -EFAULT;
@@ -4108,6 +4138,7 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata)
struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr;
struct bnxt_re_user_mmap_entry *entry;
struct bnxt_re_uctx_resp resp = {};
+ struct bnxt_re_uctx_req ureq = {};
u32 chip_met_rev_num = 0;
int rc;
@@ -4157,6 +4188,16 @@ int bnxt_re_alloc_ucontext(struct ib_ucontext *ctx, struct ib_udata *udata)
if (rdev->pacing.dbr_pacing)
resp.comp_mask |= BNXT_RE_UCNTX_CMASK_DBR_PACING_ENABLED;
+ if (udata->inlen >= sizeof(ureq)) {
+ rc = ib_copy_from_udata(&ureq, udata, min(udata->inlen, sizeof(ureq)));
+ if (rc)
+ goto cfail;
+ if (ureq.comp_mask & BNXT_RE_COMP_MASK_REQ_UCNTX_POW2_SUPPORT) {
+ resp.comp_mask |= BNXT_RE_UCNTX_CMASK_POW2_DISABLED;
+ uctx->cmask |= BNXT_RE_UCNTX_CMASK_POW2_DISABLED;
+ }
+ }
+
rc = ib_copy_to_udata(udata, &resp, min(udata->outlen, sizeof(resp)));
if (rc) {
ibdev_err(ibdev, "Failed to copy user context");
@@ -4194,6 +4235,19 @@ void bnxt_re_dealloc_ucontext(struct ib_ucontext *ib_uctx)
}
}
+static struct bnxt_re_cq *bnxt_re_search_for_cq(struct bnxt_re_dev *rdev, u32 cq_id)
+{
+ struct bnxt_re_cq *cq = NULL, *tmp_cq;
+
+ hash_for_each_possible(rdev->cq_hash, tmp_cq, hash_entry, cq_id) {
+ if (tmp_cq->qplib_cq.id == cq_id) {
+ cq = tmp_cq;
+ break;
+ }
+ }
+ return cq;
+}
+
/* Helper function to mmap the virtual memory from user app */
int bnxt_re_mmap(struct ib_ucontext *ib_uctx, struct vm_area_struct *vma)
{
@@ -4235,6 +4289,7 @@ int bnxt_re_mmap(struct ib_ucontext *ib_uctx, struct vm_area_struct *vma)
rdma_entry);
break;
case BNXT_RE_MMAP_DBR_PAGE:
+ case BNXT_RE_MMAP_TOGGLE_PAGE:
/* Driver doesn't expect write access for user space */
if (vma->vm_flags & VM_WRITE)
return -EFAULT;
@@ -4411,8 +4466,126 @@ DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_NOTIFY_DRV);
DECLARE_UVERBS_GLOBAL_METHODS(BNXT_RE_OBJECT_NOTIFY_DRV,
&UVERBS_METHOD(BNXT_RE_METHOD_NOTIFY_DRV));
+/* Toggle MEM */
+static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bundle *attrs)
+{
+ struct ib_uobject *uobj = uverbs_attr_get_uobject(attrs, BNXT_RE_TOGGLE_MEM_HANDLE);
+ enum bnxt_re_mmap_flag mmap_flag = BNXT_RE_MMAP_TOGGLE_PAGE;
+ enum bnxt_re_get_toggle_mem_type res_type;
+ struct bnxt_re_user_mmap_entry *entry;
+ struct bnxt_re_ucontext *uctx;
+ struct ib_ucontext *ib_uctx;
+ struct bnxt_re_dev *rdev;
+ struct bnxt_re_cq *cq;
+ u64 mem_offset;
+ u64 addr = 0;
+ u32 length;
+ u32 offset;
+ u32 cq_id;
+ int err;
+
+ ib_uctx = ib_uverbs_get_ucontext(attrs);
+ if (IS_ERR(ib_uctx))
+ return PTR_ERR(ib_uctx);
+
+ err = uverbs_get_const(&res_type, attrs, BNXT_RE_TOGGLE_MEM_TYPE);
+ if (err)
+ return err;
+
+ uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx);
+ rdev = uctx->rdev;
+
+ switch (res_type) {
+ case BNXT_RE_CQ_TOGGLE_MEM:
+ err = uverbs_copy_from(&cq_id, attrs, BNXT_RE_TOGGLE_MEM_RES_ID);
+ if (err)
+ return err;
+
+ cq = bnxt_re_search_for_cq(rdev, cq_id);
+ if (!cq)
+ return -EINVAL;
+
+ length = PAGE_SIZE;
+ addr = (u64)cq->uctx_cq_page;
+ mmap_flag = BNXT_RE_MMAP_TOGGLE_PAGE;
+ offset = 0;
+ break;
+ case BNXT_RE_SRQ_TOGGLE_MEM:
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ entry = bnxt_re_mmap_entry_insert(uctx, addr, mmap_flag, &mem_offset);
+ if (!entry)
+ return -ENOMEM;
+
+ uobj->object = entry;
+ uverbs_finalize_uobj_create(attrs, BNXT_RE_TOGGLE_MEM_HANDLE);
+ err = uverbs_copy_to(attrs, BNXT_RE_TOGGLE_MEM_MMAP_PAGE,
+ &mem_offset, sizeof(mem_offset));
+ if (err)
+ return err;
+
+ err = uverbs_copy_to(attrs, BNXT_RE_TOGGLE_MEM_MMAP_LENGTH,
+ &length, sizeof(length));
+ if (err)
+ return err;
+
+ err = uverbs_copy_to(attrs, BNXT_RE_TOGGLE_MEM_MMAP_OFFSET,
+ &offset, sizeof(length));
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int get_toggle_mem_obj_cleanup(struct ib_uobject *uobject,
+ enum rdma_remove_reason why,
+ struct uverbs_attr_bundle *attrs)
+{
+ struct bnxt_re_user_mmap_entry *entry = uobject->object;
+
+ rdma_user_mmap_entry_remove(&entry->rdma_entry);
+ return 0;
+}
+
+DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_GET_TOGGLE_MEM,
+ UVERBS_ATTR_IDR(BNXT_RE_TOGGLE_MEM_HANDLE,
+ BNXT_RE_OBJECT_GET_TOGGLE_MEM,
+ UVERBS_ACCESS_NEW,
+ UA_MANDATORY),
+ UVERBS_ATTR_CONST_IN(BNXT_RE_TOGGLE_MEM_TYPE,
+ enum bnxt_re_get_toggle_mem_type,
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_IN(BNXT_RE_TOGGLE_MEM_RES_ID,
+ UVERBS_ATTR_TYPE(u32),
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_OUT(BNXT_RE_TOGGLE_MEM_MMAP_PAGE,
+ UVERBS_ATTR_TYPE(u64),
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_OUT(BNXT_RE_TOGGLE_MEM_MMAP_OFFSET,
+ UVERBS_ATTR_TYPE(u32),
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_OUT(BNXT_RE_TOGGLE_MEM_MMAP_LENGTH,
+ UVERBS_ATTR_TYPE(u32),
+ UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_METHOD_DESTROY(BNXT_RE_METHOD_RELEASE_TOGGLE_MEM,
+ UVERBS_ATTR_IDR(BNXT_RE_RELEASE_TOGGLE_MEM_HANDLE,
+ BNXT_RE_OBJECT_GET_TOGGLE_MEM,
+ UVERBS_ACCESS_DESTROY,
+ UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_OBJECT(BNXT_RE_OBJECT_GET_TOGGLE_MEM,
+ UVERBS_TYPE_ALLOC_IDR(get_toggle_mem_obj_cleanup),
+ &UVERBS_METHOD(BNXT_RE_METHOD_GET_TOGGLE_MEM),
+ &UVERBS_METHOD(BNXT_RE_METHOD_RELEASE_TOGGLE_MEM));
+
const struct uapi_definition bnxt_re_uapi_defs[] = {
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_ALLOC_PAGE),
UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_NOTIFY_DRV),
+ UAPI_DEF_CHAIN_OBJ_TREE_NAMED(BNXT_RE_OBJECT_GET_TOGGLE_MEM),
{}
};
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h
index 84715b7e7a4e..b267d6d5975f 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h
@@ -108,6 +108,8 @@ struct bnxt_re_cq {
struct ib_umem *umem;
struct ib_umem *resize_umem;
int resize_cqe;
+ void *uctx_cq_page;
+ struct hlist_node hash_entry;
};
struct bnxt_re_mr {
@@ -140,6 +142,7 @@ struct bnxt_re_ucontext {
void *shpg;
spinlock_t sh_lock; /* protect shpg */
struct rdma_user_mmap_entry *shpage_mmap;
+ u64 cmask;
};
enum bnxt_re_mmap_flag {
@@ -148,6 +151,7 @@ enum bnxt_re_mmap_flag {
BNXT_RE_MMAP_WC_DB,
BNXT_RE_MMAP_DBR_PAGE,
BNXT_RE_MMAP_DBR_BAR,
+ BNXT_RE_MMAP_TOGGLE_PAGE,
};
struct bnxt_re_user_mmap_entry {
@@ -167,6 +171,12 @@ static inline u16 bnxt_re_get_rwqe_size(int nsge)
return sizeof(struct rq_wqe_hdr) + (nsge * sizeof(struct sq_sge));
}
+static inline u32 bnxt_re_init_depth(u32 ent, struct bnxt_re_ucontext *uctx)
+{
+ return uctx ? (uctx->cmask & BNXT_RE_UCNTX_CMASK_POW2_DISABLED) ?
+ ent : roundup_pow_of_two(ent) : ent;
+}
+
int bnxt_re_query_device(struct ib_device *ibdev,
struct ib_device_attr *ib_attr,
struct ib_udata *udata);
diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c
index a99c68247af0..f022c922fae5 100644
--- a/drivers/infiniband/hw/bnxt_re/main.c
+++ b/drivers/infiniband/hw/bnxt_re/main.c
@@ -54,6 +54,7 @@
#include <rdma/ib_user_verbs.h>
#include <rdma/ib_umem.h>
#include <rdma/ib_addr.h>
+#include <linux/hashtable.h>
#include "bnxt_ulp.h"
#include "roce_hsi.h"
@@ -107,9 +108,14 @@ static void bnxt_re_set_db_offset(struct bnxt_re_dev *rdev)
dev_info(rdev_to_dev(rdev),
"Couldn't get DB bar size, Low latency framework is disabled\n");
/* set register offsets for both UC and WC */
- res->dpi_tbl.ucreg.offset = res->is_vf ? BNXT_QPLIB_DBR_VF_DB_OFFSET :
- BNXT_QPLIB_DBR_PF_DB_OFFSET;
- res->dpi_tbl.wcreg.offset = res->dpi_tbl.ucreg.offset;
+ if (bnxt_qplib_is_chip_gen_p7(cctx)) {
+ res->dpi_tbl.ucreg.offset = offset;
+ res->dpi_tbl.wcreg.offset = en_dev->l2_db_size;
+ } else {
+ res->dpi_tbl.ucreg.offset = res->is_vf ? BNXT_QPLIB_DBR_VF_DB_OFFSET :
+ BNXT_QPLIB_DBR_PF_DB_OFFSET;
+ res->dpi_tbl.wcreg.offset = res->dpi_tbl.ucreg.offset;
+ }
/* If WC mapping is disabled by L2 driver then en_dev->l2_db_size
* is equal to the DB-Bar actual size. This indicates that L2
@@ -128,11 +134,13 @@ static void bnxt_re_set_drv_mode(struct bnxt_re_dev *rdev, u8 mode)
struct bnxt_qplib_chip_ctx *cctx;
cctx = rdev->chip_ctx;
- cctx->modes.wqe_mode = bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ?
+ cctx->modes.wqe_mode = bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx) ?
mode : BNXT_QPLIB_WQE_MODE_STATIC;
if (bnxt_re_hwrm_qcaps(rdev))
dev_err(rdev_to_dev(rdev),
"Failed to query hwrm qcaps\n");
+ if (bnxt_qplib_is_chip_gen_p7(rdev->chip_ctx))
+ cctx->modes.toggle_bits |= BNXT_QPLIB_CQ_TOGGLE_BIT;
}
static void bnxt_re_destroy_chip_ctx(struct bnxt_re_dev *rdev)
@@ -215,7 +223,7 @@ static void bnxt_re_limit_pf_res(struct bnxt_re_dev *rdev)
ctx->srqc_count = min_t(u32, BNXT_RE_MAX_SRQC_COUNT,
attr->max_srq);
ctx->cq_count = min_t(u32, BNXT_RE_MAX_CQ_COUNT, attr->max_cq);
- if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx))
+ if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))
for (i = 0; i < MAX_TQM_ALLOC_REQ; i++)
rdev->qplib_ctx.tqm_ctx.qcount[i] =
rdev->dev_attr.tqm_alloc_reqs[i];
@@ -264,7 +272,7 @@ static void bnxt_re_set_resource_limits(struct bnxt_re_dev *rdev)
memset(&rdev->qplib_ctx.vf_res, 0, sizeof(struct bnxt_qplib_vf_res));
bnxt_re_limit_pf_res(rdev);
- num_vfs = bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ?
+ num_vfs = bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx) ?
BNXT_RE_GEN_P5_MAX_VF : rdev->num_vfs;
if (num_vfs)
bnxt_re_limit_vf_res(&rdev->qplib_ctx, num_vfs);
@@ -276,7 +284,7 @@ static void bnxt_re_vf_res_config(struct bnxt_re_dev *rdev)
if (test_bit(BNXT_RE_FLAG_ERR_DEVICE_DETACHED, &rdev->flags))
return;
rdev->num_vfs = pci_sriov_get_totalvfs(rdev->en_dev->pdev);
- if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx)) {
+ if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx)) {
bnxt_re_set_resource_limits(rdev);
bnxt_qplib_set_func_resources(&rdev->qplib_res, &rdev->rcfw,
&rdev->qplib_ctx);
@@ -1203,25 +1211,19 @@ static int bnxt_re_cqn_handler(struct bnxt_qplib_nq *nq,
{
struct bnxt_re_cq *cq = container_of(handle, struct bnxt_re_cq,
qplib_cq);
+ u32 *cq_ptr;
if (cq->ib_cq.comp_handler) {
- /* Lock comp_handler? */
+ if (cq->uctx_cq_page) {
+ cq_ptr = (u32 *)cq->uctx_cq_page;
+ *cq_ptr = cq->qplib_cq.toggle;
+ }
(*cq->ib_cq.comp_handler)(&cq->ib_cq, cq->ib_cq.cq_context);
}
return 0;
}
-#define BNXT_RE_GEN_P5_PF_NQ_DB 0x10000
-#define BNXT_RE_GEN_P5_VF_NQ_DB 0x4000
-static u32 bnxt_re_get_nqdb_offset(struct bnxt_re_dev *rdev, u16 indx)
-{
- return bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx) ?
- (rdev->is_virtfn ? BNXT_RE_GEN_P5_VF_NQ_DB :
- BNXT_RE_GEN_P5_PF_NQ_DB) :
- rdev->en_dev->msix_entries[indx].db_offset;
-}
-
static void bnxt_re_cleanup_res(struct bnxt_re_dev *rdev)
{
int i;
@@ -1242,7 +1244,7 @@ static int bnxt_re_init_res(struct bnxt_re_dev *rdev)
bnxt_qplib_init_res(&rdev->qplib_res);
for (i = 1; i < rdev->num_msix ; i++) {
- db_offt = bnxt_re_get_nqdb_offset(rdev, i);
+ db_offt = rdev->en_dev->msix_entries[i].db_offset;
rc = bnxt_qplib_enable_nq(rdev->en_dev->pdev, &rdev->nq[i - 1],
i - 1, rdev->en_dev->msix_entries[i].vector,
db_offt, &bnxt_re_cqn_handler,
@@ -1653,7 +1655,7 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode)
ibdev_err(&rdev->ibdev, "Failed to allocate CREQ: %#x\n", rc);
goto free_rcfw;
}
- db_offt = bnxt_re_get_nqdb_offset(rdev, BNXT_RE_AEQ_IDX);
+ db_offt = rdev->en_dev->msix_entries[BNXT_RE_AEQ_IDX].db_offset;
vid = rdev->en_dev->msix_entries[BNXT_RE_AEQ_IDX].vector;
rc = bnxt_qplib_enable_rcfw_channel(&rdev->rcfw,
vid, db_offt,
@@ -1681,7 +1683,7 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode)
bnxt_re_set_resource_limits(rdev);
rc = bnxt_qplib_alloc_ctx(&rdev->qplib_res, &rdev->qplib_ctx, 0,
- bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx));
+ bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx));
if (rc) {
ibdev_err(&rdev->ibdev,
"Failed to allocate QPLIB context: %#x\n", rc);
@@ -1737,6 +1739,7 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode)
*/
bnxt_re_vf_res_config(rdev);
}
+ hash_init(rdev->cq_hash);
return 0;
free_sctx:
@@ -1804,7 +1807,7 @@ static void bnxt_re_setup_cc(struct bnxt_re_dev *rdev, bool enable)
return;
/* Currently enabling only for GenP5 adapters */
- if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx))
+ if (!bnxt_qplib_is_chip_gen_p5_p7(rdev->chip_ctx))
return;
if (enable) {
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
index abbabea7f5fa..c98e04fe2ddd 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
@@ -237,18 +237,15 @@ static void clean_nq(struct bnxt_qplib_nq *nq, struct bnxt_qplib_cq *cq)
struct bnxt_qplib_hwq *hwq = &nq->hwq;
struct nq_base *nqe, **nq_ptr;
int budget = nq->budget;
- u32 sw_cons, raw_cons;
uintptr_t q_handle;
u16 type;
spin_lock_bh(&hwq->lock);
/* Service the NQ until empty */
- raw_cons = hwq->cons;
while (budget--) {
- sw_cons = HWQ_CMP(raw_cons, hwq);
nq_ptr = (struct nq_base **)hwq->pbl_ptr;
- nqe = &nq_ptr[NQE_PG(sw_cons)][NQE_IDX(sw_cons)];
- if (!NQE_CMP_VALID(nqe, raw_cons, hwq->max_elements))
+ nqe = &nq_ptr[NQE_PG(hwq->cons)][NQE_IDX(hwq->cons)];
+ if (!NQE_CMP_VALID(nqe, nq->nq_db.dbinfo.flags))
break;
/*
@@ -276,7 +273,8 @@ static void clean_nq(struct bnxt_qplib_nq *nq, struct bnxt_qplib_cq *cq)
default:
break;
}
- raw_cons++;
+ bnxt_qplib_hwq_incr_cons(hwq->max_elements, &hwq->cons,
+ 1, &nq->nq_db.dbinfo.flags);
}
spin_unlock_bh(&hwq->lock);
}
@@ -302,18 +300,16 @@ static void bnxt_qplib_service_nq(struct tasklet_struct *t)
struct bnxt_qplib_hwq *hwq = &nq->hwq;
struct bnxt_qplib_cq *cq;
int budget = nq->budget;
- u32 sw_cons, raw_cons;
struct nq_base *nqe;
uintptr_t q_handle;
+ u32 hw_polled = 0;
u16 type;
spin_lock_bh(&hwq->lock);
/* Service the NQ until empty */
- raw_cons = hwq->cons;
while (budget--) {
- sw_cons = HWQ_CMP(raw_cons, hwq);
- nqe = bnxt_qplib_get_qe(hwq, sw_cons, NULL);
- if (!NQE_CMP_VALID(nqe, raw_cons, hwq->max_elements))
+ nqe = bnxt_qplib_get_qe(hwq, hwq->cons, NULL);
+ if (!NQE_CMP_VALID(nqe, nq->nq_db.dbinfo.flags))
break;
/*
@@ -334,6 +330,9 @@ static void bnxt_qplib_service_nq(struct tasklet_struct *t)
cq = (struct bnxt_qplib_cq *)(unsigned long)q_handle;
if (!cq)
break;
+ cq->toggle = (le16_to_cpu(nqe->info10_type) &
+ NQ_CN_TOGGLE_MASK) >> NQ_CN_TOGGLE_SFT;
+ cq->dbinfo.toggle = cq->toggle;
bnxt_qplib_armen_db(&cq->dbinfo,
DBC_DBC_TYPE_CQ_ARMENA);
spin_lock_bh(&cq->compl_lock);
@@ -372,12 +371,12 @@ static void bnxt_qplib_service_nq(struct tasklet_struct *t)
"nqe with type = 0x%x not handled\n", type);
break;
}
- raw_cons++;
+ hw_polled++;
+ bnxt_qplib_hwq_incr_cons(hwq->max_elements, &hwq->cons,
+ 1, &nq->nq_db.dbinfo.flags);
}
- if (hwq->cons != raw_cons) {
- hwq->cons = raw_cons;
+ if (hw_polled)
bnxt_qplib_ring_nq_db(&nq->nq_db.dbinfo, nq->res->cctx, true);
- }
spin_unlock_bh(&hwq->lock);
}
@@ -505,6 +504,7 @@ static int bnxt_qplib_map_nq_db(struct bnxt_qplib_nq *nq, u32 reg_offt)
pdev = nq->pdev;
nq_db = &nq->nq_db;
+ nq_db->dbinfo.flags = 0;
nq_db->reg.bar_id = NQ_CONS_PCI_BAR_REGION;
nq_db->reg.bar_base = pci_resource_start(pdev, nq_db->reg.bar_id);
if (!nq_db->reg.bar_base) {
@@ -649,7 +649,7 @@ int bnxt_qplib_create_srq(struct bnxt_qplib_res *res,
rc = -ENOMEM;
goto fail;
}
-
+ srq->dbinfo.flags = 0;
bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req,
CMDQ_BASE_OPCODE_CREATE_SRQ,
sizeof(req));
@@ -703,13 +703,9 @@ int bnxt_qplib_modify_srq(struct bnxt_qplib_res *res,
struct bnxt_qplib_srq *srq)
{
struct bnxt_qplib_hwq *srq_hwq = &srq->hwq;
- u32 sw_prod, sw_cons, count = 0;
-
- sw_prod = HWQ_CMP(srq_hwq->prod, srq_hwq);
- sw_cons = HWQ_CMP(srq_hwq->cons, srq_hwq);
+ u32 count;
- count = sw_prod > sw_cons ? sw_prod - sw_cons :
- srq_hwq->max_elements - sw_cons + sw_prod;
+ count = __bnxt_qplib_get_avail(srq_hwq);
if (count > srq->threshold) {
srq->arm_req = false;
bnxt_qplib_srq_arm_db(&srq->dbinfo, srq->threshold);
@@ -761,7 +757,7 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq,
struct bnxt_qplib_hwq *srq_hwq = &srq->hwq;
struct rq_wqe *srqe;
struct sq_sge *hw_sge;
- u32 sw_prod, sw_cons, count = 0;
+ u32 count = 0;
int i, next;
spin_lock(&srq_hwq->lock);
@@ -775,8 +771,7 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq,
srq->start_idx = srq->swq[next].next_idx;
spin_unlock(&srq_hwq->lock);
- sw_prod = HWQ_CMP(srq_hwq->prod, srq_hwq);
- srqe = bnxt_qplib_get_qe(srq_hwq, sw_prod, NULL);
+ srqe = bnxt_qplib_get_qe(srq_hwq, srq_hwq->prod, NULL);
memset(srqe, 0, srq->wqe_size);
/* Calculate wqe_size16 and data_len */
for (i = 0, hw_sge = (struct sq_sge *)srqe->data;
@@ -792,17 +787,10 @@ int bnxt_qplib_post_srq_recv(struct bnxt_qplib_srq *srq,
srqe->wr_id[0] = cpu_to_le32((u32)next);
srq->swq[next].wr_id = wqe->wr_id;
- srq_hwq->prod++;
+ bnxt_qplib_hwq_incr_prod(&srq->dbinfo, srq_hwq, srq->dbinfo.max_slot);
spin_lock(&srq_hwq->lock);
- sw_prod = HWQ_CMP(srq_hwq->prod, srq_hwq);
- /* retaining srq_hwq->cons for this logic
- * actually the lock is only required to
- * read srq_hwq->cons.
- */
- sw_cons = HWQ_CMP(srq_hwq->cons, srq_hwq);
- count = sw_prod > sw_cons ? sw_prod - sw_cons :
- srq_hwq->max_elements - sw_cons + sw_prod;
+ count = __bnxt_qplib_get_avail(srq_hwq);
spin_unlock(&srq_hwq->lock);
/* Ring DB */
bnxt_qplib_ring_prod_db(&srq->dbinfo, DBC_DBC_TYPE_SRQ);
@@ -849,6 +837,7 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
u32 tbl_indx;
int rc;
+ sq->dbinfo.flags = 0;
bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req,
CMDQ_BASE_OPCODE_CREATE_QP1,
sizeof(req));
@@ -885,6 +874,7 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
/* RQ */
if (rq->max_wqe) {
+ rq->dbinfo.flags = 0;
hwq_attr.res = res;
hwq_attr.sginfo = &rq->sg_info;
hwq_attr.stride = sizeof(struct sq_sge);
@@ -992,6 +982,10 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
u32 tbl_indx;
u16 nsge;
+ if (res->dattr)
+ qp->dev_cap_flags = res->dattr->dev_cap_flags;
+
+ sq->dbinfo.flags = 0;
bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req,
CMDQ_BASE_OPCODE_CREATE_QP,
sizeof(req));
@@ -1003,9 +997,14 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
/* SQ */
if (qp->type == CMDQ_CREATE_QP_TYPE_RC) {
- psn_sz = bnxt_qplib_is_chip_gen_p5(res->cctx) ?
+ psn_sz = bnxt_qplib_is_chip_gen_p5_p7(res->cctx) ?
sizeof(struct sq_psn_search_ext) :
sizeof(struct sq_psn_search);
+
+ if (BNXT_RE_HW_RETX(qp->dev_cap_flags)) {
+ psn_sz = sizeof(struct sq_msn_search);
+ qp->msn = 0;
+ }
}
hwq_attr.res = res;
@@ -1014,6 +1013,13 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
hwq_attr.depth = bnxt_qplib_get_depth(sq);
hwq_attr.aux_stride = psn_sz;
hwq_attr.aux_depth = bnxt_qplib_set_sq_size(sq, qp->wqe_mode);
+ /* Update msn tbl size */
+ if (BNXT_RE_HW_RETX(qp->dev_cap_flags) && psn_sz) {
+ hwq_attr.aux_depth = roundup_pow_of_two(bnxt_qplib_set_sq_size(sq, qp->wqe_mode));
+ qp->msn_tbl_sz = hwq_attr.aux_depth;
+ qp->msn = 0;
+ }
+
hwq_attr.type = HWQ_TYPE_QUEUE;
rc = bnxt_qplib_alloc_init_hwq(&sq->hwq, &hwq_attr);
if (rc)
@@ -1040,6 +1046,7 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
/* RQ */
if (!qp->srq) {
+ rq->dbinfo.flags = 0;
hwq_attr.res = res;
hwq_attr.sginfo = &rq->sg_info;
hwq_attr.stride = sizeof(struct sq_sge);
@@ -1454,12 +1461,15 @@ bail:
static void __clean_cq(struct bnxt_qplib_cq *cq, u64 qp)
{
struct bnxt_qplib_hwq *cq_hwq = &cq->hwq;
+ u32 peek_flags, peek_cons;
struct cq_base *hw_cqe;
int i;
+ peek_flags = cq->dbinfo.flags;
+ peek_cons = cq_hwq->cons;
for (i = 0; i < cq_hwq->max_elements; i++) {
- hw_cqe = bnxt_qplib_get_qe(cq_hwq, i, NULL);
- if (!CQE_CMP_VALID(hw_cqe, i, cq_hwq->max_elements))
+ hw_cqe = bnxt_qplib_get_qe(cq_hwq, peek_cons, NULL);
+ if (!CQE_CMP_VALID(hw_cqe, peek_flags))
continue;
/*
* The valid test of the entry must be done first before
@@ -1489,6 +1499,8 @@ static void __clean_cq(struct bnxt_qplib_cq *cq, u64 qp)
default:
break;
}
+ bnxt_qplib_hwq_incr_cons(cq_hwq->max_elements, &peek_cons,
+ 1, &peek_flags);
}
}
@@ -1590,6 +1602,27 @@ void *bnxt_qplib_get_qp1_rq_buf(struct bnxt_qplib_qp *qp,
return NULL;
}
+/* Fil the MSN table into the next psn row */
+static void bnxt_qplib_fill_msn_search(struct bnxt_qplib_qp *qp,
+ struct bnxt_qplib_swqe *wqe,
+ struct bnxt_qplib_swq *swq)
+{
+ struct sq_msn_search *msns;
+ u32 start_psn, next_psn;
+ u16 start_idx;
+
+ msns = (struct sq_msn_search *)swq->psn_search;
+ msns->start_idx_next_psn_start_psn = 0;
+
+ start_psn = swq->start_psn;
+ next_psn = swq->next_psn;
+ start_idx = swq->slot_idx;
+ msns->start_idx_next_psn_start_psn |=
+ bnxt_re_update_msn_tbl(start_idx, next_psn, start_psn);
+ qp->msn++;
+ qp->msn %= qp->msn_tbl_sz;
+}
+
static void bnxt_qplib_fill_psn_search(struct bnxt_qplib_qp *qp,
struct bnxt_qplib_swqe *wqe,
struct bnxt_qplib_swq *swq)
@@ -1601,6 +1634,12 @@ static void bnxt_qplib_fill_psn_search(struct bnxt_qplib_qp *qp,
if (!swq->psn_search)
return;
+ /* Handle MSN differently on cap flags */
+ if (BNXT_RE_HW_RETX(qp->dev_cap_flags)) {
+ bnxt_qplib_fill_msn_search(qp, wqe, swq);
+ return;
+ }
+ psns = (struct sq_psn_search *)swq->psn_search;
psns = swq->psn_search;
psns_ext = swq->psn_ext;
@@ -1611,7 +1650,7 @@ static void bnxt_qplib_fill_psn_search(struct bnxt_qplib_qp *qp,
flg_npsn = ((swq->next_psn << SQ_PSN_SEARCH_NEXT_PSN_SFT) &
SQ_PSN_SEARCH_NEXT_PSN_MASK);
- if (bnxt_qplib_is_chip_gen_p5(qp->cctx)) {
+ if (bnxt_qplib_is_chip_gen_p5_p7(qp->cctx)) {
psns_ext->opcode_start_psn = cpu_to_le32(op_spsn);
psns_ext->flags_next_psn = cpu_to_le32(flg_npsn);
psns_ext->start_slot_idx = cpu_to_le16(swq->slot_idx);
@@ -1709,8 +1748,8 @@ static u16 bnxt_qplib_required_slots(struct bnxt_qplib_qp *qp,
return slot;
}
-static void bnxt_qplib_pull_psn_buff(struct bnxt_qplib_q *sq,
- struct bnxt_qplib_swq *swq)
+static void bnxt_qplib_pull_psn_buff(struct bnxt_qplib_qp *qp, struct bnxt_qplib_q *sq,
+ struct bnxt_qplib_swq *swq, bool hw_retx)
{
struct bnxt_qplib_hwq *hwq;
u32 pg_num, pg_indx;
@@ -1721,6 +1760,11 @@ static void bnxt_qplib_pull_psn_buff(struct bnxt_qplib_q *sq,
if (!hwq->pad_pg)
return;
tail = swq->slot_idx / sq->dbinfo.max_slot;
+ if (hw_retx) {
+ /* For HW retx use qp msn index */
+ tail = qp->msn;
+ tail %= qp->msn_tbl_sz;
+ }
pg_num = (tail + hwq->pad_pgofft) / (PAGE_SIZE / hwq->pad_stride);
pg_indx = (tail + hwq->pad_pgofft) % (PAGE_SIZE / hwq->pad_stride);
buff = (void *)(hwq->pad_pg[pg_num] + pg_indx * hwq->pad_stride);
@@ -1745,6 +1789,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
struct bnxt_qplib_swq *swq;
bool sch_handler = false;
u16 wqe_sz, qdf = 0;
+ bool msn_update;
void *base_hdr;
void *ext_hdr;
__le32 temp32;
@@ -1772,7 +1817,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
}
swq = bnxt_qplib_get_swqe(sq, &wqe_idx);
- bnxt_qplib_pull_psn_buff(sq, swq);
+ bnxt_qplib_pull_psn_buff(qp, sq, swq, BNXT_RE_HW_RETX(qp->dev_cap_flags));
idx = 0;
swq->slot_idx = hwq->prod;
@@ -1804,6 +1849,8 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
&idx);
if (data_len < 0)
goto queue_err;
+ /* Make sure we update MSN table only for wired wqes */
+ msn_update = true;
/* Specifics */
switch (wqe->type) {
case BNXT_QPLIB_SWQE_TYPE_SEND:
@@ -1844,6 +1891,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
SQ_SEND_DST_QP_MASK);
ext_sqe->avid = cpu_to_le32(wqe->send.avid &
SQ_SEND_AVID_MASK);
+ msn_update = false;
} else {
sqe->length = cpu_to_le32(data_len);
if (qp->mtu)
@@ -1901,7 +1949,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
sqe->wqe_type = wqe->type;
sqe->flags = wqe->flags;
sqe->inv_l_key = cpu_to_le32(wqe->local_inv.inv_l_key);
-
+ msn_update = false;
break;
}
case BNXT_QPLIB_SWQE_TYPE_FAST_REG_MR:
@@ -1933,6 +1981,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
PTU_PTE_VALID);
ext_sqe->pblptr = cpu_to_le64(wqe->frmr.pbl_dma_ptr);
ext_sqe->va = cpu_to_le64(wqe->frmr.va);
+ msn_update = false;
break;
}
@@ -1950,6 +1999,7 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
sqe->l_key = cpu_to_le32(wqe->bind.r_key);
ext_sqe->va = cpu_to_le64(wqe->bind.va);
ext_sqe->length_lo = cpu_to_le32(wqe->bind.length);
+ msn_update = false;
break;
}
default:
@@ -1957,11 +2007,13 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
rc = -EINVAL;
goto done;
}
- swq->next_psn = sq->psn & BTH_PSN_MASK;
- bnxt_qplib_fill_psn_search(qp, wqe, swq);
+ if (!BNXT_RE_HW_RETX(qp->dev_cap_flags) || msn_update) {
+ swq->next_psn = sq->psn & BTH_PSN_MASK;
+ bnxt_qplib_fill_psn_search(qp, wqe, swq);
+ }
queue_err:
bnxt_qplib_swq_mod_start(sq, wqe_idx);
- bnxt_qplib_hwq_incr_prod(hwq, swq->slots);
+ bnxt_qplib_hwq_incr_prod(&sq->dbinfo, hwq, swq->slots);
qp->wqe_cnt++;
done:
if (sch_handler) {
@@ -2049,7 +2101,7 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp,
base_hdr->wr_id[0] = cpu_to_le32(wqe_idx);
queue_err:
bnxt_qplib_swq_mod_start(rq, wqe_idx);
- bnxt_qplib_hwq_incr_prod(hwq, swq->slots);
+ bnxt_qplib_hwq_incr_prod(&rq->dbinfo, hwq, swq->slots);
done:
if (sch_handler) {
nq_work = kzalloc(sizeof(*nq_work), GFP_ATOMIC);
@@ -2086,6 +2138,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq)
return -EINVAL;
}
+ cq->dbinfo.flags = 0;
hwq_attr.res = res;
hwq_attr.depth = cq->max_wqe;
hwq_attr.stride = sizeof(struct cq_base);
@@ -2101,7 +2154,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq)
req.dpi = cpu_to_le32(cq->dpi->dpi);
req.cq_handle = cpu_to_le64(cq->cq_handle);
- req.cq_size = cpu_to_le32(cq->hwq.max_elements);
+ req.cq_size = cpu_to_le32(cq->max_wqe);
pbl = &cq->hwq.pbl[PBL_LVL_0];
pg_sz_lvl = (bnxt_qplib_base_pg_size(&cq->hwq) <<
CMDQ_CREATE_CQ_PG_SIZE_SFT);
@@ -2129,6 +2182,8 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq)
cq->dbinfo.xid = cq->id;
cq->dbinfo.db = cq->dpi->dbr;
cq->dbinfo.priv_db = res->dpi_tbl.priv_db;
+ cq->dbinfo.flags = 0;
+ cq->dbinfo.toggle = 0;
bnxt_qplib_armen_db(&cq->dbinfo, DBC_DBC_TYPE_CQ_ARMENA);
@@ -2144,6 +2199,8 @@ void bnxt_qplib_resize_cq_complete(struct bnxt_qplib_res *res,
{
bnxt_qplib_free_hwq(res, &cq->hwq);
memcpy(&cq->hwq, &cq->resize_hwq, sizeof(cq->hwq));
+ /* Reset only the cons bit in the flags */
+ cq->dbinfo.flags &= ~(1UL << BNXT_QPLIB_FLAG_EPOCH_CONS_SHIFT);
}
int bnxt_qplib_resize_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq,
@@ -2240,7 +2297,8 @@ static int __flush_sq(struct bnxt_qplib_q *sq, struct bnxt_qplib_qp *qp,
cqe++;
(*budget)--;
skip_compl:
- bnxt_qplib_hwq_incr_cons(&sq->hwq, sq->swq[last].slots);
+ bnxt_qplib_hwq_incr_cons(sq->hwq.max_elements, &sq->hwq.cons,
+ sq->swq[last].slots, &sq->dbinfo.flags);
sq->swq_last = sq->swq[last].next_idx;
}
*pcqe = cqe;
@@ -2287,7 +2345,8 @@ static int __flush_rq(struct bnxt_qplib_q *rq, struct bnxt_qplib_qp *qp,
cqe->wr_id = rq->swq[last].wr_id;
cqe++;
(*budget)--;
- bnxt_qplib_hwq_incr_cons(&rq->hwq, rq->swq[last].slots);
+ bnxt_qplib_hwq_incr_cons(rq->hwq.max_elements, &rq->hwq.cons,
+ rq->swq[last].slots, &rq->dbinfo.flags);
rq->swq_last = rq->swq[last].next_idx;
}
*pcqe = cqe;
@@ -2316,7 +2375,7 @@ void bnxt_qplib_mark_qp_error(void *qp_handle)
static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq,
u32 cq_cons, u32 swq_last, u32 cqe_sq_cons)
{
- u32 peek_sw_cq_cons, peek_raw_cq_cons, peek_sq_cons_idx;
+ u32 peek_sw_cq_cons, peek_sq_cons_idx, peek_flags;
struct bnxt_qplib_q *sq = &qp->sq;
struct cq_req *peek_req_hwcqe;
struct bnxt_qplib_qp *peek_qp;
@@ -2347,16 +2406,14 @@ static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq,
}
if (sq->condition) {
/* Peek at the completions */
- peek_raw_cq_cons = cq->hwq.cons;
+ peek_flags = cq->dbinfo.flags;
peek_sw_cq_cons = cq_cons;
i = cq->hwq.max_elements;
while (i--) {
- peek_sw_cq_cons = HWQ_CMP((peek_sw_cq_cons), &cq->hwq);
peek_hwcqe = bnxt_qplib_get_qe(&cq->hwq,
peek_sw_cq_cons, NULL);
/* If the next hwcqe is VALID */
- if (CQE_CMP_VALID(peek_hwcqe, peek_raw_cq_cons,
- cq->hwq.max_elements)) {
+ if (CQE_CMP_VALID(peek_hwcqe, peek_flags)) {
/*
* The valid test of the entry must be done first before
* reading any further.
@@ -2399,8 +2456,9 @@ static int do_wa9060(struct bnxt_qplib_qp *qp, struct bnxt_qplib_cq *cq,
rc = -EINVAL;
goto out;
}
- peek_sw_cq_cons++;
- peek_raw_cq_cons++;
+ bnxt_qplib_hwq_incr_cons(cq->hwq.max_elements,
+ &peek_sw_cq_cons,
+ 1, &peek_flags);
}
dev_err(&cq->hwq.pdev->dev,
"Should not have come here! cq_cons=0x%x qp=0x%x sq cons sw=0x%x hw=0x%x\n",
@@ -2487,7 +2545,8 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq,
}
}
skip:
- bnxt_qplib_hwq_incr_cons(&sq->hwq, swq->slots);
+ bnxt_qplib_hwq_incr_cons(sq->hwq.max_elements, &sq->hwq.cons,
+ swq->slots, &sq->dbinfo.flags);
sq->swq_last = swq->next_idx;
if (sq->single)
break;
@@ -2514,7 +2573,8 @@ static void bnxt_qplib_release_srqe(struct bnxt_qplib_srq *srq, u32 tag)
srq->swq[srq->last_idx].next_idx = (int)tag;
srq->last_idx = (int)tag;
srq->swq[srq->last_idx].next_idx = -1;
- srq->hwq.cons++; /* Support for SRQE counter */
+ bnxt_qplib_hwq_incr_cons(srq->hwq.max_elements, &srq->hwq.cons,
+ srq->dbinfo.max_slot, &srq->dbinfo.flags);
spin_unlock(&srq->hwq.lock);
}
@@ -2583,7 +2643,8 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq,
cqe->wr_id = swq->wr_id;
cqe++;
(*budget)--;
- bnxt_qplib_hwq_incr_cons(&rq->hwq, swq->slots);
+ bnxt_qplib_hwq_incr_cons(rq->hwq.max_elements, &rq->hwq.cons,
+ swq->slots, &rq->dbinfo.flags);
rq->swq_last = swq->next_idx;
*pcqe = cqe;
@@ -2669,7 +2730,8 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
cqe->wr_id = swq->wr_id;
cqe++;
(*budget)--;
- bnxt_qplib_hwq_incr_cons(&rq->hwq, swq->slots);
+ bnxt_qplib_hwq_incr_cons(rq->hwq.max_elements, &rq->hwq.cons,
+ swq->slots, &rq->dbinfo.flags);
rq->swq_last = swq->next_idx;
*pcqe = cqe;
@@ -2686,14 +2748,11 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq)
{
struct cq_base *hw_cqe;
- u32 sw_cons, raw_cons;
bool rc = true;
- raw_cons = cq->hwq.cons;
- sw_cons = HWQ_CMP(raw_cons, &cq->hwq);
- hw_cqe = bnxt_qplib_get_qe(&cq->hwq, sw_cons, NULL);
+ hw_cqe = bnxt_qplib_get_qe(&cq->hwq, cq->hwq.cons, NULL);
/* Check for Valid bit. If the CQE is valid, return false */
- rc = !CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements);
+ rc = !CQE_CMP_VALID(hw_cqe, cq->dbinfo.flags);
return rc;
}
@@ -2775,7 +2834,8 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
cqe->wr_id = swq->wr_id;
cqe++;
(*budget)--;
- bnxt_qplib_hwq_incr_cons(&rq->hwq, swq->slots);
+ bnxt_qplib_hwq_incr_cons(rq->hwq.max_elements, &rq->hwq.cons,
+ swq->slots, &rq->dbinfo.flags);
rq->swq_last = swq->next_idx;
*pcqe = cqe;
@@ -2848,7 +2908,8 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq,
cqe++;
(*budget)--;
}
- bnxt_qplib_hwq_incr_cons(&sq->hwq, sq->swq[swq_last].slots);
+ bnxt_qplib_hwq_incr_cons(sq->hwq.max_elements, &sq->hwq.cons,
+ sq->swq[swq_last].slots, &sq->dbinfo.flags);
sq->swq_last = sq->swq[swq_last].next_idx;
}
*pcqe = cqe;
@@ -2933,19 +2994,17 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
int num_cqes, struct bnxt_qplib_qp **lib_qp)
{
struct cq_base *hw_cqe;
- u32 sw_cons, raw_cons;
int budget, rc = 0;
+ u32 hw_polled = 0;
u8 type;
- raw_cons = cq->hwq.cons;
budget = num_cqes;
while (budget) {
- sw_cons = HWQ_CMP(raw_cons, &cq->hwq);
- hw_cqe = bnxt_qplib_get_qe(&cq->hwq, sw_cons, NULL);
+ hw_cqe = bnxt_qplib_get_qe(&cq->hwq, cq->hwq.cons, NULL);
/* Check for Valid bit */
- if (!CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements))
+ if (!CQE_CMP_VALID(hw_cqe, cq->dbinfo.flags))
break;
/*
@@ -2960,7 +3019,7 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
rc = bnxt_qplib_cq_process_req(cq,
(struct cq_req *)hw_cqe,
&cqe, &budget,
- sw_cons, lib_qp);
+ cq->hwq.cons, lib_qp);
break;
case CQ_BASE_CQE_TYPE_RES_RC:
rc = bnxt_qplib_cq_process_res_rc(cq,
@@ -3006,18 +3065,20 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
dev_err(&cq->hwq.pdev->dev,
"process_cqe error rc = 0x%x\n", rc);
}
- raw_cons++;
+ hw_polled++;
+ bnxt_qplib_hwq_incr_cons(cq->hwq.max_elements, &cq->hwq.cons,
+ 1, &cq->dbinfo.flags);
+
}
- if (cq->hwq.cons != raw_cons) {
- cq->hwq.cons = raw_cons;
+ if (hw_polled)
bnxt_qplib_ring_db(&cq->dbinfo, DBC_DBC_TYPE_CQ);
- }
exit:
return num_cqes - budget;
}
void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type)
{
+ cq->dbinfo.toggle = cq->toggle;
if (arm_type)
bnxt_qplib_ring_db(&cq->dbinfo, arm_type);
/* Using cq->arm_state variable to track whether to issue cq handler */
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
index 404b851091ca..7fd4506b3584 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
@@ -338,6 +338,9 @@ struct bnxt_qplib_qp {
dma_addr_t rq_hdr_buf_map;
struct list_head sq_flush;
struct list_head rq_flush;
+ u32 msn;
+ u32 msn_tbl_sz;
+ u16 dev_cap_flags;
};
#define BNXT_QPLIB_MAX_CQE_ENTRY_SIZE sizeof(struct cq_base)
@@ -348,9 +351,21 @@ struct bnxt_qplib_qp {
#define CQE_IDX(x) ((x) & CQE_MAX_IDX_PER_PG)
#define ROCE_CQE_CMP_V 0
-#define CQE_CMP_VALID(hdr, raw_cons, cp_bit) \
+#define CQE_CMP_VALID(hdr, pass) \
(!!((hdr)->cqe_type_toggle & CQ_BASE_TOGGLE) == \
- !((raw_cons) & (cp_bit)))
+ !((pass) & BNXT_QPLIB_FLAG_EPOCH_CONS_MASK))
+
+static inline u32 __bnxt_qplib_get_avail(struct bnxt_qplib_hwq *hwq)
+{
+ int cons, prod, avail;
+
+ cons = hwq->cons;
+ prod = hwq->prod;
+ avail = cons - prod;
+ if (cons <= prod)
+ avail += hwq->depth;
+ return avail;
+}
static inline bool bnxt_qplib_queue_full(struct bnxt_qplib_q *que,
u8 slots)
@@ -406,6 +421,7 @@ struct bnxt_qplib_cq {
bool resize_in_progress;
struct bnxt_qplib_sg_info sg_info;
u64 cq_handle;
+ u8 toggle;
#define CQ_RESIZE_WAIT_TIME_MS 500
unsigned long flags;
@@ -443,9 +459,9 @@ struct bnxt_qplib_cq {
#define NQE_PG(x) (((x) & ~NQE_MAX_IDX_PER_PG) / NQE_CNT_PER_PG)
#define NQE_IDX(x) ((x) & NQE_MAX_IDX_PER_PG)
-#define NQE_CMP_VALID(hdr, raw_cons, cp_bit) \
+#define NQE_CMP_VALID(hdr, pass) \
(!!(le32_to_cpu((hdr)->info63_v[0]) & NQ_BASE_V) == \
- !((raw_cons) & (cp_bit)))
+ !((pass) & BNXT_QPLIB_FLAG_EPOCH_CONS_MASK))
#define BNXT_QPLIB_NQE_MAX_CNT (128 * 1024)
@@ -614,4 +630,15 @@ static inline u16 bnxt_qplib_calc_ilsize(struct bnxt_qplib_swqe *wqe, u16 max)
return size;
}
+
+/* MSN table update inlin */
+static inline __le64 bnxt_re_update_msn_tbl(u32 st_idx, u32 npsn, u32 start_psn)
+{
+ return cpu_to_le64((((u64)(st_idx) << SQ_MSN_SEARCH_START_IDX_SFT) &
+ SQ_MSN_SEARCH_START_IDX_MASK) |
+ (((u64)(npsn) << SQ_MSN_SEARCH_NEXT_PSN_SFT) &
+ SQ_MSN_SEARCH_NEXT_PSN_MASK) |
+ (((start_psn) << SQ_MSN_SEARCH_START_PSN_SFT) &
+ SQ_MSN_SEARCH_START_PSN_MASK));
+}
#endif /* __BNXT_QPLIB_FP_H__ */
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
index e47b4ca64d33..3ffaef0c2651 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
@@ -734,17 +734,15 @@ static void bnxt_qplib_service_creq(struct tasklet_struct *t)
u32 type, budget = CREQ_ENTRY_POLL_BUDGET;
struct bnxt_qplib_hwq *hwq = &creq->hwq;
struct creq_base *creqe;
- u32 sw_cons, raw_cons;
unsigned long flags;
u32 num_wakeup = 0;
+ u32 hw_polled = 0;
/* Service the CREQ until budget is over */
spin_lock_irqsave(&hwq->lock, flags);
- raw_cons = hwq->cons;
while (budget > 0) {
- sw_cons = HWQ_CMP(raw_cons, hwq);
- creqe = bnxt_qplib_get_qe(hwq, sw_cons, NULL);
- if (!CREQ_CMP_VALID(creqe, raw_cons, hwq->max_elements))
+ creqe = bnxt_qplib_get_qe(hwq, hwq->cons, NULL);
+ if (!CREQ_CMP_VALID(creqe, creq->creq_db.dbinfo.flags))
break;
/* The valid test of the entry must be done first before
* reading any further.
@@ -775,15 +773,15 @@ static void bnxt_qplib_service_creq(struct tasklet_struct *t)
type);
break;
}
- raw_cons++;
budget--;
+ hw_polled++;
+ bnxt_qplib_hwq_incr_cons(hwq->max_elements, &hwq->cons,
+ 1, &creq->creq_db.dbinfo.flags);
}
- if (hwq->cons != raw_cons) {
- hwq->cons = raw_cons;
+ if (hw_polled)
bnxt_qplib_ring_nq_db(&creq->creq_db.dbinfo,
rcfw->res->cctx, true);
- }
spin_unlock_irqrestore(&hwq->lock, flags);
if (num_wakeup)
wake_up_nr(&rcfw->cmdq.waitq, num_wakeup);
@@ -854,7 +852,7 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
*/
if (is_virtfn)
goto skip_ctx_setup;
- if (bnxt_qplib_is_chip_gen_p5(rcfw->res->cctx))
+ if (bnxt_qplib_is_chip_gen_p5_p7(rcfw->res->cctx))
goto config_vf_res;
lvl = ctx->qpc_tbl.level;
@@ -907,6 +905,8 @@ config_vf_res:
req.max_gid_per_vf = cpu_to_le32(ctx->vf_res.max_gid_per_vf);
skip_ctx_setup:
+ if (BNXT_RE_HW_RETX(rcfw->res->dattr->dev_cap_flags))
+ req.flags |= cpu_to_le16(CMDQ_INITIALIZE_FW_FLAGS_HW_REQUESTER_RETX_SUPPORTED);
req.stat_ctx_id = cpu_to_le32(ctx->stats.fw_id);
bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0);
rc = bnxt_qplib_rcfw_send_message(rcfw, &msg);
@@ -1113,6 +1113,7 @@ static int bnxt_qplib_map_creq_db(struct bnxt_qplib_rcfw *rcfw, u32 reg_offt)
pdev = rcfw->pdev;
creq_db = &rcfw->creq.creq_db;
+ creq_db->dbinfo.flags = 0;
creq_db->reg.bar_id = RCFW_COMM_CONS_PCI_BAR_REGION;
creq_db->reg.bar_base = pci_resource_start(pdev, creq_db->reg.bar_id);
if (!creq_db->reg.bar_id)
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
index 7b31bee3e000..45996e60a0d0 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
@@ -141,9 +141,9 @@ struct bnxt_qplib_crsbe {
/* Allocate 1 per QP for async error notification for now */
#define BNXT_QPLIB_CREQE_MAX_CNT (64 * 1024)
#define BNXT_QPLIB_CREQE_UNITS 16 /* 16-Bytes per prod unit */
-#define CREQ_CMP_VALID(hdr, raw_cons, cp_bit) \
+#define CREQ_CMP_VALID(hdr, pass) \
(!!((hdr)->v & CREQ_BASE_V) == \
- !((raw_cons) & (cp_bit)))
+ !((pass) & BNXT_QPLIB_FLAG_EPOCH_CONS_MASK))
#define CREQ_ENTRY_POLL_BUDGET 0x100
/* HWQ */
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c
index 157db6b7e119..dfc943fab87b 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_res.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c
@@ -343,7 +343,7 @@ done:
hwq->cons = 0;
hwq->pdev = pdev;
hwq->depth = hwq_attr->depth;
- hwq->max_elements = depth;
+ hwq->max_elements = hwq->depth;
hwq->element_size = stride;
hwq->qe_ppg = pg_size / stride;
/* For direct access to the elements */
@@ -805,7 +805,7 @@ static int bnxt_qplib_alloc_dpi_tbl(struct bnxt_qplib_res *res,
dpit = &res->dpi_tbl;
reg = &dpit->wcreg;
- if (!bnxt_qplib_is_chip_gen_p5(res->cctx)) {
+ if (!bnxt_qplib_is_chip_gen_p5_p7(res->cctx)) {
/* Offest should come from L2 driver */
dbr_offset = dev_attr->l2_db_size;
dpit->ucreg.offset = dbr_offset;
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h
index 5949f004f785..61628f7f1253 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_res.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h
@@ -44,11 +44,23 @@ extern const struct bnxt_qplib_gid bnxt_qplib_gid_zero;
#define CHIP_NUM_57508 0x1750
#define CHIP_NUM_57504 0x1751
#define CHIP_NUM_57502 0x1752
+#define CHIP_NUM_58818 0xd818
+#define CHIP_NUM_57608 0x1760
+
+#define BNXT_QPLIB_DBR_VALID (0x1UL << 26)
+#define BNXT_QPLIB_DBR_EPOCH_SHIFT 24
+#define BNXT_QPLIB_DBR_TOGGLE_SHIFT 25
struct bnxt_qplib_drv_modes {
u8 wqe_mode;
bool db_push;
bool dbr_pacing;
+ u32 toggle_bits;
+};
+
+enum bnxt_re_toggle_modes {
+ BNXT_QPLIB_CQ_TOGGLE_BIT = 0x1,
+ BNXT_QPLIB_SRQ_TOGGLE_BIT = 0x2,
};
struct bnxt_qplib_chip_ctx {
@@ -186,6 +198,20 @@ struct bnxt_qplib_db_info {
struct bnxt_qplib_hwq *hwq;
u32 xid;
u32 max_slot;
+ u32 flags;
+ u8 toggle;
+};
+
+enum bnxt_qplib_db_info_flags_mask {
+ BNXT_QPLIB_FLAG_EPOCH_CONS_SHIFT = 0x0UL,
+ BNXT_QPLIB_FLAG_EPOCH_PROD_SHIFT = 0x1UL,
+ BNXT_QPLIB_FLAG_EPOCH_CONS_MASK = 0x1UL,
+ BNXT_QPLIB_FLAG_EPOCH_PROD_MASK = 0x2UL,
+};
+
+enum bnxt_qplib_db_epoch_flag_shift {
+ BNXT_QPLIB_DB_EPOCH_CONS_SHIFT = BNXT_QPLIB_DBR_EPOCH_SHIFT,
+ BNXT_QPLIB_DB_EPOCH_PROD_SHIFT = (BNXT_QPLIB_DBR_EPOCH_SHIFT - 1),
};
/* Tables */
@@ -288,6 +314,12 @@ struct bnxt_qplib_res {
struct bnxt_qplib_db_pacing_data *pacing_data;
};
+static inline bool bnxt_qplib_is_chip_gen_p7(struct bnxt_qplib_chip_ctx *cctx)
+{
+ return (cctx->chip_num == CHIP_NUM_58818 ||
+ cctx->chip_num == CHIP_NUM_57608);
+}
+
static inline bool bnxt_qplib_is_chip_gen_p5(struct bnxt_qplib_chip_ctx *cctx)
{
return (cctx->chip_num == CHIP_NUM_57508 ||
@@ -295,15 +327,20 @@ static inline bool bnxt_qplib_is_chip_gen_p5(struct bnxt_qplib_chip_ctx *cctx)
cctx->chip_num == CHIP_NUM_57502);
}
+static inline bool bnxt_qplib_is_chip_gen_p5_p7(struct bnxt_qplib_chip_ctx *cctx)
+{
+ return bnxt_qplib_is_chip_gen_p5(cctx) || bnxt_qplib_is_chip_gen_p7(cctx);
+}
+
static inline u8 bnxt_qplib_get_hwq_type(struct bnxt_qplib_res *res)
{
- return bnxt_qplib_is_chip_gen_p5(res->cctx) ?
+ return bnxt_qplib_is_chip_gen_p5_p7(res->cctx) ?
HWQ_TYPE_QUEUE : HWQ_TYPE_L2_CMPL;
}
static inline u8 bnxt_qplib_get_ring_type(struct bnxt_qplib_chip_ctx *cctx)
{
- return bnxt_qplib_is_chip_gen_p5(cctx) ?
+ return bnxt_qplib_is_chip_gen_p5_p7(cctx) ?
RING_ALLOC_REQ_RING_TYPE_NQ :
RING_ALLOC_REQ_RING_TYPE_ROCE_CMPL;
}
@@ -396,39 +433,61 @@ void bnxt_qplib_unmap_db_bar(struct bnxt_qplib_res *res);
int bnxt_qplib_determine_atomics(struct pci_dev *dev);
-static inline void bnxt_qplib_hwq_incr_prod(struct bnxt_qplib_hwq *hwq, u32 cnt)
+static inline void bnxt_qplib_hwq_incr_prod(struct bnxt_qplib_db_info *dbinfo,
+ struct bnxt_qplib_hwq *hwq, u32 cnt)
{
- hwq->prod = (hwq->prod + cnt) % hwq->depth;
+ /* move prod and update toggle/epoch if wrap around */
+ hwq->prod += cnt;
+ if (hwq->prod >= hwq->depth) {
+ hwq->prod %= hwq->depth;
+ dbinfo->flags ^= 1UL << BNXT_QPLIB_FLAG_EPOCH_PROD_SHIFT;
+ }
}
-static inline void bnxt_qplib_hwq_incr_cons(struct bnxt_qplib_hwq *hwq,
- u32 cnt)
+static inline void bnxt_qplib_hwq_incr_cons(u32 max_elements, u32 *cons, u32 cnt,
+ u32 *dbinfo_flags)
{
- hwq->cons = (hwq->cons + cnt) % hwq->depth;
+ /* move cons and update toggle/epoch if wrap around */
+ *cons += cnt;
+ if (*cons >= max_elements) {
+ *cons %= max_elements;
+ *dbinfo_flags ^= 1UL << BNXT_QPLIB_FLAG_EPOCH_CONS_SHIFT;
+ }
}
static inline void bnxt_qplib_ring_db32(struct bnxt_qplib_db_info *info,
bool arm)
{
- u32 key;
+ u32 key = 0;
- key = info->hwq->cons & (info->hwq->max_elements - 1);
- key |= (CMPL_DOORBELL_IDX_VALID |
+ key |= info->hwq->cons | (CMPL_DOORBELL_IDX_VALID |
(CMPL_DOORBELL_KEY_CMPL & CMPL_DOORBELL_KEY_MASK));
if (!arm)
key |= CMPL_DOORBELL_MASK;
writel(key, info->db);
}
+#define BNXT_QPLIB_INIT_DBHDR(xid, type, indx, toggle) \
+ (((u64)(((xid) & DBC_DBC_XID_MASK) | DBC_DBC_PATH_ROCE | \
+ (type) | BNXT_QPLIB_DBR_VALID) << 32) | (indx) | \
+ (((u32)(toggle)) << (BNXT_QPLIB_DBR_TOGGLE_SHIFT)))
+
static inline void bnxt_qplib_ring_db(struct bnxt_qplib_db_info *info,
u32 type)
{
u64 key = 0;
+ u32 indx;
+ u8 toggle = 0;
+
+ if (type == DBC_DBC_TYPE_CQ_ARMALL ||
+ type == DBC_DBC_TYPE_CQ_ARMSE)
+ toggle = info->toggle;
+
+ indx = (info->hwq->cons & DBC_DBC_INDEX_MASK) |
+ ((info->flags & BNXT_QPLIB_FLAG_EPOCH_CONS_MASK) <<
+ BNXT_QPLIB_DB_EPOCH_CONS_SHIFT);
- key = (info->xid & DBC_DBC_XID_MASK) | DBC_DBC_PATH_ROCE | type;
- key <<= 32;
- key |= (info->hwq->cons & (info->hwq->max_elements - 1)) &
- DBC_DBC_INDEX_MASK;
+ key = BNXT_QPLIB_INIT_DBHDR(info->xid, type, indx, toggle);
writeq(key, info->db);
}
@@ -436,10 +495,12 @@ static inline void bnxt_qplib_ring_prod_db(struct bnxt_qplib_db_info *info,
u32 type)
{
u64 key = 0;
+ u32 indx;
- key = (info->xid & DBC_DBC_XID_MASK) | DBC_DBC_PATH_ROCE | type;
- key <<= 32;
- key |= ((info->hwq->prod / info->max_slot)) & DBC_DBC_INDEX_MASK;
+ indx = (((info->hwq->prod / info->max_slot) & DBC_DBC_INDEX_MASK) |
+ ((info->flags & BNXT_QPLIB_FLAG_EPOCH_PROD_MASK) <<
+ BNXT_QPLIB_DB_EPOCH_PROD_SHIFT));
+ key = BNXT_QPLIB_INIT_DBHDR(info->xid, type, indx, 0);
writeq(key, info->db);
}
@@ -447,9 +508,12 @@ static inline void bnxt_qplib_armen_db(struct bnxt_qplib_db_info *info,
u32 type)
{
u64 key = 0;
+ u8 toggle = 0;
- key = (info->xid & DBC_DBC_XID_MASK) | DBC_DBC_PATH_ROCE | type;
- key <<= 32;
+ if (type == DBC_DBC_TYPE_CQ_ARMENA || type == DBC_DBC_TYPE_SRQ_ARMENA)
+ toggle = info->toggle;
+ /* Index always at 0 */
+ key = BNXT_QPLIB_INIT_DBHDR(info->xid, type, 0, toggle);
writeq(key, info->priv_db);
}
@@ -458,9 +522,7 @@ static inline void bnxt_qplib_srq_arm_db(struct bnxt_qplib_db_info *info,
{
u64 key = 0;
- key = (info->xid & DBC_DBC_XID_MASK) | DBC_DBC_PATH_ROCE | th;
- key <<= 32;
- key |= th & DBC_DBC_INDEX_MASK;
+ key = BNXT_QPLIB_INIT_DBHDR(info->xid, DBC_DBC_TYPE_SRQ_ARM, th, info->toggle);
writeq(key, info->priv_db);
}
@@ -471,7 +533,7 @@ static inline void bnxt_qplib_ring_nq_db(struct bnxt_qplib_db_info *info,
u32 type;
type = arm ? DBC_DBC_TYPE_NQ_ARM : DBC_DBC_TYPE_NQ;
- if (bnxt_qplib_is_chip_gen_p5(cctx))
+ if (bnxt_qplib_is_chip_gen_p5_p7(cctx))
bnxt_qplib_ring_db(info, type);
else
bnxt_qplib_ring_db32(info, arm);
@@ -483,6 +545,15 @@ static inline bool _is_ext_stats_supported(u16 dev_cap_flags)
CREQ_QUERY_FUNC_RESP_SB_EXT_STATS;
}
+static inline bool _is_hw_retx_supported(u16 dev_cap_flags)
+{
+ return dev_cap_flags &
+ (CREQ_QUERY_FUNC_RESP_SB_HW_REQUESTER_RETX_ENABLED |
+ CREQ_QUERY_FUNC_RESP_SB_HW_RESPONDER_RETX_ENABLED);
+}
+
+#define BNXT_RE_HW_RETX(a) _is_hw_retx_supported((a))
+
static inline u8 bnxt_qplib_dbr_pacing_en(struct bnxt_qplib_chip_ctx *cctx)
{
return cctx->modes.dbr_pacing;
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c
index a27b68515164..8beeedd15061 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c
@@ -59,7 +59,7 @@ static bool bnxt_qplib_is_atomic_cap(struct bnxt_qplib_rcfw *rcfw)
{
u16 pcie_ctl2 = 0;
- if (!bnxt_qplib_is_chip_gen_p5(rcfw->res->cctx))
+ if (!bnxt_qplib_is_chip_gen_p5_p7(rcfw->res->cctx))
return false;
pcie_capability_read_word(rcfw->pdev, PCI_EXP_DEVCTL2, &pcie_ctl2);
@@ -133,7 +133,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
* reporting the max number
*/
attr->max_qp_wqes -= BNXT_QPLIB_RESERVED_QP_WRS + 1;
- attr->max_qp_sges = bnxt_qplib_is_chip_gen_p5(rcfw->res->cctx) ?
+ attr->max_qp_sges = bnxt_qplib_is_chip_gen_p5_p7(rcfw->res->cctx) ?
6 : sb->max_sge;
attr->max_cq = le32_to_cpu(sb->max_cq);
attr->max_cq_wqes = le32_to_cpu(sb->max_cqe);
@@ -151,8 +151,9 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
attr->max_srq_sges = sb->max_srq_sge;
attr->max_pkey = 1;
attr->max_inline_data = le32_to_cpu(sb->max_inline_data);
- attr->l2_db_size = (sb->l2_db_space_size + 1) *
- (0x01 << RCFW_DBR_BASE_PAGE_SHIFT);
+ if (!bnxt_qplib_is_chip_gen_p7(rcfw->res->cctx))
+ attr->l2_db_size = (sb->l2_db_space_size + 1) *
+ (0x01 << RCFW_DBR_BASE_PAGE_SHIFT);
attr->max_sgid = BNXT_QPLIB_NUM_GIDS_SUPPORTED;
attr->dev_cap_flags = le16_to_cpu(sb->dev_cap_flags);
@@ -934,7 +935,7 @@ int bnxt_qplib_modify_cc(struct bnxt_qplib_res *res,
req->inactivity_th = cpu_to_le16(cc_param->inact_th);
/* For chip gen P5 onwards fill extended cmd and header */
- if (bnxt_qplib_is_chip_gen_p5(res->cctx)) {
+ if (bnxt_qplib_is_chip_gen_p5_p7(res->cctx)) {
struct roce_tlv *hdr;
u32 payload;
u32 chunks;
diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h
index 84b5acd7f7a2..605c9463c408 100644
--- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h
+++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h
@@ -555,7 +555,12 @@ struct cmdq_modify_qp {
__le16 flags;
__le16 cookie;
u8 resp_size;
- u8 reserved8;
+ u8 qp_type;
+ #define CMDQ_MODIFY_QP_QP_TYPE_RC 0x2UL
+ #define CMDQ_MODIFY_QP_QP_TYPE_UD 0x4UL
+ #define CMDQ_MODIFY_QP_QP_TYPE_RAW_ETHERTYPE 0x6UL
+ #define CMDQ_MODIFY_QP_QP_TYPE_GSI 0x7UL
+ #define CMDQ_MODIFY_QP_QP_TYPE_LAST CMDQ_MODIFY_QP_QP_TYPE_GSI
__le64 resp_addr;
__le32 modify_mask;
#define CMDQ_MODIFY_QP_MODIFY_MASK_STATE 0x1UL
@@ -611,14 +616,12 @@ struct cmdq_modify_qp {
#define CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV6 (0x3UL << 6)
#define CMDQ_MODIFY_QP_NETWORK_TYPE_LAST CMDQ_MODIFY_QP_NETWORK_TYPE_ROCEV2_IPV6
u8 access;
- #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_MASK \
- 0xffUL
- #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_SFT \
- 0
- #define CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE 0x1UL
- #define CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE 0x2UL
- #define CMDQ_MODIFY_QP_ACCESS_REMOTE_READ 0x4UL
- #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC 0x8UL
+ #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_MASK 0xffUL
+ #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC_REMOTE_READ_REMOTE_WRITE_LOCAL_WRITE_SFT 0
+ #define CMDQ_MODIFY_QP_ACCESS_LOCAL_WRITE 0x1UL
+ #define CMDQ_MODIFY_QP_ACCESS_REMOTE_WRITE 0x2UL
+ #define CMDQ_MODIFY_QP_ACCESS_REMOTE_READ 0x4UL
+ #define CMDQ_MODIFY_QP_ACCESS_REMOTE_ATOMIC 0x8UL
__le16 pkey;
__le32 qkey;
__le32 dgid[4];
@@ -673,6 +676,13 @@ struct cmdq_modify_qp {
#define CMDQ_MODIFY_QP_VLAN_PCP_SFT 13
__le64 irrq_addr;
__le64 orrq_addr;
+ __le32 ext_modify_mask;
+ #define CMDQ_MODIFY_QP_EXT_MODIFY_MASK_EXT_STATS_CTX 0x1UL
+ #define CMDQ_MODIFY_QP_EXT_MODIFY_MASK_SCHQ_ID_VALID 0x2UL
+ __le32 ext_stats_ctx_id;
+ __le16 schq_id;
+ __le16 unused_0;
+ __le32 reserved32;
};
/* creq_modify_qp_resp (size:128b/16B) */
@@ -3075,6 +3085,17 @@ struct sq_psn_search_ext {
__le32 reserved32;
};
+/* sq_msn_search (size:64b/8B) */
+struct sq_msn_search {
+ __le64 start_idx_next_psn_start_psn;
+ #define SQ_MSN_SEARCH_START_PSN_MASK 0xffffffUL
+ #define SQ_MSN_SEARCH_START_PSN_SFT 0
+ #define SQ_MSN_SEARCH_NEXT_PSN_MASK 0xffffff000000ULL
+ #define SQ_MSN_SEARCH_NEXT_PSN_SFT 24
+ #define SQ_MSN_SEARCH_START_IDX_MASK 0xffff000000000000ULL
+ #define SQ_MSN_SEARCH_START_IDX_SFT 48
+};
+
/* sq_send (size:1024b/128B) */
struct sq_send {
u8 wqe_type;
@@ -3763,13 +3784,35 @@ struct cq_base {
#define CQ_BASE_CQE_TYPE_RES_UD (0x2UL << 1)
#define CQ_BASE_CQE_TYPE_RES_RAWETH_QP1 (0x3UL << 1)
#define CQ_BASE_CQE_TYPE_RES_UD_CFA (0x4UL << 1)
+ #define CQ_BASE_CQE_TYPE_REQ_V3 (0x8UL << 1)
+ #define CQ_BASE_CQE_TYPE_RES_RC_V3 (0x9UL << 1)
+ #define CQ_BASE_CQE_TYPE_RES_UD_V3 (0xaUL << 1)
+ #define CQ_BASE_CQE_TYPE_RES_RAWETH_QP1_V3 (0xbUL << 1)
+ #define CQ_BASE_CQE_TYPE_RES_UD_CFA_V3 (0xcUL << 1)
#define CQ_BASE_CQE_TYPE_NO_OP (0xdUL << 1)
#define CQ_BASE_CQE_TYPE_TERMINAL (0xeUL << 1)
#define CQ_BASE_CQE_TYPE_CUT_OFF (0xfUL << 1)
#define CQ_BASE_CQE_TYPE_LAST CQ_BASE_CQE_TYPE_CUT_OFF
u8 status;
+ #define CQ_BASE_STATUS_OK 0x0UL
+ #define CQ_BASE_STATUS_BAD_RESPONSE_ERR 0x1UL
+ #define CQ_BASE_STATUS_LOCAL_LENGTH_ERR 0x2UL
+ #define CQ_BASE_STATUS_HW_LOCAL_LENGTH_ERR 0x3UL
+ #define CQ_BASE_STATUS_LOCAL_QP_OPERATION_ERR 0x4UL
+ #define CQ_BASE_STATUS_LOCAL_PROTECTION_ERR 0x5UL
+ #define CQ_BASE_STATUS_LOCAL_ACCESS_ERROR 0x6UL
+ #define CQ_BASE_STATUS_MEMORY_MGT_OPERATION_ERR 0x7UL
+ #define CQ_BASE_STATUS_REMOTE_INVALID_REQUEST_ERR 0x8UL
+ #define CQ_BASE_STATUS_REMOTE_ACCESS_ERR 0x9UL
+ #define CQ_BASE_STATUS_REMOTE_OPERATION_ERR 0xaUL
+ #define CQ_BASE_STATUS_RNR_NAK_RETRY_CNT_ERR 0xbUL
+ #define CQ_BASE_STATUS_TRANSPORT_RETRY_CNT_ERR 0xcUL
+ #define CQ_BASE_STATUS_WORK_REQUEST_FLUSHED_ERR 0xdUL
+ #define CQ_BASE_STATUS_HW_FLUSH_ERR 0xeUL
+ #define CQ_BASE_STATUS_OVERFLOW_ERR 0xfUL
+ #define CQ_BASE_STATUS_LAST CQ_BASE_STATUS_OVERFLOW_ERR
__le16 reserved16;
- __le32 reserved32;
+ __le32 opaque;
};
/* cq_req (size:256b/32B) */
@@ -4384,6 +4427,8 @@ struct cq_cutoff {
#define CQ_CUTOFF_CQE_TYPE_SFT 1
#define CQ_CUTOFF_CQE_TYPE_CUT_OFF (0xfUL << 1)
#define CQ_CUTOFF_CQE_TYPE_LAST CQ_CUTOFF_CQE_TYPE_CUT_OFF
+ #define CQ_CUTOFF_RESIZE_TOGGLE_MASK 0x60UL
+ #define CQ_CUTOFF_RESIZE_TOGGLE_SFT 5
u8 status;
#define CQ_CUTOFF_STATUS_OK 0x0UL
#define CQ_CUTOFF_STATUS_LAST CQ_CUTOFF_STATUS_OK
@@ -4435,6 +4480,8 @@ struct nq_srq_event {
#define NQ_SRQ_EVENT_TYPE_SFT 0
#define NQ_SRQ_EVENT_TYPE_SRQ_EVENT 0x32UL
#define NQ_SRQ_EVENT_TYPE_LAST NQ_SRQ_EVENT_TYPE_SRQ_EVENT
+ #define NQ_SRQ_EVENT_TOGGLE_MASK 0xc0UL
+ #define NQ_SRQ_EVENT_TOGGLE_SFT 6
u8 event;
#define NQ_SRQ_EVENT_EVENT_SRQ_THRESHOLD_EVENT 0x1UL
#define NQ_SRQ_EVENT_EVENT_LAST NQ_SRQ_EVENT_EVENT_SRQ_THRESHOLD_EVENT
diff --git a/drivers/infiniband/hw/efa/efa.h b/drivers/infiniband/hw/efa/efa.h
index 7352a1f5d811..e2bdec32ae80 100644
--- a/drivers/infiniband/hw/efa/efa.h
+++ b/drivers/infiniband/hw/efa/efa.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
/*
- * Copyright 2018-2021 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#ifndef _EFA_H_
@@ -80,9 +80,19 @@ struct efa_pd {
u16 pdn;
};
+struct efa_mr_interconnect_info {
+ u16 recv_ic_id;
+ u16 rdma_read_ic_id;
+ u16 rdma_recv_ic_id;
+ u8 recv_ic_id_valid : 1;
+ u8 rdma_read_ic_id_valid : 1;
+ u8 rdma_recv_ic_id_valid : 1;
+};
+
struct efa_mr {
struct ib_mr ibmr;
struct ib_umem *umem;
+ struct efa_mr_interconnect_info ic_info;
};
struct efa_cq {
diff --git a/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h b/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h
index 9c65bd27bae0..7377c8a9f4d5 100644
--- a/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h
+++ b/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
/*
- * Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#ifndef _EFA_ADMIN_CMDS_H_
@@ -415,6 +415,32 @@ struct efa_admin_reg_mr_resp {
* memory region
*/
u32 r_key;
+
+ /*
+ * Mask indicating which fields have valid values
+ * 0 : recv_ic_id
+ * 1 : rdma_read_ic_id
+ * 2 : rdma_recv_ic_id
+ */
+ u8 validity;
+
+ /*
+ * Physical interconnect used by the device to reach the MR for receive
+ * operation
+ */
+ u8 recv_ic_id;
+
+ /*
+ * Physical interconnect used by the device to reach the MR for RDMA
+ * read operation
+ */
+ u8 rdma_read_ic_id;
+
+ /*
+ * Physical interconnect used by the device to reach the MR for RDMA
+ * write receive
+ */
+ u8 rdma_recv_ic_id;
};
struct efa_admin_dereg_mr_cmd {
@@ -999,6 +1025,11 @@ struct efa_admin_host_info {
#define EFA_ADMIN_REG_MR_CMD_REMOTE_WRITE_ENABLE_MASK BIT(1)
#define EFA_ADMIN_REG_MR_CMD_REMOTE_READ_ENABLE_MASK BIT(2)
+/* reg_mr_resp */
+#define EFA_ADMIN_REG_MR_RESP_RECV_IC_ID_MASK BIT(0)
+#define EFA_ADMIN_REG_MR_RESP_RDMA_READ_IC_ID_MASK BIT(1)
+#define EFA_ADMIN_REG_MR_RESP_RDMA_RECV_IC_ID_MASK BIT(2)
+
/* create_cq_cmd */
#define EFA_ADMIN_CREATE_CQ_CMD_INTERRUPT_MODE_ENABLED_MASK BIT(5)
#define EFA_ADMIN_CREATE_CQ_CMD_VIRT_MASK BIT(6)
diff --git a/drivers/infiniband/hw/efa/efa_com_cmd.c b/drivers/infiniband/hw/efa/efa_com_cmd.c
index 576811885d59..d3398c7b0bd0 100644
--- a/drivers/infiniband/hw/efa/efa_com_cmd.c
+++ b/drivers/infiniband/hw/efa/efa_com_cmd.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
/*
- * Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#include "efa_com.h"
@@ -270,6 +270,15 @@ int efa_com_register_mr(struct efa_com_dev *edev,
result->l_key = cmd_completion.l_key;
result->r_key = cmd_completion.r_key;
+ result->ic_info.recv_ic_id = cmd_completion.recv_ic_id;
+ result->ic_info.rdma_read_ic_id = cmd_completion.rdma_read_ic_id;
+ result->ic_info.rdma_recv_ic_id = cmd_completion.rdma_recv_ic_id;
+ result->ic_info.recv_ic_id_valid = EFA_GET(&cmd_completion.validity,
+ EFA_ADMIN_REG_MR_RESP_RECV_IC_ID);
+ result->ic_info.rdma_read_ic_id_valid = EFA_GET(&cmd_completion.validity,
+ EFA_ADMIN_REG_MR_RESP_RDMA_READ_IC_ID);
+ result->ic_info.rdma_recv_ic_id_valid = EFA_GET(&cmd_completion.validity,
+ EFA_ADMIN_REG_MR_RESP_RDMA_RECV_IC_ID);
return 0;
}
diff --git a/drivers/infiniband/hw/efa/efa_com_cmd.h b/drivers/infiniband/hw/efa/efa_com_cmd.h
index fc97f37bb39b..720a99ba0f7d 100644
--- a/drivers/infiniband/hw/efa/efa_com_cmd.h
+++ b/drivers/infiniband/hw/efa/efa_com_cmd.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
/*
- * Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#ifndef _EFA_COM_CMD_H_
@@ -199,6 +199,15 @@ struct efa_com_reg_mr_params {
u8 indirect;
};
+struct efa_com_mr_interconnect_info {
+ u16 recv_ic_id;
+ u16 rdma_read_ic_id;
+ u16 rdma_recv_ic_id;
+ u8 recv_ic_id_valid : 1;
+ u8 rdma_read_ic_id_valid : 1;
+ u8 rdma_recv_ic_id_valid : 1;
+};
+
struct efa_com_reg_mr_result {
/*
* To be used in conjunction with local buffers references in SQ and
@@ -210,6 +219,7 @@ struct efa_com_reg_mr_result {
* accessed memory region
*/
u32 r_key;
+ struct efa_com_mr_interconnect_info ic_info;
};
struct efa_com_dereg_mr_params {
diff --git a/drivers/infiniband/hw/efa/efa_main.c b/drivers/infiniband/hw/efa/efa_main.c
index 15ee92081118..7b1910a86216 100644
--- a/drivers/infiniband/hw/efa/efa_main.c
+++ b/drivers/infiniband/hw/efa/efa_main.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
/*
- * Copyright 2018-2022 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#include <linux/module.h>
@@ -9,6 +9,7 @@
#include <linux/version.h>
#include <rdma/ib_user_verbs.h>
+#include <rdma/uverbs_ioctl.h>
#include "efa.h"
@@ -36,6 +37,8 @@ MODULE_DEVICE_TABLE(pci, efa_pci_tbl);
(BIT(EFA_ADMIN_FATAL_ERROR) | BIT(EFA_ADMIN_WARNING) | \
BIT(EFA_ADMIN_NOTIFICATION) | BIT(EFA_ADMIN_KEEP_ALIVE))
+extern const struct uapi_definition efa_uapi_defs[];
+
/* This handler will called for unknown event group or unimplemented handlers */
static void unimplemented_aenq_handler(void *data,
struct efa_admin_aenq_entry *aenq_e)
@@ -432,6 +435,8 @@ static int efa_ib_device_add(struct efa_dev *dev)
ib_set_device_ops(&dev->ibdev, &efa_dev_ops);
+ dev->ibdev.driver_def = efa_uapi_defs;
+
err = ib_register_device(&dev->ibdev, "efa_%d", &pdev->dev);
if (err)
goto err_destroy_eqs;
diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c
index 0f8ca99d0827..2f412db2edcd 100644
--- a/drivers/infiniband/hw/efa/efa_verbs.c
+++ b/drivers/infiniband/hw/efa/efa_verbs.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
- * Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#include <linux/dma-buf.h>
@@ -13,6 +13,9 @@
#include <rdma/ib_user_verbs.h>
#include <rdma/ib_verbs.h>
#include <rdma/uverbs_ioctl.h>
+#define UVERBS_MODULE_NAME efa_ib
+#include <rdma/uverbs_named_ioctl.h>
+#include <rdma/ib_user_ioctl_cmds.h>
#include "efa.h"
#include "efa_io_defs.h"
@@ -1653,6 +1656,12 @@ static int efa_register_mr(struct ib_pd *ibpd, struct efa_mr *mr, u64 start,
mr->ibmr.lkey = result.l_key;
mr->ibmr.rkey = result.r_key;
mr->ibmr.length = length;
+ mr->ic_info.recv_ic_id = result.ic_info.recv_ic_id;
+ mr->ic_info.rdma_read_ic_id = result.ic_info.rdma_read_ic_id;
+ mr->ic_info.rdma_recv_ic_id = result.ic_info.rdma_recv_ic_id;
+ mr->ic_info.recv_ic_id_valid = result.ic_info.recv_ic_id_valid;
+ mr->ic_info.rdma_read_ic_id_valid = result.ic_info.rdma_read_ic_id_valid;
+ mr->ic_info.rdma_recv_ic_id_valid = result.ic_info.rdma_recv_ic_id_valid;
ibdev_dbg(&dev->ibdev, "Registered mr[%d]\n", mr->ibmr.lkey);
return 0;
@@ -1735,6 +1744,39 @@ err_out:
return ERR_PTR(err);
}
+static int UVERBS_HANDLER(EFA_IB_METHOD_MR_QUERY)(struct uverbs_attr_bundle *attrs)
+{
+ struct ib_mr *ibmr = uverbs_attr_get_obj(attrs, EFA_IB_ATTR_QUERY_MR_HANDLE);
+ struct efa_mr *mr = to_emr(ibmr);
+ u16 ic_id_validity = 0;
+ int ret;
+
+ ret = uverbs_copy_to(attrs, EFA_IB_ATTR_QUERY_MR_RESP_RECV_IC_ID,
+ &mr->ic_info.recv_ic_id, sizeof(mr->ic_info.recv_ic_id));
+ if (ret)
+ return ret;
+
+ ret = uverbs_copy_to(attrs, EFA_IB_ATTR_QUERY_MR_RESP_RDMA_READ_IC_ID,
+ &mr->ic_info.rdma_read_ic_id, sizeof(mr->ic_info.rdma_read_ic_id));
+ if (ret)
+ return ret;
+
+ ret = uverbs_copy_to(attrs, EFA_IB_ATTR_QUERY_MR_RESP_RDMA_RECV_IC_ID,
+ &mr->ic_info.rdma_recv_ic_id, sizeof(mr->ic_info.rdma_recv_ic_id));
+ if (ret)
+ return ret;
+
+ if (mr->ic_info.recv_ic_id_valid)
+ ic_id_validity |= EFA_QUERY_MR_VALIDITY_RECV_IC_ID;
+ if (mr->ic_info.rdma_read_ic_id_valid)
+ ic_id_validity |= EFA_QUERY_MR_VALIDITY_RDMA_READ_IC_ID;
+ if (mr->ic_info.rdma_recv_ic_id_valid)
+ ic_id_validity |= EFA_QUERY_MR_VALIDITY_RDMA_RECV_IC_ID;
+
+ return uverbs_copy_to(attrs, EFA_IB_ATTR_QUERY_MR_RESP_IC_ID_VALIDITY,
+ &ic_id_validity, sizeof(ic_id_validity));
+}
+
int efa_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
{
struct efa_dev *dev = to_edev(ibmr->device);
@@ -2157,3 +2199,30 @@ enum rdma_link_layer efa_port_link_layer(struct ib_device *ibdev,
return IB_LINK_LAYER_UNSPECIFIED;
}
+DECLARE_UVERBS_NAMED_METHOD(EFA_IB_METHOD_MR_QUERY,
+ UVERBS_ATTR_IDR(EFA_IB_ATTR_QUERY_MR_HANDLE,
+ UVERBS_OBJECT_MR,
+ UVERBS_ACCESS_READ,
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_OUT(EFA_IB_ATTR_QUERY_MR_RESP_IC_ID_VALIDITY,
+ UVERBS_ATTR_TYPE(u16),
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_OUT(EFA_IB_ATTR_QUERY_MR_RESP_RECV_IC_ID,
+ UVERBS_ATTR_TYPE(u16),
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_OUT(EFA_IB_ATTR_QUERY_MR_RESP_RDMA_READ_IC_ID,
+ UVERBS_ATTR_TYPE(u16),
+ UA_MANDATORY),
+ UVERBS_ATTR_PTR_OUT(EFA_IB_ATTR_QUERY_MR_RESP_RDMA_RECV_IC_ID,
+ UVERBS_ATTR_TYPE(u16),
+ UA_MANDATORY));
+
+ADD_UVERBS_METHODS(efa_mr,
+ UVERBS_OBJECT_MR,
+ &UVERBS_METHOD(EFA_IB_METHOD_MR_QUERY));
+
+const struct uapi_definition efa_uapi_defs[] = {
+ UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_MR,
+ &efa_mr),
+ {},
+};
diff --git a/drivers/infiniband/hw/erdma/erdma.h b/drivers/infiniband/hw/erdma/erdma.h
index f190111840e9..5df401a30cb9 100644
--- a/drivers/infiniband/hw/erdma/erdma.h
+++ b/drivers/infiniband/hw/erdma/erdma.h
@@ -212,6 +212,8 @@ struct erdma_dev {
atomic_t num_ctx;
struct list_head cep_list;
+
+ struct dma_pool *resp_pool;
};
static inline void *get_queue_entry(void *qbuf, u32 idx, u32 depth, u32 shift)
diff --git a/drivers/infiniband/hw/erdma/erdma_hw.h b/drivers/infiniband/hw/erdma/erdma_hw.h
index a155519a862f..3212a1222760 100644
--- a/drivers/infiniband/hw/erdma/erdma_hw.h
+++ b/drivers/infiniband/hw/erdma/erdma_hw.h
@@ -144,6 +144,7 @@ enum CMDQ_COMMON_OPCODE {
CMDQ_OPCODE_DESTROY_EQ = 1,
CMDQ_OPCODE_QUERY_FW_INFO = 2,
CMDQ_OPCODE_CONF_MTU = 3,
+ CMDQ_OPCODE_GET_STATS = 4,
CMDQ_OPCODE_CONF_DEVICE = 5,
CMDQ_OPCODE_ALLOC_DB = 8,
CMDQ_OPCODE_FREE_DB = 9,
@@ -355,6 +356,44 @@ struct erdma_cmdq_reflush_req {
u32 rq_pi;
};
+#define ERDMA_HW_RESP_SIZE 256
+
+struct erdma_cmdq_query_req {
+ u64 hdr;
+ u32 rsvd;
+ u32 index;
+
+ u64 target_addr;
+ u32 target_length;
+};
+
+#define ERDMA_HW_RESP_MAGIC 0x5566
+
+struct erdma_cmdq_query_resp_hdr {
+ u16 magic;
+ u8 ver;
+ u8 length;
+
+ u32 index;
+ u32 rsvd[2];
+};
+
+struct erdma_cmdq_query_stats_resp {
+ struct erdma_cmdq_query_resp_hdr hdr;
+
+ u64 tx_req_cnt;
+ u64 tx_packets_cnt;
+ u64 tx_bytes_cnt;
+ u64 tx_drop_packets_cnt;
+ u64 tx_bps_meter_drop_packets_cnt;
+ u64 tx_pps_meter_drop_packets_cnt;
+ u64 rx_packets_cnt;
+ u64 rx_bytes_cnt;
+ u64 rx_drop_packets_cnt;
+ u64 rx_bps_meter_drop_packets_cnt;
+ u64 rx_pps_meter_drop_packets_cnt;
+};
+
/* cap qword 0 definition */
#define ERDMA_CMD_DEV_CAP_MAX_CQE_MASK GENMASK_ULL(47, 40)
#define ERDMA_CMD_DEV_CAP_FLAGS_MASK GENMASK_ULL(31, 24)
diff --git a/drivers/infiniband/hw/erdma/erdma_main.c b/drivers/infiniband/hw/erdma/erdma_main.c
index 0880c79a978c..472939172f0c 100644
--- a/drivers/infiniband/hw/erdma/erdma_main.c
+++ b/drivers/infiniband/hw/erdma/erdma_main.c
@@ -172,14 +172,30 @@ static int erdma_device_init(struct erdma_dev *dev, struct pci_dev *pdev)
{
int ret;
+ dev->resp_pool = dma_pool_create("erdma_resp_pool", &pdev->dev,
+ ERDMA_HW_RESP_SIZE, ERDMA_HW_RESP_SIZE,
+ 0);
+ if (!dev->resp_pool)
+ return -ENOMEM;
+
ret = dma_set_mask_and_coherent(&pdev->dev,
DMA_BIT_MASK(ERDMA_PCI_WIDTH));
if (ret)
- return ret;
+ goto destroy_pool;
dma_set_max_seg_size(&pdev->dev, UINT_MAX);
return 0;
+
+destroy_pool:
+ dma_pool_destroy(dev->resp_pool);
+
+ return ret;
+}
+
+static void erdma_device_uninit(struct erdma_dev *dev)
+{
+ dma_pool_destroy(dev->resp_pool);
}
static void erdma_hw_reset(struct erdma_dev *dev)
@@ -273,7 +289,7 @@ static int erdma_probe_dev(struct pci_dev *pdev)
err = erdma_request_vectors(dev);
if (err)
- goto err_iounmap_func_bar;
+ goto err_uninit_device;
err = erdma_comm_irq_init(dev);
if (err)
@@ -314,6 +330,9 @@ err_uninit_comm_irq:
err_free_vectors:
pci_free_irq_vectors(dev->pdev);
+err_uninit_device:
+ erdma_device_uninit(dev);
+
err_iounmap_func_bar:
devm_iounmap(&pdev->dev, dev->func_bar);
@@ -339,6 +358,7 @@ static void erdma_remove_dev(struct pci_dev *pdev)
erdma_aeq_destroy(dev);
erdma_comm_irq_uninit(dev);
pci_free_irq_vectors(dev->pdev);
+ erdma_device_uninit(dev);
devm_iounmap(&pdev->dev, dev->func_bar);
pci_release_selected_regions(pdev, ERDMA_BAR_MASK);
@@ -448,6 +468,7 @@ static const struct ib_device_ops erdma_device_ops = {
.driver_id = RDMA_DRIVER_ERDMA,
.uverbs_abi_ver = ERDMA_ABI_VERSION,
+ .alloc_hw_port_stats = erdma_alloc_hw_port_stats,
.alloc_mr = erdma_ib_alloc_mr,
.alloc_pd = erdma_alloc_pd,
.alloc_ucontext = erdma_alloc_ucontext,
@@ -459,6 +480,7 @@ static const struct ib_device_ops erdma_device_ops = {
.destroy_cq = erdma_destroy_cq,
.destroy_qp = erdma_destroy_qp,
.get_dma_mr = erdma_get_dma_mr,
+ .get_hw_stats = erdma_get_hw_stats,
.get_port_immutable = erdma_get_port_immutable,
.iw_accept = erdma_accept,
.iw_add_ref = erdma_qp_get_ref,
diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c
index c317947563fb..23dfc01603f8 100644
--- a/drivers/infiniband/hw/erdma/erdma_verbs.c
+++ b/drivers/infiniband/hw/erdma/erdma_verbs.c
@@ -1708,3 +1708,93 @@ void erdma_port_event(struct erdma_dev *dev, enum ib_event_type reason)
ib_dispatch_event(&event);
}
+
+enum counters {
+ ERDMA_STATS_TX_REQS_CNT,
+ ERDMA_STATS_TX_PACKETS_CNT,
+ ERDMA_STATS_TX_BYTES_CNT,
+ ERDMA_STATS_TX_DISABLE_DROP_CNT,
+ ERDMA_STATS_TX_BPS_METER_DROP_CNT,
+ ERDMA_STATS_TX_PPS_METER_DROP_CNT,
+
+ ERDMA_STATS_RX_PACKETS_CNT,
+ ERDMA_STATS_RX_BYTES_CNT,
+ ERDMA_STATS_RX_DISABLE_DROP_CNT,
+ ERDMA_STATS_RX_BPS_METER_DROP_CNT,
+ ERDMA_STATS_RX_PPS_METER_DROP_CNT,
+
+ ERDMA_STATS_MAX
+};
+
+static const struct rdma_stat_desc erdma_descs[] = {
+ [ERDMA_STATS_TX_REQS_CNT].name = "tx_reqs_cnt",
+ [ERDMA_STATS_TX_PACKETS_CNT].name = "tx_packets_cnt",
+ [ERDMA_STATS_TX_BYTES_CNT].name = "tx_bytes_cnt",
+ [ERDMA_STATS_TX_DISABLE_DROP_CNT].name = "tx_disable_drop_cnt",
+ [ERDMA_STATS_TX_BPS_METER_DROP_CNT].name = "tx_bps_limit_drop_cnt",
+ [ERDMA_STATS_TX_PPS_METER_DROP_CNT].name = "tx_pps_limit_drop_cnt",
+ [ERDMA_STATS_RX_PACKETS_CNT].name = "rx_packets_cnt",
+ [ERDMA_STATS_RX_BYTES_CNT].name = "rx_bytes_cnt",
+ [ERDMA_STATS_RX_DISABLE_DROP_CNT].name = "rx_disable_drop_cnt",
+ [ERDMA_STATS_RX_BPS_METER_DROP_CNT].name = "rx_bps_limit_drop_cnt",
+ [ERDMA_STATS_RX_PPS_METER_DROP_CNT].name = "rx_pps_limit_drop_cnt",
+};
+
+struct rdma_hw_stats *erdma_alloc_hw_port_stats(struct ib_device *device,
+ u32 port_num)
+{
+ return rdma_alloc_hw_stats_struct(erdma_descs, ERDMA_STATS_MAX,
+ RDMA_HW_STATS_DEFAULT_LIFESPAN);
+}
+
+static int erdma_query_hw_stats(struct erdma_dev *dev,
+ struct rdma_hw_stats *stats)
+{
+ struct erdma_cmdq_query_stats_resp *resp;
+ struct erdma_cmdq_query_req req;
+ dma_addr_t dma_addr;
+ int err;
+
+ erdma_cmdq_build_reqhdr(&req.hdr, CMDQ_SUBMOD_COMMON,
+ CMDQ_OPCODE_GET_STATS);
+
+ resp = dma_pool_zalloc(dev->resp_pool, GFP_KERNEL, &dma_addr);
+ if (!resp)
+ return -ENOMEM;
+
+ req.target_addr = dma_addr;
+ req.target_length = ERDMA_HW_RESP_SIZE;
+
+ err = erdma_post_cmd_wait(&dev->cmdq, &req, sizeof(req), NULL, NULL);
+ if (err)
+ goto out;
+
+ if (resp->hdr.magic != ERDMA_HW_RESP_MAGIC) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ memcpy(&stats->value[0], &resp->tx_req_cnt,
+ sizeof(u64) * stats->num_counters);
+
+out:
+ dma_pool_free(dev->resp_pool, resp, dma_addr);
+
+ return err;
+}
+
+int erdma_get_hw_stats(struct ib_device *ibdev, struct rdma_hw_stats *stats,
+ u32 port, int index)
+{
+ struct erdma_dev *dev = to_edev(ibdev);
+ int ret;
+
+ if (port == 0)
+ return 0;
+
+ ret = erdma_query_hw_stats(dev, stats);
+ if (ret)
+ return ret;
+
+ return stats->num_counters;
+}
diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.h b/drivers/infiniband/hw/erdma/erdma_verbs.h
index eb9c0f92fb6f..db6018529ccc 100644
--- a/drivers/infiniband/hw/erdma/erdma_verbs.h
+++ b/drivers/infiniband/hw/erdma/erdma_verbs.h
@@ -361,5 +361,9 @@ int erdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
unsigned int *sg_offset);
void erdma_port_event(struct erdma_dev *dev, enum ib_event_type reason);
void erdma_set_mtu(struct erdma_dev *dev, u32 mtu);
+struct rdma_hw_stats *erdma_alloc_hw_port_stats(struct ib_device *device,
+ u32 port_num);
+int erdma_get_hw_stats(struct ib_device *ibdev, struct rdma_hw_stats *stats,
+ u32 port, int index);
#endif
diff --git a/drivers/infiniband/hw/hfi1/user_exp_rcv.c b/drivers/infiniband/hw/hfi1/user_exp_rcv.c
index 6419872f95cf..cf2d29098406 100644
--- a/drivers/infiniband/hw/hfi1/user_exp_rcv.c
+++ b/drivers/infiniband/hw/hfi1/user_exp_rcv.c
@@ -491,8 +491,8 @@ int hfi1_user_exp_rcv_clear(struct hfi1_filedata *fd,
if (unlikely(tinfo->tidcnt > fd->tid_used))
return -EINVAL;
- tidinfo = memdup_user(u64_to_user_ptr(tinfo->tidlist),
- sizeof(tidinfo[0]) * tinfo->tidcnt);
+ tidinfo = memdup_array_user(u64_to_user_ptr(tinfo->tidlist),
+ tinfo->tidcnt, sizeof(tidinfo[0]));
if (IS_ERR(tidinfo))
return PTR_ERR(tidinfo);
diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c
index 6a4aa59c0cbc..b72625283fcf 100644
--- a/drivers/infiniband/hw/hfi1/user_sdma.c
+++ b/drivers/infiniband/hw/hfi1/user_sdma.c
@@ -494,8 +494,8 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd,
* equal to the pkt count. However, there is no way to
* tell at this point.
*/
- tmp = memdup_user(iovec[idx].iov_base,
- ntids * sizeof(*req->tids));
+ tmp = memdup_array_user(iovec[idx].iov_base,
+ ntids, sizeof(*req->tids));
if (IS_ERR(tmp)) {
ret = PTR_ERR(tmp);
SDMA_DBG(req, "Failed to copy %d TIDs (%d)",
diff --git a/drivers/infiniband/hw/hns/Makefile b/drivers/infiniband/hw/hns/Makefile
index a7d259238305..be1e1cdbcfa8 100644
--- a/drivers/infiniband/hw/hns/Makefile
+++ b/drivers/infiniband/hw/hns/Makefile
@@ -7,7 +7,8 @@ ccflags-y := -I $(srctree)/drivers/net/ethernet/hisilicon/hns3
hns-roce-objs := hns_roce_main.o hns_roce_cmd.o hns_roce_pd.o \
hns_roce_ah.o hns_roce_hem.o hns_roce_mr.o hns_roce_qp.o \
- hns_roce_cq.o hns_roce_alloc.o hns_roce_db.o hns_roce_srq.o hns_roce_restrack.o
+ hns_roce_cq.o hns_roce_alloc.o hns_roce_db.o hns_roce_srq.o hns_roce_restrack.o \
+ hns_roce_debugfs.o
ifdef CONFIG_INFINIBAND_HNS_HIP08
hns-roce-hw-v2-objs := hns_roce_hw_v2.o $(hns-roce-objs)
diff --git a/drivers/infiniband/hw/hns/hns_roce_ah.c b/drivers/infiniband/hw/hns/hns_roce_ah.c
index 3df032ddda18..b4209b6aed8d 100644
--- a/drivers/infiniband/hw/hns/hns_roce_ah.c
+++ b/drivers/infiniband/hw/hns/hns_roce_ah.c
@@ -57,6 +57,7 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr,
struct rdma_ah_attr *ah_attr = init_attr->ah_attr;
const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr);
struct hns_roce_dev *hr_dev = to_hr_dev(ibah->device);
+ struct hns_roce_ib_create_ah_resp resp = {};
struct hns_roce_ah *ah = to_hr_ah(ibah);
int ret = 0;
u32 max_sl;
@@ -92,11 +93,21 @@ int hns_roce_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr,
ret = rdma_read_gid_l2_fields(ah_attr->grh.sgid_attr,
&ah->av.vlan_id, NULL);
if (ret)
- return ret;
+ goto err_out;
ah->av.vlan_en = ah->av.vlan_id < VLAN_N_VID;
}
+ if (udata) {
+ memcpy(resp.dmac, ah_attr->roce.dmac, ETH_ALEN);
+ ret = ib_copy_to_udata(udata, &resp,
+ min(udata->outlen, sizeof(resp)));
+ }
+
+err_out:
+ if (ret)
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_AH_CREATE_ERR_CNT]);
+
return ret;
}
diff --git a/drivers/infiniband/hw/hns/hns_roce_cmd.c b/drivers/infiniband/hw/hns/hns_roce_cmd.c
index 864413607571..873e8a69a1b9 100644
--- a/drivers/infiniband/hw/hns/hns_roce_cmd.c
+++ b/drivers/infiniband/hw/hns/hns_roce_cmd.c
@@ -41,7 +41,15 @@
static int hns_roce_cmd_mbox_post_hw(struct hns_roce_dev *hr_dev,
struct hns_roce_mbox_msg *mbox_msg)
{
- return hr_dev->hw->post_mbox(hr_dev, mbox_msg);
+ int ret;
+
+ ret = hr_dev->hw->post_mbox(hr_dev, mbox_msg);
+ if (ret)
+ return ret;
+
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MBX_POSTED_CNT]);
+
+ return 0;
}
/* this should be called with "poll_sem" */
@@ -58,7 +66,13 @@ static int __hns_roce_cmd_mbox_poll(struct hns_roce_dev *hr_dev,
return ret;
}
- return hr_dev->hw->poll_mbox_done(hr_dev);
+ ret = hr_dev->hw->poll_mbox_done(hr_dev);
+ if (ret)
+ return ret;
+
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MBX_POLLED_CNT]);
+
+ return 0;
}
static int hns_roce_cmd_mbox_poll(struct hns_roce_dev *hr_dev,
@@ -89,6 +103,7 @@ void hns_roce_cmd_event(struct hns_roce_dev *hr_dev, u16 token, u8 status,
context->result = (status == HNS_ROCE_CMD_SUCCESS) ? 0 : (-EIO);
context->out_param = out_param;
complete(&context->done);
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MBX_EVENT_CNT]);
}
static int __hns_roce_cmd_mbox_wait(struct hns_roce_dev *hr_dev,
diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c
index 736dc2f993b4..1b6d16af8c12 100644
--- a/drivers/infiniband/hw/hns/hns_roce_cq.c
+++ b/drivers/infiniband/hw/hns/hns_roce_cq.c
@@ -363,29 +363,31 @@ int hns_roce_create_cq(struct ib_cq *ib_cq, const struct ib_cq_init_attr *attr,
struct hns_roce_ib_create_cq ucmd = {};
int ret;
- if (attr->flags)
- return -EOPNOTSUPP;
+ if (attr->flags) {
+ ret = -EOPNOTSUPP;
+ goto err_out;
+ }
ret = verify_cq_create_attr(hr_dev, attr);
if (ret)
- return ret;
+ goto err_out;
if (udata) {
ret = get_cq_ucmd(hr_cq, udata, &ucmd);
if (ret)
- return ret;
+ goto err_out;
}
set_cq_param(hr_cq, attr->cqe, attr->comp_vector, &ucmd);
ret = set_cqe_size(hr_cq, udata, &ucmd);
if (ret)
- return ret;
+ goto err_out;
ret = alloc_cq_buf(hr_dev, hr_cq, udata, ucmd.buf_addr);
if (ret) {
ibdev_err(ibdev, "failed to alloc CQ buf, ret = %d.\n", ret);
- return ret;
+ goto err_out;
}
ret = alloc_cq_db(hr_dev, hr_cq, udata, ucmd.db_addr, &resp);
@@ -430,6 +432,9 @@ err_cq_db:
free_cq_db(hr_dev, hr_cq, udata);
err_cq_buf:
free_cq_buf(hr_dev, hr_cq);
+err_out:
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_CQ_CREATE_ERR_CNT]);
+
return ret;
}
diff --git a/drivers/infiniband/hw/hns/hns_roce_debugfs.c b/drivers/infiniband/hw/hns/hns_roce_debugfs.c
new file mode 100644
index 000000000000..e8febb40f645
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_debugfs.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2023 Hisilicon Limited.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+
+#include "hns_roce_device.h"
+
+static struct dentry *hns_roce_dbgfs_root;
+
+static int hns_debugfs_seqfile_open(struct inode *inode, struct file *f)
+{
+ struct hns_debugfs_seqfile *seqfile = inode->i_private;
+
+ return single_open(f, seqfile->read, seqfile->data);
+}
+
+static const struct file_operations hns_debugfs_seqfile_fops = {
+ .owner = THIS_MODULE,
+ .open = hns_debugfs_seqfile_open,
+ .release = single_release,
+ .read = seq_read,
+ .llseek = seq_lseek
+};
+
+static void init_debugfs_seqfile(struct hns_debugfs_seqfile *seq,
+ const char *name, struct dentry *parent,
+ int (*read_fn)(struct seq_file *, void *),
+ void *data)
+{
+ debugfs_create_file(name, 0400, parent, seq, &hns_debugfs_seqfile_fops);
+
+ seq->read = read_fn;
+ seq->data = data;
+}
+
+static const char * const sw_stat_info[] = {
+ [HNS_ROCE_DFX_AEQE_CNT] = "aeqe",
+ [HNS_ROCE_DFX_CEQE_CNT] = "ceqe",
+ [HNS_ROCE_DFX_CMDS_CNT] = "cmds",
+ [HNS_ROCE_DFX_CMDS_ERR_CNT] = "cmds_err",
+ [HNS_ROCE_DFX_MBX_POSTED_CNT] = "posted_mbx",
+ [HNS_ROCE_DFX_MBX_POLLED_CNT] = "polled_mbx",
+ [HNS_ROCE_DFX_MBX_EVENT_CNT] = "mbx_event",
+ [HNS_ROCE_DFX_QP_CREATE_ERR_CNT] = "qp_create_err",
+ [HNS_ROCE_DFX_QP_MODIFY_ERR_CNT] = "qp_modify_err",
+ [HNS_ROCE_DFX_CQ_CREATE_ERR_CNT] = "cq_create_err",
+ [HNS_ROCE_DFX_CQ_MODIFY_ERR_CNT] = "cq_modify_err",
+ [HNS_ROCE_DFX_SRQ_CREATE_ERR_CNT] = "srq_create_err",
+ [HNS_ROCE_DFX_SRQ_MODIFY_ERR_CNT] = "srq_modify_err",
+ [HNS_ROCE_DFX_XRCD_ALLOC_ERR_CNT] = "xrcd_alloc_err",
+ [HNS_ROCE_DFX_MR_REG_ERR_CNT] = "mr_reg_err",
+ [HNS_ROCE_DFX_MR_REREG_ERR_CNT] = "mr_rereg_err",
+ [HNS_ROCE_DFX_AH_CREATE_ERR_CNT] = "ah_create_err",
+ [HNS_ROCE_DFX_MMAP_ERR_CNT] = "mmap_err",
+ [HNS_ROCE_DFX_UCTX_ALLOC_ERR_CNT] = "uctx_alloc_err",
+};
+
+static int sw_stat_debugfs_show(struct seq_file *file, void *offset)
+{
+ struct hns_roce_dev *hr_dev = file->private;
+ int i;
+
+ for (i = 0; i < HNS_ROCE_DFX_CNT_TOTAL; i++)
+ seq_printf(file, "%-20s --- %lld\n", sw_stat_info[i],
+ atomic64_read(&hr_dev->dfx_cnt[i]));
+
+ return 0;
+}
+
+static void create_sw_stat_debugfs(struct hns_roce_dev *hr_dev,
+ struct dentry *parent)
+{
+ struct hns_sw_stat_debugfs *dbgfs = &hr_dev->dbgfs.sw_stat_root;
+
+ dbgfs->root = debugfs_create_dir("sw_stat", parent);
+
+ init_debugfs_seqfile(&dbgfs->sw_stat, "sw_stat", dbgfs->root,
+ sw_stat_debugfs_show, hr_dev);
+}
+
+/* debugfs for device */
+void hns_roce_register_debugfs(struct hns_roce_dev *hr_dev)
+{
+ struct hns_roce_dev_debugfs *dbgfs = &hr_dev->dbgfs;
+
+ dbgfs->root = debugfs_create_dir(dev_name(&hr_dev->ib_dev.dev),
+ hns_roce_dbgfs_root);
+
+ create_sw_stat_debugfs(hr_dev, dbgfs->root);
+}
+
+void hns_roce_unregister_debugfs(struct hns_roce_dev *hr_dev)
+{
+ debugfs_remove_recursive(hr_dev->dbgfs.root);
+}
+
+/* debugfs for hns module */
+void hns_roce_init_debugfs(void)
+{
+ hns_roce_dbgfs_root = debugfs_create_dir("hns_roce", NULL);
+}
+
+void hns_roce_cleanup_debugfs(void)
+{
+ debugfs_remove_recursive(hns_roce_dbgfs_root);
+ hns_roce_dbgfs_root = NULL;
+}
diff --git a/drivers/infiniband/hw/hns/hns_roce_debugfs.h b/drivers/infiniband/hw/hns/hns_roce_debugfs.h
new file mode 100644
index 000000000000..98e87bd3161e
--- /dev/null
+++ b/drivers/infiniband/hw/hns/hns_roce_debugfs.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2023 Hisilicon Limited.
+ */
+
+#ifndef __HNS_ROCE_DEBUGFS_H
+#define __HNS_ROCE_DEBUGFS_H
+
+/* debugfs seqfile */
+struct hns_debugfs_seqfile {
+ int (*read)(struct seq_file *seq, void *data);
+ void *data;
+};
+
+struct hns_sw_stat_debugfs {
+ struct dentry *root;
+ struct hns_debugfs_seqfile sw_stat;
+};
+
+/* Debugfs for device */
+struct hns_roce_dev_debugfs {
+ struct dentry *root;
+ struct hns_sw_stat_debugfs sw_stat_root;
+};
+
+struct hns_roce_dev;
+
+void hns_roce_init_debugfs(void);
+void hns_roce_cleanup_debugfs(void);
+void hns_roce_register_debugfs(struct hns_roce_dev *hr_dev);
+void hns_roce_unregister_debugfs(struct hns_roce_dev *hr_dev);
+
+#endif
diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
index 1627f3b0ef28..b1fce5ddf631 100644
--- a/drivers/infiniband/hw/hns/hns_roce_device.h
+++ b/drivers/infiniband/hw/hns/hns_roce_device.h
@@ -35,6 +35,7 @@
#include <rdma/ib_verbs.h>
#include <rdma/hns-abi.h>
+#include "hns_roce_debugfs.h"
#define PCI_REVISION_ID_HIP08 0x21
#define PCI_REVISION_ID_HIP09 0x30
@@ -869,6 +870,29 @@ enum hns_roce_hw_pkt_stat_index {
HNS_ROCE_HW_CNT_TOTAL
};
+enum hns_roce_sw_dfx_stat_index {
+ HNS_ROCE_DFX_AEQE_CNT,
+ HNS_ROCE_DFX_CEQE_CNT,
+ HNS_ROCE_DFX_CMDS_CNT,
+ HNS_ROCE_DFX_CMDS_ERR_CNT,
+ HNS_ROCE_DFX_MBX_POSTED_CNT,
+ HNS_ROCE_DFX_MBX_POLLED_CNT,
+ HNS_ROCE_DFX_MBX_EVENT_CNT,
+ HNS_ROCE_DFX_QP_CREATE_ERR_CNT,
+ HNS_ROCE_DFX_QP_MODIFY_ERR_CNT,
+ HNS_ROCE_DFX_CQ_CREATE_ERR_CNT,
+ HNS_ROCE_DFX_CQ_MODIFY_ERR_CNT,
+ HNS_ROCE_DFX_SRQ_CREATE_ERR_CNT,
+ HNS_ROCE_DFX_SRQ_MODIFY_ERR_CNT,
+ HNS_ROCE_DFX_XRCD_ALLOC_ERR_CNT,
+ HNS_ROCE_DFX_MR_REG_ERR_CNT,
+ HNS_ROCE_DFX_MR_REREG_ERR_CNT,
+ HNS_ROCE_DFX_AH_CREATE_ERR_CNT,
+ HNS_ROCE_DFX_MMAP_ERR_CNT,
+ HNS_ROCE_DFX_UCTX_ALLOC_ERR_CNT,
+ HNS_ROCE_DFX_CNT_TOTAL
+};
+
struct hns_roce_hw {
int (*cmq_init)(struct hns_roce_dev *hr_dev);
void (*cmq_exit)(struct hns_roce_dev *hr_dev);
@@ -979,6 +1003,8 @@ struct hns_roce_dev {
u32 is_vf;
u32 cong_algo_tmpl_id;
u64 dwqe_page;
+ struct hns_roce_dev_debugfs dbgfs;
+ atomic64_t *dfx_cnt;
};
static inline struct hns_roce_dev *to_hr_dev(struct ib_device *ib_dev)
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
index 2bca9560f32d..8206daea6767 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
@@ -1297,6 +1297,8 @@ static int __hns_roce_cmq_send(struct hns_roce_dev *hr_dev,
/* Write to hardware */
roce_write(hr_dev, ROCEE_TX_CMQ_PI_REG, csq->head);
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_CMDS_CNT]);
+
do {
if (hns_roce_cmq_csq_done(hr_dev))
break;
@@ -1334,6 +1336,9 @@ static int __hns_roce_cmq_send(struct hns_roce_dev *hr_dev,
spin_unlock_bh(&csq->lock);
+ if (ret)
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_CMDS_ERR_CNT]);
+
return ret;
}
@@ -2055,6 +2060,7 @@ static void set_hem_page_size(struct hns_roce_dev *hr_dev)
/* Apply all loaded caps before setting to hardware */
static void apply_func_caps(struct hns_roce_dev *hr_dev)
{
+#define MAX_GID_TBL_LEN 256
struct hns_roce_caps *caps = &hr_dev->caps;
struct hns_roce_v2_priv *priv = hr_dev->priv;
@@ -2090,8 +2096,14 @@ static void apply_func_caps(struct hns_roce_dev *hr_dev)
caps->gmv_entry_sz = HNS_ROCE_V3_GMV_ENTRY_SZ;
caps->gmv_hop_num = HNS_ROCE_HOP_NUM_0;
- caps->gid_table_len[0] = caps->gmv_bt_num *
- (HNS_HW_PAGE_SIZE / caps->gmv_entry_sz);
+
+ /* It's meaningless to support excessively large gid_table_len,
+ * as the type of sgid_index in kernel struct ib_global_route
+ * and userspace struct ibv_global_route are u8/uint8_t (0-255).
+ */
+ caps->gid_table_len[0] = min_t(u32, MAX_GID_TBL_LEN,
+ caps->gmv_bt_num *
+ (HNS_HW_PAGE_SIZE / caps->gmv_entry_sz));
caps->gmv_entry_num = caps->gmv_bt_num * (PAGE_SIZE /
caps->gmv_entry_sz);
@@ -2698,6 +2710,10 @@ static int free_mr_alloc_res(struct hns_roce_dev *hr_dev)
return 0;
create_failed_qp:
+ for (i--; i >= 0; i--) {
+ hns_roce_v2_destroy_qp(&free_mr->rsv_qp[i]->ibqp, NULL);
+ kfree(free_mr->rsv_qp[i]);
+ }
hns_roce_destroy_cq(cq, NULL);
kfree(cq);
@@ -5667,19 +5683,25 @@ static int hns_roce_v2_modify_srq(struct ib_srq *ibsrq,
struct hns_roce_srq_context *srq_context;
struct hns_roce_srq_context *srqc_mask;
struct hns_roce_cmd_mailbox *mailbox;
- int ret;
+ int ret = 0;
/* Resizing SRQs is not supported yet */
- if (srq_attr_mask & IB_SRQ_MAX_WR)
- return -EINVAL;
+ if (srq_attr_mask & IB_SRQ_MAX_WR) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
if (srq_attr_mask & IB_SRQ_LIMIT) {
- if (srq_attr->srq_limit > srq->wqe_cnt)
- return -EINVAL;
+ if (srq_attr->srq_limit > srq->wqe_cnt) {
+ ret = -EINVAL;
+ goto out;
+ }
mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
- if (IS_ERR(mailbox))
- return PTR_ERR(mailbox);
+ if (IS_ERR(mailbox)) {
+ ret = PTR_ERR(mailbox);
+ goto out;
+ }
srq_context = mailbox->buf;
srqc_mask = (struct hns_roce_srq_context *)mailbox->buf + 1;
@@ -5692,15 +5714,17 @@ static int hns_roce_v2_modify_srq(struct ib_srq *ibsrq,
ret = hns_roce_cmd_mbox(hr_dev, mailbox->dma, 0,
HNS_ROCE_CMD_MODIFY_SRQC, srq->srqn);
hns_roce_free_cmd_mailbox(hr_dev, mailbox);
- if (ret) {
+ if (ret)
ibdev_err(&hr_dev->ib_dev,
"failed to handle cmd of modifying SRQ, ret = %d.\n",
ret);
- return ret;
- }
}
- return 0;
+out:
+ if (ret)
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_SRQ_MODIFY_ERR_CNT]);
+
+ return ret;
}
static int hns_roce_v2_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr)
@@ -5744,8 +5768,9 @@ static int hns_roce_v2_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
int ret;
mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
- if (IS_ERR(mailbox))
- return PTR_ERR(mailbox);
+ ret = PTR_ERR_OR_ZERO(mailbox);
+ if (ret)
+ goto err_out;
cq_context = mailbox->buf;
cqc_mask = (struct hns_roce_v2_cq_context *)mailbox->buf + 1;
@@ -5775,6 +5800,10 @@ static int hns_roce_v2_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period)
"failed to process cmd when modifying CQ, ret = %d.\n",
ret);
+err_out:
+ if (ret)
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_CQ_MODIFY_ERR_CNT]);
+
return ret;
}
@@ -6014,6 +6043,8 @@ static irqreturn_t hns_roce_v2_aeq_int(struct hns_roce_dev *hr_dev,
++eq->cons_index;
aeqe_found = IRQ_HANDLED;
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_AEQE_CNT]);
+
hns_roce_v2_init_irq_work(hr_dev, eq, queue_num);
aeqe = next_aeqe_sw_v2(eq);
@@ -6055,6 +6086,7 @@ static irqreturn_t hns_roce_v2_ceq_int(struct hns_roce_dev *hr_dev,
++eq->cons_index;
ceqe_found = IRQ_HANDLED;
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_CEQE_CNT]);
ceqe = next_ceqe_sw_v2(eq);
}
@@ -6457,15 +6489,16 @@ static int __hns_roce_request_irq(struct hns_roce_dev *hr_dev, int irq_num,
/* irq contains: abnormal + AEQ + CEQ */
for (j = 0; j < other_num; j++)
snprintf((char *)hr_dev->irq_names[j], HNS_ROCE_INT_NAME_LEN,
- "hns-abn-%d", j);
+ "hns-%s-abn-%d", pci_name(hr_dev->pci_dev), j);
for (j = other_num; j < (other_num + aeq_num); j++)
snprintf((char *)hr_dev->irq_names[j], HNS_ROCE_INT_NAME_LEN,
- "hns-aeq-%d", j - other_num);
+ "hns-%s-aeq-%d", pci_name(hr_dev->pci_dev), j - other_num);
for (j = (other_num + aeq_num); j < irq_num; j++)
snprintf((char *)hr_dev->irq_names[j], HNS_ROCE_INT_NAME_LEN,
- "hns-ceq-%d", j - other_num - aeq_num);
+ "hns-%s-ceq-%d", pci_name(hr_dev->pci_dev),
+ j - other_num - aeq_num);
for (j = 0; j < irq_num; j++) {
if (j < other_num)
@@ -6963,12 +6996,14 @@ static struct hnae3_client hns_roce_hw_v2_client = {
static int __init hns_roce_hw_v2_init(void)
{
+ hns_roce_init_debugfs();
return hnae3_register_client(&hns_roce_hw_v2_client);
}
static void __exit hns_roce_hw_v2_exit(void)
{
hnae3_unregister_client(&hns_roce_hw_v2_client);
+ hns_roce_cleanup_debugfs();
}
module_init(hns_roce_hw_v2_init);
diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c
index a4a10a4e1aab..b55fe6911f9f 100644
--- a/drivers/infiniband/hw/hns/hns_roce_main.c
+++ b/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -361,10 +361,10 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx,
struct hns_roce_dev *hr_dev = to_hr_dev(uctx->device);
struct hns_roce_ib_alloc_ucontext_resp resp = {};
struct hns_roce_ib_alloc_ucontext ucmd = {};
- int ret;
+ int ret = -EAGAIN;
if (!hr_dev->active)
- return -EAGAIN;
+ goto error_out;
resp.qp_tab_size = hr_dev->caps.num_qps;
resp.srq_tab_size = hr_dev->caps.num_srqs;
@@ -372,7 +372,7 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx,
ret = ib_copy_from_udata(&ucmd, udata,
min(udata->inlen, sizeof(ucmd)));
if (ret)
- return ret;
+ goto error_out;
if (hr_dev->pci_dev->revision >= PCI_REVISION_ID_HIP09)
context->config = ucmd.config & HNS_ROCE_EXSGE_FLAGS;
@@ -396,7 +396,7 @@ static int hns_roce_alloc_ucontext(struct ib_ucontext *uctx,
ret = hns_roce_uar_alloc(hr_dev, &context->uar);
if (ret)
- goto error_fail_uar_alloc;
+ goto error_out;
ret = hns_roce_alloc_uar_entry(uctx);
if (ret)
@@ -423,7 +423,9 @@ error_fail_copy_to_udata:
error_fail_uar_entry:
ida_free(&hr_dev->uar_ida.ida, (int)context->uar.logic_idx);
-error_fail_uar_alloc:
+error_out:
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_UCTX_ALLOC_ERR_CNT]);
+
return ret;
}
@@ -439,6 +441,7 @@ static void hns_roce_dealloc_ucontext(struct ib_ucontext *ibcontext)
static int hns_roce_mmap(struct ib_ucontext *uctx, struct vm_area_struct *vma)
{
+ struct hns_roce_dev *hr_dev = to_hr_dev(uctx->device);
struct rdma_user_mmap_entry *rdma_entry;
struct hns_user_mmap_entry *entry;
phys_addr_t pfn;
@@ -446,8 +449,10 @@ static int hns_roce_mmap(struct ib_ucontext *uctx, struct vm_area_struct *vma)
int ret;
rdma_entry = rdma_user_mmap_entry_get_pgoff(uctx, vma->vm_pgoff);
- if (!rdma_entry)
+ if (!rdma_entry) {
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MMAP_ERR_CNT]);
return -EINVAL;
+ }
entry = to_hns_mmap(rdma_entry);
pfn = entry->address >> PAGE_SHIFT;
@@ -467,6 +472,9 @@ static int hns_roce_mmap(struct ib_ucontext *uctx, struct vm_area_struct *vma)
out:
rdma_user_mmap_entry_put(rdma_entry);
+ if (ret)
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MMAP_ERR_CNT]);
+
return ret;
}
@@ -1009,6 +1017,21 @@ void hns_roce_handle_device_err(struct hns_roce_dev *hr_dev)
spin_unlock_irqrestore(&hr_dev->qp_list_lock, flags);
}
+static int hns_roce_alloc_dfx_cnt(struct hns_roce_dev *hr_dev)
+{
+ hr_dev->dfx_cnt = kvcalloc(HNS_ROCE_DFX_CNT_TOTAL, sizeof(atomic64_t),
+ GFP_KERNEL);
+ if (!hr_dev->dfx_cnt)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void hns_roce_dealloc_dfx_cnt(struct hns_roce_dev *hr_dev)
+{
+ kvfree(hr_dev->dfx_cnt);
+}
+
int hns_roce_init(struct hns_roce_dev *hr_dev)
{
struct device *dev = hr_dev->dev;
@@ -1016,11 +1039,15 @@ int hns_roce_init(struct hns_roce_dev *hr_dev)
hr_dev->is_reset = false;
+ ret = hns_roce_alloc_dfx_cnt(hr_dev);
+ if (ret)
+ return ret;
+
if (hr_dev->hw->cmq_init) {
ret = hr_dev->hw->cmq_init(hr_dev);
if (ret) {
dev_err(dev, "init RoCE Command Queue failed!\n");
- return ret;
+ goto error_failed_alloc_dfx_cnt;
}
}
@@ -1079,6 +1106,8 @@ int hns_roce_init(struct hns_roce_dev *hr_dev)
if (ret)
goto error_failed_register_device;
+ hns_roce_register_debugfs(hr_dev);
+
return 0;
error_failed_register_device:
@@ -1103,11 +1132,15 @@ error_failed_cmd_init:
if (hr_dev->hw->cmq_exit)
hr_dev->hw->cmq_exit(hr_dev);
+error_failed_alloc_dfx_cnt:
+ hns_roce_dealloc_dfx_cnt(hr_dev);
+
return ret;
}
void hns_roce_exit(struct hns_roce_dev *hr_dev)
{
+ hns_roce_unregister_debugfs(hr_dev);
hns_roce_unregister_device(hr_dev);
if (hr_dev->hw->hw_exit)
@@ -1122,6 +1155,7 @@ void hns_roce_exit(struct hns_roce_dev *hr_dev)
hns_roce_cmd_cleanup(hr_dev);
if (hr_dev->hw->cmq_exit)
hr_dev->hw->cmq_exit(hr_dev);
+ hns_roce_dealloc_dfx_cnt(hr_dev);
}
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c
index 14376490ac22..91cd580480fe 100644
--- a/drivers/infiniband/hw/hns/hns_roce_mr.c
+++ b/drivers/infiniband/hw/hns/hns_roce_mr.c
@@ -228,8 +228,10 @@ struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
int ret;
mr = kzalloc(sizeof(*mr), GFP_KERNEL);
- if (!mr)
- return ERR_PTR(-ENOMEM);
+ if (!mr) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
mr->iova = virt_addr;
mr->size = length;
@@ -259,6 +261,9 @@ err_alloc_key:
free_mr_key(hr_dev, mr);
err_alloc_mr:
kfree(mr);
+err_out:
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MR_REG_ERR_CNT]);
+
return ERR_PTR(ret);
}
@@ -274,12 +279,15 @@ struct ib_mr *hns_roce_rereg_user_mr(struct ib_mr *ibmr, int flags, u64 start,
unsigned long mtpt_idx;
int ret;
- if (!mr->enabled)
- return ERR_PTR(-EINVAL);
+ if (!mr->enabled) {
+ ret = -EINVAL;
+ goto err_out;
+ }
mailbox = hns_roce_alloc_cmd_mailbox(hr_dev);
- if (IS_ERR(mailbox))
- return ERR_CAST(mailbox);
+ ret = PTR_ERR_OR_ZERO(mailbox);
+ if (ret)
+ goto err_out;
mtpt_idx = key_to_hw_index(mr->key) & (hr_dev->caps.num_mtpts - 1);
@@ -331,8 +339,12 @@ struct ib_mr *hns_roce_rereg_user_mr(struct ib_mr *ibmr, int flags, u64 start,
free_cmd_mbox:
hns_roce_free_cmd_mailbox(hr_dev, mailbox);
- if (ret)
+err_out:
+ if (ret) {
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_MR_REREG_ERR_CNT]);
return ERR_PTR(ret);
+ }
+
return NULL;
}
@@ -674,7 +686,7 @@ static int mtr_alloc_bufs(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
mtr->kmem = NULL;
mtr->umem = ib_umem_get(ibdev, user_addr, total_size,
buf_attr->user_access);
- if (IS_ERR_OR_NULL(mtr->umem)) {
+ if (IS_ERR(mtr->umem)) {
ibdev_err(ibdev, "failed to get umem, ret = %ld.\n",
PTR_ERR(mtr->umem));
return -ENOMEM;
diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c b/drivers/infiniband/hw/hns/hns_roce_pd.c
index 783e71852c50..d35cf59d0f43 100644
--- a/drivers/infiniband/hw/hns/hns_roce_pd.c
+++ b/drivers/infiniband/hw/hns/hns_roce_pd.c
@@ -149,14 +149,18 @@ int hns_roce_alloc_xrcd(struct ib_xrcd *ib_xrcd, struct ib_udata *udata)
struct hns_roce_xrcd *xrcd = to_hr_xrcd(ib_xrcd);
int ret;
- if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_XRC))
- return -EINVAL;
+ if (!(hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_XRC)) {
+ ret = -EOPNOTSUPP;
+ goto err_out;
+ }
ret = hns_roce_xrcd_alloc(hr_dev, &xrcd->xrcdn);
+
+err_out:
if (ret)
- return ret;
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_XRCD_ALLOC_ERR_CNT]);
- return 0;
+ return ret;
}
int hns_roce_dealloc_xrcd(struct ib_xrcd *ib_xrcd, struct ib_udata *udata)
diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c
index 828b58534aa9..31b147210688 100644
--- a/drivers/infiniband/hw/hns/hns_roce_qp.c
+++ b/drivers/infiniband/hw/hns/hns_roce_qp.c
@@ -1216,7 +1216,7 @@ int hns_roce_create_qp(struct ib_qp *qp, struct ib_qp_init_attr *init_attr,
ret = check_qp_type(hr_dev, init_attr->qp_type, !!udata);
if (ret)
- return ret;
+ goto err_out;
if (init_attr->qp_type == IB_QPT_XRC_TGT)
hr_qp->xrcdn = to_hr_xrcd(init_attr->xrcd)->xrcdn;
@@ -1231,6 +1231,10 @@ int hns_roce_create_qp(struct ib_qp *qp, struct ib_qp_init_attr *init_attr,
ibdev_err(ibdev, "create QP type 0x%x failed(%d)\n",
init_attr->qp_type, ret);
+err_out:
+ if (ret)
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_QP_CREATE_ERR_CNT]);
+
return ret;
}
@@ -1366,6 +1370,8 @@ int hns_roce_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
out:
mutex_unlock(&hr_qp->mutex);
+ if (ret)
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_QP_MODIFY_ERR_CNT]);
return ret;
}
diff --git a/drivers/infiniband/hw/hns/hns_roce_srq.c b/drivers/infiniband/hw/hns/hns_roce_srq.c
index 4e2d1c8e164a..4abae9477854 100644
--- a/drivers/infiniband/hw/hns/hns_roce_srq.c
+++ b/drivers/infiniband/hw/hns/hns_roce_srq.c
@@ -475,11 +475,11 @@ int hns_roce_create_srq(struct ib_srq *ib_srq,
ret = set_srq_param(srq, init_attr, udata);
if (ret)
- return ret;
+ goto err_out;
ret = alloc_srq_buf(hr_dev, srq, udata);
if (ret)
- return ret;
+ goto err_out;
ret = alloc_srq_db(hr_dev, srq, udata, &resp);
if (ret)
@@ -517,6 +517,8 @@ err_srq_db:
free_srq_db(hr_dev, srq, udata);
err_srq_buf:
free_srq_buf(hr_dev, srq);
+err_out:
+ atomic64_inc(&hr_dev->dfx_cnt[HNS_ROCE_DFX_SRQ_CREATE_ERR_CNT]);
return ret;
}
diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c
index 916bfe2a91eb..0422787592d8 100644
--- a/drivers/infiniband/hw/irdma/utils.c
+++ b/drivers/infiniband/hw/irdma/utils.c
@@ -1393,17 +1393,12 @@ int irdma_ieq_check_mpacrc(struct shash_desc *desc, void *addr, u32 len,
u32 val)
{
u32 crc = 0;
- int ret;
- int ret_code = 0;
- crypto_shash_init(desc);
- ret = crypto_shash_update(desc, addr, len);
- if (!ret)
- crypto_shash_final(desc, (u8 *)&crc);
+ crypto_shash_digest(desc, addr, len, (u8 *)&crc);
if (crc != val)
- ret_code = -EINVAL;
+ return -EINVAL;
- return ret_code;
+ return 0;
}
/**
diff --git a/drivers/infiniband/hw/mana/cq.c b/drivers/infiniband/hw/mana/cq.c
index d141cab8a1e6..83ebd070535a 100644
--- a/drivers/infiniband/hw/mana/cq.c
+++ b/drivers/infiniband/hw/mana/cq.c
@@ -12,13 +12,20 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
struct ib_device *ibdev = ibcq->device;
struct mana_ib_create_cq ucmd = {};
struct mana_ib_dev *mdev;
+ struct gdma_context *gc;
int err;
mdev = container_of(ibdev, struct mana_ib_dev, ib_dev);
+ gc = mdev->gdma_dev->gdma_context;
if (udata->inlen < sizeof(ucmd))
return -EINVAL;
+ if (attr->comp_vector > gc->max_num_queues)
+ return -EINVAL;
+
+ cq->comp_vector = attr->comp_vector;
+
err = ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen));
if (err) {
ibdev_dbg(ibdev,
@@ -26,7 +33,7 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
return err;
}
- if (attr->cqe > MAX_SEND_BUFFERS_PER_QUEUE) {
+ if (attr->cqe > mdev->adapter_caps.max_qp_wr) {
ibdev_dbg(ibdev, "CQE %d exceeding limit\n", attr->cqe);
return -EINVAL;
}
@@ -56,6 +63,7 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
/*
* The CQ ID is not known at this time. The ID is generated at create_qp
*/
+ cq->id = INVALID_QUEUE_ID;
return 0;
@@ -69,11 +77,33 @@ int mana_ib_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
struct mana_ib_cq *cq = container_of(ibcq, struct mana_ib_cq, ibcq);
struct ib_device *ibdev = ibcq->device;
struct mana_ib_dev *mdev;
+ struct gdma_context *gc;
+ int err;
mdev = container_of(ibdev, struct mana_ib_dev, ib_dev);
+ gc = mdev->gdma_dev->gdma_context;
+
+ err = mana_ib_gd_destroy_dma_region(mdev, cq->gdma_region);
+ if (err) {
+ ibdev_dbg(ibdev,
+ "Failed to destroy dma region, %d\n", err);
+ return err;
+ }
+
+ if (cq->id != INVALID_QUEUE_ID) {
+ kfree(gc->cq_table[cq->id]);
+ gc->cq_table[cq->id] = NULL;
+ }
- mana_ib_gd_destroy_dma_region(mdev, cq->gdma_region);
ib_umem_release(cq->umem);
return 0;
}
+
+void mana_ib_cq_handler(void *ctx, struct gdma_queue *gdma_cq)
+{
+ struct mana_ib_cq *cq = ctx;
+
+ if (cq->ibcq.comp_handler)
+ cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
+}
diff --git a/drivers/infiniband/hw/mana/device.c b/drivers/infiniband/hw/mana/device.c
index d4541b8707e4..6fa902ee80a6 100644
--- a/drivers/infiniband/hw/mana/device.c
+++ b/drivers/infiniband/hw/mana/device.c
@@ -68,7 +68,6 @@ static int mana_ib_probe(struct auxiliary_device *adev,
ibdev_dbg(&dev->ib_dev, "mdev=%p id=%d num_ports=%d\n", mdev,
mdev->dev_id.as_uint32, dev->ib_dev.phys_port_cnt);
- dev->gdma_dev = mdev;
dev->ib_dev.node_type = RDMA_NODE_IB_CA;
/*
@@ -78,16 +77,35 @@ static int mana_ib_probe(struct auxiliary_device *adev,
dev->ib_dev.num_comp_vectors = 1;
dev->ib_dev.dev.parent = mdev->gdma_context->dev;
- ret = ib_register_device(&dev->ib_dev, "mana_%d",
- mdev->gdma_context->dev);
+ ret = mana_gd_register_device(&mdev->gdma_context->mana_ib);
+ if (ret) {
+ ibdev_err(&dev->ib_dev, "Failed to register device, ret %d",
+ ret);
+ goto free_ib_device;
+ }
+ dev->gdma_dev = &mdev->gdma_context->mana_ib;
+
+ ret = mana_ib_gd_query_adapter_caps(dev);
if (ret) {
- ib_dealloc_device(&dev->ib_dev);
- return ret;
+ ibdev_err(&dev->ib_dev, "Failed to query device caps, ret %d",
+ ret);
+ goto deregister_device;
}
+ ret = ib_register_device(&dev->ib_dev, "mana_%d",
+ mdev->gdma_context->dev);
+ if (ret)
+ goto deregister_device;
+
dev_set_drvdata(&adev->dev, dev);
return 0;
+
+deregister_device:
+ mana_gd_deregister_device(dev->gdma_dev);
+free_ib_device:
+ ib_dealloc_device(&dev->ib_dev);
+ return ret;
}
static void mana_ib_remove(struct auxiliary_device *adev)
@@ -95,6 +113,9 @@ static void mana_ib_remove(struct auxiliary_device *adev)
struct mana_ib_dev *dev = dev_get_drvdata(&adev->dev);
ib_unregister_device(&dev->ib_dev);
+
+ mana_gd_deregister_device(dev->gdma_dev);
+
ib_dealloc_device(&dev->ib_dev);
}
diff --git a/drivers/infiniband/hw/mana/main.c b/drivers/infiniband/hw/mana/main.c
index 7be4c3adb4e2..faca092456fa 100644
--- a/drivers/infiniband/hw/mana/main.c
+++ b/drivers/infiniband/hw/mana/main.c
@@ -8,7 +8,7 @@
void mana_ib_uncfg_vport(struct mana_ib_dev *dev, struct mana_ib_pd *pd,
u32 port)
{
- struct gdma_dev *gd = dev->gdma_dev;
+ struct gdma_dev *gd = &dev->gdma_dev->gdma_context->mana;
struct mana_port_context *mpc;
struct net_device *ndev;
struct mana_context *mc;
@@ -31,7 +31,7 @@ void mana_ib_uncfg_vport(struct mana_ib_dev *dev, struct mana_ib_pd *pd,
int mana_ib_cfg_vport(struct mana_ib_dev *dev, u32 port, struct mana_ib_pd *pd,
u32 doorbell_id)
{
- struct gdma_dev *mdev = dev->gdma_dev;
+ struct gdma_dev *mdev = &dev->gdma_dev->gdma_context->mana;
struct mana_port_context *mpc;
struct mana_context *mc;
struct net_device *ndev;
@@ -486,20 +486,17 @@ int mana_ib_get_port_immutable(struct ib_device *ibdev, u32 port_num,
int mana_ib_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
struct ib_udata *uhw)
{
- props->max_qp = MANA_MAX_NUM_QUEUES;
- props->max_qp_wr = MAX_SEND_BUFFERS_PER_QUEUE;
-
- /*
- * max_cqe could be potentially much bigger.
- * As this version of driver only support RAW QP, set it to the same
- * value as max_qp_wr
- */
- props->max_cqe = MAX_SEND_BUFFERS_PER_QUEUE;
-
+ struct mana_ib_dev *dev = container_of(ibdev,
+ struct mana_ib_dev, ib_dev);
+
+ props->max_qp = dev->adapter_caps.max_qp_count;
+ props->max_qp_wr = dev->adapter_caps.max_qp_wr;
+ props->max_cq = dev->adapter_caps.max_cq_count;
+ props->max_cqe = dev->adapter_caps.max_qp_wr;
+ props->max_mr = dev->adapter_caps.max_mr_count;
props->max_mr_size = MANA_IB_MAX_MR_SIZE;
- props->max_mr = MANA_IB_MAX_MR;
- props->max_send_sge = MAX_TX_WQE_SGL_ENTRIES;
- props->max_recv_sge = MAX_RX_WQE_SGL_ENTRIES;
+ props->max_send_sge = dev->adapter_caps.max_send_sge_count;
+ props->max_recv_sge = dev->adapter_caps.max_recv_sge_count;
return 0;
}
@@ -521,3 +518,45 @@ int mana_ib_query_gid(struct ib_device *ibdev, u32 port, int index,
void mana_ib_disassociate_ucontext(struct ib_ucontext *ibcontext)
{
}
+
+int mana_ib_gd_query_adapter_caps(struct mana_ib_dev *dev)
+{
+ struct mana_ib_adapter_caps *caps = &dev->adapter_caps;
+ struct mana_ib_query_adapter_caps_resp resp = {};
+ struct mana_ib_query_adapter_caps_req req = {};
+ int err;
+
+ mana_gd_init_req_hdr(&req.hdr, MANA_IB_GET_ADAPTER_CAP, sizeof(req),
+ sizeof(resp));
+ req.hdr.resp.msg_version = GDMA_MESSAGE_V3;
+ req.hdr.dev_id = dev->gdma_dev->dev_id;
+
+ err = mana_gd_send_request(dev->gdma_dev->gdma_context, sizeof(req),
+ &req, sizeof(resp), &resp);
+
+ if (err) {
+ ibdev_err(&dev->ib_dev,
+ "Failed to query adapter caps err %d", err);
+ return err;
+ }
+
+ caps->max_sq_id = resp.max_sq_id;
+ caps->max_rq_id = resp.max_rq_id;
+ caps->max_cq_id = resp.max_cq_id;
+ caps->max_qp_count = resp.max_qp_count;
+ caps->max_cq_count = resp.max_cq_count;
+ caps->max_mr_count = resp.max_mr_count;
+ caps->max_pd_count = resp.max_pd_count;
+ caps->max_inbound_read_limit = resp.max_inbound_read_limit;
+ caps->max_outbound_read_limit = resp.max_outbound_read_limit;
+ caps->mw_count = resp.mw_count;
+ caps->max_srq_count = resp.max_srq_count;
+ caps->max_qp_wr = min_t(u32,
+ resp.max_requester_sq_size / GDMA_MAX_SQE_SIZE,
+ resp.max_requester_rq_size / GDMA_MAX_RQE_SIZE);
+ caps->max_inline_data_size = resp.max_inline_data_size;
+ caps->max_send_sge_count = resp.max_send_sge_count;
+ caps->max_recv_sge_count = resp.max_recv_sge_count;
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/mana/mana_ib.h b/drivers/infiniband/hw/mana/mana_ib.h
index 502cc8672eef..6bdc0f5498d5 100644
--- a/drivers/infiniband/hw/mana/mana_ib.h
+++ b/drivers/infiniband/hw/mana/mana_ib.h
@@ -27,9 +27,28 @@
*/
#define MANA_IB_MAX_MR 0xFFFFFFu
+struct mana_ib_adapter_caps {
+ u32 max_sq_id;
+ u32 max_rq_id;
+ u32 max_cq_id;
+ u32 max_qp_count;
+ u32 max_cq_count;
+ u32 max_mr_count;
+ u32 max_pd_count;
+ u32 max_inbound_read_limit;
+ u32 max_outbound_read_limit;
+ u32 mw_count;
+ u32 max_srq_count;
+ u32 max_qp_wr;
+ u32 max_send_sge_count;
+ u32 max_recv_sge_count;
+ u32 max_inline_data_size;
+};
+
struct mana_ib_dev {
struct ib_device ib_dev;
struct gdma_dev *gdma_dev;
+ struct mana_ib_adapter_caps adapter_caps;
};
struct mana_ib_wq {
@@ -67,6 +86,7 @@ struct mana_ib_cq {
int cqe;
u64 gdma_region;
u64 id;
+ u32 comp_vector;
};
struct mana_ib_qp {
@@ -92,6 +112,36 @@ struct mana_ib_rwq_ind_table {
struct ib_rwq_ind_table ib_ind_table;
};
+enum mana_ib_command_code {
+ MANA_IB_GET_ADAPTER_CAP = 0x30001,
+};
+
+struct mana_ib_query_adapter_caps_req {
+ struct gdma_req_hdr hdr;
+}; /*HW Data */
+
+struct mana_ib_query_adapter_caps_resp {
+ struct gdma_resp_hdr hdr;
+ u32 max_sq_id;
+ u32 max_rq_id;
+ u32 max_cq_id;
+ u32 max_qp_count;
+ u32 max_cq_count;
+ u32 max_mr_count;
+ u32 max_pd_count;
+ u32 max_inbound_read_limit;
+ u32 max_outbound_read_limit;
+ u32 mw_count;
+ u32 max_srq_count;
+ u32 max_requester_sq_size;
+ u32 max_responder_sq_size;
+ u32 max_requester_rq_size;
+ u32 max_responder_rq_size;
+ u32 max_send_sge_count;
+ u32 max_recv_sge_count;
+ u32 max_inline_data_size;
+}; /* HW Data */
+
int mana_ib_gd_create_dma_region(struct mana_ib_dev *dev, struct ib_umem *umem,
mana_handle_t *gdma_region);
@@ -159,4 +209,7 @@ int mana_ib_query_gid(struct ib_device *ibdev, u32 port, int index,
void mana_ib_disassociate_ucontext(struct ib_ucontext *ibcontext);
+int mana_ib_gd_query_adapter_caps(struct mana_ib_dev *mdev);
+
+void mana_ib_cq_handler(void *ctx, struct gdma_queue *gdma_cq);
#endif
diff --git a/drivers/infiniband/hw/mana/qp.c b/drivers/infiniband/hw/mana/qp.c
index 4b3b5b274e84..21ac9fcadf3f 100644
--- a/drivers/infiniband/hw/mana/qp.c
+++ b/drivers/infiniband/hw/mana/qp.c
@@ -21,8 +21,8 @@ static int mana_ib_cfg_vport_steering(struct mana_ib_dev *dev,
u32 req_buf_size;
int i, err;
- mdev = dev->gdma_dev;
- gc = mdev->gdma_context;
+ gc = dev->gdma_dev->gdma_context;
+ mdev = &gc->mana;
req_buf_size =
sizeof(*req) + sizeof(mana_handle_t) * MANA_INDIRECT_TABLE_SIZE;
@@ -102,20 +102,26 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
struct ib_rwq_ind_table *ind_tbl = attr->rwq_ind_tbl;
struct mana_ib_create_qp_rss_resp resp = {};
struct mana_ib_create_qp_rss ucmd = {};
- struct gdma_dev *gd = mdev->gdma_dev;
+ struct gdma_queue **gdma_cq_allocated;
mana_handle_t *mana_ind_table;
struct mana_port_context *mpc;
+ struct gdma_queue *gdma_cq;
+ unsigned int ind_tbl_size;
struct mana_context *mc;
struct net_device *ndev;
+ struct gdma_context *gc;
struct mana_ib_cq *cq;
struct mana_ib_wq *wq;
- unsigned int ind_tbl_size;
+ struct gdma_dev *gd;
+ struct mana_eq *eq;
struct ib_cq *ibcq;
struct ib_wq *ibwq;
int i = 0;
u32 port;
int ret;
+ gc = mdev->gdma_dev->gdma_context;
+ gd = &gc->mana;
mc = gd->driver_data;
if (!udata || udata->inlen < sizeof(ucmd))
@@ -129,7 +135,7 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
return ret;
}
- if (attr->cap.max_recv_wr > MAX_SEND_BUFFERS_PER_QUEUE) {
+ if (attr->cap.max_recv_wr > mdev->adapter_caps.max_qp_wr) {
ibdev_dbg(&mdev->ib_dev,
"Requested max_recv_wr %d exceeding limit\n",
attr->cap.max_recv_wr);
@@ -178,6 +184,13 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
goto fail;
}
+ gdma_cq_allocated = kcalloc(ind_tbl_size, sizeof(*gdma_cq_allocated),
+ GFP_KERNEL);
+ if (!gdma_cq_allocated) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
qp->port = port;
for (i = 0; i < ind_tbl_size; i++) {
@@ -196,12 +209,16 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
cq_spec.gdma_region = cq->gdma_region;
cq_spec.queue_size = cq->cqe * COMP_ENTRY_SIZE;
cq_spec.modr_ctx_id = 0;
- cq_spec.attached_eq = GDMA_CQ_NO_EQ;
+ eq = &mc->eqs[cq->comp_vector % gc->max_num_queues];
+ cq_spec.attached_eq = eq->eq->id;
ret = mana_create_wq_obj(mpc, mpc->port_handle, GDMA_RQ,
&wq_spec, &cq_spec, &wq->rx_object);
- if (ret)
+ if (ret) {
+ /* Do cleanup starting with index i-1 */
+ i--;
goto fail;
+ }
/* The GDMA regions are now owned by the WQ object */
wq->gdma_region = GDMA_INVALID_DMA_REGION;
@@ -218,6 +235,21 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
resp.entries[i].wqid = wq->id;
mana_ind_table[i] = wq->rx_object;
+
+ /* Create CQ table entry */
+ WARN_ON(gc->cq_table[cq->id]);
+ gdma_cq = kzalloc(sizeof(*gdma_cq), GFP_KERNEL);
+ if (!gdma_cq) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ gdma_cq_allocated[i] = gdma_cq;
+
+ gdma_cq->cq.context = cq;
+ gdma_cq->type = GDMA_CQ;
+ gdma_cq->cq.callback = mana_ib_cq_handler;
+ gdma_cq->id = cq->id;
+ gc->cq_table[cq->id] = gdma_cq;
}
resp.num_entries = i;
@@ -237,6 +269,7 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
goto fail;
}
+ kfree(gdma_cq_allocated);
kfree(mana_ind_table);
return 0;
@@ -244,10 +277,17 @@ static int mana_ib_create_qp_rss(struct ib_qp *ibqp, struct ib_pd *pd,
fail:
while (i-- > 0) {
ibwq = ind_tbl->ind_tbl[i];
+ ibcq = ibwq->cq;
wq = container_of(ibwq, struct mana_ib_wq, ibwq);
+ cq = container_of(ibcq, struct mana_ib_cq, ibcq);
+
+ gc->cq_table[cq->id] = NULL;
+ kfree(gdma_cq_allocated[i]);
+
mana_destroy_wq_obj(mpc, GDMA_RQ, wq->rx_object);
}
+ kfree(gdma_cq_allocated);
kfree(mana_ind_table);
return ret;
@@ -266,17 +306,20 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
struct mana_ib_ucontext *mana_ucontext =
rdma_udata_to_drv_context(udata, struct mana_ib_ucontext,
ibucontext);
+ struct gdma_dev *gd = &mdev->gdma_dev->gdma_context->mana;
struct mana_ib_create_qp_resp resp = {};
- struct gdma_dev *gd = mdev->gdma_dev;
struct mana_ib_create_qp ucmd = {};
+ struct gdma_queue *gdma_cq = NULL;
struct mana_obj_spec wq_spec = {};
struct mana_obj_spec cq_spec = {};
struct mana_port_context *mpc;
struct mana_context *mc;
struct net_device *ndev;
struct ib_umem *umem;
- int err;
+ struct mana_eq *eq;
+ int eq_vec;
u32 port;
+ int err;
mc = gd->driver_data;
@@ -295,7 +338,7 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
if (port < 1 || port > mc->num_ports)
return -EINVAL;
- if (attr->cap.max_send_wr > MAX_SEND_BUFFERS_PER_QUEUE) {
+ if (attr->cap.max_send_wr > mdev->adapter_caps.max_qp_wr) {
ibdev_dbg(&mdev->ib_dev,
"Requested max_send_wr %d exceeding limit\n",
attr->cap.max_send_wr);
@@ -353,7 +396,9 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
cq_spec.gdma_region = send_cq->gdma_region;
cq_spec.queue_size = send_cq->cqe * COMP_ENTRY_SIZE;
cq_spec.modr_ctx_id = 0;
- cq_spec.attached_eq = GDMA_CQ_NO_EQ;
+ eq_vec = send_cq->comp_vector % gd->gdma_context->max_num_queues;
+ eq = &mc->eqs[eq_vec];
+ cq_spec.attached_eq = eq->eq->id;
err = mana_create_wq_obj(mpc, mpc->port_handle, GDMA_SQ, &wq_spec,
&cq_spec, &qp->tx_object);
@@ -371,6 +416,20 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
qp->sq_id = wq_spec.queue_index;
send_cq->id = cq_spec.queue_index;
+ /* Create CQ table entry */
+ WARN_ON(gd->gdma_context->cq_table[send_cq->id]);
+ gdma_cq = kzalloc(sizeof(*gdma_cq), GFP_KERNEL);
+ if (!gdma_cq) {
+ err = -ENOMEM;
+ goto err_destroy_wq_obj;
+ }
+
+ gdma_cq->cq.context = send_cq;
+ gdma_cq->type = GDMA_CQ;
+ gdma_cq->cq.callback = mana_ib_cq_handler;
+ gdma_cq->id = send_cq->id;
+ gd->gdma_context->cq_table[send_cq->id] = gdma_cq;
+
ibdev_dbg(&mdev->ib_dev,
"ret %d qp->tx_object 0x%llx sq id %llu cq id %llu\n", err,
qp->tx_object, qp->sq_id, send_cq->id);
@@ -384,11 +443,15 @@ static int mana_ib_create_qp_raw(struct ib_qp *ibqp, struct ib_pd *ibpd,
ibdev_dbg(&mdev->ib_dev,
"Failed copy udata for create qp-raw, %d\n",
err);
- goto err_destroy_wq_obj;
+ goto err_release_gdma_cq;
}
return 0;
+err_release_gdma_cq:
+ kfree(gdma_cq);
+ gd->gdma_context->cq_table[send_cq->id] = NULL;
+
err_destroy_wq_obj:
mana_destroy_wq_obj(mpc, GDMA_SQ, qp->tx_object);
@@ -437,7 +500,7 @@ static int mana_ib_destroy_qp_rss(struct mana_ib_qp *qp,
{
struct mana_ib_dev *mdev =
container_of(qp->ibqp.device, struct mana_ib_dev, ib_dev);
- struct gdma_dev *gd = mdev->gdma_dev;
+ struct gdma_dev *gd = &mdev->gdma_dev->gdma_context->mana;
struct mana_port_context *mpc;
struct mana_context *mc;
struct net_device *ndev;
@@ -464,7 +527,7 @@ static int mana_ib_destroy_qp_raw(struct mana_ib_qp *qp, struct ib_udata *udata)
{
struct mana_ib_dev *mdev =
container_of(qp->ibqp.device, struct mana_ib_dev, ib_dev);
- struct gdma_dev *gd = mdev->gdma_dev;
+ struct gdma_dev *gd = &mdev->gdma_dev->gdma_context->mana;
struct ib_pd *ibpd = qp->ibqp.pd;
struct mana_port_context *mpc;
struct mana_context *mc;
diff --git a/drivers/infiniband/hw/mlx5/dm.c b/drivers/infiniband/hw/mlx5/dm.c
index 3669c90b2dad..b4c97fb62abf 100644
--- a/drivers/infiniband/hw/mlx5/dm.c
+++ b/drivers/infiniband/hw/mlx5/dm.c
@@ -341,6 +341,8 @@ static enum mlx5_sw_icm_type get_icm_type(int uapi_type)
return MLX5_SW_ICM_TYPE_HEADER_MODIFY;
case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM:
return MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN;
+ case MLX5_IB_UAPI_DM_TYPE_ENCAP_SW_ICM:
+ return MLX5_SW_ICM_TYPE_SW_ENCAP;
case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
default:
return MLX5_SW_ICM_TYPE_STEERING;
@@ -364,6 +366,7 @@ static struct ib_dm *handle_alloc_dm_sw_icm(struct ib_ucontext *ctx,
switch (type) {
case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
+ case MLX5_IB_UAPI_DM_TYPE_ENCAP_SW_ICM:
if (!(MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner) ||
MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner) ||
MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner_v2) ||
@@ -438,6 +441,7 @@ struct ib_dm *mlx5_ib_alloc_dm(struct ib_device *ibdev,
case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM:
+ case MLX5_IB_UAPI_DM_TYPE_ENCAP_SW_ICM:
return handle_alloc_dm_sw_icm(context, attr, attrs, type);
default:
return ERR_PTR(-EOPNOTSUPP);
@@ -491,6 +495,7 @@ static int mlx5_ib_dealloc_dm(struct ib_dm *ibdm,
case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM:
+ case MLX5_IB_UAPI_DM_TYPE_ENCAP_SW_ICM:
return mlx5_dm_icm_dealloc(ctx, to_icm(ibdm));
default:
return -EOPNOTSUPP;
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 650a15b6cfbc..c2b557e64290 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -818,6 +818,17 @@ static int mlx5_query_node_desc(struct mlx5_ib_dev *dev, char *node_desc)
MLX5_REG_NODE_DESC, 0, 0);
}
+static void fill_esw_mgr_reg_c0(struct mlx5_core_dev *mdev,
+ struct mlx5_ib_query_device_resp *resp)
+{
+ struct mlx5_eswitch *esw = mdev->priv.eswitch;
+ u16 vport = mlx5_eswitch_manager_vport(mdev);
+
+ resp->reg_c0.value = mlx5_eswitch_get_vport_metadata_for_match(esw,
+ vport);
+ resp->reg_c0.mask = mlx5_eswitch_get_vport_metadata_mask();
+}
+
static int mlx5_ib_query_device(struct ib_device *ibdev,
struct ib_device_attr *props,
struct ib_udata *uhw)
@@ -1209,6 +1220,19 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
MLX5_CAP_GEN(mdev, log_max_dci_errored_streams);
}
+ if (offsetofend(typeof(resp), reserved) <= uhw_outlen)
+ resp.response_length += sizeof(resp.reserved);
+
+ if (offsetofend(typeof(resp), reg_c0) <= uhw_outlen) {
+ struct mlx5_eswitch *esw = mdev->priv.eswitch;
+
+ resp.response_length += sizeof(resp.reg_c0);
+
+ if (mlx5_eswitch_mode(mdev) == MLX5_ESWITCH_OFFLOADS &&
+ mlx5_eswitch_vport_match_metadata_enabled(esw))
+ fill_esw_mgr_reg_c0(mdev, &resp);
+ }
+
if (uhw_outlen) {
err = ib_copy_to_udata(uhw, &resp, resp.response_length);
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 18e459b55746..a8ee2ca1f4a1 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -1347,6 +1347,7 @@ struct ib_mr *mlx5_ib_reg_dm_mr(struct ib_pd *pd, struct ib_dm *dm,
case MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM:
case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM:
case MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM:
+ case MLX5_IB_UAPI_DM_TYPE_ENCAP_SW_ICM:
if (attr->access_flags & ~MLX5_IB_DM_SW_ICM_ALLOWED_ACCESS)
return ERR_PTR(-EINVAL);
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index f330ce895d88..8fe0cef7e2be 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -635,7 +635,7 @@ void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox)
int mthca_SYS_EN(struct mthca_dev *dev)
{
- u64 out;
+ u64 out = 0;
int ret;
ret = mthca_cmd_imm(dev, 0, &out, 0, 0, CMD_SYS_EN, CMD_TIME_CLASS_D);
@@ -1955,7 +1955,7 @@ int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
u16 *hash)
{
- u64 imm;
+ u64 imm = 0;
int err;
err = mthca_cmd_imm(dev, mailbox->dma, &imm, 0, 0, CMD_MGID_HASH,
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index b54bc8865dae..1ab268b77096 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -382,7 +382,7 @@ static int mthca_init_icm(struct mthca_dev *mdev,
struct mthca_init_hca_param *init_hca,
u64 icm_size)
{
- u64 aux_pages;
+ u64 aux_pages = 0;
int err;
err = mthca_SET_ICM_SIZE(mdev, icm_size, &aux_pages);
diff --git a/drivers/infiniband/sw/siw/siw.h b/drivers/infiniband/sw/siw/siw.h
index cec5cccd2e75..75253f2b3e3d 100644
--- a/drivers/infiniband/sw/siw/siw.h
+++ b/drivers/infiniband/sw/siw/siw.h
@@ -121,11 +121,10 @@ struct siw_page_chunk {
};
struct siw_umem {
+ struct ib_umem *base_mem;
struct siw_page_chunk *page_chunk;
int num_pages;
- bool writable;
u64 fp_addr; /* First page base address */
- struct mm_struct *owning_mm;
};
struct siw_pble {
@@ -289,10 +288,11 @@ struct siw_rx_stream {
int skb_offset; /* offset in skb */
int skb_copied; /* processed bytes in skb */
+ enum siw_rx_state state;
+
union iwarp_hdr hdr;
struct mpa_trailer trailer;
-
- enum siw_rx_state state;
+ struct shash_desc *mpa_crc_hd;
/*
* For each FPDU, main RX loop runs through 3 stages:
@@ -314,7 +314,6 @@ struct siw_rx_stream {
u64 ddp_to;
u32 inval_stag; /* Stag to be invalidated */
- struct shash_desc *mpa_crc_hd;
u8 rx_suspend : 1;
u8 pad : 2; /* # of pad bytes expected */
u8 rdmap_op : 4; /* opcode of current frame */
@@ -418,10 +417,10 @@ struct siw_iwarp_tx {
struct siw_qp {
struct ib_qp base_qp;
struct siw_device *sdev;
+ int tx_cpu;
struct kref ref;
struct completion qp_free;
struct list_head devq;
- int tx_cpu;
struct siw_qp_attrs attrs;
struct siw_cep *cep;
@@ -466,7 +465,6 @@ struct siw_qp {
} term_info;
struct rdma_user_mmap_entry *sq_entry; /* mmap info for SQE array */
struct rdma_user_mmap_entry *rq_entry; /* mmap info for RQE array */
- struct rcu_head rcu;
};
/* helper macros */
@@ -659,7 +657,7 @@ static inline struct siw_sqe *orq_get_free(struct siw_qp *qp)
static inline int siw_orq_empty(struct siw_qp *qp)
{
- return qp->orq[qp->orq_get % qp->attrs.orq_size].flags == 0 ? 1 : 0;
+ return orq_get_current(qp)->flags == 0 ? 1 : 0;
}
static inline struct siw_sqe *irq_alloc_free(struct siw_qp *qp)
diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c
index 7de651cb44e8..86323918a570 100644
--- a/drivers/infiniband/sw/siw/siw_cm.c
+++ b/drivers/infiniband/sw/siw/siw_cm.c
@@ -41,16 +41,6 @@ static int siw_cm_upcall(struct siw_cep *cep, enum iw_cm_event_type reason,
static void siw_sk_assign_cm_upcalls(struct sock *sk)
{
- write_lock_bh(&sk->sk_callback_lock);
- sk->sk_state_change = siw_cm_llp_state_change;
- sk->sk_data_ready = siw_cm_llp_data_ready;
- sk->sk_write_space = siw_cm_llp_write_space;
- sk->sk_error_report = siw_cm_llp_error_report;
- write_unlock_bh(&sk->sk_callback_lock);
-}
-
-static void siw_sk_save_upcalls(struct sock *sk)
-{
struct siw_cep *cep = sk_to_cep(sk);
write_lock_bh(&sk->sk_callback_lock);
@@ -58,6 +48,11 @@ static void siw_sk_save_upcalls(struct sock *sk)
cep->sk_data_ready = sk->sk_data_ready;
cep->sk_write_space = sk->sk_write_space;
cep->sk_error_report = sk->sk_error_report;
+
+ sk->sk_state_change = siw_cm_llp_state_change;
+ sk->sk_data_ready = siw_cm_llp_data_ready;
+ sk->sk_write_space = siw_cm_llp_write_space;
+ sk->sk_error_report = siw_cm_llp_error_report;
write_unlock_bh(&sk->sk_callback_lock);
}
@@ -156,7 +151,6 @@ static void siw_cep_socket_assoc(struct siw_cep *cep, struct socket *s)
siw_cep_get(cep);
s->sk->sk_user_data = cep;
- siw_sk_save_upcalls(s->sk);
siw_sk_assign_cm_upcalls(s->sk);
}
@@ -364,6 +358,24 @@ static int siw_cm_upcall(struct siw_cep *cep, enum iw_cm_event_type reason,
return id->event_handler(id, &event);
}
+static void siw_free_cm_id(struct siw_cep *cep)
+{
+ if (!cep->cm_id)
+ return;
+
+ cep->cm_id->rem_ref(cep->cm_id);
+ cep->cm_id = NULL;
+}
+
+static void siw_destroy_cep_sock(struct siw_cep *cep)
+{
+ if (cep->sock) {
+ siw_socket_disassoc(cep->sock);
+ sock_release(cep->sock);
+ cep->sock = NULL;
+ }
+}
+
/*
* siw_qp_cm_drop()
*
@@ -393,8 +405,7 @@ void siw_qp_cm_drop(struct siw_qp *qp, int schedule)
}
siw_dbg_cep(cep, "immediate close, state %d\n", cep->state);
- if (qp->term_info.valid)
- siw_send_terminate(qp);
+ siw_send_terminate(qp);
if (cep->cm_id) {
switch (cep->state) {
@@ -416,20 +427,12 @@ void siw_qp_cm_drop(struct siw_qp *qp, int schedule)
default:
break;
}
- cep->cm_id->rem_ref(cep->cm_id);
- cep->cm_id = NULL;
+ siw_free_cm_id(cep);
siw_cep_put(cep);
}
cep->state = SIW_EPSTATE_CLOSED;
- if (cep->sock) {
- siw_socket_disassoc(cep->sock);
- /*
- * Immediately close socket
- */
- sock_release(cep->sock);
- cep->sock = NULL;
- }
+ siw_destroy_cep_sock(cep);
if (cep->qp) {
cep->qp = NULL;
siw_qp_put(qp);
@@ -445,6 +448,12 @@ void siw_cep_put(struct siw_cep *cep)
kref_put(&cep->ref, __siw_cep_dealloc);
}
+static void siw_cep_set_free_and_put(struct siw_cep *cep)
+{
+ siw_cep_set_free(cep);
+ siw_cep_put(cep);
+}
+
void siw_cep_get(struct siw_cep *cep)
{
kref_get(&cep->ref);
@@ -1061,7 +1070,7 @@ static void siw_cm_work_handler(struct work_struct *w)
/*
* QP scheduled LLP close
*/
- if (cep->qp && cep->qp->term_info.valid)
+ if (cep->qp)
siw_send_terminate(cep->qp);
if (cep->cm_id)
@@ -1175,8 +1184,7 @@ static void siw_cm_work_handler(struct work_struct *w)
cep->sock = NULL;
}
if (cep->cm_id) {
- cep->cm_id->rem_ref(cep->cm_id);
- cep->cm_id = NULL;
+ siw_free_cm_id(cep);
siw_cep_put(cep);
}
}
@@ -1515,9 +1523,7 @@ error:
cep->state = SIW_EPSTATE_CLOSED;
- siw_cep_set_free(cep);
-
- siw_cep_put(cep);
+ siw_cep_set_free_and_put(cep);
} else if (s) {
sock_release(s);
@@ -1548,7 +1554,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
struct siw_cep *cep = (struct siw_cep *)id->provider_data;
struct siw_qp *qp;
struct siw_qp_attrs qp_attrs;
- int rv, max_priv_data = MPA_MAX_PRIVDATA;
+ int rv = -EINVAL, max_priv_data = MPA_MAX_PRIVDATA;
bool wait_for_peer_rts = false;
siw_cep_set_inuse(cep);
@@ -1564,26 +1570,17 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
if (cep->state != SIW_EPSTATE_RECVD_MPAREQ) {
siw_dbg_cep(cep, "out of state\n");
-
- siw_cep_set_free(cep);
- siw_cep_put(cep);
-
- return -ECONNRESET;
+ rv = -ECONNRESET;
+ goto free_cep;
}
qp = siw_qp_id2obj(sdev, params->qpn);
if (!qp) {
WARN(1, "[QP %d] does not exist\n", params->qpn);
- siw_cep_set_free(cep);
- siw_cep_put(cep);
-
- return -EINVAL;
+ goto free_cep;
}
down_write(&qp->state_lock);
- if (qp->attrs.state > SIW_QP_STATE_RTR) {
- rv = -EINVAL;
- up_write(&qp->state_lock);
- goto error;
- }
+ if (qp->attrs.state > SIW_QP_STATE_RTR)
+ goto error_unlock;
siw_dbg_cep(cep, "[QP %d]\n", params->qpn);
if (try_gso && cep->mpa.hdr.params.bits & MPA_RR_FLAG_GSO_EXP) {
@@ -1597,9 +1594,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
"[QP %u]: ord %d (max %d), ird %d (max %d)\n",
qp_id(qp), params->ord, sdev->attrs.max_ord,
params->ird, sdev->attrs.max_ird);
- rv = -EINVAL;
- up_write(&qp->state_lock);
- goto error;
+ goto error_unlock;
}
if (cep->enhanced_rdma_conn_est)
max_priv_data -= sizeof(struct mpa_v2_data);
@@ -1609,9 +1604,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
cep,
"[QP %u]: private data length: %d (max %d)\n",
qp_id(qp), params->private_data_len, max_priv_data);
- rv = -EINVAL;
- up_write(&qp->state_lock);
- goto error;
+ goto error_unlock;
}
if (cep->enhanced_rdma_conn_est) {
if (params->ord > cep->ord) {
@@ -1620,9 +1613,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
} else {
cep->ird = params->ird;
cep->ord = params->ord;
- rv = -EINVAL;
- up_write(&qp->state_lock);
- goto error;
+ goto error_unlock;
}
}
if (params->ird < cep->ird) {
@@ -1631,8 +1622,7 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
params->ird = cep->ird;
else {
rv = -ENOMEM;
- up_write(&qp->state_lock);
- goto error;
+ goto error_unlock;
}
}
if (cep->mpa.v2_ctrl.ord &
@@ -1679,7 +1669,6 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
SIW_QP_ATTR_ORD | SIW_QP_ATTR_IRD |
SIW_QP_ATTR_MPA);
up_write(&qp->state_lock);
-
if (rv)
goto error;
@@ -1702,27 +1691,23 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params)
siw_cep_set_free(cep);
return 0;
+
+error_unlock:
+ up_write(&qp->state_lock);
error:
- siw_socket_disassoc(cep->sock);
- sock_release(cep->sock);
- cep->sock = NULL;
+ siw_destroy_cep_sock(cep);
cep->state = SIW_EPSTATE_CLOSED;
- if (cep->cm_id) {
- cep->cm_id->rem_ref(id);
- cep->cm_id = NULL;
- }
+ siw_free_cm_id(cep);
if (qp->cep) {
siw_cep_put(cep);
qp->cep = NULL;
}
cep->qp = NULL;
siw_qp_put(qp);
-
- siw_cep_set_free(cep);
- siw_cep_put(cep);
-
+free_cep:
+ siw_cep_set_free_and_put(cep);
return rv;
}
@@ -1744,8 +1729,7 @@ int siw_reject(struct iw_cm_id *id, const void *pdata, u8 pd_len)
if (cep->state != SIW_EPSTATE_RECVD_MPAREQ) {
siw_dbg_cep(cep, "out of state\n");
- siw_cep_set_free(cep);
- siw_cep_put(cep); /* put last reference */
+ siw_cep_set_free_and_put(cep); /* put last reference */
return -ECONNRESET;
}
@@ -1756,14 +1740,11 @@ int siw_reject(struct iw_cm_id *id, const void *pdata, u8 pd_len)
cep->mpa.hdr.params.bits |= MPA_RR_FLAG_REJECT; /* reject */
siw_send_mpareqrep(cep, pdata, pd_len);
}
- siw_socket_disassoc(cep->sock);
- sock_release(cep->sock);
- cep->sock = NULL;
+ siw_destroy_cep_sock(cep);
cep->state = SIW_EPSTATE_CLOSED;
- siw_cep_set_free(cep);
- siw_cep_put(cep);
+ siw_cep_set_free_and_put(cep);
return 0;
}
@@ -1890,16 +1871,12 @@ error:
if (cep) {
siw_cep_set_inuse(cep);
- if (cep->cm_id) {
- cep->cm_id->rem_ref(cep->cm_id);
- cep->cm_id = NULL;
- }
+ siw_free_cm_id(cep);
cep->sock = NULL;
siw_socket_disassoc(s);
cep->state = SIW_EPSTATE_CLOSED;
- siw_cep_set_free(cep);
- siw_cep_put(cep);
+ siw_cep_set_free_and_put(cep);
}
sock_release(s);
@@ -1923,18 +1900,14 @@ static void siw_drop_listeners(struct iw_cm_id *id)
siw_cep_set_inuse(cep);
- if (cep->cm_id) {
- cep->cm_id->rem_ref(cep->cm_id);
- cep->cm_id = NULL;
- }
+ siw_free_cm_id(cep);
if (cep->sock) {
siw_socket_disassoc(cep->sock);
sock_release(cep->sock);
cep->sock = NULL;
}
cep->state = SIW_EPSTATE_CLOSED;
- siw_cep_set_free(cep);
- siw_cep_put(cep);
+ siw_cep_set_free_and_put(cep);
}
}
diff --git a/drivers/infiniband/sw/siw/siw_main.c b/drivers/infiniband/sw/siw/siw_main.c
index 1ab62982df74..61ad8ca3d1a2 100644
--- a/drivers/infiniband/sw/siw/siw_main.c
+++ b/drivers/infiniband/sw/siw/siw_main.c
@@ -109,6 +109,17 @@ static struct {
int num_nodes;
} siw_cpu_info;
+static void siw_destroy_cpulist(int number)
+{
+ int i = 0;
+
+ while (i < number)
+ kfree(siw_cpu_info.tx_valid_cpus[i++]);
+
+ kfree(siw_cpu_info.tx_valid_cpus);
+ siw_cpu_info.tx_valid_cpus = NULL;
+}
+
static int siw_init_cpulist(void)
{
int i, num_nodes = nr_node_ids;
@@ -138,24 +149,11 @@ static int siw_init_cpulist(void)
out_err:
siw_cpu_info.num_nodes = 0;
- while (--i >= 0)
- kfree(siw_cpu_info.tx_valid_cpus[i]);
- kfree(siw_cpu_info.tx_valid_cpus);
- siw_cpu_info.tx_valid_cpus = NULL;
+ siw_destroy_cpulist(i);
return -ENOMEM;
}
-static void siw_destroy_cpulist(void)
-{
- int i = 0;
-
- while (i < siw_cpu_info.num_nodes)
- kfree(siw_cpu_info.tx_valid_cpus[i++]);
-
- kfree(siw_cpu_info.tx_valid_cpus);
-}
-
/*
* Choose CPU with least number of active QP's from NUMA node of
* TX interface.
@@ -558,7 +556,7 @@ out_error:
pr_info("SoftIWARP attach failed. Error: %d\n", rv);
siw_cm_exit();
- siw_destroy_cpulist();
+ siw_destroy_cpulist(siw_cpu_info.num_nodes);
return rv;
}
@@ -573,7 +571,7 @@ static void __exit siw_exit_module(void)
siw_cm_exit();
- siw_destroy_cpulist();
+ siw_destroy_cpulist(siw_cpu_info.num_nodes);
if (siw_crypto_shash)
crypto_free_shash(siw_crypto_shash);
diff --git a/drivers/infiniband/sw/siw/siw_mem.c b/drivers/infiniband/sw/siw/siw_mem.c
index c5f7f1669d09..dcb963607c8b 100644
--- a/drivers/infiniband/sw/siw/siw_mem.c
+++ b/drivers/infiniband/sw/siw/siw_mem.c
@@ -5,6 +5,7 @@
#include <linux/gfp.h>
#include <rdma/ib_verbs.h>
+#include <rdma/ib_umem.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/sched/mm.h>
@@ -13,18 +14,20 @@
#include "siw.h"
#include "siw_mem.h"
+/* Stag lookup is based on its index part only (24 bits). */
+#define SIW_STAG_MAX_INDEX 0x00ffffff
+
/*
- * Stag lookup is based on its index part only (24 bits).
* The code avoids special Stag of zero and tries to randomize
* STag values between 1 and SIW_STAG_MAX_INDEX.
*/
int siw_mem_add(struct siw_device *sdev, struct siw_mem *m)
{
- struct xa_limit limit = XA_LIMIT(1, 0x00ffffff);
+ struct xa_limit limit = XA_LIMIT(1, SIW_STAG_MAX_INDEX);
u32 id, next;
get_random_bytes(&next, 4);
- next &= 0x00ffffff;
+ next &= SIW_STAG_MAX_INDEX;
if (xa_alloc_cyclic(&sdev->mem_xa, &id, m, limit, &next,
GFP_KERNEL) < 0)
@@ -60,28 +63,17 @@ struct siw_mem *siw_mem_id2obj(struct siw_device *sdev, int stag_index)
return NULL;
}
-static void siw_free_plist(struct siw_page_chunk *chunk, int num_pages,
- bool dirty)
-{
- unpin_user_pages_dirty_lock(chunk->plist, num_pages, dirty);
-}
-
-void siw_umem_release(struct siw_umem *umem, bool dirty)
+void siw_umem_release(struct siw_umem *umem)
{
- struct mm_struct *mm_s = umem->owning_mm;
int i, num_pages = umem->num_pages;
- for (i = 0; num_pages; i++) {
- int to_free = min_t(int, PAGES_PER_CHUNK, num_pages);
+ if (umem->base_mem)
+ ib_umem_release(umem->base_mem);
- siw_free_plist(&umem->page_chunk[i], to_free,
- umem->writable && dirty);
+ for (i = 0; num_pages > 0; i++) {
kfree(umem->page_chunk[i].plist);
- num_pages -= to_free;
+ num_pages -= PAGES_PER_CHUNK;
}
- atomic64_sub(umem->num_pages, &mm_s->pinned_vm);
-
- mmdrop(mm_s);
kfree(umem->page_chunk);
kfree(umem);
}
@@ -91,7 +83,7 @@ int siw_mr_add_mem(struct siw_mr *mr, struct ib_pd *pd, void *mem_obj,
{
struct siw_device *sdev = to_siw_dev(pd->device);
struct siw_mem *mem = kzalloc(sizeof(*mem), GFP_KERNEL);
- struct xa_limit limit = XA_LIMIT(1, 0x00ffffff);
+ struct xa_limit limit = XA_LIMIT(1, SIW_STAG_MAX_INDEX);
u32 id, next;
if (!mem)
@@ -107,7 +99,7 @@ int siw_mr_add_mem(struct siw_mr *mr, struct ib_pd *pd, void *mem_obj,
kref_init(&mem->ref);
get_random_bytes(&next, 4);
- next &= 0x00ffffff;
+ next &= SIW_STAG_MAX_INDEX;
if (xa_alloc_cyclic(&sdev->mem_xa, &id, mem, limit, &next,
GFP_KERNEL) < 0) {
@@ -145,7 +137,7 @@ void siw_free_mem(struct kref *ref)
if (!mem->is_mw && mem->mem_obj) {
if (mem->is_pbl == 0)
- siw_umem_release(mem->umem, true);
+ siw_umem_release(mem->umem);
else
kfree(mem->pbl);
}
@@ -362,18 +354,16 @@ struct siw_pbl *siw_pbl_alloc(u32 num_buf)
return pbl;
}
-struct siw_umem *siw_umem_get(u64 start, u64 len, bool writable)
+struct siw_umem *siw_umem_get(struct ib_device *base_dev, u64 start,
+ u64 len, int rights)
{
struct siw_umem *umem;
- struct mm_struct *mm_s;
+ struct ib_umem *base_mem;
+ struct sg_page_iter sg_iter;
+ struct sg_table *sgt;
u64 first_page_va;
- unsigned long mlock_limit;
- unsigned int foll_flags = FOLL_LONGTERM;
int num_pages, num_chunks, i, rv = 0;
- if (!can_do_mlock())
- return ERR_PTR(-EPERM);
-
if (!len)
return ERR_PTR(-EINVAL);
@@ -385,65 +375,50 @@ struct siw_umem *siw_umem_get(u64 start, u64 len, bool writable)
if (!umem)
return ERR_PTR(-ENOMEM);
- mm_s = current->mm;
- umem->owning_mm = mm_s;
- umem->writable = writable;
-
- mmgrab(mm_s);
-
- if (writable)
- foll_flags |= FOLL_WRITE;
-
- mmap_read_lock(mm_s);
-
- mlock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
-
- if (atomic64_add_return(num_pages, &mm_s->pinned_vm) > mlock_limit) {
- rv = -ENOMEM;
- goto out_sem_up;
- }
- umem->fp_addr = first_page_va;
-
umem->page_chunk =
kcalloc(num_chunks, sizeof(struct siw_page_chunk), GFP_KERNEL);
if (!umem->page_chunk) {
rv = -ENOMEM;
- goto out_sem_up;
+ goto err_out;
}
- for (i = 0; num_pages; i++) {
+ base_mem = ib_umem_get(base_dev, start, len, rights);
+ if (IS_ERR(base_mem)) {
+ rv = PTR_ERR(base_mem);
+ siw_dbg(base_dev, "Cannot pin user memory: %d\n", rv);
+ goto err_out;
+ }
+ umem->fp_addr = first_page_va;
+ umem->base_mem = base_mem;
+
+ sgt = &base_mem->sgt_append.sgt;
+ __sg_page_iter_start(&sg_iter, sgt->sgl, sgt->orig_nents, 0);
+
+ if (!__sg_page_iter_next(&sg_iter)) {
+ rv = -EINVAL;
+ goto err_out;
+ }
+ for (i = 0; num_pages > 0; i++) {
int nents = min_t(int, num_pages, PAGES_PER_CHUNK);
struct page **plist =
kcalloc(nents, sizeof(struct page *), GFP_KERNEL);
if (!plist) {
rv = -ENOMEM;
- goto out_sem_up;
+ goto err_out;
}
umem->page_chunk[i].plist = plist;
- while (nents) {
- rv = pin_user_pages(first_page_va, nents, foll_flags,
- plist);
- if (rv < 0)
- goto out_sem_up;
-
- umem->num_pages += rv;
- first_page_va += rv * PAGE_SIZE;
- plist += rv;
- nents -= rv;
- num_pages -= rv;
+ while (nents--) {
+ *plist = sg_page_iter_page(&sg_iter);
+ umem->num_pages++;
+ num_pages--;
+ plist++;
+ if (!__sg_page_iter_next(&sg_iter))
+ break;
}
}
-out_sem_up:
- mmap_read_unlock(mm_s);
-
- if (rv > 0)
- return umem;
-
- /* Adjust accounting for pages not pinned */
- if (num_pages)
- atomic64_sub(num_pages, &mm_s->pinned_vm);
-
- siw_umem_release(umem, false);
+ return umem;
+err_out:
+ siw_umem_release(umem);
return ERR_PTR(rv);
}
diff --git a/drivers/infiniband/sw/siw/siw_mem.h b/drivers/infiniband/sw/siw/siw_mem.h
index a2835284fe5b..e74cfcd6dbc1 100644
--- a/drivers/infiniband/sw/siw/siw_mem.h
+++ b/drivers/infiniband/sw/siw/siw_mem.h
@@ -6,8 +6,9 @@
#ifndef _SIW_MEM_H
#define _SIW_MEM_H
-struct siw_umem *siw_umem_get(u64 start, u64 len, bool writable);
-void siw_umem_release(struct siw_umem *umem, bool dirty);
+struct siw_umem *siw_umem_get(struct ib_device *base_dave, u64 start,
+ u64 len, int rights);
+void siw_umem_release(struct siw_umem *umem);
struct siw_pbl *siw_pbl_alloc(u32 num_buf);
dma_addr_t siw_pbl_get_buffer(struct siw_pbl *pbl, u64 off, int *len, int *idx);
struct siw_mem *siw_mem_id2obj(struct siw_device *sdev, int stag_index);
diff --git a/drivers/infiniband/sw/siw/siw_qp.c b/drivers/infiniband/sw/siw/siw_qp.c
index 26e3904d2f41..da92cfa2073d 100644
--- a/drivers/infiniband/sw/siw/siw_qp.c
+++ b/drivers/infiniband/sw/siw/siw_qp.c
@@ -1183,7 +1183,7 @@ int siw_rqe_complete(struct siw_qp *qp, struct siw_rqe *rqe, u32 bytes,
/*
* siw_sq_flush()
*
- * Flush SQ and ORRQ entries to CQ.
+ * Flush SQ and ORQ entries to CQ.
*
* Must be called with QP state write lock held.
* Therefore, SQ and ORQ lock must not be taken.
diff --git a/drivers/infiniband/sw/siw/siw_qp_rx.c b/drivers/infiniband/sw/siw/siw_qp_rx.c
index 33e0fdb362ff..ed4fc39718b4 100644
--- a/drivers/infiniband/sw/siw/siw_qp_rx.c
+++ b/drivers/infiniband/sw/siw/siw_qp_rx.c
@@ -405,6 +405,20 @@ out:
return wqe;
}
+static int siw_rx_data(struct siw_mem *mem_p, struct siw_rx_stream *srx,
+ unsigned int *pbl_idx, u64 addr, int bytes)
+{
+ int rv;
+
+ if (mem_p->mem_obj == NULL)
+ rv = siw_rx_kva(srx, ib_virt_dma_to_ptr(addr), bytes);
+ else if (!mem_p->is_pbl)
+ rv = siw_rx_umem(srx, mem_p->umem, addr, bytes);
+ else
+ rv = siw_rx_pbl(srx, pbl_idx, mem_p, addr, bytes);
+ return rv;
+}
+
/*
* siw_proc_send:
*
@@ -485,17 +499,8 @@ int siw_proc_send(struct siw_qp *qp)
break;
}
mem_p = *mem;
- if (mem_p->mem_obj == NULL)
- rv = siw_rx_kva(srx,
- ib_virt_dma_to_ptr(sge->laddr + frx->sge_off),
- sge_bytes);
- else if (!mem_p->is_pbl)
- rv = siw_rx_umem(srx, mem_p->umem,
- sge->laddr + frx->sge_off, sge_bytes);
- else
- rv = siw_rx_pbl(srx, &frx->pbl_idx, mem_p,
- sge->laddr + frx->sge_off, sge_bytes);
-
+ rv = siw_rx_data(mem_p, srx, &frx->pbl_idx,
+ sge->laddr + frx->sge_off, sge_bytes);
if (unlikely(rv != sge_bytes)) {
wqe->processed += rcvd_bytes;
@@ -598,17 +603,8 @@ int siw_proc_write(struct siw_qp *qp)
return -EINVAL;
}
- if (mem->mem_obj == NULL)
- rv = siw_rx_kva(srx,
- (void *)(uintptr_t)(srx->ddp_to + srx->fpdu_part_rcvd),
- bytes);
- else if (!mem->is_pbl)
- rv = siw_rx_umem(srx, mem->umem,
- srx->ddp_to + srx->fpdu_part_rcvd, bytes);
- else
- rv = siw_rx_pbl(srx, &frx->pbl_idx, mem,
- srx->ddp_to + srx->fpdu_part_rcvd, bytes);
-
+ rv = siw_rx_data(mem, srx, &frx->pbl_idx,
+ srx->ddp_to + srx->fpdu_part_rcvd, bytes);
if (unlikely(rv != bytes)) {
siw_init_terminate(qp, TERM_ERROR_LAYER_DDP,
DDP_ETYPE_CATASTROPHIC,
@@ -849,17 +845,8 @@ int siw_proc_rresp(struct siw_qp *qp)
mem_p = *mem;
bytes = min(srx->fpdu_part_rem, srx->skb_new);
-
- if (mem_p->mem_obj == NULL)
- rv = siw_rx_kva(srx,
- ib_virt_dma_to_ptr(sge->laddr + wqe->processed),
- bytes);
- else if (!mem_p->is_pbl)
- rv = siw_rx_umem(srx, mem_p->umem, sge->laddr + wqe->processed,
- bytes);
- else
- rv = siw_rx_pbl(srx, &frx->pbl_idx, mem_p,
- sge->laddr + wqe->processed, bytes);
+ rv = siw_rx_data(mem_p, srx, &frx->pbl_idx,
+ sge->laddr + wqe->processed, bytes);
if (rv != bytes) {
wqe->wc_status = SIW_WC_GENERAL_ERR;
rv = -EINVAL;
@@ -881,6 +868,13 @@ error_term:
return rv;
}
+static void siw_update_skb_rcvd(struct siw_rx_stream *srx, u16 length)
+{
+ srx->skb_offset += length;
+ srx->skb_new -= length;
+ srx->skb_copied += length;
+}
+
int siw_proc_terminate(struct siw_qp *qp)
{
struct siw_rx_stream *srx = &qp->rx_stream;
@@ -925,9 +919,7 @@ int siw_proc_terminate(struct siw_qp *qp)
goto out;
infop += to_copy;
- srx->skb_offset += to_copy;
- srx->skb_new -= to_copy;
- srx->skb_copied += to_copy;
+ siw_update_skb_rcvd(srx, to_copy);
srx->fpdu_part_rcvd += to_copy;
srx->fpdu_part_rem -= to_copy;
@@ -949,9 +941,7 @@ int siw_proc_terminate(struct siw_qp *qp)
term->flag_m ? "valid" : "invalid");
}
out:
- srx->skb_new -= to_copy;
- srx->skb_offset += to_copy;
- srx->skb_copied += to_copy;
+ siw_update_skb_rcvd(srx, to_copy);
srx->fpdu_part_rcvd += to_copy;
srx->fpdu_part_rem -= to_copy;
@@ -970,9 +960,7 @@ static int siw_get_trailer(struct siw_qp *qp, struct siw_rx_stream *srx)
skb_copy_bits(skb, srx->skb_offset, tbuf, avail);
- srx->skb_new -= avail;
- srx->skb_offset += avail;
- srx->skb_copied += avail;
+ siw_update_skb_rcvd(srx, avail);
srx->fpdu_part_rem -= avail;
if (srx->fpdu_part_rem)
@@ -1023,12 +1011,8 @@ static int siw_get_hdr(struct siw_rx_stream *srx)
skb_copy_bits(skb, srx->skb_offset,
(char *)c_hdr + srx->fpdu_part_rcvd, bytes);
+ siw_update_skb_rcvd(srx, bytes);
srx->fpdu_part_rcvd += bytes;
-
- srx->skb_new -= bytes;
- srx->skb_offset += bytes;
- srx->skb_copied += bytes;
-
if (srx->fpdu_part_rcvd < MIN_DDP_HDR)
return -EAGAIN;
@@ -1091,12 +1075,8 @@ static int siw_get_hdr(struct siw_rx_stream *srx)
skb_copy_bits(skb, srx->skb_offset,
(char *)c_hdr + srx->fpdu_part_rcvd, bytes);
+ siw_update_skb_rcvd(srx, bytes);
srx->fpdu_part_rcvd += bytes;
-
- srx->skb_new -= bytes;
- srx->skb_offset += bytes;
- srx->skb_copied += bytes;
-
if (srx->fpdu_part_rcvd < hdrlen)
return -EAGAIN;
}
diff --git a/drivers/infiniband/sw/siw/siw_qp_tx.c b/drivers/infiniband/sw/siw/siw_qp_tx.c
index b2c06100cf01..64ad9e0895bd 100644
--- a/drivers/infiniband/sw/siw/siw_qp_tx.c
+++ b/drivers/infiniband/sw/siw/siw_qp_tx.c
@@ -34,6 +34,15 @@ static struct page *siw_get_pblpage(struct siw_mem *mem, u64 addr, int *idx)
return NULL;
}
+static struct page *siw_get_page(struct siw_mem *mem, struct siw_sge *sge,
+ unsigned long offset, int *pbl_idx)
+{
+ if (!mem->is_pbl)
+ return siw_get_upage(mem->umem, sge->laddr + offset);
+ else
+ return siw_get_pblpage(mem, sge->laddr + offset, pbl_idx);
+}
+
/*
* Copy short payload at provided destination payload address
*/
@@ -67,11 +76,7 @@ static int siw_try_1seg(struct siw_iwarp_tx *c_tx, void *paddr)
char *buffer;
int pbl_idx = 0;
- if (!mem->is_pbl)
- p = siw_get_upage(mem->umem, sge->laddr);
- else
- p = siw_get_pblpage(mem, sge->laddr, &pbl_idx);
-
+ p = siw_get_page(mem, sge, 0, &pbl_idx);
if (unlikely(!p))
return -EFAULT;
@@ -85,13 +90,7 @@ static int siw_try_1seg(struct siw_iwarp_tx *c_tx, void *paddr)
memcpy(paddr, buffer + off, part);
kunmap_local(buffer);
- if (!mem->is_pbl)
- p = siw_get_upage(mem->umem,
- sge->laddr + part);
- else
- p = siw_get_pblpage(mem,
- sge->laddr + part,
- &pbl_idx);
+ p = siw_get_page(mem, sge, part, &pbl_idx);
if (unlikely(!p))
return -EFAULT;
@@ -249,14 +248,10 @@ static int siw_qp_prepare_tx(struct siw_iwarp_tx *c_tx)
/*
* Do complete CRC if enabled and short packet
*/
- if (c_tx->mpa_crc_hd) {
- crypto_shash_init(c_tx->mpa_crc_hd);
- if (crypto_shash_update(c_tx->mpa_crc_hd,
- (u8 *)&c_tx->pkt,
- c_tx->ctrl_len))
- return -EINVAL;
- crypto_shash_final(c_tx->mpa_crc_hd, (u8 *)crc);
- }
+ if (c_tx->mpa_crc_hd &&
+ crypto_shash_digest(c_tx->mpa_crc_hd, (u8 *)&c_tx->pkt,
+ c_tx->ctrl_len, (u8 *)crc) != 0)
+ return -EINVAL;
c_tx->ctrl_len += MPA_CRC_SIZE;
return PKT_COMPLETE;
@@ -297,8 +292,7 @@ static int siw_tx_ctrl(struct siw_iwarp_tx *c_tx, struct socket *s,
(char *)&c_tx->pkt.ctrl + c_tx->ctrl_sent,
.iov_len = c_tx->ctrl_len - c_tx->ctrl_sent };
- int rv = kernel_sendmsg(s, &msg, &iov, 1,
- c_tx->ctrl_len - c_tx->ctrl_sent);
+ int rv = kernel_sendmsg(s, &msg, &iov, 1, iov.iov_len);
if (rv >= 0) {
c_tx->ctrl_sent += rv;
@@ -502,13 +496,7 @@ static int siw_tx_hdt(struct siw_iwarp_tx *c_tx, struct socket *s)
if (!is_kva) {
struct page *p;
- if (mem->is_pbl)
- p = siw_get_pblpage(
- mem, sge->laddr + sge_off,
- &pbl_idx);
- else
- p = siw_get_upage(mem->umem,
- sge->laddr + sge_off);
+ p = siw_get_page(mem, sge, sge_off, &pbl_idx);
if (unlikely(!p)) {
siw_unmap_pages(iov, kmap_mask, seg);
wqe->processed -= c_tx->bytes_unsent;
@@ -1009,13 +997,12 @@ static int siw_qp_sq_proc_local(struct siw_qp *qp, struct siw_wqe *wqe)
* MPA FPDUs, each containing a DDP segment.
*
* SQ processing may occur in user context as a result of posting
- * new WQE's or from siw_sq_work_handler() context. Processing in
+ * new WQE's or from siw_tx_thread context. Processing in
* user context is limited to non-kernel verbs users.
*
* SQ processing may get paused anytime, possibly in the middle of a WR
* or FPDU, if insufficient send space is available. SQ processing
- * gets resumed from siw_sq_work_handler(), if send space becomes
- * available again.
+ * gets resumed from siw_tx_thread, if send space becomes available again.
*
* Must be called with the QP state read-locked.
*
diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c
index c5c27db9c2fe..ecf0444666b4 100644
--- a/drivers/infiniband/sw/siw/siw_verbs.c
+++ b/drivers/infiniband/sw/siw/siw_verbs.c
@@ -19,6 +19,15 @@
#include "siw_verbs.h"
#include "siw_mem.h"
+static int siw_qp_state_to_ib_qp_state[SIW_QP_STATE_COUNT] = {
+ [SIW_QP_STATE_IDLE] = IB_QPS_INIT,
+ [SIW_QP_STATE_RTR] = IB_QPS_RTR,
+ [SIW_QP_STATE_RTS] = IB_QPS_RTS,
+ [SIW_QP_STATE_CLOSING] = IB_QPS_SQD,
+ [SIW_QP_STATE_TERMINATE] = IB_QPS_SQE,
+ [SIW_QP_STATE_ERROR] = IB_QPS_ERR
+};
+
static int ib_qp_state_to_siw_qp_state[IB_QPS_ERR + 1] = {
[IB_QPS_RESET] = SIW_QP_STATE_IDLE,
[IB_QPS_INIT] = SIW_QP_STATE_IDLE,
@@ -66,12 +75,9 @@ int siw_mmap(struct ib_ucontext *ctx, struct vm_area_struct *vma)
entry = to_siw_mmap_entry(rdma_entry);
rv = remap_vmalloc_range(vma, entry->address, 0);
- if (rv) {
+ if (rv)
pr_warn("remap_vmalloc_range failed: %lu, %zu\n", vma->vm_pgoff,
size);
- goto out;
- }
-out:
rdma_user_mmap_entry_put(rdma_entry);
return rv;
@@ -336,11 +342,10 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
goto err_atomic;
}
/*
- * NOTE: we allow for zero element SQ and RQ WQE's SGL's
- * but not for a QP unable to hold any WQE (SQ + RQ)
+ * NOTE: we don't allow for a QP unable to hold any SQ WQE
*/
- if (attrs->cap.max_send_wr + attrs->cap.max_recv_wr == 0) {
- siw_dbg(base_dev, "QP must have send or receive queue\n");
+ if (attrs->cap.max_send_wr == 0) {
+ siw_dbg(base_dev, "QP must have send queue\n");
rv = -EINVAL;
goto err_atomic;
}
@@ -360,21 +365,14 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
if (rv)
goto err_atomic;
- num_sqe = attrs->cap.max_send_wr;
- num_rqe = attrs->cap.max_recv_wr;
/* All queue indices are derived from modulo operations
* on a free running 'get' (consumer) and 'put' (producer)
* unsigned counter. Having queue sizes at power of two
* avoids handling counter wrap around.
*/
- if (num_sqe)
- num_sqe = roundup_pow_of_two(num_sqe);
- else {
- /* Zero sized SQ is not supported */
- rv = -EINVAL;
- goto err_out_xa;
- }
+ num_sqe = roundup_pow_of_two(attrs->cap.max_send_wr);
+ num_rqe = attrs->cap.max_recv_wr;
if (num_rqe)
num_rqe = roundup_pow_of_two(num_rqe);
@@ -515,6 +513,7 @@ int siw_query_qp(struct ib_qp *base_qp, struct ib_qp_attr *qp_attr,
} else {
return -EINVAL;
}
+ qp_attr->qp_state = siw_qp_state_to_ib_qp_state[qp->attrs.state];
qp_attr->cap.max_inline_data = SIW_MAX_INLINE;
qp_attr->cap.max_send_wr = qp->attrs.sq_size;
qp_attr->cap.max_send_sge = qp->attrs.sq_max_sges;
@@ -1321,8 +1320,6 @@ struct ib_mr *siw_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
struct siw_umem *umem = NULL;
struct siw_ureq_reg_mr ureq;
struct siw_device *sdev = to_siw_dev(pd->device);
-
- unsigned long mem_limit = rlimit(RLIMIT_MEMLOCK);
int rv;
siw_dbg_pd(pd, "start: 0x%pK, va: 0x%pK, len: %llu\n",
@@ -1338,20 +1335,7 @@ struct ib_mr *siw_reg_user_mr(struct ib_pd *pd, u64 start, u64 len,
rv = -EINVAL;
goto err_out;
}
- if (mem_limit != RLIM_INFINITY) {
- unsigned long num_pages =
- (PAGE_ALIGN(len + (start & ~PAGE_MASK))) >> PAGE_SHIFT;
- mem_limit >>= PAGE_SHIFT;
-
- if (num_pages > mem_limit - current->mm->locked_vm) {
- siw_dbg_pd(pd, "pages req %lu, max %lu, lock %lu\n",
- num_pages, mem_limit,
- current->mm->locked_vm);
- rv = -ENOMEM;
- goto err_out;
- }
- }
- umem = siw_umem_get(start, len, ib_access_writable(rights));
+ umem = siw_umem_get(pd->device, start, len, rights);
if (IS_ERR(umem)) {
rv = PTR_ERR(umem);
siw_dbg_pd(pd, "getting user memory failed: %d\n", rv);
@@ -1404,7 +1388,7 @@ err_out:
kfree_rcu(mr, rcu);
} else {
if (umem)
- siw_umem_release(umem, false);
+ siw_umem_release(umem);
}
return ERR_PTR(rv);
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 35e9c8a330e2..963e936da5e3 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -351,10 +351,12 @@ struct ipoib_dev_priv {
struct workqueue_struct *wq;
struct delayed_work mcast_task;
struct work_struct carrier_on_task;
+ struct work_struct reschedule_napi_work;
struct work_struct flush_light;
struct work_struct flush_normal;
struct work_struct flush_heavy;
struct work_struct restart_task;
+ struct work_struct tx_timeout_work;
struct delayed_work ah_reap_task;
struct delayed_work neigh_reap_task;
struct ib_device *ca;
@@ -499,6 +501,7 @@ int ipoib_send(struct net_device *dev, struct sk_buff *skb,
struct ib_ah *address, u32 dqpn);
void ipoib_reap_ah(struct work_struct *work);
+void ipoib_napi_schedule_work(struct work_struct *work);
struct ipoib_path *__path_find(struct net_device *dev, void *gid);
void ipoib_mark_paths_invalid(struct net_device *dev);
void ipoib_flush_paths(struct net_device *dev);
@@ -510,6 +513,7 @@ void ipoib_ib_tx_timer_func(struct timer_list *t);
void ipoib_ib_dev_flush_light(struct work_struct *work);
void ipoib_ib_dev_flush_normal(struct work_struct *work);
void ipoib_ib_dev_flush_heavy(struct work_struct *work);
+void ipoib_ib_tx_timeout_work(struct work_struct *work);
void ipoib_pkey_event(struct work_struct *work);
void ipoib_ib_dev_cleanup(struct net_device *dev);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 7f84d9866cef..5cde275daa94 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -531,11 +531,35 @@ void ipoib_ib_rx_completion(struct ib_cq *cq, void *ctx_ptr)
napi_schedule(&priv->recv_napi);
}
+/* The function will force napi_schedule */
+void ipoib_napi_schedule_work(struct work_struct *work)
+{
+ struct ipoib_dev_priv *priv =
+ container_of(work, struct ipoib_dev_priv, reschedule_napi_work);
+ bool ret;
+
+ do {
+ ret = napi_schedule(&priv->send_napi);
+ if (!ret)
+ msleep(3);
+ } while (!ret && netif_queue_stopped(priv->dev) &&
+ test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags));
+}
+
void ipoib_ib_tx_completion(struct ib_cq *cq, void *ctx_ptr)
{
struct ipoib_dev_priv *priv = ctx_ptr;
+ bool ret;
- napi_schedule(&priv->send_napi);
+ ret = napi_schedule(&priv->send_napi);
+ /*
+ * if the queue is closed the driver must be able to schedule napi,
+ * otherwise we can end with closed queue forever, because no new
+ * packets to send and napi callback might not get new event after
+ * its re-arm of the napi.
+ */
+ if (!ret && netif_queue_stopped(priv->dev))
+ schedule_work(&priv->reschedule_napi_work);
}
static inline int post_send(struct ipoib_dev_priv *priv,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 967004ccad98..7a5be705d718 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1200,7 +1200,34 @@ static void ipoib_timeout(struct net_device *dev, unsigned int txqueue)
netif_queue_stopped(dev), priv->tx_head, priv->tx_tail,
priv->global_tx_head, priv->global_tx_tail);
- /* XXX reset QP, etc. */
+
+ schedule_work(&priv->tx_timeout_work);
+}
+
+void ipoib_ib_tx_timeout_work(struct work_struct *work)
+{
+ struct ipoib_dev_priv *priv = container_of(work,
+ struct ipoib_dev_priv,
+ tx_timeout_work);
+ int err;
+
+ rtnl_lock();
+
+ if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
+ goto unlock;
+
+ ipoib_stop(priv->dev);
+ err = ipoib_open(priv->dev);
+ if (err) {
+ ipoib_warn(priv, "ipoib_open failed recovering from a tx_timeout, err(%d).\n",
+ err);
+ goto unlock;
+ }
+
+ netif_tx_wake_all_queues(priv->dev);
+unlock:
+ rtnl_unlock();
+
}
static int ipoib_hard_header(struct sk_buff *skb,
@@ -2112,7 +2139,7 @@ void ipoib_setup_common(struct net_device *dev)
ipoib_set_ethtool_ops(dev);
- dev->watchdog_timeo = HZ;
+ dev->watchdog_timeo = 10 * HZ;
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
@@ -2150,10 +2177,12 @@ static void ipoib_build_priv(struct net_device *dev)
INIT_DELAYED_WORK(&priv->mcast_task, ipoib_mcast_join_task);
INIT_WORK(&priv->carrier_on_task, ipoib_mcast_carrier_on_task);
+ INIT_WORK(&priv->reschedule_napi_work, ipoib_napi_schedule_work);
INIT_WORK(&priv->flush_light, ipoib_ib_dev_flush_light);
INIT_WORK(&priv->flush_normal, ipoib_ib_dev_flush_normal);
INIT_WORK(&priv->flush_heavy, ipoib_ib_dev_flush_heavy);
INIT_WORK(&priv->restart_task, ipoib_mcast_restart_task);
+ INIT_WORK(&priv->tx_timeout_work, ipoib_ib_tx_timeout_work);
INIT_DELAYED_WORK(&priv->ah_reap_task, ipoib_reap_ah);
INIT_DELAYED_WORK(&priv->neigh_reap_task, ipoib_reap_neigh);
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 5b3154503bf4..319d4288eddd 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -531,21 +531,18 @@ static int ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast)
if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags))
rec.join_state = SENDONLY_FULLMEMBER_JOIN;
}
- spin_unlock_irq(&priv->lock);
multicast = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port,
- &rec, comp_mask, GFP_KERNEL,
+ &rec, comp_mask, GFP_ATOMIC,
ipoib_mcast_join_complete, mcast);
- spin_lock_irq(&priv->lock);
if (IS_ERR(multicast)) {
ret = PTR_ERR(multicast);
ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret);
/* Requeue this join task with a backoff delay */
__ipoib_mcast_schedule_join_thread(priv, mcast, 1);
clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
- spin_unlock_irq(&priv->lock);
complete(&mcast->done);
- spin_lock_irq(&priv->lock);
+ return ret;
}
return 0;
}
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index dee8c97ff056..68429a5f796d 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -182,7 +182,7 @@ enum iser_data_dir {
*
* @sg: pointer to the sg list
* @size: num entries of this sg
- * @data_len: total beffer byte len
+ * @data_len: total buffer byte len
* @dma_nents: returned by dma_map_sg
*/
struct iser_data_buf {
@@ -299,7 +299,6 @@ struct ib_conn;
*
* @ib_device: RDMA device
* @pd: Protection Domain for this device
- * @mr: Global DMA memory region
* @event_handler: IB events handle routine
* @ig_list: entry in devices list
* @refcount: Reference counter, dominated by open iser connections
@@ -317,12 +316,10 @@ struct iser_device {
*
* @mr: memory region
* @sig_mr: signature memory region
- * @mr_valid: is mr valid indicator
*/
struct iser_reg_resources {
struct ib_mr *mr;
struct ib_mr *sig_mr;
- u8 mr_valid:1;
};
/**
@@ -389,7 +386,7 @@ struct ib_conn {
* to max number of post recvs
* @max_cmds: maximum cmds allowed for this connection
* @name: connection peer portal
- * @release_work: deffered work for release job
+ * @release_work: deferred work for release job
* @state_mutex: protects iser onnection state
* @stop_completion: conn_stop completion
* @ib_completion: RDMA cleanup completion
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 39ea73f69016..f5f090dc4f1e 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -581,7 +581,10 @@ static inline int iser_inv_desc(struct iser_fr_desc *desc, u32 rkey)
return -EINVAL;
}
- desc->rsc.mr_valid = 0;
+ if (desc->sig_protected)
+ desc->rsc.sig_mr->need_inval = false;
+ else
+ desc->rsc.mr->need_inval = false;
return 0;
}
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index 29ae2c6a250a..6efcb79c8efe 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -264,7 +264,7 @@ static int iser_reg_sig_mr(struct iscsi_iser_task *iser_task,
iser_set_prot_checks(iser_task->sc, &sig_attrs->check_mask);
- if (rsc->mr_valid)
+ if (rsc->sig_mr->need_inval)
iser_inv_rkey(&tx_desc->inv_wr, mr, cqe, &wr->wr);
ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey));
@@ -288,7 +288,7 @@ static int iser_reg_sig_mr(struct iscsi_iser_task *iser_task,
wr->access = IB_ACCESS_LOCAL_WRITE |
IB_ACCESS_REMOTE_READ |
IB_ACCESS_REMOTE_WRITE;
- rsc->mr_valid = 1;
+ rsc->sig_mr->need_inval = true;
sig_reg->sge.lkey = mr->lkey;
sig_reg->rkey = mr->rkey;
@@ -313,7 +313,7 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task,
struct ib_reg_wr *wr = &tx_desc->reg_wr;
int n;
- if (rsc->mr_valid)
+ if (rsc->mr->need_inval)
iser_inv_rkey(&tx_desc->inv_wr, mr, cqe, &wr->wr);
ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey));
@@ -336,7 +336,7 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task,
IB_ACCESS_REMOTE_WRITE |
IB_ACCESS_REMOTE_READ;
- rsc->mr_valid = 1;
+ rsc->mr->need_inval = true;
reg->sge.lkey = mr->lkey;
reg->rkey = mr->rkey;
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 95b8eebf7e04..6801b70dc9e0 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -129,7 +129,6 @@ iser_create_fastreg_desc(struct iser_device *device,
goto err_alloc_mr_integrity;
}
}
- desc->rsc.mr_valid = 0;
return desc;
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
index 7f3167ce2972..88106cf5ce55 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
@@ -1391,9 +1391,9 @@ static int alloc_path_reqs(struct rtrs_clt_path *clt_path)
clt_path->max_pages_per_mr);
if (IS_ERR(req->mr)) {
err = PTR_ERR(req->mr);
+ pr_err("Failed to alloc clt_path->max_pages_per_mr %d: %pe\n",
+ clt_path->max_pages_per_mr, req->mr);
req->mr = NULL;
- pr_err("Failed to alloc clt_path->max_pages_per_mr %d\n",
- clt_path->max_pages_per_mr);
goto out;
}
@@ -2025,6 +2025,8 @@ static int rtrs_clt_rdma_cm_handler(struct rdma_cm_id *cm_id,
/*
* Device removal is a special case. Queue close and return 0.
*/
+ rtrs_wrn_rl(s, "CM event: %s, status: %d\n", rdma_event_msg(ev->event),
+ ev->status);
rtrs_clt_close_conns(clt_path, false);
return 0;
default:
@@ -2058,10 +2060,8 @@ static int create_cm(struct rtrs_clt_con *con)
clt_path->s.dst_addr.ss_family == AF_IB ?
RDMA_PS_IB : RDMA_PS_TCP, IB_QPT_RC);
if (IS_ERR(cm_id)) {
- err = PTR_ERR(cm_id);
- rtrs_err(s, "Failed to create CM ID, err: %d\n", err);
-
- return err;
+ rtrs_err(s, "Failed to create CM ID, err: %pe\n", cm_id);
+ return PTR_ERR(cm_id);
}
con->c.cm_id = cm_id;
con->cm_err = 0;
diff --git a/drivers/infiniband/ulp/rtrs/rtrs.c b/drivers/infiniband/ulp/rtrs/rtrs.c
index d80edfffd2e4..4e17d546d4cc 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs.c
@@ -242,8 +242,8 @@ static int create_cq(struct rtrs_con *con, int cq_vector, int nr_cqe,
cq = ib_cq_pool_get(cm_id->device, nr_cqe, cq_vector, poll_ctx);
if (IS_ERR(cq)) {
- rtrs_err(con->path, "Creating completion queue failed, errno: %ld\n",
- PTR_ERR(cq));
+ rtrs_err(con->path, "Creating completion queue failed, errno: %pe\n",
+ cq);
return PTR_ERR(cq);
}
con->cq = cq;
diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c
index ce82548916bb..c1fa75c0f970 100644
--- a/drivers/input/misc/da7280.c
+++ b/drivers/input/misc/da7280.c
@@ -352,7 +352,7 @@ static int da7280_haptic_set_pwm(struct da7280_haptic *haptics, bool enabled)
state.duty_cycle = period_mag_multi;
}
- error = pwm_apply_state(haptics->pwm_dev, &state);
+ error = pwm_apply_might_sleep(haptics->pwm_dev, &state);
if (error)
dev_err(haptics->dev, "Failed to apply pwm state: %d\n", error);
@@ -1175,7 +1175,7 @@ static int da7280_probe(struct i2c_client *client)
/* Sync up PWM state and ensure it is off. */
pwm_init_state(haptics->pwm_dev, &state);
state.enabled = false;
- error = pwm_apply_state(haptics->pwm_dev, &state);
+ error = pwm_apply_might_sleep(haptics->pwm_dev, &state);
if (error) {
dev_err(dev, "Failed to apply PWM state: %d\n", error);
return error;
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
index 1e731d8397c6..5b9aedf4362f 100644
--- a/drivers/input/misc/pwm-beeper.c
+++ b/drivers/input/misc/pwm-beeper.c
@@ -39,7 +39,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period)
state.period = period;
pwm_set_relative_duty_cycle(&state, 50, 100);
- error = pwm_apply_state(beeper->pwm, &state);
+ error = pwm_apply_might_sleep(beeper->pwm, &state);
if (error)
return error;
@@ -138,7 +138,7 @@ static int pwm_beeper_probe(struct platform_device *pdev)
/* Sync up PWM state and ensure it is off. */
pwm_init_state(beeper->pwm, &state);
state.enabled = false;
- error = pwm_apply_state(beeper->pwm, &state);
+ error = pwm_apply_might_sleep(beeper->pwm, &state);
if (error) {
dev_err(dev, "failed to apply initial PWM state: %d\n",
error);
diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c
index acac79c488aa..3e5ed685ed8f 100644
--- a/drivers/input/misc/pwm-vibra.c
+++ b/drivers/input/misc/pwm-vibra.c
@@ -56,7 +56,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
pwm_set_relative_duty_cycle(&state, vibrator->level, 0xffff);
state.enabled = true;
- err = pwm_apply_state(vibrator->pwm, &state);
+ err = pwm_apply_might_sleep(vibrator->pwm, &state);
if (err) {
dev_err(pdev, "failed to apply pwm state: %d\n", err);
return err;
@@ -67,7 +67,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
state.duty_cycle = vibrator->direction_duty_cycle;
state.enabled = true;
- err = pwm_apply_state(vibrator->pwm_dir, &state);
+ err = pwm_apply_might_sleep(vibrator->pwm_dir, &state);
if (err) {
dev_err(pdev, "failed to apply dir-pwm state: %d\n", err);
pwm_disable(vibrator->pwm);
@@ -160,7 +160,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
/* Sync up PWM state and ensure it is off. */
pwm_init_state(vibrator->pwm, &state);
state.enabled = false;
- err = pwm_apply_state(vibrator->pwm, &state);
+ err = pwm_apply_might_sleep(vibrator->pwm, &state);
if (err) {
dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
err);
@@ -174,7 +174,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
/* Sync up PWM state and ensure it is off. */
pwm_init_state(vibrator->pwm_dir, &state);
state.enabled = false;
- err = pwm_apply_state(vibrator->pwm_dir, &state);
+ err = pwm_apply_might_sleep(vibrator->pwm_dir, &state);
if (err) {
dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
err);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 20094b9899f0..a2c4b3b87f93 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2546,7 +2546,7 @@ static const struct vb2_queue mxt_queue = {
.ops = &mxt_queue_ops,
.mem_ops = &vb2_vmalloc_memops,
.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC,
- .min_buffers_needed = 1,
+ .min_queued_buffers = 1,
};
static int mxt_vidioc_querycap(struct file *file, void *priv,
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 8ddb3f7d307a..ae3aab428337 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -847,9 +847,10 @@ static int sur40_queue_setup(struct vb2_queue *q,
unsigned int sizes[], struct device *alloc_devs[])
{
struct sur40_state *sur40 = vb2_get_drv_priv(q);
+ unsigned int q_num_bufs = vb2_get_num_buffers(q);
- if (q->num_buffers + *nbuffers < 3)
- *nbuffers = 3 - q->num_buffers;
+ if (q_num_bufs + *nbuffers < 3)
+ *nbuffers = 3 - q_num_bufs;
if (*nplanes)
return sizes[0] < sur40->pix_fmt.sizeimage ? -EINVAL : 0;
@@ -1123,7 +1124,7 @@ static const struct vb2_queue sur40_queue = {
.ops = &sur40_queue_ops,
.mem_ops = &vb2_dma_sg_memops,
.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC,
- .min_buffers_needed = 3,
+ .min_queued_buffers = 3,
};
static const struct v4l2_file_operations sur40_video_fops = {
diff --git a/drivers/interconnect/imx/imx8mm.c b/drivers/interconnect/imx/imx8mm.c
index b43325364aa3..8c40f4182263 100644
--- a/drivers/interconnect/imx/imx8mm.c
+++ b/drivers/interconnect/imx/imx8mm.c
@@ -86,16 +86,9 @@ static int imx8mm_icc_probe(struct platform_device *pdev)
return imx_icc_register(pdev, nodes, ARRAY_SIZE(nodes), NULL);
}
-static int imx8mm_icc_remove(struct platform_device *pdev)
-{
- imx_icc_unregister(pdev);
-
- return 0;
-}
-
static struct platform_driver imx8mm_icc_driver = {
.probe = imx8mm_icc_probe,
- .remove = imx8mm_icc_remove,
+ .remove_new = imx_icc_unregister,
.driver = {
.name = "imx8mm-interconnect",
},
diff --git a/drivers/interconnect/imx/imx8mn.c b/drivers/interconnect/imx/imx8mn.c
index 8ce6d8e4bf5e..fa3d4f97dfa4 100644
--- a/drivers/interconnect/imx/imx8mn.c
+++ b/drivers/interconnect/imx/imx8mn.c
@@ -75,16 +75,9 @@ static int imx8mn_icc_probe(struct platform_device *pdev)
return imx_icc_register(pdev, nodes, ARRAY_SIZE(nodes), NULL);
}
-static int imx8mn_icc_remove(struct platform_device *pdev)
-{
- imx_icc_unregister(pdev);
-
- return 0;
-}
-
static struct platform_driver imx8mn_icc_driver = {
.probe = imx8mn_icc_probe,
- .remove = imx8mn_icc_remove,
+ .remove_new = imx_icc_unregister,
.driver = {
.name = "imx8mn-interconnect",
},
diff --git a/drivers/interconnect/imx/imx8mp.c b/drivers/interconnect/imx/imx8mp.c
index a66ae3638b18..d218bb47757a 100644
--- a/drivers/interconnect/imx/imx8mp.c
+++ b/drivers/interconnect/imx/imx8mp.c
@@ -239,16 +239,9 @@ static int imx8mp_icc_probe(struct platform_device *pdev)
return imx_icc_register(pdev, nodes, ARRAY_SIZE(nodes), noc_setting_nodes);
}
-static int imx8mp_icc_remove(struct platform_device *pdev)
-{
- imx_icc_unregister(pdev);
-
- return 0;
-}
-
static struct platform_driver imx8mp_icc_driver = {
.probe = imx8mp_icc_probe,
- .remove = imx8mp_icc_remove,
+ .remove_new = imx_icc_unregister,
.driver = {
.name = "imx8mp-interconnect",
},
diff --git a/drivers/interconnect/imx/imx8mq.c b/drivers/interconnect/imx/imx8mq.c
index b6fb71305c99..8bbd672b346e 100644
--- a/drivers/interconnect/imx/imx8mq.c
+++ b/drivers/interconnect/imx/imx8mq.c
@@ -85,16 +85,9 @@ static int imx8mq_icc_probe(struct platform_device *pdev)
return imx_icc_register(pdev, nodes, ARRAY_SIZE(nodes), NULL);
}
-static int imx8mq_icc_remove(struct platform_device *pdev)
-{
- imx_icc_unregister(pdev);
-
- return 0;
-}
-
static struct platform_driver imx8mq_icc_driver = {
.probe = imx8mq_icc_probe,
- .remove = imx8mq_icc_remove,
+ .remove_new = imx_icc_unregister,
.driver = {
.name = "imx8mq-interconnect",
.sync_state = icc_sync_state,
diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig
index 62b516d38d03..697f96c49f6f 100644
--- a/drivers/interconnect/qcom/Kconfig
+++ b/drivers/interconnect/qcom/Kconfig
@@ -191,6 +191,15 @@ config INTERCONNECT_QCOM_SDX75
This is a driver for the Qualcomm Network-on-Chip on sdx75-based
platforms.
+config INTERCONNECT_QCOM_SM6115
+ tristate "Qualcomm SM6115 interconnect driver"
+ depends on INTERCONNECT_QCOM
+ depends on QCOM_SMD_RPM
+ select INTERCONNECT_QCOM_SMD_RPM
+ help
+ This is a driver for the Qualcomm Network-on-Chip on sm6115-based
+ platforms.
+
config INTERCONNECT_QCOM_SM6350
tristate "Qualcomm SM6350 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
@@ -245,5 +254,23 @@ config INTERCONNECT_QCOM_SM8550
This is a driver for the Qualcomm Network-on-Chip on SM8550-based
platforms.
+config INTERCONNECT_QCOM_SM8650
+ tristate "Qualcomm SM8650 interconnect driver"
+ depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
+ select INTERCONNECT_QCOM_RPMH
+ select INTERCONNECT_QCOM_BCM_VOTER
+ help
+ This is a driver for the Qualcomm Network-on-Chip on SM8650-based
+ platforms.
+
+config INTERCONNECT_QCOM_X1E80100
+ tristate "Qualcomm X1E80100 interconnect driver"
+ depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
+ select INTERCONNECT_QCOM_RPMH
+ select INTERCONNECT_QCOM_BCM_VOTER
+ help
+ This is a driver for the Qualcomm Network-on-Chip on X1E80100-based
+ platforms.
+
config INTERCONNECT_QCOM_SMD_RPM
tristate
diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile
index c5320e293960..704846165022 100644
--- a/drivers/interconnect/qcom/Makefile
+++ b/drivers/interconnect/qcom/Makefile
@@ -24,12 +24,15 @@ qnoc-sdm845-objs := sdm845.o
qnoc-sdx55-objs := sdx55.o
qnoc-sdx65-objs := sdx65.o
qnoc-sdx75-objs := sdx75.o
+qnoc-sm6115-objs := sm6115.o
qnoc-sm6350-objs := sm6350.o
qnoc-sm8150-objs := sm8150.o
qnoc-sm8250-objs := sm8250.o
qnoc-sm8350-objs := sm8350.o
qnoc-sm8450-objs := sm8450.o
qnoc-sm8550-objs := sm8550.o
+qnoc-sm8650-objs := sm8650.o
+qnoc-x1e80100-objs := x1e80100.o
icc-smd-rpm-objs := smd-rpm.o icc-rpm.o icc-rpm-clocks.o
obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o
@@ -53,10 +56,13 @@ obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDX65) += qnoc-sdx65.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDX75) += qnoc-sdx75.o
+obj-$(CONFIG_INTERCONNECT_QCOM_SM6115) += qnoc-sm6115.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM6350) += qnoc-sm6350.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8250) += qnoc-sm8250.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8350) += qnoc-sm8350.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8450) += qnoc-sm8450.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8550) += qnoc-sm8550.o
+obj-$(CONFIG_INTERCONNECT_QCOM_SM8650) += qnoc-sm8650.o
+obj-$(CONFIG_INTERCONNECT_QCOM_X1E80100) += qnoc-x1e80100.o
obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM) += icc-smd-rpm.o
diff --git a/drivers/interconnect/qcom/icc-rpm.c b/drivers/interconnect/qcom/icc-rpm.c
index dbacb2a7af50..a8ed435f696c 100644
--- a/drivers/interconnect/qcom/icc-rpm.c
+++ b/drivers/interconnect/qcom/icc-rpm.c
@@ -627,14 +627,12 @@ err_disable_unprepare_clk:
}
EXPORT_SYMBOL(qnoc_probe);
-int qnoc_remove(struct platform_device *pdev)
+void qnoc_remove(struct platform_device *pdev)
{
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
icc_provider_deregister(&qp->provider);
icc_nodes_remove(&qp->provider);
clk_disable_unprepare(qp->bus_clk);
-
- return 0;
}
EXPORT_SYMBOL(qnoc_remove);
diff --git a/drivers/interconnect/qcom/icc-rpm.h b/drivers/interconnect/qcom/icc-rpm.h
index a13768cfd231..f4883d43eae4 100644
--- a/drivers/interconnect/qcom/icc-rpm.h
+++ b/drivers/interconnect/qcom/icc-rpm.h
@@ -161,7 +161,7 @@ extern const struct rpm_clk_resource aggre1_branch_clk;
extern const struct rpm_clk_resource aggre2_branch_clk;
int qnoc_probe(struct platform_device *pdev);
-int qnoc_remove(struct platform_device *pdev);
+void qnoc_remove(struct platform_device *pdev);
bool qcom_icc_rpm_smd_available(void);
int qcom_icc_rpm_smd_send(int ctx, int rsc_type, int id, u32 val);
diff --git a/drivers/interconnect/qcom/msm8916.c b/drivers/interconnect/qcom/msm8916.c
index 35148880b3e8..499b1a9ac413 100644
--- a/drivers/interconnect/qcom/msm8916.c
+++ b/drivers/interconnect/qcom/msm8916.c
@@ -1344,7 +1344,7 @@ MODULE_DEVICE_TABLE(of, msm8916_noc_of_match);
static struct platform_driver msm8916_noc_driver = {
.probe = qnoc_probe,
- .remove = qnoc_remove,
+ .remove_new = qnoc_remove,
.driver = {
.name = "qnoc-msm8916",
.of_match_table = msm8916_noc_of_match,
diff --git a/drivers/interconnect/qcom/msm8939.c b/drivers/interconnect/qcom/msm8939.c
index b52c5ac1175c..8ff2c23b1ca0 100644
--- a/drivers/interconnect/qcom/msm8939.c
+++ b/drivers/interconnect/qcom/msm8939.c
@@ -1421,7 +1421,7 @@ MODULE_DEVICE_TABLE(of, msm8939_noc_of_match);
static struct platform_driver msm8939_noc_driver = {
.probe = qnoc_probe,
- .remove = qnoc_remove,
+ .remove_new = qnoc_remove,
.driver = {
.name = "qnoc-msm8939",
.of_match_table = msm8939_noc_of_match,
diff --git a/drivers/interconnect/qcom/msm8974.c b/drivers/interconnect/qcom/msm8974.c
index 21f6c852141e..241076b5f36b 100644
--- a/drivers/interconnect/qcom/msm8974.c
+++ b/drivers/interconnect/qcom/msm8974.c
@@ -740,15 +740,13 @@ err_remove_nodes:
return ret;
}
-static int msm8974_icc_remove(struct platform_device *pdev)
+static void msm8974_icc_remove(struct platform_device *pdev)
{
struct msm8974_icc_provider *qp = platform_get_drvdata(pdev);
icc_provider_deregister(&qp->provider);
icc_nodes_remove(&qp->provider);
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
-
- return 0;
}
static const struct of_device_id msm8974_noc_of_match[] = {
@@ -764,7 +762,7 @@ MODULE_DEVICE_TABLE(of, msm8974_noc_of_match);
static struct platform_driver msm8974_noc_driver = {
.probe = msm8974_icc_probe,
- .remove = msm8974_icc_remove,
+ .remove_new = msm8974_icc_remove,
.driver = {
.name = "qnoc-msm8974",
.of_match_table = msm8974_noc_of_match,
diff --git a/drivers/interconnect/qcom/msm8996.c b/drivers/interconnect/qcom/msm8996.c
index b73566c9b21f..788131400cd1 100644
--- a/drivers/interconnect/qcom/msm8996.c
+++ b/drivers/interconnect/qcom/msm8996.c
@@ -2108,7 +2108,7 @@ MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qnoc_probe,
- .remove = qnoc_remove,
+ .remove_new = qnoc_remove,
.driver = {
.name = "qnoc-msm8996",
.of_match_table = qnoc_of_match,
diff --git a/drivers/interconnect/qcom/osm-l3.c b/drivers/interconnect/qcom/osm-l3.c
index e97478bbc282..61a8695a9adc 100644
--- a/drivers/interconnect/qcom/osm-l3.c
+++ b/drivers/interconnect/qcom/osm-l3.c
@@ -148,14 +148,12 @@ static int qcom_osm_l3_set(struct icc_node *src, struct icc_node *dst)
return 0;
}
-static int qcom_osm_l3_remove(struct platform_device *pdev)
+static void qcom_osm_l3_remove(struct platform_device *pdev)
{
struct qcom_osm_l3_icc_provider *qp = platform_get_drvdata(pdev);
icc_provider_deregister(&qp->provider);
icc_nodes_remove(&qp->provider);
-
- return 0;
}
static int qcom_osm_l3_probe(struct platform_device *pdev)
@@ -292,7 +290,7 @@ MODULE_DEVICE_TABLE(of, osm_l3_of_match);
static struct platform_driver osm_l3_driver = {
.probe = qcom_osm_l3_probe,
- .remove = qcom_osm_l3_remove,
+ .remove_new = qcom_osm_l3_remove,
.driver = {
.name = "osm-l3",
.of_match_table = osm_l3_of_match,
diff --git a/drivers/interconnect/qcom/qcm2290.c b/drivers/interconnect/qcom/qcm2290.c
index b88cf9a022e0..96735800b13c 100644
--- a/drivers/interconnect/qcom/qcm2290.c
+++ b/drivers/interconnect/qcom/qcm2290.c
@@ -1367,7 +1367,7 @@ MODULE_DEVICE_TABLE(of, qcm2290_noc_of_match);
static struct platform_driver qcm2290_noc_driver = {
.probe = qnoc_probe,
- .remove = qnoc_remove,
+ .remove_new = qnoc_remove,
.driver = {
.name = "qnoc-qcm2290",
.of_match_table = qcm2290_noc_of_match,
diff --git a/drivers/interconnect/qcom/qcs404.c b/drivers/interconnect/qcom/qcs404.c
index 9fa1da70c843..11b49a89c03d 100644
--- a/drivers/interconnect/qcom/qcs404.c
+++ b/drivers/interconnect/qcom/qcs404.c
@@ -1083,7 +1083,7 @@ MODULE_DEVICE_TABLE(of, qcs404_noc_of_match);
static struct platform_driver qcs404_noc_driver = {
.probe = qnoc_probe,
- .remove = qnoc_remove,
+ .remove_new = qnoc_remove,
.driver = {
.name = "qnoc-qcs404",
.of_match_table = qcs404_noc_of_match,
diff --git a/drivers/interconnect/qcom/sdm660.c b/drivers/interconnect/qcom/sdm660.c
index 7392bebba334..ab91de446da8 100644
--- a/drivers/interconnect/qcom/sdm660.c
+++ b/drivers/interconnect/qcom/sdm660.c
@@ -1714,7 +1714,7 @@ MODULE_DEVICE_TABLE(of, sdm660_noc_of_match);
static struct platform_driver sdm660_noc_driver = {
.probe = qnoc_probe,
- .remove = qnoc_remove,
+ .remove_new = qnoc_remove,
.driver = {
.name = "qnoc-sdm660",
.of_match_table = sdm660_noc_of_match,
diff --git a/drivers/interconnect/qcom/sm6115.c b/drivers/interconnect/qcom/sm6115.c
new file mode 100644
index 000000000000..88b67634aa2f
--- /dev/null
+++ b/drivers/interconnect/qcom/sm6115.c
@@ -0,0 +1,1423 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <dt-bindings/interconnect/qcom,sm6115.h>
+#include <linux/device.h>
+#include <linux/interconnect-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "icc-rpm.h"
+
+static const char * const snoc_intf_clocks[] = {
+ "cpu_axi",
+ "ufs_axi",
+ "usb_axi",
+ "ipa", /* Required by qxm_ipa */
+};
+
+static const char * const cnoc_intf_clocks[] = {
+ "usb_axi",
+};
+
+enum {
+ SM6115_MASTER_AMPSS_M0,
+ SM6115_MASTER_ANOC_SNOC,
+ SM6115_MASTER_BIMC_SNOC,
+ SM6115_MASTER_CAMNOC_HF,
+ SM6115_MASTER_CAMNOC_SF,
+ SM6115_MASTER_CRYPTO_CORE0,
+ SM6115_MASTER_GRAPHICS_3D,
+ SM6115_MASTER_IPA,
+ SM6115_MASTER_MDP_PORT0,
+ SM6115_MASTER_PIMEM,
+ SM6115_MASTER_QDSS_BAM,
+ SM6115_MASTER_QDSS_DAP,
+ SM6115_MASTER_QDSS_ETR,
+ SM6115_MASTER_QPIC,
+ SM6115_MASTER_QUP_0,
+ SM6115_MASTER_QUP_CORE_0,
+ SM6115_MASTER_SDCC_1,
+ SM6115_MASTER_SDCC_2,
+ SM6115_MASTER_SNOC_BIMC_NRT,
+ SM6115_MASTER_SNOC_BIMC_RT,
+ SM6115_MASTER_SNOC_BIMC,
+ SM6115_MASTER_SNOC_CFG,
+ SM6115_MASTER_SNOC_CNOC,
+ SM6115_MASTER_TCU_0,
+ SM6115_MASTER_TIC,
+ SM6115_MASTER_USB3,
+ SM6115_MASTER_VIDEO_P0,
+ SM6115_MASTER_VIDEO_PROC,
+
+ SM6115_SLAVE_AHB2PHY_USB,
+ SM6115_SLAVE_ANOC_SNOC,
+ SM6115_SLAVE_APPSS,
+ SM6115_SLAVE_APSS_THROTTLE_CFG,
+ SM6115_SLAVE_BIMC_CFG,
+ SM6115_SLAVE_BIMC_SNOC,
+ SM6115_SLAVE_BOOT_ROM,
+ SM6115_SLAVE_CAMERA_CFG,
+ SM6115_SLAVE_CAMERA_NRT_THROTTLE_CFG,
+ SM6115_SLAVE_CAMERA_RT_THROTTLE_CFG,
+ SM6115_SLAVE_CLK_CTL,
+ SM6115_SLAVE_CNOC_MSS,
+ SM6115_SLAVE_CRYPTO_0_CFG,
+ SM6115_SLAVE_DCC_CFG,
+ SM6115_SLAVE_DDR_PHY_CFG,
+ SM6115_SLAVE_DDR_SS_CFG,
+ SM6115_SLAVE_DISPLAY_CFG,
+ SM6115_SLAVE_DISPLAY_THROTTLE_CFG,
+ SM6115_SLAVE_EBI_CH0,
+ SM6115_SLAVE_GPU_CFG,
+ SM6115_SLAVE_GPU_THROTTLE_CFG,
+ SM6115_SLAVE_HWKM_CORE,
+ SM6115_SLAVE_IMEM_CFG,
+ SM6115_SLAVE_IPA_CFG,
+ SM6115_SLAVE_LPASS,
+ SM6115_SLAVE_MAPSS,
+ SM6115_SLAVE_MDSP_MPU_CFG,
+ SM6115_SLAVE_MESSAGE_RAM,
+ SM6115_SLAVE_OCIMEM,
+ SM6115_SLAVE_PDM,
+ SM6115_SLAVE_PIMEM_CFG,
+ SM6115_SLAVE_PIMEM,
+ SM6115_SLAVE_PKA_CORE,
+ SM6115_SLAVE_PMIC_ARB,
+ SM6115_SLAVE_QDSS_CFG,
+ SM6115_SLAVE_QDSS_STM,
+ SM6115_SLAVE_QM_CFG,
+ SM6115_SLAVE_QM_MPU_CFG,
+ SM6115_SLAVE_QPIC,
+ SM6115_SLAVE_QUP_0,
+ SM6115_SLAVE_QUP_CORE_0,
+ SM6115_SLAVE_RBCPR_CX_CFG,
+ SM6115_SLAVE_RBCPR_MX_CFG,
+ SM6115_SLAVE_RPM,
+ SM6115_SLAVE_SDCC_1,
+ SM6115_SLAVE_SDCC_2,
+ SM6115_SLAVE_SECURITY,
+ SM6115_SLAVE_SERVICE_CNOC,
+ SM6115_SLAVE_SERVICE_SNOC,
+ SM6115_SLAVE_SNOC_BIMC_NRT,
+ SM6115_SLAVE_SNOC_BIMC_RT,
+ SM6115_SLAVE_SNOC_BIMC,
+ SM6115_SLAVE_SNOC_CFG,
+ SM6115_SLAVE_SNOC_CNOC,
+ SM6115_SLAVE_TCSR,
+ SM6115_SLAVE_TCU,
+ SM6115_SLAVE_TLMM,
+ SM6115_SLAVE_USB3,
+ SM6115_SLAVE_VENUS_CFG,
+ SM6115_SLAVE_VENUS_THROTTLE_CFG,
+ SM6115_SLAVE_VSENSE_CTRL_CFG,
+};
+
+static const u16 slv_ebi_slv_bimc_snoc_links[] = {
+ SM6115_SLAVE_EBI_CH0,
+ SM6115_SLAVE_BIMC_SNOC,
+};
+
+static struct qcom_icc_node apps_proc = {
+ .name = "apps_proc",
+ .id = SM6115_MASTER_AMPSS_M0,
+ .channels = 1,
+ .buswidth = 16,
+ .qos.qos_port = 0,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.prio_level = 0,
+ .qos.areq_prio = 0,
+ .mas_rpm_id = 0,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(slv_ebi_slv_bimc_snoc_links),
+ .links = slv_ebi_slv_bimc_snoc_links,
+};
+
+static const u16 link_slv_ebi[] = {
+ SM6115_SLAVE_EBI_CH0,
+};
+
+static struct qcom_icc_node mas_snoc_bimc_rt = {
+ .name = "mas_snoc_bimc_rt",
+ .id = SM6115_MASTER_SNOC_BIMC_RT,
+ .channels = 1,
+ .buswidth = 16,
+ .qos.qos_port = 2,
+ .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_ebi),
+ .links = link_slv_ebi,
+};
+
+static struct qcom_icc_node mas_snoc_bimc_nrt = {
+ .name = "mas_snoc_bimc_nrt",
+ .id = SM6115_MASTER_SNOC_BIMC_NRT,
+ .channels = 1,
+ .buswidth = 16,
+ .qos.qos_port = 3,
+ .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_ebi),
+ .links = link_slv_ebi,
+};
+
+static struct qcom_icc_node mas_snoc_bimc = {
+ .name = "mas_snoc_bimc",
+ .id = SM6115_MASTER_SNOC_BIMC,
+ .channels = 1,
+ .buswidth = 16,
+ .qos.qos_port = 6,
+ .qos.qos_mode = NOC_QOS_MODE_BYPASS,
+ .qos.areq_prio = 0,
+ .qos.prio_level = 0,
+ .mas_rpm_id = 3,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_ebi),
+ .links = link_slv_ebi,
+};
+
+static struct qcom_icc_node qnm_gpu = {
+ .name = "qnm_gpu",
+ .id = SM6115_MASTER_GRAPHICS_3D,
+ .channels = 1,
+ .buswidth = 32,
+ .qos.qos_port = 1,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.prio_level = 0,
+ .qos.areq_prio = 0,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(slv_ebi_slv_bimc_snoc_links),
+ .links = slv_ebi_slv_bimc_snoc_links,
+};
+
+static struct qcom_icc_node tcu_0 = {
+ .name = "tcu_0",
+ .id = SM6115_MASTER_TCU_0,
+ .channels = 1,
+ .buswidth = 8,
+ .qos.qos_port = 4,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.prio_level = 6,
+ .qos.areq_prio = 6,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(slv_ebi_slv_bimc_snoc_links),
+ .links = slv_ebi_slv_bimc_snoc_links,
+};
+
+static const u16 qup_core_0_links[] = {
+ SM6115_SLAVE_QUP_CORE_0,
+};
+
+static struct qcom_icc_node qup0_core_master = {
+ .name = "qup0_core_master",
+ .id = SM6115_MASTER_QUP_CORE_0,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = 170,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(qup_core_0_links),
+ .links = qup_core_0_links,
+};
+
+static const u16 link_slv_anoc_snoc[] = {
+ SM6115_SLAVE_ANOC_SNOC,
+};
+
+static struct qcom_icc_node crypto_c0 = {
+ .name = "crypto_c0",
+ .id = SM6115_MASTER_CRYPTO_CORE0,
+ .channels = 1,
+ .buswidth = 8,
+ .qos.qos_port = 43,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 2,
+ .mas_rpm_id = 23,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_anoc_snoc),
+ .links = link_slv_anoc_snoc,
+};
+
+static const u16 mas_snoc_cnoc_links[] = {
+ SM6115_SLAVE_AHB2PHY_USB,
+ SM6115_SLAVE_APSS_THROTTLE_CFG,
+ SM6115_SLAVE_BIMC_CFG,
+ SM6115_SLAVE_BOOT_ROM,
+ SM6115_SLAVE_CAMERA_CFG,
+ SM6115_SLAVE_CAMERA_NRT_THROTTLE_CFG,
+ SM6115_SLAVE_CAMERA_RT_THROTTLE_CFG,
+ SM6115_SLAVE_CLK_CTL,
+ SM6115_SLAVE_CNOC_MSS,
+ SM6115_SLAVE_CRYPTO_0_CFG,
+ SM6115_SLAVE_DCC_CFG,
+ SM6115_SLAVE_DDR_PHY_CFG,
+ SM6115_SLAVE_DDR_SS_CFG,
+ SM6115_SLAVE_DISPLAY_CFG,
+ SM6115_SLAVE_DISPLAY_THROTTLE_CFG,
+ SM6115_SLAVE_GPU_CFG,
+ SM6115_SLAVE_GPU_THROTTLE_CFG,
+ SM6115_SLAVE_HWKM_CORE,
+ SM6115_SLAVE_IMEM_CFG,
+ SM6115_SLAVE_IPA_CFG,
+ SM6115_SLAVE_LPASS,
+ SM6115_SLAVE_MAPSS,
+ SM6115_SLAVE_MDSP_MPU_CFG,
+ SM6115_SLAVE_MESSAGE_RAM,
+ SM6115_SLAVE_PDM,
+ SM6115_SLAVE_PIMEM_CFG,
+ SM6115_SLAVE_PKA_CORE,
+ SM6115_SLAVE_PMIC_ARB,
+ SM6115_SLAVE_QDSS_CFG,
+ SM6115_SLAVE_QM_CFG,
+ SM6115_SLAVE_QM_MPU_CFG,
+ SM6115_SLAVE_QPIC,
+ SM6115_SLAVE_QUP_0,
+ SM6115_SLAVE_RBCPR_CX_CFG,
+ SM6115_SLAVE_RBCPR_MX_CFG,
+ SM6115_SLAVE_RPM,
+ SM6115_SLAVE_SDCC_1,
+ SM6115_SLAVE_SDCC_2,
+ SM6115_SLAVE_SECURITY,
+ SM6115_SLAVE_SERVICE_CNOC,
+ SM6115_SLAVE_SNOC_CFG,
+ SM6115_SLAVE_TCSR,
+ SM6115_SLAVE_TLMM,
+ SM6115_SLAVE_USB3,
+ SM6115_SLAVE_VENUS_CFG,
+ SM6115_SLAVE_VENUS_THROTTLE_CFG,
+ SM6115_SLAVE_VSENSE_CTRL_CFG,
+};
+
+static struct qcom_icc_node mas_snoc_cnoc = {
+ .name = "mas_snoc_cnoc",
+ .id = SM6115_MASTER_SNOC_CNOC,
+ .channels = 1,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_snoc_cnoc_links),
+ .links = mas_snoc_cnoc_links,
+};
+
+static struct qcom_icc_node xm_dap = {
+ .name = "xm_dap",
+ .id = SM6115_MASTER_QDSS_DAP,
+ .channels = 1,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_snoc_cnoc_links),
+ .links = mas_snoc_cnoc_links,
+};
+
+static const u16 link_slv_snoc_bimc_nrt[] = {
+ SM6115_SLAVE_SNOC_BIMC_NRT,
+};
+
+static struct qcom_icc_node qnm_camera_nrt = {
+ .name = "qnm_camera_nrt",
+ .id = SM6115_MASTER_CAMNOC_SF,
+ .channels = 1,
+ .buswidth = 32,
+ .qos.qos_port = 25,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 3,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_snoc_bimc_nrt),
+ .links = link_slv_snoc_bimc_nrt,
+};
+
+static struct qcom_icc_node qxm_venus0 = {
+ .name = "qxm_venus0",
+ .id = SM6115_MASTER_VIDEO_P0,
+ .channels = 1,
+ .buswidth = 16,
+ .qos.qos_port = 30,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 3,
+ .qos.urg_fwd_en = true,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_snoc_bimc_nrt),
+ .links = link_slv_snoc_bimc_nrt,
+};
+
+static struct qcom_icc_node qxm_venus_cpu = {
+ .name = "qxm_venus_cpu",
+ .id = SM6115_MASTER_VIDEO_PROC,
+ .channels = 1,
+ .buswidth = 8,
+ .qos.qos_port = 34,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_snoc_bimc_nrt),
+ .links = link_slv_snoc_bimc_nrt,
+};
+
+static const u16 link_slv_snoc_bimc_rt[] = {
+ SM6115_SLAVE_SNOC_BIMC_RT,
+};
+
+static struct qcom_icc_node qnm_camera_rt = {
+ .name = "qnm_camera_rt",
+ .id = SM6115_MASTER_CAMNOC_HF,
+ .channels = 1,
+ .buswidth = 32,
+ .qos.qos_port = 31,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 3,
+ .qos.urg_fwd_en = true,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_snoc_bimc_rt),
+ .links = link_slv_snoc_bimc_rt,
+};
+
+static struct qcom_icc_node qxm_mdp0 = {
+ .name = "qxm_mdp0",
+ .id = SM6115_MASTER_MDP_PORT0,
+ .channels = 1,
+ .buswidth = 16,
+ .qos.qos_port = 26,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 3,
+ .qos.urg_fwd_en = true,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_snoc_bimc_rt),
+ .links = link_slv_snoc_bimc_rt,
+};
+
+static const u16 slv_service_snoc_links[] = {
+ SM6115_SLAVE_SERVICE_SNOC,
+};
+
+static struct qcom_icc_node qhm_snoc_cfg = {
+ .name = "qhm_snoc_cfg",
+ .id = SM6115_MASTER_SNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(slv_service_snoc_links),
+ .links = slv_service_snoc_links,
+};
+
+static const u16 mas_tic_links[] = {
+ SM6115_SLAVE_APPSS,
+ SM6115_SLAVE_OCIMEM,
+ SM6115_SLAVE_PIMEM,
+ SM6115_SLAVE_QDSS_STM,
+ SM6115_SLAVE_TCU,
+ SM6115_SLAVE_SNOC_BIMC,
+ SM6115_SLAVE_SNOC_CNOC,
+};
+
+static struct qcom_icc_node qhm_tic = {
+ .name = "qhm_tic",
+ .id = SM6115_MASTER_TIC,
+ .channels = 1,
+ .buswidth = 4,
+ .qos.qos_port = 29,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 2,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_tic_links),
+ .links = mas_tic_links,
+};
+
+static struct qcom_icc_node mas_anoc_snoc = {
+ .name = "mas_anoc_snoc",
+ .id = SM6115_MASTER_ANOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_tic_links),
+ .links = mas_tic_links,
+};
+
+static const u16 mas_bimc_snoc_links[] = {
+ SM6115_SLAVE_APPSS,
+ SM6115_SLAVE_SNOC_CNOC,
+ SM6115_SLAVE_OCIMEM,
+ SM6115_SLAVE_PIMEM,
+ SM6115_SLAVE_QDSS_STM,
+ SM6115_SLAVE_TCU,
+};
+
+static struct qcom_icc_node mas_bimc_snoc = {
+ .name = "mas_bimc_snoc",
+ .id = SM6115_MASTER_BIMC_SNOC,
+ .channels = 1,
+ .buswidth = 8,
+ .mas_rpm_id = 21,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_bimc_snoc_links),
+ .links = mas_bimc_snoc_links,
+};
+
+static const u16 mas_pimem_links[] = {
+ SM6115_SLAVE_OCIMEM,
+ SM6115_SLAVE_SNOC_BIMC,
+};
+
+static struct qcom_icc_node qxm_pimem = {
+ .name = "qxm_pimem",
+ .id = SM6115_MASTER_PIMEM,
+ .channels = 1,
+ .buswidth = 8,
+ .qos.qos_port = 41,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 2,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(mas_pimem_links),
+ .links = mas_pimem_links,
+};
+
+static struct qcom_icc_node qhm_qdss_bam = {
+ .name = "qhm_qdss_bam",
+ .id = SM6115_MASTER_QDSS_BAM,
+ .channels = 1,
+ .buswidth = 4,
+ .qos.qos_port = 23,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 2,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_anoc_snoc),
+ .links = link_slv_anoc_snoc,
+};
+
+static struct qcom_icc_node qhm_qpic = {
+ .name = "qhm_qpic",
+ .id = SM6115_MASTER_QPIC,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_anoc_snoc),
+ .links = link_slv_anoc_snoc,
+};
+
+static struct qcom_icc_node qhm_qup0 = {
+ .name = "qhm_qup0",
+ .id = SM6115_MASTER_QUP_0,
+ .channels = 1,
+ .buswidth = 4,
+ .qos.qos_port = 21,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 2,
+ .mas_rpm_id = 166,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_anoc_snoc),
+ .links = link_slv_anoc_snoc,
+};
+
+static struct qcom_icc_node qxm_ipa = {
+ .name = "qxm_ipa",
+ .id = SM6115_MASTER_IPA,
+ .channels = 1,
+ .buswidth = 8,
+ .qos.qos_port = 24,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 2,
+ .mas_rpm_id = 59,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_anoc_snoc),
+ .links = link_slv_anoc_snoc,
+};
+
+static struct qcom_icc_node xm_qdss_etr = {
+ .name = "xm_qdss_etr",
+ .id = SM6115_MASTER_QDSS_ETR,
+ .channels = 1,
+ .buswidth = 8,
+ .qos.qos_port = 33,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 2,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_anoc_snoc),
+ .links = link_slv_anoc_snoc,
+};
+
+static struct qcom_icc_node xm_sdc1 = {
+ .name = "xm_sdc1",
+ .id = SM6115_MASTER_SDCC_1,
+ .channels = 1,
+ .buswidth = 8,
+ .qos.qos_port = 38,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 2,
+ .mas_rpm_id = 33,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_anoc_snoc),
+ .links = link_slv_anoc_snoc,
+};
+
+static struct qcom_icc_node xm_sdc2 = {
+ .name = "xm_sdc2",
+ .id = SM6115_MASTER_SDCC_2,
+ .channels = 1,
+ .buswidth = 8,
+ .qos.qos_port = 44,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 2,
+ .mas_rpm_id = 35,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_anoc_snoc),
+ .links = link_slv_anoc_snoc,
+};
+
+static struct qcom_icc_node xm_usb3_0 = {
+ .name = "xm_usb3_0",
+ .id = SM6115_MASTER_USB3,
+ .channels = 1,
+ .buswidth = 8,
+ .qos.qos_port = 45,
+ .qos.qos_mode = NOC_QOS_MODE_FIXED,
+ .qos.areq_prio = 2,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(link_slv_anoc_snoc),
+ .links = link_slv_anoc_snoc,
+};
+
+static struct qcom_icc_node ebi = {
+ .name = "ebi",
+ .id = SM6115_SLAVE_EBI_CH0,
+ .channels = 2,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 0,
+};
+
+static const u16 slv_bimc_snoc_links[] = {
+ SM6115_MASTER_BIMC_SNOC,
+};
+
+static struct qcom_icc_node slv_bimc_snoc = {
+ .name = "slv_bimc_snoc",
+ .id = SM6115_SLAVE_BIMC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 2,
+ .num_links = ARRAY_SIZE(slv_bimc_snoc_links),
+ .links = slv_bimc_snoc_links,
+};
+
+static struct qcom_icc_node qup0_core_slave = {
+ .name = "qup0_core_slave",
+ .id = SM6115_SLAVE_QUP_CORE_0,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_ahb2phy_usb = {
+ .name = "qhs_ahb2phy_usb",
+ .id = SM6115_SLAVE_AHB2PHY_USB,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_apss_throttle_cfg = {
+ .name = "qhs_apss_throttle_cfg",
+ .id = SM6115_SLAVE_APSS_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_bimc_cfg = {
+ .name = "qhs_bimc_cfg",
+ .id = SM6115_SLAVE_BIMC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_boot_rom = {
+ .name = "qhs_boot_rom",
+ .id = SM6115_SLAVE_BOOT_ROM,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_camera_nrt_throttle_cfg = {
+ .name = "qhs_camera_nrt_throttle_cfg",
+ .id = SM6115_SLAVE_CAMERA_NRT_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_camera_rt_throttle_cfg = {
+ .name = "qhs_camera_rt_throttle_cfg",
+ .id = SM6115_SLAVE_CAMERA_RT_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_camera_ss_cfg = {
+ .name = "qhs_camera_ss_cfg",
+ .id = SM6115_SLAVE_CAMERA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_clk_ctl = {
+ .name = "qhs_clk_ctl",
+ .id = SM6115_SLAVE_CLK_CTL,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_cpr_cx = {
+ .name = "qhs_cpr_cx",
+ .id = SM6115_SLAVE_RBCPR_CX_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_cpr_mx = {
+ .name = "qhs_cpr_mx",
+ .id = SM6115_SLAVE_RBCPR_MX_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_crypto0_cfg = {
+ .name = "qhs_crypto0_cfg",
+ .id = SM6115_SLAVE_CRYPTO_0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_dcc_cfg = {
+ .name = "qhs_dcc_cfg",
+ .id = SM6115_SLAVE_DCC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_ddr_phy_cfg = {
+ .name = "qhs_ddr_phy_cfg",
+ .id = SM6115_SLAVE_DDR_PHY_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_ddr_ss_cfg = {
+ .name = "qhs_ddr_ss_cfg",
+ .id = SM6115_SLAVE_DDR_SS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_disp_ss_cfg = {
+ .name = "qhs_disp_ss_cfg",
+ .id = SM6115_SLAVE_DISPLAY_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_display_throttle_cfg = {
+ .name = "qhs_display_throttle_cfg",
+ .id = SM6115_SLAVE_DISPLAY_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_gpu_cfg = {
+ .name = "qhs_gpu_cfg",
+ .id = SM6115_SLAVE_GPU_CFG,
+ .channels = 1,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_gpu_throttle_cfg = {
+ .name = "qhs_gpu_throttle_cfg",
+ .id = SM6115_SLAVE_GPU_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_hwkm = {
+ .name = "qhs_hwkm",
+ .id = SM6115_SLAVE_HWKM_CORE,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_imem_cfg = {
+ .name = "qhs_imem_cfg",
+ .id = SM6115_SLAVE_IMEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_ipa_cfg = {
+ .name = "qhs_ipa_cfg",
+ .id = SM6115_SLAVE_IPA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_lpass = {
+ .name = "qhs_lpass",
+ .id = SM6115_SLAVE_LPASS,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_mapss = {
+ .name = "qhs_mapss",
+ .id = SM6115_SLAVE_MAPSS,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_mdsp_mpu_cfg = {
+ .name = "qhs_mdsp_mpu_cfg",
+ .id = SM6115_SLAVE_MDSP_MPU_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_mesg_ram = {
+ .name = "qhs_mesg_ram",
+ .id = SM6115_SLAVE_MESSAGE_RAM,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_mss = {
+ .name = "qhs_mss",
+ .id = SM6115_SLAVE_CNOC_MSS,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_pdm = {
+ .name = "qhs_pdm",
+ .id = SM6115_SLAVE_PDM,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_pimem_cfg = {
+ .name = "qhs_pimem_cfg",
+ .id = SM6115_SLAVE_PIMEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_pka_wrapper = {
+ .name = "qhs_pka_wrapper",
+ .id = SM6115_SLAVE_PKA_CORE,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_pmic_arb = {
+ .name = "qhs_pmic_arb",
+ .id = SM6115_SLAVE_PMIC_ARB,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_qdss_cfg = {
+ .name = "qhs_qdss_cfg",
+ .id = SM6115_SLAVE_QDSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_qm_cfg = {
+ .name = "qhs_qm_cfg",
+ .id = SM6115_SLAVE_QM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_qm_mpu_cfg = {
+ .name = "qhs_qm_mpu_cfg",
+ .id = SM6115_SLAVE_QM_MPU_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_qpic = {
+ .name = "qhs_qpic",
+ .id = SM6115_SLAVE_QPIC,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_qup0 = {
+ .name = "qhs_qup0",
+ .id = SM6115_SLAVE_QUP_0,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_rpm = {
+ .name = "qhs_rpm",
+ .id = SM6115_SLAVE_RPM,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_sdc1 = {
+ .name = "qhs_sdc1",
+ .id = SM6115_SLAVE_SDCC_1,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_sdc2 = {
+ .name = "qhs_sdc2",
+ .id = SM6115_SLAVE_SDCC_2,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_security = {
+ .name = "qhs_security",
+ .id = SM6115_SLAVE_SECURITY,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static const u16 slv_snoc_cfg_links[] = {
+ SM6115_MASTER_SNOC_CFG,
+};
+
+static struct qcom_icc_node qhs_snoc_cfg = {
+ .name = "qhs_snoc_cfg",
+ .id = SM6115_SLAVE_SNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(slv_snoc_cfg_links),
+ .links = slv_snoc_cfg_links,
+};
+
+static struct qcom_icc_node qhs_tcsr = {
+ .name = "qhs_tcsr",
+ .id = SM6115_SLAVE_TCSR,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_tlmm = {
+ .name = "qhs_tlmm",
+ .id = SM6115_SLAVE_TLMM,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_usb3 = {
+ .name = "qhs_usb3",
+ .id = SM6115_SLAVE_USB3,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_venus_cfg = {
+ .name = "qhs_venus_cfg",
+ .id = SM6115_SLAVE_VENUS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_venus_throttle_cfg = {
+ .name = "qhs_venus_throttle_cfg",
+ .id = SM6115_SLAVE_VENUS_THROTTLE_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node qhs_vsense_ctrl_cfg = {
+ .name = "qhs_vsense_ctrl_cfg",
+ .id = SM6115_SLAVE_VSENSE_CTRL_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node srvc_cnoc = {
+ .name = "srvc_cnoc",
+ .id = SM6115_SLAVE_SERVICE_CNOC,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static const u16 slv_snoc_bimc_nrt_links[] = {
+ SM6115_MASTER_SNOC_BIMC_NRT,
+};
+
+static struct qcom_icc_node slv_snoc_bimc_nrt = {
+ .name = "slv_snoc_bimc_nrt",
+ .id = SM6115_SLAVE_SNOC_BIMC_NRT,
+ .channels = 1,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(slv_snoc_bimc_nrt_links),
+ .links = slv_snoc_bimc_nrt_links,
+};
+
+static const u16 slv_snoc_bimc_rt_links[] = {
+ SM6115_MASTER_SNOC_BIMC_RT,
+};
+
+static struct qcom_icc_node slv_snoc_bimc_rt = {
+ .name = "slv_snoc_bimc_rt",
+ .id = SM6115_SLAVE_SNOC_BIMC_RT,
+ .channels = 1,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(slv_snoc_bimc_rt_links),
+ .links = slv_snoc_bimc_rt_links,
+};
+
+static struct qcom_icc_node qhs_apss = {
+ .name = "qhs_apss",
+ .id = SM6115_SLAVE_APPSS,
+ .channels = 1,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static const u16 slv_snoc_cnoc_links[] = {
+ SM6115_MASTER_SNOC_CNOC
+};
+
+static struct qcom_icc_node slv_snoc_cnoc = {
+ .name = "slv_snoc_cnoc",
+ .id = SM6115_SLAVE_SNOC_CNOC,
+ .channels = 1,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 25,
+ .num_links = ARRAY_SIZE(slv_snoc_cnoc_links),
+ .links = slv_snoc_cnoc_links,
+};
+
+static struct qcom_icc_node qxs_imem = {
+ .name = "qxs_imem",
+ .id = SM6115_SLAVE_OCIMEM,
+ .channels = 1,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 26,
+};
+
+static struct qcom_icc_node qxs_pimem = {
+ .name = "qxs_pimem",
+ .id = SM6115_SLAVE_PIMEM,
+ .channels = 1,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static const u16 slv_snoc_bimc_links[] = {
+ SM6115_MASTER_SNOC_BIMC,
+};
+
+static struct qcom_icc_node slv_snoc_bimc = {
+ .name = "slv_snoc_bimc",
+ .id = SM6115_SLAVE_SNOC_BIMC,
+ .channels = 1,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 24,
+ .num_links = ARRAY_SIZE(slv_snoc_bimc_links),
+ .links = slv_snoc_bimc_links,
+};
+
+static struct qcom_icc_node srvc_snoc = {
+ .name = "srvc_snoc",
+ .id = SM6115_SLAVE_SERVICE_SNOC,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static struct qcom_icc_node xs_qdss_stm = {
+ .name = "xs_qdss_stm",
+ .id = SM6115_SLAVE_QDSS_STM,
+ .channels = 1,
+ .buswidth = 4,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = 30,
+};
+
+static struct qcom_icc_node xs_sys_tcu_cfg = {
+ .name = "xs_sys_tcu_cfg",
+ .id = SM6115_SLAVE_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+};
+
+static const u16 slv_anoc_snoc_links[] = {
+ SM6115_MASTER_ANOC_SNOC,
+};
+
+static struct qcom_icc_node slv_anoc_snoc = {
+ .name = "slv_anoc_snoc",
+ .id = SM6115_SLAVE_ANOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .mas_rpm_id = -1,
+ .slv_rpm_id = -1,
+ .num_links = ARRAY_SIZE(slv_anoc_snoc_links),
+ .links = slv_anoc_snoc_links,
+};
+
+static struct qcom_icc_node *bimc_nodes[] = {
+ [MASTER_AMPSS_M0] = &apps_proc,
+ [MASTER_SNOC_BIMC_RT] = &mas_snoc_bimc_rt,
+ [MASTER_SNOC_BIMC_NRT] = &mas_snoc_bimc_nrt,
+ [SNOC_BIMC_MAS] = &mas_snoc_bimc,
+ [MASTER_GRAPHICS_3D] = &qnm_gpu,
+ [MASTER_TCU_0] = &tcu_0,
+ [SLAVE_EBI_CH0] = &ebi,
+ [BIMC_SNOC_SLV] = &slv_bimc_snoc,
+};
+
+static const struct regmap_config bimc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x80000,
+ .fast_io = true,
+};
+
+static const struct qcom_icc_desc sm6115_bimc = {
+ .type = QCOM_ICC_BIMC,
+ .nodes = bimc_nodes,
+ .num_nodes = ARRAY_SIZE(bimc_nodes),
+ .regmap_cfg = &bimc_regmap_config,
+ .bus_clk_desc = &bimc_clk,
+ .keep_alive = true,
+ .qos_offset = 0x8000,
+ .ab_coeff = 153,
+};
+
+static struct qcom_icc_node *config_noc_nodes[] = {
+ [SNOC_CNOC_MAS] = &mas_snoc_cnoc,
+ [MASTER_QDSS_DAP] = &xm_dap,
+ [SLAVE_AHB2PHY_USB] = &qhs_ahb2phy_usb,
+ [SLAVE_APSS_THROTTLE_CFG] = &qhs_apss_throttle_cfg,
+ [SLAVE_BIMC_CFG] = &qhs_bimc_cfg,
+ [SLAVE_BOOT_ROM] = &qhs_boot_rom,
+ [SLAVE_CAMERA_NRT_THROTTLE_CFG] = &qhs_camera_nrt_throttle_cfg,
+ [SLAVE_CAMERA_RT_THROTTLE_CFG] = &qhs_camera_rt_throttle_cfg,
+ [SLAVE_CAMERA_CFG] = &qhs_camera_ss_cfg,
+ [SLAVE_CLK_CTL] = &qhs_clk_ctl,
+ [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx,
+ [SLAVE_RBCPR_MX_CFG] = &qhs_cpr_mx,
+ [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg,
+ [SLAVE_DCC_CFG] = &qhs_dcc_cfg,
+ [SLAVE_DDR_PHY_CFG] = &qhs_ddr_phy_cfg,
+ [SLAVE_DDR_SS_CFG] = &qhs_ddr_ss_cfg,
+ [SLAVE_DISPLAY_CFG] = &qhs_disp_ss_cfg,
+ [SLAVE_DISPLAY_THROTTLE_CFG] = &qhs_display_throttle_cfg,
+ [SLAVE_GPU_CFG] = &qhs_gpu_cfg,
+ [SLAVE_GPU_THROTTLE_CFG] = &qhs_gpu_throttle_cfg,
+ [SLAVE_HWKM_CORE] = &qhs_hwkm,
+ [SLAVE_IMEM_CFG] = &qhs_imem_cfg,
+ [SLAVE_IPA_CFG] = &qhs_ipa_cfg,
+ [SLAVE_LPASS] = &qhs_lpass,
+ [SLAVE_MAPSS] = &qhs_mapss,
+ [SLAVE_MDSP_MPU_CFG] = &qhs_mdsp_mpu_cfg,
+ [SLAVE_MESSAGE_RAM] = &qhs_mesg_ram,
+ [SLAVE_CNOC_MSS] = &qhs_mss,
+ [SLAVE_PDM] = &qhs_pdm,
+ [SLAVE_PIMEM_CFG] = &qhs_pimem_cfg,
+ [SLAVE_PKA_CORE] = &qhs_pka_wrapper,
+ [SLAVE_PMIC_ARB] = &qhs_pmic_arb,
+ [SLAVE_QDSS_CFG] = &qhs_qdss_cfg,
+ [SLAVE_QM_CFG] = &qhs_qm_cfg,
+ [SLAVE_QM_MPU_CFG] = &qhs_qm_mpu_cfg,
+ [SLAVE_QPIC] = &qhs_qpic,
+ [SLAVE_QUP_0] = &qhs_qup0,
+ [SLAVE_RPM] = &qhs_rpm,
+ [SLAVE_SDCC_1] = &qhs_sdc1,
+ [SLAVE_SDCC_2] = &qhs_sdc2,
+ [SLAVE_SECURITY] = &qhs_security,
+ [SLAVE_SNOC_CFG] = &qhs_snoc_cfg,
+ [SLAVE_TCSR] = &qhs_tcsr,
+ [SLAVE_TLMM] = &qhs_tlmm,
+ [SLAVE_USB3] = &qhs_usb3,
+ [SLAVE_VENUS_CFG] = &qhs_venus_cfg,
+ [SLAVE_VENUS_THROTTLE_CFG] = &qhs_venus_throttle_cfg,
+ [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg,
+ [SLAVE_SERVICE_CNOC] = &srvc_cnoc,
+};
+
+static const struct regmap_config cnoc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x6200,
+ .fast_io = true,
+};
+
+static const struct qcom_icc_desc sm6115_config_noc = {
+ .type = QCOM_ICC_QNOC,
+ .nodes = config_noc_nodes,
+ .num_nodes = ARRAY_SIZE(config_noc_nodes),
+ .regmap_cfg = &cnoc_regmap_config,
+ .intf_clocks = cnoc_intf_clocks,
+ .num_intf_clocks = ARRAY_SIZE(cnoc_intf_clocks),
+ .bus_clk_desc = &bus_1_clk,
+ .keep_alive = true,
+};
+
+static struct qcom_icc_node *sys_noc_nodes[] = {
+ [MASTER_CRYPTO_CORE0] = &crypto_c0,
+ [MASTER_SNOC_CFG] = &qhm_snoc_cfg,
+ [MASTER_TIC] = &qhm_tic,
+ [MASTER_ANOC_SNOC] = &mas_anoc_snoc,
+ [BIMC_SNOC_MAS] = &mas_bimc_snoc,
+ [MASTER_PIMEM] = &qxm_pimem,
+ [MASTER_QDSS_BAM] = &qhm_qdss_bam,
+ [MASTER_QPIC] = &qhm_qpic,
+ [MASTER_QUP_0] = &qhm_qup0,
+ [MASTER_IPA] = &qxm_ipa,
+ [MASTER_QDSS_ETR] = &xm_qdss_etr,
+ [MASTER_SDCC_1] = &xm_sdc1,
+ [MASTER_SDCC_2] = &xm_sdc2,
+ [MASTER_USB3] = &xm_usb3_0,
+ [SLAVE_APPSS] = &qhs_apss,
+ [SNOC_CNOC_SLV] = &slv_snoc_cnoc,
+ [SLAVE_OCIMEM] = &qxs_imem,
+ [SLAVE_PIMEM] = &qxs_pimem,
+ [SNOC_BIMC_SLV] = &slv_snoc_bimc,
+ [SLAVE_SERVICE_SNOC] = &srvc_snoc,
+ [SLAVE_QDSS_STM] = &xs_qdss_stm,
+ [SLAVE_TCU] = &xs_sys_tcu_cfg,
+ [SLAVE_ANOC_SNOC] = &slv_anoc_snoc,
+};
+
+static const struct regmap_config sys_noc_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x5f080,
+ .fast_io = true,
+};
+
+static const struct qcom_icc_desc sm6115_sys_noc = {
+ .type = QCOM_ICC_QNOC,
+ .nodes = sys_noc_nodes,
+ .num_nodes = ARRAY_SIZE(sys_noc_nodes),
+ .regmap_cfg = &sys_noc_regmap_config,
+ .intf_clocks = snoc_intf_clocks,
+ .num_intf_clocks = ARRAY_SIZE(snoc_intf_clocks),
+ .bus_clk_desc = &bus_2_clk,
+ .keep_alive = true,
+};
+
+static struct qcom_icc_node *clk_virt_nodes[] = {
+ [MASTER_QUP_CORE_0] = &qup0_core_master,
+ [SLAVE_QUP_CORE_0] = &qup0_core_slave,
+};
+
+static const struct qcom_icc_desc sm6115_clk_virt = {
+ .type = QCOM_ICC_QNOC,
+ .nodes = clk_virt_nodes,
+ .num_nodes = ARRAY_SIZE(clk_virt_nodes),
+ .regmap_cfg = &sys_noc_regmap_config,
+ .bus_clk_desc = &qup_clk,
+ .keep_alive = true,
+};
+
+static struct qcom_icc_node *mmnrt_virt_nodes[] = {
+ [MASTER_CAMNOC_SF] = &qnm_camera_nrt,
+ [MASTER_VIDEO_P0] = &qxm_venus0,
+ [MASTER_VIDEO_PROC] = &qxm_venus_cpu,
+ [SLAVE_SNOC_BIMC_NRT] = &slv_snoc_bimc_nrt,
+};
+
+static const struct qcom_icc_desc sm6115_mmnrt_virt = {
+ .type = QCOM_ICC_QNOC,
+ .nodes = mmnrt_virt_nodes,
+ .num_nodes = ARRAY_SIZE(mmnrt_virt_nodes),
+ .regmap_cfg = &sys_noc_regmap_config,
+ .bus_clk_desc = &mmaxi_0_clk,
+ .keep_alive = true,
+ .ab_coeff = 142,
+};
+
+static struct qcom_icc_node *mmrt_virt_nodes[] = {
+ [MASTER_CAMNOC_HF] = &qnm_camera_rt,
+ [MASTER_MDP_PORT0] = &qxm_mdp0,
+ [SLAVE_SNOC_BIMC_RT] = &slv_snoc_bimc_rt,
+};
+
+static const struct qcom_icc_desc sm6115_mmrt_virt = {
+ .type = QCOM_ICC_QNOC,
+ .nodes = mmrt_virt_nodes,
+ .num_nodes = ARRAY_SIZE(mmrt_virt_nodes),
+ .regmap_cfg = &sys_noc_regmap_config,
+ .bus_clk_desc = &mmaxi_1_clk,
+ .keep_alive = true,
+ .ab_coeff = 139,
+};
+
+static const struct of_device_id qnoc_of_match[] = {
+ { .compatible = "qcom,sm6115-bimc", .data = &sm6115_bimc },
+ { .compatible = "qcom,sm6115-clk-virt", .data = &sm6115_clk_virt },
+ { .compatible = "qcom,sm6115-cnoc", .data = &sm6115_config_noc },
+ { .compatible = "qcom,sm6115-mmrt-virt", .data = &sm6115_mmrt_virt },
+ { .compatible = "qcom,sm6115-mmnrt-virt", .data = &sm6115_mmnrt_virt },
+ { .compatible = "qcom,sm6115-snoc", .data = &sm6115_sys_noc },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+ .probe = qnoc_probe,
+ .remove_new = qnoc_remove,
+ .driver = {
+ .name = "qnoc-sm6115",
+ .of_match_table = qnoc_of_match,
+ .sync_state = icc_sync_state,
+ },
+};
+
+static int __init qnoc_driver_init(void)
+{
+ return platform_driver_register(&qnoc_driver);
+}
+core_initcall(qnoc_driver_init);
+
+static void __exit qnoc_driver_exit(void)
+{
+ platform_driver_unregister(&qnoc_driver);
+}
+module_exit(qnoc_driver_exit);
+
+MODULE_DESCRIPTION("SM6115 NoC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/interconnect/qcom/sm8650.c b/drivers/interconnect/qcom/sm8650.c
new file mode 100644
index 000000000000..b83de54577b6
--- /dev/null
+++ b/drivers/interconnect/qcom/sm8650.c
@@ -0,0 +1,1674 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/device.h>
+#include <linux/interconnect.h>
+#include <linux/interconnect-provider.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <dt-bindings/interconnect/qcom,sm8650-rpmh.h>
+
+#include "bcm-voter.h"
+#include "icc-common.h"
+#include "icc-rpmh.h"
+#include "sm8650.h"
+
+static struct qcom_icc_node qhm_qspi = {
+ .name = "qhm_qspi",
+ .id = SM8650_MASTER_QSPI_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qup1 = {
+ .name = "qhm_qup1",
+ .id = SM8650_MASTER_QUP_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qxm_qup02 = {
+ .name = "qxm_qup02",
+ .id = SM8650_MASTER_QUP_3,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_sdc4 = {
+ .name = "xm_sdc4",
+ .id = SM8650_MASTER_SDCC_4,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_ufs_mem = {
+ .name = "xm_ufs_mem",
+ .id = SM8650_MASTER_UFS_MEM,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_usb3_0 = {
+ .name = "xm_usb3_0",
+ .id = SM8650_MASTER_USB3_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qdss_bam = {
+ .name = "qhm_qdss_bam",
+ .id = SM8650_MASTER_QDSS_BAM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qup2 = {
+ .name = "qhm_qup2",
+ .id = SM8650_MASTER_QUP_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qxm_crypto = {
+ .name = "qxm_crypto",
+ .id = SM8650_MASTER_CRYPTO,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qxm_ipa = {
+ .name = "qxm_ipa",
+ .id = SM8650_MASTER_IPA,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qxm_sp = {
+ .name = "qxm_sp",
+ .id = SM8650_MASTER_SP,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_qdss_etr_0 = {
+ .name = "xm_qdss_etr_0",
+ .id = SM8650_MASTER_QDSS_ETR,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_qdss_etr_1 = {
+ .name = "xm_qdss_etr_1",
+ .id = SM8650_MASTER_QDSS_ETR_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_sdc2 = {
+ .name = "xm_sdc2",
+ .id = SM8650_MASTER_SDCC_2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qup0_core_master = {
+ .name = "qup0_core_master",
+ .id = SM8650_MASTER_QUP_CORE_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_QUP_CORE_0 },
+};
+
+static struct qcom_icc_node qup1_core_master = {
+ .name = "qup1_core_master",
+ .id = SM8650_MASTER_QUP_CORE_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_QUP_CORE_1 },
+};
+
+static struct qcom_icc_node qup2_core_master = {
+ .name = "qup2_core_master",
+ .id = SM8650_MASTER_QUP_CORE_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_QUP_CORE_2 },
+};
+
+static struct qcom_icc_node qsm_cfg = {
+ .name = "qsm_cfg",
+ .id = SM8650_MASTER_CNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 46,
+ .links = { SM8650_SLAVE_AHB2PHY_SOUTH, SM8650_SLAVE_AHB2PHY_NORTH,
+ SM8650_SLAVE_CAMERA_CFG, SM8650_SLAVE_CLK_CTL,
+ SM8650_SLAVE_RBCPR_CX_CFG, SM8650_SLAVE_CPR_HMX,
+ SM8650_SLAVE_RBCPR_MMCX_CFG, SM8650_SLAVE_RBCPR_MXA_CFG,
+ SM8650_SLAVE_RBCPR_MXC_CFG, SM8650_SLAVE_CPR_NSPCX,
+ SM8650_SLAVE_CRYPTO_0_CFG, SM8650_SLAVE_CX_RDPM,
+ SM8650_SLAVE_DISPLAY_CFG, SM8650_SLAVE_GFX3D_CFG,
+ SM8650_SLAVE_I2C, SM8650_SLAVE_I3C_IBI0_CFG,
+ SM8650_SLAVE_I3C_IBI1_CFG, SM8650_SLAVE_IMEM_CFG,
+ SM8650_SLAVE_CNOC_MSS, SM8650_SLAVE_MX_2_RDPM,
+ SM8650_SLAVE_MX_RDPM, SM8650_SLAVE_PCIE_0_CFG,
+ SM8650_SLAVE_PCIE_1_CFG, SM8650_SLAVE_PCIE_RSCC,
+ SM8650_SLAVE_PDM, SM8650_SLAVE_PRNG,
+ SM8650_SLAVE_QDSS_CFG, SM8650_SLAVE_QSPI_0,
+ SM8650_SLAVE_QUP_3, SM8650_SLAVE_QUP_1,
+ SM8650_SLAVE_QUP_2, SM8650_SLAVE_SDCC_2,
+ SM8650_SLAVE_SDCC_4, SM8650_SLAVE_SPSS_CFG,
+ SM8650_SLAVE_TCSR, SM8650_SLAVE_TLMM,
+ SM8650_SLAVE_UFS_MEM_CFG, SM8650_SLAVE_USB3_0,
+ SM8650_SLAVE_VENUS_CFG, SM8650_SLAVE_VSENSE_CTRL_CFG,
+ SM8650_SLAVE_CNOC_MNOC_CFG, SM8650_SLAVE_NSP_QTB_CFG,
+ SM8650_SLAVE_PCIE_ANOC_CFG, SM8650_SLAVE_SERVICE_CNOC_CFG,
+ SM8650_SLAVE_QDSS_STM, SM8650_SLAVE_TCU },
+};
+
+static struct qcom_icc_node qnm_gemnoc_cnoc = {
+ .name = "qnm_gemnoc_cnoc",
+ .id = SM8650_MASTER_GEM_NOC_CNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 9,
+ .links = { SM8650_SLAVE_AOSS, SM8650_SLAVE_IPA_CFG,
+ SM8650_SLAVE_IPC_ROUTER_CFG, SM8650_SLAVE_TME_CFG,
+ SM8650_SLAVE_APPSS, SM8650_SLAVE_CNOC_CFG,
+ SM8650_SLAVE_DDRSS_CFG, SM8650_SLAVE_IMEM,
+ SM8650_SLAVE_SERVICE_CNOC },
+};
+
+static struct qcom_icc_node qnm_gemnoc_pcie = {
+ .name = "qnm_gemnoc_pcie",
+ .id = SM8650_MASTER_GEM_NOC_PCIE_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 2,
+ .links = { SM8650_SLAVE_PCIE_0, SM8650_SLAVE_PCIE_1 },
+};
+
+static struct qcom_icc_node alm_gpu_tcu = {
+ .name = "alm_gpu_tcu",
+ .id = SM8650_MASTER_GPU_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node alm_sys_tcu = {
+ .name = "alm_sys_tcu",
+ .id = SM8650_MASTER_SYS_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node alm_ubwc_p_tcu = {
+ .name = "alm_ubwc_p_tcu",
+ .id = SM8650_MASTER_UBWC_P_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node chm_apps = {
+ .name = "chm_apps",
+ .id = SM8650_MASTER_APPSS_PROC,
+ .channels = 3,
+ .buswidth = 32,
+ .num_links = 3,
+ .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC,
+ SM8650_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qnm_gpu = {
+ .name = "qnm_gpu",
+ .id = SM8650_MASTER_GFX3D,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_lpass_gemnoc = {
+ .name = "qnm_lpass_gemnoc",
+ .id = SM8650_MASTER_LPASS_GEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 3,
+ .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC,
+ SM8650_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qnm_mdsp = {
+ .name = "qnm_mdsp",
+ .id = SM8650_MASTER_MSS_PROC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 3,
+ .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC,
+ SM8650_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qnm_mnoc_hf = {
+ .name = "qnm_mnoc_hf",
+ .id = SM8650_MASTER_MNOC_HF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_mnoc_sf = {
+ .name = "qnm_mnoc_sf",
+ .id = SM8650_MASTER_MNOC_SF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_nsp_gemnoc = {
+ .name = "qnm_nsp_gemnoc",
+ .id = SM8650_MASTER_COMPUTE_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 3,
+ .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC,
+ SM8650_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qnm_pcie = {
+ .name = "qnm_pcie",
+ .id = SM8650_MASTER_ANOC_PCIE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 2,
+ .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_snoc_sf = {
+ .name = "qnm_snoc_sf",
+ .id = SM8650_MASTER_SNOC_SF_MEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 3,
+ .links = { SM8650_SLAVE_GEM_NOC_CNOC, SM8650_SLAVE_LLCC,
+ SM8650_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qnm_ubwc_p = {
+ .name = "qnm_ubwc_p",
+ .id = SM8650_MASTER_UBWC_P,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node xm_gic = {
+ .name = "xm_gic",
+ .id = SM8650_MASTER_GIC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_lpiaon_noc = {
+ .name = "qnm_lpiaon_noc",
+ .id = SM8650_MASTER_LPIAON_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_LPASS_GEM_NOC },
+};
+
+static struct qcom_icc_node qnm_lpass_lpinoc = {
+ .name = "qnm_lpass_lpinoc",
+ .id = SM8650_MASTER_LPASS_LPINOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_LPIAON_NOC_LPASS_AG_NOC },
+};
+
+static struct qcom_icc_node qxm_lpinoc_dsp_axim = {
+ .name = "qxm_lpinoc_dsp_axim",
+ .id = SM8650_MASTER_LPASS_PROC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_LPICX_NOC_LPIAON_NOC },
+};
+
+static struct qcom_icc_node llcc_mc = {
+ .name = "llcc_mc",
+ .id = SM8650_MASTER_LLCC,
+ .channels = 4,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_EBI1 },
+};
+
+static struct qcom_icc_node qnm_camnoc_hf = {
+ .name = "qnm_camnoc_hf",
+ .id = SM8650_MASTER_CAMNOC_HF,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_camnoc_icp = {
+ .name = "qnm_camnoc_icp",
+ .id = SM8650_MASTER_CAMNOC_ICP,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_camnoc_sf = {
+ .name = "qnm_camnoc_sf",
+ .id = SM8650_MASTER_CAMNOC_SF,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_mdp = {
+ .name = "qnm_mdp",
+ .id = SM8650_MASTER_MDP,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_vapss_hcp = {
+ .name = "qnm_vapss_hcp",
+ .id = SM8650_MASTER_CDSP_HCP,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_video = {
+ .name = "qnm_video",
+ .id = SM8650_MASTER_VIDEO,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_video_cv_cpu = {
+ .name = "qnm_video_cv_cpu",
+ .id = SM8650_MASTER_VIDEO_CV_PROC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_video_cvp = {
+ .name = "qnm_video_cvp",
+ .id = SM8650_MASTER_VIDEO_PROC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_video_v_cpu = {
+ .name = "qnm_video_v_cpu",
+ .id = SM8650_MASTER_VIDEO_V_PROC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qsm_mnoc_cfg = {
+ .name = "qsm_mnoc_cfg",
+ .id = SM8650_MASTER_CNOC_MNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_SERVICE_MNOC },
+};
+
+static struct qcom_icc_node qnm_nsp = {
+ .name = "qnm_nsp",
+ .id = SM8650_MASTER_CDSP_PROC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_CDSP_MEM_NOC },
+};
+
+static struct qcom_icc_node qsm_pcie_anoc_cfg = {
+ .name = "qsm_pcie_anoc_cfg",
+ .id = SM8650_MASTER_PCIE_ANOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_SERVICE_PCIE_ANOC },
+};
+
+static struct qcom_icc_node xm_pcie3_0 = {
+ .name = "xm_pcie3_0",
+ .id = SM8650_MASTER_PCIE_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node xm_pcie3_1 = {
+ .name = "xm_pcie3_1",
+ .id = SM8650_MASTER_PCIE_1,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node qnm_aggre1_noc = {
+ .name = "qnm_aggre1_noc",
+ .id = SM8650_MASTER_A1NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qnm_aggre2_noc = {
+ .name = "qnm_aggre2_noc",
+ .id = SM8650_MASTER_A2NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qns_a1noc_snoc = {
+ .name = "qns_a1noc_snoc",
+ .id = SM8650_SLAVE_A1NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_MASTER_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qns_a2noc_snoc = {
+ .name = "qns_a2noc_snoc",
+ .id = SM8650_SLAVE_A2NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_MASTER_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qup0_core_slave = {
+ .name = "qup0_core_slave",
+ .id = SM8650_SLAVE_QUP_CORE_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qup1_core_slave = {
+ .name = "qup1_core_slave",
+ .id = SM8650_SLAVE_QUP_CORE_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qup2_core_slave = {
+ .name = "qup2_core_slave",
+ .id = SM8650_SLAVE_QUP_CORE_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ahb2phy0 = {
+ .name = "qhs_ahb2phy0",
+ .id = SM8650_SLAVE_AHB2PHY_SOUTH,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ahb2phy1 = {
+ .name = "qhs_ahb2phy1",
+ .id = SM8650_SLAVE_AHB2PHY_NORTH,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_camera_cfg = {
+ .name = "qhs_camera_cfg",
+ .id = SM8650_SLAVE_CAMERA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_clk_ctl = {
+ .name = "qhs_clk_ctl",
+ .id = SM8650_SLAVE_CLK_CTL,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_cpr_cx = {
+ .name = "qhs_cpr_cx",
+ .id = SM8650_SLAVE_RBCPR_CX_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_cpr_hmx = {
+ .name = "qhs_cpr_hmx",
+ .id = SM8650_SLAVE_CPR_HMX,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_cpr_mmcx = {
+ .name = "qhs_cpr_mmcx",
+ .id = SM8650_SLAVE_RBCPR_MMCX_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_cpr_mxa = {
+ .name = "qhs_cpr_mxa",
+ .id = SM8650_SLAVE_RBCPR_MXA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_cpr_mxc = {
+ .name = "qhs_cpr_mxc",
+ .id = SM8650_SLAVE_RBCPR_MXC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_cpr_nspcx = {
+ .name = "qhs_cpr_nspcx",
+ .id = SM8650_SLAVE_CPR_NSPCX,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_crypto0_cfg = {
+ .name = "qhs_crypto0_cfg",
+ .id = SM8650_SLAVE_CRYPTO_0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_cx_rdpm = {
+ .name = "qhs_cx_rdpm",
+ .id = SM8650_SLAVE_CX_RDPM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_display_cfg = {
+ .name = "qhs_display_cfg",
+ .id = SM8650_SLAVE_DISPLAY_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_gpuss_cfg = {
+ .name = "qhs_gpuss_cfg",
+ .id = SM8650_SLAVE_GFX3D_CFG,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_i2c = {
+ .name = "qhs_i2c",
+ .id = SM8650_SLAVE_I2C,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_i3c_ibi0_cfg = {
+ .name = "qhs_i3c_ibi0_cfg",
+ .id = SM8650_SLAVE_I3C_IBI0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_i3c_ibi1_cfg = {
+ .name = "qhs_i3c_ibi1_cfg",
+ .id = SM8650_SLAVE_I3C_IBI1_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_imem_cfg = {
+ .name = "qhs_imem_cfg",
+ .id = SM8650_SLAVE_IMEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_mss_cfg = {
+ .name = "qhs_mss_cfg",
+ .id = SM8650_SLAVE_CNOC_MSS,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_mx_2_rdpm = {
+ .name = "qhs_mx_2_rdpm",
+ .id = SM8650_SLAVE_MX_2_RDPM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_mx_rdpm = {
+ .name = "qhs_mx_rdpm",
+ .id = SM8650_SLAVE_MX_RDPM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie0_cfg = {
+ .name = "qhs_pcie0_cfg",
+ .id = SM8650_SLAVE_PCIE_0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie1_cfg = {
+ .name = "qhs_pcie1_cfg",
+ .id = SM8650_SLAVE_PCIE_1_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie_rscc = {
+ .name = "qhs_pcie_rscc",
+ .id = SM8650_SLAVE_PCIE_RSCC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pdm = {
+ .name = "qhs_pdm",
+ .id = SM8650_SLAVE_PDM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_prng = {
+ .name = "qhs_prng",
+ .id = SM8650_SLAVE_PRNG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qdss_cfg = {
+ .name = "qhs_qdss_cfg",
+ .id = SM8650_SLAVE_QDSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qspi = {
+ .name = "qhs_qspi",
+ .id = SM8650_SLAVE_QSPI_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qup02 = {
+ .name = "qhs_qup02",
+ .id = SM8650_SLAVE_QUP_3,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qup1 = {
+ .name = "qhs_qup1",
+ .id = SM8650_SLAVE_QUP_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qup2 = {
+ .name = "qhs_qup2",
+ .id = SM8650_SLAVE_QUP_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_sdc2 = {
+ .name = "qhs_sdc2",
+ .id = SM8650_SLAVE_SDCC_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_sdc4 = {
+ .name = "qhs_sdc4",
+ .id = SM8650_SLAVE_SDCC_4,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_spss_cfg = {
+ .name = "qhs_spss_cfg",
+ .id = SM8650_SLAVE_SPSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_tcsr = {
+ .name = "qhs_tcsr",
+ .id = SM8650_SLAVE_TCSR,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_tlmm = {
+ .name = "qhs_tlmm",
+ .id = SM8650_SLAVE_TLMM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ufs_mem_cfg = {
+ .name = "qhs_ufs_mem_cfg",
+ .id = SM8650_SLAVE_UFS_MEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb3_0 = {
+ .name = "qhs_usb3_0",
+ .id = SM8650_SLAVE_USB3_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_venus_cfg = {
+ .name = "qhs_venus_cfg",
+ .id = SM8650_SLAVE_VENUS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_vsense_ctrl_cfg = {
+ .name = "qhs_vsense_ctrl_cfg",
+ .id = SM8650_SLAVE_VSENSE_CTRL_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qss_mnoc_cfg = {
+ .name = "qss_mnoc_cfg",
+ .id = SM8650_SLAVE_CNOC_MNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_MASTER_CNOC_MNOC_CFG },
+};
+
+static struct qcom_icc_node qss_nsp_qtb_cfg = {
+ .name = "qss_nsp_qtb_cfg",
+ .id = SM8650_SLAVE_NSP_QTB_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qss_pcie_anoc_cfg = {
+ .name = "qss_pcie_anoc_cfg",
+ .id = SM8650_SLAVE_PCIE_ANOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_MASTER_PCIE_ANOC_CFG },
+};
+
+static struct qcom_icc_node srvc_cnoc_cfg = {
+ .name = "srvc_cnoc_cfg",
+ .id = SM8650_SLAVE_SERVICE_CNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_qdss_stm = {
+ .name = "xs_qdss_stm",
+ .id = SM8650_SLAVE_QDSS_STM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_sys_tcu_cfg = {
+ .name = "xs_sys_tcu_cfg",
+ .id = SM8650_SLAVE_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_aoss = {
+ .name = "qhs_aoss",
+ .id = SM8650_SLAVE_AOSS,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ipa = {
+ .name = "qhs_ipa",
+ .id = SM8650_SLAVE_IPA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ipc_router = {
+ .name = "qhs_ipc_router",
+ .id = SM8650_SLAVE_IPC_ROUTER_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_tme_cfg = {
+ .name = "qhs_tme_cfg",
+ .id = SM8650_SLAVE_TME_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qss_apss = {
+ .name = "qss_apss",
+ .id = SM8650_SLAVE_APPSS,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qss_cfg = {
+ .name = "qss_cfg",
+ .id = SM8650_SLAVE_CNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { SM8650_MASTER_CNOC_CFG },
+};
+
+static struct qcom_icc_node qss_ddrss_cfg = {
+ .name = "qss_ddrss_cfg",
+ .id = SM8650_SLAVE_DDRSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qxs_imem = {
+ .name = "qxs_imem",
+ .id = SM8650_SLAVE_IMEM,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node srvc_cnoc_main = {
+ .name = "srvc_cnoc_main",
+ .id = SM8650_SLAVE_SERVICE_CNOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_0 = {
+ .name = "xs_pcie_0",
+ .id = SM8650_SLAVE_PCIE_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_1 = {
+ .name = "xs_pcie_1",
+ .id = SM8650_SLAVE_PCIE_1,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_gem_noc_cnoc = {
+ .name = "qns_gem_noc_cnoc",
+ .id = SM8650_SLAVE_GEM_NOC_CNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_MASTER_GEM_NOC_CNOC },
+};
+
+static struct qcom_icc_node qns_llcc = {
+ .name = "qns_llcc",
+ .id = SM8650_SLAVE_LLCC,
+ .channels = 4,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_MASTER_LLCC },
+};
+
+static struct qcom_icc_node qns_pcie = {
+ .name = "qns_pcie",
+ .id = SM8650_SLAVE_MEM_NOC_PCIE_SNOC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { SM8650_MASTER_GEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qns_lpass_ag_noc_gemnoc = {
+ .name = "qns_lpass_ag_noc_gemnoc",
+ .id = SM8650_SLAVE_LPASS_GEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_MASTER_LPASS_GEM_NOC },
+};
+
+static struct qcom_icc_node qns_lpass_aggnoc = {
+ .name = "qns_lpass_aggnoc",
+ .id = SM8650_SLAVE_LPIAON_NOC_LPASS_AG_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_MASTER_LPIAON_NOC },
+};
+
+static struct qcom_icc_node qns_lpi_aon_noc = {
+ .name = "qns_lpi_aon_noc",
+ .id = SM8650_SLAVE_LPICX_NOC_LPIAON_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_MASTER_LPASS_LPINOC },
+};
+
+static struct qcom_icc_node ebi = {
+ .name = "ebi",
+ .id = SM8650_SLAVE_EBI1,
+ .channels = 4,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_mem_noc_hf = {
+ .name = "qns_mem_noc_hf",
+ .id = SM8650_SLAVE_MNOC_HF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM8650_MASTER_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qns_mem_noc_sf = {
+ .name = "qns_mem_noc_sf",
+ .id = SM8650_SLAVE_MNOC_SF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM8650_MASTER_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node srvc_mnoc = {
+ .name = "srvc_mnoc",
+ .id = SM8650_SLAVE_SERVICE_MNOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_nsp_gemnoc = {
+ .name = "qns_nsp_gemnoc",
+ .id = SM8650_SLAVE_CDSP_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { SM8650_MASTER_COMPUTE_NOC },
+};
+
+static struct qcom_icc_node qns_pcie_mem_noc = {
+ .name = "qns_pcie_mem_noc",
+ .id = SM8650_SLAVE_ANOC_PCIE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_MASTER_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node srvc_pcie_aggre_noc = {
+ .name = "srvc_pcie_aggre_noc",
+ .id = SM8650_SLAVE_SERVICE_PCIE_ANOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_gemnoc_sf = {
+ .name = "qns_gemnoc_sf",
+ .id = SM8650_SLAVE_SNOC_GEM_NOC_SF,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { SM8650_MASTER_SNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_bcm bcm_acv = {
+ .name = "ACV",
+ .enable_mask = BIT(3),
+ .num_nodes = 1,
+ .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_ce0 = {
+ .name = "CE0",
+ .num_nodes = 1,
+ .nodes = { &qxm_crypto },
+};
+
+static struct qcom_icc_bcm bcm_cn0 = {
+ .name = "CN0",
+ .enable_mask = BIT(0),
+ .keepalive = true,
+ .num_nodes = 59,
+ .nodes = { &qsm_cfg, &qhs_ahb2phy0,
+ &qhs_ahb2phy1, &qhs_camera_cfg,
+ &qhs_clk_ctl, &qhs_cpr_cx,
+ &qhs_cpr_hmx, &qhs_cpr_mmcx,
+ &qhs_cpr_mxa, &qhs_cpr_mxc,
+ &qhs_cpr_nspcx, &qhs_crypto0_cfg,
+ &qhs_cx_rdpm, &qhs_display_cfg,
+ &qhs_gpuss_cfg, &qhs_i2c,
+ &qhs_i3c_ibi0_cfg, &qhs_i3c_ibi1_cfg,
+ &qhs_imem_cfg, &qhs_mss_cfg,
+ &qhs_mx_2_rdpm, &qhs_mx_rdpm,
+ &qhs_pcie0_cfg, &qhs_pcie1_cfg,
+ &qhs_pcie_rscc, &qhs_pdm,
+ &qhs_prng, &qhs_qdss_cfg,
+ &qhs_qspi, &qhs_qup02,
+ &qhs_qup1, &qhs_qup2,
+ &qhs_sdc2, &qhs_sdc4,
+ &qhs_spss_cfg, &qhs_tcsr,
+ &qhs_tlmm, &qhs_ufs_mem_cfg,
+ &qhs_usb3_0, &qhs_venus_cfg,
+ &qhs_vsense_ctrl_cfg, &qss_mnoc_cfg,
+ &qss_nsp_qtb_cfg, &qss_pcie_anoc_cfg,
+ &srvc_cnoc_cfg, &xs_qdss_stm,
+ &xs_sys_tcu_cfg, &qnm_gemnoc_cnoc,
+ &qnm_gemnoc_pcie, &qhs_aoss,
+ &qhs_ipa, &qhs_ipc_router,
+ &qhs_tme_cfg, &qss_apss,
+ &qss_cfg, &qss_ddrss_cfg,
+ &qxs_imem, &srvc_cnoc_main,
+ &xs_pcie_0, &xs_pcie_1 },
+};
+
+static struct qcom_icc_bcm bcm_co0 = {
+ .name = "CO0",
+ .enable_mask = BIT(0),
+ .num_nodes = 2,
+ .nodes = { &qnm_nsp, &qns_nsp_gemnoc },
+};
+
+static struct qcom_icc_bcm bcm_lp0 = {
+ .name = "LP0",
+ .num_nodes = 2,
+ .nodes = { &qnm_lpass_lpinoc, &qns_lpass_aggnoc },
+};
+
+static struct qcom_icc_bcm bcm_mc0 = {
+ .name = "MC0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_mm0 = {
+ .name = "MM0",
+ .num_nodes = 1,
+ .nodes = { &qns_mem_noc_hf },
+};
+
+static struct qcom_icc_bcm bcm_mm1 = {
+ .name = "MM1",
+ .enable_mask = BIT(0),
+ .num_nodes = 8,
+ .nodes = { &qnm_camnoc_hf, &qnm_camnoc_icp,
+ &qnm_camnoc_sf, &qnm_vapss_hcp,
+ &qnm_video_cv_cpu, &qnm_video_cvp,
+ &qnm_video_v_cpu, &qns_mem_noc_sf },
+};
+
+static struct qcom_icc_bcm bcm_qup0 = {
+ .name = "QUP0",
+ .keepalive = true,
+ .vote_scale = 1,
+ .num_nodes = 1,
+ .nodes = { &qup0_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_qup1 = {
+ .name = "QUP1",
+ .keepalive = true,
+ .vote_scale = 1,
+ .num_nodes = 1,
+ .nodes = { &qup1_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_qup2 = {
+ .name = "QUP2",
+ .keepalive = true,
+ .vote_scale = 1,
+ .num_nodes = 1,
+ .nodes = { &qup2_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_sh0 = {
+ .name = "SH0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_llcc },
+};
+
+static struct qcom_icc_bcm bcm_sh1 = {
+ .name = "SH1",
+ .enable_mask = BIT(0),
+ .num_nodes = 15,
+ .nodes = { &alm_gpu_tcu, &alm_sys_tcu,
+ &alm_ubwc_p_tcu, &chm_apps,
+ &qnm_gpu, &qnm_mdsp,
+ &qnm_mnoc_hf, &qnm_mnoc_sf,
+ &qnm_nsp_gemnoc, &qnm_pcie,
+ &qnm_snoc_sf, &qnm_ubwc_p,
+ &xm_gic, &qns_gem_noc_cnoc,
+ &qns_pcie },
+};
+
+static struct qcom_icc_bcm bcm_sn0 = {
+ .name = "SN0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_gemnoc_sf },
+};
+
+static struct qcom_icc_bcm bcm_sn2 = {
+ .name = "SN2",
+ .num_nodes = 1,
+ .nodes = { &qnm_aggre1_noc },
+};
+
+static struct qcom_icc_bcm bcm_sn3 = {
+ .name = "SN3",
+ .num_nodes = 1,
+ .nodes = { &qnm_aggre2_noc },
+};
+
+static struct qcom_icc_bcm bcm_sn4 = {
+ .name = "SN4",
+ .num_nodes = 1,
+ .nodes = { &qns_pcie_mem_noc },
+};
+
+static struct qcom_icc_node * const aggre1_noc_nodes[] = {
+ [MASTER_QSPI_0] = &qhm_qspi,
+ [MASTER_QUP_1] = &qhm_qup1,
+ [MASTER_QUP_3] = &qxm_qup02,
+ [MASTER_SDCC_4] = &xm_sdc4,
+ [MASTER_UFS_MEM] = &xm_ufs_mem,
+ [MASTER_USB3_0] = &xm_usb3_0,
+ [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc,
+};
+
+static const struct qcom_icc_desc sm8650_aggre1_noc = {
+ .nodes = aggre1_noc_nodes,
+ .num_nodes = ARRAY_SIZE(aggre1_noc_nodes),
+};
+
+static struct qcom_icc_bcm * const aggre2_noc_bcms[] = {
+ &bcm_ce0,
+};
+
+static struct qcom_icc_node * const aggre2_noc_nodes[] = {
+ [MASTER_QDSS_BAM] = &qhm_qdss_bam,
+ [MASTER_QUP_2] = &qhm_qup2,
+ [MASTER_CRYPTO] = &qxm_crypto,
+ [MASTER_IPA] = &qxm_ipa,
+ [MASTER_SP] = &qxm_sp,
+ [MASTER_QDSS_ETR] = &xm_qdss_etr_0,
+ [MASTER_QDSS_ETR_1] = &xm_qdss_etr_1,
+ [MASTER_SDCC_2] = &xm_sdc2,
+ [SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc,
+};
+
+static const struct qcom_icc_desc sm8650_aggre2_noc = {
+ .nodes = aggre2_noc_nodes,
+ .num_nodes = ARRAY_SIZE(aggre2_noc_nodes),
+ .bcms = aggre2_noc_bcms,
+ .num_bcms = ARRAY_SIZE(aggre2_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const clk_virt_bcms[] = {
+ &bcm_qup0,
+ &bcm_qup1,
+ &bcm_qup2,
+};
+
+static struct qcom_icc_node * const clk_virt_nodes[] = {
+ [MASTER_QUP_CORE_0] = &qup0_core_master,
+ [MASTER_QUP_CORE_1] = &qup1_core_master,
+ [MASTER_QUP_CORE_2] = &qup2_core_master,
+ [SLAVE_QUP_CORE_0] = &qup0_core_slave,
+ [SLAVE_QUP_CORE_1] = &qup1_core_slave,
+ [SLAVE_QUP_CORE_2] = &qup2_core_slave,
+};
+
+static const struct qcom_icc_desc sm8650_clk_virt = {
+ .nodes = clk_virt_nodes,
+ .num_nodes = ARRAY_SIZE(clk_virt_nodes),
+ .bcms = clk_virt_bcms,
+ .num_bcms = ARRAY_SIZE(clk_virt_bcms),
+};
+
+static struct qcom_icc_bcm * const config_noc_bcms[] = {
+ &bcm_cn0,
+};
+
+static struct qcom_icc_node * const config_noc_nodes[] = {
+ [MASTER_CNOC_CFG] = &qsm_cfg,
+ [SLAVE_AHB2PHY_SOUTH] = &qhs_ahb2phy0,
+ [SLAVE_AHB2PHY_NORTH] = &qhs_ahb2phy1,
+ [SLAVE_CAMERA_CFG] = &qhs_camera_cfg,
+ [SLAVE_CLK_CTL] = &qhs_clk_ctl,
+ [SLAVE_RBCPR_CX_CFG] = &qhs_cpr_cx,
+ [SLAVE_CPR_HMX] = &qhs_cpr_hmx,
+ [SLAVE_RBCPR_MMCX_CFG] = &qhs_cpr_mmcx,
+ [SLAVE_RBCPR_MXA_CFG] = &qhs_cpr_mxa,
+ [SLAVE_RBCPR_MXC_CFG] = &qhs_cpr_mxc,
+ [SLAVE_CPR_NSPCX] = &qhs_cpr_nspcx,
+ [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg,
+ [SLAVE_CX_RDPM] = &qhs_cx_rdpm,
+ [SLAVE_DISPLAY_CFG] = &qhs_display_cfg,
+ [SLAVE_GFX3D_CFG] = &qhs_gpuss_cfg,
+ [SLAVE_I2C] = &qhs_i2c,
+ [SLAVE_I3C_IBI0_CFG] = &qhs_i3c_ibi0_cfg,
+ [SLAVE_I3C_IBI1_CFG] = &qhs_i3c_ibi1_cfg,
+ [SLAVE_IMEM_CFG] = &qhs_imem_cfg,
+ [SLAVE_CNOC_MSS] = &qhs_mss_cfg,
+ [SLAVE_MX_2_RDPM] = &qhs_mx_2_rdpm,
+ [SLAVE_MX_RDPM] = &qhs_mx_rdpm,
+ [SLAVE_PCIE_0_CFG] = &qhs_pcie0_cfg,
+ [SLAVE_PCIE_1_CFG] = &qhs_pcie1_cfg,
+ [SLAVE_PCIE_RSCC] = &qhs_pcie_rscc,
+ [SLAVE_PDM] = &qhs_pdm,
+ [SLAVE_PRNG] = &qhs_prng,
+ [SLAVE_QDSS_CFG] = &qhs_qdss_cfg,
+ [SLAVE_QSPI_0] = &qhs_qspi,
+ [SLAVE_QUP_3] = &qhs_qup02,
+ [SLAVE_QUP_1] = &qhs_qup1,
+ [SLAVE_QUP_2] = &qhs_qup2,
+ [SLAVE_SDCC_2] = &qhs_sdc2,
+ [SLAVE_SDCC_4] = &qhs_sdc4,
+ [SLAVE_SPSS_CFG] = &qhs_spss_cfg,
+ [SLAVE_TCSR] = &qhs_tcsr,
+ [SLAVE_TLMM] = &qhs_tlmm,
+ [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg,
+ [SLAVE_USB3_0] = &qhs_usb3_0,
+ [SLAVE_VENUS_CFG] = &qhs_venus_cfg,
+ [SLAVE_VSENSE_CTRL_CFG] = &qhs_vsense_ctrl_cfg,
+ [SLAVE_CNOC_MNOC_CFG] = &qss_mnoc_cfg,
+ [SLAVE_NSP_QTB_CFG] = &qss_nsp_qtb_cfg,
+ [SLAVE_PCIE_ANOC_CFG] = &qss_pcie_anoc_cfg,
+ [SLAVE_SERVICE_CNOC_CFG] = &srvc_cnoc_cfg,
+ [SLAVE_QDSS_STM] = &xs_qdss_stm,
+ [SLAVE_TCU] = &xs_sys_tcu_cfg,
+};
+
+static const struct qcom_icc_desc sm8650_config_noc = {
+ .nodes = config_noc_nodes,
+ .num_nodes = ARRAY_SIZE(config_noc_nodes),
+ .bcms = config_noc_bcms,
+ .num_bcms = ARRAY_SIZE(config_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const cnoc_main_bcms[] = {
+ &bcm_cn0,
+};
+
+static struct qcom_icc_node * const cnoc_main_nodes[] = {
+ [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc,
+ [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie,
+ [SLAVE_AOSS] = &qhs_aoss,
+ [SLAVE_IPA_CFG] = &qhs_ipa,
+ [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router,
+ [SLAVE_TME_CFG] = &qhs_tme_cfg,
+ [SLAVE_APPSS] = &qss_apss,
+ [SLAVE_CNOC_CFG] = &qss_cfg,
+ [SLAVE_DDRSS_CFG] = &qss_ddrss_cfg,
+ [SLAVE_IMEM] = &qxs_imem,
+ [SLAVE_SERVICE_CNOC] = &srvc_cnoc_main,
+ [SLAVE_PCIE_0] = &xs_pcie_0,
+ [SLAVE_PCIE_1] = &xs_pcie_1,
+};
+
+static const struct qcom_icc_desc sm8650_cnoc_main = {
+ .nodes = cnoc_main_nodes,
+ .num_nodes = ARRAY_SIZE(cnoc_main_nodes),
+ .bcms = cnoc_main_bcms,
+ .num_bcms = ARRAY_SIZE(cnoc_main_bcms),
+};
+
+static struct qcom_icc_bcm * const gem_noc_bcms[] = {
+ &bcm_sh0,
+ &bcm_sh1,
+};
+
+static struct qcom_icc_node * const gem_noc_nodes[] = {
+ [MASTER_GPU_TCU] = &alm_gpu_tcu,
+ [MASTER_SYS_TCU] = &alm_sys_tcu,
+ [MASTER_UBWC_P_TCU] = &alm_ubwc_p_tcu,
+ [MASTER_APPSS_PROC] = &chm_apps,
+ [MASTER_GFX3D] = &qnm_gpu,
+ [MASTER_LPASS_GEM_NOC] = &qnm_lpass_gemnoc,
+ [MASTER_MSS_PROC] = &qnm_mdsp,
+ [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf,
+ [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf,
+ [MASTER_COMPUTE_NOC] = &qnm_nsp_gemnoc,
+ [MASTER_ANOC_PCIE_GEM_NOC] = &qnm_pcie,
+ [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf,
+ [MASTER_UBWC_P] = &qnm_ubwc_p,
+ [MASTER_GIC] = &xm_gic,
+ [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc,
+ [SLAVE_LLCC] = &qns_llcc,
+ [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie,
+};
+
+static const struct qcom_icc_desc sm8650_gem_noc = {
+ .nodes = gem_noc_nodes,
+ .num_nodes = ARRAY_SIZE(gem_noc_nodes),
+ .bcms = gem_noc_bcms,
+ .num_bcms = ARRAY_SIZE(gem_noc_bcms),
+};
+
+static struct qcom_icc_node * const lpass_ag_noc_nodes[] = {
+ [MASTER_LPIAON_NOC] = &qnm_lpiaon_noc,
+ [SLAVE_LPASS_GEM_NOC] = &qns_lpass_ag_noc_gemnoc,
+};
+
+static const struct qcom_icc_desc sm8650_lpass_ag_noc = {
+ .nodes = lpass_ag_noc_nodes,
+ .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes),
+};
+
+static struct qcom_icc_bcm * const lpass_lpiaon_noc_bcms[] = {
+ &bcm_lp0,
+};
+
+static struct qcom_icc_node * const lpass_lpiaon_noc_nodes[] = {
+ [MASTER_LPASS_LPINOC] = &qnm_lpass_lpinoc,
+ [SLAVE_LPIAON_NOC_LPASS_AG_NOC] = &qns_lpass_aggnoc,
+};
+
+static const struct qcom_icc_desc sm8650_lpass_lpiaon_noc = {
+ .nodes = lpass_lpiaon_noc_nodes,
+ .num_nodes = ARRAY_SIZE(lpass_lpiaon_noc_nodes),
+ .bcms = lpass_lpiaon_noc_bcms,
+ .num_bcms = ARRAY_SIZE(lpass_lpiaon_noc_bcms),
+};
+
+static struct qcom_icc_node * const lpass_lpicx_noc_nodes[] = {
+ [MASTER_LPASS_PROC] = &qxm_lpinoc_dsp_axim,
+ [SLAVE_LPICX_NOC_LPIAON_NOC] = &qns_lpi_aon_noc,
+};
+
+static const struct qcom_icc_desc sm8650_lpass_lpicx_noc = {
+ .nodes = lpass_lpicx_noc_nodes,
+ .num_nodes = ARRAY_SIZE(lpass_lpicx_noc_nodes),
+};
+
+static struct qcom_icc_bcm * const mc_virt_bcms[] = {
+ &bcm_acv,
+ &bcm_mc0,
+};
+
+static struct qcom_icc_node * const mc_virt_nodes[] = {
+ [MASTER_LLCC] = &llcc_mc,
+ [SLAVE_EBI1] = &ebi,
+};
+
+static const struct qcom_icc_desc sm8650_mc_virt = {
+ .nodes = mc_virt_nodes,
+ .num_nodes = ARRAY_SIZE(mc_virt_nodes),
+ .bcms = mc_virt_bcms,
+ .num_bcms = ARRAY_SIZE(mc_virt_bcms),
+};
+
+static struct qcom_icc_bcm * const mmss_noc_bcms[] = {
+ &bcm_mm0,
+ &bcm_mm1,
+};
+
+static struct qcom_icc_node * const mmss_noc_nodes[] = {
+ [MASTER_CAMNOC_HF] = &qnm_camnoc_hf,
+ [MASTER_CAMNOC_ICP] = &qnm_camnoc_icp,
+ [MASTER_CAMNOC_SF] = &qnm_camnoc_sf,
+ [MASTER_MDP] = &qnm_mdp,
+ [MASTER_CDSP_HCP] = &qnm_vapss_hcp,
+ [MASTER_VIDEO] = &qnm_video,
+ [MASTER_VIDEO_CV_PROC] = &qnm_video_cv_cpu,
+ [MASTER_VIDEO_PROC] = &qnm_video_cvp,
+ [MASTER_VIDEO_V_PROC] = &qnm_video_v_cpu,
+ [MASTER_CNOC_MNOC_CFG] = &qsm_mnoc_cfg,
+ [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf,
+ [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf,
+ [SLAVE_SERVICE_MNOC] = &srvc_mnoc,
+};
+
+static const struct qcom_icc_desc sm8650_mmss_noc = {
+ .nodes = mmss_noc_nodes,
+ .num_nodes = ARRAY_SIZE(mmss_noc_nodes),
+ .bcms = mmss_noc_bcms,
+ .num_bcms = ARRAY_SIZE(mmss_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const nsp_noc_bcms[] = {
+ &bcm_co0,
+};
+
+static struct qcom_icc_node * const nsp_noc_nodes[] = {
+ [MASTER_CDSP_PROC] = &qnm_nsp,
+ [SLAVE_CDSP_MEM_NOC] = &qns_nsp_gemnoc,
+};
+
+static const struct qcom_icc_desc sm8650_nsp_noc = {
+ .nodes = nsp_noc_nodes,
+ .num_nodes = ARRAY_SIZE(nsp_noc_nodes),
+ .bcms = nsp_noc_bcms,
+ .num_bcms = ARRAY_SIZE(nsp_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const pcie_anoc_bcms[] = {
+ &bcm_sn4,
+};
+
+static struct qcom_icc_node * const pcie_anoc_nodes[] = {
+ [MASTER_PCIE_ANOC_CFG] = &qsm_pcie_anoc_cfg,
+ [MASTER_PCIE_0] = &xm_pcie3_0,
+ [MASTER_PCIE_1] = &xm_pcie3_1,
+ [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc,
+ [SLAVE_SERVICE_PCIE_ANOC] = &srvc_pcie_aggre_noc,
+};
+
+static const struct qcom_icc_desc sm8650_pcie_anoc = {
+ .nodes = pcie_anoc_nodes,
+ .num_nodes = ARRAY_SIZE(pcie_anoc_nodes),
+ .bcms = pcie_anoc_bcms,
+ .num_bcms = ARRAY_SIZE(pcie_anoc_bcms),
+};
+
+static struct qcom_icc_bcm * const system_noc_bcms[] = {
+ &bcm_sn0,
+ &bcm_sn2,
+ &bcm_sn3,
+};
+
+static struct qcom_icc_node * const system_noc_nodes[] = {
+ [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc,
+ [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc,
+ [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf,
+};
+
+static const struct qcom_icc_desc sm8650_system_noc = {
+ .nodes = system_noc_nodes,
+ .num_nodes = ARRAY_SIZE(system_noc_nodes),
+ .bcms = system_noc_bcms,
+ .num_bcms = ARRAY_SIZE(system_noc_bcms),
+};
+
+static const struct of_device_id qnoc_of_match[] = {
+ { .compatible = "qcom,sm8650-aggre1-noc", .data = &sm8650_aggre1_noc },
+ { .compatible = "qcom,sm8650-aggre2-noc", .data = &sm8650_aggre2_noc },
+ { .compatible = "qcom,sm8650-clk-virt", .data = &sm8650_clk_virt },
+ { .compatible = "qcom,sm8650-config-noc", .data = &sm8650_config_noc },
+ { .compatible = "qcom,sm8650-cnoc-main", .data = &sm8650_cnoc_main },
+ { .compatible = "qcom,sm8650-gem-noc", .data = &sm8650_gem_noc },
+ { .compatible = "qcom,sm8650-lpass-ag-noc", .data = &sm8650_lpass_ag_noc },
+ { .compatible = "qcom,sm8650-lpass-lpiaon-noc", .data = &sm8650_lpass_lpiaon_noc },
+ { .compatible = "qcom,sm8650-lpass-lpicx-noc", .data = &sm8650_lpass_lpicx_noc },
+ { .compatible = "qcom,sm8650-mc-virt", .data = &sm8650_mc_virt },
+ { .compatible = "qcom,sm8650-mmss-noc", .data = &sm8650_mmss_noc },
+ { .compatible = "qcom,sm8650-nsp-noc", .data = &sm8650_nsp_noc },
+ { .compatible = "qcom,sm8650-pcie-anoc", .data = &sm8650_pcie_anoc },
+ { .compatible = "qcom,sm8650-system-noc", .data = &sm8650_system_noc },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+ .probe = qcom_icc_rpmh_probe,
+ .remove_new = qcom_icc_rpmh_remove,
+ .driver = {
+ .name = "qnoc-sm8650",
+ .of_match_table = qnoc_of_match,
+ .sync_state = icc_sync_state,
+ },
+};
+
+static int __init qnoc_driver_init(void)
+{
+ return platform_driver_register(&qnoc_driver);
+}
+core_initcall(qnoc_driver_init);
+
+static void __exit qnoc_driver_exit(void)
+{
+ platform_driver_unregister(&qnoc_driver);
+}
+module_exit(qnoc_driver_exit);
+
+MODULE_DESCRIPTION("sm8650 NoC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/interconnect/qcom/sm8650.h b/drivers/interconnect/qcom/sm8650.h
new file mode 100644
index 000000000000..de35c956fe49
--- /dev/null
+++ b/drivers/interconnect/qcom/sm8650.h
@@ -0,0 +1,143 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * SM8650 interconnect IDs
+ *
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef __DRIVERS_INTERCONNECT_QCOM_SM8650_H
+#define __DRIVERS_INTERCONNECT_QCOM_SM8650_H
+
+#define SM8650_MASTER_A1NOC_SNOC 0
+#define SM8650_MASTER_A2NOC_SNOC 1
+#define SM8650_MASTER_ANOC_PCIE_GEM_NOC 2
+#define SM8650_MASTER_APPSS_PROC 3
+#define SM8650_MASTER_CAMNOC_HF 4
+#define SM8650_MASTER_CAMNOC_ICP 5
+#define SM8650_MASTER_CAMNOC_SF 6
+#define SM8650_MASTER_CDSP_HCP 7
+#define SM8650_MASTER_CDSP_PROC 8
+#define SM8650_MASTER_CNOC_CFG 9
+#define SM8650_MASTER_CNOC_MNOC_CFG 10
+#define SM8650_MASTER_COMPUTE_NOC 11
+#define SM8650_MASTER_CRYPTO 12
+#define SM8650_MASTER_GEM_NOC_CNOC 13
+#define SM8650_MASTER_GEM_NOC_PCIE_SNOC 14
+#define SM8650_MASTER_GFX3D 15
+#define SM8650_MASTER_GIC 16
+#define SM8650_MASTER_GPU_TCU 17
+#define SM8650_MASTER_IPA 18
+#define SM8650_MASTER_LLCC 19
+#define SM8650_MASTER_LPASS_GEM_NOC 20
+#define SM8650_MASTER_LPASS_LPINOC 21
+#define SM8650_MASTER_LPASS_PROC 22
+#define SM8650_MASTER_LPIAON_NOC 23
+#define SM8650_MASTER_MDP 24
+#define SM8650_MASTER_MNOC_HF_MEM_NOC 25
+#define SM8650_MASTER_MNOC_SF_MEM_NOC 26
+#define SM8650_MASTER_MSS_PROC 27
+#define SM8650_MASTER_PCIE_0 28
+#define SM8650_MASTER_PCIE_1 29
+#define SM8650_MASTER_PCIE_ANOC_CFG 30
+#define SM8650_MASTER_QDSS_BAM 31
+#define SM8650_MASTER_QDSS_ETR 32
+#define SM8650_MASTER_QDSS_ETR_1 33
+#define SM8650_MASTER_QSPI_0 34
+#define SM8650_MASTER_QUP_1 35
+#define SM8650_MASTER_QUP_2 36
+#define SM8650_MASTER_QUP_3 37
+#define SM8650_MASTER_QUP_CORE_0 38
+#define SM8650_MASTER_QUP_CORE_1 39
+#define SM8650_MASTER_QUP_CORE_2 40
+#define SM8650_MASTER_SDCC_2 41
+#define SM8650_MASTER_SDCC_4 42
+#define SM8650_MASTER_SNOC_SF_MEM_NOC 43
+#define SM8650_MASTER_SP 44
+#define SM8650_MASTER_SYS_TCU 45
+#define SM8650_MASTER_UBWC_P 46
+#define SM8650_MASTER_UBWC_P_TCU 47
+#define SM8650_MASTER_UFS_MEM 48
+#define SM8650_MASTER_USB3_0 49
+#define SM8650_MASTER_VIDEO 50
+#define SM8650_MASTER_VIDEO_CV_PROC 51
+#define SM8650_MASTER_VIDEO_PROC 52
+#define SM8650_MASTER_VIDEO_V_PROC 53
+#define SM8650_SLAVE_A1NOC_SNOC 54
+#define SM8650_SLAVE_A2NOC_SNOC 55
+#define SM8650_SLAVE_AHB2PHY_NORTH 56
+#define SM8650_SLAVE_AHB2PHY_SOUTH 57
+#define SM8650_SLAVE_ANOC_PCIE_GEM_NOC 58
+#define SM8650_SLAVE_AOSS 59
+#define SM8650_SLAVE_APPSS 60
+#define SM8650_SLAVE_CAMERA_CFG 61
+#define SM8650_SLAVE_CDSP_MEM_NOC 62
+#define SM8650_SLAVE_CLK_CTL 63
+#define SM8650_SLAVE_CNOC_CFG 64
+#define SM8650_SLAVE_CNOC_MNOC_CFG 65
+#define SM8650_SLAVE_CNOC_MSS 66
+#define SM8650_SLAVE_CPR_HMX 67
+#define SM8650_SLAVE_CPR_NSPCX 68
+#define SM8650_SLAVE_CRYPTO_0_CFG 69
+#define SM8650_SLAVE_CX_RDPM 70
+#define SM8650_SLAVE_DDRSS_CFG 71
+#define SM8650_SLAVE_DISPLAY_CFG 72
+#define SM8650_SLAVE_EBI1 73
+#define SM8650_SLAVE_GEM_NOC_CNOC 74
+#define SM8650_SLAVE_GFX3D_CFG 75
+#define SM8650_SLAVE_I2C 76
+#define SM8650_SLAVE_I3C_IBI0_CFG 77
+#define SM8650_SLAVE_I3C_IBI1_CFG 78
+#define SM8650_SLAVE_IMEM 79
+#define SM8650_SLAVE_IMEM_CFG 80
+#define SM8650_SLAVE_IPA_CFG 81
+#define SM8650_SLAVE_IPC_ROUTER_CFG 82
+#define SM8650_SLAVE_LLCC 83
+#define SM8650_SLAVE_LPASS_GEM_NOC 84
+#define SM8650_SLAVE_LPIAON_NOC_LPASS_AG_NOC 85
+#define SM8650_SLAVE_LPICX_NOC_LPIAON_NOC 86
+#define SM8650_SLAVE_MEM_NOC_PCIE_SNOC 87
+#define SM8650_SLAVE_MNOC_HF_MEM_NOC 88
+#define SM8650_SLAVE_MNOC_SF_MEM_NOC 89
+#define SM8650_SLAVE_MX_2_RDPM 90
+#define SM8650_SLAVE_MX_RDPM 91
+#define SM8650_SLAVE_NSP_QTB_CFG 92
+#define SM8650_SLAVE_PCIE_0 93
+#define SM8650_SLAVE_PCIE_1 94
+#define SM8650_SLAVE_PCIE_0_CFG 95
+#define SM8650_SLAVE_PCIE_1_CFG 96
+#define SM8650_SLAVE_PCIE_ANOC_CFG 97
+#define SM8650_SLAVE_PCIE_RSCC 98
+#define SM8650_SLAVE_PDM 99
+#define SM8650_SLAVE_PRNG 100
+#define SM8650_SLAVE_QDSS_CFG 101
+#define SM8650_SLAVE_QDSS_STM 102
+#define SM8650_SLAVE_QSPI_0 103
+#define SM8650_SLAVE_QUP_1 104
+#define SM8650_SLAVE_QUP_2 105
+#define SM8650_SLAVE_QUP_3 106
+#define SM8650_SLAVE_QUP_CORE_0 107
+#define SM8650_SLAVE_QUP_CORE_1 108
+#define SM8650_SLAVE_QUP_CORE_2 109
+#define SM8650_SLAVE_RBCPR_CX_CFG 110
+#define SM8650_SLAVE_RBCPR_MMCX_CFG 111
+#define SM8650_SLAVE_RBCPR_MXA_CFG 112
+#define SM8650_SLAVE_RBCPR_MXC_CFG 113
+#define SM8650_SLAVE_SDCC_2 114
+#define SM8650_SLAVE_SDCC_4 115
+#define SM8650_SLAVE_SERVICE_CNOC 116
+#define SM8650_SLAVE_SERVICE_CNOC_CFG 117
+#define SM8650_SLAVE_SERVICE_MNOC 118
+#define SM8650_SLAVE_SERVICE_PCIE_ANOC 119
+#define SM8650_SLAVE_SNOC_GEM_NOC_SF 120
+#define SM8650_SLAVE_SPSS_CFG 121
+#define SM8650_SLAVE_TCSR 122
+#define SM8650_SLAVE_TCU 123
+#define SM8650_SLAVE_TLMM 124
+#define SM8650_SLAVE_TME_CFG 125
+#define SM8650_SLAVE_UFS_MEM_CFG 126
+#define SM8650_SLAVE_USB3_0 127
+#define SM8650_SLAVE_VENUS_CFG 128
+#define SM8650_SLAVE_VSENSE_CTRL_CFG 129
+
+#endif
diff --git a/drivers/interconnect/qcom/smd-rpm.c b/drivers/interconnect/qcom/smd-rpm.c
index 16a145a3c914..3816bfb4e2f3 100644
--- a/drivers/interconnect/qcom/smd-rpm.c
+++ b/drivers/interconnect/qcom/smd-rpm.c
@@ -63,11 +63,9 @@ int qcom_icc_rpm_set_bus_rate(const struct rpm_clk_resource *clk, int ctx, u32 r
}
EXPORT_SYMBOL_GPL(qcom_icc_rpm_set_bus_rate);
-static int qcom_icc_rpm_smd_remove(struct platform_device *pdev)
+static void qcom_icc_rpm_smd_remove(struct platform_device *pdev)
{
icc_smd_rpm = NULL;
-
- return 0;
}
static int qcom_icc_rpm_smd_probe(struct platform_device *pdev)
@@ -87,7 +85,7 @@ static struct platform_driver qcom_interconnect_rpm_smd_driver = {
.name = "icc_smd_rpm",
},
.probe = qcom_icc_rpm_smd_probe,
- .remove = qcom_icc_rpm_smd_remove,
+ .remove_new = qcom_icc_rpm_smd_remove,
};
module_platform_driver(qcom_interconnect_rpm_smd_driver);
MODULE_AUTHOR("Georgi Djakov <[email protected]>");
diff --git a/drivers/interconnect/qcom/x1e80100.c b/drivers/interconnect/qcom/x1e80100.c
new file mode 100644
index 000000000000..d19501d913b3
--- /dev/null
+++ b/drivers/interconnect/qcom/x1e80100.c
@@ -0,0 +1,2328 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/interconnect.h>
+#include <linux/interconnect-provider.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <dt-bindings/interconnect/qcom,x1e80100-rpmh.h>
+
+#include "bcm-voter.h"
+#include "icc-common.h"
+#include "icc-rpmh.h"
+#include "x1e80100.h"
+
+static struct qcom_icc_node qhm_qspi = {
+ .name = "qhm_qspi",
+ .id = X1E80100_MASTER_QSPI_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qup1 = {
+ .name = "qhm_qup1",
+ .id = X1E80100_MASTER_QUP_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_sdc4 = {
+ .name = "xm_sdc4",
+ .id = X1E80100_MASTER_SDCC_4,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_ufs_mem = {
+ .name = "xm_ufs_mem",
+ .id = X1E80100_MASTER_UFS_MEM,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qup0 = {
+ .name = "qhm_qup0",
+ .id = X1E80100_MASTER_QUP_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qhm_qup2 = {
+ .name = "qhm_qup2",
+ .id = X1E80100_MASTER_QUP_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qxm_crypto = {
+ .name = "qxm_crypto",
+ .id = X1E80100_MASTER_CRYPTO,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node qxm_sp = {
+ .name = "qxm_sp",
+ .id = X1E80100_MASTER_SP,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_qdss_etr_0 = {
+ .name = "xm_qdss_etr_0",
+ .id = X1E80100_MASTER_QDSS_ETR,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_qdss_etr_1 = {
+ .name = "xm_qdss_etr_1",
+ .id = X1E80100_MASTER_QDSS_ETR_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_sdc2 = {
+ .name = "xm_sdc2",
+ .id = X1E80100_MASTER_SDCC_2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node ddr_perf_mode_master = {
+ .name = "ddr_perf_mode_master",
+ .id = X1E80100_MASTER_DDR_PERF_MODE,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_DDR_PERF_MODE },
+};
+
+static struct qcom_icc_node qup0_core_master = {
+ .name = "qup0_core_master",
+ .id = X1E80100_MASTER_QUP_CORE_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_QUP_CORE_0 },
+};
+
+static struct qcom_icc_node qup1_core_master = {
+ .name = "qup1_core_master",
+ .id = X1E80100_MASTER_QUP_CORE_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_QUP_CORE_1 },
+};
+
+static struct qcom_icc_node qup2_core_master = {
+ .name = "qup2_core_master",
+ .id = X1E80100_MASTER_QUP_CORE_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_QUP_CORE_2 },
+};
+
+static struct qcom_icc_node qsm_cfg = {
+ .name = "qsm_cfg",
+ .id = X1E80100_MASTER_CNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 47,
+ .links = { X1E80100_SLAVE_AHB2PHY_SOUTH, X1E80100_SLAVE_AHB2PHY_NORTH,
+ X1E80100_SLAVE_AHB2PHY_2, X1E80100_SLAVE_AV1_ENC_CFG,
+ X1E80100_SLAVE_CAMERA_CFG, X1E80100_SLAVE_CLK_CTL,
+ X1E80100_SLAVE_CRYPTO_0_CFG, X1E80100_SLAVE_DISPLAY_CFG,
+ X1E80100_SLAVE_GFX3D_CFG, X1E80100_SLAVE_IMEM_CFG,
+ X1E80100_SLAVE_IPC_ROUTER_CFG, X1E80100_SLAVE_PCIE_0_CFG,
+ X1E80100_SLAVE_PCIE_1_CFG, X1E80100_SLAVE_PCIE_2_CFG,
+ X1E80100_SLAVE_PCIE_3_CFG, X1E80100_SLAVE_PCIE_4_CFG,
+ X1E80100_SLAVE_PCIE_5_CFG, X1E80100_SLAVE_PCIE_6A_CFG,
+ X1E80100_SLAVE_PCIE_6B_CFG, X1E80100_SLAVE_PCIE_RSC_CFG,
+ X1E80100_SLAVE_PDM, X1E80100_SLAVE_PRNG,
+ X1E80100_SLAVE_QDSS_CFG, X1E80100_SLAVE_QSPI_0,
+ X1E80100_SLAVE_QUP_0, X1E80100_SLAVE_QUP_1,
+ X1E80100_SLAVE_QUP_2, X1E80100_SLAVE_SDCC_2,
+ X1E80100_SLAVE_SDCC_4, X1E80100_SLAVE_SMMUV3_CFG,
+ X1E80100_SLAVE_TCSR, X1E80100_SLAVE_TLMM,
+ X1E80100_SLAVE_UFS_MEM_CFG, X1E80100_SLAVE_USB2,
+ X1E80100_SLAVE_USB3_0, X1E80100_SLAVE_USB3_1,
+ X1E80100_SLAVE_USB3_2, X1E80100_SLAVE_USB3_MP,
+ X1E80100_SLAVE_USB4_0, X1E80100_SLAVE_USB4_1,
+ X1E80100_SLAVE_USB4_2, X1E80100_SLAVE_VENUS_CFG,
+ X1E80100_SLAVE_LPASS_QTB_CFG, X1E80100_SLAVE_CNOC_MNOC_CFG,
+ X1E80100_SLAVE_NSP_QTB_CFG, X1E80100_SLAVE_QDSS_STM,
+ X1E80100_SLAVE_TCU },
+};
+
+static struct qcom_icc_node qnm_gemnoc_cnoc = {
+ .name = "qnm_gemnoc_cnoc",
+ .id = X1E80100_MASTER_GEM_NOC_CNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 6,
+ .links = { X1E80100_SLAVE_AOSS, X1E80100_SLAVE_TME_CFG,
+ X1E80100_SLAVE_APPSS, X1E80100_SLAVE_CNOC_CFG,
+ X1E80100_SLAVE_BOOT_IMEM, X1E80100_SLAVE_IMEM },
+};
+
+static struct qcom_icc_node qnm_gemnoc_pcie = {
+ .name = "qnm_gemnoc_pcie",
+ .id = X1E80100_MASTER_GEM_NOC_PCIE_SNOC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 8,
+ .links = { X1E80100_SLAVE_PCIE_0, X1E80100_SLAVE_PCIE_1,
+ X1E80100_SLAVE_PCIE_2, X1E80100_SLAVE_PCIE_3,
+ X1E80100_SLAVE_PCIE_4, X1E80100_SLAVE_PCIE_5,
+ X1E80100_SLAVE_PCIE_6A, X1E80100_SLAVE_PCIE_6B },
+};
+
+static struct qcom_icc_node alm_gpu_tcu = {
+ .name = "alm_gpu_tcu",
+ .id = X1E80100_MASTER_GPU_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { X1E80100_SLAVE_GEM_NOC_CNOC, X1E80100_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node alm_pcie_tcu = {
+ .name = "alm_pcie_tcu",
+ .id = X1E80100_MASTER_PCIE_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { X1E80100_SLAVE_GEM_NOC_CNOC, X1E80100_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node alm_sys_tcu = {
+ .name = "alm_sys_tcu",
+ .id = X1E80100_MASTER_SYS_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 2,
+ .links = { X1E80100_SLAVE_GEM_NOC_CNOC, X1E80100_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node chm_apps = {
+ .name = "chm_apps",
+ .id = X1E80100_MASTER_APPSS_PROC,
+ .channels = 6,
+ .buswidth = 32,
+ .num_links = 3,
+ .links = { X1E80100_SLAVE_GEM_NOC_CNOC, X1E80100_SLAVE_LLCC,
+ X1E80100_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qnm_gpu = {
+ .name = "qnm_gpu",
+ .id = X1E80100_MASTER_GFX3D,
+ .channels = 4,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { X1E80100_SLAVE_GEM_NOC_CNOC, X1E80100_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_lpass = {
+ .name = "qnm_lpass",
+ .id = X1E80100_MASTER_LPASS_GEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 3,
+ .links = { X1E80100_SLAVE_GEM_NOC_CNOC, X1E80100_SLAVE_LLCC,
+ X1E80100_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qnm_mnoc_hf = {
+ .name = "qnm_mnoc_hf",
+ .id = X1E80100_MASTER_MNOC_HF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { X1E80100_SLAVE_GEM_NOC_CNOC, X1E80100_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_mnoc_sf = {
+ .name = "qnm_mnoc_sf",
+ .id = X1E80100_MASTER_MNOC_SF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 2,
+ .links = { X1E80100_SLAVE_GEM_NOC_CNOC, X1E80100_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_nsp_noc = {
+ .name = "qnm_nsp_noc",
+ .id = X1E80100_MASTER_COMPUTE_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 3,
+ .links = { X1E80100_SLAVE_GEM_NOC_CNOC, X1E80100_SLAVE_LLCC,
+ X1E80100_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qnm_pcie = {
+ .name = "qnm_pcie",
+ .id = X1E80100_MASTER_ANOC_PCIE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 2,
+ .links = { X1E80100_SLAVE_GEM_NOC_CNOC, X1E80100_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_snoc_sf = {
+ .name = "qnm_snoc_sf",
+ .id = X1E80100_MASTER_SNOC_SF_MEM_NOC,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 3,
+ .links = { X1E80100_SLAVE_GEM_NOC_CNOC, X1E80100_SLAVE_LLCC,
+ X1E80100_SLAVE_MEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node xm_gic = {
+ .name = "xm_gic",
+ .id = X1E80100_MASTER_GIC2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_LLCC },
+};
+
+static struct qcom_icc_node qnm_lpiaon_noc = {
+ .name = "qnm_lpiaon_noc",
+ .id = X1E80100_MASTER_LPIAON_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_LPASS_GEM_NOC },
+};
+
+static struct qcom_icc_node qnm_lpass_lpinoc = {
+ .name = "qnm_lpass_lpinoc",
+ .id = X1E80100_MASTER_LPASS_LPINOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_LPIAON_NOC_LPASS_AG_NOC },
+};
+
+static struct qcom_icc_node qxm_lpinoc_dsp_axim = {
+ .name = "qxm_lpinoc_dsp_axim",
+ .id = X1E80100_MASTER_LPASS_PROC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_LPICX_NOC_LPIAON_NOC },
+};
+
+static struct qcom_icc_node llcc_mc = {
+ .name = "llcc_mc",
+ .id = X1E80100_MASTER_LLCC,
+ .channels = 8,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_EBI1 },
+};
+
+static struct qcom_icc_node qnm_av1_enc = {
+ .name = "qnm_av1_enc",
+ .id = X1E80100_MASTER_AV1_ENC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_camnoc_hf = {
+ .name = "qnm_camnoc_hf",
+ .id = X1E80100_MASTER_CAMNOC_HF,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_camnoc_icp = {
+ .name = "qnm_camnoc_icp",
+ .id = X1E80100_MASTER_CAMNOC_ICP,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_camnoc_sf = {
+ .name = "qnm_camnoc_sf",
+ .id = X1E80100_MASTER_CAMNOC_SF,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_eva = {
+ .name = "qnm_eva",
+ .id = X1E80100_MASTER_EVA,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_mdp = {
+ .name = "qnm_mdp",
+ .id = X1E80100_MASTER_MDP,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_video = {
+ .name = "qnm_video",
+ .id = X1E80100_MASTER_VIDEO,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_video_cv_cpu = {
+ .name = "qnm_video_cv_cpu",
+ .id = X1E80100_MASTER_VIDEO_CV_PROC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_video_v_cpu = {
+ .name = "qnm_video_v_cpu",
+ .id = X1E80100_MASTER_VIDEO_V_PROC,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qsm_mnoc_cfg = {
+ .name = "qsm_mnoc_cfg",
+ .id = X1E80100_MASTER_CNOC_MNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_SERVICE_MNOC },
+};
+
+static struct qcom_icc_node qxm_nsp = {
+ .name = "qxm_nsp",
+ .id = X1E80100_MASTER_CDSP_PROC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_CDSP_MEM_NOC },
+};
+
+static struct qcom_icc_node qnm_pcie_north_gem_noc = {
+ .name = "qnm_pcie_north_gem_noc",
+ .id = X1E80100_MASTER_PCIE_NORTH,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node qnm_pcie_south_gem_noc = {
+ .name = "qnm_pcie_south_gem_noc",
+ .id = X1E80100_MASTER_PCIE_SOUTH,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node xm_pcie_3 = {
+ .name = "xm_pcie_3",
+ .id = X1E80100_MASTER_PCIE_3,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_NORTH },
+};
+
+static struct qcom_icc_node xm_pcie_4 = {
+ .name = "xm_pcie_4",
+ .id = X1E80100_MASTER_PCIE_4,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_NORTH },
+};
+
+static struct qcom_icc_node xm_pcie_5 = {
+ .name = "xm_pcie_5",
+ .id = X1E80100_MASTER_PCIE_5,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_NORTH },
+};
+
+static struct qcom_icc_node xm_pcie_0 = {
+ .name = "xm_pcie_0",
+ .id = X1E80100_MASTER_PCIE_0,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_SOUTH },
+};
+
+static struct qcom_icc_node xm_pcie_1 = {
+ .name = "xm_pcie_1",
+ .id = X1E80100_MASTER_PCIE_1,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_SOUTH },
+};
+
+static struct qcom_icc_node xm_pcie_2 = {
+ .name = "xm_pcie_2",
+ .id = X1E80100_MASTER_PCIE_2,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_SOUTH },
+};
+
+static struct qcom_icc_node xm_pcie_6a = {
+ .name = "xm_pcie_6a",
+ .id = X1E80100_MASTER_PCIE_6A,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_SOUTH },
+};
+
+static struct qcom_icc_node xm_pcie_6b = {
+ .name = "xm_pcie_6b",
+ .id = X1E80100_MASTER_PCIE_6B,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_SOUTH },
+};
+
+static struct qcom_icc_node qnm_aggre1_noc = {
+ .name = "qnm_aggre1_noc",
+ .id = X1E80100_MASTER_A1NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qnm_aggre2_noc = {
+ .name = "qnm_aggre2_noc",
+ .id = X1E80100_MASTER_A2NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qnm_gic = {
+ .name = "qnm_gic",
+ .id = X1E80100_MASTER_GIC1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qnm_usb_anoc = {
+ .name = "qnm_usb_anoc",
+ .id = X1E80100_MASTER_USB_NOC_SNOC,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_SNOC_GEM_NOC_SF },
+};
+
+static struct qcom_icc_node qnm_aggre_usb_north_snoc = {
+ .name = "qnm_aggre_usb_north_snoc",
+ .id = X1E80100_MASTER_AGGRE_USB_NORTH,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_USB_NOC_SNOC },
+};
+
+static struct qcom_icc_node qnm_aggre_usb_south_snoc = {
+ .name = "qnm_aggre_usb_south_snoc",
+ .id = X1E80100_MASTER_AGGRE_USB_SOUTH,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_USB_NOC_SNOC },
+};
+
+static struct qcom_icc_node xm_usb2_0 = {
+ .name = "xm_usb2_0",
+ .id = X1E80100_MASTER_USB2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_AGGRE_USB_NORTH },
+};
+
+static struct qcom_icc_node xm_usb3_mp = {
+ .name = "xm_usb3_mp",
+ .id = X1E80100_MASTER_USB3_MP,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_AGGRE_USB_NORTH },
+};
+
+static struct qcom_icc_node xm_usb3_0 = {
+ .name = "xm_usb3_0",
+ .id = X1E80100_MASTER_USB3_0,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_AGGRE_USB_SOUTH },
+};
+
+static struct qcom_icc_node xm_usb3_1 = {
+ .name = "xm_usb3_1",
+ .id = X1E80100_MASTER_USB3_1,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_AGGRE_USB_SOUTH },
+};
+
+static struct qcom_icc_node xm_usb3_2 = {
+ .name = "xm_usb3_2",
+ .id = X1E80100_MASTER_USB3_2,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_AGGRE_USB_SOUTH },
+};
+
+static struct qcom_icc_node xm_usb4_0 = {
+ .name = "xm_usb4_0",
+ .id = X1E80100_MASTER_USB4_0,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_AGGRE_USB_SOUTH },
+};
+
+static struct qcom_icc_node xm_usb4_1 = {
+ .name = "xm_usb4_1",
+ .id = X1E80100_MASTER_USB4_1,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_AGGRE_USB_SOUTH },
+};
+
+static struct qcom_icc_node xm_usb4_2 = {
+ .name = "xm_usb4_2",
+ .id = X1E80100_MASTER_USB4_2,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_AGGRE_USB_SOUTH },
+};
+
+static struct qcom_icc_node qnm_mnoc_hf_disp = {
+ .name = "qnm_mnoc_hf_disp",
+ .id = X1E80100_MASTER_MNOC_HF_MEM_NOC_DISP,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_LLCC_DISP },
+};
+
+static struct qcom_icc_node qnm_pcie_disp = {
+ .name = "qnm_pcie_disp",
+ .id = X1E80100_MASTER_ANOC_PCIE_GEM_NOC_DISP,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_LLCC_DISP },
+};
+
+static struct qcom_icc_node llcc_mc_disp = {
+ .name = "llcc_mc_disp",
+ .id = X1E80100_MASTER_LLCC_DISP,
+ .channels = 8,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_EBI1_DISP },
+};
+
+static struct qcom_icc_node qnm_mdp_disp = {
+ .name = "qnm_mdp_disp",
+ .id = X1E80100_MASTER_MDP_DISP,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_MNOC_HF_MEM_NOC_DISP },
+};
+
+static struct qcom_icc_node qnm_pcie_pcie = {
+ .name = "qnm_pcie_pcie",
+ .id = X1E80100_MASTER_ANOC_PCIE_GEM_NOC_PCIE,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_LLCC_PCIE },
+};
+
+static struct qcom_icc_node llcc_mc_pcie = {
+ .name = "llcc_mc_pcie",
+ .id = X1E80100_MASTER_LLCC_PCIE,
+ .channels = 8,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_EBI1_PCIE },
+};
+
+static struct qcom_icc_node qnm_pcie_north_gem_noc_pcie = {
+ .name = "qnm_pcie_north_gem_noc_pcie",
+ .id = X1E80100_MASTER_PCIE_NORTH_PCIE,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_ANOC_PCIE_GEM_NOC_PCIE },
+};
+
+static struct qcom_icc_node qnm_pcie_south_gem_noc_pcie = {
+ .name = "qnm_pcie_south_gem_noc_pcie",
+ .id = X1E80100_MASTER_PCIE_SOUTH_PCIE,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_ANOC_PCIE_GEM_NOC_PCIE },
+};
+
+static struct qcom_icc_node xm_pcie_3_pcie = {
+ .name = "xm_pcie_3_pcie",
+ .id = X1E80100_MASTER_PCIE_3_PCIE,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_NORTH_PCIE },
+};
+
+static struct qcom_icc_node xm_pcie_4_pcie = {
+ .name = "xm_pcie_4_pcie",
+ .id = X1E80100_MASTER_PCIE_4_PCIE,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_NORTH_PCIE },
+};
+
+static struct qcom_icc_node xm_pcie_5_pcie = {
+ .name = "xm_pcie_5_pcie",
+ .id = X1E80100_MASTER_PCIE_5_PCIE,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_NORTH_PCIE },
+};
+
+static struct qcom_icc_node xm_pcie_0_pcie = {
+ .name = "xm_pcie_0_pcie",
+ .id = X1E80100_MASTER_PCIE_0_PCIE,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
+};
+
+static struct qcom_icc_node xm_pcie_1_pcie = {
+ .name = "xm_pcie_1_pcie",
+ .id = X1E80100_MASTER_PCIE_1_PCIE,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
+};
+
+static struct qcom_icc_node xm_pcie_2_pcie = {
+ .name = "xm_pcie_2_pcie",
+ .id = X1E80100_MASTER_PCIE_2_PCIE,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
+};
+
+static struct qcom_icc_node xm_pcie_6a_pcie = {
+ .name = "xm_pcie_6a_pcie",
+ .id = X1E80100_MASTER_PCIE_6A_PCIE,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
+};
+
+static struct qcom_icc_node xm_pcie_6b_pcie = {
+ .name = "xm_pcie_6b_pcie",
+ .id = X1E80100_MASTER_PCIE_6B_PCIE,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_SLAVE_PCIE_SOUTH_PCIE },
+};
+
+static struct qcom_icc_node qns_a1noc_snoc = {
+ .name = "qns_a1noc_snoc",
+ .id = X1E80100_SLAVE_A1NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_A1NOC_SNOC },
+};
+
+static struct qcom_icc_node qns_a2noc_snoc = {
+ .name = "qns_a2noc_snoc",
+ .id = X1E80100_SLAVE_A2NOC_SNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_A2NOC_SNOC },
+};
+
+static struct qcom_icc_node ddr_perf_mode_slave = {
+ .name = "ddr_perf_mode_slave",
+ .id = X1E80100_SLAVE_DDR_PERF_MODE,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qup0_core_slave = {
+ .name = "qup0_core_slave",
+ .id = X1E80100_SLAVE_QUP_CORE_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qup1_core_slave = {
+ .name = "qup1_core_slave",
+ .id = X1E80100_SLAVE_QUP_CORE_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qup2_core_slave = {
+ .name = "qup2_core_slave",
+ .id = X1E80100_SLAVE_QUP_CORE_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ahb2phy0 = {
+ .name = "qhs_ahb2phy0",
+ .id = X1E80100_SLAVE_AHB2PHY_SOUTH,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ahb2phy1 = {
+ .name = "qhs_ahb2phy1",
+ .id = X1E80100_SLAVE_AHB2PHY_NORTH,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ahb2phy2 = {
+ .name = "qhs_ahb2phy2",
+ .id = X1E80100_SLAVE_AHB2PHY_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_av1_enc_cfg = {
+ .name = "qhs_av1_enc_cfg",
+ .id = X1E80100_SLAVE_AV1_ENC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_camera_cfg = {
+ .name = "qhs_camera_cfg",
+ .id = X1E80100_SLAVE_CAMERA_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_clk_ctl = {
+ .name = "qhs_clk_ctl",
+ .id = X1E80100_SLAVE_CLK_CTL,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_crypto0_cfg = {
+ .name = "qhs_crypto0_cfg",
+ .id = X1E80100_SLAVE_CRYPTO_0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_display_cfg = {
+ .name = "qhs_display_cfg",
+ .id = X1E80100_SLAVE_DISPLAY_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_gpuss_cfg = {
+ .name = "qhs_gpuss_cfg",
+ .id = X1E80100_SLAVE_GFX3D_CFG,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_imem_cfg = {
+ .name = "qhs_imem_cfg",
+ .id = X1E80100_SLAVE_IMEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ipc_router = {
+ .name = "qhs_ipc_router",
+ .id = X1E80100_SLAVE_IPC_ROUTER_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie0_cfg = {
+ .name = "qhs_pcie0_cfg",
+ .id = X1E80100_SLAVE_PCIE_0_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie1_cfg = {
+ .name = "qhs_pcie1_cfg",
+ .id = X1E80100_SLAVE_PCIE_1_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie2_cfg = {
+ .name = "qhs_pcie2_cfg",
+ .id = X1E80100_SLAVE_PCIE_2_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie3_cfg = {
+ .name = "qhs_pcie3_cfg",
+ .id = X1E80100_SLAVE_PCIE_3_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie4_cfg = {
+ .name = "qhs_pcie4_cfg",
+ .id = X1E80100_SLAVE_PCIE_4_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie5_cfg = {
+ .name = "qhs_pcie5_cfg",
+ .id = X1E80100_SLAVE_PCIE_5_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie6a_cfg = {
+ .name = "qhs_pcie6a_cfg",
+ .id = X1E80100_SLAVE_PCIE_6A_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie6b_cfg = {
+ .name = "qhs_pcie6b_cfg",
+ .id = X1E80100_SLAVE_PCIE_6B_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pcie_rsc_cfg = {
+ .name = "qhs_pcie_rsc_cfg",
+ .id = X1E80100_SLAVE_PCIE_RSC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_pdm = {
+ .name = "qhs_pdm",
+ .id = X1E80100_SLAVE_PDM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_prng = {
+ .name = "qhs_prng",
+ .id = X1E80100_SLAVE_PRNG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qdss_cfg = {
+ .name = "qhs_qdss_cfg",
+ .id = X1E80100_SLAVE_QDSS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qspi = {
+ .name = "qhs_qspi",
+ .id = X1E80100_SLAVE_QSPI_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qup0 = {
+ .name = "qhs_qup0",
+ .id = X1E80100_SLAVE_QUP_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qup1 = {
+ .name = "qhs_qup1",
+ .id = X1E80100_SLAVE_QUP_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_qup2 = {
+ .name = "qhs_qup2",
+ .id = X1E80100_SLAVE_QUP_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_sdc2 = {
+ .name = "qhs_sdc2",
+ .id = X1E80100_SLAVE_SDCC_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_sdc4 = {
+ .name = "qhs_sdc4",
+ .id = X1E80100_SLAVE_SDCC_4,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_smmuv3_cfg = {
+ .name = "qhs_smmuv3_cfg",
+ .id = X1E80100_SLAVE_SMMUV3_CFG,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_tcsr = {
+ .name = "qhs_tcsr",
+ .id = X1E80100_SLAVE_TCSR,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_tlmm = {
+ .name = "qhs_tlmm",
+ .id = X1E80100_SLAVE_TLMM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_ufs_mem_cfg = {
+ .name = "qhs_ufs_mem_cfg",
+ .id = X1E80100_SLAVE_UFS_MEM_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb2_0_cfg = {
+ .name = "qhs_usb2_0_cfg",
+ .id = X1E80100_SLAVE_USB2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb3_0_cfg = {
+ .name = "qhs_usb3_0_cfg",
+ .id = X1E80100_SLAVE_USB3_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb3_1_cfg = {
+ .name = "qhs_usb3_1_cfg",
+ .id = X1E80100_SLAVE_USB3_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb3_2_cfg = {
+ .name = "qhs_usb3_2_cfg",
+ .id = X1E80100_SLAVE_USB3_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb3_mp_cfg = {
+ .name = "qhs_usb3_mp_cfg",
+ .id = X1E80100_SLAVE_USB3_MP,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb4_0_cfg = {
+ .name = "qhs_usb4_0_cfg",
+ .id = X1E80100_SLAVE_USB4_0,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb4_1_cfg = {
+ .name = "qhs_usb4_1_cfg",
+ .id = X1E80100_SLAVE_USB4_1,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_usb4_2_cfg = {
+ .name = "qhs_usb4_2_cfg",
+ .id = X1E80100_SLAVE_USB4_2,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_venus_cfg = {
+ .name = "qhs_venus_cfg",
+ .id = X1E80100_SLAVE_VENUS_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qss_lpass_qtb_cfg = {
+ .name = "qss_lpass_qtb_cfg",
+ .id = X1E80100_SLAVE_LPASS_QTB_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qss_mnoc_cfg = {
+ .name = "qss_mnoc_cfg",
+ .id = X1E80100_SLAVE_CNOC_MNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_CNOC_MNOC_CFG },
+};
+
+static struct qcom_icc_node qss_nsp_qtb_cfg = {
+ .name = "qss_nsp_qtb_cfg",
+ .id = X1E80100_SLAVE_NSP_QTB_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_qdss_stm = {
+ .name = "xs_qdss_stm",
+ .id = X1E80100_SLAVE_QDSS_STM,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_sys_tcu_cfg = {
+ .name = "xs_sys_tcu_cfg",
+ .id = X1E80100_SLAVE_TCU,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_aoss = {
+ .name = "qhs_aoss",
+ .id = X1E80100_SLAVE_AOSS,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qhs_tme_cfg = {
+ .name = "qhs_tme_cfg",
+ .id = X1E80100_SLAVE_TME_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_apss = {
+ .name = "qns_apss",
+ .id = X1E80100_SLAVE_APPSS,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qss_cfg = {
+ .name = "qss_cfg",
+ .id = X1E80100_SLAVE_CNOC_CFG,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_CNOC_CFG },
+};
+
+static struct qcom_icc_node qxs_boot_imem = {
+ .name = "qxs_boot_imem",
+ .id = X1E80100_SLAVE_BOOT_IMEM,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qxs_imem = {
+ .name = "qxs_imem",
+ .id = X1E80100_SLAVE_IMEM,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_0 = {
+ .name = "xs_pcie_0",
+ .id = X1E80100_SLAVE_PCIE_0,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_1 = {
+ .name = "xs_pcie_1",
+ .id = X1E80100_SLAVE_PCIE_1,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_2 = {
+ .name = "xs_pcie_2",
+ .id = X1E80100_SLAVE_PCIE_2,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_3 = {
+ .name = "xs_pcie_3",
+ .id = X1E80100_SLAVE_PCIE_3,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_4 = {
+ .name = "xs_pcie_4",
+ .id = X1E80100_SLAVE_PCIE_4,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_5 = {
+ .name = "xs_pcie_5",
+ .id = X1E80100_SLAVE_PCIE_5,
+ .channels = 1,
+ .buswidth = 8,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_6a = {
+ .name = "xs_pcie_6a",
+ .id = X1E80100_SLAVE_PCIE_6A,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node xs_pcie_6b = {
+ .name = "xs_pcie_6b",
+ .id = X1E80100_SLAVE_PCIE_6B,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_gem_noc_cnoc = {
+ .name = "qns_gem_noc_cnoc",
+ .id = X1E80100_SLAVE_GEM_NOC_CNOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_GEM_NOC_CNOC },
+};
+
+static struct qcom_icc_node qns_llcc = {
+ .name = "qns_llcc",
+ .id = X1E80100_SLAVE_LLCC,
+ .channels = 8,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_LLCC },
+};
+
+static struct qcom_icc_node qns_pcie = {
+ .name = "qns_pcie",
+ .id = X1E80100_SLAVE_MEM_NOC_PCIE_SNOC,
+ .channels = 1,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_GEM_NOC_PCIE_SNOC },
+};
+
+static struct qcom_icc_node qns_lpass_ag_noc_gemnoc = {
+ .name = "qns_lpass_ag_noc_gemnoc",
+ .id = X1E80100_SLAVE_LPASS_GEM_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_LPASS_GEM_NOC },
+};
+
+static struct qcom_icc_node qns_lpass_aggnoc = {
+ .name = "qns_lpass_aggnoc",
+ .id = X1E80100_SLAVE_LPIAON_NOC_LPASS_AG_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_LPIAON_NOC },
+};
+
+static struct qcom_icc_node qns_lpi_aon_noc = {
+ .name = "qns_lpi_aon_noc",
+ .id = X1E80100_SLAVE_LPICX_NOC_LPIAON_NOC,
+ .channels = 1,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_LPASS_LPINOC },
+};
+
+static struct qcom_icc_node ebi = {
+ .name = "ebi",
+ .id = X1E80100_SLAVE_EBI1,
+ .channels = 8,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_mem_noc_hf = {
+ .name = "qns_mem_noc_hf",
+ .id = X1E80100_SLAVE_MNOC_HF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_MNOC_HF_MEM_NOC },
+};
+
+static struct qcom_icc_node qns_mem_noc_sf = {
+ .name = "qns_mem_noc_sf",
+ .id = X1E80100_SLAVE_MNOC_SF_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_MNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node srvc_mnoc = {
+ .name = "srvc_mnoc",
+ .id = X1E80100_SLAVE_SERVICE_MNOC,
+ .channels = 1,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_nsp_gemnoc = {
+ .name = "qns_nsp_gemnoc",
+ .id = X1E80100_SLAVE_CDSP_MEM_NOC,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_COMPUTE_NOC },
+};
+
+static struct qcom_icc_node qns_pcie_mem_noc = {
+ .name = "qns_pcie_mem_noc",
+ .id = X1E80100_SLAVE_ANOC_PCIE_GEM_NOC,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_ANOC_PCIE_GEM_NOC },
+};
+
+static struct qcom_icc_node qns_pcie_north_gem_noc = {
+ .name = "qns_pcie_north_gem_noc",
+ .id = X1E80100_SLAVE_PCIE_NORTH,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_PCIE_NORTH },
+};
+
+static struct qcom_icc_node qns_pcie_south_gem_noc = {
+ .name = "qns_pcie_south_gem_noc",
+ .id = X1E80100_SLAVE_PCIE_SOUTH,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_PCIE_SOUTH },
+};
+
+static struct qcom_icc_node qns_gemnoc_sf = {
+ .name = "qns_gemnoc_sf",
+ .id = X1E80100_SLAVE_SNOC_GEM_NOC_SF,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_SNOC_SF_MEM_NOC },
+};
+
+static struct qcom_icc_node qns_aggre_usb_snoc = {
+ .name = "qns_aggre_usb_snoc",
+ .id = X1E80100_SLAVE_USB_NOC_SNOC,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_USB_NOC_SNOC },
+};
+
+static struct qcom_icc_node qns_aggre_usb_north_snoc = {
+ .name = "qns_aggre_usb_north_snoc",
+ .id = X1E80100_SLAVE_AGGRE_USB_NORTH,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_AGGRE_USB_NORTH },
+};
+
+static struct qcom_icc_node qns_aggre_usb_south_snoc = {
+ .name = "qns_aggre_usb_south_snoc",
+ .id = X1E80100_SLAVE_AGGRE_USB_SOUTH,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_AGGRE_USB_SOUTH },
+};
+
+static struct qcom_icc_node qns_llcc_disp = {
+ .name = "qns_llcc_disp",
+ .id = X1E80100_SLAVE_LLCC_DISP,
+ .channels = 8,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_LLCC_DISP },
+};
+
+static struct qcom_icc_node ebi_disp = {
+ .name = "ebi_disp",
+ .id = X1E80100_SLAVE_EBI1_DISP,
+ .channels = 8,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_mem_noc_hf_disp = {
+ .name = "qns_mem_noc_hf_disp",
+ .id = X1E80100_SLAVE_MNOC_HF_MEM_NOC_DISP,
+ .channels = 2,
+ .buswidth = 32,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_MNOC_HF_MEM_NOC_DISP },
+};
+
+static struct qcom_icc_node qns_llcc_pcie = {
+ .name = "qns_llcc_pcie",
+ .id = X1E80100_SLAVE_LLCC_PCIE,
+ .channels = 8,
+ .buswidth = 16,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_LLCC_PCIE },
+};
+
+static struct qcom_icc_node ebi_pcie = {
+ .name = "ebi_pcie",
+ .id = X1E80100_SLAVE_EBI1_PCIE,
+ .channels = 8,
+ .buswidth = 4,
+ .num_links = 0,
+};
+
+static struct qcom_icc_node qns_pcie_mem_noc_pcie = {
+ .name = "qns_pcie_mem_noc_pcie",
+ .id = X1E80100_SLAVE_ANOC_PCIE_GEM_NOC_PCIE,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_ANOC_PCIE_GEM_NOC_PCIE },
+};
+
+static struct qcom_icc_node qns_pcie_north_gem_noc_pcie = {
+ .name = "qns_pcie_north_gem_noc_pcie",
+ .id = X1E80100_SLAVE_PCIE_NORTH_PCIE,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_PCIE_NORTH_PCIE },
+};
+
+static struct qcom_icc_node qns_pcie_south_gem_noc_pcie = {
+ .name = "qns_pcie_south_gem_noc_pcie",
+ .id = X1E80100_SLAVE_PCIE_SOUTH_PCIE,
+ .channels = 1,
+ .buswidth = 64,
+ .num_links = 1,
+ .links = { X1E80100_MASTER_PCIE_SOUTH_PCIE },
+};
+
+static struct qcom_icc_bcm bcm_acv = {
+ .name = "ACV",
+ .num_nodes = 1,
+ .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_acv_perf = {
+ .name = "ACV_PERF",
+ .num_nodes = 1,
+ .nodes = { &ddr_perf_mode_slave },
+};
+
+static struct qcom_icc_bcm bcm_ce0 = {
+ .name = "CE0",
+ .num_nodes = 1,
+ .nodes = { &qxm_crypto },
+};
+
+static struct qcom_icc_bcm bcm_cn0 = {
+ .name = "CN0",
+ .keepalive = true,
+ .num_nodes = 63,
+ .nodes = { &qsm_cfg, &qhs_ahb2phy0,
+ &qhs_ahb2phy1, &qhs_ahb2phy2,
+ &qhs_av1_enc_cfg, &qhs_camera_cfg,
+ &qhs_clk_ctl, &qhs_crypto0_cfg,
+ &qhs_gpuss_cfg, &qhs_imem_cfg,
+ &qhs_ipc_router, &qhs_pcie0_cfg,
+ &qhs_pcie1_cfg, &qhs_pcie2_cfg,
+ &qhs_pcie3_cfg, &qhs_pcie4_cfg,
+ &qhs_pcie5_cfg, &qhs_pcie6a_cfg,
+ &qhs_pcie6b_cfg, &qhs_pcie_rsc_cfg,
+ &qhs_pdm, &qhs_prng,
+ &qhs_qdss_cfg, &qhs_qspi,
+ &qhs_qup0, &qhs_qup1,
+ &qhs_qup2, &qhs_sdc2,
+ &qhs_sdc4, &qhs_smmuv3_cfg,
+ &qhs_tcsr, &qhs_tlmm,
+ &qhs_ufs_mem_cfg, &qhs_usb2_0_cfg,
+ &qhs_usb3_0_cfg, &qhs_usb3_1_cfg,
+ &qhs_usb3_2_cfg, &qhs_usb3_mp_cfg,
+ &qhs_usb4_0_cfg, &qhs_usb4_1_cfg,
+ &qhs_usb4_2_cfg, &qhs_venus_cfg,
+ &qss_lpass_qtb_cfg, &qss_mnoc_cfg,
+ &qss_nsp_qtb_cfg, &xs_qdss_stm,
+ &xs_sys_tcu_cfg, &qnm_gemnoc_cnoc,
+ &qnm_gemnoc_pcie, &qhs_aoss,
+ &qhs_tme_cfg, &qns_apss,
+ &qss_cfg, &qxs_boot_imem,
+ &qxs_imem, &xs_pcie_0,
+ &xs_pcie_1, &xs_pcie_2,
+ &xs_pcie_3, &xs_pcie_4,
+ &xs_pcie_5, &xs_pcie_6a,
+ &xs_pcie_6b },
+};
+
+static struct qcom_icc_bcm bcm_cn1 = {
+ .name = "CN1",
+ .num_nodes = 1,
+ .nodes = { &qhs_display_cfg },
+};
+
+static struct qcom_icc_bcm bcm_co0 = {
+ .name = "CO0",
+ .num_nodes = 2,
+ .nodes = { &qxm_nsp, &qns_nsp_gemnoc },
+};
+
+static struct qcom_icc_bcm bcm_lp0 = {
+ .name = "LP0",
+ .num_nodes = 2,
+ .nodes = { &qnm_lpass_lpinoc, &qns_lpass_aggnoc },
+};
+
+static struct qcom_icc_bcm bcm_mc0 = {
+ .name = "MC0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &ebi },
+};
+
+static struct qcom_icc_bcm bcm_mm0 = {
+ .name = "MM0",
+ .num_nodes = 1,
+ .nodes = { &qns_mem_noc_hf },
+};
+
+static struct qcom_icc_bcm bcm_mm1 = {
+ .name = "MM1",
+ .num_nodes = 10,
+ .nodes = { &qnm_av1_enc, &qnm_camnoc_hf,
+ &qnm_camnoc_icp, &qnm_camnoc_sf,
+ &qnm_eva, &qnm_mdp,
+ &qnm_video, &qnm_video_cv_cpu,
+ &qnm_video_v_cpu, &qns_mem_noc_sf },
+};
+
+static struct qcom_icc_bcm bcm_pc0 = {
+ .name = "PC0",
+ .num_nodes = 1,
+ .nodes = { &qns_pcie_mem_noc },
+};
+
+static struct qcom_icc_bcm bcm_qup0 = {
+ .name = "QUP0",
+ .keepalive = true,
+ .vote_scale = 1,
+ .num_nodes = 1,
+ .nodes = { &qup0_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_qup1 = {
+ .name = "QUP1",
+ .keepalive = true,
+ .vote_scale = 1,
+ .num_nodes = 1,
+ .nodes = { &qup1_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_qup2 = {
+ .name = "QUP2",
+ .keepalive = true,
+ .vote_scale = 1,
+ .num_nodes = 1,
+ .nodes = { &qup2_core_slave },
+};
+
+static struct qcom_icc_bcm bcm_sh0 = {
+ .name = "SH0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_llcc },
+};
+
+static struct qcom_icc_bcm bcm_sh1 = {
+ .name = "SH1",
+ .num_nodes = 13,
+ .nodes = { &alm_gpu_tcu, &alm_pcie_tcu,
+ &alm_sys_tcu, &chm_apps,
+ &qnm_gpu, &qnm_lpass,
+ &qnm_mnoc_hf, &qnm_mnoc_sf,
+ &qnm_nsp_noc, &qnm_pcie,
+ &xm_gic, &qns_gem_noc_cnoc,
+ &qns_pcie },
+};
+
+static struct qcom_icc_bcm bcm_sn0 = {
+ .name = "SN0",
+ .keepalive = true,
+ .num_nodes = 1,
+ .nodes = { &qns_gemnoc_sf },
+};
+
+static struct qcom_icc_bcm bcm_sn2 = {
+ .name = "SN2",
+ .num_nodes = 1,
+ .nodes = { &qnm_aggre1_noc },
+};
+
+static struct qcom_icc_bcm bcm_sn3 = {
+ .name = "SN3",
+ .num_nodes = 1,
+ .nodes = { &qnm_aggre2_noc },
+};
+
+static struct qcom_icc_bcm bcm_sn4 = {
+ .name = "SN4",
+ .num_nodes = 1,
+ .nodes = { &qnm_usb_anoc },
+};
+
+static struct qcom_icc_bcm bcm_acv_disp = {
+ .name = "ACV",
+ .num_nodes = 1,
+ .nodes = { &ebi_disp },
+};
+
+static struct qcom_icc_bcm bcm_mc0_disp = {
+ .name = "MC0",
+ .num_nodes = 1,
+ .nodes = { &ebi_disp },
+};
+
+static struct qcom_icc_bcm bcm_mm0_disp = {
+ .name = "MM0",
+ .num_nodes = 1,
+ .nodes = { &qns_mem_noc_hf_disp },
+};
+
+static struct qcom_icc_bcm bcm_mm1_disp = {
+ .name = "MM1",
+ .num_nodes = 1,
+ .nodes = { &qnm_mdp_disp },
+};
+
+static struct qcom_icc_bcm bcm_sh0_disp = {
+ .name = "SH0",
+ .num_nodes = 1,
+ .nodes = { &qns_llcc_disp },
+};
+
+static struct qcom_icc_bcm bcm_sh1_disp = {
+ .name = "SH1",
+ .num_nodes = 2,
+ .nodes = { &qnm_mnoc_hf_disp, &qnm_pcie_disp },
+};
+
+static struct qcom_icc_bcm bcm_acv_pcie = {
+ .name = "ACV",
+ .num_nodes = 1,
+ .nodes = { &ebi_pcie },
+};
+
+static struct qcom_icc_bcm bcm_mc0_pcie = {
+ .name = "MC0",
+ .num_nodes = 1,
+ .nodes = { &ebi_pcie },
+};
+
+static struct qcom_icc_bcm bcm_pc0_pcie = {
+ .name = "PC0",
+ .num_nodes = 1,
+ .nodes = { &qns_pcie_mem_noc_pcie },
+};
+
+static struct qcom_icc_bcm bcm_sh0_pcie = {
+ .name = "SH0",
+ .num_nodes = 1,
+ .nodes = { &qns_llcc_pcie },
+};
+
+static struct qcom_icc_bcm bcm_sh1_pcie = {
+ .name = "SH1",
+ .num_nodes = 1,
+ .nodes = { &qnm_pcie_pcie },
+};
+
+static struct qcom_icc_bcm *aggre1_noc_bcms[] = {
+};
+
+static struct qcom_icc_node * const aggre1_noc_nodes[] = {
+ [MASTER_QSPI_0] = &qhm_qspi,
+ [MASTER_QUP_1] = &qhm_qup1,
+ [MASTER_SDCC_4] = &xm_sdc4,
+ [MASTER_UFS_MEM] = &xm_ufs_mem,
+ [SLAVE_A1NOC_SNOC] = &qns_a1noc_snoc,
+};
+
+static const struct qcom_icc_desc x1e80100_aggre1_noc = {
+ .nodes = aggre1_noc_nodes,
+ .num_nodes = ARRAY_SIZE(aggre1_noc_nodes),
+ .bcms = aggre1_noc_bcms,
+ .num_bcms = ARRAY_SIZE(aggre1_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const aggre2_noc_bcms[] = {
+ &bcm_ce0,
+};
+
+static struct qcom_icc_node * const aggre2_noc_nodes[] = {
+ [MASTER_QUP_0] = &qhm_qup0,
+ [MASTER_QUP_2] = &qhm_qup2,
+ [MASTER_CRYPTO] = &qxm_crypto,
+ [MASTER_SP] = &qxm_sp,
+ [MASTER_QDSS_ETR] = &xm_qdss_etr_0,
+ [MASTER_QDSS_ETR_1] = &xm_qdss_etr_1,
+ [MASTER_SDCC_2] = &xm_sdc2,
+ [SLAVE_A2NOC_SNOC] = &qns_a2noc_snoc,
+};
+
+static const struct qcom_icc_desc x1e80100_aggre2_noc = {
+ .nodes = aggre2_noc_nodes,
+ .num_nodes = ARRAY_SIZE(aggre2_noc_nodes),
+ .bcms = aggre2_noc_bcms,
+ .num_bcms = ARRAY_SIZE(aggre2_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const clk_virt_bcms[] = {
+ &bcm_acv_perf,
+ &bcm_qup0,
+ &bcm_qup1,
+ &bcm_qup2,
+};
+
+static struct qcom_icc_node * const clk_virt_nodes[] = {
+ [MASTER_DDR_PERF_MODE] = &ddr_perf_mode_master,
+ [MASTER_QUP_CORE_0] = &qup0_core_master,
+ [MASTER_QUP_CORE_1] = &qup1_core_master,
+ [MASTER_QUP_CORE_2] = &qup2_core_master,
+ [SLAVE_DDR_PERF_MODE] = &ddr_perf_mode_slave,
+ [SLAVE_QUP_CORE_0] = &qup0_core_slave,
+ [SLAVE_QUP_CORE_1] = &qup1_core_slave,
+ [SLAVE_QUP_CORE_2] = &qup2_core_slave,
+};
+
+static const struct qcom_icc_desc x1e80100_clk_virt = {
+ .nodes = clk_virt_nodes,
+ .num_nodes = ARRAY_SIZE(clk_virt_nodes),
+ .bcms = clk_virt_bcms,
+ .num_bcms = ARRAY_SIZE(clk_virt_bcms),
+};
+
+static struct qcom_icc_bcm * const cnoc_cfg_bcms[] = {
+ &bcm_cn0,
+ &bcm_cn1,
+};
+
+static struct qcom_icc_node * const cnoc_cfg_nodes[] = {
+ [MASTER_CNOC_CFG] = &qsm_cfg,
+ [SLAVE_AHB2PHY_SOUTH] = &qhs_ahb2phy0,
+ [SLAVE_AHB2PHY_NORTH] = &qhs_ahb2phy1,
+ [SLAVE_AHB2PHY_2] = &qhs_ahb2phy2,
+ [SLAVE_AV1_ENC_CFG] = &qhs_av1_enc_cfg,
+ [SLAVE_CAMERA_CFG] = &qhs_camera_cfg,
+ [SLAVE_CLK_CTL] = &qhs_clk_ctl,
+ [SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg,
+ [SLAVE_DISPLAY_CFG] = &qhs_display_cfg,
+ [SLAVE_GFX3D_CFG] = &qhs_gpuss_cfg,
+ [SLAVE_IMEM_CFG] = &qhs_imem_cfg,
+ [SLAVE_IPC_ROUTER_CFG] = &qhs_ipc_router,
+ [SLAVE_PCIE_0_CFG] = &qhs_pcie0_cfg,
+ [SLAVE_PCIE_1_CFG] = &qhs_pcie1_cfg,
+ [SLAVE_PCIE_2_CFG] = &qhs_pcie2_cfg,
+ [SLAVE_PCIE_3_CFG] = &qhs_pcie3_cfg,
+ [SLAVE_PCIE_4_CFG] = &qhs_pcie4_cfg,
+ [SLAVE_PCIE_5_CFG] = &qhs_pcie5_cfg,
+ [SLAVE_PCIE_6A_CFG] = &qhs_pcie6a_cfg,
+ [SLAVE_PCIE_6B_CFG] = &qhs_pcie6b_cfg,
+ [SLAVE_PCIE_RSC_CFG] = &qhs_pcie_rsc_cfg,
+ [SLAVE_PDM] = &qhs_pdm,
+ [SLAVE_PRNG] = &qhs_prng,
+ [SLAVE_QDSS_CFG] = &qhs_qdss_cfg,
+ [SLAVE_QSPI_0] = &qhs_qspi,
+ [SLAVE_QUP_0] = &qhs_qup0,
+ [SLAVE_QUP_1] = &qhs_qup1,
+ [SLAVE_QUP_2] = &qhs_qup2,
+ [SLAVE_SDCC_2] = &qhs_sdc2,
+ [SLAVE_SDCC_4] = &qhs_sdc4,
+ [SLAVE_SMMUV3_CFG] = &qhs_smmuv3_cfg,
+ [SLAVE_TCSR] = &qhs_tcsr,
+ [SLAVE_TLMM] = &qhs_tlmm,
+ [SLAVE_UFS_MEM_CFG] = &qhs_ufs_mem_cfg,
+ [SLAVE_USB2] = &qhs_usb2_0_cfg,
+ [SLAVE_USB3_0] = &qhs_usb3_0_cfg,
+ [SLAVE_USB3_1] = &qhs_usb3_1_cfg,
+ [SLAVE_USB3_2] = &qhs_usb3_2_cfg,
+ [SLAVE_USB3_MP] = &qhs_usb3_mp_cfg,
+ [SLAVE_USB4_0] = &qhs_usb4_0_cfg,
+ [SLAVE_USB4_1] = &qhs_usb4_1_cfg,
+ [SLAVE_USB4_2] = &qhs_usb4_2_cfg,
+ [SLAVE_VENUS_CFG] = &qhs_venus_cfg,
+ [SLAVE_LPASS_QTB_CFG] = &qss_lpass_qtb_cfg,
+ [SLAVE_CNOC_MNOC_CFG] = &qss_mnoc_cfg,
+ [SLAVE_NSP_QTB_CFG] = &qss_nsp_qtb_cfg,
+ [SLAVE_QDSS_STM] = &xs_qdss_stm,
+ [SLAVE_TCU] = &xs_sys_tcu_cfg,
+};
+
+static const struct qcom_icc_desc x1e80100_cnoc_cfg = {
+ .nodes = cnoc_cfg_nodes,
+ .num_nodes = ARRAY_SIZE(cnoc_cfg_nodes),
+ .bcms = cnoc_cfg_bcms,
+ .num_bcms = ARRAY_SIZE(cnoc_cfg_bcms),
+};
+
+static struct qcom_icc_bcm * const cnoc_main_bcms[] = {
+ &bcm_cn0,
+};
+
+static struct qcom_icc_node * const cnoc_main_nodes[] = {
+ [MASTER_GEM_NOC_CNOC] = &qnm_gemnoc_cnoc,
+ [MASTER_GEM_NOC_PCIE_SNOC] = &qnm_gemnoc_pcie,
+ [SLAVE_AOSS] = &qhs_aoss,
+ [SLAVE_TME_CFG] = &qhs_tme_cfg,
+ [SLAVE_APPSS] = &qns_apss,
+ [SLAVE_CNOC_CFG] = &qss_cfg,
+ [SLAVE_BOOT_IMEM] = &qxs_boot_imem,
+ [SLAVE_IMEM] = &qxs_imem,
+ [SLAVE_PCIE_0] = &xs_pcie_0,
+ [SLAVE_PCIE_1] = &xs_pcie_1,
+ [SLAVE_PCIE_2] = &xs_pcie_2,
+ [SLAVE_PCIE_3] = &xs_pcie_3,
+ [SLAVE_PCIE_4] = &xs_pcie_4,
+ [SLAVE_PCIE_5] = &xs_pcie_5,
+ [SLAVE_PCIE_6A] = &xs_pcie_6a,
+ [SLAVE_PCIE_6B] = &xs_pcie_6b,
+};
+
+static const struct qcom_icc_desc x1e80100_cnoc_main = {
+ .nodes = cnoc_main_nodes,
+ .num_nodes = ARRAY_SIZE(cnoc_main_nodes),
+ .bcms = cnoc_main_bcms,
+ .num_bcms = ARRAY_SIZE(cnoc_main_bcms),
+};
+
+static struct qcom_icc_bcm * const gem_noc_bcms[] = {
+ &bcm_sh0,
+ &bcm_sh1,
+ &bcm_sh0_disp,
+ &bcm_sh1_disp,
+ &bcm_sh0_pcie,
+ &bcm_sh1_pcie,
+};
+
+static struct qcom_icc_node * const gem_noc_nodes[] = {
+ [MASTER_GPU_TCU] = &alm_gpu_tcu,
+ [MASTER_PCIE_TCU] = &alm_pcie_tcu,
+ [MASTER_SYS_TCU] = &alm_sys_tcu,
+ [MASTER_APPSS_PROC] = &chm_apps,
+ [MASTER_GFX3D] = &qnm_gpu,
+ [MASTER_LPASS_GEM_NOC] = &qnm_lpass,
+ [MASTER_MNOC_HF_MEM_NOC] = &qnm_mnoc_hf,
+ [MASTER_MNOC_SF_MEM_NOC] = &qnm_mnoc_sf,
+ [MASTER_COMPUTE_NOC] = &qnm_nsp_noc,
+ [MASTER_ANOC_PCIE_GEM_NOC] = &qnm_pcie,
+ [MASTER_SNOC_SF_MEM_NOC] = &qnm_snoc_sf,
+ [MASTER_GIC2] = &xm_gic,
+ [SLAVE_GEM_NOC_CNOC] = &qns_gem_noc_cnoc,
+ [SLAVE_LLCC] = &qns_llcc,
+ [SLAVE_MEM_NOC_PCIE_SNOC] = &qns_pcie,
+ [MASTER_MNOC_HF_MEM_NOC_DISP] = &qnm_mnoc_hf_disp,
+ [MASTER_ANOC_PCIE_GEM_NOC_DISP] = &qnm_pcie_disp,
+ [SLAVE_LLCC_DISP] = &qns_llcc_disp,
+ [MASTER_ANOC_PCIE_GEM_NOC_PCIE] = &qnm_pcie_pcie,
+ [SLAVE_LLCC_PCIE] = &qns_llcc_pcie,
+};
+
+static const struct qcom_icc_desc x1e80100_gem_noc = {
+ .nodes = gem_noc_nodes,
+ .num_nodes = ARRAY_SIZE(gem_noc_nodes),
+ .bcms = gem_noc_bcms,
+ .num_bcms = ARRAY_SIZE(gem_noc_bcms),
+};
+
+static struct qcom_icc_bcm *lpass_ag_noc_bcms[] = {
+};
+
+static struct qcom_icc_node * const lpass_ag_noc_nodes[] = {
+ [MASTER_LPIAON_NOC] = &qnm_lpiaon_noc,
+ [SLAVE_LPASS_GEM_NOC] = &qns_lpass_ag_noc_gemnoc,
+};
+
+static const struct qcom_icc_desc x1e80100_lpass_ag_noc = {
+ .nodes = lpass_ag_noc_nodes,
+ .num_nodes = ARRAY_SIZE(lpass_ag_noc_nodes),
+ .bcms = lpass_ag_noc_bcms,
+ .num_bcms = ARRAY_SIZE(lpass_ag_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const lpass_lpiaon_noc_bcms[] = {
+ &bcm_lp0,
+};
+
+static struct qcom_icc_node * const lpass_lpiaon_noc_nodes[] = {
+ [MASTER_LPASS_LPINOC] = &qnm_lpass_lpinoc,
+ [SLAVE_LPIAON_NOC_LPASS_AG_NOC] = &qns_lpass_aggnoc,
+};
+
+static const struct qcom_icc_desc x1e80100_lpass_lpiaon_noc = {
+ .nodes = lpass_lpiaon_noc_nodes,
+ .num_nodes = ARRAY_SIZE(lpass_lpiaon_noc_nodes),
+ .bcms = lpass_lpiaon_noc_bcms,
+ .num_bcms = ARRAY_SIZE(lpass_lpiaon_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const lpass_lpicx_noc_bcms[] = {
+};
+
+static struct qcom_icc_node * const lpass_lpicx_noc_nodes[] = {
+ [MASTER_LPASS_PROC] = &qxm_lpinoc_dsp_axim,
+ [SLAVE_LPICX_NOC_LPIAON_NOC] = &qns_lpi_aon_noc,
+};
+
+static const struct qcom_icc_desc x1e80100_lpass_lpicx_noc = {
+ .nodes = lpass_lpicx_noc_nodes,
+ .num_nodes = ARRAY_SIZE(lpass_lpicx_noc_nodes),
+ .bcms = lpass_lpicx_noc_bcms,
+ .num_bcms = ARRAY_SIZE(lpass_lpicx_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const mc_virt_bcms[] = {
+ &bcm_acv,
+ &bcm_mc0,
+ &bcm_acv_disp,
+ &bcm_mc0_disp,
+ &bcm_acv_pcie,
+ &bcm_mc0_pcie,
+};
+
+static struct qcom_icc_node * const mc_virt_nodes[] = {
+ [MASTER_LLCC] = &llcc_mc,
+ [SLAVE_EBI1] = &ebi,
+ [MASTER_LLCC_DISP] = &llcc_mc_disp,
+ [SLAVE_EBI1_DISP] = &ebi_disp,
+ [MASTER_LLCC_PCIE] = &llcc_mc_pcie,
+ [SLAVE_EBI1_PCIE] = &ebi_pcie,
+};
+
+static const struct qcom_icc_desc x1e80100_mc_virt = {
+ .nodes = mc_virt_nodes,
+ .num_nodes = ARRAY_SIZE(mc_virt_nodes),
+ .bcms = mc_virt_bcms,
+ .num_bcms = ARRAY_SIZE(mc_virt_bcms),
+};
+
+static struct qcom_icc_bcm * const mmss_noc_bcms[] = {
+ &bcm_mm0,
+ &bcm_mm1,
+ &bcm_mm0_disp,
+ &bcm_mm1_disp,
+};
+
+static struct qcom_icc_node * const mmss_noc_nodes[] = {
+ [MASTER_AV1_ENC] = &qnm_av1_enc,
+ [MASTER_CAMNOC_HF] = &qnm_camnoc_hf,
+ [MASTER_CAMNOC_ICP] = &qnm_camnoc_icp,
+ [MASTER_CAMNOC_SF] = &qnm_camnoc_sf,
+ [MASTER_EVA] = &qnm_eva,
+ [MASTER_MDP] = &qnm_mdp,
+ [MASTER_VIDEO] = &qnm_video,
+ [MASTER_VIDEO_CV_PROC] = &qnm_video_cv_cpu,
+ [MASTER_VIDEO_V_PROC] = &qnm_video_v_cpu,
+ [MASTER_CNOC_MNOC_CFG] = &qsm_mnoc_cfg,
+ [SLAVE_MNOC_HF_MEM_NOC] = &qns_mem_noc_hf,
+ [SLAVE_MNOC_SF_MEM_NOC] = &qns_mem_noc_sf,
+ [SLAVE_SERVICE_MNOC] = &srvc_mnoc,
+ [MASTER_MDP_DISP] = &qnm_mdp_disp,
+ [SLAVE_MNOC_HF_MEM_NOC_DISP] = &qns_mem_noc_hf_disp,
+};
+
+static const struct qcom_icc_desc x1e80100_mmss_noc = {
+ .nodes = mmss_noc_nodes,
+ .num_nodes = ARRAY_SIZE(mmss_noc_nodes),
+ .bcms = mmss_noc_bcms,
+ .num_bcms = ARRAY_SIZE(mmss_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const nsp_noc_bcms[] = {
+ &bcm_co0,
+};
+
+static struct qcom_icc_node * const nsp_noc_nodes[] = {
+ [MASTER_CDSP_PROC] = &qxm_nsp,
+ [SLAVE_CDSP_MEM_NOC] = &qns_nsp_gemnoc,
+};
+
+static const struct qcom_icc_desc x1e80100_nsp_noc = {
+ .nodes = nsp_noc_nodes,
+ .num_nodes = ARRAY_SIZE(nsp_noc_nodes),
+ .bcms = nsp_noc_bcms,
+ .num_bcms = ARRAY_SIZE(nsp_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const pcie_center_anoc_bcms[] = {
+ &bcm_pc0,
+ &bcm_pc0_pcie,
+};
+
+static struct qcom_icc_node * const pcie_center_anoc_nodes[] = {
+ [MASTER_PCIE_NORTH] = &qnm_pcie_north_gem_noc,
+ [MASTER_PCIE_SOUTH] = &qnm_pcie_south_gem_noc,
+ [SLAVE_ANOC_PCIE_GEM_NOC] = &qns_pcie_mem_noc,
+ [MASTER_PCIE_NORTH_PCIE] = &qnm_pcie_north_gem_noc_pcie,
+ [MASTER_PCIE_SOUTH_PCIE] = &qnm_pcie_south_gem_noc_pcie,
+ [SLAVE_ANOC_PCIE_GEM_NOC_PCIE] = &qns_pcie_mem_noc_pcie,
+};
+
+static const struct qcom_icc_desc x1e80100_pcie_center_anoc = {
+ .nodes = pcie_center_anoc_nodes,
+ .num_nodes = ARRAY_SIZE(pcie_center_anoc_nodes),
+ .bcms = pcie_center_anoc_bcms,
+ .num_bcms = ARRAY_SIZE(pcie_center_anoc_bcms),
+};
+
+static struct qcom_icc_bcm * const pcie_north_anoc_bcms[] = {
+};
+
+static struct qcom_icc_node * const pcie_north_anoc_nodes[] = {
+ [MASTER_PCIE_3] = &xm_pcie_3,
+ [MASTER_PCIE_4] = &xm_pcie_4,
+ [MASTER_PCIE_5] = &xm_pcie_5,
+ [SLAVE_PCIE_NORTH] = &qns_pcie_north_gem_noc,
+ [MASTER_PCIE_3_PCIE] = &xm_pcie_3_pcie,
+ [MASTER_PCIE_4_PCIE] = &xm_pcie_4_pcie,
+ [MASTER_PCIE_5_PCIE] = &xm_pcie_5_pcie,
+ [SLAVE_PCIE_NORTH_PCIE] = &qns_pcie_north_gem_noc_pcie,
+};
+
+static const struct qcom_icc_desc x1e80100_pcie_north_anoc = {
+ .nodes = pcie_north_anoc_nodes,
+ .num_nodes = ARRAY_SIZE(pcie_north_anoc_nodes),
+ .bcms = pcie_north_anoc_bcms,
+ .num_bcms = ARRAY_SIZE(pcie_north_anoc_bcms),
+};
+
+static struct qcom_icc_bcm *pcie_south_anoc_bcms[] = {
+};
+
+static struct qcom_icc_node * const pcie_south_anoc_nodes[] = {
+ [MASTER_PCIE_0] = &xm_pcie_0,
+ [MASTER_PCIE_1] = &xm_pcie_1,
+ [MASTER_PCIE_2] = &xm_pcie_2,
+ [MASTER_PCIE_6A] = &xm_pcie_6a,
+ [MASTER_PCIE_6B] = &xm_pcie_6b,
+ [SLAVE_PCIE_SOUTH] = &qns_pcie_south_gem_noc,
+ [MASTER_PCIE_0_PCIE] = &xm_pcie_0_pcie,
+ [MASTER_PCIE_1_PCIE] = &xm_pcie_1_pcie,
+ [MASTER_PCIE_2_PCIE] = &xm_pcie_2_pcie,
+ [MASTER_PCIE_6A_PCIE] = &xm_pcie_6a_pcie,
+ [MASTER_PCIE_6B_PCIE] = &xm_pcie_6b_pcie,
+ [SLAVE_PCIE_SOUTH_PCIE] = &qns_pcie_south_gem_noc_pcie,
+};
+
+static const struct qcom_icc_desc x1e80100_pcie_south_anoc = {
+ .nodes = pcie_south_anoc_nodes,
+ .num_nodes = ARRAY_SIZE(pcie_south_anoc_nodes),
+ .bcms = pcie_south_anoc_bcms,
+ .num_bcms = ARRAY_SIZE(pcie_south_anoc_bcms),
+};
+
+static struct qcom_icc_bcm *system_noc_bcms[] = {
+ &bcm_sn0,
+ &bcm_sn2,
+ &bcm_sn3,
+ &bcm_sn4,
+};
+
+static struct qcom_icc_node * const system_noc_nodes[] = {
+ [MASTER_A1NOC_SNOC] = &qnm_aggre1_noc,
+ [MASTER_A2NOC_SNOC] = &qnm_aggre2_noc,
+ [MASTER_GIC1] = &qnm_gic,
+ [MASTER_USB_NOC_SNOC] = &qnm_usb_anoc,
+ [SLAVE_SNOC_GEM_NOC_SF] = &qns_gemnoc_sf,
+};
+
+static const struct qcom_icc_desc x1e80100_system_noc = {
+ .nodes = system_noc_nodes,
+ .num_nodes = ARRAY_SIZE(system_noc_nodes),
+ .bcms = system_noc_bcms,
+ .num_bcms = ARRAY_SIZE(system_noc_bcms),
+};
+
+static struct qcom_icc_bcm * const usb_center_anoc_bcms[] = {
+};
+
+static struct qcom_icc_node * const usb_center_anoc_nodes[] = {
+ [MASTER_AGGRE_USB_NORTH] = &qnm_aggre_usb_north_snoc,
+ [MASTER_AGGRE_USB_SOUTH] = &qnm_aggre_usb_south_snoc,
+ [SLAVE_USB_NOC_SNOC] = &qns_aggre_usb_snoc,
+};
+
+static const struct qcom_icc_desc x1e80100_usb_center_anoc = {
+ .nodes = usb_center_anoc_nodes,
+ .num_nodes = ARRAY_SIZE(usb_center_anoc_nodes),
+ .bcms = usb_center_anoc_bcms,
+ .num_bcms = ARRAY_SIZE(usb_center_anoc_bcms),
+};
+
+static struct qcom_icc_bcm *usb_north_anoc_bcms[] = {
+};
+
+static struct qcom_icc_node * const usb_north_anoc_nodes[] = {
+ [MASTER_USB2] = &xm_usb2_0,
+ [MASTER_USB3_MP] = &xm_usb3_mp,
+ [SLAVE_AGGRE_USB_NORTH] = &qns_aggre_usb_north_snoc,
+};
+
+static const struct qcom_icc_desc x1e80100_usb_north_anoc = {
+ .nodes = usb_north_anoc_nodes,
+ .num_nodes = ARRAY_SIZE(usb_north_anoc_nodes),
+ .bcms = usb_north_anoc_bcms,
+ .num_bcms = ARRAY_SIZE(usb_north_anoc_bcms),
+};
+
+static struct qcom_icc_bcm *usb_south_anoc_bcms[] = {
+};
+
+static struct qcom_icc_node * const usb_south_anoc_nodes[] = {
+ [MASTER_USB3_0] = &xm_usb3_0,
+ [MASTER_USB3_1] = &xm_usb3_1,
+ [MASTER_USB3_2] = &xm_usb3_2,
+ [MASTER_USB4_0] = &xm_usb4_0,
+ [MASTER_USB4_1] = &xm_usb4_1,
+ [MASTER_USB4_2] = &xm_usb4_2,
+ [SLAVE_AGGRE_USB_SOUTH] = &qns_aggre_usb_south_snoc,
+};
+
+static const struct qcom_icc_desc x1e80100_usb_south_anoc = {
+ .nodes = usb_south_anoc_nodes,
+ .num_nodes = ARRAY_SIZE(usb_south_anoc_nodes),
+ .bcms = usb_south_anoc_bcms,
+ .num_bcms = ARRAY_SIZE(usb_south_anoc_bcms),
+};
+
+static const struct of_device_id qnoc_of_match[] = {
+ { .compatible = "qcom,x1e80100-aggre1-noc", .data = &x1e80100_aggre1_noc},
+ { .compatible = "qcom,x1e80100-aggre2-noc", .data = &x1e80100_aggre2_noc},
+ { .compatible = "qcom,x1e80100-clk-virt", .data = &x1e80100_clk_virt},
+ { .compatible = "qcom,x1e80100-cnoc-cfg", .data = &x1e80100_cnoc_cfg},
+ { .compatible = "qcom,x1e80100-cnoc-main", .data = &x1e80100_cnoc_main},
+ { .compatible = "qcom,x1e80100-gem-noc", .data = &x1e80100_gem_noc},
+ { .compatible = "qcom,x1e80100-lpass-ag-noc", .data = &x1e80100_lpass_ag_noc},
+ { .compatible = "qcom,x1e80100-lpass-lpiaon-noc", .data = &x1e80100_lpass_lpiaon_noc},
+ { .compatible = "qcom,x1e80100-lpass-lpicx-noc", .data = &x1e80100_lpass_lpicx_noc},
+ { .compatible = "qcom,x1e80100-mc-virt", .data = &x1e80100_mc_virt},
+ { .compatible = "qcom,x1e80100-mmss-noc", .data = &x1e80100_mmss_noc},
+ { .compatible = "qcom,x1e80100-nsp-noc", .data = &x1e80100_nsp_noc},
+ { .compatible = "qcom,x1e80100-pcie-center-anoc", .data = &x1e80100_pcie_center_anoc},
+ { .compatible = "qcom,x1e80100-pcie-north-anoc", .data = &x1e80100_pcie_north_anoc},
+ { .compatible = "qcom,x1e80100-pcie-south-anoc", .data = &x1e80100_pcie_south_anoc},
+ { .compatible = "qcom,x1e80100-system-noc", .data = &x1e80100_system_noc},
+ { .compatible = "qcom,x1e80100-usb-center-anoc", .data = &x1e80100_usb_center_anoc},
+ { .compatible = "qcom,x1e80100-usb-north-anoc", .data = &x1e80100_usb_north_anoc},
+ { .compatible = "qcom,x1e80100-usb-south-anoc", .data = &x1e80100_usb_south_anoc},
+ { }
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+ .probe = qcom_icc_rpmh_probe,
+ .remove_new = qcom_icc_rpmh_remove,
+ .driver = {
+ .name = "qnoc-x1e80100",
+ .of_match_table = qnoc_of_match,
+ .sync_state = icc_sync_state,
+ },
+};
+
+static int __init qnoc_driver_init(void)
+{
+ return platform_driver_register(&qnoc_driver);
+}
+core_initcall(qnoc_driver_init);
+
+static void __exit qnoc_driver_exit(void)
+{
+ platform_driver_unregister(&qnoc_driver);
+}
+module_exit(qnoc_driver_exit);
+
+MODULE_DESCRIPTION("x1e80100 NoC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/interconnect/qcom/x1e80100.h b/drivers/interconnect/qcom/x1e80100.h
new file mode 100644
index 000000000000..2e14264f4c2b
--- /dev/null
+++ b/drivers/interconnect/qcom/x1e80100.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * X1E80100 interconnect IDs
+ *
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#ifndef __DRIVERS_INTERCONNECT_QCOM_X1E80100_H
+#define __DRIVERS_INTERCONNECT_QCOM_X1E80100_H
+
+#define X1E80100_MASTER_A1NOC_SNOC 0
+#define X1E80100_MASTER_A2NOC_SNOC 1
+#define X1E80100_MASTER_ANOC_PCIE_GEM_NOC 2
+#define X1E80100_MASTER_ANOC_PCIE_GEM_NOC_DISP 3
+#define X1E80100_MASTER_APPSS_PROC 4
+#define X1E80100_MASTER_CAMNOC_HF 5
+#define X1E80100_MASTER_CAMNOC_ICP 6
+#define X1E80100_MASTER_CAMNOC_SF 7
+#define X1E80100_MASTER_CDSP_PROC 8
+#define X1E80100_MASTER_CNOC_CFG 9
+#define X1E80100_MASTER_CNOC_MNOC_CFG 10
+#define X1E80100_MASTER_COMPUTE_NOC 11
+#define X1E80100_MASTER_CRYPTO 12
+#define X1E80100_MASTER_GEM_NOC_CNOC 13
+#define X1E80100_MASTER_GEM_NOC_PCIE_SNOC 14
+#define X1E80100_MASTER_GFX3D 15
+#define X1E80100_MASTER_GPU_TCU 16
+#define X1E80100_MASTER_IPA 17
+#define X1E80100_MASTER_LLCC 18
+#define X1E80100_MASTER_LLCC_DISP 19
+#define X1E80100_MASTER_LPASS_GEM_NOC 20
+#define X1E80100_MASTER_LPASS_LPINOC 21
+#define X1E80100_MASTER_LPASS_PROC 22
+#define X1E80100_MASTER_LPIAON_NOC 23
+#define X1E80100_MASTER_MDP 24
+#define X1E80100_MASTER_MDP_DISP 25
+#define X1E80100_MASTER_MNOC_HF_MEM_NOC 26
+#define X1E80100_MASTER_MNOC_HF_MEM_NOC_DISP 27
+#define X1E80100_MASTER_MNOC_SF_MEM_NOC 28
+#define X1E80100_MASTER_PCIE_0 29
+#define X1E80100_MASTER_PCIE_1 30
+#define X1E80100_MASTER_QDSS_ETR 31
+#define X1E80100_MASTER_QDSS_ETR_1 32
+#define X1E80100_MASTER_QSPI_0 33
+#define X1E80100_MASTER_QUP_0 34
+#define X1E80100_MASTER_QUP_1 35
+#define X1E80100_MASTER_QUP_2 36
+#define X1E80100_MASTER_QUP_CORE_0 37
+#define X1E80100_MASTER_QUP_CORE_1 38
+#define X1E80100_MASTER_SDCC_2 39
+#define X1E80100_MASTER_SDCC_4 40
+#define X1E80100_MASTER_SNOC_SF_MEM_NOC 41
+#define X1E80100_MASTER_SP 42
+#define X1E80100_MASTER_SYS_TCU 43
+#define X1E80100_MASTER_UFS_MEM 44
+#define X1E80100_MASTER_USB3_0 45
+#define X1E80100_MASTER_VIDEO 46
+#define X1E80100_MASTER_VIDEO_CV_PROC 47
+#define X1E80100_MASTER_VIDEO_V_PROC 48
+#define X1E80100_SLAVE_A1NOC_SNOC 49
+#define X1E80100_SLAVE_A2NOC_SNOC 50
+#define X1E80100_SLAVE_AHB2PHY_NORTH 51
+#define X1E80100_SLAVE_AHB2PHY_SOUTH 52
+#define X1E80100_SLAVE_ANOC_PCIE_GEM_NOC 53
+#define X1E80100_SLAVE_AOSS 54
+#define X1E80100_SLAVE_APPSS 55
+#define X1E80100_SLAVE_BOOT_IMEM 56
+#define X1E80100_SLAVE_CAMERA_CFG 57
+#define X1E80100_SLAVE_CDSP_MEM_NOC 58
+#define X1E80100_SLAVE_CLK_CTL 59
+#define X1E80100_SLAVE_CNOC_CFG 60
+#define X1E80100_SLAVE_CNOC_MNOC_CFG 61
+#define X1E80100_SLAVE_CRYPTO_0_CFG 62
+#define X1E80100_SLAVE_DISPLAY_CFG 63
+#define X1E80100_SLAVE_EBI1 64
+#define X1E80100_SLAVE_EBI1_DISP 65
+#define X1E80100_SLAVE_GEM_NOC_CNOC 66
+#define X1E80100_SLAVE_GFX3D_CFG 67
+#define X1E80100_SLAVE_IMEM 68
+#define X1E80100_SLAVE_IMEM_CFG 69
+#define X1E80100_SLAVE_IPC_ROUTER_CFG 70
+#define X1E80100_SLAVE_LLCC 71
+#define X1E80100_SLAVE_LLCC_DISP 72
+#define X1E80100_SLAVE_LPASS_GEM_NOC 73
+#define X1E80100_SLAVE_LPASS_QTB_CFG 74
+#define X1E80100_SLAVE_LPIAON_NOC_LPASS_AG_NOC 75
+#define X1E80100_SLAVE_LPICX_NOC_LPIAON_NOC 76
+#define X1E80100_SLAVE_MEM_NOC_PCIE_SNOC 77
+#define X1E80100_SLAVE_MNOC_HF_MEM_NOC 78
+#define X1E80100_SLAVE_MNOC_HF_MEM_NOC_DISP 79
+#define X1E80100_SLAVE_MNOC_SF_MEM_NOC 80
+#define X1E80100_SLAVE_NSP_QTB_CFG 81
+#define X1E80100_SLAVE_PCIE_0 82
+#define X1E80100_SLAVE_PCIE_0_CFG 83
+#define X1E80100_SLAVE_PCIE_1 84
+#define X1E80100_SLAVE_PCIE_1_CFG 85
+#define X1E80100_SLAVE_PDM 86
+#define X1E80100_SLAVE_PRNG 87
+#define X1E80100_SLAVE_QDSS_CFG 88
+#define X1E80100_SLAVE_QDSS_STM 89
+#define X1E80100_SLAVE_QSPI_0 90
+#define X1E80100_SLAVE_QUP_1 91
+#define X1E80100_SLAVE_QUP_2 92
+#define X1E80100_SLAVE_QUP_CORE_0 93
+#define X1E80100_SLAVE_QUP_CORE_1 94
+#define X1E80100_SLAVE_QUP_CORE_2 95
+#define X1E80100_SLAVE_SDCC_2 96
+#define X1E80100_SLAVE_SDCC_4 97
+#define X1E80100_SLAVE_SERVICE_MNOC 98
+#define X1E80100_SLAVE_SNOC_GEM_NOC_SF 99
+#define X1E80100_SLAVE_TCSR 100
+#define X1E80100_SLAVE_TCU 101
+#define X1E80100_SLAVE_TLMM 102
+#define X1E80100_SLAVE_TME_CFG 103
+#define X1E80100_SLAVE_UFS_MEM_CFG 104
+#define X1E80100_SLAVE_USB3_0 105
+#define X1E80100_SLAVE_VENUS_CFG 106
+#define X1E80100_MASTER_DDR_PERF_MODE 107
+#define X1E80100_MASTER_QUP_CORE_2 108
+#define X1E80100_MASTER_PCIE_TCU 109
+#define X1E80100_MASTER_GIC2 110
+#define X1E80100_MASTER_AV1_ENC 111
+#define X1E80100_MASTER_EVA 112
+#define X1E80100_MASTER_PCIE_NORTH 113
+#define X1E80100_MASTER_PCIE_SOUTH 114
+#define X1E80100_MASTER_PCIE_3 115
+#define X1E80100_MASTER_PCIE_4 116
+#define X1E80100_MASTER_PCIE_5 117
+#define X1E80100_MASTER_PCIE_2 118
+#define X1E80100_MASTER_PCIE_6A 119
+#define X1E80100_MASTER_PCIE_6B 120
+#define X1E80100_MASTER_GIC1 121
+#define X1E80100_MASTER_USB_NOC_SNOC 122
+#define X1E80100_MASTER_AGGRE_USB_NORTH 123
+#define X1E80100_MASTER_AGGRE_USB_SOUTH 124
+#define X1E80100_MASTER_USB2 125
+#define X1E80100_MASTER_USB3_MP 126
+#define X1E80100_MASTER_USB3_1 127
+#define X1E80100_MASTER_USB3_2 128
+#define X1E80100_MASTER_USB4_0 129
+#define X1E80100_MASTER_USB4_1 130
+#define X1E80100_MASTER_USB4_2 131
+#define X1E80100_MASTER_ANOC_PCIE_GEM_NOC_PCIE 132
+#define X1E80100_MASTER_LLCC_PCIE 133
+#define X1E80100_MASTER_PCIE_NORTH_PCIE 134
+#define X1E80100_MASTER_PCIE_SOUTH_PCIE 135
+#define X1E80100_MASTER_PCIE_3_PCIE 136
+#define X1E80100_MASTER_PCIE_4_PCIE 137
+#define X1E80100_MASTER_PCIE_5_PCIE 138
+#define X1E80100_MASTER_PCIE_0_PCIE 139
+#define X1E80100_MASTER_PCIE_1_PCIE 140
+#define X1E80100_MASTER_PCIE_2_PCIE 141
+#define X1E80100_MASTER_PCIE_6A_PCIE 142
+#define X1E80100_MASTER_PCIE_6B_PCIE 143
+#define X1E80100_SLAVE_AHB2PHY_2 144
+#define X1E80100_SLAVE_AV1_ENC_CFG 145
+#define X1E80100_SLAVE_PCIE_2_CFG 146
+#define X1E80100_SLAVE_PCIE_3_CFG 147
+#define X1E80100_SLAVE_PCIE_4_CFG 148
+#define X1E80100_SLAVE_PCIE_5_CFG 149
+#define X1E80100_SLAVE_PCIE_6A_CFG 150
+#define X1E80100_SLAVE_PCIE_6B_CFG 151
+#define X1E80100_SLAVE_PCIE_RSC_CFG 152
+#define X1E80100_SLAVE_QUP_0 153
+#define X1E80100_SLAVE_SMMUV3_CFG 154
+#define X1E80100_SLAVE_USB2 155
+#define X1E80100_SLAVE_USB3_1 156
+#define X1E80100_SLAVE_USB3_2 157
+#define X1E80100_SLAVE_USB3_MP 158
+#define X1E80100_SLAVE_USB4_0 159
+#define X1E80100_SLAVE_USB4_1 160
+#define X1E80100_SLAVE_USB4_2 161
+#define X1E80100_SLAVE_PCIE_2 162
+#define X1E80100_SLAVE_PCIE_3 163
+#define X1E80100_SLAVE_PCIE_4 164
+#define X1E80100_SLAVE_PCIE_5 165
+#define X1E80100_SLAVE_PCIE_6A 166
+#define X1E80100_SLAVE_PCIE_6B 167
+#define X1E80100_SLAVE_DDR_PERF_MODE 168
+#define X1E80100_SLAVE_PCIE_NORTH 169
+#define X1E80100_SLAVE_PCIE_SOUTH 170
+#define X1E80100_SLAVE_USB_NOC_SNOC 171
+#define X1E80100_SLAVE_AGGRE_USB_NORTH 172
+#define X1E80100_SLAVE_AGGRE_USB_SOUTH 173
+#define X1E80100_SLAVE_LLCC_PCIE 174
+#define X1E80100_SLAVE_EBI1_PCIE 175
+#define X1E80100_SLAVE_ANOC_PCIE_GEM_NOC_PCIE 176
+#define X1E80100_SLAVE_PCIE_NORTH_PCIE 177
+#define X1E80100_SLAVE_PCIE_SOUTH_PCIE 178
+
+#endif
diff --git a/drivers/interconnect/samsung/exynos.c b/drivers/interconnect/samsung/exynos.c
index ebf09bbf725b..1ba14cb45d5a 100644
--- a/drivers/interconnect/samsung/exynos.c
+++ b/drivers/interconnect/samsung/exynos.c
@@ -93,14 +93,12 @@ static struct icc_node *exynos_generic_icc_xlate(struct of_phandle_args *spec,
return priv->node;
}
-static int exynos_generic_icc_remove(struct platform_device *pdev)
+static void exynos_generic_icc_remove(struct platform_device *pdev)
{
struct exynos_icc_priv *priv = platform_get_drvdata(pdev);
icc_provider_deregister(&priv->provider);
icc_nodes_remove(&priv->provider);
-
- return 0;
}
static int exynos_generic_icc_probe(struct platform_device *pdev)
@@ -182,7 +180,7 @@ static struct platform_driver exynos_generic_icc_driver = {
.sync_state = icc_sync_state,
},
.probe = exynos_generic_icc_probe,
- .remove = exynos_generic_icc_remove,
+ .remove_new = exynos_generic_icc_remove,
};
module_platform_driver(exynos_generic_icc_driver);
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 7673bb82945b..9a29d742617e 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -160,6 +160,7 @@ config IOMMU_DMA
# Shared Virtual Addressing
config IOMMU_SVA
+ select IOMMU_MM_DATA
bool
config FSL_PAMU
diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
index 86be1edd50ee..8b3601f285fd 100644
--- a/drivers/iommu/amd/amd_iommu.h
+++ b/drivers/iommu/amd/amd_iommu.h
@@ -53,10 +53,16 @@ int amd_iommu_pdev_enable_cap_pri(struct pci_dev *pdev);
void amd_iommu_pdev_disable_cap_pri(struct pci_dev *pdev);
int amd_iommu_flush_page(struct iommu_domain *dom, u32 pasid, u64 address);
+/*
+ * This function flushes all internal caches of
+ * the IOMMU used by this driver.
+ */
+void amd_iommu_flush_all_caches(struct amd_iommu *iommu);
void amd_iommu_update_and_flush_device_table(struct protection_domain *domain);
void amd_iommu_domain_update(struct protection_domain *domain);
void amd_iommu_domain_flush_complete(struct protection_domain *domain);
-void amd_iommu_domain_flush_tlb_pde(struct protection_domain *domain);
+void amd_iommu_domain_flush_pages(struct protection_domain *domain,
+ u64 address, size_t size);
int amd_iommu_flush_tlb(struct iommu_domain *dom, u32 pasid);
int amd_iommu_domain_set_gcr3(struct iommu_domain *dom, u32 pasid,
unsigned long cr3);
diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
index 90b7d7950a9e..809d74faa1a5 100644
--- a/drivers/iommu/amd/amd_iommu_types.h
+++ b/drivers/iommu/amd/amd_iommu_types.h
@@ -902,12 +902,6 @@ extern int amd_iommu_max_glx_val;
extern u64 amd_iommu_efr;
extern u64 amd_iommu_efr2;
-/*
- * This function flushes all internal caches of
- * the IOMMU used by this driver.
- */
-void iommu_flush_all_caches(struct amd_iommu *iommu);
-
static inline int get_ioapic_devid(int id)
{
struct devid_map *entry;
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 64bcf3df37ee..c83bd0c2a1c9 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -2223,7 +2223,7 @@ static int __init amd_iommu_init_pci(void)
init_device_table_dma(pci_seg);
for_each_iommu(iommu)
- iommu_flush_all_caches(iommu);
+ amd_iommu_flush_all_caches(iommu);
print_iommu_info();
@@ -2773,7 +2773,7 @@ static void early_enable_iommu(struct amd_iommu *iommu)
iommu_enable_xt(iommu);
iommu_enable_irtcachedis(iommu);
iommu_enable(iommu);
- iommu_flush_all_caches(iommu);
+ amd_iommu_flush_all_caches(iommu);
}
/*
@@ -2829,7 +2829,7 @@ static void early_enable_iommus(void)
iommu_enable_xt(iommu);
iommu_enable_irtcachedis(iommu);
iommu_set_device_table(iommu);
- iommu_flush_all_caches(iommu);
+ amd_iommu_flush_all_caches(iommu);
}
}
}
@@ -3293,7 +3293,7 @@ static int __init state_next(void)
uninit_device_table_dma(pci_seg);
for_each_iommu(iommu)
- iommu_flush_all_caches(iommu);
+ amd_iommu_flush_all_caches(iommu);
}
}
return ret;
diff --git a/drivers/iommu/amd/io_pgtable.c b/drivers/iommu/amd/io_pgtable.c
index 6c0621f6f572..2a0d1e97e52f 100644
--- a/drivers/iommu/amd/io_pgtable.c
+++ b/drivers/iommu/amd/io_pgtable.c
@@ -369,6 +369,8 @@ static int iommu_v1_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
bool updated = false;
u64 __pte, *pte;
int ret, i, count;
+ size_t size = pgcount << __ffs(pgsize);
+ unsigned long o_iova = iova;
BUG_ON(!IS_ALIGNED(iova, pgsize));
BUG_ON(!IS_ALIGNED(paddr, pgsize));
@@ -424,8 +426,7 @@ out:
* Updates and flushing already happened in
* increase_address_space().
*/
- amd_iommu_domain_flush_tlb_pde(dom);
- amd_iommu_domain_flush_complete(dom);
+ amd_iommu_domain_flush_pages(dom, o_iova, size);
spin_unlock_irqrestore(&dom->lock, flags);
}
diff --git a/drivers/iommu/amd/io_pgtable_v2.c b/drivers/iommu/amd/io_pgtable_v2.c
index f818a7e254d4..6d69ba60744f 100644
--- a/drivers/iommu/amd/io_pgtable_v2.c
+++ b/drivers/iommu/amd/io_pgtable_v2.c
@@ -244,7 +244,6 @@ static int iommu_v2_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
unsigned long mapped_size = 0;
unsigned long o_iova = iova;
size_t size = pgcount << __ffs(pgsize);
- int count = 0;
int ret = 0;
bool updated = false;
@@ -265,19 +264,14 @@ static int iommu_v2_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
*pte = set_pte_attr(paddr, map_size, prot);
- count++;
iova += map_size;
paddr += map_size;
mapped_size += map_size;
}
out:
- if (updated) {
- if (count > 1)
- amd_iommu_flush_tlb(&pdom->domain, 0);
- else
- amd_iommu_flush_page(&pdom->domain, 0, o_iova);
- }
+ if (updated)
+ amd_iommu_domain_flush_pages(pdom, o_iova, size);
if (mapped)
*mapped += mapped_size;
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
index b9a0523cbb0a..4283dd8191f0 100644
--- a/drivers/iommu/amd/iommu.c
+++ b/drivers/iommu/amd/iommu.c
@@ -64,7 +64,7 @@ LIST_HEAD(hpet_map);
LIST_HEAD(acpihid_map);
const struct iommu_ops amd_iommu_ops;
-const struct iommu_dirty_ops amd_dirty_ops;
+static const struct iommu_dirty_ops amd_dirty_ops;
int amd_iommu_max_glx_val = -1;
@@ -85,6 +85,11 @@ static void detach_device(struct device *dev);
*
****************************************************************************/
+static inline bool pdom_is_v2_pgtbl_mode(struct protection_domain *pdom)
+{
+ return (pdom && (pdom->flags & PD_IOMMUV2_MASK));
+}
+
static inline int get_acpihid_device_id(struct device *dev,
struct acpihid_map_entry **entry)
{
@@ -551,8 +556,6 @@ static void amd_iommu_uninit_device(struct device *dev)
if (dev_data->domain)
detach_device(dev);
- dev_iommu_priv_set(dev, NULL);
-
/*
* We keep dev_data around for unplugged devices and reuse it when the
* device is re-plugged - not doing so would introduce a ton of races.
@@ -1124,68 +1127,44 @@ static inline u64 build_inv_address(u64 address, size_t size)
}
static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
- size_t size, u16 domid, int pde)
+ size_t size, u16 domid,
+ ioasid_t pasid, bool gn)
{
u64 inv_address = build_inv_address(address, size);
memset(cmd, 0, sizeof(*cmd));
+
cmd->data[1] |= domid;
cmd->data[2] = lower_32_bits(inv_address);
cmd->data[3] = upper_32_bits(inv_address);
+ /* PDE bit - we want to flush everything, not only the PTEs */
+ cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
+ if (gn) {
+ cmd->data[0] |= pasid;
+ cmd->data[2] |= CMD_INV_IOMMU_PAGES_GN_MASK;
+ }
CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES);
- if (pde) /* PDE bit - we want to flush everything, not only the PTEs */
- cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
}
static void build_inv_iotlb_pages(struct iommu_cmd *cmd, u16 devid, int qdep,
- u64 address, size_t size)
+ u64 address, size_t size,
+ ioasid_t pasid, bool gn)
{
u64 inv_address = build_inv_address(address, size);
memset(cmd, 0, sizeof(*cmd));
+
cmd->data[0] = devid;
cmd->data[0] |= (qdep & 0xff) << 24;
cmd->data[1] = devid;
cmd->data[2] = lower_32_bits(inv_address);
cmd->data[3] = upper_32_bits(inv_address);
- CMD_SET_TYPE(cmd, CMD_INV_IOTLB_PAGES);
-}
-
-static void build_inv_iommu_pasid(struct iommu_cmd *cmd, u16 domid, u32 pasid,
- u64 address, bool size)
-{
- memset(cmd, 0, sizeof(*cmd));
-
- address &= ~(0xfffULL);
-
- cmd->data[0] = pasid;
- cmd->data[1] = domid;
- cmd->data[2] = lower_32_bits(address);
- cmd->data[3] = upper_32_bits(address);
- cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
- cmd->data[2] |= CMD_INV_IOMMU_PAGES_GN_MASK;
- if (size)
- cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
- CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES);
-}
-
-static void build_inv_iotlb_pasid(struct iommu_cmd *cmd, u16 devid, u32 pasid,
- int qdep, u64 address, bool size)
-{
- memset(cmd, 0, sizeof(*cmd));
-
- address &= ~(0xfffULL);
+ if (gn) {
+ cmd->data[0] |= ((pasid >> 8) & 0xff) << 16;
+ cmd->data[1] |= (pasid & 0xff) << 16;
+ cmd->data[2] |= CMD_INV_IOMMU_PAGES_GN_MASK;
+ }
- cmd->data[0] = devid;
- cmd->data[0] |= ((pasid >> 8) & 0xff) << 16;
- cmd->data[0] |= (qdep & 0xff) << 24;
- cmd->data[1] = devid;
- cmd->data[1] |= (pasid & 0xff) << 16;
- cmd->data[2] = lower_32_bits(address);
- cmd->data[2] |= CMD_INV_IOMMU_PAGES_GN_MASK;
- cmd->data[3] = upper_32_bits(address);
- if (size)
- cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
CMD_SET_TYPE(cmd, CMD_INV_IOTLB_PAGES);
}
@@ -1341,7 +1320,7 @@ static void amd_iommu_flush_tlb_all(struct amd_iommu *iommu)
for (dom_id = 0; dom_id <= last_bdf; ++dom_id) {
struct iommu_cmd cmd;
build_inv_iommu_pages(&cmd, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
- dom_id, 1);
+ dom_id, IOMMU_NO_PASID, false);
iommu_queue_command(iommu, &cmd);
}
@@ -1353,7 +1332,7 @@ static void amd_iommu_flush_tlb_domid(struct amd_iommu *iommu, u32 dom_id)
struct iommu_cmd cmd;
build_inv_iommu_pages(&cmd, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
- dom_id, 1);
+ dom_id, IOMMU_NO_PASID, false);
iommu_queue_command(iommu, &cmd);
iommu_completion_wait(iommu);
@@ -1392,7 +1371,7 @@ static void amd_iommu_flush_irt_all(struct amd_iommu *iommu)
iommu_completion_wait(iommu);
}
-void iommu_flush_all_caches(struct amd_iommu *iommu)
+void amd_iommu_flush_all_caches(struct amd_iommu *iommu)
{
if (check_feature(FEATURE_IA)) {
amd_iommu_flush_all(iommu);
@@ -1406,8 +1385,8 @@ void iommu_flush_all_caches(struct amd_iommu *iommu)
/*
* Command send function for flushing on-device TLB
*/
-static int device_flush_iotlb(struct iommu_dev_data *dev_data,
- u64 address, size_t size)
+static int device_flush_iotlb(struct iommu_dev_data *dev_data, u64 address,
+ size_t size, ioasid_t pasid, bool gn)
{
struct amd_iommu *iommu;
struct iommu_cmd cmd;
@@ -1418,7 +1397,8 @@ static int device_flush_iotlb(struct iommu_dev_data *dev_data,
if (!iommu)
return -EINVAL;
- build_inv_iotlb_pages(&cmd, dev_data->devid, qdep, address, size);
+ build_inv_iotlb_pages(&cmd, dev_data->devid, qdep, address,
+ size, pasid, gn);
return iommu_queue_command(iommu, &cmd);
}
@@ -1464,8 +1444,11 @@ static int device_flush_dte(struct iommu_dev_data *dev_data)
return ret;
}
- if (dev_data->ats_enabled)
- ret = device_flush_iotlb(dev_data, 0, ~0UL);
+ if (dev_data->ats_enabled) {
+ /* Invalidate the entire contents of an IOTLB */
+ ret = device_flush_iotlb(dev_data, 0, ~0UL,
+ IOMMU_NO_PASID, false);
+ }
return ret;
}
@@ -1476,13 +1459,18 @@ static int device_flush_dte(struct iommu_dev_data *dev_data)
* page. Otherwise it flushes the whole TLB of the IOMMU.
*/
static void __domain_flush_pages(struct protection_domain *domain,
- u64 address, size_t size, int pde)
+ u64 address, size_t size)
{
struct iommu_dev_data *dev_data;
struct iommu_cmd cmd;
int ret = 0, i;
+ ioasid_t pasid = IOMMU_NO_PASID;
+ bool gn = false;
+
+ if (pdom_is_v2_pgtbl_mode(domain))
+ gn = true;
- build_inv_iommu_pages(&cmd, address, size, domain->id, pde);
+ build_inv_iommu_pages(&cmd, address, size, domain->id, pasid, gn);
for (i = 0; i < amd_iommu_get_num_iommus(); ++i) {
if (!domain->dev_iommu[i])
@@ -1500,17 +1488,21 @@ static void __domain_flush_pages(struct protection_domain *domain,
if (!dev_data->ats_enabled)
continue;
- ret |= device_flush_iotlb(dev_data, address, size);
+ ret |= device_flush_iotlb(dev_data, address, size, pasid, gn);
}
WARN_ON(ret);
}
-static void domain_flush_pages(struct protection_domain *domain,
- u64 address, size_t size, int pde)
+void amd_iommu_domain_flush_pages(struct protection_domain *domain,
+ u64 address, size_t size)
{
if (likely(!amd_iommu_np_cache)) {
- __domain_flush_pages(domain, address, size, pde);
+ __domain_flush_pages(domain, address, size);
+
+ /* Wait until IOMMU TLB and all device IOTLB flushes are complete */
+ amd_iommu_domain_flush_complete(domain);
+
return;
}
@@ -1543,16 +1535,20 @@ static void domain_flush_pages(struct protection_domain *domain,
flush_size = 1ul << min_alignment;
- __domain_flush_pages(domain, address, flush_size, pde);
+ __domain_flush_pages(domain, address, flush_size);
address += flush_size;
size -= flush_size;
}
+
+ /* Wait until IOMMU TLB and all device IOTLB flushes are complete */
+ amd_iommu_domain_flush_complete(domain);
}
/* Flush the whole IO/TLB for a given protection domain - including PDE */
-void amd_iommu_domain_flush_tlb_pde(struct protection_domain *domain)
+static void amd_iommu_domain_flush_all(struct protection_domain *domain)
{
- domain_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 1);
+ amd_iommu_domain_flush_pages(domain, 0,
+ CMD_INV_IOMMU_ALL_PAGES_ADDRESS);
}
void amd_iommu_domain_flush_complete(struct protection_domain *domain)
@@ -1579,8 +1575,7 @@ static void domain_flush_np_cache(struct protection_domain *domain,
unsigned long flags;
spin_lock_irqsave(&domain->lock, flags);
- domain_flush_pages(domain, iova, size, 1);
- amd_iommu_domain_flush_complete(domain);
+ amd_iommu_domain_flush_pages(domain, iova, size);
spin_unlock_irqrestore(&domain->lock, flags);
}
}
@@ -1858,11 +1853,8 @@ static void do_detach(struct iommu_dev_data *dev_data)
/* Flush the DTE entry */
device_flush_dte(dev_data);
- /* Flush IOTLB */
- amd_iommu_domain_flush_tlb_pde(domain);
-
- /* Wait for the flushes to finish */
- amd_iommu_domain_flush_complete(domain);
+ /* Flush IOTLB and wait for the flushes to finish */
+ amd_iommu_domain_flush_all(domain);
/* decrease reference counters - needs to happen after the flushes */
domain->dev_iommu[iommu->index] -= 1;
@@ -1896,15 +1888,6 @@ static int attach_device(struct device *dev,
do_attach(dev_data, domain);
- /*
- * We might boot into a crash-kernel here. The crashed kernel
- * left the caches in the IOMMU dirty. So we have to flush
- * here to evict all dirty stuff.
- */
- amd_iommu_domain_flush_tlb_pde(domain);
-
- amd_iommu_domain_flush_complete(domain);
-
out:
spin_unlock(&dev_data->lock);
@@ -2048,8 +2031,7 @@ void amd_iommu_domain_update(struct protection_domain *domain)
amd_iommu_update_and_flush_device_table(domain);
/* Flush domain TLB(s) and wait for completion */
- amd_iommu_domain_flush_tlb_pde(domain);
- amd_iommu_domain_flush_complete(domain);
+ amd_iommu_domain_flush_all(domain);
}
/*****************************************************************************
@@ -2482,10 +2464,9 @@ static int amd_iommu_set_dirty_tracking(struct iommu_domain *domain,
}
/* Flush IOTLB to mark IOPTE dirty on the next translation(s) */
- if (domain_flush) {
- amd_iommu_domain_flush_tlb_pde(pdomain);
- amd_iommu_domain_flush_complete(pdomain);
- }
+ if (domain_flush)
+ amd_iommu_domain_flush_all(pdomain);
+
pdomain->dirty_tracking = enable;
spin_unlock_irqrestore(&pdomain->lock, flags);
@@ -2588,8 +2569,7 @@ static void amd_iommu_flush_iotlb_all(struct iommu_domain *domain)
unsigned long flags;
spin_lock_irqsave(&dom->lock, flags);
- amd_iommu_domain_flush_tlb_pde(dom);
- amd_iommu_domain_flush_complete(dom);
+ amd_iommu_domain_flush_all(dom);
spin_unlock_irqrestore(&dom->lock, flags);
}
@@ -2600,8 +2580,8 @@ static void amd_iommu_iotlb_sync(struct iommu_domain *domain,
unsigned long flags;
spin_lock_irqsave(&dom->lock, flags);
- domain_flush_pages(dom, gather->start, gather->end - gather->start + 1, 1);
- amd_iommu_domain_flush_complete(dom);
+ amd_iommu_domain_flush_pages(dom, gather->start,
+ gather->end - gather->start + 1);
spin_unlock_irqrestore(&dom->lock, flags);
}
@@ -2635,7 +2615,7 @@ static bool amd_iommu_enforce_cache_coherency(struct iommu_domain *domain)
return true;
}
-const struct iommu_dirty_ops amd_dirty_ops = {
+static const struct iommu_dirty_ops amd_dirty_ops = {
.set_dirty_tracking = amd_iommu_set_dirty_tracking,
.read_and_clear_dirty = amd_iommu_read_and_clear_dirty,
};
@@ -2666,7 +2646,7 @@ const struct iommu_ops amd_iommu_ops = {
};
static int __flush_pasid(struct protection_domain *domain, u32 pasid,
- u64 address, bool size)
+ u64 address, size_t size)
{
struct iommu_dev_data *dev_data;
struct iommu_cmd cmd;
@@ -2675,7 +2655,7 @@ static int __flush_pasid(struct protection_domain *domain, u32 pasid,
if (!(domain->flags & PD_IOMMUV2_MASK))
return -EINVAL;
- build_inv_iommu_pasid(&cmd, domain->id, pasid, address, size);
+ build_inv_iommu_pages(&cmd, address, size, domain->id, pasid, true);
/*
* IOMMU TLB needs to be flushed before Device TLB to
@@ -2709,8 +2689,8 @@ static int __flush_pasid(struct protection_domain *domain, u32 pasid,
iommu = rlookup_amd_iommu(dev_data->dev);
if (!iommu)
continue;
- build_inv_iotlb_pasid(&cmd, dev_data->devid, pasid,
- qdep, address, size);
+ build_inv_iotlb_pages(&cmd, dev_data->devid, qdep,
+ address, size, pasid, true);
ret = iommu_queue_command(iommu, &cmd);
if (ret != 0)
@@ -2730,7 +2710,7 @@ out:
static int __amd_iommu_flush_page(struct protection_domain *domain, u32 pasid,
u64 address)
{
- return __flush_pasid(domain, pasid, address, false);
+ return __flush_pasid(domain, pasid, address, PAGE_SIZE);
}
int amd_iommu_flush_page(struct iommu_domain *dom, u32 pasid,
@@ -2749,8 +2729,7 @@ int amd_iommu_flush_page(struct iommu_domain *dom, u32 pasid,
static int __amd_iommu_flush_tlb(struct protection_domain *domain, u32 pasid)
{
- return __flush_pasid(domain, pasid, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
- true);
+ return __flush_pasid(domain, pasid, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS);
}
int amd_iommu_flush_tlb(struct iommu_domain *dom, u32 pasid)
@@ -3111,8 +3090,8 @@ out:
return index;
}
-static int modify_irte_ga(struct amd_iommu *iommu, u16 devid, int index,
- struct irte_ga *irte)
+static int __modify_irte_ga(struct amd_iommu *iommu, u16 devid, int index,
+ struct irte_ga *irte)
{
struct irq_remap_table *table;
struct irte_ga *entry;
@@ -3139,6 +3118,18 @@ static int modify_irte_ga(struct amd_iommu *iommu, u16 devid, int index,
raw_spin_unlock_irqrestore(&table->lock, flags);
+ return 0;
+}
+
+static int modify_irte_ga(struct amd_iommu *iommu, u16 devid, int index,
+ struct irte_ga *irte)
+{
+ bool ret;
+
+ ret = __modify_irte_ga(iommu, devid, index, irte);
+ if (ret)
+ return ret;
+
iommu_flush_irt_and_complete(iommu, devid);
return 0;
@@ -3822,8 +3813,8 @@ int amd_iommu_update_ga(int cpu, bool is_run, void *data)
}
entry->lo.fields_vapic.is_run = is_run;
- return modify_irte_ga(ir_data->iommu, ir_data->irq_2_irte.devid,
- ir_data->irq_2_irte.index, entry);
+ return __modify_irte_ga(ir_data->iommu, ir_data->irq_2_irte.devid,
+ ir_data->irq_2_irte.index, entry);
}
EXPORT_SYMBOL(amd_iommu_update_ga);
#endif
diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c
index ee05f4824bfa..ef3ee95706da 100644
--- a/drivers/iommu/apple-dart.c
+++ b/drivers/iommu/apple-dart.c
@@ -81,6 +81,7 @@
#define DART_T8020_TCR_BYPASS_DAPF BIT(12)
#define DART_T8020_TTBR 0x200
+#define DART_T8020_USB4_TTBR 0x400
#define DART_T8020_TTBR_VALID BIT(31)
#define DART_T8020_TTBR_ADDR_FIELD_SHIFT 0
#define DART_T8020_TTBR_SHIFT 12
@@ -368,12 +369,14 @@ apple_dart_t8020_hw_stream_command(struct apple_dart_stream_map *stream_map,
u32 command)
{
unsigned long flags;
- int ret;
+ int ret, i;
u32 command_reg;
spin_lock_irqsave(&stream_map->dart->lock, flags);
- writel(stream_map->sidmap[0], stream_map->dart->regs + DART_T8020_STREAM_SELECT);
+ for (i = 0; i < BITS_TO_U32(stream_map->dart->num_streams); i++)
+ writel(stream_map->sidmap[i],
+ stream_map->dart->regs + DART_T8020_STREAM_SELECT + 4 * i);
writel(command, stream_map->dart->regs + DART_T8020_STREAM_COMMAND);
ret = readl_poll_timeout_atomic(
@@ -740,7 +743,6 @@ static void apple_dart_release_device(struct device *dev)
{
struct apple_dart_master_cfg *cfg = dev_iommu_priv_get(dev);
- dev_iommu_priv_set(dev, NULL);
kfree(cfg);
}
@@ -908,7 +910,7 @@ static struct iommu_group *apple_dart_device_group(struct device *dev)
ret = apple_dart_merge_master_cfg(group_master_cfg, cfg);
if (ret) {
- dev_err(dev, "Failed to merge DART IOMMU grups.\n");
+ dev_err(dev, "Failed to merge DART IOMMU groups.\n");
iommu_group_put(group);
res = ERR_PTR(ret);
goto out;
@@ -1215,6 +1217,33 @@ static const struct apple_dart_hw apple_dart_hw_t8103 = {
.ttbr_shift = DART_T8020_TTBR_SHIFT,
.ttbr_count = 4,
};
+
+static const struct apple_dart_hw apple_dart_hw_t8103_usb4 = {
+ .type = DART_T8020,
+ .irq_handler = apple_dart_t8020_irq,
+ .invalidate_tlb = apple_dart_t8020_hw_invalidate_tlb,
+ .oas = 36,
+ .fmt = APPLE_DART,
+ .max_sid_count = 64,
+
+ .enable_streams = DART_T8020_STREAMS_ENABLE,
+ .lock = DART_T8020_CONFIG,
+ .lock_bit = DART_T8020_CONFIG_LOCK,
+
+ .error = DART_T8020_ERROR,
+
+ .tcr = DART_T8020_TCR,
+ .tcr_enabled = DART_T8020_TCR_TRANSLATE_ENABLE,
+ .tcr_disabled = 0,
+ .tcr_bypass = 0,
+
+ .ttbr = DART_T8020_USB4_TTBR,
+ .ttbr_valid = DART_T8020_TTBR_VALID,
+ .ttbr_addr_field_shift = DART_T8020_TTBR_ADDR_FIELD_SHIFT,
+ .ttbr_shift = DART_T8020_TTBR_SHIFT,
+ .ttbr_count = 4,
+};
+
static const struct apple_dart_hw apple_dart_hw_t6000 = {
.type = DART_T6000,
.irq_handler = apple_dart_t8020_irq,
@@ -1272,7 +1301,7 @@ static __maybe_unused int apple_dart_suspend(struct device *dev)
unsigned int sid, idx;
for (sid = 0; sid < dart->num_streams; sid++) {
- dart->save_tcr[sid] = readl_relaxed(dart->regs + DART_TCR(dart, sid));
+ dart->save_tcr[sid] = readl(dart->regs + DART_TCR(dart, sid));
for (idx = 0; idx < dart->hw->ttbr_count; idx++)
dart->save_ttbr[sid][idx] =
readl(dart->regs + DART_TTBR(dart, sid, idx));
@@ -1307,6 +1336,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(apple_dart_pm_ops, apple_dart_suspend, apple_dar
static const struct of_device_id apple_dart_of_match[] = {
{ .compatible = "apple,t8103-dart", .data = &apple_dart_hw_t8103 },
+ { .compatible = "apple,t8103-usb4-dart", .data = &apple_dart_hw_t8103_usb4 },
{ .compatible = "apple,t8110-dart", .data = &apple_dart_hw_t8110 },
{ .compatible = "apple,t6000-dart", .data = &apple_dart_hw_t6000 },
{},
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
index 353248ab18e7..05722121f00e 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c
@@ -246,7 +246,8 @@ static void arm_smmu_mm_arch_invalidate_secondary_tlbs(struct mmu_notifier *mn,
smmu_domain);
}
- arm_smmu_atc_inv_domain(smmu_domain, mm->pasid, start, size);
+ arm_smmu_atc_inv_domain(smmu_domain, mm_get_enqcmd_pasid(mm), start,
+ size);
}
static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
@@ -264,10 +265,11 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
* DMA may still be running. Keep the cd valid to avoid C_BAD_CD events,
* but disable translation.
*/
- arm_smmu_update_ctx_desc_devices(smmu_domain, mm->pasid, &quiet_cd);
+ arm_smmu_update_ctx_desc_devices(smmu_domain, mm_get_enqcmd_pasid(mm),
+ &quiet_cd);
arm_smmu_tlb_inv_asid(smmu_domain->smmu, smmu_mn->cd->asid);
- arm_smmu_atc_inv_domain(smmu_domain, mm->pasid, 0, 0);
+ arm_smmu_atc_inv_domain(smmu_domain, mm_get_enqcmd_pasid(mm), 0, 0);
smmu_mn->cleared = true;
mutex_unlock(&sva_lock);
@@ -325,10 +327,13 @@ arm_smmu_mmu_notifier_get(struct arm_smmu_domain *smmu_domain,
spin_lock_irqsave(&smmu_domain->devices_lock, flags);
list_for_each_entry(master, &smmu_domain->devices, domain_head) {
- ret = arm_smmu_write_ctx_desc(master, mm->pasid, cd);
+ ret = arm_smmu_write_ctx_desc(master, mm_get_enqcmd_pasid(mm),
+ cd);
if (ret) {
- list_for_each_entry_from_reverse(master, &smmu_domain->devices, domain_head)
- arm_smmu_write_ctx_desc(master, mm->pasid, NULL);
+ list_for_each_entry_from_reverse(
+ master, &smmu_domain->devices, domain_head)
+ arm_smmu_write_ctx_desc(
+ master, mm_get_enqcmd_pasid(mm), NULL);
break;
}
}
@@ -358,7 +363,8 @@ static void arm_smmu_mmu_notifier_put(struct arm_smmu_mmu_notifier *smmu_mn)
list_del(&smmu_mn->list);
- arm_smmu_update_ctx_desc_devices(smmu_domain, mm->pasid, NULL);
+ arm_smmu_update_ctx_desc_devices(smmu_domain, mm_get_enqcmd_pasid(mm),
+ NULL);
/*
* If we went through clear(), we've already invalidated, and no
@@ -366,7 +372,8 @@ static void arm_smmu_mmu_notifier_put(struct arm_smmu_mmu_notifier *smmu_mn)
*/
if (!smmu_mn->cleared) {
arm_smmu_tlb_inv_asid(smmu_domain->smmu, cd->asid);
- arm_smmu_atc_inv_domain(smmu_domain, mm->pasid, 0, 0);
+ arm_smmu_atc_inv_domain(smmu_domain, mm_get_enqcmd_pasid(mm), 0,
+ 0);
}
/* Frees smmu_mn */
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 7445454c2af2..0ffb1cf17e0b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1063,6 +1063,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
bool cd_live;
__le64 *cdptr;
struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
+ struct arm_smmu_device *smmu = master->smmu;
if (WARN_ON(ssid >= (1 << cd_table->s1cdmax)))
return -E2BIG;
@@ -1077,6 +1078,8 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
if (!cd) { /* (5) */
val = 0;
} else if (cd == &quiet_cd) { /* (4) */
+ if (!(smmu->features & ARM_SMMU_FEAT_STALL_FORCE))
+ val &= ~(CTXDESC_CD_0_S | CTXDESC_CD_0_R);
val |= CTXDESC_CD_0_TCR_EPD0;
} else if (cd_live) { /* (3) */
val &= ~CTXDESC_CD_0_ASID;
@@ -1249,7 +1252,7 @@ static void arm_smmu_sync_ste_for_sid(struct arm_smmu_device *smmu, u32 sid)
}
static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
- __le64 *dst)
+ struct arm_smmu_ste *dst)
{
/*
* This is hideously complicated, but we only really care about
@@ -1267,12 +1270,12 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
* 2. Write everything apart from dword 0, sync, write dword 0, sync
* 3. Update Config, sync
*/
- u64 val = le64_to_cpu(dst[0]);
+ u64 val = le64_to_cpu(dst->data[0]);
bool ste_live = false;
- struct arm_smmu_device *smmu = NULL;
+ struct arm_smmu_device *smmu = master->smmu;
struct arm_smmu_ctx_desc_cfg *cd_table = NULL;
struct arm_smmu_s2_cfg *s2_cfg = NULL;
- struct arm_smmu_domain *smmu_domain = NULL;
+ struct arm_smmu_domain *smmu_domain = master->domain;
struct arm_smmu_cmdq_ent prefetch_cmd = {
.opcode = CMDQ_OP_PREFETCH_CFG,
.prefetch = {
@@ -1280,18 +1283,12 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
},
};
- if (master) {
- smmu_domain = master->domain;
- smmu = master->smmu;
- }
-
if (smmu_domain) {
switch (smmu_domain->stage) {
case ARM_SMMU_DOMAIN_S1:
cd_table = &master->cd_table;
break;
case ARM_SMMU_DOMAIN_S2:
- case ARM_SMMU_DOMAIN_NESTED:
s2_cfg = &smmu_domain->s2_cfg;
break;
default:
@@ -1325,10 +1322,10 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
else
val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_BYPASS);
- dst[0] = cpu_to_le64(val);
- dst[1] = cpu_to_le64(FIELD_PREP(STRTAB_STE_1_SHCFG,
+ dst->data[0] = cpu_to_le64(val);
+ dst->data[1] = cpu_to_le64(FIELD_PREP(STRTAB_STE_1_SHCFG,
STRTAB_STE_1_SHCFG_INCOMING));
- dst[2] = 0; /* Nuke the VMID */
+ dst->data[2] = 0; /* Nuke the VMID */
/*
* The SMMU can perform negative caching, so we must sync
* the STE regardless of whether the old value was live.
@@ -1343,7 +1340,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
STRTAB_STE_1_STRW_EL2 : STRTAB_STE_1_STRW_NSEL1;
BUG_ON(ste_live);
- dst[1] = cpu_to_le64(
+ dst->data[1] = cpu_to_le64(
FIELD_PREP(STRTAB_STE_1_S1DSS, STRTAB_STE_1_S1DSS_SSID0) |
FIELD_PREP(STRTAB_STE_1_S1CIR, STRTAB_STE_1_S1C_CACHE_WBRA) |
FIELD_PREP(STRTAB_STE_1_S1COR, STRTAB_STE_1_S1C_CACHE_WBRA) |
@@ -1352,7 +1349,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
if (smmu->features & ARM_SMMU_FEAT_STALLS &&
!master->stall_enabled)
- dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD);
+ dst->data[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD);
val |= (cd_table->cdtab_dma & STRTAB_STE_0_S1CTXPTR_MASK) |
FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S1_TRANS) |
@@ -1362,7 +1359,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
if (s2_cfg) {
BUG_ON(ste_live);
- dst[2] = cpu_to_le64(
+ dst->data[2] = cpu_to_le64(
FIELD_PREP(STRTAB_STE_2_S2VMID, s2_cfg->vmid) |
FIELD_PREP(STRTAB_STE_2_VTCR, s2_cfg->vtcr) |
#ifdef __BIG_ENDIAN
@@ -1371,18 +1368,18 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
STRTAB_STE_2_S2PTW | STRTAB_STE_2_S2AA64 |
STRTAB_STE_2_S2R);
- dst[3] = cpu_to_le64(s2_cfg->vttbr & STRTAB_STE_3_S2TTB_MASK);
+ dst->data[3] = cpu_to_le64(s2_cfg->vttbr & STRTAB_STE_3_S2TTB_MASK);
val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_S2_TRANS);
}
if (master->ats_enabled)
- dst[1] |= cpu_to_le64(FIELD_PREP(STRTAB_STE_1_EATS,
+ dst->data[1] |= cpu_to_le64(FIELD_PREP(STRTAB_STE_1_EATS,
STRTAB_STE_1_EATS_TRANS));
arm_smmu_sync_ste_for_sid(smmu, sid);
/* See comment in arm_smmu_write_ctx_desc() */
- WRITE_ONCE(dst[0], cpu_to_le64(val));
+ WRITE_ONCE(dst->data[0], cpu_to_le64(val));
arm_smmu_sync_ste_for_sid(smmu, sid);
/* It's likely that we'll want to use the new STE soon */
@@ -1390,7 +1387,8 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
arm_smmu_cmdq_issue_cmd(smmu, &prefetch_cmd);
}
-static void arm_smmu_init_bypass_stes(__le64 *strtab, unsigned int nent, bool force)
+static void arm_smmu_init_bypass_stes(struct arm_smmu_ste *strtab,
+ unsigned int nent, bool force)
{
unsigned int i;
u64 val = STRTAB_STE_0_V;
@@ -1401,11 +1399,11 @@ static void arm_smmu_init_bypass_stes(__le64 *strtab, unsigned int nent, bool fo
val |= FIELD_PREP(STRTAB_STE_0_CFG, STRTAB_STE_0_CFG_BYPASS);
for (i = 0; i < nent; ++i) {
- strtab[0] = cpu_to_le64(val);
- strtab[1] = cpu_to_le64(FIELD_PREP(STRTAB_STE_1_SHCFG,
- STRTAB_STE_1_SHCFG_INCOMING));
- strtab[2] = 0;
- strtab += STRTAB_STE_DWORDS;
+ strtab->data[0] = cpu_to_le64(val);
+ strtab->data[1] = cpu_to_le64(FIELD_PREP(
+ STRTAB_STE_1_SHCFG, STRTAB_STE_1_SHCFG_INCOMING));
+ strtab->data[2] = 0;
+ strtab++;
}
}
@@ -2171,7 +2169,6 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
fmt = ARM_64_LPAE_S1;
finalise_stage_fn = arm_smmu_domain_finalise_s1;
break;
- case ARM_SMMU_DOMAIN_NESTED:
case ARM_SMMU_DOMAIN_S2:
ias = smmu->ias;
oas = smmu->oas;
@@ -2209,26 +2206,23 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
return 0;
}
-static __le64 *arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
+static struct arm_smmu_ste *
+arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid)
{
- __le64 *step;
struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) {
- struct arm_smmu_strtab_l1_desc *l1_desc;
- int idx;
+ unsigned int idx1, idx2;
/* Two-level walk */
- idx = (sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS;
- l1_desc = &cfg->l1_desc[idx];
- idx = (sid & ((1 << STRTAB_SPLIT) - 1)) * STRTAB_STE_DWORDS;
- step = &l1_desc->l2ptr[idx];
+ idx1 = (sid >> STRTAB_SPLIT) * STRTAB_L1_DESC_DWORDS;
+ idx2 = sid & ((1 << STRTAB_SPLIT) - 1);
+ return &cfg->l1_desc[idx1].l2ptr[idx2];
} else {
/* Simple linear lookup */
- step = &cfg->strtab[sid * STRTAB_STE_DWORDS];
+ return (struct arm_smmu_ste *)&cfg
+ ->strtab[sid * STRTAB_STE_DWORDS];
}
-
- return step;
}
static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master)
@@ -2238,7 +2232,8 @@ static void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master)
for (i = 0; i < master->num_streams; ++i) {
u32 sid = master->streams[i].id;
- __le64 *step = arm_smmu_get_step_for_sid(smmu, sid);
+ struct arm_smmu_ste *step =
+ arm_smmu_get_step_for_sid(smmu, sid);
/* Bridged PCI devices may end up with duplicated IDs */
for (j = 0; j < i; j++)
@@ -2649,9 +2644,6 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
struct arm_smmu_master *master;
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- if (!fwspec || fwspec->ops != &arm_smmu_ops)
- return ERR_PTR(-ENODEV);
-
if (WARN_ON_ONCE(dev_iommu_priv_get(dev)))
return ERR_PTR(-EBUSY);
@@ -2698,7 +2690,6 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
err_free_master:
kfree(master);
- dev_iommu_priv_set(dev, NULL);
return ERR_PTR(ret);
}
@@ -2742,7 +2733,7 @@ static int arm_smmu_enable_nesting(struct iommu_domain *domain)
if (smmu_domain->smmu)
ret = -EPERM;
else
- smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED;
+ smmu_domain->stage = ARM_SMMU_DOMAIN_S2;
mutex_unlock(&smmu_domain->init_mutex);
return ret;
@@ -3769,7 +3760,7 @@ static void arm_smmu_rmr_install_bypass_ste(struct arm_smmu_device *smmu)
iort_get_rmr_sids(dev_fwnode(smmu->dev), &rmr_list);
list_for_each_entry(e, &rmr_list, list) {
- __le64 *step;
+ struct arm_smmu_ste *step;
struct iommu_iort_rmr_data *rmr;
int ret, i;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 925ac6a47bce..65fb388d5173 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -206,6 +206,11 @@
#define STRTAB_L1_DESC_L2PTR_MASK GENMASK_ULL(51, 6)
#define STRTAB_STE_DWORDS 8
+
+struct arm_smmu_ste {
+ __le64 data[STRTAB_STE_DWORDS];
+};
+
#define STRTAB_STE_0_V (1UL << 0)
#define STRTAB_STE_0_CFG GENMASK_ULL(3, 1)
#define STRTAB_STE_0_CFG_ABORT 0
@@ -571,7 +576,7 @@ struct arm_smmu_priq {
struct arm_smmu_strtab_l1_desc {
u8 span;
- __le64 *l2ptr;
+ struct arm_smmu_ste *l2ptr;
dma_addr_t l2ptr_dma;
};
@@ -710,7 +715,6 @@ struct arm_smmu_master {
enum arm_smmu_domain_stage {
ARM_SMMU_DOMAIN_S1 = 0,
ARM_SMMU_DOMAIN_S2,
- ARM_SMMU_DOMAIN_NESTED,
ARM_SMMU_DOMAIN_BYPASS,
};
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index 549ae4dba3a6..8b04ece00420 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
@@ -243,8 +243,10 @@ static int qcom_adreno_smmu_init_context(struct arm_smmu_domain *smmu_domain,
static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = {
{ .compatible = "qcom,adreno" },
+ { .compatible = "qcom,adreno-gmu" },
{ .compatible = "qcom,mdp4" },
{ .compatible = "qcom,mdss" },
+ { .compatible = "qcom,qcm2290-mdss" },
{ .compatible = "qcom,sc7180-mdss" },
{ .compatible = "qcom,sc7180-mss-pil" },
{ .compatible = "qcom,sc7280-mdss" },
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index d6d1a2a55cc0..68b6bc5e7c71 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -82,6 +82,23 @@ static inline void arm_smmu_rpm_put(struct arm_smmu_device *smmu)
pm_runtime_put_autosuspend(smmu->dev);
}
+static void arm_smmu_rpm_use_autosuspend(struct arm_smmu_device *smmu)
+{
+ /*
+ * Setup an autosuspend delay to avoid bouncing runpm state.
+ * Otherwise, if a driver for a suspended consumer device
+ * unmaps buffers, it will runpm resume/suspend for each one.
+ *
+ * For example, when used by a GPU device, when an application
+ * or game exits, it can trigger unmapping 100s or 1000s of
+ * buffers. With a runpm cycle for each buffer, that adds up
+ * to 5-10sec worth of reprogramming the context bank, while
+ * the system appears to be locked up to the user.
+ */
+ pm_runtime_set_autosuspend_delay(smmu->dev, 20);
+ pm_runtime_use_autosuspend(smmu->dev);
+}
+
static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
{
return container_of(dom, struct arm_smmu_domain, domain);
@@ -392,8 +409,7 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
{
u32 fsr, fsynr, cbfrsynra;
unsigned long iova;
- struct iommu_domain *domain = dev;
- struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ struct arm_smmu_domain *smmu_domain = dev;
struct arm_smmu_device *smmu = smmu_domain->smmu;
int idx = smmu_domain->cfg.cbndx;
int ret;
@@ -406,7 +422,7 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
iova = arm_smmu_cb_readq(smmu, idx, ARM_SMMU_CB_FAR);
cbfrsynra = arm_smmu_gr1_read(smmu, ARM_SMMU_GR1_CBFRSYNRA(idx));
- ret = report_iommu_fault(domain, NULL, iova,
+ ret = report_iommu_fault(&smmu_domain->domain, NULL, iova,
fsynr & ARM_SMMU_FSYNR0_WNR ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ);
if (ret == -ENOSYS)
@@ -607,7 +623,7 @@ static int arm_smmu_alloc_context_bank(struct arm_smmu_domain *smmu_domain,
return __arm_smmu_alloc_bitmap(smmu->context_map, start, smmu->num_context_banks);
}
-static int arm_smmu_init_domain_context(struct iommu_domain *domain,
+static int arm_smmu_init_domain_context(struct arm_smmu_domain *smmu_domain,
struct arm_smmu_device *smmu,
struct device *dev)
{
@@ -616,7 +632,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
struct io_pgtable_ops *pgtbl_ops;
struct io_pgtable_cfg pgtbl_cfg;
enum io_pgtable_fmt fmt;
- struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ struct iommu_domain *domain = &smmu_domain->domain;
struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
irqreturn_t (*context_fault)(int irq, void *dev);
@@ -624,12 +640,6 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
if (smmu_domain->smmu)
goto out_unlock;
- if (domain->type == IOMMU_DOMAIN_IDENTITY) {
- smmu_domain->stage = ARM_SMMU_DOMAIN_BYPASS;
- smmu_domain->smmu = smmu;
- goto out_unlock;
- }
-
/*
* Mapping the requested stage onto what we support is surprisingly
* complicated, mainly because the spec allows S1+S2 SMMUs without
@@ -796,8 +806,8 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
else
context_fault = arm_smmu_context_fault;
- ret = devm_request_irq(smmu->dev, irq, context_fault,
- IRQF_SHARED, "arm-smmu-context-fault", domain);
+ ret = devm_request_irq(smmu->dev, irq, context_fault, IRQF_SHARED,
+ "arm-smmu-context-fault", smmu_domain);
if (ret < 0) {
dev_err(smmu->dev, "failed to request context IRQ %d (%u)\n",
cfg->irptndx, irq);
@@ -818,14 +828,13 @@ out_unlock:
return ret;
}
-static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
+static void arm_smmu_destroy_domain_context(struct arm_smmu_domain *smmu_domain)
{
- struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
struct arm_smmu_device *smmu = smmu_domain->smmu;
struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
int ret, irq;
- if (!smmu || domain->type == IOMMU_DOMAIN_IDENTITY)
+ if (!smmu)
return;
ret = arm_smmu_rpm_get(smmu);
@@ -841,7 +850,7 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
if (cfg->irptndx != ARM_SMMU_INVALID_IRPTNDX) {
irq = smmu->irqs[cfg->irptndx];
- devm_free_irq(smmu->dev, irq, domain);
+ devm_free_irq(smmu->dev, irq, smmu_domain);
}
free_io_pgtable_ops(smmu_domain->pgtbl_ops);
@@ -850,14 +859,10 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
arm_smmu_rpm_put(smmu);
}
-static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
+static struct iommu_domain *arm_smmu_domain_alloc_paging(struct device *dev)
{
struct arm_smmu_domain *smmu_domain;
- if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_IDENTITY) {
- if (using_legacy_binding || type != IOMMU_DOMAIN_DMA)
- return NULL;
- }
/*
* Allocate the domain and initialise some of its data structures.
* We can't really do anything meaningful until we've added a
@@ -870,6 +875,15 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
mutex_init(&smmu_domain->init_mutex);
spin_lock_init(&smmu_domain->cb_lock);
+ if (dev) {
+ struct arm_smmu_master_cfg *cfg = dev_iommu_priv_get(dev);
+
+ if (arm_smmu_init_domain_context(smmu_domain, cfg->smmu, dev)) {
+ kfree(smmu_domain);
+ return NULL;
+ }
+ }
+
return &smmu_domain->domain;
}
@@ -881,7 +895,7 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)
* Free the domain resources. We assume that all devices have
* already been detached.
*/
- arm_smmu_destroy_domain_context(domain);
+ arm_smmu_destroy_domain_context(smmu_domain);
kfree(smmu_domain);
}
@@ -1081,21 +1095,14 @@ static void arm_smmu_master_free_smes(struct arm_smmu_master_cfg *cfg,
mutex_unlock(&smmu->stream_map_mutex);
}
-static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
- struct arm_smmu_master_cfg *cfg,
- struct iommu_fwspec *fwspec)
+static void arm_smmu_master_install_s2crs(struct arm_smmu_master_cfg *cfg,
+ enum arm_smmu_s2cr_type type,
+ u8 cbndx, struct iommu_fwspec *fwspec)
{
- struct arm_smmu_device *smmu = smmu_domain->smmu;
+ struct arm_smmu_device *smmu = cfg->smmu;
struct arm_smmu_s2cr *s2cr = smmu->s2crs;
- u8 cbndx = smmu_domain->cfg.cbndx;
- enum arm_smmu_s2cr_type type;
int i, idx;
- if (smmu_domain->stage == ARM_SMMU_DOMAIN_BYPASS)
- type = S2CR_TYPE_BYPASS;
- else
- type = S2CR_TYPE_TRANS;
-
for_each_cfg_sme(cfg, fwspec, i, idx) {
if (type == s2cr[idx].type && cbndx == s2cr[idx].cbndx)
continue;
@@ -1105,7 +1112,6 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
s2cr[idx].cbndx = cbndx;
arm_smmu_write_s2cr(smmu, idx);
}
- return 0;
}
static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
@@ -1116,11 +1122,6 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
struct arm_smmu_device *smmu;
int ret;
- if (!fwspec || fwspec->ops != &arm_smmu_ops) {
- dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n");
- return -ENXIO;
- }
-
/*
* FIXME: The arch/arm DMA API code tries to attach devices to its own
* domains between of_xlate() and probe_device() - we have no way to cope
@@ -1139,7 +1140,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
return ret;
/* Ensure that the domain is finalised */
- ret = arm_smmu_init_domain_context(domain, smmu, dev);
+ ret = arm_smmu_init_domain_context(smmu_domain, smmu, dev);
if (ret < 0)
goto rpm_put;
@@ -1153,27 +1154,66 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
}
/* Looks ok, so add the device to the domain */
- ret = arm_smmu_domain_add_master(smmu_domain, cfg, fwspec);
-
- /*
- * Setup an autosuspend delay to avoid bouncing runpm state.
- * Otherwise, if a driver for a suspended consumer device
- * unmaps buffers, it will runpm resume/suspend for each one.
- *
- * For example, when used by a GPU device, when an application
- * or game exits, it can trigger unmapping 100s or 1000s of
- * buffers. With a runpm cycle for each buffer, that adds up
- * to 5-10sec worth of reprogramming the context bank, while
- * the system appears to be locked up to the user.
- */
- pm_runtime_set_autosuspend_delay(smmu->dev, 20);
- pm_runtime_use_autosuspend(smmu->dev);
-
+ arm_smmu_master_install_s2crs(cfg, S2CR_TYPE_TRANS,
+ smmu_domain->cfg.cbndx, fwspec);
+ arm_smmu_rpm_use_autosuspend(smmu);
rpm_put:
arm_smmu_rpm_put(smmu);
return ret;
}
+static int arm_smmu_attach_dev_type(struct device *dev,
+ enum arm_smmu_s2cr_type type)
+{
+ struct arm_smmu_master_cfg *cfg = dev_iommu_priv_get(dev);
+ struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
+ struct arm_smmu_device *smmu;
+ int ret;
+
+ if (!cfg)
+ return -ENODEV;
+ smmu = cfg->smmu;
+
+ ret = arm_smmu_rpm_get(smmu);
+ if (ret < 0)
+ return ret;
+
+ arm_smmu_master_install_s2crs(cfg, type, 0, fwspec);
+ arm_smmu_rpm_use_autosuspend(smmu);
+ arm_smmu_rpm_put(smmu);
+ return 0;
+}
+
+static int arm_smmu_attach_dev_identity(struct iommu_domain *domain,
+ struct device *dev)
+{
+ return arm_smmu_attach_dev_type(dev, S2CR_TYPE_BYPASS);
+}
+
+static const struct iommu_domain_ops arm_smmu_identity_ops = {
+ .attach_dev = arm_smmu_attach_dev_identity,
+};
+
+static struct iommu_domain arm_smmu_identity_domain = {
+ .type = IOMMU_DOMAIN_IDENTITY,
+ .ops = &arm_smmu_identity_ops,
+};
+
+static int arm_smmu_attach_dev_blocked(struct iommu_domain *domain,
+ struct device *dev)
+{
+ return arm_smmu_attach_dev_type(dev, S2CR_TYPE_FAULT);
+}
+
+static const struct iommu_domain_ops arm_smmu_blocked_ops = {
+ .attach_dev = arm_smmu_attach_dev_blocked,
+};
+
+static struct iommu_domain arm_smmu_blocked_domain = {
+ .type = IOMMU_DOMAIN_BLOCKED,
+ .ops = &arm_smmu_blocked_ops,
+};
+
static int arm_smmu_map_pages(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t pgsize, size_t pgcount,
int prot, gfp_t gfp, size_t *mapped)
@@ -1357,10 +1397,8 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
fwspec = dev_iommu_fwspec_get(dev);
if (ret)
goto out_free;
- } else if (fwspec && fwspec->ops == &arm_smmu_ops) {
- smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
} else {
- return ERR_PTR(-ENODEV);
+ smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
}
ret = -EINVAL;
@@ -1427,7 +1465,6 @@ static void arm_smmu_release_device(struct device *dev)
arm_smmu_rpm_put(cfg->smmu);
- dev_iommu_priv_set(dev, NULL);
kfree(cfg);
}
@@ -1560,8 +1597,10 @@ static int arm_smmu_def_domain_type(struct device *dev)
}
static struct iommu_ops arm_smmu_ops = {
+ .identity_domain = &arm_smmu_identity_domain,
+ .blocked_domain = &arm_smmu_blocked_domain,
.capable = arm_smmu_capable,
- .domain_alloc = arm_smmu_domain_alloc,
+ .domain_alloc_paging = arm_smmu_domain_alloc_paging,
.probe_device = arm_smmu_probe_device,
.release_device = arm_smmu_release_device,
.probe_finalize = arm_smmu_probe_finalize,
@@ -2161,7 +2200,8 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
return err;
}
- err = iommu_device_register(&smmu->iommu, &arm_smmu_ops, dev);
+ err = iommu_device_register(&smmu->iommu, &arm_smmu_ops,
+ using_legacy_binding ? NULL : dev);
if (err) {
dev_err(dev, "Failed to register iommu\n");
iommu_device_sysfs_remove(&smmu->iommu);
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h b/drivers/iommu/arm/arm-smmu/arm-smmu.h
index 703fd5817ec1..836ed6799a80 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.h
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h
@@ -361,7 +361,6 @@ enum arm_smmu_domain_stage {
ARM_SMMU_DOMAIN_S1 = 0,
ARM_SMMU_DOMAIN_S2,
ARM_SMMU_DOMAIN_NESTED,
- ARM_SMMU_DOMAIN_BYPASS,
};
struct arm_smmu_domain {
diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
index 97b2122032b2..17a1c163fef6 100644
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -79,16 +79,6 @@ static struct qcom_iommu_domain *to_qcom_iommu_domain(struct iommu_domain *dom)
static const struct iommu_ops qcom_iommu_ops;
-static struct qcom_iommu_dev * to_iommu(struct device *dev)
-{
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
-
- if (!fwspec || fwspec->ops != &qcom_iommu_ops)
- return NULL;
-
- return dev_iommu_priv_get(dev);
-}
-
static struct qcom_iommu_ctx * to_ctx(struct qcom_iommu_domain *d, unsigned asid)
{
struct qcom_iommu_dev *qcom_iommu = d->iommu;
@@ -372,7 +362,7 @@ static void qcom_iommu_domain_free(struct iommu_domain *domain)
static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
{
- struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
+ struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev);
struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
int ret;
@@ -404,7 +394,7 @@ static int qcom_iommu_identity_attach(struct iommu_domain *identity_domain,
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
struct qcom_iommu_domain *qcom_domain;
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
+ struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev);
unsigned int i;
if (domain == identity_domain || !domain)
@@ -535,7 +525,7 @@ static bool qcom_iommu_capable(struct device *dev, enum iommu_cap cap)
static struct iommu_device *qcom_iommu_probe_device(struct device *dev)
{
- struct qcom_iommu_dev *qcom_iommu = to_iommu(dev);
+ struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev);
struct device_link *link;
if (!qcom_iommu)
@@ -900,8 +890,16 @@ static void qcom_iommu_device_remove(struct platform_device *pdev)
static int __maybe_unused qcom_iommu_resume(struct device *dev)
{
struct qcom_iommu_dev *qcom_iommu = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_bulk_prepare_enable(CLK_NUM, qcom_iommu->clks);
+ if (ret < 0)
+ return ret;
+
+ if (dev->pm_domain)
+ return qcom_scm_restore_sec_cfg(qcom_iommu->sec_id, 0);
- return clk_bulk_prepare_enable(CLK_NUM, qcom_iommu->clks);
+ return ret;
}
static int __maybe_unused qcom_iommu_suspend(struct device *dev)
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index e59f50e11ea8..50ccc4f1ef81 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -29,6 +29,7 @@
#include <linux/spinlock.h>
#include <linux/swiotlb.h>
#include <linux/vmalloc.h>
+#include <trace/events/swiotlb.h>
#include "dma-iommu.h"
@@ -1156,6 +1157,8 @@ static dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
return DMA_MAPPING_ERROR;
}
+ trace_swiotlb_bounced(dev, phys, size);
+
aligned_size = iova_align(iovad, size);
phys = swiotlb_tbl_map_single(dev, phys, size, aligned_size,
iova_mask(iovad), dir, attrs);
diff --git a/drivers/iommu/intel/debugfs.c b/drivers/iommu/intel/debugfs.c
index dee61e513be6..86b506af7daa 100644
--- a/drivers/iommu/intel/debugfs.c
+++ b/drivers/iommu/intel/debugfs.c
@@ -106,9 +106,6 @@ static const struct iommu_regset iommu_regs_64[] = {
IOMMU_REGSET_ENTRY(MTRR_PHYSMASK8),
IOMMU_REGSET_ENTRY(MTRR_PHYSBASE9),
IOMMU_REGSET_ENTRY(MTRR_PHYSMASK9),
- IOMMU_REGSET_ENTRY(VCCAP),
- IOMMU_REGSET_ENTRY(VCMD),
- IOMMU_REGSET_ENTRY(VCRSP),
};
static struct dentry *intel_iommu_debug;
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index 897159dba47d..6fb5f6fceea1 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -46,9 +46,6 @@
#define DEFAULT_DOMAIN_ADDRESS_WIDTH 57
-#define MAX_AGAW_WIDTH 64
-#define MAX_AGAW_PFN_WIDTH (MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
-
#define __DOMAIN_MAX_PFN(gaw) ((((uint64_t)1) << ((gaw) - VTD_PAGE_SHIFT)) - 1)
#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << (gaw)) - 1)
@@ -63,74 +60,6 @@
#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
-/* page table handling */
-#define LEVEL_STRIDE (9)
-#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
-
-static inline int agaw_to_level(int agaw)
-{
- return agaw + 2;
-}
-
-static inline int agaw_to_width(int agaw)
-{
- return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
-}
-
-static inline int width_to_agaw(int width)
-{
- return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
-}
-
-static inline unsigned int level_to_offset_bits(int level)
-{
- return (level - 1) * LEVEL_STRIDE;
-}
-
-static inline int pfn_level_offset(u64 pfn, int level)
-{
- return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
-}
-
-static inline u64 level_mask(int level)
-{
- return -1ULL << level_to_offset_bits(level);
-}
-
-static inline u64 level_size(int level)
-{
- return 1ULL << level_to_offset_bits(level);
-}
-
-static inline u64 align_to_level(u64 pfn, int level)
-{
- return (pfn + level_size(level) - 1) & level_mask(level);
-}
-
-static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
-{
- return 1UL << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
-}
-
-/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
- are never going to work. */
-static inline unsigned long mm_to_dma_pfn_start(unsigned long mm_pfn)
-{
- return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
-}
-static inline unsigned long mm_to_dma_pfn_end(unsigned long mm_pfn)
-{
- return ((mm_pfn + 1) << (PAGE_SHIFT - VTD_PAGE_SHIFT)) - 1;
-}
-static inline unsigned long page_to_dma_pfn(struct page *pg)
-{
- return mm_to_dma_pfn_start(page_to_pfn(pg));
-}
-static inline unsigned long virt_to_dma_pfn(void *p)
-{
- return page_to_dma_pfn(virt_to_page(p));
-}
-
static void __init check_tylersburg_isoch(void);
static int rwbf_quirk;
@@ -168,78 +97,6 @@ static phys_addr_t root_entry_uctp(struct root_entry *re)
return re->hi & VTD_PAGE_MASK;
}
-static inline void context_set_present(struct context_entry *context)
-{
- context->lo |= 1;
-}
-
-static inline void context_set_fault_enable(struct context_entry *context)
-{
- context->lo &= (((u64)-1) << 2) | 1;
-}
-
-static inline void context_set_translation_type(struct context_entry *context,
- unsigned long value)
-{
- context->lo &= (((u64)-1) << 4) | 3;
- context->lo |= (value & 3) << 2;
-}
-
-static inline void context_set_address_root(struct context_entry *context,
- unsigned long value)
-{
- context->lo &= ~VTD_PAGE_MASK;
- context->lo |= value & VTD_PAGE_MASK;
-}
-
-static inline void context_set_address_width(struct context_entry *context,
- unsigned long value)
-{
- context->hi |= value & 7;
-}
-
-static inline void context_set_domain_id(struct context_entry *context,
- unsigned long value)
-{
- context->hi |= (value & ((1 << 16) - 1)) << 8;
-}
-
-static inline void context_set_pasid(struct context_entry *context)
-{
- context->lo |= CONTEXT_PASIDE;
-}
-
-static inline int context_domain_id(struct context_entry *c)
-{
- return((c->hi >> 8) & 0xffff);
-}
-
-static inline void context_clear_entry(struct context_entry *context)
-{
- context->lo = 0;
- context->hi = 0;
-}
-
-static inline bool context_copied(struct intel_iommu *iommu, u8 bus, u8 devfn)
-{
- if (!iommu->copied_tables)
- return false;
-
- return test_bit(((long)bus << 8) | devfn, iommu->copied_tables);
-}
-
-static inline void
-set_context_copied(struct intel_iommu *iommu, u8 bus, u8 devfn)
-{
- set_bit(((long)bus << 8) | devfn, iommu->copied_tables);
-}
-
-static inline void
-clear_context_copied(struct intel_iommu *iommu, u8 bus, u8 devfn)
-{
- clear_bit(((long)bus << 8) | devfn, iommu->copied_tables);
-}
-
/*
* This domain is a statically identity mapping domain.
* 1. This domain creats a static 1:1 mapping to all usable memory.
@@ -383,13 +240,12 @@ void free_pgtable_page(void *vaddr)
free_page((unsigned long)vaddr);
}
-static inline int domain_type_is_si(struct dmar_domain *domain)
+static int domain_type_is_si(struct dmar_domain *domain)
{
return domain->domain.type == IOMMU_DOMAIN_IDENTITY;
}
-static inline int domain_pfn_supported(struct dmar_domain *domain,
- unsigned long pfn)
+static int domain_pfn_supported(struct dmar_domain *domain, unsigned long pfn)
{
int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
@@ -451,7 +307,7 @@ int iommu_calculate_agaw(struct intel_iommu *iommu)
return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
}
-static inline bool iommu_paging_structure_coherency(struct intel_iommu *iommu)
+static bool iommu_paging_structure_coherency(struct intel_iommu *iommu)
{
return sm_supported(iommu) ?
ecap_smpwc(iommu->ecap) : ecap_coherent(iommu->ecap);
@@ -703,7 +559,7 @@ static bool iommu_is_dummy(struct intel_iommu *iommu, struct device *dev)
return false;
}
-struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
+static struct intel_iommu *device_lookup_iommu(struct device *dev, u8 *bus, u8 *devfn)
{
struct dmar_drhd_unit *drhd = NULL;
struct pci_dev *pdev = NULL;
@@ -1574,9 +1430,8 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu,
}
/* Notification for newly created mappings */
-static inline void __mapping_notify_one(struct intel_iommu *iommu,
- struct dmar_domain *domain,
- unsigned long pfn, unsigned int pages)
+static void __mapping_notify_one(struct intel_iommu *iommu, struct dmar_domain *domain,
+ unsigned long pfn, unsigned int pages)
{
/*
* It's a non-present to present mapping. Only flush if caching mode
@@ -1843,7 +1698,7 @@ void domain_detach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu)
spin_unlock(&iommu->lock);
}
-static inline int guestwidth_to_adjustwidth(int gaw)
+static int guestwidth_to_adjustwidth(int gaw)
{
int agaw;
int r = (gaw - 12) % 9;
@@ -1877,7 +1732,7 @@ static void domain_exit(struct dmar_domain *domain)
* Value of X in the PDTS field of a scalable mode context entry
* indicates PASID directory with 2^(X + 7) entries.
*/
-static inline unsigned long context_get_sm_pds(struct pasid_table *table)
+static unsigned long context_get_sm_pds(struct pasid_table *table)
{
unsigned long pds, max_pde;
@@ -1889,38 +1744,6 @@ static inline unsigned long context_get_sm_pds(struct pasid_table *table)
return pds - 7;
}
-/*
- * Set the RID_PASID field of a scalable mode context entry. The
- * IOMMU hardware will use the PASID value set in this field for
- * DMA translations of DMA requests without PASID.
- */
-static inline void
-context_set_sm_rid2pasid(struct context_entry *context, unsigned long pasid)
-{
- context->hi |= pasid & ((1 << 20) - 1);
-}
-
-/*
- * Set the DTE(Device-TLB Enable) field of a scalable mode context
- * entry.
- */
-static inline void context_set_sm_dte(struct context_entry *context)
-{
- context->lo |= BIT_ULL(2);
-}
-
-/*
- * Set the PRE(Page Request Enable) field of a scalable mode context
- * entry.
- */
-static inline void context_set_sm_pre(struct context_entry *context)
-{
- context->lo |= BIT_ULL(4);
-}
-
-/* Convert value to context PASID directory size field coding. */
-#define context_pdts(pds) (((pds) & 0x7) << 9)
-
static int domain_context_mapping_one(struct dmar_domain *domain,
struct intel_iommu *iommu,
struct pasid_table *table,
@@ -2081,14 +1904,11 @@ static int domain_context_mapping_cb(struct pci_dev *pdev,
static int
domain_context_mapping(struct dmar_domain *domain, struct device *dev)
{
+ struct device_domain_info *info = dev_iommu_priv_get(dev);
struct domain_context_mapping_data data;
+ struct intel_iommu *iommu = info->iommu;
+ u8 bus = info->bus, devfn = info->devfn;
struct pasid_table *table;
- struct intel_iommu *iommu;
- u8 bus, devfn;
-
- iommu = device_to_iommu(dev, &bus, &devfn);
- if (!iommu)
- return -ENODEV;
table = intel_pasid_get_table(dev);
@@ -2105,18 +1925,15 @@ domain_context_mapping(struct dmar_domain *domain, struct device *dev)
}
/* Returns a number of VTD pages, but aligned to MM page size */
-static inline unsigned long aligned_nrpages(unsigned long host_addr,
- size_t size)
+static unsigned long aligned_nrpages(unsigned long host_addr, size_t size)
{
host_addr &= ~PAGE_MASK;
return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
}
/* Return largest possible superpage level for a given mapping */
-static inline int hardware_largepage_caps(struct dmar_domain *domain,
- unsigned long iov_pfn,
- unsigned long phy_pfn,
- unsigned long pages)
+static int hardware_largepage_caps(struct dmar_domain *domain, unsigned long iov_pfn,
+ unsigned long phy_pfn, unsigned long pages)
{
int support, level = 1;
unsigned long pfnmerge;
@@ -2449,15 +2266,10 @@ static int dmar_domain_attach_device(struct dmar_domain *domain,
struct device *dev)
{
struct device_domain_info *info = dev_iommu_priv_get(dev);
- struct intel_iommu *iommu;
+ struct intel_iommu *iommu = info->iommu;
unsigned long flags;
- u8 bus, devfn;
int ret;
- iommu = device_to_iommu(dev, &bus, &devfn);
- if (!iommu)
- return -ENODEV;
-
ret = domain_attach_iommu(domain, iommu);
if (ret)
return ret;
@@ -2470,7 +2282,7 @@ static int dmar_domain_attach_device(struct dmar_domain *domain,
if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) {
/* Setup the PASID entry for requests without PASID: */
if (hw_pass_through && domain_type_is_si(domain))
- ret = intel_pasid_setup_pass_through(iommu, domain,
+ ret = intel_pasid_setup_pass_through(iommu,
dev, IOMMU_NO_PASID);
else if (domain->use_first_level)
ret = domain_setup_first_level(iommu, domain, dev,
@@ -3615,7 +3427,7 @@ void intel_iommu_shutdown(void)
up_write(&dmar_global_lock);
}
-static inline struct intel_iommu *dev_to_intel_iommu(struct device *dev)
+static struct intel_iommu *dev_to_intel_iommu(struct device *dev)
{
struct iommu_device *iommu_dev = dev_to_iommu_device(dev);
@@ -3694,7 +3506,7 @@ const struct attribute_group *intel_iommu_groups[] = {
NULL,
};
-static inline bool has_external_pci(void)
+static bool has_external_pci(void)
{
struct pci_dev *pdev = NULL;
@@ -4119,14 +3931,11 @@ static void intel_iommu_domain_free(struct iommu_domain *domain)
int prepare_domain_attach_device(struct iommu_domain *domain,
struct device *dev)
{
+ struct device_domain_info *info = dev_iommu_priv_get(dev);
struct dmar_domain *dmar_domain = to_dmar_domain(domain);
- struct intel_iommu *iommu;
+ struct intel_iommu *iommu = info->iommu;
int addr_width;
- iommu = device_to_iommu(dev, NULL, NULL);
- if (!iommu)
- return -ENODEV;
-
if (dmar_domain->force_snooping && !ecap_sc_support(iommu->ecap))
return -EINVAL;
@@ -4403,7 +4212,7 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
u8 bus, devfn;
int ret;
- iommu = device_to_iommu(dev, &bus, &devfn);
+ iommu = device_lookup_iommu(dev, &bus, &devfn);
if (!iommu || !iommu->iommu.ops)
return ERR_PTR(-ENODEV);
@@ -4461,7 +4270,6 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)
ret = intel_pasid_alloc_table(dev);
if (ret) {
dev_err(dev, "PASID table allocation failed\n");
- dev_iommu_priv_set(dev, NULL);
kfree(info);
return ERR_PTR(ret);
}
@@ -4479,7 +4287,6 @@ static void intel_iommu_release_device(struct device *dev)
dmar_remove_one_dev_info(dev);
intel_pasid_free_table(dev);
intel_iommu_debugfs_remove_dev(info);
- dev_iommu_priv_set(dev, NULL);
kfree(info);
set_dma_ops(dev, NULL);
}
@@ -4739,8 +4546,9 @@ static int intel_iommu_iotlb_sync_map(struct iommu_domain *domain,
static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid)
{
- struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL);
+ struct device_domain_info *info = dev_iommu_priv_get(dev);
struct dev_pasid_info *curr, *dev_pasid = NULL;
+ struct intel_iommu *iommu = info->iommu;
struct dmar_domain *dmar_domain;
struct iommu_domain *domain;
unsigned long flags;
@@ -4811,8 +4619,7 @@ static int intel_iommu_set_dev_pasid(struct iommu_domain *domain,
goto out_free;
if (domain_type_is_si(dmar_domain))
- ret = intel_pasid_setup_pass_through(iommu, dmar_domain,
- dev, pasid);
+ ret = intel_pasid_setup_pass_through(iommu, dev, pasid);
else if (dmar_domain->use_first_level)
ret = domain_setup_first_level(iommu, dmar_domain,
dev, pasid);
diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h
index ce030c5b5772..d02f916d8e59 100644
--- a/drivers/iommu/intel/iommu.h
+++ b/drivers/iommu/intel/iommu.h
@@ -140,9 +140,6 @@
#define DMAR_ECEO_REG 0x408
#define DMAR_ECRSP_REG 0x410
#define DMAR_ECCAP_REG 0x430
-#define DMAR_VCCAP_REG 0xe30 /* Virtual command capability register */
-#define DMAR_VCMD_REG 0xe00 /* Virtual command register */
-#define DMAR_VCRSP_REG 0xe10 /* Virtual command response register */
#define DMAR_IQER_REG_IQEI(reg) FIELD_GET(GENMASK_ULL(3, 0), reg)
#define DMAR_IQER_REG_ITESID(reg) FIELD_GET(GENMASK_ULL(47, 32), reg)
@@ -854,6 +851,181 @@ static inline bool context_present(struct context_entry *context)
return (context->lo & 1);
}
+#define LEVEL_STRIDE (9)
+#define LEVEL_MASK (((u64)1 << LEVEL_STRIDE) - 1)
+#define MAX_AGAW_WIDTH (64)
+#define MAX_AGAW_PFN_WIDTH (MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
+
+static inline int agaw_to_level(int agaw)
+{
+ return agaw + 2;
+}
+
+static inline int agaw_to_width(int agaw)
+{
+ return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
+}
+
+static inline int width_to_agaw(int width)
+{
+ return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
+}
+
+static inline unsigned int level_to_offset_bits(int level)
+{
+ return (level - 1) * LEVEL_STRIDE;
+}
+
+static inline int pfn_level_offset(u64 pfn, int level)
+{
+ return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
+}
+
+static inline u64 level_mask(int level)
+{
+ return -1ULL << level_to_offset_bits(level);
+}
+
+static inline u64 level_size(int level)
+{
+ return 1ULL << level_to_offset_bits(level);
+}
+
+static inline u64 align_to_level(u64 pfn, int level)
+{
+ return (pfn + level_size(level) - 1) & level_mask(level);
+}
+
+static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
+{
+ return 1UL << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
+}
+
+/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
+ are never going to work. */
+static inline unsigned long mm_to_dma_pfn_start(unsigned long mm_pfn)
+{
+ return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
+}
+static inline unsigned long mm_to_dma_pfn_end(unsigned long mm_pfn)
+{
+ return ((mm_pfn + 1) << (PAGE_SHIFT - VTD_PAGE_SHIFT)) - 1;
+}
+static inline unsigned long page_to_dma_pfn(struct page *pg)
+{
+ return mm_to_dma_pfn_start(page_to_pfn(pg));
+}
+static inline unsigned long virt_to_dma_pfn(void *p)
+{
+ return page_to_dma_pfn(virt_to_page(p));
+}
+
+static inline void context_set_present(struct context_entry *context)
+{
+ context->lo |= 1;
+}
+
+static inline void context_set_fault_enable(struct context_entry *context)
+{
+ context->lo &= (((u64)-1) << 2) | 1;
+}
+
+static inline void context_set_translation_type(struct context_entry *context,
+ unsigned long value)
+{
+ context->lo &= (((u64)-1) << 4) | 3;
+ context->lo |= (value & 3) << 2;
+}
+
+static inline void context_set_address_root(struct context_entry *context,
+ unsigned long value)
+{
+ context->lo &= ~VTD_PAGE_MASK;
+ context->lo |= value & VTD_PAGE_MASK;
+}
+
+static inline void context_set_address_width(struct context_entry *context,
+ unsigned long value)
+{
+ context->hi |= value & 7;
+}
+
+static inline void context_set_domain_id(struct context_entry *context,
+ unsigned long value)
+{
+ context->hi |= (value & ((1 << 16) - 1)) << 8;
+}
+
+static inline void context_set_pasid(struct context_entry *context)
+{
+ context->lo |= CONTEXT_PASIDE;
+}
+
+static inline int context_domain_id(struct context_entry *c)
+{
+ return((c->hi >> 8) & 0xffff);
+}
+
+static inline void context_clear_entry(struct context_entry *context)
+{
+ context->lo = 0;
+ context->hi = 0;
+}
+
+#ifdef CONFIG_INTEL_IOMMU
+static inline bool context_copied(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+ if (!iommu->copied_tables)
+ return false;
+
+ return test_bit(((long)bus << 8) | devfn, iommu->copied_tables);
+}
+
+static inline void
+set_context_copied(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+ set_bit(((long)bus << 8) | devfn, iommu->copied_tables);
+}
+
+static inline void
+clear_context_copied(struct intel_iommu *iommu, u8 bus, u8 devfn)
+{
+ clear_bit(((long)bus << 8) | devfn, iommu->copied_tables);
+}
+#endif /* CONFIG_INTEL_IOMMU */
+
+/*
+ * Set the RID_PASID field of a scalable mode context entry. The
+ * IOMMU hardware will use the PASID value set in this field for
+ * DMA translations of DMA requests without PASID.
+ */
+static inline void
+context_set_sm_rid2pasid(struct context_entry *context, unsigned long pasid)
+{
+ context->hi |= pasid & ((1 << 20) - 1);
+}
+
+/*
+ * Set the DTE(Device-TLB Enable) field of a scalable mode context
+ * entry.
+ */
+static inline void context_set_sm_dte(struct context_entry *context)
+{
+ context->lo |= BIT_ULL(2);
+}
+
+/*
+ * Set the PRE(Page Request Enable) field of a scalable mode context
+ * entry.
+ */
+static inline void context_set_sm_pre(struct context_entry *context)
+{
+ context->lo |= BIT_ULL(4);
+}
+
+/* Convert value to context PASID directory size field coding. */
+#define context_pdts(pds) (((pds) & 0x7) << 9)
+
struct dmar_drhd_unit *dmar_find_matched_drhd_unit(struct pci_dev *dev);
int dmar_enable_qi(struct intel_iommu *iommu);
@@ -900,7 +1072,6 @@ int dmar_ir_support(void);
void *alloc_pgtable_page(int node, gfp_t gfp);
void free_pgtable_page(void *vaddr);
void iommu_flush_write_buffer(struct intel_iommu *iommu);
-struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn);
struct iommu_domain *intel_nested_domain_alloc(struct iommu_domain *parent,
const struct iommu_user_data *user_data);
diff --git a/drivers/iommu/intel/nested.c b/drivers/iommu/intel/nested.c
index b5a5563ab32c..f26c7f1c46cc 100644
--- a/drivers/iommu/intel/nested.c
+++ b/drivers/iommu/intel/nested.c
@@ -73,9 +73,97 @@ static void intel_nested_domain_free(struct iommu_domain *domain)
kfree(to_dmar_domain(domain));
}
+static void nested_flush_dev_iotlb(struct dmar_domain *domain, u64 addr,
+ unsigned int mask)
+{
+ struct device_domain_info *info;
+ unsigned long flags;
+ u16 sid, qdep;
+
+ spin_lock_irqsave(&domain->lock, flags);
+ list_for_each_entry(info, &domain->devices, link) {
+ if (!info->ats_enabled)
+ continue;
+ sid = info->bus << 8 | info->devfn;
+ qdep = info->ats_qdep;
+ qi_flush_dev_iotlb(info->iommu, sid, info->pfsid,
+ qdep, addr, mask);
+ quirk_extra_dev_tlb_flush(info, addr, mask,
+ IOMMU_NO_PASID, qdep);
+ }
+ spin_unlock_irqrestore(&domain->lock, flags);
+}
+
+static void intel_nested_flush_cache(struct dmar_domain *domain, u64 addr,
+ unsigned long npages, bool ih)
+{
+ struct iommu_domain_info *info;
+ unsigned int mask;
+ unsigned long i;
+
+ xa_for_each(&domain->iommu_array, i, info)
+ qi_flush_piotlb(info->iommu,
+ domain_id_iommu(domain, info->iommu),
+ IOMMU_NO_PASID, addr, npages, ih);
+
+ if (!domain->has_iotlb_device)
+ return;
+
+ if (npages == U64_MAX)
+ mask = 64 - VTD_PAGE_SHIFT;
+ else
+ mask = ilog2(__roundup_pow_of_two(npages));
+
+ nested_flush_dev_iotlb(domain, addr, mask);
+}
+
+static int intel_nested_cache_invalidate_user(struct iommu_domain *domain,
+ struct iommu_user_data_array *array)
+{
+ struct dmar_domain *dmar_domain = to_dmar_domain(domain);
+ struct iommu_hwpt_vtd_s1_invalidate inv_entry;
+ u32 index, processed = 0;
+ int ret = 0;
+
+ if (array->type != IOMMU_HWPT_INVALIDATE_DATA_VTD_S1) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (index = 0; index < array->entry_num; index++) {
+ ret = iommu_copy_struct_from_user_array(&inv_entry, array,
+ IOMMU_HWPT_INVALIDATE_DATA_VTD_S1,
+ index, __reserved);
+ if (ret)
+ break;
+
+ if ((inv_entry.flags & ~IOMMU_VTD_INV_FLAGS_LEAF) ||
+ inv_entry.__reserved) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ if (!IS_ALIGNED(inv_entry.addr, VTD_PAGE_SIZE) ||
+ ((inv_entry.npages == U64_MAX) && inv_entry.addr)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ intel_nested_flush_cache(dmar_domain, inv_entry.addr,
+ inv_entry.npages,
+ inv_entry.flags & IOMMU_VTD_INV_FLAGS_LEAF);
+ processed++;
+ }
+
+out:
+ array->entry_num = processed;
+ return ret;
+}
+
static const struct iommu_domain_ops intel_nested_domain_ops = {
.attach_dev = intel_nested_attach_dev,
.free = intel_nested_domain_free,
+ .cache_invalidate_user = intel_nested_cache_invalidate_user,
};
struct iommu_domain *intel_nested_domain_alloc(struct iommu_domain *parent,
diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
index 74e8e4c17e81..3239cefa4c33 100644
--- a/drivers/iommu/intel/pasid.c
+++ b/drivers/iommu/intel/pasid.c
@@ -26,63 +26,6 @@
*/
u32 intel_pasid_max_id = PASID_MAX;
-int vcmd_alloc_pasid(struct intel_iommu *iommu, u32 *pasid)
-{
- unsigned long flags;
- u8 status_code;
- int ret = 0;
- u64 res;
-
- raw_spin_lock_irqsave(&iommu->register_lock, flags);
- dmar_writeq(iommu->reg + DMAR_VCMD_REG, VCMD_CMD_ALLOC);
- IOMMU_WAIT_OP(iommu, DMAR_VCRSP_REG, dmar_readq,
- !(res & VCMD_VRSP_IP), res);
- raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
-
- status_code = VCMD_VRSP_SC(res);
- switch (status_code) {
- case VCMD_VRSP_SC_SUCCESS:
- *pasid = VCMD_VRSP_RESULT_PASID(res);
- break;
- case VCMD_VRSP_SC_NO_PASID_AVAIL:
- pr_info("IOMMU: %s: No PASID available\n", iommu->name);
- ret = -ENOSPC;
- break;
- default:
- ret = -ENODEV;
- pr_warn("IOMMU: %s: Unexpected error code %d\n",
- iommu->name, status_code);
- }
-
- return ret;
-}
-
-void vcmd_free_pasid(struct intel_iommu *iommu, u32 pasid)
-{
- unsigned long flags;
- u8 status_code;
- u64 res;
-
- raw_spin_lock_irqsave(&iommu->register_lock, flags);
- dmar_writeq(iommu->reg + DMAR_VCMD_REG,
- VCMD_CMD_OPERAND(pasid) | VCMD_CMD_FREE);
- IOMMU_WAIT_OP(iommu, DMAR_VCRSP_REG, dmar_readq,
- !(res & VCMD_VRSP_IP), res);
- raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
-
- status_code = VCMD_VRSP_SC(res);
- switch (status_code) {
- case VCMD_VRSP_SC_SUCCESS:
- break;
- case VCMD_VRSP_SC_INVALID_PASID:
- pr_info("IOMMU: %s: Invalid PASID\n", iommu->name);
- break;
- default:
- pr_warn("IOMMU: %s: Unexpected error code %d\n",
- iommu->name, status_code);
- }
-}
-
/*
* Per device pasid table management:
*/
@@ -230,30 +173,6 @@ retry:
/*
* Interfaces for PASID table entry manipulation:
*/
-static inline void pasid_clear_entry(struct pasid_entry *pe)
-{
- WRITE_ONCE(pe->val[0], 0);
- WRITE_ONCE(pe->val[1], 0);
- WRITE_ONCE(pe->val[2], 0);
- WRITE_ONCE(pe->val[3], 0);
- WRITE_ONCE(pe->val[4], 0);
- WRITE_ONCE(pe->val[5], 0);
- WRITE_ONCE(pe->val[6], 0);
- WRITE_ONCE(pe->val[7], 0);
-}
-
-static inline void pasid_clear_entry_with_fpd(struct pasid_entry *pe)
-{
- WRITE_ONCE(pe->val[0], PASID_PTE_FPD);
- WRITE_ONCE(pe->val[1], 0);
- WRITE_ONCE(pe->val[2], 0);
- WRITE_ONCE(pe->val[3], 0);
- WRITE_ONCE(pe->val[4], 0);
- WRITE_ONCE(pe->val[5], 0);
- WRITE_ONCE(pe->val[6], 0);
- WRITE_ONCE(pe->val[7], 0);
-}
-
static void
intel_pasid_clear_entry(struct device *dev, u32 pasid, bool fault_ignore)
{
@@ -269,192 +188,6 @@ intel_pasid_clear_entry(struct device *dev, u32 pasid, bool fault_ignore)
pasid_clear_entry(pe);
}
-static inline void pasid_set_bits(u64 *ptr, u64 mask, u64 bits)
-{
- u64 old;
-
- old = READ_ONCE(*ptr);
- WRITE_ONCE(*ptr, (old & ~mask) | bits);
-}
-
-static inline u64 pasid_get_bits(u64 *ptr)
-{
- return READ_ONCE(*ptr);
-}
-
-/*
- * Setup the DID(Domain Identifier) field (Bit 64~79) of scalable mode
- * PASID entry.
- */
-static inline void
-pasid_set_domain_id(struct pasid_entry *pe, u64 value)
-{
- pasid_set_bits(&pe->val[1], GENMASK_ULL(15, 0), value);
-}
-
-/*
- * Get domain ID value of a scalable mode PASID entry.
- */
-static inline u16
-pasid_get_domain_id(struct pasid_entry *pe)
-{
- return (u16)(READ_ONCE(pe->val[1]) & GENMASK_ULL(15, 0));
-}
-
-/*
- * Setup the SLPTPTR(Second Level Page Table Pointer) field (Bit 12~63)
- * of a scalable mode PASID entry.
- */
-static inline void
-pasid_set_slptr(struct pasid_entry *pe, u64 value)
-{
- pasid_set_bits(&pe->val[0], VTD_PAGE_MASK, value);
-}
-
-/*
- * Setup the AW(Address Width) field (Bit 2~4) of a scalable mode PASID
- * entry.
- */
-static inline void
-pasid_set_address_width(struct pasid_entry *pe, u64 value)
-{
- pasid_set_bits(&pe->val[0], GENMASK_ULL(4, 2), value << 2);
-}
-
-/*
- * Setup the PGTT(PASID Granular Translation Type) field (Bit 6~8)
- * of a scalable mode PASID entry.
- */
-static inline void
-pasid_set_translation_type(struct pasid_entry *pe, u64 value)
-{
- pasid_set_bits(&pe->val[0], GENMASK_ULL(8, 6), value << 6);
-}
-
-/*
- * Enable fault processing by clearing the FPD(Fault Processing
- * Disable) field (Bit 1) of a scalable mode PASID entry.
- */
-static inline void pasid_set_fault_enable(struct pasid_entry *pe)
-{
- pasid_set_bits(&pe->val[0], 1 << 1, 0);
-}
-
-/*
- * Enable second level A/D bits by setting the SLADE (Second Level
- * Access Dirty Enable) field (Bit 9) of a scalable mode PASID
- * entry.
- */
-static inline void pasid_set_ssade(struct pasid_entry *pe)
-{
- pasid_set_bits(&pe->val[0], 1 << 9, 1 << 9);
-}
-
-/*
- * Disable second level A/D bits by clearing the SLADE (Second Level
- * Access Dirty Enable) field (Bit 9) of a scalable mode PASID
- * entry.
- */
-static inline void pasid_clear_ssade(struct pasid_entry *pe)
-{
- pasid_set_bits(&pe->val[0], 1 << 9, 0);
-}
-
-/*
- * Checks if second level A/D bits specifically the SLADE (Second Level
- * Access Dirty Enable) field (Bit 9) of a scalable mode PASID
- * entry is set.
- */
-static inline bool pasid_get_ssade(struct pasid_entry *pe)
-{
- return pasid_get_bits(&pe->val[0]) & (1 << 9);
-}
-
-/*
- * Setup the SRE(Supervisor Request Enable) field (Bit 128) of a
- * scalable mode PASID entry.
- */
-static inline void pasid_set_sre(struct pasid_entry *pe)
-{
- pasid_set_bits(&pe->val[2], 1 << 0, 1);
-}
-
-/*
- * Setup the WPE(Write Protect Enable) field (Bit 132) of a
- * scalable mode PASID entry.
- */
-static inline void pasid_set_wpe(struct pasid_entry *pe)
-{
- pasid_set_bits(&pe->val[2], 1 << 4, 1 << 4);
-}
-
-/*
- * Setup the P(Present) field (Bit 0) of a scalable mode PASID
- * entry.
- */
-static inline void pasid_set_present(struct pasid_entry *pe)
-{
- pasid_set_bits(&pe->val[0], 1 << 0, 1);
-}
-
-/*
- * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
- * entry.
- */
-static inline void pasid_set_page_snoop(struct pasid_entry *pe, bool value)
-{
- pasid_set_bits(&pe->val[1], 1 << 23, value << 23);
-}
-
-/*
- * Setup No Execute Enable bit (Bit 133) of a scalable mode PASID
- * entry. It is required when XD bit of the first level page table
- * entry is about to be set.
- */
-static inline void pasid_set_nxe(struct pasid_entry *pe)
-{
- pasid_set_bits(&pe->val[2], 1 << 5, 1 << 5);
-}
-
-/*
- * Setup the Page Snoop (PGSNP) field (Bit 88) of a scalable mode
- * PASID entry.
- */
-static inline void
-pasid_set_pgsnp(struct pasid_entry *pe)
-{
- pasid_set_bits(&pe->val[1], 1ULL << 24, 1ULL << 24);
-}
-
-/*
- * Setup the First Level Page table Pointer field (Bit 140~191)
- * of a scalable mode PASID entry.
- */
-static inline void
-pasid_set_flptr(struct pasid_entry *pe, u64 value)
-{
- pasid_set_bits(&pe->val[2], VTD_PAGE_MASK, value);
-}
-
-/*
- * Setup the First Level Paging Mode field (Bit 130~131) of a
- * scalable mode PASID entry.
- */
-static inline void
-pasid_set_flpm(struct pasid_entry *pe, u64 value)
-{
- pasid_set_bits(&pe->val[2], GENMASK_ULL(3, 2), value << 2);
-}
-
-/*
- * Setup the Extended Access Flag Enable (EAFE) field (Bit 135)
- * of a scalable mode PASID entry.
- */
-static inline void pasid_set_eafe(struct pasid_entry *pe)
-{
- pasid_set_bits(&pe->val[2], 1 << 7, 1 << 7);
-}
-
static void
pasid_cache_invalidation_with_pasid(struct intel_iommu *iommu,
u16 did, u32 pasid)
@@ -613,9 +346,9 @@ int intel_pasid_setup_first_level(struct intel_iommu *iommu,
* Skip top levels of page tables for iommu which has less agaw
* than default. Unnecessary for PT mode.
*/
-static inline int iommu_skip_agaw(struct dmar_domain *domain,
- struct intel_iommu *iommu,
- struct dma_pte **pgd)
+static int iommu_skip_agaw(struct dmar_domain *domain,
+ struct intel_iommu *iommu,
+ struct dma_pte **pgd)
{
int agaw;
@@ -767,7 +500,6 @@ int intel_pasid_setup_dirty_tracking(struct intel_iommu *iommu,
* Set up the scalable mode pasid entry for passthrough translation type.
*/
int intel_pasid_setup_pass_through(struct intel_iommu *iommu,
- struct dmar_domain *domain,
struct device *dev, u32 pasid)
{
u16 did = FLPT_DEFAULT_DID;
diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
index dd37611175cc..8d40d4c66e31 100644
--- a/drivers/iommu/intel/pasid.h
+++ b/drivers/iommu/intel/pasid.h
@@ -22,16 +22,6 @@
#define is_pasid_enabled(entry) (((entry)->lo >> 3) & 0x1)
#define get_pasid_dir_size(entry) (1 << ((((entry)->lo >> 9) & 0x7) + 7))
-/* Virtual command interface for enlightened pasid management. */
-#define VCMD_CMD_ALLOC 0x1
-#define VCMD_CMD_FREE 0x2
-#define VCMD_VRSP_IP 0x1
-#define VCMD_VRSP_SC(e) (((e) & 0xff) >> 1)
-#define VCMD_VRSP_SC_SUCCESS 0
-#define VCMD_VRSP_SC_NO_PASID_AVAIL 16
-#define VCMD_VRSP_SC_INVALID_PASID 16
-#define VCMD_VRSP_RESULT_PASID(e) (((e) >> 16) & 0xfffff)
-#define VCMD_CMD_OPERAND(e) ((e) << 16)
/*
* Domain ID reserved for pasid entries programmed for first-level
* only and pass-through transfer modes.
@@ -96,6 +86,216 @@ static inline u16 pasid_pte_get_pgtt(struct pasid_entry *pte)
return (u16)((READ_ONCE(pte->val[0]) >> 6) & 0x7);
}
+static inline void pasid_clear_entry(struct pasid_entry *pe)
+{
+ WRITE_ONCE(pe->val[0], 0);
+ WRITE_ONCE(pe->val[1], 0);
+ WRITE_ONCE(pe->val[2], 0);
+ WRITE_ONCE(pe->val[3], 0);
+ WRITE_ONCE(pe->val[4], 0);
+ WRITE_ONCE(pe->val[5], 0);
+ WRITE_ONCE(pe->val[6], 0);
+ WRITE_ONCE(pe->val[7], 0);
+}
+
+static inline void pasid_clear_entry_with_fpd(struct pasid_entry *pe)
+{
+ WRITE_ONCE(pe->val[0], PASID_PTE_FPD);
+ WRITE_ONCE(pe->val[1], 0);
+ WRITE_ONCE(pe->val[2], 0);
+ WRITE_ONCE(pe->val[3], 0);
+ WRITE_ONCE(pe->val[4], 0);
+ WRITE_ONCE(pe->val[5], 0);
+ WRITE_ONCE(pe->val[6], 0);
+ WRITE_ONCE(pe->val[7], 0);
+}
+
+static inline void pasid_set_bits(u64 *ptr, u64 mask, u64 bits)
+{
+ u64 old;
+
+ old = READ_ONCE(*ptr);
+ WRITE_ONCE(*ptr, (old & ~mask) | bits);
+}
+
+static inline u64 pasid_get_bits(u64 *ptr)
+{
+ return READ_ONCE(*ptr);
+}
+
+/*
+ * Setup the DID(Domain Identifier) field (Bit 64~79) of scalable mode
+ * PASID entry.
+ */
+static inline void
+pasid_set_domain_id(struct pasid_entry *pe, u64 value)
+{
+ pasid_set_bits(&pe->val[1], GENMASK_ULL(15, 0), value);
+}
+
+/*
+ * Get domain ID value of a scalable mode PASID entry.
+ */
+static inline u16
+pasid_get_domain_id(struct pasid_entry *pe)
+{
+ return (u16)(READ_ONCE(pe->val[1]) & GENMASK_ULL(15, 0));
+}
+
+/*
+ * Setup the SLPTPTR(Second Level Page Table Pointer) field (Bit 12~63)
+ * of a scalable mode PASID entry.
+ */
+static inline void
+pasid_set_slptr(struct pasid_entry *pe, u64 value)
+{
+ pasid_set_bits(&pe->val[0], VTD_PAGE_MASK, value);
+}
+
+/*
+ * Setup the AW(Address Width) field (Bit 2~4) of a scalable mode PASID
+ * entry.
+ */
+static inline void
+pasid_set_address_width(struct pasid_entry *pe, u64 value)
+{
+ pasid_set_bits(&pe->val[0], GENMASK_ULL(4, 2), value << 2);
+}
+
+/*
+ * Setup the PGTT(PASID Granular Translation Type) field (Bit 6~8)
+ * of a scalable mode PASID entry.
+ */
+static inline void
+pasid_set_translation_type(struct pasid_entry *pe, u64 value)
+{
+ pasid_set_bits(&pe->val[0], GENMASK_ULL(8, 6), value << 6);
+}
+
+/*
+ * Enable fault processing by clearing the FPD(Fault Processing
+ * Disable) field (Bit 1) of a scalable mode PASID entry.
+ */
+static inline void pasid_set_fault_enable(struct pasid_entry *pe)
+{
+ pasid_set_bits(&pe->val[0], 1 << 1, 0);
+}
+
+/*
+ * Enable second level A/D bits by setting the SLADE (Second Level
+ * Access Dirty Enable) field (Bit 9) of a scalable mode PASID
+ * entry.
+ */
+static inline void pasid_set_ssade(struct pasid_entry *pe)
+{
+ pasid_set_bits(&pe->val[0], 1 << 9, 1 << 9);
+}
+
+/*
+ * Disable second level A/D bits by clearing the SLADE (Second Level
+ * Access Dirty Enable) field (Bit 9) of a scalable mode PASID
+ * entry.
+ */
+static inline void pasid_clear_ssade(struct pasid_entry *pe)
+{
+ pasid_set_bits(&pe->val[0], 1 << 9, 0);
+}
+
+/*
+ * Checks if second level A/D bits specifically the SLADE (Second Level
+ * Access Dirty Enable) field (Bit 9) of a scalable mode PASID
+ * entry is set.
+ */
+static inline bool pasid_get_ssade(struct pasid_entry *pe)
+{
+ return pasid_get_bits(&pe->val[0]) & (1 << 9);
+}
+
+/*
+ * Setup the SRE(Supervisor Request Enable) field (Bit 128) of a
+ * scalable mode PASID entry.
+ */
+static inline void pasid_set_sre(struct pasid_entry *pe)
+{
+ pasid_set_bits(&pe->val[2], 1 << 0, 1);
+}
+
+/*
+ * Setup the WPE(Write Protect Enable) field (Bit 132) of a
+ * scalable mode PASID entry.
+ */
+static inline void pasid_set_wpe(struct pasid_entry *pe)
+{
+ pasid_set_bits(&pe->val[2], 1 << 4, 1 << 4);
+}
+
+/*
+ * Setup the P(Present) field (Bit 0) of a scalable mode PASID
+ * entry.
+ */
+static inline void pasid_set_present(struct pasid_entry *pe)
+{
+ pasid_set_bits(&pe->val[0], 1 << 0, 1);
+}
+
+/*
+ * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
+ * entry.
+ */
+static inline void pasid_set_page_snoop(struct pasid_entry *pe, bool value)
+{
+ pasid_set_bits(&pe->val[1], 1 << 23, value << 23);
+}
+
+/*
+ * Setup No Execute Enable bit (Bit 133) of a scalable mode PASID
+ * entry. It is required when XD bit of the first level page table
+ * entry is about to be set.
+ */
+static inline void pasid_set_nxe(struct pasid_entry *pe)
+{
+ pasid_set_bits(&pe->val[2], 1 << 5, 1 << 5);
+}
+
+/*
+ * Setup the Page Snoop (PGSNP) field (Bit 88) of a scalable mode
+ * PASID entry.
+ */
+static inline void
+pasid_set_pgsnp(struct pasid_entry *pe)
+{
+ pasid_set_bits(&pe->val[1], 1ULL << 24, 1ULL << 24);
+}
+
+/*
+ * Setup the First Level Page table Pointer field (Bit 140~191)
+ * of a scalable mode PASID entry.
+ */
+static inline void
+pasid_set_flptr(struct pasid_entry *pe, u64 value)
+{
+ pasid_set_bits(&pe->val[2], VTD_PAGE_MASK, value);
+}
+
+/*
+ * Setup the First Level Paging Mode field (Bit 130~131) of a
+ * scalable mode PASID entry.
+ */
+static inline void
+pasid_set_flpm(struct pasid_entry *pe, u64 value)
+{
+ pasid_set_bits(&pe->val[2], GENMASK_ULL(3, 2), value << 2);
+}
+
+/*
+ * Setup the Extended Access Flag Enable (EAFE) field (Bit 135)
+ * of a scalable mode PASID entry.
+ */
+static inline void pasid_set_eafe(struct pasid_entry *pe)
+{
+ pasid_set_bits(&pe->val[2], 1 << 7, 1 << 7);
+}
+
extern unsigned int intel_pasid_max_id;
int intel_pasid_alloc_table(struct device *dev);
void intel_pasid_free_table(struct device *dev);
@@ -111,15 +311,12 @@ int intel_pasid_setup_dirty_tracking(struct intel_iommu *iommu,
struct device *dev, u32 pasid,
bool enabled);
int intel_pasid_setup_pass_through(struct intel_iommu *iommu,
- struct dmar_domain *domain,
struct device *dev, u32 pasid);
int intel_pasid_setup_nested(struct intel_iommu *iommu, struct device *dev,
u32 pasid, struct dmar_domain *domain);
void intel_pasid_tear_down_entry(struct intel_iommu *iommu,
struct device *dev, u32 pasid,
bool fault_ignore);
-int vcmd_alloc_pasid(struct intel_iommu *iommu, u32 *pasid);
-void vcmd_free_pasid(struct intel_iommu *iommu, u32 pasid);
void intel_pasid_setup_page_snoop_control(struct intel_iommu *iommu,
struct device *dev, u32 pasid);
#endif /* __INTEL_PASID_H */
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index ac12f76c1212..40edd282903f 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -316,21 +316,22 @@ out:
}
static int intel_svm_bind_mm(struct intel_iommu *iommu, struct device *dev,
- struct mm_struct *mm)
+ struct iommu_domain *domain, ioasid_t pasid)
{
struct device_domain_info *info = dev_iommu_priv_get(dev);
+ struct mm_struct *mm = domain->mm;
struct intel_svm_dev *sdev;
struct intel_svm *svm;
unsigned long sflags;
int ret = 0;
- svm = pasid_private_find(mm->pasid);
+ svm = pasid_private_find(pasid);
if (!svm) {
svm = kzalloc(sizeof(*svm), GFP_KERNEL);
if (!svm)
return -ENOMEM;
- svm->pasid = mm->pasid;
+ svm->pasid = pasid;
svm->mm = mm;
INIT_LIST_HEAD_RCU(&svm->devs);
@@ -368,7 +369,7 @@ static int intel_svm_bind_mm(struct intel_iommu *iommu, struct device *dev,
/* Setup the pasid table: */
sflags = cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
- ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd, mm->pasid,
+ ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd, pasid,
FLPT_DEFAULT_DID, sflags);
if (ret)
goto free_sdev;
@@ -382,7 +383,7 @@ free_sdev:
free_svm:
if (list_empty(&svm->devs)) {
mmu_notifier_unregister(&svm->notifier, mm);
- pasid_private_remove(mm->pasid);
+ pasid_private_remove(pasid);
kfree(svm);
}
@@ -392,14 +393,9 @@ free_svm:
void intel_svm_remove_dev_pasid(struct device *dev, u32 pasid)
{
struct intel_svm_dev *sdev;
- struct intel_iommu *iommu;
struct intel_svm *svm;
struct mm_struct *mm;
- iommu = device_to_iommu(dev, NULL, NULL);
- if (!iommu)
- return;
-
if (pasid_to_svm_sdev(dev, pasid, &svm, &sdev))
return;
mm = svm->mm;
@@ -750,25 +746,16 @@ int intel_svm_page_response(struct device *dev,
struct iommu_fault_event *evt,
struct iommu_page_response *msg)
{
+ struct device_domain_info *info = dev_iommu_priv_get(dev);
+ struct intel_iommu *iommu = info->iommu;
+ u8 bus = info->bus, devfn = info->devfn;
struct iommu_fault_page_request *prm;
- struct intel_iommu *iommu;
bool private_present;
bool pasid_present;
bool last_page;
- u8 bus, devfn;
int ret = 0;
u16 sid;
- if (!dev || !dev_is_pci(dev))
- return -ENODEV;
-
- iommu = device_to_iommu(dev, &bus, &devfn);
- if (!iommu)
- return -ENODEV;
-
- if (!msg || !evt)
- return -EINVAL;
-
prm = &evt->fault.prm;
sid = PCI_DEVID(bus, devfn);
pasid_present = prm->flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
@@ -822,9 +809,8 @@ static int intel_svm_set_dev_pasid(struct iommu_domain *domain,
{
struct device_domain_info *info = dev_iommu_priv_get(dev);
struct intel_iommu *iommu = info->iommu;
- struct mm_struct *mm = domain->mm;
- return intel_svm_bind_mm(iommu, dev, mm);
+ return intel_svm_bind_mm(iommu, dev, domain, pasid);
}
static void intel_svm_domain_free(struct iommu_domain *domain)
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
index 72dcdd468cf3..f7828a7aad41 100644
--- a/drivers/iommu/io-pgtable-arm.c
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -188,20 +188,28 @@ static dma_addr_t __arm_lpae_dma_addr(void *pages)
}
static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp,
- struct io_pgtable_cfg *cfg)
+ struct io_pgtable_cfg *cfg,
+ void *cookie)
{
struct device *dev = cfg->iommu_dev;
int order = get_order(size);
- struct page *p;
dma_addr_t dma;
void *pages;
VM_BUG_ON((gfp & __GFP_HIGHMEM));
- p = alloc_pages_node(dev_to_node(dev), gfp | __GFP_ZERO, order);
- if (!p)
+
+ if (cfg->alloc) {
+ pages = cfg->alloc(cookie, size, gfp);
+ } else {
+ struct page *p;
+
+ p = alloc_pages_node(dev_to_node(dev), gfp | __GFP_ZERO, order);
+ pages = p ? page_address(p) : NULL;
+ }
+
+ if (!pages)
return NULL;
- pages = page_address(p);
if (!cfg->coherent_walk) {
dma = dma_map_single(dev, pages, size, DMA_TO_DEVICE);
if (dma_mapping_error(dev, dma))
@@ -220,18 +228,28 @@ static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp,
out_unmap:
dev_err(dev, "Cannot accommodate DMA translation for IOMMU page tables\n");
dma_unmap_single(dev, dma, size, DMA_TO_DEVICE);
+
out_free:
- __free_pages(p, order);
+ if (cfg->free)
+ cfg->free(cookie, pages, size);
+ else
+ free_pages((unsigned long)pages, order);
+
return NULL;
}
static void __arm_lpae_free_pages(void *pages, size_t size,
- struct io_pgtable_cfg *cfg)
+ struct io_pgtable_cfg *cfg,
+ void *cookie)
{
if (!cfg->coherent_walk)
dma_unmap_single(cfg->iommu_dev, __arm_lpae_dma_addr(pages),
size, DMA_TO_DEVICE);
- free_pages((unsigned long)pages, get_order(size));
+
+ if (cfg->free)
+ cfg->free(cookie, pages, size);
+ else
+ free_pages((unsigned long)pages, get_order(size));
}
static void __arm_lpae_sync_pte(arm_lpae_iopte *ptep, int num_entries,
@@ -373,13 +391,13 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
/* Grab a pointer to the next level */
pte = READ_ONCE(*ptep);
if (!pte) {
- cptep = __arm_lpae_alloc_pages(tblsz, gfp, cfg);
+ cptep = __arm_lpae_alloc_pages(tblsz, gfp, cfg, data->iop.cookie);
if (!cptep)
return -ENOMEM;
pte = arm_lpae_install_table(cptep, ptep, 0, data);
if (pte)
- __arm_lpae_free_pages(cptep, tblsz, cfg);
+ __arm_lpae_free_pages(cptep, tblsz, cfg, data->iop.cookie);
} else if (!cfg->coherent_walk && !(pte & ARM_LPAE_PTE_SW_SYNC)) {
__arm_lpae_sync_pte(ptep, 1, cfg);
}
@@ -524,7 +542,7 @@ static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl,
__arm_lpae_free_pgtable(data, lvl + 1, iopte_deref(pte, data));
}
- __arm_lpae_free_pages(start, table_size, &data->iop.cfg);
+ __arm_lpae_free_pages(start, table_size, &data->iop.cfg, data->iop.cookie);
}
static void arm_lpae_free_pgtable(struct io_pgtable *iop)
@@ -552,7 +570,7 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
if (WARN_ON(lvl == ARM_LPAE_MAX_LEVELS))
return 0;
- tablep = __arm_lpae_alloc_pages(tablesz, GFP_ATOMIC, cfg);
+ tablep = __arm_lpae_alloc_pages(tablesz, GFP_ATOMIC, cfg, data->iop.cookie);
if (!tablep)
return 0; /* Bytes unmapped */
@@ -575,7 +593,7 @@ static size_t arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
pte = arm_lpae_install_table(tablep, ptep, blk_pte, data);
if (pte != blk_pte) {
- __arm_lpae_free_pages(tablep, tablesz, cfg);
+ __arm_lpae_free_pages(tablep, tablesz, cfg, data->iop.cookie);
/*
* We may race against someone unmapping another part of this
* block, but anything else is invalid. We can't misinterpret
@@ -882,7 +900,7 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
/* Looking good; allocate a pgd */
data->pgd = __arm_lpae_alloc_pages(ARM_LPAE_PGD_SIZE(data),
- GFP_KERNEL, cfg);
+ GFP_KERNEL, cfg, cookie);
if (!data->pgd)
goto out_free_data;
@@ -984,7 +1002,7 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
/* Allocate pgd pages */
data->pgd = __arm_lpae_alloc_pages(ARM_LPAE_PGD_SIZE(data),
- GFP_KERNEL, cfg);
+ GFP_KERNEL, cfg, cookie);
if (!data->pgd)
goto out_free_data;
@@ -1059,7 +1077,7 @@ arm_mali_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
<< ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_DEV));
data->pgd = __arm_lpae_alloc_pages(ARM_LPAE_PGD_SIZE(data), GFP_KERNEL,
- cfg);
+ cfg, cookie);
if (!data->pgd)
goto out_free_data;
@@ -1080,26 +1098,31 @@ out_free_data:
}
struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns = {
+ .caps = IO_PGTABLE_CAP_CUSTOM_ALLOCATOR,
.alloc = arm_64_lpae_alloc_pgtable_s1,
.free = arm_lpae_free_pgtable,
};
struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s2_init_fns = {
+ .caps = IO_PGTABLE_CAP_CUSTOM_ALLOCATOR,
.alloc = arm_64_lpae_alloc_pgtable_s2,
.free = arm_lpae_free_pgtable,
};
struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s1_init_fns = {
+ .caps = IO_PGTABLE_CAP_CUSTOM_ALLOCATOR,
.alloc = arm_32_lpae_alloc_pgtable_s1,
.free = arm_lpae_free_pgtable,
};
struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s2_init_fns = {
+ .caps = IO_PGTABLE_CAP_CUSTOM_ALLOCATOR,
.alloc = arm_32_lpae_alloc_pgtable_s2,
.free = arm_lpae_free_pgtable,
};
struct io_pgtable_init_fns io_pgtable_arm_mali_lpae_init_fns = {
+ .caps = IO_PGTABLE_CAP_CUSTOM_ALLOCATOR,
.alloc = arm_mali_lpae_alloc_pgtable,
.free = arm_lpae_free_pgtable,
};
diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c
index b843fcd365d2..8841c1487f00 100644
--- a/drivers/iommu/io-pgtable.c
+++ b/drivers/iommu/io-pgtable.c
@@ -34,6 +34,26 @@ io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] = {
#endif
};
+static int check_custom_allocator(enum io_pgtable_fmt fmt,
+ struct io_pgtable_cfg *cfg)
+{
+ /* No custom allocator, no need to check the format. */
+ if (!cfg->alloc && !cfg->free)
+ return 0;
+
+ /* When passing a custom allocator, both the alloc and free
+ * functions should be provided.
+ */
+ if (!cfg->alloc || !cfg->free)
+ return -EINVAL;
+
+ /* Make sure the format supports custom allocators. */
+ if (io_pgtable_init_table[fmt]->caps & IO_PGTABLE_CAP_CUSTOM_ALLOCATOR)
+ return 0;
+
+ return -EINVAL;
+}
+
struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt,
struct io_pgtable_cfg *cfg,
void *cookie)
@@ -44,6 +64,9 @@ struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt,
if (fmt >= IO_PGTABLE_NUM_FMTS)
return NULL;
+ if (check_custom_allocator(fmt, cfg))
+ return NULL;
+
fns = io_pgtable_init_table[fmt];
if (!fns)
return NULL;
diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c
index b78671a8a914..c3fc9201d0be 100644
--- a/drivers/iommu/iommu-sva.c
+++ b/drivers/iommu/iommu-sva.c
@@ -12,32 +12,42 @@
static DEFINE_MUTEX(iommu_sva_lock);
/* Allocate a PASID for the mm within range (inclusive) */
-static int iommu_sva_alloc_pasid(struct mm_struct *mm, struct device *dev)
+static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm, struct device *dev)
{
+ struct iommu_mm_data *iommu_mm;
ioasid_t pasid;
- int ret = 0;
+
+ lockdep_assert_held(&iommu_sva_lock);
if (!arch_pgtable_dma_compat(mm))
- return -EBUSY;
+ return ERR_PTR(-EBUSY);
- mutex_lock(&iommu_sva_lock);
+ iommu_mm = mm->iommu_mm;
/* Is a PASID already associated with this mm? */
- if (mm_valid_pasid(mm)) {
- if (mm->pasid >= dev->iommu->max_pasids)
- ret = -EOVERFLOW;
- goto out;
+ if (iommu_mm) {
+ if (iommu_mm->pasid >= dev->iommu->max_pasids)
+ return ERR_PTR(-EOVERFLOW);
+ return iommu_mm;
}
+ iommu_mm = kzalloc(sizeof(struct iommu_mm_data), GFP_KERNEL);
+ if (!iommu_mm)
+ return ERR_PTR(-ENOMEM);
+
pasid = iommu_alloc_global_pasid(dev);
if (pasid == IOMMU_PASID_INVALID) {
- ret = -ENOSPC;
- goto out;
+ kfree(iommu_mm);
+ return ERR_PTR(-ENOSPC);
}
- mm->pasid = pasid;
- ret = 0;
-out:
- mutex_unlock(&iommu_sva_lock);
- return ret;
+ iommu_mm->pasid = pasid;
+ INIT_LIST_HEAD(&iommu_mm->sva_domains);
+ /*
+ * Make sure the write to mm->iommu_mm is not reordered in front of
+ * initialization to iommu_mm fields. If it does, readers may see a
+ * valid iommu_mm with uninitialized values.
+ */
+ smp_store_release(&mm->iommu_mm, iommu_mm);
+ return iommu_mm;
}
/**
@@ -58,57 +68,60 @@ out:
*/
struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
{
+ struct iommu_mm_data *iommu_mm;
struct iommu_domain *domain;
struct iommu_sva *handle;
int ret;
+ mutex_lock(&iommu_sva_lock);
+
/* Allocate mm->pasid if necessary. */
- ret = iommu_sva_alloc_pasid(mm, dev);
- if (ret)
- return ERR_PTR(ret);
+ iommu_mm = iommu_alloc_mm_data(mm, dev);
+ if (IS_ERR(iommu_mm)) {
+ ret = PTR_ERR(iommu_mm);
+ goto out_unlock;
+ }
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
- if (!handle)
- return ERR_PTR(-ENOMEM);
-
- mutex_lock(&iommu_sva_lock);
- /* Search for an existing domain. */
- domain = iommu_get_domain_for_dev_pasid(dev, mm->pasid,
- IOMMU_DOMAIN_SVA);
- if (IS_ERR(domain)) {
- ret = PTR_ERR(domain);
+ if (!handle) {
+ ret = -ENOMEM;
goto out_unlock;
}
- if (domain) {
- domain->users++;
- goto out;
+ /* Search for an existing domain. */
+ list_for_each_entry(domain, &mm->iommu_mm->sva_domains, next) {
+ ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid);
+ if (!ret) {
+ domain->users++;
+ goto out;
+ }
}
/* Allocate a new domain and set it on device pasid. */
domain = iommu_sva_domain_alloc(dev, mm);
if (!domain) {
ret = -ENOMEM;
- goto out_unlock;
+ goto out_free_handle;
}
- ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
+ ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid);
if (ret)
goto out_free_domain;
domain->users = 1;
+ list_add(&domain->next, &mm->iommu_mm->sva_domains);
+
out:
mutex_unlock(&iommu_sva_lock);
handle->dev = dev;
handle->domain = domain;
-
return handle;
out_free_domain:
iommu_domain_free(domain);
+out_free_handle:
+ kfree(handle);
out_unlock:
mutex_unlock(&iommu_sva_lock);
- kfree(handle);
-
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
@@ -124,12 +137,13 @@ EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
void iommu_sva_unbind_device(struct iommu_sva *handle)
{
struct iommu_domain *domain = handle->domain;
- ioasid_t pasid = domain->mm->pasid;
+ struct iommu_mm_data *iommu_mm = domain->mm->iommu_mm;
struct device *dev = handle->dev;
mutex_lock(&iommu_sva_lock);
+ iommu_detach_device_pasid(domain, dev, iommu_mm->pasid);
if (--domain->users == 0) {
- iommu_detach_device_pasid(domain, dev, pasid);
+ list_del(&domain->next);
iommu_domain_free(domain);
}
mutex_unlock(&iommu_sva_lock);
@@ -141,7 +155,7 @@ u32 iommu_sva_get_pasid(struct iommu_sva *handle)
{
struct iommu_domain *domain = handle->domain;
- return domain->mm->pasid;
+ return mm_get_enqcmd_pasid(domain->mm);
}
EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
@@ -205,8 +219,11 @@ out_put_mm:
void mm_pasid_drop(struct mm_struct *mm)
{
- if (likely(!mm_valid_pasid(mm)))
+ struct iommu_mm_data *iommu_mm = mm->iommu_mm;
+
+ if (!iommu_mm)
return;
- iommu_free_global_pasid(mm->pasid);
+ iommu_free_global_pasid(iommu_mm->pasid);
+ kfree(iommu_mm);
}
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 33e2a9b5d339..68e648b55767 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -148,7 +148,7 @@ struct iommu_group_attribute iommu_group_attr_##_name = \
static LIST_HEAD(iommu_device_list);
static DEFINE_SPINLOCK(iommu_device_lock);
-static struct bus_type * const iommu_buses[] = {
+static const struct bus_type * const iommu_buses[] = {
&platform_bus_type,
#ifdef CONFIG_PCI
&pci_bus_type,
@@ -257,13 +257,6 @@ int iommu_device_register(struct iommu_device *iommu,
/* We need to be able to take module references appropriately */
if (WARN_ON(is_module_address((unsigned long)ops) && !ops->owner))
return -EINVAL;
- /*
- * Temporarily enforce global restriction to a single driver. This was
- * already the de-facto behaviour, since any possible combination of
- * existing drivers would compete for at least the PCI or platform bus.
- */
- if (iommu_buses[0]->iommu_ops && iommu_buses[0]->iommu_ops != ops)
- return -EBUSY;
iommu->ops = ops;
if (hwdev)
@@ -273,10 +266,8 @@ int iommu_device_register(struct iommu_device *iommu,
list_add_tail(&iommu->list, &iommu_device_list);
spin_unlock(&iommu_device_lock);
- for (int i = 0; i < ARRAY_SIZE(iommu_buses) && !err; i++) {
- iommu_buses[i]->iommu_ops = ops;
+ for (int i = 0; i < ARRAY_SIZE(iommu_buses) && !err; i++)
err = bus_iommu_probe(iommu_buses[i]);
- }
if (err)
iommu_device_unregister(iommu);
return err;
@@ -329,7 +320,6 @@ int iommu_device_register_bus(struct iommu_device *iommu,
list_add_tail(&iommu->list, &iommu_device_list);
spin_unlock(&iommu_device_lock);
- bus->iommu_ops = ops;
err = bus_iommu_probe(bus);
if (err) {
iommu_device_unregister_bus(iommu, bus, nb);
@@ -344,6 +334,8 @@ static struct dev_iommu *dev_iommu_get(struct device *dev)
{
struct dev_iommu *param = dev->iommu;
+ lockdep_assert_held(&iommu_probe_device_lock);
+
if (param)
return param;
@@ -368,6 +360,15 @@ static void dev_iommu_free(struct device *dev)
kfree(param);
}
+/*
+ * Internal equivalent of device_iommu_mapped() for when we care that a device
+ * actually has API ops, and don't want false positives from VFIO-only groups.
+ */
+static bool dev_has_iommu(struct device *dev)
+{
+ return dev->iommu && dev->iommu->iommu_dev;
+}
+
static u32 dev_iommu_get_max_pasids(struct device *dev)
{
u32 max_pasids = 0, bits = 0;
@@ -386,6 +387,15 @@ static u32 dev_iommu_get_max_pasids(struct device *dev)
return min_t(u32, max_pasids, dev->iommu->iommu_dev->max_pasids);
}
+void dev_iommu_priv_set(struct device *dev, void *priv)
+{
+ /* FSL_PAMU does something weird */
+ if (!IS_ENABLED(CONFIG_FSL_PAMU))
+ lockdep_assert_held(&iommu_probe_device_lock);
+ dev->iommu->priv = priv;
+}
+EXPORT_SYMBOL_GPL(dev_iommu_priv_set);
+
/*
* Init the dev->iommu and dev->iommu_group in the struct device and get the
* driver probed
@@ -489,11 +499,26 @@ DEFINE_MUTEX(iommu_probe_device_lock);
static int __iommu_probe_device(struct device *dev, struct list_head *group_list)
{
- const struct iommu_ops *ops = dev->bus->iommu_ops;
+ const struct iommu_ops *ops;
+ struct iommu_fwspec *fwspec;
struct iommu_group *group;
struct group_device *gdev;
int ret;
+ /*
+ * For FDT-based systems and ACPI IORT/VIOT, drivers register IOMMU
+ * instances with non-NULL fwnodes, and client devices should have been
+ * identified with a fwspec by this point. Otherwise, we can currently
+ * assume that only one of Intel, AMD, s390, PAMU or legacy SMMUv2 can
+ * be present, and that any of their registered instances has suitable
+ * ops for probing, and thus cheekily co-opt the same mechanism.
+ */
+ fwspec = dev_iommu_fwspec_get(dev);
+ if (fwspec && fwspec->ops)
+ ops = fwspec->ops;
+ else
+ ops = iommu_ops_from_fwnode(NULL);
+
if (!ops)
return -ENODEV;
/*
@@ -618,7 +643,7 @@ static void __iommu_group_remove_device(struct device *dev)
list_del(&device->list);
__iommu_group_free_device(group, device);
- if (dev->iommu && dev->iommu->iommu_dev)
+ if (dev_has_iommu(dev))
iommu_deinit_device(dev);
else
dev->iommu_group = NULL;
@@ -817,7 +842,7 @@ int iommu_get_group_resv_regions(struct iommu_group *group,
* Non-API groups still expose reserved_regions in sysfs,
* so filter out calls that get here that way.
*/
- if (!device->dev->iommu)
+ if (!dev_has_iommu(device->dev))
break;
INIT_LIST_HEAD(&dev_resv_regions);
@@ -1223,6 +1248,12 @@ void iommu_group_remove_device(struct device *dev)
}
EXPORT_SYMBOL_GPL(iommu_group_remove_device);
+static struct device *iommu_group_first_dev(struct iommu_group *group)
+{
+ lockdep_assert_held(&group->mutex);
+ return list_first_entry(&group->devices, struct group_device, list)->dev;
+}
+
/**
* iommu_group_for_each_dev - iterate over each device in the group
* @group: the group
@@ -1751,30 +1782,13 @@ __iommu_group_alloc_default_domain(struct iommu_group *group, int req_type)
}
/*
- * Returns the iommu_ops for the devices in an iommu group.
- *
- * It is assumed that all devices in an iommu group are managed by a single
- * IOMMU unit. Therefore, this returns the dev_iommu_ops of the first device
- * in the group.
- */
-static const struct iommu_ops *group_iommu_ops(struct iommu_group *group)
-{
- struct group_device *device =
- list_first_entry(&group->devices, struct group_device, list);
-
- lockdep_assert_held(&group->mutex);
-
- return dev_iommu_ops(device->dev);
-}
-
-/*
* req_type of 0 means "auto" which means to select a domain based on
* iommu_def_domain_type or what the driver actually supports.
*/
static struct iommu_domain *
iommu_group_alloc_default_domain(struct iommu_group *group, int req_type)
{
- const struct iommu_ops *ops = group_iommu_ops(group);
+ const struct iommu_ops *ops = dev_iommu_ops(iommu_group_first_dev(group));
struct iommu_domain *dom;
lockdep_assert_held(&group->mutex);
@@ -1854,7 +1868,7 @@ static int iommu_bus_notifier(struct notifier_block *nb,
static int iommu_get_def_domain_type(struct iommu_group *group,
struct device *dev, int cur_type)
{
- const struct iommu_ops *ops = group_iommu_ops(group);
+ const struct iommu_ops *ops = dev_iommu_ops(dev);
int type;
if (!ops->def_domain_type)
@@ -2003,9 +2017,28 @@ int bus_iommu_probe(const struct bus_type *bus)
return 0;
}
+/**
+ * iommu_present() - make platform-specific assumptions about an IOMMU
+ * @bus: bus to check
+ *
+ * Do not use this function. You want device_iommu_mapped() instead.
+ *
+ * Return: true if some IOMMU is present and aware of devices on the given bus;
+ * in general it may not be the only IOMMU, and it may not have anything to do
+ * with whatever device you are ultimately interested in.
+ */
bool iommu_present(const struct bus_type *bus)
{
- return bus->iommu_ops != NULL;
+ bool ret = false;
+
+ for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) {
+ if (iommu_buses[i] == bus) {
+ spin_lock(&iommu_device_lock);
+ ret = !list_empty(&iommu_device_list);
+ spin_unlock(&iommu_device_lock);
+ }
+ }
+ return ret;
}
EXPORT_SYMBOL_GPL(iommu_present);
@@ -2021,7 +2054,7 @@ bool device_iommu_capable(struct device *dev, enum iommu_cap cap)
{
const struct iommu_ops *ops;
- if (!dev->iommu || !dev->iommu->iommu_dev)
+ if (!dev_has_iommu(dev))
return false;
ops = dev_iommu_ops(dev);
@@ -2107,6 +2140,7 @@ static struct iommu_domain *__iommu_domain_alloc(const struct iommu_ops *ops,
return ERR_PTR(-ENOMEM);
domain->type = type;
+ domain->owner = ops;
/*
* If not already set, assume all sizes by default; the driver
* may override this later
@@ -2132,21 +2166,37 @@ static struct iommu_domain *__iommu_domain_alloc(const struct iommu_ops *ops,
static struct iommu_domain *
__iommu_group_domain_alloc(struct iommu_group *group, unsigned int type)
{
- struct device *dev =
- list_first_entry(&group->devices, struct group_device, list)
- ->dev;
+ struct device *dev = iommu_group_first_dev(group);
- return __iommu_domain_alloc(group_iommu_ops(group), dev, type);
+ return __iommu_domain_alloc(dev_iommu_ops(dev), dev, type);
+}
+
+static int __iommu_domain_alloc_dev(struct device *dev, void *data)
+{
+ const struct iommu_ops **ops = data;
+
+ if (!dev_has_iommu(dev))
+ return 0;
+
+ if (WARN_ONCE(*ops && *ops != dev_iommu_ops(dev),
+ "Multiple IOMMU drivers present for bus %s, which the public IOMMU API can't fully support yet. You will still need to disable one or more for this to work, sorry!\n",
+ dev_bus_name(dev)))
+ return -EBUSY;
+
+ *ops = dev_iommu_ops(dev);
+ return 0;
}
struct iommu_domain *iommu_domain_alloc(const struct bus_type *bus)
{
+ const struct iommu_ops *ops = NULL;
+ int err = bus_for_each_dev(bus, NULL, &ops, __iommu_domain_alloc_dev);
struct iommu_domain *domain;
- if (bus == NULL || bus->iommu_ops == NULL)
+ if (err || !ops)
return NULL;
- domain = __iommu_domain_alloc(bus->iommu_ops, NULL,
- IOMMU_DOMAIN_UNMANAGED);
+
+ domain = __iommu_domain_alloc(ops, NULL, IOMMU_DOMAIN_UNMANAGED);
if (IS_ERR(domain))
return NULL;
return domain;
@@ -2284,10 +2334,16 @@ struct iommu_domain *iommu_get_dma_domain(struct device *dev)
static int __iommu_attach_group(struct iommu_domain *domain,
struct iommu_group *group)
{
+ struct device *dev;
+
if (group->domain && group->domain != group->default_domain &&
group->domain != group->blocking_domain)
return -EBUSY;
+ dev = iommu_group_first_dev(group);
+ if (!dev_has_iommu(dev) || dev_iommu_ops(dev) != domain->owner)
+ return -EINVAL;
+
return __iommu_group_set_domain(group, domain);
}
@@ -3004,8 +3060,8 @@ EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids);
*/
int iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features feat)
{
- if (dev->iommu && dev->iommu->iommu_dev) {
- const struct iommu_ops *ops = dev->iommu->iommu_dev->ops;
+ if (dev_has_iommu(dev)) {
+ const struct iommu_ops *ops = dev_iommu_ops(dev);
if (ops->dev_enable_feat)
return ops->dev_enable_feat(dev, feat);
@@ -3020,8 +3076,8 @@ EXPORT_SYMBOL_GPL(iommu_dev_enable_feature);
*/
int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)
{
- if (dev->iommu && dev->iommu->iommu_dev) {
- const struct iommu_ops *ops = dev->iommu->iommu_dev->ops;
+ if (dev_has_iommu(dev)) {
+ const struct iommu_ops *ops = dev_iommu_ops(dev);
if (ops->dev_disable_feat)
return ops->dev_disable_feat(dev, feat);
@@ -3481,6 +3537,9 @@ int iommu_attach_device_pasid(struct iommu_domain *domain,
if (!group)
return -ENODEV;
+ if (!dev_has_iommu(dev) || dev_iommu_ops(dev) != domain->owner)
+ return -EINVAL;
+
mutex_lock(&group->mutex);
curr = xa_cmpxchg(&group->pasid_array, pasid, NULL, domain, GFP_KERNEL);
if (curr) {
@@ -3569,6 +3628,7 @@ struct iommu_domain *iommu_sva_domain_alloc(struct device *dev,
domain->type = IOMMU_DOMAIN_SVA;
mmgrab(mm);
domain->mm = mm;
+ domain->owner = ops;
domain->iopf_handler = iommu_sva_handle_iopf;
domain->fault_data = mm;
diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c
index cbb5df0a6c32..3f3f1fa1a0a9 100644
--- a/drivers/iommu/iommufd/hw_pagetable.c
+++ b/drivers/iommu/iommufd/hw_pagetable.c
@@ -135,6 +135,7 @@ iommufd_hwpt_paging_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
hwpt->domain = NULL;
goto out_abort;
}
+ hwpt->domain->owner = ops;
} else {
hwpt->domain = iommu_domain_alloc(idev->dev->bus);
if (!hwpt->domain) {
@@ -233,6 +234,7 @@ iommufd_hwpt_nested_alloc(struct iommufd_ctx *ictx,
hwpt->domain = NULL;
goto out_abort;
}
+ hwpt->domain->owner = ops;
if (WARN_ON_ONCE(hwpt->domain->type != IOMMU_DOMAIN_NESTED)) {
rc = -EINVAL;
@@ -371,3 +373,44 @@ int iommufd_hwpt_get_dirty_bitmap(struct iommufd_ucmd *ucmd)
iommufd_put_object(ucmd->ictx, &hwpt_paging->common.obj);
return rc;
}
+
+int iommufd_hwpt_invalidate(struct iommufd_ucmd *ucmd)
+{
+ struct iommu_hwpt_invalidate *cmd = ucmd->cmd;
+ struct iommu_user_data_array data_array = {
+ .type = cmd->data_type,
+ .uptr = u64_to_user_ptr(cmd->data_uptr),
+ .entry_len = cmd->entry_len,
+ .entry_num = cmd->entry_num,
+ };
+ struct iommufd_hw_pagetable *hwpt;
+ u32 done_num = 0;
+ int rc;
+
+ if (cmd->__reserved) {
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (cmd->entry_num && (!cmd->data_uptr || !cmd->entry_len)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ hwpt = iommufd_get_hwpt_nested(ucmd, cmd->hwpt_id);
+ if (IS_ERR(hwpt)) {
+ rc = PTR_ERR(hwpt);
+ goto out;
+ }
+
+ rc = hwpt->domain->ops->cache_invalidate_user(hwpt->domain,
+ &data_array);
+ done_num = data_array.entry_num;
+
+ iommufd_put_object(ucmd->ictx, &hwpt->obj);
+out:
+ cmd->entry_num = done_num;
+ if (iommufd_ucmd_respond(ucmd, sizeof(*cmd)))
+ return -EFAULT;
+ return rc;
+}
diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
index abae041e256f..991f864d1f9b 100644
--- a/drivers/iommu/iommufd/iommufd_private.h
+++ b/drivers/iommu/iommufd/iommufd_private.h
@@ -328,6 +328,15 @@ iommufd_get_hwpt_paging(struct iommufd_ucmd *ucmd, u32 id)
IOMMUFD_OBJ_HWPT_PAGING),
struct iommufd_hwpt_paging, common.obj);
}
+
+static inline struct iommufd_hw_pagetable *
+iommufd_get_hwpt_nested(struct iommufd_ucmd *ucmd, u32 id)
+{
+ return container_of(iommufd_get_object(ucmd->ictx, id,
+ IOMMUFD_OBJ_HWPT_NESTED),
+ struct iommufd_hw_pagetable, obj);
+}
+
int iommufd_hwpt_set_dirty_tracking(struct iommufd_ucmd *ucmd);
int iommufd_hwpt_get_dirty_bitmap(struct iommufd_ucmd *ucmd);
@@ -345,6 +354,7 @@ void iommufd_hwpt_paging_abort(struct iommufd_object *obj);
void iommufd_hwpt_nested_destroy(struct iommufd_object *obj);
void iommufd_hwpt_nested_abort(struct iommufd_object *obj);
int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd);
+int iommufd_hwpt_invalidate(struct iommufd_ucmd *ucmd);
static inline void iommufd_hw_pagetable_put(struct iommufd_ctx *ictx,
struct iommufd_hw_pagetable *hwpt)
diff --git a/drivers/iommu/iommufd/iommufd_test.h b/drivers/iommu/iommufd/iommufd_test.h
index 7910fbe1962d..482d4059f5db 100644
--- a/drivers/iommu/iommufd/iommufd_test.h
+++ b/drivers/iommu/iommufd/iommufd_test.h
@@ -21,6 +21,7 @@ enum {
IOMMU_TEST_OP_ACCESS_REPLACE_IOAS,
IOMMU_TEST_OP_MOCK_DOMAIN_FLAGS,
IOMMU_TEST_OP_DIRTY,
+ IOMMU_TEST_OP_MD_CHECK_IOTLB,
};
enum {
@@ -121,6 +122,10 @@ struct iommu_test_cmd {
__aligned_u64 uptr;
__aligned_u64 out_nr_dirty;
} dirty;
+ struct {
+ __u32 id;
+ __u32 iotlb;
+ } check_iotlb;
};
__u32 last;
};
@@ -148,4 +153,22 @@ struct iommu_hwpt_selftest {
__u32 iotlb;
};
+/* Should not be equal to any defined value in enum iommu_hwpt_invalidate_data_type */
+#define IOMMU_HWPT_INVALIDATE_DATA_SELFTEST 0xdeadbeef
+#define IOMMU_HWPT_INVALIDATE_DATA_SELFTEST_INVALID 0xdadbeef
+
+/**
+ * struct iommu_hwpt_invalidate_selftest - Invalidation data for Mock driver
+ * (IOMMU_HWPT_INVALIDATE_DATA_SELFTEST)
+ * @flags: Invalidate flags
+ * @iotlb_id: Invalidate iotlb entry index
+ *
+ * If IOMMU_TEST_INVALIDATE_ALL is set in @flags, @iotlb_id will be ignored
+ */
+struct iommu_hwpt_invalidate_selftest {
+#define IOMMU_TEST_INVALIDATE_FLAG_ALL (1 << 0)
+ __u32 flags;
+ __u32 iotlb_id;
+};
+
#endif
diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c
index c9091e46d208..39b32932c61e 100644
--- a/drivers/iommu/iommufd/main.c
+++ b/drivers/iommu/iommufd/main.c
@@ -322,6 +322,7 @@ union ucmd_buffer {
struct iommu_hw_info info;
struct iommu_hwpt_alloc hwpt;
struct iommu_hwpt_get_dirty_bitmap get_dirty_bitmap;
+ struct iommu_hwpt_invalidate cache;
struct iommu_hwpt_set_dirty_tracking set_dirty_tracking;
struct iommu_ioas_alloc alloc;
struct iommu_ioas_allow_iovas allow_iovas;
@@ -360,6 +361,8 @@ static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = {
__reserved),
IOCTL_OP(IOMMU_HWPT_GET_DIRTY_BITMAP, iommufd_hwpt_get_dirty_bitmap,
struct iommu_hwpt_get_dirty_bitmap, data),
+ IOCTL_OP(IOMMU_HWPT_INVALIDATE, iommufd_hwpt_invalidate,
+ struct iommu_hwpt_invalidate, __reserved),
IOCTL_OP(IOMMU_HWPT_SET_DIRTY_TRACKING, iommufd_hwpt_set_dirty_tracking,
struct iommu_hwpt_set_dirty_tracking, __reserved),
IOCTL_OP(IOMMU_IOAS_ALLOC, iommufd_ioas_alloc_ioctl,
diff --git a/drivers/iommu/iommufd/selftest.c b/drivers/iommu/iommufd/selftest.c
index 022ef8f55088..d9e9920c7eba 100644
--- a/drivers/iommu/iommufd/selftest.c
+++ b/drivers/iommu/iommufd/selftest.c
@@ -25,6 +25,19 @@ static struct iommu_domain_ops domain_nested_ops;
size_t iommufd_test_memory_limit = 65536;
+struct mock_bus_type {
+ struct bus_type bus;
+ struct notifier_block nb;
+};
+
+static struct mock_bus_type iommufd_mock_bus_type = {
+ .bus = {
+ .name = "iommufd_mock",
+ },
+};
+
+static atomic_t mock_dev_num;
+
enum {
MOCK_DIRTY_TRACK = 1,
MOCK_IO_PAGE_SIZE = PAGE_SIZE / 2,
@@ -437,6 +450,8 @@ static struct iommu_device mock_iommu_device = {
static struct iommu_device *mock_probe_device(struct device *dev)
{
+ if (dev->bus != &iommufd_mock_bus_type.bus)
+ return ERR_PTR(-ENODEV);
return &mock_iommu_device;
}
@@ -473,9 +488,59 @@ static void mock_domain_free_nested(struct iommu_domain *domain)
kfree(mock_nested);
}
+static int
+mock_domain_cache_invalidate_user(struct iommu_domain *domain,
+ struct iommu_user_data_array *array)
+{
+ struct mock_iommu_domain_nested *mock_nested =
+ container_of(domain, struct mock_iommu_domain_nested, domain);
+ struct iommu_hwpt_invalidate_selftest inv;
+ u32 processed = 0;
+ int i = 0, j;
+ int rc = 0;
+
+ if (array->type != IOMMU_HWPT_INVALIDATE_DATA_SELFTEST) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ for ( ; i < array->entry_num; i++) {
+ rc = iommu_copy_struct_from_user_array(&inv, array,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ i, iotlb_id);
+ if (rc)
+ break;
+
+ if (inv.flags & ~IOMMU_TEST_INVALIDATE_FLAG_ALL) {
+ rc = -EOPNOTSUPP;
+ break;
+ }
+
+ if (inv.iotlb_id > MOCK_NESTED_DOMAIN_IOTLB_ID_MAX) {
+ rc = -EINVAL;
+ break;
+ }
+
+ if (inv.flags & IOMMU_TEST_INVALIDATE_FLAG_ALL) {
+ /* Invalidate all mock iotlb entries and ignore iotlb_id */
+ for (j = 0; j < MOCK_NESTED_DOMAIN_IOTLB_NUM; j++)
+ mock_nested->iotlb[j] = 0;
+ } else {
+ mock_nested->iotlb[inv.iotlb_id] = 0;
+ }
+
+ processed++;
+ }
+
+out:
+ array->entry_num = processed;
+ return rc;
+}
+
static struct iommu_domain_ops domain_nested_ops = {
.free = mock_domain_free_nested,
.attach_dev = mock_domain_nop_attach,
+ .cache_invalidate_user = mock_domain_cache_invalidate_user,
};
static inline struct iommufd_hw_pagetable *
@@ -526,19 +591,6 @@ get_md_pagetable_nested(struct iommufd_ucmd *ucmd, u32 mockpt_id,
return hwpt;
}
-struct mock_bus_type {
- struct bus_type bus;
- struct notifier_block nb;
-};
-
-static struct mock_bus_type iommufd_mock_bus_type = {
- .bus = {
- .name = "iommufd_mock",
- },
-};
-
-static atomic_t mock_dev_num;
-
static void mock_dev_release(struct device *dev)
{
struct mock_dev *mdev = container_of(dev, struct mock_dev, dev);
@@ -793,6 +845,28 @@ static int iommufd_test_md_check_refs(struct iommufd_ucmd *ucmd,
return 0;
}
+static int iommufd_test_md_check_iotlb(struct iommufd_ucmd *ucmd,
+ u32 mockpt_id, unsigned int iotlb_id,
+ u32 iotlb)
+{
+ struct mock_iommu_domain_nested *mock_nested;
+ struct iommufd_hw_pagetable *hwpt;
+ int rc = 0;
+
+ hwpt = get_md_pagetable_nested(ucmd, mockpt_id, &mock_nested);
+ if (IS_ERR(hwpt))
+ return PTR_ERR(hwpt);
+
+ mock_nested = container_of(hwpt->domain,
+ struct mock_iommu_domain_nested, domain);
+
+ if (iotlb_id > MOCK_NESTED_DOMAIN_IOTLB_ID_MAX ||
+ mock_nested->iotlb[iotlb_id] != iotlb)
+ rc = -EINVAL;
+ iommufd_put_object(ucmd->ictx, &hwpt->obj);
+ return rc;
+}
+
struct selftest_access {
struct iommufd_access *access;
struct file *file;
@@ -1274,6 +1348,10 @@ int iommufd_test(struct iommufd_ucmd *ucmd)
return iommufd_test_md_check_refs(
ucmd, u64_to_user_ptr(cmd->check_refs.uptr),
cmd->check_refs.length, cmd->check_refs.refs);
+ case IOMMU_TEST_OP_MD_CHECK_IOTLB:
+ return iommufd_test_md_check_iotlb(ucmd, cmd->id,
+ cmd->check_iotlb.id,
+ cmd->check_iotlb.iotlb);
case IOMMU_TEST_OP_CREATE_ACCESS:
return iommufd_test_create_access(ucmd, cmd->id,
cmd->create_access.flags);
diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 75279500a4a8..7abe9e85a570 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -863,16 +863,11 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain,
static struct iommu_device *mtk_iommu_probe_device(struct device *dev)
{
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- struct mtk_iommu_data *data;
+ struct mtk_iommu_data *data = dev_iommu_priv_get(dev);
struct device_link *link;
struct device *larbdev;
unsigned int larbid, larbidx, i;
- if (!fwspec || fwspec->ops != &mtk_iommu_ops)
- return ERR_PTR(-ENODEV); /* Not a iommu client device */
-
- data = dev_iommu_priv_get(dev);
-
if (!MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_MM))
return &data->iommu;
diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c
index 67e044c1a7d9..25b41222abae 100644
--- a/drivers/iommu/mtk_iommu_v1.c
+++ b/drivers/iommu/mtk_iommu_v1.c
@@ -481,9 +481,6 @@ static struct iommu_device *mtk_iommu_v1_probe_device(struct device *dev)
idx++;
}
- if (!fwspec || fwspec->ops != &mtk_iommu_v1_ops)
- return ERR_PTR(-ENODEV); /* Not a iommu client device */
-
data = dev_iommu_priv_get(dev);
/* Link the consumer device with the smi-larb device(supplier) */
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 35ba090f3b5e..719652b60840 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -17,8 +17,6 @@
#include <linux/slab.h>
#include <linux/fsl/mc.h>
-#define NO_IOMMU 1
-
static int of_iommu_xlate(struct device *dev,
struct of_phandle_args *iommu_spec)
{
@@ -29,7 +27,7 @@ static int of_iommu_xlate(struct device *dev,
ops = iommu_ops_from_fwnode(fwnode);
if ((ops && !ops->of_xlate) ||
!of_device_is_available(iommu_spec->np))
- return NO_IOMMU;
+ return -ENODEV;
ret = iommu_fwspec_init(dev, &iommu_spec->np->fwnode, ops);
if (ret)
@@ -61,7 +59,7 @@ static int of_iommu_configure_dev_id(struct device_node *master_np,
"iommu-map-mask", &iommu_spec.np,
iommu_spec.args);
if (err)
- return err == -ENODEV ? NO_IOMMU : err;
+ return err;
err = of_iommu_xlate(dev, &iommu_spec);
of_node_put(iommu_spec.np);
@@ -72,7 +70,7 @@ static int of_iommu_configure_dev(struct device_node *master_np,
struct device *dev)
{
struct of_phandle_args iommu_spec;
- int err = NO_IOMMU, idx = 0;
+ int err = -ENODEV, idx = 0;
while (!of_parse_phandle_with_args(master_np, "iommus",
"#iommu-cells",
@@ -107,16 +105,21 @@ static int of_iommu_configure_device(struct device_node *master_np,
of_iommu_configure_dev(master_np, dev);
}
-const struct iommu_ops *of_iommu_configure(struct device *dev,
- struct device_node *master_np,
- const u32 *id)
+/*
+ * Returns:
+ * 0 on success, an iommu was configured
+ * -ENODEV if the device does not have any IOMMU
+ * -EPROBEDEFER if probing should be tried again
+ * -errno fatal errors
+ */
+int of_iommu_configure(struct device *dev, struct device_node *master_np,
+ const u32 *id)
{
- const struct iommu_ops *ops = NULL;
struct iommu_fwspec *fwspec;
- int err = NO_IOMMU;
+ int err;
if (!master_np)
- return NULL;
+ return -ENODEV;
/* Serialise to make dev->iommu stable under our potential fwspec */
mutex_lock(&iommu_probe_device_lock);
@@ -124,7 +127,7 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
if (fwspec) {
if (fwspec->ops) {
mutex_unlock(&iommu_probe_device_lock);
- return fwspec->ops;
+ return 0;
}
/* In the deferred case, start again from scratch */
iommu_fwspec_free(dev);
@@ -147,36 +150,21 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
} else {
err = of_iommu_configure_device(master_np, dev, id);
}
-
- /*
- * Two success conditions can be represented by non-negative err here:
- * >0 : there is no IOMMU, or one was unavailable for non-fatal reasons
- * 0 : we found an IOMMU, and dev->fwspec is initialised appropriately
- * <0 : any actual error
- */
- if (!err) {
- /* The fwspec pointer changed, read it again */
- fwspec = dev_iommu_fwspec_get(dev);
- ops = fwspec->ops;
- }
mutex_unlock(&iommu_probe_device_lock);
- /*
- * If we have reason to believe the IOMMU driver missed the initial
- * probe for dev, replay it to get things in order.
- */
- if (!err && dev->bus)
- err = iommu_probe_device(dev);
-
- /* Ignore all other errors apart from EPROBE_DEFER */
- if (err == -EPROBE_DEFER) {
- ops = ERR_PTR(err);
- } else if (err < 0) {
- dev_dbg(dev, "Adding to IOMMU failed: %d\n", err);
- ops = NULL;
- }
+ if (err == -ENODEV || err == -EPROBE_DEFER)
+ return err;
+ if (err)
+ goto err_log;
- return ops;
+ err = iommu_probe_device(dev);
+ if (err)
+ goto err_log;
+ return 0;
+
+err_log:
+ dev_dbg(dev, "Adding to IOMMU failed: %pe\n", ERR_PTR(err));
+ return err;
}
static enum iommu_resv_type __maybe_unused
@@ -260,7 +248,14 @@ void of_iommu_get_resv_regions(struct device *dev, struct list_head *list)
phys_addr_t iova;
size_t length;
+ if (of_dma_is_coherent(dev->of_node))
+ prot |= IOMMU_CACHE;
+
maps = of_translate_dma_region(np, maps, &iova, &length);
+ if (length == 0) {
+ dev_warn(dev, "Cannot reserve IOVA region of 0 size\n");
+ continue;
+ }
type = iommu_resv_region_get_type(dev, &phys, iova, length);
region = iommu_alloc_resv_region(iova, length, prot, type,
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index c66b070841dd..c9528065a59a 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -1719,7 +1719,6 @@ static void omap_iommu_release_device(struct device *dev)
if (!dev->of_node || !arch_data)
return;
- dev_iommu_priv_set(dev, NULL);
kfree(arch_data);
}
diff --git a/drivers/iommu/sprd-iommu.c b/drivers/iommu/sprd-iommu.c
index 2eb9fb46703b..537359f10997 100644
--- a/drivers/iommu/sprd-iommu.c
+++ b/drivers/iommu/sprd-iommu.c
@@ -385,13 +385,7 @@ static phys_addr_t sprd_iommu_iova_to_phys(struct iommu_domain *domain,
static struct iommu_device *sprd_iommu_probe_device(struct device *dev)
{
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- struct sprd_iommu_device *sdev;
-
- if (!fwspec || fwspec->ops != &sprd_iommu_ops)
- return ERR_PTR(-ENODEV);
-
- sdev = dev_iommu_priv_get(dev);
+ struct sprd_iommu_device *sdev = dev_iommu_priv_get(dev);
return &sdev->iommu;
}
diff --git a/drivers/iommu/virtio-iommu.c b/drivers/iommu/virtio-iommu.c
index 379ebe03efb6..34db37fd9675 100644
--- a/drivers/iommu/virtio-iommu.c
+++ b/drivers/iommu/virtio-iommu.c
@@ -843,7 +843,7 @@ static int viommu_map_pages(struct iommu_domain *domain, unsigned long iova,
.flags = cpu_to_le32(flags),
};
- ret = viommu_send_req_sync(vdomain->viommu, &map, sizeof(map));
+ ret = viommu_add_req(vdomain->viommu, &map, sizeof(map));
if (ret) {
viommu_del_mappings(vdomain, iova, end);
return ret;
@@ -912,6 +912,33 @@ static void viommu_iotlb_sync(struct iommu_domain *domain,
viommu_sync_req(vdomain->viommu);
}
+static int viommu_iotlb_sync_map(struct iommu_domain *domain,
+ unsigned long iova, size_t size)
+{
+ struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+ /*
+ * May be called before the viommu is initialized including
+ * while creating direct mapping
+ */
+ if (!vdomain->nr_endpoints)
+ return 0;
+ return viommu_sync_req(vdomain->viommu);
+}
+
+static void viommu_flush_iotlb_all(struct iommu_domain *domain)
+{
+ struct viommu_domain *vdomain = to_viommu_domain(domain);
+
+ /*
+ * May be called before the viommu is initialized including
+ * while creating direct mapping
+ */
+ if (!vdomain->nr_endpoints)
+ return;
+ viommu_sync_req(vdomain->viommu);
+}
+
static void viommu_get_resv_regions(struct device *dev, struct list_head *head)
{
struct iommu_resv_region *entry, *new_entry, *msi = NULL;
@@ -969,9 +996,6 @@ static struct iommu_device *viommu_probe_device(struct device *dev)
struct viommu_dev *viommu = NULL;
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- if (!fwspec || fwspec->ops != &viommu_ops)
- return ERR_PTR(-ENODEV);
-
viommu = viommu_get_by_fwnode(fwspec->iommu_fwnode);
if (!viommu)
return ERR_PTR(-ENODEV);
@@ -1037,6 +1061,8 @@ static bool viommu_capable(struct device *dev, enum iommu_cap cap)
switch (cap) {
case IOMMU_CAP_CACHE_COHERENCY:
return true;
+ case IOMMU_CAP_DEFERRED_FLUSH:
+ return true;
default:
return false;
}
@@ -1057,7 +1083,9 @@ static struct iommu_ops viommu_ops = {
.map_pages = viommu_map_pages,
.unmap_pages = viommu_unmap_pages,
.iova_to_phys = viommu_iova_to_phys,
+ .flush_iotlb_all = viommu_flush_iotlb_all,
.iotlb_sync = viommu_iotlb_sync,
+ .iotlb_sync_map = viommu_iotlb_sync_map,
.free = viommu_domain_free,
}
};
diff --git a/drivers/ipack/devices/ipoctal.c b/drivers/ipack/devices/ipoctal.c
index da308be6c487..ba2e9e52d72b 100644
--- a/drivers/ipack/devices/ipoctal.c
+++ b/drivers/ipack/devices/ipoctal.c
@@ -158,9 +158,7 @@ static int ipoctal_get_icount(struct tty_struct *tty,
static void ipoctal_irq_rx(struct ipoctal_channel *channel, u8 sr)
{
struct tty_port *port = &channel->tty_port;
- unsigned char value;
- unsigned char flag;
- u8 isr;
+ u8 isr, value, flag;
do {
value = ioread8(&channel->regs->r.rhr);
@@ -202,8 +200,8 @@ static void ipoctal_irq_rx(struct ipoctal_channel *channel, u8 sr)
static void ipoctal_irq_tx(struct ipoctal_channel *channel)
{
- unsigned char value;
unsigned int *pointer_write = &channel->pointer_write;
+ u8 value;
if (channel->nb_bytes == 0)
return;
@@ -436,11 +434,11 @@ err_put_driver:
return res;
}
-static inline int ipoctal_copy_write_buffer(struct ipoctal_channel *channel,
- const u8 *buf, int count)
+static inline size_t ipoctal_copy_write_buffer(struct ipoctal_channel *channel,
+ const u8 *buf, size_t count)
{
unsigned long flags;
- int i;
+ size_t i;
unsigned int *pointer_read = &channel->pointer_read;
/* Copy the bytes from the user buffer to the internal one */
@@ -462,7 +460,7 @@ static ssize_t ipoctal_write_tty(struct tty_struct *tty, const u8 *buf,
size_t count)
{
struct ipoctal_channel *channel = tty->driver_data;
- unsigned int char_copied;
+ size_t char_copied;
char_copied = ipoctal_copy_write_buffer(channel, buf, count);
diff --git a/drivers/ipack/ipack.c b/drivers/ipack/ipack.c
index cc1ecfd49928..b1471ba016a5 100644
--- a/drivers/ipack/ipack.c
+++ b/drivers/ipack/ipack.c
@@ -207,7 +207,7 @@ struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
if (!bus)
return NULL;
- bus_nr = ida_simple_get(&ipack_ida, 0, 0, GFP_KERNEL);
+ bus_nr = ida_alloc(&ipack_ida, GFP_KERNEL);
if (bus_nr < 0) {
kfree(bus);
return NULL;
@@ -237,7 +237,7 @@ int ipack_bus_unregister(struct ipack_bus_device *bus)
{
bus_for_each_dev(&ipack_bus_type, NULL, bus,
ipack_unregister_bus_member);
- ida_simple_remove(&ipack_ida, bus->bus_nr);
+ ida_free(&ipack_ida, bus->bus_nr);
kfree(bus);
return 0;
}
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 2f3789515445..6e80d7bd3c4d 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1231,9 +1231,9 @@ static void capinc_tty_hangup(struct tty_struct *tty)
tty_port_hangup(&mp->port);
}
-static void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
+static void capinc_tty_send_xchar(struct tty_struct *tty, u8 ch)
{
- pr_debug("capinc_tty_send_xchar(%d)\n", ch);
+ pr_debug("capinc_tty_send_xchar(%u)\n", ch);
}
static const struct tty_operations capinc_ops = {
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 6292fddcc55c..d721b254e1e4 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -95,14 +95,18 @@ config LEDS_ARIEL
Say Y to if your machine is a Dell Wyse 3020 thin client.
config LEDS_AW200XX
- tristate "LED support for Awinic AW20036/AW20054/AW20072"
+ tristate "LED support for Awinic AW20036/AW20054/AW20072/AW20108"
depends on LEDS_CLASS
depends on I2C
help
- This option enables support for the AW20036/AW20054/AW20072 LED driver.
- It is a 3x12/6x9/6x12 matrix LED driver programmed via
- an I2C interface, up to 36/54/72 LEDs or 12/18/24 RGBs,
- 3 pattern controllers for auto breathing or group dimming control.
+ This option enables support for the Awinic AW200XX LED controllers.
+ It is a matrix LED driver programmed via an I2C interface. Devices have
+ a set of individually controlled LEDs and support 3 pattern controllers
+ for auto breathing or group dimming control. Supported devices:
+ - AW20036 (3x12) 36 LEDs
+ - AW20054 (6x9) 54 LEDs
+ - AW20072 (6x12) 72 LEDs
+ - AW20108 (9x12) 108 LEDs
To compile this driver as a module, choose M here: the module
will be called leds-aw200xx.
@@ -110,6 +114,7 @@ config LEDS_AW200XX
config LEDS_AW2013
tristate "LED support for Awinic AW2013"
depends on LEDS_CLASS && I2C && OF
+ select REGMAP_I2C
help
This option enables support for the AW2013 3-channel
LED driver.
@@ -298,6 +303,15 @@ config LEDS_COBALT_RAQ
help
This option enables support for the Cobalt Raq series LEDs.
+config LEDS_SUN50I_A100
+ tristate "LED support for Allwinner A100 RGB LED controller"
+ depends on LEDS_CLASS_MULTICOLOR
+ depends on ARCH_SUNXI || COMPILE_TEST
+ help
+ This option enables support for the RGB LED controller found
+ in some Allwinner sunxi SoCs, including A100, R329, and D1.
+ It uses a one-wire interface to control up to 1024 LEDs.
+
config LEDS_SUNFIRE
tristate "LED support for SunFire servers."
depends on LEDS_CLASS
@@ -638,6 +652,17 @@ config LEDS_ADP5520
To compile this driver as a module, choose M here: the module will
be called leds-adp5520.
+config LEDS_MAX5970
+ tristate "LED Support for Maxim 5970"
+ depends on LEDS_CLASS
+ depends on MFD_MAX5970
+ help
+ This option enables support for the Maxim MAX5970 & MAX5978 smart
+ switch indication LEDs via the I2C bus.
+
+ To compile this driver as a module, choose M here: the module will
+ be called leds-max5970.
+
config LEDS_MC13783
tristate "LED Support for MC13XXX PMIC"
depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index d7348e8bc019..ce07dc295ff0 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_LEDS_LP8501) += leds-lp8501.o
obj-$(CONFIG_LEDS_LP8788) += leds-lp8788.o
obj-$(CONFIG_LEDS_LP8860) += leds-lp8860.o
obj-$(CONFIG_LEDS_LT3593) += leds-lt3593.o
+obj-$(CONFIG_LEDS_MAX5970) += leds-max5970.o
obj-$(CONFIG_LEDS_MAX77650) += leds-max77650.o
obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
@@ -78,6 +79,7 @@ obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o
obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
+obj-$(CONFIG_LEDS_SUN50I_A100) += leds-sun50i-a100.o
obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o
obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 6a5e1f41f9a4..bd59a14a4a90 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -269,19 +269,6 @@ void led_trigger_set_default(struct led_classdev *led_cdev)
}
EXPORT_SYMBOL_GPL(led_trigger_set_default);
-void led_trigger_rename_static(const char *name, struct led_trigger *trig)
-{
- /* new name must be on a temporary string to prevent races */
- BUG_ON(name == trig->name);
-
- down_write(&triggers_list_lock);
- /* this assumes that trig->name was originaly allocated to
- * non constant storage */
- strcpy((char *)trig->name, name);
- up_write(&triggers_list_lock);
-}
-EXPORT_SYMBOL_GPL(led_trigger_rename_static);
-
/* LED Trigger Interface */
int led_trigger_register(struct led_trigger *trig)
diff --git a/drivers/leds/leds-aw200xx.c b/drivers/leds/leds-aw200xx.c
index 14ca236ce29e..f584a7f98fc5 100644
--- a/drivers/leds/leds-aw200xx.c
+++ b/drivers/leds/leds-aw200xx.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Awinic AW20036/AW20054/AW20072 LED driver
+ * Awinic AW20036/AW20054/AW20072/AW20108 LED driver
*
* Copyright (c) 2023, SberDevices. All Rights Reserved.
*
@@ -10,6 +10,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/container_of.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/leds.h>
#include <linux/mod_devicetable.h>
@@ -74,6 +75,10 @@
#define AW200XX_LED2REG(x, columns) \
((x) + (((x) / (columns)) * (AW200XX_DSIZE_COLUMNS_MAX - (columns))))
+/* DIM current configuration register on page 1 */
+#define AW200XX_REG_DIM_PAGE1(x, columns) \
+ AW200XX_REG(AW200XX_PAGE1, AW200XX_LED2REG(x, columns))
+
/*
* DIM current configuration register (page 4).
* The even address for current DIM configuration.
@@ -82,6 +87,8 @@
#define AW200XX_REG_DIM(x, columns) \
AW200XX_REG(AW200XX_PAGE4, AW200XX_LED2REG(x, columns) * 2)
#define AW200XX_REG_DIM2FADE(x) ((x) + 1)
+#define AW200XX_REG_FADE2DIM(fade) \
+ DIV_ROUND_UP((fade) * AW200XX_DIM_MAX, AW200XX_FADE_MAX)
/*
* Duty ratio of display scan (see p.15 of datasheet for formula):
@@ -112,6 +119,7 @@ struct aw200xx {
struct mutex mutex;
u32 num_leds;
u32 display_rows;
+ struct gpio_desc *hwen;
struct aw200xx_led leds[] __counted_by(num_leds);
};
@@ -153,7 +161,8 @@ static ssize_t dim_store(struct device *dev, struct device_attribute *devattr,
if (dim >= 0) {
ret = regmap_write(chip->regmap,
- AW200XX_REG_DIM(led->num, columns), dim);
+ AW200XX_REG_DIM_PAGE1(led->num, columns),
+ dim);
if (ret)
goto out_unlock;
}
@@ -188,9 +197,7 @@ static int aw200xx_brightness_set(struct led_classdev *cdev,
dim = led->dim;
if (dim < 0)
- dim = max_t(int,
- brightness / (AW200XX_FADE_MAX / AW200XX_DIM_MAX),
- 1);
+ dim = AW200XX_REG_FADE2DIM(brightness);
ret = regmap_write(chip->regmap, reg, dim);
if (ret)
@@ -314,6 +321,9 @@ static int aw200xx_chip_reset(const struct aw200xx *const chip)
if (ret)
return ret;
+ /* According to the datasheet software reset takes at least 1ms */
+ fsleep(1000);
+
regcache_mark_dirty(chip->regmap);
return regmap_write(chip->regmap, AW200XX_REG_FCD, AW200XX_FCD_CLEAR);
}
@@ -353,6 +363,50 @@ static int aw200xx_chip_check(const struct aw200xx *const chip)
return 0;
}
+static void aw200xx_enable(const struct aw200xx *const chip)
+{
+ gpiod_set_value_cansleep(chip->hwen, 1);
+
+ /*
+ * After HWEN pin set high the chip begins to load the OTP information,
+ * which takes 200us to complete. About 200us wait time is needed for
+ * internal oscillator startup and display SRAM initialization. After
+ * display SRAM initialization, the registers in page1 to page5 can be
+ * configured via i2c interface.
+ */
+ fsleep(400);
+}
+
+static void aw200xx_disable(const struct aw200xx *const chip)
+{
+ return gpiod_set_value_cansleep(chip->hwen, 0);
+}
+
+static int aw200xx_probe_get_display_rows(struct device *dev,
+ struct aw200xx *chip)
+{
+ struct fwnode_handle *child;
+ u32 max_source = 0;
+
+ device_for_each_child_node(dev, child) {
+ u32 source;
+ int ret;
+
+ ret = fwnode_property_read_u32(child, "reg", &source);
+ if (ret || source >= chip->cdef->channels)
+ continue;
+
+ max_source = max(max_source, source);
+ }
+
+ if (max_source == 0)
+ return -EINVAL;
+
+ chip->display_rows = max_source / chip->cdef->display_size_columns + 1;
+
+ return 0;
+}
+
static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip)
{
struct fwnode_handle *child;
@@ -360,18 +414,10 @@ static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip)
int ret;
int i;
- ret = device_property_read_u32(dev, "awinic,display-rows",
- &chip->display_rows);
+ ret = aw200xx_probe_get_display_rows(dev, chip);
if (ret)
return dev_err_probe(dev, ret,
- "Failed to read 'display-rows' property\n");
-
- if (!chip->display_rows ||
- chip->display_rows > chip->cdef->display_size_rows_max) {
- return dev_err_probe(dev, -EINVAL,
- "Invalid leds display size %u\n",
- chip->display_rows);
- }
+ "No valid led definitions found\n");
current_max = aw200xx_imax_from_global(chip, AW200XX_IMAX_MAX_uA);
current_min = aw200xx_imax_from_global(chip, AW200XX_IMAX_MIN_uA);
@@ -416,6 +462,7 @@ static int aw200xx_probe_fw(struct device *dev, struct aw200xx *chip)
led->num = source;
led->chip = chip;
led->cdev.brightness_set_blocking = aw200xx_brightness_set;
+ led->cdev.max_brightness = AW200XX_FADE_MAX;
led->cdev.groups = dim_groups;
init_data.fwnode = child;
@@ -480,6 +527,7 @@ static const struct regmap_config aw200xx_regmap_config = {
.rd_table = &aw200xx_readable_table,
.wr_table = &aw200xx_writeable_table,
.cache_type = REGCACHE_MAPLE,
+ .disable_locking = true,
};
static int aw200xx_probe(struct i2c_client *client)
@@ -512,6 +560,14 @@ static int aw200xx_probe(struct i2c_client *client)
if (IS_ERR(chip->regmap))
return PTR_ERR(chip->regmap);
+ chip->hwen = devm_gpiod_get_optional(&client->dev, "enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(chip->hwen))
+ return dev_err_probe(&client->dev, PTR_ERR(chip->hwen),
+ "Cannot get enable GPIO");
+
+ aw200xx_enable(chip);
+
ret = aw200xx_chip_check(chip);
if (ret)
return ret;
@@ -532,6 +588,9 @@ static int aw200xx_probe(struct i2c_client *client)
ret = aw200xx_chip_init(chip);
out_unlock:
+ if (ret)
+ aw200xx_disable(chip);
+
mutex_unlock(&chip->mutex);
return ret;
}
@@ -541,6 +600,7 @@ static void aw200xx_remove(struct i2c_client *client)
struct aw200xx *chip = i2c_get_clientdata(client);
aw200xx_chip_reset(chip);
+ aw200xx_disable(chip);
mutex_destroy(&chip->mutex);
}
@@ -562,10 +622,17 @@ static const struct aw200xx_chipdef aw20072_cdef = {
.display_size_columns = 12,
};
+static const struct aw200xx_chipdef aw20108_cdef = {
+ .channels = 108,
+ .display_size_rows_max = 9,
+ .display_size_columns = 12,
+};
+
static const struct i2c_device_id aw200xx_id[] = {
{ "aw20036" },
{ "aw20054" },
{ "aw20072" },
+ { "aw20108" },
{}
};
MODULE_DEVICE_TABLE(i2c, aw200xx_id);
@@ -574,6 +641,7 @@ static const struct of_device_id aw200xx_match_table[] = {
{ .compatible = "awinic,aw20036", .data = &aw20036_cdef, },
{ .compatible = "awinic,aw20054", .data = &aw20054_cdef, },
{ .compatible = "awinic,aw20072", .data = &aw20072_cdef, },
+ { .compatible = "awinic,aw20108", .data = &aw20108_cdef, },
{}
};
MODULE_DEVICE_TABLE(of, aw200xx_match_table);
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 710c319ad312..83fcd7b6afff 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -172,6 +172,8 @@ static struct gpio_leds_priv *gpio_leds_create(struct device *dev)
led.gpiod = devm_fwnode_gpiod_get(dev, child, NULL, GPIOD_ASIS,
NULL);
if (IS_ERR(led.gpiod)) {
+ dev_err_probe(dev, PTR_ERR(led.gpiod), "Failed to get GPIO '%pfw'\n",
+ child);
fwnode_handle_put(child);
return ERR_CAST(led.gpiod);
}
diff --git a/drivers/leds/leds-max5970.c b/drivers/leds/leds-max5970.c
new file mode 100644
index 000000000000..56a584311581
--- /dev/null
+++ b/drivers/leds/leds-max5970.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device driver for leds in MAX5970 and MAX5978 IC
+ *
+ * Copyright (c) 2022 9elements GmbH
+ *
+ * Author: Patrick Rudolph <[email protected]>
+ */
+
+#include <linux/bits.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/leds.h>
+#include <linux/mfd/max5970.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#define ldev_to_maxled(c) container_of(c, struct max5970_led, cdev)
+
+struct max5970_led {
+ struct device *dev;
+ struct regmap *regmap;
+ struct led_classdev cdev;
+ unsigned int index;
+};
+
+static int max5970_led_set_brightness(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct max5970_led *ddata = ldev_to_maxled(cdev);
+ int ret, val;
+
+ /* Set/clear corresponding bit for given led index */
+ val = !brightness ? BIT(ddata->index) : 0;
+
+ ret = regmap_update_bits(ddata->regmap, MAX5970_REG_LED_FLASH, BIT(ddata->index), val);
+ if (ret < 0)
+ dev_err(cdev->dev, "failed to set brightness %d", ret);
+
+ return ret;
+}
+
+static int max5970_led_probe(struct platform_device *pdev)
+{
+ struct fwnode_handle *led_node, *child;
+ struct device *dev = &pdev->dev;
+ struct regmap *regmap;
+ struct max5970_led *ddata;
+ int ret = -ENODEV;
+
+ regmap = dev_get_regmap(dev->parent, NULL);
+ if (!regmap)
+ return -ENODEV;
+
+ led_node = device_get_named_child_node(dev->parent, "leds");
+ if (!led_node)
+ return -ENODEV;
+
+ fwnode_for_each_available_child_node(led_node, child) {
+ u32 reg;
+
+ if (fwnode_property_read_u32(child, "reg", &reg))
+ continue;
+
+ if (reg >= MAX5970_NUM_LEDS) {
+ dev_err_probe(dev, -EINVAL, "invalid LED (%u >= %d)\n", reg, MAX5970_NUM_LEDS);
+ continue;
+ }
+
+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata) {
+ fwnode_handle_put(child);
+ return -ENOMEM;
+ }
+
+ ddata->index = reg;
+ ddata->regmap = regmap;
+ ddata->dev = dev;
+
+ if (fwnode_property_read_string(child, "label", &ddata->cdev.name))
+ ddata->cdev.name = fwnode_get_name(child);
+
+ ddata->cdev.max_brightness = 1;
+ ddata->cdev.brightness_set_blocking = max5970_led_set_brightness;
+ ddata->cdev.default_trigger = "none";
+
+ ret = devm_led_classdev_register(dev, &ddata->cdev);
+ if (ret < 0) {
+ fwnode_handle_put(child);
+ return dev_err_probe(dev, ret, "Failed to initialize LED %u\n", reg);
+ }
+ }
+
+ return ret;
+}
+
+static struct platform_driver max5970_led_driver = {
+ .driver = {
+ .name = "max5970-led",
+ },
+ .probe = max5970_led_probe,
+};
+module_platform_driver(max5970_led_driver);
+
+MODULE_AUTHOR("Patrick Rudolph <[email protected]>");
+MODULE_AUTHOR("Naresh Solanki <[email protected]>");
+MODULE_DESCRIPTION("MAX5970_hot-swap controller LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 2b3bf1353b70..4e3936a39d0e 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -54,7 +54,7 @@ static int led_pwm_set(struct led_classdev *led_cdev,
led_dat->pwmstate.duty_cycle = duty;
led_dat->pwmstate.enabled = true;
- return pwm_apply_state(led_dat->pwm, &led_dat->pwmstate);
+ return pwm_apply_might_sleep(led_dat->pwm, &led_dat->pwmstate);
}
__attribute__((nonnull))
diff --git a/drivers/leds/leds-sun50i-a100.c b/drivers/leds/leds-sun50i-a100.c
new file mode 100644
index 000000000000..62d21c3a3575
--- /dev/null
+++ b/drivers/leds/leds-sun50i-a100.c
@@ -0,0 +1,584 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021-2023 Samuel Holland <[email protected]>
+ *
+ * Partly based on drivers/leds/leds-turris-omnia.c, which is:
+ * Copyright (c) 2020 by Marek Behún <[email protected]>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/led-class-multicolor.h>
+#include <linux/leds.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/property.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+
+#define LEDC_CTRL_REG 0x0000
+#define LEDC_CTRL_REG_DATA_LENGTH GENMASK(28, 16)
+#define LEDC_CTRL_REG_RGB_MODE GENMASK(8, 6)
+#define LEDC_CTRL_REG_LEDC_EN BIT(0)
+#define LEDC_T01_TIMING_CTRL_REG 0x0004
+#define LEDC_T01_TIMING_CTRL_REG_T1H GENMASK(26, 21)
+#define LEDC_T01_TIMING_CTRL_REG_T1L GENMASK(20, 16)
+#define LEDC_T01_TIMING_CTRL_REG_T0H GENMASK(10, 6)
+#define LEDC_T01_TIMING_CTRL_REG_T0L GENMASK(5, 0)
+#define LEDC_RESET_TIMING_CTRL_REG 0x000c
+#define LEDC_RESET_TIMING_CTRL_REG_TR GENMASK(28, 16)
+#define LEDC_RESET_TIMING_CTRL_REG_LED_NUM GENMASK(9, 0)
+#define LEDC_DATA_REG 0x0014
+#define LEDC_DMA_CTRL_REG 0x0018
+#define LEDC_DMA_CTRL_REG_DMA_EN BIT(5)
+#define LEDC_DMA_CTRL_REG_FIFO_TRIG_LEVEL GENMASK(4, 0)
+#define LEDC_INT_CTRL_REG 0x001c
+#define LEDC_INT_CTRL_REG_GLOBAL_INT_EN BIT(5)
+#define LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN BIT(1)
+#define LEDC_INT_CTRL_REG_TRANS_FINISH_INT_EN BIT(0)
+#define LEDC_INT_STS_REG 0x0020
+#define LEDC_INT_STS_REG_FIFO_WLW GENMASK(15, 10)
+#define LEDC_INT_STS_REG_FIFO_CPUREQ_INT BIT(1)
+#define LEDC_INT_STS_REG_TRANS_FINISH_INT BIT(0)
+
+#define LEDC_FIFO_DEPTH 32U
+#define LEDC_MAX_LEDS 1024
+#define LEDC_CHANNELS_PER_LED 3 /* RGB */
+
+#define LEDS_TO_BYTES(n) ((n) * sizeof(u32))
+
+struct sun50i_a100_ledc_led {
+ struct led_classdev_mc mc_cdev;
+ struct mc_subled subled_info[LEDC_CHANNELS_PER_LED];
+ u32 addr;
+};
+
+#define to_ledc_led(mc) container_of(mc, struct sun50i_a100_ledc_led, mc_cdev)
+
+struct sun50i_a100_ledc_timing {
+ u32 t0h_ns;
+ u32 t0l_ns;
+ u32 t1h_ns;
+ u32 t1l_ns;
+ u32 treset_ns;
+};
+
+struct sun50i_a100_ledc {
+ struct device *dev;
+ void __iomem *base;
+ struct clk *bus_clk;
+ struct clk *mod_clk;
+ struct reset_control *reset;
+
+ u32 *buffer;
+ struct dma_chan *dma_chan;
+ dma_addr_t dma_handle;
+ unsigned int pio_length;
+ unsigned int pio_offset;
+
+ spinlock_t lock;
+ unsigned int next_length;
+ bool xfer_active;
+
+ u32 format;
+ struct sun50i_a100_ledc_timing timing;
+
+ u32 max_addr;
+ u32 num_leds;
+ struct sun50i_a100_ledc_led leds[] __counted_by(num_leds);
+};
+
+static int sun50i_a100_ledc_dma_xfer(struct sun50i_a100_ledc *priv, unsigned int length)
+{
+ struct dma_async_tx_descriptor *desc;
+ dma_cookie_t cookie;
+
+ desc = dmaengine_prep_slave_single(priv->dma_chan, priv->dma_handle,
+ LEDS_TO_BYTES(length), DMA_MEM_TO_DEV, 0);
+ if (!desc)
+ return -ENOMEM;
+
+ cookie = dmaengine_submit(desc);
+ if (dma_submit_error(cookie))
+ return -EIO;
+
+ dma_async_issue_pending(priv->dma_chan);
+
+ return 0;
+}
+
+static void sun50i_a100_ledc_pio_xfer(struct sun50i_a100_ledc *priv, unsigned int fifo_used)
+{
+ unsigned int burst, length, offset;
+ u32 control;
+
+ length = priv->pio_length;
+ offset = priv->pio_offset;
+ burst = min(length, LEDC_FIFO_DEPTH - fifo_used);
+
+ iowrite32_rep(priv->base + LEDC_DATA_REG, priv->buffer + offset, burst);
+
+ if (burst < length) {
+ priv->pio_length = length - burst;
+ priv->pio_offset = offset + burst;
+
+ if (!offset) {
+ control = readl(priv->base + LEDC_INT_CTRL_REG);
+ control |= LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN;
+ writel(control, priv->base + LEDC_INT_CTRL_REG);
+ }
+ } else {
+ /* Disable the request IRQ once all data is written. */
+ control = readl(priv->base + LEDC_INT_CTRL_REG);
+ control &= ~LEDC_INT_CTRL_REG_FIFO_CPUREQ_INT_EN;
+ writel(control, priv->base + LEDC_INT_CTRL_REG);
+ }
+}
+
+static void sun50i_a100_ledc_start_xfer(struct sun50i_a100_ledc *priv, unsigned int length)
+{
+ bool use_dma = false;
+ u32 control;
+
+ if (priv->dma_chan && length > LEDC_FIFO_DEPTH) {
+ int ret;
+
+ ret = sun50i_a100_ledc_dma_xfer(priv, length);
+ if (ret)
+ dev_warn(priv->dev, "Failed to set up DMA (%d), using PIO\n", ret);
+ else
+ use_dma = true;
+ }
+
+ /* The DMA trigger level must be at least the burst length. */
+ control = FIELD_PREP(LEDC_DMA_CTRL_REG_DMA_EN, use_dma) |
+ FIELD_PREP_CONST(LEDC_DMA_CTRL_REG_FIFO_TRIG_LEVEL, LEDC_FIFO_DEPTH / 2);
+ writel(control, priv->base + LEDC_DMA_CTRL_REG);
+
+ control = readl(priv->base + LEDC_CTRL_REG);
+ control &= ~LEDC_CTRL_REG_DATA_LENGTH;
+ control |= FIELD_PREP(LEDC_CTRL_REG_DATA_LENGTH, length) | LEDC_CTRL_REG_LEDC_EN;
+ writel(control, priv->base + LEDC_CTRL_REG);
+
+ if (!use_dma) {
+ /* The FIFO is empty when starting a new transfer. */
+ unsigned int fifo_used = 0;
+
+ priv->pio_length = length;
+ priv->pio_offset = 0;
+
+ sun50i_a100_ledc_pio_xfer(priv, fifo_used);
+ }
+}
+
+static irqreturn_t sun50i_a100_ledc_irq(int irq, void *data)
+{
+ struct sun50i_a100_ledc *priv = data;
+ u32 status;
+
+ status = readl(priv->base + LEDC_INT_STS_REG);
+
+ if (status & LEDC_INT_STS_REG_TRANS_FINISH_INT) {
+ unsigned int next_length;
+
+ spin_lock(&priv->lock);
+
+ /* If another transfer is queued, dequeue and start it. */
+ next_length = priv->next_length;
+ if (next_length)
+ priv->next_length = 0;
+ else
+ priv->xfer_active = false;
+
+ spin_unlock(&priv->lock);
+
+ if (next_length)
+ sun50i_a100_ledc_start_xfer(priv, next_length);
+ } else if (status & LEDC_INT_STS_REG_FIFO_CPUREQ_INT) {
+ /* Continue the current transfer. */
+ sun50i_a100_ledc_pio_xfer(priv, FIELD_GET(LEDC_INT_STS_REG_FIFO_WLW, status));
+ }
+
+ /* Clear the W1C status bits. */
+ writel(status, priv->base + LEDC_INT_STS_REG);
+
+ return IRQ_HANDLED;
+}
+
+static void sun50i_a100_ledc_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ struct sun50i_a100_ledc *priv = dev_get_drvdata(cdev->dev->parent);
+ struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
+ struct sun50i_a100_ledc_led *led = to_ledc_led(mc_cdev);
+ unsigned int next_length;
+ unsigned long flags;
+ bool xfer_active;
+
+ led_mc_calc_color_components(mc_cdev, brightness);
+
+ priv->buffer[led->addr] = led->subled_info[0].brightness << 16 |
+ led->subled_info[1].brightness << 8 |
+ led->subled_info[2].brightness;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Start, enqueue, or extend an enqueued transfer, as appropriate. */
+ next_length = max(priv->next_length, led->addr + 1);
+ xfer_active = priv->xfer_active;
+ if (xfer_active)
+ priv->next_length = next_length;
+ else
+ priv->xfer_active = true;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (!xfer_active)
+ sun50i_a100_ledc_start_xfer(priv, next_length);
+}
+
+static const char *const sun50i_a100_ledc_formats[] = {
+ "rgb", "rbg", "grb", "gbr", "brg", "bgr",
+};
+
+static int sun50i_a100_ledc_parse_format(struct device *dev,
+ struct sun50i_a100_ledc *priv)
+{
+ const char *format = "grb";
+ u32 i;
+
+ device_property_read_string(dev, "allwinner,pixel-format", &format);
+
+ for (i = 0; i < ARRAY_SIZE(sun50i_a100_ledc_formats); i++) {
+ if (!strcmp(format, sun50i_a100_ledc_formats[i])) {
+ priv->format = i;
+ return 0;
+ }
+ }
+
+ return dev_err_probe(dev, -EINVAL, "Bad pixel format '%s'\n", format);
+}
+
+static void sun50i_a100_ledc_set_format(struct sun50i_a100_ledc *priv)
+{
+ u32 control;
+
+ control = readl(priv->base + LEDC_CTRL_REG);
+ control &= ~LEDC_CTRL_REG_RGB_MODE;
+ control |= FIELD_PREP(LEDC_CTRL_REG_RGB_MODE, priv->format);
+ writel(control, priv->base + LEDC_CTRL_REG);
+}
+
+static const struct sun50i_a100_ledc_timing sun50i_a100_ledc_default_timing = {
+ .t0h_ns = 336,
+ .t0l_ns = 840,
+ .t1h_ns = 882,
+ .t1l_ns = 294,
+ .treset_ns = 300000,
+};
+
+static int sun50i_a100_ledc_parse_timing(struct device *dev,
+ struct sun50i_a100_ledc *priv)
+{
+ struct sun50i_a100_ledc_timing *timing = &priv->timing;
+
+ *timing = sun50i_a100_ledc_default_timing;
+
+ device_property_read_u32(dev, "allwinner,t0h-ns", &timing->t0h_ns);
+ device_property_read_u32(dev, "allwinner,t0l-ns", &timing->t0l_ns);
+ device_property_read_u32(dev, "allwinner,t1h-ns", &timing->t1h_ns);
+ device_property_read_u32(dev, "allwinner,t1l-ns", &timing->t1l_ns);
+ device_property_read_u32(dev, "allwinner,treset-ns", &timing->treset_ns);
+
+ return 0;
+}
+
+static void sun50i_a100_ledc_set_timing(struct sun50i_a100_ledc *priv)
+{
+ const struct sun50i_a100_ledc_timing *timing = &priv->timing;
+ unsigned long mod_freq = clk_get_rate(priv->mod_clk);
+ u32 cycle_ns;
+ u32 control;
+
+ if (!mod_freq)
+ return;
+
+ cycle_ns = NSEC_PER_SEC / mod_freq;
+ control = FIELD_PREP(LEDC_T01_TIMING_CTRL_REG_T1H, timing->t1h_ns / cycle_ns) |
+ FIELD_PREP(LEDC_T01_TIMING_CTRL_REG_T1L, timing->t1l_ns / cycle_ns) |
+ FIELD_PREP(LEDC_T01_TIMING_CTRL_REG_T0H, timing->t0h_ns / cycle_ns) |
+ FIELD_PREP(LEDC_T01_TIMING_CTRL_REG_T0L, timing->t0l_ns / cycle_ns);
+ writel(control, priv->base + LEDC_T01_TIMING_CTRL_REG);
+
+ control = FIELD_PREP(LEDC_RESET_TIMING_CTRL_REG_TR, timing->treset_ns / cycle_ns) |
+ FIELD_PREP(LEDC_RESET_TIMING_CTRL_REG_LED_NUM, priv->max_addr);
+ writel(control, priv->base + LEDC_RESET_TIMING_CTRL_REG);
+}
+
+static int sun50i_a100_ledc_resume(struct device *dev)
+{
+ struct sun50i_a100_ledc *priv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = reset_control_deassert(priv->reset);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(priv->bus_clk);
+ if (ret)
+ goto err_assert_reset;
+
+ ret = clk_prepare_enable(priv->mod_clk);
+ if (ret)
+ goto err_disable_bus_clk;
+
+ sun50i_a100_ledc_set_format(priv);
+ sun50i_a100_ledc_set_timing(priv);
+
+ writel(LEDC_INT_CTRL_REG_GLOBAL_INT_EN | LEDC_INT_CTRL_REG_TRANS_FINISH_INT_EN,
+ priv->base + LEDC_INT_CTRL_REG);
+
+ return 0;
+
+err_disable_bus_clk:
+ clk_disable_unprepare(priv->bus_clk);
+err_assert_reset:
+ reset_control_assert(priv->reset);
+
+ return ret;
+}
+
+static int sun50i_a100_ledc_suspend(struct device *dev)
+{
+ struct sun50i_a100_ledc *priv = dev_get_drvdata(dev);
+
+ /* Wait for all transfers to complete. */
+ for (;;) {
+ unsigned long flags;
+ bool xfer_active;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ xfer_active = priv->xfer_active;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ if (!xfer_active)
+ break;
+
+ msleep(1);
+ }
+
+ clk_disable_unprepare(priv->mod_clk);
+ clk_disable_unprepare(priv->bus_clk);
+ reset_control_assert(priv->reset);
+
+ return 0;
+}
+
+static void sun50i_a100_ledc_dma_cleanup(void *data)
+{
+ struct sun50i_a100_ledc *priv = data;
+
+ dma_release_channel(priv->dma_chan);
+}
+
+static int sun50i_a100_ledc_probe(struct platform_device *pdev)
+{
+ struct dma_slave_config dma_cfg = {};
+ struct led_init_data init_data = {};
+ struct sun50i_a100_ledc_led *led;
+ struct device *dev = &pdev->dev;
+ struct sun50i_a100_ledc *priv;
+ struct fwnode_handle *child;
+ struct resource *mem;
+ u32 max_addr = 0;
+ u32 num_leds = 0;
+ int irq, ret;
+
+ /*
+ * The maximum LED address must be known in sun50i_a100_ledc_resume() before
+ * class device registration, so parse and validate the subnodes up front.
+ */
+ device_for_each_child_node(dev, child) {
+ u32 addr, color;
+
+ ret = fwnode_property_read_u32(child, "reg", &addr);
+ if (ret || addr >= LEDC_MAX_LEDS) {
+ fwnode_handle_put(child);
+ return dev_err_probe(dev, -EINVAL, "'reg' must be between 0 and %d\n",
+ LEDC_MAX_LEDS - 1);
+ }
+
+ ret = fwnode_property_read_u32(child, "color", &color);
+ if (ret || color != LED_COLOR_ID_RGB) {
+ fwnode_handle_put(child);
+ return dev_err_probe(dev, -EINVAL, "'color' must be LED_COLOR_ID_RGB\n");
+ }
+
+ max_addr = max(max_addr, addr);
+ num_leds++;
+ }
+
+ if (!num_leds)
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, struct_size(priv, leds, num_leds), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->max_addr = max_addr;
+ priv->num_leds = num_leds;
+ spin_lock_init(&priv->lock);
+ dev_set_drvdata(dev, priv);
+
+ ret = sun50i_a100_ledc_parse_format(dev, priv);
+ if (ret)
+ return ret;
+
+ ret = sun50i_a100_ledc_parse_timing(dev, priv);
+ if (ret)
+ return ret;
+
+ priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->bus_clk = devm_clk_get(dev, "bus");
+ if (IS_ERR(priv->bus_clk))
+ return PTR_ERR(priv->bus_clk);
+
+ priv->mod_clk = devm_clk_get(dev, "mod");
+ if (IS_ERR(priv->mod_clk))
+ return PTR_ERR(priv->mod_clk);
+
+ priv->reset = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(priv->reset))
+ return PTR_ERR(priv->reset);
+
+ priv->dma_chan = dma_request_chan(dev, "tx");
+ if (IS_ERR(priv->dma_chan)) {
+ if (PTR_ERR(priv->dma_chan) != -ENODEV)
+ return PTR_ERR(priv->dma_chan);
+
+ priv->dma_chan = NULL;
+
+ priv->buffer = devm_kzalloc(dev, LEDS_TO_BYTES(LEDC_MAX_LEDS), GFP_KERNEL);
+ if (!priv->buffer)
+ return -ENOMEM;
+ } else {
+ ret = devm_add_action_or_reset(dev, sun50i_a100_ledc_dma_cleanup, priv);
+ if (ret)
+ return ret;
+
+ dma_cfg.dst_addr = mem->start + LEDC_DATA_REG;
+ dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ dma_cfg.dst_maxburst = LEDC_FIFO_DEPTH / 2;
+
+ ret = dmaengine_slave_config(priv->dma_chan, &dma_cfg);
+ if (ret)
+ return ret;
+
+ priv->buffer = dmam_alloc_attrs(dmaengine_get_dma_device(priv->dma_chan),
+ LEDS_TO_BYTES(LEDC_MAX_LEDS), &priv->dma_handle,
+ GFP_KERNEL, DMA_ATTR_WRITE_COMBINE);
+ if (!priv->buffer)
+ return -ENOMEM;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(dev, irq, sun50i_a100_ledc_irq, 0, dev_name(dev), priv);
+ if (ret)
+ return ret;
+
+ ret = sun50i_a100_ledc_resume(dev);
+ if (ret)
+ return ret;
+
+ led = priv->leds;
+ device_for_each_child_node(dev, child) {
+ struct led_classdev *cdev;
+
+ /* The node was already validated above. */
+ fwnode_property_read_u32(child, "reg", &led->addr);
+
+ led->subled_info[0].color_index = LED_COLOR_ID_RED;
+ led->subled_info[0].channel = 0;
+ led->subled_info[1].color_index = LED_COLOR_ID_GREEN;
+ led->subled_info[1].channel = 1;
+ led->subled_info[2].color_index = LED_COLOR_ID_BLUE;
+ led->subled_info[2].channel = 2;
+
+ led->mc_cdev.num_colors = ARRAY_SIZE(led->subled_info);
+ led->mc_cdev.subled_info = led->subled_info;
+
+ cdev = &led->mc_cdev.led_cdev;
+ cdev->max_brightness = U8_MAX;
+ cdev->brightness_set = sun50i_a100_ledc_brightness_set;
+
+ init_data.fwnode = child;
+
+ ret = led_classdev_multicolor_register_ext(dev, &led->mc_cdev, &init_data);
+ if (ret) {
+ dev_err_probe(dev, ret, "Failed to register multicolor LED %u", led->addr);
+ goto err_put_child;
+ }
+
+ led++;
+ }
+
+ dev_info(dev, "Registered %u LEDs\n", num_leds);
+
+ return 0;
+
+err_put_child:
+ fwnode_handle_put(child);
+ while (led-- > priv->leds)
+ led_classdev_multicolor_unregister(&led->mc_cdev);
+ sun50i_a100_ledc_suspend(&pdev->dev);
+
+ return ret;
+}
+
+static void sun50i_a100_ledc_remove(struct platform_device *pdev)
+{
+ struct sun50i_a100_ledc *priv = platform_get_drvdata(pdev);
+
+ for (u32 i = 0; i < priv->num_leds; i++)
+ led_classdev_multicolor_unregister(&priv->leds[i].mc_cdev);
+ sun50i_a100_ledc_suspend(&pdev->dev);
+}
+
+static const struct of_device_id sun50i_a100_ledc_of_match[] = {
+ { .compatible = "allwinner,sun50i-a100-ledc" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun50i_a100_ledc_of_match);
+
+static DEFINE_SIMPLE_DEV_PM_OPS(sun50i_a100_ledc_pm,
+ sun50i_a100_ledc_suspend,
+ sun50i_a100_ledc_resume);
+
+static struct platform_driver sun50i_a100_ledc_driver = {
+ .probe = sun50i_a100_ledc_probe,
+ .remove_new = sun50i_a100_ledc_remove,
+ .shutdown = sun50i_a100_ledc_remove,
+ .driver = {
+ .name = "sun50i-a100-ledc",
+ .of_match_table = sun50i_a100_ledc_of_match,
+ .pm = pm_ptr(&sun50i_a100_ledc_pm),
+ },
+};
+module_platform_driver(sun50i_a100_ledc_driver);
+
+MODULE_AUTHOR("Samuel Holland <[email protected]>");
+MODULE_DESCRIPTION("Allwinner A100 LED controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c
index 360a376fa738..d633ad519d0c 100644
--- a/drivers/leds/leds-syscon.c
+++ b/drivers/leds/leds-syscon.c
@@ -81,7 +81,8 @@ static int syscon_led_probe(struct platform_device *pdev)
sled->map = map;
- if (of_property_read_u32(np, "offset", &sled->offset))
+ if (of_property_read_u32(np, "reg", &sled->offset) &&
+ of_property_read_u32(np, "offset", &sled->offset))
return -EINVAL;
if (of_property_read_u32(np, "mask", &sled->mask))
return -EINVAL;
diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c
index e19074614095..4f22f4224946 100644
--- a/drivers/leds/leds-tca6507.c
+++ b/drivers/leds/leds-tca6507.c
@@ -638,19 +638,13 @@ static int tca6507_probe_gpios(struct device *dev,
tca->gpio.direction_output = tca6507_gpio_direction_output;
tca->gpio.set = tca6507_gpio_set_value;
tca->gpio.parent = dev;
- err = gpiochip_add_data(&tca->gpio, tca);
+ err = devm_gpiochip_add_data(dev, &tca->gpio, tca);
if (err) {
tca->gpio.ngpio = 0;
return err;
}
return 0;
}
-
-static void tca6507_remove_gpio(struct tca6507_chip *tca)
-{
- if (tca->gpio.ngpio)
- gpiochip_remove(&tca->gpio);
-}
#else /* CONFIG_GPIOLIB */
static int tca6507_probe_gpios(struct device *dev,
struct tca6507_chip *tca,
@@ -658,9 +652,6 @@ static int tca6507_probe_gpios(struct device *dev,
{
return 0;
}
-static void tca6507_remove_gpio(struct tca6507_chip *tca)
-{
-}
#endif /* CONFIG_GPIOLIB */
static struct tca6507_platform_data *
@@ -762,38 +753,25 @@ static int tca6507_probe(struct i2c_client *client)
l->led_cdev.brightness_set = tca6507_brightness_set;
l->led_cdev.blink_set = tca6507_blink_set;
l->bank = -1;
- err = led_classdev_register(dev, &l->led_cdev);
+ err = devm_led_classdev_register(dev, &l->led_cdev);
if (err < 0)
- goto exit;
+ return err;
}
}
err = tca6507_probe_gpios(dev, tca, pdata);
if (err)
- goto exit;
+ return err;
/* set all registers to known state - zero */
tca->reg_set = 0x7f;
schedule_work(&tca->work);
return 0;
-exit:
- while (i--) {
- if (tca->leds[i].led_cdev.name)
- led_classdev_unregister(&tca->leds[i].led_cdev);
- }
- return err;
}
static void tca6507_remove(struct i2c_client *client)
{
- int i;
struct tca6507_chip *tca = i2c_get_clientdata(client);
- struct tca6507_led *tca_leds = tca->leds;
- for (i = 0; i < NUM_LEDS; i++) {
- if (tca_leds[i].led_cdev.name)
- led_classdev_unregister(&tca_leds[i].led_cdev);
- }
- tca6507_remove_gpio(tca);
cancel_work_sync(&tca->work);
}
diff --git a/drivers/leds/rgb/Kconfig b/drivers/leds/rgb/Kconfig
index a6a21f564673..e66bd21b9852 100644
--- a/drivers/leds/rgb/Kconfig
+++ b/drivers/leds/rgb/Kconfig
@@ -4,7 +4,7 @@ if LEDS_CLASS_MULTICOLOR
config LEDS_GROUP_MULTICOLOR
tristate "LEDs group multi-color support"
- depends on OF || COMPILE_TEST
+ depends on OF
help
This option enables support for monochrome LEDs that are grouped
into multicolor LEDs which is useful in the case where LEDs of
diff --git a/drivers/leds/rgb/leds-pwm-multicolor.c b/drivers/leds/rgb/leds-pwm-multicolor.c
index 46cd062b8b24..e1a81e0109e8 100644
--- a/drivers/leds/rgb/leds-pwm-multicolor.c
+++ b/drivers/leds/rgb/leds-pwm-multicolor.c
@@ -51,8 +51,8 @@ static int led_pwm_mc_set(struct led_classdev *cdev,
priv->leds[i].state.duty_cycle = duty;
priv->leds[i].state.enabled = duty > 0;
- ret = pwm_apply_state(priv->leds[i].pwm,
- &priv->leds[i].state);
+ ret = pwm_apply_might_sleep(priv->leds[i].pwm,
+ &priv->leds[i].state);
if (ret)
break;
}
diff --git a/drivers/leds/rgb/leds-qcom-lpg.c b/drivers/leds/rgb/leds-qcom-lpg.c
index 68d82a682bf6..156b73d1f4a2 100644
--- a/drivers/leds/rgb/leds-qcom-lpg.c
+++ b/drivers/leds/rgb/leds-qcom-lpg.c
@@ -552,9 +552,9 @@ static int lpg_parse_dtest(struct lpg *lpg)
ret = count;
goto err_malformed;
} else if (count != lpg->data->num_channels * 2) {
- dev_err(lpg->dev, "qcom,dtest needs to be %d items\n",
- lpg->data->num_channels * 2);
- return -EINVAL;
+ return dev_err_probe(lpg->dev, -EINVAL,
+ "qcom,dtest needs to be %d items\n",
+ lpg->data->num_channels * 2);
}
for (i = 0; i < lpg->data->num_channels; i++) {
@@ -574,8 +574,7 @@ static int lpg_parse_dtest(struct lpg *lpg)
return 0;
err_malformed:
- dev_err(lpg->dev, "malformed qcom,dtest\n");
- return ret;
+ return dev_err_probe(lpg->dev, ret, "malformed qcom,dtest\n");
}
static void lpg_apply_dtest(struct lpg_channel *chan)
@@ -977,9 +976,14 @@ static int lpg_pattern_mc_clear(struct led_classdev *cdev)
return lpg_pattern_clear(led);
}
+static inline struct lpg *lpg_pwm_from_chip(struct pwm_chip *chip)
+{
+ return container_of(chip, struct lpg, pwm);
+}
+
static int lpg_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
{
- struct lpg *lpg = container_of(chip, struct lpg, pwm);
+ struct lpg *lpg = lpg_pwm_from_chip(chip);
struct lpg_channel *chan = &lpg->channels[pwm->hwpwm];
return chan->in_use ? -EBUSY : 0;
@@ -995,7 +999,7 @@ static int lpg_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
static int lpg_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state)
{
- struct lpg *lpg = container_of(chip, struct lpg, pwm);
+ struct lpg *lpg = lpg_pwm_from_chip(chip);
struct lpg_channel *chan = &lpg->channels[pwm->hwpwm];
int ret = 0;
@@ -1026,7 +1030,7 @@ out_unlock:
static int lpg_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
{
- struct lpg *lpg = container_of(chip, struct lpg, pwm);
+ struct lpg *lpg = lpg_pwm_from_chip(chip);
struct lpg_channel *chan = &lpg->channels[pwm->hwpwm];
unsigned int resolution;
unsigned int pre_div;
@@ -1095,9 +1099,9 @@ static int lpg_add_pwm(struct lpg *lpg)
lpg->pwm.npwm = lpg->num_channels;
lpg->pwm.ops = &lpg_pwm_ops;
- ret = pwmchip_add(&lpg->pwm);
+ ret = devm_pwmchip_add(lpg->dev, &lpg->pwm);
if (ret)
- dev_err(lpg->dev, "failed to add PWM chip: ret %d\n", ret);
+ dev_err_probe(lpg->dev, ret, "failed to add PWM chip\n");
return ret;
}
@@ -1111,19 +1115,16 @@ static int lpg_parse_channel(struct lpg *lpg, struct device_node *np,
int ret;
ret = of_property_read_u32(np, "reg", &reg);
- if (ret || !reg || reg > lpg->num_channels) {
- dev_err(lpg->dev, "invalid \"reg\" of %pOFn\n", np);
- return -EINVAL;
- }
+ if (ret || !reg || reg > lpg->num_channels)
+ return dev_err_probe(lpg->dev, -EINVAL, "invalid \"reg\" of %pOFn\n", np);
chan = &lpg->channels[reg - 1];
chan->in_use = true;
ret = of_property_read_u32(np, "color", &color);
- if (ret < 0 && ret != -EINVAL) {
- dev_err(lpg->dev, "failed to parse \"color\" of %pOF\n", np);
- return ret;
- }
+ if (ret < 0 && ret != -EINVAL)
+ return dev_err_probe(lpg->dev, ret,
+ "failed to parse \"color\" of %pOF\n", np);
chan->color = color;
@@ -1146,10 +1147,9 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np)
int i;
ret = of_property_read_u32(np, "color", &color);
- if (ret < 0 && ret != -EINVAL) {
- dev_err(lpg->dev, "failed to parse \"color\" of %pOF\n", np);
- return ret;
- }
+ if (ret < 0 && ret != -EINVAL)
+ return dev_err_probe(lpg->dev, ret,
+ "failed to parse \"color\" of %pOF\n", np);
if (color == LED_COLOR_ID_RGB)
num_channels = of_get_available_child_count(np);
@@ -1226,7 +1226,7 @@ static int lpg_add_led(struct lpg *lpg, struct device_node *np)
else
ret = devm_led_classdev_register_ext(lpg->dev, &led->cdev, &init_data);
if (ret)
- dev_err(lpg->dev, "unable to register %s\n", cdev->name);
+ dev_err_probe(lpg->dev, ret, "unable to register %s\n", cdev->name);
return ret;
}
@@ -1272,10 +1272,9 @@ static int lpg_init_triled(struct lpg *lpg)
if (lpg->triled_has_src_sel) {
ret = of_property_read_u32(np, "qcom,power-source", &lpg->triled_src);
- if (ret || lpg->triled_src == 2 || lpg->triled_src > 3) {
- dev_err(lpg->dev, "invalid power source\n");
- return -EINVAL;
- }
+ if (ret || lpg->triled_src == 2 || lpg->triled_src > 3)
+ return dev_err_probe(lpg->dev, -EINVAL,
+ "invalid power source\n");
}
/* Disable automatic trickle charge LED */
@@ -1324,8 +1323,6 @@ static int lpg_probe(struct platform_device *pdev)
if (!lpg->data)
return -EINVAL;
- platform_set_drvdata(pdev, lpg);
-
lpg->dev = &pdev->dev;
mutex_init(&lpg->lock);
@@ -1363,13 +1360,6 @@ static int lpg_probe(struct platform_device *pdev)
return lpg_add_pwm(lpg);
}
-static void lpg_remove(struct platform_device *pdev)
-{
- struct lpg *lpg = platform_get_drvdata(pdev);
-
- pwmchip_remove(&lpg->pwm);
-}
-
static const struct lpg_data pm8916_pwm_data = {
.num_channels = 1,
.channels = (const struct lpg_channel_data[]) {
@@ -1529,7 +1519,6 @@ MODULE_DEVICE_TABLE(of, lpg_of_table);
static struct platform_driver lpg_driver = {
.probe = lpg_probe,
- .remove_new = lpg_remove,
.driver = {
.name = "qcom-spmi-lpg",
.of_match_table = lpg_of_table,
diff --git a/drivers/leds/trigger/ledtrig-gpio.c b/drivers/leds/trigger/ledtrig-gpio.c
index 9b7fe5dd5208..7f6a2352b0ac 100644
--- a/drivers/leds/trigger/ledtrig-gpio.c
+++ b/drivers/leds/trigger/ledtrig-gpio.c
@@ -41,33 +41,30 @@ static irqreturn_t gpio_trig_irq(int irq, void *_led)
return IRQ_HANDLED;
}
-static ssize_t gpio_trig_brightness_show(struct device *dev,
+static ssize_t desired_brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
- return sprintf(buf, "%u\n", gpio_data->desired_brightness);
+ return sysfs_emit(buf, "%u\n", gpio_data->desired_brightness);
}
-static ssize_t gpio_trig_brightness_store(struct device *dev,
+static ssize_t desired_brightness_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t n)
{
struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
- unsigned desired_brightness;
+ u8 desired_brightness;
int ret;
- ret = sscanf(buf, "%u", &desired_brightness);
- if (ret < 1 || desired_brightness > 255) {
- dev_err(dev, "invalid value\n");
- return -EINVAL;
- }
+ ret = kstrtou8(buf, 10, &desired_brightness);
+ if (ret)
+ return ret;
gpio_data->desired_brightness = desired_brightness;
return n;
}
-static DEVICE_ATTR(desired_brightness, 0644, gpio_trig_brightness_show,
- gpio_trig_brightness_store);
+static DEVICE_ATTR_RW(desired_brightness);
static struct attribute *gpio_trig_attrs[] = {
&dev_attr_desired_brightness.attr,
@@ -89,10 +86,7 @@ static int gpio_trig_activate(struct led_classdev *led)
* The generic property "trigger-sources" is followed,
* and we hope that this is a GPIO.
*/
- gpio_data->gpiod = fwnode_gpiod_get_index(dev->fwnode,
- "trigger-sources",
- 0, GPIOD_IN,
- "led-trigger");
+ gpio_data->gpiod = gpiod_get_optional(dev, "trigger-sources", GPIOD_IN);
if (IS_ERR(gpio_data->gpiod)) {
ret = PTR_ERR(gpio_data->gpiod);
kfree(gpio_data);
@@ -104,6 +98,8 @@ static int gpio_trig_activate(struct led_classdev *led)
return -EINVAL;
}
+ gpiod_set_consumer_name(gpio_data->gpiod, "led-trigger");
+
gpio_data->led = led;
led_set_trigger_data(led, gpio_data);
diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index d76214fa9ad8..8e5475819590 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -38,6 +38,16 @@
* tx - LED blinks on transmitted data
* rx - LED blinks on receive data
*
+ * Note: If the user selects a mode that is not supported by hw, default
+ * behavior is to fall back to software control of the LED. However not every
+ * hw supports software control. LED callbacks brightness_set() and
+ * brightness_set_blocking() are NULL in this case. hw_control_is_supported()
+ * should use available means supported by hw to inform the user that selected
+ * mode isn't supported by hw. This could be switching off the LED or any
+ * hw blink mode. If software control fallback isn't possible, we return
+ * -EOPNOTSUPP to the user, but still store the selected mode. This is needed
+ * in case an intermediate unsupported mode is necessary to switch from one
+ * supported mode to another.
*/
struct led_netdev_data {
@@ -99,6 +109,18 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)
trigger_data->link_speed == SPEED_1000)
blink_on = true;
+ if (test_bit(TRIGGER_NETDEV_LINK_2500, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_2500)
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_5000, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_5000)
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_10000, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_10000)
+ blink_on = true;
+
if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) &&
trigger_data->duplex == DUPLEX_HALF)
blink_on = true;
@@ -289,6 +311,9 @@ static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
case TRIGGER_NETDEV_LINK_10:
case TRIGGER_NETDEV_LINK_100:
case TRIGGER_NETDEV_LINK_1000:
+ case TRIGGER_NETDEV_LINK_2500:
+ case TRIGGER_NETDEV_LINK_5000:
+ case TRIGGER_NETDEV_LINK_10000:
case TRIGGER_NETDEV_HALF_DUPLEX:
case TRIGGER_NETDEV_FULL_DUPLEX:
case TRIGGER_NETDEV_TX:
@@ -306,6 +331,7 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
size_t size, enum led_trigger_netdev_modes attr)
{
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
+ struct led_classdev *led_cdev = trigger_data->led_cdev;
unsigned long state, mode = trigger_data->mode;
int ret;
int bit;
@@ -319,6 +345,9 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
case TRIGGER_NETDEV_LINK_10:
case TRIGGER_NETDEV_LINK_100:
case TRIGGER_NETDEV_LINK_1000:
+ case TRIGGER_NETDEV_LINK_2500:
+ case TRIGGER_NETDEV_LINK_5000:
+ case TRIGGER_NETDEV_LINK_10000:
case TRIGGER_NETDEV_HALF_DUPLEX:
case TRIGGER_NETDEV_FULL_DUPLEX:
case TRIGGER_NETDEV_TX:
@@ -337,7 +366,10 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
if (test_bit(TRIGGER_NETDEV_LINK, &mode) &&
(test_bit(TRIGGER_NETDEV_LINK_10, &mode) ||
test_bit(TRIGGER_NETDEV_LINK_100, &mode) ||
- test_bit(TRIGGER_NETDEV_LINK_1000, &mode)))
+ test_bit(TRIGGER_NETDEV_LINK_1000, &mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_2500, &mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_5000, &mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_10000, &mode)))
return -EINVAL;
cancel_delayed_work_sync(&trigger_data->work);
@@ -345,6 +377,10 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
trigger_data->mode = mode;
trigger_data->hw_control = can_hw_control(trigger_data);
+ if (!led_cdev->brightness_set && !led_cdev->brightness_set_blocking &&
+ !trigger_data->hw_control)
+ return -EOPNOTSUPP;
+
set_baseline_state(trigger_data);
return size;
@@ -367,6 +403,9 @@ DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETDEV_LINK);
DEFINE_NETDEV_TRIGGER(link_10, TRIGGER_NETDEV_LINK_10);
DEFINE_NETDEV_TRIGGER(link_100, TRIGGER_NETDEV_LINK_100);
DEFINE_NETDEV_TRIGGER(link_1000, TRIGGER_NETDEV_LINK_1000);
+DEFINE_NETDEV_TRIGGER(link_2500, TRIGGER_NETDEV_LINK_2500);
+DEFINE_NETDEV_TRIGGER(link_5000, TRIGGER_NETDEV_LINK_5000);
+DEFINE_NETDEV_TRIGGER(link_10000, TRIGGER_NETDEV_LINK_10000);
DEFINE_NETDEV_TRIGGER(half_duplex, TRIGGER_NETDEV_HALF_DUPLEX);
DEFINE_NETDEV_TRIGGER(full_duplex, TRIGGER_NETDEV_FULL_DUPLEX);
DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX);
@@ -425,6 +464,9 @@ static struct attribute *netdev_trig_attrs[] = {
&dev_attr_link_10.attr,
&dev_attr_link_100.attr,
&dev_attr_link_1000.attr,
+ &dev_attr_link_2500.attr,
+ &dev_attr_link_5000.attr,
+ &dev_attr_link_10000.attr,
&dev_attr_full_duplex.attr,
&dev_attr_half_duplex.attr,
&dev_attr_rx.attr,
@@ -522,6 +564,9 @@ static void netdev_trig_work(struct work_struct *work)
test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) ||
test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) ||
test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_2500, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_5000, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_10000, &trigger_data->mode) ||
test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) ||
test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &trigger_data->mode);
interval = jiffies_to_msecs(
diff --git a/drivers/leds/trigger/ledtrig-panic.c b/drivers/leds/trigger/ledtrig-panic.c
index 64abf2e91608..5a6b21bfeb9a 100644
--- a/drivers/leds/trigger/ledtrig-panic.c
+++ b/drivers/leds/trigger/ledtrig-panic.c
@@ -64,10 +64,13 @@ static long led_panic_blink(int state)
static int __init ledtrig_panic_init(void)
{
+ led_trigger_register_simple("panic", &trigger);
+ if (!trigger)
+ return -ENOMEM;
+
atomic_notifier_chain_register(&panic_notifier_list,
&led_trigger_panic_nb);
- led_trigger_register_simple("panic", &trigger);
panic_blink = led_panic_blink;
return 0;
}
diff --git a/drivers/leds/trigger/ledtrig-tty.c b/drivers/leds/trigger/ledtrig-tty.c
index 8ae0d2d284af..8cf1485e8165 100644
--- a/drivers/leds/trigger/ledtrig-tty.c
+++ b/drivers/leds/trigger/ledtrig-tty.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/leds.h>
#include <linux/module.h>
@@ -12,15 +13,45 @@
struct ledtrig_tty_data {
struct led_classdev *led_cdev;
struct delayed_work dwork;
- struct mutex mutex;
+ struct completion sysfs;
const char *ttyname;
struct tty_struct *tty;
int rx, tx;
+ bool mode_rx;
+ bool mode_tx;
+ bool mode_cts;
+ bool mode_dsr;
+ bool mode_dcd;
+ bool mode_rng;
};
-static void ledtrig_tty_restart(struct ledtrig_tty_data *trigger_data)
+/* Indicates which state the LED should now display */
+enum led_trigger_tty_state {
+ TTY_LED_BLINK,
+ TTY_LED_ENABLE,
+ TTY_LED_DISABLE,
+};
+
+enum led_trigger_tty_modes {
+ TRIGGER_TTY_RX = 0,
+ TRIGGER_TTY_TX,
+ TRIGGER_TTY_CTS,
+ TRIGGER_TTY_DSR,
+ TRIGGER_TTY_DCD,
+ TRIGGER_TTY_RNG,
+};
+
+static int ledtrig_tty_wait_for_completion(struct device *dev)
{
- schedule_delayed_work(&trigger_data->dwork, 0);
+ struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
+ int ret;
+
+ ret = wait_for_completion_timeout(&trigger_data->sysfs,
+ msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 20));
+ if (ret == 0)
+ return -ETIMEDOUT;
+
+ return ret;
}
static ssize_t ttyname_show(struct device *dev,
@@ -28,14 +59,16 @@ static ssize_t ttyname_show(struct device *dev,
{
struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
ssize_t len = 0;
+ int completion;
- mutex_lock(&trigger_data->mutex);
+ reinit_completion(&trigger_data->sysfs);
+ completion = ledtrig_tty_wait_for_completion(dev);
+ if (completion < 0)
+ return completion;
if (trigger_data->ttyname)
len = sprintf(buf, "%s\n", trigger_data->ttyname);
- mutex_unlock(&trigger_data->mutex);
-
return len;
}
@@ -46,7 +79,7 @@ static ssize_t ttyname_store(struct device *dev,
struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
char *ttyname;
ssize_t ret = size;
- bool running;
+ int completion;
if (size > 0 && buf[size - 1] == '\n')
size -= 1;
@@ -59,9 +92,10 @@ static ssize_t ttyname_store(struct device *dev,
ttyname = NULL;
}
- mutex_lock(&trigger_data->mutex);
-
- running = trigger_data->ttyname != NULL;
+ reinit_completion(&trigger_data->sysfs);
+ completion = ledtrig_tty_wait_for_completion(dev);
+ if (completion < 0)
+ return completion;
kfree(trigger_data->ttyname);
tty_kref_put(trigger_data->tty);
@@ -69,29 +103,107 @@ static ssize_t ttyname_store(struct device *dev,
trigger_data->ttyname = ttyname;
- mutex_unlock(&trigger_data->mutex);
-
- if (ttyname && !running)
- ledtrig_tty_restart(trigger_data);
-
return ret;
}
static DEVICE_ATTR_RW(ttyname);
+static ssize_t ledtrig_tty_attr_show(struct device *dev, char *buf,
+ enum led_trigger_tty_modes attr)
+{
+ struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
+ bool state;
+
+ switch (attr) {
+ case TRIGGER_TTY_RX:
+ state = trigger_data->mode_rx;
+ break;
+ case TRIGGER_TTY_TX:
+ state = trigger_data->mode_tx;
+ break;
+ case TRIGGER_TTY_CTS:
+ state = trigger_data->mode_cts;
+ break;
+ case TRIGGER_TTY_DSR:
+ state = trigger_data->mode_dsr;
+ break;
+ case TRIGGER_TTY_DCD:
+ state = trigger_data->mode_dcd;
+ break;
+ case TRIGGER_TTY_RNG:
+ state = trigger_data->mode_rng;
+ break;
+ }
+
+ return sysfs_emit(buf, "%u\n", state);
+}
+
+static ssize_t ledtrig_tty_attr_store(struct device *dev, const char *buf,
+ size_t size, enum led_trigger_tty_modes attr)
+{
+ struct ledtrig_tty_data *trigger_data = led_trigger_get_drvdata(dev);
+ bool state;
+ int ret;
+
+ ret = kstrtobool(buf, &state);
+ if (ret)
+ return ret;
+
+ switch (attr) {
+ case TRIGGER_TTY_RX:
+ trigger_data->mode_rx = state;
+ break;
+ case TRIGGER_TTY_TX:
+ trigger_data->mode_tx = state;
+ break;
+ case TRIGGER_TTY_CTS:
+ trigger_data->mode_cts = state;
+ break;
+ case TRIGGER_TTY_DSR:
+ trigger_data->mode_dsr = state;
+ break;
+ case TRIGGER_TTY_DCD:
+ trigger_data->mode_dcd = state;
+ break;
+ case TRIGGER_TTY_RNG:
+ trigger_data->mode_rng = state;
+ break;
+ }
+
+ return size;
+}
+
+#define DEFINE_TTY_TRIGGER(trigger_name, trigger) \
+ static ssize_t trigger_name##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+ { \
+ return ledtrig_tty_attr_show(dev, buf, trigger); \
+ } \
+ static ssize_t trigger_name##_store(struct device *dev, \
+ struct device_attribute *attr, const char *buf, size_t size) \
+ { \
+ return ledtrig_tty_attr_store(dev, buf, size, trigger); \
+ } \
+ static DEVICE_ATTR_RW(trigger_name)
+
+DEFINE_TTY_TRIGGER(rx, TRIGGER_TTY_RX);
+DEFINE_TTY_TRIGGER(tx, TRIGGER_TTY_TX);
+DEFINE_TTY_TRIGGER(cts, TRIGGER_TTY_CTS);
+DEFINE_TTY_TRIGGER(dsr, TRIGGER_TTY_DSR);
+DEFINE_TTY_TRIGGER(dcd, TRIGGER_TTY_DCD);
+DEFINE_TTY_TRIGGER(rng, TRIGGER_TTY_RNG);
+
static void ledtrig_tty_work(struct work_struct *work)
{
struct ledtrig_tty_data *trigger_data =
container_of(work, struct ledtrig_tty_data, dwork.work);
- struct serial_icounter_struct icount;
+ enum led_trigger_tty_state state = TTY_LED_DISABLE;
+ unsigned long interval = LEDTRIG_TTY_INTERVAL;
+ bool invert = false;
+ int status;
int ret;
- mutex_lock(&trigger_data->mutex);
-
- if (!trigger_data->ttyname) {
- /* exit without rescheduling */
- mutex_unlock(&trigger_data->mutex);
- return;
- }
+ if (!trigger_data->ttyname)
+ goto out;
/* try to get the tty corresponding to $ttyname */
if (!trigger_data->tty) {
@@ -115,32 +227,83 @@ static void ledtrig_tty_work(struct work_struct *work)
trigger_data->tty = tty;
}
- ret = tty_get_icount(trigger_data->tty, &icount);
- if (ret) {
- dev_info(trigger_data->tty->dev, "Failed to get icount, stopped polling\n");
- mutex_unlock(&trigger_data->mutex);
- return;
+ status = tty_get_tiocm(trigger_data->tty);
+ if (status > 0) {
+ if (trigger_data->mode_cts) {
+ if (status & TIOCM_CTS)
+ state = TTY_LED_ENABLE;
+ }
+
+ if (trigger_data->mode_dsr) {
+ if (status & TIOCM_DSR)
+ state = TTY_LED_ENABLE;
+ }
+
+ if (trigger_data->mode_dcd) {
+ if (status & TIOCM_CAR)
+ state = TTY_LED_ENABLE;
+ }
+
+ if (trigger_data->mode_rng) {
+ if (status & TIOCM_RNG)
+ state = TTY_LED_ENABLE;
+ }
}
- if (icount.rx != trigger_data->rx ||
- icount.tx != trigger_data->tx) {
- unsigned long interval = LEDTRIG_TTY_INTERVAL;
+ /*
+ * The evaluation of rx/tx must be done after the evaluation
+ * of TIOCM_*, because rx/tx has priority.
+ */
+ if (trigger_data->mode_rx || trigger_data->mode_tx) {
+ struct serial_icounter_struct icount;
- led_blink_set_oneshot(trigger_data->led_cdev, &interval,
- &interval, 0);
+ ret = tty_get_icount(trigger_data->tty, &icount);
+ if (ret)
+ goto out;
- trigger_data->rx = icount.rx;
- trigger_data->tx = icount.tx;
+ if (trigger_data->mode_tx && (icount.tx != trigger_data->tx)) {
+ trigger_data->tx = icount.tx;
+ invert = state == TTY_LED_ENABLE;
+ state = TTY_LED_BLINK;
+ }
+
+ if (trigger_data->mode_rx && (icount.rx != trigger_data->rx)) {
+ trigger_data->rx = icount.rx;
+ invert = state == TTY_LED_ENABLE;
+ state = TTY_LED_BLINK;
+ }
}
out:
- mutex_unlock(&trigger_data->mutex);
+ switch (state) {
+ case TTY_LED_BLINK:
+ led_blink_set_oneshot(trigger_data->led_cdev, &interval,
+ &interval, invert);
+ break;
+ case TTY_LED_ENABLE:
+ led_set_brightness(trigger_data->led_cdev,
+ trigger_data->led_cdev->blink_brightness);
+ break;
+ case TTY_LED_DISABLE:
+ fallthrough;
+ default:
+ led_set_brightness(trigger_data->led_cdev, LED_OFF);
+ break;
+ }
+
+ complete_all(&trigger_data->sysfs);
schedule_delayed_work(&trigger_data->dwork,
msecs_to_jiffies(LEDTRIG_TTY_INTERVAL * 2));
}
static struct attribute *ledtrig_tty_attrs[] = {
&dev_attr_ttyname.attr,
+ &dev_attr_rx.attr,
+ &dev_attr_tx.attr,
+ &dev_attr_cts.attr,
+ &dev_attr_dsr.attr,
+ &dev_attr_dcd.attr,
+ &dev_attr_rng.attr,
NULL
};
ATTRIBUTE_GROUPS(ledtrig_tty);
@@ -153,11 +316,17 @@ static int ledtrig_tty_activate(struct led_classdev *led_cdev)
if (!trigger_data)
return -ENOMEM;
+ /* Enable default rx/tx mode */
+ trigger_data->mode_rx = true;
+ trigger_data->mode_tx = true;
+
led_set_trigger_data(led_cdev, trigger_data);
INIT_DELAYED_WORK(&trigger_data->dwork, ledtrig_tty_work);
trigger_data->led_cdev = led_cdev;
- mutex_init(&trigger_data->mutex);
+ init_completion(&trigger_data->sysfs);
+
+ schedule_delayed_work(&trigger_data->dwork, 0);
return 0;
}
@@ -168,6 +337,10 @@ static void ledtrig_tty_deactivate(struct led_classdev *led_cdev)
cancel_delayed_work_sync(&trigger_data->dwork);
+ kfree(trigger_data->ttyname);
+ tty_kref_put(trigger_data->tty);
+ trigger_data->tty = NULL;
+
kfree(trigger_data);
}
diff --git a/drivers/mailbox/arm_mhuv2.c b/drivers/mailbox/arm_mhuv2.c
index c6d4957c4da8..0ec21dcdbde7 100644
--- a/drivers/mailbox/arm_mhuv2.c
+++ b/drivers/mailbox/arm_mhuv2.c
@@ -553,7 +553,8 @@ static irqreturn_t mhuv2_sender_interrupt(int irq, void *data)
priv = chan->con_priv;
if (!IS_PROTOCOL_DOORBELL(priv)) {
- writel_relaxed(1, &mhu->send->ch_wn[priv->ch_wn_idx + priv->windows - 1].int_clr);
+ for (i = 0; i < priv->windows; i++)
+ writel_relaxed(1, &mhu->send->ch_wn[priv->ch_wn_idx + i].int_clr);
if (chan->cl) {
mbox_chan_txdone(chan, 0);
diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c
index a2b8839d4e7c..e3e28a4f7d01 100644
--- a/drivers/mailbox/bcm-flexrm-mailbox.c
+++ b/drivers/mailbox/bcm-flexrm-mailbox.c
@@ -1650,7 +1650,7 @@ fail:
return ret;
}
-static int flexrm_mbox_remove(struct platform_device *pdev)
+static void flexrm_mbox_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct flexrm_mbox *mbox = platform_get_drvdata(pdev);
@@ -1661,8 +1661,6 @@ static int flexrm_mbox_remove(struct platform_device *pdev)
dma_pool_destroy(mbox->cmpl_pool);
dma_pool_destroy(mbox->bd_pool);
-
- return 0;
}
static const struct of_device_id flexrm_mbox_of_match[] = {
@@ -1677,7 +1675,7 @@ static struct platform_driver flexrm_mbox_driver = {
.of_match_table = flexrm_mbox_of_match,
},
.probe = flexrm_mbox_probe,
- .remove = flexrm_mbox_remove,
+ .remove_new = flexrm_mbox_remove,
};
module_platform_driver(flexrm_mbox_driver);
diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c
index 778faeced81e..1768d3d5aaa0 100644
--- a/drivers/mailbox/bcm-pdc-mailbox.c
+++ b/drivers/mailbox/bcm-pdc-mailbox.c
@@ -1605,7 +1605,7 @@ cleanup:
return err;
}
-static int pdc_remove(struct platform_device *pdev)
+static void pdc_remove(struct platform_device *pdev)
{
struct pdc_state *pdcs = platform_get_drvdata(pdev);
@@ -1617,12 +1617,11 @@ static int pdc_remove(struct platform_device *pdev)
dma_pool_destroy(pdcs->rx_buf_pool);
dma_pool_destroy(pdcs->ring_pool);
- return 0;
}
static struct platform_driver pdc_mbox_driver = {
.probe = pdc_probe,
- .remove = pdc_remove,
+ .remove_new = pdc_remove,
.driver = {
.name = "brcm-iproc-pdc-mbox",
.of_match_table = pdc_mbox_of_match,
diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
index 0af739ab571c..656171362fe9 100644
--- a/drivers/mailbox/imx-mailbox.c
+++ b/drivers/mailbox/imx-mailbox.c
@@ -903,13 +903,11 @@ disable_runtime_pm:
return ret;
}
-static int imx_mu_remove(struct platform_device *pdev)
+static void imx_mu_remove(struct platform_device *pdev)
{
struct imx_mu_priv *priv = platform_get_drvdata(pdev);
pm_runtime_disable(priv->dev);
-
- return 0;
}
static const struct imx_mu_dcfg imx_mu_cfg_imx6sx = {
@@ -1070,7 +1068,7 @@ static const struct dev_pm_ops imx_mu_pm_ops = {
static struct platform_driver imx_mu_driver = {
.probe = imx_mu_probe,
- .remove = imx_mu_remove,
+ .remove_new = imx_mu_remove,
.driver = {
.name = "imx_mu",
.of_match_table = imx_mu_dt_ids,
diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c
index 22d6018ceec3..3386b4e72551 100644
--- a/drivers/mailbox/mailbox-test.c
+++ b/drivers/mailbox/mailbox-test.c
@@ -418,7 +418,7 @@ static int mbox_test_probe(struct platform_device *pdev)
return 0;
}
-static int mbox_test_remove(struct platform_device *pdev)
+static void mbox_test_remove(struct platform_device *pdev)
{
struct mbox_test_device *tdev = platform_get_drvdata(pdev);
@@ -428,8 +428,6 @@ static int mbox_test_remove(struct platform_device *pdev)
mbox_free_channel(tdev->tx_channel);
if (tdev->rx_channel)
mbox_free_channel(tdev->rx_channel);
-
- return 0;
}
static const struct of_device_id mbox_test_match[] = {
@@ -444,7 +442,7 @@ static struct platform_driver mbox_test_driver = {
.of_match_table = mbox_test_match,
},
.probe = mbox_test_probe,
- .remove = mbox_test_remove,
+ .remove_new = mbox_test_remove,
};
module_platform_driver(mbox_test_driver);
diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
index de862e9137d5..ead2200f39ba 100644
--- a/drivers/mailbox/mtk-cmdq-mailbox.c
+++ b/drivers/mailbox/mtk-cmdq-mailbox.c
@@ -367,7 +367,7 @@ static int cmdq_resume(struct device *dev)
return 0;
}
-static int cmdq_remove(struct platform_device *pdev)
+static void cmdq_remove(struct platform_device *pdev)
{
struct cmdq *cmdq = platform_get_drvdata(pdev);
@@ -378,7 +378,6 @@ static int cmdq_remove(struct platform_device *pdev)
cmdq_runtime_suspend(&pdev->dev);
clk_bulk_unprepare(cmdq->pdata->gce_num, cmdq->clocks);
- return 0;
}
static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
@@ -706,62 +705,70 @@ static const struct dev_pm_ops cmdq_pm_ops = {
cmdq_runtime_resume, NULL)
};
-static const struct gce_plat gce_plat_v2 = {
- .thread_nr = 16,
- .shift = 0,
+static const struct gce_plat gce_plat_mt6779 = {
+ .thread_nr = 24,
+ .shift = 3,
.control_by_sw = false,
.gce_num = 1
};
-static const struct gce_plat gce_plat_v3 = {
- .thread_nr = 24,
+static const struct gce_plat gce_plat_mt8173 = {
+ .thread_nr = 16,
.shift = 0,
.control_by_sw = false,
.gce_num = 1
};
-static const struct gce_plat gce_plat_v4 = {
+static const struct gce_plat gce_plat_mt8183 = {
.thread_nr = 24,
- .shift = 3,
+ .shift = 0,
.control_by_sw = false,
.gce_num = 1
};
-static const struct gce_plat gce_plat_v5 = {
+static const struct gce_plat gce_plat_mt8186 = {
.thread_nr = 24,
.shift = 3,
.control_by_sw = true,
+ .sw_ddr_en = true,
.gce_num = 1
};
-static const struct gce_plat gce_plat_v6 = {
- .thread_nr = 24,
+static const struct gce_plat gce_plat_mt8188 = {
+ .thread_nr = 32,
.shift = 3,
.control_by_sw = true,
.gce_num = 2
};
-static const struct gce_plat gce_plat_v7 = {
+static const struct gce_plat gce_plat_mt8192 = {
.thread_nr = 24,
.shift = 3,
.control_by_sw = true,
- .sw_ddr_en = true,
.gce_num = 1
};
+static const struct gce_plat gce_plat_mt8195 = {
+ .thread_nr = 24,
+ .shift = 3,
+ .control_by_sw = true,
+ .gce_num = 2
+};
+
static const struct of_device_id cmdq_of_ids[] = {
- {.compatible = "mediatek,mt8173-gce", .data = (void *)&gce_plat_v2},
- {.compatible = "mediatek,mt8183-gce", .data = (void *)&gce_plat_v3},
- {.compatible = "mediatek,mt8186-gce", .data = (void *)&gce_plat_v7},
- {.compatible = "mediatek,mt6779-gce", .data = (void *)&gce_plat_v4},
- {.compatible = "mediatek,mt8192-gce", .data = (void *)&gce_plat_v5},
- {.compatible = "mediatek,mt8195-gce", .data = (void *)&gce_plat_v6},
+ {.compatible = "mediatek,mt6779-gce", .data = (void *)&gce_plat_mt6779},
+ {.compatible = "mediatek,mt8173-gce", .data = (void *)&gce_plat_mt8173},
+ {.compatible = "mediatek,mt8183-gce", .data = (void *)&gce_plat_mt8183},
+ {.compatible = "mediatek,mt8186-gce", .data = (void *)&gce_plat_mt8186},
+ {.compatible = "mediatek,mt8188-gce", .data = (void *)&gce_plat_mt8188},
+ {.compatible = "mediatek,mt8192-gce", .data = (void *)&gce_plat_mt8192},
+ {.compatible = "mediatek,mt8195-gce", .data = (void *)&gce_plat_mt8195},
{}
};
static struct platform_driver cmdq_drv = {
.probe = cmdq_probe,
- .remove = cmdq_remove,
+ .remove_new = cmdq_remove,
.driver = {
.name = "mtk_cmdq",
.pm = &cmdq_pm_ops,
diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c
index 792bcaebbc9b..c961706fe61d 100644
--- a/drivers/mailbox/omap-mailbox.c
+++ b/drivers/mailbox/omap-mailbox.c
@@ -865,19 +865,17 @@ unregister:
return ret;
}
-static int omap_mbox_remove(struct platform_device *pdev)
+static void omap_mbox_remove(struct platform_device *pdev)
{
struct omap_mbox_device *mdev = platform_get_drvdata(pdev);
pm_runtime_disable(mdev->dev);
omap_mbox_unregister(mdev);
-
- return 0;
}
static struct platform_driver omap_mbox_driver = {
.probe = omap_mbox_probe,
- .remove = omap_mbox_remove,
+ .remove_new = omap_mbox_remove,
.driver = {
.name = "omap-mailbox",
.pm = &omap_mbox_pm_ops,
diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c
index 002a135ee868..7d91e7c016ba 100644
--- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c
+++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c
@@ -129,14 +129,12 @@ static int qcom_apcs_ipc_probe(struct platform_device *pdev)
return 0;
}
-static int qcom_apcs_ipc_remove(struct platform_device *pdev)
+static void qcom_apcs_ipc_remove(struct platform_device *pdev)
{
struct qcom_apcs_ipc *apcs = platform_get_drvdata(pdev);
struct platform_device *clk = apcs->clk;
platform_device_unregister(clk);
-
- return 0;
}
/* .data is the offset of the ipc register within the global block */
@@ -145,19 +143,19 @@ static const struct of_device_id qcom_apcs_ipc_of_match[] = {
{ .compatible = "qcom,msm8916-apcs-kpss-global", .data = &msm8916_apcs_data },
{ .compatible = "qcom,msm8939-apcs-kpss-global", .data = &msm8916_apcs_data },
{ .compatible = "qcom,msm8953-apcs-kpss-global", .data = &msm8994_apcs_data },
- { .compatible = "qcom,msm8976-apcs-kpss-global", .data = &msm8994_apcs_data },
{ .compatible = "qcom,msm8994-apcs-kpss-global", .data = &msm8994_apcs_data },
{ .compatible = "qcom,msm8996-apcs-hmss-global", .data = &msm8996_apcs_data },
- { .compatible = "qcom,msm8998-apcs-hmss-global", .data = &msm8994_apcs_data },
{ .compatible = "qcom,qcm2290-apcs-hmss-global", .data = &msm8994_apcs_data },
+ { .compatible = "qcom,sdm845-apss-shared", .data = &apps_shared_apcs_data },
+ { .compatible = "qcom,sdx55-apcs-gcc", .data = &sdx55_apcs_data },
+ /* Do not add any more entries using existing driver data */
+ { .compatible = "qcom,msm8976-apcs-kpss-global", .data = &msm8994_apcs_data },
+ { .compatible = "qcom,msm8998-apcs-hmss-global", .data = &msm8994_apcs_data },
{ .compatible = "qcom,qcs404-apcs-apps-global", .data = &msm8916_apcs_data },
{ .compatible = "qcom,sdm660-apcs-hmss-global", .data = &msm8994_apcs_data },
- { .compatible = "qcom,sdm845-apss-shared", .data = &apps_shared_apcs_data },
{ .compatible = "qcom,sm4250-apcs-hmss-global", .data = &msm8994_apcs_data },
{ .compatible = "qcom,sm6125-apcs-hmss-global", .data = &msm8994_apcs_data },
{ .compatible = "qcom,sm6115-apcs-hmss-global", .data = &msm8994_apcs_data },
- { .compatible = "qcom,sdx55-apcs-gcc", .data = &sdx55_apcs_data },
- /* Do not add any more entries using existing driver data */
{ .compatible = "qcom,ipq5332-apcs-apps-global", .data = &ipq6018_apcs_data },
{ .compatible = "qcom,ipq8074-apcs-apps-global", .data = &ipq6018_apcs_data },
{ .compatible = "qcom,sc7180-apss-shared", .data = &apps_shared_apcs_data },
@@ -169,7 +167,7 @@ MODULE_DEVICE_TABLE(of, qcom_apcs_ipc_of_match);
static struct platform_driver qcom_apcs_ipc_driver = {
.probe = qcom_apcs_ipc_probe,
- .remove = qcom_apcs_ipc_remove,
+ .remove_new = qcom_apcs_ipc_remove,
.driver = {
.name = "qcom_apcs_ipc",
.of_match_table = qcom_apcs_ipc_of_match,
diff --git a/drivers/mailbox/qcom-ipcc.c b/drivers/mailbox/qcom-ipcc.c
index f597a1bd5684..d537cc9c4d4b 100644
--- a/drivers/mailbox/qcom-ipcc.c
+++ b/drivers/mailbox/qcom-ipcc.c
@@ -326,14 +326,12 @@ err_mbox:
return ret;
}
-static int qcom_ipcc_remove(struct platform_device *pdev)
+static void qcom_ipcc_remove(struct platform_device *pdev)
{
struct qcom_ipcc *ipcc = platform_get_drvdata(pdev);
disable_irq_wake(ipcc->irq);
irq_domain_remove(ipcc->irq_domain);
-
- return 0;
}
static const struct of_device_id qcom_ipcc_of_match[] = {
@@ -348,7 +346,7 @@ static const struct dev_pm_ops qcom_ipcc_dev_pm_ops = {
static struct platform_driver qcom_ipcc_driver = {
.probe = qcom_ipcc_probe,
- .remove = qcom_ipcc_remove,
+ .remove_new = qcom_ipcc_remove,
.driver = {
.name = "qcom-ipcc",
.of_match_table = qcom_ipcc_of_match,
diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c
index 4ad3653f3866..1442f275782b 100644
--- a/drivers/mailbox/stm32-ipcc.c
+++ b/drivers/mailbox/stm32-ipcc.c
@@ -331,7 +331,7 @@ err_clk:
return ret;
}
-static int stm32_ipcc_remove(struct platform_device *pdev)
+static void stm32_ipcc_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -339,8 +339,6 @@ static int stm32_ipcc_remove(struct platform_device *pdev)
dev_pm_clear_wake_irq(&pdev->dev);
device_set_wakeup_capable(dev, false);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -381,7 +379,7 @@ static struct platform_driver stm32_ipcc_driver = {
.of_match_table = stm32_ipcc_of_match,
},
.probe = stm32_ipcc_probe,
- .remove = stm32_ipcc_remove,
+ .remove_new = stm32_ipcc_remove,
};
module_platform_driver(stm32_ipcc_driver);
diff --git a/drivers/mailbox/sun6i-msgbox.c b/drivers/mailbox/sun6i-msgbox.c
index 7f8d931042d3..3dcc54dc83b2 100644
--- a/drivers/mailbox/sun6i-msgbox.c
+++ b/drivers/mailbox/sun6i-msgbox.c
@@ -287,15 +287,13 @@ err_disable_unprepare:
return ret;
}
-static int sun6i_msgbox_remove(struct platform_device *pdev)
+static void sun6i_msgbox_remove(struct platform_device *pdev)
{
struct sun6i_msgbox *mbox = platform_get_drvdata(pdev);
mbox_controller_unregister(&mbox->controller);
/* See the comment in sun6i_msgbox_probe about the reset line. */
clk_disable_unprepare(mbox->clk);
-
- return 0;
}
static const struct of_device_id sun6i_msgbox_of_match[] = {
@@ -310,7 +308,7 @@ static struct platform_driver sun6i_msgbox_driver = {
.of_match_table = sun6i_msgbox_of_match,
},
.probe = sun6i_msgbox_probe,
- .remove = sun6i_msgbox_remove,
+ .remove_new = sun6i_msgbox_remove,
};
module_platform_driver(sun6i_msgbox_driver);
diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
index fe29fc2ca526..19ef56cbcfd3 100644
--- a/drivers/mailbox/tegra-hsp.c
+++ b/drivers/mailbox/tegra-hsp.c
@@ -868,13 +868,11 @@ static int tegra_hsp_probe(struct platform_device *pdev)
return 0;
}
-static int tegra_hsp_remove(struct platform_device *pdev)
+static void tegra_hsp_remove(struct platform_device *pdev)
{
struct tegra_hsp *hsp = platform_get_drvdata(pdev);
lockdep_unregister_key(&hsp->lock_key);
-
- return 0;
}
static int __maybe_unused tegra_hsp_resume(struct device *dev)
@@ -953,7 +951,7 @@ static struct platform_driver tegra_hsp_driver = {
.pm = &tegra_hsp_pm_ops,
},
.probe = tegra_hsp_probe,
- .remove = tegra_hsp_remove,
+ .remove_new = tegra_hsp_remove,
};
static int __init tegra_hsp_init(void)
diff --git a/drivers/mailbox/zynqmp-ipi-mailbox.c b/drivers/mailbox/zynqmp-ipi-mailbox.c
index 7fa533e80dd9..25c65afc030a 100644
--- a/drivers/mailbox/zynqmp-ipi-mailbox.c
+++ b/drivers/mailbox/zynqmp-ipi-mailbox.c
@@ -81,7 +81,6 @@ struct zynqmp_ipi_mchan {
* @remote_id: remote IPI agent ID
* @mbox: mailbox Controller
* @mchans: array for channels, tx channel and rx channel.
- * @irq: IPI agent interrupt ID
*/
struct zynqmp_ipi_mbox {
struct zynqmp_ipi_pdata *pdata;
@@ -688,19 +687,17 @@ free_mbox_dev:
return ret;
}
-static int zynqmp_ipi_remove(struct platform_device *pdev)
+static void zynqmp_ipi_remove(struct platform_device *pdev)
{
struct zynqmp_ipi_pdata *pdata;
pdata = platform_get_drvdata(pdev);
zynqmp_ipi_free_mboxes(pdata);
-
- return 0;
}
static struct platform_driver zynqmp_ipi_driver = {
.probe = zynqmp_ipi_probe,
- .remove = zynqmp_ipi_remove,
+ .remove_new = zynqmp_ipi_remove,
.driver = {
.name = "zynqmp-ipi",
.of_match_table = of_match_ptr(zynqmp_ipi_of_match),
diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c
index ba4530459de8..61994da7bad0 100644
--- a/drivers/mcb/mcb-core.c
+++ b/drivers/mcb/mcb-core.c
@@ -263,6 +263,7 @@ static void mcb_free_bus(struct device *dev)
/**
* mcb_alloc_bus() - Allocate a new @mcb_bus
+ * @carrier: generic &struct device for the carrier device
*
* Allocate a new @mcb_bus.
*/
@@ -327,7 +328,7 @@ void mcb_release_bus(struct mcb_bus *bus)
EXPORT_SYMBOL_NS_GPL(mcb_release_bus, MCB);
/**
- * mcb_bus_put() - Increment refcnt
+ * mcb_bus_get() - Increment refcnt
* @bus: The @mcb_bus
*
* Get a @mcb_bus' ref
@@ -455,7 +456,7 @@ EXPORT_SYMBOL_NS_GPL(mcb_request_mem, MCB);
/**
* mcb_release_mem() - Release memory requested by device
- * @dev: The @mcb_device that requested the memory
+ * @mem: The memory resource to be released
*
* Release memory that was prior requested via @mcb_request_mem().
*/
diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c
index 6bb49bb3f98c..5741adf09a2e 100644
--- a/drivers/media/cec/core/cec-adap.c
+++ b/drivers/media/cec/core/cec-adap.c
@@ -511,7 +511,7 @@ int cec_thread_func(void *_adap)
pr_warn("cec-%s: transmit timed out\n", adap->name);
}
adap->transmit_in_progress = false;
- adap->tx_timeouts++;
+ adap->tx_timeout_cnt++;
goto unlock;
}
@@ -625,6 +625,33 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
msg->tx_low_drive_cnt += low_drive_cnt;
msg->tx_error_cnt += error_cnt;
+ adap->tx_arb_lost_cnt += arb_lost_cnt;
+ adap->tx_low_drive_cnt += low_drive_cnt;
+ adap->tx_error_cnt += error_cnt;
+
+ /*
+ * Low Drive transmission errors should really not happen for
+ * well-behaved CEC devices and proper HDMI cables.
+ *
+ * Ditto for the 'Error' status.
+ *
+ * For the first few times that this happens, log this.
+ * Stop logging after that, since that will not add any more
+ * useful information and instead it will just flood the kernel log.
+ */
+ if (done && adap->tx_low_drive_log_cnt < 8 && msg->tx_low_drive_cnt) {
+ adap->tx_low_drive_log_cnt++;
+ dprintk(0, "low drive counter: %u (seq %u: %*ph)\n",
+ msg->tx_low_drive_cnt, msg->sequence,
+ msg->len, msg->msg);
+ }
+ if (done && adap->tx_error_log_cnt < 8 && msg->tx_error_cnt) {
+ adap->tx_error_log_cnt++;
+ dprintk(0, "error counter: %u (seq %u: %*ph)\n",
+ msg->tx_error_cnt, msg->sequence,
+ msg->len, msg->msg);
+ }
+
/* Mark that we're done with this transmit */
adap->transmitting = NULL;
@@ -1607,6 +1634,8 @@ int cec_adap_enable(struct cec_adapter *adap)
if (enable) {
adap->last_initiator = 0xff;
adap->transmit_in_progress = false;
+ adap->tx_low_drive_log_cnt = 0;
+ adap->tx_error_log_cnt = 0;
ret = adap->ops->adap_enable(adap, true);
if (!ret) {
/*
@@ -2265,10 +2294,25 @@ int cec_adap_status(struct seq_file *file, void *priv)
if (adap->monitor_pin_cnt)
seq_printf(file, "file handles in Monitor Pin mode: %u\n",
adap->monitor_pin_cnt);
- if (adap->tx_timeouts) {
- seq_printf(file, "transmit timeouts: %u\n",
- adap->tx_timeouts);
- adap->tx_timeouts = 0;
+ if (adap->tx_timeout_cnt) {
+ seq_printf(file, "transmit timeout count: %u\n",
+ adap->tx_timeout_cnt);
+ adap->tx_timeout_cnt = 0;
+ }
+ if (adap->tx_low_drive_cnt) {
+ seq_printf(file, "transmit low drive count: %u\n",
+ adap->tx_low_drive_cnt);
+ adap->tx_low_drive_cnt = 0;
+ }
+ if (adap->tx_arb_lost_cnt) {
+ seq_printf(file, "transmit arbitration lost count: %u\n",
+ adap->tx_arb_lost_cnt);
+ adap->tx_arb_lost_cnt = 0;
+ }
+ if (adap->tx_error_cnt) {
+ seq_printf(file, "transmit error count: %u\n",
+ adap->tx_error_cnt);
+ adap->tx_error_cnt = 0;
}
data = adap->transmitting;
if (data)
diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
index 42dde3f0dbde..52ec0ba4b339 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -324,6 +324,8 @@ static const struct cec_dmi_match cec_dmi_match_table[] = {
{ "Google", "Boxy", "0000:00:02.0", port_d_conns },
/* Google Taranza */
{ "Google", "Taranza", "0000:00:02.0", port_db_conns },
+ /* Google Dexi */
+ { "Google", "Dexi", "0000:00:02.0", port_db_conns },
};
static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
index 79214459387a..a7047e548245 100644
--- a/drivers/media/common/saa7146/saa7146_fops.c
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -387,7 +387,7 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev,
q->gfp_flags = __GFP_DMA32;
q->buf_struct_size = sizeof(struct saa7146_buf);
q->lock = &dev->v4l2_lock;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->dev = &dev->pci->dev;
err = vb2_queue_init(q);
if (err)
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index 27aee92f3eea..41a832dd1426 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -31,6 +31,16 @@
#include <trace/events/vb2.h>
+#define PLANE_INDEX_BITS 3
+#define PLANE_INDEX_SHIFT (PAGE_SHIFT + PLANE_INDEX_BITS)
+#define PLANE_INDEX_MASK (BIT_MASK(PLANE_INDEX_BITS) - 1)
+#define MAX_BUFFER_INDEX BIT_MASK(30 - PLANE_INDEX_SHIFT)
+#define BUFFER_INDEX_MASK (MAX_BUFFER_INDEX - 1)
+
+#if BIT(PLANE_INDEX_BITS) != VIDEO_MAX_PLANES
+#error PLANE_INDEX_BITS order must be equal to VIDEO_MAX_PLANES
+#endif
+
static int debug;
module_param(debug, int, 0644);
@@ -356,23 +366,29 @@ static void __setup_offsets(struct vb2_buffer *vb)
{
struct vb2_queue *q = vb->vb2_queue;
unsigned int plane;
- unsigned long off = 0;
-
- if (vb->index) {
- struct vb2_buffer *prev = q->bufs[vb->index - 1];
- struct vb2_plane *p = &prev->planes[prev->num_planes - 1];
+ unsigned long offset = 0;
- off = PAGE_ALIGN(p->m.offset + p->length);
- }
+ /*
+ * The offset "cookie" value has the following constraints:
+ * - a buffer can have up to 8 planes.
+ * - v4l2 mem2mem uses bit 30 to distinguish between
+ * OUTPUT (aka "source", bit 30 is 0) and
+ * CAPTURE (aka "destination", bit 30 is 1) buffers.
+ * - must be page aligned
+ * That led to this bit mapping when PAGE_SHIFT = 12:
+ * |30 |29 15|14 12|11 0|
+ * |DST_QUEUE_OFF_BASE|buffer index|plane index| 0 |
+ * where there are 15 bits to store the buffer index.
+ * Depending on PAGE_SHIFT value we can have fewer bits
+ * to store the buffer index.
+ */
+ offset = vb->index << PLANE_INDEX_SHIFT;
for (plane = 0; plane < vb->num_planes; ++plane) {
- vb->planes[plane].m.offset = off;
+ vb->planes[plane].m.offset = offset + (plane << PAGE_SHIFT);
dprintk(q, 3, "buffer %d, plane %d offset 0x%08lx\n",
- vb->index, plane, off);
-
- off += vb->planes[plane].length;
- off = PAGE_ALIGN(off);
+ vb->index, plane, offset);
}
}
@@ -397,6 +413,31 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
vb->skip_cache_sync_on_finish = 1;
}
+/**
+ * vb2_queue_add_buffer() - add a buffer to a queue
+ * @q: pointer to &struct vb2_queue with videobuf2 queue.
+ * @vb: pointer to &struct vb2_buffer to be added to the queue.
+ * @index: index where add vb2_buffer in the queue
+ */
+static void vb2_queue_add_buffer(struct vb2_queue *q, struct vb2_buffer *vb, unsigned int index)
+{
+ WARN_ON(index >= q->max_num_buffers || q->bufs[index] || vb->vb2_queue);
+
+ q->bufs[index] = vb;
+ vb->index = index;
+ vb->vb2_queue = q;
+}
+
+/**
+ * vb2_queue_remove_buffer() - remove a buffer from a queue
+ * @vb: pointer to &struct vb2_buffer to be removed from the queue.
+ */
+static void vb2_queue_remove_buffer(struct vb2_buffer *vb)
+{
+ vb->vb2_queue->bufs[vb->index] = NULL;
+ vb->vb2_queue = NULL;
+}
+
/*
* __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type)
* video buffer memory for all buffers/planes on the queue and initializes the
@@ -408,13 +449,17 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
unsigned int num_buffers, unsigned int num_planes,
const unsigned plane_sizes[VB2_MAX_PLANES])
{
+ unsigned int q_num_buffers = vb2_get_num_buffers(q);
unsigned int buffer, plane;
struct vb2_buffer *vb;
int ret;
- /* Ensure that q->num_buffers+num_buffers is below VB2_MAX_FRAME */
+ /*
+ * Ensure that the number of already queue + the number of buffers already
+ * in the queue is below q->max_num_buffers
+ */
num_buffers = min_t(unsigned int, num_buffers,
- VB2_MAX_FRAME - q->num_buffers);
+ q->max_num_buffers - q_num_buffers);
for (buffer = 0; buffer < num_buffers; ++buffer) {
/* Allocate vb2 buffer structures */
@@ -425,9 +470,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
}
vb->state = VB2_BUF_STATE_DEQUEUED;
- vb->vb2_queue = q;
vb->num_planes = num_planes;
- vb->index = q->num_buffers + buffer;
vb->type = q->type;
vb->memory = memory;
init_buffer_cache_hints(q, vb);
@@ -435,9 +478,9 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
vb->planes[plane].length = plane_sizes[plane];
vb->planes[plane].min_length = plane_sizes[plane];
}
- call_void_bufop(q, init_buffer, vb);
- q->bufs[vb->index] = vb;
+ vb2_queue_add_buffer(q, vb, q_num_buffers + buffer);
+ call_void_bufop(q, init_buffer, vb);
/* Allocate video buffer memory for the MMAP type */
if (memory == VB2_MEMORY_MMAP) {
@@ -445,7 +488,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
if (ret) {
dprintk(q, 1, "failed allocating memory for buffer %d\n",
buffer);
- q->bufs[vb->index] = NULL;
+ vb2_queue_remove_buffer(vb);
kfree(vb);
break;
}
@@ -460,7 +503,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
dprintk(q, 1, "buffer %d %p initialization failed\n",
buffer, vb);
__vb2_buf_mem_free(vb);
- q->bufs[vb->index] = NULL;
+ vb2_queue_remove_buffer(vb);
kfree(vb);
break;
}
@@ -480,10 +523,11 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
{
unsigned int buffer;
struct vb2_buffer *vb;
+ unsigned int q_num_buffers = vb2_get_num_buffers(q);
- for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
+ for (buffer = q_num_buffers - buffers; buffer < q_num_buffers;
++buffer) {
- vb = q->bufs[buffer];
+ vb = vb2_get_buffer(q, buffer);
if (!vb)
continue;
@@ -505,13 +549,14 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
{
unsigned int buffer;
+ unsigned int q_num_buffers = vb2_get_num_buffers(q);
lockdep_assert_held(&q->mmap_lock);
/* Call driver-provided cleanup function for each buffer, if provided */
- for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
+ for (buffer = q_num_buffers - buffers; buffer < q_num_buffers;
++buffer) {
- struct vb2_buffer *vb = q->bufs[buffer];
+ struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
if (vb && vb->planes[0].mem_priv)
call_void_vb_qop(vb, buf_cleanup, vb);
@@ -522,25 +567,26 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
#ifdef CONFIG_VIDEO_ADV_DEBUG
/*
- * Check that all the calls were balances during the life-time of this
- * queue. If not (or if the debug level is 1 or up), then dump the
- * counters to the kernel log.
+ * Check that all the calls were balanced during the life-time of this
+ * queue. If not then dump the counters to the kernel log.
*/
- if (q->num_buffers) {
+ if (q_num_buffers) {
bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming ||
q->cnt_prepare_streaming != q->cnt_unprepare_streaming ||
q->cnt_wait_prepare != q->cnt_wait_finish;
- if (unbalanced || debug) {
- pr_info("counters for queue %p:%s\n", q,
- unbalanced ? " UNBALANCED!" : "");
- pr_info(" setup: %u start_streaming: %u stop_streaming: %u\n",
- q->cnt_queue_setup, q->cnt_start_streaming,
- q->cnt_stop_streaming);
- pr_info(" prepare_streaming: %u unprepare_streaming: %u\n",
- q->cnt_prepare_streaming, q->cnt_unprepare_streaming);
- pr_info(" wait_prepare: %u wait_finish: %u\n",
- q->cnt_wait_prepare, q->cnt_wait_finish);
+ if (unbalanced) {
+ pr_info("unbalanced counters for queue %p:\n", q);
+ if (q->cnt_start_streaming != q->cnt_stop_streaming)
+ pr_info(" setup: %u start_streaming: %u stop_streaming: %u\n",
+ q->cnt_queue_setup, q->cnt_start_streaming,
+ q->cnt_stop_streaming);
+ if (q->cnt_prepare_streaming != q->cnt_unprepare_streaming)
+ pr_info(" prepare_streaming: %u unprepare_streaming: %u\n",
+ q->cnt_prepare_streaming, q->cnt_unprepare_streaming);
+ if (q->cnt_wait_prepare != q->cnt_wait_finish)
+ pr_info(" wait_prepare: %u wait_finish: %u\n",
+ q->cnt_wait_prepare, q->cnt_wait_finish);
}
q->cnt_queue_setup = 0;
q->cnt_wait_prepare = 0;
@@ -550,53 +596,71 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
q->cnt_stop_streaming = 0;
q->cnt_unprepare_streaming = 0;
}
- for (buffer = 0; buffer < q->num_buffers; ++buffer) {
- struct vb2_buffer *vb = q->bufs[buffer];
- bool unbalanced = vb->cnt_mem_alloc != vb->cnt_mem_put ||
- vb->cnt_mem_prepare != vb->cnt_mem_finish ||
- vb->cnt_mem_get_userptr != vb->cnt_mem_put_userptr ||
- vb->cnt_mem_attach_dmabuf != vb->cnt_mem_detach_dmabuf ||
- vb->cnt_mem_map_dmabuf != vb->cnt_mem_unmap_dmabuf ||
- vb->cnt_buf_queue != vb->cnt_buf_done ||
- vb->cnt_buf_prepare != vb->cnt_buf_finish ||
- vb->cnt_buf_init != vb->cnt_buf_cleanup;
-
- if (unbalanced || debug) {
- pr_info(" counters for queue %p, buffer %d:%s\n",
- q, buffer, unbalanced ? " UNBALANCED!" : "");
- pr_info(" buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n",
- vb->cnt_buf_init, vb->cnt_buf_cleanup,
- vb->cnt_buf_prepare, vb->cnt_buf_finish);
- pr_info(" buf_out_validate: %u buf_queue: %u buf_done: %u buf_request_complete: %u\n",
- vb->cnt_buf_out_validate, vb->cnt_buf_queue,
- vb->cnt_buf_done, vb->cnt_buf_request_complete);
- pr_info(" alloc: %u put: %u prepare: %u finish: %u mmap: %u\n",
- vb->cnt_mem_alloc, vb->cnt_mem_put,
- vb->cnt_mem_prepare, vb->cnt_mem_finish,
- vb->cnt_mem_mmap);
- pr_info(" get_userptr: %u put_userptr: %u\n",
- vb->cnt_mem_get_userptr, vb->cnt_mem_put_userptr);
- pr_info(" attach_dmabuf: %u detach_dmabuf: %u map_dmabuf: %u unmap_dmabuf: %u\n",
- vb->cnt_mem_attach_dmabuf, vb->cnt_mem_detach_dmabuf,
- vb->cnt_mem_map_dmabuf, vb->cnt_mem_unmap_dmabuf);
- pr_info(" get_dmabuf: %u num_users: %u vaddr: %u cookie: %u\n",
+ for (buffer = 0; buffer < vb2_get_num_buffers(q); buffer++) {
+ struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
+ bool unbalanced;
+
+ if (!vb)
+ continue;
+
+ unbalanced = vb->cnt_mem_alloc != vb->cnt_mem_put ||
+ vb->cnt_mem_prepare != vb->cnt_mem_finish ||
+ vb->cnt_mem_get_userptr != vb->cnt_mem_put_userptr ||
+ vb->cnt_mem_attach_dmabuf != vb->cnt_mem_detach_dmabuf ||
+ vb->cnt_mem_map_dmabuf != vb->cnt_mem_unmap_dmabuf ||
+ vb->cnt_buf_queue != vb->cnt_buf_done ||
+ vb->cnt_buf_prepare != vb->cnt_buf_finish ||
+ vb->cnt_buf_init != vb->cnt_buf_cleanup;
+
+ if (unbalanced) {
+ pr_info("unbalanced counters for queue %p, buffer %d:\n",
+ q, buffer);
+ if (vb->cnt_buf_init != vb->cnt_buf_cleanup)
+ pr_info(" buf_init: %u buf_cleanup: %u\n",
+ vb->cnt_buf_init, vb->cnt_buf_cleanup);
+ if (vb->cnt_buf_prepare != vb->cnt_buf_finish)
+ pr_info(" buf_prepare: %u buf_finish: %u\n",
+ vb->cnt_buf_prepare, vb->cnt_buf_finish);
+ if (vb->cnt_buf_queue != vb->cnt_buf_done)
+ pr_info(" buf_out_validate: %u buf_queue: %u buf_done: %u buf_request_complete: %u\n",
+ vb->cnt_buf_out_validate, vb->cnt_buf_queue,
+ vb->cnt_buf_done, vb->cnt_buf_request_complete);
+ if (vb->cnt_mem_alloc != vb->cnt_mem_put)
+ pr_info(" alloc: %u put: %u\n",
+ vb->cnt_mem_alloc, vb->cnt_mem_put);
+ if (vb->cnt_mem_prepare != vb->cnt_mem_finish)
+ pr_info(" prepare: %u finish: %u\n",
+ vb->cnt_mem_prepare, vb->cnt_mem_finish);
+ if (vb->cnt_mem_get_userptr != vb->cnt_mem_put_userptr)
+ pr_info(" get_userptr: %u put_userptr: %u\n",
+ vb->cnt_mem_get_userptr, vb->cnt_mem_put_userptr);
+ if (vb->cnt_mem_attach_dmabuf != vb->cnt_mem_detach_dmabuf)
+ pr_info(" attach_dmabuf: %u detach_dmabuf: %u\n",
+ vb->cnt_mem_attach_dmabuf, vb->cnt_mem_detach_dmabuf);
+ if (vb->cnt_mem_map_dmabuf != vb->cnt_mem_unmap_dmabuf)
+ pr_info(" map_dmabuf: %u unmap_dmabuf: %u\n",
+ vb->cnt_mem_map_dmabuf, vb->cnt_mem_unmap_dmabuf);
+ pr_info(" get_dmabuf: %u num_users: %u\n",
vb->cnt_mem_get_dmabuf,
- vb->cnt_mem_num_users,
- vb->cnt_mem_vaddr,
- vb->cnt_mem_cookie);
+ vb->cnt_mem_num_users);
}
}
#endif
/* Free vb2 buffers */
- for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
+ for (buffer = q_num_buffers - buffers; buffer < q_num_buffers;
++buffer) {
- kfree(q->bufs[buffer]);
- q->bufs[buffer] = NULL;
+ struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
+
+ if (!vb)
+ continue;
+
+ vb2_queue_remove_buffer(vb);
+ kfree(vb);
}
q->num_buffers -= buffers;
- if (!q->num_buffers) {
+ if (!vb2_get_num_buffers(q)) {
q->memory = VB2_MEMORY_UNKNOWN;
INIT_LIST_HEAD(&q->queued_list);
}
@@ -627,16 +691,21 @@ EXPORT_SYMBOL(vb2_buffer_in_use);
static bool __buffers_in_use(struct vb2_queue *q)
{
unsigned int buffer;
- for (buffer = 0; buffer < q->num_buffers; ++buffer) {
- if (vb2_buffer_in_use(q, q->bufs[buffer]))
+ for (buffer = 0; buffer < vb2_get_num_buffers(q); ++buffer) {
+ struct vb2_buffer *vb = vb2_get_buffer(q, buffer);
+
+ if (!vb)
+ continue;
+
+ if (vb2_buffer_in_use(q, vb))
return true;
}
return false;
}
-void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
+void vb2_core_querybuf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb)
{
- call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
+ call_void_bufop(q, fill_user_buffer, vb, pb);
}
EXPORT_SYMBOL_GPL(vb2_core_querybuf);
@@ -748,10 +817,11 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
unsigned int flags, unsigned int *count)
{
unsigned int num_buffers, allocated_buffers, num_planes = 0;
+ unsigned int q_num_bufs = vb2_get_num_buffers(q);
unsigned plane_sizes[VB2_MAX_PLANES] = { };
bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT;
unsigned int i;
- int ret;
+ int ret = 0;
if (q->streaming) {
dprintk(q, 1, "streaming active\n");
@@ -763,7 +833,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
return -EBUSY;
}
- if (*count == 0 || q->num_buffers != 0 ||
+ if (*count == 0 || q_num_bufs != 0 ||
(q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory) ||
!verify_coherency_flags(q, non_coherent_mem)) {
/*
@@ -781,7 +851,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
* queued without ever calling STREAMON.
*/
__vb2_queue_cancel(q);
- __vb2_queue_free(q, q->num_buffers);
+ __vb2_queue_free(q, q_num_bufs);
mutex_unlock(&q->mmap_lock);
/*
@@ -795,17 +865,22 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
/*
* Make sure the requested values and current defaults are sane.
*/
- WARN_ON(q->min_buffers_needed > VB2_MAX_FRAME);
- num_buffers = max_t(unsigned int, *count, q->min_buffers_needed);
- num_buffers = min_t(unsigned int, num_buffers, VB2_MAX_FRAME);
+ num_buffers = max_t(unsigned int, *count, q->min_queued_buffers);
+ num_buffers = min_t(unsigned int, num_buffers, q->max_num_buffers);
memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
/*
* Set this now to ensure that drivers see the correct q->memory value
* in the queue_setup op.
*/
mutex_lock(&q->mmap_lock);
+ if (!q->bufs)
+ q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL);
+ if (!q->bufs)
+ ret = -ENOMEM;
q->memory = memory;
mutex_unlock(&q->mmap_lock);
+ if (ret)
+ return ret;
set_queue_coherency(q, non_coherent_mem);
/*
@@ -842,7 +917,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
* There is no point in continuing if we can't allocate the minimum
* number of buffers needed by this vb2_queue.
*/
- if (allocated_buffers < q->min_buffers_needed)
+ if (allocated_buffers < q->min_queued_buffers)
ret = -ENOMEM;
/*
@@ -876,7 +951,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
if (ret < 0) {
/*
* Note: __vb2_queue_free() will subtract 'allocated_buffers'
- * from q->num_buffers and it will reset q->memory to
+ * from already queued buffers and it will reset q->memory to
* VB2_MEMORY_UNKNOWN.
*/
__vb2_queue_free(q, allocated_buffers);
@@ -910,10 +985,11 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
unsigned int num_planes = 0, num_buffers, allocated_buffers;
unsigned plane_sizes[VB2_MAX_PLANES] = { };
bool non_coherent_mem = flags & V4L2_MEMORY_FLAG_NON_COHERENT;
- bool no_previous_buffers = !q->num_buffers;
- int ret;
+ unsigned int q_num_bufs = vb2_get_num_buffers(q);
+ bool no_previous_buffers = !q_num_bufs;
+ int ret = 0;
- if (q->num_buffers == VB2_MAX_FRAME) {
+ if (q->num_buffers == q->max_num_buffers) {
dprintk(q, 1, "maximum number of buffers already allocated\n");
return -ENOBUFS;
}
@@ -930,7 +1006,13 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
*/
mutex_lock(&q->mmap_lock);
q->memory = memory;
+ if (!q->bufs)
+ q->bufs = kcalloc(q->max_num_buffers, sizeof(*q->bufs), GFP_KERNEL);
+ if (!q->bufs)
+ ret = -ENOMEM;
mutex_unlock(&q->mmap_lock);
+ if (ret)
+ return ret;
q->waiting_for_buffers = !q->is_output;
set_queue_coherency(q, non_coherent_mem);
} else {
@@ -942,7 +1024,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
return -EINVAL;
}
- num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers);
+ num_buffers = min(*count, q->max_num_buffers - q_num_bufs);
if (requested_planes && requested_sizes) {
num_planes = requested_planes;
@@ -974,7 +1056,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
num_buffers = allocated_buffers;
/*
- * q->num_buffers contains the total number of buffers, that the
+ * num_buffers contains the total number of buffers, that the
* queue driver has set up
*/
ret = call_qop(q, queue_setup, q, &num_buffers,
@@ -995,7 +1077,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
if (ret < 0) {
/*
* Note: __vb2_queue_free() will subtract 'allocated_buffers'
- * from q->num_buffers and it will reset q->memory to
+ * from already queued buffers and it will reset q->memory to
* VB2_MEMORY_UNKNOWN.
*/
__vb2_queue_free(q, allocated_buffers);
@@ -1470,9 +1552,6 @@ static void vb2_req_unprepare(struct media_request_object *obj)
WARN_ON(!vb->req_obj.req);
}
-int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
- struct media_request *req);
-
static void vb2_req_queue(struct media_request_object *obj)
{
struct vb2_buffer *vb = container_of(obj, struct vb2_buffer, req_obj);
@@ -1487,7 +1566,7 @@ static void vb2_req_queue(struct media_request_object *obj)
* set. We just ignore that, and expect this will be caught the
* next time vb2_req_prepare() is called.
*/
- err = vb2_core_qbuf(vb->vb2_queue, vb->index, NULL, NULL);
+ err = vb2_core_qbuf(vb->vb2_queue, vb, NULL, NULL);
WARN_ON_ONCE(err && err != -EIO);
mutex_unlock(vb->vb2_queue->lock);
}
@@ -1542,12 +1621,10 @@ unsigned int vb2_request_buffer_cnt(struct media_request *req)
}
EXPORT_SYMBOL_GPL(vb2_request_buffer_cnt);
-int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
+int vb2_core_prepare_buf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb)
{
- struct vb2_buffer *vb;
int ret;
- vb = q->bufs[index];
if (vb->state != VB2_BUF_STATE_DEQUEUED) {
dprintk(q, 1, "invalid buffer state %s\n",
vb2_state_name(vb->state));
@@ -1576,7 +1653,7 @@ EXPORT_SYMBOL_GPL(vb2_core_prepare_buf);
* @q: videobuf2 queue
*
* Attempt to start streaming. When this function is called there must be
- * at least q->min_buffers_needed buffers queued up (i.e. the minimum
+ * at least q->min_queued_buffers queued up (i.e. the minimum
* number of buffers required for the DMA engine to function). If the
* @start_streaming op fails it is supposed to return all the driver-owned
* buffers back to vb2 in state QUEUED. Check if that happened and if
@@ -1617,8 +1694,12 @@ static int vb2_start_streaming(struct vb2_queue *q)
* Forcefully reclaim buffers if the driver did not
* correctly return them to vb2.
*/
- for (i = 0; i < q->num_buffers; ++i) {
- vb = q->bufs[i];
+ for (i = 0; i < vb2_get_num_buffers(q); ++i) {
+ vb = vb2_get_buffer(q, i);
+
+ if (!vb)
+ continue;
+
if (vb->state == VB2_BUF_STATE_ACTIVE)
vb2_buffer_done(vb, VB2_BUF_STATE_QUEUED);
}
@@ -1634,10 +1715,9 @@ static int vb2_start_streaming(struct vb2_queue *q)
return ret;
}
-int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
+int vb2_core_qbuf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb,
struct media_request *req)
{
- struct vb2_buffer *vb;
enum vb2_buffer_state orig_state;
int ret;
@@ -1646,8 +1726,6 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
return -EIO;
}
- vb = q->bufs[index];
-
if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST &&
q->requires_requests) {
dprintk(q, 1, "qbuf requires a request\n");
@@ -1768,7 +1846,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
* then we can finally call start_streaming().
*/
if (q->streaming && !q->start_streaming_called &&
- q->queued_count >= q->min_buffers_needed) {
+ q->queued_count >= q->min_queued_buffers) {
ret = vb2_start_streaming(q);
if (ret) {
/*
@@ -2022,12 +2100,18 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
* to vb2 in stop_streaming().
*/
if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
- for (i = 0; i < q->num_buffers; ++i)
- if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) {
- pr_warn("driver bug: stop_streaming operation is leaving buf %p in active state\n",
- q->bufs[i]);
- vb2_buffer_done(q->bufs[i], VB2_BUF_STATE_ERROR);
+ for (i = 0; i < vb2_get_num_buffers(q); i++) {
+ struct vb2_buffer *vb = vb2_get_buffer(q, i);
+
+ if (!vb)
+ continue;
+
+ if (vb->state == VB2_BUF_STATE_ACTIVE) {
+ pr_warn("driver bug: stop_streaming operation is leaving buffer %u in active state\n",
+ vb->index);
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
}
+ }
/* Must be zero now */
WARN_ON(atomic_read(&q->owned_by_drv_count));
}
@@ -2060,10 +2144,15 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
* call to __fill_user_buffer() after buf_finish(). That order can't
* be changed, so we can't move the buf_finish() to __vb2_dqbuf().
*/
- for (i = 0; i < q->num_buffers; ++i) {
- struct vb2_buffer *vb = q->bufs[i];
- struct media_request *req = vb->req_obj.req;
+ for (i = 0; i < vb2_get_num_buffers(q); i++) {
+ struct vb2_buffer *vb;
+ struct media_request *req;
+
+ vb = vb2_get_buffer(q, i);
+ if (!vb)
+ continue;
+ req = vb->req_obj.req;
/*
* If a request is associated with this buffer, then
* call buf_request_cancel() to give the driver to complete()
@@ -2103,6 +2192,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
int vb2_core_streamon(struct vb2_queue *q, unsigned int type)
{
+ unsigned int q_num_bufs = vb2_get_num_buffers(q);
int ret;
if (type != q->type) {
@@ -2115,14 +2205,14 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type)
return 0;
}
- if (!q->num_buffers) {
+ if (!q_num_bufs) {
dprintk(q, 1, "no buffers have been allocated\n");
return -EINVAL;
}
- if (q->num_buffers < q->min_buffers_needed) {
- dprintk(q, 1, "need at least %u allocated buffers\n",
- q->min_buffers_needed);
+ if (q_num_bufs < q->min_queued_buffers) {
+ dprintk(q, 1, "need at least %u queued buffers\n",
+ q->min_queued_buffers);
return -EINVAL;
}
@@ -2134,7 +2224,7 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type)
* Tell driver to start streaming provided sufficient buffers
* are available.
*/
- if (q->queued_count >= q->min_buffers_needed) {
+ if (q->queued_count >= q->min_queued_buffers) {
ret = vb2_start_streaming(q);
if (ret)
goto unprepare;
@@ -2185,13 +2275,12 @@ int vb2_core_streamoff(struct vb2_queue *q, unsigned int type)
EXPORT_SYMBOL_GPL(vb2_core_streamoff);
/*
- * __find_plane_by_offset() - find plane associated with the given offset off
+ * __find_plane_by_offset() - find plane associated with the given offset
*/
-static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
- unsigned int *_buffer, unsigned int *_plane)
+static int __find_plane_by_offset(struct vb2_queue *q, unsigned long offset,
+ struct vb2_buffer **vb, unsigned int *plane)
{
- struct vb2_buffer *vb;
- unsigned int buffer, plane;
+ unsigned int buffer;
/*
* Sanity checks to ensure the lock is held, MEMORY_MMAP is
@@ -2209,30 +2298,22 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off,
return -EBUSY;
}
- /*
- * Go over all buffers and their planes, comparing the given offset
- * with an offset assigned to each plane. If a match is found,
- * return its buffer and plane numbers.
- */
- for (buffer = 0; buffer < q->num_buffers; ++buffer) {
- vb = q->bufs[buffer];
+ /* Get buffer and plane from the offset */
+ buffer = (offset >> PLANE_INDEX_SHIFT) & BUFFER_INDEX_MASK;
+ *plane = (offset >> PAGE_SHIFT) & PLANE_INDEX_MASK;
- for (plane = 0; plane < vb->num_planes; ++plane) {
- if (vb->planes[plane].m.offset == off) {
- *_buffer = buffer;
- *_plane = plane;
- return 0;
- }
- }
- }
+ *vb = vb2_get_buffer(q, buffer);
+ if (!*vb)
+ return -EINVAL;
+ if (*plane >= (*vb)->num_planes)
+ return -EINVAL;
- return -EINVAL;
+ return 0;
}
int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
- unsigned int index, unsigned int plane, unsigned int flags)
+ struct vb2_buffer *vb, unsigned int plane, unsigned int flags)
{
- struct vb2_buffer *vb = NULL;
struct vb2_plane *vb_plane;
int ret;
struct dma_buf *dbuf;
@@ -2257,13 +2338,6 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
return -EINVAL;
}
- if (index >= q->num_buffers) {
- dprintk(q, 1, "buffer index out of range\n");
- return -EINVAL;
- }
-
- vb = q->bufs[index];
-
if (plane >= vb->num_planes) {
dprintk(q, 1, "buffer plane out of range\n");
return -EINVAL;
@@ -2282,20 +2356,20 @@ int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
flags & O_ACCMODE);
if (IS_ERR_OR_NULL(dbuf)) {
dprintk(q, 1, "failed to export buffer %d, plane %d\n",
- index, plane);
+ vb->index, plane);
return -EINVAL;
}
ret = dma_buf_fd(dbuf, flags & ~O_ACCMODE);
if (ret < 0) {
dprintk(q, 3, "buffer %d, plane %d failed to export (%d)\n",
- index, plane, ret);
+ vb->index, plane, ret);
dma_buf_put(dbuf);
return ret;
}
dprintk(q, 3, "buffer %d, plane %d exported as %d descriptor\n",
- index, plane, ret);
+ vb->index, plane, ret);
*fd = ret;
return 0;
@@ -2304,9 +2378,9 @@ EXPORT_SYMBOL_GPL(vb2_core_expbuf);
int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
{
- unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
struct vb2_buffer *vb;
- unsigned int buffer = 0, plane = 0;
+ unsigned int plane = 0;
int ret;
unsigned long length;
@@ -2335,12 +2409,10 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
* Find the plane corresponding to the offset passed by userspace. This
* will return an error if not MEMORY_MMAP or file I/O is in progress.
*/
- ret = __find_plane_by_offset(q, off, &buffer, &plane);
+ ret = __find_plane_by_offset(q, offset, &vb, &plane);
if (ret)
goto unlock;
- vb = q->bufs[buffer];
-
/*
* MMAP requires page_aligned buffers.
* The buffer length was page_aligned at __vb2_buf_mem_alloc(),
@@ -2368,7 +2440,7 @@ unlock:
if (ret)
return ret;
- dprintk(q, 3, "buffer %d, plane %d successfully mapped\n", buffer, plane);
+ dprintk(q, 3, "buffer %u, plane %d successfully mapped\n", vb->index, plane);
return 0;
}
EXPORT_SYMBOL_GPL(vb2_mmap);
@@ -2380,9 +2452,9 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
unsigned long pgoff,
unsigned long flags)
{
- unsigned long off = pgoff << PAGE_SHIFT;
+ unsigned long offset = pgoff << PAGE_SHIFT;
struct vb2_buffer *vb;
- unsigned int buffer, plane;
+ unsigned int plane;
void *vaddr;
int ret;
@@ -2392,12 +2464,10 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
* Find the plane corresponding to the offset passed by userspace. This
* will return an error if not MEMORY_MMAP or file I/O is in progress.
*/
- ret = __find_plane_by_offset(q, off, &buffer, &plane);
+ ret = __find_plane_by_offset(q, offset, &vb, &plane);
if (ret)
goto unlock;
- vb = q->bufs[buffer];
-
vaddr = vb2_plane_vaddr(vb, plane);
mutex_unlock(&q->mmap_lock);
return vaddr ? (unsigned long)vaddr : -EINVAL;
@@ -2414,6 +2484,16 @@ int vb2_core_queue_init(struct vb2_queue *q)
/*
* Sanity check
*/
+ /*
+ * For drivers who don't support max_num_buffers ensure
+ * a backward compatibility.
+ */
+ if (!q->max_num_buffers)
+ q->max_num_buffers = VB2_MAX_FRAME;
+
+ /* The maximum is limited by offset cookie encoding pattern */
+ q->max_num_buffers = min_t(unsigned int, q->max_num_buffers, MAX_BUFFER_INDEX);
+
if (WARN_ON(!q) ||
WARN_ON(!q->ops) ||
WARN_ON(!q->mem_ops) ||
@@ -2423,18 +2503,22 @@ int vb2_core_queue_init(struct vb2_queue *q)
WARN_ON(!q->ops->buf_queue))
return -EINVAL;
+ if (WARN_ON(q->max_num_buffers > MAX_BUFFER_INDEX) ||
+ WARN_ON(q->min_queued_buffers > q->max_num_buffers))
+ return -EINVAL;
+
if (WARN_ON(q->requires_requests && !q->supports_requests))
return -EINVAL;
/*
* This combination is not allowed since a non-zero value of
- * q->min_buffers_needed can cause vb2_core_qbuf() to fail if
+ * q->min_queued_buffers can cause vb2_core_qbuf() to fail if
* it has to call start_streaming(), and the Request API expects
* that queueing a request (and thus queueing a buffer contained
* in that request) will always succeed. There is no method of
* propagating an error back to userspace.
*/
- if (WARN_ON(q->supports_requests && q->min_buffers_needed))
+ if (WARN_ON(q->supports_requests && q->min_queued_buffers))
return -EINVAL;
INIT_LIST_HEAD(&q->queued_list);
@@ -2468,7 +2552,9 @@ void vb2_core_queue_release(struct vb2_queue *q)
__vb2_cleanup_fileio(q);
__vb2_queue_cancel(q);
mutex_lock(&q->mmap_lock);
- __vb2_queue_free(q, q->num_buffers);
+ __vb2_queue_free(q, vb2_get_num_buffers(q));
+ kfree(q->bufs);
+ q->bufs = NULL;
mutex_unlock(&q->mmap_lock);
}
EXPORT_SYMBOL_GPL(vb2_core_queue_release);
@@ -2497,7 +2583,7 @@ __poll_t vb2_core_poll(struct vb2_queue *q, struct file *file,
/*
* Start file I/O emulator only if streaming API has not been used yet.
*/
- if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) {
+ if (vb2_get_num_buffers(q) == 0 && !vb2_fileio_is_active(q)) {
if (!q->is_output && (q->io_modes & VB2_READ) &&
(req_events & (EPOLLIN | EPOLLRDNORM))) {
if (__vb2_init_fileio(q, 1))
@@ -2535,7 +2621,7 @@ __poll_t vb2_core_poll(struct vb2_queue *q, struct file *file,
* For output streams you can call write() as long as there are fewer
* buffers queued than there are buffers available.
*/
- if (q->is_output && q->fileio && q->queued_count < q->num_buffers)
+ if (q->is_output && q->fileio && q->queued_count < vb2_get_num_buffers(q))
return EPOLLOUT | EPOLLWRNORM;
if (list_empty(&q->done_list)) {
@@ -2584,8 +2670,8 @@ struct vb2_fileio_buf {
* struct vb2_fileio_data - queue context used by file io emulator
*
* @cur_index: the index of the buffer currently being read from or
- * written to. If equal to q->num_buffers then a new buffer
- * must be dequeued.
+ * written to. If equal to number of buffers in the vb2_queue
+ * then a new buffer must be dequeued.
* @initial_index: in the read() case all buffers are queued up immediately
* in __vb2_init_fileio() and __vb2_perform_fileio() just cycles
* buffers. However, in the write() case no buffers are initially
@@ -2595,9 +2681,9 @@ struct vb2_fileio_buf {
* buffers. This means that initially __vb2_perform_fileio()
* needs to know what buffer index to use when it is queuing up
* the buffers for the first time. That initial index is stored
- * in this field. Once it is equal to q->num_buffers all
- * available buffers have been queued and __vb2_perform_fileio()
- * should start the normal dequeue/queue cycle.
+ * in this field. Once it is equal to number of buffers in the
+ * vb2_queue all available buffers have been queued and
+ * __vb2_perform_fileio() should start the normal dequeue/queue cycle.
*
* vb2 provides a compatibility layer and emulator of file io (read and
* write) calls on top of streaming API. For proper operation it required
@@ -2625,6 +2711,7 @@ struct vb2_fileio_data {
static int __vb2_init_fileio(struct vb2_queue *q, int read)
{
struct vb2_fileio_data *fileio;
+ struct vb2_buffer *vb;
int i, ret;
unsigned int count = 0;
@@ -2644,13 +2731,18 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
/*
* Check if streaming api has not been already activated.
*/
- if (q->streaming || q->num_buffers > 0)
+ if (q->streaming || vb2_get_num_buffers(q) > 0)
return -EBUSY;
/*
- * Start with count 1, driver can increase it in queue_setup()
+ * Start with q->min_queued_buffers + 1, driver can increase it in
+ * queue_setup()
+ *
+ * 'min_queued_buffers' buffers need to be queued up before you
+ * can start streaming, plus 1 for userspace (or in this case,
+ * kernelspace) processing.
*/
- count = 1;
+ count = max(2, q->min_queued_buffers + 1);
dprintk(q, 3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n",
(read) ? "read" : "write", count, q->fileio_read_once,
@@ -2676,10 +2768,17 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
goto err_kfree;
/*
+ * Userspace can never add or delete buffers later, so there
+ * will never be holes. It is safe to assume that vb2_get_buffer(q, 0)
+ * will always return a valid vb pointer
+ */
+ vb = vb2_get_buffer(q, 0);
+
+ /*
* Check if plane_count is correct
* (multiplane buffers are not supported).
*/
- if (q->bufs[0]->num_planes != 1) {
+ if (vb->num_planes != 1) {
ret = -EBUSY;
goto err_reqbufs;
}
@@ -2687,13 +2786,16 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
/*
* Get kernel address of each buffer.
*/
- for (i = 0; i < q->num_buffers; i++) {
- fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
+ for (i = 0; i < vb2_get_num_buffers(q); i++) {
+ /* vb can never be NULL when using fileio. */
+ vb = vb2_get_buffer(q, i);
+
+ fileio->bufs[i].vaddr = vb2_plane_vaddr(vb, 0);
if (fileio->bufs[i].vaddr == NULL) {
ret = -EINVAL;
goto err_reqbufs;
}
- fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
+ fileio->bufs[i].size = vb2_plane_size(vb, 0);
}
/*
@@ -2703,18 +2805,23 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
/*
* Queue all buffers.
*/
- for (i = 0; i < q->num_buffers; i++) {
- ret = vb2_core_qbuf(q, i, NULL, NULL);
+ for (i = 0; i < vb2_get_num_buffers(q); i++) {
+ struct vb2_buffer *vb2 = vb2_get_buffer(q, i);
+
+ if (!vb2)
+ continue;
+
+ ret = vb2_core_qbuf(q, vb2, NULL, NULL);
if (ret)
goto err_reqbufs;
fileio->bufs[i].queued = 1;
}
/*
* All buffers have been queued, so mark that by setting
- * initial_index to q->num_buffers
+ * initial_index to the number of buffers in the vb2_queue
*/
- fileio->initial_index = q->num_buffers;
- fileio->cur_index = q->num_buffers;
+ fileio->initial_index = vb2_get_num_buffers(q);
+ fileio->cur_index = fileio->initial_index;
}
/*
@@ -2807,7 +2914,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
* Check if we need to dequeue the buffer.
*/
index = fileio->cur_index;
- if (index >= q->num_buffers) {
+ if (index >= vb2_get_num_buffers(q)) {
struct vb2_buffer *b;
/*
@@ -2821,15 +2928,17 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
fileio->cur_index = index;
buf = &fileio->bufs[index];
- b = q->bufs[index];
+
+ /* b can never be NULL when using fileio. */
+ b = vb2_get_buffer(q, index);
/*
* Get number of bytes filled by the driver
*/
buf->pos = 0;
buf->queued = 0;
- buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
- : vb2_plane_size(q->bufs[index], 0);
+ buf->size = read ? vb2_get_plane_payload(b, 0)
+ : vb2_plane_size(b, 0);
/* Compensate for data_offset on read in the multiplanar case. */
if (is_multiplanar && read &&
b->planes[0].data_offset < buf->size) {
@@ -2872,7 +2981,8 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
* Queue next buffer if required.
*/
if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
- struct vb2_buffer *b = q->bufs[index];
+ /* b can never be NULL when using fileio. */
+ struct vb2_buffer *b = vb2_get_buffer(q, index);
/*
* Check if this is the last buffer to read.
@@ -2889,7 +2999,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
if (copy_timestamp)
b->timestamp = ktime_get_ns();
- ret = vb2_core_qbuf(q, index, NULL, NULL);
+ ret = vb2_core_qbuf(q, b, NULL, NULL);
dprintk(q, 5, "vb2_qbuf result: %d\n", ret);
if (ret)
return ret;
@@ -2899,20 +3009,20 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
*/
buf->pos = 0;
buf->queued = 1;
- buf->size = vb2_plane_size(q->bufs[index], 0);
+ buf->size = vb2_plane_size(b, 0);
fileio->q_count += 1;
/*
* If we are queuing up buffers for the first time, then
* increase initial_index by one.
*/
- if (fileio->initial_index < q->num_buffers)
+ if (fileio->initial_index < vb2_get_num_buffers(q))
fileio->initial_index++;
/*
* The next buffer to use is either a buffer that's going to be
- * queued for the first time (initial_index < q->num_buffers)
- * or it is equal to q->num_buffers, meaning that the next
- * time we need to dequeue a buffer since we've now queued up
- * all the 'first time' buffers.
+ * queued for the first time (initial_index < number of buffers in the vb2_queue)
+ * or it is equal to the number of buffers in the vb2_queue,
+ * meaning that the next time we need to dequeue a buffer since
+ * we've now queued up all the 'first time' buffers.
*/
fileio->cur_index = fileio->initial_index;
}
@@ -2957,7 +3067,7 @@ static int vb2_thread(void *data)
int ret = 0;
if (q->is_output) {
- prequeue = q->num_buffers;
+ prequeue = vb2_get_num_buffers(q);
copy_timestamp = q->copy_timestamp;
}
@@ -2970,7 +3080,9 @@ static int vb2_thread(void *data)
* Call vb2_dqbuf to get buffer back.
*/
if (prequeue) {
- vb = q->bufs[index++];
+ vb = vb2_get_buffer(q, index++);
+ if (!vb)
+ continue;
prequeue--;
} else {
call_void_qop(q, wait_finish, q);
@@ -2979,7 +3091,7 @@ static int vb2_thread(void *data)
call_void_qop(q, wait_prepare, q);
dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret);
if (!ret)
- vb = q->bufs[index];
+ vb = vb2_get_buffer(q, index);
}
if (ret || threadio->stop)
break;
@@ -2992,7 +3104,7 @@ static int vb2_thread(void *data)
if (copy_timestamp)
vb->timestamp = ktime_get_ns();
if (!threadio->stop)
- ret = vb2_core_qbuf(q, vb->index, NULL, NULL);
+ ret = vb2_core_qbuf(q, vb, NULL, NULL);
call_void_qop(q, wait_prepare, q);
if (ret || threadio->stop)
break;
diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
index 28f3fdfe23a2..6975a71d740f 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
@@ -487,9 +487,15 @@ vb2_dma_sg_dmabuf_ops_end_cpu_access(struct dma_buf *dbuf,
static int vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf,
struct iosys_map *map)
{
- struct vb2_dma_sg_buf *buf = dbuf->priv;
+ struct vb2_dma_sg_buf *buf;
+ void *vaddr;
+
+ buf = dbuf->priv;
+ vaddr = vb2_dma_sg_vaddr(buf->vb, buf);
+ if (!vaddr)
+ return -EINVAL;
- iosys_map_set_vaddr(map, buf->vaddr);
+ iosys_map_set_vaddr(map, vaddr);
return 0;
}
diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index c7a54d82a55e..54d572c3b515 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -364,13 +364,12 @@ static void set_buffer_cache_hints(struct vb2_queue *q,
}
static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *mdev,
- struct v4l2_buffer *b, bool is_prepare,
- struct media_request **p_req)
+ struct vb2_buffer *vb, struct v4l2_buffer *b,
+ bool is_prepare, struct media_request **p_req)
{
const char *opname = is_prepare ? "prepare_buf" : "qbuf";
struct media_request *req;
struct vb2_v4l2_buffer *vbuf;
- struct vb2_buffer *vb;
int ret;
if (b->type != q->type) {
@@ -378,23 +377,11 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md
return -EINVAL;
}
- if (b->index >= q->num_buffers) {
- dprintk(q, 1, "%s: buffer index out of range\n", opname);
- return -EINVAL;
- }
-
- if (q->bufs[b->index] == NULL) {
- /* Should never happen */
- dprintk(q, 1, "%s: buffer is NULL\n", opname);
- return -EINVAL;
- }
-
if (b->memory != q->memory) {
dprintk(q, 1, "%s: invalid memory type\n", opname);
return -EINVAL;
}
- vb = q->bufs[b->index];
vbuf = to_vb2_v4l2_buffer(vb);
ret = __verify_planes_array(vb, b);
if (ret)
@@ -628,11 +615,22 @@ static const struct vb2_buf_ops v4l2_buf_ops = {
struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
{
unsigned int i;
+ struct vb2_buffer *vb2;
- for (i = 0; i < q->num_buffers; i++)
- if (q->bufs[i]->copied_timestamp &&
- q->bufs[i]->timestamp == timestamp)
- return vb2_get_buffer(q, i);
+ /*
+ * This loop doesn't scale if there is a really large number of buffers.
+ * Maybe something more efficient will be needed in this case.
+ */
+ for (i = 0; i < q->max_num_buffers; i++) {
+ vb2 = vb2_get_buffer(q, i);
+
+ if (!vb2)
+ continue;
+
+ if (vb2->copied_timestamp &&
+ vb2->timestamp == timestamp)
+ return vb2;
+ }
return NULL;
}
EXPORT_SYMBOL_GPL(vb2_find_buffer);
@@ -660,14 +658,15 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
return -EINVAL;
}
- if (b->index >= q->num_buffers) {
- dprintk(q, 1, "buffer index out of range\n");
+ vb = vb2_get_buffer(q, b->index);
+ if (!vb) {
+ dprintk(q, 1, "can't find the requested buffer %u\n", b->index);
return -EINVAL;
}
- vb = q->bufs[b->index];
+
ret = __verify_planes_array(vb, b);
if (!ret)
- vb2_core_querybuf(q, b->index, b);
+ vb2_core_querybuf(q, vb, b);
return ret;
}
EXPORT_SYMBOL(vb2_querybuf);
@@ -685,10 +684,8 @@ static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
*caps |= V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
if (q->allow_cache_hints && q->io_modes & VB2_MMAP)
*caps |= V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS;
-#ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API
if (q->supports_requests)
*caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS;
-#endif
}
static void validate_memory_flags(struct vb2_queue *q,
@@ -723,6 +720,7 @@ EXPORT_SYMBOL_GPL(vb2_reqbufs);
int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev,
struct v4l2_buffer *b)
{
+ struct vb2_buffer *vb;
int ret;
if (vb2_fileio_is_active(q)) {
@@ -733,9 +731,15 @@ int vb2_prepare_buf(struct vb2_queue *q, struct media_device *mdev,
if (b->flags & V4L2_BUF_FLAG_REQUEST_FD)
return -EINVAL;
- ret = vb2_queue_or_prepare_buf(q, mdev, b, true, NULL);
+ vb = vb2_get_buffer(q, b->index);
+ if (!vb) {
+ dprintk(q, 1, "can't find the requested buffer %u\n", b->index);
+ return -EINVAL;
+ }
- return ret ? ret : vb2_core_prepare_buf(q, b->index, b);
+ ret = vb2_queue_or_prepare_buf(q, mdev, vb, b, true, NULL);
+
+ return ret ? ret : vb2_core_prepare_buf(q, vb, b);
}
EXPORT_SYMBOL_GPL(vb2_prepare_buf);
@@ -749,7 +753,9 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
fill_buf_caps(q, &create->capabilities);
validate_memory_flags(q, create->memory, &create->flags);
- create->index = q->num_buffers;
+ create->index = vb2_get_num_buffers(q);
+ create->max_num_buffers = q->max_num_buffers;
+ create->capabilities |= V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS;
if (create->count == 0)
return ret != -EBUSY ? ret : 0;
@@ -803,6 +809,7 @@ int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev,
struct v4l2_buffer *b)
{
struct media_request *req = NULL;
+ struct vb2_buffer *vb;
int ret;
if (vb2_fileio_is_active(q)) {
@@ -810,10 +817,16 @@ int vb2_qbuf(struct vb2_queue *q, struct media_device *mdev,
return -EBUSY;
}
- ret = vb2_queue_or_prepare_buf(q, mdev, b, false, &req);
+ vb = vb2_get_buffer(q, b->index);
+ if (!vb) {
+ dprintk(q, 1, "can't find the requested buffer %u\n", b->index);
+ return -EINVAL;
+ }
+
+ ret = vb2_queue_or_prepare_buf(q, mdev, vb, b, false, &req);
if (ret)
return ret;
- ret = vb2_core_qbuf(q, b->index, b, req);
+ ret = vb2_core_qbuf(q, vb, b, req);
if (req)
media_request_put(req);
return ret;
@@ -873,7 +886,15 @@ EXPORT_SYMBOL_GPL(vb2_streamoff);
int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb)
{
- return vb2_core_expbuf(q, &eb->fd, eb->type, eb->index,
+ struct vb2_buffer *vb;
+
+ vb = vb2_get_buffer(q, eb->index);
+ if (!vb) {
+ dprintk(q, 1, "can't find the requested buffer %u\n", eb->index);
+ return -EINVAL;
+ }
+
+ return vb2_core_expbuf(q, &eb->fd, eb->type, vb,
eb->plane, eb->flags);
}
EXPORT_SYMBOL_GPL(vb2_expbuf);
@@ -1115,7 +1136,7 @@ int _vb2_fop_release(struct file *file, struct mutex *lock)
if (lock)
mutex_lock(lock);
- if (file->private_data == vdev->queue->owner) {
+ if (!vdev->queue->owner || file->private_data == vdev->queue->owner) {
vb2_queue_release(vdev->queue);
vdev->queue->owner = NULL;
}
@@ -1243,7 +1264,7 @@ void vb2_video_unregister_device(struct video_device *vdev)
*/
get_device(&vdev->dev);
video_unregister_device(vdev);
- if (vdev->queue && vdev->queue->owner) {
+ if (vdev->queue) {
struct mutex *lock = vdev->queue->lock ?
vdev->queue->lock : vdev->lock;
diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c
index 909df82fed33..192a8230c4aa 100644
--- a/drivers/media/dvb-core/dvb_vb2.c
+++ b/drivers/media/dvb-core/dvb_vb2.c
@@ -167,17 +167,14 @@ int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name, int nonblocking)
memset(ctx, 0, sizeof(struct dvb_vb2_ctx));
q->type = DVB_BUF_TYPE_CAPTURE;
- /**capture type*/
- q->is_output = 0;
/**only mmap is supported currently*/
q->io_modes = VB2_MMAP;
q->drv_priv = ctx;
q->buf_struct_size = sizeof(struct dvb_buffer);
- q->min_buffers_needed = 1;
+ q->min_queued_buffers = 1;
q->ops = &dvb_vb2_qops;
q->mem_ops = &vb2_vmalloc_memops;
q->buf_ops = &dvb_vb2_buf_ops;
- q->num_buffers = 0;
ret = vb2_core_queue_init(q);
if (ret) {
ctx->state = DVB_VB2_STATE_NONE;
@@ -355,12 +352,13 @@ int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req)
int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
{
struct vb2_queue *q = &ctx->vb_q;
+ struct vb2_buffer *vb2 = vb2_get_buffer(q, b->index);
- if (b->index >= q->num_buffers) {
- dprintk(1, "[%s] buffer index out of range\n", ctx->name);
+ if (!vb2) {
+ dprintk(1, "[%s] invalid buffer index\n", ctx->name);
return -EINVAL;
}
- vb2_core_querybuf(&ctx->vb_q, b->index, b);
+ vb2_core_querybuf(&ctx->vb_q, vb2, b);
dprintk(3, "[%s] index=%d\n", ctx->name, b->index);
return 0;
}
@@ -370,7 +368,7 @@ int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp)
struct vb2_queue *q = &ctx->vb_q;
int ret;
- ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, exp->index,
+ ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, q->bufs[exp->index],
0, exp->flags);
if (ret) {
dprintk(1, "[%s] index=%d errno=%d\n", ctx->name,
@@ -385,13 +383,14 @@ int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp)
int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
{
struct vb2_queue *q = &ctx->vb_q;
+ struct vb2_buffer *vb2 = vb2_get_buffer(q, b->index);
int ret;
- if (b->index >= q->num_buffers) {
- dprintk(1, "[%s] buffer index out of range\n", ctx->name);
+ if (!vb2) {
+ dprintk(1, "[%s] invalid buffer index\n", ctx->name);
return -EINVAL;
}
- ret = vb2_core_qbuf(&ctx->vb_q, b->index, b, NULL);
+ ret = vb2_core_qbuf(&ctx->vb_q, vb2, b, NULL);
if (ret) {
dprintk(1, "[%s] index=%d errno=%d\n", ctx->name,
b->index, ret);
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index 305bb21d843c..49f0eb7d0b9d 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -104,6 +104,8 @@ static int dvb_device_open(struct inode *inode, struct file *file)
err = file->f_op->open(inode, file);
up_read(&minor_rwsem);
mutex_unlock(&dvbdev_mutex);
+ if (err)
+ dvb_device_put(dvbdev);
return err;
}
fail:
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index 26c67ef05d13..e0272054fca5 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -1894,7 +1894,7 @@ static int m88ds3103_probe(struct i2c_client *client)
/* get frontend address */
ret = regmap_read(dev->regmap, 0x29, &utmp);
if (ret)
- goto err_kfree;
+ goto err_del_adapters;
dev->dt_addr = ((utmp & 0x80) == 0) ? 0x42 >> 1 : 0x40 >> 1;
dev_dbg(&client->dev, "dt addr is 0x%02x\n", dev->dt_addr);
@@ -1902,11 +1902,14 @@ static int m88ds3103_probe(struct i2c_client *client)
dev->dt_addr);
if (IS_ERR(dev->dt_client)) {
ret = PTR_ERR(dev->dt_client);
- goto err_kfree;
+ goto err_del_adapters;
}
}
return 0;
+
+err_del_adapters:
+ i2c_mux_del_adapters(dev->muxc);
err_kfree:
kfree(dev);
err:
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index 02c619e51641..023db6e793f8 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -439,12 +439,13 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq,
{
struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq);
struct platform_device *pdev = dev->pdev;
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
dev_dbg(&pdev->dev, "nbuffers=%d\n", *nbuffers);
/* Need at least 8 buffers */
- if (vq->num_buffers + *nbuffers < 8)
- *nbuffers = 8 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 8)
+ *nbuffers = 8 - q_num_bufs;
*nplanes = 1;
sizes[0] = PAGE_ALIGN(dev->buffersize);
dev_dbg(&pdev->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 59ee0ca2c978..4c3435921f19 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -41,6 +41,16 @@ config VIDEO_APTINA_PLL
config VIDEO_CCS_PLL
tristate
+config VIDEO_ALVIUM_CSI2
+ tristate "Allied Vision ALVIUM MIPI CSI-2 camera support"
+ select V4L2_CCI_I2C
+ help
+ This is a Video4Linux2 sensor-level driver for the Allied Vision
+ ALVIUM camera connected via MIPI CSI-2 interface.
+
+ To compile this driver as a module, choose M here: the
+ module will be called alvium-csi2.
+
config VIDEO_AR0521
tristate "ON Semiconductor AR0521 sensor support"
help
@@ -50,6 +60,26 @@ config VIDEO_AR0521
To compile this driver as a module, choose M here: the
module will be called ar0521.
+config VIDEO_GC0308
+ tristate "GalaxyCore GC0308 sensor support"
+ select V4L2_CCI_I2C
+ help
+ This is a Video4Linux2 sensor driver for the GalaxyCore
+ GC0308 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gc0308.
+
+config VIDEO_GC2145
+ select V4L2_CCI_I2C
+ tristate "GalaxyCore GC2145 sensor support"
+ help
+ This is a V4L2 sensor-level driver for GalaxyCore GC2145
+ 2 Mpixel camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gc2145.
+
config VIDEO_HI556
tristate "Hynix Hi-556 sensor support"
help
@@ -455,6 +485,16 @@ config VIDEO_OV5695
To compile this driver as a module, choose M here: the
module will be called ov5695.
+config VIDEO_OV64A40
+ tristate "OmniVision OV64A40 sensor support"
+ select V4L2_CCI_I2C
+ help
+ This is a Video4Linux2 sensor driver for the OmniVision
+ OV64A40 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov64a40.
+
config VIDEO_OV6650
tristate "OmniVision OV6650 sensor support"
help
@@ -628,6 +668,23 @@ source "drivers/media/i2c/et8ek8/Kconfig"
endif
+menu "Camera ISPs"
+ visible if MEDIA_CAMERA_SUPPORT
+
+config VIDEO_THP7312
+ tristate "THine THP7312 support"
+ depends on I2C
+ select FW_LOADER
+ select MEDIA_CONTROLLER
+ select V4L2_CCI_I2C
+ select V4L2_FWNODE
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ This is a Video4Linux2 sensor-level driver for the THine
+ THP7312 ISP.
+
+endmenu
+
menu "Lens drivers"
visible if MEDIA_CAMERA_SUPPORT
@@ -1186,6 +1243,21 @@ config VIDEO_TW2804
To compile this driver as a module, choose M here: the
module will be called tw2804.
+config VIDEO_TW9900
+ tristate "Techwell TW9900 video decoder"
+ depends on GPIOLIB
+ depends on VIDEO_DEV && I2C
+ depends on PM
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select V4L2_ASYNC
+ help
+ Support for the Techwell TW9900 multi-standard video decoder.
+ It supports NTSC, PAL standards with auto-detection features.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tw9900.
+
config VIDEO_TW9903
tristate "Techwell TW9903 video decoder"
depends on VIDEO_DEV && I2C
@@ -1432,6 +1504,7 @@ config VIDEO_ST_MIPID02
depends on I2C && VIDEO_DEV
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
+ select V4L2_CCI_I2C
select V4L2_FWNODE
help
Support for STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge.
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index f5010f80a21f..dfbe6448b549 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o
obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o
obj-$(CONFIG_VIDEO_AK7375) += ak7375.o
obj-$(CONFIG_VIDEO_AK881X) += ak881x.o
+obj-$(CONFIG_VIDEO_ALVIUM_CSI2) += alvium-csi2.o
obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o
obj-$(CONFIG_VIDEO_AR0521) += ar0521.o
obj-$(CONFIG_VIDEO_BT819) += bt819.o
@@ -36,6 +37,8 @@ obj-$(CONFIG_VIDEO_DW9719) += dw9719.o
obj-$(CONFIG_VIDEO_DW9768) += dw9768.o
obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o
obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/
+obj-$(CONFIG_VIDEO_GC0308) += gc0308.o
+obj-$(CONFIG_VIDEO_GC2145) += gc2145.o
obj-$(CONFIG_VIDEO_HI556) += hi556.o
obj-$(CONFIG_VIDEO_HI846) += hi846.o
obj-$(CONFIG_VIDEO_HI847) += hi847.o
@@ -92,6 +95,7 @@ obj-$(CONFIG_VIDEO_OV5670) += ov5670.o
obj-$(CONFIG_VIDEO_OV5675) += ov5675.o
obj-$(CONFIG_VIDEO_OV5693) += ov5693.o
obj-$(CONFIG_VIDEO_OV5695) += ov5695.o
+obj-$(CONFIG_VIDEO_OV64A40) += ov64a40.o
obj-$(CONFIG_VIDEO_OV6650) += ov6650.o
obj-$(CONFIG_VIDEO_OV7251) += ov7251.o
obj-$(CONFIG_VIDEO_OV7640) += ov7640.o
@@ -128,6 +132,7 @@ obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
+obj-$(CONFIG_VIDEO_THP7312) += thp7312.o
obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
obj-$(CONFIG_VIDEO_THS8200) += ths8200.o
obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
@@ -136,6 +141,7 @@ obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
obj-$(CONFIG_VIDEO_TW2804) += tw2804.o
+obj-$(CONFIG_VIDEO_TW9900) += tw9900.o
obj-$(CONFIG_VIDEO_TW9903) += tw9903.o
obj-$(CONFIG_VIDEO_TW9906) += tw9906.o
obj-$(CONFIG_VIDEO_TW9910) += tw9910.o
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 54134473186b..409b9a37f018 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -463,11 +463,19 @@ static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
return 0;
}
-static int adv7180_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int adv7180_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct adv7180_state *state = to_state(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (state->curr_norm & V4L2_STD_525_60) {
fi->interval.numerator = 1001;
fi->interval.denominator = 30000;
@@ -769,7 +777,7 @@ static int adv7180_get_pad_format(struct v4l2_subdev *sd,
struct adv7180_state *state = to_state(sd);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
+ format->format = *v4l2_subdev_state_get_format(sd_state, 0);
} else {
adv7180_mbus_fmt(sd, &format->format);
format->format.field = state->field;
@@ -806,15 +814,15 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd,
adv7180_set_power(state, true);
}
} else {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ framefmt = v4l2_subdev_state_get_format(sd_state, 0);
*framefmt = format->format;
}
return ret;
}
-static int adv7180_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int adv7180_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = {
.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
@@ -913,7 +921,6 @@ static int adv7180_subscribe_event(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
.s_std = adv7180_s_std,
.g_std = adv7180_g_std,
- .g_frame_interval = adv7180_g_frame_interval,
.querystd = adv7180_querystd,
.g_input_status = adv7180_g_input_status,
.s_routing = adv7180_s_routing,
@@ -929,10 +936,10 @@ static const struct v4l2_subdev_core_ops adv7180_core_ops = {
};
static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
- .init_cfg = adv7180_init_cfg,
.enum_mbus_code = adv7180_enum_mbus_code,
.set_fmt = adv7180_set_pad_format,
.get_fmt = adv7180_get_pad_format,
+ .get_frame_interval = adv7180_get_frame_interval,
.get_mbus_config = adv7180_get_mbus_config,
};
@@ -947,6 +954,10 @@ static const struct v4l2_subdev_ops adv7180_ops = {
.sensor = &adv7180_sensor_ops,
};
+static const struct v4l2_subdev_internal_ops adv7180_internal_ops = {
+ .init_state = adv7180_init_state,
+};
+
static irqreturn_t adv7180_irq(int irq, void *devid)
{
struct adv7180_state *state = devid;
@@ -1458,6 +1469,7 @@ static int adv7180_probe(struct i2c_client *client)
state->input = 0;
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
+ sd->internal_ops = &adv7180_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
ret = adv7180_init_controls(state);
diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c
index 3659feafac69..2a2cace4a153 100644
--- a/drivers/media/i2c/adv7183.c
+++ b/drivers/media/i2c/adv7183.c
@@ -442,8 +442,6 @@ static int adv7183_set_fmt(struct v4l2_subdev *sd,
}
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
decoder->fmt = *fmt;
- else
- sd_state->pads->try_fmt = *fmt;
return 0;
}
diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c
index 00095c7762c2..50d9fbadbe38 100644
--- a/drivers/media/i2c/adv748x/adv748x-afe.c
+++ b/drivers/media/i2c/adv748x/adv748x-afe.c
@@ -354,8 +354,8 @@ static int adv748x_afe_get_format(struct v4l2_subdev *sd,
return -EINVAL;
if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) {
- mbusformat = v4l2_subdev_get_try_format(sd, sd_state,
- sdformat->pad);
+ mbusformat = v4l2_subdev_state_get_format(sd_state,
+ sdformat->pad);
sdformat->format = *mbusformat;
} else {
adv748x_afe_fill_format(afe, &sdformat->format);
@@ -378,7 +378,7 @@ static int adv748x_afe_set_format(struct v4l2_subdev *sd,
if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return adv748x_afe_get_format(sd, sd_state, sdformat);
- mbusformat = v4l2_subdev_get_try_format(sd, sd_state, sdformat->pad);
+ mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
*mbusformat = sdformat->format;
return 0;
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index a5a7cb228896..5b265b722394 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -147,7 +147,7 @@ adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
return &tx->format;
}
diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c
index 400d71c2745c..ec151dc69c23 100644
--- a/drivers/media/i2c/adv748x/adv748x-hdmi.c
+++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c
@@ -441,8 +441,8 @@ static int adv748x_hdmi_get_format(struct v4l2_subdev *sd,
return -EINVAL;
if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) {
- mbusformat = v4l2_subdev_get_try_format(sd, sd_state,
- sdformat->pad);
+ mbusformat = v4l2_subdev_state_get_format(sd_state,
+ sdformat->pad);
sdformat->format = *mbusformat;
} else {
adv748x_hdmi_fill_format(hdmi, &sdformat->format);
@@ -464,7 +464,7 @@ static int adv748x_hdmi_set_format(struct v4l2_subdev *sd,
if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return adv748x_hdmi_get_format(sd, sd_state, sdformat);
- mbusformat = v4l2_subdev_get_try_format(sd, sd_state, sdformat->pad);
+ mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
*mbusformat = sdformat->format;
return 0;
diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c
index a9183d9282fd..0f780eb6ef63 100644
--- a/drivers/media/i2c/adv7511-v4l2.c
+++ b/drivers/media/i2c/adv7511-v4l2.c
@@ -1238,7 +1238,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
format->format.code = fmt->code;
format->format.colorspace = fmt->colorspace;
format->format.ycbcr_enc = fmt->ycbcr_enc;
@@ -1293,7 +1293,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
fmt->code = format->format.code;
fmt->colorspace = format->format.colorspace;
fmt->ycbcr_enc = format->format.ycbcr_enc;
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index b202a85fbeaa..810fa8826f30 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -1929,7 +1929,7 @@ static int adv76xx_get_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
format->format.code = fmt->code;
} else {
format->format.code = state->format->code;
@@ -1978,7 +1978,7 @@ static int adv76xx_set_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
fmt->code = format->format.code;
} else {
state->format = info;
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index c1664a3620c8..2ad0f9f5503d 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -2087,7 +2087,7 @@ static int adv7842_get_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
format->format.code = fmt->code;
} else {
format->format.code = state->format->code;
@@ -2119,7 +2119,7 @@ static int adv7842_set_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
fmt->code = format->format.code;
} else {
state->format = info;
diff --git a/drivers/media/i2c/ak7375.c b/drivers/media/i2c/ak7375.c
index 463b51d46320..9a2432cea3ff 100644
--- a/drivers/media/i2c/ak7375.c
+++ b/drivers/media/i2c/ak7375.c
@@ -10,30 +10,60 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
-#define AK7375_MAX_FOCUS_POS 4095
-/*
- * This sets the minimum granularity for the focus positions.
- * A value of 1 gives maximum accuracy for a desired focus position
- */
-#define AK7375_FOCUS_STEPS 1
-/*
- * This acts as the minimum granularity of lens movement.
- * Keep this value power of 2, so the control steps can be
- * uniformly adjusted for gradual lens movement, with desired
- * number of control steps.
- */
-#define AK7375_CTRL_STEPS 64
-#define AK7375_CTRL_DELAY_US 1000
-/*
- * The vcm may take up 10 ms (tDELAY) to power on and start taking
- * I2C messages. Based on AK7371 datasheet.
- */
-#define AK7375_POWER_DELAY_US 10000
+struct ak73xx_chipdef {
+ u8 reg_position;
+ u8 reg_cont;
+ u8 shift_pos;
+ u8 mode_active;
+ u8 mode_standby;
+ bool has_standby; /* Some chips may not have standby mode */
+ u16 focus_pos_max;
+ /*
+ * This sets the minimum granularity for the focus positions.
+ * A value of 1 gives maximum accuracy for a desired focus position
+ */
+ u16 focus_steps;
+ /*
+ * This acts as the minimum granularity of lens movement.
+ * Keep this value power of 2, so the control steps can be
+ * uniformly adjusted for gradual lens movement, with desired
+ * number of control steps.
+ */
+ u16 ctrl_steps;
+ u16 ctrl_delay_us;
+ /*
+ * The vcm may take time (tDELAY) to power on and start taking
+ * I2C messages.
+ */
+ u16 power_delay_us;
+};
-#define AK7375_REG_POSITION 0x0
-#define AK7375_REG_CONT 0x2
-#define AK7375_MODE_ACTIVE 0x0
-#define AK7375_MODE_STANDBY 0x40
+static const struct ak73xx_chipdef ak7345_cdef = {
+ .reg_position = 0x0,
+ .reg_cont = 0x2,
+ .shift_pos = 7, /* 9 bits position values, need to << 7 */
+ .mode_active = 0x0,
+ .has_standby = false,
+ .focus_pos_max = 511,
+ .focus_steps = 1,
+ .ctrl_steps = 16,
+ .ctrl_delay_us = 1000,
+ .power_delay_us = 20000,
+};
+
+static const struct ak73xx_chipdef ak7375_cdef = {
+ .reg_position = 0x0,
+ .reg_cont = 0x2,
+ .shift_pos = 4, /* 12 bits position values, need to << 4 */
+ .mode_active = 0x0,
+ .mode_standby = 0x40,
+ .has_standby = true,
+ .focus_pos_max = 4095,
+ .focus_steps = 1,
+ .ctrl_steps = 64,
+ .ctrl_delay_us = 1000,
+ .power_delay_us = 10000,
+};
static const char * const ak7375_supply_names[] = {
"vdd",
@@ -42,6 +72,7 @@ static const char * const ak7375_supply_names[] = {
/* ak7375 device structure */
struct ak7375_device {
+ const struct ak73xx_chipdef *cdef;
struct v4l2_ctrl_handler ctrls_vcm;
struct v4l2_subdev sd;
struct v4l2_ctrl *focus;
@@ -86,10 +117,11 @@ static int ak7375_i2c_write(struct ak7375_device *ak7375,
static int ak7375_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct ak7375_device *dev_vcm = to_ak7375_vcm(ctrl);
+ const struct ak73xx_chipdef *cdef = dev_vcm->cdef;
if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE)
- return ak7375_i2c_write(dev_vcm, AK7375_REG_POSITION,
- ctrl->val << 4, 2);
+ return ak7375_i2c_write(dev_vcm, cdef->reg_position,
+ ctrl->val << cdef->shift_pos, 2);
return -EINVAL;
}
@@ -128,11 +160,12 @@ static int ak7375_init_controls(struct ak7375_device *dev_vcm)
{
struct v4l2_ctrl_handler *hdl = &dev_vcm->ctrls_vcm;
const struct v4l2_ctrl_ops *ops = &ak7375_vcm_ctrl_ops;
+ const struct ak73xx_chipdef *cdef = dev_vcm->cdef;
v4l2_ctrl_handler_init(hdl, 1);
dev_vcm->focus = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE,
- 0, AK7375_MAX_FOCUS_POS, AK7375_FOCUS_STEPS, 0);
+ 0, cdef->focus_pos_max, cdef->focus_steps, 0);
if (hdl->error)
dev_err(dev_vcm->sd.dev, "%s fail error: 0x%x\n",
@@ -153,6 +186,8 @@ static int ak7375_probe(struct i2c_client *client)
if (!ak7375_dev)
return -ENOMEM;
+ ak7375_dev->cdef = device_get_match_data(&client->dev);
+
for (i = 0; i < ARRAY_SIZE(ak7375_supply_names); i++)
ak7375_dev->supplies[i].supply = ak7375_supply_names[i];
@@ -206,32 +241,35 @@ static void ak7375_remove(struct i2c_client *client)
/*
* This function sets the vcm position, so it consumes least current
- * The lens position is gradually moved in units of AK7375_CTRL_STEPS,
+ * The lens position is gradually moved in units of ctrl_steps,
* to make the movements smoothly.
*/
static int __maybe_unused ak7375_vcm_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct ak7375_device *ak7375_dev = sd_to_ak7375_vcm(sd);
+ const struct ak73xx_chipdef *cdef = ak7375_dev->cdef;
int ret, val;
if (!ak7375_dev->active)
return 0;
- for (val = ak7375_dev->focus->val & ~(AK7375_CTRL_STEPS - 1);
- val >= 0; val -= AK7375_CTRL_STEPS) {
- ret = ak7375_i2c_write(ak7375_dev, AK7375_REG_POSITION,
- val << 4, 2);
+ for (val = ak7375_dev->focus->val & ~(cdef->ctrl_steps - 1);
+ val >= 0; val -= cdef->ctrl_steps) {
+ ret = ak7375_i2c_write(ak7375_dev, cdef->reg_position,
+ val << cdef->shift_pos, 2);
if (ret)
dev_err_once(dev, "%s I2C failure: %d\n",
__func__, ret);
- usleep_range(AK7375_CTRL_DELAY_US, AK7375_CTRL_DELAY_US + 10);
+ usleep_range(cdef->ctrl_delay_us, cdef->ctrl_delay_us + 10);
}
- ret = ak7375_i2c_write(ak7375_dev, AK7375_REG_CONT,
- AK7375_MODE_STANDBY, 1);
- if (ret)
- dev_err(dev, "%s I2C failure: %d\n", __func__, ret);
+ if (cdef->has_standby) {
+ ret = ak7375_i2c_write(ak7375_dev, cdef->reg_cont,
+ cdef->mode_standby, 1);
+ if (ret)
+ dev_err(dev, "%s I2C failure: %d\n", __func__, ret);
+ }
ret = regulator_bulk_disable(ARRAY_SIZE(ak7375_supply_names),
ak7375_dev->supplies);
@@ -246,13 +284,14 @@ static int __maybe_unused ak7375_vcm_suspend(struct device *dev)
/*
* This function sets the vcm position to the value set by the user
* through v4l2_ctrl_ops s_ctrl handler
- * The lens position is gradually moved in units of AK7375_CTRL_STEPS,
+ * The lens position is gradually moved in units of ctrl_steps,
* to make the movements smoothly.
*/
static int __maybe_unused ak7375_vcm_resume(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct ak7375_device *ak7375_dev = sd_to_ak7375_vcm(sd);
+ const struct ak73xx_chipdef *cdef = ak7375_dev->cdef;
int ret, val;
if (ak7375_dev->active)
@@ -264,24 +303,24 @@ static int __maybe_unused ak7375_vcm_resume(struct device *dev)
return ret;
/* Wait for vcm to become ready */
- usleep_range(AK7375_POWER_DELAY_US, AK7375_POWER_DELAY_US + 500);
+ usleep_range(cdef->power_delay_us, cdef->power_delay_us + 500);
- ret = ak7375_i2c_write(ak7375_dev, AK7375_REG_CONT,
- AK7375_MODE_ACTIVE, 1);
+ ret = ak7375_i2c_write(ak7375_dev, cdef->reg_cont,
+ cdef->mode_active, 1);
if (ret) {
dev_err(dev, "%s I2C failure: %d\n", __func__, ret);
return ret;
}
- for (val = ak7375_dev->focus->val % AK7375_CTRL_STEPS;
+ for (val = ak7375_dev->focus->val % cdef->ctrl_steps;
val <= ak7375_dev->focus->val;
- val += AK7375_CTRL_STEPS) {
- ret = ak7375_i2c_write(ak7375_dev, AK7375_REG_POSITION,
- val << 4, 2);
+ val += cdef->ctrl_steps) {
+ ret = ak7375_i2c_write(ak7375_dev, cdef->reg_position,
+ val << cdef->shift_pos, 2);
if (ret)
dev_err_ratelimited(dev, "%s I2C failure: %d\n",
__func__, ret);
- usleep_range(AK7375_CTRL_DELAY_US, AK7375_CTRL_DELAY_US + 10);
+ usleep_range(cdef->ctrl_delay_us, cdef->ctrl_delay_us + 10);
}
ak7375_dev->active = true;
@@ -290,7 +329,8 @@ static int __maybe_unused ak7375_vcm_resume(struct device *dev)
}
static const struct of_device_id ak7375_of_table[] = {
- { .compatible = "asahi-kasei,ak7375" },
+ { .compatible = "asahi-kasei,ak7345", .data = &ak7345_cdef, },
+ { .compatible = "asahi-kasei,ak7375", .data = &ak7375_cdef, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ak7375_of_table);
diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c
new file mode 100644
index 000000000000..34ff7fad3877
--- /dev/null
+++ b/drivers/media/i2c/alvium-csi2.c
@@ -0,0 +1,2558 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Allied Vision Technologies GmbH Alvium camera driver
+ *
+ * Copyright (C) 2023 Tommaso Merciai
+ * Copyright (C) 2023 Martin Hecht
+ * Copyright (C) 2023 Avnet EMG GmbH
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <media/mipi-csi2.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#include "alvium-csi2.h"
+
+static const struct v4l2_mbus_framefmt alvium_csi2_default_fmt = {
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .width = 640,
+ .height = 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
+ .quantization = V4L2_QUANTIZATION_FULL_RANGE,
+ .xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
+ .field = V4L2_FIELD_NONE,
+};
+
+static const struct alvium_pixfmt alvium_csi2_fmts[] = {
+ {
+ /* UYVY8_2X8 */
+ .id = ALVIUM_FMT_UYVY8_2X8,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt_av_bit = ALVIUM_BIT_YUV422_8,
+ .bay_av_bit = ALVIUM_BIT_BAY_NONE,
+ .mipi_fmt_regval = MIPI_CSI2_DT_YUV422_8B,
+ .bay_fmt_regval = -1,
+ .is_raw = 0,
+ }, {
+ /* UYVY8_1X16 */
+ .id = ALVIUM_FMT_UYVY8_1X16,
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt_av_bit = ALVIUM_BIT_YUV422_8,
+ .bay_av_bit = ALVIUM_BIT_BAY_NONE,
+ .mipi_fmt_regval = MIPI_CSI2_DT_YUV422_8B,
+ .bay_fmt_regval = -1,
+ .is_raw = 0,
+ }, {
+ /* YUYV8_1X16 */
+ .id = ALVIUM_FMT_YUYV8_1X16,
+ .code = MEDIA_BUS_FMT_YUYV8_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt_av_bit = ALVIUM_BIT_YUV422_8,
+ .bay_av_bit = ALVIUM_BIT_BAY_NONE,
+ .mipi_fmt_regval = MIPI_CSI2_DT_YUV422_8B,
+ .bay_fmt_regval = -1,
+ .is_raw = 0,
+ }, {
+ /* YUYV8_2X8 */
+ .id = ALVIUM_FMT_YUYV8_2X8,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt_av_bit = ALVIUM_BIT_YUV422_8,
+ .bay_av_bit = ALVIUM_BIT_BAY_NONE,
+ .mipi_fmt_regval = MIPI_CSI2_DT_YUV422_8B,
+ .bay_fmt_regval = -1,
+ .is_raw = 0,
+ }, {
+ /* YUYV10_1X20 */
+ .id = ALVIUM_FMT_YUYV10_1X20,
+ .code = MEDIA_BUS_FMT_YUYV10_1X20,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt_av_bit = ALVIUM_BIT_YUV422_10,
+ .bay_av_bit = ALVIUM_BIT_BAY_NONE,
+ .mipi_fmt_regval = MIPI_CSI2_DT_YUV422_10B,
+ .bay_fmt_regval = -1,
+ .is_raw = 0,
+ }, {
+ /* RGB888_1X24 */
+ .id = ALVIUM_FMT_RGB888_1X24,
+ .code = MEDIA_BUS_FMT_RGB888_1X24,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt_av_bit = ALVIUM_BIT_RGB888,
+ .bay_av_bit = ALVIUM_BIT_BAY_NONE,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RGB888,
+ .bay_fmt_regval = -1,
+ .is_raw = 0,
+ }, {
+ /* RBG888_1X24 */
+ .id = ALVIUM_FMT_RBG888_1X24,
+ .code = MEDIA_BUS_FMT_RBG888_1X24,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt_av_bit = ALVIUM_BIT_RGB888,
+ .bay_av_bit = ALVIUM_BIT_BAY_NONE,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RGB888,
+ .bay_fmt_regval = -1,
+ .is_raw = 0,
+ }, {
+ /* BGR888_1X24 */
+ .id = ALVIUM_FMT_BGR888_1X24,
+ .code = MEDIA_BUS_FMT_BGR888_1X24,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt_av_bit = ALVIUM_BIT_RGB888,
+ .bay_av_bit = ALVIUM_BIT_BAY_NONE,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RGB888,
+ .bay_fmt_regval = -1,
+ .is_raw = 0,
+ }, {
+ /* RGB888_3X8 */
+ .id = ALVIUM_FMT_RGB888_3X8,
+ .code = MEDIA_BUS_FMT_RGB888_3X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .fmt_av_bit = ALVIUM_BIT_RGB888,
+ .bay_av_bit = ALVIUM_BIT_BAY_NONE,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RGB888,
+ .bay_fmt_regval = -1,
+ .is_raw = 0,
+ }, {
+ /* Y8_1X8 */
+ .id = ALVIUM_FMT_Y8_1X8,
+ .code = MEDIA_BUS_FMT_Y8_1X8,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW8,
+ .bay_av_bit = ALVIUM_BIT_BAY_MONO,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW8,
+ .bay_fmt_regval = 0x00,
+ .is_raw = 1,
+ }, {
+ /* SGRBG8_1X8 */
+ .id = ALVIUM_FMT_SGRBG8_1X8,
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW8,
+ .bay_av_bit = ALVIUM_BIT_BAY_GR,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW8,
+ .bay_fmt_regval = 0x01,
+ .is_raw = 1,
+ }, {
+ /* SRGGB8_1X8 */
+ .id = ALVIUM_FMT_SRGGB8_1X8,
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW8,
+ .bay_av_bit = ALVIUM_BIT_BAY_RG,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW8,
+ .bay_fmt_regval = 0x02,
+ .is_raw = 1,
+ }, {
+ /* SGBRG8_1X8 */
+ .id = ALVIUM_FMT_SGBRG8_1X8,
+ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW8,
+ .bay_av_bit = ALVIUM_BIT_BAY_GB,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW8,
+ .bay_fmt_regval = 0x03,
+ .is_raw = 1,
+ }, {
+ /* SBGGR8_1X8 */
+ .id = ALVIUM_FMT_SBGGR8_1X8,
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW8,
+ .bay_av_bit = ALVIUM_BIT_BAY_BG,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW8,
+ .bay_fmt_regval = 0x04,
+ .is_raw = 1,
+ }, {
+ /* Y10_1X10 */
+ .id = ALVIUM_FMT_Y10_1X10,
+ .code = MEDIA_BUS_FMT_Y10_1X10,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW10,
+ .bay_av_bit = ALVIUM_BIT_BAY_MONO,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW10,
+ .bay_fmt_regval = 0x00,
+ .is_raw = 1,
+ }, {
+ /* SGRBG10_1X10 */
+ .id = ALVIUM_FMT_SGRBG10_1X10,
+ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW10,
+ .bay_av_bit = ALVIUM_BIT_BAY_GR,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW10,
+ .bay_fmt_regval = 0x01,
+ .is_raw = 1,
+ }, {
+ /* SRGGB10_1X10 */
+ .id = ALVIUM_FMT_SRGGB10_1X10,
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW10,
+ .bay_av_bit = ALVIUM_BIT_BAY_RG,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW10,
+ .bay_fmt_regval = 0x02,
+ .is_raw = 1,
+ }, {
+ /* SGBRG10_1X10 */
+ .id = ALVIUM_FMT_SGBRG10_1X10,
+ .code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW10,
+ .bay_av_bit = ALVIUM_BIT_BAY_GB,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW10,
+ .bay_fmt_regval = 0x03,
+ .is_raw = 1,
+ }, {
+ /* SBGGR10_1X10 */
+ .id = ALVIUM_FMT_SBGGR10_1X10,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW10,
+ .bay_av_bit = ALVIUM_BIT_BAY_BG,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW10,
+ .bay_fmt_regval = 0x04,
+ .is_raw = 1,
+ }, {
+ /* Y12_1X12 */
+ .id = ALVIUM_FMT_Y12_1X12,
+ .code = MEDIA_BUS_FMT_Y12_1X12,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW12,
+ .bay_av_bit = ALVIUM_BIT_BAY_MONO,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW12,
+ .bay_fmt_regval = 0x00,
+ .is_raw = 1,
+ }, {
+ /* SGRBG12_1X12 */
+ .id = ALVIUM_FMT_SGRBG12_1X12,
+ .code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW12,
+ .bay_av_bit = ALVIUM_BIT_BAY_GR,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW12,
+ .bay_fmt_regval = 0x01,
+ .is_raw = 1,
+ }, {
+ /* SRGGB12_1X12 */
+ .id = ALVIUM_FMT_SRGGB12_1X12,
+ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW12,
+ .bay_av_bit = ALVIUM_BIT_BAY_RG,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW12,
+ .bay_fmt_regval = 0x02,
+ .is_raw = 1,
+ }, {
+ /* SGBRG12_1X12 */
+ .id = ALVIUM_FMT_SGBRG12_1X12,
+ .code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW12,
+ .bay_av_bit = ALVIUM_BIT_BAY_GB,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW12,
+ .bay_fmt_regval = 0x03,
+ .is_raw = 1,
+ }, {
+ /* SBGGR12_1X12 */
+ .id = ALVIUM_FMT_SBGGR12_1X12,
+ .code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW12,
+ .bay_av_bit = ALVIUM_BIT_BAY_BG,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW12,
+ .bay_fmt_regval = 0x04,
+ .is_raw = 1,
+ }, {
+ /* SBGGR14_1X14 */
+ .id = ALVIUM_FMT_SBGGR14_1X14,
+ .code = MEDIA_BUS_FMT_SBGGR14_1X14,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW14,
+ .bay_av_bit = ALVIUM_BIT_BAY_GR,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW14,
+ .bay_fmt_regval = 0x01,
+ .is_raw = 1,
+ }, {
+ /* SGBRG14_1X14 */
+ .id = ALVIUM_FMT_SGBRG14_1X14,
+ .code = MEDIA_BUS_FMT_SGBRG14_1X14,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW14,
+ .bay_av_bit = ALVIUM_BIT_BAY_RG,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW14,
+ .bay_fmt_regval = 0x02,
+ .is_raw = 1,
+ }, {
+ /* SRGGB14_1X14 */
+ .id = ALVIUM_FMT_SRGGB14_1X14,
+ .code = MEDIA_BUS_FMT_SRGGB14_1X14,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW14,
+ .bay_av_bit = ALVIUM_BIT_BAY_GB,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW14,
+ .bay_fmt_regval = 0x03,
+ .is_raw = 1,
+ }, {
+ /* SGRBG14_1X14 */
+ .id = ALVIUM_FMT_SGRBG14_1X14,
+ .code = MEDIA_BUS_FMT_SGRBG14_1X14,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .fmt_av_bit = ALVIUM_BIT_RAW14,
+ .bay_av_bit = ALVIUM_BIT_BAY_BG,
+ .mipi_fmt_regval = MIPI_CSI2_DT_RAW14,
+ .bay_fmt_regval = 0x04,
+ .is_raw = 1,
+ },
+ { /* sentinel */ }
+};
+
+static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val, int *err)
+{
+ if (reg & REG_BCRM_V4L2) {
+ reg &= ~REG_BCRM_V4L2;
+ reg += alvium->bcrm_addr;
+ }
+
+ return cci_read(alvium->regmap, reg, val, err);
+}
+
+static int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val, int *err)
+{
+ if (reg & REG_BCRM_V4L2) {
+ reg &= ~REG_BCRM_V4L2;
+ reg += alvium->bcrm_addr;
+ }
+
+ return cci_write(alvium->regmap, reg, val, err);
+}
+
+static int alvium_write_hshake(struct alvium_dev *alvium, u32 reg, u64 val)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ u64 hshake_bit;
+ int ret = 0;
+
+ /* reset handshake bit and write alvium reg */
+ alvium_write(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, 0, &ret);
+ alvium_write(alvium, reg, val, &ret);
+ if (ret) {
+ dev_err(dev, "Fail to write reg\n");
+ return ret;
+ }
+
+ /* poll handshake bit since bit0 = 1 */
+ read_poll_timeout(alvium_read, hshake_bit,
+ ((hshake_bit & BCRM_HANDSHAKE_W_DONE_EN_BIT) == 1),
+ 15000, 45000, true,
+ alvium, REG_BCRM_WRITE_HANDSHAKE_RW,
+ &hshake_bit, &ret);
+ if (ret) {
+ dev_err(dev, "poll bit[0] = 1, hshake reg fail\n");
+ return ret;
+ }
+
+ /* reset handshake bit, write 0 to bit0 */
+ alvium_write(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, 0, &ret);
+ if (ret) {
+ dev_err(dev, "Fail to reset hshake reg\n");
+ return ret;
+ }
+
+ /* poll handshake bit since bit0 = 0 */
+ read_poll_timeout(alvium_read, hshake_bit,
+ ((hshake_bit & BCRM_HANDSHAKE_W_DONE_EN_BIT) == 0),
+ 15000, 45000, true,
+ alvium, REG_BCRM_WRITE_HANDSHAKE_RW,
+ &hshake_bit, &ret);
+ if (ret) {
+ dev_err(dev, "poll bit[0] = 0, hshake reg fail\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_get_bcrm_vers(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ u64 min, maj;
+ int ret = 0;
+
+ ret = alvium_read(alvium, REG_BCRM_MINOR_VERSION_R, &min, &ret);
+ ret = alvium_read(alvium, REG_BCRM_MAJOR_VERSION_R, &maj, &ret);
+ if (ret)
+ return ret;
+
+ dev_info(dev, "bcrm version: %llu.%llu\n", min, maj);
+
+ return 0;
+}
+
+static int alvium_get_fw_version(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ u64 spec, maj, min, pat;
+ int ret = 0;
+
+ ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_SPEC_VERSION_R,
+ &spec, &ret);
+ ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_MAJOR_VERSION_R,
+ &maj, &ret);
+ ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_MINOR_VERSION_R,
+ &min, &ret);
+ ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_PATCH_VERSION_R,
+ &pat, &ret);
+ if (ret)
+ return ret;
+
+ dev_info(dev, "fw version: %llu.%llu.%llu.%llu\n", spec, maj, min, pat);
+
+ return 0;
+}
+
+static int alvium_get_bcrm_addr(struct alvium_dev *alvium)
+{
+ u64 val;
+ int ret;
+
+ ret = alvium_read(alvium, REG_BCRM_REG_ADDR_R, &val, NULL);
+ if (ret)
+ return ret;
+
+ alvium->bcrm_addr = val;
+
+ return 0;
+}
+
+static int alvium_is_alive(struct alvium_dev *alvium)
+{
+ u64 bcrm, hbeat;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_MINOR_VERSION_R, &bcrm, &ret);
+ alvium_read(alvium, REG_BCRM_HEARTBEAT_RW, &hbeat, &ret);
+ if (ret)
+ return ret;
+
+ return hbeat;
+}
+
+static void alvium_print_avail_mipi_fmt(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+
+ dev_dbg(dev, "avail mipi_fmt yuv420_8_leg: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_8_LEG]);
+ dev_dbg(dev, "avail mipi_fmt yuv420_8: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_8]);
+ dev_dbg(dev, "avail mipi_fmt yuv420_10: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_10]);
+ dev_dbg(dev, "avail mipi_fmt yuv420_8_csps: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_8_CSPS]);
+ dev_dbg(dev, "avail mipi_fmt yuv420_10_csps: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_10_CSPS]);
+ dev_dbg(dev, "avail mipi_fmt yuv422_8: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV422_8]);
+ dev_dbg(dev, "avail mipi_fmt yuv422_10: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV422_10]);
+ dev_dbg(dev, "avail mipi_fmt rgb888: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB888]);
+ dev_dbg(dev, "avail mipi_fmt rgb666: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB666]);
+ dev_dbg(dev, "avail mipi_fmt rgb565: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB565]);
+ dev_dbg(dev, "avail mipi_fmt rgb555: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB555]);
+ dev_dbg(dev, "avail mipi_fmt rgb444: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB444]);
+ dev_dbg(dev, "avail mipi_fmt raw6: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW6]);
+ dev_dbg(dev, "avail mipi_fmt raw7: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW7]);
+ dev_dbg(dev, "avail mipi_fmt raw8: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW8]);
+ dev_dbg(dev, "avail mipi_fmt raw10: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW10]);
+ dev_dbg(dev, "avail mipi_fmt raw12: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW12]);
+ dev_dbg(dev, "avail mipi_fmt raw14: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW14]);
+ dev_dbg(dev, "avail mipi_fmt jpeg: %u\n",
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_JPEG]);
+}
+
+static void alvium_print_avail_feat(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+
+ dev_dbg(dev, "feature rev_x: %u\n", alvium->avail_ft.rev_x);
+ dev_dbg(dev, "feature rev_y: %u\n", alvium->avail_ft.rev_y);
+ dev_dbg(dev, "feature int_autop: %u\n", alvium->avail_ft.int_autop);
+ dev_dbg(dev, "feature black_lvl: %u\n", alvium->avail_ft.black_lvl);
+ dev_dbg(dev, "feature gain: %u\n", alvium->avail_ft.gain);
+ dev_dbg(dev, "feature gamma: %u\n", alvium->avail_ft.gamma);
+ dev_dbg(dev, "feature contrast: %u\n", alvium->avail_ft.contrast);
+ dev_dbg(dev, "feature sat: %u\n", alvium->avail_ft.sat);
+ dev_dbg(dev, "feature hue: %u\n", alvium->avail_ft.hue);
+ dev_dbg(dev, "feature whiteb: %u\n", alvium->avail_ft.whiteb);
+ dev_dbg(dev, "feature sharp: %u\n", alvium->avail_ft.sharp);
+ dev_dbg(dev, "feature auto_exp: %u\n", alvium->avail_ft.auto_exp);
+ dev_dbg(dev, "feature auto_gain: %u\n", alvium->avail_ft.auto_gain);
+ dev_dbg(dev, "feature auto_whiteb: %u\n", alvium->avail_ft.auto_whiteb);
+ dev_dbg(dev, "feature dev_temp: %u\n", alvium->avail_ft.dev_temp);
+ dev_dbg(dev, "feature acq_abort: %u\n", alvium->avail_ft.acq_abort);
+ dev_dbg(dev, "feature acq_fr: %u\n", alvium->avail_ft.acq_fr);
+ dev_dbg(dev, "feature fr_trigger: %u\n", alvium->avail_ft.fr_trigger);
+ dev_dbg(dev, "feature exp_acq_line: %u\n",
+ alvium->avail_ft.exp_acq_line);
+}
+
+static void alvium_print_avail_bayer(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+
+ dev_dbg(dev, "avail bayer mono: %u\n",
+ alvium->is_bay_avail[ALVIUM_BIT_BAY_MONO]);
+ dev_dbg(dev, "avail bayer gr: %u\n",
+ alvium->is_bay_avail[ALVIUM_BIT_BAY_GR]);
+ dev_dbg(dev, "avail bayer rg: %u\n",
+ alvium->is_bay_avail[ALVIUM_BIT_BAY_RG]);
+ dev_dbg(dev, "avail bayer gb: %u\n",
+ alvium->is_bay_avail[ALVIUM_BIT_BAY_GB]);
+ dev_dbg(dev, "avail bayer bg: %u\n",
+ alvium->is_bay_avail[ALVIUM_BIT_BAY_BG]);
+}
+
+static int alvium_get_feat_inq(struct alvium_dev *alvium)
+{
+ struct alvium_avail_feat *f;
+ u64 val;
+ int ret;
+
+ ret = alvium_read(alvium, REG_BCRM_FEATURE_INQUIRY_R, &val, NULL);
+ if (ret)
+ return ret;
+
+ f = (struct alvium_avail_feat *)&val;
+ alvium->avail_ft = *f;
+ alvium_print_avail_feat(alvium);
+
+ return 0;
+}
+
+static int alvium_get_host_supp_csi_lanes(struct alvium_dev *alvium)
+{
+ u64 val;
+ int ret;
+
+ ret = alvium_read(alvium, REG_BCRM_CSI2_LANE_COUNT_RW, &val, NULL);
+ if (ret)
+ return ret;
+
+ alvium->h_sup_csi_lanes = val;
+
+ return 0;
+}
+
+static int alvium_set_csi_lanes(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ u64 num_lanes;
+ int ret;
+
+ num_lanes = alvium->ep.bus.mipi_csi2.num_data_lanes;
+
+ if (num_lanes > alvium->h_sup_csi_lanes)
+ return -EINVAL;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_CSI2_LANE_COUNT_RW,
+ num_lanes);
+ if (ret) {
+ dev_err(dev, "Fail to set csi lanes reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_lp2hs_delay(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret = 0;
+
+ /*
+ * The purpose of this reg is force a DPhy reset
+ * for the period described by the millisecond on
+ * the reg, before it starts streaming.
+ *
+ * To be clear, with that value bigger than 0 the
+ * Alvium forces a dphy-reset on all lanes for that period.
+ * That means all lanes go up into low power state.
+ *
+ */
+ alvium_write(alvium, REG_BCRM_LP2HS_DELAY_RW,
+ ALVIUM_LP2HS_DELAY_MS, &ret);
+ if (ret) {
+ dev_err(dev, "Fail to set lp2hs delay reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_get_csi_clk_params(struct alvium_dev *alvium)
+{
+ u64 min_csi_clk, max_csi_clk;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_CSI2_CLOCK_MIN_R, &min_csi_clk, &ret);
+ alvium_read(alvium, REG_BCRM_CSI2_CLOCK_MAX_R, &max_csi_clk, &ret);
+ if (ret)
+ return ret;
+
+ alvium->min_csi_clk = min_csi_clk;
+ alvium->max_csi_clk = max_csi_clk;
+
+ return 0;
+}
+
+static int alvium_set_csi_clk(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ u64 csi_clk;
+ int ret;
+
+ csi_clk = clamp(alvium->ep.link_frequencies[0],
+ (u64)alvium->min_csi_clk, (u64)alvium->max_csi_clk);
+
+ if (alvium->ep.link_frequencies[0] != (u64)csi_clk) {
+ dev_warn(dev,
+ "requested csi clock (%llu MHz) out of range [%u, %u] Adjusted to %llu\n",
+ alvium->ep.link_frequencies[0],
+ alvium->min_csi_clk, alvium->max_csi_clk, csi_clk);
+ }
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_CSI2_CLOCK_RW, csi_clk);
+ if (ret) {
+ dev_err(dev, "Fail to set csi clock reg\n");
+ return ret;
+ }
+
+ alvium->link_freq = csi_clk;
+
+ return 0;
+}
+
+static int alvium_get_img_width_params(struct alvium_dev *alvium)
+{
+ u64 imgw, imgw_min, imgw_max, imgw_inc;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_IMG_WIDTH_RW, &imgw, &ret);
+ alvium_read(alvium, REG_BCRM_IMG_WIDTH_MIN_R, &imgw_min, &ret);
+ alvium_read(alvium, REG_BCRM_IMG_WIDTH_MAX_R, &imgw_max, &ret);
+ alvium_read(alvium, REG_BCRM_IMG_WIDTH_INC_R, &imgw_inc, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_img_width = imgw;
+ alvium->img_min_width = imgw_min;
+ alvium->img_max_width = imgw_max;
+ alvium->img_inc_width = imgw_inc;
+
+ return 0;
+}
+
+static int alvium_get_img_height_params(struct alvium_dev *alvium)
+{
+ u64 imgh, imgh_min, imgh_max, imgh_inc;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_IMG_HEIGHT_RW, &imgh, &ret);
+ alvium_read(alvium, REG_BCRM_IMG_HEIGHT_MIN_R, &imgh_min, &ret);
+ alvium_read(alvium, REG_BCRM_IMG_HEIGHT_MAX_R, &imgh_max, &ret);
+ alvium_read(alvium, REG_BCRM_IMG_HEIGHT_INC_R, &imgh_inc, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_img_height = imgh;
+ alvium->img_min_height = imgh_min;
+ alvium->img_max_height = imgh_max;
+ alvium->img_inc_height = imgh_inc;
+
+ return 0;
+}
+
+static int alvium_set_img_width(struct alvium_dev *alvium, u32 width)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_IMG_WIDTH_RW, width);
+ if (ret) {
+ dev_err(dev, "Fail to set img width\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_img_height(struct alvium_dev *alvium, u32 height)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_IMG_HEIGHT_RW, height);
+ if (ret) {
+ dev_err(dev, "Fail to set img height\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_img_offx(struct alvium_dev *alvium, u32 offx)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_IMG_OFFSET_X_RW, offx);
+ if (ret) {
+ dev_err(dev, "Fail to set img offx\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_img_offy(struct alvium_dev *alvium, u32 offy)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_IMG_OFFSET_Y_RW, offy);
+ if (ret) {
+ dev_err(dev, "Fail to set img offy\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_get_offx_params(struct alvium_dev *alvium)
+{
+ u64 min_offx, max_offx, inc_offx;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_IMG_OFFSET_X_MIN_R, &min_offx, &ret);
+ alvium_read(alvium, REG_BCRM_IMG_OFFSET_X_MAX_R, &max_offx, &ret);
+ alvium_read(alvium, REG_BCRM_IMG_OFFSET_X_INC_R, &inc_offx, &ret);
+ if (ret)
+ return ret;
+
+ alvium->min_offx = min_offx;
+ alvium->max_offx = max_offx;
+ alvium->inc_offx = inc_offx;
+
+ return 0;
+}
+
+static int alvium_get_offy_params(struct alvium_dev *alvium)
+{
+ u64 min_offy, max_offy, inc_offy;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_IMG_OFFSET_Y_MIN_R, &min_offy, &ret);
+ alvium_read(alvium, REG_BCRM_IMG_OFFSET_Y_MAX_R, &max_offy, &ret);
+ alvium_read(alvium, REG_BCRM_IMG_OFFSET_Y_INC_R, &inc_offy, &ret);
+ if (ret)
+ return ret;
+
+ alvium->min_offy = min_offy;
+ alvium->max_offy = max_offy;
+ alvium->inc_offy = inc_offy;
+
+ return 0;
+}
+
+static int alvium_get_gain_params(struct alvium_dev *alvium)
+{
+ u64 dft_gain, min_gain, max_gain, inc_gain;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_GAIN_RW, &dft_gain, &ret);
+ alvium_read(alvium, REG_BCRM_GAIN_MIN_R, &min_gain, &ret);
+ alvium_read(alvium, REG_BCRM_GAIN_MAX_R, &max_gain, &ret);
+ alvium_read(alvium, REG_BCRM_GAIN_INC_R, &inc_gain, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_gain = dft_gain;
+ alvium->min_gain = min_gain;
+ alvium->max_gain = max_gain;
+ alvium->inc_gain = inc_gain;
+
+ return 0;
+}
+
+static int alvium_get_exposure_params(struct alvium_dev *alvium)
+{
+ u64 dft_exp, min_exp, max_exp, inc_exp;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_EXPOSURE_TIME_RW, &dft_exp, &ret);
+ alvium_read(alvium, REG_BCRM_EXPOSURE_TIME_MIN_R, &min_exp, &ret);
+ alvium_read(alvium, REG_BCRM_EXPOSURE_TIME_MAX_R, &max_exp, &ret);
+ alvium_read(alvium, REG_BCRM_EXPOSURE_TIME_INC_R, &inc_exp, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_exp = dft_exp;
+ alvium->min_exp = min_exp;
+ alvium->max_exp = max_exp;
+ alvium->inc_exp = inc_exp;
+
+ return 0;
+}
+
+static int alvium_get_red_balance_ratio_params(struct alvium_dev *alvium)
+{
+ u64 dft_rb, min_rb, max_rb, inc_rb;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_RED_BALANCE_RATIO_RW, &dft_rb, &ret);
+ alvium_read(alvium, REG_BCRM_RED_BALANCE_RATIO_MIN_R, &min_rb, &ret);
+ alvium_read(alvium, REG_BCRM_RED_BALANCE_RATIO_MAX_R, &max_rb, &ret);
+ alvium_read(alvium, REG_BCRM_RED_BALANCE_RATIO_INC_R, &inc_rb, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_rbalance = dft_rb;
+ alvium->min_rbalance = min_rb;
+ alvium->max_rbalance = max_rb;
+ alvium->inc_rbalance = inc_rb;
+
+ return 0;
+}
+
+static int alvium_get_blue_balance_ratio_params(struct alvium_dev *alvium)
+{
+ u64 dft_bb, min_bb, max_bb, inc_bb;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_BLUE_BALANCE_RATIO_RW, &dft_bb, &ret);
+ alvium_read(alvium, REG_BCRM_BLUE_BALANCE_RATIO_MIN_R, &min_bb, &ret);
+ alvium_read(alvium, REG_BCRM_BLUE_BALANCE_RATIO_MAX_R, &max_bb, &ret);
+ alvium_read(alvium, REG_BCRM_BLUE_BALANCE_RATIO_INC_R, &inc_bb, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_bbalance = dft_bb;
+ alvium->min_bbalance = min_bb;
+ alvium->max_bbalance = max_bb;
+ alvium->inc_bbalance = inc_bb;
+
+ return 0;
+}
+
+static int alvium_get_hue_params(struct alvium_dev *alvium)
+{
+ u64 dft_hue, min_hue, max_hue, inc_hue;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_HUE_RW, &dft_hue, &ret);
+ alvium_read(alvium, REG_BCRM_HUE_MIN_R, &min_hue, &ret);
+ alvium_read(alvium, REG_BCRM_HUE_MAX_R, &max_hue, &ret);
+ alvium_read(alvium, REG_BCRM_HUE_INC_R, &inc_hue, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_hue = (s32)dft_hue;
+ alvium->min_hue = (s32)min_hue;
+ alvium->max_hue = (s32)max_hue;
+ alvium->inc_hue = (s32)inc_hue;
+
+ return 0;
+}
+
+static int alvium_get_black_lvl_params(struct alvium_dev *alvium)
+{
+ u64 dft_blvl, min_blvl, max_blvl, inc_blvl;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_BLACK_LEVEL_RW, &dft_blvl, &ret);
+ alvium_read(alvium, REG_BCRM_BLACK_LEVEL_MIN_R, &min_blvl, &ret);
+ alvium_read(alvium, REG_BCRM_BLACK_LEVEL_MAX_R, &max_blvl, &ret);
+ alvium_read(alvium, REG_BCRM_BLACK_LEVEL_INC_R, &inc_blvl, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_black_lvl = (s32)dft_blvl;
+ alvium->min_black_lvl = (s32)min_blvl;
+ alvium->max_black_lvl = (s32)max_blvl;
+ alvium->inc_black_lvl = (s32)inc_blvl;
+
+ return 0;
+}
+
+static int alvium_get_gamma_params(struct alvium_dev *alvium)
+{
+ u64 dft_g, min_g, max_g, inc_g;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_GAMMA_RW, &dft_g, &ret);
+ alvium_read(alvium, REG_BCRM_GAMMA_MIN_R, &min_g, &ret);
+ alvium_read(alvium, REG_BCRM_GAMMA_MAX_R, &max_g, &ret);
+ alvium_read(alvium, REG_BCRM_GAMMA_INC_R, &inc_g, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_gamma = dft_g;
+ alvium->min_gamma = min_g;
+ alvium->max_gamma = max_g;
+ alvium->inc_gamma = inc_g;
+
+ return 0;
+}
+
+static int alvium_get_sharpness_params(struct alvium_dev *alvium)
+{
+ u64 dft_sh, min_sh, max_sh, inc_sh;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_SHARPNESS_RW, &dft_sh, &ret);
+ alvium_read(alvium, REG_BCRM_SHARPNESS_MIN_R, &min_sh, &ret);
+ alvium_read(alvium, REG_BCRM_BLACK_LEVEL_MAX_R, &max_sh, &ret);
+ alvium_read(alvium, REG_BCRM_SHARPNESS_INC_R, &inc_sh, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_sharp = (s32)dft_sh;
+ alvium->min_sharp = (s32)min_sh;
+ alvium->max_sharp = (s32)max_sh;
+ alvium->inc_sharp = (s32)inc_sh;
+
+ return 0;
+}
+
+static int alvium_get_contrast_params(struct alvium_dev *alvium)
+{
+ u64 dft_c, min_c, max_c, inc_c;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_CONTRAST_VALUE_RW, &dft_c, &ret);
+ alvium_read(alvium, REG_BCRM_CONTRAST_VALUE_MIN_R, &min_c, &ret);
+ alvium_read(alvium, REG_BCRM_CONTRAST_VALUE_MAX_R, &max_c, &ret);
+ alvium_read(alvium, REG_BCRM_CONTRAST_VALUE_INC_R, &inc_c, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_contrast = dft_c;
+ alvium->min_contrast = min_c;
+ alvium->max_contrast = max_c;
+ alvium->inc_contrast = inc_c;
+
+ return 0;
+}
+
+static int alvium_get_saturation_params(struct alvium_dev *alvium)
+{
+ u64 dft_sat, min_sat, max_sat, inc_sat;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_SATURATION_RW, &dft_sat, &ret);
+ alvium_read(alvium, REG_BCRM_SATURATION_MIN_R, &min_sat, &ret);
+ alvium_read(alvium, REG_BCRM_SATURATION_MAX_R, &max_sat, &ret);
+ alvium_read(alvium, REG_BCRM_SATURATION_INC_R, &inc_sat, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_sat = dft_sat;
+ alvium->min_sat = min_sat;
+ alvium->max_sat = max_sat;
+ alvium->inc_sat = inc_sat;
+
+ return 0;
+}
+
+static int alvium_set_bcm_mode(struct alvium_dev *alvium)
+{
+ int ret = 0;
+
+ alvium_write(alvium, REG_GENCP_CHANGEMODE_W, ALVIUM_BCM_MODE, &ret);
+ alvium->bcrm_mode = ALVIUM_BCM_MODE;
+
+ return ret;
+}
+
+static int alvium_get_mode(struct alvium_dev *alvium)
+{
+ u64 bcrm_mode;
+ int ret;
+
+ ret = alvium_read(alvium, REG_GENCP_CURRENTMODE_R, &bcrm_mode, NULL);
+ if (ret)
+ return ret;
+
+ switch (bcrm_mode) {
+ case ALVIUM_BCM_MODE:
+ alvium->bcrm_mode = ALVIUM_BCM_MODE;
+ break;
+ case ALVIUM_GENCP_MODE:
+ alvium->bcrm_mode = ALVIUM_GENCP_MODE;
+ break;
+ }
+
+ return 0;
+}
+
+static int alvium_get_avail_mipi_data_format(struct alvium_dev *alvium)
+{
+ struct alvium_avail_mipi_fmt *avail_fmt;
+ u64 val;
+ int ret;
+
+ ret = alvium_read(alvium, REG_BCRM_IMG_AVAILABLE_MIPI_DATA_FORMATS_R,
+ &val, NULL);
+ if (ret)
+ return ret;
+
+ avail_fmt = (struct alvium_avail_mipi_fmt *)&val;
+
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_8_LEG] =
+ avail_fmt->yuv420_8_leg;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_8] =
+ avail_fmt->yuv420_8;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_10] =
+ avail_fmt->yuv420_10;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_8_CSPS] =
+ avail_fmt->yuv420_8_csps;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_10_CSPS] =
+ avail_fmt->yuv420_10_csps;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV422_8] =
+ avail_fmt->yuv422_8;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV422_10] =
+ avail_fmt->yuv422_10;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB888] =
+ avail_fmt->rgb888;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB666] =
+ avail_fmt->rgb666;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB565] =
+ avail_fmt->rgb565;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB555] =
+ avail_fmt->rgb555;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB444] =
+ avail_fmt->rgb444;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW6] =
+ avail_fmt->raw6;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW7] =
+ avail_fmt->raw7;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW8] =
+ avail_fmt->raw8;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW10] =
+ avail_fmt->raw10;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW12] =
+ avail_fmt->raw12;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW14] =
+ avail_fmt->raw14;
+ alvium->is_mipi_fmt_avail[ALVIUM_BIT_JPEG] =
+ avail_fmt->jpeg;
+
+ alvium_print_avail_mipi_fmt(alvium);
+
+ return 0;
+}
+
+static int alvium_setup_mipi_fmt(struct alvium_dev *alvium)
+{
+ unsigned int avail_fmt_cnt = 0;
+ unsigned int fmt = 0;
+ size_t sz = 0;
+
+ /* calculate fmt array size */
+ for (fmt = 0; fmt < ALVIUM_NUM_SUPP_MIPI_DATA_FMT; fmt++) {
+ if (!alvium->is_mipi_fmt_avail[alvium_csi2_fmts[fmt].fmt_av_bit])
+ continue;
+
+ if (!alvium_csi2_fmts[fmt].is_raw ||
+ alvium->is_bay_avail[alvium_csi2_fmts[fmt].bay_av_bit])
+ sz++;
+ }
+
+ /* init alvium_csi2_fmt array */
+ alvium->alvium_csi2_fmt_n = sz;
+ alvium->alvium_csi2_fmt =
+ kmalloc_array(sz, sizeof(struct alvium_pixfmt), GFP_KERNEL);
+ if (!alvium->alvium_csi2_fmt)
+ return -ENOMEM;
+
+ /* Create the alvium_csi2 fmt array from formats available */
+ for (fmt = 0; fmt < ALVIUM_NUM_SUPP_MIPI_DATA_FMT; fmt++) {
+ if (!alvium->is_mipi_fmt_avail[alvium_csi2_fmts[fmt].fmt_av_bit])
+ continue;
+
+ if (!alvium_csi2_fmts[fmt].is_raw ||
+ alvium->is_bay_avail[alvium_csi2_fmts[fmt].bay_av_bit]) {
+ alvium->alvium_csi2_fmt[avail_fmt_cnt] =
+ alvium_csi2_fmts[fmt];
+ avail_fmt_cnt++;
+ }
+ }
+
+ return 0;
+}
+
+static int alvium_set_mipi_fmt(struct alvium_dev *alvium,
+ const struct alvium_pixfmt *pixfmt)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_IMG_MIPI_DATA_FORMAT_RW,
+ pixfmt->mipi_fmt_regval);
+ if (ret) {
+ dev_err(dev, "Fail to set mipi fmt\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_get_avail_bayer(struct alvium_dev *alvium)
+{
+ struct alvium_avail_bayer *avail_bay;
+ u64 val;
+ int ret;
+
+ ret = alvium_read(alvium, REG_BCRM_IMG_BAYER_PATTERN_INQUIRY_R,
+ &val, NULL);
+ if (ret)
+ return ret;
+
+ avail_bay = (struct alvium_avail_bayer *)&val;
+
+ alvium->is_bay_avail[ALVIUM_BIT_BAY_MONO] = avail_bay->mono;
+ alvium->is_bay_avail[ALVIUM_BIT_BAY_GR] = avail_bay->gr;
+ alvium->is_bay_avail[ALVIUM_BIT_BAY_RG] = avail_bay->rg;
+ alvium->is_bay_avail[ALVIUM_BIT_BAY_GB] = avail_bay->gb;
+ alvium->is_bay_avail[ALVIUM_BIT_BAY_BG] = avail_bay->bg;
+
+ alvium_print_avail_bayer(alvium);
+
+ return 0;
+}
+
+static int alvium_set_bayer_pattern(struct alvium_dev *alvium,
+ const struct alvium_pixfmt *pixfmt)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_IMG_BAYER_PATTERN_RW,
+ pixfmt->bay_fmt_regval);
+ if (ret) {
+ dev_err(dev, "Fail to set bayer pattern\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_get_frame_interval(struct alvium_dev *alvium)
+{
+ u64 dft_fr, min_fr, max_fr;
+ int ret = 0;
+
+ alvium_read(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_RW,
+ &dft_fr, &ret);
+ alvium_read(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_MIN_R,
+ &min_fr, &ret);
+ alvium_read(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_MAX_R,
+ &max_fr, &ret);
+ if (ret)
+ return ret;
+
+ alvium->dft_fr = dft_fr;
+ alvium->min_fr = min_fr;
+ alvium->max_fr = max_fr;
+
+ return 0;
+}
+
+static int alvium_set_frame_rate(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_RW,
+ alvium->fr);
+ if (ret) {
+ dev_err(dev, "Fail to set frame rate lanes reg\n");
+ return ret;
+ }
+
+ dev_dbg(dev, "set frame rate: %llu us\n", alvium->fr);
+
+ return 0;
+}
+
+static int alvium_set_stream_mipi(struct alvium_dev *alvium, bool on)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, on ? REG_BCRM_ACQUISITION_START_RW :
+ REG_BCRM_ACQUISITION_STOP_RW, 0x01);
+ if (ret) {
+ dev_err(dev, "Fail set_stream_mipi\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_get_gain(struct alvium_dev *alvium)
+{
+ u64 gain;
+ int ret;
+
+ /* The unit is millibel (1 mB = 0.01 dB) */
+ ret = alvium_read(alvium, REG_BCRM_GAIN_RW, &gain, NULL);
+ if (ret)
+ return ret;
+
+ return gain;
+}
+
+static int alvium_set_ctrl_gain(struct alvium_dev *alvium, int gain)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ /* The unit is millibel (1 mB = 0.01 dB) */
+ ret = alvium_write_hshake(alvium, REG_BCRM_GAIN_RW, (u64)gain);
+ if (ret) {
+ dev_err(dev, "Fail to set gain value reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_ctrl_auto_gain(struct alvium_dev *alvium, bool on)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_GAIN_AUTO_RW,
+ on ? 0x02 : 0x00);
+ if (ret) {
+ dev_err(dev, "Fail to set autogain reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_get_exposure(struct alvium_dev *alvium)
+{
+ u64 exp;
+ int ret;
+
+ /* Exposure time in ns */
+ ret = alvium_read(alvium, REG_BCRM_EXPOSURE_TIME_RW, &exp, NULL);
+ if (ret)
+ return ret;
+
+ return exp;
+}
+
+static int alvium_set_ctrl_auto_exposure(struct alvium_dev *alvium, bool on)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_WHITE_BALANCE_AUTO_RW,
+ on ? 0x02 : 0x00);
+ if (ret) {
+ dev_err(dev, "Fail to set autoexposure reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_ctrl_exposure(struct alvium_dev *alvium, int exposure_ns)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_EXPOSURE_TIME_RW,
+ (u64)exposure_ns);
+ if (ret) {
+ dev_err(dev, "Fail to set exposure value reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_ctrl_blue_balance_ratio(struct alvium_dev *alvium,
+ int blue)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_BLUE_BALANCE_RATIO_RW,
+ (u64)blue);
+ if (ret) {
+ dev_err(dev, "Fail to set blue ratio value reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_ctrl_red_balance_ratio(struct alvium_dev *alvium, int red)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_RED_BALANCE_RATIO_RW,
+ (u64)red);
+ if (ret) {
+ dev_err(dev, "Fail to set red ratio value reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_ctrl_awb(struct alvium_dev *alvium, bool on)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_WHITE_BALANCE_AUTO_RW,
+ on ? 0x02 : 0x00);
+ if (ret) {
+ dev_err(dev, "Fail to set awb reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_ctrl_hue(struct alvium_dev *alvium, int val)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_HUE_RW, (u64)val);
+ if (ret) {
+ dev_err(dev, "Fail to set hue value reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_ctrl_contrast(struct alvium_dev *alvium, int val)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_CONTRAST_VALUE_RW, (u64)val);
+ if (ret) {
+ dev_err(dev, "Fail to set contrast value reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_ctrl_saturation(struct alvium_dev *alvium, int val)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_SATURATION_RW, (u64)val);
+ if (ret) {
+ dev_err(dev, "Fail to set contrast value reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_ctrl_gamma(struct alvium_dev *alvium, int val)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_GAMMA_RW, (u64)val);
+ if (ret) {
+ dev_err(dev, "Fail to set gamma value reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_ctrl_sharpness(struct alvium_dev *alvium, int val)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_SHARPNESS_RW, (u64)val);
+ if (ret) {
+ dev_err(dev, "Fail to set sharpness value reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_ctrl_hflip(struct alvium_dev *alvium, int val)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_IMG_REVERSE_X_RW, (u64)val);
+ if (ret) {
+ dev_err(dev, "Fail to set reverse_x value reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_set_ctrl_vflip(struct alvium_dev *alvium, int val)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_IMG_REVERSE_Y_RW, (u64)val);
+ if (ret) {
+ dev_err(dev, "Fail to set reverse_y value reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_get_hw_features_params(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_get_csi_clk_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read min/max csi clock regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_img_width_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read img width regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_img_height_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read img heigth regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_offx_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read offx regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_offy_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read offy regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_gain_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read gain regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_exposure_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read min/max exp regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_red_balance_ratio_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read red balance ratio regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_blue_balance_ratio_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read blue balance ratio regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_hue_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read hue regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_contrast_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read contrast regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_saturation_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read saturation regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_black_lvl_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read black lvl regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_gamma_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read gamma regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_sharpness_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read sharpness regs\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_get_hw_info(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ ret = alvium_get_bcrm_vers(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read bcrm version reg\n");
+ return ret;
+ }
+
+ ret = alvium_get_bcrm_addr(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to bcrm address reg\n");
+ return ret;
+ }
+
+ ret = alvium_get_fw_version(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read fw version reg\n");
+ return ret;
+ }
+
+ ret = alvium_get_host_supp_csi_lanes(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read host supported csi lanes reg\n");
+ return ret;
+ }
+
+ ret = alvium_get_feat_inq(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read bcrm feature inquiry reg\n");
+ return ret;
+ }
+
+ ret = alvium_get_hw_features_params(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read features params regs\n");
+ return ret;
+ }
+
+ ret = alvium_get_avail_mipi_data_format(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read available mipi data formats reg\n");
+ return ret;
+ }
+
+ ret = alvium_get_avail_bayer(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to read available Bayer patterns reg\n");
+ return ret;
+ }
+
+ ret = alvium_get_mode(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to get current mode reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_hw_init(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ int ret;
+
+ /* Set Alvium BCM mode*/
+ ret = alvium_set_bcm_mode(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to set BCM mode\n");
+ return ret;
+ }
+
+ ret = alvium_set_csi_lanes(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to set csi lanes\n");
+ return ret;
+ }
+
+ ret = alvium_set_csi_clk(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to set csi clk\n");
+ return ret;
+ }
+
+ ret = alvium_set_lp2hs_delay(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to set lp2hs reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+/* --------------- Subdev Operations --------------- */
+
+static int alvium_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ fi->interval = alvium->frame_interval;
+
+ return 0;
+}
+
+static int alvium_set_frame_interval(struct alvium_dev *alvium,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ u64 req_fr, min_fr, max_fr;
+ int ret;
+
+ if (fi->interval.denominator == 0)
+ return -EINVAL;
+
+ ret = alvium_get_frame_interval(alvium);
+ if (ret) {
+ dev_err(dev, "Fail to get frame interval\n");
+ return ret;
+ }
+
+ min_fr = alvium->min_fr;
+ max_fr = alvium->max_fr;
+
+ dev_dbg(dev, "fi->interval.numerator = %d\n",
+ fi->interval.numerator);
+ dev_dbg(dev, "fi->interval.denominator = %d\n",
+ fi->interval.denominator);
+
+ req_fr = (u64)((fi->interval.denominator * USEC_PER_SEC) /
+ fi->interval.numerator);
+
+ if (req_fr >= max_fr && req_fr <= min_fr)
+ req_fr = alvium->dft_fr;
+
+ alvium->fr = req_fr;
+ alvium->frame_interval.numerator = fi->interval.numerator;
+ alvium->frame_interval.denominator = fi->interval.denominator;
+
+ return 0;
+}
+
+static int alvium_s_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+ int ret;
+
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ if (alvium->streaming)
+ return -EBUSY;
+
+ ret = alvium_set_frame_interval(alvium, fi);
+ if (!ret)
+ ret = alvium_set_frame_rate(alvium);
+
+ return ret;
+}
+
+static int alvium_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+
+ if (code->index >= alvium->alvium_csi2_fmt_n)
+ return -EINVAL;
+
+ code->code = alvium->alvium_csi2_fmt[code->index].code;
+
+ return 0;
+}
+
+static const struct alvium_pixfmt *
+alvium_code_to_pixfmt(struct alvium_dev *alvium, u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; alvium->alvium_csi2_fmt[i].code; ++i)
+ if (alvium->alvium_csi2_fmt[i].code == code)
+ return &alvium->alvium_csi2_fmt[i];
+
+ return &alvium->alvium_csi2_fmt[0];
+}
+
+static int alvium_set_mode(struct alvium_dev *alvium,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_rect *crop;
+ int ret;
+
+ crop = v4l2_subdev_state_get_crop(state, 0);
+ fmt = v4l2_subdev_state_get_format(state, 0);
+
+ v4l_bound_align_image(&fmt->width, alvium->img_min_width,
+ alvium->img_max_width, 0,
+ &fmt->height, alvium->img_min_height,
+ alvium->img_max_height, 0, 0);
+
+ /* alvium don't accept negative crop left/top */
+ crop->left = clamp((u32)max(0, crop->left), alvium->min_offx,
+ (u32)(alvium->img_max_width - fmt->width));
+ crop->top = clamp((u32)max(0, crop->top), alvium->min_offy,
+ (u32)(alvium->img_max_height - fmt->height));
+
+ ret = alvium_set_img_width(alvium, fmt->width);
+ if (ret)
+ return ret;
+
+ ret = alvium_set_img_height(alvium, fmt->height);
+ if (ret)
+ return ret;
+
+ ret = alvium_set_img_offx(alvium, crop->left);
+ if (ret)
+ return ret;
+
+ ret = alvium_set_img_offy(alvium, crop->top);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int alvium_set_framefmt(struct alvium_dev *alvium,
+ struct v4l2_mbus_framefmt *format)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ const struct alvium_pixfmt *alvium_csi2_fmt;
+ int ret = 0;
+
+ alvium_csi2_fmt = alvium_code_to_pixfmt(alvium, format->code);
+
+ ret = alvium_set_mipi_fmt(alvium, alvium_csi2_fmt);
+ if (ret)
+ return ret;
+
+ if (alvium_csi2_fmt->is_raw) {
+ ret = alvium_set_bayer_pattern(alvium, alvium_csi2_fmt);
+ if (ret)
+ return ret;
+ }
+
+ dev_dbg(dev, "start: %s, mipi_fmt_regval regval = 0x%llx",
+ __func__, alvium_csi2_fmt->mipi_fmt_regval);
+
+ return ret;
+}
+
+static int alvium_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(&alvium->sd);
+ struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_subdev_state *state;
+ int ret = 0;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ if (enable) {
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
+ goto out;
+
+ ret = __v4l2_ctrl_handler_setup(&alvium->ctrls.handler);
+ if (ret)
+ goto out;
+
+ ret = alvium_set_mode(alvium, state);
+ if (ret)
+ goto out;
+
+ fmt = v4l2_subdev_state_get_format(state, 0);
+ ret = alvium_set_framefmt(alvium, fmt);
+ if (ret)
+ goto out;
+
+ ret = alvium_set_stream_mipi(alvium, enable);
+ if (ret)
+ goto out;
+
+ } else {
+ alvium_set_stream_mipi(alvium, enable);
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+ }
+
+ alvium->streaming = !!enable;
+ v4l2_subdev_unlock_state(state);
+
+ return 0;
+
+out:
+ pm_runtime_put(&client->dev);
+ v4l2_subdev_unlock_state(state);
+ return ret;
+}
+
+static int alvium_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+ struct alvium_mode *mode = &alvium->mode;
+ struct v4l2_subdev_format sd_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ .format = alvium_csi2_default_fmt,
+ };
+ struct v4l2_subdev_crop sd_crop = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ .rect = {
+ .left = mode->crop.left,
+ .top = mode->crop.top,
+ .width = mode->crop.width,
+ .height = mode->crop.height,
+ },
+ };
+
+ *v4l2_subdev_state_get_crop(state, 0) = sd_crop.rect;
+ *v4l2_subdev_state_get_format(state, 0) = sd_fmt.format;
+
+ return 0;
+}
+
+static int alvium_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *format)
+{
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+ const struct alvium_pixfmt *alvium_csi2_fmt;
+ struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_rect *crop;
+
+ fmt = v4l2_subdev_state_get_format(sd_state, 0);
+ crop = v4l2_subdev_state_get_crop(sd_state, 0);
+
+ v4l_bound_align_image(&format->format.width, alvium->img_min_width,
+ alvium->img_max_width, 0,
+ &format->format.height, alvium->img_min_height,
+ alvium->img_max_height, 0, 0);
+
+ /* Adjust left and top to prevent roll over sensor area */
+ crop->left = clamp((u32)crop->left, (u32)0,
+ (alvium->img_max_width - fmt->width));
+ crop->top = clamp((u32)crop->top, (u32)0,
+ (alvium->img_max_height - fmt->height));
+
+ /* Set also the crop width and height when set a new fmt */
+ crop->width = fmt->width;
+ crop->height = fmt->height;
+
+ alvium_csi2_fmt = alvium_code_to_pixfmt(alvium, format->format.code);
+ fmt->code = alvium_csi2_fmt->code;
+
+ *fmt = format->format;
+
+ return 0;
+}
+
+static int alvium_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+ struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_rect *crop;
+
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ crop = v4l2_subdev_state_get_crop(sd_state, 0);
+ fmt = v4l2_subdev_state_get_format(sd_state, 0);
+
+ /*
+ * Alvium can only shift the origin of the img
+ * then we accept only value with the same value of the actual fmt
+ */
+ if (sel->r.width != fmt->width)
+ sel->r.width = fmt->width;
+
+ if (sel->r.height != fmt->height)
+ sel->r.height = fmt->height;
+
+ /* alvium don't accept negative crop left/top */
+ crop->left = clamp((u32)max(0, sel->r.left), alvium->min_offx,
+ alvium->img_max_width - sel->r.width);
+ crop->top = clamp((u32)max(0, sel->r.top), alvium->min_offy,
+ alvium->img_max_height - sel->r.height);
+
+ sel->r = *crop;
+
+ return 0;
+}
+
+static int alvium_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+
+ switch (sel->target) {
+ /* Current cropping area */
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, 0);
+ break;
+ /* Cropping bounds */
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = alvium->img_max_width;
+ sel->r.height = alvium->img_max_height;
+ break;
+ /* Default cropping area */
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.top = alvium->min_offy;
+ sel->r.left = alvium->min_offx;
+ sel->r.width = alvium->img_max_width;
+ sel->r.height = alvium->img_max_height;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int alvium_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+ int val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ val = alvium_get_gain(alvium);
+ if (val < 0)
+ return val;
+ alvium->ctrls.gain->val = val;
+ break;
+ case V4L2_CID_EXPOSURE:
+ val = alvium_get_exposure(alvium);
+ if (val < 0)
+ return val;
+ alvium->ctrls.exposure->val = val;
+ break;
+ }
+
+ return 0;
+}
+
+static int alvium_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(&alvium->sd);
+ int ret;
+
+ /*
+ * Applying V4L2 control value only happens
+ * when power is up for streaming
+ */
+ if (!pm_runtime_get_if_in_use(&client->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ ret = alvium_set_ctrl_gain(alvium, ctrl->val);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ ret = alvium_set_ctrl_auto_gain(alvium, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ret = alvium_set_ctrl_exposure(alvium, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ret = alvium_set_ctrl_auto_exposure(alvium, ctrl->val);
+ break;
+ case V4L2_CID_RED_BALANCE:
+ ret = alvium_set_ctrl_red_balance_ratio(alvium, ctrl->val);
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ ret = alvium_set_ctrl_blue_balance_ratio(alvium, ctrl->val);
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = alvium_set_ctrl_awb(alvium, ctrl->val);
+ break;
+ case V4L2_CID_HUE:
+ ret = alvium_set_ctrl_hue(alvium, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ ret = alvium_set_ctrl_contrast(alvium, ctrl->val);
+ break;
+ case V4L2_CID_SATURATION:
+ ret = alvium_set_ctrl_saturation(alvium, ctrl->val);
+ break;
+ case V4L2_CID_GAMMA:
+ ret = alvium_set_ctrl_gamma(alvium, ctrl->val);
+ break;
+ case V4L2_CID_SHARPNESS:
+ ret = alvium_set_ctrl_sharpness(alvium, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ ret = alvium_set_ctrl_hflip(alvium, ctrl->val);
+ break;
+ case V4L2_CID_VFLIP:
+ ret = alvium_set_ctrl_vflip(alvium, ctrl->val);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops alvium_ctrl_ops = {
+ .g_volatile_ctrl = alvium_g_volatile_ctrl,
+ .s_ctrl = alvium_s_ctrl,
+};
+
+static int alvium_ctrl_init(struct alvium_dev *alvium)
+{
+ const struct v4l2_ctrl_ops *ops = &alvium_ctrl_ops;
+ struct alvium_ctrls *ctrls = &alvium->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+ struct v4l2_fwnode_device_properties props;
+ int ret;
+
+ v4l2_ctrl_handler_init(hdl, 32);
+
+ /* Pixel rate is fixed */
+ ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_PIXEL_RATE, 0,
+ ALVIUM_DEFAULT_PIXEL_RATE_MHZ, 1,
+ ALVIUM_DEFAULT_PIXEL_RATE_MHZ);
+ ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /* Link freq is fixed */
+ ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
+ V4L2_CID_LINK_FREQ,
+ 0, 0, &alvium->link_freq);
+ ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /* Auto/manual white balance */
+ if (alvium->avail_ft.auto_whiteb) {
+ ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 1);
+ v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
+ }
+
+ ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_BLUE_BALANCE,
+ alvium->min_bbalance,
+ alvium->max_bbalance,
+ alvium->inc_bbalance,
+ alvium->dft_bbalance);
+ ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_RED_BALANCE,
+ alvium->min_rbalance,
+ alvium->max_rbalance,
+ alvium->inc_rbalance,
+ alvium->dft_rbalance);
+
+ /* Auto/manual exposure */
+ if (alvium->avail_ft.auto_exp) {
+ ctrls->auto_exp =
+ v4l2_ctrl_new_std_menu(hdl, ops,
+ V4L2_CID_EXPOSURE_AUTO,
+ V4L2_EXPOSURE_MANUAL, 0,
+ V4L2_EXPOSURE_AUTO);
+ v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
+ }
+
+ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_EXPOSURE,
+ alvium->min_exp,
+ alvium->max_exp,
+ alvium->inc_exp,
+ alvium->dft_exp);
+ ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+ /* Auto/manual gain */
+ if (alvium->avail_ft.auto_gain) {
+ ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_AUTOGAIN,
+ 0, 1, 1, 1);
+ v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
+ }
+
+ if (alvium->avail_ft.gain) {
+ ctrls->gain = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_GAIN,
+ alvium->min_gain,
+ alvium->max_gain,
+ alvium->inc_gain,
+ alvium->dft_gain);
+ ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ }
+
+ if (alvium->avail_ft.sat)
+ ctrls->saturation = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_SATURATION,
+ alvium->min_sat,
+ alvium->max_sat,
+ alvium->inc_sat,
+ alvium->dft_sat);
+
+ if (alvium->avail_ft.hue)
+ ctrls->hue = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_HUE,
+ alvium->min_hue,
+ alvium->max_hue,
+ alvium->inc_hue,
+ alvium->dft_hue);
+
+ if (alvium->avail_ft.contrast)
+ ctrls->contrast = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_CONTRAST,
+ alvium->min_contrast,
+ alvium->max_contrast,
+ alvium->inc_contrast,
+ alvium->dft_contrast);
+
+ if (alvium->avail_ft.gamma)
+ ctrls->gamma = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_GAMMA,
+ alvium->min_gamma,
+ alvium->max_gamma,
+ alvium->inc_gamma,
+ alvium->dft_gamma);
+
+ if (alvium->avail_ft.sharp)
+ ctrls->sharpness = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_SHARPNESS,
+ alvium->min_sharp,
+ alvium->max_sharp,
+ alvium->inc_sharp,
+ alvium->dft_sharp);
+
+ if (alvium->avail_ft.rev_x)
+ ctrls->hflip = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+
+ if (alvium->avail_ft.rev_y)
+ ctrls->vflip = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ ret = hdl->error;
+ goto free_ctrls;
+ }
+
+ ret = v4l2_fwnode_device_parse(&alvium->i2c_client->dev, &props);
+ if (ret)
+ goto free_ctrls;
+
+ ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props);
+ if (ret)
+ goto free_ctrls;
+
+ alvium->sd.ctrl_handler = hdl;
+ return 0;
+
+free_ctrls:
+ v4l2_ctrl_handler_free(hdl);
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops alvium_core_ops = {
+ .log_status = v4l2_ctrl_subdev_log_status,
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops alvium_video_ops = {
+ .s_stream = alvium_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops alvium_pad_ops = {
+ .enum_mbus_code = alvium_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = alvium_set_fmt,
+ .get_selection = alvium_get_selection,
+ .set_selection = alvium_set_selection,
+ .get_frame_interval = alvium_g_frame_interval,
+ .set_frame_interval = alvium_s_frame_interval,
+};
+
+static const struct v4l2_subdev_internal_ops alvium_internal_ops = {
+ .init_state = alvium_init_state,
+};
+
+static const struct v4l2_subdev_ops alvium_subdev_ops = {
+ .core = &alvium_core_ops,
+ .pad = &alvium_pad_ops,
+ .video = &alvium_video_ops,
+};
+
+static int alvium_subdev_init(struct alvium_dev *alvium)
+{
+ struct i2c_client *client = alvium->i2c_client;
+ struct device *dev = &alvium->i2c_client->dev;
+ struct v4l2_subdev *sd = &alvium->sd;
+ int ret;
+
+ /* Setup initial frame interval*/
+ alvium->frame_interval.numerator = 1;
+ alvium->frame_interval.denominator = ALVIUM_DEFAULT_FR_HZ;
+ alvium->fr = ALVIUM_DEFAULT_FR_HZ;
+
+ /* Setup the initial mode */
+ alvium->mode.fmt = alvium_csi2_default_fmt;
+ alvium->mode.width = alvium_csi2_default_fmt.width;
+ alvium->mode.height = alvium_csi2_default_fmt.height;
+ alvium->mode.crop.left = alvium->min_offx;
+ alvium->mode.crop.top = alvium->min_offy;
+ alvium->mode.crop.width = alvium_csi2_default_fmt.width;
+ alvium->mode.crop.height = alvium_csi2_default_fmt.height;
+
+ /* init alvium sd */
+ v4l2_i2c_subdev_init(sd, client, &alvium_subdev_ops);
+
+ sd->internal_ops = &alvium_internal_ops;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
+ alvium->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ ret = media_entity_pads_init(&sd->entity, 1, &alvium->pad);
+ if (ret) {
+ dev_err(dev, "Could not register media entity\n");
+ return ret;
+ }
+
+ ret = alvium_ctrl_init(alvium);
+ if (ret) {
+ dev_err(dev, "Control initialization error %d\n", ret);
+ goto entity_cleanup;
+ }
+
+ alvium->sd.state_lock = alvium->ctrls.handler.lock;
+
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret < 0) {
+ dev_err(dev, "subdev initialization error %d\n", ret);
+ goto err_ctrls;
+ }
+
+ return 0;
+
+err_ctrls:
+ v4l2_ctrl_handler_free(&alvium->ctrls.handler);
+entity_cleanup:
+ media_entity_cleanup(&alvium->sd.entity);
+ return ret;
+}
+
+static void alvium_subdev_cleanup(struct alvium_dev *alvium)
+{
+ v4l2_fwnode_endpoint_free(&alvium->ep);
+ v4l2_subdev_cleanup(&alvium->sd);
+ media_entity_cleanup(&alvium->sd.entity);
+ v4l2_ctrl_handler_free(&alvium->ctrls.handler);
+}
+
+static int alvium_get_dt_data(struct alvium_dev *alvium)
+{
+ struct device *dev = &alvium->i2c_client->dev;
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+ struct fwnode_handle *endpoint;
+
+ if (!fwnode)
+ return -EINVAL;
+
+ /* Only CSI2 is supported for now: */
+ alvium->ep.bus_type = V4L2_MBUS_CSI2_DPHY;
+
+ endpoint = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0);
+ if (!endpoint) {
+ dev_err(dev, "endpoint node not found\n");
+ return -EINVAL;
+ }
+
+ if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &alvium->ep)) {
+ dev_err(dev, "could not parse endpoint\n");
+ goto error_out;
+ }
+
+ if (!alvium->ep.nr_of_link_frequencies) {
+ dev_err(dev, "no link frequencies defined");
+ goto error_out;
+ }
+
+ return 0;
+
+error_out:
+ v4l2_fwnode_endpoint_free(&alvium->ep);
+ fwnode_handle_put(endpoint);
+
+ return -EINVAL;
+}
+
+static int alvium_set_power(struct alvium_dev *alvium, bool on)
+{
+ int ret;
+
+ if (!on)
+ return regulator_disable(alvium->reg_vcc);
+
+ ret = regulator_enable(alvium->reg_vcc);
+ if (ret)
+ return ret;
+
+ /* alvium boot time 7s */
+ msleep(7000);
+ return 0;
+}
+
+static int alvium_runtime_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+ int ret;
+
+ ret = alvium_set_power(alvium, true);
+ if (ret)
+ return ret;
+
+ ret = alvium_hw_init(alvium);
+ if (ret) {
+ alvium_set_power(alvium, false);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int alvium_runtime_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+
+ alvium_set_power(alvium, false);
+
+ return 0;
+}
+
+static const struct dev_pm_ops alvium_pm_ops = {
+ RUNTIME_PM_OPS(alvium_runtime_suspend, alvium_runtime_resume, NULL)
+};
+
+static int alvium_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct alvium_dev *alvium;
+ int ret;
+
+ alvium = devm_kzalloc(dev, sizeof(*alvium), GFP_KERNEL);
+ if (!alvium)
+ return -ENOMEM;
+
+ alvium->i2c_client = client;
+
+ alvium->regmap = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(alvium->regmap))
+ return PTR_ERR(alvium->regmap);
+
+ ret = alvium_get_dt_data(alvium);
+ if (ret)
+ return ret;
+
+ alvium->reg_vcc = devm_regulator_get_optional(dev, "vcc-ext-in");
+ if (IS_ERR(alvium->reg_vcc))
+ return dev_err_probe(dev, PTR_ERR(alvium->reg_vcc),
+ "no vcc-ext-in regulator provided\n");
+
+ ret = alvium_set_power(alvium, true);
+ if (ret)
+ goto err_powerdown;
+
+ if (!alvium_is_alive(alvium)) {
+ ret = -ENODEV;
+ dev_err_probe(dev, ret, "Device detection failed\n");
+ goto err_powerdown;
+ }
+
+ ret = alvium_get_hw_info(alvium);
+ if (ret) {
+ dev_err_probe(dev, ret, "get_hw_info fail\n");
+ goto err_powerdown;
+ }
+
+ ret = alvium_hw_init(alvium);
+ if (ret) {
+ dev_err_probe(dev, ret, "hw_init fail\n");
+ goto err_powerdown;
+ }
+
+ ret = alvium_setup_mipi_fmt(alvium);
+ if (ret) {
+ dev_err_probe(dev, ret, "setup_mipi_fmt fail\n");
+ goto err_powerdown;
+ }
+
+ /*
+ * Enable runtime PM without autosuspend:
+ *
+ * Don't use pm autosuspend (alvium have ~7s boot time).
+ * Alvium has been powered manually:
+ * - mark it as active
+ * - increase the usage count without resuming the device.
+ */
+ pm_runtime_set_active(dev);
+ pm_runtime_get_noresume(dev);
+ pm_runtime_enable(dev);
+
+ /* Initialize the V4L2 subdev. */
+ ret = alvium_subdev_init(alvium);
+ if (ret)
+ goto err_pm;
+
+ ret = v4l2_async_register_subdev(&alvium->sd);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "Could not register v4l2 device\n");
+ goto err_subdev;
+ }
+
+ return 0;
+
+err_subdev:
+ alvium_subdev_cleanup(alvium);
+err_pm:
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
+ kfree(alvium->alvium_csi2_fmt);
+err_powerdown:
+ alvium_set_power(alvium, false);
+
+ return ret;
+}
+
+static void alvium_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+ struct device *dev = &alvium->i2c_client->dev;
+
+ v4l2_async_unregister_subdev(sd);
+ alvium_subdev_cleanup(alvium);
+ kfree(alvium->alvium_csi2_fmt);
+ /*
+ * Disable runtime PM. In case runtime PM is disabled in the kernel,
+ * make sure to turn power off manually.
+ */
+ pm_runtime_disable(dev);
+ if (!pm_runtime_status_suspended(dev))
+ alvium_set_power(alvium, false);
+ pm_runtime_set_suspended(dev);
+}
+
+static const struct of_device_id alvium_of_ids[] = {
+ { .compatible = "alliedvision,alvium-csi2", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, alvium_of_ids);
+
+static struct i2c_driver alvium_i2c_driver = {
+ .driver = {
+ .name = "alvium-csi2",
+ .pm = pm_ptr(&alvium_pm_ops),
+ .of_match_table = alvium_of_ids,
+ },
+ .probe = alvium_probe,
+ .remove = alvium_remove,
+};
+
+module_i2c_driver(alvium_i2c_driver);
+
+MODULE_DESCRIPTION("Allied Vision's Alvium Camera Driver");
+MODULE_AUTHOR("Tommaso Merciai <[email protected]>");
+MODULE_AUTHOR("Martin Hecht <[email protected]>");
+MODULE_AUTHOR("Avnet Silica Software & Services EMEA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/alvium-csi2.h b/drivers/media/i2c/alvium-csi2.h
new file mode 100644
index 000000000000..b85a25169e79
--- /dev/null
+++ b/drivers/media/i2c/alvium-csi2.h
@@ -0,0 +1,475 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Allied Vision Technologies GmbH Alvium camera driver
+ *
+ * Copyright (C) 2023 Tommaso Merciai
+ * Copyright (C) 2023 Martin Hecht
+ * Copyright (C) 2023 Avnet EMG GmbH
+ */
+
+#ifndef ALVIUM_CSI2_H_
+#define ALVIUM_CSI2_H_
+
+#include <linux/kernel.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-cci.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define REG_BCRM_V4L2 BIT(31)
+
+#define REG_BCRM_V4L2_8BIT(n) (REG_BCRM_V4L2 | CCI_REG8(n))
+#define REG_BCRM_V4L2_16BIT(n) (REG_BCRM_V4L2 | CCI_REG16(n))
+#define REG_BCRM_V4L2_32BIT(n) (REG_BCRM_V4L2 | CCI_REG32(n))
+#define REG_BCRM_V4L2_64BIT(n) (REG_BCRM_V4L2 | CCI_REG64(n))
+
+/* Basic Control Register Map register offsets (BCRM) */
+#define REG_BCRM_MINOR_VERSION_R CCI_REG16(0x0000)
+#define REG_BCRM_MAJOR_VERSION_R CCI_REG16(0x0002)
+#define REG_BCRM_REG_ADDR_R CCI_REG16(0x0014)
+
+#define REG_BCRM_FEATURE_INQUIRY_R REG_BCRM_V4L2_64BIT(0x0008)
+#define REG_BCRM_DEVICE_FW_SPEC_VERSION_R REG_BCRM_V4L2_8BIT(0x0010)
+#define REG_BCRM_DEVICE_FW_MAJOR_VERSION_R REG_BCRM_V4L2_8BIT(0x0011)
+#define REG_BCRM_DEVICE_FW_MINOR_VERSION_R REG_BCRM_V4L2_16BIT(0x0012)
+#define REG_BCRM_DEVICE_FW_PATCH_VERSION_R REG_BCRM_V4L2_32BIT(0x0014)
+#define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0018)
+
+/* Streaming Control Registers */
+#define REG_BCRM_SUPPORTED_CSI2_LANE_COUNTS_R REG_BCRM_V4L2_8BIT(0x0040)
+#define REG_BCRM_CSI2_LANE_COUNT_RW REG_BCRM_V4L2_8BIT(0x0044)
+#define REG_BCRM_CSI2_CLOCK_MIN_R REG_BCRM_V4L2_32BIT(0x0048)
+#define REG_BCRM_CSI2_CLOCK_MAX_R REG_BCRM_V4L2_32BIT(0x004c)
+#define REG_BCRM_CSI2_CLOCK_RW REG_BCRM_V4L2_32BIT(0x0050)
+#define REG_BCRM_BUFFER_SIZE_R REG_BCRM_V4L2_32BIT(0x0054)
+
+#define REG_BCRM_IPU_X_MIN_W REG_BCRM_V4L2_32BIT(0x0058)
+#define REG_BCRM_IPU_X_MAX_W REG_BCRM_V4L2_32BIT(0x005c)
+#define REG_BCRM_IPU_X_INC_W REG_BCRM_V4L2_32BIT(0x0060)
+#define REG_BCRM_IPU_Y_MIN_W REG_BCRM_V4L2_32BIT(0x0064)
+#define REG_BCRM_IPU_Y_MAX_W REG_BCRM_V4L2_32BIT(0x0068)
+#define REG_BCRM_IPU_Y_INC_W REG_BCRM_V4L2_32BIT(0x006c)
+#define REG_BCRM_IPU_X_R REG_BCRM_V4L2_32BIT(0x0070)
+#define REG_BCRM_IPU_Y_R REG_BCRM_V4L2_32BIT(0x0074)
+
+#define REG_BCRM_PHY_RESET_RW REG_BCRM_V4L2_8BIT(0x0078)
+#define REG_BCRM_LP2HS_DELAY_RW REG_BCRM_V4L2_32BIT(0x007c)
+
+/* Acquisition Control Registers */
+#define REG_BCRM_ACQUISITION_START_RW REG_BCRM_V4L2_8BIT(0x0080)
+#define REG_BCRM_ACQUISITION_STOP_RW REG_BCRM_V4L2_8BIT(0x0084)
+#define REG_BCRM_ACQUISITION_ABORT_RW REG_BCRM_V4L2_8BIT(0x0088)
+#define REG_BCRM_ACQUISITION_STATUS_R REG_BCRM_V4L2_8BIT(0x008c)
+#define REG_BCRM_ACQUISITION_FRAME_RATE_RW REG_BCRM_V4L2_64BIT(0x0090)
+#define REG_BCRM_ACQUISITION_FRAME_RATE_MIN_R REG_BCRM_V4L2_64BIT(0x0098)
+#define REG_BCRM_ACQUISITION_FRAME_RATE_MAX_R REG_BCRM_V4L2_64BIT(0x00a0)
+#define REG_BCRM_ACQUISITION_FRAME_RATE_INC_R REG_BCRM_V4L2_64BIT(0x00a8)
+#define REG_BCRM_ACQUISITION_FRAME_RATE_ENABLE_RW REG_BCRM_V4L2_8BIT(0x00b0)
+
+#define REG_BCRM_FRAME_START_TRIGGER_MODE_RW REG_BCRM_V4L2_8BIT(0x00b4)
+#define REG_BCRM_FRAME_START_TRIGGER_SOURCE_RW REG_BCRM_V4L2_8BIT(0x00b8)
+#define REG_BCRM_FRAME_START_TRIGGER_ACTIVATION_RW REG_BCRM_V4L2_8BIT(0x00bc)
+#define REG_BCRM_FRAME_START_TRIGGER_SOFTWARE_W REG_BCRM_V4L2_8BIT(0x00c0)
+#define REG_BCRM_FRAME_START_TRIGGER_DELAY_RW REG_BCRM_V4L2_32BIT(0x00c4)
+#define REG_BCRM_EXPOSURE_ACTIVE_LINE_MODE_RW REG_BCRM_V4L2_8BIT(0x00c8)
+#define REG_BCRM_EXPOSURE_ACTIVE_LINE_SELECTOR_RW REG_BCRM_V4L2_8BIT(0x00cc)
+#define REG_BCRM_LINE_CONFIGURATION_RW REG_BCRM_V4L2_32BIT(0x00d0)
+
+#define REG_BCRM_IMG_WIDTH_RW REG_BCRM_V4L2_32BIT(0x0100)
+#define REG_BCRM_IMG_WIDTH_MIN_R REG_BCRM_V4L2_32BIT(0x0104)
+#define REG_BCRM_IMG_WIDTH_MAX_R REG_BCRM_V4L2_32BIT(0x0108)
+#define REG_BCRM_IMG_WIDTH_INC_R REG_BCRM_V4L2_32BIT(0x010c)
+
+#define REG_BCRM_IMG_HEIGHT_RW REG_BCRM_V4L2_32BIT(0x0110)
+#define REG_BCRM_IMG_HEIGHT_MIN_R REG_BCRM_V4L2_32BIT(0x0114)
+#define REG_BCRM_IMG_HEIGHT_MAX_R REG_BCRM_V4L2_32BIT(0x0118)
+#define REG_BCRM_IMG_HEIGHT_INC_R REG_BCRM_V4L2_32BIT(0x011c)
+
+#define REG_BCRM_IMG_OFFSET_X_RW REG_BCRM_V4L2_32BIT(0x0120)
+#define REG_BCRM_IMG_OFFSET_X_MIN_R REG_BCRM_V4L2_32BIT(0x0124)
+#define REG_BCRM_IMG_OFFSET_X_MAX_R REG_BCRM_V4L2_32BIT(0x0128)
+#define REG_BCRM_IMG_OFFSET_X_INC_R REG_BCRM_V4L2_32BIT(0x012c)
+
+#define REG_BCRM_IMG_OFFSET_Y_RW REG_BCRM_V4L2_32BIT(0x0130)
+#define REG_BCRM_IMG_OFFSET_Y_MIN_R REG_BCRM_V4L2_32BIT(0x0134)
+#define REG_BCRM_IMG_OFFSET_Y_MAX_R REG_BCRM_V4L2_32BIT(0x0138)
+#define REG_BCRM_IMG_OFFSET_Y_INC_R REG_BCRM_V4L2_32BIT(0x013c)
+
+#define REG_BCRM_IMG_MIPI_DATA_FORMAT_RW REG_BCRM_V4L2_32BIT(0x0140)
+#define REG_BCRM_IMG_AVAILABLE_MIPI_DATA_FORMATS_R REG_BCRM_V4L2_64BIT(0x0148)
+#define REG_BCRM_IMG_BAYER_PATTERN_INQUIRY_R REG_BCRM_V4L2_8BIT(0x0150)
+#define REG_BCRM_IMG_BAYER_PATTERN_RW REG_BCRM_V4L2_8BIT(0x0154)
+#define REG_BCRM_IMG_REVERSE_X_RW REG_BCRM_V4L2_8BIT(0x0158)
+#define REG_BCRM_IMG_REVERSE_Y_RW REG_BCRM_V4L2_8BIT(0x015c)
+
+#define REG_BCRM_SENSOR_WIDTH_R REG_BCRM_V4L2_32BIT(0x0160)
+#define REG_BCRM_SENSOR_HEIGHT_R REG_BCRM_V4L2_32BIT(0x0164)
+#define REG_BCRM_WIDTH_MAX_R REG_BCRM_V4L2_32BIT(0x0168)
+#define REG_BCRM_HEIGHT_MAX_R REG_BCRM_V4L2_32BIT(0x016c)
+
+#define REG_BCRM_EXPOSURE_TIME_RW REG_BCRM_V4L2_64BIT(0x0180)
+#define REG_BCRM_EXPOSURE_TIME_MIN_R REG_BCRM_V4L2_64BIT(0x0188)
+#define REG_BCRM_EXPOSURE_TIME_MAX_R REG_BCRM_V4L2_64BIT(0x0190)
+#define REG_BCRM_EXPOSURE_TIME_INC_R REG_BCRM_V4L2_64BIT(0x0198)
+#define REG_BCRM_EXPOSURE_AUTO_RW REG_BCRM_V4L2_8BIT(0x01a0)
+
+#define REG_BCRM_INTENSITY_AUTO_PRECEDENCE_RW REG_BCRM_V4L2_8BIT(0x01a4)
+#define REG_BCRM_INTENSITY_AUTO_PRECEDENCE_VALUE_RW REG_BCRM_V4L2_32BIT(0x01a8)
+#define REG_BCRM_INTENSITY_AUTO_PRECEDENCE_MIN_R REG_BCRM_V4L2_32BIT(0x01ac)
+#define REG_BCRM_INTENSITY_AUTO_PRECEDENCE_MAX_R REG_BCRM_V4L2_32BIT(0x01b0)
+#define REG_BCRM_INTENSITY_AUTO_PRECEDENCE_INC_R REG_BCRM_V4L2_32BIT(0x01b4)
+
+#define REG_BCRM_BLACK_LEVEL_RW REG_BCRM_V4L2_32BIT(0x01b8)
+#define REG_BCRM_BLACK_LEVEL_MIN_R REG_BCRM_V4L2_32BIT(0x01bc)
+#define REG_BCRM_BLACK_LEVEL_MAX_R REG_BCRM_V4L2_32BIT(0x01c0)
+#define REG_BCRM_BLACK_LEVEL_INC_R REG_BCRM_V4L2_32BIT(0x01c4)
+
+#define REG_BCRM_GAIN_RW REG_BCRM_V4L2_64BIT(0x01c8)
+#define REG_BCRM_GAIN_MIN_R REG_BCRM_V4L2_64BIT(0x01d0)
+#define REG_BCRM_GAIN_MAX_R REG_BCRM_V4L2_64BIT(0x01d8)
+#define REG_BCRM_GAIN_INC_R REG_BCRM_V4L2_64BIT(0x01e0)
+#define REG_BCRM_GAIN_AUTO_RW REG_BCRM_V4L2_8BIT(0x01e8)
+
+#define REG_BCRM_GAMMA_RW REG_BCRM_V4L2_64BIT(0x01f0)
+#define REG_BCRM_GAMMA_MIN_R REG_BCRM_V4L2_64BIT(0x01f8)
+#define REG_BCRM_GAMMA_MAX_R REG_BCRM_V4L2_64BIT(0x0200)
+#define REG_BCRM_GAMMA_INC_R REG_BCRM_V4L2_64BIT(0x0208)
+
+#define REG_BCRM_CONTRAST_VALUE_RW REG_BCRM_V4L2_32BIT(0x0214)
+#define REG_BCRM_CONTRAST_VALUE_MIN_R REG_BCRM_V4L2_32BIT(0x0218)
+#define REG_BCRM_CONTRAST_VALUE_MAX_R REG_BCRM_V4L2_32BIT(0x021c)
+#define REG_BCRM_CONTRAST_VALUE_INC_R REG_BCRM_V4L2_32BIT(0x0220)
+
+#define REG_BCRM_SATURATION_RW REG_BCRM_V4L2_32BIT(0x0240)
+#define REG_BCRM_SATURATION_MIN_R REG_BCRM_V4L2_32BIT(0x0244)
+#define REG_BCRM_SATURATION_MAX_R REG_BCRM_V4L2_32BIT(0x0248)
+#define REG_BCRM_SATURATION_INC_R REG_BCRM_V4L2_32BIT(0x024c)
+
+#define REG_BCRM_HUE_RW REG_BCRM_V4L2_32BIT(0x0250)
+#define REG_BCRM_HUE_MIN_R REG_BCRM_V4L2_32BIT(0x0254)
+#define REG_BCRM_HUE_MAX_R REG_BCRM_V4L2_32BIT(0x0258)
+#define REG_BCRM_HUE_INC_R REG_BCRM_V4L2_32BIT(0x025c)
+
+#define REG_BCRM_ALL_BALANCE_RATIO_RW REG_BCRM_V4L2_64BIT(0x0260)
+#define REG_BCRM_ALL_BALANCE_RATIO_MIN_R REG_BCRM_V4L2_64BIT(0x0268)
+#define REG_BCRM_ALL_BALANCE_RATIO_MAX_R REG_BCRM_V4L2_64BIT(0x0270)
+#define REG_BCRM_ALL_BALANCE_RATIO_INC_R REG_BCRM_V4L2_64BIT(0x0278)
+
+#define REG_BCRM_RED_BALANCE_RATIO_RW REG_BCRM_V4L2_64BIT(0x0280)
+#define REG_BCRM_RED_BALANCE_RATIO_MIN_R REG_BCRM_V4L2_64BIT(0x0288)
+#define REG_BCRM_RED_BALANCE_RATIO_MAX_R REG_BCRM_V4L2_64BIT(0x0290)
+#define REG_BCRM_RED_BALANCE_RATIO_INC_R REG_BCRM_V4L2_64BIT(0x0298)
+
+#define REG_BCRM_GREEN_BALANCE_RATIO_RW REG_BCRM_V4L2_64BIT(0x02a0)
+#define REG_BCRM_GREEN_BALANCE_RATIO_MIN_R REG_BCRM_V4L2_64BIT(0x02a8)
+#define REG_BCRM_GREEN_BALANCE_RATIO_MAX_R REG_BCRM_V4L2_64BIT(0x02b0)
+#define REG_BCRM_GREEN_BALANCE_RATIO_INC_R REG_BCRM_V4L2_64BIT(0x02b8)
+
+#define REG_BCRM_BLUE_BALANCE_RATIO_RW REG_BCRM_V4L2_64BIT(0x02c0)
+#define REG_BCRM_BLUE_BALANCE_RATIO_MIN_R REG_BCRM_V4L2_64BIT(0x02c8)
+#define REG_BCRM_BLUE_BALANCE_RATIO_MAX_R REG_BCRM_V4L2_64BIT(0x02d0)
+#define REG_BCRM_BLUE_BALANCE_RATIO_INC_R REG_BCRM_V4L2_64BIT(0x02d8)
+
+#define REG_BCRM_WHITE_BALANCE_AUTO_RW REG_BCRM_V4L2_8BIT(0x02e0)
+#define REG_BCRM_SHARPNESS_RW REG_BCRM_V4L2_32BIT(0x0300)
+#define REG_BCRM_SHARPNESS_MIN_R REG_BCRM_V4L2_32BIT(0x0304)
+#define REG_BCRM_SHARPNESS_MAX_R REG_BCRM_V4L2_32BIT(0x0308)
+#define REG_BCRM_SHARPNESS_INC_R REG_BCRM_V4L2_32BIT(0x030c)
+
+#define REG_BCRM_DEVICE_TEMPERATURE_R REG_BCRM_V4L2_32BIT(0x0310)
+#define REG_BCRM_EXPOSURE_AUTO_MIN_RW REG_BCRM_V4L2_64BIT(0x0330)
+#define REG_BCRM_EXPOSURE_AUTO_MAX_RW REG_BCRM_V4L2_64BIT(0x0338)
+#define REG_BCRM_GAIN_AUTO_MIN_RW REG_BCRM_V4L2_64BIT(0x0340)
+#define REG_BCRM_GAIN_AUTO_MAX_RW REG_BCRM_V4L2_64BIT(0x0348)
+
+/* Heartbeat reg*/
+#define REG_BCRM_HEARTBEAT_RW CCI_REG8(0x021f)
+
+/* GenCP Registers */
+#define REG_GENCP_CHANGEMODE_W CCI_REG8(0x021c)
+#define REG_GENCP_CURRENTMODE_R CCI_REG8(0x021d)
+#define REG_GENCP_IN_HANDSHAKE_RW CCI_REG8(0x001c)
+#define REG_GENCP_OUT_SIZE_W CCI_REG16(0x0020)
+#define REG_GENCP_IN_SIZE_R CCI_REG16(0x0024)
+
+/* defines */
+#define REG_BCRM_HANDSHAKE_STATUS_MASK 0x01
+#define REG_BCRM_HANDSHAKE_AVAILABLE_MASK 0x80
+
+#define BCRM_HANDSHAKE_W_DONE_EN_BIT BIT(0)
+
+#define ALVIUM_DEFAULT_FR_HZ 10
+#define ALVIUM_DEFAULT_PIXEL_RATE_MHZ 148000000
+
+#define ALVIUM_LP2HS_DELAY_MS 100
+
+enum alvium_bcrm_mode {
+ ALVIUM_BCM_MODE,
+ ALVIUM_GENCP_MODE,
+ ALVIUM_NUM_MODE
+};
+
+enum alvium_mipi_fmt {
+ ALVIUM_FMT_UYVY8_2X8 = 0,
+ ALVIUM_FMT_UYVY8_1X16,
+ ALVIUM_FMT_YUYV8_1X16,
+ ALVIUM_FMT_YUYV8_2X8,
+ ALVIUM_FMT_YUYV10_1X20,
+ ALVIUM_FMT_RGB888_1X24,
+ ALVIUM_FMT_RBG888_1X24,
+ ALVIUM_FMT_BGR888_1X24,
+ ALVIUM_FMT_RGB888_3X8,
+ ALVIUM_FMT_Y8_1X8,
+ ALVIUM_FMT_SGRBG8_1X8,
+ ALVIUM_FMT_SRGGB8_1X8,
+ ALVIUM_FMT_SGBRG8_1X8,
+ ALVIUM_FMT_SBGGR8_1X8,
+ ALVIUM_FMT_Y10_1X10,
+ ALVIUM_FMT_SGRBG10_1X10,
+ ALVIUM_FMT_SRGGB10_1X10,
+ ALVIUM_FMT_SGBRG10_1X10,
+ ALVIUM_FMT_SBGGR10_1X10,
+ ALVIUM_FMT_Y12_1X12,
+ ALVIUM_FMT_SGRBG12_1X12,
+ ALVIUM_FMT_SRGGB12_1X12,
+ ALVIUM_FMT_SGBRG12_1X12,
+ ALVIUM_FMT_SBGGR12_1X12,
+ ALVIUM_FMT_SBGGR14_1X14,
+ ALVIUM_FMT_SGBRG14_1X14,
+ ALVIUM_FMT_SRGGB14_1X14,
+ ALVIUM_FMT_SGRBG14_1X14,
+ ALVIUM_NUM_SUPP_MIPI_DATA_FMT
+};
+
+enum alvium_av_bayer_bit {
+ ALVIUM_BIT_BAY_NONE = -1,
+ ALVIUM_BIT_BAY_MONO = 0,
+ ALVIUM_BIT_BAY_GR,
+ ALVIUM_BIT_BAY_RG,
+ ALVIUM_BIT_BAY_GB,
+ ALVIUM_BIT_BAY_BG,
+ ALVIUM_NUM_BAY_AV_BIT
+};
+
+enum alvium_av_mipi_bit {
+ ALVIUM_BIT_YUV420_8_LEG = 0,
+ ALVIUM_BIT_YUV420_8,
+ ALVIUM_BIT_YUV420_10,
+ ALVIUM_BIT_YUV420_8_CSPS,
+ ALVIUM_BIT_YUV420_10_CSPS,
+ ALVIUM_BIT_YUV422_8,
+ ALVIUM_BIT_YUV422_10,
+ ALVIUM_BIT_RGB888,
+ ALVIUM_BIT_RGB666,
+ ALVIUM_BIT_RGB565,
+ ALVIUM_BIT_RGB555,
+ ALVIUM_BIT_RGB444,
+ ALVIUM_BIT_RAW6,
+ ALVIUM_BIT_RAW7,
+ ALVIUM_BIT_RAW8,
+ ALVIUM_BIT_RAW10,
+ ALVIUM_BIT_RAW12,
+ ALVIUM_BIT_RAW14,
+ ALVIUM_BIT_JPEG,
+ ALVIUM_NUM_SUPP_MIPI_DATA_BIT
+};
+
+struct alvium_avail_feat {
+ u64 rev_x:1;
+ u64 rev_y:1;
+ u64 int_autop:1;
+ u64 black_lvl:1;
+ u64 gain:1;
+ u64 gamma:1;
+ u64 contrast:1;
+ u64 sat:1;
+ u64 hue:1;
+ u64 whiteb:1;
+ u64 sharp:1;
+ u64 auto_exp:1;
+ u64 auto_gain:1;
+ u64 auto_whiteb:1;
+ u64 dev_temp:1;
+ u64 acq_abort:1;
+ u64 acq_fr:1;
+ u64 fr_trigger:1;
+ u64 exp_acq_line:1;
+ u64 reserved:45;
+};
+
+struct alvium_avail_mipi_fmt {
+ u64 yuv420_8_leg:1;
+ u64 yuv420_8:1;
+ u64 yuv420_10:1;
+ u64 yuv420_8_csps:1;
+ u64 yuv420_10_csps:1;
+ u64 yuv422_8:1;
+ u64 yuv422_10:1;
+ u64 rgb888:1;
+ u64 rgb666:1;
+ u64 rgb565:1;
+ u64 rgb555:1;
+ u64 rgb444:1;
+ u64 raw6:1;
+ u64 raw7:1;
+ u64 raw8:1;
+ u64 raw10:1;
+ u64 raw12:1;
+ u64 raw14:1;
+ u64 jpeg:1;
+ u64 reserved:45;
+};
+
+struct alvium_avail_bayer {
+ u8 mono:1;
+ u8 gr:1;
+ u8 rg:1;
+ u8 gb:1;
+ u8 bg:1;
+ u8 reserved:3;
+};
+
+struct alvium_mode {
+ struct v4l2_rect crop;
+ struct v4l2_mbus_framefmt fmt;
+ u32 width;
+ u32 height;
+};
+
+struct alvium_pixfmt {
+ u32 code;
+ u32 colorspace;
+ u64 mipi_fmt_regval;
+ u64 bay_fmt_regval;
+ u8 id;
+ u8 is_raw;
+ u8 fmt_av_bit;
+ u8 bay_av_bit;
+};
+
+struct alvium_ctrls {
+ struct v4l2_ctrl_handler handler;
+ struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *auto_exp;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *auto_wb;
+ struct v4l2_ctrl *blue_balance;
+ struct v4l2_ctrl *red_balance;
+ struct v4l2_ctrl *auto_gain;
+ struct v4l2_ctrl *gain;
+ struct v4l2_ctrl *saturation;
+ struct v4l2_ctrl *hue;
+ struct v4l2_ctrl *contrast;
+ struct v4l2_ctrl *gamma;
+ struct v4l2_ctrl *sharpness;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+};
+
+struct alvium_dev {
+ struct i2c_client *i2c_client;
+ struct v4l2_subdev sd;
+ struct v4l2_fwnode_endpoint ep;
+ struct media_pad pad;
+ struct regmap *regmap;
+
+ struct regulator *reg_vcc;
+
+ u16 bcrm_addr;
+
+ struct alvium_avail_feat avail_ft;
+ u8 is_mipi_fmt_avail[ALVIUM_NUM_SUPP_MIPI_DATA_BIT];
+ u8 is_bay_avail[ALVIUM_NUM_BAY_AV_BIT];
+
+ u32 min_csi_clk;
+ u32 max_csi_clk;
+ u32 dft_img_width;
+ u32 img_min_width;
+ u32 img_max_width;
+ u32 img_inc_width;
+ u32 dft_img_height;
+ u32 img_min_height;
+ u32 img_max_height;
+ u32 img_inc_height;
+ u32 min_offx;
+ u32 max_offx;
+ u32 inc_offx;
+ u32 min_offy;
+ u32 max_offy;
+ u32 inc_offy;
+ u64 dft_gain;
+ u64 min_gain;
+ u64 max_gain;
+ u64 inc_gain;
+ u64 dft_exp;
+ u64 min_exp;
+ u64 max_exp;
+ u64 inc_exp;
+ u64 dft_rbalance;
+ u64 min_rbalance;
+ u64 max_rbalance;
+ u64 inc_rbalance;
+ u64 dft_bbalance;
+ u64 min_bbalance;
+ u64 max_bbalance;
+ u64 inc_bbalance;
+ s32 dft_hue;
+ s32 min_hue;
+ s32 max_hue;
+ s32 inc_hue;
+ u32 dft_contrast;
+ u32 min_contrast;
+ u32 max_contrast;
+ u32 inc_contrast;
+ u32 dft_sat;
+ u32 min_sat;
+ u32 max_sat;
+ u32 inc_sat;
+ s32 dft_black_lvl;
+ s32 min_black_lvl;
+ s32 max_black_lvl;
+ s32 inc_black_lvl;
+ u64 dft_gamma;
+ u64 min_gamma;
+ u64 max_gamma;
+ u64 inc_gamma;
+ s32 dft_sharp;
+ s32 min_sharp;
+ s32 max_sharp;
+ s32 inc_sharp;
+
+ struct alvium_mode mode;
+ struct v4l2_fract frame_interval;
+ u64 dft_fr;
+ u64 min_fr;
+ u64 max_fr;
+ u64 fr;
+
+ u8 h_sup_csi_lanes;
+ u64 link_freq;
+
+ struct alvium_ctrls ctrls;
+
+ u8 bcrm_mode;
+
+ struct alvium_pixfmt *alvium_csi2_fmt;
+ u8 alvium_csi2_fmt_n;
+
+ u8 streaming;
+ u8 apply_fiv;
+};
+
+static inline struct alvium_dev *sd_to_alvium(struct v4l2_subdev *sd)
+{
+ return container_of_const(sd, struct alvium_dev, sd);
+}
+
+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of_const(ctrl->handler, struct alvium_dev,
+ ctrls.handler)->sd;
+}
+#endif /* ALVIUM_CSI2_H_ */
diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c
index 701f36345f1e..c7d5fa532ae1 100644
--- a/drivers/media/i2c/ar0521.c
+++ b/drivers/media/i2c/ar0521.c
@@ -446,8 +446,7 @@ static int ar0521_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&sensor->lock);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state, 0
- /* pad */);
+ fmt = v4l2_subdev_state_get_format(sd_state, 0);
else
fmt = &sensor->fmt;
@@ -472,7 +471,7 @@ static int ar0521_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, sd_state, 0 /* pad */);
+ fmt = v4l2_subdev_state_get_format(sd_state, 0);
*fmt = format->format;
mutex_unlock(&sensor->lock);
diff --git a/drivers/media/i2c/ccs/Kconfig b/drivers/media/i2c/ccs/Kconfig
index b55c93a2e204..710a729ae42d 100644
--- a/drivers/media/i2c/ccs/Kconfig
+++ b/drivers/media/i2c/ccs/Kconfig
@@ -2,6 +2,7 @@
config VIDEO_CCS
tristate "MIPI CCS/SMIA++/SMIA sensor support"
depends on HAVE_CLK
+ select V4L2_CCI_I2C
select VIDEO_CCS_PLL
help
This is a generic driver for MIPI CCS, SMIA++ and SMIA compliant
diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c
index 12e6f0a26fc8..e21287d50c15 100644
--- a/drivers/media/i2c/ccs/ccs-core.c
+++ b/drivers/media/i2c/ccs/ccs-core.c
@@ -25,8 +25,9 @@
#include <linux/slab.h>
#include <linux/smiapp.h>
#include <linux/v4l2-mediabus.h>
-#include <media/v4l2-fwnode.h>
+#include <media/v4l2-cci.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
#include <uapi/linux/ccs.h>
#include "ccs.h"
@@ -98,7 +99,7 @@ static int ccs_limit_ptr(struct ccs_sensor *sensor, unsigned int limit,
linfo = &ccs_limits[ccs_limit_offsets[limit].info];
if (WARN_ON(!sensor->ccs_limits) ||
- WARN_ON(offset + ccs_reg_width(linfo->reg) >
+ WARN_ON(offset + CCI_REG_WIDTH_BYTES(linfo->reg) >
ccs_limit_offsets[limit + 1].lim))
return -EINVAL;
@@ -124,7 +125,7 @@ void ccs_replace_limit(struct ccs_sensor *sensor,
dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %u, 0x%x\n",
linfo->reg, linfo->name, offset, val, val);
- ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val);
+ ccs_assign_limit(ptr, CCI_REG_WIDTH_BYTES(linfo->reg), val);
}
u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit,
@@ -138,7 +139,7 @@ u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit,
if (ret)
return 0;
- switch (ccs_reg_width(ccs_limits[ccs_limit_offsets[limit].info].reg)) {
+ switch (CCI_REG_WIDTH_BYTES(ccs_limits[ccs_limit_offsets[limit].info].reg)) {
case sizeof(u8):
val = *(u8 *)ptr;
break;
@@ -172,9 +173,11 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor)
end = alloc + ccs_limit_offsets[CCS_L_LAST].lim;
+ sensor->ccs_limits = alloc;
+
for (i = 0, l = 0, ptr = alloc; ccs_limits[i].size; i++) {
u32 reg = ccs_limits[i].reg;
- unsigned int width = ccs_reg_width(reg);
+ unsigned int width = CCI_REG_WIDTH_BYTES(reg);
unsigned int j;
if (l == CCS_L_LAST) {
@@ -186,6 +189,7 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor)
for (j = 0; j < ccs_limits[i].size / width;
j++, reg += width, ptr += width) {
+ char str[16] = "";
u32 val;
ret = ccs_read_addr_noconv(sensor, reg, &val);
@@ -204,8 +208,15 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor)
ccs_assign_limit(ptr, width, val);
- dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n",
- reg, ccs_limits[i].name, val, val);
+#ifdef CONFIG_DYNAMIC_DEBUG
+ if (reg & (CCS_FL_FLOAT_IREAL | CCS_FL_IREAL))
+ snprintf(str, sizeof(str), ", %u",
+ ccs_reg_conv(sensor, reg, val));
+#endif
+
+ dev_dbg(&client->dev,
+ "0x%8.8x \"%s\" = %u, 0x%x%s\n",
+ reg, ccs_limits[i].name, val, val, str);
}
if (ccs_limits[i].flags & CCS_L_FL_SAME_REG)
@@ -222,14 +233,13 @@ static int ccs_read_all_limits(struct ccs_sensor *sensor)
goto out_err;
}
- sensor->ccs_limits = alloc;
-
if (CCS_LIM(sensor, SCALER_N_MIN) < 16)
ccs_replace_limit(sensor, CCS_L_SCALER_N_MIN, 0, 16);
return 0;
out_err:
+ sensor->ccs_limits = NULL;
kfree(alloc);
return ret;
@@ -1878,9 +1888,11 @@ static int ccs_pm_get_init(struct ccs_sensor *sensor)
goto error;
/* Device was already active, so don't set controls */
- if (rval == 1)
+ if (rval == 1 && !sensor->handler_setup_needed)
return 0;
+ sensor->handler_setup_needed = false;
+
/* Restore V4L2 controls to the previously suspended device */
rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler);
if (rval)
@@ -2030,7 +2042,7 @@ static int __ccs_get_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- fmt->format = *v4l2_subdev_get_pad_format(subdev, sd_state, fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format.code = __ccs_get_mbus_code(subdev, fmt->pad);
return 0;
@@ -2061,10 +2073,10 @@ static void ccs_get_crop_compose(struct v4l2_subdev *subdev,
if (crops)
for (i = 0; i < subdev->entity.num_pads; i++)
crops[i] =
- v4l2_subdev_get_pad_crop(subdev, sd_state, i);
+ v4l2_subdev_state_get_crop(sd_state, i);
if (comps)
- *comps = v4l2_subdev_get_pad_compose(subdev, sd_state,
- ssd->sink_pad);
+ *comps = v4l2_subdev_state_get_compose(sd_state,
+ ssd->sink_pad);
}
/* Changes require propagation only on sink pad. */
@@ -2097,7 +2109,7 @@ static void ccs_propagate(struct v4l2_subdev *subdev,
fallthrough;
case V4L2_SEL_TGT_COMPOSE:
*crops[CCS_PAD_SRC] = *comp;
- fmt = v4l2_subdev_get_pad_format(subdev, sd_state, CCS_PAD_SRC);
+ fmt = v4l2_subdev_state_get_format(sd_state, CCS_PAD_SRC);
fmt->width = comp->width;
fmt->height = comp->height;
if (which == V4L2_SUBDEV_FORMAT_ACTIVE && ssd == sensor->src)
@@ -2507,7 +2519,7 @@ static int ccs_set_crop(struct v4l2_subdev *subdev,
if (sel->pad == ssd->sink_pad) {
struct v4l2_mbus_framefmt *mfmt =
- v4l2_subdev_get_pad_format(subdev, sd_state, sel->pad);
+ v4l2_subdev_state_get_format(sd_state, sel->pad);
src_size.width = mfmt->width;
src_size.height = mfmt->height;
@@ -2567,8 +2579,8 @@ static int ccs_get_selection(struct v4l2_subdev *subdev,
ccs_get_native_size(ssd, &sel->r);
} else if (sel->pad == ssd->sink_pad) {
struct v4l2_mbus_framefmt *sink_fmt =
- v4l2_subdev_get_pad_format(subdev, sd_state,
- ssd->sink_pad);
+ v4l2_subdev_state_get_format(sd_state,
+ ssd->sink_pad);
sel->r.top = sel->r.left = 0;
sel->r.width = sink_fmt->width;
sel->r.height = sink_fmt->height;
@@ -2714,66 +2726,54 @@ static int ccs_identify_module(struct ccs_sensor *sensor)
rval = ccs_read(sensor, MODULE_MANUFACTURER_ID,
&minfo->mipi_manufacturer_id);
if (!rval && !minfo->mipi_manufacturer_id)
- rval = ccs_read_addr_8only(sensor,
- SMIAPP_REG_U8_MANUFACTURER_ID,
- &minfo->smia_manufacturer_id);
+ rval = ccs_read_addr(sensor, SMIAPP_REG_U8_MANUFACTURER_ID,
+ &minfo->smia_manufacturer_id);
if (!rval)
- rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_MODEL_ID,
- &minfo->model_id);
+ rval = ccs_read(sensor, MODULE_MODEL_ID, &minfo->model_id);
if (!rval)
- rval = ccs_read_addr_8only(sensor,
- CCS_R_MODULE_REVISION_NUMBER_MAJOR,
- &rev);
+ rval = ccs_read(sensor, MODULE_REVISION_NUMBER_MAJOR, &rev);
if (!rval) {
- rval = ccs_read_addr_8only(sensor,
- CCS_R_MODULE_REVISION_NUMBER_MINOR,
- &minfo->revision_number);
+ rval = ccs_read(sensor, MODULE_REVISION_NUMBER_MINOR,
+ &minfo->revision_number);
minfo->revision_number |= rev << 8;
}
if (!rval)
- rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_YEAR,
- &minfo->module_year);
+ rval = ccs_read(sensor, MODULE_DATE_YEAR, &minfo->module_year);
if (!rval)
- rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_MONTH,
- &minfo->module_month);
+ rval = ccs_read(sensor, MODULE_DATE_MONTH,
+ &minfo->module_month);
if (!rval)
- rval = ccs_read_addr_8only(sensor, CCS_R_MODULE_DATE_DAY,
- &minfo->module_day);
+ rval = ccs_read(sensor, MODULE_DATE_DAY, &minfo->module_day);
/* Sensor info */
if (!rval)
rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID,
&minfo->sensor_mipi_manufacturer_id);
if (!rval && !minfo->sensor_mipi_manufacturer_id)
- rval = ccs_read_addr_8only(sensor,
- CCS_R_SENSOR_MANUFACTURER_ID,
- &minfo->sensor_smia_manufacturer_id);
+ rval = ccs_read(sensor, SENSOR_MANUFACTURER_ID,
+ &minfo->sensor_smia_manufacturer_id);
if (!rval)
- rval = ccs_read_addr_8only(sensor,
- CCS_R_SENSOR_MODEL_ID,
- &minfo->sensor_model_id);
+ rval = ccs_read(sensor, SENSOR_MODEL_ID,
+ &minfo->sensor_model_id);
if (!rval)
- rval = ccs_read_addr_8only(sensor,
- CCS_R_SENSOR_REVISION_NUMBER,
- &minfo->sensor_revision_number);
+ rval = ccs_read(sensor, SENSOR_REVISION_NUMBER,
+ &minfo->sensor_revision_number);
if (!rval && !minfo->sensor_revision_number)
- rval = ccs_read_addr_8only(sensor,
- CCS_R_SENSOR_REVISION_NUMBER_16,
- &minfo->sensor_revision_number);
+ rval = ccs_read(sensor, SENSOR_REVISION_NUMBER_16,
+ &minfo->sensor_revision_number);
if (!rval)
- rval = ccs_read_addr_8only(sensor,
- CCS_R_SENSOR_FIRMWARE_VERSION,
- &minfo->sensor_firmware_version);
+ rval = ccs_read(sensor, SENSOR_FIRMWARE_VERSION,
+ &minfo->sensor_firmware_version);
/* SMIA */
if (!rval)
rval = ccs_read(sensor, MIPI_CCS_VERSION, &minfo->ccs_version);
if (!rval && !minfo->ccs_version)
- rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION,
- &minfo->smia_version);
+ rval = ccs_read_addr(sensor, SMIAPP_REG_U8_SMIA_VERSION,
+ &minfo->smia_version);
if (!rval && !minfo->ccs_version)
- rval = ccs_read_addr_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION,
- &minfo->smiapp_version);
+ rval = ccs_read_addr(sensor, SMIAPP_REG_U8_SMIAPP_VERSION,
+ &minfo->smiapp_version);
if (rval) {
dev_err(&client->dev, "sensor detection failed\n");
@@ -3004,17 +3004,17 @@ static int ccs_init_subdev(struct ccs_sensor *sensor,
return 0;
}
-static int ccs_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int ccs_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct ccs_subdev *ssd = to_ccs_subdev(sd);
struct ccs_sensor *sensor = ssd->sensor;
unsigned int pad = ssd == sensor->pixel_array ?
CCS_PA_PAD_SRC : CCS_PAD_SINK;
struct v4l2_mbus_framefmt *fmt =
- v4l2_subdev_get_pad_format(sd, sd_state, pad);
+ v4l2_subdev_state_get_format(sd_state, pad);
struct v4l2_rect *crop =
- v4l2_subdev_get_pad_crop(sd, sd_state, pad);
+ v4l2_subdev_state_get_crop(sd_state, pad);
bool is_active = !sd->active_state || sd->active_state == sd_state;
mutex_lock(&sensor->mutex);
@@ -3034,7 +3034,7 @@ static int ccs_init_cfg(struct v4l2_subdev *sd,
return 0;
}
- fmt = v4l2_subdev_get_pad_format(sd, sd_state, CCS_PAD_SRC);
+ fmt = v4l2_subdev_state_get_format(sd_state, CCS_PAD_SRC);
fmt->code = ssd == sensor->src ?
sensor->csi_format->code : sensor->internal_csi_format->code;
fmt->field = V4L2_FIELD_NONE;
@@ -3053,7 +3053,6 @@ static const struct v4l2_subdev_video_ops ccs_video_ops = {
};
static const struct v4l2_subdev_pad_ops ccs_pad_ops = {
- .init_cfg = ccs_init_cfg,
.enum_mbus_code = ccs_enum_mbus_code,
.get_fmt = ccs_get_format,
.set_fmt = ccs_set_format,
@@ -3077,6 +3076,7 @@ static const struct media_entity_operations ccs_entity_ops = {
};
static const struct v4l2_subdev_internal_ops ccs_internal_src_ops = {
+ .init_state = ccs_init_state,
.registered = ccs_registered,
.unregistered = ccs_unregistered,
};
@@ -3307,6 +3307,13 @@ static int ccs_probe(struct i2c_client *client)
if (IS_ERR(sensor->xshutdown))
return PTR_ERR(sensor->xshutdown);
+ sensor->regmap = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(sensor->regmap)) {
+ dev_err(&client->dev, "can't initialise CCI (%ld)\n",
+ PTR_ERR(sensor->regmap));
+ return PTR_ERR(sensor->regmap);
+ }
+
rval = ccs_power_on(&client->dev);
if (rval < 0)
return rval;
@@ -3532,6 +3539,7 @@ static int ccs_probe(struct i2c_client *client)
sensor->streaming = false;
sensor->dev_init_done = true;
+ sensor->handler_setup_needed = true;
rval = ccs_write_msr_regs(sensor);
if (rval)
@@ -3636,12 +3644,16 @@ static int ccs_module_init(void)
{
unsigned int i, l;
+ CCS_BUILD_BUG;
+
for (i = 0, l = 0; ccs_limits[i].size && l < CCS_L_LAST; i++) {
if (!(ccs_limits[i].flags & CCS_L_FL_SAME_REG)) {
ccs_limit_offsets[l + 1].lim =
ALIGN(ccs_limit_offsets[l].lim +
ccs_limits[i].size,
- ccs_reg_width(ccs_limits[i + 1].reg));
+ ccs_limits[i + 1].reg ?
+ CCI_REG_WIDTH_BYTES(ccs_limits[i + 1].reg) :
+ 1U);
ccs_limit_offsets[l].info = i;
l++;
} else {
diff --git a/drivers/media/i2c/ccs/ccs-reg-access.c b/drivers/media/i2c/ccs/ccs-reg-access.c
index 25993445f4fe..ed79075505e6 100644
--- a/drivers/media/i2c/ccs/ccs-reg-access.c
+++ b/drivers/media/i2c/ccs/ccs-reg-access.c
@@ -62,87 +62,6 @@ static u32 float_to_u32_mul_1000000(struct i2c_client *client, u32 phloat)
}
-/*
- * Read a 8/16/32-bit i2c register. The value is returned in 'val'.
- * Returns zero if successful, or non-zero otherwise.
- */
-static int ____ccs_read_addr(struct ccs_sensor *sensor, u16 reg, u16 len,
- u32 *val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- struct i2c_msg msg;
- unsigned char data_buf[sizeof(u32)] = { 0 };
- unsigned char offset_buf[sizeof(u16)];
- int r;
-
- if (len > sizeof(data_buf))
- return -EINVAL;
-
- msg.addr = client->addr;
- msg.flags = 0;
- msg.len = sizeof(offset_buf);
- msg.buf = offset_buf;
- put_unaligned_be16(reg, offset_buf);
-
- r = i2c_transfer(client->adapter, &msg, 1);
- if (r != 1) {
- if (r >= 0)
- r = -EBUSY;
- goto err;
- }
-
- msg.len = len;
- msg.flags = I2C_M_RD;
- msg.buf = &data_buf[sizeof(data_buf) - len];
-
- r = i2c_transfer(client->adapter, &msg, 1);
- if (r != 1) {
- if (r >= 0)
- r = -EBUSY;
- goto err;
- }
-
- *val = get_unaligned_be32(data_buf);
-
- return 0;
-
-err:
- dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r);
-
- return r;
-}
-
-/* Read a register using 8-bit access only. */
-static int ____ccs_read_addr_8only(struct ccs_sensor *sensor, u16 reg,
- u16 len, u32 *val)
-{
- unsigned int i;
- int rval;
-
- *val = 0;
-
- for (i = 0; i < len; i++) {
- u32 val8;
-
- rval = ____ccs_read_addr(sensor, reg + i, 1, &val8);
- if (rval < 0)
- return rval;
- *val |= val8 << ((len - i - 1) << 3);
- }
-
- return 0;
-}
-
-unsigned int ccs_reg_width(u32 reg)
-{
- if (reg & CCS_FL_16BIT)
- return sizeof(u16);
- if (reg & CCS_FL_32BIT)
- return sizeof(u32);
-
- return sizeof(u8);
-}
-
static u32 ireal32_to_u32_mul_1000000(struct i2c_client *client, u32 val)
{
if (val >> 10 > U32_MAX / 15625) {
@@ -178,29 +97,22 @@ u32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val)
static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val,
bool only8, bool conv)
{
- unsigned int len = ccs_reg_width(reg);
+ u64 __val;
int rval;
- if (!only8)
- rval = ____ccs_read_addr(sensor, CCS_REG_ADDR(reg), len, val);
- else
- rval = ____ccs_read_addr_8only(sensor, CCS_REG_ADDR(reg), len,
- val);
+ rval = cci_read(sensor->regmap, reg, &__val, NULL);
if (rval < 0)
return rval;
- if (!conv)
- return 0;
-
- *val = ccs_reg_conv(sensor, reg, *val);
+ *val = conv ? ccs_reg_conv(sensor, reg, __val) : __val;
return 0;
}
-static int __ccs_read_data(struct ccs_reg *regs, size_t num_regs,
- u32 reg, u32 *val)
+static int __ccs_static_data_read_ro_reg(struct ccs_reg *regs, size_t num_regs,
+ u32 reg, u32 *val)
{
- unsigned int width = ccs_reg_width(reg);
+ unsigned int width = CCI_REG_WIDTH_BYTES(reg);
size_t i;
for (i = 0; i < num_regs; i++, regs++) {
@@ -235,16 +147,17 @@ static int __ccs_read_data(struct ccs_reg *regs, size_t num_regs,
return -ENOENT;
}
-static int ccs_read_data(struct ccs_sensor *sensor, u32 reg, u32 *val)
+static int
+ccs_static_data_read_ro_reg(struct ccs_sensor *sensor, u32 reg, u32 *val)
{
- if (!__ccs_read_data(sensor->sdata.sensor_read_only_regs,
- sensor->sdata.num_sensor_read_only_regs,
- reg, val))
+ if (!__ccs_static_data_read_ro_reg(sensor->sdata.sensor_read_only_regs,
+ sensor->sdata.num_sensor_read_only_regs,
+ reg, val))
return 0;
- return __ccs_read_data(sensor->mdata.module_read_only_regs,
- sensor->mdata.num_module_read_only_regs,
- reg, val);
+ return __ccs_static_data_read_ro_reg(sensor->mdata.module_read_only_regs,
+ sensor->mdata.num_module_read_only_regs,
+ reg, val);
}
static int ccs_read_addr_raw(struct ccs_sensor *sensor, u32 reg, u32 *val,
@@ -253,7 +166,7 @@ static int ccs_read_addr_raw(struct ccs_sensor *sensor, u32 reg, u32 *val,
int rval;
if (data) {
- rval = ccs_read_data(sensor, reg, val);
+ rval = ccs_static_data_read_ro_reg(sensor, reg, val);
if (!rval)
return 0;
}
@@ -291,71 +204,13 @@ int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val)
return ccs_read_addr_raw(sensor, reg, val, false, true, false, true);
}
-static int ccs_write_retry(struct i2c_client *client, struct i2c_msg *msg)
-{
- unsigned int retries;
- int r;
-
- for (retries = 0; retries < 10; retries++) {
- /*
- * Due to unknown reason sensor stops responding. This
- * loop is a temporaty solution until the root cause
- * is found.
- */
- r = i2c_transfer(client->adapter, msg, 1);
- if (r != 1) {
- usleep_range(1000, 2000);
- continue;
- }
-
- if (retries)
- dev_err(&client->dev,
- "sensor i2c stall encountered. retries: %d\n",
- retries);
- return 0;
- }
-
- return r;
-}
-
-int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- struct i2c_msg msg;
- unsigned char data[6];
- unsigned int len = ccs_reg_width(reg);
- int r;
-
- if (len > sizeof(data) - 2)
- return -EINVAL;
-
- msg.addr = client->addr;
- msg.flags = 0; /* Write */
- msg.len = 2 + len;
- msg.buf = data;
-
- put_unaligned_be16(CCS_REG_ADDR(reg), data);
- put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2);
-
- dev_dbg(&client->dev, "writing reg 0x%4.4x value 0x%*.*x (%u)\n",
- CCS_REG_ADDR(reg), ccs_reg_width(reg) << 1,
- ccs_reg_width(reg) << 1, val, val);
-
- r = ccs_write_retry(client, &msg);
- if (r)
- dev_err(&client->dev,
- "wrote 0x%x to offset 0x%x error %d\n", val,
- CCS_REG_ADDR(reg), r);
-
- return r;
-}
-
/*
* Write to a 8/16-bit register.
* Returns zero if successful, or non-zero otherwise.
*/
int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val)
{
+ unsigned int retries = 10;
int rval;
rval = ccs_call_quirk(sensor, reg_access, true, &reg, &val);
@@ -364,7 +219,13 @@ int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val)
if (rval < 0)
return rval;
- return ccs_write_addr_no_quirk(sensor, reg, val);
+ rval = 0;
+ do {
+ if (cci_write(sensor->regmap, reg, val, &rval))
+ fsleep(1000);
+ } while (rval && --retries);
+
+ return rval;
}
#define MAX_WRITE_LEN 32U
@@ -373,40 +234,38 @@ int ccs_write_data_regs(struct ccs_sensor *sensor, struct ccs_reg *regs,
size_t num_regs)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- unsigned char buf[2 + MAX_WRITE_LEN];
- struct i2c_msg msg = {
- .addr = client->addr,
- .buf = buf,
- };
size_t i;
for (i = 0; i < num_regs; i++, regs++) {
unsigned char *regdata = regs->value;
unsigned int j;
+ int len;
- for (j = 0; j < regs->len;
- j += msg.len - 2, regdata += msg.len - 2) {
+ for (j = 0; j < regs->len; j += len, regdata += len) {
char printbuf[(MAX_WRITE_LEN << 1) +
1 /* \0 */] = { 0 };
+ unsigned int retries = 10;
int rval;
- msg.len = min(regs->len - j, MAX_WRITE_LEN);
+ len = min(regs->len - j, MAX_WRITE_LEN);
- bin2hex(printbuf, regdata, msg.len);
+ bin2hex(printbuf, regdata, len);
dev_dbg(&client->dev,
"writing msr reg 0x%4.4x value 0x%s\n",
regs->addr + j, printbuf);
- put_unaligned_be16(regs->addr + j, buf);
- memcpy(buf + 2, regdata, msg.len);
-
- msg.len += 2;
+ do {
+ rval = regmap_bulk_write(sensor->regmap,
+ regs->addr + j,
+ regdata, len);
+ if (rval)
+ fsleep(1000);
+ } while (rval && --retries);
- rval = ccs_write_retry(client, &msg);
if (rval) {
dev_err(&client->dev,
"error writing %u octets to address 0x%4.4x\n",
- msg.len, regs->addr + j);
+ len, regs->addr + j);
return rval;
}
}
diff --git a/drivers/media/i2c/ccs/ccs-regs.h b/drivers/media/i2c/ccs/ccs-regs.h
index 6ce84c5ecf20..7b5dbc86e4cd 100644
--- a/drivers/media/i2c/ccs/ccs-regs.h
+++ b/drivers/media/i2c/ccs/ccs-regs.h
@@ -10,59 +10,59 @@
#include <linux/bits.h>
-#define CCS_FL_BASE 16
-#define CCS_FL_16BIT BIT(CCS_FL_BASE)
-#define CCS_FL_32BIT BIT(CCS_FL_BASE + 1)
-#define CCS_FL_FLOAT_IREAL BIT(CCS_FL_BASE + 2)
-#define CCS_FL_IREAL BIT(CCS_FL_BASE + 3)
-#define CCS_R_ADDR(r) ((r) & 0xffff)
+#include <media/v4l2-cci.h>
-#define CCS_R_MODULE_MODEL_ID (0x0000 | CCS_FL_16BIT)
-#define CCS_R_MODULE_REVISION_NUMBER_MAJOR 0x0002
-#define CCS_R_FRAME_COUNT 0x0005
-#define CCS_R_PIXEL_ORDER 0x0006
+#define CCS_FL_BASE CCI_REG_PRIVATE_SHIFT
+#define CCS_FL_FLOAT_IREAL BIT(CCS_FL_BASE)
+#define CCS_FL_IREAL BIT(CCS_FL_BASE + 1)
+#define CCS_BUILD_BUG \
+ BUILD_BUG_ON(~CCI_REG_PRIVATE_MASK & (BIT(CCS_FL_BASE) | BIT(CCS_FL_BASE + 1)))
+#define CCS_R_MODULE_MODEL_ID CCI_REG16(0x0000)
+#define CCS_R_MODULE_REVISION_NUMBER_MAJOR CCI_REG8(0x0002)
+#define CCS_R_FRAME_COUNT CCI_REG8(0x0005)
+#define CCS_R_PIXEL_ORDER CCI_REG8(0x0006)
#define CCS_PIXEL_ORDER_GRBG 0U
#define CCS_PIXEL_ORDER_RGGB 1U
#define CCS_PIXEL_ORDER_BGGR 2U
#define CCS_PIXEL_ORDER_GBRG 3U
-#define CCS_R_MIPI_CCS_VERSION 0x0007
+#define CCS_R_MIPI_CCS_VERSION CCI_REG8(0x0007)
#define CCS_MIPI_CCS_VERSION_V1_0 0x10
#define CCS_MIPI_CCS_VERSION_V1_1 0x11
#define CCS_MIPI_CCS_VERSION_MAJOR_SHIFT 4U
#define CCS_MIPI_CCS_VERSION_MAJOR_MASK 0xf0
#define CCS_MIPI_CCS_VERSION_MINOR_SHIFT 0U
#define CCS_MIPI_CCS_VERSION_MINOR_MASK 0xf
-#define CCS_R_DATA_PEDESTAL (0x0008 | CCS_FL_16BIT)
-#define CCS_R_MODULE_MANUFACTURER_ID (0x000e | CCS_FL_16BIT)
-#define CCS_R_MODULE_REVISION_NUMBER_MINOR 0x0010
-#define CCS_R_MODULE_DATE_YEAR 0x0012
-#define CCS_R_MODULE_DATE_MONTH 0x0013
-#define CCS_R_MODULE_DATE_DAY 0x0014
-#define CCS_R_MODULE_DATE_PHASE 0x0015
+#define CCS_R_DATA_PEDESTAL CCI_REG16(0x0008)
+#define CCS_R_MODULE_MANUFACTURER_ID CCI_REG16(0x000e)
+#define CCS_R_MODULE_REVISION_NUMBER_MINOR CCI_REG8(0x0010)
+#define CCS_R_MODULE_DATE_YEAR CCI_REG8(0x0012)
+#define CCS_R_MODULE_DATE_MONTH CCI_REG8(0x0013)
+#define CCS_R_MODULE_DATE_DAY CCI_REG8(0x0014)
+#define CCS_R_MODULE_DATE_PHASE CCI_REG8(0x0015)
#define CCS_MODULE_DATE_PHASE_SHIFT 0U
#define CCS_MODULE_DATE_PHASE_MASK 0x7
#define CCS_MODULE_DATE_PHASE_TS 0U
#define CCS_MODULE_DATE_PHASE_ES 1U
#define CCS_MODULE_DATE_PHASE_CS 2U
#define CCS_MODULE_DATE_PHASE_MP 3U
-#define CCS_R_SENSOR_MODEL_ID (0x0016 | CCS_FL_16BIT)
-#define CCS_R_SENSOR_REVISION_NUMBER 0x0018
-#define CCS_R_SENSOR_FIRMWARE_VERSION 0x001a
-#define CCS_R_SERIAL_NUMBER (0x001c | CCS_FL_32BIT)
-#define CCS_R_SENSOR_MANUFACTURER_ID (0x0020 | CCS_FL_16BIT)
-#define CCS_R_SENSOR_REVISION_NUMBER_16 (0x0022 | CCS_FL_16BIT)
-#define CCS_R_FRAME_FORMAT_MODEL_TYPE 0x0040
+#define CCS_R_SENSOR_MODEL_ID CCI_REG16(0x0016)
+#define CCS_R_SENSOR_REVISION_NUMBER CCI_REG8(0x0018)
+#define CCS_R_SENSOR_FIRMWARE_VERSION CCI_REG8(0x001a)
+#define CCS_R_SERIAL_NUMBER CCI_REG32(0x001c)
+#define CCS_R_SENSOR_MANUFACTURER_ID CCI_REG16(0x0020)
+#define CCS_R_SENSOR_REVISION_NUMBER_16 CCI_REG16(0x0022)
+#define CCS_R_FRAME_FORMAT_MODEL_TYPE CCI_REG8(0x0040)
#define CCS_FRAME_FORMAT_MODEL_TYPE_2_BYTE 1U
#define CCS_FRAME_FORMAT_MODEL_TYPE_4_BYTE 2U
-#define CCS_R_FRAME_FORMAT_MODEL_SUBTYPE 0x0041
+#define CCS_R_FRAME_FORMAT_MODEL_SUBTYPE CCI_REG8(0x0041)
#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_SHIFT 0U
#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_ROWS_MASK 0xf
#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT 4U
#define CCS_FRAME_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK 0xf0
-#define CCS_R_FRAME_FORMAT_DESCRIPTOR(n) ((0x0042 | CCS_FL_16BIT) + (n) * 2)
+#define CCS_R_FRAME_FORMAT_DESCRIPTOR(n) CCI_REG16(0x0042 + (n) * 2)
#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_MIN_N 0U
#define CCS_LIM_FRAME_FORMAT_DESCRIPTOR_MAX_N 14U
-#define CCS_R_FRAME_FORMAT_DESCRIPTOR_4(n) ((0x0060 | CCS_FL_32BIT) + (n) * 4)
+#define CCS_R_FRAME_FORMAT_DESCRIPTOR_4(n) CCI_REG32(0x0060 + (n) * 4)
#define CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_SHIFT 0U
#define CCS_FRAME_FORMAT_DESCRIPTOR_PIXELS_MASK 0xfff
#define CCS_FRAME_FORMAT_DESCRIPTOR_PCODE_SHIFT 12U
@@ -97,91 +97,91 @@
#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_4 12U
#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_5 13U
#define CCS_FRAME_FORMAT_DESCRIPTOR_4_PCODE_MANUF_SPECIFIC_6 14U
-#define CCS_R_ANALOG_GAIN_CAPABILITY (0x0080 | CCS_FL_16BIT)
+#define CCS_R_ANALOG_GAIN_CAPABILITY CCI_REG16(0x0080)
#define CCS_ANALOG_GAIN_CAPABILITY_GLOBAL 0U
#define CCS_ANALOG_GAIN_CAPABILITY_ALTERNATE_GLOBAL 2U
-#define CCS_R_ANALOG_GAIN_CODE_MIN (0x0084 | CCS_FL_16BIT)
-#define CCS_R_ANALOG_GAIN_CODE_MAX (0x0086 | CCS_FL_16BIT)
-#define CCS_R_ANALOG_GAIN_CODE_STEP (0x0088 | CCS_FL_16BIT)
-#define CCS_R_ANALOG_GAIN_TYPE (0x008a | CCS_FL_16BIT)
-#define CCS_R_ANALOG_GAIN_M0 (0x008c | CCS_FL_16BIT)
-#define CCS_R_ANALOG_GAIN_C0 (0x008e | CCS_FL_16BIT)
-#define CCS_R_ANALOG_GAIN_M1 (0x0090 | CCS_FL_16BIT)
-#define CCS_R_ANALOG_GAIN_C1 (0x0092 | CCS_FL_16BIT)
-#define CCS_R_ANALOG_LINEAR_GAIN_MIN (0x0094 | CCS_FL_16BIT)
-#define CCS_R_ANALOG_LINEAR_GAIN_MAX (0x0096 | CCS_FL_16BIT)
-#define CCS_R_ANALOG_LINEAR_GAIN_STEP_SIZE (0x0098 | CCS_FL_16BIT)
-#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MIN (0x009a | CCS_FL_16BIT)
-#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MAX (0x009c | CCS_FL_16BIT)
-#define CCS_R_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE (0x009e | CCS_FL_16BIT)
-#define CCS_R_DATA_FORMAT_MODEL_TYPE 0x00c0
+#define CCS_R_ANALOG_GAIN_CODE_MIN CCI_REG16(0x0084)
+#define CCS_R_ANALOG_GAIN_CODE_MAX CCI_REG16(0x0086)
+#define CCS_R_ANALOG_GAIN_CODE_STEP CCI_REG16(0x0088)
+#define CCS_R_ANALOG_GAIN_TYPE CCI_REG16(0x008a)
+#define CCS_R_ANALOG_GAIN_M0 CCI_REG16(0x008c)
+#define CCS_R_ANALOG_GAIN_C0 CCI_REG16(0x008e)
+#define CCS_R_ANALOG_GAIN_M1 CCI_REG16(0x0090)
+#define CCS_R_ANALOG_GAIN_C1 CCI_REG16(0x0092)
+#define CCS_R_ANALOG_LINEAR_GAIN_MIN CCI_REG16(0x0094)
+#define CCS_R_ANALOG_LINEAR_GAIN_MAX CCI_REG16(0x0096)
+#define CCS_R_ANALOG_LINEAR_GAIN_STEP_SIZE CCI_REG16(0x0098)
+#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MIN CCI_REG16(0x009a)
+#define CCS_R_ANALOG_EXPONENTIAL_GAIN_MAX CCI_REG16(0x009c)
+#define CCS_R_ANALOG_EXPONENTIAL_GAIN_STEP_SIZE CCI_REG16(0x009e)
+#define CCS_R_DATA_FORMAT_MODEL_TYPE CCI_REG8(0x00c0)
#define CCS_DATA_FORMAT_MODEL_TYPE_NORMAL 1U
#define CCS_DATA_FORMAT_MODEL_TYPE_EXTENDED 2U
-#define CCS_R_DATA_FORMAT_MODEL_SUBTYPE 0x00c1
+#define CCS_R_DATA_FORMAT_MODEL_SUBTYPE CCI_REG8(0x00c1)
#define CCS_DATA_FORMAT_MODEL_SUBTYPE_ROWS_SHIFT 0U
#define CCS_DATA_FORMAT_MODEL_SUBTYPE_ROWS_MASK 0xf
#define CCS_DATA_FORMAT_MODEL_SUBTYPE_COLUMNS_SHIFT 4U
#define CCS_DATA_FORMAT_MODEL_SUBTYPE_COLUMNS_MASK 0xf0
-#define CCS_R_DATA_FORMAT_DESCRIPTOR(n) ((0x00c2 | CCS_FL_16BIT) + (n) * 2)
+#define CCS_R_DATA_FORMAT_DESCRIPTOR(n) CCI_REG16(0x00c2 + (n) * 2)
#define CCS_LIM_DATA_FORMAT_DESCRIPTOR_MIN_N 0U
#define CCS_LIM_DATA_FORMAT_DESCRIPTOR_MAX_N 15U
#define CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_SHIFT 0U
#define CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK 0xff
#define CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_SHIFT 8U
#define CCS_DATA_FORMAT_DESCRIPTOR_UNCOMPRESSED_MASK 0xff00
-#define CCS_R_MODE_SELECT 0x0100
+#define CCS_R_MODE_SELECT CCI_REG8(0x0100)
#define CCS_MODE_SELECT_SOFTWARE_STANDBY 0U
#define CCS_MODE_SELECT_STREAMING 1U
-#define CCS_R_IMAGE_ORIENTATION 0x0101
+#define CCS_R_IMAGE_ORIENTATION CCI_REG8(0x0101)
#define CCS_IMAGE_ORIENTATION_HORIZONTAL_MIRROR BIT(0)
#define CCS_IMAGE_ORIENTATION_VERTICAL_FLIP BIT(1)
-#define CCS_R_SOFTWARE_RESET 0x0103
+#define CCS_R_SOFTWARE_RESET CCI_REG8(0x0103)
#define CCS_SOFTWARE_RESET_OFF 0U
#define CCS_SOFTWARE_RESET_ON 1U
-#define CCS_R_GROUPED_PARAMETER_HOLD 0x0104
-#define CCS_R_MASK_CORRUPTED_FRAMES 0x0105
+#define CCS_R_GROUPED_PARAMETER_HOLD CCI_REG8(0x0104)
+#define CCS_R_MASK_CORRUPTED_FRAMES CCI_REG8(0x0105)
#define CCS_MASK_CORRUPTED_FRAMES_ALLOW 0U
#define CCS_MASK_CORRUPTED_FRAMES_MASK 1U
-#define CCS_R_FAST_STANDBY_CTRL 0x0106
+#define CCS_R_FAST_STANDBY_CTRL CCI_REG8(0x0106)
#define CCS_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0U
#define CCS_FAST_STANDBY_CTRL_FRAME_TRUNCATION 1U
-#define CCS_R_CCI_ADDRESS_CTRL 0x0107
-#define CCS_R_2ND_CCI_IF_CTRL 0x0108
+#define CCS_R_CCI_ADDRESS_CTRL CCI_REG8(0x0107)
+#define CCS_R_2ND_CCI_IF_CTRL CCI_REG8(0x0108)
#define CCS_2ND_CCI_IF_CTRL_ENABLE BIT(0)
#define CCS_2ND_CCI_IF_CTRL_ACK BIT(1)
-#define CCS_R_2ND_CCI_ADDRESS_CTRL 0x0109
-#define CCS_R_CSI_CHANNEL_IDENTIFIER 0x0110
-#define CCS_R_CSI_SIGNALING_MODE 0x0111
+#define CCS_R_2ND_CCI_ADDRESS_CTRL CCI_REG8(0x0109)
+#define CCS_R_CSI_CHANNEL_IDENTIFIER CCI_REG8(0x0110)
+#define CCS_R_CSI_SIGNALING_MODE CCI_REG8(0x0111)
#define CCS_CSI_SIGNALING_MODE_CSI_2_DPHY 2U
#define CCS_CSI_SIGNALING_MODE_CSI_2_CPHY 3U
-#define CCS_R_CSI_DATA_FORMAT (0x0112 | CCS_FL_16BIT)
-#define CCS_R_CSI_LANE_MODE 0x0114
-#define CCS_R_DPCM_FRAME_DT 0x011d
-#define CCS_R_BOTTOM_EMBEDDED_DATA_DT 0x011e
-#define CCS_R_BOTTOM_EMBEDDED_DATA_VC 0x011f
-#define CCS_R_GAIN_MODE 0x0120
+#define CCS_R_CSI_DATA_FORMAT CCI_REG16(0x0112)
+#define CCS_R_CSI_LANE_MODE CCI_REG8(0x0114)
+#define CCS_R_DPCM_FRAME_DT CCI_REG8(0x011d)
+#define CCS_R_BOTTOM_EMBEDDED_DATA_DT CCI_REG8(0x011e)
+#define CCS_R_BOTTOM_EMBEDDED_DATA_VC CCI_REG8(0x011f)
+#define CCS_R_GAIN_MODE CCI_REG8(0x0120)
#define CCS_GAIN_MODE_GLOBAL 0U
#define CCS_GAIN_MODE_ALTERNATE 1U
-#define CCS_R_ADC_BIT_DEPTH 0x0121
-#define CCS_R_EMB_DATA_CTRL 0x0122
+#define CCS_R_ADC_BIT_DEPTH CCI_REG8(0x0121)
+#define CCS_R_EMB_DATA_CTRL CCI_REG8(0x0122)
#define CCS_EMB_DATA_CTRL_RAW8_PACKING_FOR_RAW16 BIT(0)
#define CCS_EMB_DATA_CTRL_RAW10_PACKING_FOR_RAW20 BIT(1)
#define CCS_EMB_DATA_CTRL_RAW12_PACKING_FOR_RAW24 BIT(2)
-#define CCS_R_GPIO_TRIG_MODE 0x0130
-#define CCS_R_EXTCLK_FREQUENCY_MHZ (0x0136 | (CCS_FL_16BIT | CCS_FL_IREAL))
-#define CCS_R_TEMP_SENSOR_CTRL 0x0138
+#define CCS_R_GPIO_TRIG_MODE CCI_REG8(0x0130)
+#define CCS_R_EXTCLK_FREQUENCY_MHZ (CCI_REG16(0x0136) | CCS_FL_IREAL)
+#define CCS_R_TEMP_SENSOR_CTRL CCI_REG8(0x0138)
#define CCS_TEMP_SENSOR_CTRL_ENABLE BIT(0)
-#define CCS_R_TEMP_SENSOR_MODE 0x0139
-#define CCS_R_TEMP_SENSOR_OUTPUT 0x013a
-#define CCS_R_FINE_INTEGRATION_TIME (0x0200 | CCS_FL_16BIT)
-#define CCS_R_COARSE_INTEGRATION_TIME (0x0202 | CCS_FL_16BIT)
-#define CCS_R_ANALOG_GAIN_CODE_GLOBAL (0x0204 | CCS_FL_16BIT)
-#define CCS_R_ANALOG_LINEAR_GAIN_GLOBAL (0x0206 | CCS_FL_16BIT)
-#define CCS_R_ANALOG_EXPONENTIAL_GAIN_GLOBAL (0x0208 | CCS_FL_16BIT)
-#define CCS_R_DIGITAL_GAIN_GLOBAL (0x020e | CCS_FL_16BIT)
-#define CCS_R_SHORT_ANALOG_GAIN_GLOBAL (0x0216 | CCS_FL_16BIT)
-#define CCS_R_SHORT_DIGITAL_GAIN_GLOBAL (0x0218 | CCS_FL_16BIT)
-#define CCS_R_HDR_MODE 0x0220
+#define CCS_R_TEMP_SENSOR_MODE CCI_REG8(0x0139)
+#define CCS_R_TEMP_SENSOR_OUTPUT CCI_REG8(0x013a)
+#define CCS_R_FINE_INTEGRATION_TIME CCI_REG16(0x0200)
+#define CCS_R_COARSE_INTEGRATION_TIME CCI_REG16(0x0202)
+#define CCS_R_ANALOG_GAIN_CODE_GLOBAL CCI_REG16(0x0204)
+#define CCS_R_ANALOG_LINEAR_GAIN_GLOBAL CCI_REG16(0x0206)
+#define CCS_R_ANALOG_EXPONENTIAL_GAIN_GLOBAL CCI_REG16(0x0208)
+#define CCS_R_DIGITAL_GAIN_GLOBAL CCI_REG16(0x020e)
+#define CCS_R_SHORT_ANALOG_GAIN_GLOBAL CCI_REG16(0x0216)
+#define CCS_R_SHORT_DIGITAL_GAIN_GLOBAL CCI_REG16(0x0218)
+#define CCS_R_HDR_MODE CCI_REG8(0x0220)
#define CCS_HDR_MODE_ENABLED BIT(0)
#define CCS_HDR_MODE_SEPARATE_ANALOG_GAIN BIT(1)
#define CCS_HDR_MODE_UPSCALING BIT(2)
@@ -189,421 +189,421 @@
#define CCS_HDR_MODE_TIMING_MODE BIT(4)
#define CCS_HDR_MODE_EXPOSURE_CTRL_DIRECT BIT(5)
#define CCS_HDR_MODE_SEPARATE_DIGITAL_GAIN BIT(6)
-#define CCS_R_HDR_RESOLUTION_REDUCTION 0x0221
+#define CCS_R_HDR_RESOLUTION_REDUCTION CCI_REG8(0x0221)
#define CCS_HDR_RESOLUTION_REDUCTION_ROW_SHIFT 0U
#define CCS_HDR_RESOLUTION_REDUCTION_ROW_MASK 0xf
#define CCS_HDR_RESOLUTION_REDUCTION_COLUMN_SHIFT 4U
#define CCS_HDR_RESOLUTION_REDUCTION_COLUMN_MASK 0xf0
-#define CCS_R_EXPOSURE_RATIO 0x0222
-#define CCS_R_HDR_INTERNAL_BIT_DEPTH 0x0223
-#define CCS_R_DIRECT_SHORT_INTEGRATION_TIME (0x0224 | CCS_FL_16BIT)
-#define CCS_R_SHORT_ANALOG_LINEAR_GAIN_GLOBAL (0x0226 | CCS_FL_16BIT)
-#define CCS_R_SHORT_ANALOG_EXPONENTIAL_GAIN_GLOBAL (0x0228 | CCS_FL_16BIT)
-#define CCS_R_VT_PIX_CLK_DIV (0x0300 | CCS_FL_16BIT)
-#define CCS_R_VT_SYS_CLK_DIV (0x0302 | CCS_FL_16BIT)
-#define CCS_R_PRE_PLL_CLK_DIV (0x0304 | CCS_FL_16BIT)
-#define CCS_R_PLL_MULTIPLIER (0x0306 | CCS_FL_16BIT)
-#define CCS_R_OP_PIX_CLK_DIV (0x0308 | CCS_FL_16BIT)
-#define CCS_R_OP_SYS_CLK_DIV (0x030a | CCS_FL_16BIT)
-#define CCS_R_OP_PRE_PLL_CLK_DIV (0x030c | CCS_FL_16BIT)
-#define CCS_R_OP_PLL_MULTIPLIER (0x030e | CCS_FL_16BIT)
-#define CCS_R_PLL_MODE 0x0310
+#define CCS_R_EXPOSURE_RATIO CCI_REG8(0x0222)
+#define CCS_R_HDR_INTERNAL_BIT_DEPTH CCI_REG8(0x0223)
+#define CCS_R_DIRECT_SHORT_INTEGRATION_TIME CCI_REG16(0x0224)
+#define CCS_R_SHORT_ANALOG_LINEAR_GAIN_GLOBAL CCI_REG16(0x0226)
+#define CCS_R_SHORT_ANALOG_EXPONENTIAL_GAIN_GLOBAL CCI_REG16(0x0228)
+#define CCS_R_VT_PIX_CLK_DIV CCI_REG16(0x0300)
+#define CCS_R_VT_SYS_CLK_DIV CCI_REG16(0x0302)
+#define CCS_R_PRE_PLL_CLK_DIV CCI_REG16(0x0304)
+#define CCS_R_PLL_MULTIPLIER CCI_REG16(0x0306)
+#define CCS_R_OP_PIX_CLK_DIV CCI_REG16(0x0308)
+#define CCS_R_OP_SYS_CLK_DIV CCI_REG16(0x030a)
+#define CCS_R_OP_PRE_PLL_CLK_DIV CCI_REG16(0x030c)
+#define CCS_R_OP_PLL_MULTIPLIER CCI_REG16(0x030e)
+#define CCS_R_PLL_MODE CCI_REG8(0x0310)
#define CCS_PLL_MODE_SHIFT 0U
#define CCS_PLL_MODE_MASK 0x1
#define CCS_PLL_MODE_SINGLE 0U
#define CCS_PLL_MODE_DUAL 1U
-#define CCS_R_OP_PIX_CLK_DIV_REV (0x0312 | CCS_FL_16BIT)
-#define CCS_R_OP_SYS_CLK_DIV_REV (0x0314 | CCS_FL_16BIT)
-#define CCS_R_FRAME_LENGTH_LINES (0x0340 | CCS_FL_16BIT)
-#define CCS_R_LINE_LENGTH_PCK (0x0342 | CCS_FL_16BIT)
-#define CCS_R_X_ADDR_START (0x0344 | CCS_FL_16BIT)
-#define CCS_R_Y_ADDR_START (0x0346 | CCS_FL_16BIT)
-#define CCS_R_X_ADDR_END (0x0348 | CCS_FL_16BIT)
-#define CCS_R_Y_ADDR_END (0x034a | CCS_FL_16BIT)
-#define CCS_R_X_OUTPUT_SIZE (0x034c | CCS_FL_16BIT)
-#define CCS_R_Y_OUTPUT_SIZE (0x034e | CCS_FL_16BIT)
-#define CCS_R_FRAME_LENGTH_CTRL 0x0350
+#define CCS_R_OP_PIX_CLK_DIV_REV CCI_REG16(0x0312)
+#define CCS_R_OP_SYS_CLK_DIV_REV CCI_REG16(0x0314)
+#define CCS_R_FRAME_LENGTH_LINES CCI_REG16(0x0340)
+#define CCS_R_LINE_LENGTH_PCK CCI_REG16(0x0342)
+#define CCS_R_X_ADDR_START CCI_REG16(0x0344)
+#define CCS_R_Y_ADDR_START CCI_REG16(0x0346)
+#define CCS_R_X_ADDR_END CCI_REG16(0x0348)
+#define CCS_R_Y_ADDR_END CCI_REG16(0x034a)
+#define CCS_R_X_OUTPUT_SIZE CCI_REG16(0x034c)
+#define CCS_R_Y_OUTPUT_SIZE CCI_REG16(0x034e)
+#define CCS_R_FRAME_LENGTH_CTRL CCI_REG8(0x0350)
#define CCS_FRAME_LENGTH_CTRL_AUTOMATIC BIT(0)
-#define CCS_R_TIMING_MODE_CTRL 0x0352
+#define CCS_R_TIMING_MODE_CTRL CCI_REG8(0x0352)
#define CCS_TIMING_MODE_CTRL_MANUAL_READOUT BIT(0)
#define CCS_TIMING_MODE_CTRL_DELAYED_EXPOSURE BIT(1)
-#define CCS_R_START_READOUT_RS 0x0353
+#define CCS_R_START_READOUT_RS CCI_REG8(0x0353)
#define CCS_START_READOUT_RS_MANUAL_READOUT_START BIT(0)
-#define CCS_R_FRAME_MARGIN (0x0354 | CCS_FL_16BIT)
-#define CCS_R_X_EVEN_INC (0x0380 | CCS_FL_16BIT)
-#define CCS_R_X_ODD_INC (0x0382 | CCS_FL_16BIT)
-#define CCS_R_Y_EVEN_INC (0x0384 | CCS_FL_16BIT)
-#define CCS_R_Y_ODD_INC (0x0386 | CCS_FL_16BIT)
-#define CCS_R_MONOCHROME_EN 0x0390
+#define CCS_R_FRAME_MARGIN CCI_REG16(0x0354)
+#define CCS_R_X_EVEN_INC CCI_REG16(0x0380)
+#define CCS_R_X_ODD_INC CCI_REG16(0x0382)
+#define CCS_R_Y_EVEN_INC CCI_REG16(0x0384)
+#define CCS_R_Y_ODD_INC CCI_REG16(0x0386)
+#define CCS_R_MONOCHROME_EN CCI_REG8(0x0390)
#define CCS_MONOCHROME_EN_ENABLED 0U
-#define CCS_R_SCALING_MODE (0x0400 | CCS_FL_16BIT)
+#define CCS_R_SCALING_MODE CCI_REG16(0x0400)
#define CCS_SCALING_MODE_NO_SCALING 0U
#define CCS_SCALING_MODE_HORIZONTAL 1U
-#define CCS_R_SCALE_M (0x0404 | CCS_FL_16BIT)
-#define CCS_R_SCALE_N (0x0406 | CCS_FL_16BIT)
-#define CCS_R_DIGITAL_CROP_X_OFFSET (0x0408 | CCS_FL_16BIT)
-#define CCS_R_DIGITAL_CROP_Y_OFFSET (0x040a | CCS_FL_16BIT)
-#define CCS_R_DIGITAL_CROP_IMAGE_WIDTH (0x040c | CCS_FL_16BIT)
-#define CCS_R_DIGITAL_CROP_IMAGE_HEIGHT (0x040e | CCS_FL_16BIT)
-#define CCS_R_COMPRESSION_MODE (0x0500 | CCS_FL_16BIT)
+#define CCS_R_SCALE_M CCI_REG16(0x0404)
+#define CCS_R_SCALE_N CCI_REG16(0x0406)
+#define CCS_R_DIGITAL_CROP_X_OFFSET CCI_REG16(0x0408)
+#define CCS_R_DIGITAL_CROP_Y_OFFSET CCI_REG16(0x040a)
+#define CCS_R_DIGITAL_CROP_IMAGE_WIDTH CCI_REG16(0x040c)
+#define CCS_R_DIGITAL_CROP_IMAGE_HEIGHT CCI_REG16(0x040e)
+#define CCS_R_COMPRESSION_MODE CCI_REG16(0x0500)
#define CCS_COMPRESSION_MODE_NONE 0U
#define CCS_COMPRESSION_MODE_DPCM_PCM_SIMPLE 1U
-#define CCS_R_TEST_PATTERN_MODE (0x0600 | CCS_FL_16BIT)
+#define CCS_R_TEST_PATTERN_MODE CCI_REG16(0x0600)
#define CCS_TEST_PATTERN_MODE_NONE 0U
#define CCS_TEST_PATTERN_MODE_SOLID_COLOR 1U
#define CCS_TEST_PATTERN_MODE_COLOR_BARS 2U
#define CCS_TEST_PATTERN_MODE_FADE_TO_GREY 3U
#define CCS_TEST_PATTERN_MODE_PN9 4U
#define CCS_TEST_PATTERN_MODE_COLOR_TILE 5U
-#define CCS_R_TEST_DATA_RED (0x0602 | CCS_FL_16BIT)
-#define CCS_R_TEST_DATA_GREENR (0x0604 | CCS_FL_16BIT)
-#define CCS_R_TEST_DATA_BLUE (0x0606 | CCS_FL_16BIT)
-#define CCS_R_TEST_DATA_GREENB (0x0608 | CCS_FL_16BIT)
-#define CCS_R_VALUE_STEP_SIZE_SMOOTH 0x060a
-#define CCS_R_VALUE_STEP_SIZE_QUANTISED 0x060b
-#define CCS_R_TCLK_POST 0x0800
-#define CCS_R_THS_PREPARE 0x0801
-#define CCS_R_THS_ZERO_MIN 0x0802
-#define CCS_R_THS_TRAIL 0x0803
-#define CCS_R_TCLK_TRAIL_MIN 0x0804
-#define CCS_R_TCLK_PREPARE 0x0805
-#define CCS_R_TCLK_ZERO 0x0806
-#define CCS_R_TLPX 0x0807
-#define CCS_R_PHY_CTRL 0x0808
+#define CCS_R_TEST_DATA_RED CCI_REG16(0x0602)
+#define CCS_R_TEST_DATA_GREENR CCI_REG16(0x0604)
+#define CCS_R_TEST_DATA_BLUE CCI_REG16(0x0606)
+#define CCS_R_TEST_DATA_GREENB CCI_REG16(0x0608)
+#define CCS_R_VALUE_STEP_SIZE_SMOOTH CCI_REG8(0x060a)
+#define CCS_R_VALUE_STEP_SIZE_QUANTISED CCI_REG8(0x060b)
+#define CCS_R_TCLK_POST CCI_REG8(0x0800)
+#define CCS_R_THS_PREPARE CCI_REG8(0x0801)
+#define CCS_R_THS_ZERO_MIN CCI_REG8(0x0802)
+#define CCS_R_THS_TRAIL CCI_REG8(0x0803)
+#define CCS_R_TCLK_TRAIL_MIN CCI_REG8(0x0804)
+#define CCS_R_TCLK_PREPARE CCI_REG8(0x0805)
+#define CCS_R_TCLK_ZERO CCI_REG8(0x0806)
+#define CCS_R_TLPX CCI_REG8(0x0807)
+#define CCS_R_PHY_CTRL CCI_REG8(0x0808)
#define CCS_PHY_CTRL_AUTO 0U
#define CCS_PHY_CTRL_UI 1U
#define CCS_PHY_CTRL_MANUAL 2U
-#define CCS_R_TCLK_POST_EX (0x080a | CCS_FL_16BIT)
-#define CCS_R_THS_PREPARE_EX (0x080c | CCS_FL_16BIT)
-#define CCS_R_THS_ZERO_MIN_EX (0x080e | CCS_FL_16BIT)
-#define CCS_R_THS_TRAIL_EX (0x0810 | CCS_FL_16BIT)
-#define CCS_R_TCLK_TRAIL_MIN_EX (0x0812 | CCS_FL_16BIT)
-#define CCS_R_TCLK_PREPARE_EX (0x0814 | CCS_FL_16BIT)
-#define CCS_R_TCLK_ZERO_EX (0x0816 | CCS_FL_16BIT)
-#define CCS_R_TLPX_EX (0x0818 | CCS_FL_16BIT)
-#define CCS_R_REQUESTED_LINK_RATE (0x0820 | CCS_FL_32BIT)
-#define CCS_R_DPHY_EQUALIZATION_MODE 0x0824
+#define CCS_R_TCLK_POST_EX CCI_REG16(0x080a)
+#define CCS_R_THS_PREPARE_EX CCI_REG16(0x080c)
+#define CCS_R_THS_ZERO_MIN_EX CCI_REG16(0x080e)
+#define CCS_R_THS_TRAIL_EX CCI_REG16(0x0810)
+#define CCS_R_TCLK_TRAIL_MIN_EX CCI_REG16(0x0812)
+#define CCS_R_TCLK_PREPARE_EX CCI_REG16(0x0814)
+#define CCS_R_TCLK_ZERO_EX CCI_REG16(0x0816)
+#define CCS_R_TLPX_EX CCI_REG16(0x0818)
+#define CCS_R_REQUESTED_LINK_RATE CCI_REG32(0x0820)
+#define CCS_R_DPHY_EQUALIZATION_MODE CCI_REG8(0x0824)
#define CCS_DPHY_EQUALIZATION_MODE_EQ2 BIT(0)
-#define CCS_R_PHY_EQUALIZATION_CTRL 0x0825
+#define CCS_R_PHY_EQUALIZATION_CTRL CCI_REG8(0x0825)
#define CCS_PHY_EQUALIZATION_CTRL_ENABLE BIT(0)
-#define CCS_R_DPHY_PREAMBLE_CTRL 0x0826
+#define CCS_R_DPHY_PREAMBLE_CTRL CCI_REG8(0x0826)
#define CCS_DPHY_PREAMBLE_CTRL_ENABLE BIT(0)
-#define CCS_R_DPHY_PREAMBLE_LENGTH 0x0826
-#define CCS_R_PHY_SSC_CTRL 0x0828
+#define CCS_R_DPHY_PREAMBLE_LENGTH CCI_REG8(0x0826)
+#define CCS_R_PHY_SSC_CTRL CCI_REG8(0x0828)
#define CCS_PHY_SSC_CTRL_ENABLE BIT(0)
-#define CCS_R_MANUAL_LP_CTRL 0x0829
+#define CCS_R_MANUAL_LP_CTRL CCI_REG8(0x0829)
#define CCS_MANUAL_LP_CTRL_ENABLE BIT(0)
-#define CCS_R_TWAKEUP 0x082a
-#define CCS_R_TINIT 0x082b
-#define CCS_R_THS_EXIT 0x082c
-#define CCS_R_THS_EXIT_EX (0x082e | CCS_FL_16BIT)
-#define CCS_R_PHY_PERIODIC_CALIBRATION_CTRL 0x0830
+#define CCS_R_TWAKEUP CCI_REG8(0x082a)
+#define CCS_R_TINIT CCI_REG8(0x082b)
+#define CCS_R_THS_EXIT CCI_REG8(0x082c)
+#define CCS_R_THS_EXIT_EX CCI_REG16(0x082e)
+#define CCS_R_PHY_PERIODIC_CALIBRATION_CTRL CCI_REG8(0x0830)
#define CCS_PHY_PERIODIC_CALIBRATION_CTRL_FRAME_BLANKING BIT(0)
-#define CCS_R_PHY_PERIODIC_CALIBRATION_INTERVAL 0x0831
-#define CCS_R_PHY_INIT_CALIBRATION_CTRL 0x0832
+#define CCS_R_PHY_PERIODIC_CALIBRATION_INTERVAL CCI_REG8(0x0831)
+#define CCS_R_PHY_INIT_CALIBRATION_CTRL CCI_REG8(0x0832)
#define CCS_PHY_INIT_CALIBRATION_CTRL_STREAM_START BIT(0)
-#define CCS_R_DPHY_CALIBRATION_MODE 0x0833
+#define CCS_R_DPHY_CALIBRATION_MODE CCI_REG8(0x0833)
#define CCS_DPHY_CALIBRATION_MODE_ALSO_ALTERNATE BIT(0)
-#define CCS_R_CPHY_CALIBRATION_MODE 0x0834
+#define CCS_R_CPHY_CALIBRATION_MODE CCI_REG8(0x0834)
#define CCS_CPHY_CALIBRATION_MODE_FORMAT_1 0U
#define CCS_CPHY_CALIBRATION_MODE_FORMAT_2 1U
#define CCS_CPHY_CALIBRATION_MODE_FORMAT_3 2U
-#define CCS_R_T3_CALPREAMBLE_LENGTH 0x0835
-#define CCS_R_T3_CALPREAMBLE_LENGTH_PER 0x0836
-#define CCS_R_T3_CALALTSEQ_LENGTH 0x0837
-#define CCS_R_T3_CALALTSEQ_LENGTH_PER 0x0838
-#define CCS_R_FM2_INIT_SEED (0x083a | CCS_FL_16BIT)
-#define CCS_R_T3_CALUDEFSEQ_LENGTH (0x083c | CCS_FL_16BIT)
-#define CCS_R_T3_CALUDEFSEQ_LENGTH_PER (0x083e | CCS_FL_16BIT)
-#define CCS_R_TGR_PREAMBLE_LENGTH 0x0841
+#define CCS_R_T3_CALPREAMBLE_LENGTH CCI_REG8(0x0835)
+#define CCS_R_T3_CALPREAMBLE_LENGTH_PER CCI_REG8(0x0836)
+#define CCS_R_T3_CALALTSEQ_LENGTH CCI_REG8(0x0837)
+#define CCS_R_T3_CALALTSEQ_LENGTH_PER CCI_REG8(0x0838)
+#define CCS_R_FM2_INIT_SEED CCI_REG16(0x083a)
+#define CCS_R_T3_CALUDEFSEQ_LENGTH CCI_REG16(0x083c)
+#define CCS_R_T3_CALUDEFSEQ_LENGTH_PER CCI_REG16(0x083e)
+#define CCS_R_TGR_PREAMBLE_LENGTH CCI_REG8(0x0841)
#define CCS_TGR_PREAMBLE_LENGTH_PREAMABLE_PROG_SEQ BIT(7)
#define CCS_TGR_PREAMBLE_LENGTH_BEGIN_PREAMBLE_LENGTH_SHIFT 0U
#define CCS_TGR_PREAMBLE_LENGTH_BEGIN_PREAMBLE_LENGTH_MASK 0x3f
-#define CCS_R_TGR_POST_LENGTH 0x0842
+#define CCS_R_TGR_POST_LENGTH CCI_REG8(0x0842)
#define CCS_TGR_POST_LENGTH_POST_LENGTH_SHIFT 0U
#define CCS_TGR_POST_LENGTH_POST_LENGTH_MASK 0x1f
-#define CCS_R_TGR_PREAMBLE_PROG_SEQUENCE(n2) (0x0843 + (n2))
+#define CCS_R_TGR_PREAMBLE_PROG_SEQUENCE(n2) CCI_REG8(0x0843 + (n2))
#define CCS_LIM_TGR_PREAMBLE_PROG_SEQUENCE_MIN_N2 0U
#define CCS_LIM_TGR_PREAMBLE_PROG_SEQUENCE_MAX_N2 6U
#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_1_SHIFT 3U
#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_1_MASK 0x38
#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_SHIFT 0U
#define CCS_TGR_PREAMBLE_PROG_SEQUENCE_SYMBOL_N_MASK 0x7
-#define CCS_R_T3_PREPARE (0x084e | CCS_FL_16BIT)
-#define CCS_R_T3_LPX (0x0850 | CCS_FL_16BIT)
-#define CCS_R_ALPS_CTRL 0x085a
+#define CCS_R_T3_PREPARE CCI_REG16(0x084e)
+#define CCS_R_T3_LPX CCI_REG16(0x0850)
+#define CCS_R_ALPS_CTRL CCI_REG8(0x085a)
#define CCS_ALPS_CTRL_LVLP_DPHY BIT(0)
#define CCS_ALPS_CTRL_LVLP_CPHY BIT(1)
#define CCS_ALPS_CTRL_ALP_CPHY BIT(2)
-#define CCS_R_TX_REG_CSI_EPD_EN_SSP_CPHY (0x0860 | CCS_FL_16BIT)
-#define CCS_R_TX_REG_CSI_EPD_OP_SLP_CPHY (0x0862 | CCS_FL_16BIT)
-#define CCS_R_TX_REG_CSI_EPD_EN_SSP_DPHY (0x0864 | CCS_FL_16BIT)
-#define CCS_R_TX_REG_CSI_EPD_OP_SLP_DPHY (0x0866 | CCS_FL_16BIT)
-#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_CPHY 0x0868
-#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_DPHY 0x0869
-#define CCS_R_SCRAMBLING_CTRL 0x0870
+#define CCS_R_TX_REG_CSI_EPD_EN_SSP_CPHY CCI_REG16(0x0860)
+#define CCS_R_TX_REG_CSI_EPD_OP_SLP_CPHY CCI_REG16(0x0862)
+#define CCS_R_TX_REG_CSI_EPD_EN_SSP_DPHY CCI_REG16(0x0864)
+#define CCS_R_TX_REG_CSI_EPD_OP_SLP_DPHY CCI_REG16(0x0866)
+#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_CPHY CCI_REG8(0x0868)
+#define CCS_R_TX_REG_CSI_EPD_MISC_OPTION_DPHY CCI_REG8(0x0869)
+#define CCS_R_SCRAMBLING_CTRL CCI_REG8(0x0870)
#define CCS_SCRAMBLING_CTRL_ENABLED BIT(0)
#define CCS_SCRAMBLING_CTRL_SHIFT 2U
#define CCS_SCRAMBLING_CTRL_MASK 0xc
#define CCS_SCRAMBLING_CTRL_1_SEED_CPHY 0U
#define CCS_SCRAMBLING_CTRL_4_SEED_CPHY 3U
-#define CCS_R_LANE_SEED_VALUE(seed, lane) ((0x0872 | CCS_FL_16BIT) + (seed) * 16 + (lane) * 2)
+#define CCS_R_LANE_SEED_VALUE(seed, lane) CCI_REG16(0x0872 + (seed) * 16 + (lane) * 2)
#define CCS_LIM_LANE_SEED_VALUE_MIN_SEED 0U
#define CCS_LIM_LANE_SEED_VALUE_MAX_SEED 3U
#define CCS_LIM_LANE_SEED_VALUE_MIN_LANE 0U
#define CCS_LIM_LANE_SEED_VALUE_MAX_LANE 7U
-#define CCS_R_TX_USL_REV_ENTRY (0x08c0 | CCS_FL_16BIT)
-#define CCS_R_TX_USL_REV_CLOCK_COUNTER (0x08c2 | CCS_FL_16BIT)
-#define CCS_R_TX_USL_REV_LP_COUNTER (0x08c4 | CCS_FL_16BIT)
-#define CCS_R_TX_USL_REV_FRAME_COUNTER (0x08c6 | CCS_FL_16BIT)
-#define CCS_R_TX_USL_REV_CHRONOLOGICAL_TIMER (0x08c8 | CCS_FL_16BIT)
-#define CCS_R_TX_USL_FWD_ENTRY (0x08ca | CCS_FL_16BIT)
-#define CCS_R_TX_USL_GPIO (0x08cc | CCS_FL_16BIT)
-#define CCS_R_TX_USL_OPERATION (0x08ce | CCS_FL_16BIT)
+#define CCS_R_TX_USL_REV_ENTRY CCI_REG16(0x08c0)
+#define CCS_R_TX_USL_REV_CLOCK_COUNTER CCI_REG16(0x08c2)
+#define CCS_R_TX_USL_REV_LP_COUNTER CCI_REG16(0x08c4)
+#define CCS_R_TX_USL_REV_FRAME_COUNTER CCI_REG16(0x08c6)
+#define CCS_R_TX_USL_REV_CHRONOLOGICAL_TIMER CCI_REG16(0x08c8)
+#define CCS_R_TX_USL_FWD_ENTRY CCI_REG16(0x08ca)
+#define CCS_R_TX_USL_GPIO CCI_REG16(0x08cc)
+#define CCS_R_TX_USL_OPERATION CCI_REG16(0x08ce)
#define CCS_TX_USL_OPERATION_RESET BIT(0)
-#define CCS_R_TX_USL_ALP_CTRL (0x08d0 | CCS_FL_16BIT)
+#define CCS_R_TX_USL_ALP_CTRL CCI_REG16(0x08d0)
#define CCS_TX_USL_ALP_CTRL_CLOCK_PAUSE BIT(0)
-#define CCS_R_TX_USL_APP_BTA_ACK_TIMEOUT (0x08d2 | CCS_FL_16BIT)
-#define CCS_R_TX_USL_SNS_BTA_ACK_TIMEOUT (0x08d2 | CCS_FL_16BIT)
-#define CCS_R_USL_CLOCK_MODE_D_CTRL 0x08d2
+#define CCS_R_TX_USL_APP_BTA_ACK_TIMEOUT CCI_REG16(0x08d2)
+#define CCS_R_TX_USL_SNS_BTA_ACK_TIMEOUT CCI_REG16(0x08d2)
+#define CCS_R_USL_CLOCK_MODE_D_CTRL CCI_REG8(0x08d2)
#define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_STANDBY BIT(0)
#define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_VBLANK BIT(1)
#define CCS_USL_CLOCK_MODE_D_CTRL_CONT_CLOCK_HBLANK BIT(2)
-#define CCS_R_BINNING_MODE 0x0900
-#define CCS_R_BINNING_TYPE 0x0901
-#define CCS_R_BINNING_WEIGHTING 0x0902
-#define CCS_R_DATA_TRANSFER_IF_1_CTRL 0x0a00
+#define CCS_R_BINNING_MODE CCI_REG8(0x0900)
+#define CCS_R_BINNING_TYPE CCI_REG8(0x0901)
+#define CCS_R_BINNING_WEIGHTING CCI_REG8(0x0902)
+#define CCS_R_DATA_TRANSFER_IF_1_CTRL CCI_REG8(0x0a00)
#define CCS_DATA_TRANSFER_IF_1_CTRL_ENABLE BIT(0)
#define CCS_DATA_TRANSFER_IF_1_CTRL_WRITE BIT(1)
#define CCS_DATA_TRANSFER_IF_1_CTRL_CLEAR_ERROR BIT(2)
-#define CCS_R_DATA_TRANSFER_IF_1_STATUS 0x0a01
+#define CCS_R_DATA_TRANSFER_IF_1_STATUS CCI_REG8(0x0a01)
#define CCS_DATA_TRANSFER_IF_1_STATUS_READ_IF_READY BIT(0)
#define CCS_DATA_TRANSFER_IF_1_STATUS_WRITE_IF_READY BIT(1)
#define CCS_DATA_TRANSFER_IF_1_STATUS_DATA_CORRUPTED BIT(2)
#define CCS_DATA_TRANSFER_IF_1_STATUS_IMPROPER_IF_USAGE BIT(3)
-#define CCS_R_DATA_TRANSFER_IF_1_PAGE_SELECT 0x0a02
-#define CCS_R_DATA_TRANSFER_IF_1_DATA(p) (0x0a04 + (p))
+#define CCS_R_DATA_TRANSFER_IF_1_PAGE_SELECT CCI_REG8(0x0a02)
+#define CCS_R_DATA_TRANSFER_IF_1_DATA(p) CCI_REG8(0x0a04 + (p))
#define CCS_LIM_DATA_TRANSFER_IF_1_DATA_MIN_P 0U
#define CCS_LIM_DATA_TRANSFER_IF_1_DATA_MAX_P 63U
-#define CCS_R_SHADING_CORRECTION_EN 0x0b00
+#define CCS_R_SHADING_CORRECTION_EN CCI_REG8(0x0b00)
#define CCS_SHADING_CORRECTION_EN_ENABLE BIT(0)
-#define CCS_R_LUMINANCE_CORRECTION_LEVEL 0x0b01
-#define CCS_R_GREEN_IMBALANCE_FILTER_EN 0x0b02
+#define CCS_R_LUMINANCE_CORRECTION_LEVEL CCI_REG8(0x0b01)
+#define CCS_R_GREEN_IMBALANCE_FILTER_EN CCI_REG8(0x0b02)
#define CCS_GREEN_IMBALANCE_FILTER_EN_ENABLE BIT(0)
-#define CCS_R_MAPPED_DEFECT_CORRECT_EN 0x0b05
+#define CCS_R_MAPPED_DEFECT_CORRECT_EN CCI_REG8(0x0b05)
#define CCS_MAPPED_DEFECT_CORRECT_EN_ENABLE BIT(0)
-#define CCS_R_SINGLE_DEFECT_CORRECT_EN 0x0b06
+#define CCS_R_SINGLE_DEFECT_CORRECT_EN CCI_REG8(0x0b06)
#define CCS_SINGLE_DEFECT_CORRECT_EN_ENABLE BIT(0)
-#define CCS_R_DYNAMIC_COUPLET_CORRECT_EN 0x0b08
+#define CCS_R_DYNAMIC_COUPLET_CORRECT_EN CCI_REG8(0x0b08)
#define CCS_DYNAMIC_COUPLET_CORRECT_EN_ENABLE BIT(0)
-#define CCS_R_COMBINED_DEFECT_CORRECT_EN 0x0b0a
+#define CCS_R_COMBINED_DEFECT_CORRECT_EN CCI_REG8(0x0b0a)
#define CCS_COMBINED_DEFECT_CORRECT_EN_ENABLE BIT(0)
-#define CCS_R_MODULE_SPECIFIC_CORRECTION_EN 0x0b0c
+#define CCS_R_MODULE_SPECIFIC_CORRECTION_EN CCI_REG8(0x0b0c)
#define CCS_MODULE_SPECIFIC_CORRECTION_EN_ENABLE BIT(0)
-#define CCS_R_DYNAMIC_TRIPLET_DEFECT_CORRECT_EN 0x0b13
+#define CCS_R_DYNAMIC_TRIPLET_DEFECT_CORRECT_EN CCI_REG8(0x0b13)
#define CCS_DYNAMIC_TRIPLET_DEFECT_CORRECT_EN_ENABLE BIT(0)
-#define CCS_R_NF_CTRL 0x0b15
+#define CCS_R_NF_CTRL CCI_REG8(0x0b15)
#define CCS_NF_CTRL_LUMA BIT(0)
#define CCS_NF_CTRL_CHROMA BIT(1)
#define CCS_NF_CTRL_COMBINED BIT(2)
-#define CCS_R_OB_READOUT_CONTROL 0x0b30
+#define CCS_R_OB_READOUT_CONTROL CCI_REG8(0x0b30)
#define CCS_OB_READOUT_CONTROL_ENABLE BIT(0)
#define CCS_OB_READOUT_CONTROL_INTERLEAVING BIT(1)
-#define CCS_R_OB_VIRTUAL_CHANNEL 0x0b31
-#define CCS_R_OB_DT 0x0b32
-#define CCS_R_OB_DATA_FORMAT 0x0b33
-#define CCS_R_COLOR_TEMPERATURE (0x0b8c | CCS_FL_16BIT)
-#define CCS_R_ABSOLUTE_GAIN_GREENR (0x0b8e | CCS_FL_16BIT)
-#define CCS_R_ABSOLUTE_GAIN_RED (0x0b90 | CCS_FL_16BIT)
-#define CCS_R_ABSOLUTE_GAIN_BLUE (0x0b92 | CCS_FL_16BIT)
-#define CCS_R_ABSOLUTE_GAIN_GREENB (0x0b94 | CCS_FL_16BIT)
-#define CCS_R_CFA_CONVERSION_CTRL 0x0ba0
+#define CCS_R_OB_VIRTUAL_CHANNEL CCI_REG8(0x0b31)
+#define CCS_R_OB_DT CCI_REG8(0x0b32)
+#define CCS_R_OB_DATA_FORMAT CCI_REG8(0x0b33)
+#define CCS_R_COLOR_TEMPERATURE CCI_REG16(0x0b8c)
+#define CCS_R_ABSOLUTE_GAIN_GREENR CCI_REG16(0x0b8e)
+#define CCS_R_ABSOLUTE_GAIN_RED CCI_REG16(0x0b90)
+#define CCS_R_ABSOLUTE_GAIN_BLUE CCI_REG16(0x0b92)
+#define CCS_R_ABSOLUTE_GAIN_GREENB CCI_REG16(0x0b94)
+#define CCS_R_CFA_CONVERSION_CTRL CCI_REG8(0x0ba0)
#define CCS_CFA_CONVERSION_CTRL_BAYER_CONVERSION_ENABLE BIT(0)
-#define CCS_R_FLASH_STROBE_ADJUSTMENT 0x0c12
-#define CCS_R_FLASH_STROBE_START_POINT (0x0c14 | CCS_FL_16BIT)
-#define CCS_R_TFLASH_STROBE_DELAY_RS_CTRL (0x0c16 | CCS_FL_16BIT)
-#define CCS_R_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL (0x0c18 | CCS_FL_16BIT)
-#define CCS_R_FLASH_MODE_RS 0x0c1a
+#define CCS_R_FLASH_STROBE_ADJUSTMENT CCI_REG8(0x0c12)
+#define CCS_R_FLASH_STROBE_START_POINT CCI_REG16(0x0c14)
+#define CCS_R_TFLASH_STROBE_DELAY_RS_CTRL CCI_REG16(0x0c16)
+#define CCS_R_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL CCI_REG16(0x0c18)
+#define CCS_R_FLASH_MODE_RS CCI_REG8(0x0c1a)
#define CCS_FLASH_MODE_RS_CONTINUOUS BIT(0)
#define CCS_FLASH_MODE_RS_TRUNCATE BIT(1)
#define CCS_FLASH_MODE_RS_ASYNC BIT(3)
-#define CCS_R_FLASH_TRIGGER_RS 0x0c1b
-#define CCS_R_FLASH_STATUS 0x0c1c
+#define CCS_R_FLASH_TRIGGER_RS CCI_REG8(0x0c1b)
+#define CCS_R_FLASH_STATUS CCI_REG8(0x0c1c)
#define CCS_FLASH_STATUS_RETIMED BIT(0)
-#define CCS_R_SA_STROBE_MODE 0x0c1d
+#define CCS_R_SA_STROBE_MODE CCI_REG8(0x0c1d)
#define CCS_SA_STROBE_MODE_CONTINUOUS BIT(0)
#define CCS_SA_STROBE_MODE_TRUNCATE BIT(1)
#define CCS_SA_STROBE_MODE_ASYNC BIT(3)
#define CCS_SA_STROBE_MODE_ADJUST_EDGE BIT(4)
-#define CCS_R_SA_STROBE_START_POINT (0x0c1e | CCS_FL_16BIT)
-#define CCS_R_TSA_STROBE_DELAY_CTRL (0x0c20 | CCS_FL_16BIT)
-#define CCS_R_TSA_STROBE_WIDTH_CTRL (0x0c22 | CCS_FL_16BIT)
-#define CCS_R_SA_STROBE_TRIGGER 0x0c24
-#define CCS_R_SA_STROBE_STATUS 0x0c25
+#define CCS_R_SA_STROBE_START_POINT CCI_REG16(0x0c1e)
+#define CCS_R_TSA_STROBE_DELAY_CTRL CCI_REG16(0x0c20)
+#define CCS_R_TSA_STROBE_WIDTH_CTRL CCI_REG16(0x0c22)
+#define CCS_R_SA_STROBE_TRIGGER CCI_REG8(0x0c24)
+#define CCS_R_SA_STROBE_STATUS CCI_REG8(0x0c25)
#define CCS_SA_STROBE_STATUS_RETIMED BIT(0)
-#define CCS_R_TSA_STROBE_RE_DELAY_CTRL (0x0c30 | CCS_FL_16BIT)
-#define CCS_R_TSA_STROBE_FE_DELAY_CTRL (0x0c32 | CCS_FL_16BIT)
-#define CCS_R_PDAF_CTRL (0x0d00 | CCS_FL_16BIT)
+#define CCS_R_TSA_STROBE_RE_DELAY_CTRL CCI_REG16(0x0c30)
+#define CCS_R_TSA_STROBE_FE_DELAY_CTRL CCI_REG16(0x0c32)
+#define CCS_R_PDAF_CTRL CCI_REG16(0x0d00)
#define CCS_PDAF_CTRL_ENABLE BIT(0)
#define CCS_PDAF_CTRL_PROCESSED BIT(1)
#define CCS_PDAF_CTRL_INTERLEAVED BIT(2)
#define CCS_PDAF_CTRL_VISIBLE_PDAF_CORRECTION BIT(3)
-#define CCS_R_PDAF_VC 0x0d02
-#define CCS_R_PDAF_DT 0x0d03
-#define CCS_R_PD_X_ADDR_START (0x0d04 | CCS_FL_16BIT)
-#define CCS_R_PD_Y_ADDR_START (0x0d06 | CCS_FL_16BIT)
-#define CCS_R_PD_X_ADDR_END (0x0d08 | CCS_FL_16BIT)
-#define CCS_R_PD_Y_ADDR_END (0x0d0a | CCS_FL_16BIT)
-#define CCS_R_BRACKETING_LUT_CTRL 0x0e00
-#define CCS_R_BRACKETING_LUT_MODE 0x0e01
+#define CCS_R_PDAF_VC CCI_REG8(0x0d02)
+#define CCS_R_PDAF_DT CCI_REG8(0x0d03)
+#define CCS_R_PD_X_ADDR_START CCI_REG16(0x0d04)
+#define CCS_R_PD_Y_ADDR_START CCI_REG16(0x0d06)
+#define CCS_R_PD_X_ADDR_END CCI_REG16(0x0d08)
+#define CCS_R_PD_Y_ADDR_END CCI_REG16(0x0d0a)
+#define CCS_R_BRACKETING_LUT_CTRL CCI_REG8(0x0e00)
+#define CCS_R_BRACKETING_LUT_MODE CCI_REG8(0x0e01)
#define CCS_BRACKETING_LUT_MODE_CONTINUE_STREAMING BIT(0)
#define CCS_BRACKETING_LUT_MODE_LOOP_MODE BIT(1)
-#define CCS_R_BRACKETING_LUT_ENTRY_CTRL 0x0e02
-#define CCS_R_BRACKETING_LUT_FRAME(n) (0x0e10 + (n))
+#define CCS_R_BRACKETING_LUT_ENTRY_CTRL CCI_REG8(0x0e02)
+#define CCS_R_BRACKETING_LUT_FRAME(n) CCI_REG8(0x0e10 + (n))
#define CCS_LIM_BRACKETING_LUT_FRAME_MIN_N 0U
#define CCS_LIM_BRACKETING_LUT_FRAME_MAX_N 239U
-#define CCS_R_INTEGRATION_TIME_CAPABILITY (0x1000 | CCS_FL_16BIT)
+#define CCS_R_INTEGRATION_TIME_CAPABILITY CCI_REG16(0x1000)
#define CCS_INTEGRATION_TIME_CAPABILITY_FINE BIT(0)
-#define CCS_R_COARSE_INTEGRATION_TIME_MIN (0x1004 | CCS_FL_16BIT)
-#define CCS_R_COARSE_INTEGRATION_TIME_MAX_MARGIN (0x1006 | CCS_FL_16BIT)
-#define CCS_R_FINE_INTEGRATION_TIME_MIN (0x1008 | CCS_FL_16BIT)
-#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN (0x100a | CCS_FL_16BIT)
-#define CCS_R_DIGITAL_GAIN_CAPABILITY 0x1081
+#define CCS_R_COARSE_INTEGRATION_TIME_MIN CCI_REG16(0x1004)
+#define CCS_R_COARSE_INTEGRATION_TIME_MAX_MARGIN CCI_REG16(0x1006)
+#define CCS_R_FINE_INTEGRATION_TIME_MIN CCI_REG16(0x1008)
+#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN CCI_REG16(0x100a)
+#define CCS_R_DIGITAL_GAIN_CAPABILITY CCI_REG8(0x1081)
#define CCS_DIGITAL_GAIN_CAPABILITY_NONE 0U
#define CCS_DIGITAL_GAIN_CAPABILITY_GLOBAL 2U
-#define CCS_R_DIGITAL_GAIN_MIN (0x1084 | CCS_FL_16BIT)
-#define CCS_R_DIGITAL_GAIN_MAX (0x1086 | CCS_FL_16BIT)
-#define CCS_R_DIGITAL_GAIN_STEP_SIZE (0x1088 | CCS_FL_16BIT)
-#define CCS_R_PEDESTAL_CAPABILITY 0x10e0
-#define CCS_R_ADC_CAPABILITY 0x10f0
+#define CCS_R_DIGITAL_GAIN_MIN CCI_REG16(0x1084)
+#define CCS_R_DIGITAL_GAIN_MAX CCI_REG16(0x1086)
+#define CCS_R_DIGITAL_GAIN_STEP_SIZE CCI_REG16(0x1088)
+#define CCS_R_PEDESTAL_CAPABILITY CCI_REG8(0x10e0)
+#define CCS_R_ADC_CAPABILITY CCI_REG8(0x10f0)
#define CCS_ADC_CAPABILITY_BIT_DEPTH_CTRL BIT(0)
-#define CCS_R_ADC_BIT_DEPTH_CAPABILITY (0x10f4 | CCS_FL_32BIT)
-#define CCS_R_MIN_EXT_CLK_FREQ_MHZ (0x1100 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MAX_EXT_CLK_FREQ_MHZ (0x1104 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MIN_PRE_PLL_CLK_DIV (0x1108 | CCS_FL_16BIT)
-#define CCS_R_MAX_PRE_PLL_CLK_DIV (0x110a | CCS_FL_16BIT)
-#define CCS_R_MIN_PLL_IP_CLK_FREQ_MHZ (0x110c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MAX_PLL_IP_CLK_FREQ_MHZ (0x1110 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MIN_PLL_MULTIPLIER (0x1114 | CCS_FL_16BIT)
-#define CCS_R_MAX_PLL_MULTIPLIER (0x1116 | CCS_FL_16BIT)
-#define CCS_R_MIN_PLL_OP_CLK_FREQ_MHZ (0x1118 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MAX_PLL_OP_CLK_FREQ_MHZ (0x111c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MIN_VT_SYS_CLK_DIV (0x1120 | CCS_FL_16BIT)
-#define CCS_R_MAX_VT_SYS_CLK_DIV (0x1122 | CCS_FL_16BIT)
-#define CCS_R_MIN_VT_SYS_CLK_FREQ_MHZ (0x1124 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MAX_VT_SYS_CLK_FREQ_MHZ (0x1128 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MIN_VT_PIX_CLK_FREQ_MHZ (0x112c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MAX_VT_PIX_CLK_FREQ_MHZ (0x1130 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MIN_VT_PIX_CLK_DIV (0x1134 | CCS_FL_16BIT)
-#define CCS_R_MAX_VT_PIX_CLK_DIV (0x1136 | CCS_FL_16BIT)
-#define CCS_R_CLOCK_CALCULATION 0x1138
+#define CCS_R_ADC_BIT_DEPTH_CAPABILITY CCI_REG32(0x10f4)
+#define CCS_R_MIN_EXT_CLK_FREQ_MHZ (CCI_REG32(0x1100) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MAX_EXT_CLK_FREQ_MHZ (CCI_REG32(0x1104) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MIN_PRE_PLL_CLK_DIV CCI_REG16(0x1108)
+#define CCS_R_MAX_PRE_PLL_CLK_DIV CCI_REG16(0x110a)
+#define CCS_R_MIN_PLL_IP_CLK_FREQ_MHZ (CCI_REG32(0x110c) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MAX_PLL_IP_CLK_FREQ_MHZ (CCI_REG32(0x1110) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MIN_PLL_MULTIPLIER CCI_REG16(0x1114)
+#define CCS_R_MAX_PLL_MULTIPLIER CCI_REG16(0x1116)
+#define CCS_R_MIN_PLL_OP_CLK_FREQ_MHZ (CCI_REG32(0x1118) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MAX_PLL_OP_CLK_FREQ_MHZ (CCI_REG32(0x111c) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MIN_VT_SYS_CLK_DIV CCI_REG16(0x1120)
+#define CCS_R_MAX_VT_SYS_CLK_DIV CCI_REG16(0x1122)
+#define CCS_R_MIN_VT_SYS_CLK_FREQ_MHZ (CCI_REG32(0x1124) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MAX_VT_SYS_CLK_FREQ_MHZ (CCI_REG32(0x1128) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MIN_VT_PIX_CLK_FREQ_MHZ (CCI_REG32(0x112c) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MAX_VT_PIX_CLK_FREQ_MHZ (CCI_REG32(0x1130) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MIN_VT_PIX_CLK_DIV CCI_REG16(0x1134)
+#define CCS_R_MAX_VT_PIX_CLK_DIV CCI_REG16(0x1136)
+#define CCS_R_CLOCK_CALCULATION CCI_REG8(0x1138)
#define CCS_CLOCK_CALCULATION_LANE_SPEED BIT(0)
#define CCS_CLOCK_CALCULATION_LINK_DECOUPLED BIT(1)
#define CCS_CLOCK_CALCULATION_DUAL_PLL_OP_SYS_DDR BIT(2)
#define CCS_CLOCK_CALCULATION_DUAL_PLL_OP_PIX_DDR BIT(3)
-#define CCS_R_NUM_OF_VT_LANES 0x1139
-#define CCS_R_NUM_OF_OP_LANES 0x113a
-#define CCS_R_OP_BITS_PER_LANE 0x113b
-#define CCS_R_MIN_FRAME_LENGTH_LINES (0x1140 | CCS_FL_16BIT)
-#define CCS_R_MAX_FRAME_LENGTH_LINES (0x1142 | CCS_FL_16BIT)
-#define CCS_R_MIN_LINE_LENGTH_PCK (0x1144 | CCS_FL_16BIT)
-#define CCS_R_MAX_LINE_LENGTH_PCK (0x1146 | CCS_FL_16BIT)
-#define CCS_R_MIN_LINE_BLANKING_PCK (0x1148 | CCS_FL_16BIT)
-#define CCS_R_MIN_FRAME_BLANKING_LINES (0x114a | CCS_FL_16BIT)
-#define CCS_R_MIN_LINE_LENGTH_PCK_STEP_SIZE 0x114c
-#define CCS_R_TIMING_MODE_CAPABILITY 0x114d
+#define CCS_R_NUM_OF_VT_LANES CCI_REG8(0x1139)
+#define CCS_R_NUM_OF_OP_LANES CCI_REG8(0x113a)
+#define CCS_R_OP_BITS_PER_LANE CCI_REG8(0x113b)
+#define CCS_R_MIN_FRAME_LENGTH_LINES CCI_REG16(0x1140)
+#define CCS_R_MAX_FRAME_LENGTH_LINES CCI_REG16(0x1142)
+#define CCS_R_MIN_LINE_LENGTH_PCK CCI_REG16(0x1144)
+#define CCS_R_MAX_LINE_LENGTH_PCK CCI_REG16(0x1146)
+#define CCS_R_MIN_LINE_BLANKING_PCK CCI_REG16(0x1148)
+#define CCS_R_MIN_FRAME_BLANKING_LINES CCI_REG16(0x114a)
+#define CCS_R_MIN_LINE_LENGTH_PCK_STEP_SIZE CCI_REG8(0x114c)
+#define CCS_R_TIMING_MODE_CAPABILITY CCI_REG8(0x114d)
#define CCS_TIMING_MODE_CAPABILITY_AUTO_FRAME_LENGTH BIT(0)
#define CCS_TIMING_MODE_CAPABILITY_ROLLING_SHUTTER_MANUAL_READOUT BIT(2)
#define CCS_TIMING_MODE_CAPABILITY_DELAYED_EXPOSURE_START BIT(3)
#define CCS_TIMING_MODE_CAPABILITY_MANUAL_EXPOSURE_EMBEDDED_DATA BIT(4)
-#define CCS_R_FRAME_MARGIN_MAX_VALUE (0x114e | CCS_FL_16BIT)
-#define CCS_R_FRAME_MARGIN_MIN_VALUE 0x1150
-#define CCS_R_GAIN_DELAY_TYPE 0x1151
+#define CCS_R_FRAME_MARGIN_MAX_VALUE CCI_REG16(0x114e)
+#define CCS_R_FRAME_MARGIN_MIN_VALUE CCI_REG8(0x1150)
+#define CCS_R_GAIN_DELAY_TYPE CCI_REG8(0x1151)
#define CCS_GAIN_DELAY_TYPE_FIXED 0U
#define CCS_GAIN_DELAY_TYPE_VARIABLE 1U
-#define CCS_R_MIN_OP_SYS_CLK_DIV (0x1160 | CCS_FL_16BIT)
-#define CCS_R_MAX_OP_SYS_CLK_DIV (0x1162 | CCS_FL_16BIT)
-#define CCS_R_MIN_OP_SYS_CLK_FREQ_MHZ (0x1164 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MAX_OP_SYS_CLK_FREQ_MHZ (0x1168 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MIN_OP_PIX_CLK_DIV (0x116c | CCS_FL_16BIT)
-#define CCS_R_MAX_OP_PIX_CLK_DIV (0x116e | CCS_FL_16BIT)
-#define CCS_R_MIN_OP_PIX_CLK_FREQ_MHZ (0x1170 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MAX_OP_PIX_CLK_FREQ_MHZ (0x1174 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_X_ADDR_MIN (0x1180 | CCS_FL_16BIT)
-#define CCS_R_Y_ADDR_MIN (0x1182 | CCS_FL_16BIT)
-#define CCS_R_X_ADDR_MAX (0x1184 | CCS_FL_16BIT)
-#define CCS_R_Y_ADDR_MAX (0x1186 | CCS_FL_16BIT)
-#define CCS_R_MIN_X_OUTPUT_SIZE (0x1188 | CCS_FL_16BIT)
-#define CCS_R_MIN_Y_OUTPUT_SIZE (0x118a | CCS_FL_16BIT)
-#define CCS_R_MAX_X_OUTPUT_SIZE (0x118c | CCS_FL_16BIT)
-#define CCS_R_MAX_Y_OUTPUT_SIZE (0x118e | CCS_FL_16BIT)
-#define CCS_R_X_ADDR_START_DIV_CONSTANT 0x1190
-#define CCS_R_Y_ADDR_START_DIV_CONSTANT 0x1191
-#define CCS_R_X_ADDR_END_DIV_CONSTANT 0x1192
-#define CCS_R_Y_ADDR_END_DIV_CONSTANT 0x1193
-#define CCS_R_X_SIZE_DIV 0x1194
-#define CCS_R_Y_SIZE_DIV 0x1195
-#define CCS_R_X_OUTPUT_DIV 0x1196
-#define CCS_R_Y_OUTPUT_DIV 0x1197
-#define CCS_R_NON_FLEXIBLE_RESOLUTION_SUPPORT 0x1198
+#define CCS_R_MIN_OP_SYS_CLK_DIV CCI_REG16(0x1160)
+#define CCS_R_MAX_OP_SYS_CLK_DIV CCI_REG16(0x1162)
+#define CCS_R_MIN_OP_SYS_CLK_FREQ_MHZ (CCI_REG32(0x1164) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MAX_OP_SYS_CLK_FREQ_MHZ (CCI_REG32(0x1168) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MIN_OP_PIX_CLK_DIV CCI_REG16(0x116c)
+#define CCS_R_MAX_OP_PIX_CLK_DIV CCI_REG16(0x116e)
+#define CCS_R_MIN_OP_PIX_CLK_FREQ_MHZ (CCI_REG32(0x1170) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MAX_OP_PIX_CLK_FREQ_MHZ (CCI_REG32(0x1174) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_X_ADDR_MIN CCI_REG16(0x1180)
+#define CCS_R_Y_ADDR_MIN CCI_REG16(0x1182)
+#define CCS_R_X_ADDR_MAX CCI_REG16(0x1184)
+#define CCS_R_Y_ADDR_MAX CCI_REG16(0x1186)
+#define CCS_R_MIN_X_OUTPUT_SIZE CCI_REG16(0x1188)
+#define CCS_R_MIN_Y_OUTPUT_SIZE CCI_REG16(0x118a)
+#define CCS_R_MAX_X_OUTPUT_SIZE CCI_REG16(0x118c)
+#define CCS_R_MAX_Y_OUTPUT_SIZE CCI_REG16(0x118e)
+#define CCS_R_X_ADDR_START_DIV_CONSTANT CCI_REG8(0x1190)
+#define CCS_R_Y_ADDR_START_DIV_CONSTANT CCI_REG8(0x1191)
+#define CCS_R_X_ADDR_END_DIV_CONSTANT CCI_REG8(0x1192)
+#define CCS_R_Y_ADDR_END_DIV_CONSTANT CCI_REG8(0x1193)
+#define CCS_R_X_SIZE_DIV CCI_REG8(0x1194)
+#define CCS_R_Y_SIZE_DIV CCI_REG8(0x1195)
+#define CCS_R_X_OUTPUT_DIV CCI_REG8(0x1196)
+#define CCS_R_Y_OUTPUT_DIV CCI_REG8(0x1197)
+#define CCS_R_NON_FLEXIBLE_RESOLUTION_SUPPORT CCI_REG8(0x1198)
#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_NEW_PIX_ADDR BIT(0)
#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_NEW_OUTPUT_RES BIT(1)
#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_OUTPUT_CROP_NO_PAD BIT(2)
#define CCS_NON_FLEXIBLE_RESOLUTION_SUPPORT_OUTPUT_SIZE_LANE_DEP BIT(3)
-#define CCS_R_MIN_OP_PRE_PLL_CLK_DIV (0x11a0 | CCS_FL_16BIT)
-#define CCS_R_MAX_OP_PRE_PLL_CLK_DIV (0x11a2 | CCS_FL_16BIT)
-#define CCS_R_MIN_OP_PLL_IP_CLK_FREQ_MHZ (0x11a4 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MAX_OP_PLL_IP_CLK_FREQ_MHZ (0x11a8 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MIN_OP_PLL_MULTIPLIER (0x11ac | CCS_FL_16BIT)
-#define CCS_R_MAX_OP_PLL_MULTIPLIER (0x11ae | CCS_FL_16BIT)
-#define CCS_R_MIN_OP_PLL_OP_CLK_FREQ_MHZ (0x11b0 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MAX_OP_PLL_OP_CLK_FREQ_MHZ (0x11b4 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_CLOCK_TREE_PLL_CAPABILITY 0x11b8
+#define CCS_R_MIN_OP_PRE_PLL_CLK_DIV CCI_REG16(0x11a0)
+#define CCS_R_MAX_OP_PRE_PLL_CLK_DIV CCI_REG16(0x11a2)
+#define CCS_R_MIN_OP_PLL_IP_CLK_FREQ_MHZ (CCI_REG32(0x11a4) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MAX_OP_PLL_IP_CLK_FREQ_MHZ (CCI_REG32(0x11a8) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MIN_OP_PLL_MULTIPLIER CCI_REG16(0x11ac)
+#define CCS_R_MAX_OP_PLL_MULTIPLIER CCI_REG16(0x11ae)
+#define CCS_R_MIN_OP_PLL_OP_CLK_FREQ_MHZ (CCI_REG32(0x11b0) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MAX_OP_PLL_OP_CLK_FREQ_MHZ (CCI_REG32(0x11b4) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_CLOCK_TREE_PLL_CAPABILITY CCI_REG8(0x11b8)
#define CCS_CLOCK_TREE_PLL_CAPABILITY_DUAL_PLL BIT(0)
#define CCS_CLOCK_TREE_PLL_CAPABILITY_SINGLE_PLL BIT(1)
#define CCS_CLOCK_TREE_PLL_CAPABILITY_EXT_DIVIDER BIT(2)
#define CCS_CLOCK_TREE_PLL_CAPABILITY_FLEXIBLE_OP_PIX_CLK_DIV BIT(3)
-#define CCS_R_CLOCK_CAPA_TYPE_CAPABILITY 0x11b9
+#define CCS_R_CLOCK_CAPA_TYPE_CAPABILITY CCI_REG8(0x11b9)
#define CCS_CLOCK_CAPA_TYPE_CAPABILITY_IREAL BIT(0)
-#define CCS_R_MIN_EVEN_INC (0x11c0 | CCS_FL_16BIT)
-#define CCS_R_MIN_ODD_INC (0x11c2 | CCS_FL_16BIT)
-#define CCS_R_MAX_EVEN_INC (0x11c4 | CCS_FL_16BIT)
-#define CCS_R_MAX_ODD_INC (0x11c6 | CCS_FL_16BIT)
-#define CCS_R_AUX_SUBSAMP_CAPABILITY 0x11c8
+#define CCS_R_MIN_EVEN_INC CCI_REG16(0x11c0)
+#define CCS_R_MIN_ODD_INC CCI_REG16(0x11c2)
+#define CCS_R_MAX_EVEN_INC CCI_REG16(0x11c4)
+#define CCS_R_MAX_ODD_INC CCI_REG16(0x11c6)
+#define CCS_R_AUX_SUBSAMP_CAPABILITY CCI_REG8(0x11c8)
#define CCS_AUX_SUBSAMP_CAPABILITY_FACTOR_POWER_OF_2 BIT(1)
-#define CCS_R_AUX_SUBSAMP_MONO_CAPABILITY 0x11c9
+#define CCS_R_AUX_SUBSAMP_MONO_CAPABILITY CCI_REG8(0x11c9)
#define CCS_AUX_SUBSAMP_MONO_CAPABILITY_FACTOR_POWER_OF_2 BIT(1)
-#define CCS_R_MONOCHROME_CAPABILITY 0x11ca
+#define CCS_R_MONOCHROME_CAPABILITY CCI_REG8(0x11ca)
#define CCS_MONOCHROME_CAPABILITY_INC_ODD 0U
#define CCS_MONOCHROME_CAPABILITY_INC_EVEN 1U
-#define CCS_R_PIXEL_READOUT_CAPABILITY 0x11cb
+#define CCS_R_PIXEL_READOUT_CAPABILITY CCI_REG8(0x11cb)
#define CCS_PIXEL_READOUT_CAPABILITY_BAYER 0U
#define CCS_PIXEL_READOUT_CAPABILITY_MONOCHROME 1U
#define CCS_PIXEL_READOUT_CAPABILITY_BAYER_AND_MONO 2U
-#define CCS_R_MIN_EVEN_INC_MONO (0x11cc | CCS_FL_16BIT)
-#define CCS_R_MAX_EVEN_INC_MONO (0x11ce | CCS_FL_16BIT)
-#define CCS_R_MIN_ODD_INC_MONO (0x11d0 | CCS_FL_16BIT)
-#define CCS_R_MAX_ODD_INC_MONO (0x11d2 | CCS_FL_16BIT)
-#define CCS_R_MIN_EVEN_INC_BC2 (0x11d4 | CCS_FL_16BIT)
-#define CCS_R_MAX_EVEN_INC_BC2 (0x11d6 | CCS_FL_16BIT)
-#define CCS_R_MIN_ODD_INC_BC2 (0x11d8 | CCS_FL_16BIT)
-#define CCS_R_MAX_ODD_INC_BC2 (0x11da | CCS_FL_16BIT)
-#define CCS_R_MIN_EVEN_INC_MONO_BC2 (0x11dc | CCS_FL_16BIT)
-#define CCS_R_MAX_EVEN_INC_MONO_BC2 (0x11de | CCS_FL_16BIT)
-#define CCS_R_MIN_ODD_INC_MONO_BC2 (0x11f0 | CCS_FL_16BIT)
-#define CCS_R_MAX_ODD_INC_MONO_BC2 (0x11f2 | CCS_FL_16BIT)
-#define CCS_R_SCALING_CAPABILITY (0x1200 | CCS_FL_16BIT)
+#define CCS_R_MIN_EVEN_INC_MONO CCI_REG16(0x11cc)
+#define CCS_R_MAX_EVEN_INC_MONO CCI_REG16(0x11ce)
+#define CCS_R_MIN_ODD_INC_MONO CCI_REG16(0x11d0)
+#define CCS_R_MAX_ODD_INC_MONO CCI_REG16(0x11d2)
+#define CCS_R_MIN_EVEN_INC_BC2 CCI_REG16(0x11d4)
+#define CCS_R_MAX_EVEN_INC_BC2 CCI_REG16(0x11d6)
+#define CCS_R_MIN_ODD_INC_BC2 CCI_REG16(0x11d8)
+#define CCS_R_MAX_ODD_INC_BC2 CCI_REG16(0x11da)
+#define CCS_R_MIN_EVEN_INC_MONO_BC2 CCI_REG16(0x11dc)
+#define CCS_R_MAX_EVEN_INC_MONO_BC2 CCI_REG16(0x11de)
+#define CCS_R_MIN_ODD_INC_MONO_BC2 CCI_REG16(0x11f0)
+#define CCS_R_MAX_ODD_INC_MONO_BC2 CCI_REG16(0x11f2)
+#define CCS_R_SCALING_CAPABILITY CCI_REG16(0x1200)
#define CCS_SCALING_CAPABILITY_NONE 0U
#define CCS_SCALING_CAPABILITY_HORIZONTAL 1U
#define CCS_SCALING_CAPABILITY_RESERVED 2U
-#define CCS_R_SCALER_M_MIN (0x1204 | CCS_FL_16BIT)
-#define CCS_R_SCALER_M_MAX (0x1206 | CCS_FL_16BIT)
-#define CCS_R_SCALER_N_MIN (0x1208 | CCS_FL_16BIT)
-#define CCS_R_SCALER_N_MAX (0x120a | CCS_FL_16BIT)
-#define CCS_R_DIGITAL_CROP_CAPABILITY 0x120e
+#define CCS_R_SCALER_M_MIN CCI_REG16(0x1204)
+#define CCS_R_SCALER_M_MAX CCI_REG16(0x1206)
+#define CCS_R_SCALER_N_MIN CCI_REG16(0x1208)
+#define CCS_R_SCALER_N_MAX CCI_REG16(0x120a)
+#define CCS_R_DIGITAL_CROP_CAPABILITY CCI_REG8(0x120e)
#define CCS_DIGITAL_CROP_CAPABILITY_NONE 0U
#define CCS_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1U
-#define CCS_R_HDR_CAPABILITY_1 0x1210
+#define CCS_R_HDR_CAPABILITY_1 CCI_REG8(0x1210)
#define CCS_HDR_CAPABILITY_1_2X2_BINNING BIT(0)
#define CCS_HDR_CAPABILITY_1_COMBINED_ANALOG_GAIN BIT(1)
#define CCS_HDR_CAPABILITY_1_SEPARATE_ANALOG_GAIN BIT(2)
@@ -611,66 +611,66 @@
#define CCS_HDR_CAPABILITY_1_RESET_SYNC BIT(4)
#define CCS_HDR_CAPABILITY_1_DIRECT_SHORT_EXP_TIMING BIT(5)
#define CCS_HDR_CAPABILITY_1_DIRECT_SHORT_EXP_SYNTHESIS BIT(6)
-#define CCS_R_MIN_HDR_BIT_DEPTH 0x1211
-#define CCS_R_HDR_RESOLUTION_SUB_TYPES 0x1212
-#define CCS_R_HDR_RESOLUTION_SUB_TYPE(n) (0x1213 + (n))
+#define CCS_R_MIN_HDR_BIT_DEPTH CCI_REG8(0x1211)
+#define CCS_R_HDR_RESOLUTION_SUB_TYPES CCI_REG8(0x1212)
+#define CCS_R_HDR_RESOLUTION_SUB_TYPE(n) CCI_REG8(0x1213 + (n))
#define CCS_LIM_HDR_RESOLUTION_SUB_TYPE_MIN_N 0U
#define CCS_LIM_HDR_RESOLUTION_SUB_TYPE_MAX_N 1U
#define CCS_HDR_RESOLUTION_SUB_TYPE_ROW_SHIFT 0U
#define CCS_HDR_RESOLUTION_SUB_TYPE_ROW_MASK 0xf
#define CCS_HDR_RESOLUTION_SUB_TYPE_COLUMN_SHIFT 4U
#define CCS_HDR_RESOLUTION_SUB_TYPE_COLUMN_MASK 0xf0
-#define CCS_R_HDR_CAPABILITY_2 0x121b
+#define CCS_R_HDR_CAPABILITY_2 CCI_REG8(0x121b)
#define CCS_HDR_CAPABILITY_2_COMBINED_DIGITAL_GAIN BIT(0)
#define CCS_HDR_CAPABILITY_2_SEPARATE_DIGITAL_GAIN BIT(1)
#define CCS_HDR_CAPABILITY_2_TIMING_MODE BIT(3)
#define CCS_HDR_CAPABILITY_2_SYNTHESIS_MODE BIT(4)
-#define CCS_R_MAX_HDR_BIT_DEPTH 0x121c
-#define CCS_R_USL_SUPPORT_CAPABILITY 0x1230
+#define CCS_R_MAX_HDR_BIT_DEPTH CCI_REG8(0x121c)
+#define CCS_R_USL_SUPPORT_CAPABILITY CCI_REG8(0x1230)
#define CCS_USL_SUPPORT_CAPABILITY_CLOCK_TREE BIT(0)
#define CCS_USL_SUPPORT_CAPABILITY_REV_CLOCK_TREE BIT(1)
#define CCS_USL_SUPPORT_CAPABILITY_REV_CLOCK_CALC BIT(2)
-#define CCS_R_USL_CLOCK_MODE_D_CAPABILITY 0x1231
+#define CCS_R_USL_CLOCK_MODE_D_CAPABILITY CCI_REG8(0x1231)
#define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_STANDBY BIT(0)
#define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_VBLANK BIT(1)
#define CCS_USL_CLOCK_MODE_D_CAPABILITY_CONT_CLOCK_HBLANK BIT(2)
#define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_STANDBY BIT(3)
#define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_VBLANK BIT(4)
#define CCS_USL_CLOCK_MODE_D_CAPABILITY_NONCONT_CLOCK_HBLANK BIT(5)
-#define CCS_R_MIN_OP_SYS_CLK_DIV_REV 0x1234
-#define CCS_R_MAX_OP_SYS_CLK_DIV_REV 0x1236
-#define CCS_R_MIN_OP_PIX_CLK_DIV_REV 0x1238
-#define CCS_R_MAX_OP_PIX_CLK_DIV_REV 0x123a
-#define CCS_R_MIN_OP_SYS_CLK_FREQ_REV_MHZ (0x123c | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MAX_OP_SYS_CLK_FREQ_REV_MHZ (0x1240 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MIN_OP_PIX_CLK_FREQ_REV_MHZ (0x1244 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MAX_OP_PIX_CLK_FREQ_REV_MHZ (0x1248 | (CCS_FL_32BIT | CCS_FL_FLOAT_IREAL))
-#define CCS_R_MAX_BITRATE_REV_D_MODE_MBPS (0x124c | (CCS_FL_32BIT | CCS_FL_IREAL))
-#define CCS_R_MAX_SYMRATE_REV_C_MODE_MSPS (0x1250 | (CCS_FL_32BIT | CCS_FL_IREAL))
-#define CCS_R_COMPRESSION_CAPABILITY 0x1300
+#define CCS_R_MIN_OP_SYS_CLK_DIV_REV CCI_REG8(0x1234)
+#define CCS_R_MAX_OP_SYS_CLK_DIV_REV CCI_REG8(0x1236)
+#define CCS_R_MIN_OP_PIX_CLK_DIV_REV CCI_REG8(0x1238)
+#define CCS_R_MAX_OP_PIX_CLK_DIV_REV CCI_REG8(0x123a)
+#define CCS_R_MIN_OP_SYS_CLK_FREQ_REV_MHZ (CCI_REG32(0x123c) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MAX_OP_SYS_CLK_FREQ_REV_MHZ (CCI_REG32(0x1240) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MIN_OP_PIX_CLK_FREQ_REV_MHZ (CCI_REG32(0x1244) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MAX_OP_PIX_CLK_FREQ_REV_MHZ (CCI_REG32(0x1248) | CCS_FL_FLOAT_IREAL)
+#define CCS_R_MAX_BITRATE_REV_D_MODE_MBPS (CCI_REG32(0x124c) | CCS_FL_IREAL)
+#define CCS_R_MAX_SYMRATE_REV_C_MODE_MSPS (CCI_REG32(0x1250) | CCS_FL_IREAL)
+#define CCS_R_COMPRESSION_CAPABILITY CCI_REG8(0x1300)
#define CCS_COMPRESSION_CAPABILITY_DPCM_PCM_SIMPLE BIT(0)
-#define CCS_R_TEST_MODE_CAPABILITY (0x1310 | CCS_FL_16BIT)
+#define CCS_R_TEST_MODE_CAPABILITY CCI_REG16(0x1310)
#define CCS_TEST_MODE_CAPABILITY_SOLID_COLOR BIT(0)
#define CCS_TEST_MODE_CAPABILITY_COLOR_BARS BIT(1)
#define CCS_TEST_MODE_CAPABILITY_FADE_TO_GREY BIT(2)
#define CCS_TEST_MODE_CAPABILITY_PN9 BIT(3)
#define CCS_TEST_MODE_CAPABILITY_COLOR_TILE BIT(5)
-#define CCS_R_PN9_DATA_FORMAT1 0x1312
-#define CCS_R_PN9_DATA_FORMAT2 0x1313
-#define CCS_R_PN9_DATA_FORMAT3 0x1314
-#define CCS_R_PN9_DATA_FORMAT4 0x1315
-#define CCS_R_PN9_MISC_CAPABILITY 0x1316
+#define CCS_R_PN9_DATA_FORMAT1 CCI_REG8(0x1312)
+#define CCS_R_PN9_DATA_FORMAT2 CCI_REG8(0x1313)
+#define CCS_R_PN9_DATA_FORMAT3 CCI_REG8(0x1314)
+#define CCS_R_PN9_DATA_FORMAT4 CCI_REG8(0x1315)
+#define CCS_R_PN9_MISC_CAPABILITY CCI_REG8(0x1316)
#define CCS_PN9_MISC_CAPABILITY_NUM_PIXELS_SHIFT 0U
#define CCS_PN9_MISC_CAPABILITY_NUM_PIXELS_MASK 0x7
#define CCS_PN9_MISC_CAPABILITY_COMPRESSION BIT(3)
-#define CCS_R_TEST_PATTERN_CAPABILITY 0x1317
+#define CCS_R_TEST_PATTERN_CAPABILITY CCI_REG8(0x1317)
#define CCS_TEST_PATTERN_CAPABILITY_NO_REPEAT BIT(1)
-#define CCS_R_PATTERN_SIZE_DIV_M1 0x1318
-#define CCS_R_FIFO_SUPPORT_CAPABILITY 0x1502
+#define CCS_R_PATTERN_SIZE_DIV_M1 CCI_REG8(0x1318)
+#define CCS_R_FIFO_SUPPORT_CAPABILITY CCI_REG8(0x1502)
#define CCS_FIFO_SUPPORT_CAPABILITY_NONE 0U
#define CCS_FIFO_SUPPORT_CAPABILITY_DERATING 1U
#define CCS_FIFO_SUPPORT_CAPABILITY_DERATING_OVERRATING 2U
-#define CCS_R_PHY_CTRL_CAPABILITY 0x1600
+#define CCS_R_PHY_CTRL_CAPABILITY CCI_REG8(0x1600)
#define CCS_PHY_CTRL_CAPABILITY_AUTO_PHY_CTL BIT(0)
#define CCS_PHY_CTRL_CAPABILITY_UI_PHY_CTL BIT(1)
#define CCS_PHY_CTRL_CAPABILITY_DPHY_TIME_UI_REG_1_CTL BIT(2)
@@ -679,7 +679,7 @@
#define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_UI_REG_1_CTL BIT(5)
#define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_UI_REG_2_CTL BIT(6)
#define CCS_PHY_CTRL_CAPABILITY_DPHY_EXT_TIME_CTL BIT(7)
-#define CCS_R_CSI_DPHY_LANE_MODE_CAPABILITY 0x1601
+#define CCS_R_CSI_DPHY_LANE_MODE_CAPABILITY CCI_REG8(0x1601)
#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_1_LANE BIT(0)
#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_2_LANE BIT(1)
#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_3_LANE BIT(2)
@@ -688,22 +688,22 @@
#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_6_LANE BIT(5)
#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_7_LANE BIT(6)
#define CCS_CSI_DPHY_LANE_MODE_CAPABILITY_8_LANE BIT(7)
-#define CCS_R_CSI_SIGNALING_MODE_CAPABILITY 0x1602
+#define CCS_R_CSI_SIGNALING_MODE_CAPABILITY CCI_REG8(0x1602)
#define CCS_CSI_SIGNALING_MODE_CAPABILITY_CSI_DPHY BIT(2)
#define CCS_CSI_SIGNALING_MODE_CAPABILITY_CSI_CPHY BIT(3)
-#define CCS_R_FAST_STANDBY_CAPABILITY 0x1603
+#define CCS_R_FAST_STANDBY_CAPABILITY CCI_REG8(0x1603)
#define CCS_FAST_STANDBY_CAPABILITY_NO_FRAME_TRUNCATION 0U
#define CCS_FAST_STANDBY_CAPABILITY_FRAME_TRUNCATION 1U
-#define CCS_R_CSI_ADDRESS_CONTROL_CAPABILITY 0x1604
+#define CCS_R_CSI_ADDRESS_CONTROL_CAPABILITY CCI_REG8(0x1604)
#define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_CCI_ADDR_CHANGE BIT(0)
#define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_2ND_CCI_ADDR BIT(1)
#define CCS_CSI_ADDRESS_CONTROL_CAPABILITY_SW_CHANGEABLE_2ND_CCI_ADDR BIT(2)
-#define CCS_R_DATA_TYPE_CAPABILITY 0x1605
+#define CCS_R_DATA_TYPE_CAPABILITY CCI_REG8(0x1605)
#define CCS_DATA_TYPE_CAPABILITY_DPCM_PROGRAMMABLE BIT(0)
#define CCS_DATA_TYPE_CAPABILITY_BOTTOM_EMBEDDED_DT_PROGRAMMABLE BIT(1)
#define CCS_DATA_TYPE_CAPABILITY_BOTTOM_EMBEDDED_VC_PROGRAMMABLE BIT(2)
#define CCS_DATA_TYPE_CAPABILITY_EXT_VC_RANGE BIT(3)
-#define CCS_R_CSI_CPHY_LANE_MODE_CAPABILITY 0x1606
+#define CCS_R_CSI_CPHY_LANE_MODE_CAPABILITY CCI_REG8(0x1606)
#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_1_LANE BIT(0)
#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_2_LANE BIT(1)
#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_3_LANE BIT(2)
@@ -712,44 +712,44 @@
#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_6_LANE BIT(5)
#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_7_LANE BIT(6)
#define CCS_CSI_CPHY_LANE_MODE_CAPABILITY_8_LANE BIT(7)
-#define CCS_R_EMB_DATA_CAPABILITY 0x1607
+#define CCS_R_EMB_DATA_CAPABILITY CCI_REG8(0x1607)
#define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW16 BIT(0)
#define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW20 BIT(1)
#define CCS_EMB_DATA_CAPABILITY_TWO_BYTES_PER_RAW24 BIT(2)
#define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW16 BIT(3)
#define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW20 BIT(4)
#define CCS_EMB_DATA_CAPABILITY_NO_ONE_BYTE_PER_RAW24 BIT(5)
-#define CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(n) ((0x1608 | (CCS_FL_32BIT | CCS_FL_IREAL)) + ((n) < 4 ? (n) * 4 : 0x32 + ((n) - 4) * 4))
+#define CCS_R_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS(n) (CCI_REG32(0x1608 + ((n) < 4 ? (n) * 4 : 0x32 + ((n) - 4) * 4)) | CCS_FL_IREAL)
#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_MIN_N 0U
#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_D_MODE_MBPS_MAX_N 7U
-#define CCS_R_TEMP_SENSOR_CAPABILITY 0x1618
+#define CCS_R_TEMP_SENSOR_CAPABILITY CCI_REG8(0x1618)
#define CCS_TEMP_SENSOR_CAPABILITY_SUPPORTED BIT(0)
#define CCS_TEMP_SENSOR_CAPABILITY_CCS_FORMAT BIT(1)
#define CCS_TEMP_SENSOR_CAPABILITY_RESET_0X80 BIT(2)
-#define CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(n) ((0x161a | (CCS_FL_32BIT | CCS_FL_IREAL)) + ((n) < 4 ? (n) * 4 : 0x30 + ((n) - 4) * 4))
+#define CCS_R_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS(n) (CCI_REG32(0x161a + ((n) < 4 ? (n) * 4 : 0x30 + ((n) - 4) * 4)) | CCS_FL_IREAL)
#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_MIN_N 0U
#define CCS_LIM_MAX_PER_LANE_BITRATE_LANE_C_MODE_MBPS_MAX_N 7U
-#define CCS_R_DPHY_EQUALIZATION_CAPABILITY 0x162b
+#define CCS_R_DPHY_EQUALIZATION_CAPABILITY CCI_REG8(0x162b)
#define CCS_DPHY_EQUALIZATION_CAPABILITY_EQUALIZATION_CTRL BIT(0)
#define CCS_DPHY_EQUALIZATION_CAPABILITY_EQ1 BIT(1)
#define CCS_DPHY_EQUALIZATION_CAPABILITY_EQ2 BIT(2)
-#define CCS_R_CPHY_EQUALIZATION_CAPABILITY 0x162c
+#define CCS_R_CPHY_EQUALIZATION_CAPABILITY CCI_REG8(0x162c)
#define CCS_CPHY_EQUALIZATION_CAPABILITY_EQUALIZATION_CTRL BIT(0)
-#define CCS_R_DPHY_PREAMBLE_CAPABILITY 0x162d
+#define CCS_R_DPHY_PREAMBLE_CAPABILITY CCI_REG8(0x162d)
#define CCS_DPHY_PREAMBLE_CAPABILITY_PREAMBLE_SEQ_CTRL BIT(0)
-#define CCS_R_DPHY_SSC_CAPABILITY 0x162e
+#define CCS_R_DPHY_SSC_CAPABILITY CCI_REG8(0x162e)
#define CCS_DPHY_SSC_CAPABILITY_SUPPORTED BIT(0)
-#define CCS_R_CPHY_CALIBRATION_CAPABILITY 0x162f
+#define CCS_R_CPHY_CALIBRATION_CAPABILITY CCI_REG8(0x162f)
#define CCS_CPHY_CALIBRATION_CAPABILITY_MANUAL BIT(0)
#define CCS_CPHY_CALIBRATION_CAPABILITY_MANUAL_STREAMING BIT(1)
#define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_1_CTRL BIT(2)
#define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_2_CTRL BIT(3)
#define CCS_CPHY_CALIBRATION_CAPABILITY_FORMAT_3_CTRL BIT(4)
-#define CCS_R_DPHY_CALIBRATION_CAPABILITY 0x1630
+#define CCS_R_DPHY_CALIBRATION_CAPABILITY CCI_REG8(0x1630)
#define CCS_DPHY_CALIBRATION_CAPABILITY_MANUAL BIT(0)
#define CCS_DPHY_CALIBRATION_CAPABILITY_MANUAL_STREAMING BIT(1)
#define CCS_DPHY_CALIBRATION_CAPABILITY_ALTERNATE_SEQ BIT(2)
-#define CCS_R_PHY_CTRL_CAPABILITY_2 0x1631
+#define CCS_R_PHY_CTRL_CAPABILITY_2 CCI_REG8(0x1631)
#define CCS_PHY_CTRL_CAPABILITY_2_TGR_LENGTH BIT(0)
#define CCS_PHY_CTRL_CAPABILITY_2_TGR_PREAMBLE_PROG_SEQ BIT(1)
#define CCS_PHY_CTRL_CAPABILITY_2_EXTRA_CPHY_MANUAL_TIMING BIT(2)
@@ -758,13 +758,13 @@
#define CCS_PHY_CTRL_CAPABILITY_2_CLOCK_BASED_MANUAL_CPHY BIT(5)
#define CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_DPHY BIT(6)
#define CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_CPHY BIT(7)
-#define CCS_R_LRTE_CPHY_CAPABILITY 0x1632
+#define CCS_R_LRTE_CPHY_CAPABILITY CCI_REG8(0x1632)
#define CCS_LRTE_CPHY_CAPABILITY_PDQ_SHORT BIT(0)
#define CCS_LRTE_CPHY_CAPABILITY_SPACER_SHORT BIT(1)
#define CCS_LRTE_CPHY_CAPABILITY_PDQ_LONG BIT(2)
#define CCS_LRTE_CPHY_CAPABILITY_SPACER_LONG BIT(3)
#define CCS_LRTE_CPHY_CAPABILITY_SPACER_NO_PDQ BIT(4)
-#define CCS_R_LRTE_DPHY_CAPABILITY 0x1633
+#define CCS_R_LRTE_DPHY_CAPABILITY CCI_REG8(0x1633)
#define CCS_LRTE_DPHY_CAPABILITY_PDQ_SHORT_OPT1 BIT(0)
#define CCS_LRTE_DPHY_CAPABILITY_SPACER_SHORT_OPT1 BIT(1)
#define CCS_LRTE_DPHY_CAPABILITY_PDQ_LONG_OPT1 BIT(2)
@@ -773,18 +773,18 @@
#define CCS_LRTE_DPHY_CAPABILITY_SPACER_LONG_OPT2 BIT(5)
#define CCS_LRTE_DPHY_CAPABILITY_SPACER_NO_PDQ_OPT1 BIT(6)
#define CCS_LRTE_DPHY_CAPABILITY_SPACER_VARIABLE_OPT2 BIT(7)
-#define CCS_R_ALPS_CAPABILITY_DPHY 0x1634
+#define CCS_R_ALPS_CAPABILITY_DPHY CCI_REG8(0x1634)
#define CCS_ALPS_CAPABILITY_DPHY_LVLP_NOT_SUPPORTED 0U
#define CCS_ALPS_CAPABILITY_DPHY_LVLP_SUPPORTED 1U
#define CCS_ALPS_CAPABILITY_DPHY_CONTROLLABLE_LVLP 2U
-#define CCS_R_ALPS_CAPABILITY_CPHY 0x1635
+#define CCS_R_ALPS_CAPABILITY_CPHY CCI_REG8(0x1635)
#define CCS_ALPS_CAPABILITY_CPHY_LVLP_NOT_SUPPORTED 0U
#define CCS_ALPS_CAPABILITY_CPHY_LVLP_SUPPORTED 1U
#define CCS_ALPS_CAPABILITY_CPHY_CONTROLLABLE_LVLP 2U
#define CCS_ALPS_CAPABILITY_CPHY_ALP_NOT_SUPPORTED 0xc
#define CCS_ALPS_CAPABILITY_CPHY_ALP_SUPPORTED 0xd
#define CCS_ALPS_CAPABILITY_CPHY_CONTROLLABLE_ALP 0xe
-#define CCS_R_SCRAMBLING_CAPABILITY 0x1636
+#define CCS_R_SCRAMBLING_CAPABILITY CCI_REG8(0x1636)
#define CCS_SCRAMBLING_CAPABILITY_SCRAMBLING_SUPPORTED BIT(0)
#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_SHIFT 1U
#define CCS_SCRAMBLING_CAPABILITY_MAX_SEEDS_PER_LANE_C_MASK 0x6
@@ -796,11 +796,11 @@
#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_1 1U
#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_REGS_4 4U
#define CCS_SCRAMBLING_CAPABILITY_NUM_SEED_PER_LANE BIT(6)
-#define CCS_R_DPHY_MANUAL_CONSTANT 0x1637
-#define CCS_R_CPHY_MANUAL_CONSTANT 0x1638
-#define CCS_R_CSI2_INTERFACE_CAPABILITY_MISC 0x1639
+#define CCS_R_DPHY_MANUAL_CONSTANT CCI_REG8(0x1637)
+#define CCS_R_CPHY_MANUAL_CONSTANT CCI_REG8(0x1638)
+#define CCS_R_CSI2_INTERFACE_CAPABILITY_MISC CCI_REG8(0x1639)
#define CCS_CSI2_INTERFACE_CAPABILITY_MISC_EOTP_SHORT_PKT_OPT2 BIT(0)
-#define CCS_R_PHY_CTRL_CAPABILITY_3 0x165c
+#define CCS_R_PHY_CTRL_CAPABILITY_3 CCI_REG8(0x165c)
#define CCS_PHY_CTRL_CAPABILITY_3_DPHY_TIMING_NOT_MULTIPLE BIT(0)
#define CCS_PHY_CTRL_CAPABILITY_3_DPHY_MIN_TIMING_VALUE_1 BIT(1)
#define CCS_PHY_CTRL_CAPABILITY_3_TWAKEUP_SUPPORTED BIT(2)
@@ -808,130 +808,130 @@
#define CCS_PHY_CTRL_CAPABILITY_3_THS_EXIT_SUPPORTED BIT(4)
#define CCS_PHY_CTRL_CAPABILITY_3_CPHY_TIMING_NOT_MULTIPLE BIT(5)
#define CCS_PHY_CTRL_CAPABILITY_3_CPHY_MIN_TIMING_VALUE_1 BIT(6)
-#define CCS_R_DPHY_SF 0x165d
-#define CCS_R_CPHY_SF 0x165e
+#define CCS_R_DPHY_SF CCI_REG8(0x165d)
+#define CCS_R_CPHY_SF CCI_REG8(0x165e)
#define CCS_CPHY_SF_TWAKEUP_SHIFT 0U
#define CCS_CPHY_SF_TWAKEUP_MASK 0xf
#define CCS_CPHY_SF_TINIT_SHIFT 4U
#define CCS_CPHY_SF_TINIT_MASK 0xf0
-#define CCS_R_DPHY_LIMITS_1 0x165f
+#define CCS_R_DPHY_LIMITS_1 CCI_REG8(0x165f)
#define CCS_DPHY_LIMITS_1_THS_PREPARE_SHIFT 0U
#define CCS_DPHY_LIMITS_1_THS_PREPARE_MASK 0xf
#define CCS_DPHY_LIMITS_1_THS_ZERO_SHIFT 4U
#define CCS_DPHY_LIMITS_1_THS_ZERO_MASK 0xf0
-#define CCS_R_DPHY_LIMITS_2 0x1660
+#define CCS_R_DPHY_LIMITS_2 CCI_REG8(0x1660)
#define CCS_DPHY_LIMITS_2_THS_TRAIL_SHIFT 0U
#define CCS_DPHY_LIMITS_2_THS_TRAIL_MASK 0xf
#define CCS_DPHY_LIMITS_2_TCLK_TRAIL_MIN_SHIFT 4U
#define CCS_DPHY_LIMITS_2_TCLK_TRAIL_MIN_MASK 0xf0
-#define CCS_R_DPHY_LIMITS_3 0x1661
+#define CCS_R_DPHY_LIMITS_3 CCI_REG8(0x1661)
#define CCS_DPHY_LIMITS_3_TCLK_PREPARE_SHIFT 0U
#define CCS_DPHY_LIMITS_3_TCLK_PREPARE_MASK 0xf
#define CCS_DPHY_LIMITS_3_TCLK_ZERO_SHIFT 4U
#define CCS_DPHY_LIMITS_3_TCLK_ZERO_MASK 0xf0
-#define CCS_R_DPHY_LIMITS_4 0x1662
+#define CCS_R_DPHY_LIMITS_4 CCI_REG8(0x1662)
#define CCS_DPHY_LIMITS_4_TCLK_POST_SHIFT 0U
#define CCS_DPHY_LIMITS_4_TCLK_POST_MASK 0xf
#define CCS_DPHY_LIMITS_4_TLPX_SHIFT 4U
#define CCS_DPHY_LIMITS_4_TLPX_MASK 0xf0
-#define CCS_R_DPHY_LIMITS_5 0x1663
+#define CCS_R_DPHY_LIMITS_5 CCI_REG8(0x1663)
#define CCS_DPHY_LIMITS_5_THS_EXIT_SHIFT 0U
#define CCS_DPHY_LIMITS_5_THS_EXIT_MASK 0xf
#define CCS_DPHY_LIMITS_5_TWAKEUP_SHIFT 4U
#define CCS_DPHY_LIMITS_5_TWAKEUP_MASK 0xf0
-#define CCS_R_DPHY_LIMITS_6 0x1664
+#define CCS_R_DPHY_LIMITS_6 CCI_REG8(0x1664)
#define CCS_DPHY_LIMITS_6_TINIT_SHIFT 0U
#define CCS_DPHY_LIMITS_6_TINIT_MASK 0xf
-#define CCS_R_CPHY_LIMITS_1 0x1665
+#define CCS_R_CPHY_LIMITS_1 CCI_REG8(0x1665)
#define CCS_CPHY_LIMITS_1_T3_PREPARE_MAX_SHIFT 0U
#define CCS_CPHY_LIMITS_1_T3_PREPARE_MAX_MASK 0xf
#define CCS_CPHY_LIMITS_1_T3_LPX_MAX_SHIFT 4U
#define CCS_CPHY_LIMITS_1_T3_LPX_MAX_MASK 0xf0
-#define CCS_R_CPHY_LIMITS_2 0x1666
+#define CCS_R_CPHY_LIMITS_2 CCI_REG8(0x1666)
#define CCS_CPHY_LIMITS_2_THS_EXIT_MAX_SHIFT 0U
#define CCS_CPHY_LIMITS_2_THS_EXIT_MAX_MASK 0xf
#define CCS_CPHY_LIMITS_2_TWAKEUP_MAX_SHIFT 4U
#define CCS_CPHY_LIMITS_2_TWAKEUP_MAX_MASK 0xf0
-#define CCS_R_CPHY_LIMITS_3 0x1667
+#define CCS_R_CPHY_LIMITS_3 CCI_REG8(0x1667)
#define CCS_CPHY_LIMITS_3_TINIT_MAX_SHIFT 0U
#define CCS_CPHY_LIMITS_3_TINIT_MAX_MASK 0xf
-#define CCS_R_MIN_FRAME_LENGTH_LINES_BIN (0x1700 | CCS_FL_16BIT)
-#define CCS_R_MAX_FRAME_LENGTH_LINES_BIN (0x1702 | CCS_FL_16BIT)
-#define CCS_R_MIN_LINE_LENGTH_PCK_BIN (0x1704 | CCS_FL_16BIT)
-#define CCS_R_MAX_LINE_LENGTH_PCK_BIN (0x1706 | CCS_FL_16BIT)
-#define CCS_R_MIN_LINE_BLANKING_PCK_BIN (0x1708 | CCS_FL_16BIT)
-#define CCS_R_FINE_INTEGRATION_TIME_MIN_BIN (0x170a | CCS_FL_16BIT)
-#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN (0x170c | CCS_FL_16BIT)
-#define CCS_R_BINNING_CAPABILITY 0x1710
+#define CCS_R_MIN_FRAME_LENGTH_LINES_BIN CCI_REG16(0x1700)
+#define CCS_R_MAX_FRAME_LENGTH_LINES_BIN CCI_REG16(0x1702)
+#define CCS_R_MIN_LINE_LENGTH_PCK_BIN CCI_REG16(0x1704)
+#define CCS_R_MAX_LINE_LENGTH_PCK_BIN CCI_REG16(0x1706)
+#define CCS_R_MIN_LINE_BLANKING_PCK_BIN CCI_REG16(0x1708)
+#define CCS_R_FINE_INTEGRATION_TIME_MIN_BIN CCI_REG16(0x170a)
+#define CCS_R_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN CCI_REG16(0x170c)
+#define CCS_R_BINNING_CAPABILITY CCI_REG8(0x1710)
#define CCS_BINNING_CAPABILITY_UNSUPPORTED 0U
#define CCS_BINNING_CAPABILITY_BINNING_THEN_SUBSAMPLING 1U
#define CCS_BINNING_CAPABILITY_SUBSAMPLING_THEN_BINNING 2U
-#define CCS_R_BINNING_WEIGHTING_CAPABILITY 0x1711
+#define CCS_R_BINNING_WEIGHTING_CAPABILITY CCI_REG8(0x1711)
#define CCS_BINNING_WEIGHTING_CAPABILITY_AVERAGED BIT(0)
#define CCS_BINNING_WEIGHTING_CAPABILITY_SUMMED BIT(1)
#define CCS_BINNING_WEIGHTING_CAPABILITY_BAYER_CORRECTED BIT(2)
#define CCS_BINNING_WEIGHTING_CAPABILITY_MODULE_SPECIFIC_WEIGHT BIT(3)
-#define CCS_R_BINNING_SUB_TYPES 0x1712
-#define CCS_R_BINNING_SUB_TYPE(n) (0x1713 + (n))
+#define CCS_R_BINNING_SUB_TYPES CCI_REG8(0x1712)
+#define CCS_R_BINNING_SUB_TYPE(n) CCI_REG8(0x1713 + (n))
#define CCS_LIM_BINNING_SUB_TYPE_MIN_N 0U
#define CCS_LIM_BINNING_SUB_TYPE_MAX_N 63U
#define CCS_BINNING_SUB_TYPE_ROW_SHIFT 0U
#define CCS_BINNING_SUB_TYPE_ROW_MASK 0xf
#define CCS_BINNING_SUB_TYPE_COLUMN_SHIFT 4U
#define CCS_BINNING_SUB_TYPE_COLUMN_MASK 0xf0
-#define CCS_R_BINNING_WEIGHTING_MONO_CAPABILITY 0x1771
+#define CCS_R_BINNING_WEIGHTING_MONO_CAPABILITY CCI_REG8(0x1771)
#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_AVERAGED BIT(0)
#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_SUMMED BIT(1)
#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_BAYER_CORRECTED BIT(2)
#define CCS_BINNING_WEIGHTING_MONO_CAPABILITY_MODULE_SPECIFIC_WEIGHT BIT(3)
-#define CCS_R_BINNING_SUB_TYPES_MONO 0x1772
-#define CCS_R_BINNING_SUB_TYPE_MONO(n) (0x1773 + (n))
+#define CCS_R_BINNING_SUB_TYPES_MONO CCI_REG8(0x1772)
+#define CCS_R_BINNING_SUB_TYPE_MONO(n) CCI_REG8(0x1773 + (n))
#define CCS_LIM_BINNING_SUB_TYPE_MONO_MIN_N 0U
#define CCS_LIM_BINNING_SUB_TYPE_MONO_MAX_N 63U
-#define CCS_R_DATA_TRANSFER_IF_CAPABILITY 0x1800
+#define CCS_R_DATA_TRANSFER_IF_CAPABILITY CCI_REG8(0x1800)
#define CCS_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED BIT(0)
#define CCS_DATA_TRANSFER_IF_CAPABILITY_POLLING BIT(2)
-#define CCS_R_SHADING_CORRECTION_CAPABILITY 0x1900
+#define CCS_R_SHADING_CORRECTION_CAPABILITY CCI_REG8(0x1900)
#define CCS_SHADING_CORRECTION_CAPABILITY_COLOR_SHADING BIT(0)
#define CCS_SHADING_CORRECTION_CAPABILITY_LUMINANCE_CORRECTION BIT(1)
-#define CCS_R_GREEN_IMBALANCE_CAPABILITY 0x1901
+#define CCS_R_GREEN_IMBALANCE_CAPABILITY CCI_REG8(0x1901)
#define CCS_GREEN_IMBALANCE_CAPABILITY_SUPPORTED BIT(0)
-#define CCS_R_MODULE_SPECIFIC_CORRECTION_CAPABILITY 0x1903
-#define CCS_R_DEFECT_CORRECTION_CAPABILITY (0x1904 | CCS_FL_16BIT)
+#define CCS_R_MODULE_SPECIFIC_CORRECTION_CAPABILITY CCI_REG8(0x1903)
+#define CCS_R_DEFECT_CORRECTION_CAPABILITY CCI_REG16(0x1904)
#define CCS_DEFECT_CORRECTION_CAPABILITY_MAPPED_DEFECT BIT(0)
#define CCS_DEFECT_CORRECTION_CAPABILITY_DYNAMIC_COUPLET BIT(2)
#define CCS_DEFECT_CORRECTION_CAPABILITY_DYNAMIC_SINGLE BIT(5)
#define CCS_DEFECT_CORRECTION_CAPABILITY_COMBINED_DYNAMIC BIT(8)
-#define CCS_R_DEFECT_CORRECTION_CAPABILITY_2 (0x1906 | CCS_FL_16BIT)
+#define CCS_R_DEFECT_CORRECTION_CAPABILITY_2 CCI_REG16(0x1906)
#define CCS_DEFECT_CORRECTION_CAPABILITY_2_DYNAMIC_TRIPLET BIT(3)
-#define CCS_R_NF_CAPABILITY 0x1908
+#define CCS_R_NF_CAPABILITY CCI_REG8(0x1908)
#define CCS_NF_CAPABILITY_LUMA BIT(0)
#define CCS_NF_CAPABILITY_CHROMA BIT(1)
#define CCS_NF_CAPABILITY_COMBINED BIT(2)
-#define CCS_R_OB_READOUT_CAPABILITY 0x1980
+#define CCS_R_OB_READOUT_CAPABILITY CCI_REG8(0x1980)
#define CCS_OB_READOUT_CAPABILITY_CONTROLLABLE_READOUT BIT(0)
#define CCS_OB_READOUT_CAPABILITY_VISIBLE_PIXEL_READOUT BIT(1)
#define CCS_OB_READOUT_CAPABILITY_DIFFERENT_VC_READOUT BIT(2)
#define CCS_OB_READOUT_CAPABILITY_DIFFERENT_DT_READOUT BIT(3)
#define CCS_OB_READOUT_CAPABILITY_PROG_DATA_FORMAT BIT(4)
-#define CCS_R_COLOR_FEEDBACK_CAPABILITY 0x1987
+#define CCS_R_COLOR_FEEDBACK_CAPABILITY CCI_REG8(0x1987)
#define CCS_COLOR_FEEDBACK_CAPABILITY_KELVIN BIT(0)
#define CCS_COLOR_FEEDBACK_CAPABILITY_AWB_GAIN BIT(1)
-#define CCS_R_CFA_PATTERN_CAPABILITY 0x1990
+#define CCS_R_CFA_PATTERN_CAPABILITY CCI_REG8(0x1990)
#define CCS_CFA_PATTERN_CAPABILITY_BAYER 0U
#define CCS_CFA_PATTERN_CAPABILITY_MONOCHROME 1U
#define CCS_CFA_PATTERN_CAPABILITY_4X4_QUAD_BAYER 2U
#define CCS_CFA_PATTERN_CAPABILITY_VENDOR_SPECIFIC 3U
-#define CCS_R_CFA_PATTERN_CONVERSION_CAPABILITY 0x1991
+#define CCS_R_CFA_PATTERN_CONVERSION_CAPABILITY CCI_REG8(0x1991)
#define CCS_CFA_PATTERN_CONVERSION_CAPABILITY_BAYER BIT(0)
-#define CCS_R_FLASH_MODE_CAPABILITY 0x1a02
+#define CCS_R_FLASH_MODE_CAPABILITY CCI_REG8(0x1a02)
#define CCS_FLASH_MODE_CAPABILITY_SINGLE_STROBE BIT(0)
-#define CCS_R_SA_STROBE_MODE_CAPABILITY 0x1a03
+#define CCS_R_SA_STROBE_MODE_CAPABILITY CCI_REG8(0x1a03)
#define CCS_SA_STROBE_MODE_CAPABILITY_FIXED_WIDTH BIT(0)
#define CCS_SA_STROBE_MODE_CAPABILITY_EDGE_CTRL BIT(1)
-#define CCS_R_RESET_MAX_DELAY 0x1a10
-#define CCS_R_RESET_MIN_TIME 0x1a11
-#define CCS_R_PDAF_CAPABILITY_1 0x1b80
+#define CCS_R_RESET_MAX_DELAY CCI_REG8(0x1a10)
+#define CCS_R_RESET_MIN_TIME CCI_REG8(0x1a11)
+#define CCS_R_PDAF_CAPABILITY_1 CCI_REG8(0x1b80)
#define CCS_PDAF_CAPABILITY_1_SUPPORTED BIT(0)
#define CCS_PDAF_CAPABILITY_1_PROCESSED_BOTTOM_EMBEDDED BIT(1)
#define CCS_PDAF_CAPABILITY_1_PROCESSED_INTERLEAVED BIT(2)
@@ -940,19 +940,19 @@
#define CCS_PDAF_CAPABILITY_1_VISIBLE_PDAF_CORRECTION BIT(5)
#define CCS_PDAF_CAPABILITY_1_VC_INTERLEAVING BIT(6)
#define CCS_PDAF_CAPABILITY_1_DT_INTERLEAVING BIT(7)
-#define CCS_R_PDAF_CAPABILITY_2 0x1b81
+#define CCS_R_PDAF_CAPABILITY_2 CCI_REG8(0x1b81)
#define CCS_PDAF_CAPABILITY_2_ROI BIT(0)
#define CCS_PDAF_CAPABILITY_2_AFTER_DIGITAL_CROP BIT(1)
#define CCS_PDAF_CAPABILITY_2_CTRL_RETIMED BIT(2)
-#define CCS_R_BRACKETING_LUT_CAPABILITY_1 0x1c00
+#define CCS_R_BRACKETING_LUT_CAPABILITY_1 CCI_REG8(0x1c00)
#define CCS_BRACKETING_LUT_CAPABILITY_1_COARSE_INTEGRATION BIT(0)
#define CCS_BRACKETING_LUT_CAPABILITY_1_GLOBAL_ANALOG_GAIN BIT(1)
#define CCS_BRACKETING_LUT_CAPABILITY_1_FLASH BIT(4)
#define CCS_BRACKETING_LUT_CAPABILITY_1_GLOBAL_DIGITAL_GAIN BIT(5)
#define CCS_BRACKETING_LUT_CAPABILITY_1_ALTERNATE_GLOBAL_ANALOG_GAIN BIT(6)
-#define CCS_R_BRACKETING_LUT_CAPABILITY_2 0x1c01
+#define CCS_R_BRACKETING_LUT_CAPABILITY_2 CCI_REG8(0x1c01)
#define CCS_BRACKETING_LUT_CAPABILITY_2_SINGLE_BRACKETING_MODE BIT(0)
#define CCS_BRACKETING_LUT_CAPABILITY_2_LOOPED_BRACKETING_MODE BIT(1)
-#define CCS_R_BRACKETING_LUT_SIZE 0x1c02
+#define CCS_R_BRACKETING_LUT_SIZE CCI_REG8(0x1c02)
#endif /* __CCS_REGS_H__ */
diff --git a/drivers/media/i2c/ccs/ccs.h b/drivers/media/i2c/ccs/ccs.h
index 9c3587b2fbe7..096573845a10 100644
--- a/drivers/media/i2c/ccs/ccs.h
+++ b/drivers/media/i2c/ccs/ccs.h
@@ -13,6 +13,7 @@
#define __CCS_H__
#include <linux/mutex.h>
+#include <linux/regmap.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
@@ -211,6 +212,7 @@ struct ccs_sensor {
struct clk *ext_clk;
struct gpio_desc *xshutdown;
struct gpio_desc *reset;
+ struct regmap *regmap;
void *ccs_limits;
u8 nbinning_subtypes;
struct ccs_binning_subtype binning_subtypes[CCS_LIM_BINNING_SUB_TYPE_MAX_N + 1];
@@ -236,6 +238,7 @@ struct ccs_sensor {
bool streaming;
bool dev_init_done;
+ bool handler_setup_needed;
u8 compressed_min_bpp;
struct ccs_module_info minfo;
diff --git a/drivers/media/i2c/ccs/smiapp-reg-defs.h b/drivers/media/i2c/ccs/smiapp-reg-defs.h
index 177e3e51207a..ebd0f90e1092 100644
--- a/drivers/media/i2c/ccs/smiapp-reg-defs.h
+++ b/drivers/media/i2c/ccs/smiapp-reg-defs.h
@@ -12,481 +12,484 @@
#ifndef __SMIAPP_REG_DEFS_H__
#define __SMIAPP_REG_DEFS_H__
+#include <linux/bits.h>
+#include <media/v4l2-cci.h>
+
/* Register addresses */
-#define SMIAPP_REG_U16_MODEL_ID (0x0000 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR 0x0002
-#define SMIAPP_REG_U8_MANUFACTURER_ID 0x0003
-#define SMIAPP_REG_U8_SMIA_VERSION 0x0004
-#define SMIAPP_REG_U8_FRAME_COUNT 0x0005
-#define SMIAPP_REG_U8_PIXEL_ORDER 0x0006
-#define SMIAPP_REG_U16_DATA_PEDESTAL (0x0008 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_PIXEL_DEPTH 0x000c
-#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR 0x0010
-#define SMIAPP_REG_U8_SMIAPP_VERSION 0x0011
-#define SMIAPP_REG_U8_MODULE_DATE_YEAR 0x0012
-#define SMIAPP_REG_U8_MODULE_DATE_MONTH 0x0013
-#define SMIAPP_REG_U8_MODULE_DATE_DAY 0x0014
-#define SMIAPP_REG_U8_MODULE_DATE_PHASE 0x0015
-#define SMIAPP_REG_U16_SENSOR_MODEL_ID (0x0016 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER 0x0018
-#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID 0x0019
-#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION 0x001a
-#define SMIAPP_REG_U32_SERIAL_NUMBER (0x001c | CCS_FL_32BIT)
-#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE 0x0040
-#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE 0x0041
-#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n) ((0x0042 + ((n) << 1)) | CCS_FL_16BIT) /* 0 <= n <= 14 */
-#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n) ((0x0060 + ((n) << 2)) | CCS_FL_32BIT) /* 0 <= n <= 7 */
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY (0x0080 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN (0x0084 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX (0x0086 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP (0x0088 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE (0x008a | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0 (0x008c | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0 (0x008e | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1 (0x0090 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1 (0x0092 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE 0x00c0
-#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE 0x00c1
-#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n) ((0x00c2 + ((n) << 1)) | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_MODE_SELECT 0x0100
-#define SMIAPP_REG_U8_IMAGE_ORIENTATION 0x0101
-#define SMIAPP_REG_U8_SOFTWARE_RESET 0x0103
-#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD 0x0104
-#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES 0x0105
-#define SMIAPP_REG_U8_FAST_STANDBY_CTRL 0x0106
-#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL 0x0107
-#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL 0x0108
-#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL 0x0109
-#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER 0x0110
-#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE 0x0111
-#define SMIAPP_REG_U16_CSI_DATA_FORMAT (0x0112 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_CSI_LANE_MODE 0x0114
-#define SMIAPP_REG_U8_CSI2_10_TO_8_DT 0x0115
-#define SMIAPP_REG_U8_CSI2_10_TO_7_DT 0x0116
-#define SMIAPP_REG_U8_CSI2_10_TO_6_DT 0x0117
-#define SMIAPP_REG_U8_CSI2_12_TO_8_DT 0x0118
-#define SMIAPP_REG_U8_CSI2_12_TO_7_DT 0x0119
-#define SMIAPP_REG_U8_CSI2_12_TO_6_DT 0x011a
-#define SMIAPP_REG_U8_CSI2_14_TO_10_DT 0x011b
-#define SMIAPP_REG_U8_CSI2_14_TO_8_DT 0x011c
-#define SMIAPP_REG_U8_CSI2_16_TO_10_DT 0x011d
-#define SMIAPP_REG_U8_CSI2_16_TO_8_DT 0x011e
-#define SMIAPP_REG_U8_GAIN_MODE 0x0120
-#define SMIAPP_REG_U16_VANA_VOLTAGE (0x0130 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_VDIG_VOLTAGE (0x0132 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_VIO_VOLTAGE (0x0134 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ (0x0136 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL 0x0138
-#define SMIAPP_REG_U8_TEMP_SENSOR_MODE 0x0139
-#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT 0x013a
-#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME (0x0200 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME (0x0202 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL (0x0204 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR (0x0206 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED (0x0208 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE (0x020a | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB (0x020c | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR (0x020e | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_RED (0x0210 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE (0x0212 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB (0x0214 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_VT_PIX_CLK_DIV (0x0300 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_VT_SYS_CLK_DIV (0x0302 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV (0x0304 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_PLL_MULTIPLIER (0x0306 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_OP_PIX_CLK_DIV (0x0308 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_OP_SYS_CLK_DIV (0x030a | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_FRAME_LENGTH_LINES (0x0340 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_LINE_LENGTH_PCK (0x0342 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_X_ADDR_START (0x0344 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_Y_ADDR_START (0x0346 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_X_ADDR_END (0x0348 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_Y_ADDR_END (0x034a | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_X_OUTPUT_SIZE (0x034c | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_Y_OUTPUT_SIZE (0x034e | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_X_EVEN_INC (0x0380 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_X_ODD_INC (0x0382 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_Y_EVEN_INC (0x0384 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_Y_ODD_INC (0x0386 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_SCALING_MODE (0x0400 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_SPATIAL_SAMPLING (0x0402 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_SCALE_M (0x0404 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_SCALE_N (0x0406 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET (0x0408 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET (0x040a | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH (0x040c | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT (0x040e | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_COMPRESSION_MODE (0x0500 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TEST_PATTERN_MODE (0x0600 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TEST_DATA_RED (0x0602 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TEST_DATA_GREENR (0x0604 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TEST_DATA_BLUE (0x0606 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TEST_DATA_GREENB (0x0608 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH (0x060a | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION (0x060c | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH (0x060e | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION (0x0610 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS (0x0700 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_TCLK_POST 0x0800
-#define SMIAPP_REG_U8_THS_PREPARE 0x0801
-#define SMIAPP_REG_U8_THS_ZERO_MIN 0x0802
-#define SMIAPP_REG_U8_THS_TRAIL 0x0803
-#define SMIAPP_REG_U8_TCLK_TRAIL_MIN 0x0804
-#define SMIAPP_REG_U8_TCLK_PREPARE 0x0805
-#define SMIAPP_REG_U8_TCLK_ZERO 0x0806
-#define SMIAPP_REG_U8_TLPX 0x0807
-#define SMIAPP_REG_U8_DPHY_CTRL 0x0808
-#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS (0x0820 | CCS_FL_32BIT)
-#define SMIAPP_REG_U8_BINNING_MODE 0x0900
-#define SMIAPP_REG_U8_BINNING_TYPE 0x0901
-#define SMIAPP_REG_U8_BINNING_WEIGHTING 0x0902
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL 0x0a00
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS 0x0a01
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT 0x0a02
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 0x0a04
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1 0x0a05
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2 0x0a06
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3 0x0a07
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4 0x0a08
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5 0x0a09
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12 0x0a10
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13 0x0a11
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14 0x0a12
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15 0x0a13
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16 0x0a14
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17 0x0a15
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18 0x0a16
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19 0x0a17
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20 0x0a18
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21 0x0a19
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22 0x0a1a
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23 0x0a1b
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24 0x0a1c
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25 0x0a1d
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26 0x0a1e
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27 0x0a1f
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28 0x0a20
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29 0x0a21
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30 0x0a22
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31 0x0a23
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32 0x0a24
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33 0x0a25
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34 0x0a26
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35 0x0a27
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36 0x0a28
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37 0x0a29
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38 0x0a2a
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39 0x0a2b
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40 0x0a2c
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41 0x0a2d
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42 0x0a2e
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43 0x0a2f
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44 0x0a30
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45 0x0a31
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46 0x0a32
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47 0x0a33
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48 0x0a34
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49 0x0a35
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50 0x0a36
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51 0x0a37
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52 0x0a38
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53 0x0a39
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54 0x0a3a
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55 0x0a3b
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56 0x0a3c
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57 0x0a3d
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58 0x0a3e
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59 0x0a3f
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60 0x0a40
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61 0x0a41
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62 0x0a42
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63 0x0a43
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL 0x0a44
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS 0x0a45
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT 0x0a46
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0 0x0a48
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1 0x0a49
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2 0x0a4a
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3 0x0a4b
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4 0x0a4c
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5 0x0a4d
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6 0x0a4e
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7 0x0a4f
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8 0x0a50
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9 0x0a51
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10 0x0a52
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11 0x0a53
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12 0x0a54
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13 0x0a55
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14 0x0a56
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15 0x0a57
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16 0x0a58
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17 0x0a59
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18 0x0a5a
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19 0x0a5b
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20 0x0a5c
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21 0x0a5d
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22 0x0a5e
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23 0x0a5f
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24 0x0a60
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25 0x0a61
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26 0x0a62
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27 0x0a63
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28 0x0a64
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29 0x0a65
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30 0x0a66
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31 0x0a67
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32 0x0a68
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33 0x0a69
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34 0x0a6a
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35 0x0a6b
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36 0x0a6c
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37 0x0a6d
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38 0x0a6e
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39 0x0a6f
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40 0x0a70
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41 0x0a71
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42 0x0a72
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43 0x0a73
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44 0x0a74
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45 0x0a75
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46 0x0a76
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47 0x0a77
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48 0x0a78
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49 0x0a79
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50 0x0a7a
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51 0x0a7b
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52 0x0a7c
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53 0x0a7d
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54 0x0a7e
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55 0x0a7f
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56 0x0a80
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57 0x0a81
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58 0x0a82
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59 0x0a83
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60 0x0a84
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61 0x0a85
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62 0x0a86
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63 0x0a87
-#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE 0x0b00
-#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL 0x0b01
-#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE 0x0b02
-#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT 0x0b03
-#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE 0x0b04
-#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE 0x0b05
-#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE 0x0b06
-#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT 0x0b07
-#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE 0x0b08
-#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT 0x0b09
-#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE 0x0b0a
-#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT 0x0b0b
-#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE 0x0b0c
-#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT 0x0b0d
-#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE 0x0b0e
-#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST 0x0b0f
-#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST 0x0b10
-#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE 0x0b11
-#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST 0x0b12
-#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE 0x0b13
-#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST 0x0b14
-#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE 0x0b15
-#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST 0x0b16
-#define SMIAPP_REG_U8_EDOF_MODE 0x0b80
-#define SMIAPP_REG_U8_SHARPNESS 0x0b83
-#define SMIAPP_REG_U8_DENOISING 0x0b84
-#define SMIAPP_REG_U8_MODULE_SPECIFIC 0x0b85
-#define SMIAPP_REG_U16_DEPTH_OF_FIELD (0x0b86 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_FOCUS_DISTANCE (0x0b88 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL 0x0b8a
-#define SMIAPP_REG_U16_COLOUR_TEMPERATURE (0x0b8c | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR (0x0b8e | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED (0x0b90 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE (0x0b92 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB (0x0b94 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE 0x0bc0
-#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING (0x0bc2 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START (0x0bc4 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START (0x0bc6 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH (0x0bc8 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT (0x0bca | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1 0x0c00
-#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2 0x0c01
-#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1 0x0c02
-#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2 0x0c03
-#define SMIAPP_REG_U16_TRDY_CTRL (0x0c04 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TRDOUT_CTRL (0x0c06 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL (0x0c08 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL (0x0c0a | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL (0x0c0c | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL (0x0c0e | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL (0x0c10 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT 0x0c12
-#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT (0x0c14 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL (0x0c16 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL (0x0c18 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_FLASH_MODE_RS 0x0c1a
-#define SMIAPP_REG_U8_FLASH_TRIGGER_RS 0x0c1b
-#define SMIAPP_REG_U8_FLASH_STATUS 0x0c1c
-#define SMIAPP_REG_U8_SA_STROBE_MODE 0x0c1d
-#define SMIAPP_REG_U16_SA_STROBE_START_POINT (0x0c1e | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL (0x0c20 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL (0x0c22 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_SA_STROBE_TRIGGER 0x0c24
-#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS 0x0c25
-#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL (0x0c26 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL (0x0c28 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL 0x0c2a
-#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL 0x0c2b
-#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL (0x0c2c | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL (0x0c2e | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_LOW_LEVEL_CTRL 0x0c80
-#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT (0x0c82 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAIN_TRIGGER_T3 (0x0c84 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT 0x0c86
-#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3 (0x0c88 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT 0x0c8a
-#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3 (0x0c8c | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT 0x0c8e
-#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL 0x0d00
-#define SMIAPP_REG_U8_OPERATION_MODE 0x0d01
-#define SMIAPP_REG_U8_ACT_STATE1 0x0d02
-#define SMIAPP_REG_U8_ACT_STATE2 0x0d03
-#define SMIAPP_REG_U16_FOCUS_CHANGE (0x0d80 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL (0x0d82 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1 (0x0d84 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2 (0x0d86 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1 0x0d88
-#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2 0x0d89
-#define SMIAPP_REG_U8_POSITION 0x0d8a
-#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL 0x0e00
-#define SMIAPP_REG_U8_BRACKETING_LUT_MODE 0x0e01
-#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL 0x0e02
-#define SMIAPP_REG_U8_LUT_PARAMETERS_START 0x0e10
-#define SMIAPP_REG_U8_LUT_PARAMETERS_END 0x0eff
-#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY (0x1000 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN (0x1004 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN (0x1006 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN (0x1008 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN (0x100a | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY (0x1080 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN (0x1084 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX (0x1086 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE (0x1088 | CCS_FL_16BIT)
-#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ (0x1100 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ (0x1104 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV (0x1108 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV (0x110a | CCS_FL_16BIT)
-#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ (0x110c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ (0x1110 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER (0x1114 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER (0x1116 | CCS_FL_16BIT)
-#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ (0x1118 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ (0x111c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV (0x1120 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV (0x1122 | CCS_FL_16BIT)
-#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ (0x1124 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ (0x1128 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ (0x112c | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ (0x1130 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV (0x1134 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV (0x1136 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES (0x1140 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES (0x1142 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK (0x1144 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK (0x1146 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK (0x1148 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES (0x114a | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE 0x114c
-#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV (0x1160 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV (0x1162 | CCS_FL_16BIT)
-#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ (0x1164 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ (0x1168 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV (0x116c | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV (0x116e | CCS_FL_16BIT)
-#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ (0x1170 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ (0x1174 | CCS_FL_FLOAT_IREAL | CCS_FL_32BIT)
-#define SMIAPP_REG_U16_X_ADDR_MIN (0x1180 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_Y_ADDR_MIN (0x1182 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_X_ADDR_MAX (0x1184 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_Y_ADDR_MAX (0x1186 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE (0x1188 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE (0x118a | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE (0x118c | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE (0x118e | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MIN_EVEN_INC (0x11c0 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_EVEN_INC (0x11c2 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MIN_ODD_INC (0x11c4 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_ODD_INC (0x11c6 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_SCALING_CAPABILITY (0x1200 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_SCALER_M_MIN (0x1204 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_SCALER_M_MAX (0x1206 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_SCALER_N_MIN (0x1208 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_SCALER_N_MAX (0x120a | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY (0x120c | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY 0x120e
-#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY (0x1300 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED (0x1400 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED (0x1402 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED (0x1404 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN (0x1406 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN (0x1408 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN (0x140a | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE (0x140c | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE (0x140e | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE (0x1410 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS (0x1500 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY 0x1502
-#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY 0x1600
-#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY 0x1601
-#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY 0x1602
-#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY 0x1603
-#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY 0x1604
-#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS (0x1608 | CCS_FL_32BIT)
-#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS (0x160c | CCS_FL_32BIT)
-#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS (0x1610 | CCS_FL_32BIT)
-#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS (0x1614 | CCS_FL_32BIT)
-#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY 0x1618
-#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN (0x1700 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN (0x1702 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN (0x1704 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN (0x1706 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN (0x1708 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN (0x170a | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN (0x170c | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_BINNING_CAPABILITY 0x1710
-#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY 0x1711
-#define SMIAPP_REG_U8_BINNING_SUBTYPES 0x1712
-#define SMIAPP_REG_U8_BINNING_TYPE_n(n) (0x1713 + (n)) /* 1 <= n <= 237 */
-#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY 0x1800
-#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY 0x1900
-#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY 0x1901
-#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY 0x1902
-#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY 0x1903
-#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY (0x1904 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2 (0x1906 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_EDOF_CAPABILITY 0x1980
-#define SMIAPP_REG_U8_ESTIMATION_FRAMES 0x1981
-#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ 0x1982
-#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ 0x1983
-#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ 0x1984
-#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ 0x1985
-#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ 0x1986
-#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY 0x1987
-#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM 0x1988
-#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY 0x19c0
-#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY 0x19c1
-#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD (0x19c2 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE (0x19c4 | CCS_FL_16BIT)
-#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN (0x1a00 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY 0x1a02
-#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR (0x1b02 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY 0x1b04
-#define SMIAPP_REG_U16_ACTUATOR_TYPE (0x1b40 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS 0x1b42
-#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS (0x1b44 | CCS_FL_16BIT)
-#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1 0x1c00
-#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2 0x1c01
-#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE 0x1c02
+#define SMIAPP_REG_U16_MODEL_ID CCI_REG16(0x0000)
+#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR CCI_REG8(0x0002)
+#define SMIAPP_REG_U8_MANUFACTURER_ID CCI_REG8(0x0003)
+#define SMIAPP_REG_U8_SMIA_VERSION CCI_REG8(0x0004)
+#define SMIAPP_REG_U8_FRAME_COUNT CCI_REG8(0x0005)
+#define SMIAPP_REG_U8_PIXEL_ORDER CCI_REG8(0x0006)
+#define SMIAPP_REG_U16_DATA_PEDESTAL CCI_REG16(0x0008)
+#define SMIAPP_REG_U8_PIXEL_DEPTH CCI_REG8(0x000c)
+#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR CCI_REG8(0x0010)
+#define SMIAPP_REG_U8_SMIAPP_VERSION CCI_REG8(0x0011)
+#define SMIAPP_REG_U8_MODULE_DATE_YEAR CCI_REG8(0x0012)
+#define SMIAPP_REG_U8_MODULE_DATE_MONTH CCI_REG8(0x0013)
+#define SMIAPP_REG_U8_MODULE_DATE_DAY CCI_REG8(0x0014)
+#define SMIAPP_REG_U8_MODULE_DATE_PHASE CCI_REG8(0x0015)
+#define SMIAPP_REG_U16_SENSOR_MODEL_ID CCI_REG16(0x0016)
+#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER CCI_REG8(0x0018)
+#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID CCI_REG8(0x0019)
+#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION CCI_REG8(0x001a)
+#define SMIAPP_REG_U32_SERIAL_NUMBER CCI_REG32(0x001c)
+#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE CCI_REG8(0x0040)
+#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE CCI_REG8(0x0041)
+#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n) CCI_REG16(0x0042 + ((n) << 1)) /* 0 <= n <= 14 */
+#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n) CCI_REG32(0x0060 + ((n) << 2)) /* 0 <= n <= 7 */
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY CCI_REG16(0x0080)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN CCI_REG16(0x0084)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX CCI_REG16(0x0086)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP CCI_REG16(0x0088)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE CCI_REG16(0x008a)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0 CCI_REG16(0x008c)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0 CCI_REG16(0x008e)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1 CCI_REG16(0x0090)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1 CCI_REG16(0x0092)
+#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE CCI_REG8(0x00c0)
+#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE CCI_REG8(0x00c1)
+#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n) CCI_REG16(0x00c2 + ((n) << 1))
+#define SMIAPP_REG_U8_MODE_SELECT CCI_REG8(0x0100)
+#define SMIAPP_REG_U8_IMAGE_ORIENTATION CCI_REG8(0x0101)
+#define SMIAPP_REG_U8_SOFTWARE_RESET CCI_REG8(0x0103)
+#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD CCI_REG8(0x0104)
+#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES CCI_REG8(0x0105)
+#define SMIAPP_REG_U8_FAST_STANDBY_CTRL CCI_REG8(0x0106)
+#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL CCI_REG8(0x0107)
+#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL CCI_REG8(0x0108)
+#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL CCI_REG8(0x0109)
+#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER CCI_REG8(0x0110)
+#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE CCI_REG8(0x0111)
+#define SMIAPP_REG_U16_CSI_DATA_FORMAT CCI_REG16(0x0112)
+#define SMIAPP_REG_U8_CSI_LANE_MODE CCI_REG8(0x0114)
+#define SMIAPP_REG_U8_CSI2_10_TO_8_DT CCI_REG8(0x0115)
+#define SMIAPP_REG_U8_CSI2_10_TO_7_DT CCI_REG8(0x0116)
+#define SMIAPP_REG_U8_CSI2_10_TO_6_DT CCI_REG8(0x0117)
+#define SMIAPP_REG_U8_CSI2_12_TO_8_DT CCI_REG8(0x0118)
+#define SMIAPP_REG_U8_CSI2_12_TO_7_DT CCI_REG8(0x0119)
+#define SMIAPP_REG_U8_CSI2_12_TO_6_DT CCI_REG8(0x011a)
+#define SMIAPP_REG_U8_CSI2_14_TO_10_DT CCI_REG8(0x011b)
+#define SMIAPP_REG_U8_CSI2_14_TO_8_DT CCI_REG8(0x011c)
+#define SMIAPP_REG_U8_CSI2_16_TO_10_DT CCI_REG8(0x011d)
+#define SMIAPP_REG_U8_CSI2_16_TO_8_DT CCI_REG8(0x011e)
+#define SMIAPP_REG_U8_GAIN_MODE CCI_REG8(0x0120)
+#define SMIAPP_REG_U16_VANA_VOLTAGE CCI_REG16(0x0130)
+#define SMIAPP_REG_U16_VDIG_VOLTAGE CCI_REG16(0x0132)
+#define SMIAPP_REG_U16_VIO_VOLTAGE CCI_REG16(0x0134)
+#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ CCI_REG16(0x0136)
+#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL CCI_REG8(0x0138)
+#define SMIAPP_REG_U8_TEMP_SENSOR_MODE CCI_REG8(0x0139)
+#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT CCI_REG8(0x013a)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME CCI_REG16(0x0200)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME CCI_REG16(0x0202)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL CCI_REG16(0x0204)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR CCI_REG16(0x0206)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED CCI_REG16(0x0208)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE CCI_REG16(0x020a)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB CCI_REG16(0x020c)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR CCI_REG16(0x020e)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_RED CCI_REG16(0x0210)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE CCI_REG16(0x0212)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB CCI_REG16(0x0214)
+#define SMIAPP_REG_U16_VT_PIX_CLK_DIV CCI_REG16(0x0300)
+#define SMIAPP_REG_U16_VT_SYS_CLK_DIV CCI_REG16(0x0302)
+#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV CCI_REG16(0x0304)
+#define SMIAPP_REG_U16_PLL_MULTIPLIER CCI_REG16(0x0306)
+#define SMIAPP_REG_U16_OP_PIX_CLK_DIV CCI_REG16(0x0308)
+#define SMIAPP_REG_U16_OP_SYS_CLK_DIV CCI_REG16(0x030a)
+#define SMIAPP_REG_U16_FRAME_LENGTH_LINES CCI_REG16(0x0340)
+#define SMIAPP_REG_U16_LINE_LENGTH_PCK CCI_REG16(0x0342)
+#define SMIAPP_REG_U16_X_ADDR_START CCI_REG16(0x0344)
+#define SMIAPP_REG_U16_Y_ADDR_START CCI_REG16(0x0346)
+#define SMIAPP_REG_U16_X_ADDR_END CCI_REG16(0x0348)
+#define SMIAPP_REG_U16_Y_ADDR_END CCI_REG16(0x034a)
+#define SMIAPP_REG_U16_X_OUTPUT_SIZE CCI_REG16(0x034c)
+#define SMIAPP_REG_U16_Y_OUTPUT_SIZE CCI_REG16(0x034e)
+#define SMIAPP_REG_U16_X_EVEN_INC CCI_REG16(0x0380)
+#define SMIAPP_REG_U16_X_ODD_INC CCI_REG16(0x0382)
+#define SMIAPP_REG_U16_Y_EVEN_INC CCI_REG16(0x0384)
+#define SMIAPP_REG_U16_Y_ODD_INC CCI_REG16(0x0386)
+#define SMIAPP_REG_U16_SCALING_MODE CCI_REG16(0x0400)
+#define SMIAPP_REG_U16_SPATIAL_SAMPLING CCI_REG16(0x0402)
+#define SMIAPP_REG_U16_SCALE_M CCI_REG16(0x0404)
+#define SMIAPP_REG_U16_SCALE_N CCI_REG16(0x0406)
+#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET CCI_REG16(0x0408)
+#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET CCI_REG16(0x040a)
+#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH CCI_REG16(0x040c)
+#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT CCI_REG16(0x040e)
+#define SMIAPP_REG_U16_COMPRESSION_MODE CCI_REG16(0x0500)
+#define SMIAPP_REG_U16_TEST_PATTERN_MODE CCI_REG16(0x0600)
+#define SMIAPP_REG_U16_TEST_DATA_RED CCI_REG16(0x0602)
+#define SMIAPP_REG_U16_TEST_DATA_GREENR CCI_REG16(0x0604)
+#define SMIAPP_REG_U16_TEST_DATA_BLUE CCI_REG16(0x0606)
+#define SMIAPP_REG_U16_TEST_DATA_GREENB CCI_REG16(0x0608)
+#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH CCI_REG16(0x060a)
+#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION CCI_REG16(0x060c)
+#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH CCI_REG16(0x060e)
+#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION CCI_REG16(0x0610)
+#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS CCI_REG16(0x0700)
+#define SMIAPP_REG_U8_TCLK_POST CCI_REG8(0x0800)
+#define SMIAPP_REG_U8_THS_PREPARE CCI_REG8(0x0801)
+#define SMIAPP_REG_U8_THS_ZERO_MIN CCI_REG8(0x0802)
+#define SMIAPP_REG_U8_THS_TRAIL CCI_REG8(0x0803)
+#define SMIAPP_REG_U8_TCLK_TRAIL_MIN CCI_REG8(0x0804)
+#define SMIAPP_REG_U8_TCLK_PREPARE CCI_REG8(0x0805)
+#define SMIAPP_REG_U8_TCLK_ZERO CCI_REG8(0x0806)
+#define SMIAPP_REG_U8_TLPX CCI_REG8(0x0807)
+#define SMIAPP_REG_U8_DPHY_CTRL CCI_REG8(0x0808)
+#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS CCI_REG32(0x0820)
+#define SMIAPP_REG_U8_BINNING_MODE CCI_REG8(0x0900)
+#define SMIAPP_REG_U8_BINNING_TYPE CCI_REG8(0x0901)
+#define SMIAPP_REG_U8_BINNING_WEIGHTING CCI_REG8(0x0902)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL CCI_REG8(0x0a00)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS CCI_REG8(0x0a01)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT CCI_REG8(0x0a02)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 CCI_REG8(0x0a04)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1 CCI_REG8(0x0a05)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2 CCI_REG8(0x0a06)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3 CCI_REG8(0x0a07)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4 CCI_REG8(0x0a08)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5 CCI_REG8(0x0a09)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12 CCI_REG8(0x0a10)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13 CCI_REG8(0x0a11)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14 CCI_REG8(0x0a12)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15 CCI_REG8(0x0a13)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16 CCI_REG8(0x0a14)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17 CCI_REG8(0x0a15)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18 CCI_REG8(0x0a16)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19 CCI_REG8(0x0a17)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20 CCI_REG8(0x0a18)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21 CCI_REG8(0x0a19)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22 CCI_REG8(0x0a1a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23 CCI_REG8(0x0a1b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24 CCI_REG8(0x0a1c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25 CCI_REG8(0x0a1d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26 CCI_REG8(0x0a1e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27 CCI_REG8(0x0a1f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28 CCI_REG8(0x0a20)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29 CCI_REG8(0x0a21)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30 CCI_REG8(0x0a22)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31 CCI_REG8(0x0a23)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32 CCI_REG8(0x0a24)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33 CCI_REG8(0x0a25)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34 CCI_REG8(0x0a26)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35 CCI_REG8(0x0a27)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36 CCI_REG8(0x0a28)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37 CCI_REG8(0x0a29)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38 CCI_REG8(0x0a2a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39 CCI_REG8(0x0a2b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40 CCI_REG8(0x0a2c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41 CCI_REG8(0x0a2d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42 CCI_REG8(0x0a2e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43 CCI_REG8(0x0a2f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44 CCI_REG8(0x0a30)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45 CCI_REG8(0x0a31)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46 CCI_REG8(0x0a32)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47 CCI_REG8(0x0a33)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48 CCI_REG8(0x0a34)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49 CCI_REG8(0x0a35)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50 CCI_REG8(0x0a36)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51 CCI_REG8(0x0a37)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52 CCI_REG8(0x0a38)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53 CCI_REG8(0x0a39)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54 CCI_REG8(0x0a3a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55 CCI_REG8(0x0a3b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56 CCI_REG8(0x0a3c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57 CCI_REG8(0x0a3d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58 CCI_REG8(0x0a3e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59 CCI_REG8(0x0a3f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60 CCI_REG8(0x0a40)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61 CCI_REG8(0x0a41)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62 CCI_REG8(0x0a42)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63 CCI_REG8(0x0a43)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL CCI_REG8(0x0a44)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS CCI_REG8(0x0a45)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT CCI_REG8(0x0a46)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0 CCI_REG8(0x0a48)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1 CCI_REG8(0x0a49)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2 CCI_REG8(0x0a4a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3 CCI_REG8(0x0a4b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4 CCI_REG8(0x0a4c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5 CCI_REG8(0x0a4d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6 CCI_REG8(0x0a4e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7 CCI_REG8(0x0a4f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8 CCI_REG8(0x0a50)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9 CCI_REG8(0x0a51)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10 CCI_REG8(0x0a52)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11 CCI_REG8(0x0a53)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12 CCI_REG8(0x0a54)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13 CCI_REG8(0x0a55)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14 CCI_REG8(0x0a56)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15 CCI_REG8(0x0a57)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16 CCI_REG8(0x0a58)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17 CCI_REG8(0x0a59)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18 CCI_REG8(0x0a5a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19 CCI_REG8(0x0a5b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20 CCI_REG8(0x0a5c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21 CCI_REG8(0x0a5d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22 CCI_REG8(0x0a5e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23 CCI_REG8(0x0a5f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24 CCI_REG8(0x0a60)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25 CCI_REG8(0x0a61)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26 CCI_REG8(0x0a62)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27 CCI_REG8(0x0a63)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28 CCI_REG8(0x0a64)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29 CCI_REG8(0x0a65)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30 CCI_REG8(0x0a66)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31 CCI_REG8(0x0a67)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32 CCI_REG8(0x0a68)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33 CCI_REG8(0x0a69)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34 CCI_REG8(0x0a6a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35 CCI_REG8(0x0a6b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36 CCI_REG8(0x0a6c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37 CCI_REG8(0x0a6d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38 CCI_REG8(0x0a6e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39 CCI_REG8(0x0a6f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40 CCI_REG8(0x0a70)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41 CCI_REG8(0x0a71)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42 CCI_REG8(0x0a72)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43 CCI_REG8(0x0a73)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44 CCI_REG8(0x0a74)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45 CCI_REG8(0x0a75)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46 CCI_REG8(0x0a76)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47 CCI_REG8(0x0a77)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48 CCI_REG8(0x0a78)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49 CCI_REG8(0x0a79)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50 CCI_REG8(0x0a7a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51 CCI_REG8(0x0a7b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52 CCI_REG8(0x0a7c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53 CCI_REG8(0x0a7d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54 CCI_REG8(0x0a7e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55 CCI_REG8(0x0a7f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56 CCI_REG8(0x0a80)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57 CCI_REG8(0x0a81)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58 CCI_REG8(0x0a82)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59 CCI_REG8(0x0a83)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60 CCI_REG8(0x0a84)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61 CCI_REG8(0x0a85)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62 CCI_REG8(0x0a86)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63 CCI_REG8(0x0a87)
+#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE CCI_REG8(0x0b00)
+#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL CCI_REG8(0x0b01)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE CCI_REG8(0x0b02)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT CCI_REG8(0x0b03)
+#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE CCI_REG8(0x0b04)
+#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE CCI_REG8(0x0b05)
+#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE CCI_REG8(0x0b06)
+#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT CCI_REG8(0x0b07)
+#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE CCI_REG8(0x0b08)
+#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT CCI_REG8(0x0b09)
+#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE CCI_REG8(0x0b0a)
+#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT CCI_REG8(0x0b0b)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE CCI_REG8(0x0b0c)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT CCI_REG8(0x0b0d)
+#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE CCI_REG8(0x0b0e)
+#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST CCI_REG8(0x0b0f)
+#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST CCI_REG8(0x0b10)
+#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE CCI_REG8(0x0b11)
+#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST CCI_REG8(0x0b12)
+#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE CCI_REG8(0x0b13)
+#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST CCI_REG8(0x0b14)
+#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE CCI_REG8(0x0b15)
+#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST CCI_REG8(0x0b16)
+#define SMIAPP_REG_U8_EDOF_MODE CCI_REG8(0x0b80)
+#define SMIAPP_REG_U8_SHARPNESS CCI_REG8(0x0b83)
+#define SMIAPP_REG_U8_DENOISING CCI_REG8(0x0b84)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC CCI_REG8(0x0b85)
+#define SMIAPP_REG_U16_DEPTH_OF_FIELD CCI_REG16(0x0b86)
+#define SMIAPP_REG_U16_FOCUS_DISTANCE CCI_REG16(0x0b88)
+#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL CCI_REG8(0x0b8a)
+#define SMIAPP_REG_U16_COLOUR_TEMPERATURE CCI_REG16(0x0b8c)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR CCI_REG16(0x0b8e)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED CCI_REG16(0x0b90)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE CCI_REG16(0x0b92)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB CCI_REG16(0x0b94)
+#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE CCI_REG8(0x0bc0)
+#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING CCI_REG16(0x0bc2)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START CCI_REG16(0x0bc4)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START CCI_REG16(0x0bc6)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH CCI_REG16(0x0bc8)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT CCI_REG16(0x0bca)
+#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1 CCI_REG8(0x0c00)
+#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2 CCI_REG8(0x0c01)
+#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1 CCI_REG8(0x0c02)
+#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2 CCI_REG8(0x0c03)
+#define SMIAPP_REG_U16_TRDY_CTRL CCI_REG16(0x0c04)
+#define SMIAPP_REG_U16_TRDOUT_CTRL CCI_REG16(0x0c06)
+#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL CCI_REG16(0x0c08)
+#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL CCI_REG16(0x0c0a)
+#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL CCI_REG16(0x0c0c)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL CCI_REG16(0x0c0e)
+#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL CCI_REG16(0x0c10)
+#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT CCI_REG8(0x0c12)
+#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT CCI_REG16(0x0c14)
+#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL CCI_REG16(0x0c16)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL CCI_REG16(0x0c18)
+#define SMIAPP_REG_U8_FLASH_MODE_RS CCI_REG8(0x0c1a)
+#define SMIAPP_REG_U8_FLASH_TRIGGER_RS CCI_REG8(0x0c1b)
+#define SMIAPP_REG_U8_FLASH_STATUS CCI_REG8(0x0c1c)
+#define SMIAPP_REG_U8_SA_STROBE_MODE CCI_REG8(0x0c1d)
+#define SMIAPP_REG_U16_SA_STROBE_START_POINT CCI_REG16(0x0c1e)
+#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL CCI_REG16(0x0c20)
+#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL CCI_REG16(0x0c22)
+#define SMIAPP_REG_U8_SA_STROBE_TRIGGER CCI_REG8(0x0c24)
+#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS CCI_REG8(0x0c25)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL CCI_REG16(0x0c26)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL CCI_REG16(0x0c28)
+#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL CCI_REG8(0x0c2a)
+#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL CCI_REG8(0x0c2b)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL CCI_REG16(0x0c2c)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL CCI_REG16(0x0c2e)
+#define SMIAPP_REG_U8_LOW_LEVEL_CTRL CCI_REG8(0x0c80)
+#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT CCI_REG16(0x0c82)
+#define SMIAPP_REG_U16_MAIN_TRIGGER_T3 CCI_REG16(0x0c84)
+#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT CCI_REG8(0x0c86)
+#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3 CCI_REG16(0x0c88)
+#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT CCI_REG8(0x0c8a)
+#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3 CCI_REG16(0x0c8c)
+#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT CCI_REG8(0x0c8e)
+#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL CCI_REG8(0x0d00)
+#define SMIAPP_REG_U8_OPERATION_MODE CCI_REG8(0x0d01)
+#define SMIAPP_REG_U8_ACT_STATE1 CCI_REG8(0x0d02)
+#define SMIAPP_REG_U8_ACT_STATE2 CCI_REG8(0x0d03)
+#define SMIAPP_REG_U16_FOCUS_CHANGE CCI_REG16(0x0d80)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL CCI_REG16(0x0d82)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1 CCI_REG16(0x0d84)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2 CCI_REG16(0x0d86)
+#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1 CCI_REG8(0x0d88)
+#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2 CCI_REG8(0x0d89)
+#define SMIAPP_REG_U8_POSITION CCI_REG8(0x0d8a)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL CCI_REG8(0x0e00)
+#define SMIAPP_REG_U8_BRACKETING_LUT_MODE CCI_REG8(0x0e01)
+#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL CCI_REG8(0x0e02)
+#define SMIAPP_REG_U8_LUT_PARAMETERS_START CCI_REG8(0x0e10)
+#define SMIAPP_REG_U8_LUT_PARAMETERS_END CCI_REG8(0x0eff)
+#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY CCI_REG16(0x1000)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN CCI_REG16(0x1004)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN CCI_REG16(0x1006)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN CCI_REG16(0x1008)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN CCI_REG16(0x100a)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY CCI_REG16(0x1080)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN CCI_REG16(0x1084)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX CCI_REG16(0x1086)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE CCI_REG16(0x1088)
+#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ (CCI_REG32(0x1100) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ (CCI_REG32(0x1104) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV CCI_REG16(0x1108)
+#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV CCI_REG16(0x110a)
+#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ (CCI_REG32(0x110c) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ (CCI_REG32(0x1110) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER CCI_REG16(0x1114)
+#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER CCI_REG16(0x1116)
+#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ (CCI_REG32(0x1118) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ (CCI_REG32(0x111c) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV CCI_REG16(0x1120)
+#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV CCI_REG16(0x1122)
+#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ (CCI_REG32(0x1124) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ (CCI_REG32(0x1128) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ (CCI_REG32(0x112c) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ (CCI_REG32(0x1130) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV CCI_REG16(0x1134)
+#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV CCI_REG16(0x1136)
+#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES CCI_REG16(0x1140)
+#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES CCI_REG16(0x1142)
+#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK CCI_REG16(0x1144)
+#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK CCI_REG16(0x1146)
+#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK CCI_REG16(0x1148)
+#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES CCI_REG16(0x114a)
+#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE CCI_REG8(0x114c)
+#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV CCI_REG16(0x1160)
+#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV CCI_REG16(0x1162)
+#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ (CCI_REG32(0x1164) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ (CCI_REG32(0x1168) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV CCI_REG16(0x116c)
+#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV CCI_REG16(0x116e)
+#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ (CCI_REG32(0x1170) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ (CCI_REG32(0x1174) | CCS_FL_FLOAT_IREAL)
+#define SMIAPP_REG_U16_X_ADDR_MIN CCI_REG16(0x1180)
+#define SMIAPP_REG_U16_Y_ADDR_MIN CCI_REG16(0x1182)
+#define SMIAPP_REG_U16_X_ADDR_MAX CCI_REG16(0x1184)
+#define SMIAPP_REG_U16_Y_ADDR_MAX CCI_REG16(0x1186)
+#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE CCI_REG16(0x1188)
+#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE CCI_REG16(0x118a)
+#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE CCI_REG16(0x118c)
+#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE CCI_REG16(0x118e)
+#define SMIAPP_REG_U16_MIN_EVEN_INC CCI_REG16(0x11c0)
+#define SMIAPP_REG_U16_MAX_EVEN_INC CCI_REG16(0x11c2)
+#define SMIAPP_REG_U16_MIN_ODD_INC CCI_REG16(0x11c4)
+#define SMIAPP_REG_U16_MAX_ODD_INC CCI_REG16(0x11c6)
+#define SMIAPP_REG_U16_SCALING_CAPABILITY CCI_REG16(0x1200)
+#define SMIAPP_REG_U16_SCALER_M_MIN CCI_REG16(0x1204)
+#define SMIAPP_REG_U16_SCALER_M_MAX CCI_REG16(0x1206)
+#define SMIAPP_REG_U16_SCALER_N_MIN CCI_REG16(0x1208)
+#define SMIAPP_REG_U16_SCALER_N_MAX CCI_REG16(0x120a)
+#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY CCI_REG16(0x120c)
+#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY CCI_REG8(0x120e)
+#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY CCI_REG16(0x1300)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED CCI_REG16(0x1400)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED CCI_REG16(0x1402)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED CCI_REG16(0x1404)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN CCI_REG16(0x1406)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN CCI_REG16(0x1408)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN CCI_REG16(0x140a)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE CCI_REG16(0x140c)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE CCI_REG16(0x140e)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE CCI_REG16(0x1410)
+#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS CCI_REG16(0x1500)
+#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY CCI_REG8(0x1502)
+#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY CCI_REG8(0x1600)
+#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY CCI_REG8(0x1601)
+#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY CCI_REG8(0x1602)
+#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY CCI_REG8(0x1603)
+#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY CCI_REG8(0x1604)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS CCI_REG32(0x1608)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS CCI_REG32(0x160c)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS CCI_REG32(0x1610)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS CCI_REG32(0x1614)
+#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY CCI_REG8(0x1618)
+#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN CCI_REG16(0x1700)
+#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN CCI_REG16(0x1702)
+#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN CCI_REG16(0x1704)
+#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN CCI_REG16(0x1706)
+#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN CCI_REG16(0x1708)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN CCI_REG16(0x170a)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN CCI_REG16(0x170c)
+#define SMIAPP_REG_U8_BINNING_CAPABILITY CCI_REG8(0x1710)
+#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY CCI_REG8(0x1711)
+#define SMIAPP_REG_U8_BINNING_SUBTYPES CCI_REG8(0x1712)
+#define SMIAPP_REG_U8_BINNING_TYPE_n(n) CCI_REG8(0x1713 + (n)) /* 1 <= n <= 237 */
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY CCI_REG8(0x1800)
+#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY CCI_REG8(0x1900)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY CCI_REG8(0x1901)
+#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY CCI_REG8(0x1902)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY CCI_REG8(0x1903)
+#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY CCI_REG16(0x1904)
+#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2 CCI_REG16(0x1906)
+#define SMIAPP_REG_U8_EDOF_CAPABILITY CCI_REG8(0x1980)
+#define SMIAPP_REG_U8_ESTIMATION_FRAMES CCI_REG8(0x1981)
+#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ CCI_REG8(0x1982)
+#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ CCI_REG8(0x1983)
+#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ CCI_REG8(0x1984)
+#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ CCI_REG8(0x1985)
+#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ CCI_REG8(0x1986)
+#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY CCI_REG8(0x1987)
+#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM CCI_REG8(0x1988)
+#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY CCI_REG8(0x19c0)
+#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY CCI_REG8(0x19c1)
+#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD CCI_REG16(0x19c2)
+#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE CCI_REG16(0x19c4)
+#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN CCI_REG16(0x1a00)
+#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY CCI_REG8(0x1a02)
+#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR CCI_REG16(0x1b02)
+#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY CCI_REG8(0x1b04)
+#define SMIAPP_REG_U16_ACTUATOR_TYPE CCI_REG16(0x1b40)
+#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS CCI_REG8(0x1b42)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS CCI_REG16(0x1b44)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1 CCI_REG8(0x1c00)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2 CCI_REG8(0x1c01)
+#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE CCI_REG8(0x1c02)
/* Register bit definitions */
#define SMIAPP_IMAGE_ORIENTATION_HFLIP BIT(0)
diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c
index 8e9ebed09f64..ca9bb29dab89 100644
--- a/drivers/media/i2c/ds90ub913.c
+++ b/drivers/media/i2c/ds90ub913.c
@@ -424,8 +424,7 @@ static int ub913_set_fmt(struct v4l2_subdev *sd,
}
/* Set sink format */
- fmt = v4l2_subdev_state_get_stream_format(state, format->pad,
- format->stream);
+ fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
if (!fmt)
return -EINVAL;
@@ -444,8 +443,8 @@ static int ub913_set_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int ub913_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int ub913_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct v4l2_subdev_route routes[] = {
{
@@ -504,7 +503,6 @@ static const struct v4l2_subdev_pad_ops ub913_pad_ops = {
.get_frame_desc = ub913_get_frame_desc,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = ub913_set_fmt,
- .init_cfg = ub913_init_cfg,
};
static const struct v4l2_subdev_ops ub913_subdev_ops = {
@@ -512,6 +510,10 @@ static const struct v4l2_subdev_ops ub913_subdev_ops = {
.pad = &ub913_pad_ops,
};
+static const struct v4l2_subdev_internal_ops ub913_internal_ops = {
+ .init_state = ub913_init_state,
+};
+
static const struct media_entity_operations ub913_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -745,6 +747,7 @@ static int ub913_subdev_init(struct ub913_data *priv)
int ret;
v4l2_i2c_subdev_init(&priv->sd, priv->client, &ub913_subdev_ops);
+ priv->sd.internal_ops = &ub913_internal_ops;
priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
priv->sd.entity.ops = &ub913_entity_ops;
diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c
index 644022312833..16f88db14981 100644
--- a/drivers/media/i2c/ds90ub953.c
+++ b/drivers/media/i2c/ds90ub953.c
@@ -558,8 +558,7 @@ static int ub953_set_fmt(struct v4l2_subdev *sd,
return v4l2_subdev_get_fmt(sd, state, format);
/* Set sink format */
- fmt = v4l2_subdev_state_get_stream_format(state, format->pad,
- format->stream);
+ fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
if (!fmt)
return -EINVAL;
@@ -576,8 +575,8 @@ static int ub953_set_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int ub953_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int ub953_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct v4l2_subdev_route routes[] = {
{
@@ -714,7 +713,6 @@ static const struct v4l2_subdev_pad_ops ub953_pad_ops = {
.get_frame_desc = ub953_get_frame_desc,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = ub953_set_fmt,
- .init_cfg = ub953_init_cfg,
};
static const struct v4l2_subdev_core_ops ub953_subdev_core_ops = {
@@ -728,6 +726,10 @@ static const struct v4l2_subdev_ops ub953_subdev_ops = {
.pad = &ub953_pad_ops,
};
+static const struct v4l2_subdev_internal_ops ub953_internal_ops = {
+ .init_state = ub953_init_state,
+};
+
static const struct media_entity_operations ub953_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -1241,6 +1243,7 @@ static int ub953_subdev_init(struct ub953_data *priv)
int ret;
v4l2_i2c_subdev_init(&priv->sd, priv->client, &ub953_subdev_ops);
+ priv->sd.internal_ops = &ub953_internal_ops;
priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_STREAMS;
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c
index b8f3e5ca03ef..ffe5f25f8647 100644
--- a/drivers/media/i2c/ds90ub960.c
+++ b/drivers/media/i2c/ds90ub960.c
@@ -2451,9 +2451,8 @@ static int ub960_configure_ports_for_streaming(struct ub960_data *priv,
if (rx_data[nport].num_streams > 2)
return -EPIPE;
- fmt = v4l2_subdev_state_get_stream_format(state,
- route->sink_pad,
- route->sink_stream);
+ fmt = v4l2_subdev_state_get_format(state, route->sink_pad,
+ route->sink_stream);
if (!fmt)
return -EPIPE;
@@ -2842,8 +2841,8 @@ static int ub960_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
const struct ub960_format_info *ub960_fmt;
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_state_get_stream_format(state, pad,
- route->source_stream);
+ fmt = v4l2_subdev_state_get_format(state, pad,
+ route->source_stream);
if (!fmt) {
ret = -EINVAL;
@@ -2891,8 +2890,7 @@ static int ub960_set_fmt(struct v4l2_subdev *sd,
if (!ub960_find_format(format->format.code))
format->format.code = ub960_formats[0].code;
- fmt = v4l2_subdev_state_get_stream_format(state, format->pad,
- format->stream);
+ fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
if (!fmt)
return -EINVAL;
@@ -2908,8 +2906,8 @@ static int ub960_set_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int ub960_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int ub960_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct ub960_data *priv = sd_to_ub960(sd);
@@ -2940,8 +2938,6 @@ static const struct v4l2_subdev_pad_ops ub960_pad_ops = {
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = ub960_set_fmt,
-
- .init_cfg = ub960_init_cfg,
};
static int ub960_log_status(struct v4l2_subdev *sd)
@@ -3093,6 +3089,10 @@ static const struct v4l2_subdev_core_ops ub960_subdev_core_ops = {
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
+static const struct v4l2_subdev_internal_ops ub960_internal_ops = {
+ .init_state = ub960_init_state,
+};
+
static const struct v4l2_subdev_ops ub960_subdev_ops = {
.core = &ub960_subdev_core_ops,
.pad = &ub960_pad_ops,
@@ -3652,6 +3652,7 @@ static int ub960_create_subdev(struct ub960_data *priv)
int ret;
v4l2_i2c_subdev_init(&priv->sd, priv->client, &ub960_subdev_ops);
+ priv->sd.internal_ops = &ub960_internal_ops;
v4l2_ctrl_handler_init(&priv->ctrl_handler, 1);
priv->sd.ctrl_handler = &priv->ctrl_handler;
diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c
index d6fc843f9368..f548b1bb75fb 100644
--- a/drivers/media/i2c/et8ek8/et8ek8_driver.c
+++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c
@@ -995,8 +995,7 @@ __et8ek8_get_pad_format(struct et8ek8_sensor *sensor,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&sensor->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &sensor->format;
default:
@@ -1047,10 +1046,18 @@ static int et8ek8_set_pad_format(struct v4l2_subdev *subdev,
}
static int et8ek8_get_frame_interval(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval *fi)
{
struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
memset(fi, 0, sizeof(*fi));
fi->interval = sensor->current_reglist->mode.timeperframe;
@@ -1058,11 +1065,19 @@ static int et8ek8_get_frame_interval(struct v4l2_subdev *subdev,
}
static int et8ek8_set_frame_interval(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval *fi)
{
struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev);
struct et8ek8_reglist *reglist;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
reglist = et8ek8_reglist_find_mode_ival(&meta_reglist,
sensor->current_reglist,
&fi->interval);
@@ -1343,8 +1358,6 @@ static int et8ek8_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
static const struct v4l2_subdev_video_ops et8ek8_video_ops = {
.s_stream = et8ek8_s_stream,
- .g_frame_interval = et8ek8_get_frame_interval,
- .s_frame_interval = et8ek8_set_frame_interval,
};
static const struct v4l2_subdev_core_ops et8ek8_core_ops = {
@@ -1357,6 +1370,8 @@ static const struct v4l2_subdev_pad_ops et8ek8_pad_ops = {
.enum_frame_interval = et8ek8_enum_frame_ival,
.get_fmt = et8ek8_get_pad_format,
.set_fmt = et8ek8_set_pad_format,
+ .get_frame_interval = et8ek8_get_frame_interval,
+ .set_frame_interval = et8ek8_set_frame_interval,
};
static const struct v4l2_subdev_ops et8ek8_ops = {
diff --git a/drivers/media/i2c/gc0308.c b/drivers/media/i2c/gc0308.c
new file mode 100644
index 000000000000..fa754a8a39a6
--- /dev/null
+++ b/drivers/media/i2c/gc0308.c
@@ -0,0 +1,1451 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the GalaxyCore GC0308 camera sensor.
+ *
+ * Copyright (c) 2023 Sebastian Reichel <[email protected]>
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+/* Analog & CISCTL*/
+#define GC0308_CHIP_ID CCI_REG8(0x000)
+#define GC0308_HBLANK CCI_REG8(0x001)
+#define GC0308_VBLANK CCI_REG8(0x002)
+#define GC0308_EXP CCI_REG16(0x003)
+#define GC0308_ROW_START CCI_REG16(0x005)
+#define GC0308_COL_START CCI_REG16(0x007)
+#define GC0308_WIN_HEIGHT CCI_REG16(0x009)
+#define GC0308_WIN_WIDTH CCI_REG16(0x00b)
+#define GC0308_VS_START_TIME CCI_REG8(0x00d) /* in rows */
+#define GC0308_VS_END_TIME CCI_REG8(0x00e) /* in rows */
+#define GC0308_VB_HB CCI_REG8(0x00f)
+#define GC0308_RSH_WIDTH CCI_REG8(0x010)
+#define GC0308_TSP_WIDTH CCI_REG8(0x011)
+#define GC0308_SAMPLE_HOLD_DELAY CCI_REG8(0x012)
+#define GC0308_ROW_TAIL_WIDTH CCI_REG8(0x013)
+#define GC0308_CISCTL_MODE1 CCI_REG8(0x014)
+#define GC0308_CISCTL_MODE2 CCI_REG8(0x015)
+#define GC0308_CISCTL_MODE3 CCI_REG8(0x016)
+#define GC0308_CISCTL_MODE4 CCI_REG8(0x017)
+#define GC0308_ANALOG_MODE1 CCI_REG8(0x01a)
+#define GC0308_ANALOG_MODE2 CCI_REG8(0x01b)
+#define GC0308_HRST_RSG_V18 CCI_REG8(0x01c)
+#define GC0308_VREF_V25 CCI_REG8(0x01d)
+#define GC0308_ADC_R CCI_REG8(0x01e)
+#define GC0308_PAD_DRV CCI_REG8(0x01f)
+#define GC0308_SOFT_RESET CCI_REG8(0x0fe)
+
+/* ISP */
+#define GC0308_BLOCK_EN1 CCI_REG8(0x020)
+#define GC0308_BLOCK_EN2 CCI_REG8(0x021)
+#define GC0308_AAAA_EN CCI_REG8(0x022)
+#define GC0308_SPECIAL_EFFECT CCI_REG8(0x023)
+#define GC0308_OUT_FORMAT CCI_REG8(0x024)
+#define GC0308_OUT_EN CCI_REG8(0x025)
+#define GC0308_SYNC_MODE CCI_REG8(0x026)
+#define GC0308_CLK_DIV_MODE CCI_REG8(0x028)
+#define GC0308_BYPASS_MODE CCI_REG8(0x029)
+#define GC0308_CLK_GATING CCI_REG8(0x02a)
+#define GC0308_DITHER_MODE CCI_REG8(0x02b)
+#define GC0308_DITHER_BIT CCI_REG8(0x02c)
+#define GC0308_DEBUG_MODE1 CCI_REG8(0x02d)
+#define GC0308_DEBUG_MODE2 CCI_REG8(0x02e)
+#define GC0308_DEBUG_MODE3 CCI_REG8(0x02f)
+#define GC0308_CROP_WIN_MODE CCI_REG8(0x046)
+#define GC0308_CROP_WIN_Y1 CCI_REG8(0x047)
+#define GC0308_CROP_WIN_X1 CCI_REG8(0x048)
+#define GC0308_CROP_WIN_HEIGHT CCI_REG16(0x049)
+#define GC0308_CROP_WIN_WIDTH CCI_REG16(0x04b)
+
+/* BLK */
+#define GC0308_BLK_MODE CCI_REG8(0x030)
+#define GC0308_BLK_LIMIT_VAL CCI_REG8(0x031)
+#define GC0308_GLOBAL_OFF CCI_REG8(0x032)
+#define GC0308_CURRENT_R_OFF CCI_REG8(0x033)
+#define GC0308_CURRENT_G_OFF CCI_REG8(0x034)
+#define GC0308_CURRENT_B_OFF CCI_REG8(0x035)
+#define GC0308_CURRENT_R_DARK_CURRENT CCI_REG8(0x036)
+#define GC0308_CURRENT_G_DARK_CURRENT CCI_REG8(0x037)
+#define GC0308_CURRENT_B_DARK_CURRENT CCI_REG8(0x038)
+#define GC0308_EXP_RATE_DARKC CCI_REG8(0x039)
+#define GC0308_OFF_SUBMODE CCI_REG8(0x03a)
+#define GC0308_DARKC_SUBMODE CCI_REG8(0x03b)
+#define GC0308_MANUAL_G1_OFF CCI_REG8(0x03c)
+#define GC0308_MANUAL_R1_OFF CCI_REG8(0x03d)
+#define GC0308_MANUAL_B2_OFF CCI_REG8(0x03e)
+#define GC0308_MANUAL_G2_OFF CCI_REG8(0x03f)
+
+/* PREGAIN */
+#define GC0308_GLOBAL_GAIN CCI_REG8(0x050)
+#define GC0308_AUTO_PREGAIN CCI_REG8(0x051)
+#define GC0308_AUTO_POSTGAIN CCI_REG8(0x052)
+#define GC0308_CHANNEL_GAIN_G1 CCI_REG8(0x053)
+#define GC0308_CHANNEL_GAIN_R CCI_REG8(0x054)
+#define GC0308_CHANNEL_GAIN_B CCI_REG8(0x055)
+#define GC0308_CHANNEL_GAIN_G2 CCI_REG8(0x056)
+#define GC0308_R_RATIO CCI_REG8(0x057)
+#define GC0308_G_RATIO CCI_REG8(0x058)
+#define GC0308_B_RATIO CCI_REG8(0x059)
+#define GC0308_AWB_R_GAIN CCI_REG8(0x05a)
+#define GC0308_AWB_G_GAIN CCI_REG8(0x05b)
+#define GC0308_AWB_B_GAIN CCI_REG8(0x05c)
+#define GC0308_LSC_DEC_LVL1 CCI_REG8(0x05d)
+#define GC0308_LSC_DEC_LVL2 CCI_REG8(0x05e)
+#define GC0308_LSC_DEC_LVL3 CCI_REG8(0x05f)
+
+/* DNDD */
+#define GC0308_DN_MODE_EN CCI_REG8(0x060)
+#define GC0308_DN_MODE_RATIO CCI_REG8(0x061)
+#define GC0308_DN_BILAT_B_BASE CCI_REG8(0x062)
+#define GC0308_DN_B_INCR CCI_REG8(0x063)
+#define GC0308_DN_BILAT_N_BASE CCI_REG8(0x064)
+#define GC0308_DN_N_INCR CCI_REG8(0x065)
+#define GC0308_DD_DARK_BRIGHT_TH CCI_REG8(0x066)
+#define GC0308_DD_FLAT_TH CCI_REG8(0x067)
+#define GC0308_DD_LIMIT CCI_REG8(0x068)
+
+/* ASDE - Auto Saturation De-noise and Edge-Enhancement */
+#define GC0308_ASDE_GAIN_TRESH CCI_REG8(0x069)
+#define GC0308_ASDE_GAIN_MODE CCI_REG8(0x06a)
+#define GC0308_ASDE_DN_SLOPE CCI_REG8(0x06b)
+#define GC0308_ASDE_DD_BRIGHT CCI_REG8(0x06c)
+#define GC0308_ASDE_DD_LIMIT CCI_REG8(0x06d)
+#define GC0308_ASDE_AUTO_EE1 CCI_REG8(0x06e)
+#define GC0308_ASDE_AUTO_EE2 CCI_REG8(0x06f)
+#define GC0308_ASDE_AUTO_SAT_DEC_SLOPE CCI_REG8(0x070)
+#define GC0308_ASDE_AUTO_SAT_LOW_LIMIT CCI_REG8(0x071)
+
+/* INTPEE - Interpolation and Edge-Enhancement */
+#define GC0308_EEINTP_MODE_1 CCI_REG8(0x072)
+#define GC0308_EEINTP_MODE_2 CCI_REG8(0x073)
+#define GC0308_DIRECTION_TH1 CCI_REG8(0x074)
+#define GC0308_DIRECTION_TH2 CCI_REG8(0x075)
+#define GC0308_DIFF_HV_TI_TH CCI_REG8(0x076)
+#define GC0308_EDGE12_EFFECT CCI_REG8(0x077)
+#define GC0308_EDGE_POS_RATIO CCI_REG8(0x078)
+#define GC0308_EDGE1_MINMAX CCI_REG8(0x079)
+#define GC0308_EDGE2_MINMAX CCI_REG8(0x07a)
+#define GC0308_EDGE12_TH CCI_REG8(0x07b)
+#define GC0308_EDGE_MAX CCI_REG8(0x07c)
+
+/* ABB - Auto Black Balance */
+#define GC0308_ABB_MODE CCI_REG8(0x080)
+#define GC0308_ABB_TARGET_AVGH CCI_REG8(0x081)
+#define GC0308_ABB_TARGET_AVGL CCI_REG8(0x082)
+#define GC0308_ABB_LIMIT_VAL CCI_REG8(0x083)
+#define GC0308_ABB_SPEED CCI_REG8(0x084)
+#define GC0308_CURR_R_BLACK_LVL CCI_REG8(0x085)
+#define GC0308_CURR_G_BLACK_LVL CCI_REG8(0x086)
+#define GC0308_CURR_B_BLACK_LVL CCI_REG8(0x087)
+#define GC0308_CURR_R_BLACK_FACTOR CCI_REG8(0x088)
+#define GC0308_CURR_G_BLACK_FACTOR CCI_REG8(0x089)
+#define GC0308_CURR_B_BLACK_FACTOR CCI_REG8(0x08a)
+
+/* LSC - Lens Shading Correction */
+#define GC0308_LSC_RED_B2 CCI_REG8(0x08b)
+#define GC0308_LSC_GREEN_B2 CCI_REG8(0x08c)
+#define GC0308_LSC_BLUE_B2 CCI_REG8(0x08d)
+#define GC0308_LSC_RED_B4 CCI_REG8(0x08e)
+#define GC0308_LSC_GREEN_B4 CCI_REG8(0x08f)
+#define GC0308_LSC_BLUE_B4 CCI_REG8(0x090)
+#define GC0308_LSC_ROW_CENTER CCI_REG8(0x091)
+#define GC0308_LSC_COL_CENTER CCI_REG8(0x092)
+
+/* CC - Channel Coefficient */
+#define GC0308_CC_MATRIX_C11 CCI_REG8(0x093)
+#define GC0308_CC_MATRIX_C12 CCI_REG8(0x094)
+#define GC0308_CC_MATRIX_C13 CCI_REG8(0x095)
+#define GC0308_CC_MATRIX_C21 CCI_REG8(0x096)
+#define GC0308_CC_MATRIX_C22 CCI_REG8(0x097)
+#define GC0308_CC_MATRIX_C23 CCI_REG8(0x098)
+#define GC0308_CC_MATRIX_C41 CCI_REG8(0x09c)
+#define GC0308_CC_MATRIX_C42 CCI_REG8(0x09d)
+#define GC0308_CC_MATRIX_C43 CCI_REG8(0x09e)
+
+/* GAMMA */
+#define GC0308_GAMMA_OUT0 CCI_REG8(0x09f)
+#define GC0308_GAMMA_OUT1 CCI_REG8(0x0a0)
+#define GC0308_GAMMA_OUT2 CCI_REG8(0x0a1)
+#define GC0308_GAMMA_OUT3 CCI_REG8(0x0a2)
+#define GC0308_GAMMA_OUT4 CCI_REG8(0x0a3)
+#define GC0308_GAMMA_OUT5 CCI_REG8(0x0a4)
+#define GC0308_GAMMA_OUT6 CCI_REG8(0x0a5)
+#define GC0308_GAMMA_OUT7 CCI_REG8(0x0a6)
+#define GC0308_GAMMA_OUT8 CCI_REG8(0x0a7)
+#define GC0308_GAMMA_OUT9 CCI_REG8(0x0a8)
+#define GC0308_GAMMA_OUT10 CCI_REG8(0x0a9)
+#define GC0308_GAMMA_OUT11 CCI_REG8(0x0aa)
+#define GC0308_GAMMA_OUT12 CCI_REG8(0x0ab)
+#define GC0308_GAMMA_OUT13 CCI_REG8(0x0ac)
+#define GC0308_GAMMA_OUT14 CCI_REG8(0x0ad)
+#define GC0308_GAMMA_OUT15 CCI_REG8(0x0ae)
+#define GC0308_GAMMA_OUT16 CCI_REG8(0x0af)
+
+/* YCP */
+#define GC0308_GLOBAL_SATURATION CCI_REG8(0x0b0)
+#define GC0308_SATURATION_CB CCI_REG8(0x0b1)
+#define GC0308_SATURATION_CR CCI_REG8(0x0b2)
+#define GC0308_LUMA_CONTRAST CCI_REG8(0x0b3)
+#define GC0308_CONTRAST_CENTER CCI_REG8(0x0b4)
+#define GC0308_LUMA_OFFSET CCI_REG8(0x0b5)
+#define GC0308_SKIN_CB_CENTER CCI_REG8(0x0b6)
+#define GC0308_SKIN_CR_CENTER CCI_REG8(0x0b7)
+#define GC0308_SKIN_RADIUS_SQUARE CCI_REG8(0x0b8)
+#define GC0308_SKIN_BRIGHTNESS CCI_REG8(0x0b9)
+#define GC0308_FIXED_CB CCI_REG8(0x0ba)
+#define GC0308_FIXED_CR CCI_REG8(0x0bb)
+#define GC0308_EDGE_DEC_SA CCI_REG8(0x0bd)
+#define GC0308_AUTO_GRAY_MODE CCI_REG8(0x0be)
+#define GC0308_SATURATION_SUB_STRENGTH CCI_REG8(0x0bf)
+#define GC0308_Y_GAMMA_OUT0 CCI_REG8(0x0c0)
+#define GC0308_Y_GAMMA_OUT1 CCI_REG8(0x0c1)
+#define GC0308_Y_GAMMA_OUT2 CCI_REG8(0x0c2)
+#define GC0308_Y_GAMMA_OUT3 CCI_REG8(0x0c3)
+#define GC0308_Y_GAMMA_OUT4 CCI_REG8(0x0c4)
+#define GC0308_Y_GAMMA_OUT5 CCI_REG8(0x0c5)
+#define GC0308_Y_GAMMA_OUT6 CCI_REG8(0x0c6)
+#define GC0308_Y_GAMMA_OUT7 CCI_REG8(0x0c7)
+#define GC0308_Y_GAMMA_OUT8 CCI_REG8(0x0c8)
+#define GC0308_Y_GAMMA_OUT9 CCI_REG8(0x0c9)
+#define GC0308_Y_GAMMA_OUT10 CCI_REG8(0x0ca)
+#define GC0308_Y_GAMMA_OUT11 CCI_REG8(0x0cb)
+#define GC0308_Y_GAMMA_OUT12 CCI_REG8(0x0cc)
+
+/* AEC - Automatic Exposure Control */
+#define GC0308_AEC_MODE1 CCI_REG8(0x0d0)
+#define GC0308_AEC_MODE2 CCI_REG8(0x0d1)
+#define GC0308_AEC_MODE3 CCI_REG8(0x0d2)
+#define GC0308_AEC_TARGET_Y CCI_REG8(0x0d3)
+#define GC0308_Y_AVG CCI_REG8(0x0d4)
+#define GC0308_AEC_HIGH_LOW_RANGE CCI_REG8(0x0d5)
+#define GC0308_AEC_IGNORE CCI_REG8(0x0d6)
+#define GC0308_AEC_LIMIT_HIGH_RANGE CCI_REG8(0x0d7)
+#define GC0308_AEC_R_OFFSET CCI_REG8(0x0d9)
+#define GC0308_AEC_GB_OFFSET CCI_REG8(0x0da)
+#define GC0308_AEC_SLOW_MARGIN CCI_REG8(0x0db)
+#define GC0308_AEC_FAST_MARGIN CCI_REG8(0x0dc)
+#define GC0308_AEC_EXP_CHANGE_GAIN CCI_REG8(0x0dd)
+#define GC0308_AEC_STEP2_SUNLIGHT CCI_REG8(0x0de)
+#define GC0308_AEC_I_FRAMES CCI_REG8(0x0df)
+#define GC0308_AEC_I_STOP_L_MARGIN CCI_REG8(0x0e0)
+#define GC0308_AEC_I_STOP_MARGIN CCI_REG8(0x0e1)
+#define GC0308_ANTI_FLICKER_STEP CCI_REG16(0x0e2)
+#define GC0308_EXP_LVL_1 CCI_REG16(0x0e4)
+#define GC0308_EXP_LVL_2 CCI_REG16(0x0e6)
+#define GC0308_EXP_LVL_3 CCI_REG16(0x0e8)
+#define GC0308_EXP_LVL_4 CCI_REG16(0x0ea)
+#define GC0308_MAX_EXP_LVL CCI_REG8(0x0ec)
+#define GC0308_EXP_MIN_L CCI_REG8(0x0ed)
+#define GC0308_MAX_POST_DF_GAIN CCI_REG8(0x0ee)
+#define GC0308_MAX_PRE_DG_GAIN CCI_REG8(0x0ef)
+
+/* ABS */
+#define GC0308_ABS_RANGE_COMP CCI_REG8(0x0f0)
+#define GC0308_ABS_STOP_MARGIN CCI_REG8(0x0f1)
+#define GC0308_Y_S_COMP CCI_REG8(0x0f2)
+#define GC0308_Y_STRETCH_LIMIT CCI_REG8(0x0f3)
+#define GC0308_Y_TILT CCI_REG8(0x0f4)
+#define GC0308_Y_STRETCH CCI_REG8(0x0f5)
+
+/* Measure Window */
+#define GC0308_BIG_WIN_X0 CCI_REG8(0x0f7)
+#define GC0308_BIG_WIN_Y0 CCI_REG8(0x0f8)
+#define GC0308_BIG_WIN_X1 CCI_REG8(0x0f9)
+#define GC0308_BIG_WIN_Y1 CCI_REG8(0x0fa)
+#define GC0308_DIFF_Y_BIG_THD CCI_REG8(0x0fb)
+
+/* OUT Module (P1) */
+#define GC0308_CLOSE_FRAME_EN CCI_REG8(0x150)
+#define GC0308_CLOSE_FRAME_NUM1 CCI_REG8(0x151)
+#define GC0308_CLOSE_FRAME_NUM2 CCI_REG8(0x152)
+#define GC0308_BAYER_MODE CCI_REG8(0x153)
+#define GC0308_SUBSAMPLE CCI_REG8(0x154)
+#define GC0308_SUBMODE CCI_REG8(0x155)
+#define GC0308_SUB_ROW_N1 CCI_REG8(0x156)
+#define GC0308_SUB_ROW_N2 CCI_REG8(0x157)
+#define GC0308_SUB_COL_N1 CCI_REG8(0x158)
+#define GC0308_SUB_COL_N2 CCI_REG8(0x159)
+
+/* AWB (P1) - Auto White Balance */
+#define GC0308_AWB_RGB_HIGH_LOW CCI_REG8(0x100)
+#define GC0308_AWB_Y_TO_C_DIFF2 CCI_REG8(0x102)
+#define GC0308_AWB_C_MAX CCI_REG8(0x104)
+#define GC0308_AWB_C_INTER CCI_REG8(0x105)
+#define GC0308_AWB_C_INTER2 CCI_REG8(0x106)
+#define GC0308_AWB_C_MAX_BIG CCI_REG8(0x108)
+#define GC0308_AWB_Y_HIGH CCI_REG8(0x109)
+#define GC0308_AWB_NUMBER_LIMIT CCI_REG8(0x10a)
+#define GC0308_KWIN_RATIO CCI_REG8(0x10b)
+#define GC0308_KWIN_THD CCI_REG8(0x10c)
+#define GC0308_LIGHT_GAIN_RANGE CCI_REG8(0x10d)
+#define GC0308_SMALL_WIN_WIDTH_STEP CCI_REG8(0x10e)
+#define GC0308_SMALL_WIN_HEIGHT_STEP CCI_REG8(0x10f)
+#define GC0308_AWB_YELLOW_TH CCI_REG8(0x110)
+#define GC0308_AWB_MODE CCI_REG8(0x111)
+#define GC0308_AWB_ADJUST_SPEED CCI_REG8(0x112)
+#define GC0308_AWB_EVERY_N CCI_REG8(0x113)
+#define GC0308_R_AVG_USE CCI_REG8(0x1d0)
+#define GC0308_G_AVG_USE CCI_REG8(0x1d1)
+#define GC0308_B_AVG_USE CCI_REG8(0x1d2)
+
+#define GC0308_HBLANK_MIN 0x021
+#define GC0308_HBLANK_MAX 0xfff
+#define GC0308_HBLANK_DEF 0x040
+
+#define GC0308_VBLANK_MIN 0x000
+#define GC0308_VBLANK_MAX 0xfff
+#define GC0308_VBLANK_DEF 0x020
+
+#define GC0308_PIXEL_RATE 24000000
+
+/*
+ * frame_time = (BT + height + 8) * row_time
+ * width = 640 (driver does not change window size)
+ * height = 480 (driver does not change window size)
+ * row_time = HBLANK + SAMPLE_HOLD_DELAY + width + 8 + 4
+ *
+ * When EXP_TIME > (BT + height):
+ * BT = EXP_TIME - height - 8 - VS_START_TIME + VS_END_TIME
+ * else:
+ * BT = VBLANK + VS_START_TIME + VS_END_TIME
+ *
+ * max is 30 FPS
+ *
+ * In my tests frame rate mostly depends on exposure time. Unfortuantely
+ * it's unclear how this is calculated exactly. Also since we enable AEC,
+ * the frame times vary depending on ambient light conditions.
+ */
+#define GC0308_FRAME_RATE_MAX 30
+
+enum gc0308_exp_val {
+ GC0308_EXP_M4 = 0,
+ GC0308_EXP_M3,
+ GC0308_EXP_M2,
+ GC0308_EXP_M1,
+ GC0308_EXP_0,
+ GC0308_EXP_P1,
+ GC0308_EXP_P2,
+ GC0308_EXP_P3,
+ GC0308_EXP_P4,
+};
+
+static const s64 gc0308_exposure_menu[] = {
+ -4, -3, -2, -1, 0, 1, 2, 3, 4
+};
+
+struct gc0308_exposure {
+ u8 luma_offset;
+ u8 aec_target_y;
+};
+
+#define GC0308_EXPOSURE(luma_offset_reg, aec_target_y_reg) \
+ { .luma_offset = luma_offset_reg, .aec_target_y = aec_target_y_reg }
+
+static const struct gc0308_exposure gc0308_exposure_values[] = {
+ [GC0308_EXP_M4] = GC0308_EXPOSURE(0xc0, 0x30),
+ [GC0308_EXP_M3] = GC0308_EXPOSURE(0xd0, 0x38),
+ [GC0308_EXP_M2] = GC0308_EXPOSURE(0xe0, 0x40),
+ [GC0308_EXP_M1] = GC0308_EXPOSURE(0xf0, 0x48),
+ [GC0308_EXP_0] = GC0308_EXPOSURE(0x08, 0x50),
+ [GC0308_EXP_P1] = GC0308_EXPOSURE(0x10, 0x5c),
+ [GC0308_EXP_P2] = GC0308_EXPOSURE(0x20, 0x60),
+ [GC0308_EXP_P3] = GC0308_EXPOSURE(0x30, 0x68),
+ [GC0308_EXP_P4] = GC0308_EXPOSURE(0x40, 0x70),
+};
+
+struct gc0308_awb_gains {
+ u8 r;
+ u8 g;
+ u8 b;
+};
+
+#define GC0308_AWB_GAINS(red, green, blue) \
+ { .r = red, .g = green, .b = blue }
+
+static const struct gc0308_awb_gains gc0308_awb_gains[] = {
+ [V4L2_WHITE_BALANCE_AUTO] = GC0308_AWB_GAINS(0x56, 0x40, 0x4a),
+ [V4L2_WHITE_BALANCE_CLOUDY] = GC0308_AWB_GAINS(0x8c, 0x50, 0x40),
+ [V4L2_WHITE_BALANCE_DAYLIGHT] = GC0308_AWB_GAINS(0x74, 0x52, 0x40),
+ [V4L2_WHITE_BALANCE_INCANDESCENT] = GC0308_AWB_GAINS(0x48, 0x40, 0x5c),
+ [V4L2_WHITE_BALANCE_FLUORESCENT] = GC0308_AWB_GAINS(0x40, 0x42, 0x50),
+};
+
+struct gc0308_format {
+ u32 code;
+ u8 regval;
+};
+
+#define GC0308_FORMAT(v4l2_code, gc0308_regval) \
+ { .code = v4l2_code, .regval = gc0308_regval }
+
+static const struct gc0308_format gc0308_formats[] = {
+ GC0308_FORMAT(MEDIA_BUS_FMT_UYVY8_2X8, 0x00),
+ GC0308_FORMAT(MEDIA_BUS_FMT_VYUY8_2X8, 0x01),
+ GC0308_FORMAT(MEDIA_BUS_FMT_YUYV8_2X8, 0x02),
+ GC0308_FORMAT(MEDIA_BUS_FMT_YVYU8_2X8, 0x03),
+ GC0308_FORMAT(MEDIA_BUS_FMT_RGB565_2X8_BE, 0x06),
+ GC0308_FORMAT(MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, 0x07),
+ GC0308_FORMAT(MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, 0x09),
+};
+
+struct gc0308_frame_size {
+ u8 subsample;
+ u32 width;
+ u32 height;
+};
+
+#define GC0308_FRAME_SIZE(s, w, h) \
+ { .subsample = s, .width = w, .height = h }
+
+static const struct gc0308_frame_size gc0308_frame_sizes[] = {
+ GC0308_FRAME_SIZE(0x11, 640, 480),
+ GC0308_FRAME_SIZE(0x22, 320, 240),
+ GC0308_FRAME_SIZE(0x44, 160, 120),
+};
+
+struct gc0308_mode_registers {
+ u8 out_format;
+ u8 subsample;
+ u16 width;
+ u16 height;
+};
+
+struct gc0308 {
+ struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ struct media_pad pad;
+ struct device *dev;
+ struct clk *clk;
+ struct regmap *regmap;
+ struct regulator *vdd;
+ struct gpio_desc *pwdn_gpio;
+ struct gpio_desc *reset_gpio;
+ unsigned int mbus_config;
+ struct gc0308_mode_registers mode;
+ struct {
+ /* mirror cluster */
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ };
+ struct {
+ /* blanking cluster */
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
+ };
+};
+
+static inline struct gc0308 *to_gc0308(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct gc0308, sd);
+}
+
+static const struct regmap_range_cfg gc0308_ranges[] = {
+ {
+ .range_min = 0x0000,
+ .range_max = 0x01ff,
+ .selector_reg = 0xfe,
+ .selector_mask = 0x01,
+ .selector_shift = 0x00,
+ .window_start = 0x00,
+ .window_len = 0x100,
+ },
+};
+
+static const struct regmap_config gc0308_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
+ .max_register = 0x1ff,
+ .ranges = gc0308_ranges,
+ .num_ranges = ARRAY_SIZE(gc0308_ranges),
+ .disable_locking = true,
+};
+
+static const struct cci_reg_sequence sensor_default_regs[] = {
+ {GC0308_VB_HB, 0x00},
+ {GC0308_HBLANK, 0x40},
+ {GC0308_VBLANK, 0x20},
+ {GC0308_EXP, 0x0258},
+ {GC0308_AWB_R_GAIN, 0x56},
+ {GC0308_AWB_G_GAIN, 0x40},
+ {GC0308_AWB_B_GAIN, 0x4a},
+ {GC0308_ANTI_FLICKER_STEP, 0x0078},
+ {GC0308_EXP_LVL_1, 0x0258},
+ {GC0308_EXP_LVL_2, 0x0258},
+ {GC0308_EXP_LVL_3, 0x0258},
+ {GC0308_EXP_LVL_4, 0x0ea6},
+ {GC0308_MAX_EXP_LVL, 0x20},
+ {GC0308_ROW_START, 0x0000},
+ {GC0308_COL_START, 0x0000},
+ {GC0308_WIN_HEIGHT, 488},
+ {GC0308_WIN_WIDTH, 648},
+ {GC0308_VS_START_TIME, 0x02},
+ {GC0308_VS_END_TIME, 0x02},
+ {GC0308_RSH_WIDTH, 0x22},
+ {GC0308_TSP_WIDTH, 0x0d},
+ {GC0308_SAMPLE_HOLD_DELAY, 0x50},
+ {GC0308_ROW_TAIL_WIDTH, 0x0f},
+ {GC0308_CISCTL_MODE1, 0x10},
+ {GC0308_CISCTL_MODE2, 0x0a},
+ {GC0308_CISCTL_MODE3, 0x05},
+ {GC0308_CISCTL_MODE4, 0x01},
+ {CCI_REG8(0x018), 0x44}, /* undocumented */
+ {CCI_REG8(0x019), 0x44}, /* undocumented */
+ {GC0308_ANALOG_MODE1, 0x2a},
+ {GC0308_ANALOG_MODE2, 0x00},
+ {GC0308_HRST_RSG_V18, 0x49},
+ {GC0308_VREF_V25, 0x9a},
+ {GC0308_ADC_R, 0x61},
+ {GC0308_PAD_DRV, 0x01}, /* drv strength: pclk=4mA */
+ {GC0308_BLOCK_EN1, 0x7f},
+ {GC0308_BLOCK_EN2, 0xfa},
+ {GC0308_AAAA_EN, 0x57},
+ {GC0308_OUT_FORMAT, 0xa2}, /* YCbYCr */
+ {GC0308_OUT_EN, 0x0f},
+ {GC0308_SYNC_MODE, 0x03},
+ {GC0308_CLK_DIV_MODE, 0x00},
+ {GC0308_DEBUG_MODE1, 0x0a},
+ {GC0308_DEBUG_MODE2, 0x00},
+ {GC0308_DEBUG_MODE3, 0x01},
+ {GC0308_BLK_MODE, 0xf7},
+ {GC0308_BLK_LIMIT_VAL, 0x50},
+ {GC0308_GLOBAL_OFF, 0x00},
+ {GC0308_CURRENT_R_OFF, 0x28},
+ {GC0308_CURRENT_G_OFF, 0x2a},
+ {GC0308_CURRENT_B_OFF, 0x28},
+ {GC0308_EXP_RATE_DARKC, 0x04},
+ {GC0308_OFF_SUBMODE, 0x20},
+ {GC0308_DARKC_SUBMODE, 0x20},
+ {GC0308_MANUAL_G1_OFF, 0x00},
+ {GC0308_MANUAL_R1_OFF, 0x00},
+ {GC0308_MANUAL_B2_OFF, 0x00},
+ {GC0308_MANUAL_G2_OFF, 0x00},
+ {GC0308_GLOBAL_GAIN, 0x14},
+ {GC0308_AUTO_POSTGAIN, 0x41},
+ {GC0308_CHANNEL_GAIN_G1, 0x80},
+ {GC0308_CHANNEL_GAIN_R, 0x80},
+ {GC0308_CHANNEL_GAIN_B, 0x80},
+ {GC0308_CHANNEL_GAIN_G2, 0x80},
+ {GC0308_LSC_RED_B2, 0x20},
+ {GC0308_LSC_GREEN_B2, 0x20},
+ {GC0308_LSC_BLUE_B2, 0x20},
+ {GC0308_LSC_RED_B4, 0x14},
+ {GC0308_LSC_GREEN_B4, 0x10},
+ {GC0308_LSC_BLUE_B4, 0x14},
+ {GC0308_LSC_ROW_CENTER, 0x3c},
+ {GC0308_LSC_COL_CENTER, 0x50},
+ {GC0308_LSC_DEC_LVL1, 0x12},
+ {GC0308_LSC_DEC_LVL2, 0x1a},
+ {GC0308_LSC_DEC_LVL3, 0x24},
+ {GC0308_DN_MODE_EN, 0x07},
+ {GC0308_DN_MODE_RATIO, 0x15},
+ {GC0308_DN_BILAT_B_BASE, 0x08},
+ {GC0308_DN_BILAT_N_BASE, 0x03},
+ {GC0308_DD_DARK_BRIGHT_TH, 0xe8},
+ {GC0308_DD_FLAT_TH, 0x86},
+ {GC0308_DD_LIMIT, 0x82},
+ {GC0308_ASDE_GAIN_TRESH, 0x18},
+ {GC0308_ASDE_GAIN_MODE, 0x0f},
+ {GC0308_ASDE_DN_SLOPE, 0x00},
+ {GC0308_ASDE_DD_BRIGHT, 0x5f},
+ {GC0308_ASDE_DD_LIMIT, 0x8f},
+ {GC0308_ASDE_AUTO_EE1, 0x55},
+ {GC0308_ASDE_AUTO_EE2, 0x38},
+ {GC0308_ASDE_AUTO_SAT_DEC_SLOPE, 0x15},
+ {GC0308_ASDE_AUTO_SAT_LOW_LIMIT, 0x33},
+ {GC0308_EEINTP_MODE_1, 0xdc},
+ {GC0308_EEINTP_MODE_2, 0x00},
+ {GC0308_DIRECTION_TH1, 0x02},
+ {GC0308_DIRECTION_TH2, 0x3f},
+ {GC0308_DIFF_HV_TI_TH, 0x02},
+ {GC0308_EDGE12_EFFECT, 0x38},
+ {GC0308_EDGE_POS_RATIO, 0x88},
+ {GC0308_EDGE1_MINMAX, 0x81},
+ {GC0308_EDGE2_MINMAX, 0x81},
+ {GC0308_EDGE12_TH, 0x22},
+ {GC0308_EDGE_MAX, 0xff},
+ {GC0308_CC_MATRIX_C11, 0x48},
+ {GC0308_CC_MATRIX_C12, 0x02},
+ {GC0308_CC_MATRIX_C13, 0x07},
+ {GC0308_CC_MATRIX_C21, 0xe0},
+ {GC0308_CC_MATRIX_C22, 0x40},
+ {GC0308_CC_MATRIX_C23, 0xf0},
+ {GC0308_SATURATION_CB, 0x40},
+ {GC0308_SATURATION_CR, 0x40},
+ {GC0308_LUMA_CONTRAST, 0x40},
+ {GC0308_SKIN_CB_CENTER, 0xe0},
+ {GC0308_EDGE_DEC_SA, 0x38},
+ {GC0308_AUTO_GRAY_MODE, 0x36},
+ {GC0308_AEC_MODE1, 0xcb},
+ {GC0308_AEC_MODE2, 0x10},
+ {GC0308_AEC_MODE3, 0x90},
+ {GC0308_AEC_TARGET_Y, 0x48},
+ {GC0308_AEC_HIGH_LOW_RANGE, 0xf2},
+ {GC0308_AEC_IGNORE, 0x16},
+ {GC0308_AEC_SLOW_MARGIN, 0x92},
+ {GC0308_AEC_FAST_MARGIN, 0xa5},
+ {GC0308_AEC_I_FRAMES, 0x23},
+ {GC0308_AEC_R_OFFSET, 0x00},
+ {GC0308_AEC_GB_OFFSET, 0x00},
+ {GC0308_AEC_I_STOP_L_MARGIN, 0x09},
+ {GC0308_EXP_MIN_L, 0x04},
+ {GC0308_MAX_POST_DF_GAIN, 0xa0},
+ {GC0308_MAX_PRE_DG_GAIN, 0x40},
+ {GC0308_ABB_MODE, 0x03},
+ {GC0308_GAMMA_OUT0, 0x10},
+ {GC0308_GAMMA_OUT1, 0x20},
+ {GC0308_GAMMA_OUT2, 0x38},
+ {GC0308_GAMMA_OUT3, 0x4e},
+ {GC0308_GAMMA_OUT4, 0x63},
+ {GC0308_GAMMA_OUT5, 0x76},
+ {GC0308_GAMMA_OUT6, 0x87},
+ {GC0308_GAMMA_OUT7, 0xa2},
+ {GC0308_GAMMA_OUT8, 0xb8},
+ {GC0308_GAMMA_OUT9, 0xca},
+ {GC0308_GAMMA_OUT10, 0xd8},
+ {GC0308_GAMMA_OUT11, 0xe3},
+ {GC0308_GAMMA_OUT12, 0xeb},
+ {GC0308_GAMMA_OUT13, 0xf0},
+ {GC0308_GAMMA_OUT14, 0xf8},
+ {GC0308_GAMMA_OUT15, 0xfd},
+ {GC0308_GAMMA_OUT16, 0xff},
+ {GC0308_Y_GAMMA_OUT0, 0x00},
+ {GC0308_Y_GAMMA_OUT1, 0x10},
+ {GC0308_Y_GAMMA_OUT2, 0x1c},
+ {GC0308_Y_GAMMA_OUT3, 0x30},
+ {GC0308_Y_GAMMA_OUT4, 0x43},
+ {GC0308_Y_GAMMA_OUT5, 0x54},
+ {GC0308_Y_GAMMA_OUT6, 0x65},
+ {GC0308_Y_GAMMA_OUT7, 0x75},
+ {GC0308_Y_GAMMA_OUT8, 0x93},
+ {GC0308_Y_GAMMA_OUT9, 0xb0},
+ {GC0308_Y_GAMMA_OUT10, 0xcb},
+ {GC0308_Y_GAMMA_OUT11, 0xe6},
+ {GC0308_Y_GAMMA_OUT12, 0xff},
+ {GC0308_ABS_RANGE_COMP, 0x02},
+ {GC0308_ABS_STOP_MARGIN, 0x01},
+ {GC0308_Y_S_COMP, 0x02},
+ {GC0308_Y_STRETCH_LIMIT, 0x30},
+ {GC0308_BIG_WIN_X0, 0x12},
+ {GC0308_BIG_WIN_Y0, 0x0a},
+ {GC0308_BIG_WIN_X1, 0x9f},
+ {GC0308_BIG_WIN_Y1, 0x78},
+ {GC0308_AWB_RGB_HIGH_LOW, 0xf5},
+ {GC0308_AWB_Y_TO_C_DIFF2, 0x20},
+ {GC0308_AWB_C_MAX, 0x10},
+ {GC0308_AWB_C_INTER, 0x08},
+ {GC0308_AWB_C_INTER2, 0x20},
+ {GC0308_AWB_C_MAX_BIG, 0x0a},
+ {GC0308_AWB_NUMBER_LIMIT, 0xa0},
+ {GC0308_KWIN_RATIO, 0x60},
+ {GC0308_KWIN_THD, 0x08},
+ {GC0308_SMALL_WIN_WIDTH_STEP, 0x44},
+ {GC0308_SMALL_WIN_HEIGHT_STEP, 0x32},
+ {GC0308_AWB_YELLOW_TH, 0x41},
+ {GC0308_AWB_MODE, 0x37},
+ {GC0308_AWB_ADJUST_SPEED, 0x22},
+ {GC0308_AWB_EVERY_N, 0x19},
+ {CCI_REG8(0x114), 0x44}, /* AWB set1 */
+ {CCI_REG8(0x115), 0x44}, /* AWB set1 */
+ {CCI_REG8(0x116), 0xc2}, /* AWB set1 */
+ {CCI_REG8(0x117), 0xa8}, /* AWB set1 */
+ {CCI_REG8(0x118), 0x18}, /* AWB set1 */
+ {CCI_REG8(0x119), 0x50}, /* AWB set1 */
+ {CCI_REG8(0x11a), 0xd8}, /* AWB set1 */
+ {CCI_REG8(0x11b), 0xf5}, /* AWB set1 */
+ {CCI_REG8(0x170), 0x40}, /* AWB set2 */
+ {CCI_REG8(0x171), 0x58}, /* AWB set2 */
+ {CCI_REG8(0x172), 0x30}, /* AWB set2 */
+ {CCI_REG8(0x173), 0x48}, /* AWB set2 */
+ {CCI_REG8(0x174), 0x20}, /* AWB set2 */
+ {CCI_REG8(0x175), 0x60}, /* AWB set2 */
+ {CCI_REG8(0x177), 0x20}, /* AWB set2 */
+ {CCI_REG8(0x178), 0x32}, /* AWB set2 */
+ {CCI_REG8(0x130), 0x03}, /* undocumented */
+ {CCI_REG8(0x131), 0x40}, /* undocumented */
+ {CCI_REG8(0x132), 0x10}, /* undocumented */
+ {CCI_REG8(0x133), 0xe0}, /* undocumented */
+ {CCI_REG8(0x134), 0xe0}, /* undocumented */
+ {CCI_REG8(0x135), 0x00}, /* undocumented */
+ {CCI_REG8(0x136), 0x80}, /* undocumented */
+ {CCI_REG8(0x137), 0x00}, /* undocumented */
+ {CCI_REG8(0x138), 0x04}, /* undocumented */
+ {CCI_REG8(0x139), 0x09}, /* undocumented */
+ {CCI_REG8(0x13a), 0x12}, /* undocumented */
+ {CCI_REG8(0x13b), 0x1c}, /* undocumented */
+ {CCI_REG8(0x13c), 0x28}, /* undocumented */
+ {CCI_REG8(0x13d), 0x31}, /* undocumented */
+ {CCI_REG8(0x13e), 0x44}, /* undocumented */
+ {CCI_REG8(0x13f), 0x57}, /* undocumented */
+ {CCI_REG8(0x140), 0x6c}, /* undocumented */
+ {CCI_REG8(0x141), 0x81}, /* undocumented */
+ {CCI_REG8(0x142), 0x94}, /* undocumented */
+ {CCI_REG8(0x143), 0xa7}, /* undocumented */
+ {CCI_REG8(0x144), 0xb8}, /* undocumented */
+ {CCI_REG8(0x145), 0xd6}, /* undocumented */
+ {CCI_REG8(0x146), 0xee}, /* undocumented */
+ {CCI_REG8(0x147), 0x0d}, /* undocumented */
+ {CCI_REG8(0x162), 0xf7}, /* undocumented */
+ {CCI_REG8(0x163), 0x68}, /* undocumented */
+ {CCI_REG8(0x164), 0xd3}, /* undocumented */
+ {CCI_REG8(0x165), 0xd3}, /* undocumented */
+ {CCI_REG8(0x166), 0x60}, /* undocumented */
+};
+
+struct gc0308_colormode {
+ u8 special_effect;
+ u8 dbg_mode1;
+ u8 block_en1;
+ u8 aec_mode3;
+ u8 eeintp_mode_2;
+ u8 edge12_effect;
+ u8 luma_contrast;
+ u8 contrast_center;
+ u8 fixed_cb;
+ u8 fixed_cr;
+};
+
+#define GC0308_COLOR_FX(reg_special_effect, reg_dbg_mode1, reg_block_en1, \
+ reg_aec_mode3, reg_eeintp_mode_2, reg_edge12_effect, \
+ reg_luma_contrast, reg_contrast_center, \
+ reg_fixed_cb, reg_fixed_cr) \
+ { \
+ .special_effect = reg_special_effect, \
+ .dbg_mode1 = reg_dbg_mode1, \
+ .block_en1 = reg_block_en1, \
+ .aec_mode3 = reg_aec_mode3, \
+ .eeintp_mode_2 = reg_eeintp_mode_2, \
+ .edge12_effect = reg_edge12_effect, \
+ .luma_contrast = reg_luma_contrast, \
+ .contrast_center = reg_contrast_center, \
+ .fixed_cb = reg_fixed_cb, \
+ .fixed_cr = reg_fixed_cr, \
+ }
+
+static const struct gc0308_colormode gc0308_colormodes[] = {
+ [V4L2_COLORFX_NONE] =
+ GC0308_COLOR_FX(0x00, 0x0a, 0xff, 0x90, 0x00,
+ 0x54, 0x3c, 0x80, 0x00, 0x00),
+ [V4L2_COLORFX_BW] =
+ GC0308_COLOR_FX(0x02, 0x0a, 0xff, 0x90, 0x00,
+ 0x54, 0x40, 0x80, 0x00, 0x00),
+ [V4L2_COLORFX_SEPIA] =
+ GC0308_COLOR_FX(0x02, 0x0a, 0xff, 0x90, 0x00,
+ 0x38, 0x40, 0x80, 0xd0, 0x28),
+ [V4L2_COLORFX_NEGATIVE] =
+ GC0308_COLOR_FX(0x01, 0x0a, 0xff, 0x90, 0x00,
+ 0x38, 0x40, 0x80, 0x00, 0x00),
+ [V4L2_COLORFX_EMBOSS] =
+ GC0308_COLOR_FX(0x02, 0x0a, 0xbf, 0x10, 0x01,
+ 0x38, 0x40, 0x80, 0x00, 0x00),
+ [V4L2_COLORFX_SKETCH] =
+ GC0308_COLOR_FX(0x02, 0x0a, 0xff, 0x10, 0x80,
+ 0x38, 0x80, 0x90, 0x00, 0x00),
+ [V4L2_COLORFX_SKY_BLUE] =
+ GC0308_COLOR_FX(0x02, 0x0a, 0xff, 0x90, 0x00,
+ 0x38, 0x40, 0x80, 0x50, 0xe0),
+ [V4L2_COLORFX_GRASS_GREEN] =
+ GC0308_COLOR_FX(0x02, 0x0a, 0xff, 0x90, 0x01,
+ 0x38, 0x40, 0x80, 0xc0, 0xc0),
+ [V4L2_COLORFX_SKIN_WHITEN] =
+ GC0308_COLOR_FX(0x02, 0x0a, 0xbf, 0x10, 0x01,
+ 0x38, 0x60, 0x40, 0x00, 0x00),
+};
+
+static int gc0308_power_on(struct device *dev)
+{
+ struct gc0308 *gc0308 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regulator_enable(gc0308->vdd);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(gc0308->clk);
+ if (ret)
+ goto clk_fail;
+
+ gpiod_set_value_cansleep(gc0308->pwdn_gpio, 0);
+ usleep_range(10000, 20000);
+
+ gpiod_set_value_cansleep(gc0308->reset_gpio, 1);
+ usleep_range(10000, 20000);
+ gpiod_set_value_cansleep(gc0308->reset_gpio, 0);
+ msleep(30);
+
+ return 0;
+
+clk_fail:
+ regulator_disable(gc0308->vdd);
+ return ret;
+}
+
+static int gc0308_power_off(struct device *dev)
+{
+ struct gc0308 *gc0308 = dev_get_drvdata(dev);
+
+ gpiod_set_value_cansleep(gc0308->pwdn_gpio, 1);
+ clk_disable_unprepare(gc0308->clk);
+ regulator_disable(gc0308->vdd);
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int gc0308_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct gc0308 *gc0308 = to_gc0308(sd);
+
+ return cci_read(gc0308->regmap, CCI_REG8(reg->reg), &reg->val, NULL);
+}
+
+static int gc0308_s_register(struct v4l2_subdev *sd,
+ const struct v4l2_dbg_register *reg)
+{
+ struct gc0308 *gc0308 = to_gc0308(sd);
+
+ return cci_write(gc0308->regmap, CCI_REG8(reg->reg), reg->val, NULL);
+}
+#endif
+
+static int gc0308_set_exposure(struct gc0308 *gc0308, enum gc0308_exp_val exp)
+{
+ const struct gc0308_exposure *regs = &gc0308_exposure_values[exp];
+ struct cci_reg_sequence exposure_reg_seq[] = {
+ {GC0308_LUMA_OFFSET, regs->luma_offset},
+ {GC0308_AEC_TARGET_Y, regs->aec_target_y},
+ };
+
+ return cci_multi_reg_write(gc0308->regmap, exposure_reg_seq,
+ ARRAY_SIZE(exposure_reg_seq), NULL);
+}
+
+static int gc0308_set_awb_mode(struct gc0308 *gc0308,
+ enum v4l2_auto_n_preset_white_balance val)
+{
+ const struct gc0308_awb_gains *regs = &gc0308_awb_gains[val];
+ struct cci_reg_sequence awb_reg_seq[] = {
+ {GC0308_AWB_R_GAIN, regs->r},
+ {GC0308_AWB_G_GAIN, regs->g},
+ {GC0308_AWB_B_GAIN, regs->b},
+ };
+ int ret;
+
+ ret = cci_update_bits(gc0308->regmap, GC0308_AAAA_EN,
+ BIT(1), val == V4L2_WHITE_BALANCE_AUTO, NULL);
+ ret = cci_multi_reg_write(gc0308->regmap, awb_reg_seq,
+ ARRAY_SIZE(awb_reg_seq), &ret);
+
+ return ret;
+}
+
+static int gc0308_set_colormode(struct gc0308 *gc0308, enum v4l2_colorfx mode)
+{
+ const struct gc0308_colormode *regs = &gc0308_colormodes[mode];
+ struct cci_reg_sequence colormode_reg_seq[] = {
+ {GC0308_SPECIAL_EFFECT, regs->special_effect},
+ {GC0308_DEBUG_MODE1, regs->dbg_mode1},
+ {GC0308_BLOCK_EN1, regs->block_en1},
+ {GC0308_AEC_MODE3, regs->aec_mode3},
+ {GC0308_EEINTP_MODE_2, regs->eeintp_mode_2},
+ {GC0308_EDGE12_EFFECT, regs->edge12_effect},
+ {GC0308_LUMA_CONTRAST, regs->luma_contrast},
+ {GC0308_CONTRAST_CENTER, regs->contrast_center},
+ {GC0308_FIXED_CB, regs->fixed_cb},
+ {GC0308_FIXED_CR, regs->fixed_cr},
+ };
+
+ return cci_multi_reg_write(gc0308->regmap, colormode_reg_seq,
+ ARRAY_SIZE(colormode_reg_seq), NULL);
+}
+
+static int gc0308_set_power_line_freq(struct gc0308 *gc0308, int frequency)
+{
+ static const struct cci_reg_sequence pwr_line_50hz[] = {
+ {GC0308_ANTI_FLICKER_STEP, 0x0078},
+ {GC0308_EXP_LVL_1, 0x0258},
+ {GC0308_EXP_LVL_2, 0x0348},
+ {GC0308_EXP_LVL_3, 0x04b0},
+ {GC0308_EXP_LVL_4, 0x05a0},
+ };
+ static const struct cci_reg_sequence pwr_line_60hz[] = {
+ {GC0308_ANTI_FLICKER_STEP, 0x0064},
+ {GC0308_EXP_LVL_1, 0x0258},
+ {GC0308_EXP_LVL_2, 0x0384},
+ {GC0308_EXP_LVL_3, 0x04b0},
+ {GC0308_EXP_LVL_4, 0x05dc},
+ };
+
+ switch (frequency) {
+ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
+ return cci_multi_reg_write(gc0308->regmap, pwr_line_60hz,
+ ARRAY_SIZE(pwr_line_60hz), NULL);
+ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
+ return cci_multi_reg_write(gc0308->regmap, pwr_line_50hz,
+ ARRAY_SIZE(pwr_line_50hz), NULL);
+ }
+
+ return -EINVAL;
+}
+
+static int gc0308_update_mirror(struct gc0308 *gc0308)
+{
+ u8 regval = 0x00;
+
+ if (gc0308->vflip->val)
+ regval |= BIT(1);
+
+ if (gc0308->hflip->val)
+ regval |= BIT(0);
+
+ return cci_update_bits(gc0308->regmap, GC0308_CISCTL_MODE1,
+ GENMASK(1, 0), regval, NULL);
+}
+
+static int gc0308_update_blanking(struct gc0308 *gc0308)
+{
+ u16 vblank = gc0308->vblank->val;
+ u16 hblank = gc0308->hblank->val;
+ u8 vbhb = ((vblank >> 4) & 0xf0) | ((hblank >> 8) & 0x0f);
+ int ret = 0;
+
+ cci_write(gc0308->regmap, GC0308_VB_HB, vbhb, &ret);
+ cci_write(gc0308->regmap, GC0308_HBLANK, hblank & 0xff, &ret);
+ cci_write(gc0308->regmap, GC0308_VBLANK, vblank & 0xff, &ret);
+
+ return ret;
+}
+
+static int _gc0308_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gc0308 *gc0308 = container_of(ctrl->handler, struct gc0308, hdl);
+ u8 flipval = ctrl->val ? 0xff : 0x00;
+
+ switch (ctrl->id) {
+ case V4L2_CID_HBLANK:
+ case V4L2_CID_VBLANK:
+ return gc0308_update_blanking(gc0308);
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HFLIP:
+ return gc0308_update_mirror(gc0308);
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ return cci_update_bits(gc0308->regmap, GC0308_AAAA_EN,
+ BIT(1), flipval, NULL);
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+ return gc0308_set_awb_mode(gc0308, ctrl->val);
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ return gc0308_set_power_line_freq(gc0308, ctrl->val);
+ case V4L2_CID_COLORFX:
+ return gc0308_set_colormode(gc0308, ctrl->val);
+ case V4L2_CID_TEST_PATTERN:
+ return cci_update_bits(gc0308->regmap, GC0308_DEBUG_MODE2,
+ GENMASK(1, 0), ctrl->val, NULL);
+ case V4L2_CID_AUTO_EXPOSURE_BIAS:
+ return gc0308_set_exposure(gc0308, ctrl->val);
+ }
+
+ return -EINVAL;
+}
+
+static int gc0308_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gc0308 *gc0308 = container_of(ctrl->handler, struct gc0308, hdl);
+ int ret;
+
+ if (!pm_runtime_get_if_in_use(gc0308->dev))
+ return 0;
+
+ ret = _gc0308_s_ctrl(ctrl);
+ if (ret)
+ dev_err(gc0308->dev, "failed to set control: %d\n", ret);
+
+ pm_runtime_mark_last_busy(gc0308->dev);
+ pm_runtime_put_autosuspend(gc0308->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops gc0308_ctrl_ops = {
+ .s_ctrl = gc0308_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops gc0308_core_ops = {
+ .log_status = v4l2_ctrl_subdev_log_status,
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = gc0308_g_register,
+ .s_register = gc0308_s_register,
+#endif
+};
+
+static int gc0308_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(gc0308_formats))
+ return -EINVAL;
+
+ code->code = gc0308_formats[code->index].code;
+
+ return 0;
+}
+
+static int gc0308_get_format_idx(u32 code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(gc0308_formats); i++) {
+ if (gc0308_formats[i].code == code)
+ return i;
+ }
+
+ return -1;
+}
+
+static int gc0308_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index >= ARRAY_SIZE(gc0308_frame_sizes))
+ return -EINVAL;
+
+ if (gc0308_get_format_idx(fse->code) < 0)
+ return -EINVAL;
+
+ fse->min_width = gc0308_frame_sizes[fse->index].width;
+ fse->max_width = gc0308_frame_sizes[fse->index].width;
+ fse->min_height = gc0308_frame_sizes[fse->index].height;
+ fse->max_height = gc0308_frame_sizes[fse->index].height;
+
+ return 0;
+}
+
+static void gc0308_update_pad_format(const struct gc0308_frame_size *mode,
+ struct v4l2_mbus_framefmt *fmt, u32 code)
+{
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->code = code;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+}
+
+static int gc0308_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct gc0308 *gc0308 = to_gc0308(sd);
+ const struct gc0308_frame_size *mode;
+ int i = gc0308_get_format_idx(fmt->format.code);
+
+ if (i < 0)
+ i = 0;
+
+ mode = v4l2_find_nearest_size(gc0308_frame_sizes,
+ ARRAY_SIZE(gc0308_frame_sizes), width,
+ height, fmt->format.width,
+ fmt->format.height);
+
+ gc0308_update_pad_format(mode, &fmt->format, gc0308_formats[i].code);
+ *v4l2_subdev_state_get_format(sd_state, 0) = fmt->format;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ gc0308->mode.out_format = gc0308_formats[i].regval;
+ gc0308->mode.subsample = mode->subsample;
+ gc0308->mode.width = mode->width;
+ gc0308->mode.height = mode->height;
+
+ return 0;
+}
+
+static int gc0308_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct v4l2_mbus_framefmt *format =
+ v4l2_subdev_state_get_format(sd_state, 0);
+
+ format->width = 640;
+ format->height = 480;
+ format->code = gc0308_formats[0].code;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+ format->field = V4L2_FIELD_NONE;
+ format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ format->quantization = V4L2_QUANTIZATION_DEFAULT;
+ format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops gc0308_pad_ops = {
+ .enum_mbus_code = gc0308_enum_mbus_code,
+ .enum_frame_size = gc0308_enum_frame_size,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = gc0308_set_format,
+};
+
+static int gc0308_set_resolution(struct gc0308 *gc0308, int *ret)
+{
+ struct cci_reg_sequence resolution_regs[] = {
+ {GC0308_SUBSAMPLE, gc0308->mode.subsample},
+ {GC0308_SUBMODE, 0x03},
+ {GC0308_SUB_ROW_N1, 0x00},
+ {GC0308_SUB_ROW_N2, 0x00},
+ {GC0308_SUB_COL_N1, 0x00},
+ {GC0308_SUB_COL_N2, 0x00},
+ {GC0308_CROP_WIN_MODE, 0x80},
+ {GC0308_CROP_WIN_Y1, 0x00},
+ {GC0308_CROP_WIN_X1, 0x00},
+ {GC0308_CROP_WIN_HEIGHT, gc0308->mode.height},
+ {GC0308_CROP_WIN_WIDTH, gc0308->mode.width},
+ };
+
+ return cci_multi_reg_write(gc0308->regmap, resolution_regs,
+ ARRAY_SIZE(resolution_regs), ret);
+}
+
+static int gc0308_start_stream(struct gc0308 *gc0308)
+{
+ int ret, sync_mode;
+
+ ret = pm_runtime_resume_and_get(gc0308->dev);
+ if (ret < 0)
+ return ret;
+
+ cci_multi_reg_write(gc0308->regmap, sensor_default_regs,
+ ARRAY_SIZE(sensor_default_regs), &ret);
+ cci_update_bits(gc0308->regmap, GC0308_OUT_FORMAT,
+ GENMASK(4, 0), gc0308->mode.out_format, &ret);
+ gc0308_set_resolution(gc0308, &ret);
+
+ if (ret) {
+ dev_err(gc0308->dev, "failed to update registers: %d\n", ret);
+ goto disable_pm;
+ }
+
+ ret = __v4l2_ctrl_handler_setup(&gc0308->hdl);
+ if (ret) {
+ dev_err(gc0308->dev, "failed to setup controls\n");
+ goto disable_pm;
+ }
+
+ /* HSYNC/VSYNC polarity */
+ sync_mode = 0x3;
+ if (gc0308->mbus_config & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ sync_mode &= ~BIT(0);
+ if (gc0308->mbus_config & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ sync_mode &= ~BIT(1);
+ ret = cci_write(gc0308->regmap, GC0308_SYNC_MODE, sync_mode, NULL);
+ if (ret)
+ goto disable_pm;
+
+ return 0;
+
+disable_pm:
+ pm_runtime_mark_last_busy(gc0308->dev);
+ pm_runtime_put_autosuspend(gc0308->dev);
+ return ret;
+}
+
+static int gc0308_stop_stream(struct gc0308 *gc0308)
+{
+ pm_runtime_mark_last_busy(gc0308->dev);
+ pm_runtime_put_autosuspend(gc0308->dev);
+ return 0;
+}
+
+static int gc0308_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct gc0308 *gc0308 = to_gc0308(sd);
+ struct v4l2_subdev_state *sd_state;
+ int ret;
+
+ sd_state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ if (enable)
+ ret = gc0308_start_stream(gc0308);
+ else
+ ret = gc0308_stop_stream(gc0308);
+
+ v4l2_subdev_unlock_state(sd_state);
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops gc0308_video_ops = {
+ .s_stream = gc0308_s_stream,
+};
+
+static const struct v4l2_subdev_ops gc0308_subdev_ops = {
+ .core = &gc0308_core_ops,
+ .pad = &gc0308_pad_ops,
+ .video = &gc0308_video_ops,
+};
+
+static const struct v4l2_subdev_internal_ops gc0308_internal_ops = {
+ .init_state = gc0308_init_state,
+};
+
+static int gc0308_bus_config(struct gc0308 *gc0308)
+{
+ struct device *dev = gc0308->dev;
+ struct v4l2_fwnode_endpoint bus_cfg = {
+ .bus_type = V4L2_MBUS_PARALLEL
+ };
+ struct fwnode_handle *ep;
+ int ret;
+
+ ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
+ if (!ep)
+ return -EINVAL;
+
+ ret = v4l2_fwnode_endpoint_parse(ep, &bus_cfg);
+ fwnode_handle_put(ep);
+ if (ret)
+ return ret;
+
+ gc0308->mbus_config = bus_cfg.bus.parallel.flags;
+
+ return 0;
+}
+
+static const char * const gc0308_test_pattern_menu[] = {
+ "Disabled",
+ "Test Image 1",
+ "Test Image 2",
+};
+
+static int gc0308_init_controls(struct gc0308 *gc0308)
+{
+ int ret;
+
+ v4l2_ctrl_handler_init(&gc0308->hdl, 11);
+ gc0308->hblank = v4l2_ctrl_new_std(&gc0308->hdl, &gc0308_ctrl_ops,
+ V4L2_CID_HBLANK, GC0308_HBLANK_MIN,
+ GC0308_HBLANK_MAX, 1,
+ GC0308_HBLANK_DEF);
+ gc0308->vblank = v4l2_ctrl_new_std(&gc0308->hdl, &gc0308_ctrl_ops,
+ V4L2_CID_VBLANK, GC0308_VBLANK_MIN,
+ GC0308_VBLANK_MAX, 1,
+ GC0308_VBLANK_DEF);
+ gc0308->hflip = v4l2_ctrl_new_std(&gc0308->hdl, &gc0308_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ gc0308->vflip = v4l2_ctrl_new_std(&gc0308->hdl, &gc0308_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&gc0308->hdl, &gc0308_ctrl_ops, V4L2_CID_PIXEL_RATE,
+ GC0308_PIXEL_RATE, GC0308_PIXEL_RATE, 1,
+ GC0308_PIXEL_RATE);
+ v4l2_ctrl_new_std(&gc0308->hdl, &gc0308_ctrl_ops,
+ V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+ v4l2_ctrl_new_std_menu_items(&gc0308->hdl, &gc0308_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(gc0308_test_pattern_menu) - 1,
+ 0, 0, gc0308_test_pattern_menu);
+ v4l2_ctrl_new_std_menu(&gc0308->hdl, &gc0308_ctrl_ops,
+ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+ 8, ~0x14e, V4L2_WHITE_BALANCE_AUTO);
+ v4l2_ctrl_new_std_menu(&gc0308->hdl, &gc0308_ctrl_ops,
+ V4L2_CID_COLORFX, 8, 0, V4L2_COLORFX_NONE);
+ v4l2_ctrl_new_std_menu(&gc0308->hdl, &gc0308_ctrl_ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ ~0x6, V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
+ v4l2_ctrl_new_int_menu(&gc0308->hdl, &gc0308_ctrl_ops,
+ V4L2_CID_AUTO_EXPOSURE_BIAS,
+ ARRAY_SIZE(gc0308_exposure_menu) - 1,
+ ARRAY_SIZE(gc0308_exposure_menu) / 2,
+ gc0308_exposure_menu);
+
+ gc0308->sd.ctrl_handler = &gc0308->hdl;
+ if (gc0308->hdl.error) {
+ ret = gc0308->hdl.error;
+ v4l2_ctrl_handler_free(&gc0308->hdl);
+ return ret;
+ }
+
+ v4l2_ctrl_cluster(2, &gc0308->hflip);
+ v4l2_ctrl_cluster(2, &gc0308->hblank);
+
+ return 0;
+}
+
+static int gc0308_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct gc0308 *gc0308;
+ unsigned long clkrate;
+ u64 regval;
+ int ret;
+
+ gc0308 = devm_kzalloc(dev, sizeof(*gc0308), GFP_KERNEL);
+ if (!gc0308)
+ return -ENOMEM;
+
+ gc0308->dev = dev;
+ dev_set_drvdata(dev, gc0308);
+
+ ret = gc0308_bus_config(gc0308);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get bus config\n");
+
+ gc0308->clk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(gc0308->clk))
+ return dev_err_probe(dev, PTR_ERR(gc0308->clk),
+ "could not get clk\n");
+
+ gc0308->vdd = devm_regulator_get(dev, "vdd28");
+ if (IS_ERR(gc0308->vdd))
+ return dev_err_probe(dev, PTR_ERR(gc0308->vdd),
+ "failed to get vdd28 regulator\n");
+
+ gc0308->pwdn_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_LOW);
+ if (IS_ERR(gc0308->pwdn_gpio))
+ return dev_err_probe(dev, PTR_ERR(gc0308->pwdn_gpio),
+ "failed to get powerdown gpio\n");
+
+ gc0308->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(gc0308->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(gc0308->reset_gpio),
+ "failed to get reset gpio\n");
+
+ /*
+ * This is not using devm_cci_regmap_init_i2c(), because the driver
+ * makes use of regmap's pagination feature. The chosen settings are
+ * compatible with the CCI helpers.
+ */
+ gc0308->regmap = devm_regmap_init_i2c(client, &gc0308_regmap_config);
+ if (IS_ERR(gc0308->regmap))
+ return dev_err_probe(dev, PTR_ERR(gc0308->regmap),
+ "failed to init regmap\n");
+
+ v4l2_i2c_subdev_init(&gc0308->sd, client, &gc0308_subdev_ops);
+ gc0308->sd.internal_ops = &gc0308_internal_ops;
+ gc0308->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ gc0308->sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+
+ ret = gc0308_init_controls(gc0308);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to init controls\n");
+
+ gc0308->sd.state_lock = gc0308->hdl.lock;
+ gc0308->pad.flags = MEDIA_PAD_FL_SOURCE;
+ gc0308->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&gc0308->sd.entity, 1, &gc0308->pad);
+ if (ret < 0)
+ goto fail_ctrl_hdl_cleanup;
+
+ ret = v4l2_subdev_init_finalize(&gc0308->sd);
+ if (ret)
+ goto fail_media_entity_cleanup;
+
+ ret = gc0308_power_on(dev);
+ if (ret)
+ goto fail_subdev_cleanup;
+
+ if (gc0308->clk) {
+ clkrate = clk_get_rate(gc0308->clk);
+ if (clkrate != 24000000)
+ dev_warn(dev, "unexpected clock rate: %lu\n", clkrate);
+ }
+
+ ret = cci_read(gc0308->regmap, GC0308_CHIP_ID, &regval, NULL);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "failed to read chip ID\n");
+ goto fail_power_off;
+ }
+
+ if (regval != 0x9b) {
+ ret = -EINVAL;
+ dev_err_probe(dev, ret, "invalid chip ID (%02llx)\n", regval);
+ goto fail_power_off;
+ }
+
+ /*
+ * Enable runtime PM with autosuspend. As the device has been powered
+ * manually, mark it as active, and increase the usage count without
+ * resuming the device.
+ */
+ pm_runtime_set_active(dev);
+ pm_runtime_get_noresume(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+
+ ret = v4l2_async_register_subdev(&gc0308->sd);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to register v4l subdev\n");
+ goto fail_rpm;
+ }
+
+ return 0;
+
+fail_rpm:
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
+fail_power_off:
+ gc0308_power_off(dev);
+fail_subdev_cleanup:
+ v4l2_subdev_cleanup(&gc0308->sd);
+fail_media_entity_cleanup:
+ media_entity_cleanup(&gc0308->sd.entity);
+fail_ctrl_hdl_cleanup:
+ v4l2_ctrl_handler_free(&gc0308->hdl);
+ return ret;
+}
+
+static void gc0308_remove(struct i2c_client *client)
+{
+ struct gc0308 *gc0308 = i2c_get_clientdata(client);
+ struct device *dev = &client->dev;
+
+ v4l2_async_unregister_subdev(&gc0308->sd);
+ v4l2_ctrl_handler_free(&gc0308->hdl);
+ media_entity_cleanup(&gc0308->sd.entity);
+
+ pm_runtime_disable(dev);
+ if (!pm_runtime_status_suspended(dev))
+ gc0308_power_off(dev);
+ pm_runtime_set_suspended(dev);
+}
+
+static const struct dev_pm_ops gc0308_pm_ops = {
+ SET_RUNTIME_PM_OPS(gc0308_power_off, gc0308_power_on, NULL)
+};
+
+static const struct of_device_id gc0308_of_match[] = {
+ { .compatible = "galaxycore,gc0308" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, gc0308_of_match);
+
+static struct i2c_driver gc0308_i2c_driver = {
+ .driver = {
+ .name = "gc0308",
+ .pm = &gc0308_pm_ops,
+ .of_match_table = gc0308_of_match,
+ },
+ .probe = gc0308_probe,
+ .remove = gc0308_remove,
+};
+module_i2c_driver(gc0308_i2c_driver);
+
+MODULE_DESCRIPTION("GalaxyCore GC0308 Camera Driver");
+MODULE_AUTHOR("Sebastian Reichel <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c
new file mode 100644
index 000000000000..bef7b0e056a8
--- /dev/null
+++ b/drivers/media/i2c/gc2145.c
@@ -0,0 +1,1450 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A V4L2 driver for Galaxycore GC2145 camera.
+ * Copyright (C) 2023, STMicroelectronics SA
+ *
+ * Inspired by the imx219.c driver
+ *
+ * Datasheet v1.0 available at http://files.pine64.org/doc/datasheet/PinebookPro/GC2145%20CSP%20DataSheet%20release%20V1.0_20131201.pdf
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/units.h>
+
+#include <media/mipi-csi2.h>
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
+
+/* Chip ID */
+#define GC2145_CHIP_ID 0x2145
+
+/* Page 0 */
+#define GC2145_REG_EXPOSURE CCI_REG16(0x03)
+#define GC2145_REG_HBLANK CCI_REG16(0x05)
+#define GC2145_REG_VBLANK CCI_REG16(0x07)
+#define GC2145_REG_ROW_START CCI_REG16(0x09)
+#define GC2145_REG_COL_START CCI_REG16(0x0b)
+#define GC2145_REG_WIN_HEIGHT CCI_REG16(0x0d)
+#define GC2145_REG_WIN_WIDTH CCI_REG16(0x0f)
+#define GC2145_REG_ANALOG_MODE1 CCI_REG8(0x17)
+#define GC2145_REG_OUTPUT_FMT CCI_REG8(0x84)
+#define GC2145_REG_SYNC_MODE CCI_REG8(0x86)
+#define GC2145_SYNC_MODE_COL_SWITCH BIT(4)
+#define GC2145_SYNC_MODE_ROW_SWITCH BIT(5)
+#define GC2145_REG_BYPASS_MODE CCI_REG8(0x89)
+#define GC2145_BYPASS_MODE_SWITCH BIT(5)
+#define GC2145_REG_DEBUG_MODE2 CCI_REG8(0x8c)
+#define GC2145_REG_DEBUG_MODE3 CCI_REG8(0x8d)
+#define GC2145_REG_CROP_ENABLE CCI_REG8(0x90)
+#define GC2145_REG_CROP_Y CCI_REG16(0x91)
+#define GC2145_REG_CROP_X CCI_REG16(0x93)
+#define GC2145_REG_CROP_HEIGHT CCI_REG16(0x95)
+#define GC2145_REG_CROP_WIDTH CCI_REG16(0x97)
+#define GC2145_REG_GLOBAL_GAIN CCI_REG8(0xb0)
+#define GC2145_REG_CHIP_ID CCI_REG16(0xf0)
+#define GC2145_REG_PAD_IO CCI_REG8(0xf2)
+#define GC2145_REG_PAGE_SELECT CCI_REG8(0xfe)
+/* Page 3 */
+#define GC2145_REG_DPHY_ANALOG_MODE1 CCI_REG8(0x01)
+#define GC2145_DPHY_MODE_PHY_CLK_EN BIT(0)
+#define GC2145_DPHY_MODE_PHY_LANE0_EN BIT(1)
+#define GC2145_DPHY_MODE_PHY_LANE1_EN BIT(2)
+#define GC2145_DPHY_MODE_PHY_CLK_LANE_P2S_SEL BIT(7)
+#define GC2145_REG_DPHY_ANALOG_MODE2 CCI_REG8(0x02)
+#define GC2145_DPHY_CLK_DIFF(a) ((a) & 0x07)
+#define GC2145_DPHY_LANE0_DIFF(a) (((a) & 0x07) << 4)
+#define GC2145_REG_DPHY_ANALOG_MODE3 CCI_REG8(0x03)
+#define GC2145_DPHY_LANE1_DIFF(a) ((a) & 0x07)
+#define GC2145_DPHY_CLK_DELAY BIT(4)
+#define GC2145_DPHY_LANE0_DELAY BIT(5)
+#define GC2145_DPHY_LANE1_DELAY BIT(6)
+#define GC2145_REG_FIFO_FULL_LVL_LOW CCI_REG8(0x04)
+#define GC2145_REG_FIFO_FULL_LVL_HIGH CCI_REG8(0x05)
+#define GC2145_REG_FIFO_MODE CCI_REG8(0x06)
+#define GC2145_FIFO_MODE_READ_GATE BIT(3)
+#define GC2145_FIFO_MODE_MIPI_CLK_MODULE BIT(7)
+#define GC2145_REG_BUF_CSI2_MODE CCI_REG8(0x10)
+#define GC2145_CSI2_MODE_DOUBLE BIT(0)
+#define GC2145_CSI2_MODE_RAW8 BIT(2)
+#define GC2145_CSI2_MODE_MIPI_EN BIT(4)
+#define GC2145_CSI2_MODE_EN BIT(7)
+#define GC2145_REG_MIPI_DT CCI_REG8(0x11)
+#define GC2145_REG_LWC_LOW CCI_REG8(0x12)
+#define GC2145_REG_LWC_HIGH CCI_REG8(0x13)
+#define GC2145_REG_DPHY_MODE CCI_REG8(0x15)
+#define GC2145_DPHY_MODE_TRIGGER_PROG BIT(4)
+#define GC2145_REG_FIFO_GATE_MODE CCI_REG8(0x17)
+#define GC2145_REG_T_LPX CCI_REG8(0x21)
+#define GC2145_REG_T_CLK_HS_PREPARE CCI_REG8(0x22)
+#define GC2145_REG_T_CLK_ZERO CCI_REG8(0x23)
+#define GC2145_REG_T_CLK_PRE CCI_REG8(0x24)
+#define GC2145_REG_T_CLK_POST CCI_REG8(0x25)
+#define GC2145_REG_T_CLK_TRAIL CCI_REG8(0x26)
+#define GC2145_REG_T_HS_EXIT CCI_REG8(0x27)
+#define GC2145_REG_T_WAKEUP CCI_REG8(0x28)
+#define GC2145_REG_T_HS_PREPARE CCI_REG8(0x29)
+#define GC2145_REG_T_HS_ZERO CCI_REG8(0x2a)
+#define GC2145_REG_T_HS_TRAIL CCI_REG8(0x2b)
+
+/* External clock frequency is 24.0MHz */
+#define GC2145_XCLK_FREQ (24 * HZ_PER_MHZ)
+
+#define GC2145_NATIVE_WIDTH 1616U
+#define GC2145_NATIVE_HEIGHT 1232U
+
+/**
+ * struct gc2145_mode - GC2145 mode description
+ * @width: frame width (in pixels)
+ * @height: frame height (in pixels)
+ * @reg_seq: registers config sequence to enter into the mode
+ * @reg_seq_size: size of the sequence
+ * @pixel_rate: pixel rate associated with the mode
+ * @crop: window area captured
+ * @hblank: default horizontal blanking
+ * @vblank: default vertical blanking
+ * @link_freq_index: index within the link frequency menu
+ */
+struct gc2145_mode {
+ unsigned int width;
+ unsigned int height;
+ const struct cci_reg_sequence *reg_seq;
+ size_t reg_seq_size;
+ unsigned long pixel_rate;
+ struct v4l2_rect crop;
+ unsigned int hblank;
+ unsigned int vblank;
+ unsigned int link_freq_index;
+};
+
+#define GC2145_DEFAULT_EXPOSURE 0x04e2
+#define GC2145_DEFAULT_GLOBAL_GAIN 0x55
+static const struct cci_reg_sequence gc2145_common_regs[] = {
+ {GC2145_REG_PAGE_SELECT, 0x00},
+ /* SH Delay */
+ {CCI_REG8(0x12), 0x2e},
+ /* Flip */
+ {GC2145_REG_ANALOG_MODE1, 0x14},
+ /* Analog Conf */
+ {CCI_REG8(0x18), 0x22}, {CCI_REG8(0x19), 0x0e}, {CCI_REG8(0x1a), 0x01},
+ {CCI_REG8(0x1b), 0x4b}, {CCI_REG8(0x1c), 0x07}, {CCI_REG8(0x1d), 0x10},
+ {CCI_REG8(0x1e), 0x88}, {CCI_REG8(0x1f), 0x78}, {CCI_REG8(0x20), 0x03},
+ {CCI_REG8(0x21), 0x40}, {CCI_REG8(0x22), 0xa0}, {CCI_REG8(0x24), 0x16},
+ {CCI_REG8(0x25), 0x01}, {CCI_REG8(0x26), 0x10}, {CCI_REG8(0x2d), 0x60},
+ {CCI_REG8(0x30), 0x01}, {CCI_REG8(0x31), 0x90}, {CCI_REG8(0x33), 0x06},
+ {CCI_REG8(0x34), 0x01},
+ /* ISP related */
+ {CCI_REG8(0x80), 0x7f}, {CCI_REG8(0x81), 0x26}, {CCI_REG8(0x82), 0xfa},
+ {CCI_REG8(0x83), 0x00}, {CCI_REG8(0x84), 0x02}, {CCI_REG8(0x86), 0x02},
+ {CCI_REG8(0x88), 0x03},
+ {GC2145_REG_BYPASS_MODE, 0x03},
+ {CCI_REG8(0x85), 0x08}, {CCI_REG8(0x8a), 0x00}, {CCI_REG8(0x8b), 0x00},
+ {GC2145_REG_GLOBAL_GAIN, GC2145_DEFAULT_GLOBAL_GAIN},
+ {CCI_REG8(0xc3), 0x00}, {CCI_REG8(0xc4), 0x80}, {CCI_REG8(0xc5), 0x90},
+ {CCI_REG8(0xc6), 0x3b}, {CCI_REG8(0xc7), 0x46},
+ /* BLK */
+ {GC2145_REG_PAGE_SELECT, 0x00},
+ {CCI_REG8(0x40), 0x42}, {CCI_REG8(0x41), 0x00}, {CCI_REG8(0x43), 0x5b},
+ {CCI_REG8(0x5e), 0x00}, {CCI_REG8(0x5f), 0x00}, {CCI_REG8(0x60), 0x00},
+ {CCI_REG8(0x61), 0x00}, {CCI_REG8(0x62), 0x00}, {CCI_REG8(0x63), 0x00},
+ {CCI_REG8(0x64), 0x00}, {CCI_REG8(0x65), 0x00}, {CCI_REG8(0x66), 0x20},
+ {CCI_REG8(0x67), 0x20}, {CCI_REG8(0x68), 0x20}, {CCI_REG8(0x69), 0x20},
+ {CCI_REG8(0x76), 0x00}, {CCI_REG8(0x6a), 0x08}, {CCI_REG8(0x6b), 0x08},
+ {CCI_REG8(0x6c), 0x08}, {CCI_REG8(0x6d), 0x08}, {CCI_REG8(0x6e), 0x08},
+ {CCI_REG8(0x6f), 0x08}, {CCI_REG8(0x70), 0x08}, {CCI_REG8(0x71), 0x08},
+ {CCI_REG8(0x76), 0x00}, {CCI_REG8(0x72), 0xf0}, {CCI_REG8(0x7e), 0x3c},
+ {CCI_REG8(0x7f), 0x00},
+ {GC2145_REG_PAGE_SELECT, 0x02},
+ {CCI_REG8(0x48), 0x15}, {CCI_REG8(0x49), 0x00}, {CCI_REG8(0x4b), 0x0b},
+ /* AEC */
+ {GC2145_REG_PAGE_SELECT, 0x00},
+ {GC2145_REG_EXPOSURE, GC2145_DEFAULT_EXPOSURE},
+ {GC2145_REG_PAGE_SELECT, 0x01},
+ {CCI_REG8(0x01), 0x04}, {CCI_REG8(0x02), 0xc0}, {CCI_REG8(0x03), 0x04},
+ {CCI_REG8(0x04), 0x90}, {CCI_REG8(0x05), 0x30}, {CCI_REG8(0x06), 0x90},
+ {CCI_REG8(0x07), 0x30}, {CCI_REG8(0x08), 0x80}, {CCI_REG8(0x09), 0x00},
+ {CCI_REG8(0x0a), 0x82}, {CCI_REG8(0x0b), 0x11}, {CCI_REG8(0x0c), 0x10},
+ {CCI_REG8(0x11), 0x10}, {CCI_REG8(0x13), 0x7b}, {CCI_REG8(0x17), 0x00},
+ {CCI_REG8(0x1c), 0x11}, {CCI_REG8(0x1e), 0x61}, {CCI_REG8(0x1f), 0x35},
+ {CCI_REG8(0x20), 0x40}, {CCI_REG8(0x22), 0x40}, {CCI_REG8(0x23), 0x20},
+ {GC2145_REG_PAGE_SELECT, 0x02},
+ {CCI_REG8(0x0f), 0x04},
+ {GC2145_REG_PAGE_SELECT, 0x01},
+ {CCI_REG8(0x12), 0x35}, {CCI_REG8(0x15), 0xb0}, {CCI_REG8(0x10), 0x31},
+ {CCI_REG8(0x3e), 0x28}, {CCI_REG8(0x3f), 0xb0}, {CCI_REG8(0x40), 0x90},
+ {CCI_REG8(0x41), 0x0f},
+ /* INTPEE */
+ {GC2145_REG_PAGE_SELECT, 0x02},
+ {CCI_REG8(0x90), 0x6c}, {CCI_REG8(0x91), 0x03}, {CCI_REG8(0x92), 0xcb},
+ {CCI_REG8(0x94), 0x33}, {CCI_REG8(0x95), 0x84}, {CCI_REG8(0x97), 0x65},
+ {CCI_REG8(0xa2), 0x11},
+ /* DNDD */
+ {GC2145_REG_PAGE_SELECT, 0x02},
+ {CCI_REG8(0x80), 0xc1}, {CCI_REG8(0x81), 0x08}, {CCI_REG8(0x82), 0x05},
+ {CCI_REG8(0x83), 0x08}, {CCI_REG8(0x84), 0x0a}, {CCI_REG8(0x86), 0xf0},
+ {CCI_REG8(0x87), 0x50}, {CCI_REG8(0x88), 0x15}, {CCI_REG8(0x89), 0xb0},
+ {CCI_REG8(0x8a), 0x30}, {CCI_REG8(0x8b), 0x10},
+ /* ASDE */
+ {GC2145_REG_PAGE_SELECT, 0x01},
+ {CCI_REG8(0x21), 0x04},
+ {GC2145_REG_PAGE_SELECT, 0x02},
+ {CCI_REG8(0xa3), 0x50}, {CCI_REG8(0xa4), 0x20}, {CCI_REG8(0xa5), 0x40},
+ {CCI_REG8(0xa6), 0x80}, {CCI_REG8(0xab), 0x40}, {CCI_REG8(0xae), 0x0c},
+ {CCI_REG8(0xb3), 0x46}, {CCI_REG8(0xb4), 0x64}, {CCI_REG8(0xb6), 0x38},
+ {CCI_REG8(0xb7), 0x01}, {CCI_REG8(0xb9), 0x2b}, {CCI_REG8(0x3c), 0x04},
+ {CCI_REG8(0x3d), 0x15}, {CCI_REG8(0x4b), 0x06}, {CCI_REG8(0x4c), 0x20},
+ /* Gamma */
+ {GC2145_REG_PAGE_SELECT, 0x02},
+ {CCI_REG8(0x10), 0x09}, {CCI_REG8(0x11), 0x0d}, {CCI_REG8(0x12), 0x13},
+ {CCI_REG8(0x13), 0x19}, {CCI_REG8(0x14), 0x27}, {CCI_REG8(0x15), 0x37},
+ {CCI_REG8(0x16), 0x45}, {CCI_REG8(0x17), 0x53}, {CCI_REG8(0x18), 0x69},
+ {CCI_REG8(0x19), 0x7d}, {CCI_REG8(0x1a), 0x8f}, {CCI_REG8(0x1b), 0x9d},
+ {CCI_REG8(0x1c), 0xa9}, {CCI_REG8(0x1d), 0xbd}, {CCI_REG8(0x1e), 0xcd},
+ {CCI_REG8(0x1f), 0xd9}, {CCI_REG8(0x20), 0xe3}, {CCI_REG8(0x21), 0xea},
+ {CCI_REG8(0x22), 0xef}, {CCI_REG8(0x23), 0xf5}, {CCI_REG8(0x24), 0xf9},
+ {CCI_REG8(0x25), 0xff},
+ {GC2145_REG_PAGE_SELECT, 0x00},
+ {CCI_REG8(0xc6), 0x20}, {CCI_REG8(0xc7), 0x2b},
+ /* Gamma 2 */
+ {GC2145_REG_PAGE_SELECT, 0x02},
+ {CCI_REG8(0x26), 0x0f}, {CCI_REG8(0x27), 0x14}, {CCI_REG8(0x28), 0x19},
+ {CCI_REG8(0x29), 0x1e}, {CCI_REG8(0x2a), 0x27}, {CCI_REG8(0x2b), 0x33},
+ {CCI_REG8(0x2c), 0x3b}, {CCI_REG8(0x2d), 0x45}, {CCI_REG8(0x2e), 0x59},
+ {CCI_REG8(0x2f), 0x69}, {CCI_REG8(0x30), 0x7c}, {CCI_REG8(0x31), 0x89},
+ {CCI_REG8(0x32), 0x98}, {CCI_REG8(0x33), 0xae}, {CCI_REG8(0x34), 0xc0},
+ {CCI_REG8(0x35), 0xcf}, {CCI_REG8(0x36), 0xda}, {CCI_REG8(0x37), 0xe2},
+ {CCI_REG8(0x38), 0xe9}, {CCI_REG8(0x39), 0xf3}, {CCI_REG8(0x3a), 0xf9},
+ {CCI_REG8(0x3b), 0xff},
+ /* YCP */
+ {GC2145_REG_PAGE_SELECT, 0x02},
+ {CCI_REG8(0xd1), 0x32}, {CCI_REG8(0xd2), 0x32}, {CCI_REG8(0xd3), 0x40},
+ {CCI_REG8(0xd6), 0xf0}, {CCI_REG8(0xd7), 0x10}, {CCI_REG8(0xd8), 0xda},
+ {CCI_REG8(0xdd), 0x14}, {CCI_REG8(0xde), 0x86}, {CCI_REG8(0xed), 0x80},
+ {CCI_REG8(0xee), 0x00}, {CCI_REG8(0xef), 0x3f}, {CCI_REG8(0xd8), 0xd8},
+ /* ABS */
+ {GC2145_REG_PAGE_SELECT, 0x01},
+ {CCI_REG8(0x9f), 0x40},
+ /* LSC */
+ {GC2145_REG_PAGE_SELECT, 0x01},
+ {CCI_REG8(0xc2), 0x14}, {CCI_REG8(0xc3), 0x0d}, {CCI_REG8(0xc4), 0x0c},
+ {CCI_REG8(0xc8), 0x15}, {CCI_REG8(0xc9), 0x0d}, {CCI_REG8(0xca), 0x0a},
+ {CCI_REG8(0xbc), 0x24}, {CCI_REG8(0xbd), 0x10}, {CCI_REG8(0xbe), 0x0b},
+ {CCI_REG8(0xb6), 0x25}, {CCI_REG8(0xb7), 0x16}, {CCI_REG8(0xb8), 0x15},
+ {CCI_REG8(0xc5), 0x00}, {CCI_REG8(0xc6), 0x00}, {CCI_REG8(0xc7), 0x00},
+ {CCI_REG8(0xcb), 0x00}, {CCI_REG8(0xcc), 0x00}, {CCI_REG8(0xcd), 0x00},
+ {CCI_REG8(0xbf), 0x07}, {CCI_REG8(0xc0), 0x00}, {CCI_REG8(0xc1), 0x00},
+ {CCI_REG8(0xb9), 0x00}, {CCI_REG8(0xba), 0x00}, {CCI_REG8(0xbb), 0x00},
+ {CCI_REG8(0xaa), 0x01}, {CCI_REG8(0xab), 0x01}, {CCI_REG8(0xac), 0x00},
+ {CCI_REG8(0xad), 0x05}, {CCI_REG8(0xae), 0x06}, {CCI_REG8(0xaf), 0x0e},
+ {CCI_REG8(0xb0), 0x0b}, {CCI_REG8(0xb1), 0x07}, {CCI_REG8(0xb2), 0x06},
+ {CCI_REG8(0xb3), 0x17}, {CCI_REG8(0xb4), 0x0e}, {CCI_REG8(0xb5), 0x0e},
+ {CCI_REG8(0xd0), 0x09}, {CCI_REG8(0xd1), 0x00}, {CCI_REG8(0xd2), 0x00},
+ {CCI_REG8(0xd6), 0x08}, {CCI_REG8(0xd7), 0x00}, {CCI_REG8(0xd8), 0x00},
+ {CCI_REG8(0xd9), 0x00}, {CCI_REG8(0xda), 0x00}, {CCI_REG8(0xdb), 0x00},
+ {CCI_REG8(0xd3), 0x0a}, {CCI_REG8(0xd4), 0x00}, {CCI_REG8(0xd5), 0x00},
+ {CCI_REG8(0xa4), 0x00}, {CCI_REG8(0xa5), 0x00}, {CCI_REG8(0xa6), 0x77},
+ {CCI_REG8(0xa7), 0x77}, {CCI_REG8(0xa8), 0x77}, {CCI_REG8(0xa9), 0x77},
+ {CCI_REG8(0xa1), 0x80}, {CCI_REG8(0xa2), 0x80},
+ {GC2145_REG_PAGE_SELECT, 0x01},
+ {CCI_REG8(0xdf), 0x0d}, {CCI_REG8(0xdc), 0x25}, {CCI_REG8(0xdd), 0x30},
+ {CCI_REG8(0xe0), 0x77}, {CCI_REG8(0xe1), 0x80}, {CCI_REG8(0xe2), 0x77},
+ {CCI_REG8(0xe3), 0x90}, {CCI_REG8(0xe6), 0x90}, {CCI_REG8(0xe7), 0xa0},
+ {CCI_REG8(0xe8), 0x90}, {CCI_REG8(0xe9), 0xa0},
+ /* AWB */
+ /* measure window */
+ {GC2145_REG_PAGE_SELECT, 0x00},
+ {CCI_REG8(0xec), 0x06}, {CCI_REG8(0xed), 0x04}, {CCI_REG8(0xee), 0x60},
+ {CCI_REG8(0xef), 0x90}, {CCI_REG8(0xb6), 0x01},
+ {GC2145_REG_PAGE_SELECT, 0x01},
+ {CCI_REG8(0x4f), 0x00}, {CCI_REG8(0x4f), 0x00}, {CCI_REG8(0x4b), 0x01},
+ {CCI_REG8(0x4f), 0x00},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x71}, {CCI_REG8(0x4e), 0x01},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x91}, {CCI_REG8(0x4e), 0x01},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x70}, {CCI_REG8(0x4e), 0x01},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x90}, {CCI_REG8(0x4e), 0x02},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xb0}, {CCI_REG8(0x4e), 0x02},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8f}, {CCI_REG8(0x4e), 0x02},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6f}, {CCI_REG8(0x4e), 0x02},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xaf}, {CCI_REG8(0x4e), 0x02},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xd0}, {CCI_REG8(0x4e), 0x02},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xf0}, {CCI_REG8(0x4e), 0x02},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xcf}, {CCI_REG8(0x4e), 0x02},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xef}, {CCI_REG8(0x4e), 0x02},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6e}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8e}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xae}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xce}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x4d}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6d}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8d}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xad}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xcd}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x4c}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6c}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8c}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xac}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xcc}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xcb}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x4b}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x6b}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8b}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xab}, {CCI_REG8(0x4e), 0x03},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8a}, {CCI_REG8(0x4e), 0x04},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xaa}, {CCI_REG8(0x4e), 0x04},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xca}, {CCI_REG8(0x4e), 0x04},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xca}, {CCI_REG8(0x4e), 0x04},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xc9}, {CCI_REG8(0x4e), 0x04},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x8a}, {CCI_REG8(0x4e), 0x04},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0x89}, {CCI_REG8(0x4e), 0x04},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xa9}, {CCI_REG8(0x4e), 0x04},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x0b}, {CCI_REG8(0x4e), 0x05},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x0a}, {CCI_REG8(0x4e), 0x05},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xeb}, {CCI_REG8(0x4e), 0x05},
+ {CCI_REG8(0x4c), 0x01}, {CCI_REG8(0x4d), 0xea}, {CCI_REG8(0x4e), 0x05},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x09}, {CCI_REG8(0x4e), 0x05},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x29}, {CCI_REG8(0x4e), 0x05},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x2a}, {CCI_REG8(0x4e), 0x05},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x4a}, {CCI_REG8(0x4e), 0x05},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x8a}, {CCI_REG8(0x4e), 0x06},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x49}, {CCI_REG8(0x4e), 0x06},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x69}, {CCI_REG8(0x4e), 0x06},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x89}, {CCI_REG8(0x4e), 0x06},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xa9}, {CCI_REG8(0x4e), 0x06},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x48}, {CCI_REG8(0x4e), 0x06},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x68}, {CCI_REG8(0x4e), 0x06},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0x69}, {CCI_REG8(0x4e), 0x06},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xca}, {CCI_REG8(0x4e), 0x07},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xc9}, {CCI_REG8(0x4e), 0x07},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xe9}, {CCI_REG8(0x4e), 0x07},
+ {CCI_REG8(0x4c), 0x03}, {CCI_REG8(0x4d), 0x09}, {CCI_REG8(0x4e), 0x07},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xc8}, {CCI_REG8(0x4e), 0x07},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xe8}, {CCI_REG8(0x4e), 0x07},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xa7}, {CCI_REG8(0x4e), 0x07},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xc7}, {CCI_REG8(0x4e), 0x07},
+ {CCI_REG8(0x4c), 0x02}, {CCI_REG8(0x4d), 0xe7}, {CCI_REG8(0x4e), 0x07},
+ {CCI_REG8(0x4c), 0x03}, {CCI_REG8(0x4d), 0x07}, {CCI_REG8(0x4e), 0x07},
+ {CCI_REG8(0x4f), 0x01},
+ {CCI_REG8(0x50), 0x80}, {CCI_REG8(0x51), 0xa8}, {CCI_REG8(0x52), 0x47},
+ {CCI_REG8(0x53), 0x38}, {CCI_REG8(0x54), 0xc7}, {CCI_REG8(0x56), 0x0e},
+ {CCI_REG8(0x58), 0x08}, {CCI_REG8(0x5b), 0x00}, {CCI_REG8(0x5c), 0x74},
+ {CCI_REG8(0x5d), 0x8b}, {CCI_REG8(0x61), 0xdb}, {CCI_REG8(0x62), 0xb8},
+ {CCI_REG8(0x63), 0x86}, {CCI_REG8(0x64), 0xc0}, {CCI_REG8(0x65), 0x04},
+ {CCI_REG8(0x67), 0xa8}, {CCI_REG8(0x68), 0xb0}, {CCI_REG8(0x69), 0x00},
+ {CCI_REG8(0x6a), 0xa8}, {CCI_REG8(0x6b), 0xb0}, {CCI_REG8(0x6c), 0xaf},
+ {CCI_REG8(0x6d), 0x8b}, {CCI_REG8(0x6e), 0x50}, {CCI_REG8(0x6f), 0x18},
+ {CCI_REG8(0x73), 0xf0}, {CCI_REG8(0x70), 0x0d}, {CCI_REG8(0x71), 0x60},
+ {CCI_REG8(0x72), 0x80}, {CCI_REG8(0x74), 0x01}, {CCI_REG8(0x75), 0x01},
+ {CCI_REG8(0x7f), 0x0c}, {CCI_REG8(0x76), 0x70}, {CCI_REG8(0x77), 0x58},
+ {CCI_REG8(0x78), 0xa0}, {CCI_REG8(0x79), 0x5e}, {CCI_REG8(0x7a), 0x54},
+ {CCI_REG8(0x7b), 0x58},
+ /* CC */
+ {GC2145_REG_PAGE_SELECT, 0x02},
+ {CCI_REG8(0xc0), 0x01}, {CCI_REG8(0xc1), 0x44}, {CCI_REG8(0xc2), 0xfd},
+ {CCI_REG8(0xc3), 0x04}, {CCI_REG8(0xc4), 0xf0}, {CCI_REG8(0xc5), 0x48},
+ {CCI_REG8(0xc6), 0xfd}, {CCI_REG8(0xc7), 0x46}, {CCI_REG8(0xc8), 0xfd},
+ {CCI_REG8(0xc9), 0x02}, {CCI_REG8(0xca), 0xe0}, {CCI_REG8(0xcb), 0x45},
+ {CCI_REG8(0xcc), 0xec}, {CCI_REG8(0xcd), 0x48}, {CCI_REG8(0xce), 0xf0},
+ {CCI_REG8(0xcf), 0xf0}, {CCI_REG8(0xe3), 0x0c}, {CCI_REG8(0xe4), 0x4b},
+ {CCI_REG8(0xe5), 0xe0},
+ /* ABS */
+ {GC2145_REG_PAGE_SELECT, 0x01},
+ {CCI_REG8(0x9f), 0x40},
+ /* Dark sun */
+ {GC2145_REG_PAGE_SELECT, 0x02},
+ {CCI_REG8(0x40), 0xbf}, {CCI_REG8(0x46), 0xcf},
+};
+
+#define GC2145_640_480_PIXELRATE 30000000
+#define GC2145_640_480_LINKFREQ 120000000
+#define GC2145_640_480_HBLANK 0x0130
+#define GC2145_640_480_VBLANK 0x000c
+static const struct cci_reg_sequence gc2145_mode_640_480_regs[] = {
+ {GC2145_REG_PAGE_SELECT, 0xf0}, {GC2145_REG_PAGE_SELECT, 0xf0},
+ {GC2145_REG_PAGE_SELECT, 0xf0}, {CCI_REG8(0xfc), 0x06},
+ {CCI_REG8(0xf6), 0x00}, {CCI_REG8(0xf7), 0x1d}, {CCI_REG8(0xf8), 0x86},
+ {CCI_REG8(0xfa), 0x00}, {CCI_REG8(0xf9), 0x8e},
+ /* Disable PAD IO */
+ {GC2145_REG_PAD_IO, 0x00},
+ {GC2145_REG_PAGE_SELECT, 0x00},
+ /* Row/Col start - 0/0 */
+ {GC2145_REG_ROW_START, 0x0000},
+ {GC2145_REG_COL_START, 0x0000},
+ /* Window size 1216/1618 */
+ {GC2145_REG_WIN_HEIGHT, 0x04c0},
+ {GC2145_REG_WIN_WIDTH, 0x0652},
+ /* Scalar more */
+ {CCI_REG8(0xfd), 0x01}, {CCI_REG8(0xfa), 0x00},
+ /* Crop 640-480@0-0 */
+ {GC2145_REG_CROP_ENABLE, 0x01},
+ {GC2145_REG_CROP_Y, 0x0000},
+ {GC2145_REG_CROP_X, 0x0000},
+ {GC2145_REG_CROP_HEIGHT, 0x01e0},
+ {GC2145_REG_CROP_WIDTH, 0x0280},
+ /* Subsampling configuration */
+ {CCI_REG8(0x99), 0x55}, {CCI_REG8(0x9a), 0x06}, {CCI_REG8(0x9b), 0x01},
+ {CCI_REG8(0x9c), 0x23}, {CCI_REG8(0x9d), 0x00}, {CCI_REG8(0x9e), 0x00},
+ {CCI_REG8(0x9f), 0x01}, {CCI_REG8(0xa0), 0x23}, {CCI_REG8(0xa1), 0x00},
+ {CCI_REG8(0xa2), 0x00},
+ {GC2145_REG_PAGE_SELECT, 0x01},
+ /* AEC anti-flicker */
+ {CCI_REG16(0x25), 0x0175},
+ /* AEC exposure level 1-5 */
+ {CCI_REG16(0x27), 0x045f}, {CCI_REG16(0x29), 0x045f},
+ {CCI_REG16(0x2b), 0x045f}, {CCI_REG16(0x2d), 0x045f},
+};
+
+#define GC2145_1280_720_PIXELRATE 48000000
+#define GC2145_1280_720_LINKFREQ 192000000
+#define GC2145_1280_720_HBLANK 0x0156
+#define GC2145_1280_720_VBLANK 0x0011
+static const struct cci_reg_sequence gc2145_mode_1280_720_regs[] = {
+ {GC2145_REG_PAGE_SELECT, 0xf0}, {GC2145_REG_PAGE_SELECT, 0xf0},
+ {GC2145_REG_PAGE_SELECT, 0xf0}, {CCI_REG8(0xfc), 0x06},
+ {CCI_REG8(0xf6), 0x00}, {CCI_REG8(0xf7), 0x1d}, {CCI_REG8(0xf8), 0x83},
+ {CCI_REG8(0xfa), 0x00}, {CCI_REG8(0xf9), 0x8e},
+ /* Disable PAD IO */
+ {GC2145_REG_PAD_IO, 0x00},
+ {GC2145_REG_PAGE_SELECT, 0x00},
+ /* Row/Col start - 240/160 */
+ {GC2145_REG_ROW_START, 0x00f0},
+ {GC2145_REG_COL_START, 0x00a0},
+ /* Window size 736/1296 */
+ {GC2145_REG_WIN_HEIGHT, 0x02e0},
+ {GC2145_REG_WIN_WIDTH, 0x0510},
+ /* Crop 1280-720@0-0 */
+ {GC2145_REG_CROP_ENABLE, 0x01},
+ {GC2145_REG_CROP_Y, 0x0000},
+ {GC2145_REG_CROP_X, 0x0000},
+ {GC2145_REG_CROP_HEIGHT, 0x02d0},
+ {GC2145_REG_CROP_WIDTH, 0x0500},
+ {GC2145_REG_PAGE_SELECT, 0x01},
+ /* AEC anti-flicker */
+ {CCI_REG16(0x25), 0x00e6},
+ /* AEC exposure level 1-5 */
+ {CCI_REG16(0x27), 0x02b2}, {CCI_REG16(0x29), 0x02b2},
+ {CCI_REG16(0x2b), 0x02b2}, {CCI_REG16(0x2d), 0x02b2},
+};
+
+#define GC2145_1600_1200_PIXELRATE 60000000
+#define GC2145_1600_1200_LINKFREQ 240000000
+#define GC2145_1600_1200_HBLANK 0x0156
+#define GC2145_1600_1200_VBLANK 0x0010
+static const struct cci_reg_sequence gc2145_mode_1600_1200_regs[] = {
+ {GC2145_REG_PAGE_SELECT, 0xf0}, {GC2145_REG_PAGE_SELECT, 0xf0},
+ {GC2145_REG_PAGE_SELECT, 0xf0}, {CCI_REG8(0xfc), 0x06},
+ {CCI_REG8(0xf6), 0x00}, {CCI_REG8(0xf7), 0x1d}, {CCI_REG8(0xf8), 0x84},
+ {CCI_REG8(0xfa), 0x00}, {CCI_REG8(0xf9), 0x8e},
+ /* Disable PAD IO */
+ {GC2145_REG_PAD_IO, 0x00},
+ {GC2145_REG_PAGE_SELECT, 0x00},
+ /* Row/Col start - 0/0 */
+ {GC2145_REG_ROW_START, 0x0000},
+ {GC2145_REG_COL_START, 0x0000},
+ /* Window size: 1216/1618 */
+ {GC2145_REG_WIN_HEIGHT, 0x04c0},
+ {GC2145_REG_WIN_WIDTH, 0x0652},
+ /* Crop 1600-1200@0-0 */
+ {GC2145_REG_CROP_ENABLE, 0x01},
+ {GC2145_REG_CROP_Y, 0x0000},
+ {GC2145_REG_CROP_X, 0x0000},
+ {GC2145_REG_CROP_HEIGHT, 0x04b0},
+ {GC2145_REG_CROP_WIDTH, 0x0640},
+ {GC2145_REG_PAGE_SELECT, 0x01},
+ /* AEC anti-flicker */
+ {CCI_REG16(0x25), 0x00fa},
+ /* AEC exposure level 1-5 */
+ {CCI_REG16(0x27), 0x04e2}, {CCI_REG16(0x29), 0x04e2},
+ {CCI_REG16(0x2b), 0x04e2}, {CCI_REG16(0x2d), 0x04e2},
+};
+
+static const s64 gc2145_link_freq_menu[] = {
+ GC2145_640_480_LINKFREQ,
+ GC2145_1280_720_LINKFREQ,
+ GC2145_1600_1200_LINKFREQ,
+};
+
+/* Regulators supplies */
+static const char * const gc2145_supply_name[] = {
+ "iovdd", /* Digital I/O (1.7-3V) suppply */
+ "avdd", /* Analog (2.7-3V) supply */
+ "dvdd", /* Digital Core (1.7-1.9V) supply */
+};
+
+#define GC2145_NUM_SUPPLIES ARRAY_SIZE(gc2145_supply_name)
+
+/* Mode configs */
+#define GC2145_MODE_640X480 0
+#define GC2145_MODE_1280X720 1
+#define GC2145_MODE_1600X1200 2
+static const struct gc2145_mode supported_modes[] = {
+ {
+ /* 640x480 30fps mode */
+ .width = 640,
+ .height = 480,
+ .reg_seq = gc2145_mode_640_480_regs,
+ .reg_seq_size = ARRAY_SIZE(gc2145_mode_640_480_regs),
+ .pixel_rate = GC2145_640_480_PIXELRATE,
+ .crop = {
+ .top = 0,
+ .left = 0,
+ .width = 640,
+ .height = 480,
+ },
+ .hblank = GC2145_640_480_HBLANK,
+ .vblank = GC2145_640_480_VBLANK,
+ .link_freq_index = GC2145_MODE_640X480,
+ },
+ {
+ /* 1280x720 30fps mode */
+ .width = 1280,
+ .height = 720,
+ .reg_seq = gc2145_mode_1280_720_regs,
+ .reg_seq_size = ARRAY_SIZE(gc2145_mode_1280_720_regs),
+ .pixel_rate = GC2145_1280_720_PIXELRATE,
+ .crop = {
+ .top = 160,
+ .left = 240,
+ .width = 1280,
+ .height = 720,
+ },
+ .hblank = GC2145_1280_720_HBLANK,
+ .vblank = GC2145_1280_720_VBLANK,
+ .link_freq_index = GC2145_MODE_1280X720,
+ },
+ {
+ /* 1600x1200 20fps mode */
+ .width = 1600,
+ .height = 1200,
+ .reg_seq = gc2145_mode_1600_1200_regs,
+ .reg_seq_size = ARRAY_SIZE(gc2145_mode_1600_1200_regs),
+ .pixel_rate = GC2145_1600_1200_PIXELRATE,
+ .crop = {
+ .top = 0,
+ .left = 0,
+ .width = 1600,
+ .height = 1200,
+ },
+ .hblank = GC2145_1600_1200_HBLANK,
+ .vblank = GC2145_1600_1200_VBLANK,
+ .link_freq_index = GC2145_MODE_1600X1200,
+ },
+};
+
+/**
+ * struct gc2145_format - GC2145 pixel format description
+ * @code: media bus (MBUS) associated code
+ * @datatype: MIPI CSI2 data type
+ * @output_fmt: GC2145 output format
+ * @switch_bit: GC2145 first/second switch
+ */
+struct gc2145_format {
+ unsigned int code;
+ unsigned char datatype;
+ unsigned char output_fmt;
+ bool switch_bit;
+};
+
+/* All supported formats */
+static const struct gc2145_format supported_formats[] = {
+ {
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .datatype = MIPI_CSI2_DT_YUV422_8B,
+ .output_fmt = 0x00,
+ },
+ {
+ .code = MEDIA_BUS_FMT_VYUY8_1X16,
+ .datatype = MIPI_CSI2_DT_YUV422_8B,
+ .output_fmt = 0x01,
+ },
+ {
+ .code = MEDIA_BUS_FMT_YUYV8_1X16,
+ .datatype = MIPI_CSI2_DT_YUV422_8B,
+ .output_fmt = 0x02,
+ },
+ {
+ .code = MEDIA_BUS_FMT_YVYU8_1X16,
+ .datatype = MIPI_CSI2_DT_YUV422_8B,
+ .output_fmt = 0x03,
+ },
+ {
+ .code = MEDIA_BUS_FMT_RGB565_1X16,
+ .datatype = MIPI_CSI2_DT_RGB565,
+ .output_fmt = 0x06,
+ .switch_bit = true,
+ },
+};
+
+struct gc2145_ctrls {
+ struct v4l2_ctrl_handler handler;
+ struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *test_pattern;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
+};
+
+struct gc2145 {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+
+ struct regmap *regmap;
+ struct clk *xclk;
+
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *powerdown_gpio;
+ struct regulator_bulk_data supplies[GC2145_NUM_SUPPLIES];
+
+ /* V4L2 controls */
+ struct gc2145_ctrls ctrls;
+
+ /* Current mode */
+ const struct gc2145_mode *mode;
+};
+
+static inline struct gc2145 *to_gc2145(struct v4l2_subdev *_sd)
+{
+ return container_of(_sd, struct gc2145, sd);
+}
+
+static inline struct v4l2_subdev *gc2145_ctrl_to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct gc2145,
+ ctrls.handler)->sd;
+}
+
+static const struct gc2145_format *
+gc2145_get_format_code(struct gc2145 *gc2145, u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(supported_formats); i++) {
+ if (supported_formats[i].code == code)
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(supported_formats))
+ i = 0;
+
+ return &supported_formats[i];
+}
+
+static void gc2145_update_pad_format(struct gc2145 *gc2145,
+ const struct gc2145_mode *mode,
+ struct v4l2_mbus_framefmt *fmt, u32 code)
+{
+ fmt->code = code;
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
+ fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static int gc2145_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct gc2145 *gc2145 = to_gc2145(sd);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ /* Initialize pad format */
+ format = v4l2_subdev_state_get_format(state, 0);
+ gc2145_update_pad_format(gc2145, &supported_modes[0], format,
+ MEDIA_BUS_FMT_RGB565_1X16);
+
+ /* Initialize crop rectangle. */
+ crop = v4l2_subdev_state_get_crop(state, 0);
+ *crop = supported_modes[0].crop;
+
+ return 0;
+}
+
+static int gc2145_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, 0);
+ return 0;
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = GC2145_NATIVE_WIDTH;
+ sel->r.height = GC2145_NATIVE_HEIGHT;
+
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = 1600;
+ sel->r.height = 1200;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int gc2145_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(supported_formats))
+ return -EINVAL;
+
+ code->code = supported_formats[code->index].code;
+ return 0;
+}
+
+static int gc2145_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct gc2145 *gc2145 = to_gc2145(sd);
+ const struct gc2145_format *gc2145_format;
+ u32 code;
+
+ if (fse->index >= ARRAY_SIZE(supported_modes))
+ return -EINVAL;
+
+ gc2145_format = gc2145_get_format_code(gc2145, fse->code);
+ code = gc2145_format->code;
+ if (fse->code != code)
+ return -EINVAL;
+
+ fse->min_width = supported_modes[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->min_height = supported_modes[fse->index].height;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static int gc2145_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct gc2145 *gc2145 = to_gc2145(sd);
+ const struct gc2145_mode *mode;
+ const struct gc2145_format *gc2145_fmt;
+ struct v4l2_mbus_framefmt *framefmt;
+ struct gc2145_ctrls *ctrls = &gc2145->ctrls;
+ struct v4l2_rect *crop;
+
+ gc2145_fmt = gc2145_get_format_code(gc2145, fmt->format.code);
+ mode = v4l2_find_nearest_size(supported_modes,
+ ARRAY_SIZE(supported_modes),
+ width, height,
+ fmt->format.width, fmt->format.height);
+
+ gc2145_update_pad_format(gc2145, mode, &fmt->format, gc2145_fmt->code);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ gc2145->mode = mode;
+ /* Update pixel_rate based on the mode */
+ __v4l2_ctrl_s_ctrl_int64(ctrls->pixel_rate, mode->pixel_rate);
+ /* Update link_freq based on the mode */
+ __v4l2_ctrl_s_ctrl(ctrls->link_freq, mode->link_freq_index);
+ /* Update hblank/vblank based on the mode */
+ __v4l2_ctrl_s_ctrl(ctrls->hblank, mode->hblank);
+ __v4l2_ctrl_s_ctrl(ctrls->vblank, mode->vblank);
+ }
+ *framefmt = fmt->format;
+ crop = v4l2_subdev_state_get_crop(sd_state, fmt->pad);
+ *crop = mode->crop;
+
+ return 0;
+}
+
+static const struct cci_reg_sequence gc2145_common_mipi_regs[] = {
+ {GC2145_REG_PAGE_SELECT, 0x03},
+ {GC2145_REG_DPHY_ANALOG_MODE1, GC2145_DPHY_MODE_PHY_CLK_EN |
+ GC2145_DPHY_MODE_PHY_LANE0_EN |
+ GC2145_DPHY_MODE_PHY_LANE1_EN |
+ GC2145_DPHY_MODE_PHY_CLK_LANE_P2S_SEL},
+ {GC2145_REG_DPHY_ANALOG_MODE2, GC2145_DPHY_CLK_DIFF(2) |
+ GC2145_DPHY_LANE0_DIFF(2)},
+ {GC2145_REG_DPHY_ANALOG_MODE3, GC2145_DPHY_LANE1_DIFF(0) |
+ GC2145_DPHY_CLK_DELAY},
+ {GC2145_REG_FIFO_MODE, GC2145_FIFO_MODE_READ_GATE |
+ GC2145_FIFO_MODE_MIPI_CLK_MODULE},
+ {GC2145_REG_DPHY_MODE, GC2145_DPHY_MODE_TRIGGER_PROG},
+ /* Clock & Data lanes timing */
+ {GC2145_REG_T_LPX, 0x10},
+ {GC2145_REG_T_CLK_HS_PREPARE, 0x04}, {GC2145_REG_T_CLK_ZERO, 0x10},
+ {GC2145_REG_T_CLK_PRE, 0x10}, {GC2145_REG_T_CLK_POST, 0x10},
+ {GC2145_REG_T_CLK_TRAIL, 0x05},
+ {GC2145_REG_T_HS_PREPARE, 0x03}, {GC2145_REG_T_HS_ZERO, 0x0a},
+ {GC2145_REG_T_HS_TRAIL, 0x06},
+};
+
+static int gc2145_config_mipi_mode(struct gc2145 *gc2145,
+ const struct gc2145_format *gc2145_format)
+{
+ u16 lwc, fifo_full_lvl;
+ int ret = 0;
+
+ /* Common MIPI settings */
+ cci_multi_reg_write(gc2145->regmap, gc2145_common_mipi_regs,
+ ARRAY_SIZE(gc2145_common_mipi_regs), &ret);
+
+ /*
+ * Adjust the MIPI buffer settings.
+ * For YUV/RGB, LWC = image width * 2
+ * For RAW8, LWC = image width
+ * For RAW10, LWC = image width * 1.25
+ */
+ lwc = gc2145->mode->width * 2;
+ cci_write(gc2145->regmap, GC2145_REG_LWC_HIGH, lwc >> 8, &ret);
+ cci_write(gc2145->regmap, GC2145_REG_LWC_LOW, lwc & 0xff, &ret);
+
+ /*
+ * Adjust the MIPI FIFO Full Level
+ * 640x480 RGB: 0x0190
+ * 1280x720 / 1600x1200 (aka no scaler) non RAW: 0x0001
+ * 1600x1200 RAW: 0x0190
+ */
+ if (gc2145->mode->width == 1280 || gc2145->mode->width == 1600)
+ fifo_full_lvl = 0x0001;
+ else
+ fifo_full_lvl = 0x0190;
+
+ cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_HIGH,
+ fifo_full_lvl >> 8, &ret);
+ cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_LOW,
+ fifo_full_lvl & 0xff, &ret);
+
+ /*
+ * Set the FIFO gate mode / MIPI wdiv set:
+ * 0xf1 in case of RAW mode and 0xf0 otherwise
+ */
+ cci_write(gc2145->regmap, GC2145_REG_FIFO_GATE_MODE, 0xf0, &ret);
+
+ /* Set the MIPI data type */
+ cci_write(gc2145->regmap, GC2145_REG_MIPI_DT,
+ gc2145_format->datatype, &ret);
+
+ /* Configure mode and enable CSI */
+ cci_write(gc2145->regmap, GC2145_REG_BUF_CSI2_MODE,
+ GC2145_CSI2_MODE_RAW8 | GC2145_CSI2_MODE_DOUBLE |
+ GC2145_CSI2_MODE_EN | GC2145_CSI2_MODE_MIPI_EN, &ret);
+
+ return ret;
+}
+
+static int gc2145_start_streaming(struct gc2145 *gc2145,
+ struct v4l2_subdev_state *state)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd);
+ const struct gc2145_format *gc2145_format;
+ struct v4l2_mbus_framefmt *fmt;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
+ return ret;
+
+ /* Apply default values of current mode */
+ cci_multi_reg_write(gc2145->regmap, gc2145->mode->reg_seq,
+ gc2145->mode->reg_seq_size, &ret);
+ cci_multi_reg_write(gc2145->regmap, gc2145_common_regs,
+ ARRAY_SIZE(gc2145_common_regs), &ret);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to write regs\n", __func__);
+ goto err_rpm_put;
+ }
+
+ fmt = v4l2_subdev_state_get_format(state, 0);
+ gc2145_format = gc2145_get_format_code(gc2145, fmt->code);
+
+ /* Set the output format */
+ cci_write(gc2145->regmap, GC2145_REG_PAGE_SELECT, 0x00, &ret);
+
+ cci_write(gc2145->regmap, GC2145_REG_OUTPUT_FMT,
+ gc2145_format->output_fmt, &ret);
+ cci_update_bits(gc2145->regmap, GC2145_REG_BYPASS_MODE,
+ GC2145_BYPASS_MODE_SWITCH,
+ gc2145_format->switch_bit ? GC2145_BYPASS_MODE_SWITCH
+ : 0, &ret);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to write regs\n", __func__);
+ goto err_rpm_put;
+ }
+
+ /* Apply customized values from user */
+ ret = __v4l2_ctrl_handler_setup(&gc2145->ctrls.handler);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to apply ctrls\n", __func__);
+ goto err_rpm_put;
+ }
+
+ /* Perform MIPI specific configuration */
+ ret = gc2145_config_mipi_mode(gc2145, gc2145_format);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to write mipi conf\n",
+ __func__);
+ goto err_rpm_put;
+ }
+
+ cci_write(gc2145->regmap, GC2145_REG_PAGE_SELECT, 0x00, &ret);
+
+ return 0;
+
+err_rpm_put:
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+ return ret;
+}
+
+static void gc2145_stop_streaming(struct gc2145 *gc2145)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd);
+ int ret = 0;
+
+ /* Disable lanes & mipi streaming */
+ cci_write(gc2145->regmap, GC2145_REG_PAGE_SELECT, 0x03, &ret);
+ cci_update_bits(gc2145->regmap, GC2145_REG_BUF_CSI2_MODE,
+ GC2145_CSI2_MODE_EN | GC2145_CSI2_MODE_MIPI_EN, 0,
+ &ret);
+ cci_write(gc2145->regmap, GC2145_REG_PAGE_SELECT, 0x00, &ret);
+ if (ret)
+ dev_err(&client->dev, "%s failed to write regs\n", __func__);
+
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+}
+
+static int gc2145_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct gc2145 *gc2145 = to_gc2145(sd);
+ struct v4l2_subdev_state *state;
+ int ret = 0;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ if (enable)
+ ret = gc2145_start_streaming(gc2145, state);
+ else
+ gc2145_stop_streaming(gc2145);
+
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+/* Power/clock management functions */
+static int gc2145_power_on(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct gc2145 *gc2145 = to_gc2145(sd);
+ int ret;
+
+ ret = regulator_bulk_enable(GC2145_NUM_SUPPLIES, gc2145->supplies);
+ if (ret) {
+ dev_err(dev, "failed to enable regulators\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(gc2145->xclk);
+ if (ret) {
+ dev_err(dev, "failed to enable clock\n");
+ goto reg_off;
+ }
+
+ gpiod_set_value_cansleep(gc2145->powerdown_gpio, 0);
+ gpiod_set_value_cansleep(gc2145->reset_gpio, 0);
+
+ /*
+ * Datasheet doesn't mention timing between PWDN/RESETB control and
+ * i2c access however, experimentation shows that a rather big delay is
+ * needed.
+ */
+ msleep(41);
+
+ return 0;
+
+reg_off:
+ regulator_bulk_disable(GC2145_NUM_SUPPLIES, gc2145->supplies);
+
+ return ret;
+}
+
+static int gc2145_power_off(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct gc2145 *gc2145 = to_gc2145(sd);
+
+ gpiod_set_value_cansleep(gc2145->powerdown_gpio, 1);
+ gpiod_set_value_cansleep(gc2145->reset_gpio, 1);
+ clk_disable_unprepare(gc2145->xclk);
+ regulator_bulk_disable(GC2145_NUM_SUPPLIES, gc2145->supplies);
+
+ return 0;
+}
+
+static int gc2145_get_regulators(struct gc2145 *gc2145)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd);
+ unsigned int i;
+
+ for (i = 0; i < GC2145_NUM_SUPPLIES; i++)
+ gc2145->supplies[i].supply = gc2145_supply_name[i];
+
+ return devm_regulator_bulk_get(&client->dev, GC2145_NUM_SUPPLIES,
+ gc2145->supplies);
+}
+
+/* Verify chip ID */
+static int gc2145_identify_module(struct gc2145 *gc2145)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd);
+ int ret;
+ u64 chip_id;
+
+ ret = cci_read(gc2145->regmap, GC2145_REG_CHIP_ID, &chip_id, NULL);
+ if (ret) {
+ dev_err(&client->dev, "failed to read chip id (%d)\n", ret);
+ return ret;
+ }
+
+ if (chip_id != GC2145_CHIP_ID) {
+ dev_err(&client->dev, "chip id mismatch: %x!=%llx\n",
+ GC2145_CHIP_ID, chip_id);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static const char * const test_pattern_menu[] = {
+ "Disabled",
+ "Colored patterns",
+ "Uniform white",
+ "Uniform yellow",
+ "Uniform cyan",
+ "Uniform green",
+ "Uniform magenta",
+ "Uniform red",
+ "Uniform black",
+};
+
+#define GC2145_TEST_PATTERN_ENABLE BIT(0)
+#define GC2145_TEST_PATTERN_UXGA BIT(3)
+
+#define GC2145_TEST_UNIFORM BIT(3)
+#define GC2145_TEST_WHITE (4 << 4)
+#define GC2145_TEST_YELLOW (8 << 4)
+#define GC2145_TEST_CYAN (9 << 4)
+#define GC2145_TEST_GREEN (6 << 4)
+#define GC2145_TEST_MAGENTA (10 << 4)
+#define GC2145_TEST_RED (5 << 4)
+#define GC2145_TEST_BLACK (0)
+
+static const u8 test_pattern_val[] = {
+ 0,
+ GC2145_TEST_PATTERN_ENABLE,
+ GC2145_TEST_UNIFORM | GC2145_TEST_WHITE,
+ GC2145_TEST_UNIFORM | GC2145_TEST_YELLOW,
+ GC2145_TEST_UNIFORM | GC2145_TEST_CYAN,
+ GC2145_TEST_UNIFORM | GC2145_TEST_GREEN,
+ GC2145_TEST_UNIFORM | GC2145_TEST_MAGENTA,
+ GC2145_TEST_UNIFORM | GC2145_TEST_RED,
+ GC2145_TEST_UNIFORM | GC2145_TEST_BLACK,
+};
+
+static const struct v4l2_subdev_core_ops gc2145_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops gc2145_video_ops = {
+ .s_stream = gc2145_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops gc2145_pad_ops = {
+ .enum_mbus_code = gc2145_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = gc2145_set_pad_format,
+ .get_selection = gc2145_get_selection,
+ .enum_frame_size = gc2145_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops gc2145_subdev_ops = {
+ .core = &gc2145_core_ops,
+ .video = &gc2145_video_ops,
+ .pad = &gc2145_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops gc2145_subdev_internal_ops = {
+ .init_state = gc2145_init_state,
+};
+
+static int gc2145_set_ctrl_test_pattern(struct gc2145 *gc2145, int value)
+{
+ int ret = 0;
+
+ if (!value) {
+ /* Disable test pattern */
+ cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE2, 0, &ret);
+ return cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE3, 0,
+ &ret);
+ }
+
+ /* Enable test pattern, colored or uniform */
+ cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE2,
+ GC2145_TEST_PATTERN_ENABLE | GC2145_TEST_PATTERN_UXGA, &ret);
+
+ if (!(test_pattern_val[value] & GC2145_TEST_UNIFORM))
+ return cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE3, 0,
+ &ret);
+
+ /* Uniform */
+ return cci_write(gc2145->regmap, GC2145_REG_DEBUG_MODE3,
+ test_pattern_val[value], &ret);
+}
+
+static int gc2145_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = gc2145_ctrl_to_sd(ctrl);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct gc2145 *gc2145 = to_gc2145(sd);
+ int ret;
+
+ if (pm_runtime_get_if_in_use(&client->dev) == 0)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_HBLANK:
+ ret = cci_write(gc2145->regmap, GC2145_REG_HBLANK, ctrl->val,
+ NULL);
+ break;
+ case V4L2_CID_VBLANK:
+ ret = cci_write(gc2145->regmap, GC2145_REG_VBLANK, ctrl->val,
+ NULL);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = gc2145_set_ctrl_test_pattern(gc2145, ctrl->val);
+ break;
+ case V4L2_CID_HFLIP:
+ ret = cci_update_bits(gc2145->regmap, GC2145_REG_ANALOG_MODE1,
+ BIT(0), (ctrl->val ? BIT(0) : 0), NULL);
+ break;
+ case V4L2_CID_VFLIP:
+ ret = cci_update_bits(gc2145->regmap, GC2145_REG_ANALOG_MODE1,
+ BIT(1), (ctrl->val ? BIT(1) : 0), NULL);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops gc2145_ctrl_ops = {
+ .s_ctrl = gc2145_s_ctrl,
+};
+
+/* Initialize control handlers */
+static int gc2145_init_controls(struct gc2145 *gc2145)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd);
+ const struct v4l2_ctrl_ops *ops = &gc2145_ctrl_ops;
+ struct gc2145_ctrls *ctrls = &gc2145->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+ struct v4l2_fwnode_device_properties props;
+ int ret;
+
+ ret = v4l2_ctrl_handler_init(hdl, 12);
+ if (ret)
+ return ret;
+
+ ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
+ GC2145_640_480_PIXELRATE,
+ GC2145_1600_1200_PIXELRATE, 1,
+ supported_modes[0].pixel_rate);
+
+ ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(gc2145_link_freq_menu) - 1,
+ 0, gc2145_link_freq_menu);
+ if (ctrls->link_freq)
+ ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK,
+ 0, 0xfff, 1, GC2145_640_480_HBLANK);
+
+ ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
+ 0, 0x1fff, 1, GC2145_640_480_VBLANK);
+
+ ctrls->test_pattern =
+ v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(test_pattern_menu) - 1,
+ 0, 0, test_pattern_menu);
+ ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ ret = hdl->error;
+ dev_err(&client->dev, "control init failed (%d)\n", ret);
+ goto error;
+ }
+
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret)
+ goto error;
+
+ ret = v4l2_ctrl_new_fwnode_properties(hdl, &gc2145_ctrl_ops,
+ &props);
+ if (ret)
+ goto error;
+
+ gc2145->sd.ctrl_handler = hdl;
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(hdl);
+
+ return ret;
+}
+
+static int gc2145_check_hwcfg(struct device *dev)
+{
+ struct fwnode_handle *endpoint;
+ struct v4l2_fwnode_endpoint ep_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ int ret;
+
+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
+ if (!endpoint) {
+ dev_err(dev, "endpoint node not found\n");
+ return -EINVAL;
+ }
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg);
+ fwnode_handle_put(endpoint);
+ if (ret)
+ return ret;
+
+ /* Check the number of MIPI CSI2 data lanes */
+ if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
+ dev_err(dev, "only 2 data lanes are currently supported\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Check the link frequency set in device tree */
+ if (!ep_cfg.nr_of_link_frequencies) {
+ dev_err(dev, "link-frequency property not found in DT\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ep_cfg.nr_of_link_frequencies != 3 ||
+ ep_cfg.link_frequencies[0] != GC2145_640_480_LINKFREQ ||
+ ep_cfg.link_frequencies[1] != GC2145_1280_720_LINKFREQ ||
+ ep_cfg.link_frequencies[2] != GC2145_1600_1200_LINKFREQ) {
+ dev_err(dev, "Invalid link-frequencies provided\n");
+ ret = -EINVAL;
+ }
+
+out:
+ v4l2_fwnode_endpoint_free(&ep_cfg);
+
+ return ret;
+}
+
+static int gc2145_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ unsigned int xclk_freq;
+ struct gc2145 *gc2145;
+ int ret;
+
+ gc2145 = devm_kzalloc(&client->dev, sizeof(*gc2145), GFP_KERNEL);
+ if (!gc2145)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&gc2145->sd, client, &gc2145_subdev_ops);
+ gc2145->sd.internal_ops = &gc2145_subdev_internal_ops;
+
+ /* Check the hardware configuration in device tree */
+ if (gc2145_check_hwcfg(dev))
+ return -EINVAL;
+
+ /* Get system clock (xclk) */
+ gc2145->xclk = devm_clk_get(dev, NULL);
+ if (IS_ERR(gc2145->xclk))
+ return dev_err_probe(dev, PTR_ERR(gc2145->xclk),
+ "failed to get xclk\n");
+
+ xclk_freq = clk_get_rate(gc2145->xclk);
+ if (xclk_freq != GC2145_XCLK_FREQ) {
+ dev_err(dev, "xclk frequency not supported: %d Hz\n",
+ xclk_freq);
+ return -EINVAL;
+ }
+
+ ret = gc2145_get_regulators(gc2145);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to get regulators\n");
+
+ /* Request optional reset pin */
+ gc2145->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(gc2145->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(gc2145->reset_gpio),
+ "failed to get reset_gpio\n");
+
+ /* Request optional powerdown pin */
+ gc2145->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(gc2145->powerdown_gpio))
+ return dev_err_probe(dev, PTR_ERR(gc2145->powerdown_gpio),
+ "failed to get powerdown_gpio\n");
+
+ /* Initialise the regmap for further cci access */
+ gc2145->regmap = devm_cci_regmap_init_i2c(client, 8);
+ if (IS_ERR(gc2145->regmap))
+ return dev_err_probe(dev, PTR_ERR(gc2145->regmap),
+ "failed to get cci regmap\n");
+
+ /*
+ * The sensor must be powered for gc2145_identify_module()
+ * to be able to read the CHIP_ID register
+ */
+ ret = gc2145_power_on(dev);
+ if (ret)
+ return ret;
+
+ ret = gc2145_identify_module(gc2145);
+ if (ret)
+ goto error_power_off;
+
+ /* Set default mode */
+ gc2145->mode = &supported_modes[0];
+
+ ret = gc2145_init_controls(gc2145);
+ if (ret)
+ goto error_power_off;
+
+ /* Initialize subdev */
+ gc2145->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
+ gc2145->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ /* Initialize source pad */
+ gc2145->pad.flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&gc2145->sd.entity, 1, &gc2145->pad);
+ if (ret) {
+ dev_err(dev, "failed to init entity pads: %d\n", ret);
+ goto error_handler_free;
+ }
+
+ gc2145->sd.state_lock = gc2145->ctrls.handler.lock;
+ ret = v4l2_subdev_init_finalize(&gc2145->sd);
+ if (ret < 0) {
+ dev_err(dev, "subdev init error: %d\n", ret);
+ goto error_media_entity;
+ }
+
+ /* Enable runtime PM and turn off the device */
+ pm_runtime_set_active(dev);
+ pm_runtime_get_noresume(&client->dev);
+ pm_runtime_enable(dev);
+
+ pm_runtime_set_autosuspend_delay(&client->dev, 1000);
+ pm_runtime_use_autosuspend(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+
+ ret = v4l2_async_register_subdev_sensor(&gc2145->sd);
+ if (ret < 0) {
+ dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
+ goto error_subdev_cleanup;
+ }
+
+ return 0;
+
+error_subdev_cleanup:
+ v4l2_subdev_cleanup(&gc2145->sd);
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+error_media_entity:
+ media_entity_cleanup(&gc2145->sd.entity);
+
+error_handler_free:
+ v4l2_ctrl_handler_free(&gc2145->ctrls.handler);
+
+error_power_off:
+ gc2145_power_off(dev);
+
+ return ret;
+}
+
+static void gc2145_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct gc2145 *gc2145 = to_gc2145(sd);
+
+ v4l2_subdev_cleanup(sd);
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(&gc2145->ctrls.handler);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ gc2145_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+}
+
+static const struct of_device_id gc2145_dt_ids[] = {
+ { .compatible = "galaxycore,gc2145" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, gc2145_dt_ids);
+
+static const struct dev_pm_ops gc2145_pm_ops = {
+ RUNTIME_PM_OPS(gc2145_power_off, gc2145_power_on, NULL)
+};
+
+static struct i2c_driver gc2145_i2c_driver = {
+ .driver = {
+ .name = "gc2145",
+ .of_match_table = gc2145_dt_ids,
+ .pm = pm_ptr(&gc2145_pm_ops),
+ },
+ .probe = gc2145_probe,
+ .remove = gc2145_remove,
+};
+
+module_i2c_driver(gc2145_i2c_driver);
+
+MODULE_AUTHOR("Alain Volmat <[email protected]>");
+MODULE_DESCRIPTION("GalaxyCore GC2145 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c
index f6ea9b7b9700..38c77d515786 100644
--- a/drivers/media/i2c/hi556.c
+++ b/drivers/media/i2c/hi556.c
@@ -935,7 +935,7 @@ __hi556_get_pad_crop(struct hi556 *hi556,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&hi556->sd, sd_state, pad);
+ return v4l2_subdev_state_get_crop(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &hi556->cur_mode->crop;
}
@@ -1075,7 +1075,7 @@ static int hi556_set_format(struct v4l2_subdev *sd,
mutex_lock(&hi556->mutex);
hi556_assign_pad_format(mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
} else {
hi556->cur_mode = mode;
__v4l2_ctrl_s_ctrl(hi556->link_freq, mode->link_freq_index);
@@ -1109,9 +1109,8 @@ static int hi556_get_format(struct v4l2_subdev *sd,
mutex_lock(&hi556->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&hi556->sd,
- sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
else
hi556_assign_pad_format(hi556->cur_mode, &fmt->format);
@@ -1157,10 +1156,10 @@ static int hi556_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&hi556->mutex);
hi556_assign_pad_format(&supported_modes[0],
- v4l2_subdev_get_try_format(sd, fh->state, 0));
+ v4l2_subdev_state_get_format(fh->state, 0));
/* Initialize try_crop rectangle. */
- try_crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
+ try_crop = v4l2_subdev_state_get_crop(fh->state, 0);
try_crop->top = HI556_PIXEL_ARRAY_TOP;
try_crop->left = HI556_PIXEL_ARRAY_LEFT;
try_crop->width = HI556_PIXEL_ARRAY_WIDTH;
diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c
index 825fc8dc48f5..9c565ec033d4 100644
--- a/drivers/media/i2c/hi846.c
+++ b/drivers/media/i2c/hi846.c
@@ -1705,7 +1705,7 @@ static int hi846_set_format(struct v4l2_subdev *sd,
}
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, format->pad) = *mf;
+ *v4l2_subdev_state_get_format(sd_state, format->pad) = *mf;
return 0;
}
@@ -1783,9 +1783,8 @@ static int hi846_get_format(struct v4l2_subdev *sd,
struct i2c_client *client = v4l2_get_subdevdata(sd);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- format->format = *v4l2_subdev_get_try_format(&hi846->sd,
- sd_state,
- format->pad);
+ format->format = *v4l2_subdev_state_get_format(sd_state,
+ format->pad);
return 0;
}
@@ -1852,7 +1851,7 @@ static int hi846_get_selection(struct v4l2_subdev *sd,
mutex_lock(&hi846->mutex);
switch (sel->which) {
case V4L2_SUBDEV_FORMAT_TRY:
- v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
+ v4l2_subdev_state_get_crop(sd_state, sel->pad);
break;
case V4L2_SUBDEV_FORMAT_ACTIVE:
sel->r = hi846->cur_mode->crop;
@@ -1872,13 +1871,13 @@ static int hi846_get_selection(struct v4l2_subdev *sd,
}
}
-static int hi846_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int hi846_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct hi846 *hi846 = to_hi846(sd);
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ mf = v4l2_subdev_state_get_format(sd_state, 0);
mutex_lock(&hi846->mutex);
mf->code = HI846_MEDIA_BUS_FORMAT;
@@ -1896,7 +1895,6 @@ static const struct v4l2_subdev_video_ops hi846_video_ops = {
};
static const struct v4l2_subdev_pad_ops hi846_pad_ops = {
- .init_cfg = hi846_init_cfg,
.enum_frame_size = hi846_enum_frame_size,
.enum_mbus_code = hi846_enum_mbus_code,
.set_fmt = hi846_set_format,
@@ -1909,6 +1907,10 @@ static const struct v4l2_subdev_ops hi846_subdev_ops = {
.pad = &hi846_pad_ops,
};
+static const struct v4l2_subdev_internal_ops hi846_internal_ops = {
+ .init_state = hi846_init_state,
+};
+
static const struct media_entity_operations hi846_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -2072,6 +2074,7 @@ static int hi846_probe(struct i2c_client *client)
return ret;
v4l2_i2c_subdev_init(&hi846->sd, client, &hi846_subdev_ops);
+ hi846->sd.internal_ops = &hi846_internal_ops;
mutex_init(&hi846->mutex);
diff --git a/drivers/media/i2c/hi847.c b/drivers/media/i2c/hi847.c
index 4075c389804c..72c60747a839 100644
--- a/drivers/media/i2c/hi847.c
+++ b/drivers/media/i2c/hi847.c
@@ -2655,7 +2655,7 @@ static int hi847_set_format(struct v4l2_subdev *sd,
mutex_lock(&hi847->mutex);
hi847_assign_pad_format(mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) =
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) =
fmt->format;
} else {
hi847->cur_mode = mode;
@@ -2690,9 +2690,8 @@ static int hi847_get_format(struct v4l2_subdev *sd,
mutex_lock(&hi847->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&hi847->sd,
- sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
else
hi847_assign_pad_format(hi847->cur_mode, &fmt->format);
@@ -2737,7 +2736,7 @@ static int hi847_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&hi847->mutex);
hi847_assign_pad_format(&supported_modes[0],
- v4l2_subdev_get_try_format(sd, fh->state, 0));
+ v4l2_subdev_state_get_format(fh->state, 0));
mutex_unlock(&hi847->mutex);
return 0;
diff --git a/drivers/media/i2c/imx208.c b/drivers/media/i2c/imx208.c
index a9b0aea1ae3b..639e05340dbb 100644
--- a/drivers/media/i2c/imx208.c
+++ b/drivers/media/i2c/imx208.c
@@ -395,7 +395,7 @@ static int imx208_write_regs(struct imx208 *imx208,
static int imx208_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
+ v4l2_subdev_state_get_format(fh->state, 0);
/* Initialize try_fmt */
try_fmt->width = supported_modes[0].width;
@@ -548,9 +548,8 @@ static int __imx208_get_pad_format(struct imx208 *imx208,
struct v4l2_subdev_format *fmt)
{
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&imx208->sd,
- sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
else
imx208_mode_to_pad_format(imx208, imx208->cur_mode, fmt);
@@ -591,7 +590,7 @@ static int imx208_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
imx208_mode_to_pad_format(imx208, mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
} else {
imx208->cur_mode = mode;
__v4l2_ctrl_s_ctrl(imx208->link_freq, mode->link_freq_index);
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 4f77ea02cc27..b148b1bd2bc3 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -19,12 +19,31 @@
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
+#define IMX214_REG_MODE_SELECT 0x0100
+#define IMX214_MODE_STANDBY 0x00
+#define IMX214_MODE_STREAMING 0x01
+
#define IMX214_DEFAULT_CLK_FREQ 24000000
#define IMX214_DEFAULT_LINK_FREQ 480000000
#define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10)
#define IMX214_FPS 30
#define IMX214_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10
+/* Exposure control */
+#define IMX214_REG_EXPOSURE 0x0202
+#define IMX214_EXPOSURE_MIN 0
+#define IMX214_EXPOSURE_MAX 3184
+#define IMX214_EXPOSURE_STEP 1
+#define IMX214_EXPOSURE_DEFAULT 3184
+
+/* IMX214 native and active pixel array size */
+#define IMX214_NATIVE_WIDTH 4224U
+#define IMX214_NATIVE_HEIGHT 3136U
+#define IMX214_PIXEL_ARRAY_LEFT 8U
+#define IMX214_PIXEL_ARRAY_TOP 8U
+#define IMX214_PIXEL_ARRAY_WIDTH 4208U
+#define IMX214_PIXEL_ARRAY_HEIGHT 3120U
+
static const char * const imx214_supply_name[] = {
"vdda",
"vddd",
@@ -538,7 +557,7 @@ __imx214_get_pad_format(struct imx214 *imx214,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&imx214->sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &imx214->fmt;
default:
@@ -568,7 +587,7 @@ __imx214_get_pad_crop(struct imx214 *imx214,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&imx214->sd, sd_state, pad);
+ return v4l2_subdev_state_get_crop(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &imx214->crop;
default:
@@ -623,18 +642,35 @@ static int imx214_get_selection(struct v4l2_subdev *sd,
{
struct imx214 *imx214 = to_imx214(sd);
- if (sel->target != V4L2_SEL_TGT_CROP)
- return -EINVAL;
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ mutex_lock(&imx214->mutex);
+ sel->r = *__imx214_get_pad_crop(imx214, sd_state, sel->pad,
+ sel->which);
+ mutex_unlock(&imx214->mutex);
+ return 0;
- mutex_lock(&imx214->mutex);
- sel->r = *__imx214_get_pad_crop(imx214, sd_state, sel->pad,
- sel->which);
- mutex_unlock(&imx214->mutex);
- return 0;
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = IMX214_NATIVE_WIDTH;
+ sel->r.height = IMX214_NATIVE_HEIGHT;
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = IMX214_PIXEL_ARRAY_TOP;
+ sel->r.left = IMX214_PIXEL_ARRAY_LEFT;
+ sel->r.width = IMX214_PIXEL_ARRAY_WIDTH;
+ sel->r.height = IMX214_PIXEL_ARRAY_HEIGHT;
+ return 0;
+ }
+
+ return -EINVAL;
}
-static int imx214_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state)
+static int imx214_entity_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = { };
@@ -665,7 +701,7 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE:
vals[1] = ctrl->val;
vals[0] = ctrl->val >> 8;
- ret = regmap_bulk_write(imx214->regmap, 0x202, vals, 2);
+ ret = regmap_bulk_write(imx214->regmap, IMX214_REG_EXPOSURE, vals, 2);
if (ret < 0)
dev_err(imx214->dev, "Error %d\n", ret);
ret = 0;
@@ -684,6 +720,76 @@ static const struct v4l2_ctrl_ops imx214_ctrl_ops = {
.s_ctrl = imx214_set_ctrl,
};
+static int imx214_ctrls_init(struct imx214 *imx214)
+{
+ static const s64 link_freq[] = {
+ IMX214_DEFAULT_LINK_FREQ
+ };
+ static const struct v4l2_area unit_size = {
+ .width = 1120,
+ .height = 1120,
+ };
+ struct v4l2_fwnode_device_properties props;
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ int ret;
+
+ ret = v4l2_fwnode_device_parse(imx214->dev, &props);
+ if (ret < 0)
+ return ret;
+
+ ctrl_hdlr = &imx214->ctrls;
+ ret = v4l2_ctrl_handler_init(&imx214->ctrls, 6);
+ if (ret)
+ return ret;
+
+ imx214->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, NULL,
+ V4L2_CID_PIXEL_RATE, 0,
+ IMX214_DEFAULT_PIXEL_RATE, 1,
+ IMX214_DEFAULT_PIXEL_RATE);
+
+ imx214->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, NULL,
+ V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(link_freq) - 1,
+ 0, link_freq);
+ if (imx214->link_freq)
+ imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /*
+ * WARNING!
+ * Values obtained reverse engineering blobs and/or devices.
+ * Ranges and functionality might be wrong.
+ *
+ * Sony, please release some register set documentation for the
+ * device.
+ *
+ * Yours sincerely, Ricardo.
+ */
+ imx214->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ IMX214_EXPOSURE_MIN,
+ IMX214_EXPOSURE_MAX,
+ IMX214_EXPOSURE_STEP,
+ IMX214_EXPOSURE_DEFAULT);
+
+ imx214->unit_size = v4l2_ctrl_new_std_compound(ctrl_hdlr,
+ NULL,
+ V4L2_CID_UNIT_CELL_SIZE,
+ v4l2_ctrl_ptr_create((void *)&unit_size));
+
+ v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx214_ctrl_ops, &props);
+
+ ret = ctrl_hdlr->error;
+ if (ret) {
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+ dev_err(imx214->dev, "failed to add controls: %d\n", ret);
+ return ret;
+ }
+
+ imx214->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+};
+
#define MAX_CMD 4
static int imx214_write_table(struct imx214 *imx214,
const struct reg_8 table[])
@@ -743,7 +849,7 @@ static int imx214_start_streaming(struct imx214 *imx214)
dev_err(imx214->dev, "could not sync v4l2 controls\n");
goto error;
}
- ret = regmap_write(imx214->regmap, 0x100, 1);
+ ret = regmap_write(imx214->regmap, IMX214_REG_MODE_SELECT, IMX214_MODE_STREAMING);
if (ret < 0) {
dev_err(imx214->dev, "could not sent start table %d\n", ret);
goto error;
@@ -761,7 +867,7 @@ static int imx214_stop_streaming(struct imx214 *imx214)
{
int ret;
- ret = regmap_write(imx214->regmap, 0x100, 0);
+ ret = regmap_write(imx214->regmap, IMX214_REG_MODE_SELECT, IMX214_MODE_STANDBY);
if (ret < 0)
dev_err(imx214->dev, "could not sent stop table %d\n", ret);
@@ -795,9 +901,17 @@ err_rpm_put:
return ret;
}
-static int imx214_g_frame_interval(struct v4l2_subdev *subdev,
- struct v4l2_subdev_frame_interval *fival)
+static int imx214_get_frame_interval(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fival)
{
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
fival->interval.numerator = 1;
fival->interval.denominator = IMX214_FPS;
@@ -828,8 +942,6 @@ static int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
static const struct v4l2_subdev_video_ops imx214_video_ops = {
.s_stream = imx214_s_stream,
- .g_frame_interval = imx214_g_frame_interval,
- .s_frame_interval = imx214_g_frame_interval,
};
static const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = {
@@ -839,7 +951,8 @@ static const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = {
.get_fmt = imx214_get_format,
.set_fmt = imx214_set_format,
.get_selection = imx214_get_selection,
- .init_cfg = imx214_entity_init_cfg,
+ .get_frame_interval = imx214_get_frame_interval,
+ .set_frame_interval = imx214_get_frame_interval,
};
static const struct v4l2_subdev_ops imx214_subdev_ops = {
@@ -848,6 +961,10 @@ static const struct v4l2_subdev_ops imx214_subdev_ops = {
.pad = &imx214_subdev_pad_ops,
};
+static const struct v4l2_subdev_internal_ops imx214_internal_ops = {
+ .init_state = imx214_entity_init_state,
+};
+
static const struct regmap_config sensor_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
@@ -907,13 +1024,6 @@ static int imx214_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct imx214 *imx214;
- static const s64 link_freq[] = {
- IMX214_DEFAULT_LINK_FREQ,
- };
- static const struct v4l2_area unit_size = {
- .width = 1120,
- .height = 1120,
- };
int ret;
ret = imx214_parse_fwnode(dev);
@@ -957,6 +1067,7 @@ static int imx214_probe(struct i2c_client *client)
}
v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops);
+ imx214->sd.internal_ops = &imx214_internal_ops;
/*
* Enable power initially, to avoid warnings
@@ -968,45 +1079,10 @@ static int imx214_probe(struct i2c_client *client)
pm_runtime_enable(imx214->dev);
pm_runtime_idle(imx214->dev);
- v4l2_ctrl_handler_init(&imx214->ctrls, 3);
-
- imx214->pixel_rate = v4l2_ctrl_new_std(&imx214->ctrls, NULL,
- V4L2_CID_PIXEL_RATE, 0,
- IMX214_DEFAULT_PIXEL_RATE, 1,
- IMX214_DEFAULT_PIXEL_RATE);
- imx214->link_freq = v4l2_ctrl_new_int_menu(&imx214->ctrls, NULL,
- V4L2_CID_LINK_FREQ,
- ARRAY_SIZE(link_freq) - 1,
- 0, link_freq);
- if (imx214->link_freq)
- imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-
- /*
- * WARNING!
- * Values obtained reverse engineering blobs and/or devices.
- * Ranges and functionality might be wrong.
- *
- * Sony, please release some register set documentation for the
- * device.
- *
- * Yours sincerely, Ricardo.
- */
- imx214->exposure = v4l2_ctrl_new_std(&imx214->ctrls, &imx214_ctrl_ops,
- V4L2_CID_EXPOSURE,
- 0, 3184, 1, 0x0c70);
-
- imx214->unit_size = v4l2_ctrl_new_std_compound(&imx214->ctrls,
- NULL,
- V4L2_CID_UNIT_CELL_SIZE,
- v4l2_ctrl_ptr_create((void *)&unit_size));
- ret = imx214->ctrls.error;
- if (ret) {
- dev_err(&client->dev, "%s control init failed (%d)\n",
- __func__, ret);
- goto free_ctrl;
- }
+ ret = imx214_ctrls_init(imx214);
+ if (ret < 0)
+ goto error_power_off;
- imx214->sd.ctrl_handler = &imx214->ctrls;
mutex_init(&imx214->mutex);
imx214->ctrls.lock = &imx214->mutex;
@@ -1021,7 +1097,7 @@ static int imx214_probe(struct i2c_client *client)
goto free_ctrl;
}
- imx214_entity_init_cfg(&imx214->sd, NULL);
+ imx214_entity_init_state(&imx214->sd, NULL);
ret = v4l2_async_register_subdev_sensor(&imx214->sd);
if (ret < 0) {
@@ -1036,6 +1112,7 @@ free_entity:
free_ctrl:
mutex_destroy(&imx214->mutex);
v4l2_ctrl_handler_free(&imx214->ctrls);
+error_power_off:
pm_runtime_disable(imx214->dev);
return ret;
diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index 8436880dcf7a..e17ef2e9d9d0 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -374,7 +374,7 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
int ret = 0;
state = v4l2_subdev_get_locked_active_state(&imx219->sd);
- format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
if (ctrl->id == V4L2_CID_VBLANK) {
int exposure_max, exposure_def;
@@ -593,8 +593,8 @@ static int imx219_set_framefmt(struct imx219 *imx219,
u64 bin_h, bin_v;
int ret = 0;
- format = v4l2_subdev_get_pad_format(&imx219->sd, state, 0);
- crop = v4l2_subdev_get_pad_crop(&imx219->sd, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
+ crop = v4l2_subdev_state_get_crop(state, 0);
switch (format->code) {
case MEDIA_BUS_FMT_SRGGB8_1X8:
@@ -826,7 +826,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code);
- format = v4l2_subdev_get_pad_format(sd, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
*format = fmt->format;
/*
@@ -836,7 +836,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
bin_h = min(IMX219_PIXEL_ARRAY_WIDTH / format->width, 2U);
bin_v = min(IMX219_PIXEL_ARRAY_HEIGHT / format->height, 2U);
- crop = v4l2_subdev_get_pad_crop(sd, state, 0);
+ crop = v4l2_subdev_state_get_crop(state, 0);
crop->width = format->width * bin_h;
crop->height = format->height * bin_v;
crop->left = (IMX219_NATIVE_WIDTH - crop->width) / 2;
@@ -880,7 +880,7 @@ static int imx219_get_selection(struct v4l2_subdev *sd,
{
switch (sel->target) {
case V4L2_SEL_TGT_CROP: {
- sel->r = *v4l2_subdev_get_pad_crop(sd, state, 0);
+ sel->r = *v4l2_subdev_state_get_crop(state, 0);
return 0;
}
@@ -905,8 +905,8 @@ static int imx219_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
}
-static int imx219_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int imx219_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct v4l2_subdev_format fmt = {
.which = V4L2_SUBDEV_FORMAT_TRY,
@@ -933,7 +933,6 @@ static const struct v4l2_subdev_video_ops imx219_video_ops = {
};
static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
- .init_cfg = imx219_init_cfg,
.enum_mbus_code = imx219_enum_mbus_code,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = imx219_set_pad_format,
@@ -947,6 +946,9 @@ static const struct v4l2_subdev_ops imx219_subdev_ops = {
.pad = &imx219_pad_ops,
};
+static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
+ .init_state = imx219_init_state,
+};
/* -----------------------------------------------------------------------------
* Power management
@@ -1098,6 +1100,7 @@ static int imx219_probe(struct i2c_client *client)
return -ENOMEM;
v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
+ imx219->sd.internal_ops = &imx219_internal_ops;
/* Check the hardware configuration in device tree */
if (imx219_check_hwcfg(dev, imx219))
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index b3827f4bc0eb..a577afb530b7 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -708,7 +708,7 @@ static int imx258_write_regs(struct imx258 *imx258,
static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
+ v4l2_subdev_state_get_format(fh->state, 0);
/* Initialize try_fmt */
try_fmt->width = supported_modes[0].width;
@@ -862,9 +862,8 @@ static int __imx258_get_pad_format(struct imx258 *imx258,
struct v4l2_subdev_format *fmt)
{
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&imx258->sd,
- sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
else
imx258_update_pad_format(imx258->cur_mode, fmt);
@@ -908,7 +907,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
imx258_update_pad_format(mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
imx258->cur_mode = mode;
diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c
index f33b692e6951..352da68b8b41 100644
--- a/drivers/media/i2c/imx274.c
+++ b/drivers/media/i2c/imx274.c
@@ -594,8 +594,8 @@ static int imx274_set_gain(struct stimx274 *priv, struct v4l2_ctrl *ctrl);
static int imx274_set_exposure(struct stimx274 *priv, int val);
static int imx274_set_vflip(struct stimx274 *priv, int val);
static int imx274_set_test_pattern(struct stimx274 *priv, int val);
-static int imx274_set_frame_interval(struct stimx274 *priv,
- struct v4l2_fract frame_interval);
+static int __imx274_set_frame_interval(struct stimx274 *priv,
+ struct v4l2_fract frame_interval);
static inline void msleep_range(unsigned int delay_base)
{
@@ -1018,8 +1018,8 @@ static int __imx274_change_compose(struct stimx274 *imx274,
int best_goodness = INT_MIN;
if (which == V4L2_SUBDEV_FORMAT_TRY) {
- cur_crop = &sd_state->pads->try_crop;
- tgt_fmt = &sd_state->pads->try_fmt;
+ cur_crop = v4l2_subdev_state_get_crop(sd_state, 0);
+ tgt_fmt = v4l2_subdev_state_get_format(sd_state, 0);
} else {
cur_crop = &imx274->crop;
tgt_fmt = &imx274->format;
@@ -1112,7 +1112,7 @@ static int imx274_set_fmt(struct v4l2_subdev *sd,
*/
fmt->field = V4L2_FIELD_NONE;
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- sd_state->pads->try_fmt = *fmt;
+ *v4l2_subdev_state_get_format(sd_state, 0) = *fmt;
else
imx274->format = *fmt;
@@ -1143,8 +1143,8 @@ static int imx274_get_selection(struct v4l2_subdev *sd,
}
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- src_crop = &sd_state->pads->try_crop;
- src_fmt = &sd_state->pads->try_fmt;
+ src_crop = v4l2_subdev_state_get_crop(sd_state, 0);
+ src_fmt = v4l2_subdev_state_get_format(sd_state, 0);
} else {
src_crop = &imx274->crop;
src_fmt = &imx274->format;
@@ -1215,7 +1215,7 @@ static int imx274_set_selection_crop(struct stimx274 *imx274,
sel->r = new_crop;
if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
- tgt_crop = &sd_state->pads->try_crop;
+ tgt_crop = v4l2_subdev_state_get_crop(sd_state, 0);
else
tgt_crop = &imx274->crop;
@@ -1327,20 +1327,19 @@ static int imx274_apply_trimming(struct stimx274 *imx274)
return err;
}
-/**
- * imx274_g_frame_interval - Get the frame interval
- * @sd: Pointer to V4L2 Sub device structure
- * @fi: Pointer to V4l2 Sub device frame interval structure
- *
- * This function is used to get the frame interval.
- *
- * Return: 0 on success
- */
-static int imx274_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int imx274_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct stimx274 *imx274 = to_imx274(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
fi->interval = imx274->frame_interval;
dev_dbg(&imx274->client->dev, "%s frame rate = %d / %d\n",
__func__, imx274->frame_interval.numerator,
@@ -1349,29 +1348,28 @@ static int imx274_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-/**
- * imx274_s_frame_interval - Set the frame interval
- * @sd: Pointer to V4L2 Sub device structure
- * @fi: Pointer to V4l2 Sub device frame interval structure
- *
- * This function is used to set the frame intervavl.
- *
- * Return: 0 on success
- */
-static int imx274_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int imx274_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct stimx274 *imx274 = to_imx274(sd);
struct v4l2_ctrl *ctrl = imx274->ctrls.exposure;
int min, max, def;
int ret;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
ret = pm_runtime_resume_and_get(&imx274->client->dev);
if (ret < 0)
return ret;
mutex_lock(&imx274->lock);
- ret = imx274_set_frame_interval(imx274, fi->interval);
+ ret = __imx274_set_frame_interval(imx274, fi->interval);
if (!ret) {
fi->interval = imx274->frame_interval;
@@ -1466,8 +1464,8 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on)
* are changed.
* gain is not affected.
*/
- ret = imx274_set_frame_interval(imx274,
- imx274->frame_interval);
+ ret = __imx274_set_frame_interval(imx274,
+ imx274->frame_interval);
if (ret)
goto fail;
@@ -1830,7 +1828,7 @@ fail:
}
/*
- * imx274_set_frame_interval - Function called when setting frame interval
+ * __imx274_set_frame_interval - Function called when setting frame interval
* @priv: Pointer to device structure
* @frame_interval: Variable for frame interval
*
@@ -1839,8 +1837,8 @@ fail:
*
* Return: 0 on success
*/
-static int imx274_set_frame_interval(struct stimx274 *priv,
- struct v4l2_fract frame_interval)
+static int __imx274_set_frame_interval(struct stimx274 *priv,
+ struct v4l2_fract frame_interval)
{
int err;
u32 frame_length, req_frame_rate;
@@ -1927,11 +1925,11 @@ static const struct v4l2_subdev_pad_ops imx274_pad_ops = {
.set_fmt = imx274_set_fmt,
.get_selection = imx274_get_selection,
.set_selection = imx274_set_selection,
+ .get_frame_interval = imx274_get_frame_interval,
+ .set_frame_interval = imx274_set_frame_interval,
};
static const struct v4l2_subdev_video_ops imx274_video_ops = {
- .g_frame_interval = imx274_g_frame_interval,
- .s_frame_interval = imx274_s_frame_interval,
.s_stream = imx274_s_stream,
};
diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c
index 29098612813c..9967f3477433 100644
--- a/drivers/media/i2c/imx290.c
+++ b/drivers/media/i2c/imx290.c
@@ -41,18 +41,18 @@
#define IMX290_WINMODE_720P (1 << 4)
#define IMX290_WINMODE_CROP (4 << 4)
#define IMX290_FR_FDG_SEL CCI_REG8(0x3009)
-#define IMX290_BLKLEVEL CCI_REG16(0x300a)
+#define IMX290_BLKLEVEL CCI_REG16_LE(0x300a)
#define IMX290_GAIN CCI_REG8(0x3014)
-#define IMX290_VMAX CCI_REG24(0x3018)
+#define IMX290_VMAX CCI_REG24_LE(0x3018)
#define IMX290_VMAX_MAX 0x3ffff
-#define IMX290_HMAX CCI_REG16(0x301c)
+#define IMX290_HMAX CCI_REG16_LE(0x301c)
#define IMX290_HMAX_MAX 0xffff
-#define IMX290_SHS1 CCI_REG24(0x3020)
+#define IMX290_SHS1 CCI_REG24_LE(0x3020)
#define IMX290_WINWV_OB CCI_REG8(0x303a)
-#define IMX290_WINPV CCI_REG16(0x303c)
-#define IMX290_WINWV CCI_REG16(0x303e)
-#define IMX290_WINPH CCI_REG16(0x3040)
-#define IMX290_WINWH CCI_REG16(0x3042)
+#define IMX290_WINPV CCI_REG16_LE(0x303c)
+#define IMX290_WINWV CCI_REG16_LE(0x303e)
+#define IMX290_WINPH CCI_REG16_LE(0x3040)
+#define IMX290_WINWH CCI_REG16_LE(0x3042)
#define IMX290_OUT_CTRL CCI_REG8(0x3046)
#define IMX290_ODBIT_10BIT (0 << 0)
#define IMX290_ODBIT_12BIT (1 << 0)
@@ -78,28 +78,28 @@
#define IMX290_ADBIT2 CCI_REG8(0x317c)
#define IMX290_ADBIT2_10BIT 0x12
#define IMX290_ADBIT2_12BIT 0x00
-#define IMX290_CHIP_ID CCI_REG16(0x319a)
+#define IMX290_CHIP_ID CCI_REG16_LE(0x319a)
#define IMX290_ADBIT3 CCI_REG8(0x31ec)
#define IMX290_ADBIT3_10BIT 0x37
#define IMX290_ADBIT3_12BIT 0x0e
#define IMX290_REPETITION CCI_REG8(0x3405)
#define IMX290_PHY_LANE_NUM CCI_REG8(0x3407)
#define IMX290_OPB_SIZE_V CCI_REG8(0x3414)
-#define IMX290_Y_OUT_SIZE CCI_REG16(0x3418)
-#define IMX290_CSI_DT_FMT CCI_REG16(0x3441)
+#define IMX290_Y_OUT_SIZE CCI_REG16_LE(0x3418)
+#define IMX290_CSI_DT_FMT CCI_REG16_LE(0x3441)
#define IMX290_CSI_DT_FMT_RAW10 0x0a0a
#define IMX290_CSI_DT_FMT_RAW12 0x0c0c
#define IMX290_CSI_LANE_MODE CCI_REG8(0x3443)
-#define IMX290_EXTCK_FREQ CCI_REG16(0x3444)
-#define IMX290_TCLKPOST CCI_REG16(0x3446)
-#define IMX290_THSZERO CCI_REG16(0x3448)
-#define IMX290_THSPREPARE CCI_REG16(0x344a)
-#define IMX290_TCLKTRAIL CCI_REG16(0x344c)
-#define IMX290_THSTRAIL CCI_REG16(0x344e)
-#define IMX290_TCLKZERO CCI_REG16(0x3450)
-#define IMX290_TCLKPREPARE CCI_REG16(0x3452)
-#define IMX290_TLPX CCI_REG16(0x3454)
-#define IMX290_X_OUT_SIZE CCI_REG16(0x3472)
+#define IMX290_EXTCK_FREQ CCI_REG16_LE(0x3444)
+#define IMX290_TCLKPOST CCI_REG16_LE(0x3446)
+#define IMX290_THSZERO CCI_REG16_LE(0x3448)
+#define IMX290_THSPREPARE CCI_REG16_LE(0x344a)
+#define IMX290_TCLKTRAIL CCI_REG16_LE(0x344c)
+#define IMX290_THSTRAIL CCI_REG16_LE(0x344e)
+#define IMX290_TCLKZERO CCI_REG16_LE(0x3450)
+#define IMX290_TCLKPREPARE CCI_REG16_LE(0x3452)
+#define IMX290_TLPX CCI_REG16_LE(0x3454)
+#define IMX290_X_OUT_SIZE CCI_REG16_LE(0x3472)
#define IMX290_INCKSEL7 CCI_REG8(0x3480)
#define IMX290_PGCTRL_REGEN BIT(0)
@@ -758,7 +758,7 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
return 0;
state = v4l2_subdev_get_locked_active_state(&imx290->sd);
- format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
switch (ctrl->id) {
case V4L2_CID_ANALOGUE_GAIN:
@@ -994,7 +994,7 @@ static int imx290_start_streaming(struct imx290 *imx290,
}
/* Apply the register values related to current frame format */
- format = v4l2_subdev_get_pad_format(&imx290->sd, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
ret = imx290_setup_format(imx290, format);
if (ret < 0) {
dev_err(imx290->dev, "Could not set frame format - %d\n", ret);
@@ -1132,7 +1132,7 @@ static int imx290_set_fmt(struct v4l2_subdev *sd,
fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE;
fmt->format.xfer_func = V4L2_XFER_FUNC_NONE;
- format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
+ format = v4l2_subdev_state_get_format(sd_state, 0);
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
imx290->current_mode = mode;
@@ -1155,7 +1155,7 @@ static int imx290_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP: {
- format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
+ format = v4l2_subdev_state_get_format(sd_state, 0);
/*
* The sensor moves the readout by 1 pixel based on flips to
@@ -1195,8 +1195,8 @@ static int imx290_get_selection(struct v4l2_subdev *sd,
}
}
-static int imx290_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state)
+static int imx290_entity_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = {
.which = V4L2_SUBDEV_FORMAT_TRY,
@@ -1221,7 +1221,6 @@ static const struct v4l2_subdev_video_ops imx290_video_ops = {
};
static const struct v4l2_subdev_pad_ops imx290_pad_ops = {
- .init_cfg = imx290_entity_init_cfg,
.enum_mbus_code = imx290_enum_mbus_code,
.enum_frame_size = imx290_enum_frame_size,
.get_fmt = v4l2_subdev_get_fmt,
@@ -1235,6 +1234,10 @@ static const struct v4l2_subdev_ops imx290_subdev_ops = {
.pad = &imx290_pad_ops,
};
+static const struct v4l2_subdev_internal_ops imx290_internal_ops = {
+ .init_state = imx290_entity_init_state,
+};
+
static const struct media_entity_operations imx290_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -1248,6 +1251,7 @@ static int imx290_subdev_init(struct imx290 *imx290)
imx290->current_mode = &imx290_modes_ptr(imx290)[0];
v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops);
+ imx290->sd.internal_ops = &imx290_internal_ops;
imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
imx290->sd.dev = imx290->dev;
diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c
index 94aac9d2732f..83149fa729c4 100644
--- a/drivers/media/i2c/imx296.c
+++ b/drivers/media/i2c/imx296.c
@@ -323,7 +323,7 @@ static int imx296_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
state = v4l2_subdev_get_locked_active_state(&sensor->subdev);
- format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
@@ -511,8 +511,8 @@ static int imx296_setup(struct imx296 *sensor, struct v4l2_subdev_state *state)
unsigned int i;
int ret = 0;
- format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0);
- crop = v4l2_subdev_get_pad_crop(&sensor->subdev, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
+ crop = v4l2_subdev_state_get_crop(state, 0);
for (i = 0; i < ARRAY_SIZE(imx296_init_table); ++i)
imx296_write(sensor, imx296_init_table[i].reg,
@@ -662,7 +662,7 @@ static int imx296_enum_frame_size(struct v4l2_subdev *sd,
{
const struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_pad_format(sd, state, fse->pad);
+ format = v4l2_subdev_state_get_format(state, fse->pad);
if (fse->index >= 2 || fse->code != format->code)
return -EINVAL;
@@ -683,8 +683,8 @@ static int imx296_set_format(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- crop = v4l2_subdev_get_pad_crop(sd, state, fmt->pad);
- format = v4l2_subdev_get_pad_format(sd, state, fmt->pad);
+ crop = v4l2_subdev_state_get_crop(state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
/*
* Binning is only allowed when cropping is disabled according to the
@@ -732,7 +732,7 @@ static int imx296_get_selection(struct v4l2_subdev *sd,
{
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- sel->r = *v4l2_subdev_get_pad_crop(sd, state, sel->pad);
+ sel->r = *v4l2_subdev_state_get_crop(state, sel->pad);
break;
case V4L2_SEL_TGT_CROP_DEFAULT:
@@ -780,14 +780,14 @@ static int imx296_set_selection(struct v4l2_subdev *sd,
rect.height = min_t(unsigned int, rect.height,
IMX296_PIXEL_ARRAY_HEIGHT - rect.top);
- crop = v4l2_subdev_get_pad_crop(sd, state, sel->pad);
+ crop = v4l2_subdev_state_get_crop(state, sel->pad);
if (rect.width != crop->width || rect.height != crop->height) {
/*
* Reset the output image size if the crop rectangle size has
* been modified.
*/
- format = v4l2_subdev_get_pad_format(sd, state, sel->pad);
+ format = v4l2_subdev_state_get_format(state, sel->pad);
format->width = rect.width;
format->height = rect.height;
}
@@ -798,8 +798,8 @@ static int imx296_set_selection(struct v4l2_subdev *sd,
return 0;
}
-static int imx296_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int imx296_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct v4l2_subdev_selection sel = {
.target = V4L2_SEL_TGT_CROP,
@@ -830,7 +830,6 @@ static const struct v4l2_subdev_pad_ops imx296_subdev_pad_ops = {
.set_fmt = imx296_set_format,
.get_selection = imx296_get_selection,
.set_selection = imx296_set_selection,
- .init_cfg = imx296_init_cfg,
};
static const struct v4l2_subdev_ops imx296_subdev_ops = {
@@ -838,12 +837,17 @@ static const struct v4l2_subdev_ops imx296_subdev_ops = {
.pad = &imx296_subdev_pad_ops,
};
+static const struct v4l2_subdev_internal_ops imx296_internal_ops = {
+ .init_state = imx296_init_state,
+};
+
static int imx296_subdev_init(struct imx296 *sensor)
{
struct i2c_client *client = to_i2c_client(sensor->dev);
int ret;
v4l2_i2c_subdev_init(&sensor->subdev, client, &imx296_subdev_ops);
+ sensor->subdev.internal_ops = &imx296_internal_ops;
ret = imx296_ctrls_init(sensor);
if (ret < 0)
diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c
index 5378f607f340..e47eff672e0c 100644
--- a/drivers/media/i2c/imx319.c
+++ b/drivers/media/i2c/imx319.c
@@ -1860,7 +1860,7 @@ static int imx319_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct imx319 *imx319 = to_imx319(sd);
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
+ v4l2_subdev_state_get_format(fh->state, 0);
mutex_lock(&imx319->mutex);
@@ -2001,10 +2001,9 @@ static int imx319_do_get_pad_format(struct imx319 *imx319,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *framefmt;
- struct v4l2_subdev *sd = &imx319->sd;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
imx319_update_pad_format(imx319, imx319->cur_mode, fmt);
@@ -2055,7 +2054,7 @@ imx319_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
imx319_update_pad_format(imx319, mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
imx319->cur_mode = mode;
@@ -2464,19 +2463,21 @@ static int imx319_probe(struct i2c_client *client)
goto error_handler_free;
}
- ret = v4l2_async_register_subdev_sensor(&imx319->sd);
- if (ret < 0)
- goto error_media_entity;
-
/* Set the device's state to active if it's in D0 state. */
if (full_power)
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
pm_runtime_idle(&client->dev);
+ ret = v4l2_async_register_subdev_sensor(&imx319->sd);
+ if (ret < 0)
+ goto error_media_entity_pm;
+
return 0;
-error_media_entity:
+error_media_entity_pm:
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
media_entity_cleanup(&imx319->sd.entity);
error_handler_free:
diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c
index 1196fe93506b..6725b3e2a73e 100644
--- a/drivers/media/i2c/imx334.c
+++ b/drivers/media/i2c/imx334.c
@@ -879,7 +879,7 @@ static int imx334_get_pad_format(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *framefmt;
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
fmt->format.code = imx334->cur_code;
@@ -920,7 +920,7 @@ static int imx334_set_pad_format(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *framefmt;
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
} else if (imx334->cur_mode != mode || imx334->cur_code != fmt->format.code) {
imx334->cur_code = fmt->format.code;
@@ -935,14 +935,14 @@ static int imx334_set_pad_format(struct v4l2_subdev *sd,
}
/**
- * imx334_init_pad_cfg() - Initialize sub-device pad configuration
+ * imx334_init_state() - Initialize sub-device state
* @sd: pointer to imx334 V4L2 sub-device structure
* @sd_state: V4L2 sub-device state
*
* Return: 0 if successful, error code otherwise.
*/
-static int imx334_init_pad_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int imx334_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct imx334 *imx334 = to_imx334(sd);
struct v4l2_subdev_format fmt = { 0 };
@@ -1190,7 +1190,6 @@ static const struct v4l2_subdev_video_ops imx334_video_ops = {
};
static const struct v4l2_subdev_pad_ops imx334_pad_ops = {
- .init_cfg = imx334_init_pad_cfg,
.enum_mbus_code = imx334_enum_mbus_code,
.enum_frame_size = imx334_enum_frame_size,
.get_fmt = imx334_get_pad_format,
@@ -1202,6 +1201,10 @@ static const struct v4l2_subdev_ops imx334_subdev_ops = {
.pad = &imx334_pad_ops,
};
+static const struct v4l2_subdev_internal_ops imx334_internal_ops = {
+ .init_state = imx334_init_state,
+};
+
/**
* imx334_power_on() - Sensor power on sequence
* @dev: pointer to i2c device
@@ -1359,6 +1362,7 @@ static int imx334_probe(struct i2c_client *client)
/* Initialize subdev */
v4l2_i2c_subdev_init(&imx334->sd, client, &imx334_subdev_ops);
+ imx334->sd.internal_ops = &imx334_internal_ops;
ret = imx334_parse_hw_config(imx334);
if (ret) {
diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c
index ec729126274b..7a37eb327ff4 100644
--- a/drivers/media/i2c/imx335.c
+++ b/drivers/media/i2c/imx335.c
@@ -55,6 +55,14 @@
#define IMX335_REG_MIN 0x00
#define IMX335_REG_MAX 0xfffff
+/* IMX335 native and active pixel array size. */
+#define IMX335_NATIVE_WIDTH 2616U
+#define IMX335_NATIVE_HEIGHT 1964U
+#define IMX335_PIXEL_ARRAY_LEFT 12U
+#define IMX335_PIXEL_ARRAY_TOP 12U
+#define IMX335_PIXEL_ARRAY_WIDTH 2592U
+#define IMX335_PIXEL_ARRAY_HEIGHT 1944U
+
/**
* struct imx335_reg - imx335 sensor register
* @address: Register address
@@ -75,6 +83,12 @@ struct imx335_reg_list {
const struct imx335_reg *regs;
};
+static const char * const imx335_supply_name[] = {
+ "avdd", /* Analog (2.9V) supply */
+ "ovdd", /* Digital I/O (1.8V) supply */
+ "dvdd", /* Digital Core (1.2V) supply */
+};
+
/**
* struct imx335_mode - imx335 sensor mode structure
* @width: Frame width
@@ -108,6 +122,7 @@ struct imx335_mode {
* @sd: V4L2 sub-device
* @pad: Media pad. Only one pad supported
* @reset_gpio: Sensor reset gpio
+ * @supplies: Regulator supplies to handle power control
* @inclk: Sensor input clock
* @ctrl_handler: V4L2 control handler
* @link_freq_ctrl: Pointer to link frequency control
@@ -119,6 +134,7 @@ struct imx335_mode {
* @vblank: Vertical blanking in lines
* @cur_mode: Pointer to current selected sensor mode
* @mutex: Mutex for serializing sensor controls
+ * @cur_mbus_code: Currently selected media bus format code
*/
struct imx335 {
struct device *dev;
@@ -126,6 +142,8 @@ struct imx335 {
struct v4l2_subdev sd;
struct media_pad pad;
struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(imx335_supply_name)];
+
struct clk *inclk;
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_ctrl *link_freq_ctrl;
@@ -139,6 +157,7 @@ struct imx335 {
u32 vblank;
const struct imx335_mode *cur_mode;
struct mutex mutex;
+ u32 cur_mbus_code;
};
static const s64 link_freq[] = {
@@ -233,6 +252,25 @@ static const struct imx335_reg mode_2592x1940_regs[] = {
{0x3a00, 0x01},
};
+static const struct imx335_reg raw10_framefmt_regs[] = {
+ {0x3050, 0x00},
+ {0x319d, 0x00},
+ {0x341c, 0xff},
+ {0x341d, 0x01},
+};
+
+static const struct imx335_reg raw12_framefmt_regs[] = {
+ {0x3050, 0x01},
+ {0x319d, 0x01},
+ {0x341c, 0x47},
+ {0x341d, 0x00},
+};
+
+static const u32 imx335_mbus_codes[] = {
+ MEDIA_BUS_FMT_SRGGB12_1X12,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+};
+
/* Supported sensor mode configurations */
static const struct imx335_mode supported_mode = {
.width = 2592,
@@ -243,7 +281,6 @@ static const struct imx335_mode supported_mode = {
.vblank_max = 133060,
.pclk = 396000000,
.link_freq_idx = 0,
- .code = MEDIA_BUS_FMT_SRGGB12_1X12,
.reg_list = {
.num_of_regs = ARRAY_SIZE(mode_2592x1940_regs),
.regs = mode_2592x1940_regs,
@@ -396,7 +433,7 @@ static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain)
lpfr = imx335->vblank + imx335->cur_mode->height;
shutter = lpfr - exposure;
- dev_dbg(imx335->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u",
+ dev_dbg(imx335->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u\n",
exposure, gain, shutter, lpfr);
ret = imx335_write_reg(imx335, IMX335_REG_HOLD, 1, 1);
@@ -443,7 +480,7 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_VBLANK:
imx335->vblank = imx335->vblank_ctrl->val;
- dev_dbg(imx335->dev, "Received vblank %u, new lpfr %u",
+ dev_dbg(imx335->dev, "Received vblank %u, new lpfr %u\n",
imx335->vblank,
imx335->vblank + imx335->cur_mode->height);
@@ -462,7 +499,7 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl)
exposure = ctrl->val;
analog_gain = imx335->again_ctrl->val;
- dev_dbg(imx335->dev, "Received exp %u, analog gain %u",
+ dev_dbg(imx335->dev, "Received exp %u, analog gain %u\n",
exposure, analog_gain);
ret = imx335_update_exp_gain(imx335, exposure, analog_gain);
@@ -471,7 +508,7 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl)
break;
default:
- dev_err(imx335->dev, "Invalid control %d", ctrl->id);
+ dev_err(imx335->dev, "Invalid control %d\n", ctrl->id);
ret = -EINVAL;
}
@@ -483,6 +520,18 @@ static const struct v4l2_ctrl_ops imx335_ctrl_ops = {
.s_ctrl = imx335_set_ctrl,
};
+static int imx335_get_format_code(struct imx335 *imx335, u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(imx335_mbus_codes); i++) {
+ if (imx335_mbus_codes[i] == code)
+ return imx335_mbus_codes[i];
+ }
+
+ return imx335_mbus_codes[0];
+}
+
/**
* imx335_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes
* @sd: pointer to imx335 V4L2 sub-device structure
@@ -495,10 +544,10 @@ static int imx335_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- if (code->index > 0)
+ if (code->index >= ARRAY_SIZE(imx335_mbus_codes))
return -EINVAL;
- code->code = supported_mode.code;
+ code->code = imx335_mbus_codes[code->index];
return 0;
}
@@ -515,10 +564,14 @@ static int imx335_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fsize)
{
- if (fsize->index > 0)
+ struct imx335 *imx335 = to_imx335(sd);
+ u32 code;
+
+ if (fsize->index > ARRAY_SIZE(imx335_mbus_codes))
return -EINVAL;
- if (fsize->code != supported_mode.code)
+ code = imx335_get_format_code(imx335, fsize->code);
+ if (fsize->code != code)
return -EINVAL;
fsize->min_width = supported_mode.width;
@@ -542,7 +595,7 @@ static void imx335_fill_pad_format(struct imx335 *imx335,
{
fmt->format.width = mode->width;
fmt->format.height = mode->height;
- fmt->format.code = mode->code;
+ fmt->format.code = imx335->cur_mbus_code;
fmt->format.field = V4L2_FIELD_NONE;
fmt->format.colorspace = V4L2_COLORSPACE_RAW;
fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
@@ -569,7 +622,7 @@ static int imx335_get_pad_format(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *framefmt;
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
imx335_fill_pad_format(imx335, imx335->cur_mode, fmt);
@@ -594,17 +647,22 @@ static int imx335_set_pad_format(struct v4l2_subdev *sd,
{
struct imx335 *imx335 = to_imx335(sd);
const struct imx335_mode *mode;
- int ret = 0;
+ int i, ret = 0;
mutex_lock(&imx335->mutex);
mode = &supported_mode;
+ for (i = 0; i < ARRAY_SIZE(imx335_mbus_codes); i++) {
+ if (imx335_mbus_codes[i] == fmt->format.code)
+ imx335->cur_mbus_code = imx335_mbus_codes[i];
+ }
+
imx335_fill_pad_format(imx335, mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *framefmt;
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
ret = imx335_update_controls(imx335, mode);
@@ -618,14 +676,14 @@ static int imx335_set_pad_format(struct v4l2_subdev *sd,
}
/**
- * imx335_init_pad_cfg() - Initialize sub-device pad configuration
+ * imx335_init_state() - Initialize sub-device state
* @sd: pointer to imx335 V4L2 sub-device structure
* @sd_state: V4L2 sub-device configuration
*
* Return: 0 if successful, error code otherwise.
*/
-static int imx335_init_pad_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int imx335_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct imx335 *imx335 = to_imx335(sd);
struct v4l2_subdev_format fmt = { 0 };
@@ -637,6 +695,56 @@ static int imx335_init_pad_cfg(struct v4l2_subdev *sd,
}
/**
+ * imx335_get_selection() - Selection API
+ * @sd: pointer to imx335 V4L2 sub-device structure
+ * @sd_state: V4L2 sub-device configuration
+ * @sel: V4L2 selection info
+ *
+ * Return: 0 if successful, error code otherwise.
+ */
+static int imx335_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = IMX335_NATIVE_WIDTH;
+ sel->r.height = IMX335_NATIVE_HEIGHT;
+
+ return 0;
+
+ case V4L2_SEL_TGT_CROP:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = IMX335_PIXEL_ARRAY_TOP;
+ sel->r.left = IMX335_PIXEL_ARRAY_LEFT;
+ sel->r.width = IMX335_PIXEL_ARRAY_WIDTH;
+ sel->r.height = IMX335_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int imx335_set_framefmt(struct imx335 *imx335)
+{
+ switch (imx335->cur_mbus_code) {
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ return imx335_write_regs(imx335, raw10_framefmt_regs,
+ ARRAY_SIZE(raw10_framefmt_regs));
+
+ case MEDIA_BUS_FMT_SRGGB12_1X12:
+ return imx335_write_regs(imx335, raw12_framefmt_regs,
+ ARRAY_SIZE(raw12_framefmt_regs));
+ }
+
+ return -EINVAL;
+}
+
+/**
* imx335_start_streaming() - Start sensor stream
* @imx335: pointer to imx335 device
*
@@ -652,14 +760,21 @@ static int imx335_start_streaming(struct imx335 *imx335)
ret = imx335_write_regs(imx335, reg_list->regs,
reg_list->num_of_regs);
if (ret) {
- dev_err(imx335->dev, "fail to write initial registers");
+ dev_err(imx335->dev, "fail to write initial registers\n");
+ return ret;
+ }
+
+ ret = imx335_set_framefmt(imx335);
+ if (ret) {
+ dev_err(imx335->dev, "%s failed to set frame format: %d\n",
+ __func__, ret);
return ret;
}
/* Setup handler will write actual exposure and gain */
ret = __v4l2_ctrl_handler_setup(imx335->sd.ctrl_handler);
if (ret) {
- dev_err(imx335->dev, "fail to setup handler");
+ dev_err(imx335->dev, "fail to setup handler\n");
return ret;
}
@@ -667,7 +782,7 @@ static int imx335_start_streaming(struct imx335 *imx335)
ret = imx335_write_reg(imx335, IMX335_REG_MODE_SELECT,
1, IMX335_MODE_STREAMING);
if (ret) {
- dev_err(imx335->dev, "fail to start streaming");
+ dev_err(imx335->dev, "fail to start streaming\n");
return ret;
}
@@ -744,7 +859,7 @@ static int imx335_detect(struct imx335 *imx335)
return ret;
if (val != IMX335_ID) {
- dev_err(imx335->dev, "chip id mismatch: %x!=%x",
+ dev_err(imx335->dev, "chip id mismatch: %x!=%x\n",
IMX335_ID, val);
return -ENXIO;
}
@@ -776,27 +891,40 @@ static int imx335_parse_hw_config(struct imx335 *imx335)
imx335->reset_gpio = devm_gpiod_get_optional(imx335->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(imx335->reset_gpio)) {
- dev_err(imx335->dev, "failed to get reset gpio %ld",
+ dev_err(imx335->dev, "failed to get reset gpio %ld\n",
PTR_ERR(imx335->reset_gpio));
return PTR_ERR(imx335->reset_gpio);
}
+ for (i = 0; i < ARRAY_SIZE(imx335_supply_name); i++)
+ imx335->supplies[i].supply = imx335_supply_name[i];
+
+ ret = devm_regulator_bulk_get(imx335->dev,
+ ARRAY_SIZE(imx335_supply_name),
+ imx335->supplies);
+ if (ret) {
+ dev_err(imx335->dev, "Failed to get regulators\n");
+ return ret;
+ }
+
/* Get sensor input clock */
imx335->inclk = devm_clk_get(imx335->dev, NULL);
if (IS_ERR(imx335->inclk)) {
- dev_err(imx335->dev, "could not get inclk");
+ dev_err(imx335->dev, "could not get inclk\n");
return PTR_ERR(imx335->inclk);
}
rate = clk_get_rate(imx335->inclk);
if (rate != IMX335_INCLK_RATE) {
- dev_err(imx335->dev, "inclk frequency mismatch");
+ dev_err(imx335->dev, "inclk frequency mismatch\n");
return -EINVAL;
}
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
- if (!ep)
+ if (!ep) {
+ dev_err(imx335->dev, "Failed to get next endpoint\n");
return -ENXIO;
+ }
ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
fwnode_handle_put(ep);
@@ -805,14 +933,14 @@ static int imx335_parse_hw_config(struct imx335 *imx335)
if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX335_NUM_DATA_LANES) {
dev_err(imx335->dev,
- "number of CSI2 data lanes %d is not supported",
+ "number of CSI2 data lanes %d is not supported\n",
bus_cfg.bus.mipi_csi2.num_data_lanes);
ret = -EINVAL;
goto done_endpoint_free;
}
if (!bus_cfg.nr_of_link_frequencies) {
- dev_err(imx335->dev, "no link frequencies defined");
+ dev_err(imx335->dev, "no link frequencies defined\n");
ret = -EINVAL;
goto done_endpoint_free;
}
@@ -821,6 +949,8 @@ static int imx335_parse_hw_config(struct imx335 *imx335)
if (bus_cfg.link_frequencies[i] == IMX335_LINK_FREQ)
goto done_endpoint_free;
+ dev_err(imx335->dev, "no compatible link frequencies found\n");
+
ret = -EINVAL;
done_endpoint_free:
@@ -835,9 +965,10 @@ static const struct v4l2_subdev_video_ops imx335_video_ops = {
};
static const struct v4l2_subdev_pad_ops imx335_pad_ops = {
- .init_cfg = imx335_init_pad_cfg,
.enum_mbus_code = imx335_enum_mbus_code,
.enum_frame_size = imx335_enum_frame_size,
+ .get_selection = imx335_get_selection,
+ .set_selection = imx335_get_selection,
.get_fmt = imx335_get_pad_format,
.set_fmt = imx335_set_pad_format,
};
@@ -847,6 +978,10 @@ static const struct v4l2_subdev_ops imx335_subdev_ops = {
.pad = &imx335_pad_ops,
};
+static const struct v4l2_subdev_internal_ops imx335_internal_ops = {
+ .init_state = imx335_init_state,
+};
+
/**
* imx335_power_on() - Sensor power on sequence
* @dev: pointer to i2c device
@@ -859,20 +994,32 @@ static int imx335_power_on(struct device *dev)
struct imx335 *imx335 = to_imx335(sd);
int ret;
+ ret = regulator_bulk_enable(ARRAY_SIZE(imx335_supply_name),
+ imx335->supplies);
+ if (ret) {
+ dev_err(dev, "%s: failed to enable regulators\n",
+ __func__);
+ return ret;
+ }
+
+ usleep_range(500, 550); /* Tlow */
+
+ /* Set XCLR */
gpiod_set_value_cansleep(imx335->reset_gpio, 1);
ret = clk_prepare_enable(imx335->inclk);
if (ret) {
- dev_err(imx335->dev, "fail to enable inclk");
+ dev_err(imx335->dev, "fail to enable inclk\n");
goto error_reset;
}
- usleep_range(20, 22);
+ usleep_range(20, 22); /* T4 */
return 0;
error_reset:
gpiod_set_value_cansleep(imx335->reset_gpio, 0);
+ regulator_bulk_disable(ARRAY_SIZE(imx335_supply_name), imx335->supplies);
return ret;
}
@@ -889,8 +1036,8 @@ static int imx335_power_off(struct device *dev)
struct imx335 *imx335 = to_imx335(sd);
gpiod_set_value_cansleep(imx335->reset_gpio, 0);
-
clk_disable_unprepare(imx335->inclk);
+ regulator_bulk_disable(ARRAY_SIZE(imx335_supply_name), imx335->supplies);
return 0;
}
@@ -962,14 +1109,14 @@ static int imx335_init_controls(struct imx335 *imx335)
imx335->hblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
&imx335_ctrl_ops,
V4L2_CID_HBLANK,
- IMX335_REG_MIN,
- IMX335_REG_MAX,
+ mode->hblank,
+ mode->hblank,
1, mode->hblank);
if (imx335->hblank_ctrl)
imx335->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
if (ctrl_hdlr->error) {
- dev_err(imx335->dev, "control init failed: %d",
+ dev_err(imx335->dev, "control init failed: %d\n",
ctrl_hdlr->error);
v4l2_ctrl_handler_free(ctrl_hdlr);
return ctrl_hdlr->error;
@@ -999,10 +1146,11 @@ static int imx335_probe(struct i2c_client *client)
/* Initialize subdev */
v4l2_i2c_subdev_init(&imx335->sd, client, &imx335_subdev_ops);
+ imx335->sd.internal_ops = &imx335_internal_ops;
ret = imx335_parse_hw_config(imx335);
if (ret) {
- dev_err(imx335->dev, "HW configuration is not supported");
+ dev_err(imx335->dev, "HW configuration is not supported\n");
return ret;
}
@@ -1010,24 +1158,25 @@ static int imx335_probe(struct i2c_client *client)
ret = imx335_power_on(imx335->dev);
if (ret) {
- dev_err(imx335->dev, "failed to power-on the sensor");
+ dev_err(imx335->dev, "failed to power-on the sensor\n");
goto error_mutex_destroy;
}
/* Check module identity */
ret = imx335_detect(imx335);
if (ret) {
- dev_err(imx335->dev, "failed to find sensor: %d", ret);
+ dev_err(imx335->dev, "failed to find sensor: %d\n", ret);
goto error_power_off;
}
/* Set default mode to max resolution */
imx335->cur_mode = &supported_mode;
+ imx335->cur_mbus_code = imx335_mbus_codes[0];
imx335->vblank = imx335->cur_mode->vblank;
ret = imx335_init_controls(imx335);
if (ret) {
- dev_err(imx335->dev, "failed to init controls: %d", ret);
+ dev_err(imx335->dev, "failed to init controls: %d\n", ret);
goto error_power_off;
}
@@ -1039,14 +1188,14 @@ static int imx335_probe(struct i2c_client *client)
imx335->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&imx335->sd.entity, 1, &imx335->pad);
if (ret) {
- dev_err(imx335->dev, "failed to init entity pads: %d", ret);
+ dev_err(imx335->dev, "failed to init entity pads: %d\n", ret);
goto error_handler_free;
}
ret = v4l2_async_register_subdev_sensor(&imx335->sd);
if (ret < 0) {
dev_err(imx335->dev,
- "failed to register async subdev: %d", ret);
+ "failed to register async subdev: %d\n", ret);
goto error_media_entity;
}
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c
index 9c58c1a80cba..8c995c58743a 100644
--- a/drivers/media/i2c/imx355.c
+++ b/drivers/media/i2c/imx355.c
@@ -1158,7 +1158,7 @@ static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct imx355 *imx355 = to_imx355(sd);
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
+ v4l2_subdev_state_get_format(fh->state, 0);
mutex_lock(&imx355->mutex);
@@ -1299,10 +1299,9 @@ static int imx355_do_get_pad_format(struct imx355 *imx355,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *framefmt;
- struct v4l2_subdev *sd = &imx355->sd;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
imx355_update_pad_format(imx355, imx355->cur_mode, fmt);
@@ -1353,7 +1352,7 @@ imx355_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
imx355_update_pad_format(imx355, mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
imx355->cur_mode = mode;
@@ -1748,10 +1747,6 @@ static int imx355_probe(struct i2c_client *client)
goto error_handler_free;
}
- ret = v4l2_async_register_subdev_sensor(&imx355->sd);
- if (ret < 0)
- goto error_media_entity;
-
/*
* Device is already turned on by i2c-core with ACPI domain PM.
* Enable runtime PM and turn off the device.
@@ -1760,9 +1755,15 @@ static int imx355_probe(struct i2c_client *client)
pm_runtime_enable(&client->dev);
pm_runtime_idle(&client->dev);
+ ret = v4l2_async_register_subdev_sensor(&imx355->sd);
+ if (ret < 0)
+ goto error_media_entity_runtime_pm;
+
return 0;
-error_media_entity:
+error_media_entity_runtime_pm:
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
media_entity_cleanup(&imx355->sd.entity);
error_handler_free:
diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c
index 962b3136c31e..0efce329525e 100644
--- a/drivers/media/i2c/imx412.c
+++ b/drivers/media/i2c/imx412.c
@@ -721,7 +721,7 @@ static int imx412_get_pad_format(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *framefmt;
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
imx412_fill_pad_format(imx412, imx412->cur_mode, fmt);
@@ -756,7 +756,7 @@ static int imx412_set_pad_format(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *framefmt;
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
ret = imx412_update_controls(imx412, mode);
@@ -770,14 +770,14 @@ static int imx412_set_pad_format(struct v4l2_subdev *sd,
}
/**
- * imx412_init_pad_cfg() - Initialize sub-device pad configuration
+ * imx412_init_state() - Initialize sub-device state
* @sd: pointer to imx412 V4L2 sub-device structure
* @sd_state: V4L2 sub-device configuration
*
* Return: 0 if successful, error code otherwise.
*/
-static int imx412_init_pad_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int imx412_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct imx412 *imx412 = to_imx412(sd);
struct v4l2_subdev_format fmt = { 0 };
@@ -997,7 +997,6 @@ static const struct v4l2_subdev_video_ops imx412_video_ops = {
};
static const struct v4l2_subdev_pad_ops imx412_pad_ops = {
- .init_cfg = imx412_init_pad_cfg,
.enum_mbus_code = imx412_enum_mbus_code,
.enum_frame_size = imx412_enum_frame_size,
.get_fmt = imx412_get_pad_format,
@@ -1009,6 +1008,10 @@ static const struct v4l2_subdev_ops imx412_subdev_ops = {
.pad = &imx412_pad_ops,
};
+static const struct v4l2_subdev_internal_ops imx412_internal_ops = {
+ .init_state = imx412_init_state,
+};
+
/**
* imx412_power_on() - Sensor power on sequence
* @dev: pointer to i2c device
@@ -1177,6 +1180,7 @@ static int imx412_probe(struct i2c_client *client)
/* Initialize subdev */
v4l2_i2c_subdev_init(&imx412->sd, client, &imx412_subdev_ops);
+ imx412->sd.internal_ops = &imx412_internal_ops;
ret = imx412_parse_hw_config(imx412);
if (ret) {
diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c
index b3fa71a16839..1e5f20c3ed82 100644
--- a/drivers/media/i2c/imx415.c
+++ b/drivers/media/i2c/imx415.c
@@ -546,7 +546,7 @@ static int imx415_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
state = v4l2_subdev_get_locked_active_state(&sensor->subdev);
- format = v4l2_subdev_get_pad_format(&sensor->subdev, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
@@ -828,7 +828,7 @@ static int imx415_enum_frame_size(struct v4l2_subdev *sd,
{
const struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_pad_format(sd, state, fse->pad);
+ format = v4l2_subdev_state_get_format(state, fse->pad);
if (fse->index > 0 || fse->code != format->code)
return -EINVAL;
@@ -846,7 +846,7 @@ static int imx415_set_format(struct v4l2_subdev *sd,
{
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_pad_format(sd, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
format->width = fmt->format.width;
format->height = fmt->format.height;
@@ -880,8 +880,8 @@ static int imx415_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
}
-static int imx415_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int imx415_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct v4l2_subdev_format format = {
.format = {
@@ -905,7 +905,6 @@ static const struct v4l2_subdev_pad_ops imx415_subdev_pad_ops = {
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = imx415_set_format,
.get_selection = imx415_get_selection,
- .init_cfg = imx415_init_cfg,
};
static const struct v4l2_subdev_ops imx415_subdev_ops = {
@@ -913,12 +912,17 @@ static const struct v4l2_subdev_ops imx415_subdev_ops = {
.pad = &imx415_subdev_pad_ops,
};
+static const struct v4l2_subdev_internal_ops imx415_internal_ops = {
+ .init_state = imx415_init_state,
+};
+
static int imx415_subdev_init(struct imx415 *sensor)
{
struct i2c_client *client = to_i2c_client(sensor->dev);
int ret;
v4l2_i2c_subdev_init(&sensor->subdev, client, &imx415_subdev_ops);
+ sensor->subdev.internal_ops = &imx415_internal_ops;
ret = imx415_ctrls_init(sensor);
if (ret)
diff --git a/drivers/media/i2c/isl7998x.c b/drivers/media/i2c/isl7998x.c
index 73460688c356..89e13ebbce0c 100644
--- a/drivers/media/i2c/isl7998x.c
+++ b/drivers/media/i2c/isl7998x.c
@@ -1007,8 +1007,8 @@ static int isl7998x_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&isl7998x->lock);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- format->format = *v4l2_subdev_get_try_format(sd, sd_state,
- format->pad);
+ format->format = *v4l2_subdev_state_get_format(sd_state,
+ format->pad);
goto out;
}
@@ -1044,7 +1044,7 @@ static int isl7998x_set_fmt(struct v4l2_subdev *sd,
mf->field = mode->field;
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *v4l2_subdev_get_try_format(sd, sd_state, format->pad) = format->format;
+ *v4l2_subdev_state_get_format(sd_state, format->pad) = format->format;
mutex_unlock(&isl7998x->lock);
diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index fc1cf196ef01..d685d445cf23 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -868,11 +868,19 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
-static int max9286_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval)
+static int max9286_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *interval)
{
struct max9286_priv *priv = sd_to_max9286(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (interval->pad != MAX9286_SRC_PAD)
return -EINVAL;
@@ -881,11 +889,19 @@ static int max9286_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int max9286_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval)
+static int max9286_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *interval)
{
struct max9286_priv *priv = sd_to_max9286(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (interval->pad != MAX9286_SRC_PAD)
return -EINVAL;
@@ -913,7 +929,7 @@ max9286_get_pad_format(struct max9286_priv *priv,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &priv->fmt[pad];
default:
@@ -983,14 +999,14 @@ static int max9286_get_fmt(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops max9286_video_ops = {
.s_stream = max9286_s_stream,
- .g_frame_interval = max9286_g_frame_interval,
- .s_frame_interval = max9286_s_frame_interval,
};
static const struct v4l2_subdev_pad_ops max9286_pad_ops = {
.enum_mbus_code = max9286_enum_mbus_code,
.get_fmt = max9286_get_fmt,
.set_fmt = max9286_set_fmt,
+ .get_frame_interval = max9286_get_frame_interval,
+ .set_frame_interval = max9286_set_frame_interval,
};
static const struct v4l2_subdev_ops max9286_subdev_ops = {
@@ -1020,7 +1036,7 @@ static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
unsigned int i;
for (i = 0; i < MAX9286_N_SINKS; i++) {
- format = v4l2_subdev_get_try_format(subdev, fh->state, i);
+ format = v4l2_subdev_state_get_format(fh->state, i);
max9286_init_format(format);
}
diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c
index 79192cf79d28..ad1a3ab77411 100644
--- a/drivers/media/i2c/mt9m001.c
+++ b/drivers/media/i2c/mt9m001.c
@@ -325,7 +325,7 @@ static int mt9m001_get_fmt(struct v4l2_subdev *sd,
return -EINVAL;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ mf = v4l2_subdev_state_get_format(sd_state, 0);
format->format = *mf;
return 0;
}
@@ -405,7 +405,7 @@ static int mt9m001_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return mt9m001_s_fmt(sd, fmt, mf);
- sd_state->pads->try_fmt = *mf;
+ *v4l2_subdev_state_get_format(sd_state, 0) = *mf;
return 0;
}
@@ -650,13 +650,13 @@ static const struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
#endif
};
-static int mt9m001_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int mt9m001_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, sd_state, 0);
+ v4l2_subdev_state_get_format(sd_state, 0);
try_fmt->width = MT9M001_MAX_WIDTH;
try_fmt->height = MT9M001_MAX_HEIGHT;
@@ -708,7 +708,6 @@ static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = {
};
static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = {
- .init_cfg = mt9m001_init_cfg,
.enum_mbus_code = mt9m001_enum_mbus_code,
.get_selection = mt9m001_get_selection,
.set_selection = mt9m001_set_selection,
@@ -724,6 +723,10 @@ static const struct v4l2_subdev_ops mt9m001_subdev_ops = {
.pad = &mt9m001_subdev_pad_ops,
};
+static const struct v4l2_subdev_internal_ops mt9m001_internal_ops = {
+ .init_state = mt9m001_init_state,
+};
+
static int mt9m001_probe(struct i2c_client *client)
{
struct mt9m001 *mt9m001;
@@ -755,6 +758,7 @@ static int mt9m001_probe(struct i2c_client *client)
return PTR_ERR(mt9m001->reset_gpio);
v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);
+ mt9m001->subdev.internal_ops = &mt9m001_internal_ops;
mt9m001->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
v4l2_ctrl_handler_init(&mt9m001->hdl, 4);
diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
index 1f44b72e8a70..ceeeb94c38d5 100644
--- a/drivers/media/i2c/mt9m111.c
+++ b/drivers/media/i2c/mt9m111.c
@@ -525,7 +525,7 @@ static int mt9m111_get_fmt(struct v4l2_subdev *sd,
return -EINVAL;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
+ mf = v4l2_subdev_state_get_format(sd_state, format->pad);
format->format = *mf;
return 0;
}
@@ -671,7 +671,7 @@ static int mt9m111_set_fmt(struct v4l2_subdev *sd,
mf->xfer_func = V4L2_XFER_FUNC_DEFAULT;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sd_state->pads->try_fmt = *mf;
+ *v4l2_subdev_state_get_format(sd_state, 0) = *mf;
return 0;
}
@@ -1045,18 +1045,27 @@ static const struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
#endif
};
-static int mt9m111_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int mt9m111_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
fi->interval = mt9m111->frame_interval;
return 0;
}
-static int mt9m111_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int mt9m111_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
const struct mt9m111_mode_info *mode;
@@ -1066,6 +1075,13 @@ static int mt9m111_s_frame_interval(struct v4l2_subdev *sd,
if (mt9m111->is_streaming)
return -EBUSY;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (fi->pad != 0)
return -EINVAL;
@@ -1111,11 +1127,11 @@ static int mt9m111_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
-static int mt9m111_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int mt9m111_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *format =
- v4l2_subdev_get_try_format(sd, sd_state, 0);
+ v4l2_subdev_state_get_format(sd_state, 0);
format->width = MT9M111_MAX_WIDTH;
format->height = MT9M111_MAX_HEIGHT;
@@ -1151,17 +1167,16 @@ static int mt9m111_get_mbus_config(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
.s_stream = mt9m111_s_stream,
- .g_frame_interval = mt9m111_g_frame_interval,
- .s_frame_interval = mt9m111_s_frame_interval,
};
static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = {
- .init_cfg = mt9m111_init_cfg,
.enum_mbus_code = mt9m111_enum_mbus_code,
.get_selection = mt9m111_get_selection,
.set_selection = mt9m111_set_selection,
.get_fmt = mt9m111_get_fmt,
.set_fmt = mt9m111_set_fmt,
+ .get_frame_interval = mt9m111_get_frame_interval,
+ .set_frame_interval = mt9m111_set_frame_interval,
.get_mbus_config = mt9m111_get_mbus_config,
};
@@ -1171,6 +1186,10 @@ static const struct v4l2_subdev_ops mt9m111_subdev_ops = {
.pad = &mt9m111_subdev_pad_ops,
};
+static const struct v4l2_subdev_internal_ops mt9m111_internal_ops = {
+ .init_state = mt9m111_init_state,
+};
+
/*
* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one
@@ -1275,6 +1294,7 @@ static int mt9m111_probe(struct i2c_client *client)
mt9m111->ctx = &context_b;
v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
+ mt9m111->subdev.internal_ops = &mt9m111_internal_ops;
mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c
index ac19078ceda3..5f0b0ad8f885 100644
--- a/drivers/media/i2c/mt9m114.c
+++ b/drivers/media/i2c/mt9m114.c
@@ -796,13 +796,13 @@ static int mt9m114_configure(struct mt9m114 *sensor,
u64 read_mode;
int ret = 0;
- pa_format = v4l2_subdev_get_pad_format(&sensor->pa.sd, pa_state, 0);
- pa_crop = v4l2_subdev_get_pad_crop(&sensor->pa.sd, pa_state, 0);
+ pa_format = v4l2_subdev_state_get_format(pa_state, 0);
+ pa_crop = v4l2_subdev_state_get_crop(pa_state, 0);
- ifp_format = v4l2_subdev_get_pad_format(&sensor->ifp.sd, ifp_state, 1);
+ ifp_format = v4l2_subdev_state_get_format(ifp_state, 1);
ifp_info = mt9m114_format_info(sensor, 1, ifp_format->code);
- ifp_crop = v4l2_subdev_get_pad_crop(&sensor->ifp.sd, ifp_state, 0);
- ifp_compose = v4l2_subdev_get_pad_compose(&sensor->ifp.sd, ifp_state, 0);
+ ifp_crop = v4l2_subdev_state_get_crop(ifp_state, 0);
+ ifp_compose = v4l2_subdev_state_get_compose(ifp_state, 0);
ret = cci_read(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE,
&read_mode, NULL);
@@ -1045,7 +1045,7 @@ static int mt9m114_pa_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
state = v4l2_subdev_get_locked_active_state(&sensor->pa.sd);
- format = v4l2_subdev_get_pad_format(&sensor->pa.sd, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
switch (ctrl->id) {
case V4L2_CID_HBLANK:
@@ -1152,20 +1152,20 @@ static inline struct mt9m114 *pa_to_mt9m114(struct v4l2_subdev *sd)
return container_of(sd, struct mt9m114, pa.sd);
}
-static int mt9m114_pa_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int mt9m114_pa_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- crop = v4l2_subdev_get_pad_crop(sd, state, 0);
+ crop = v4l2_subdev_state_get_crop(state, 0);
crop->left = 0;
crop->top = 0;
crop->width = MT9M114_PIXEL_ARRAY_WIDTH;
crop->height = MT9M114_PIXEL_ARRAY_HEIGHT;
- format = v4l2_subdev_get_pad_format(sd, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
format->width = MT9M114_PIXEL_ARRAY_WIDTH;
format->height = MT9M114_PIXEL_ARRAY_HEIGHT;
@@ -1220,8 +1220,8 @@ static int mt9m114_pa_set_fmt(struct v4l2_subdev *sd,
unsigned int hscale;
unsigned int vscale;
- crop = v4l2_subdev_get_pad_crop(sd, state, fmt->pad);
- format = v4l2_subdev_get_pad_format(sd, state, fmt->pad);
+ crop = v4l2_subdev_state_get_crop(state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
/* The sensor can bin horizontally and vertically. */
hscale = DIV_ROUND_CLOSEST(crop->width, fmt->format.width ? : 1);
@@ -1243,7 +1243,7 @@ static int mt9m114_pa_get_selection(struct v4l2_subdev *sd,
{
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- sel->r = *v4l2_subdev_get_pad_crop(sd, state, sel->pad);
+ sel->r = *v4l2_subdev_state_get_crop(state, sel->pad);
return 0;
case V4L2_SEL_TGT_CROP_DEFAULT:
@@ -1271,8 +1271,8 @@ static int mt9m114_pa_set_selection(struct v4l2_subdev *sd,
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- crop = v4l2_subdev_get_pad_crop(sd, state, sel->pad);
- format = v4l2_subdev_get_pad_format(sd, state, sel->pad);
+ crop = v4l2_subdev_state_get_crop(state, sel->pad);
+ format = v4l2_subdev_state_get_format(state, sel->pad);
/*
* Clamp the crop rectangle. The vertical coordinates must be even, and
@@ -1304,7 +1304,6 @@ static int mt9m114_pa_set_selection(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_pad_ops mt9m114_pa_pad_ops = {
- .init_cfg = mt9m114_pa_init_cfg,
.enum_mbus_code = mt9m114_pa_enum_mbus_code,
.enum_frame_size = mt9m114_pa_enum_framesizes,
.get_fmt = v4l2_subdev_get_fmt,
@@ -1317,6 +1316,10 @@ static const struct v4l2_subdev_ops mt9m114_pa_ops = {
.pad = &mt9m114_pa_pad_ops,
};
+static const struct v4l2_subdev_internal_ops mt9m114_pa_internal_ops = {
+ .init_state = mt9m114_pa_init_state,
+};
+
static int mt9m114_pa_init(struct mt9m114 *sensor)
{
struct v4l2_ctrl_handler *hdl = &sensor->pa.hdl;
@@ -1329,6 +1332,7 @@ static int mt9m114_pa_init(struct mt9m114 *sensor)
/* Initialize the subdev. */
v4l2_subdev_init(sd, &mt9m114_pa_ops);
+ sd->internal_ops = &mt9m114_pa_internal_ops;
v4l2_i2c_subdev_set_name(sd, sensor->client, NULL, " pixel array");
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -1402,7 +1406,7 @@ static int mt9m114_pa_init(struct mt9m114 *sensor)
/* Update the range of the blanking controls based on the format. */
state = v4l2_subdev_lock_and_get_active_state(sd);
- format = v4l2_subdev_get_pad_format(sd, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
mt9m114_pa_ctrl_update_blanking(sensor, format);
v4l2_subdev_unlock_state(state);
@@ -1581,12 +1585,20 @@ static int mt9m114_ifp_s_stream(struct v4l2_subdev *sd, int enable)
return ret;
}
-static int mt9m114_ifp_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval)
+static int mt9m114_ifp_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *interval)
{
struct v4l2_fract *ival = &interval->interval;
struct mt9m114 *sensor = ifp_to_mt9m114(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(sensor->ifp.hdl.lock);
ival->numerator = 1;
@@ -1597,13 +1609,21 @@ static int mt9m114_ifp_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int mt9m114_ifp_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval)
+static int mt9m114_ifp_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *interval)
{
struct v4l2_fract *ival = &interval->interval;
struct mt9m114 *sensor = ifp_to_mt9m114(sd);
int ret = 0;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(sensor->ifp.hdl.lock);
if (ival->numerator != 0 && ival->denominator != 0)
@@ -1624,15 +1644,15 @@ static int mt9m114_ifp_s_frame_interval(struct v4l2_subdev *sd,
return ret;
}
-static int mt9m114_ifp_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int mt9m114_ifp_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct mt9m114 *sensor = ifp_to_mt9m114(sd);
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
struct v4l2_rect *compose;
- format = v4l2_subdev_get_pad_format(sd, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
format->width = MT9M114_PIXEL_ARRAY_WIDTH;
format->height = MT9M114_PIXEL_ARRAY_HEIGHT;
@@ -1643,21 +1663,21 @@ static int mt9m114_ifp_init_cfg(struct v4l2_subdev *sd,
format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
format->xfer_func = V4L2_XFER_FUNC_NONE;
- crop = v4l2_subdev_get_pad_crop(sd, state, 0);
+ crop = v4l2_subdev_state_get_crop(state, 0);
crop->left = 4;
crop->top = 4;
crop->width = format->width - 8;
crop->height = format->height - 8;
- compose = v4l2_subdev_get_pad_compose(sd, state, 0);
+ compose = v4l2_subdev_state_get_compose(state, 0);
compose->left = 0;
compose->top = 0;
compose->width = crop->width;
compose->height = crop->height;
- format = v4l2_subdev_get_pad_format(sd, state, 1);
+ format = v4l2_subdev_state_get_format(state, 1);
format->width = compose->width;
format->height = compose->height;
@@ -1738,7 +1758,7 @@ static int mt9m114_ifp_enum_framesizes(struct v4l2_subdev *sd,
} else {
const struct v4l2_rect *crop;
- crop = v4l2_subdev_get_pad_crop(sd, state, 0);
+ crop = v4l2_subdev_state_get_crop(state, 0);
fse->max_width = crop->width;
fse->max_height = crop->height;
@@ -1777,7 +1797,7 @@ static int mt9m114_ifp_set_fmt(struct v4l2_subdev *sd,
struct mt9m114 *sensor = ifp_to_mt9m114(sd);
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_pad_format(sd, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
if (fmt->pad == 0) {
/* Only the size can be changed on the sink pad. */
@@ -1797,7 +1817,7 @@ static int mt9m114_ifp_set_fmt(struct v4l2_subdev *sd,
/* If the output format is RAW10, bypass the scaler. */
if (format->code == MEDIA_BUS_FMT_SGRBG10_1X10)
- *format = *v4l2_subdev_get_pad_format(sd, state, 0);
+ *format = *v4l2_subdev_state_get_format(state, 0);
}
fmt->format = *format;
@@ -1819,7 +1839,7 @@ static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- sel->r = *v4l2_subdev_get_pad_crop(sd, state, 0);
+ sel->r = *v4l2_subdev_state_get_crop(state, 0);
break;
case V4L2_SEL_TGT_CROP_DEFAULT:
@@ -1828,7 +1848,7 @@ static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd,
* The crop default and bounds are equal to the sink
* format size minus 4 pixels on each side for demosaicing.
*/
- format = v4l2_subdev_get_pad_format(sd, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
sel->r.left = 4;
sel->r.top = 4;
@@ -1837,7 +1857,7 @@ static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd,
break;
case V4L2_SEL_TGT_COMPOSE:
- sel->r = *v4l2_subdev_get_pad_compose(sd, state, 0);
+ sel->r = *v4l2_subdev_state_get_compose(state, 0);
break;
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
@@ -1846,7 +1866,7 @@ static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd,
* The compose default and bounds sizes are equal to the sink
* crop rectangle size.
*/
- crop = v4l2_subdev_get_pad_crop(sd, state, 0);
+ crop = v4l2_subdev_state_get_crop(state, 0);
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = crop->width;
@@ -1877,9 +1897,9 @@ static int mt9m114_ifp_set_selection(struct v4l2_subdev *sd,
if (sel->pad != 0)
return -EINVAL;
- format = v4l2_subdev_get_pad_format(sd, state, 0);
- crop = v4l2_subdev_get_pad_crop(sd, state, 0);
- compose = v4l2_subdev_get_pad_compose(sd, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
+ crop = v4l2_subdev_state_get_crop(state, 0);
+ compose = v4l2_subdev_state_get_compose(state, 0);
if (sel->target == V4L2_SEL_TGT_CROP) {
/*
@@ -1921,7 +1941,7 @@ static int mt9m114_ifp_set_selection(struct v4l2_subdev *sd,
}
/* Propagate the compose rectangle to the source format. */
- format = v4l2_subdev_get_pad_format(sd, state, 1);
+ format = v4l2_subdev_state_get_format(state, 1);
format->width = compose->width;
format->height = compose->height;
@@ -1963,12 +1983,9 @@ static int mt9m114_ifp_registered(struct v4l2_subdev *sd)
static const struct v4l2_subdev_video_ops mt9m114_ifp_video_ops = {
.s_stream = mt9m114_ifp_s_stream,
- .g_frame_interval = mt9m114_ifp_g_frame_interval,
- .s_frame_interval = mt9m114_ifp_s_frame_interval,
};
static const struct v4l2_subdev_pad_ops mt9m114_ifp_pad_ops = {
- .init_cfg = mt9m114_ifp_init_cfg,
.enum_mbus_code = mt9m114_ifp_enum_mbus_code,
.enum_frame_size = mt9m114_ifp_enum_framesizes,
.enum_frame_interval = mt9m114_ifp_enum_frameintervals,
@@ -1976,6 +1993,8 @@ static const struct v4l2_subdev_pad_ops mt9m114_ifp_pad_ops = {
.set_fmt = mt9m114_ifp_set_fmt,
.get_selection = mt9m114_ifp_get_selection,
.set_selection = mt9m114_ifp_set_selection,
+ .get_frame_interval = mt9m114_ifp_get_frame_interval,
+ .set_frame_interval = mt9m114_ifp_set_frame_interval,
};
static const struct v4l2_subdev_ops mt9m114_ifp_ops = {
@@ -1984,6 +2003,7 @@ static const struct v4l2_subdev_ops mt9m114_ifp_ops = {
};
static const struct v4l2_subdev_internal_ops mt9m114_ifp_internal_ops = {
+ .init_state = mt9m114_ifp_init_state,
.registered = mt9m114_ifp_registered,
.unregistered = mt9m114_ifp_unregistered,
};
@@ -2112,7 +2132,7 @@ static int mt9m114_power_on(struct mt9m114 *sensor)
duration = DIV_ROUND_UP(2 * 50 * 1000000, freq);
gpiod_set_value(sensor->reset, 1);
- udelay(duration);
+ fsleep(duration);
gpiod_set_value(sensor->reset, 0);
} else {
/*
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index 348f1e1098fb..596200d0248c 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -549,8 +549,7 @@ __mt9p031_get_pad_format(struct mt9p031 *mt9p031,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&mt9p031->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9p031->format;
default:
@@ -565,8 +564,7 @@ __mt9p031_get_pad_crop(struct mt9p031 *mt9p031,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&mt9p031->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_crop(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9p031->crop;
default:
@@ -698,8 +696,8 @@ static int mt9p031_set_selection(struct v4l2_subdev *subdev,
return 0;
}
-static int mt9p031_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state)
+static int mt9p031_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
struct v4l2_mbus_framefmt *format;
@@ -1043,7 +1041,6 @@ static const struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = {
};
static const struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
- .init_cfg = mt9p031_init_cfg,
.enum_mbus_code = mt9p031_enum_mbus_code,
.enum_frame_size = mt9p031_enum_frame_size,
.get_fmt = mt9p031_get_format,
@@ -1059,6 +1056,7 @@ static const struct v4l2_subdev_ops mt9p031_subdev_ops = {
};
static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = {
+ .init_state = mt9p031_init_state,
.registered = mt9p031_registered,
.open = mt9p031_open,
.close = mt9p031_close,
@@ -1191,7 +1189,7 @@ static int mt9p031_probe(struct i2c_client *client)
mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- ret = mt9p031_init_cfg(&mt9p031->subdev, NULL);
+ ret = mt9p031_init_state(&mt9p031->subdev, NULL);
if (ret)
goto done;
diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c
index 93f34b767027..fb1588c57cc8 100644
--- a/drivers/media/i2c/mt9t112.c
+++ b/drivers/media/i2c/mt9t112.c
@@ -982,7 +982,6 @@ static int mt9t112_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return mt9t112_s_fmt(sd, mf);
- sd_state->pads->try_fmt = *mf;
return 0;
}
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index 37a634b92cd5..8834ff8786e5 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -356,15 +356,23 @@ static int mt9v011_set_fmt(struct v4l2_subdev *sd,
set_res(sd);
} else {
- sd_state->pads->try_fmt = *fmt;
+ *v4l2_subdev_state_get_format(sd_state, 0) = *fmt;
}
return 0;
}
-static int mt9v011_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
+static int mt9v011_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
{
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
calc_fps(sd,
&ival->interval.numerator,
&ival->interval.denominator);
@@ -372,12 +380,20 @@ static int mt9v011_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int mt9v011_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
+static int mt9v011_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
{
struct v4l2_fract *tpf = &ival->interval;
u16 speed;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
speed = calc_speed(sd, tpf->numerator, tpf->denominator);
mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed);
@@ -455,19 +471,15 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
#endif
};
-static const struct v4l2_subdev_video_ops mt9v011_video_ops = {
- .g_frame_interval = mt9v011_g_frame_interval,
- .s_frame_interval = mt9v011_s_frame_interval,
-};
-
static const struct v4l2_subdev_pad_ops mt9v011_pad_ops = {
.enum_mbus_code = mt9v011_enum_mbus_code,
.set_fmt = mt9v011_set_fmt,
+ .get_frame_interval = mt9v011_get_frame_interval,
+ .set_frame_interval = mt9v011_set_frame_interval,
};
static const struct v4l2_subdev_ops mt9v011_ops = {
.core = &mt9v011_core_ops,
- .video = &mt9v011_video_ops,
.pad = &mt9v011_pad_ops,
};
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 1c6f6cea1204..3ca76eeae7ff 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -356,8 +356,7 @@ __mt9v032_get_pad_format(struct mt9v032 *mt9v032,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&mt9v032->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9v032->format;
default:
@@ -372,8 +371,7 @@ __mt9v032_get_pad_crop(struct mt9v032 *mt9v032,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&mt9v032->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_crop(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9v032->crop;
default:
@@ -931,13 +929,13 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
- crop = v4l2_subdev_get_try_crop(subdev, fh->state, 0);
+ crop = v4l2_subdev_state_get_crop(fh->state, 0);
crop->left = MT9V032_COLUMN_START_DEF;
crop->top = MT9V032_ROW_START_DEF;
crop->width = MT9V032_WINDOW_WIDTH_DEF;
crop->height = MT9V032_WINDOW_HEIGHT_DEF;
- format = v4l2_subdev_get_try_format(subdev, fh->state, 0);
+ format = v4l2_subdev_state_get_format(fh->state, 0);
if (mt9v032->model->color)
format->code = MEDIA_BUS_FMT_SGRBG10_1X10;
diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c
index f859b49e13bf..b0b98ed3c150 100644
--- a/drivers/media/i2c/mt9v111.c
+++ b/drivers/media/i2c/mt9v111.c
@@ -35,7 +35,7 @@
* The IFP can produce several output image formats from the sensor core
* output. This driver currently supports only YUYV format permutations.
*
- * The driver allows manual frame rate control through s_frame_interval subdev
+ * The driver allows manual frame rate control through set_frame_interval subdev
* operation or V4L2_CID_V/HBLANK controls, but it is known that the
* auto-exposure algorithm might modify the programmed frame rate. While the
* driver initially programs the sensor with auto-exposure and
@@ -719,8 +719,9 @@ error_unlock:
return ret;
}
-static int mt9v111_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
+static int mt9v111_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
{
struct mt9v111_dev *mt9v111 = sd_to_mt9v111(sd);
struct v4l2_fract *tpf = &ival->interval;
@@ -729,6 +730,13 @@ static int mt9v111_s_frame_interval(struct v4l2_subdev *sd,
tpf->denominator;
unsigned int max_fps;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (!tpf->numerator)
tpf->numerator = 1;
@@ -771,12 +779,20 @@ static int mt9v111_s_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int mt9v111_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
+static int mt9v111_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
{
struct mt9v111_dev *mt9v111 = sd_to_mt9v111(sd);
struct v4l2_fract *tpf = &ival->interval;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(&mt9v111->stream_mutex);
tpf->numerator = 1;
@@ -795,7 +811,7 @@ static struct v4l2_mbus_framefmt *__mt9v111_get_pad_format(
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&mt9v111->sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &mt9v111->fmt;
default:
@@ -948,10 +964,10 @@ done:
return 0;
}
-static int mt9v111_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state)
+static int mt9v111_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state)
{
- sd_state->pads->try_fmt = mt9v111_def_fmt;
+ *v4l2_subdev_state_get_format(sd_state, 0) = mt9v111_def_fmt;
return 0;
}
@@ -962,17 +978,16 @@ static const struct v4l2_subdev_core_ops mt9v111_core_ops = {
static const struct v4l2_subdev_video_ops mt9v111_video_ops = {
.s_stream = mt9v111_s_stream,
- .s_frame_interval = mt9v111_s_frame_interval,
- .g_frame_interval = mt9v111_g_frame_interval,
};
static const struct v4l2_subdev_pad_ops mt9v111_pad_ops = {
- .init_cfg = mt9v111_init_cfg,
.enum_mbus_code = mt9v111_enum_mbus_code,
.enum_frame_size = mt9v111_enum_frame_size,
.enum_frame_interval = mt9v111_enum_frame_interval,
.get_fmt = mt9v111_get_format,
.set_fmt = mt9v111_set_format,
+ .get_frame_interval = mt9v111_get_frame_interval,
+ .set_frame_interval = mt9v111_set_frame_interval,
};
static const struct v4l2_subdev_ops mt9v111_ops = {
@@ -981,6 +996,10 @@ static const struct v4l2_subdev_ops mt9v111_ops = {
.pad = &mt9v111_pad_ops,
};
+static const struct v4l2_subdev_internal_ops mt9v111_internal_ops = {
+ .init_state = mt9v111_init_state,
+};
+
static const struct media_entity_operations mt9v111_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -1194,6 +1213,7 @@ static int mt9v111_probe(struct i2c_client *client)
mt9v111->pending = true;
v4l2_i2c_subdev_init(&mt9v111->sd, client, &mt9v111_ops);
+ mt9v111->sd.internal_ops = &mt9v111_internal_ops;
mt9v111->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
mt9v111->sd.entity.ops = &mt9v111_subdev_entity_ops;
diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c
index 51378ba16a5d..bac9597faf68 100644
--- a/drivers/media/i2c/og01a1b.c
+++ b/drivers/media/i2c/og01a1b.c
@@ -769,8 +769,7 @@ static int og01a1b_set_format(struct v4l2_subdev *sd,
mutex_lock(&og01a1b->mutex);
og01a1b_update_pad_format(mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state,
- fmt->pad) = fmt->format;
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
} else {
og01a1b->cur_mode = mode;
__v4l2_ctrl_s_ctrl(og01a1b->link_freq, mode->link_freq_index);
@@ -803,9 +802,8 @@ static int og01a1b_get_format(struct v4l2_subdev *sd,
mutex_lock(&og01a1b->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&og01a1b->sd,
- sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
else
og01a1b_update_pad_format(og01a1b->cur_mode, &fmt->format);
@@ -850,7 +848,7 @@ static int og01a1b_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&og01a1b->mutex);
og01a1b_update_pad_format(&supported_modes[0],
- v4l2_subdev_get_try_format(sd, fh->state, 0));
+ v4l2_subdev_state_get_format(fh->state, 0));
mutex_unlock(&og01a1b->mutex);
return 0;
diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c
index bbd5740d2280..5606437f37d0 100644
--- a/drivers/media/i2c/ov01a10.c
+++ b/drivers/media/i2c/ov01a10.c
@@ -723,14 +723,14 @@ static int ov01a10_set_format(struct v4l2_subdev *sd,
h_blank);
}
- format = v4l2_subdev_get_pad_format(sd, sd_state, fmt->stream);
+ format = v4l2_subdev_state_get_format(sd_state, fmt->stream);
*format = fmt->format;
return 0;
}
-static int ov01a10_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int ov01a10_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct v4l2_subdev_format fmt = {
.which = V4L2_SUBDEV_FORMAT_TRY,
@@ -813,7 +813,6 @@ static const struct v4l2_subdev_video_ops ov01a10_video_ops = {
};
static const struct v4l2_subdev_pad_ops ov01a10_pad_ops = {
- .init_cfg = ov01a10_init_cfg,
.set_fmt = ov01a10_set_format,
.get_fmt = v4l2_subdev_get_fmt,
.get_selection = ov01a10_get_selection,
@@ -827,6 +826,10 @@ static const struct v4l2_subdev_ops ov01a10_subdev_ops = {
.pad = &ov01a10_pad_ops,
};
+static const struct v4l2_subdev_internal_ops ov01a10_internal_ops = {
+ .init_state = ov01a10_init_state,
+};
+
static const struct media_entity_operations ov01a10_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -859,6 +862,7 @@ static void ov01a10_remove(struct i2c_client *client)
v4l2_ctrl_handler_free(sd->ctrl_handler);
pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
}
static int ov01a10_probe(struct i2c_client *client)
@@ -872,6 +876,7 @@ static int ov01a10_probe(struct i2c_client *client)
return -ENOMEM;
v4l2_i2c_subdev_init(&ov01a10->sd, client, &ov01a10_subdev_ops);
+ ov01a10->sd.internal_ops = &ov01a10_internal_ops;
ret = ov01a10_identify_module(ov01a10);
if (ret)
@@ -905,17 +910,26 @@ static int ov01a10_probe(struct i2c_client *client)
goto err_media_entity_cleanup;
}
+ /*
+ * Device is already turned on by i2c-core with ACPI domain PM.
+ * Enable runtime PM and turn off the device.
+ */
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(dev);
+ pm_runtime_idle(dev);
+
ret = v4l2_async_register_subdev_sensor(&ov01a10->sd);
if (ret < 0) {
dev_err(dev, "Failed to register subdev: %d\n", ret);
- goto err_media_entity_cleanup;
+ goto err_pm_disable;
}
- pm_runtime_enable(dev);
- pm_runtime_idle(dev);
-
return 0;
+err_pm_disable:
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(&client->dev);
+
err_media_entity_cleanup:
media_entity_cleanup(&ov01a10->sd.entity);
diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c
index 848e47a464ac..6c30e1a0d814 100644
--- a/drivers/media/i2c/ov02a10.c
+++ b/drivers/media/i2c/ov02a10.c
@@ -315,7 +315,7 @@ static int ov02a10_set_fmt(struct v4l2_subdev *sd,
ov02a10_fill_fmt(ov02a10->cur_mode, mbus_fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- frame_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ frame_fmt = v4l2_subdev_state_get_format(sd_state, 0);
else
frame_fmt = &ov02a10->fmt;
@@ -336,8 +336,8 @@ static int ov02a10_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&ov02a10->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
} else {
fmt->format = ov02a10->fmt;
mbus_fmt->code = ov02a10->fmt.code;
@@ -511,8 +511,8 @@ static int __ov02a10_stop_stream(struct ov02a10 *ov02a10)
SC_CTRL_MODE_STANDBY);
}
-static int ov02a10_entity_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int ov02a10_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = {
.which = V4L2_SUBDEV_FORMAT_TRY,
@@ -709,7 +709,6 @@ static const struct v4l2_subdev_video_ops ov02a10_video_ops = {
};
static const struct v4l2_subdev_pad_ops ov02a10_pad_ops = {
- .init_cfg = ov02a10_entity_init_cfg,
.enum_mbus_code = ov02a10_enum_mbus_code,
.enum_frame_size = ov02a10_enum_frame_sizes,
.get_fmt = ov02a10_get_fmt,
@@ -721,6 +720,10 @@ static const struct v4l2_subdev_ops ov02a10_subdev_ops = {
.pad = &ov02a10_pad_ops,
};
+static const struct v4l2_subdev_internal_ops ov02a10_internal_ops = {
+ .init_state = ov02a10_init_state,
+};
+
static const struct media_entity_operations ov02a10_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -869,6 +872,7 @@ static int ov02a10_probe(struct i2c_client *client)
"failed to check HW configuration\n");
v4l2_i2c_subdev_init(&ov02a10->subdev, client, &ov02a10_subdev_ops);
+ ov02a10->subdev.internal_ops = &ov02a10_internal_ops;
ov02a10->mipi_clock_voltage = OV02A10_MIPI_TX_SPEED_DEFAULT;
ov02a10->fmt.code = MEDIA_BUS_FMT_SBGGR10_1X10;
diff --git a/drivers/media/i2c/ov08d10.c b/drivers/media/i2c/ov08d10.c
index 3d49e3fa8e56..1bacbdfa4298 100644
--- a/drivers/media/i2c/ov08d10.c
+++ b/drivers/media/i2c/ov08d10.c
@@ -1145,7 +1145,7 @@ static int ov08d10_set_format(struct v4l2_subdev *sd,
mutex_lock(&ov08d10->mutex);
ov08d10_update_pad_format(ov08d10, mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) =
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) =
fmt->format;
} else {
ov08d10->cur_mode = mode;
@@ -1184,9 +1184,8 @@ static int ov08d10_get_format(struct v4l2_subdev *sd,
mutex_lock(&ov08d10->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&ov08d10->sd,
- sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
else
ov08d10_update_pad_format(ov08d10, ov08d10->cur_mode,
&fmt->format);
@@ -1242,7 +1241,7 @@ static int ov08d10_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&ov08d10->mutex);
ov08d10_update_pad_format(ov08d10, &ov08d10->priv_lane->sp_modes[0],
- v4l2_subdev_get_try_format(sd, fh->state, 0));
+ v4l2_subdev_state_get_format(fh->state, 0));
mutex_unlock(&ov08d10->mutex);
return 0;
diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c
index b41b6866a0ab..abbb0b774d43 100644
--- a/drivers/media/i2c/ov08x40.c
+++ b/drivers/media/i2c/ov08x40.c
@@ -2536,7 +2536,7 @@ static int ov08x40_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
const struct ov08x40_mode *default_mode = &supported_modes[0];
struct ov08x40 *ov08x = to_ov08x40(sd);
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
+ v4l2_subdev_state_get_format(fh->state, 0);
mutex_lock(&ov08x->mutex);
@@ -2774,10 +2774,9 @@ static int ov08x40_do_get_pad_format(struct ov08x40 *ov08x,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *framefmt;
- struct v4l2_subdev *sd = &ov08x->sd;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
ov08x40_update_pad_format(ov08x->cur_mode, fmt);
@@ -2826,7 +2825,7 @@ ov08x40_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
ov08x40_update_pad_format(mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
ov08x->cur_mode = mode;
diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c
index 4c419014dd7b..09387e335d80 100644
--- a/drivers/media/i2c/ov13858.c
+++ b/drivers/media/i2c/ov13858.c
@@ -1147,9 +1147,8 @@ static int ov13858_write_reg_list(struct ov13858 *ov13858,
static int ov13858_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct ov13858 *ov13858 = to_ov13858(sd);
- struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd,
- fh->state,
- 0);
+ struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_state_get_format(fh->state,
+ 0);
mutex_lock(&ov13858->mutex);
@@ -1317,10 +1316,9 @@ static int ov13858_do_get_pad_format(struct ov13858 *ov13858,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *framefmt;
- struct v4l2_subdev *sd = &ov13858->sd;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
ov13858_update_pad_format(ov13858->cur_mode, fmt);
@@ -1369,7 +1367,7 @@ ov13858_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
ov13858_update_pad_format(mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
ov13858->cur_mode = mode;
diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c
index 970d2caeb3d6..73c844aa5697 100644
--- a/drivers/media/i2c/ov13b10.c
+++ b/drivers/media/i2c/ov13b10.c
@@ -755,9 +755,8 @@ static int ov13b10_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
const struct ov13b10_mode *default_mode = &supported_modes[0];
struct ov13b10 *ov13b = to_ov13b10(sd);
- struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd,
- fh->state,
- 0);
+ struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_state_get_format(fh->state,
+ 0);
mutex_lock(&ov13b->mutex);
@@ -1002,10 +1001,9 @@ static int ov13b10_do_get_pad_format(struct ov13b10 *ov13b,
struct v4l2_subdev_format *fmt)
{
struct v4l2_mbus_framefmt *framefmt;
- struct v4l2_subdev *sd = &ov13b->sd;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
ov13b10_update_pad_format(ov13b->cur_mode, fmt);
@@ -1054,7 +1052,7 @@ ov13b10_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
ov13b10_update_pad_format(mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
ov13b->cur_mode = mode;
@@ -1556,24 +1554,27 @@ static int ov13b10_probe(struct i2c_client *client)
goto error_handler_free;
}
- ret = v4l2_async_register_subdev_sensor(&ov13b->sd);
- if (ret < 0)
- goto error_media_entity;
/*
* Device is already turned on by i2c-core with ACPI domain PM.
* Enable runtime PM and turn off the device.
*/
-
/* Set the device's state to active if it's in D0 state. */
if (full_power)
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
pm_runtime_idle(&client->dev);
+ ret = v4l2_async_register_subdev_sensor(&ov13b->sd);
+ if (ret < 0)
+ goto error_media_entity_runtime_pm;
+
return 0;
-error_media_entity:
+error_media_entity_runtime_pm:
+ pm_runtime_disable(&client->dev);
+ if (full_power)
+ pm_runtime_set_suspended(&client->dev);
media_entity_cleanup(&ov13b->sd.entity);
error_handler_free:
@@ -1596,6 +1597,7 @@ static void ov13b10_remove(struct i2c_client *client)
ov13b10_free_controls(ov13b);
pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
}
static DEFINE_RUNTIME_DEV_PM_OPS(ov13b10_pm_ops, ov13b10_suspend,
diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c
index 28a01c6eff64..67c4bd2916e8 100644
--- a/drivers/media/i2c/ov2640.c
+++ b/drivers/media/i2c/ov2640.c
@@ -920,7 +920,7 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd,
return -EINVAL;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ mf = v4l2_subdev_state_get_format(sd_state, 0);
format->format = *mf;
return 0;
}
@@ -988,7 +988,7 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd,
/* select format */
priv->cfmt_code = mf->code;
} else {
- sd_state->pads->try_fmt = *mf;
+ *v4l2_subdev_state_get_format(sd_state, 0) = *mf;
}
out:
mutex_unlock(&priv->lock);
@@ -996,11 +996,11 @@ out:
return ret;
}
-static int ov2640_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int ov2640_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, sd_state, 0);
+ v4l2_subdev_state_get_format(sd_state, 0);
const struct ov2640_win_size *win =
ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT);
@@ -1125,7 +1125,6 @@ static const struct v4l2_subdev_core_ops ov2640_subdev_core_ops = {
};
static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = {
- .init_cfg = ov2640_init_cfg,
.enum_mbus_code = ov2640_enum_mbus_code,
.get_selection = ov2640_get_selection,
.get_fmt = ov2640_get_fmt,
@@ -1142,6 +1141,10 @@ static const struct v4l2_subdev_ops ov2640_subdev_ops = {
.video = &ov2640_subdev_video_ops,
};
+static const struct v4l2_subdev_internal_ops ov2640_internal_ops = {
+ .init_state = ov2640_init_state,
+};
+
static int ov2640_probe_dt(struct i2c_client *client,
struct ov2640_priv *priv)
{
@@ -1211,6 +1214,7 @@ static int ov2640_probe(struct i2c_client *client)
priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8;
v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);
+ priv->subdev.internal_ops = &ov2640_internal_ops;
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
mutex_init(&priv->lock);
diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c
index 2c3dbe164eb6..1d0ef72a6403 100644
--- a/drivers/media/i2c/ov2659.c
+++ b/drivers/media/i2c/ov2659.c
@@ -1033,7 +1033,7 @@ static int ov2659_get_fmt(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ mf = v4l2_subdev_state_get_format(sd_state, 0);
mutex_lock(&ov2659->lock);
fmt->format = *mf;
mutex_unlock(&ov2659->lock);
@@ -1109,7 +1109,7 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd,
mutex_lock(&ov2659->lock);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*mf = fmt->format;
} else {
s64 val;
@@ -1304,7 +1304,7 @@ static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
+ v4l2_subdev_state_get_format(fh->state, 0);
dev_dbg(&client->dev, "%s:\n", __func__);
diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c
index 72bab0ff8a36..39d321e2b7f9 100644
--- a/drivers/media/i2c/ov2680.c
+++ b/drivers/media/i2c/ov2680.c
@@ -309,7 +309,7 @@ __ov2680_get_pad_format(struct ov2680_dev *sensor,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&sensor->sd, state, pad);
+ return v4l2_subdev_state_get_format(state, pad);
return &sensor->mode.fmt;
}
@@ -321,7 +321,7 @@ __ov2680_get_pad_crop(struct ov2680_dev *sensor,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&sensor->sd, state, pad);
+ return v4l2_subdev_state_get_crop(state, pad);
return &sensor->mode.crop;
}
@@ -552,11 +552,19 @@ err_disable_regulators:
return ret;
}
-static int ov2680_s_g_frame_interval(struct v4l2_subdev *sd,
+static int ov2680_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval *fi)
{
struct ov2680_dev *sensor = to_ov2680_dev(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(&sensor->lock);
fi->interval = sensor->mode.frame_interval;
mutex_unlock(&sensor->lock);
@@ -650,7 +658,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd,
ov2680_fill_format(sensor, &format->format, width, height);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- try_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ try_fmt = v4l2_subdev_state_get_format(sd_state, 0);
*try_fmt = format->format;
return 0;
}
@@ -755,14 +763,14 @@ static int ov2680_set_selection(struct v4l2_subdev *sd,
return 0;
}
-static int ov2680_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int ov2680_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct ov2680_dev *sensor = to_ov2680_dev(sd);
- sd_state->pads[0].try_crop = ov2680_default_crop;
+ *v4l2_subdev_state_get_crop(sd_state, 0) = ov2680_default_crop;
- ov2680_fill_format(sensor, &sd_state->pads[0].try_fmt,
+ ov2680_fill_format(sensor, v4l2_subdev_state_get_format(sd_state, 0),
OV2680_DEFAULT_WIDTH, OV2680_DEFAULT_HEIGHT);
return 0;
}
@@ -870,13 +878,10 @@ static const struct v4l2_ctrl_ops ov2680_ctrl_ops = {
};
static const struct v4l2_subdev_video_ops ov2680_video_ops = {
- .g_frame_interval = ov2680_s_g_frame_interval,
- .s_frame_interval = ov2680_s_g_frame_interval,
.s_stream = ov2680_s_stream,
};
static const struct v4l2_subdev_pad_ops ov2680_pad_ops = {
- .init_cfg = ov2680_init_cfg,
.enum_mbus_code = ov2680_enum_mbus_code,
.enum_frame_size = ov2680_enum_frame_size,
.enum_frame_interval = ov2680_enum_frame_interval,
@@ -884,6 +889,8 @@ static const struct v4l2_subdev_pad_ops ov2680_pad_ops = {
.set_fmt = ov2680_set_fmt,
.get_selection = ov2680_get_selection,
.set_selection = ov2680_set_selection,
+ .get_frame_interval = ov2680_get_frame_interval,
+ .set_frame_interval = ov2680_get_frame_interval,
};
static const struct v4l2_subdev_ops ov2680_subdev_ops = {
@@ -891,6 +898,10 @@ static const struct v4l2_subdev_ops ov2680_subdev_ops = {
.pad = &ov2680_pad_ops,
};
+static const struct v4l2_subdev_internal_ops ov2680_internal_ops = {
+ .init_state = ov2680_init_state,
+};
+
static int ov2680_mode_init(struct ov2680_dev *sensor)
{
/* set initial mode */
@@ -915,6 +926,7 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor)
int ret = 0;
v4l2_i2c_subdev_init(&sensor->sd, client, &ov2680_subdev_ops);
+ sensor->sd.internal_ops = &ov2680_internal_ops;
sensor->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c
index 396583826ae9..9b8481b8dcd4 100644
--- a/drivers/media/i2c/ov2685.c
+++ b/drivers/media/i2c/ov2685.c
@@ -404,7 +404,7 @@ __ov2685_get_pad_crop(struct ov2685 *ov2685,
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&ov2685->subdev, state, pad);
+ return v4l2_subdev_state_get_crop(state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return mode->analog_crop;
}
@@ -547,7 +547,7 @@ static int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&ov2685->mutex);
- try_fmt = v4l2_subdev_get_try_format(sd, fh->state, 0);
+ try_fmt = v4l2_subdev_state_get_format(fh->state, 0);
/* Initialize try_fmt */
ov2685_fill_fmt(&supported_modes[0], try_fmt);
diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c
index 24e468485fbf..552935ccb4a9 100644
--- a/drivers/media/i2c/ov2740.c
+++ b/drivers/media/i2c/ov2740.c
@@ -3,7 +3,9 @@
#include <asm/unaligned.h>
#include <linux/acpi.h>
+#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
@@ -14,6 +16,7 @@
#include <media/v4l2-fwnode.h>
#define OV2740_LINK_FREQ_360MHZ 360000000ULL
+#define OV2740_LINK_FREQ_180MHZ 180000000ULL
#define OV2740_SCLK 72000000LL
#define OV2740_MCLK 19200000
#define OV2740_DATA_LANES 2
@@ -28,9 +31,6 @@
/* vertical-timings from sensor */
#define OV2740_REG_VTS 0x380e
-#define OV2740_VTS_DEF 0x088a
-#define OV2740_VTS_MIN 0x0460
-#define OV2740_VTS_MAX 0x7fff
/* horizontal-timings from sensor */
#define OV2740_REG_HTS 0x380c
@@ -84,6 +84,7 @@ struct nvm_data {
enum {
OV2740_LINK_FREQ_360MHZ_INDEX,
+ OV2740_LINK_FREQ_180MHZ_INDEX,
};
struct ov2740_reg {
@@ -116,6 +117,9 @@ struct ov2740_mode {
/* Min vertical timining size */
u32 vts_min;
+ /* Max vertical timining size */
+ u32 vts_max;
+
/* Link frequency needed for this resolution */
u32 link_freq_index;
@@ -124,7 +128,6 @@ struct ov2740_mode {
};
static const struct ov2740_reg mipi_data_rate_720mbps[] = {
- {0x0103, 0x01},
{0x0302, 0x4b},
{0x030d, 0x4b},
{0x030e, 0x02},
@@ -132,7 +135,17 @@ static const struct ov2740_reg mipi_data_rate_720mbps[] = {
{0x0312, 0x11},
};
-static const struct ov2740_reg mode_1932x1092_regs[] = {
+static const struct ov2740_reg mipi_data_rate_360mbps[] = {
+ {0x0302, 0x4b},
+ {0x0303, 0x01},
+ {0x030d, 0x4b},
+ {0x030e, 0x02},
+ {0x030a, 0x01},
+ {0x0312, 0x11},
+ {0x4837, 0x2c},
+};
+
+static const struct ov2740_reg mode_1932x1092_regs_360mhz[] = {
{0x3000, 0x00},
{0x3018, 0x32},
{0x3031, 0x0a},
@@ -285,6 +298,159 @@ static const struct ov2740_reg mode_1932x1092_regs[] = {
{0x3813, 0x01},
};
+static const struct ov2740_reg mode_1932x1092_regs_180mhz[] = {
+ {0x3000, 0x00},
+ {0x3018, 0x32}, /* 0x32 for 2 lanes, 0x12 for 1 lane */
+ {0x3031, 0x0a},
+ {0x3080, 0x08},
+ {0x3083, 0xB4},
+ {0x3103, 0x00},
+ {0x3104, 0x01},
+ {0x3106, 0x01},
+ {0x3500, 0x00},
+ {0x3501, 0x44},
+ {0x3502, 0x40},
+ {0x3503, 0x88},
+ {0x3507, 0x00},
+ {0x3508, 0x00},
+ {0x3509, 0x80},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x3510, 0x00},
+ {0x3511, 0x00},
+ {0x3512, 0x20},
+ {0x3632, 0x00},
+ {0x3633, 0x10},
+ {0x3634, 0x10},
+ {0x3635, 0x10},
+ {0x3645, 0x13},
+ {0x3646, 0x81},
+ {0x3636, 0x10},
+ {0x3651, 0x0a},
+ {0x3656, 0x02},
+ {0x3659, 0x04},
+ {0x365a, 0xda},
+ {0x365b, 0xa2},
+ {0x365c, 0x04},
+ {0x365d, 0x1d},
+ {0x365e, 0x1a},
+ {0x3662, 0xd7},
+ {0x3667, 0x78},
+ {0x3669, 0x0a},
+ {0x366a, 0x92},
+ {0x3700, 0x54},
+ {0x3702, 0x10},
+ {0x3706, 0x42},
+ {0x3709, 0x30},
+ {0x370b, 0xc2},
+ {0x3714, 0x63},
+ {0x3715, 0x01},
+ {0x3716, 0x00},
+ {0x371a, 0x3e},
+ {0x3732, 0x0e},
+ {0x3733, 0x10},
+ {0x375f, 0x0e},
+ {0x3768, 0x30},
+ {0x3769, 0x44},
+ {0x376a, 0x22},
+ {0x377b, 0x20},
+ {0x377c, 0x00},
+ {0x377d, 0x0c},
+ {0x3798, 0x00},
+ {0x37a1, 0x55},
+ {0x37a8, 0x6d},
+ {0x37c2, 0x04},
+ {0x37c5, 0x00},
+ {0x37c8, 0x00},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x07},
+ {0x3805, 0x8f},
+ {0x3806, 0x04},
+ {0x3807, 0x47},
+ {0x3808, 0x07},
+ {0x3809, 0x88},
+ {0x380a, 0x04},
+ {0x380b, 0x40},
+ {0x380c, 0x08},
+ {0x380d, 0x70},
+ {0x380e, 0x04},
+ {0x380f, 0x56},
+ {0x3810, 0x00},
+ {0x3811, 0x04},
+ {0x3812, 0x00},
+ {0x3813, 0x04},
+ {0x3814, 0x01},
+ {0x3815, 0x01},
+ {0x3820, 0x80},
+ {0x3821, 0x46},
+ {0x3822, 0x84},
+ {0x3829, 0x00},
+ {0x382a, 0x01},
+ {0x382b, 0x01},
+ {0x3830, 0x04},
+ {0x3836, 0x01},
+ {0x3837, 0x08},
+ {0x3839, 0x01},
+ {0x383a, 0x00},
+ {0x383b, 0x08},
+ {0x383c, 0x00},
+ {0x3f0b, 0x00},
+ {0x4001, 0x20},
+ {0x4009, 0x07},
+ {0x4003, 0x10},
+ {0x4010, 0xe0},
+ {0x4016, 0x00},
+ {0x4017, 0x10},
+ {0x4044, 0x02},
+ {0x4304, 0x08},
+ {0x4307, 0x30},
+ {0x4320, 0x80},
+ {0x4322, 0x00},
+ {0x4323, 0x00},
+ {0x4324, 0x00},
+ {0x4325, 0x00},
+ {0x4326, 0x00},
+ {0x4327, 0x00},
+ {0x4328, 0x00},
+ {0x4329, 0x00},
+ {0x432c, 0x03},
+ {0x432d, 0x81},
+ {0x4501, 0x84},
+ {0x4502, 0x40},
+ {0x4503, 0x18},
+ {0x4504, 0x04},
+ {0x4508, 0x02},
+ {0x4601, 0x10},
+ {0x4800, 0x00},
+ {0x4816, 0x52},
+ {0x5000, 0x73}, /* 0x7f enable DPC */
+ {0x5001, 0x00},
+ {0x5005, 0x38},
+ {0x501e, 0x0d},
+ {0x5040, 0x00},
+ {0x5901, 0x00},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x07},
+ {0x3805, 0x8f},
+ {0x3806, 0x04},
+ {0x3807, 0x47},
+ {0x3808, 0x07},
+ {0x3809, 0x8c},
+ {0x380a, 0x04},
+ {0x380b, 0x44},
+ {0x3810, 0x00},
+ {0x3811, 0x00},
+ {0x3812, 0x00},
+ {0x3813, 0x01},
+ {0x4003, 0x40}, /* set Black level to 0x40 */
+};
+
static const char * const ov2740_test_pattern_menu[] = {
"Disabled",
"Color Bar",
@@ -295,6 +461,7 @@ static const char * const ov2740_test_pattern_menu[] = {
static const s64 link_freq_menu_items[] = {
OV2740_LINK_FREQ_360MHZ,
+ OV2740_LINK_FREQ_180MHZ,
};
static const struct ov2740_link_freq_config link_freq_configs[] = {
@@ -304,23 +471,46 @@ static const struct ov2740_link_freq_config link_freq_configs[] = {
.regs = mipi_data_rate_720mbps,
}
},
+ [OV2740_LINK_FREQ_180MHZ_INDEX] = {
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mipi_data_rate_360mbps),
+ .regs = mipi_data_rate_360mbps,
+ }
+ },
};
-static const struct ov2740_mode supported_modes[] = {
+static const struct ov2740_mode supported_modes_360mhz[] = {
{
.width = 1932,
.height = 1092,
- .hts = 1080,
- .vts_def = OV2740_VTS_DEF,
- .vts_min = OV2740_VTS_MIN,
+ .hts = 2160,
+ .vts_min = 1120,
+ .vts_def = 2186,
+ .vts_max = 32767,
.reg_list = {
- .num_of_regs = ARRAY_SIZE(mode_1932x1092_regs),
- .regs = mode_1932x1092_regs,
+ .num_of_regs = ARRAY_SIZE(mode_1932x1092_regs_360mhz),
+ .regs = mode_1932x1092_regs_360mhz,
},
.link_freq_index = OV2740_LINK_FREQ_360MHZ_INDEX,
},
};
+static const struct ov2740_mode supported_modes_180mhz[] = {
+ {
+ .width = 1932,
+ .height = 1092,
+ .hts = 2160,
+ .vts_min = 1110,
+ .vts_def = 1110,
+ .vts_max = 2047,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1932x1092_regs_180mhz),
+ .regs = mode_1932x1092_regs_180mhz,
+ },
+ .link_freq_index = OV2740_LINK_FREQ_180MHZ_INDEX,
+ },
+};
+
struct ov2740 {
struct v4l2_subdev sd;
struct media_pad pad;
@@ -333,12 +523,20 @@ struct ov2740 {
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *exposure;
+ /* GPIOs, clocks */
+ struct gpio_desc *reset_gpio;
+ struct clk *clk;
+
/* Current mode */
const struct ov2740_mode *cur_mode;
/* NVM data inforamtion */
struct nvm_data *nvm;
+ /* Supported modes */
+ const struct ov2740_mode *supported_modes;
+ int supported_modes_count;
+
/* True if the device has been identified */
bool identified;
};
@@ -357,15 +555,6 @@ static u64 to_pixel_rate(u32 f_index)
return pixel_rate;
}
-static u64 to_pixels_per_line(u32 hts, u32 f_index)
-{
- u64 ppl = hts * to_pixel_rate(f_index);
-
- do_div(ppl, OV2740_SCLK);
-
- return ppl;
-}
-
static int ov2740_read_reg(struct ov2740 *ov2740, u16 reg, u16 len, u32 *val)
{
struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd);
@@ -592,14 +781,13 @@ static int ov2740_init_controls(struct ov2740 *ov2740)
pixel_rate, 1, pixel_rate);
vblank_min = cur_mode->vts_min - cur_mode->height;
- vblank_max = OV2740_VTS_MAX - cur_mode->height;
+ vblank_max = cur_mode->vts_max - cur_mode->height;
vblank_default = cur_mode->vts_def - cur_mode->height;
ov2740->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops,
V4L2_CID_VBLANK, vblank_min,
vblank_max, 1, vblank_default);
- h_blank = to_pixels_per_line(cur_mode->hts, cur_mode->link_freq_index);
- h_blank -= cur_mode->width;
+ h_blank = cur_mode->hts - cur_mode->width;
ov2740->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops,
V4L2_CID_HBLANK, h_blank, h_blank, 1,
h_blank);
@@ -745,6 +933,15 @@ static int ov2740_start_streaming(struct ov2740 *ov2740)
if (ov2740->nvm)
ov2740_load_otp_data(ov2740->nvm);
+ /* Reset the sensor */
+ ret = ov2740_write_reg(ov2740, 0x0103, 1, 0x01);
+ if (ret) {
+ dev_err(&client->dev, "failed to reset\n");
+ return ret;
+ }
+
+ usleep_range(10000, 15000);
+
link_freq_index = ov2740->cur_mode->link_freq_index;
reg_list = &link_freq_configs[link_freq_index].reg_list;
ret = ov2740_write_reg_list(ov2740, reg_list);
@@ -820,13 +1017,13 @@ static int ov2740_set_format(struct v4l2_subdev *sd,
const struct ov2740_mode *mode;
s32 vblank_def, h_blank;
- mode = v4l2_find_nearest_size(supported_modes,
- ARRAY_SIZE(supported_modes), width,
- height, fmt->format.width,
- fmt->format.height);
+ mode = v4l2_find_nearest_size(ov2740->supported_modes,
+ ov2740->supported_modes_count,
+ width, height,
+ fmt->format.width, fmt->format.height);
ov2740_update_pad_format(mode, &fmt->format);
- *v4l2_subdev_get_pad_format(sd, sd_state, fmt->pad) = fmt->format;
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
@@ -840,10 +1037,9 @@ static int ov2740_set_format(struct v4l2_subdev *sd,
vblank_def = mode->vts_def - mode->height;
__v4l2_ctrl_modify_range(ov2740->vblank,
mode->vts_min - mode->height,
- OV2740_VTS_MAX - mode->height, 1, vblank_def);
+ mode->vts_max - mode->height, 1, vblank_def);
__v4l2_ctrl_s_ctrl(ov2740->vblank, vblank_def);
- h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) -
- mode->width;
+ h_blank = mode->hts - mode->width;
__v4l2_ctrl_modify_range(ov2740->hblank, h_blank, h_blank, 1, h_blank);
return 0;
@@ -865,7 +1061,10 @@ static int ov2740_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
- if (fse->index >= ARRAY_SIZE(supported_modes))
+ struct ov2740 *ov2740 = to_ov2740(sd);
+ const struct ov2740_mode *supported_modes = ov2740->supported_modes;
+
+ if (fse->index >= ov2740->supported_modes_count)
return -EINVAL;
if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
@@ -879,12 +1078,13 @@ static int ov2740_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-static int ov2740_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int ov2740_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
- ov2740_update_pad_format(&supported_modes[0],
- v4l2_subdev_get_pad_format(sd, sd_state, 0));
+ struct ov2740 *ov2740 = to_ov2740(sd);
+ ov2740_update_pad_format(&ov2740->supported_modes[0],
+ v4l2_subdev_state_get_format(sd_state, 0));
return 0;
}
@@ -897,7 +1097,6 @@ static const struct v4l2_subdev_pad_ops ov2740_pad_ops = {
.set_fmt = ov2740_set_format,
.enum_mbus_code = ov2740_enum_mbus_code,
.enum_frame_size = ov2740_enum_frame_size,
- .init_cfg = ov2740_init_cfg,
};
static const struct v4l2_subdev_ops ov2740_subdev_ops = {
@@ -905,12 +1104,18 @@ static const struct v4l2_subdev_ops ov2740_subdev_ops = {
.pad = &ov2740_pad_ops,
};
+static const struct v4l2_subdev_internal_ops ov2740_internal_ops = {
+ .init_state = ov2740_init_state,
+};
+
static const struct media_entity_operations ov2740_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
static int ov2740_check_hwcfg(struct device *dev)
{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov2740 *ov2740 = to_ov2740(sd);
struct fwnode_handle *ep;
struct fwnode_handle *fwnode = dev_fwnode(dev);
struct v4l2_fwnode_endpoint bus_cfg = {
@@ -920,23 +1125,32 @@ static int ov2740_check_hwcfg(struct device *dev)
int ret;
unsigned int i, j;
+ /*
+ * Sometimes the fwnode graph is initialized by the bridge driver,
+ * wait for this.
+ */
+ ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
+ if (!ep)
+ return -EPROBE_DEFER;
+
ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk);
- if (ret)
- return ret;
+ if (ret) {
+ fwnode_handle_put(ep);
+ return dev_err_probe(dev, ret,
+ "reading clock-frequency property\n");
+ }
- if (mclk != OV2740_MCLK)
+ if (mclk != OV2740_MCLK) {
+ fwnode_handle_put(ep);
return dev_err_probe(dev, -EINVAL,
"external clock %d is not supported\n",
mclk);
-
- ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
- if (!ep)
- return -EPROBE_DEFER;
+ }
ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
fwnode_handle_put(ep);
if (ret)
- return ret;
+ return dev_err_probe(dev, ret, "parsing endpoint failed\n");
if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV2740_DATA_LANES) {
ret = dev_err_probe(dev, -EINVAL,
@@ -957,14 +1171,29 @@ static int ov2740_check_hwcfg(struct device *dev)
break;
}
- if (j == bus_cfg.nr_of_link_frequencies) {
- ret = dev_err_probe(dev, -EINVAL,
- "no link frequency %lld supported\n",
- link_freq_menu_items[i]);
- goto check_hwcfg_error;
+ if (j == bus_cfg.nr_of_link_frequencies)
+ continue;
+
+ switch (i) {
+ case OV2740_LINK_FREQ_360MHZ_INDEX:
+ ov2740->supported_modes = supported_modes_360mhz;
+ ov2740->supported_modes_count =
+ ARRAY_SIZE(supported_modes_360mhz);
+ break;
+ case OV2740_LINK_FREQ_180MHZ_INDEX:
+ ov2740->supported_modes = supported_modes_180mhz;
+ ov2740->supported_modes_count =
+ ARRAY_SIZE(supported_modes_180mhz);
+ break;
}
+
+ break; /* Prefer modes from first available link-freq */
}
+ if (!ov2740->supported_modes)
+ ret = dev_err_probe(dev, -EINVAL,
+ "no supported link frequencies\n");
+
check_hwcfg_error:
v4l2_fwnode_endpoint_free(&bus_cfg);
@@ -1058,6 +1287,32 @@ static int ov2740_register_nvmem(struct i2c_client *client,
return 0;
}
+static int ov2740_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov2740 *ov2740 = to_ov2740(sd);
+
+ gpiod_set_value_cansleep(ov2740->reset_gpio, 1);
+ clk_disable_unprepare(ov2740->clk);
+ return 0;
+}
+
+static int ov2740_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov2740 *ov2740 = to_ov2740(sd);
+ int ret;
+
+ ret = clk_prepare_enable(ov2740->clk);
+ if (ret)
+ return ret;
+
+ gpiod_set_value_cansleep(ov2740->reset_gpio, 0);
+ msleep(20);
+
+ return 0;
+}
+
static int ov2740_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -1065,23 +1320,42 @@ static int ov2740_probe(struct i2c_client *client)
bool full_power;
int ret;
- ret = ov2740_check_hwcfg(&client->dev);
- if (ret)
- return dev_err_probe(dev, ret, "failed to check HW configuration\n");
-
ov2740 = devm_kzalloc(&client->dev, sizeof(*ov2740), GFP_KERNEL);
if (!ov2740)
return -ENOMEM;
v4l2_i2c_subdev_init(&ov2740->sd, client, &ov2740_subdev_ops);
+ ov2740->sd.internal_ops = &ov2740_internal_ops;
+
+ ret = ov2740_check_hwcfg(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to check HW configuration\n");
+
+ ov2740->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(ov2740->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ov2740->reset_gpio),
+ "failed to get reset GPIO\n");
+
+ ov2740->clk = devm_clk_get_optional(dev, "clk");
+ if (IS_ERR(ov2740->clk))
+ return dev_err_probe(dev, PTR_ERR(ov2740->clk),
+ "failed to get clock\n");
+
full_power = acpi_dev_state_d0(&client->dev);
if (full_power) {
- ret = ov2740_identify_module(ov2740);
+ /* ACPI does not always clear the reset GPIO / enable the clock */
+ ret = ov2740_resume(dev);
if (ret)
- return dev_err_probe(dev, ret, "failed to find sensor\n");
+ return dev_err_probe(dev, ret, "failed to power on sensor\n");
+
+ ret = ov2740_identify_module(ov2740);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to find sensor\n");
+ goto probe_error_power_off;
+ }
}
- ov2740->cur_mode = &supported_modes[0];
+ ov2740->cur_mode = &ov2740->supported_modes[0];
ret = ov2740_init_controls(ov2740);
if (ret) {
dev_err_probe(dev, ret, "failed to init controls\n");
@@ -1132,9 +1406,16 @@ probe_error_media_entity_cleanup:
probe_error_v4l2_ctrl_handler_free:
v4l2_ctrl_handler_free(ov2740->sd.ctrl_handler);
+probe_error_power_off:
+ if (full_power)
+ ov2740_suspend(dev);
+
return ret;
}
+static DEFINE_RUNTIME_DEV_PM_OPS(ov2740_pm_ops, ov2740_suspend, ov2740_resume,
+ NULL);
+
static const struct acpi_device_id ov2740_acpi_ids[] = {
{"INT3474"},
{}
@@ -1146,6 +1427,7 @@ static struct i2c_driver ov2740_i2c_driver = {
.driver = {
.name = "ov2740",
.acpi_match_table = ov2740_acpi_ids,
+ .pm = pm_sleep_ptr(&ov2740_pm_ops),
},
.probe = ov2740_probe,
.remove = ov2740_remove,
diff --git a/drivers/media/i2c/ov4689.c b/drivers/media/i2c/ov4689.c
index 3bd972a822e7..403091651885 100644
--- a/drivers/media/i2c/ov4689.c
+++ b/drivers/media/i2c/ov4689.c
@@ -570,7 +570,7 @@ static int ov4689_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&ov4689->mutex);
- try_fmt = v4l2_subdev_get_try_format(sd, fh->state, 0);
+ try_fmt = v4l2_subdev_state_get_format(fh->state, 0);
/* Initialize try_fmt */
ov4689_fill_fmt(&supported_modes[OV4689_MODE_2688_1520], try_fmt);
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 40532f7bcabe..5162d45fe73b 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -399,7 +399,7 @@ struct ov5640_mode_info {
const struct reg_value *reg_data;
u32 reg_data_size;
- /* Used by s_frame_interval only. */
+ /* Used by set_frame_interval only. */
u32 max_fps;
u32 def_fps;
};
@@ -2797,8 +2797,7 @@ static int ov5640_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&sensor->lock);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
- format->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
else
fmt = &sensor->fmt;
@@ -2971,7 +2970,7 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd,
goto out;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
+ *v4l2_subdev_state_get_format(sd_state, 0) = *mbus_fmt;
goto out;
}
@@ -3605,11 +3604,19 @@ static int ov5640_enum_frame_interval(
return 0;
}
-static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int ov5640_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct ov5640_dev *sensor = to_ov5640_dev(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(&sensor->lock);
fi->interval = sensor->frame_interval;
mutex_unlock(&sensor->lock);
@@ -3617,13 +3624,21 @@ static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int ov5640_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct ov5640_dev *sensor = to_ov5640_dev(sd);
const struct ov5640_mode_info *mode;
int frame_rate, ret = 0;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (fi->pad != 0)
return -EINVAL;
@@ -3745,13 +3760,13 @@ out:
return ret;
}
-static int ov5640_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int ov5640_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct ov5640_dev *sensor = to_ov5640_dev(sd);
struct v4l2_mbus_framefmt *fmt =
- v4l2_subdev_get_try_format(sd, state, 0);
- struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
+ v4l2_subdev_state_get_format(state, 0);
+ struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0);
*fmt = ov5640_is_csi2(sensor) ? ov5640_csi2_default_fmt :
ov5640_dvp_default_fmt;
@@ -3771,17 +3786,16 @@ static const struct v4l2_subdev_core_ops ov5640_core_ops = {
};
static const struct v4l2_subdev_video_ops ov5640_video_ops = {
- .g_frame_interval = ov5640_g_frame_interval,
- .s_frame_interval = ov5640_s_frame_interval,
.s_stream = ov5640_s_stream,
};
static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
- .init_cfg = ov5640_init_cfg,
.enum_mbus_code = ov5640_enum_mbus_code,
.get_fmt = ov5640_get_fmt,
.set_fmt = ov5640_set_fmt,
.get_selection = ov5640_get_selection,
+ .get_frame_interval = ov5640_get_frame_interval,
+ .set_frame_interval = ov5640_set_frame_interval,
.enum_frame_size = ov5640_enum_frame_size,
.enum_frame_interval = ov5640_enum_frame_interval,
};
@@ -3792,6 +3806,10 @@ static const struct v4l2_subdev_ops ov5640_subdev_ops = {
.pad = &ov5640_pad_ops,
};
+static const struct v4l2_subdev_internal_ops ov5640_internal_ops = {
+ .init_state = ov5640_init_state,
+};
+
static int ov5640_get_regulators(struct ov5640_dev *sensor)
{
int i;
@@ -3906,6 +3924,7 @@ static int ov5640_probe(struct i2c_client *client)
return PTR_ERR(sensor->reset_gpio);
v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
+ sensor->sd.internal_ops = &ov5640_internal_ops;
sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c
index a70db7e601a4..a26ac11c989d 100644
--- a/drivers/media/i2c/ov5645.c
+++ b/drivers/media/i2c/ov5645.c
@@ -851,7 +851,7 @@ __ov5645_get_pad_format(struct ov5645 *ov5645,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&ov5645->sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov5645->fmt;
default:
@@ -878,7 +878,7 @@ __ov5645_get_pad_crop(struct ov5645 *ov5645,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&ov5645->sd, sd_state, pad);
+ return v4l2_subdev_state_get_crop(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov5645->crop;
default:
@@ -934,8 +934,8 @@ static int ov5645_set_format(struct v4l2_subdev *sd,
return 0;
}
-static int ov5645_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state)
+static int ov5645_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = { 0 };
@@ -1023,7 +1023,6 @@ static const struct v4l2_subdev_video_ops ov5645_video_ops = {
};
static const struct v4l2_subdev_pad_ops ov5645_subdev_pad_ops = {
- .init_cfg = ov5645_entity_init_cfg,
.enum_mbus_code = ov5645_enum_mbus_code,
.enum_frame_size = ov5645_enum_frame_size,
.get_fmt = ov5645_get_format,
@@ -1036,6 +1035,10 @@ static const struct v4l2_subdev_ops ov5645_subdev_ops = {
.pad = &ov5645_subdev_pad_ops,
};
+static const struct v4l2_subdev_internal_ops ov5645_internal_ops = {
+ .init_state = ov5645_init_state,
+};
+
static int ov5645_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -1162,6 +1165,7 @@ static int ov5645_probe(struct i2c_client *client)
}
v4l2_i2c_subdev_init(&ov5645->sd, client, &ov5645_subdev_ops);
+ ov5645->sd.internal_ops = &ov5645_internal_ops;
ov5645->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
ov5645->pad.flags = MEDIA_PAD_FL_SOURCE;
ov5645->sd.dev = &client->dev;
@@ -1220,7 +1224,7 @@ static int ov5645_probe(struct i2c_client *client)
pm_runtime_get_noresume(dev);
pm_runtime_enable(dev);
- ov5645_entity_init_cfg(&ov5645->sd, NULL);
+ ov5645_init_state(&ov5645->sd, NULL);
ret = v4l2_async_register_subdev(&ov5645->sd);
if (ret < 0) {
diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index dcfe3129c63a..96c0fd4ff5ab 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -882,7 +882,7 @@ __ov5647_get_pad_crop(struct ov5647 *ov5647,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&ov5647->sd, sd_state, pad);
+ return v4l2_subdev_state_get_crop(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov5647->mode->crop;
}
@@ -975,8 +975,8 @@ static int ov5647_get_pad_fmt(struct v4l2_subdev *sd,
mutex_lock(&sensor->lock);
switch (format->which) {
case V4L2_SUBDEV_FORMAT_TRY:
- sensor_format = v4l2_subdev_get_try_format(sd, sd_state,
- format->pad);
+ sensor_format = v4l2_subdev_state_get_format(sd_state,
+ format->pad);
break;
default:
sensor_format = &sensor->mode->format;
@@ -1004,7 +1004,7 @@ static int ov5647_set_pad_fmt(struct v4l2_subdev *sd,
/* Update the sensor mode and apply at it at streamon time. */
mutex_lock(&sensor->lock);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, format->pad) = mode->format;
+ *v4l2_subdev_state_get_format(sd_state, format->pad) = mode->format;
} else {
int exposure_max, exposure_def;
int hblank, vblank;
@@ -1121,8 +1121,8 @@ static int ov5647_detect(struct v4l2_subdev *sd)
static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *format =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
- struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->state, 0);
+ v4l2_subdev_state_get_format(fh->state, 0);
+ struct v4l2_rect *crop = v4l2_subdev_state_get_crop(fh->state, 0);
crop->left = OV5647_PIXEL_ARRAY_LEFT;
crop->top = OV5647_PIXEL_ARRAY_TOP;
diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c
index aa10eb4e3991..4b86d2631bd1 100644
--- a/drivers/media/i2c/ov5648.c
+++ b/drivers/media/i2c/ov5648.c
@@ -2158,37 +2158,8 @@ static int ov5648_s_stream(struct v4l2_subdev *subdev, int enable)
return 0;
}
-static int ov5648_g_frame_interval(struct v4l2_subdev *subdev,
- struct v4l2_subdev_frame_interval *interval)
-{
- struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
- const struct ov5648_mode *mode;
- int ret = 0;
-
- mutex_lock(&sensor->mutex);
-
- mode = sensor->state.mode;
-
- switch (sensor->state.mbus_code) {
- case MEDIA_BUS_FMT_SBGGR8_1X8:
- interval->interval = mode->frame_interval[0];
- break;
- case MEDIA_BUS_FMT_SBGGR10_1X10:
- interval->interval = mode->frame_interval[1];
- break;
- default:
- ret = -EINVAL;
- }
-
- mutex_unlock(&sensor->mutex);
-
- return ret;
-}
-
static const struct v4l2_subdev_video_ops ov5648_subdev_video_ops = {
.s_stream = ov5648_s_stream,
- .g_frame_interval = ov5648_g_frame_interval,
- .s_frame_interval = ov5648_g_frame_interval,
};
/* Subdev Pad Operations */
@@ -2232,8 +2203,8 @@ static int ov5648_get_fmt(struct v4l2_subdev *subdev,
mutex_lock(&sensor->mutex);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *mbus_format = *v4l2_subdev_get_try_format(subdev, sd_state,
- format->pad);
+ *mbus_format = *v4l2_subdev_state_get_format(sd_state,
+ format->pad);
else
ov5648_mbus_format_fill(mbus_format, sensor->state.mbus_code,
sensor->state.mode);
@@ -2285,7 +2256,7 @@ static int ov5648_set_fmt(struct v4l2_subdev *subdev,
ov5648_mbus_format_fill(mbus_format, mbus_code, mode);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *v4l2_subdev_get_try_format(subdev, sd_state, format->pad) =
+ *v4l2_subdev_state_get_format(sd_state, format->pad) =
*mbus_format;
else if (sensor->state.mode != mode ||
sensor->state.mbus_code != mbus_code)
@@ -2297,6 +2268,41 @@ complete:
return ret;
}
+static int ov5648_get_frame_interval(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *interval)
+{
+ struct ov5648_sensor *sensor = ov5648_subdev_sensor(subdev);
+ const struct ov5648_mode *mode;
+ int ret = 0;
+
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ mutex_lock(&sensor->mutex);
+
+ mode = sensor->state.mode;
+
+ switch (sensor->state.mbus_code) {
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ interval->interval = mode->frame_interval[0];
+ break;
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ interval->interval = mode->frame_interval[1];
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&sensor->mutex);
+
+ return ret;
+}
+
static int ov5648_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *size_enum)
@@ -2363,6 +2369,8 @@ static const struct v4l2_subdev_pad_ops ov5648_subdev_pad_ops = {
.enum_mbus_code = ov5648_enum_mbus_code,
.get_fmt = ov5648_get_fmt,
.set_fmt = ov5648_set_fmt,
+ .get_frame_interval = ov5648_get_frame_interval,
+ .set_frame_interval = ov5648_get_frame_interval,
.enum_frame_size = ov5648_enum_frame_size,
.enum_frame_interval = ov5648_enum_frame_interval,
};
diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index e80db3ecd4f8..2aee85965cf7 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -2196,13 +2196,13 @@ error:
return ret;
}
-static int ov5670_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int ov5670_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct v4l2_mbus_framefmt *fmt =
- v4l2_subdev_get_try_format(sd, state, 0);
+ v4l2_subdev_state_get_format(state, 0);
const struct ov5670_mode *default_mode = &supported_modes[0];
- struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
+ struct v4l2_rect *crop = v4l2_subdev_state_get_crop(state, 0);
fmt->width = default_mode->width;
fmt->height = default_mode->height;
@@ -2263,9 +2263,8 @@ static int ov5670_do_get_pad_format(struct ov5670 *ov5670,
struct v4l2_subdev_format *fmt)
{
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&ov5670->sd,
- sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
else
ov5670_update_pad_format(ov5670->cur_mode, fmt);
@@ -2310,7 +2309,7 @@ static int ov5670_set_pad_format(struct v4l2_subdev *sd,
fmt->format.width, fmt->format.height);
ov5670_update_pad_format(mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
} else {
ov5670->cur_mode = mode;
__v4l2_ctrl_s_ctrl(ov5670->link_freq, mode->link_freq_index);
@@ -2550,7 +2549,7 @@ __ov5670_get_pad_crop(struct ov5670 *sensor, struct v4l2_subdev_state *state,
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&sensor->sd, state, pad);
+ return v4l2_subdev_state_get_crop(state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return mode->analog_crop;
}
@@ -2593,7 +2592,6 @@ static const struct v4l2_subdev_video_ops ov5670_video_ops = {
};
static const struct v4l2_subdev_pad_ops ov5670_pad_ops = {
- .init_cfg = ov5670_init_cfg,
.enum_mbus_code = ov5670_enum_mbus_code,
.get_fmt = ov5670_get_pad_format,
.set_fmt = ov5670_set_pad_format,
@@ -2613,6 +2611,10 @@ static const struct v4l2_subdev_ops ov5670_subdev_ops = {
.sensor = &ov5670_sensor_ops,
};
+static const struct v4l2_subdev_internal_ops ov5670_internal_ops = {
+ .init_state = ov5670_init_state,
+};
+
static const struct media_entity_operations ov5670_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -2676,6 +2678,7 @@ static int ov5670_probe(struct i2c_client *client)
/* Initialize subdev */
v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops);
+ ov5670->sd.internal_ops = &ov5670_internal_ops;
ret = ov5670_regulators_probe(ov5670);
if (ret)
diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c
index e63d9d402d34..3641911bc73f 100644
--- a/drivers/media/i2c/ov5675.c
+++ b/drivers/media/i2c/ov5675.c
@@ -1036,7 +1036,7 @@ static int ov5675_set_format(struct v4l2_subdev *sd,
mutex_lock(&ov5675->mutex);
ov5675_update_pad_format(mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
} else {
ov5675->cur_mode = mode;
__v4l2_ctrl_s_ctrl(ov5675->link_freq, mode->link_freq_index);
@@ -1069,9 +1069,8 @@ static int ov5675_get_format(struct v4l2_subdev *sd,
mutex_lock(&ov5675->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&ov5675->sd,
- sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
else
ov5675_update_pad_format(ov5675->cur_mode, &fmt->format);
@@ -1141,7 +1140,7 @@ static int ov5675_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&ov5675->mutex);
ov5675_update_pad_format(&supported_modes[0],
- v4l2_subdev_get_try_format(sd, fh->state, 0));
+ v4l2_subdev_state_get_format(fh->state, 0));
mutex_unlock(&ov5675->mutex);
return 0;
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 819425e21349..8deb28b55983 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -775,7 +775,7 @@ __ov5693_get_pad_format(struct ov5693_device *ov5693,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&ov5693->sd, state, pad);
+ return v4l2_subdev_state_get_format(state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov5693->mode.format;
default:
@@ -790,7 +790,7 @@ __ov5693_get_pad_crop(struct ov5693_device *ov5693,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&ov5693->sd, state, pad);
+ return v4l2_subdev_state_get_crop(state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov5693->mode.crop;
}
@@ -1004,14 +1004,22 @@ err_power_down:
return ret;
}
-static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval)
+static int ov5693_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *interval)
{
struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
unsigned int framesize = OV5693_FIXED_PPL * (ov5693->mode.format.height +
ov5693->ctrls.vblank->val);
unsigned int fps = DIV_ROUND_CLOSEST(OV5693_PIXEL_RATE, framesize);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
interval->interval.numerator = 1;
interval->interval.denominator = fps;
@@ -1054,7 +1062,6 @@ static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops ov5693_video_ops = {
.s_stream = ov5693_s_stream,
- .g_frame_interval = ov5693_g_frame_interval,
};
static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
@@ -1064,6 +1071,7 @@ static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
.set_fmt = ov5693_set_fmt,
.get_selection = ov5693_get_selection,
.set_selection = ov5693_set_selection,
+ .get_frame_interval = ov5693_get_frame_interval,
};
static const struct v4l2_subdev_ops ov5693_ops = {
diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c
index c8f57ce1578d..663eccdfea6a 100644
--- a/drivers/media/i2c/ov5695.c
+++ b/drivers/media/i2c/ov5695.c
@@ -820,7 +820,7 @@ static int ov5695_set_fmt(struct v4l2_subdev *sd,
fmt->format.height = mode->height;
fmt->format.field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
} else {
ov5695->cur_mode = mode;
h_blank = mode->hts_def - mode->width;
@@ -846,8 +846,8 @@ static int ov5695_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&ov5695->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
} else {
fmt->format.width = mode->width;
fmt->format.height = mode->height;
@@ -1039,7 +1039,7 @@ static int ov5695_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct ov5695 *ov5695 = to_ov5695(sd);
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
+ v4l2_subdev_state_get_format(fh->state, 0);
const struct ov5695_mode *def_mode = &supported_modes[0];
mutex_lock(&ov5695->mutex);
diff --git a/drivers/media/i2c/ov64a40.c b/drivers/media/i2c/ov64a40.c
new file mode 100644
index 000000000000..4fba4c2cb064
--- /dev/null
+++ b/drivers/media/i2c/ov64a40.c
@@ -0,0 +1,3690 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * V4L2 sensor driver for OmniVision OV64A40
+ *
+ * Copyright (C) 2023 Ideas On Board Oy
+ * Copyright (C) 2023 Arducam
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define OV64A40_XCLK_FREQ 24000000
+
+#define OV64A40_NATIVE_WIDTH 9286
+#define OV64A40_NATIVE_HEIGHT 6976
+#define OV64A40_PIXEL_ARRAY_TOP 0
+#define OV64A40_PIXEL_ARRAY_LEFT 0
+#define OV64A40_PIXEL_ARRAY_WIDTH 9248
+#define OV64A40_PIXEL_ARRAY_HEIGHT 6944
+
+#define OV64A40_PIXEL_RATE 300000000
+
+#define OV64A40_LINK_FREQ_360M 360000000
+#define OV64A40_LINK_FREQ_456M 456000000
+
+#define OV64A40_PLL1_PRE_DIV0 CCI_REG8(0x0301)
+#define OV64A40_PLL1_PRE_DIV CCI_REG8(0x0303)
+#define OV64A40_PLL1_MULTIPLIER CCI_REG16(0x0304)
+#define OV64A40_PLL1_M_DIV CCI_REG8(0x0307)
+#define OV64A40_PLL2_SEL_BAK_SA1 CCI_REG8(0x0320)
+#define OV64A40_PLL2_PRE_DIV CCI_REG8(0x0323)
+#define OV64A40_PLL2_MULTIPLIER CCI_REG16(0x0324)
+#define OV64A40_PLL2_PRE_DIV0 CCI_REG8(0x0326)
+#define OV64A40_PLL2_DIVDAC CCI_REG8(0x0329)
+#define OV64A40_PLL2_DIVSP CCI_REG8(0x032d)
+#define OV64A40_PLL2_DACPREDIV CCI_REG8(0x032e)
+
+/* TODO: validate vblank_min, it's not characterized in the datasheet. */
+#define OV64A40_VBLANK_MIN 128
+#define OV64A40_VTS_MAX 0xffffff
+
+#define OV64A40_REG_MEC_LONG_EXPO CCI_REG24(0x3500)
+#define OV64A40_EXPOSURE_MIN 16
+#define OV64A40_EXPOSURE_MARGIN 32
+
+#define OV64A40_REG_MEC_LONG_GAIN CCI_REG16(0x3508)
+#define OV64A40_ANA_GAIN_MIN 0x80
+#define OV64A40_ANA_GAIN_MAX 0x7ff
+#define OV64A40_ANA_GAIN_DEFAULT 0x80
+
+#define OV64A40_REG_TIMING_CTRL0 CCI_REG16(0x3800)
+#define OV64A40_REG_TIMING_CTRL2 CCI_REG16(0x3802)
+#define OV64A40_REG_TIMING_CTRL4 CCI_REG16(0x3804)
+#define OV64A40_REG_TIMING_CTRL6 CCI_REG16(0x3806)
+#define OV64A40_REG_TIMING_CTRL8 CCI_REG16(0x3808)
+#define OV64A40_REG_TIMING_CTRLA CCI_REG16(0x380a)
+#define OV64A40_REG_TIMING_CTRLC CCI_REG16(0x380c)
+#define OV64A40_REG_TIMING_CTRLE CCI_REG16(0x380e)
+#define OV64A40_REG_TIMING_CTRL10 CCI_REG16(0x3810)
+#define OV64A40_REG_TIMING_CTRL12 CCI_REG16(0x3812)
+
+/*
+ * Careful: a typo in the datasheet calls this register
+ * OV64A40_REG_TIMING_CTRL20.
+ */
+#define OV64A40_REG_TIMING_CTRL14 CCI_REG8(0x3814)
+#define OV64A40_REG_TIMING_CTRL15 CCI_REG8(0x3815)
+#define OV64A40_ODD_INC_SHIFT 4
+#define OV64A40_SKIPPING_CONFIG(_odd, _even) \
+ (((_odd) << OV64A40_ODD_INC_SHIFT) | (_even))
+
+#define OV64A40_REG_TIMING_CTRL_20 CCI_REG8(0x3820)
+#define OV64A40_TIMING_CTRL_20_VFLIP BIT(2)
+#define OV64A40_TIMING_CTRL_20_VBIN BIT(1)
+
+#define OV64A40_REG_TIMING_CTRL_21 CCI_REG8(0x3821)
+#define OV64A40_TIMING_CTRL_21_HBIN BIT(4)
+#define OV64A40_TIMING_CTRL_21_HFLIP BIT(2)
+#define OV64A40_TIMING_CTRL_21_DSPEED BIT(0)
+#define OV64A40_TIMING_CTRL_21_HBIN_CONF \
+ (OV64A40_TIMING_CTRL_21_HBIN | \
+ OV64A40_TIMING_CTRL_21_DSPEED)
+
+#define OV64A40_REG_TIMINGS_VTS_HIGH CCI_REG8(0x3840)
+#define OV64A40_REG_TIMINGS_VTS_MID CCI_REG8(0x380e)
+#define OV64A40_REG_TIMINGS_VTS_LOW CCI_REG8(0x380f)
+
+/* The test pattern control is weirdly named PRE_ISP_2325_D2V2_TOP_1 in TRM. */
+#define OV64A40_REG_TEST_PATTERN CCI_REG8(0x50c1)
+#define OV64A40_TEST_PATTERN_DISABLED 0x00
+#define OV64A40_TEST_PATTERN_TYPE1 BIT(0)
+#define OV64A40_TEST_PATTERN_TYPE2 (BIT(4) | BIT(0))
+#define OV64A40_TEST_PATTERN_TYPE3 (BIT(5) | BIT(0))
+#define OV64A40_TEST_PATTERN_TYPE4 (BIT(5) | BIT(4) | BIT(0))
+
+#define OV64A40_REG_CHIP_ID CCI_REG24(0x300a)
+#define OV64A40_CHIP_ID 0x566441
+
+#define OV64A40_REG_SMIA CCI_REG8(0x0100)
+#define OV64A40_REG_SMIA_STREAMING BIT(0)
+
+enum ov64a40_link_freq_ids {
+ OV64A40_LINK_FREQ_456M_ID,
+ OV64A40_LINK_FREQ_360M_ID,
+ OV64A40_NUM_LINK_FREQ,
+};
+
+static const char * const ov64a40_supply_names[] = {
+ /* Supplies can be enabled in any order */
+ "avdd", /* Analog (2.8V) supply */
+ "dovdd", /* Digital Core (1.8V) supply */
+ "dvdd", /* IF (1.1V) supply */
+};
+
+static const char * const ov64a40_test_pattern_menu[] = {
+ "Disabled",
+ "Type1",
+ "Type2",
+ "Type3",
+ "Type4",
+};
+
+static const int ov64a40_test_pattern_val[] = {
+ OV64A40_TEST_PATTERN_DISABLED,
+ OV64A40_TEST_PATTERN_TYPE1,
+ OV64A40_TEST_PATTERN_TYPE2,
+ OV64A40_TEST_PATTERN_TYPE3,
+ OV64A40_TEST_PATTERN_TYPE4,
+};
+
+static const unsigned int ov64a40_mbus_codes[] = {
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+};
+
+static const struct cci_reg_sequence ov64a40_init[] = {
+ { CCI_REG8(0x0103), 0x01 }, { CCI_REG8(0x0301), 0x88 },
+ { CCI_REG8(0x0304), 0x00 }, { CCI_REG8(0x0305), 0x96 },
+ { CCI_REG8(0x0306), 0x03 }, { CCI_REG8(0x0307), 0x00 },
+ { CCI_REG8(0x0345), 0x2c }, { CCI_REG8(0x034a), 0x02 },
+ { CCI_REG8(0x034b), 0x02 }, { CCI_REG8(0x0350), 0xc0 },
+ { CCI_REG8(0x0360), 0x09 }, { CCI_REG8(0x3012), 0x31 },
+ { CCI_REG8(0x3015), 0xf0 }, { CCI_REG8(0x3017), 0xf0 },
+ { CCI_REG8(0x301d), 0xf6 }, { CCI_REG8(0x301e), 0xf1 },
+ { CCI_REG8(0x3022), 0xf0 }, { CCI_REG8(0x3400), 0x08 },
+ { CCI_REG8(0x3608), 0x41 }, { CCI_REG8(0x3421), 0x02 },
+ { CCI_REG8(0x3500), 0x00 }, { CCI_REG8(0x3501), 0x00 },
+ { CCI_REG8(0x3502), 0x18 }, { CCI_REG8(0x3504), 0x0c },
+ { CCI_REG8(0x3508), 0x01 }, { CCI_REG8(0x3509), 0x00 },
+ { CCI_REG8(0x350a), 0x01 }, { CCI_REG8(0x350b), 0x00 },
+ { CCI_REG8(0x350b), 0x00 }, { CCI_REG8(0x3540), 0x00 },
+ { CCI_REG8(0x3541), 0x00 }, { CCI_REG8(0x3542), 0x08 },
+ { CCI_REG8(0x3548), 0x01 }, { CCI_REG8(0x3549), 0xa0 },
+ { CCI_REG8(0x3549), 0x00 }, { CCI_REG8(0x3549), 0x00 },
+ { CCI_REG8(0x3549), 0x00 }, { CCI_REG8(0x3580), 0x00 },
+ { CCI_REG8(0x3581), 0x00 }, { CCI_REG8(0x3582), 0x04 },
+ { CCI_REG8(0x3588), 0x01 }, { CCI_REG8(0x3589), 0xf0 },
+ { CCI_REG8(0x3589), 0x00 }, { CCI_REG8(0x3589), 0x00 },
+ { CCI_REG8(0x3589), 0x00 }, { CCI_REG8(0x360d), 0x83 },
+ { CCI_REG8(0x3616), 0xa0 }, { CCI_REG8(0x3617), 0x31 },
+ { CCI_REG8(0x3623), 0x10 }, { CCI_REG8(0x3633), 0x03 },
+ { CCI_REG8(0x3634), 0x03 }, { CCI_REG8(0x3635), 0x77 },
+ { CCI_REG8(0x3640), 0x19 }, { CCI_REG8(0x3641), 0x80 },
+ { CCI_REG8(0x364d), 0x0f }, { CCI_REG8(0x3680), 0x80 },
+ { CCI_REG8(0x3682), 0x00 }, { CCI_REG8(0x3683), 0x00 },
+ { CCI_REG8(0x3684), 0x07 }, { CCI_REG8(0x3688), 0x01 },
+ { CCI_REG8(0x3689), 0x08 }, { CCI_REG8(0x368a), 0x26 },
+ { CCI_REG8(0x368b), 0xc8 }, { CCI_REG8(0x368e), 0x70 },
+ { CCI_REG8(0x368f), 0x00 }, { CCI_REG8(0x3692), 0x04 },
+ { CCI_REG8(0x3693), 0x00 }, { CCI_REG8(0x3696), 0xd1 },
+ { CCI_REG8(0x3697), 0xe0 }, { CCI_REG8(0x3698), 0x80 },
+ { CCI_REG8(0x3699), 0x2b }, { CCI_REG8(0x369a), 0x00 },
+ { CCI_REG8(0x369d), 0x00 }, { CCI_REG8(0x369e), 0x14 },
+ { CCI_REG8(0x369f), 0x20 }, { CCI_REG8(0x36a5), 0x80 },
+ { CCI_REG8(0x36a6), 0x00 }, { CCI_REG8(0x36a7), 0x00 },
+ { CCI_REG8(0x36a8), 0x00 }, { CCI_REG8(0x36b5), 0x17 },
+ { CCI_REG8(0x3701), 0x30 }, { CCI_REG8(0x3706), 0x2b },
+ { CCI_REG8(0x3709), 0x8d }, { CCI_REG8(0x370b), 0x4f },
+ { CCI_REG8(0x3711), 0x00 }, { CCI_REG8(0x3712), 0x01 },
+ { CCI_REG8(0x3713), 0x00 }, { CCI_REG8(0x3720), 0x08 },
+ { CCI_REG8(0x3727), 0x22 }, { CCI_REG8(0x3728), 0x01 },
+ { CCI_REG8(0x375e), 0x00 }, { CCI_REG8(0x3760), 0x08 },
+ { CCI_REG8(0x3761), 0x10 }, { CCI_REG8(0x3762), 0x08 },
+ { CCI_REG8(0x3765), 0x10 }, { CCI_REG8(0x3766), 0x18 },
+ { CCI_REG8(0x376a), 0x08 }, { CCI_REG8(0x376b), 0x00 },
+ { CCI_REG8(0x376d), 0x1b }, { CCI_REG8(0x3791), 0x2b },
+ { CCI_REG8(0x3793), 0x2b }, { CCI_REG8(0x3795), 0x2b },
+ { CCI_REG8(0x3797), 0x4f }, { CCI_REG8(0x3799), 0x4f },
+ { CCI_REG8(0x379b), 0x4f }, { CCI_REG8(0x37a0), 0x22 },
+ { CCI_REG8(0x37da), 0x04 }, { CCI_REG8(0x37f9), 0x02 },
+ { CCI_REG8(0x37fa), 0x02 }, { CCI_REG8(0x37fb), 0x02 },
+ { CCI_REG8(0x3814), 0x11 }, { CCI_REG8(0x3815), 0x11 },
+ { CCI_REG8(0x3820), 0x40 }, { CCI_REG8(0x3821), 0x04 },
+ { CCI_REG8(0x3822), 0x00 }, { CCI_REG8(0x3823), 0x04 },
+ { CCI_REG8(0x3827), 0x08 }, { CCI_REG8(0x3828), 0x00 },
+ { CCI_REG8(0x382a), 0x81 }, { CCI_REG8(0x382e), 0x70 },
+ { CCI_REG8(0x3837), 0x10 }, { CCI_REG8(0x3839), 0x00 },
+ { CCI_REG8(0x383b), 0x00 }, { CCI_REG8(0x383c), 0x00 },
+ { CCI_REG8(0x383d), 0x10 }, { CCI_REG8(0x383f), 0x00 },
+ { CCI_REG8(0x384c), 0x02 }, { CCI_REG8(0x384d), 0x8c },
+ { CCI_REG8(0x3852), 0x00 }, { CCI_REG8(0x3856), 0x10 },
+ { CCI_REG8(0x3857), 0x10 }, { CCI_REG8(0x3858), 0x20 },
+ { CCI_REG8(0x3859), 0x20 }, { CCI_REG8(0x3894), 0x00 },
+ { CCI_REG8(0x3895), 0x00 }, { CCI_REG8(0x3896), 0x00 },
+ { CCI_REG8(0x3897), 0x00 }, { CCI_REG8(0x3900), 0x40 },
+ { CCI_REG8(0x3aed), 0x6e }, { CCI_REG8(0x3af1), 0x73 },
+ { CCI_REG8(0x3d86), 0x12 }, { CCI_REG8(0x3d87), 0x30 },
+ { CCI_REG8(0x3d8c), 0xab }, { CCI_REG8(0x3d8d), 0xb0 },
+ { CCI_REG8(0x3f00), 0x12 }, { CCI_REG8(0x3f00), 0x12 },
+ { CCI_REG8(0x3f00), 0x12 }, { CCI_REG8(0x3f01), 0x03 },
+ { CCI_REG8(0x4009), 0x01 }, { CCI_REG8(0x400e), 0xc6 },
+ { CCI_REG8(0x400f), 0x00 }, { CCI_REG8(0x4010), 0x28 },
+ { CCI_REG8(0x4011), 0x01 }, { CCI_REG8(0x4012), 0x0c },
+ { CCI_REG8(0x4015), 0x00 }, { CCI_REG8(0x4016), 0x1f },
+ { CCI_REG8(0x4017), 0x00 }, { CCI_REG8(0x4018), 0x07 },
+ { CCI_REG8(0x401a), 0x40 }, { CCI_REG8(0x4028), 0x01 },
+ { CCI_REG8(0x4504), 0x00 }, { CCI_REG8(0x4506), 0x01 },
+ { CCI_REG8(0x4508), 0x00 }, { CCI_REG8(0x4509), 0x35 },
+ { CCI_REG8(0x450a), 0x08 }, { CCI_REG8(0x450c), 0x00 },
+ { CCI_REG8(0x450d), 0x20 }, { CCI_REG8(0x450e), 0x00 },
+ { CCI_REG8(0x450f), 0x20 }, { CCI_REG8(0x451e), 0x00 },
+ { CCI_REG8(0x451f), 0x00 }, { CCI_REG8(0x4523), 0x00 },
+ { CCI_REG8(0x4526), 0x00 }, { CCI_REG8(0x4527), 0x18 },
+ { CCI_REG8(0x4580), 0x01 }, { CCI_REG8(0x4583), 0x00 },
+ { CCI_REG8(0x4584), 0x00 }, { CCI_REG8(0x45c0), 0xa1 },
+ { CCI_REG8(0x4602), 0x08 }, { CCI_REG8(0x4603), 0x05 },
+ { CCI_REG8(0x4606), 0x12 }, { CCI_REG8(0x4607), 0x30 },
+ { CCI_REG8(0x460b), 0x00 }, { CCI_REG8(0x460d), 0x00 },
+ { CCI_REG8(0x4640), 0x00 }, { CCI_REG8(0x4641), 0x24 },
+ { CCI_REG8(0x4643), 0x08 }, { CCI_REG8(0x4645), 0x14 },
+ { CCI_REG8(0x4648), 0x0a }, { CCI_REG8(0x4649), 0x06 },
+ { CCI_REG8(0x464a), 0x00 }, { CCI_REG8(0x464b), 0x30 },
+ { CCI_REG8(0x4800), 0x04 }, { CCI_REG8(0x4802), 0x02 },
+ { CCI_REG8(0x480b), 0x10 }, { CCI_REG8(0x480c), 0x80 },
+ { CCI_REG8(0x480e), 0x04 }, { CCI_REG8(0x480f), 0x32 },
+ { CCI_REG8(0x481b), 0x12 }, { CCI_REG8(0x4833), 0x30 },
+ { CCI_REG8(0x4837), 0x08 }, { CCI_REG8(0x484b), 0x27 },
+ { CCI_REG8(0x4850), 0x42 }, { CCI_REG8(0x4851), 0xaa },
+ { CCI_REG8(0x4860), 0x01 }, { CCI_REG8(0x4861), 0xec },
+ { CCI_REG8(0x4862), 0x25 }, { CCI_REG8(0x4888), 0x00 },
+ { CCI_REG8(0x4889), 0x03 }, { CCI_REG8(0x488c), 0x60 },
+ { CCI_REG8(0x4910), 0x28 }, { CCI_REG8(0x4911), 0x01 },
+ { CCI_REG8(0x4912), 0x0c }, { CCI_REG8(0x491a), 0x40 },
+ { CCI_REG8(0x4915), 0x00 }, { CCI_REG8(0x4916), 0x0f },
+ { CCI_REG8(0x4917), 0x00 }, { CCI_REG8(0x4918), 0x07 },
+ { CCI_REG8(0x4a10), 0x28 }, { CCI_REG8(0x4a11), 0x01 },
+ { CCI_REG8(0x4a12), 0x0c }, { CCI_REG8(0x4a1a), 0x40 },
+ { CCI_REG8(0x4a15), 0x00 }, { CCI_REG8(0x4a16), 0x0f },
+ { CCI_REG8(0x4a17), 0x00 }, { CCI_REG8(0x4a18), 0x07 },
+ { CCI_REG8(0x4d00), 0x04 }, { CCI_REG8(0x4d01), 0x5a },
+ { CCI_REG8(0x4d02), 0xbb }, { CCI_REG8(0x4d03), 0x84 },
+ { CCI_REG8(0x4d04), 0xd1 }, { CCI_REG8(0x4d05), 0x68 },
+ { CCI_REG8(0xc4fa), 0x10 }, { CCI_REG8(0x3b56), 0x0a },
+ { CCI_REG8(0x3b57), 0x0a }, { CCI_REG8(0x3b58), 0x0c },
+ { CCI_REG8(0x3b59), 0x10 }, { CCI_REG8(0x3a1d), 0x30 },
+ { CCI_REG8(0x3a1e), 0x30 }, { CCI_REG8(0x3a21), 0x30 },
+ { CCI_REG8(0x3a22), 0x30 }, { CCI_REG8(0x3992), 0x02 },
+ { CCI_REG8(0x399e), 0x02 }, { CCI_REG8(0x39fb), 0x30 },
+ { CCI_REG8(0x39fc), 0x30 }, { CCI_REG8(0x39fd), 0x30 },
+ { CCI_REG8(0x39fe), 0x30 }, { CCI_REG8(0x3a6d), 0x83 },
+ { CCI_REG8(0x3a5e), 0x83 }, { CCI_REG8(0xc500), 0x12 },
+ { CCI_REG8(0xc501), 0x12 }, { CCI_REG8(0xc502), 0x12 },
+ { CCI_REG8(0xc503), 0x12 }, { CCI_REG8(0xc505), 0x12 },
+ { CCI_REG8(0xc506), 0x12 }, { CCI_REG8(0xc507), 0x12 },
+ { CCI_REG8(0xc508), 0x12 }, { CCI_REG8(0x3a77), 0x12 },
+ { CCI_REG8(0x3a73), 0x12 }, { CCI_REG8(0x3a7b), 0x12 },
+ { CCI_REG8(0x3a7f), 0x12 }, { CCI_REG8(0x3b2e), 0x13 },
+ { CCI_REG8(0x3b29), 0x13 }, { CCI_REG8(0xc439), 0x13 },
+ { CCI_REG8(0xc469), 0x13 }, { CCI_REG8(0xc41c), 0x89 },
+ { CCI_REG8(0x3618), 0x80 }, { CCI_REG8(0xc514), 0x51 },
+ { CCI_REG8(0xc515), 0x2c }, { CCI_REG8(0xc516), 0x16 },
+ { CCI_REG8(0xc517), 0x0d }, { CCI_REG8(0x3615), 0x7f },
+ { CCI_REG8(0x3632), 0x99 }, { CCI_REG8(0x3642), 0x00 },
+ { CCI_REG8(0x3645), 0x80 }, { CCI_REG8(0x3702), 0x2a },
+ { CCI_REG8(0x3703), 0x2a }, { CCI_REG8(0x3708), 0x2f },
+ { CCI_REG8(0x3721), 0x15 }, { CCI_REG8(0x3744), 0x28 },
+ { CCI_REG8(0x3991), 0x0c }, { CCI_REG8(0x371d), 0x24 },
+ { CCI_REG8(0x371f), 0x0c }, { CCI_REG8(0x374b), 0x03 },
+ { CCI_REG8(0x37d0), 0x00 }, { CCI_REG8(0x391d), 0x55 },
+ { CCI_REG8(0x391e), 0x52 }, { CCI_REG8(0x399d), 0x0c },
+ { CCI_REG8(0x3a2f), 0x01 }, { CCI_REG8(0x3a30), 0x01 },
+ { CCI_REG8(0x3a31), 0x01 }, { CCI_REG8(0x3a32), 0x01 },
+ { CCI_REG8(0x3a34), 0x01 }, { CCI_REG8(0x3a35), 0x01 },
+ { CCI_REG8(0x3a36), 0x01 }, { CCI_REG8(0x3a37), 0x01 },
+ { CCI_REG8(0x3a43), 0x01 }, { CCI_REG8(0x3a44), 0x01 },
+ { CCI_REG8(0x3a45), 0x01 }, { CCI_REG8(0x3a46), 0x01 },
+ { CCI_REG8(0x3a48), 0x01 }, { CCI_REG8(0x3a49), 0x01 },
+ { CCI_REG8(0x3a4a), 0x01 }, { CCI_REG8(0x3a4b), 0x01 },
+ { CCI_REG8(0x3a50), 0x14 }, { CCI_REG8(0x3a54), 0x14 },
+ { CCI_REG8(0x3a60), 0x20 }, { CCI_REG8(0x3a6f), 0x20 },
+ { CCI_REG8(0x3ac5), 0x01 }, { CCI_REG8(0x3ac6), 0x01 },
+ { CCI_REG8(0x3ac7), 0x01 }, { CCI_REG8(0x3ac8), 0x01 },
+ { CCI_REG8(0x3ac9), 0x01 }, { CCI_REG8(0x3aca), 0x01 },
+ { CCI_REG8(0x3acb), 0x01 }, { CCI_REG8(0x3acc), 0x01 },
+ { CCI_REG8(0x3acd), 0x01 }, { CCI_REG8(0x3ace), 0x01 },
+ { CCI_REG8(0x3acf), 0x01 }, { CCI_REG8(0x3ad0), 0x01 },
+ { CCI_REG8(0x3ad1), 0x01 }, { CCI_REG8(0x3ad2), 0x01 },
+ { CCI_REG8(0x3ad3), 0x01 }, { CCI_REG8(0x3ad4), 0x01 },
+ { CCI_REG8(0x3add), 0x1f }, { CCI_REG8(0x3adf), 0x24 },
+ { CCI_REG8(0x3aef), 0x1f }, { CCI_REG8(0x3af0), 0x24 },
+ { CCI_REG8(0x3b92), 0x08 }, { CCI_REG8(0x3b93), 0x08 },
+ { CCI_REG8(0x3b94), 0x08 }, { CCI_REG8(0x3b95), 0x08 },
+ { CCI_REG8(0x3be7), 0x1e }, { CCI_REG8(0x3be8), 0x26 },
+ { CCI_REG8(0xc44a), 0x20 }, { CCI_REG8(0xc44c), 0x20 },
+ { CCI_REG8(0xc483), 0x00 }, { CCI_REG8(0xc484), 0x00 },
+ { CCI_REG8(0xc485), 0x00 }, { CCI_REG8(0xc486), 0x00 },
+ { CCI_REG8(0xc487), 0x01 }, { CCI_REG8(0xc488), 0x01 },
+ { CCI_REG8(0xc489), 0x01 }, { CCI_REG8(0xc48a), 0x01 },
+ { CCI_REG8(0xc4c1), 0x00 }, { CCI_REG8(0xc4c2), 0x00 },
+ { CCI_REG8(0xc4c3), 0x00 }, { CCI_REG8(0xc4c4), 0x00 },
+ { CCI_REG8(0xc4c6), 0x10 }, { CCI_REG8(0xc4c7), 0x10 },
+ { CCI_REG8(0xc4c8), 0x10 }, { CCI_REG8(0xc4c9), 0x10 },
+ { CCI_REG8(0xc4ca), 0x10 }, { CCI_REG8(0xc4cb), 0x10 },
+ { CCI_REG8(0xc4cc), 0x10 }, { CCI_REG8(0xc4cd), 0x10 },
+ { CCI_REG8(0xc4ea), 0x07 }, { CCI_REG8(0xc4eb), 0x07 },
+ { CCI_REG8(0xc4ec), 0x07 }, { CCI_REG8(0xc4ed), 0x07 },
+ { CCI_REG8(0xc4ee), 0x07 }, { CCI_REG8(0xc4f6), 0x10 },
+ { CCI_REG8(0xc4f7), 0x10 }, { CCI_REG8(0xc4f8), 0x10 },
+ { CCI_REG8(0xc4f9), 0x10 }, { CCI_REG8(0xc518), 0x0e },
+ { CCI_REG8(0xc519), 0x0e }, { CCI_REG8(0xc51a), 0x0e },
+ { CCI_REG8(0xc51b), 0x0e }, { CCI_REG8(0xc51c), 0x0e },
+ { CCI_REG8(0xc51d), 0x0e }, { CCI_REG8(0xc51e), 0x0e },
+ { CCI_REG8(0xc51f), 0x0e }, { CCI_REG8(0xc520), 0x0e },
+ { CCI_REG8(0xc521), 0x0e }, { CCI_REG8(0xc522), 0x0e },
+ { CCI_REG8(0xc523), 0x0e }, { CCI_REG8(0xc524), 0x0e },
+ { CCI_REG8(0xc525), 0x0e }, { CCI_REG8(0xc526), 0x0e },
+ { CCI_REG8(0xc527), 0x0e }, { CCI_REG8(0xc528), 0x0e },
+ { CCI_REG8(0xc529), 0x0e }, { CCI_REG8(0xc52a), 0x0e },
+ { CCI_REG8(0xc52b), 0x0e }, { CCI_REG8(0xc52c), 0x0e },
+ { CCI_REG8(0xc52d), 0x0e }, { CCI_REG8(0xc52e), 0x0e },
+ { CCI_REG8(0xc52f), 0x0e }, { CCI_REG8(0xc530), 0x0e },
+ { CCI_REG8(0xc531), 0x0e }, { CCI_REG8(0xc532), 0x0e },
+ { CCI_REG8(0xc533), 0x0e }, { CCI_REG8(0xc534), 0x0e },
+ { CCI_REG8(0xc535), 0x0e }, { CCI_REG8(0xc536), 0x0e },
+ { CCI_REG8(0xc537), 0x0e }, { CCI_REG8(0xc538), 0x0e },
+ { CCI_REG8(0xc539), 0x0e }, { CCI_REG8(0xc53a), 0x0e },
+ { CCI_REG8(0xc53b), 0x0e }, { CCI_REG8(0xc53c), 0x0e },
+ { CCI_REG8(0xc53d), 0x0e }, { CCI_REG8(0xc53e), 0x0e },
+ { CCI_REG8(0xc53f), 0x0e }, { CCI_REG8(0xc540), 0x0e },
+ { CCI_REG8(0xc541), 0x0e }, { CCI_REG8(0xc542), 0x0e },
+ { CCI_REG8(0xc543), 0x0e }, { CCI_REG8(0xc544), 0x0e },
+ { CCI_REG8(0xc545), 0x0e }, { CCI_REG8(0xc546), 0x0e },
+ { CCI_REG8(0xc547), 0x0e }, { CCI_REG8(0xc548), 0x0e },
+ { CCI_REG8(0xc549), 0x0e }, { CCI_REG8(0xc57f), 0x22 },
+ { CCI_REG8(0xc580), 0x22 }, { CCI_REG8(0xc581), 0x22 },
+ { CCI_REG8(0xc582), 0x22 }, { CCI_REG8(0xc583), 0x22 },
+ { CCI_REG8(0xc584), 0x22 }, { CCI_REG8(0xc585), 0x22 },
+ { CCI_REG8(0xc586), 0x22 }, { CCI_REG8(0xc587), 0x22 },
+ { CCI_REG8(0xc588), 0x22 }, { CCI_REG8(0xc589), 0x22 },
+ { CCI_REG8(0xc58a), 0x22 }, { CCI_REG8(0xc58b), 0x22 },
+ { CCI_REG8(0xc58c), 0x22 }, { CCI_REG8(0xc58d), 0x22 },
+ { CCI_REG8(0xc58e), 0x22 }, { CCI_REG8(0xc58f), 0x22 },
+ { CCI_REG8(0xc590), 0x22 }, { CCI_REG8(0xc591), 0x22 },
+ { CCI_REG8(0xc592), 0x22 }, { CCI_REG8(0xc598), 0x22 },
+ { CCI_REG8(0xc599), 0x22 }, { CCI_REG8(0xc59a), 0x22 },
+ { CCI_REG8(0xc59b), 0x22 }, { CCI_REG8(0xc59c), 0x22 },
+ { CCI_REG8(0xc59d), 0x22 }, { CCI_REG8(0xc59e), 0x22 },
+ { CCI_REG8(0xc59f), 0x22 }, { CCI_REG8(0xc5a0), 0x22 },
+ { CCI_REG8(0xc5a1), 0x22 }, { CCI_REG8(0xc5a2), 0x22 },
+ { CCI_REG8(0xc5a3), 0x22 }, { CCI_REG8(0xc5a4), 0x22 },
+ { CCI_REG8(0xc5a5), 0x22 }, { CCI_REG8(0xc5a6), 0x22 },
+ { CCI_REG8(0xc5a7), 0x22 }, { CCI_REG8(0xc5a8), 0x22 },
+ { CCI_REG8(0xc5a9), 0x22 }, { CCI_REG8(0xc5aa), 0x22 },
+ { CCI_REG8(0xc5ab), 0x22 }, { CCI_REG8(0xc5b1), 0x2a },
+ { CCI_REG8(0xc5b2), 0x2a }, { CCI_REG8(0xc5b3), 0x2a },
+ { CCI_REG8(0xc5b4), 0x2a }, { CCI_REG8(0xc5b5), 0x2a },
+ { CCI_REG8(0xc5b6), 0x2a }, { CCI_REG8(0xc5b7), 0x2a },
+ { CCI_REG8(0xc5b8), 0x2a }, { CCI_REG8(0xc5b9), 0x2a },
+ { CCI_REG8(0xc5ba), 0x2a }, { CCI_REG8(0xc5bb), 0x2a },
+ { CCI_REG8(0xc5bc), 0x2a }, { CCI_REG8(0xc5bd), 0x2a },
+ { CCI_REG8(0xc5be), 0x2a }, { CCI_REG8(0xc5bf), 0x2a },
+ { CCI_REG8(0xc5c0), 0x2a }, { CCI_REG8(0xc5c1), 0x2a },
+ { CCI_REG8(0xc5c2), 0x2a }, { CCI_REG8(0xc5c3), 0x2a },
+ { CCI_REG8(0xc5c4), 0x2a }, { CCI_REG8(0xc5ca), 0x2a },
+ { CCI_REG8(0xc5cb), 0x2a }, { CCI_REG8(0xc5cc), 0x2a },
+ { CCI_REG8(0xc5cd), 0x2a }, { CCI_REG8(0xc5ce), 0x2a },
+ { CCI_REG8(0xc5cf), 0x2a }, { CCI_REG8(0xc5d0), 0x2a },
+ { CCI_REG8(0xc5d1), 0x2a }, { CCI_REG8(0xc5d2), 0x2a },
+ { CCI_REG8(0xc5d3), 0x2a }, { CCI_REG8(0xc5d4), 0x2a },
+ { CCI_REG8(0xc5d5), 0x2a }, { CCI_REG8(0xc5d6), 0x2a },
+ { CCI_REG8(0xc5d7), 0x2a }, { CCI_REG8(0xc5d8), 0x2a },
+ { CCI_REG8(0xc5d9), 0x2a }, { CCI_REG8(0xc5da), 0x2a },
+ { CCI_REG8(0xc5db), 0x2a }, { CCI_REG8(0xc5dc), 0x2a },
+ { CCI_REG8(0xc5dd), 0x2a }, { CCI_REG8(0xc5e8), 0x22 },
+ { CCI_REG8(0xc5ea), 0x22 }, { CCI_REG8(0x4540), 0x12 },
+ { CCI_REG8(0x4541), 0x30 }, { CCI_REG8(0x3d86), 0x12 },
+ { CCI_REG8(0x3d87), 0x30 }, { CCI_REG8(0x4606), 0x12 },
+ { CCI_REG8(0x4607), 0x30 }, { CCI_REG8(0x4648), 0x0a },
+ { CCI_REG8(0x4649), 0x06 }, { CCI_REG8(0x3220), 0x12 },
+ { CCI_REG8(0x3221), 0x30 }, { CCI_REG8(0x40c2), 0x12 },
+ { CCI_REG8(0x49c2), 0x12 }, { CCI_REG8(0x4ac2), 0x12 },
+ { CCI_REG8(0x40c3), 0x30 }, { CCI_REG8(0x49c3), 0x30 },
+ { CCI_REG8(0x4ac3), 0x30 }, { CCI_REG8(0x36b0), 0x12 },
+ { CCI_REG8(0x36b1), 0x30 }, { CCI_REG8(0x45cb), 0x12 },
+ { CCI_REG8(0x45cc), 0x30 }, { CCI_REG8(0x4585), 0x12 },
+ { CCI_REG8(0x4586), 0x30 }, { CCI_REG8(0x36b2), 0x12 },
+ { CCI_REG8(0x36b3), 0x30 }, { CCI_REG8(0x5a40), 0x75 },
+ { CCI_REG8(0x5a41), 0x75 }, { CCI_REG8(0x5a42), 0x75 },
+ { CCI_REG8(0x5a43), 0x75 }, { CCI_REG8(0x5a44), 0x75 },
+ { CCI_REG8(0x5a45), 0x75 }, { CCI_REG8(0x5a46), 0x75 },
+ { CCI_REG8(0x5a47), 0x75 }, { CCI_REG8(0x5a48), 0x75 },
+ { CCI_REG8(0x5a49), 0x75 }, { CCI_REG8(0x5a4a), 0x75 },
+ { CCI_REG8(0x5a4b), 0x75 }, { CCI_REG8(0x5a4c), 0x75 },
+ { CCI_REG8(0x5a4d), 0x75 }, { CCI_REG8(0x5a4e), 0x75 },
+ { CCI_REG8(0x5a4f), 0x75 }, { CCI_REG8(0x5a50), 0x75 },
+ { CCI_REG8(0x5a51), 0x75 }, { CCI_REG8(0x5a52), 0x75 },
+ { CCI_REG8(0x5a53), 0x75 }, { CCI_REG8(0x5a54), 0x75 },
+ { CCI_REG8(0x5a55), 0x75 }, { CCI_REG8(0x5a56), 0x75 },
+ { CCI_REG8(0x5a57), 0x75 }, { CCI_REG8(0x5a58), 0x75 },
+ { CCI_REG8(0x5a59), 0x75 }, { CCI_REG8(0x5a5a), 0x75 },
+ { CCI_REG8(0x5a5b), 0x75 }, { CCI_REG8(0x5a5c), 0x75 },
+ { CCI_REG8(0x5a5d), 0x75 }, { CCI_REG8(0x5a5e), 0x75 },
+ { CCI_REG8(0x5a5f), 0x75 }, { CCI_REG8(0x5a60), 0x75 },
+ { CCI_REG8(0x5a61), 0x75 }, { CCI_REG8(0x5a62), 0x75 },
+ { CCI_REG8(0x5a63), 0x75 }, { CCI_REG8(0x5a64), 0x75 },
+ { CCI_REG8(0x5a65), 0x75 }, { CCI_REG8(0x5a66), 0x75 },
+ { CCI_REG8(0x5a67), 0x75 }, { CCI_REG8(0x5a68), 0x75 },
+ { CCI_REG8(0x5a69), 0x75 }, { CCI_REG8(0x5a6a), 0x75 },
+ { CCI_REG8(0x5a6b), 0x75 }, { CCI_REG8(0x5a6c), 0x75 },
+ { CCI_REG8(0x5a6d), 0x75 }, { CCI_REG8(0x5a6e), 0x75 },
+ { CCI_REG8(0x5a6f), 0x75 }, { CCI_REG8(0x5a70), 0x75 },
+ { CCI_REG8(0x5a71), 0x75 }, { CCI_REG8(0x5a72), 0x75 },
+ { CCI_REG8(0x5a73), 0x75 }, { CCI_REG8(0x5a74), 0x75 },
+ { CCI_REG8(0x5a75), 0x75 }, { CCI_REG8(0x5a76), 0x75 },
+ { CCI_REG8(0x5a77), 0x75 }, { CCI_REG8(0x5a78), 0x75 },
+ { CCI_REG8(0x5a79), 0x75 }, { CCI_REG8(0x5a7a), 0x75 },
+ { CCI_REG8(0x5a7b), 0x75 }, { CCI_REG8(0x5a7c), 0x75 },
+ { CCI_REG8(0x5a7d), 0x75 }, { CCI_REG8(0x5a7e), 0x75 },
+ { CCI_REG8(0x5a7f), 0x75 }, { CCI_REG8(0x5a80), 0x75 },
+ { CCI_REG8(0x5a81), 0x75 }, { CCI_REG8(0x5a82), 0x75 },
+ { CCI_REG8(0x5a83), 0x75 }, { CCI_REG8(0x5a84), 0x75 },
+ { CCI_REG8(0x5a85), 0x75 }, { CCI_REG8(0x5a86), 0x75 },
+ { CCI_REG8(0x5a87), 0x75 }, { CCI_REG8(0x5a88), 0x75 },
+ { CCI_REG8(0x5a89), 0x75 }, { CCI_REG8(0x5a8a), 0x75 },
+ { CCI_REG8(0x5a8b), 0x75 }, { CCI_REG8(0x5a8c), 0x75 },
+ { CCI_REG8(0x5a8d), 0x75 }, { CCI_REG8(0x5a8e), 0x75 },
+ { CCI_REG8(0x5a8f), 0x75 }, { CCI_REG8(0x5a90), 0x75 },
+ { CCI_REG8(0x5a91), 0x75 }, { CCI_REG8(0x5a92), 0x75 },
+ { CCI_REG8(0x5a93), 0x75 }, { CCI_REG8(0x5a94), 0x75 },
+ { CCI_REG8(0x5a95), 0x75 }, { CCI_REG8(0x5a96), 0x75 },
+ { CCI_REG8(0x5a97), 0x75 }, { CCI_REG8(0x5a98), 0x75 },
+ { CCI_REG8(0x5a99), 0x75 }, { CCI_REG8(0x5a9a), 0x75 },
+ { CCI_REG8(0x5a9b), 0x75 }, { CCI_REG8(0x5a9c), 0x75 },
+ { CCI_REG8(0x5a9d), 0x75 }, { CCI_REG8(0x5a9e), 0x75 },
+ { CCI_REG8(0x5a9f), 0x75 }, { CCI_REG8(0x5aa0), 0x75 },
+ { CCI_REG8(0x5aa1), 0x75 }, { CCI_REG8(0x5aa2), 0x75 },
+ { CCI_REG8(0x5aa3), 0x75 }, { CCI_REG8(0x5aa4), 0x75 },
+ { CCI_REG8(0x5aa5), 0x75 }, { CCI_REG8(0x5aa6), 0x75 },
+ { CCI_REG8(0x5aa7), 0x75 }, { CCI_REG8(0x5aa8), 0x75 },
+ { CCI_REG8(0x5aa9), 0x75 }, { CCI_REG8(0x5aaa), 0x75 },
+ { CCI_REG8(0x5aab), 0x75 }, { CCI_REG8(0x5aac), 0x75 },
+ { CCI_REG8(0x5aad), 0x75 }, { CCI_REG8(0x5aae), 0x75 },
+ { CCI_REG8(0x5aaf), 0x75 }, { CCI_REG8(0x5ab0), 0x75 },
+ { CCI_REG8(0x5ab1), 0x75 }, { CCI_REG8(0x5ab2), 0x75 },
+ { CCI_REG8(0x5ab3), 0x75 }, { CCI_REG8(0x5ab4), 0x75 },
+ { CCI_REG8(0x5ab5), 0x75 }, { CCI_REG8(0x5ab6), 0x75 },
+ { CCI_REG8(0x5ab7), 0x75 }, { CCI_REG8(0x5ab8), 0x75 },
+ { CCI_REG8(0x5ab9), 0x75 }, { CCI_REG8(0x5aba), 0x75 },
+ { CCI_REG8(0x5abb), 0x75 }, { CCI_REG8(0x5abc), 0x75 },
+ { CCI_REG8(0x5abd), 0x75 }, { CCI_REG8(0x5abe), 0x75 },
+ { CCI_REG8(0x5abf), 0x75 }, { CCI_REG8(0x5ac0), 0x75 },
+ { CCI_REG8(0x5ac1), 0x75 }, { CCI_REG8(0x5ac2), 0x75 },
+ { CCI_REG8(0x5ac3), 0x75 }, { CCI_REG8(0x5ac4), 0x75 },
+ { CCI_REG8(0x5ac5), 0x75 }, { CCI_REG8(0x5ac6), 0x75 },
+ { CCI_REG8(0x5ac7), 0x75 }, { CCI_REG8(0x5ac8), 0x75 },
+ { CCI_REG8(0x5ac9), 0x75 }, { CCI_REG8(0x5aca), 0x75 },
+ { CCI_REG8(0x5acb), 0x75 }, { CCI_REG8(0x5acc), 0x75 },
+ { CCI_REG8(0x5acd), 0x75 }, { CCI_REG8(0x5ace), 0x75 },
+ { CCI_REG8(0x5acf), 0x75 }, { CCI_REG8(0x5ad0), 0x75 },
+ { CCI_REG8(0x5ad1), 0x75 }, { CCI_REG8(0x5ad2), 0x75 },
+ { CCI_REG8(0x5ad3), 0x75 }, { CCI_REG8(0x5ad4), 0x75 },
+ { CCI_REG8(0x5ad5), 0x75 }, { CCI_REG8(0x5ad6), 0x75 },
+ { CCI_REG8(0x5ad7), 0x75 }, { CCI_REG8(0x5ad8), 0x75 },
+ { CCI_REG8(0x5ad9), 0x75 }, { CCI_REG8(0x5ada), 0x75 },
+ { CCI_REG8(0x5adb), 0x75 }, { CCI_REG8(0x5adc), 0x75 },
+ { CCI_REG8(0x5add), 0x75 }, { CCI_REG8(0x5ade), 0x75 },
+ { CCI_REG8(0x5adf), 0x75 }, { CCI_REG8(0x5ae0), 0x75 },
+ { CCI_REG8(0x5ae1), 0x75 }, { CCI_REG8(0x5ae2), 0x75 },
+ { CCI_REG8(0x5ae3), 0x75 }, { CCI_REG8(0x5ae4), 0x75 },
+ { CCI_REG8(0x5ae5), 0x75 }, { CCI_REG8(0x5ae6), 0x75 },
+ { CCI_REG8(0x5ae7), 0x75 }, { CCI_REG8(0x5ae8), 0x75 },
+ { CCI_REG8(0x5ae9), 0x75 }, { CCI_REG8(0x5aea), 0x75 },
+ { CCI_REG8(0x5aeb), 0x75 }, { CCI_REG8(0x5aec), 0x75 },
+ { CCI_REG8(0x5aed), 0x75 }, { CCI_REG8(0x5aee), 0x75 },
+ { CCI_REG8(0x5aef), 0x75 }, { CCI_REG8(0x5af0), 0x75 },
+ { CCI_REG8(0x5af1), 0x75 }, { CCI_REG8(0x5af2), 0x75 },
+ { CCI_REG8(0x5af3), 0x75 }, { CCI_REG8(0x5af4), 0x75 },
+ { CCI_REG8(0x5af5), 0x75 }, { CCI_REG8(0x5af6), 0x75 },
+ { CCI_REG8(0x5af7), 0x75 }, { CCI_REG8(0x5af8), 0x75 },
+ { CCI_REG8(0x5af9), 0x75 }, { CCI_REG8(0x5afa), 0x75 },
+ { CCI_REG8(0x5afb), 0x75 }, { CCI_REG8(0x5afc), 0x75 },
+ { CCI_REG8(0x5afd), 0x75 }, { CCI_REG8(0x5afe), 0x75 },
+ { CCI_REG8(0x5aff), 0x75 }, { CCI_REG8(0x5b00), 0x75 },
+ { CCI_REG8(0x5b01), 0x75 }, { CCI_REG8(0x5b02), 0x75 },
+ { CCI_REG8(0x5b03), 0x75 }, { CCI_REG8(0x5b04), 0x75 },
+ { CCI_REG8(0x5b05), 0x75 }, { CCI_REG8(0x5b06), 0x75 },
+ { CCI_REG8(0x5b07), 0x75 }, { CCI_REG8(0x5b08), 0x75 },
+ { CCI_REG8(0x5b09), 0x75 }, { CCI_REG8(0x5b0a), 0x75 },
+ { CCI_REG8(0x5b0b), 0x75 }, { CCI_REG8(0x5b0c), 0x75 },
+ { CCI_REG8(0x5b0d), 0x75 }, { CCI_REG8(0x5b0e), 0x75 },
+ { CCI_REG8(0x5b0f), 0x75 }, { CCI_REG8(0x5b10), 0x75 },
+ { CCI_REG8(0x5b11), 0x75 }, { CCI_REG8(0x5b12), 0x75 },
+ { CCI_REG8(0x5b13), 0x75 }, { CCI_REG8(0x5b14), 0x75 },
+ { CCI_REG8(0x5b15), 0x75 }, { CCI_REG8(0x5b16), 0x75 },
+ { CCI_REG8(0x5b17), 0x75 }, { CCI_REG8(0x5b18), 0x75 },
+ { CCI_REG8(0x5b19), 0x75 }, { CCI_REG8(0x5b1a), 0x75 },
+ { CCI_REG8(0x5b1b), 0x75 }, { CCI_REG8(0x5b1c), 0x75 },
+ { CCI_REG8(0x5b1d), 0x75 }, { CCI_REG8(0x5b1e), 0x75 },
+ { CCI_REG8(0x5b1f), 0x75 }, { CCI_REG8(0x5b20), 0x75 },
+ { CCI_REG8(0x5b21), 0x75 }, { CCI_REG8(0x5b22), 0x75 },
+ { CCI_REG8(0x5b23), 0x75 }, { CCI_REG8(0x5b24), 0x75 },
+ { CCI_REG8(0x5b25), 0x75 }, { CCI_REG8(0x5b26), 0x75 },
+ { CCI_REG8(0x5b27), 0x75 }, { CCI_REG8(0x5b28), 0x75 },
+ { CCI_REG8(0x5b29), 0x75 }, { CCI_REG8(0x5b2a), 0x75 },
+ { CCI_REG8(0x5b2b), 0x75 }, { CCI_REG8(0x5b2c), 0x75 },
+ { CCI_REG8(0x5b2d), 0x75 }, { CCI_REG8(0x5b2e), 0x75 },
+ { CCI_REG8(0x5b2f), 0x75 }, { CCI_REG8(0x5b30), 0x75 },
+ { CCI_REG8(0x5b31), 0x75 }, { CCI_REG8(0x5b32), 0x75 },
+ { CCI_REG8(0x5b33), 0x75 }, { CCI_REG8(0x5b34), 0x75 },
+ { CCI_REG8(0x5b35), 0x75 }, { CCI_REG8(0x5b36), 0x75 },
+ { CCI_REG8(0x5b37), 0x75 }, { CCI_REG8(0x5b38), 0x75 },
+ { CCI_REG8(0x5b39), 0x75 }, { CCI_REG8(0x5b3a), 0x75 },
+ { CCI_REG8(0x5b3b), 0x75 }, { CCI_REG8(0x5b3c), 0x75 },
+ { CCI_REG8(0x5b3d), 0x75 }, { CCI_REG8(0x5b3e), 0x75 },
+ { CCI_REG8(0x5b3f), 0x75 }, { CCI_REG8(0x5b40), 0x75 },
+ { CCI_REG8(0x5b41), 0x75 }, { CCI_REG8(0x5b42), 0x75 },
+ { CCI_REG8(0x5b43), 0x75 }, { CCI_REG8(0x5b44), 0x75 },
+ { CCI_REG8(0x5b45), 0x75 }, { CCI_REG8(0x5b46), 0x75 },
+ { CCI_REG8(0x5b47), 0x75 }, { CCI_REG8(0x5b48), 0x75 },
+ { CCI_REG8(0x5b49), 0x75 }, { CCI_REG8(0x5b4a), 0x75 },
+ { CCI_REG8(0x5b4b), 0x75 }, { CCI_REG8(0x5b4c), 0x75 },
+ { CCI_REG8(0x5b4d), 0x75 }, { CCI_REG8(0x5b4e), 0x75 },
+ { CCI_REG8(0x5b4f), 0x75 }, { CCI_REG8(0x5b50), 0x75 },
+ { CCI_REG8(0x5b51), 0x75 }, { CCI_REG8(0x5b52), 0x75 },
+ { CCI_REG8(0x5b53), 0x75 }, { CCI_REG8(0x5b54), 0x75 },
+ { CCI_REG8(0x5b55), 0x75 }, { CCI_REG8(0x5b56), 0x75 },
+ { CCI_REG8(0x5b57), 0x75 }, { CCI_REG8(0x5b58), 0x75 },
+ { CCI_REG8(0x5b59), 0x75 }, { CCI_REG8(0x5b5a), 0x75 },
+ { CCI_REG8(0x5b5b), 0x75 }, { CCI_REG8(0x5b5c), 0x75 },
+ { CCI_REG8(0x5b5d), 0x75 }, { CCI_REG8(0x5b5e), 0x75 },
+ { CCI_REG8(0x5b5f), 0x75 }, { CCI_REG8(0x5b80), 0x75 },
+ { CCI_REG8(0x5b81), 0x75 }, { CCI_REG8(0x5b82), 0x75 },
+ { CCI_REG8(0x5b83), 0x75 }, { CCI_REG8(0x5b84), 0x75 },
+ { CCI_REG8(0x5b85), 0x75 }, { CCI_REG8(0x5b86), 0x75 },
+ { CCI_REG8(0x5b87), 0x75 }, { CCI_REG8(0x5b88), 0x75 },
+ { CCI_REG8(0x5b89), 0x75 }, { CCI_REG8(0x5b8a), 0x75 },
+ { CCI_REG8(0x5b8b), 0x75 }, { CCI_REG8(0x5b8c), 0x75 },
+ { CCI_REG8(0x5b8d), 0x75 }, { CCI_REG8(0x5b8e), 0x75 },
+ { CCI_REG8(0x5b8f), 0x75 }, { CCI_REG8(0x5b90), 0x75 },
+ { CCI_REG8(0x5b91), 0x75 }, { CCI_REG8(0x5b92), 0x75 },
+ { CCI_REG8(0x5b93), 0x75 }, { CCI_REG8(0x5b94), 0x75 },
+ { CCI_REG8(0x5b95), 0x75 }, { CCI_REG8(0x5b96), 0x75 },
+ { CCI_REG8(0x5b97), 0x75 }, { CCI_REG8(0x5b98), 0x75 },
+ { CCI_REG8(0x5b99), 0x75 }, { CCI_REG8(0x5b9a), 0x75 },
+ { CCI_REG8(0x5b9b), 0x75 }, { CCI_REG8(0x5b9c), 0x75 },
+ { CCI_REG8(0x5b9d), 0x75 }, { CCI_REG8(0x5b9e), 0x75 },
+ { CCI_REG8(0x5b9f), 0x75 }, { CCI_REG8(0x5ba0), 0x75 },
+ { CCI_REG8(0x5ba1), 0x75 }, { CCI_REG8(0x5ba2), 0x75 },
+ { CCI_REG8(0x5ba3), 0x75 }, { CCI_REG8(0x5ba4), 0x75 },
+ { CCI_REG8(0x5ba5), 0x75 }, { CCI_REG8(0x5ba6), 0x75 },
+ { CCI_REG8(0x5ba7), 0x75 }, { CCI_REG8(0x5ba8), 0x75 },
+ { CCI_REG8(0x5ba9), 0x75 }, { CCI_REG8(0x5baa), 0x75 },
+ { CCI_REG8(0x5bab), 0x75 }, { CCI_REG8(0x5bac), 0x75 },
+ { CCI_REG8(0x5bad), 0x75 }, { CCI_REG8(0x5bae), 0x75 },
+ { CCI_REG8(0x5baf), 0x75 }, { CCI_REG8(0x5bb0), 0x75 },
+ { CCI_REG8(0x5bb1), 0x75 }, { CCI_REG8(0x5bb2), 0x75 },
+ { CCI_REG8(0x5bb3), 0x75 }, { CCI_REG8(0x5bb4), 0x75 },
+ { CCI_REG8(0x5bb5), 0x75 }, { CCI_REG8(0x5bb6), 0x75 },
+ { CCI_REG8(0x5bb7), 0x75 }, { CCI_REG8(0x5bb8), 0x75 },
+ { CCI_REG8(0x5bb9), 0x75 }, { CCI_REG8(0x5bba), 0x75 },
+ { CCI_REG8(0x5bbb), 0x75 }, { CCI_REG8(0x5bbc), 0x75 },
+ { CCI_REG8(0x5bbd), 0x75 }, { CCI_REG8(0x5bbe), 0x75 },
+ { CCI_REG8(0x5bbf), 0x75 }, { CCI_REG8(0x5bc0), 0x75 },
+ { CCI_REG8(0x5bc1), 0x75 }, { CCI_REG8(0x5bc2), 0x75 },
+ { CCI_REG8(0x5bc3), 0x75 }, { CCI_REG8(0x5bc4), 0x75 },
+ { CCI_REG8(0x5bc5), 0x75 }, { CCI_REG8(0x5bc6), 0x75 },
+ { CCI_REG8(0x5bc7), 0x75 }, { CCI_REG8(0x5bc8), 0x75 },
+ { CCI_REG8(0x5bc9), 0x75 }, { CCI_REG8(0x5bca), 0x75 },
+ { CCI_REG8(0x5bcb), 0x75 }, { CCI_REG8(0x5bcc), 0x75 },
+ { CCI_REG8(0x5bcd), 0x75 }, { CCI_REG8(0x5bce), 0x75 },
+ { CCI_REG8(0x5bcf), 0x75 }, { CCI_REG8(0x5bd0), 0x75 },
+ { CCI_REG8(0x5bd1), 0x75 }, { CCI_REG8(0x5bd2), 0x75 },
+ { CCI_REG8(0x5bd3), 0x75 }, { CCI_REG8(0x5bd4), 0x75 },
+ { CCI_REG8(0x5bd5), 0x75 }, { CCI_REG8(0x5bd6), 0x75 },
+ { CCI_REG8(0x5bd7), 0x75 }, { CCI_REG8(0x5bd8), 0x75 },
+ { CCI_REG8(0x5bd9), 0x75 }, { CCI_REG8(0x5bda), 0x75 },
+ { CCI_REG8(0x5bdb), 0x75 }, { CCI_REG8(0x5bdc), 0x75 },
+ { CCI_REG8(0x5bdd), 0x75 }, { CCI_REG8(0x5bde), 0x75 },
+ { CCI_REG8(0x5bdf), 0x75 }, { CCI_REG8(0x5be0), 0x75 },
+ { CCI_REG8(0x5be1), 0x75 }, { CCI_REG8(0x5be2), 0x75 },
+ { CCI_REG8(0x5be3), 0x75 }, { CCI_REG8(0x5be4), 0x75 },
+ { CCI_REG8(0x5be5), 0x75 }, { CCI_REG8(0x5be6), 0x75 },
+ { CCI_REG8(0x5be7), 0x75 }, { CCI_REG8(0x5be8), 0x75 },
+ { CCI_REG8(0x5be9), 0x75 }, { CCI_REG8(0x5bea), 0x75 },
+ { CCI_REG8(0x5beb), 0x75 }, { CCI_REG8(0x5bec), 0x75 },
+ { CCI_REG8(0x5bed), 0x75 }, { CCI_REG8(0x5bee), 0x75 },
+ { CCI_REG8(0x5bef), 0x75 }, { CCI_REG8(0x5bf0), 0x75 },
+ { CCI_REG8(0x5bf1), 0x75 }, { CCI_REG8(0x5bf2), 0x75 },
+ { CCI_REG8(0x5bf3), 0x75 }, { CCI_REG8(0x5bf4), 0x75 },
+ { CCI_REG8(0x5bf5), 0x75 }, { CCI_REG8(0x5bf6), 0x75 },
+ { CCI_REG8(0x5bf7), 0x75 }, { CCI_REG8(0x5bf8), 0x75 },
+ { CCI_REG8(0x5bf9), 0x75 }, { CCI_REG8(0x5bfa), 0x75 },
+ { CCI_REG8(0x5bfb), 0x75 }, { CCI_REG8(0x5bfc), 0x75 },
+ { CCI_REG8(0x5bfd), 0x75 }, { CCI_REG8(0x5bfe), 0x75 },
+ { CCI_REG8(0x5bff), 0x75 }, { CCI_REG8(0x5c00), 0x75 },
+ { CCI_REG8(0x5c01), 0x75 }, { CCI_REG8(0x5c02), 0x75 },
+ { CCI_REG8(0x5c03), 0x75 }, { CCI_REG8(0x5c04), 0x75 },
+ { CCI_REG8(0x5c05), 0x75 }, { CCI_REG8(0x5c06), 0x75 },
+ { CCI_REG8(0x5c07), 0x75 }, { CCI_REG8(0x5c08), 0x75 },
+ { CCI_REG8(0x5c09), 0x75 }, { CCI_REG8(0x5c0a), 0x75 },
+ { CCI_REG8(0x5c0b), 0x75 }, { CCI_REG8(0x5c0c), 0x75 },
+ { CCI_REG8(0x5c0d), 0x75 }, { CCI_REG8(0x5c0e), 0x75 },
+ { CCI_REG8(0x5c0f), 0x75 }, { CCI_REG8(0x5c10), 0x75 },
+ { CCI_REG8(0x5c11), 0x75 }, { CCI_REG8(0x5c12), 0x75 },
+ { CCI_REG8(0x5c13), 0x75 }, { CCI_REG8(0x5c14), 0x75 },
+ { CCI_REG8(0x5c15), 0x75 }, { CCI_REG8(0x5c16), 0x75 },
+ { CCI_REG8(0x5c17), 0x75 }, { CCI_REG8(0x5c18), 0x75 },
+ { CCI_REG8(0x5c19), 0x75 }, { CCI_REG8(0x5c1a), 0x75 },
+ { CCI_REG8(0x5c1b), 0x75 }, { CCI_REG8(0x5c1c), 0x75 },
+ { CCI_REG8(0x5c1d), 0x75 }, { CCI_REG8(0x5c1e), 0x75 },
+ { CCI_REG8(0x5c1f), 0x75 }, { CCI_REG8(0x5c20), 0x75 },
+ { CCI_REG8(0x5c21), 0x75 }, { CCI_REG8(0x5c22), 0x75 },
+ { CCI_REG8(0x5c23), 0x75 }, { CCI_REG8(0x5c24), 0x75 },
+ { CCI_REG8(0x5c25), 0x75 }, { CCI_REG8(0x5c26), 0x75 },
+ { CCI_REG8(0x5c27), 0x75 }, { CCI_REG8(0x5c28), 0x75 },
+ { CCI_REG8(0x5c29), 0x75 }, { CCI_REG8(0x5c2a), 0x75 },
+ { CCI_REG8(0x5c2b), 0x75 }, { CCI_REG8(0x5c2c), 0x75 },
+ { CCI_REG8(0x5c2d), 0x75 }, { CCI_REG8(0x5c2e), 0x75 },
+ { CCI_REG8(0x5c2f), 0x75 }, { CCI_REG8(0x5c30), 0x75 },
+ { CCI_REG8(0x5c31), 0x75 }, { CCI_REG8(0x5c32), 0x75 },
+ { CCI_REG8(0x5c33), 0x75 }, { CCI_REG8(0x5c34), 0x75 },
+ { CCI_REG8(0x5c35), 0x75 }, { CCI_REG8(0x5c36), 0x75 },
+ { CCI_REG8(0x5c37), 0x75 }, { CCI_REG8(0x5c38), 0x75 },
+ { CCI_REG8(0x5c39), 0x75 }, { CCI_REG8(0x5c3a), 0x75 },
+ { CCI_REG8(0x5c3b), 0x75 }, { CCI_REG8(0x5c3c), 0x75 },
+ { CCI_REG8(0x5c3d), 0x75 }, { CCI_REG8(0x5c3e), 0x75 },
+ { CCI_REG8(0x5c3f), 0x75 }, { CCI_REG8(0x5c40), 0x75 },
+ { CCI_REG8(0x5c41), 0x75 }, { CCI_REG8(0x5c42), 0x75 },
+ { CCI_REG8(0x5c43), 0x75 }, { CCI_REG8(0x5c44), 0x75 },
+ { CCI_REG8(0x5c45), 0x75 }, { CCI_REG8(0x5c46), 0x75 },
+ { CCI_REG8(0x5c47), 0x75 }, { CCI_REG8(0x5c48), 0x75 },
+ { CCI_REG8(0x5c49), 0x75 }, { CCI_REG8(0x5c4a), 0x75 },
+ { CCI_REG8(0x5c4b), 0x75 }, { CCI_REG8(0x5c4c), 0x75 },
+ { CCI_REG8(0x5c4d), 0x75 }, { CCI_REG8(0x5c4e), 0x75 },
+ { CCI_REG8(0x5c4f), 0x75 }, { CCI_REG8(0x5c50), 0x75 },
+ { CCI_REG8(0x5c51), 0x75 }, { CCI_REG8(0x5c52), 0x75 },
+ { CCI_REG8(0x5c53), 0x75 }, { CCI_REG8(0x5c54), 0x75 },
+ { CCI_REG8(0x5c55), 0x75 }, { CCI_REG8(0x5c56), 0x75 },
+ { CCI_REG8(0x5c57), 0x75 }, { CCI_REG8(0x5c58), 0x75 },
+ { CCI_REG8(0x5c59), 0x75 }, { CCI_REG8(0x5c5a), 0x75 },
+ { CCI_REG8(0x5c5b), 0x75 }, { CCI_REG8(0x5c5c), 0x75 },
+ { CCI_REG8(0x5c5d), 0x75 }, { CCI_REG8(0x5c5e), 0x75 },
+ { CCI_REG8(0x5c5f), 0x75 }, { CCI_REG8(0x5c60), 0x75 },
+ { CCI_REG8(0x5c61), 0x75 }, { CCI_REG8(0x5c62), 0x75 },
+ { CCI_REG8(0x5c63), 0x75 }, { CCI_REG8(0x5c64), 0x75 },
+ { CCI_REG8(0x5c65), 0x75 }, { CCI_REG8(0x5c66), 0x75 },
+ { CCI_REG8(0x5c67), 0x75 }, { CCI_REG8(0x5c68), 0x75 },
+ { CCI_REG8(0x5c69), 0x75 }, { CCI_REG8(0x5c6a), 0x75 },
+ { CCI_REG8(0x5c6b), 0x75 }, { CCI_REG8(0x5c6c), 0x75 },
+ { CCI_REG8(0x5c6d), 0x75 }, { CCI_REG8(0x5c6e), 0x75 },
+ { CCI_REG8(0x5c6f), 0x75 }, { CCI_REG8(0x5c70), 0x75 },
+ { CCI_REG8(0x5c71), 0x75 }, { CCI_REG8(0x5c72), 0x75 },
+ { CCI_REG8(0x5c73), 0x75 }, { CCI_REG8(0x5c74), 0x75 },
+ { CCI_REG8(0x5c75), 0x75 }, { CCI_REG8(0x5c76), 0x75 },
+ { CCI_REG8(0x5c77), 0x75 }, { CCI_REG8(0x5c78), 0x75 },
+ { CCI_REG8(0x5c79), 0x75 }, { CCI_REG8(0x5c7a), 0x75 },
+ { CCI_REG8(0x5c7b), 0x75 }, { CCI_REG8(0x5c7c), 0x75 },
+ { CCI_REG8(0x5c7d), 0x75 }, { CCI_REG8(0x5c7e), 0x75 },
+ { CCI_REG8(0x5c7f), 0x75 }, { CCI_REG8(0x5c80), 0x75 },
+ { CCI_REG8(0x5c81), 0x75 }, { CCI_REG8(0x5c82), 0x75 },
+ { CCI_REG8(0x5c83), 0x75 }, { CCI_REG8(0x5c84), 0x75 },
+ { CCI_REG8(0x5c85), 0x75 }, { CCI_REG8(0x5c86), 0x75 },
+ { CCI_REG8(0x5c87), 0x75 }, { CCI_REG8(0x5c88), 0x75 },
+ { CCI_REG8(0x5c89), 0x75 }, { CCI_REG8(0x5c8a), 0x75 },
+ { CCI_REG8(0x5c8b), 0x75 }, { CCI_REG8(0x5c8c), 0x75 },
+ { CCI_REG8(0x5c8d), 0x75 }, { CCI_REG8(0x5c8e), 0x75 },
+ { CCI_REG8(0x5c8f), 0x75 }, { CCI_REG8(0x5c90), 0x75 },
+ { CCI_REG8(0x5c91), 0x75 }, { CCI_REG8(0x5c92), 0x75 },
+ { CCI_REG8(0x5c93), 0x75 }, { CCI_REG8(0x5c94), 0x75 },
+ { CCI_REG8(0x5c95), 0x75 }, { CCI_REG8(0x5c96), 0x75 },
+ { CCI_REG8(0x5c97), 0x75 }, { CCI_REG8(0x5c98), 0x75 },
+ { CCI_REG8(0x5c99), 0x75 }, { CCI_REG8(0x5c9a), 0x75 },
+ { CCI_REG8(0x5c9b), 0x75 }, { CCI_REG8(0x5c9c), 0x75 },
+ { CCI_REG8(0x5c9d), 0x75 }, { CCI_REG8(0x5c9e), 0x75 },
+ { CCI_REG8(0x5c9f), 0x75 }, { CCI_REG8(0x5ca0), 0x75 },
+ { CCI_REG8(0x5ca1), 0x75 }, { CCI_REG8(0x5ca2), 0x75 },
+ { CCI_REG8(0x5ca3), 0x75 }, { CCI_REG8(0x5ca4), 0x75 },
+ { CCI_REG8(0x5ca5), 0x75 }, { CCI_REG8(0x5ca6), 0x75 },
+ { CCI_REG8(0x5ca7), 0x75 }, { CCI_REG8(0x5ca8), 0x75 },
+ { CCI_REG8(0x5ca9), 0x75 }, { CCI_REG8(0x5caa), 0x75 },
+ { CCI_REG8(0x5cab), 0x75 }, { CCI_REG8(0x5cac), 0x75 },
+ { CCI_REG8(0x5cad), 0x75 }, { CCI_REG8(0x5cae), 0x75 },
+ { CCI_REG8(0x5caf), 0x75 }, { CCI_REG8(0x5cb0), 0x75 },
+ { CCI_REG8(0x5cb1), 0x75 }, { CCI_REG8(0x5cb2), 0x75 },
+ { CCI_REG8(0x5cb3), 0x75 }, { CCI_REG8(0x5cb4), 0x75 },
+ { CCI_REG8(0x5cb5), 0x75 }, { CCI_REG8(0x5cb6), 0x75 },
+ { CCI_REG8(0x5cb7), 0x75 }, { CCI_REG8(0x5cb8), 0x75 },
+ { CCI_REG8(0x5cb9), 0x75 }, { CCI_REG8(0x5cba), 0x75 },
+ { CCI_REG8(0x5cbb), 0x75 }, { CCI_REG8(0x5cbc), 0x75 },
+ { CCI_REG8(0x5cbd), 0x75 }, { CCI_REG8(0x5cbe), 0x75 },
+ { CCI_REG8(0x5cbf), 0x75 }, { CCI_REG8(0x5cc0), 0x75 },
+ { CCI_REG8(0x5cc1), 0x75 }, { CCI_REG8(0x5cc2), 0x75 },
+ { CCI_REG8(0x5cc3), 0x75 }, { CCI_REG8(0x5cc4), 0x75 },
+ { CCI_REG8(0x5cc5), 0x75 }, { CCI_REG8(0x5cc6), 0x75 },
+ { CCI_REG8(0x5cc7), 0x75 }, { CCI_REG8(0x5cc8), 0x75 },
+ { CCI_REG8(0x5cc9), 0x75 }, { CCI_REG8(0x5cca), 0x75 },
+ { CCI_REG8(0x5ccb), 0x75 }, { CCI_REG8(0x5ccc), 0x75 },
+ { CCI_REG8(0x5ccd), 0x75 }, { CCI_REG8(0x5cce), 0x75 },
+ { CCI_REG8(0x5ccf), 0x75 }, { CCI_REG8(0x5cd0), 0x75 },
+ { CCI_REG8(0x5cd1), 0x75 }, { CCI_REG8(0x5cd2), 0x75 },
+ { CCI_REG8(0x5cd3), 0x75 }, { CCI_REG8(0x5cd4), 0x75 },
+ { CCI_REG8(0x5cd5), 0x75 }, { CCI_REG8(0x5cd6), 0x75 },
+ { CCI_REG8(0x5cd7), 0x75 }, { CCI_REG8(0x5cd8), 0x75 },
+ { CCI_REG8(0x5cd9), 0x75 }, { CCI_REG8(0x5cda), 0x75 },
+ { CCI_REG8(0x5cdb), 0x75 }, { CCI_REG8(0x5cdc), 0x75 },
+ { CCI_REG8(0x5cdd), 0x75 }, { CCI_REG8(0x5cde), 0x75 },
+ { CCI_REG8(0x5cdf), 0x75 }, { CCI_REG8(0x5ce0), 0x75 },
+ { CCI_REG8(0x5ce1), 0x75 }, { CCI_REG8(0x5ce2), 0x75 },
+ { CCI_REG8(0x5ce3), 0x75 }, { CCI_REG8(0x5ce4), 0x75 },
+ { CCI_REG8(0x5ce5), 0x75 }, { CCI_REG8(0x5ce6), 0x75 },
+ { CCI_REG8(0x5ce7), 0x75 }, { CCI_REG8(0x5ce8), 0x75 },
+ { CCI_REG8(0x5ce9), 0x75 }, { CCI_REG8(0x5cea), 0x75 },
+ { CCI_REG8(0x5ceb), 0x75 }, { CCI_REG8(0x5cec), 0x75 },
+ { CCI_REG8(0x5ced), 0x75 }, { CCI_REG8(0x5cee), 0x75 },
+ { CCI_REG8(0x5cef), 0x75 }, { CCI_REG8(0x5cf0), 0x75 },
+ { CCI_REG8(0x5cf1), 0x75 }, { CCI_REG8(0x5cf2), 0x75 },
+ { CCI_REG8(0x5cf3), 0x75 }, { CCI_REG8(0x5cf4), 0x75 },
+ { CCI_REG8(0x5cf5), 0x75 }, { CCI_REG8(0x5cf6), 0x75 },
+ { CCI_REG8(0x5cf7), 0x75 }, { CCI_REG8(0x5cf8), 0x75 },
+ { CCI_REG8(0x5cf9), 0x75 }, { CCI_REG8(0x5cfa), 0x75 },
+ { CCI_REG8(0x5cfb), 0x75 }, { CCI_REG8(0x5cfc), 0x75 },
+ { CCI_REG8(0x5cfd), 0x75 }, { CCI_REG8(0x5cfe), 0x75 },
+ { CCI_REG8(0x5cff), 0x75 }, { CCI_REG8(0x5d00), 0x75 },
+ { CCI_REG8(0x5d01), 0x75 }, { CCI_REG8(0x5d02), 0x75 },
+ { CCI_REG8(0x5d03), 0x75 }, { CCI_REG8(0x5d04), 0x75 },
+ { CCI_REG8(0x5d05), 0x75 }, { CCI_REG8(0x5d06), 0x75 },
+ { CCI_REG8(0x5d07), 0x75 }, { CCI_REG8(0x5d08), 0x75 },
+ { CCI_REG8(0x5d09), 0x75 }, { CCI_REG8(0x5d0a), 0x75 },
+ { CCI_REG8(0x5d0b), 0x75 }, { CCI_REG8(0x5d0c), 0x75 },
+ { CCI_REG8(0x5d0d), 0x75 }, { CCI_REG8(0x5d0e), 0x75 },
+ { CCI_REG8(0x5d0f), 0x75 }, { CCI_REG8(0x5d10), 0x75 },
+ { CCI_REG8(0x5d11), 0x75 }, { CCI_REG8(0x5d12), 0x75 },
+ { CCI_REG8(0x5d13), 0x75 }, { CCI_REG8(0x5d14), 0x75 },
+ { CCI_REG8(0x5d15), 0x75 }, { CCI_REG8(0x5d16), 0x75 },
+ { CCI_REG8(0x5d17), 0x75 }, { CCI_REG8(0x5d18), 0x75 },
+ { CCI_REG8(0x5d19), 0x75 }, { CCI_REG8(0x5d1a), 0x75 },
+ { CCI_REG8(0x5d1b), 0x75 }, { CCI_REG8(0x5d1c), 0x75 },
+ { CCI_REG8(0x5d1d), 0x75 }, { CCI_REG8(0x5d1e), 0x75 },
+ { CCI_REG8(0x5d1f), 0x75 }, { CCI_REG8(0x5d20), 0x75 },
+ { CCI_REG8(0x5d21), 0x75 }, { CCI_REG8(0x5d22), 0x75 },
+ { CCI_REG8(0x5d23), 0x75 }, { CCI_REG8(0x5d24), 0x75 },
+ { CCI_REG8(0x5d25), 0x75 }, { CCI_REG8(0x5d26), 0x75 },
+ { CCI_REG8(0x5d27), 0x75 }, { CCI_REG8(0x5d28), 0x75 },
+ { CCI_REG8(0x5d29), 0x75 }, { CCI_REG8(0x5d2a), 0x75 },
+ { CCI_REG8(0x5d2b), 0x75 }, { CCI_REG8(0x5d2c), 0x75 },
+ { CCI_REG8(0x5d2d), 0x75 }, { CCI_REG8(0x5d2e), 0x75 },
+ { CCI_REG8(0x5d2f), 0x75 }, { CCI_REG8(0x5d30), 0x75 },
+ { CCI_REG8(0x5d31), 0x75 }, { CCI_REG8(0x5d32), 0x75 },
+ { CCI_REG8(0x5d33), 0x75 }, { CCI_REG8(0x5d34), 0x75 },
+ { CCI_REG8(0x5d35), 0x75 }, { CCI_REG8(0x5d36), 0x75 },
+ { CCI_REG8(0x5d37), 0x75 }, { CCI_REG8(0x5d38), 0x75 },
+ { CCI_REG8(0x5d39), 0x75 }, { CCI_REG8(0x5d3a), 0x75 },
+ { CCI_REG8(0x5d3b), 0x75 }, { CCI_REG8(0x5d3c), 0x75 },
+ { CCI_REG8(0x5d3d), 0x75 }, { CCI_REG8(0x5d3e), 0x75 },
+ { CCI_REG8(0x5d3f), 0x75 }, { CCI_REG8(0x5d40), 0x75 },
+ { CCI_REG8(0x5d41), 0x75 }, { CCI_REG8(0x5d42), 0x75 },
+ { CCI_REG8(0x5d43), 0x75 }, { CCI_REG8(0x5d44), 0x75 },
+ { CCI_REG8(0x5d45), 0x75 }, { CCI_REG8(0x5d46), 0x75 },
+ { CCI_REG8(0x5d47), 0x75 }, { CCI_REG8(0x5d48), 0x75 },
+ { CCI_REG8(0x5d49), 0x75 }, { CCI_REG8(0x5d4a), 0x75 },
+ { CCI_REG8(0x5d4b), 0x75 }, { CCI_REG8(0x5d4c), 0x75 },
+ { CCI_REG8(0x5d4d), 0x75 }, { CCI_REG8(0x5d4e), 0x75 },
+ { CCI_REG8(0x5d4f), 0x75 }, { CCI_REG8(0x5d50), 0x75 },
+ { CCI_REG8(0x5d51), 0x75 }, { CCI_REG8(0x5d52), 0x75 },
+ { CCI_REG8(0x5d53), 0x75 }, { CCI_REG8(0x5d54), 0x75 },
+ { CCI_REG8(0x5d55), 0x75 }, { CCI_REG8(0x5d56), 0x75 },
+ { CCI_REG8(0x5d57), 0x75 }, { CCI_REG8(0x5d58), 0x75 },
+ { CCI_REG8(0x5d59), 0x75 }, { CCI_REG8(0x5d5a), 0x75 },
+ { CCI_REG8(0x5d5b), 0x75 }, { CCI_REG8(0x5d5c), 0x75 },
+ { CCI_REG8(0x5d5d), 0x75 }, { CCI_REG8(0x5d5e), 0x75 },
+ { CCI_REG8(0x5d5f), 0x75 }, { CCI_REG8(0x5d60), 0x75 },
+ { CCI_REG8(0x5d61), 0x75 }, { CCI_REG8(0x5d62), 0x75 },
+ { CCI_REG8(0x5d63), 0x75 }, { CCI_REG8(0x5d64), 0x75 },
+ { CCI_REG8(0x5d65), 0x75 }, { CCI_REG8(0x5d66), 0x75 },
+ { CCI_REG8(0x5d67), 0x75 }, { CCI_REG8(0x5d68), 0x75 },
+ { CCI_REG8(0x5d69), 0x75 }, { CCI_REG8(0x5d6a), 0x75 },
+ { CCI_REG8(0x5d6b), 0x75 }, { CCI_REG8(0x5d6c), 0x75 },
+ { CCI_REG8(0x5d6d), 0x75 }, { CCI_REG8(0x5d6e), 0x75 },
+ { CCI_REG8(0x5d6f), 0x75 }, { CCI_REG8(0x5d70), 0x75 },
+ { CCI_REG8(0x5d71), 0x75 }, { CCI_REG8(0x5d72), 0x75 },
+ { CCI_REG8(0x5d73), 0x75 }, { CCI_REG8(0x5d74), 0x75 },
+ { CCI_REG8(0x5d75), 0x75 }, { CCI_REG8(0x5d76), 0x75 },
+ { CCI_REG8(0x5d77), 0x75 }, { CCI_REG8(0x5d78), 0x75 },
+ { CCI_REG8(0x5d79), 0x75 }, { CCI_REG8(0x5d7a), 0x75 },
+ { CCI_REG8(0x5d7b), 0x75 }, { CCI_REG8(0x5d7c), 0x75 },
+ { CCI_REG8(0x5d7d), 0x75 }, { CCI_REG8(0x5d7e), 0x75 },
+ { CCI_REG8(0x5d7f), 0x75 }, { CCI_REG8(0x5d80), 0x75 },
+ { CCI_REG8(0x5d81), 0x75 }, { CCI_REG8(0x5d82), 0x75 },
+ { CCI_REG8(0x5d83), 0x75 }, { CCI_REG8(0x5d84), 0x75 },
+ { CCI_REG8(0x5d85), 0x75 }, { CCI_REG8(0x5d86), 0x75 },
+ { CCI_REG8(0x5d87), 0x75 }, { CCI_REG8(0x5d88), 0x75 },
+ { CCI_REG8(0x5d89), 0x75 }, { CCI_REG8(0x5d8a), 0x75 },
+ { CCI_REG8(0x5d8b), 0x75 }, { CCI_REG8(0x5d8c), 0x75 },
+ { CCI_REG8(0x5d8d), 0x75 }, { CCI_REG8(0x5d8e), 0x75 },
+ { CCI_REG8(0x5d8f), 0x75 }, { CCI_REG8(0x5d90), 0x75 },
+ { CCI_REG8(0x5d91), 0x75 }, { CCI_REG8(0x5d92), 0x75 },
+ { CCI_REG8(0x5d93), 0x75 }, { CCI_REG8(0x5d94), 0x75 },
+ { CCI_REG8(0x5d95), 0x75 }, { CCI_REG8(0x5d96), 0x75 },
+ { CCI_REG8(0x5d97), 0x75 }, { CCI_REG8(0x5d98), 0x75 },
+ { CCI_REG8(0x5d99), 0x75 }, { CCI_REG8(0x5d9a), 0x75 },
+ { CCI_REG8(0x5d9b), 0x75 }, { CCI_REG8(0x5d9c), 0x75 },
+ { CCI_REG8(0x5d9d), 0x75 }, { CCI_REG8(0x5d9e), 0x75 },
+ { CCI_REG8(0x5d9f), 0x75 }, { CCI_REG8(0x5da0), 0x75 },
+ { CCI_REG8(0x5da1), 0x75 }, { CCI_REG8(0x5da2), 0x75 },
+ { CCI_REG8(0x5da3), 0x75 }, { CCI_REG8(0x5da4), 0x75 },
+ { CCI_REG8(0x5da5), 0x75 }, { CCI_REG8(0x5da6), 0x75 },
+ { CCI_REG8(0x5da7), 0x75 }, { CCI_REG8(0x5da8), 0x75 },
+ { CCI_REG8(0x5da9), 0x75 }, { CCI_REG8(0x5daa), 0x75 },
+ { CCI_REG8(0x5dab), 0x75 }, { CCI_REG8(0x5dac), 0x75 },
+ { CCI_REG8(0x5dad), 0x75 }, { CCI_REG8(0x5dae), 0x75 },
+ { CCI_REG8(0x5daf), 0x75 }, { CCI_REG8(0x5db0), 0x75 },
+ { CCI_REG8(0x5db1), 0x75 }, { CCI_REG8(0x5db2), 0x75 },
+ { CCI_REG8(0x5db3), 0x75 }, { CCI_REG8(0x5db4), 0x75 },
+ { CCI_REG8(0x5db5), 0x75 }, { CCI_REG8(0x5db6), 0x75 },
+ { CCI_REG8(0x5db7), 0x75 }, { CCI_REG8(0x5db8), 0x75 },
+ { CCI_REG8(0x5db9), 0x75 }, { CCI_REG8(0x5dba), 0x75 },
+ { CCI_REG8(0x5dbb), 0x75 }, { CCI_REG8(0x5dbc), 0x75 },
+ { CCI_REG8(0x5dbd), 0x75 }, { CCI_REG8(0x5dbe), 0x75 },
+ { CCI_REG8(0x5dbf), 0x75 }, { CCI_REG8(0x5dc0), 0x75 },
+ { CCI_REG8(0x5dc1), 0x75 }, { CCI_REG8(0x5dc2), 0x75 },
+ { CCI_REG8(0x5dc3), 0x75 }, { CCI_REG8(0x5dc4), 0x75 },
+ { CCI_REG8(0x5dc5), 0x75 }, { CCI_REG8(0x5dc6), 0x75 },
+ { CCI_REG8(0x5dc7), 0x75 }, { CCI_REG8(0x5dc8), 0x75 },
+ { CCI_REG8(0x5dc9), 0x75 }, { CCI_REG8(0x5dca), 0x75 },
+ { CCI_REG8(0x5dcb), 0x75 }, { CCI_REG8(0x5dcc), 0x75 },
+ { CCI_REG8(0x5dcd), 0x75 }, { CCI_REG8(0x5dce), 0x75 },
+ { CCI_REG8(0x5dcf), 0x75 }, { CCI_REG8(0x5dd0), 0x75 },
+ { CCI_REG8(0x5dd1), 0x75 }, { CCI_REG8(0x5dd2), 0x75 },
+ { CCI_REG8(0x5dd3), 0x75 }, { CCI_REG8(0x5dd4), 0x75 },
+ { CCI_REG8(0x5dd5), 0x75 }, { CCI_REG8(0x5dd6), 0x75 },
+ { CCI_REG8(0x5dd7), 0x75 }, { CCI_REG8(0x5dd8), 0x75 },
+ { CCI_REG8(0x5dd9), 0x75 }, { CCI_REG8(0x5dda), 0x75 },
+ { CCI_REG8(0x5ddb), 0x75 }, { CCI_REG8(0x5ddc), 0x75 },
+ { CCI_REG8(0x5ddd), 0x75 }, { CCI_REG8(0x5dde), 0x75 },
+ { CCI_REG8(0x5ddf), 0x75 }, { CCI_REG8(0x5de0), 0x75 },
+ { CCI_REG8(0x5de1), 0x75 }, { CCI_REG8(0x5de2), 0x75 },
+ { CCI_REG8(0x5de3), 0x75 }, { CCI_REG8(0x5de4), 0x75 },
+ { CCI_REG8(0x5de5), 0x75 }, { CCI_REG8(0x5de6), 0x75 },
+ { CCI_REG8(0x5de7), 0x75 }, { CCI_REG8(0x5de8), 0x75 },
+ { CCI_REG8(0x5de9), 0x75 }, { CCI_REG8(0x5dea), 0x75 },
+ { CCI_REG8(0x5deb), 0x75 }, { CCI_REG8(0x5dec), 0x75 },
+ { CCI_REG8(0x5ded), 0x75 }, { CCI_REG8(0x5dee), 0x75 },
+ { CCI_REG8(0x5def), 0x75 }, { CCI_REG8(0x5df0), 0x75 },
+ { CCI_REG8(0x5df1), 0x75 }, { CCI_REG8(0x5df2), 0x75 },
+ { CCI_REG8(0x5df3), 0x75 }, { CCI_REG8(0x5df4), 0x75 },
+ { CCI_REG8(0x5df5), 0x75 }, { CCI_REG8(0x5df6), 0x75 },
+ { CCI_REG8(0x5df7), 0x75 }, { CCI_REG8(0x5df8), 0x75 },
+ { CCI_REG8(0x5df9), 0x75 }, { CCI_REG8(0x5dfa), 0x75 },
+ { CCI_REG8(0x5dfb), 0x75 }, { CCI_REG8(0x5dfc), 0x75 },
+ { CCI_REG8(0x5dfd), 0x75 }, { CCI_REG8(0x5dfe), 0x75 },
+ { CCI_REG8(0x5dff), 0x75 }, { CCI_REG8(0x5e00), 0x75 },
+ { CCI_REG8(0x5e01), 0x75 }, { CCI_REG8(0x5e02), 0x75 },
+ { CCI_REG8(0x5e03), 0x75 }, { CCI_REG8(0x5e04), 0x75 },
+ { CCI_REG8(0x5e05), 0x75 }, { CCI_REG8(0x5e06), 0x75 },
+ { CCI_REG8(0x5e07), 0x75 }, { CCI_REG8(0x5e08), 0x75 },
+ { CCI_REG8(0x5e09), 0x75 }, { CCI_REG8(0x5e0a), 0x75 },
+ { CCI_REG8(0x5e0b), 0x75 }, { CCI_REG8(0x5e0c), 0x75 },
+ { CCI_REG8(0x5e0d), 0x75 }, { CCI_REG8(0x5e0e), 0x75 },
+ { CCI_REG8(0x5e0f), 0x75 }, { CCI_REG8(0x5e10), 0x75 },
+ { CCI_REG8(0x5e11), 0x75 }, { CCI_REG8(0x5e12), 0x75 },
+ { CCI_REG8(0x5e13), 0x75 }, { CCI_REG8(0x5e14), 0x75 },
+ { CCI_REG8(0x5e15), 0x75 }, { CCI_REG8(0x5e16), 0x75 },
+ { CCI_REG8(0x5e17), 0x75 }, { CCI_REG8(0x5e18), 0x75 },
+ { CCI_REG8(0x5e19), 0x75 }, { CCI_REG8(0x5e1a), 0x75 },
+ { CCI_REG8(0x5e1b), 0x75 }, { CCI_REG8(0x5e1c), 0x75 },
+ { CCI_REG8(0x5e1d), 0x75 }, { CCI_REG8(0x5e1e), 0x75 },
+ { CCI_REG8(0x5e1f), 0x75 }, { CCI_REG8(0x5e20), 0x75 },
+ { CCI_REG8(0x5e21), 0x75 }, { CCI_REG8(0x5e22), 0x75 },
+ { CCI_REG8(0x5e23), 0x75 }, { CCI_REG8(0x5e24), 0x75 },
+ { CCI_REG8(0x5e25), 0x75 }, { CCI_REG8(0x5e26), 0x75 },
+ { CCI_REG8(0x5e27), 0x75 }, { CCI_REG8(0x5e28), 0x75 },
+ { CCI_REG8(0x5e29), 0x75 }, { CCI_REG8(0x5e2a), 0x75 },
+ { CCI_REG8(0x5e2b), 0x75 }, { CCI_REG8(0x5e2c), 0x75 },
+ { CCI_REG8(0x5e2d), 0x75 }, { CCI_REG8(0x5e2e), 0x75 },
+ { CCI_REG8(0x5e2f), 0x75 }, { CCI_REG8(0x5e30), 0x75 },
+ { CCI_REG8(0x5e31), 0x75 }, { CCI_REG8(0x5e32), 0x75 },
+ { CCI_REG8(0x5e33), 0x75 }, { CCI_REG8(0x5e34), 0x75 },
+ { CCI_REG8(0x5e35), 0x75 }, { CCI_REG8(0x5e36), 0x75 },
+ { CCI_REG8(0x5e37), 0x75 }, { CCI_REG8(0x5e38), 0x75 },
+ { CCI_REG8(0x5e39), 0x75 }, { CCI_REG8(0x5e3a), 0x75 },
+ { CCI_REG8(0x5e3b), 0x75 }, { CCI_REG8(0x5e3c), 0x75 },
+ { CCI_REG8(0x5e3d), 0x75 }, { CCI_REG8(0x5e3e), 0x75 },
+ { CCI_REG8(0x5e3f), 0x75 }, { CCI_REG8(0x5e40), 0x75 },
+ { CCI_REG8(0x5e41), 0x75 }, { CCI_REG8(0x5e42), 0x75 },
+ { CCI_REG8(0x5e43), 0x75 }, { CCI_REG8(0x5e44), 0x75 },
+ { CCI_REG8(0x5e45), 0x75 }, { CCI_REG8(0x5e46), 0x75 },
+ { CCI_REG8(0x5e47), 0x75 }, { CCI_REG8(0x5e48), 0x75 },
+ { CCI_REG8(0x5e49), 0x75 }, { CCI_REG8(0x5e4a), 0x75 },
+ { CCI_REG8(0x5e4b), 0x75 }, { CCI_REG8(0x5e4c), 0x75 },
+ { CCI_REG8(0x5e4d), 0x75 }, { CCI_REG8(0x5e4e), 0x75 },
+ { CCI_REG8(0x5e4f), 0x75 }, { CCI_REG8(0x5e50), 0x75 },
+ { CCI_REG8(0x5e51), 0x75 }, { CCI_REG8(0x5e52), 0x75 },
+ { CCI_REG8(0x5e53), 0x75 }, { CCI_REG8(0x5e54), 0x75 },
+ { CCI_REG8(0x5e55), 0x75 }, { CCI_REG8(0x5e56), 0x75 },
+ { CCI_REG8(0x5e57), 0x75 }, { CCI_REG8(0x5e58), 0x75 },
+ { CCI_REG8(0x5e59), 0x75 }, { CCI_REG8(0x5e5a), 0x75 },
+ { CCI_REG8(0x5e5b), 0x75 }, { CCI_REG8(0x5e5c), 0x75 },
+ { CCI_REG8(0x5e5d), 0x75 }, { CCI_REG8(0x5e5e), 0x75 },
+ { CCI_REG8(0x5e5f), 0x75 }, { CCI_REG8(0x5e60), 0x75 },
+ { CCI_REG8(0x5e61), 0x75 }, { CCI_REG8(0x5e62), 0x75 },
+ { CCI_REG8(0x5e63), 0x75 }, { CCI_REG8(0x5e64), 0x75 },
+ { CCI_REG8(0x5e65), 0x75 }, { CCI_REG8(0x5e66), 0x75 },
+ { CCI_REG8(0x5e67), 0x75 }, { CCI_REG8(0x5e68), 0x75 },
+ { CCI_REG8(0x5e69), 0x75 }, { CCI_REG8(0x5e6a), 0x75 },
+ { CCI_REG8(0x5e6b), 0x75 }, { CCI_REG8(0x5e6c), 0x75 },
+ { CCI_REG8(0x5e6d), 0x75 }, { CCI_REG8(0x5e6e), 0x75 },
+ { CCI_REG8(0x5e6f), 0x75 }, { CCI_REG8(0x5e70), 0x75 },
+ { CCI_REG8(0x5e71), 0x75 }, { CCI_REG8(0x5e72), 0x75 },
+ { CCI_REG8(0x5e73), 0x75 }, { CCI_REG8(0x5e74), 0x75 },
+ { CCI_REG8(0x5e75), 0x75 }, { CCI_REG8(0x5e76), 0x75 },
+ { CCI_REG8(0x5e77), 0x75 }, { CCI_REG8(0x5e78), 0x75 },
+ { CCI_REG8(0x5e79), 0x75 }, { CCI_REG8(0x5e7a), 0x75 },
+ { CCI_REG8(0x5e7b), 0x75 }, { CCI_REG8(0x5e7c), 0x75 },
+ { CCI_REG8(0x5e7d), 0x75 }, { CCI_REG8(0x5e7e), 0x75 },
+ { CCI_REG8(0x5e7f), 0x75 }, { CCI_REG8(0x5e80), 0x75 },
+ { CCI_REG8(0x5e81), 0x75 }, { CCI_REG8(0x5e82), 0x75 },
+ { CCI_REG8(0x5e83), 0x75 }, { CCI_REG8(0x5e84), 0x75 },
+ { CCI_REG8(0x5e85), 0x75 }, { CCI_REG8(0x5e86), 0x75 },
+ { CCI_REG8(0x5e87), 0x75 }, { CCI_REG8(0x5e88), 0x75 },
+ { CCI_REG8(0x5e89), 0x75 }, { CCI_REG8(0x5e8a), 0x75 },
+ { CCI_REG8(0x5e8b), 0x75 }, { CCI_REG8(0x5e8c), 0x75 },
+ { CCI_REG8(0x5e8d), 0x75 }, { CCI_REG8(0x5e8e), 0x75 },
+ { CCI_REG8(0x5e8f), 0x75 }, { CCI_REG8(0x5e90), 0x75 },
+ { CCI_REG8(0x5e91), 0x75 }, { CCI_REG8(0x5e92), 0x75 },
+ { CCI_REG8(0x5e93), 0x75 }, { CCI_REG8(0x5e94), 0x75 },
+ { CCI_REG8(0x5e95), 0x75 }, { CCI_REG8(0x5e96), 0x75 },
+ { CCI_REG8(0x5e97), 0x75 }, { CCI_REG8(0x5e98), 0x75 },
+ { CCI_REG8(0x5e99), 0x75 }, { CCI_REG8(0x5e9a), 0x75 },
+ { CCI_REG8(0x5e9b), 0x75 }, { CCI_REG8(0x5e9c), 0x75 },
+ { CCI_REG8(0x5e9d), 0x75 }, { CCI_REG8(0x5e9e), 0x75 },
+ { CCI_REG8(0x5e9f), 0x75 }, { CCI_REG8(0x5ea0), 0x75 },
+ { CCI_REG8(0x5ea1), 0x75 }, { CCI_REG8(0x5ea2), 0x75 },
+ { CCI_REG8(0x5ea3), 0x75 }, { CCI_REG8(0x5ea4), 0x75 },
+ { CCI_REG8(0x5ea5), 0x75 }, { CCI_REG8(0x5ea6), 0x75 },
+ { CCI_REG8(0x5ea7), 0x75 }, { CCI_REG8(0x5ea8), 0x75 },
+ { CCI_REG8(0x5ea9), 0x75 }, { CCI_REG8(0x5eaa), 0x75 },
+ { CCI_REG8(0x5eab), 0x75 }, { CCI_REG8(0x5eac), 0x75 },
+ { CCI_REG8(0x5ead), 0x75 }, { CCI_REG8(0x5eae), 0x75 },
+ { CCI_REG8(0x5eaf), 0x75 }, { CCI_REG8(0x5eb0), 0x75 },
+ { CCI_REG8(0x5eb1), 0x75 }, { CCI_REG8(0x5eb2), 0x75 },
+ { CCI_REG8(0x5eb3), 0x75 }, { CCI_REG8(0x5eb4), 0x75 },
+ { CCI_REG8(0x5eb5), 0x75 }, { CCI_REG8(0x5eb6), 0x75 },
+ { CCI_REG8(0x5eb7), 0x75 }, { CCI_REG8(0x5eb8), 0x75 },
+ { CCI_REG8(0x5eb9), 0x75 }, { CCI_REG8(0x5eba), 0x75 },
+ { CCI_REG8(0x5ebb), 0x75 }, { CCI_REG8(0x5ebc), 0x75 },
+ { CCI_REG8(0x5ebd), 0x75 }, { CCI_REG8(0x5ebe), 0x75 },
+ { CCI_REG8(0x5ebf), 0x75 }, { CCI_REG8(0x5ec0), 0x75 },
+ { CCI_REG8(0x5ec1), 0x75 }, { CCI_REG8(0x5ec2), 0x75 },
+ { CCI_REG8(0x5ec3), 0x75 }, { CCI_REG8(0x5ec4), 0x75 },
+ { CCI_REG8(0x5ec5), 0x75 }, { CCI_REG8(0x5ec6), 0x75 },
+ { CCI_REG8(0x5ec7), 0x75 }, { CCI_REG8(0x5ec8), 0x75 },
+ { CCI_REG8(0x5ec9), 0x75 }, { CCI_REG8(0x5eca), 0x75 },
+ { CCI_REG8(0x5ecb), 0x75 }, { CCI_REG8(0x5ecc), 0x75 },
+ { CCI_REG8(0x5ecd), 0x75 }, { CCI_REG8(0x5ece), 0x75 },
+ { CCI_REG8(0x5ecf), 0x75 }, { CCI_REG8(0x5ed0), 0x75 },
+ { CCI_REG8(0x5ed1), 0x75 }, { CCI_REG8(0x5ed2), 0x75 },
+ { CCI_REG8(0x5ed3), 0x75 }, { CCI_REG8(0x5ed4), 0x75 },
+ { CCI_REG8(0x5ed5), 0x75 }, { CCI_REG8(0x5ed6), 0x75 },
+ { CCI_REG8(0x5ed7), 0x75 }, { CCI_REG8(0x5ed8), 0x75 },
+ { CCI_REG8(0x5ed9), 0x75 }, { CCI_REG8(0x5eda), 0x75 },
+ { CCI_REG8(0x5edb), 0x75 }, { CCI_REG8(0x5edc), 0x75 },
+ { CCI_REG8(0x5edd), 0x75 }, { CCI_REG8(0x5ede), 0x75 },
+ { CCI_REG8(0x5edf), 0x75 }, { CCI_REG8(0xfff9), 0x08 },
+ { CCI_REG8(0x1570), 0x00 }, { CCI_REG8(0x15d0), 0x00 },
+ { CCI_REG8(0x15a0), 0x02 }, { CCI_REG8(0x15a1), 0x00 },
+ { CCI_REG8(0x15a2), 0x02 }, { CCI_REG8(0x15a3), 0x76 },
+ { CCI_REG8(0x15a4), 0x03 }, { CCI_REG8(0x15a5), 0x08 },
+ { CCI_REG8(0x15a6), 0x00 }, { CCI_REG8(0x15a7), 0x60 },
+ { CCI_REG8(0x15a8), 0x01 }, { CCI_REG8(0x15a9), 0x00 },
+ { CCI_REG8(0x15aa), 0x02 }, { CCI_REG8(0x15ab), 0x00 },
+ { CCI_REG8(0x1600), 0x02 }, { CCI_REG8(0x1601), 0x00 },
+ { CCI_REG8(0x1602), 0x02 }, { CCI_REG8(0x1603), 0x76 },
+ { CCI_REG8(0x1604), 0x03 }, { CCI_REG8(0x1605), 0x08 },
+ { CCI_REG8(0x1606), 0x00 }, { CCI_REG8(0x1607), 0x60 },
+ { CCI_REG8(0x1608), 0x01 }, { CCI_REG8(0x1609), 0x00 },
+ { CCI_REG8(0x160a), 0x02 }, { CCI_REG8(0x160b), 0x00 },
+ { CCI_REG8(0x1633), 0x03 }, { CCI_REG8(0x1634), 0x01 },
+ { CCI_REG8(0x163c), 0x3a }, { CCI_REG8(0x163d), 0x01 },
+ { CCI_REG8(0x1648), 0x32 }, { CCI_REG8(0x1658), 0x01 },
+ { CCI_REG8(0x1659), 0x01 }, { CCI_REG8(0x165f), 0x01 },
+ { CCI_REG8(0x1677), 0x01 }, { CCI_REG8(0x1690), 0x08 },
+ { CCI_REG8(0x1691), 0x00 }, { CCI_REG8(0x1692), 0x20 },
+ { CCI_REG8(0x1693), 0x00 }, { CCI_REG8(0x1694), 0x10 },
+ { CCI_REG8(0x1695), 0x14 }, { CCI_REG8(0x1696), 0x10 },
+ { CCI_REG8(0x1697), 0x0e }, { CCI_REG8(0x1730), 0x01 },
+ { CCI_REG8(0x1732), 0x00 }, { CCI_REG8(0x1733), 0x10 },
+ { CCI_REG8(0x1734), 0x01 }, { CCI_REG8(0x1735), 0x00 },
+ { CCI_REG8(0x1748), 0x01 }, { CCI_REG8(0xfff9), 0x06 },
+ { CCI_REG8(0x5000), 0xff }, { CCI_REG8(0x5001), 0x3d },
+ { CCI_REG8(0x5002), 0xf5 }, { CCI_REG8(0x5004), 0x80 },
+ { CCI_REG8(0x5006), 0x04 }, { CCI_REG8(0x5061), 0x20 },
+ { CCI_REG8(0x5063), 0x20 }, { CCI_REG8(0x5064), 0x24 },
+ { CCI_REG8(0x5065), 0x00 }, { CCI_REG8(0x5066), 0x1b },
+ { CCI_REG8(0x5067), 0x00 }, { CCI_REG8(0x5068), 0x03 },
+ { CCI_REG8(0x5069), 0x10 }, { CCI_REG8(0x506a), 0x20 },
+ { CCI_REG8(0x506b), 0x04 }, { CCI_REG8(0x506c), 0x04 },
+ { CCI_REG8(0x506d), 0x0c }, { CCI_REG8(0x506e), 0x0c },
+ { CCI_REG8(0x506f), 0x04 }, { CCI_REG8(0x5070), 0x0c },
+ { CCI_REG8(0x5071), 0x14 }, { CCI_REG8(0x5072), 0x1c },
+ { CCI_REG8(0x5073), 0x01 }, { CCI_REG8(0x5074), 0x01 },
+ { CCI_REG8(0x5075), 0xbe }, { CCI_REG8(0x5083), 0x00 },
+ { CCI_REG8(0x5114), 0x03 }, { CCI_REG8(0x51b0), 0x00 },
+ { CCI_REG8(0x51b3), 0x0e }, { CCI_REG8(0x51b5), 0x02 },
+ { CCI_REG8(0x51b6), 0x00 }, { CCI_REG8(0x51b7), 0x00 },
+ { CCI_REG8(0x51b8), 0x00 }, { CCI_REG8(0x51b9), 0x70 },
+ { CCI_REG8(0x51ba), 0x00 }, { CCI_REG8(0x51bb), 0x10 },
+ { CCI_REG8(0x51bc), 0x00 }, { CCI_REG8(0x51bd), 0x00 },
+ { CCI_REG8(0x51d2), 0xff }, { CCI_REG8(0x51d3), 0x1c },
+ { CCI_REG8(0x5250), 0x34 }, { CCI_REG8(0x5251), 0x00 },
+ { CCI_REG8(0x525b), 0x00 }, { CCI_REG8(0x525d), 0x00 },
+ { CCI_REG8(0x527a), 0x00 }, { CCI_REG8(0x527b), 0x38 },
+ { CCI_REG8(0x527c), 0x00 }, { CCI_REG8(0x527d), 0x4b },
+ { CCI_REG8(0x5286), 0x1b }, { CCI_REG8(0x5287), 0x40 },
+ { CCI_REG8(0x5290), 0x00 }, { CCI_REG8(0x5291), 0x50 },
+ { CCI_REG8(0x5292), 0x00 }, { CCI_REG8(0x5293), 0x50 },
+ { CCI_REG8(0x5294), 0x00 }, { CCI_REG8(0x5295), 0x50 },
+ { CCI_REG8(0x5296), 0x00 }, { CCI_REG8(0x5297), 0x50 },
+ { CCI_REG8(0x5298), 0x00 }, { CCI_REG8(0x5299), 0x50 },
+ { CCI_REG8(0x529a), 0x01 }, { CCI_REG8(0x529b), 0x00 },
+ { CCI_REG8(0x529c), 0x01 }, { CCI_REG8(0x529d), 0x00 },
+ { CCI_REG8(0x529e), 0x00 }, { CCI_REG8(0x529f), 0x50 },
+ { CCI_REG8(0x52a0), 0x00 }, { CCI_REG8(0x52a1), 0x50 },
+ { CCI_REG8(0x52a2), 0x01 }, { CCI_REG8(0x52a3), 0x00 },
+ { CCI_REG8(0x52a4), 0x01 }, { CCI_REG8(0x52a5), 0x00 },
+ { CCI_REG8(0x52a6), 0x00 }, { CCI_REG8(0x52a7), 0x50 },
+ { CCI_REG8(0x52a8), 0x00 }, { CCI_REG8(0x52a9), 0x50 },
+ { CCI_REG8(0x52aa), 0x00 }, { CCI_REG8(0x52ab), 0x50 },
+ { CCI_REG8(0x52ac), 0x00 }, { CCI_REG8(0x52ad), 0x50 },
+ { CCI_REG8(0x52ae), 0x00 }, { CCI_REG8(0x52af), 0x50 },
+ { CCI_REG8(0x52b0), 0x00 }, { CCI_REG8(0x52b1), 0x50 },
+ { CCI_REG8(0x52b2), 0x00 }, { CCI_REG8(0x52b3), 0x50 },
+ { CCI_REG8(0x52b4), 0x00 }, { CCI_REG8(0x52b5), 0x50 },
+ { CCI_REG8(0x52b6), 0x00 }, { CCI_REG8(0x52b7), 0x50 },
+ { CCI_REG8(0x52b8), 0x00 }, { CCI_REG8(0x52b9), 0x50 },
+ { CCI_REG8(0x52ba), 0x01 }, { CCI_REG8(0x52bb), 0x00 },
+ { CCI_REG8(0x52bc), 0x01 }, { CCI_REG8(0x52bd), 0x00 },
+ { CCI_REG8(0x52be), 0x00 }, { CCI_REG8(0x52bf), 0x50 },
+ { CCI_REG8(0x52c0), 0x00 }, { CCI_REG8(0x52c1), 0x50 },
+ { CCI_REG8(0x52c2), 0x01 }, { CCI_REG8(0x52c3), 0x00 },
+ { CCI_REG8(0x52c4), 0x01 }, { CCI_REG8(0x52c5), 0x00 },
+ { CCI_REG8(0x52c6), 0x00 }, { CCI_REG8(0x52c7), 0x50 },
+ { CCI_REG8(0x52c8), 0x00 }, { CCI_REG8(0x52c9), 0x50 },
+ { CCI_REG8(0x52ca), 0x00 }, { CCI_REG8(0x52cb), 0x50 },
+ { CCI_REG8(0x52cc), 0x00 }, { CCI_REG8(0x52cd), 0x50 },
+ { CCI_REG8(0x52ce), 0x00 }, { CCI_REG8(0x52cf), 0x50 },
+ { CCI_REG8(0x52f0), 0x04 }, { CCI_REG8(0x52f1), 0x03 },
+ { CCI_REG8(0x52f2), 0x02 }, { CCI_REG8(0x52f3), 0x01 },
+ { CCI_REG8(0x52f4), 0x08 }, { CCI_REG8(0x52f5), 0x07 },
+ { CCI_REG8(0x52f6), 0x06 }, { CCI_REG8(0x52f7), 0x05 },
+ { CCI_REG8(0x52f8), 0x0c }, { CCI_REG8(0x52f9), 0x0b },
+ { CCI_REG8(0x52fa), 0x0a }, { CCI_REG8(0x52fb), 0x09 },
+ { CCI_REG8(0x52fc), 0x10 }, { CCI_REG8(0x52fd), 0x0f },
+ { CCI_REG8(0x52fe), 0x0e }, { CCI_REG8(0x52ff), 0x0d },
+ { CCI_REG8(0x5300), 0x14 }, { CCI_REG8(0x5301), 0x13 },
+ { CCI_REG8(0x5302), 0x12 }, { CCI_REG8(0x5303), 0x11 },
+ { CCI_REG8(0x5304), 0x18 }, { CCI_REG8(0x5305), 0x17 },
+ { CCI_REG8(0x5306), 0x16 }, { CCI_REG8(0x5307), 0x15 },
+ { CCI_REG8(0x5308), 0x1c }, { CCI_REG8(0x5309), 0x1b },
+ { CCI_REG8(0x530a), 0x1a }, { CCI_REG8(0x530b), 0x19 },
+ { CCI_REG8(0x530c), 0x20 }, { CCI_REG8(0x530d), 0x1f },
+ { CCI_REG8(0x530e), 0x1e }, { CCI_REG8(0x530f), 0x1d },
+ { CCI_REG8(0x5310), 0x03 }, { CCI_REG8(0x5311), 0xe8 },
+ { CCI_REG8(0x5331), 0x0a }, { CCI_REG8(0x5332), 0x43 },
+ { CCI_REG8(0x5333), 0x45 }, { CCI_REG8(0x5353), 0x09 },
+ { CCI_REG8(0x5354), 0x00 }, { CCI_REG8(0x5414), 0x03 },
+ { CCI_REG8(0x54b0), 0x10 }, { CCI_REG8(0x54b3), 0x0e },
+ { CCI_REG8(0x54b5), 0x02 }, { CCI_REG8(0x54b6), 0x00 },
+ { CCI_REG8(0x54b7), 0x00 }, { CCI_REG8(0x54b8), 0x00 },
+ { CCI_REG8(0x54b9), 0x70 }, { CCI_REG8(0x54ba), 0x00 },
+ { CCI_REG8(0x54bb), 0x10 }, { CCI_REG8(0x54bc), 0x00 },
+ { CCI_REG8(0x54bd), 0x00 }, { CCI_REG8(0x54d2), 0xff },
+ { CCI_REG8(0x54d3), 0x1c }, { CCI_REG8(0x5510), 0x03 },
+ { CCI_REG8(0x5511), 0xe8 }, { CCI_REG8(0x5550), 0x6c },
+ { CCI_REG8(0x5551), 0x00 }, { CCI_REG8(0x557a), 0x00 },
+ { CCI_REG8(0x557b), 0x38 }, { CCI_REG8(0x557c), 0x00 },
+ { CCI_REG8(0x557d), 0x4b }, { CCI_REG8(0x5590), 0x00 },
+ { CCI_REG8(0x5591), 0x50 }, { CCI_REG8(0x5592), 0x00 },
+ { CCI_REG8(0x5593), 0x50 }, { CCI_REG8(0x5594), 0x00 },
+ { CCI_REG8(0x5595), 0x50 }, { CCI_REG8(0x5596), 0x00 },
+ { CCI_REG8(0x5597), 0x50 }, { CCI_REG8(0x5598), 0x00 },
+ { CCI_REG8(0x5599), 0x50 }, { CCI_REG8(0x559a), 0x01 },
+ { CCI_REG8(0x559b), 0x00 }, { CCI_REG8(0x559c), 0x01 },
+ { CCI_REG8(0x559d), 0x00 }, { CCI_REG8(0x559e), 0x00 },
+ { CCI_REG8(0x559f), 0x50 }, { CCI_REG8(0x55a0), 0x00 },
+ { CCI_REG8(0x55a1), 0x50 }, { CCI_REG8(0x55a2), 0x01 },
+ { CCI_REG8(0x55a3), 0x00 }, { CCI_REG8(0x55a4), 0x01 },
+ { CCI_REG8(0x55a5), 0x00 }, { CCI_REG8(0x55a6), 0x00 },
+ { CCI_REG8(0x55a7), 0x50 }, { CCI_REG8(0x55a8), 0x00 },
+ { CCI_REG8(0x55a9), 0x50 }, { CCI_REG8(0x55aa), 0x00 },
+ { CCI_REG8(0x55ab), 0x50 }, { CCI_REG8(0x55ac), 0x00 },
+ { CCI_REG8(0x55ad), 0x50 }, { CCI_REG8(0x55ae), 0x00 },
+ { CCI_REG8(0x55af), 0x50 }, { CCI_REG8(0x55b0), 0x00 },
+ { CCI_REG8(0x55b1), 0x50 }, { CCI_REG8(0x55b2), 0x00 },
+ { CCI_REG8(0x55b3), 0x50 }, { CCI_REG8(0x55b4), 0x00 },
+ { CCI_REG8(0x55b5), 0x50 }, { CCI_REG8(0x55b6), 0x00 },
+ { CCI_REG8(0x55b7), 0x50 }, { CCI_REG8(0x55b8), 0x00 },
+ { CCI_REG8(0x55b9), 0x50 }, { CCI_REG8(0x55ba), 0x01 },
+ { CCI_REG8(0x55bb), 0x00 }, { CCI_REG8(0x55bc), 0x01 },
+ { CCI_REG8(0x55bd), 0x00 }, { CCI_REG8(0x55be), 0x00 },
+ { CCI_REG8(0x55bf), 0x50 }, { CCI_REG8(0x55c0), 0x00 },
+ { CCI_REG8(0x55c1), 0x50 }, { CCI_REG8(0x55c2), 0x01 },
+ { CCI_REG8(0x55c3), 0x00 }, { CCI_REG8(0x55c4), 0x01 },
+ { CCI_REG8(0x55c5), 0x00 }, { CCI_REG8(0x55c6), 0x00 },
+ { CCI_REG8(0x55c7), 0x50 }, { CCI_REG8(0x55c8), 0x00 },
+ { CCI_REG8(0x55c9), 0x50 }, { CCI_REG8(0x55ca), 0x00 },
+ { CCI_REG8(0x55cb), 0x50 }, { CCI_REG8(0x55cc), 0x00 },
+ { CCI_REG8(0x55cd), 0x50 }, { CCI_REG8(0x55ce), 0x00 },
+ { CCI_REG8(0x55cf), 0x50 }, { CCI_REG8(0x55f0), 0x04 },
+ { CCI_REG8(0x55f1), 0x03 }, { CCI_REG8(0x55f2), 0x02 },
+ { CCI_REG8(0x55f3), 0x01 }, { CCI_REG8(0x55f4), 0x08 },
+ { CCI_REG8(0x55f5), 0x07 }, { CCI_REG8(0x55f6), 0x06 },
+ { CCI_REG8(0x55f7), 0x05 }, { CCI_REG8(0x55f8), 0x0c },
+ { CCI_REG8(0x55f9), 0x0b }, { CCI_REG8(0x55fa), 0x0a },
+ { CCI_REG8(0x55fb), 0x09 }, { CCI_REG8(0x55fc), 0x10 },
+ { CCI_REG8(0x55fd), 0x0f }, { CCI_REG8(0x55fe), 0x0e },
+ { CCI_REG8(0x55ff), 0x0d }, { CCI_REG8(0x5600), 0x14 },
+ { CCI_REG8(0x5601), 0x13 }, { CCI_REG8(0x5602), 0x12 },
+ { CCI_REG8(0x5603), 0x11 }, { CCI_REG8(0x5604), 0x18 },
+ { CCI_REG8(0x5605), 0x17 }, { CCI_REG8(0x5606), 0x16 },
+ { CCI_REG8(0x5607), 0x15 }, { CCI_REG8(0x5608), 0x1c },
+ { CCI_REG8(0x5609), 0x1b }, { CCI_REG8(0x560a), 0x1a },
+ { CCI_REG8(0x560b), 0x19 }, { CCI_REG8(0x560c), 0x20 },
+ { CCI_REG8(0x560d), 0x1f }, { CCI_REG8(0x560e), 0x1e },
+ { CCI_REG8(0x560f), 0x1d }, { CCI_REG8(0x5631), 0x02 },
+ { CCI_REG8(0x5632), 0x42 }, { CCI_REG8(0x5633), 0x24 },
+ { CCI_REG8(0x5653), 0x09 }, { CCI_REG8(0x5654), 0x00 },
+ { CCI_REG8(0x5714), 0x03 }, { CCI_REG8(0x57b0), 0x10 },
+ { CCI_REG8(0x57b3), 0x0e }, { CCI_REG8(0x57b5), 0x02 },
+ { CCI_REG8(0x57b6), 0x00 }, { CCI_REG8(0x57b7), 0x00 },
+ { CCI_REG8(0x57b8), 0x00 }, { CCI_REG8(0x57b9), 0x70 },
+ { CCI_REG8(0x57ba), 0x00 }, { CCI_REG8(0x57bb), 0x10 },
+ { CCI_REG8(0x57bc), 0x00 }, { CCI_REG8(0x57bd), 0x00 },
+ { CCI_REG8(0x57d2), 0xff }, { CCI_REG8(0x57d3), 0x1c },
+ { CCI_REG8(0x5810), 0x03 }, { CCI_REG8(0x5811), 0xe8 },
+ { CCI_REG8(0x5850), 0x6c }, { CCI_REG8(0x5851), 0x00 },
+ { CCI_REG8(0x587a), 0x00 }, { CCI_REG8(0x587b), 0x38 },
+ { CCI_REG8(0x587c), 0x00 }, { CCI_REG8(0x587d), 0x4b },
+ { CCI_REG8(0x5890), 0x00 }, { CCI_REG8(0x5891), 0x50 },
+ { CCI_REG8(0x5892), 0x00 }, { CCI_REG8(0x5893), 0x50 },
+ { CCI_REG8(0x5894), 0x00 }, { CCI_REG8(0x5895), 0x50 },
+ { CCI_REG8(0x5896), 0x00 }, { CCI_REG8(0x5897), 0x50 },
+ { CCI_REG8(0x5898), 0x00 }, { CCI_REG8(0x5899), 0x50 },
+ { CCI_REG8(0x589a), 0x01 }, { CCI_REG8(0x589b), 0x00 },
+ { CCI_REG8(0x589c), 0x01 }, { CCI_REG8(0x589d), 0x00 },
+ { CCI_REG8(0x589e), 0x00 }, { CCI_REG8(0x589f), 0x50 },
+ { CCI_REG8(0x58a0), 0x00 }, { CCI_REG8(0x58a1), 0x50 },
+ { CCI_REG8(0x58a2), 0x01 }, { CCI_REG8(0x58a3), 0x00 },
+ { CCI_REG8(0x58a4), 0x01 }, { CCI_REG8(0x58a5), 0x00 },
+ { CCI_REG8(0x58a6), 0x00 }, { CCI_REG8(0x58a7), 0x50 },
+ { CCI_REG8(0x58a8), 0x00 }, { CCI_REG8(0x58a9), 0x50 },
+ { CCI_REG8(0x58aa), 0x00 }, { CCI_REG8(0x58ab), 0x50 },
+ { CCI_REG8(0x58ac), 0x00 }, { CCI_REG8(0x58ad), 0x50 },
+ { CCI_REG8(0x58ae), 0x00 }, { CCI_REG8(0x58af), 0x50 },
+ { CCI_REG8(0x58b0), 0x00 }, { CCI_REG8(0x58b1), 0x50 },
+ { CCI_REG8(0x58b2), 0x00 }, { CCI_REG8(0x58b3), 0x50 },
+ { CCI_REG8(0x58b4), 0x00 }, { CCI_REG8(0x58b5), 0x50 },
+ { CCI_REG8(0x58b6), 0x00 }, { CCI_REG8(0x58b7), 0x50 },
+ { CCI_REG8(0x58b8), 0x00 }, { CCI_REG8(0x58b9), 0x50 },
+ { CCI_REG8(0x58ba), 0x01 }, { CCI_REG8(0x58bb), 0x00 },
+ { CCI_REG8(0x58bc), 0x01 }, { CCI_REG8(0x58bd), 0x00 },
+ { CCI_REG8(0x58be), 0x00 }, { CCI_REG8(0x58bf), 0x50 },
+ { CCI_REG8(0x58c0), 0x00 }, { CCI_REG8(0x58c1), 0x50 },
+ { CCI_REG8(0x58c2), 0x01 }, { CCI_REG8(0x58c3), 0x00 },
+ { CCI_REG8(0x58c4), 0x01 }, { CCI_REG8(0x58c5), 0x00 },
+ { CCI_REG8(0x58c6), 0x00 }, { CCI_REG8(0x58c7), 0x50 },
+ { CCI_REG8(0x58c8), 0x00 }, { CCI_REG8(0x58c9), 0x50 },
+ { CCI_REG8(0x58ca), 0x00 }, { CCI_REG8(0x58cb), 0x50 },
+ { CCI_REG8(0x58cc), 0x00 }, { CCI_REG8(0x58cd), 0x50 },
+ { CCI_REG8(0x58ce), 0x00 }, { CCI_REG8(0x58cf), 0x50 },
+ { CCI_REG8(0x58f0), 0x04 }, { CCI_REG8(0x58f1), 0x03 },
+ { CCI_REG8(0x58f2), 0x02 }, { CCI_REG8(0x58f3), 0x01 },
+ { CCI_REG8(0x58f4), 0x08 }, { CCI_REG8(0x58f5), 0x07 },
+ { CCI_REG8(0x58f6), 0x06 }, { CCI_REG8(0x58f7), 0x05 },
+ { CCI_REG8(0x58f8), 0x0c }, { CCI_REG8(0x58f9), 0x0b },
+ { CCI_REG8(0x58fa), 0x0a }, { CCI_REG8(0x58fb), 0x09 },
+ { CCI_REG8(0x58fc), 0x10 }, { CCI_REG8(0x58fd), 0x0f },
+ { CCI_REG8(0x58fe), 0x0e }, { CCI_REG8(0x58ff), 0x0d },
+ { CCI_REG8(0x5900), 0x14 }, { CCI_REG8(0x5901), 0x13 },
+ { CCI_REG8(0x5902), 0x12 }, { CCI_REG8(0x5903), 0x11 },
+ { CCI_REG8(0x5904), 0x18 }, { CCI_REG8(0x5905), 0x17 },
+ { CCI_REG8(0x5906), 0x16 }, { CCI_REG8(0x5907), 0x15 },
+ { CCI_REG8(0x5908), 0x1c }, { CCI_REG8(0x5909), 0x1b },
+ { CCI_REG8(0x590a), 0x1a }, { CCI_REG8(0x590b), 0x19 },
+ { CCI_REG8(0x590c), 0x20 }, { CCI_REG8(0x590d), 0x1f },
+ { CCI_REG8(0x590e), 0x1e }, { CCI_REG8(0x590f), 0x1d },
+ { CCI_REG8(0x5931), 0x02 }, { CCI_REG8(0x5932), 0x42 },
+ { CCI_REG8(0x5933), 0x24 }, { CCI_REG8(0x5953), 0x09 },
+ { CCI_REG8(0x5954), 0x00 }, { CCI_REG8(0x5989), 0x84 },
+ { CCI_REG8(0x59c3), 0x04 }, { CCI_REG8(0x59c4), 0x24 },
+ { CCI_REG8(0x59c5), 0x40 }, { CCI_REG8(0x59c6), 0x1b },
+ { CCI_REG8(0x59c7), 0x40 }, { CCI_REG8(0x5a02), 0x0f },
+ { CCI_REG8(0x5f00), 0x29 }, { CCI_REG8(0x5f2d), 0x28 },
+ { CCI_REG8(0x5f2e), 0x28 }, { CCI_REG8(0x6801), 0x11 },
+ { CCI_REG8(0x6802), 0x3f }, { CCI_REG8(0x6803), 0xe7 },
+ { CCI_REG8(0x6825), 0x0f }, { CCI_REG8(0x6826), 0x20 },
+ { CCI_REG8(0x6827), 0x00 }, { CCI_REG8(0x6829), 0x16 },
+ { CCI_REG8(0x682b), 0xb3 }, { CCI_REG8(0x682c), 0x01 },
+ { CCI_REG8(0x6832), 0xff }, { CCI_REG8(0x6833), 0xff },
+ { CCI_REG8(0x6898), 0x80 }, { CCI_REG8(0x6899), 0x80 },
+ { CCI_REG8(0x689b), 0x40 }, { CCI_REG8(0x689c), 0x20 },
+ { CCI_REG8(0x689d), 0x20 }, { CCI_REG8(0x689e), 0x80 },
+ { CCI_REG8(0x689f), 0x60 }, { CCI_REG8(0x68a0), 0x40 },
+ { CCI_REG8(0x68a4), 0x40 }, { CCI_REG8(0x68a5), 0x20 },
+ { CCI_REG8(0x68a6), 0x00 }, { CCI_REG8(0x68b6), 0x80 },
+ { CCI_REG8(0x68b7), 0x80 }, { CCI_REG8(0x68b8), 0x80 },
+ { CCI_REG8(0x68bc), 0x80 }, { CCI_REG8(0x68bd), 0x80 },
+ { CCI_REG8(0x68be), 0x80 }, { CCI_REG8(0x68bf), 0x40 },
+ { CCI_REG8(0x68c2), 0x80 }, { CCI_REG8(0x68c3), 0x80 },
+ { CCI_REG8(0x68c4), 0x60 }, { CCI_REG8(0x68c5), 0x30 },
+ { CCI_REG8(0x6918), 0x80 }, { CCI_REG8(0x6919), 0x80 },
+ { CCI_REG8(0x691b), 0x40 }, { CCI_REG8(0x691c), 0x20 },
+ { CCI_REG8(0x691d), 0x20 }, { CCI_REG8(0x691e), 0x80 },
+ { CCI_REG8(0x691f), 0x60 }, { CCI_REG8(0x6920), 0x40 },
+ { CCI_REG8(0x6924), 0x40 }, { CCI_REG8(0x6925), 0x20 },
+ { CCI_REG8(0x6926), 0x00 }, { CCI_REG8(0x6936), 0x40 },
+ { CCI_REG8(0x6937), 0x40 }, { CCI_REG8(0x6938), 0x20 },
+ { CCI_REG8(0x6939), 0x20 }, { CCI_REG8(0x693a), 0x10 },
+ { CCI_REG8(0x693b), 0x10 }, { CCI_REG8(0x693c), 0x20 },
+ { CCI_REG8(0x693d), 0x20 }, { CCI_REG8(0x693e), 0x10 },
+ { CCI_REG8(0x693f), 0x10 }, { CCI_REG8(0x6940), 0x00 },
+ { CCI_REG8(0x6941), 0x00 }, { CCI_REG8(0x6942), 0x08 },
+ { CCI_REG8(0x6943), 0x08 }, { CCI_REG8(0x6944), 0x00 },
+ { CCI_REG8(0x69c2), 0x07 }, { CCI_REG8(0x6a20), 0x01 },
+ { CCI_REG8(0x6a23), 0x10 }, { CCI_REG8(0x6a26), 0x3d },
+ { CCI_REG8(0x6a27), 0x3e }, { CCI_REG8(0x6a38), 0x02 },
+ { CCI_REG8(0x6a39), 0x20 }, { CCI_REG8(0x6a3a), 0x02 },
+ { CCI_REG8(0x6a3b), 0x84 }, { CCI_REG8(0x6a3e), 0x02 },
+ { CCI_REG8(0x6a3f), 0x20 }, { CCI_REG8(0x6a47), 0x3b },
+ { CCI_REG8(0x6a63), 0x04 }, { CCI_REG8(0x6a65), 0x00 },
+ { CCI_REG8(0x6a67), 0x0f }, { CCI_REG8(0x6b22), 0x07 },
+ { CCI_REG8(0x6b23), 0xc2 }, { CCI_REG8(0x6b2f), 0x00 },
+ { CCI_REG8(0x6b60), 0x1f }, { CCI_REG8(0x6bd2), 0x5a },
+ { CCI_REG8(0x6c20), 0x50 }, { CCI_REG8(0x6c60), 0x50 },
+ { CCI_REG8(0x6c61), 0x06 }, { CCI_REG8(0x7318), 0x04 },
+ { CCI_REG8(0x7319), 0x01 }, { CCI_REG8(0x731a), 0x04 },
+ { CCI_REG8(0x731b), 0x01 }, { CCI_REG8(0x731c), 0x00 },
+ { CCI_REG8(0x731d), 0x00 }, { CCI_REG8(0x731e), 0x04 },
+ { CCI_REG8(0x731f), 0x01 }, { CCI_REG8(0x7320), 0x04 },
+ { CCI_REG8(0x7321), 0x00 }, { CCI_REG8(0x7322), 0x04 },
+ { CCI_REG8(0x7323), 0x00 }, { CCI_REG8(0x7324), 0x04 },
+ { CCI_REG8(0x7325), 0x00 }, { CCI_REG8(0x7326), 0x04 },
+ { CCI_REG8(0x7327), 0x00 }, { CCI_REG8(0x7600), 0x00 },
+ { CCI_REG8(0x7601), 0x00 }, { CCI_REG8(0x7602), 0x10 },
+ { CCI_REG8(0x7603), 0x00 }, { CCI_REG8(0x7604), 0x00 },
+ { CCI_REG8(0x7605), 0x00 }, { CCI_REG8(0x7606), 0x10 },
+ { CCI_REG8(0x7607), 0x00 }, { CCI_REG8(0x7608), 0x00 },
+ { CCI_REG8(0x7609), 0x00 }, { CCI_REG8(0x760a), 0x10 },
+ { CCI_REG8(0x760b), 0x00 }, { CCI_REG8(0x760c), 0x00 },
+ { CCI_REG8(0x760d), 0x00 }, { CCI_REG8(0x760e), 0x10 },
+ { CCI_REG8(0x760f), 0x00 }, { CCI_REG8(0x7610), 0x00 },
+ { CCI_REG8(0x7611), 0x00 }, { CCI_REG8(0x7612), 0x10 },
+ { CCI_REG8(0x7613), 0x00 }, { CCI_REG8(0x7614), 0x00 },
+ { CCI_REG8(0x7615), 0x00 }, { CCI_REG8(0x7616), 0x10 },
+ { CCI_REG8(0x7617), 0x00 }, { CCI_REG8(0x7618), 0x00 },
+ { CCI_REG8(0x7619), 0x00 }, { CCI_REG8(0x761a), 0x10 },
+ { CCI_REG8(0x761b), 0x00 }, { CCI_REG8(0x761c), 0x00 },
+ { CCI_REG8(0x761d), 0x00 }, { CCI_REG8(0x761e), 0x10 },
+ { CCI_REG8(0x761f), 0x00 }, { CCI_REG8(0x7620), 0x00 },
+ { CCI_REG8(0x7621), 0x00 }, { CCI_REG8(0x7622), 0x10 },
+ { CCI_REG8(0x7623), 0x00 }, { CCI_REG8(0x7624), 0x00 },
+ { CCI_REG8(0x7625), 0x00 }, { CCI_REG8(0x7626), 0x10 },
+ { CCI_REG8(0x7627), 0x00 }, { CCI_REG8(0x7628), 0x00 },
+ { CCI_REG8(0x7629), 0x00 }, { CCI_REG8(0x762a), 0x10 },
+ { CCI_REG8(0x762b), 0x00 }, { CCI_REG8(0x762c), 0x00 },
+ { CCI_REG8(0x762d), 0x00 }, { CCI_REG8(0x762e), 0x10 },
+ { CCI_REG8(0x762f), 0x00 }, { CCI_REG8(0x7630), 0x00 },
+ { CCI_REG8(0x7631), 0x00 }, { CCI_REG8(0x7632), 0x10 },
+ { CCI_REG8(0x7633), 0x00 }, { CCI_REG8(0x7634), 0x00 },
+ { CCI_REG8(0x7635), 0x00 }, { CCI_REG8(0x7636), 0x10 },
+ { CCI_REG8(0x7637), 0x00 }, { CCI_REG8(0x7638), 0x00 },
+ { CCI_REG8(0x7639), 0x00 }, { CCI_REG8(0x763a), 0x10 },
+ { CCI_REG8(0x763b), 0x00 }, { CCI_REG8(0x763c), 0x00 },
+ { CCI_REG8(0x763d), 0x00 }, { CCI_REG8(0x763e), 0x10 },
+ { CCI_REG8(0x763f), 0x00 }, { CCI_REG8(0x7640), 0x00 },
+ { CCI_REG8(0x7641), 0x00 }, { CCI_REG8(0x7642), 0x10 },
+ { CCI_REG8(0x7643), 0x00 }, { CCI_REG8(0x7644), 0x00 },
+ { CCI_REG8(0x7645), 0x00 }, { CCI_REG8(0x7646), 0x10 },
+ { CCI_REG8(0x7647), 0x00 }, { CCI_REG8(0x7648), 0x00 },
+ { CCI_REG8(0x7649), 0x00 }, { CCI_REG8(0x764a), 0x10 },
+ { CCI_REG8(0x764b), 0x00 }, { CCI_REG8(0x764c), 0x00 },
+ { CCI_REG8(0x764d), 0x00 }, { CCI_REG8(0x764e), 0x10 },
+ { CCI_REG8(0x764f), 0x00 }, { CCI_REG8(0x7650), 0x00 },
+ { CCI_REG8(0x7651), 0x00 }, { CCI_REG8(0x7652), 0x10 },
+ { CCI_REG8(0x7653), 0x00 }, { CCI_REG8(0x7654), 0x00 },
+ { CCI_REG8(0x7655), 0x00 }, { CCI_REG8(0x7656), 0x10 },
+ { CCI_REG8(0x7657), 0x00 }, { CCI_REG8(0x7658), 0x00 },
+ { CCI_REG8(0x7659), 0x00 }, { CCI_REG8(0x765a), 0x10 },
+ { CCI_REG8(0x765b), 0x00 }, { CCI_REG8(0x765c), 0x00 },
+ { CCI_REG8(0x765d), 0x00 }, { CCI_REG8(0x765e), 0x10 },
+ { CCI_REG8(0x765f), 0x00 }, { CCI_REG8(0x7660), 0x00 },
+ { CCI_REG8(0x7661), 0x00 }, { CCI_REG8(0x7662), 0x10 },
+ { CCI_REG8(0x7663), 0x00 }, { CCI_REG8(0x7664), 0x00 },
+ { CCI_REG8(0x7665), 0x00 }, { CCI_REG8(0x7666), 0x10 },
+ { CCI_REG8(0x7667), 0x00 }, { CCI_REG8(0x7668), 0x00 },
+ { CCI_REG8(0x7669), 0x00 }, { CCI_REG8(0x766a), 0x10 },
+ { CCI_REG8(0x766b), 0x00 }, { CCI_REG8(0x766c), 0x00 },
+ { CCI_REG8(0x766d), 0x00 }, { CCI_REG8(0x766e), 0x10 },
+ { CCI_REG8(0x766f), 0x00 }, { CCI_REG8(0x7670), 0x00 },
+ { CCI_REG8(0x7671), 0x00 }, { CCI_REG8(0x7672), 0x10 },
+ { CCI_REG8(0x7673), 0x00 }, { CCI_REG8(0x7674), 0x00 },
+ { CCI_REG8(0x7675), 0x00 }, { CCI_REG8(0x7676), 0x10 },
+ { CCI_REG8(0x7677), 0x00 }, { CCI_REG8(0x7678), 0x00 },
+ { CCI_REG8(0x7679), 0x00 }, { CCI_REG8(0x767a), 0x10 },
+ { CCI_REG8(0x767b), 0x00 }, { CCI_REG8(0x767c), 0x00 },
+ { CCI_REG8(0x767d), 0x00 }, { CCI_REG8(0x767e), 0x10 },
+ { CCI_REG8(0x767f), 0x00 }, { CCI_REG8(0x7680), 0x00 },
+ { CCI_REG8(0x7681), 0x00 }, { CCI_REG8(0x7682), 0x10 },
+ { CCI_REG8(0x7683), 0x00 }, { CCI_REG8(0x7684), 0x00 },
+ { CCI_REG8(0x7685), 0x00 }, { CCI_REG8(0x7686), 0x10 },
+ { CCI_REG8(0x7687), 0x00 }, { CCI_REG8(0x7688), 0x00 },
+ { CCI_REG8(0x7689), 0x00 }, { CCI_REG8(0x768a), 0x10 },
+ { CCI_REG8(0x768b), 0x00 }, { CCI_REG8(0x768c), 0x00 },
+ { CCI_REG8(0x768d), 0x00 }, { CCI_REG8(0x768e), 0x10 },
+ { CCI_REG8(0x768f), 0x00 }, { CCI_REG8(0x7690), 0x00 },
+ { CCI_REG8(0x7691), 0x00 }, { CCI_REG8(0x7692), 0x10 },
+ { CCI_REG8(0x7693), 0x00 }, { CCI_REG8(0x7694), 0x00 },
+ { CCI_REG8(0x7695), 0x00 }, { CCI_REG8(0x7696), 0x10 },
+ { CCI_REG8(0x7697), 0x00 }, { CCI_REG8(0x7698), 0x00 },
+ { CCI_REG8(0x7699), 0x00 }, { CCI_REG8(0x769a), 0x10 },
+ { CCI_REG8(0x769b), 0x00 }, { CCI_REG8(0x769c), 0x00 },
+ { CCI_REG8(0x769d), 0x00 }, { CCI_REG8(0x769e), 0x10 },
+ { CCI_REG8(0x769f), 0x00 }, { CCI_REG8(0x76a0), 0x00 },
+ { CCI_REG8(0x76a1), 0x00 }, { CCI_REG8(0x76a2), 0x10 },
+ { CCI_REG8(0x76a3), 0x00 }, { CCI_REG8(0x76a4), 0x00 },
+ { CCI_REG8(0x76a5), 0x00 }, { CCI_REG8(0x76a6), 0x10 },
+ { CCI_REG8(0x76a7), 0x00 }, { CCI_REG8(0x76a8), 0x00 },
+ { CCI_REG8(0x76a9), 0x00 }, { CCI_REG8(0x76aa), 0x10 },
+ { CCI_REG8(0x76ab), 0x00 }, { CCI_REG8(0x76ac), 0x00 },
+ { CCI_REG8(0x76ad), 0x00 }, { CCI_REG8(0x76ae), 0x10 },
+ { CCI_REG8(0x76af), 0x00 }, { CCI_REG8(0x76b0), 0x00 },
+ { CCI_REG8(0x76b1), 0x00 }, { CCI_REG8(0x76b2), 0x10 },
+ { CCI_REG8(0x76b3), 0x00 }, { CCI_REG8(0x76b4), 0x00 },
+ { CCI_REG8(0x76b5), 0x00 }, { CCI_REG8(0x76b6), 0x10 },
+ { CCI_REG8(0x76b7), 0x00 }, { CCI_REG8(0x76b8), 0x00 },
+ { CCI_REG8(0x76b9), 0x00 }, { CCI_REG8(0x76ba), 0x10 },
+ { CCI_REG8(0x76bb), 0x00 }, { CCI_REG8(0x76bc), 0x00 },
+ { CCI_REG8(0x76bd), 0x00 }, { CCI_REG8(0x76be), 0x10 },
+ { CCI_REG8(0x76bf), 0x00 }, { CCI_REG8(0x76c0), 0x00 },
+ { CCI_REG8(0x76c1), 0x00 }, { CCI_REG8(0x76c2), 0x10 },
+ { CCI_REG8(0x76c3), 0x00 }, { CCI_REG8(0x76c4), 0x00 },
+ { CCI_REG8(0x76c5), 0x00 }, { CCI_REG8(0x76c6), 0x10 },
+ { CCI_REG8(0x76c7), 0x00 }, { CCI_REG8(0x76c8), 0x00 },
+ { CCI_REG8(0x76c9), 0x00 }, { CCI_REG8(0x76ca), 0x10 },
+ { CCI_REG8(0x76cb), 0x00 }, { CCI_REG8(0x76cc), 0x00 },
+ { CCI_REG8(0x76cd), 0x00 }, { CCI_REG8(0x76ce), 0x10 },
+ { CCI_REG8(0x76cf), 0x00 }, { CCI_REG8(0x76d0), 0x00 },
+ { CCI_REG8(0x76d1), 0x00 }, { CCI_REG8(0x76d2), 0x10 },
+ { CCI_REG8(0x76d3), 0x00 }, { CCI_REG8(0x76d4), 0x00 },
+ { CCI_REG8(0x76d5), 0x00 }, { CCI_REG8(0x76d6), 0x10 },
+ { CCI_REG8(0x76d7), 0x00 }, { CCI_REG8(0x76d8), 0x00 },
+ { CCI_REG8(0x76d9), 0x00 }, { CCI_REG8(0x76da), 0x10 },
+ { CCI_REG8(0x76db), 0x00 }, { CCI_REG8(0x76dc), 0x00 },
+ { CCI_REG8(0x76dd), 0x00 }, { CCI_REG8(0x76de), 0x10 },
+ { CCI_REG8(0x76df), 0x00 }, { CCI_REG8(0x76e0), 0x00 },
+ { CCI_REG8(0x76e1), 0x00 }, { CCI_REG8(0x76e2), 0x10 },
+ { CCI_REG8(0x76e3), 0x00 }, { CCI_REG8(0x76e4), 0x00 },
+ { CCI_REG8(0x76e5), 0x00 }, { CCI_REG8(0x76e6), 0x10 },
+ { CCI_REG8(0x76e7), 0x00 }, { CCI_REG8(0x76e8), 0x00 },
+ { CCI_REG8(0x76e9), 0x00 }, { CCI_REG8(0x76ea), 0x10 },
+ { CCI_REG8(0x76eb), 0x00 }, { CCI_REG8(0x76ec), 0x00 },
+ { CCI_REG8(0x76ed), 0x00 }, { CCI_REG8(0x76ee), 0x10 },
+ { CCI_REG8(0x76ef), 0x00 }, { CCI_REG8(0x76f0), 0x00 },
+ { CCI_REG8(0x76f1), 0x00 }, { CCI_REG8(0x76f2), 0x10 },
+ { CCI_REG8(0x76f3), 0x00 }, { CCI_REG8(0x76f4), 0x00 },
+ { CCI_REG8(0x76f5), 0x00 }, { CCI_REG8(0x76f6), 0x10 },
+ { CCI_REG8(0x76f7), 0x00 }, { CCI_REG8(0x76f8), 0x00 },
+ { CCI_REG8(0x76f9), 0x00 }, { CCI_REG8(0x76fa), 0x10 },
+ { CCI_REG8(0x76fb), 0x00 }, { CCI_REG8(0x76fc), 0x00 },
+ { CCI_REG8(0x76fd), 0x00 }, { CCI_REG8(0x76fe), 0x10 },
+ { CCI_REG8(0x76ff), 0x00 }, { CCI_REG8(0x7700), 0x00 },
+ { CCI_REG8(0x7701), 0x00 }, { CCI_REG8(0x7702), 0x10 },
+ { CCI_REG8(0x7703), 0x00 }, { CCI_REG8(0x7704), 0x00 },
+ { CCI_REG8(0x7705), 0x00 }, { CCI_REG8(0x7706), 0x10 },
+ { CCI_REG8(0x7707), 0x00 }, { CCI_REG8(0x7708), 0x00 },
+ { CCI_REG8(0x7709), 0x00 }, { CCI_REG8(0x770a), 0x10 },
+ { CCI_REG8(0x770b), 0x00 }, { CCI_REG8(0x770c), 0x00 },
+ { CCI_REG8(0x770d), 0x00 }, { CCI_REG8(0x770e), 0x10 },
+ { CCI_REG8(0x770f), 0x00 }, { CCI_REG8(0x7710), 0x00 },
+ { CCI_REG8(0x7711), 0x00 }, { CCI_REG8(0x7712), 0x10 },
+ { CCI_REG8(0x7713), 0x00 }, { CCI_REG8(0x7714), 0x00 },
+ { CCI_REG8(0x7715), 0x00 }, { CCI_REG8(0x7716), 0x10 },
+ { CCI_REG8(0x7717), 0x00 }, { CCI_REG8(0x7718), 0x00 },
+ { CCI_REG8(0x7719), 0x00 }, { CCI_REG8(0x771a), 0x10 },
+ { CCI_REG8(0x771b), 0x00 }, { CCI_REG8(0x771c), 0x00 },
+ { CCI_REG8(0x771d), 0x00 }, { CCI_REG8(0x771e), 0x10 },
+ { CCI_REG8(0x771f), 0x00 }, { CCI_REG8(0x7720), 0x00 },
+ { CCI_REG8(0x7721), 0x00 }, { CCI_REG8(0x7722), 0x10 },
+ { CCI_REG8(0x7723), 0x00 }, { CCI_REG8(0x7724), 0x00 },
+ { CCI_REG8(0x7725), 0x00 }, { CCI_REG8(0x7726), 0x10 },
+ { CCI_REG8(0x7727), 0x00 }, { CCI_REG8(0x7728), 0x00 },
+ { CCI_REG8(0x7729), 0x00 }, { CCI_REG8(0x772a), 0x10 },
+ { CCI_REG8(0x772b), 0x00 }, { CCI_REG8(0x772c), 0x00 },
+ { CCI_REG8(0x772d), 0x00 }, { CCI_REG8(0x772e), 0x10 },
+ { CCI_REG8(0x772f), 0x00 }, { CCI_REG8(0x7730), 0x00 },
+ { CCI_REG8(0x7731), 0x00 }, { CCI_REG8(0x7732), 0x10 },
+ { CCI_REG8(0x7733), 0x00 }, { CCI_REG8(0x7734), 0x00 },
+ { CCI_REG8(0x7735), 0x00 }, { CCI_REG8(0x7736), 0x10 },
+ { CCI_REG8(0x7737), 0x00 }, { CCI_REG8(0x7738), 0x00 },
+ { CCI_REG8(0x7739), 0x00 }, { CCI_REG8(0x773a), 0x10 },
+ { CCI_REG8(0x773b), 0x00 }, { CCI_REG8(0x773c), 0x00 },
+ { CCI_REG8(0x773d), 0x00 }, { CCI_REG8(0x773e), 0x10 },
+ { CCI_REG8(0x773f), 0x00 }, { CCI_REG8(0x7740), 0x00 },
+ { CCI_REG8(0x7741), 0x00 }, { CCI_REG8(0x7742), 0x10 },
+ { CCI_REG8(0x7743), 0x00 }, { CCI_REG8(0x3421), 0x02 },
+ { CCI_REG8(0x37d0), 0x00 }, { CCI_REG8(0x3632), 0x99 },
+ { CCI_REG8(0xc518), 0x1f }, { CCI_REG8(0xc519), 0x1f },
+ { CCI_REG8(0xc51a), 0x1f }, { CCI_REG8(0xc51b), 0x1f },
+ { CCI_REG8(0xc51c), 0x1f }, { CCI_REG8(0xc51d), 0x1f },
+ { CCI_REG8(0xc51e), 0x1f }, { CCI_REG8(0xc51f), 0x1f },
+ { CCI_REG8(0xc520), 0x1f }, { CCI_REG8(0xc521), 0x1f },
+ { CCI_REG8(0x3616), 0xa0 }, { CCI_REG8(0x3615), 0xc5 },
+ { CCI_REG8(0xc4c1), 0x02 }, { CCI_REG8(0xc4c2), 0x02 },
+ { CCI_REG8(0xc4c3), 0x03 }, { CCI_REG8(0xc4c4), 0x03 },
+ { CCI_REG8(0xc4f6), 0x0a }, { CCI_REG8(0xc4f7), 0x0a },
+ { CCI_REG8(0xc4f8), 0x0a }, { CCI_REG8(0xc4f9), 0x0a },
+ { CCI_REG8(0xc4fa), 0x0a }, { CCI_REG8(0xc4c6), 0x0a },
+ { CCI_REG8(0xc4c7), 0x0a }, { CCI_REG8(0xc4c8), 0x0a },
+ { CCI_REG8(0xc4c9), 0x0a }, { CCI_REG8(0xc4ca), 0x14 },
+ { CCI_REG8(0xc4cb), 0x14 }, { CCI_REG8(0xc4cc), 0x14 },
+ { CCI_REG8(0xc4cd), 0x14 }, { CCI_REG8(0x3b92), 0x05 },
+ { CCI_REG8(0x3b93), 0x05 }, { CCI_REG8(0x3b94), 0x05 },
+ { CCI_REG8(0x3b95), 0x05 }, { CCI_REG8(0x3623), 0x10 },
+ { CCI_REG8(0xc522), 0x18 }, { CCI_REG8(0xc523), 0x12 },
+ { CCI_REG8(0xc524), 0x0e }, { CCI_REG8(0xc525), 0x0b },
+ { CCI_REG8(0xc526), 0x18 }, { CCI_REG8(0xc527), 0x12 },
+ { CCI_REG8(0xc528), 0x0c }, { CCI_REG8(0xc529), 0x08 },
+ { CCI_REG8(0xc52a), 0x18 }, { CCI_REG8(0xc52b), 0x12 },
+ { CCI_REG8(0xc52c), 0x0e }, { CCI_REG8(0xc52d), 0x0b },
+ { CCI_REG8(0xc52e), 0x18 }, { CCI_REG8(0xc52f), 0x12 },
+ { CCI_REG8(0xc530), 0x0e }, { CCI_REG8(0xc531), 0x0b },
+ { CCI_REG8(0xc532), 0x18 }, { CCI_REG8(0xc533), 0x12 },
+ { CCI_REG8(0xc534), 0x0e }, { CCI_REG8(0xc535), 0x0b },
+ { CCI_REG8(0xc536), 0x18 }, { CCI_REG8(0xc537), 0x12 },
+ { CCI_REG8(0xc538), 0x0e }, { CCI_REG8(0xc539), 0x0b },
+ { CCI_REG8(0xc53a), 0x18 }, { CCI_REG8(0xc53b), 0x12 },
+ { CCI_REG8(0xc53c), 0x0c }, { CCI_REG8(0xc53d), 0x08 },
+ { CCI_REG8(0xc53e), 0x18 }, { CCI_REG8(0xc53f), 0x12 },
+ { CCI_REG8(0xc540), 0x0e }, { CCI_REG8(0xc541), 0x0b },
+ { CCI_REG8(0xc542), 0x18 }, { CCI_REG8(0xc543), 0x12 },
+ { CCI_REG8(0xc544), 0x0e }, { CCI_REG8(0xc545), 0x0b },
+ { CCI_REG8(0xc546), 0x18 }, { CCI_REG8(0xc547), 0x12 },
+ { CCI_REG8(0xc548), 0x0e }, { CCI_REG8(0xc549), 0x0b },
+ { CCI_REG8(0x3701), 0x18 }, { CCI_REG8(0x3702), 0x38 },
+ { CCI_REG8(0x3703), 0x72 }, { CCI_REG8(0x3708), 0x26 },
+ { CCI_REG8(0x3709), 0xe6 }, { CCI_REG8(0x3a1d), 0x18 },
+ { CCI_REG8(0x3a1e), 0x18 }, { CCI_REG8(0x3a21), 0x18 },
+ { CCI_REG8(0x3a22), 0x18 }, { CCI_REG8(0x39fb), 0x18 },
+ { CCI_REG8(0x39fc), 0x18 }, { CCI_REG8(0x39fd), 0x18 },
+ { CCI_REG8(0x39fe), 0x18 }, { CCI_REG8(0xc44a), 0x08 },
+ { CCI_REG8(0xc44c), 0x08 }, { CCI_REG8(0xc5e8), 0x0a },
+ { CCI_REG8(0xc5ea), 0x0a }, { CCI_REG8(0x391d), 0x54 },
+ { CCI_REG8(0x391e), 0xca }, { CCI_REG8(0x3991), 0x0c },
+ { CCI_REG8(0x399d), 0x0c }, { CCI_REG8(0x3744), 0x24 },
+ { CCI_REG8(0x374b), 0x0c }, { CCI_REG8(0x3be7), 0x1e },
+ { CCI_REG8(0x3be8), 0x26 }, { CCI_REG8(0x3a50), 0x14 },
+ { CCI_REG8(0x3a54), 0x14 }, { CCI_REG8(0x3add), 0x1f },
+ { CCI_REG8(0x3adf), 0x24 }, { CCI_REG8(0x3aef), 0x1f },
+ { CCI_REG8(0x3af0), 0x24 }, { CCI_REG8(0xc57f), 0x30 },
+ { CCI_REG8(0xc580), 0x30 }, { CCI_REG8(0xc581), 0x30 },
+ { CCI_REG8(0xc582), 0x30 }, { CCI_REG8(0xc583), 0x30 },
+ { CCI_REG8(0xc584), 0x30 }, { CCI_REG8(0xc585), 0x30 },
+ { CCI_REG8(0xc586), 0x30 }, { CCI_REG8(0xc587), 0x30 },
+ { CCI_REG8(0xc588), 0x30 }, { CCI_REG8(0xc589), 0x30 },
+ { CCI_REG8(0xc58a), 0x30 }, { CCI_REG8(0xc58b), 0x30 },
+ { CCI_REG8(0xc58c), 0x30 }, { CCI_REG8(0xc58d), 0x30 },
+ { CCI_REG8(0xc58e), 0x30 }, { CCI_REG8(0xc58f), 0x30 },
+ { CCI_REG8(0xc590), 0x30 }, { CCI_REG8(0xc591), 0x30 },
+ { CCI_REG8(0xc592), 0x30 }, { CCI_REG8(0xc598), 0x30 },
+ { CCI_REG8(0xc599), 0x30 }, { CCI_REG8(0xc59a), 0x30 },
+ { CCI_REG8(0xc59b), 0x30 }, { CCI_REG8(0xc59c), 0x30 },
+ { CCI_REG8(0xc59d), 0x30 }, { CCI_REG8(0xc59e), 0x30 },
+ { CCI_REG8(0xc59f), 0x30 }, { CCI_REG8(0xc5a0), 0x30 },
+ { CCI_REG8(0xc5a1), 0x30 }, { CCI_REG8(0xc5a2), 0x30 },
+ { CCI_REG8(0xc5a3), 0x30 }, { CCI_REG8(0xc5a4), 0x30 },
+ { CCI_REG8(0xc5a5), 0x30 }, { CCI_REG8(0xc5a6), 0x30 },
+ { CCI_REG8(0xc5a7), 0x30 }, { CCI_REG8(0xc5a8), 0x30 },
+ { CCI_REG8(0xc5a9), 0x30 }, { CCI_REG8(0xc5aa), 0x30 },
+ { CCI_REG8(0xc5ab), 0x30 }, { CCI_REG8(0xc5b1), 0x38 },
+ { CCI_REG8(0xc5b2), 0x38 }, { CCI_REG8(0xc5b3), 0x38 },
+ { CCI_REG8(0xc5b4), 0x38 }, { CCI_REG8(0xc5b5), 0x38 },
+ { CCI_REG8(0xc5b6), 0x38 }, { CCI_REG8(0xc5b7), 0x38 },
+ { CCI_REG8(0xc5b8), 0x38 }, { CCI_REG8(0xc5b9), 0x38 },
+ { CCI_REG8(0xc5ba), 0x38 }, { CCI_REG8(0xc5bb), 0x38 },
+ { CCI_REG8(0xc5bc), 0x38 }, { CCI_REG8(0xc5bd), 0x38 },
+ { CCI_REG8(0xc5be), 0x38 }, { CCI_REG8(0xc5bf), 0x38 },
+ { CCI_REG8(0xc5c0), 0x38 }, { CCI_REG8(0xc5c1), 0x38 },
+ { CCI_REG8(0xc5c2), 0x38 }, { CCI_REG8(0xc5c3), 0x38 },
+ { CCI_REG8(0xc5c4), 0x38 }, { CCI_REG8(0xc5ca), 0x38 },
+ { CCI_REG8(0xc5cb), 0x38 }, { CCI_REG8(0xc5cc), 0x38 },
+ { CCI_REG8(0xc5cd), 0x38 }, { CCI_REG8(0xc5ce), 0x38 },
+ { CCI_REG8(0xc5cf), 0x38 }, { CCI_REG8(0xc5d0), 0x38 },
+ { CCI_REG8(0xc5d1), 0x38 }, { CCI_REG8(0xc5d2), 0x38 },
+ { CCI_REG8(0xc5d3), 0x38 }, { CCI_REG8(0xc5d4), 0x38 },
+ { CCI_REG8(0xc5d5), 0x38 }, { CCI_REG8(0xc5d6), 0x38 },
+ { CCI_REG8(0xc5d7), 0x38 }, { CCI_REG8(0xc5d8), 0x38 },
+ { CCI_REG8(0xc5d9), 0x38 }, { CCI_REG8(0xc5da), 0x38 },
+ { CCI_REG8(0xc5db), 0x38 }, { CCI_REG8(0xc5dc), 0x38 },
+ { CCI_REG8(0xc5dd), 0x38 }, { CCI_REG8(0x3a60), 0x68 },
+ { CCI_REG8(0x3a6f), 0x68 }, { CCI_REG8(0x3a5e), 0xdc },
+ { CCI_REG8(0x3a6d), 0xdc }, { CCI_REG8(0x3aed), 0x6e },
+ { CCI_REG8(0x3af1), 0x73 }, { CCI_REG8(0x3992), 0x02 },
+ { CCI_REG8(0x399e), 0x02 }, { CCI_REG8(0x371d), 0x17 },
+ { CCI_REG8(0x371f), 0x08 }, { CCI_REG8(0x3721), 0xc9 },
+ { CCI_REG8(0x401e), 0x00 }, { CCI_REG8(0x401f), 0xf8 },
+ { CCI_REG8(0x3642), 0x00 }, { CCI_REG8(0x3641), 0x7f },
+ { CCI_REG8(0x3ac5), 0x0c }, { CCI_REG8(0x3ac6), 0x09 },
+ { CCI_REG8(0x3ac7), 0x06 }, { CCI_REG8(0x3ac8), 0x02 },
+ { CCI_REG8(0x3ac9), 0x0c }, { CCI_REG8(0x3aca), 0x09 },
+ { CCI_REG8(0x3acb), 0x06 }, { CCI_REG8(0x3acc), 0x02 },
+ { CCI_REG8(0x3acd), 0x0c }, { CCI_REG8(0x3ace), 0x09 },
+ { CCI_REG8(0x3acf), 0x07 }, { CCI_REG8(0x3ad0), 0x04 },
+ { CCI_REG8(0x3ad1), 0x0c }, { CCI_REG8(0x3ad2), 0x09 },
+ { CCI_REG8(0x3ad3), 0x07 }, { CCI_REG8(0x3ad4), 0x04 },
+ { CCI_REG8(0xc483), 0x0c }, { CCI_REG8(0xc484), 0x0c },
+ { CCI_REG8(0xc485), 0x0c }, { CCI_REG8(0xc486), 0x0c },
+ { CCI_REG8(0x3a2f), 0x0c }, { CCI_REG8(0x3a30), 0x09 },
+ { CCI_REG8(0x3a31), 0x06 }, { CCI_REG8(0x3a32), 0x02 },
+ { CCI_REG8(0x3a34), 0x0c }, { CCI_REG8(0x3a35), 0x09 },
+ { CCI_REG8(0x3a36), 0x07 }, { CCI_REG8(0x3a37), 0x04 },
+ { CCI_REG8(0x3a43), 0x0c }, { CCI_REG8(0x3a44), 0x09 },
+ { CCI_REG8(0x3a45), 0x06 }, { CCI_REG8(0x3a46), 0x02 },
+ { CCI_REG8(0x3a48), 0x0c }, { CCI_REG8(0x3a49), 0x09 },
+ { CCI_REG8(0x3a4a), 0x07 }, { CCI_REG8(0x3a4b), 0x04 },
+ { CCI_REG8(0xc487), 0x0c }, { CCI_REG8(0xc488), 0x0c },
+ { CCI_REG8(0xc489), 0x0c }, { CCI_REG8(0xc48a), 0x0c },
+ { CCI_REG8(0x3645), 0xbd }, { CCI_REG8(0x373f), 0x00 },
+ { CCI_REG8(0x374f), 0x10 }, { CCI_REG8(0x3743), 0xc6 },
+ { CCI_REG8(0x3717), 0x82 }, { CCI_REG8(0x3732), 0x07 },
+ { CCI_REG8(0x3731), 0x16 }, { CCI_REG8(0x3730), 0x16 },
+ { CCI_REG8(0x3828), 0x07 }, { CCI_REG8(0x3714), 0x68 },
+ { CCI_REG8(0x371d), 0x02 }, { CCI_REG8(0x371f), 0x02 },
+ { CCI_REG8(0x37e0), 0x00 }, { CCI_REG8(0x37e1), 0x03 },
+ { CCI_REG8(0x37e2), 0x07 }, { CCI_REG8(0x3734), 0x3e },
+ { CCI_REG8(0x3736), 0x02 }, { CCI_REG8(0x37e4), 0x36 },
+ { CCI_REG8(0x37e9), 0x1c }, { CCI_REG8(0x37ea), 0x01 },
+ { CCI_REG8(0x37eb), 0x0a }, { CCI_REG8(0x37ec), 0x1c },
+ { CCI_REG8(0x37ed), 0x01 }, { CCI_REG8(0x37ee), 0x36 },
+ { CCI_REG8(0x373b), 0x1c }, { CCI_REG8(0x373c), 0x02 },
+ { CCI_REG8(0x37bb), 0x1c }, { CCI_REG8(0x37bc), 0x02 },
+ { CCI_REG8(0x37b8), 0x0c }, { CCI_REG8(0x371c), 0x01 },
+ { CCI_REG8(0x371e), 0x11 }, { CCI_REG8(0x371d), 0x01 },
+ { CCI_REG8(0x371f), 0x01 }, { CCI_REG8(0x3721), 0x01 },
+ { CCI_REG8(0x3725), 0x12 }, { CCI_REG8(0x37e3), 0x06 },
+ { CCI_REG8(0x37dd), 0x86 }, { CCI_REG8(0x37db), 0x0a },
+ { CCI_REG8(0x37dc), 0x14 }, { CCI_REG8(0x3727), 0x20 },
+ { CCI_REG8(0x37b2), 0x80 }, { CCI_REG8(0x37da), 0x04 },
+ { CCI_REG8(0x37df), 0x01 }, { CCI_REG8(0x3731), 0x11 },
+ { CCI_REG8(0x37dd), 0x86 }, { CCI_REG8(0x37df), 0x01 },
+ { CCI_REG8(0x37da), 0x03 }, { CCI_REG8(0x37b2), 0x80 },
+ { CCI_REG8(0x3727), 0x20 }, { CCI_REG8(0x4883), 0x26 },
+ { CCI_REG8(0x488b), 0x88 }, { CCI_REG8(0x3d85), 0x1f },
+ { CCI_REG8(0x3d81), 0x01 }, { CCI_REG8(0x3d84), 0x40 },
+ { CCI_REG8(0x3d88), 0x00 }, { CCI_REG8(0x3d89), 0x00 },
+ { CCI_REG8(0x3d8a), 0x0b }, { CCI_REG8(0x3d8b), 0xff },
+ { CCI_REG8(0x4d00), 0x05 }, { CCI_REG8(0x4d01), 0xc4 },
+ { CCI_REG8(0x4d02), 0xa3 }, { CCI_REG8(0x4d03), 0x8c },
+ { CCI_REG8(0x4d04), 0xfb }, { CCI_REG8(0x4d05), 0xed },
+ { CCI_REG8(0x4010), 0x28 }, { CCI_REG8(0x4030), 0x00 },
+ { CCI_REG8(0x4031), 0x00 }, { CCI_REG8(0x4032), 0x00 },
+ { CCI_REG8(0x4033), 0x00 }, { CCI_REG8(0x4034), 0x00 },
+ { CCI_REG8(0x4035), 0x00 }, { CCI_REG8(0x4036), 0x00 },
+ { CCI_REG8(0x4037), 0x00 }, { CCI_REG8(0x4040), 0x00 },
+ { CCI_REG8(0x4041), 0x00 }, { CCI_REG8(0x4042), 0x00 },
+ { CCI_REG8(0x4043), 0x00 }, { CCI_REG8(0x4044), 0x00 },
+ { CCI_REG8(0x4045), 0x00 }, { CCI_REG8(0x4046), 0x00 },
+ { CCI_REG8(0x4047), 0x00 }, { CCI_REG8(0x3400), 0x00 },
+ { CCI_REG8(0x3421), 0x23 }, { CCI_REG8(0x3422), 0xfc },
+ { CCI_REG8(0x3423), 0x07 }, { CCI_REG8(0x3424), 0x01 },
+ { CCI_REG8(0x3425), 0x04 }, { CCI_REG8(0x3426), 0x50 },
+ { CCI_REG8(0x3427), 0x55 }, { CCI_REG8(0x3428), 0x15 },
+ { CCI_REG8(0x3429), 0x00 }, { CCI_REG8(0x3025), 0x03 },
+ { CCI_REG8(0x3053), 0x00 }, { CCI_REG8(0x3054), 0x00 },
+ { CCI_REG8(0x3055), 0x00 }, { CCI_REG8(0x3056), 0x00 },
+ { CCI_REG8(0x3057), 0x00 }, { CCI_REG8(0x3058), 0x00 },
+ { CCI_REG8(0x305c), 0x00 }, { CCI_REG8(0x340c), 0x1f },
+ { CCI_REG8(0x340d), 0x00 }, { CCI_REG8(0x3501), 0x01 },
+ { CCI_REG8(0x3542), 0x48 }, { CCI_REG8(0x3582), 0x24 },
+ { CCI_REG8(0x3015), 0xf1 }, { CCI_REG8(0x3018), 0xf2 },
+ { CCI_REG8(0x301c), 0xf2 }, { CCI_REG8(0x301d), 0xf6 },
+ { CCI_REG8(0x301e), 0xf1 }, { CCI_REG8(0x0100), 0x01 },
+ { CCI_REG8(0xfff9), 0x08 }, { CCI_REG8(0x3900), 0xcd },
+ { CCI_REG8(0x3901), 0xcd }, { CCI_REG8(0x3902), 0xcd },
+ { CCI_REG8(0x3903), 0xcd }, { CCI_REG8(0x3904), 0xcd },
+ { CCI_REG8(0x3905), 0xcd }, { CCI_REG8(0x3906), 0xcd },
+ { CCI_REG8(0x3907), 0xcd }, { CCI_REG8(0x3908), 0xcd },
+ { CCI_REG8(0x3909), 0xcd }, { CCI_REG8(0x390a), 0xcd },
+ { CCI_REG8(0x390b), 0xcd }, { CCI_REG8(0x390c), 0xcd },
+ { CCI_REG8(0x390d), 0xcd }, { CCI_REG8(0x390e), 0xcd },
+ { CCI_REG8(0x390f), 0xcd }, { CCI_REG8(0x3910), 0xcd },
+ { CCI_REG8(0x3911), 0xcd }, { CCI_REG8(0x3912), 0xcd },
+ { CCI_REG8(0x3913), 0xcd }, { CCI_REG8(0x3914), 0xcd },
+ { CCI_REG8(0x3915), 0xcd }, { CCI_REG8(0x3916), 0xcd },
+ { CCI_REG8(0x3917), 0xcd }, { CCI_REG8(0x3918), 0xcd },
+ { CCI_REG8(0x3919), 0xcd }, { CCI_REG8(0x391a), 0xcd },
+ { CCI_REG8(0x391b), 0xcd }, { CCI_REG8(0x391c), 0xcd },
+ { CCI_REG8(0x391d), 0xcd }, { CCI_REG8(0x391e), 0xcd },
+ { CCI_REG8(0x391f), 0xcd }, { CCI_REG8(0x3920), 0xcd },
+ { CCI_REG8(0x3921), 0xcd }, { CCI_REG8(0x3922), 0xcd },
+ { CCI_REG8(0x3923), 0xcd }, { CCI_REG8(0x3924), 0xcd },
+ { CCI_REG8(0x3925), 0xcd }, { CCI_REG8(0x3926), 0xcd },
+ { CCI_REG8(0x3927), 0xcd }, { CCI_REG8(0x3928), 0xcd },
+ { CCI_REG8(0x3929), 0xcd }, { CCI_REG8(0x392a), 0xcd },
+ { CCI_REG8(0x392b), 0xcd }, { CCI_REG8(0x392c), 0xcd },
+ { CCI_REG8(0x392d), 0xcd }, { CCI_REG8(0x392e), 0xcd },
+ { CCI_REG8(0x392f), 0xcd }, { CCI_REG8(0x3930), 0xcd },
+ { CCI_REG8(0x3931), 0xcd }, { CCI_REG8(0x3932), 0xcd },
+ { CCI_REG8(0x3933), 0xcd }, { CCI_REG8(0x3934), 0xcd },
+ { CCI_REG8(0x3935), 0xcd }, { CCI_REG8(0x3936), 0xcd },
+ { CCI_REG8(0x3937), 0xcd }, { CCI_REG8(0x3938), 0xcd },
+ { CCI_REG8(0x3939), 0xcd }, { CCI_REG8(0x393a), 0xcd },
+ { CCI_REG8(0x393b), 0xcd }, { CCI_REG8(0x393c), 0xcd },
+ { CCI_REG8(0x393d), 0xcd }, { CCI_REG8(0x393e), 0xcd },
+ { CCI_REG8(0x393f), 0xcd }, { CCI_REG8(0x3940), 0xcd },
+ { CCI_REG8(0x3941), 0xcd }, { CCI_REG8(0x3942), 0xcd },
+ { CCI_REG8(0x3943), 0xcd }, { CCI_REG8(0x3944), 0xcd },
+ { CCI_REG8(0x3945), 0xcd }, { CCI_REG8(0x3946), 0xcd },
+ { CCI_REG8(0x3947), 0xcd }, { CCI_REG8(0x3948), 0xcd },
+ { CCI_REG8(0x3949), 0xcd }, { CCI_REG8(0x394a), 0xcd },
+ { CCI_REG8(0x394b), 0xcd }, { CCI_REG8(0x394c), 0xcd },
+ { CCI_REG8(0x394d), 0xcd }, { CCI_REG8(0x394e), 0xcd },
+ { CCI_REG8(0x394f), 0xcd }, { CCI_REG8(0x3950), 0xcd },
+ { CCI_REG8(0x3951), 0xcd }, { CCI_REG8(0x3952), 0xcd },
+ { CCI_REG8(0x3953), 0xcd }, { CCI_REG8(0x3954), 0xcd },
+ { CCI_REG8(0x3955), 0xcd }, { CCI_REG8(0x3956), 0xcd },
+ { CCI_REG8(0x3957), 0xcd }, { CCI_REG8(0x3958), 0xcd },
+ { CCI_REG8(0x3959), 0xcd }, { CCI_REG8(0x395a), 0xcd },
+ { CCI_REG8(0x395b), 0xcd }, { CCI_REG8(0x395c), 0xcd },
+ { CCI_REG8(0x395d), 0xcd }, { CCI_REG8(0x395e), 0xcd },
+ { CCI_REG8(0x395f), 0xcd }, { CCI_REG8(0x3960), 0xcd },
+ { CCI_REG8(0x3961), 0xcd }, { CCI_REG8(0x3962), 0xcd },
+ { CCI_REG8(0x3963), 0xcd }, { CCI_REG8(0x3964), 0xcd },
+ { CCI_REG8(0x3965), 0xcd }, { CCI_REG8(0x3966), 0xcd },
+ { CCI_REG8(0x3967), 0xcd }, { CCI_REG8(0x3968), 0xcd },
+ { CCI_REG8(0x3969), 0xcd }, { CCI_REG8(0x396a), 0xcd },
+ { CCI_REG8(0x396b), 0xcd }, { CCI_REG8(0x396c), 0xcd },
+ { CCI_REG8(0x396d), 0xcd }, { CCI_REG8(0x396e), 0xcd },
+ { CCI_REG8(0x396f), 0xcd }, { CCI_REG8(0x3970), 0xcd },
+ { CCI_REG8(0x3971), 0xcd }, { CCI_REG8(0x3972), 0xcd },
+ { CCI_REG8(0x3973), 0xcd }, { CCI_REG8(0x3974), 0xcd },
+ { CCI_REG8(0x3975), 0xcd }, { CCI_REG8(0x3976), 0xcd },
+ { CCI_REG8(0x3977), 0xcd }, { CCI_REG8(0x3978), 0xcd },
+ { CCI_REG8(0x3979), 0xcd }, { CCI_REG8(0x397a), 0xcd },
+ { CCI_REG8(0x397b), 0xcd }, { CCI_REG8(0x397c), 0xcd },
+ { CCI_REG8(0x397d), 0xcd }, { CCI_REG8(0x397e), 0xcd },
+ { CCI_REG8(0x397f), 0xcd }, { CCI_REG8(0x3980), 0xcd },
+ { CCI_REG8(0x3981), 0xcd }, { CCI_REG8(0x3982), 0xcd },
+ { CCI_REG8(0x3983), 0xcd }, { CCI_REG8(0x3984), 0xcd },
+ { CCI_REG8(0x3985), 0xcd }, { CCI_REG8(0x3986), 0xcd },
+ { CCI_REG8(0x3987), 0xcd }, { CCI_REG8(0x3988), 0xcd },
+ { CCI_REG8(0x3989), 0xcd }, { CCI_REG8(0x398a), 0xcd },
+ { CCI_REG8(0x398b), 0xcd }, { CCI_REG8(0x398c), 0xcd },
+ { CCI_REG8(0x398d), 0xcd }, { CCI_REG8(0x398e), 0xcd },
+ { CCI_REG8(0x398f), 0xcd }, { CCI_REG8(0x3990), 0xcd },
+ { CCI_REG8(0x3991), 0xcd }, { CCI_REG8(0x3992), 0xcd },
+ { CCI_REG8(0x3993), 0xcd }, { CCI_REG8(0x3994), 0xcd },
+ { CCI_REG8(0x3995), 0xcd }, { CCI_REG8(0x3996), 0xcd },
+ { CCI_REG8(0x3997), 0xcd }, { CCI_REG8(0x3998), 0xcd },
+ { CCI_REG8(0x3999), 0xcd }, { CCI_REG8(0x399a), 0xcd },
+ { CCI_REG8(0x399b), 0xcd }, { CCI_REG8(0x399c), 0xcd },
+ { CCI_REG8(0x399d), 0xcd }, { CCI_REG8(0x399e), 0xcd },
+ { CCI_REG8(0x399f), 0xcd }, { CCI_REG8(0x39a0), 0xcd },
+ { CCI_REG8(0x39a1), 0xcd }, { CCI_REG8(0x39a2), 0xcd },
+ { CCI_REG8(0x39a3), 0xcd }, { CCI_REG8(0x39a4), 0xcd },
+ { CCI_REG8(0x39a5), 0xcd }, { CCI_REG8(0x39a6), 0xcd },
+ { CCI_REG8(0x39a7), 0xcd }, { CCI_REG8(0x39a8), 0xcd },
+ { CCI_REG8(0x39a9), 0xcd }, { CCI_REG8(0x39aa), 0xcd },
+ { CCI_REG8(0x39ab), 0xcd }, { CCI_REG8(0x39ac), 0xcd },
+ { CCI_REG8(0x39ad), 0xcd }, { CCI_REG8(0x39ae), 0xcd },
+ { CCI_REG8(0x39af), 0xcd }, { CCI_REG8(0x39b0), 0xcd },
+ { CCI_REG8(0x39b1), 0xcd }, { CCI_REG8(0x39b2), 0xcd },
+ { CCI_REG8(0x39b3), 0xcd }, { CCI_REG8(0x39b4), 0xcd },
+ { CCI_REG8(0x39b5), 0xcd }, { CCI_REG8(0x39b6), 0xcd },
+ { CCI_REG8(0x39b7), 0xcd }, { CCI_REG8(0x39b8), 0xcd },
+ { CCI_REG8(0x39b9), 0xcd }, { CCI_REG8(0x39ba), 0xcd },
+ { CCI_REG8(0x39bb), 0xcd }, { CCI_REG8(0x39bc), 0xcd },
+ { CCI_REG8(0x39bd), 0xcd }, { CCI_REG8(0x39be), 0xcd },
+ { CCI_REG8(0x39bf), 0xcd }, { CCI_REG8(0x39c0), 0xcd },
+ { CCI_REG8(0x39c1), 0xcd }, { CCI_REG8(0x39c2), 0xcd },
+ { CCI_REG8(0x39c3), 0xcd }, { CCI_REG8(0x39c4), 0xcd },
+ { CCI_REG8(0x39c5), 0xcd }, { CCI_REG8(0x39c6), 0xcd },
+ { CCI_REG8(0x39c7), 0xcd }, { CCI_REG8(0x39c8), 0xcd },
+ { CCI_REG8(0x39c9), 0xcd }, { CCI_REG8(0x39ca), 0xcd },
+ { CCI_REG8(0x39cb), 0xcd }, { CCI_REG8(0x39cc), 0xcd },
+ { CCI_REG8(0x39cd), 0xcd }, { CCI_REG8(0x39ce), 0xcd },
+ { CCI_REG8(0x39cf), 0xcd }, { CCI_REG8(0x39d0), 0xcd },
+ { CCI_REG8(0x39d1), 0xcd }, { CCI_REG8(0x39d2), 0xcd },
+ { CCI_REG8(0x39d3), 0xcd }, { CCI_REG8(0x39d4), 0xcd },
+ { CCI_REG8(0x39d5), 0xcd }, { CCI_REG8(0x39d6), 0xcd },
+ { CCI_REG8(0x39d7), 0xcd }, { CCI_REG8(0x39d8), 0xcd },
+ { CCI_REG8(0x39d9), 0xcd }, { CCI_REG8(0x39da), 0xcd },
+ { CCI_REG8(0x39db), 0xcd }, { CCI_REG8(0x39dc), 0xcd },
+ { CCI_REG8(0x39dd), 0xcd }, { CCI_REG8(0x39de), 0xcd },
+ { CCI_REG8(0x39df), 0xcd }, { CCI_REG8(0x39e0), 0xcd },
+ { CCI_REG8(0x39e1), 0x40 }, { CCI_REG8(0x39e2), 0x40 },
+ { CCI_REG8(0x39e3), 0x40 }, { CCI_REG8(0x39e4), 0x40 },
+ { CCI_REG8(0x39e5), 0x40 }, { CCI_REG8(0x39e6), 0x40 },
+ { CCI_REG8(0x39e7), 0x40 }, { CCI_REG8(0x39e8), 0x40 },
+ { CCI_REG8(0x39e9), 0x40 }, { CCI_REG8(0x39ea), 0x40 },
+ { CCI_REG8(0x39eb), 0x40 }, { CCI_REG8(0x39ec), 0x40 },
+ { CCI_REG8(0x39ed), 0x40 }, { CCI_REG8(0x39ee), 0x40 },
+ { CCI_REG8(0x39ef), 0x40 }, { CCI_REG8(0x39f0), 0x40 },
+ { CCI_REG8(0x39f1), 0x40 }, { CCI_REG8(0x39f2), 0x40 },
+ { CCI_REG8(0x39f3), 0x40 }, { CCI_REG8(0x39f4), 0x40 },
+ { CCI_REG8(0x39f5), 0x40 }, { CCI_REG8(0x39f6), 0x40 },
+ { CCI_REG8(0x39f7), 0x40 }, { CCI_REG8(0x39f8), 0x40 },
+ { CCI_REG8(0x39f9), 0x40 }, { CCI_REG8(0x39fa), 0x40 },
+ { CCI_REG8(0x39fb), 0x40 }, { CCI_REG8(0x39fc), 0x40 },
+ { CCI_REG8(0x39fd), 0x40 }, { CCI_REG8(0x39fe), 0x40 },
+ { CCI_REG8(0x39ff), 0x40 }, { CCI_REG8(0x3a00), 0x40 },
+ { CCI_REG8(0x3a01), 0x40 }, { CCI_REG8(0x3a02), 0x40 },
+ { CCI_REG8(0x3a03), 0x40 }, { CCI_REG8(0x3a04), 0x40 },
+ { CCI_REG8(0x3a05), 0x40 }, { CCI_REG8(0x3a06), 0x40 },
+ { CCI_REG8(0x3a07), 0x40 }, { CCI_REG8(0x3a08), 0x40 },
+ { CCI_REG8(0x3a09), 0x40 }, { CCI_REG8(0x3a0a), 0x40 },
+ { CCI_REG8(0x3a0b), 0x40 }, { CCI_REG8(0x3a0c), 0x40 },
+ { CCI_REG8(0x3a0d), 0x40 }, { CCI_REG8(0x3a0e), 0x40 },
+ { CCI_REG8(0x3a0f), 0x40 }, { CCI_REG8(0x3a10), 0x40 },
+ { CCI_REG8(0x3a11), 0x40 }, { CCI_REG8(0x3a12), 0x40 },
+ { CCI_REG8(0x3a13), 0x40 }, { CCI_REG8(0x3a14), 0x40 },
+ { CCI_REG8(0x3a15), 0x40 }, { CCI_REG8(0x3a16), 0x40 },
+ { CCI_REG8(0x3a17), 0x40 }, { CCI_REG8(0x3a18), 0x40 },
+ { CCI_REG8(0x3a19), 0x40 }, { CCI_REG8(0x3a1a), 0x40 },
+ { CCI_REG8(0x3a1b), 0x40 }, { CCI_REG8(0x3a1c), 0x40 },
+ { CCI_REG8(0x3a1d), 0x40 }, { CCI_REG8(0x3a1e), 0x40 },
+ { CCI_REG8(0x3a1f), 0x40 }, { CCI_REG8(0x3a20), 0x40 },
+ { CCI_REG8(0x3a21), 0x40 }, { CCI_REG8(0x3a22), 0x40 },
+ { CCI_REG8(0x3a23), 0x40 }, { CCI_REG8(0x3a24), 0x40 },
+ { CCI_REG8(0x3a25), 0x40 }, { CCI_REG8(0x3a26), 0x40 },
+ { CCI_REG8(0x3a27), 0x40 }, { CCI_REG8(0x3a28), 0x40 },
+ { CCI_REG8(0x3a29), 0x40 }, { CCI_REG8(0x3a2a), 0x40 },
+ { CCI_REG8(0x3a2b), 0x40 }, { CCI_REG8(0x3a2c), 0x40 },
+ { CCI_REG8(0x3a2d), 0x40 }, { CCI_REG8(0x3a2e), 0x40 },
+ { CCI_REG8(0x3a2f), 0x40 }, { CCI_REG8(0x3a30), 0x40 },
+ { CCI_REG8(0x3a31), 0x40 }, { CCI_REG8(0x3a32), 0x40 },
+ { CCI_REG8(0x3a33), 0x40 }, { CCI_REG8(0x3a34), 0x40 },
+ { CCI_REG8(0x3a35), 0x40 }, { CCI_REG8(0x3a36), 0x40 },
+ { CCI_REG8(0x3a37), 0x40 }, { CCI_REG8(0x3a38), 0x40 },
+ { CCI_REG8(0x3a39), 0x40 }, { CCI_REG8(0x3a3a), 0x40 },
+ { CCI_REG8(0x3a3b), 0xcd }, { CCI_REG8(0x3a3c), 0xcd },
+ { CCI_REG8(0x3a3d), 0xcd }, { CCI_REG8(0x3a3e), 0xcd },
+ { CCI_REG8(0x3a3f), 0xcd }, { CCI_REG8(0x3a40), 0xcd },
+ { CCI_REG8(0x3a41), 0xcd }, { CCI_REG8(0x3a42), 0xcd },
+ { CCI_REG8(0x3a43), 0xcd }, { CCI_REG8(0x3a44), 0xcd },
+ { CCI_REG8(0x3a45), 0xcd }, { CCI_REG8(0x3a46), 0xcd },
+ { CCI_REG8(0x3a47), 0xcd }, { CCI_REG8(0x3a48), 0xcd },
+ { CCI_REG8(0x3a49), 0xcd }, { CCI_REG8(0x3a4a), 0xcd },
+ { CCI_REG8(0x3a4b), 0xcd }, { CCI_REG8(0x3a4c), 0xcd },
+ { CCI_REG8(0x3a4d), 0xcd }, { CCI_REG8(0x3a4e), 0xcd },
+ { CCI_REG8(0x3a4f), 0xcd }, { CCI_REG8(0x3a50), 0xcd },
+ { CCI_REG8(0x3a51), 0xcd }, { CCI_REG8(0x3a52), 0xcd },
+ { CCI_REG8(0x3a53), 0xcd }, { CCI_REG8(0x3a54), 0xcd },
+ { CCI_REG8(0x3a55), 0xcd }, { CCI_REG8(0x3a56), 0xcd },
+ { CCI_REG8(0x3a57), 0xcd }, { CCI_REG8(0x3a58), 0xcd },
+ { CCI_REG8(0x3a59), 0xcd }, { CCI_REG8(0x3a5a), 0xcd },
+ { CCI_REG8(0x3a5b), 0xcd }, { CCI_REG8(0x3a5c), 0xcd },
+ { CCI_REG8(0x3a5d), 0xcd }, { CCI_REG8(0x3a5e), 0xcd },
+ { CCI_REG8(0x3a5f), 0xcd }, { CCI_REG8(0x3a60), 0xcd },
+ { CCI_REG8(0x3a61), 0xcd }, { CCI_REG8(0x3a62), 0xcd },
+ { CCI_REG8(0x3a63), 0xcd }, { CCI_REG8(0x3a64), 0xcd },
+ { CCI_REG8(0x3a65), 0xcd }, { CCI_REG8(0x3a66), 0xcd },
+ { CCI_REG8(0x3a67), 0xcd }, { CCI_REG8(0x3a68), 0xcd },
+ { CCI_REG8(0x3a69), 0xcd }, { CCI_REG8(0x3a6a), 0xcd },
+ { CCI_REG8(0x3a6b), 0xcd }, { CCI_REG8(0x3a6c), 0xcd },
+ { CCI_REG8(0x3a6d), 0xcd }, { CCI_REG8(0x3a6e), 0xcd },
+ { CCI_REG8(0x3a6f), 0xcd }, { CCI_REG8(0x3a70), 0xcd },
+ { CCI_REG8(0x3a71), 0xcd }, { CCI_REG8(0x3a72), 0xcd },
+ { CCI_REG8(0x3a73), 0xcd }, { CCI_REG8(0x3a74), 0xcd },
+ { CCI_REG8(0x3a75), 0xcd }, { CCI_REG8(0x3a76), 0xcd },
+ { CCI_REG8(0x3a77), 0xcd }, { CCI_REG8(0x3a78), 0xcd },
+ { CCI_REG8(0x3a79), 0xcd }, { CCI_REG8(0x3a7a), 0xcd },
+ { CCI_REG8(0x3a7b), 0xcd }, { CCI_REG8(0x3a7c), 0xcd },
+ { CCI_REG8(0x3a7d), 0xcd }, { CCI_REG8(0x3a7e), 0xcd },
+ { CCI_REG8(0x3a7f), 0xcd }, { CCI_REG8(0x3a80), 0xcd },
+ { CCI_REG8(0x3a81), 0xcd }, { CCI_REG8(0x3a82), 0xcd },
+ { CCI_REG8(0x3a83), 0xcd }, { CCI_REG8(0x3a84), 0xcd },
+ { CCI_REG8(0x3a85), 0xcd }, { CCI_REG8(0x3a86), 0xcd },
+ { CCI_REG8(0x3a87), 0xcd }, { CCI_REG8(0x3a88), 0xcd },
+ { CCI_REG8(0x3a89), 0xcd }, { CCI_REG8(0x3a8a), 0xcd },
+ { CCI_REG8(0x3a8b), 0xcd }, { CCI_REG8(0x3a8c), 0xcd },
+ { CCI_REG8(0x3a8d), 0xcd }, { CCI_REG8(0x3a8e), 0xcd },
+ { CCI_REG8(0x3a8f), 0xcd }, { CCI_REG8(0x3a90), 0xcd },
+ { CCI_REG8(0x3a91), 0xcd }, { CCI_REG8(0x3a92), 0xcd },
+ { CCI_REG8(0x3a93), 0xcd }, { CCI_REG8(0x3a94), 0xcd },
+ { CCI_REG8(0x3a95), 0x40 }, { CCI_REG8(0x3a96), 0x40 },
+ { CCI_REG8(0x3a97), 0x40 }, { CCI_REG8(0x3a98), 0x40 },
+ { CCI_REG8(0x3a99), 0x40 }, { CCI_REG8(0x3a9a), 0x40 },
+ { CCI_REG8(0x3a9b), 0x40 }, { CCI_REG8(0x3a9c), 0x40 },
+ { CCI_REG8(0x3a9d), 0x40 }, { CCI_REG8(0x3a9e), 0x40 },
+ { CCI_REG8(0x3a9f), 0x40 }, { CCI_REG8(0x3aa0), 0x40 },
+ { CCI_REG8(0x3aa1), 0x40 }, { CCI_REG8(0x3aa2), 0x40 },
+ { CCI_REG8(0x3aa3), 0x40 }, { CCI_REG8(0x3aa4), 0x40 },
+ { CCI_REG8(0x3aa5), 0x40 }, { CCI_REG8(0x3aa6), 0x40 },
+ { CCI_REG8(0x3aa7), 0x40 }, { CCI_REG8(0x3aa8), 0x40 },
+ { CCI_REG8(0x3aa9), 0x40 }, { CCI_REG8(0x3aaa), 0x40 },
+ { CCI_REG8(0x3aab), 0x40 }, { CCI_REG8(0x3aac), 0x40 },
+ { CCI_REG8(0x3aad), 0x40 }, { CCI_REG8(0x3aae), 0x40 },
+ { CCI_REG8(0x3aaf), 0x40 }, { CCI_REG8(0x3ab0), 0x40 },
+ { CCI_REG8(0x3ab1), 0x40 }, { CCI_REG8(0x3ab2), 0x40 },
+ { CCI_REG8(0x3ab3), 0x40 }, { CCI_REG8(0x3ab4), 0x40 },
+ { CCI_REG8(0x3ab5), 0x40 }, { CCI_REG8(0x3ab6), 0x40 },
+ { CCI_REG8(0x3ab7), 0x40 }, { CCI_REG8(0x3ab8), 0x40 },
+ { CCI_REG8(0x3ab9), 0x40 }, { CCI_REG8(0x3aba), 0x40 },
+ { CCI_REG8(0x3abb), 0x40 }, { CCI_REG8(0x3abc), 0x40 },
+ { CCI_REG8(0x3abd), 0x40 }, { CCI_REG8(0x3abe), 0x40 },
+ { CCI_REG8(0x3abf), 0x40 }, { CCI_REG8(0x3ac0), 0x40 },
+ { CCI_REG8(0x3ac1), 0x40 }, { CCI_REG8(0x3ac2), 0x40 },
+ { CCI_REG8(0x3ac3), 0x40 }, { CCI_REG8(0x3ac4), 0x40 },
+ { CCI_REG8(0x3ac5), 0x40 }, { CCI_REG8(0x3ac6), 0x40 },
+ { CCI_REG8(0x3ac7), 0x40 }, { CCI_REG8(0x3ac8), 0x40 },
+ { CCI_REG8(0x3ac9), 0x40 }, { CCI_REG8(0x3aca), 0x40 },
+ { CCI_REG8(0x3acb), 0x40 }, { CCI_REG8(0x3acc), 0x40 },
+ { CCI_REG8(0x3acd), 0x40 }, { CCI_REG8(0x3ace), 0x40 },
+ { CCI_REG8(0x3acf), 0x40 }, { CCI_REG8(0x3ad0), 0x40 },
+ { CCI_REG8(0x3ad1), 0x40 }, { CCI_REG8(0x3ad2), 0x40 },
+ { CCI_REG8(0x3ad3), 0x40 }, { CCI_REG8(0x3ad4), 0x40 },
+ { CCI_REG8(0x3ad5), 0x40 }, { CCI_REG8(0x3ad6), 0x40 },
+ { CCI_REG8(0x3ad7), 0x40 }, { CCI_REG8(0x3ad8), 0x40 },
+ { CCI_REG8(0x3ad9), 0x40 }, { CCI_REG8(0x3ada), 0x40 },
+ { CCI_REG8(0x3adb), 0x40 }, { CCI_REG8(0x3adc), 0x40 },
+ { CCI_REG8(0x3add), 0x40 }, { CCI_REG8(0x3ade), 0x40 },
+ { CCI_REG8(0x3adf), 0x40 }, { CCI_REG8(0x3ae0), 0x40 },
+ { CCI_REG8(0x3ae1), 0x40 }, { CCI_REG8(0x3ae2), 0x40 },
+ { CCI_REG8(0x3ae3), 0x40 }, { CCI_REG8(0x3ae4), 0x40 },
+ { CCI_REG8(0x3ae5), 0x40 }, { CCI_REG8(0x3ae6), 0x40 },
+ { CCI_REG8(0x3ae7), 0x40 }, { CCI_REG8(0x3ae8), 0x40 },
+ { CCI_REG8(0x3ae9), 0x40 }, { CCI_REG8(0x3aea), 0x40 },
+ { CCI_REG8(0x3aeb), 0x40 }, { CCI_REG8(0x3aec), 0x40 },
+ { CCI_REG8(0x3aed), 0x40 }, { CCI_REG8(0x3aee), 0x40 },
+ { CCI_REG8(0x3aef), 0xcd }, { CCI_REG8(0x3af0), 0xcd },
+ { CCI_REG8(0x3af1), 0xcd }, { CCI_REG8(0x3af2), 0xcd },
+ { CCI_REG8(0x3af3), 0xcd }, { CCI_REG8(0x3af4), 0xcd },
+ { CCI_REG8(0x3af5), 0xcd }, { CCI_REG8(0x3af6), 0xcd },
+ { CCI_REG8(0x3af7), 0xcd }, { CCI_REG8(0x3af8), 0xcd },
+ { CCI_REG8(0x3af9), 0xcd }, { CCI_REG8(0x3afa), 0xcd },
+ { CCI_REG8(0x3afb), 0xcd }, { CCI_REG8(0x3afc), 0xcd },
+ { CCI_REG8(0x3afd), 0xcd }, { CCI_REG8(0x3afe), 0xcd },
+ { CCI_REG8(0x3aff), 0xcd }, { CCI_REG8(0x3b00), 0xcd },
+ { CCI_REG8(0x3b01), 0xcd }, { CCI_REG8(0x3b02), 0xcd },
+ { CCI_REG8(0x3b03), 0xcd }, { CCI_REG8(0x3b04), 0xcd },
+ { CCI_REG8(0x3b05), 0xcd }, { CCI_REG8(0x3b06), 0xcd },
+ { CCI_REG8(0x3b07), 0xcd }, { CCI_REG8(0x3b08), 0xcd },
+ { CCI_REG8(0x3b09), 0xcd }, { CCI_REG8(0x3b0a), 0xcd },
+ { CCI_REG8(0x3b0b), 0xcd }, { CCI_REG8(0x3b0c), 0xcd },
+ { CCI_REG8(0x3b0d), 0xcd }, { CCI_REG8(0x3b0e), 0xcd },
+ { CCI_REG8(0x3b0f), 0xcd }, { CCI_REG8(0x3b10), 0xcd },
+ { CCI_REG8(0x3b11), 0xcd }, { CCI_REG8(0x3b12), 0xcd },
+ { CCI_REG8(0x3b13), 0xcd }, { CCI_REG8(0x3b14), 0xcd },
+ { CCI_REG8(0x3b15), 0xcd }, { CCI_REG8(0x3b16), 0xcd },
+ { CCI_REG8(0x3b17), 0xcd }, { CCI_REG8(0x3b18), 0xcd },
+ { CCI_REG8(0x3b19), 0xcd }, { CCI_REG8(0x3b1a), 0xcd },
+ { CCI_REG8(0x3b1b), 0xcd }, { CCI_REG8(0x3b1c), 0xcd },
+ { CCI_REG8(0x3b1d), 0xcd }, { CCI_REG8(0x3b1e), 0xcd },
+ { CCI_REG8(0x3b1f), 0xcd }, { CCI_REG8(0x3b20), 0xcd },
+ { CCI_REG8(0x3b21), 0xcd }, { CCI_REG8(0x3b22), 0xcd },
+ { CCI_REG8(0x3b23), 0xcd }, { CCI_REG8(0x3b24), 0xcd },
+ { CCI_REG8(0x3b25), 0xcd }, { CCI_REG8(0x3b26), 0xcd },
+ { CCI_REG8(0x3b27), 0xcd }, { CCI_REG8(0x3b28), 0xcd },
+ { CCI_REG8(0x3b29), 0xcd }, { CCI_REG8(0x3b2a), 0xcd },
+ { CCI_REG8(0x3b2b), 0xcd }, { CCI_REG8(0x3b2c), 0xcd },
+ { CCI_REG8(0x3b2d), 0xcd }, { CCI_REG8(0x3b2e), 0xcd },
+ { CCI_REG8(0x3b2f), 0xcd }, { CCI_REG8(0x3b30), 0xcd },
+ { CCI_REG8(0x3b31), 0xcd }, { CCI_REG8(0x3b32), 0xcd },
+ { CCI_REG8(0x3b33), 0xcd }, { CCI_REG8(0x3b34), 0xcd },
+ { CCI_REG8(0x3b35), 0xcd }, { CCI_REG8(0x3b36), 0xcd },
+ { CCI_REG8(0x3b37), 0xcd }, { CCI_REG8(0x3b38), 0xcd },
+ { CCI_REG8(0x3b39), 0xcd }, { CCI_REG8(0x3b3a), 0xcd },
+ { CCI_REG8(0x3b3b), 0xcd }, { CCI_REG8(0x3b3c), 0xcd },
+ { CCI_REG8(0x3b3d), 0xcd }, { CCI_REG8(0x3b3e), 0xcd },
+ { CCI_REG8(0x3b3f), 0xcd }, { CCI_REG8(0x3b40), 0xcd },
+ { CCI_REG8(0x3b41), 0xcd }, { CCI_REG8(0x3b42), 0xcd },
+ { CCI_REG8(0x3b43), 0xcd }, { CCI_REG8(0x3b44), 0xcd },
+ { CCI_REG8(0x3b45), 0xcd }, { CCI_REG8(0x3b46), 0xcd },
+ { CCI_REG8(0x3b47), 0xcd }, { CCI_REG8(0x3b48), 0xcd },
+ { CCI_REG8(0x3b49), 0xcd }, { CCI_REG8(0x3b4a), 0xcd },
+ { CCI_REG8(0x3b4b), 0xcd }, { CCI_REG8(0x3b4c), 0xcd },
+ { CCI_REG8(0x3b4d), 0xcd }, { CCI_REG8(0x3b4e), 0xcd },
+ { CCI_REG8(0x3b4f), 0xcd }, { CCI_REG8(0x3b50), 0xcd },
+ { CCI_REG8(0x3b51), 0xcd }, { CCI_REG8(0x3b52), 0xcd },
+ { CCI_REG8(0x3b53), 0xcd }, { CCI_REG8(0x3b54), 0xcd },
+ { CCI_REG8(0x3b55), 0xcd }, { CCI_REG8(0x3b56), 0xcd },
+ { CCI_REG8(0x3b57), 0xcd }, { CCI_REG8(0x3b58), 0xcd },
+ { CCI_REG8(0x3b59), 0xcd }, { CCI_REG8(0x3b5a), 0xcd },
+ { CCI_REG8(0x3b5b), 0xcd }, { CCI_REG8(0x3b5c), 0xcd },
+ { CCI_REG8(0x3b5d), 0xcd }, { CCI_REG8(0x3b5e), 0xcd },
+ { CCI_REG8(0x3b5f), 0xcd }, { CCI_REG8(0x3b60), 0xcd },
+ { CCI_REG8(0x3b61), 0xcd }, { CCI_REG8(0x3b62), 0xcd },
+ { CCI_REG8(0x3b63), 0xcd }, { CCI_REG8(0x3b64), 0xcd },
+ { CCI_REG8(0x3b65), 0xcd }, { CCI_REG8(0x3b66), 0xcd },
+ { CCI_REG8(0x3b67), 0xcd }, { CCI_REG8(0x3b68), 0xcd },
+ { CCI_REG8(0x3b69), 0xcd }, { CCI_REG8(0x3b6a), 0xcd },
+ { CCI_REG8(0x3b6b), 0xcd }, { CCI_REG8(0x3b6c), 0xcd },
+ { CCI_REG8(0x3b6d), 0xcd }, { CCI_REG8(0x3b6e), 0xcd },
+ { CCI_REG8(0x3b6f), 0xcd }, { CCI_REG8(0x3b70), 0xcd },
+ { CCI_REG8(0x3b71), 0xcd }, { CCI_REG8(0x3b72), 0xcd },
+ { CCI_REG8(0x3b73), 0xcd }, { CCI_REG8(0x3b74), 0xcd },
+ { CCI_REG8(0x3b75), 0xcd }, { CCI_REG8(0x3b76), 0xcd },
+ { CCI_REG8(0x3b77), 0xcd }, { CCI_REG8(0x3b78), 0xcd },
+ { CCI_REG8(0x3b79), 0xcd }, { CCI_REG8(0x3b7a), 0xcd },
+ { CCI_REG8(0x3b7b), 0xcd }, { CCI_REG8(0x3b7c), 0xcd },
+ { CCI_REG8(0x3b7d), 0xcd }, { CCI_REG8(0x3b7e), 0xcd },
+ { CCI_REG8(0x3b7f), 0xcd }, { CCI_REG8(0x3b80), 0xcd },
+ { CCI_REG8(0x3b81), 0xcd }, { CCI_REG8(0x3b82), 0xcd },
+ { CCI_REG8(0x3b83), 0xcd }, { CCI_REG8(0x3b84), 0xcd },
+ { CCI_REG8(0x3b85), 0xcd }, { CCI_REG8(0x3b86), 0xcd },
+ { CCI_REG8(0x3b87), 0xcd }, { CCI_REG8(0x3b88), 0xcd },
+ { CCI_REG8(0x3b89), 0xcd }, { CCI_REG8(0x3b8a), 0xcd },
+ { CCI_REG8(0x3b8b), 0xcd }, { CCI_REG8(0x3b8c), 0xcd },
+ { CCI_REG8(0x3b8d), 0xcd }, { CCI_REG8(0x3b8e), 0xcd },
+ { CCI_REG8(0x3b8f), 0xcd }, { CCI_REG8(0x3b90), 0xcd },
+ { CCI_REG8(0x3b91), 0xcd }, { CCI_REG8(0x3b92), 0xcd },
+ { CCI_REG8(0x3b93), 0xcd }, { CCI_REG8(0x3b94), 0xcd },
+ { CCI_REG8(0x3b95), 0xcd }, { CCI_REG8(0x3b96), 0xcd },
+ { CCI_REG8(0x3b97), 0xcd }, { CCI_REG8(0x3b98), 0xcd },
+ { CCI_REG8(0x3b99), 0xcd }, { CCI_REG8(0x3b9a), 0xcd },
+ { CCI_REG8(0x3b9b), 0xcd }, { CCI_REG8(0x3b9c), 0xcd },
+ { CCI_REG8(0x3b9d), 0xcd }, { CCI_REG8(0x3b9e), 0xcd },
+ { CCI_REG8(0x3b9f), 0xcd }, { CCI_REG8(0x3ba0), 0xcd },
+ { CCI_REG8(0x3ba1), 0xcd }, { CCI_REG8(0x3ba2), 0xcd },
+ { CCI_REG8(0x3ba3), 0xcd }, { CCI_REG8(0x3ba4), 0xcd },
+ { CCI_REG8(0x3ba5), 0xcd }, { CCI_REG8(0x3ba6), 0xcd },
+ { CCI_REG8(0x3ba7), 0xcd }, { CCI_REG8(0x3ba8), 0xcd },
+ { CCI_REG8(0x3ba9), 0xcd }, { CCI_REG8(0x3baa), 0xcd },
+ { CCI_REG8(0x3bab), 0xcd }, { CCI_REG8(0x3bac), 0xcd },
+ { CCI_REG8(0x3bad), 0xcd }, { CCI_REG8(0x3bae), 0xcd },
+ { CCI_REG8(0x3baf), 0xcd }, { CCI_REG8(0x3bb0), 0xcd },
+ { CCI_REG8(0x3bb1), 0xcd }, { CCI_REG8(0x3bb2), 0xcd },
+ { CCI_REG8(0x3bb3), 0xcd }, { CCI_REG8(0x3bb4), 0xcd },
+ { CCI_REG8(0x3bb5), 0xcd }, { CCI_REG8(0x3bb6), 0xcd },
+ { CCI_REG8(0x3bb7), 0xcd }, { CCI_REG8(0x3bb8), 0xcd },
+ { CCI_REG8(0x3bb9), 0xcd }, { CCI_REG8(0x3bba), 0xcd },
+ { CCI_REG8(0x3bbb), 0xcd }, { CCI_REG8(0x3bbc), 0xcd },
+ { CCI_REG8(0x3bbd), 0xcd }, { CCI_REG8(0x3bbe), 0xcd },
+ { CCI_REG8(0x3bbf), 0xcd }, { CCI_REG8(0x3bc0), 0xcd },
+ { CCI_REG8(0x3bc1), 0xcd }, { CCI_REG8(0x3bc2), 0xcd },
+ { CCI_REG8(0x3bc3), 0xcd }, { CCI_REG8(0x3bc4), 0xcd },
+ { CCI_REG8(0x3bc5), 0xcd }, { CCI_REG8(0x3bc6), 0xcd },
+ { CCI_REG8(0x3bc7), 0xcd }, { CCI_REG8(0x3bc8), 0xcd },
+ { CCI_REG8(0x3bc9), 0xcd }, { CCI_REG8(0x3bca), 0xcd },
+ { CCI_REG8(0x3bcb), 0xcd }, { CCI_REG8(0x3bcc), 0xcd },
+ { CCI_REG8(0x3bcd), 0xcd }, { CCI_REG8(0x3bce), 0xcd },
+ { CCI_REG8(0x3bcf), 0xcd }, { CCI_REG8(0x3bd0), 0xcd },
+ { CCI_REG8(0x3bd1), 0xcd }, { CCI_REG8(0x3bd2), 0xcd },
+ { CCI_REG8(0x3bd3), 0xcd }, { CCI_REG8(0x3bd4), 0xcd },
+ { CCI_REG8(0x3bd5), 0xcd }, { CCI_REG8(0x3bd6), 0xcd },
+ { CCI_REG8(0x3bd7), 0xcd }, { CCI_REG8(0x3bd8), 0xcd },
+ { CCI_REG8(0x3bd9), 0xcd }, { CCI_REG8(0x3bda), 0xcd },
+ { CCI_REG8(0x3bdb), 0xcd }, { CCI_REG8(0x3bdc), 0xcd },
+ { CCI_REG8(0x3bdd), 0xcd }, { CCI_REG8(0x3bde), 0xcd },
+ { CCI_REG8(0x3bdf), 0xcd }, { CCI_REG8(0x3be0), 0xcd },
+ { CCI_REG8(0x3be1), 0xcd }, { CCI_REG8(0x3be2), 0xcd },
+ { CCI_REG8(0x3be3), 0xcd }, { CCI_REG8(0x3be4), 0xcd },
+ { CCI_REG8(0x3be5), 0xcd }, { CCI_REG8(0x3be6), 0xcd },
+ { CCI_REG8(0x3be7), 0xcd }, { CCI_REG8(0x3be8), 0xcd },
+ { CCI_REG8(0x3be9), 0xcd }, { CCI_REG8(0x3bea), 0xcd },
+ { CCI_REG8(0x3beb), 0xcd }, { CCI_REG8(0x3bec), 0xcd },
+ { CCI_REG8(0x3bed), 0xcd }, { CCI_REG8(0x3bee), 0xcd },
+ { CCI_REG8(0x3bef), 0xcd }, { CCI_REG8(0x3bf0), 0xcd },
+ { CCI_REG8(0x3bf1), 0xcd }, { CCI_REG8(0x3bf2), 0xcd },
+ { CCI_REG8(0x3bf3), 0xcd }, { CCI_REG8(0x3bf4), 0xcd },
+ { CCI_REG8(0x3bf5), 0xcd }, { CCI_REG8(0x3bf6), 0xcd },
+ { CCI_REG8(0x3bf7), 0xcd }, { CCI_REG8(0x3bf8), 0xcd },
+ { CCI_REG8(0x3bf9), 0xcd }, { CCI_REG8(0x3bfa), 0xcd },
+ { CCI_REG8(0x3bfb), 0xcd }, { CCI_REG8(0x3bfc), 0xcd },
+ { CCI_REG8(0x3bfd), 0xcd }, { CCI_REG8(0x3bfe), 0xcd },
+ { CCI_REG8(0x3bff), 0xcd }, { CCI_REG8(0x3c00), 0xcd },
+ { CCI_REG8(0x3c01), 0xcd }, { CCI_REG8(0x3c02), 0xcd },
+ { CCI_REG8(0x3c03), 0xcd }, { CCI_REG8(0x3c04), 0xcd },
+ { CCI_REG8(0x3c05), 0xcd }, { CCI_REG8(0x3c06), 0xcd },
+ { CCI_REG8(0x3c07), 0xcd }, { CCI_REG8(0x3c08), 0xcd },
+ { CCI_REG8(0x3c09), 0xcd }, { CCI_REG8(0x3c0a), 0xcd },
+ { CCI_REG8(0x3c0b), 0xcd }, { CCI_REG8(0x3c0c), 0xcd },
+ { CCI_REG8(0x3c0d), 0xcd }, { CCI_REG8(0x3c0e), 0xcd },
+ { CCI_REG8(0x3c0f), 0xcd }, { CCI_REG8(0x3c10), 0xcd },
+ { CCI_REG8(0x3c11), 0xcd }, { CCI_REG8(0x3c12), 0xcd },
+ { CCI_REG8(0x3c13), 0xcd }, { CCI_REG8(0x3c14), 0xcd },
+ { CCI_REG8(0x3c15), 0xcd }, { CCI_REG8(0x3c16), 0xcd },
+ { CCI_REG8(0x3c17), 0xcd }, { CCI_REG8(0x3c18), 0xcd },
+ { CCI_REG8(0x3c19), 0xcd }, { CCI_REG8(0x3c1a), 0xcd },
+ { CCI_REG8(0x3c1b), 0xcd }, { CCI_REG8(0x3c1c), 0xcd },
+ { CCI_REG8(0x3c1d), 0xcd }, { CCI_REG8(0x3c1e), 0xcd },
+ { CCI_REG8(0x3c1f), 0xcd }, { CCI_REG8(0x3c20), 0xcd },
+ { CCI_REG8(0x3c21), 0xcd }, { CCI_REG8(0x3c22), 0xcd },
+ { CCI_REG8(0x3c23), 0xcd }, { CCI_REG8(0x3c24), 0xcd },
+ { CCI_REG8(0x3c25), 0xcd }, { CCI_REG8(0x3c26), 0xcd },
+ { CCI_REG8(0x3c27), 0xcd }, { CCI_REG8(0x3c28), 0xcd },
+ { CCI_REG8(0x3c29), 0xcd }, { CCI_REG8(0x3c2a), 0xcd },
+ { CCI_REG8(0x3c2b), 0xcd }, { CCI_REG8(0x3c2c), 0xcd },
+ { CCI_REG8(0x3c2d), 0xcd }, { CCI_REG8(0x3c2e), 0xcd },
+ { CCI_REG8(0x3c2f), 0xcd }, { CCI_REG8(0x3c30), 0xcd },
+ { CCI_REG8(0x3c31), 0xcd }, { CCI_REG8(0x3c32), 0xcd },
+ { CCI_REG8(0x3c33), 0xcd }, { CCI_REG8(0x3c34), 0xcd },
+ { CCI_REG8(0x3c35), 0xcd }, { CCI_REG8(0x3c36), 0xcd },
+ { CCI_REG8(0x3c37), 0xcd }, { CCI_REG8(0x3c38), 0xcd },
+ { CCI_REG8(0x3c39), 0xcd }, { CCI_REG8(0x3c3a), 0xcd },
+ { CCI_REG8(0x3c3b), 0xcd }, { CCI_REG8(0x3c3c), 0xcd },
+ { CCI_REG8(0x3c3d), 0xcd }, { CCI_REG8(0x3c3e), 0xcd },
+ { CCI_REG8(0x3c3f), 0xcd }, { CCI_REG8(0x3c40), 0xcd },
+ { CCI_REG8(0x3c41), 0xcd }, { CCI_REG8(0x3c42), 0xcd },
+ { CCI_REG8(0x3c43), 0xcd }, { CCI_REG8(0x3c44), 0xcd },
+ { CCI_REG8(0x3c45), 0xcd }, { CCI_REG8(0x3c46), 0xcd },
+ { CCI_REG8(0x3c47), 0xcd }, { CCI_REG8(0x3c48), 0xcd },
+ { CCI_REG8(0x3c49), 0xcd }, { CCI_REG8(0x3c4a), 0xcd },
+ { CCI_REG8(0x3c4b), 0xcd }, { CCI_REG8(0x3c4c), 0xcd },
+ { CCI_REG8(0x3c4d), 0xcd }, { CCI_REG8(0x3c4e), 0xcd },
+ { CCI_REG8(0x3c4f), 0xcd }, { CCI_REG8(0x3c50), 0xcd },
+ { CCI_REG8(0x3c51), 0xcd }, { CCI_REG8(0x3c52), 0xcd },
+ { CCI_REG8(0x3c53), 0xcd }, { CCI_REG8(0x3c54), 0xcd },
+ { CCI_REG8(0x3c55), 0xcd }, { CCI_REG8(0x3c56), 0xcd },
+ { CCI_REG8(0x3c57), 0xcd }, { CCI_REG8(0x3c58), 0xcd },
+ { CCI_REG8(0x3c59), 0xcd }, { CCI_REG8(0x3c5a), 0xcd },
+ { CCI_REG8(0x3c5b), 0xcd }, { CCI_REG8(0x3c5c), 0xcd },
+ { CCI_REG8(0x3c5d), 0xcd }, { CCI_REG8(0x3c5e), 0xcd },
+ { CCI_REG8(0x3c5f), 0xcd }, { CCI_REG8(0x3c60), 0xcd },
+ { CCI_REG8(0x3c61), 0xcd }, { CCI_REG8(0x3c62), 0xcd },
+ { CCI_REG8(0x3c63), 0xcd }, { CCI_REG8(0x3c64), 0xcd },
+ { CCI_REG8(0x3c65), 0xcd }, { CCI_REG8(0x3c66), 0xcd },
+ { CCI_REG8(0x3c67), 0xcd }, { CCI_REG8(0x3c68), 0xcd },
+ { CCI_REG8(0x3c69), 0xcd }, { CCI_REG8(0x3c6a), 0xcd },
+ { CCI_REG8(0x3c6b), 0xcd }, { CCI_REG8(0x3c6c), 0xcd },
+ { CCI_REG8(0x3c6d), 0xcd }, { CCI_REG8(0x3c6e), 0xcd },
+ { CCI_REG8(0x3c6f), 0xcd }, { CCI_REG8(0x3c70), 0xcd },
+ { CCI_REG8(0x3c71), 0xcd }, { CCI_REG8(0x3c72), 0xcd },
+ { CCI_REG8(0x3c73), 0xcd }, { CCI_REG8(0x3c74), 0xcd },
+ { CCI_REG8(0x3c75), 0xcd }, { CCI_REG8(0x3c76), 0xcd },
+ { CCI_REG8(0x3c77), 0xcd }, { CCI_REG8(0x3c78), 0xcd },
+ { CCI_REG8(0x3c79), 0xcd }, { CCI_REG8(0x3c7a), 0xcd },
+ { CCI_REG8(0x3c7b), 0xcd }, { CCI_REG8(0x3c7c), 0xcd },
+ { CCI_REG8(0x3c7d), 0xcd }, { CCI_REG8(0x3c7e), 0xcd },
+ { CCI_REG8(0x3c7f), 0xcd }, { CCI_REG8(0x3c80), 0xcd },
+ { CCI_REG8(0x3c81), 0xcd }, { CCI_REG8(0x3c82), 0xcd },
+ { CCI_REG8(0x3c83), 0xcd }, { CCI_REG8(0x3c84), 0xcd },
+ { CCI_REG8(0x3c85), 0xcd }, { CCI_REG8(0x3c86), 0xcd },
+ { CCI_REG8(0x3c87), 0xcd }, { CCI_REG8(0x3c88), 0xcd },
+ { CCI_REG8(0x3c89), 0xcd }, { CCI_REG8(0x3c8a), 0xcd },
+ { CCI_REG8(0x3c8b), 0xcd }, { CCI_REG8(0x3c8c), 0xcd },
+ { CCI_REG8(0x3c8d), 0xcd }, { CCI_REG8(0x3c8e), 0xcd },
+ { CCI_REG8(0x3c8f), 0xcd }, { CCI_REG8(0x3c90), 0xcd },
+ { CCI_REG8(0x3c91), 0xcd }, { CCI_REG8(0x3c92), 0xcd },
+ { CCI_REG8(0x3c93), 0xcd }, { CCI_REG8(0x3c94), 0xcd },
+ { CCI_REG8(0x3c95), 0xcd }, { CCI_REG8(0x3c96), 0xcd },
+ { CCI_REG8(0x3c97), 0xcd }, { CCI_REG8(0x3c98), 0xcd },
+ { CCI_REG8(0x3c99), 0xcd }, { CCI_REG8(0x3c9a), 0xcd },
+ { CCI_REG8(0x3c9b), 0xcd }, { CCI_REG8(0x3c9c), 0xcd },
+ { CCI_REG8(0x3c9d), 0xcd }, { CCI_REG8(0x3c9e), 0xcd },
+ { CCI_REG8(0x3c9f), 0xcd }, { CCI_REG8(0x3ca0), 0xcd },
+ { CCI_REG8(0x3ca1), 0xcd }, { CCI_REG8(0x3ca2), 0xcd },
+ { CCI_REG8(0x3ca3), 0xcd }, { CCI_REG8(0x3ca4), 0xcd },
+ { CCI_REG8(0x3ca5), 0xcd }, { CCI_REG8(0x3ca6), 0xcd },
+ { CCI_REG8(0x3ca7), 0xcd }, { CCI_REG8(0x3ca8), 0xcd },
+ { CCI_REG8(0x3ca9), 0xcd }, { CCI_REG8(0x3caa), 0xcd },
+ { CCI_REG8(0x3cab), 0xcd }, { CCI_REG8(0x3cac), 0xcd },
+ { CCI_REG8(0x3cad), 0xcd }, { CCI_REG8(0x3cae), 0xcd },
+ { CCI_REG8(0x3caf), 0xcd }, { CCI_REG8(0x3cb0), 0xcd },
+ { CCI_REG8(0x3cb1), 0x40 }, { CCI_REG8(0x3cb2), 0x40 },
+ { CCI_REG8(0x3cb3), 0x40 }, { CCI_REG8(0x3cb4), 0x40 },
+ { CCI_REG8(0x3cb5), 0x40 }, { CCI_REG8(0x3cb6), 0x40 },
+ { CCI_REG8(0x3cb7), 0x40 }, { CCI_REG8(0x3cb8), 0x40 },
+ { CCI_REG8(0x3cb9), 0x40 }, { CCI_REG8(0x3cba), 0x40 },
+ { CCI_REG8(0x3cbb), 0x40 }, { CCI_REG8(0x3cbc), 0x40 },
+ { CCI_REG8(0x3cbd), 0x40 }, { CCI_REG8(0x3cbe), 0x40 },
+ { CCI_REG8(0x3cbf), 0x40 }, { CCI_REG8(0x3cc0), 0x40 },
+ { CCI_REG8(0x3cc1), 0x40 }, { CCI_REG8(0x3cc2), 0x40 },
+ { CCI_REG8(0x3cc3), 0x40 }, { CCI_REG8(0x3cc4), 0x40 },
+ { CCI_REG8(0x3cc5), 0x40 }, { CCI_REG8(0x3cc6), 0x40 },
+ { CCI_REG8(0x3cc7), 0x40 }, { CCI_REG8(0x3cc8), 0x40 },
+ { CCI_REG8(0x3cc9), 0x40 }, { CCI_REG8(0x3cca), 0x40 },
+ { CCI_REG8(0x3ccb), 0x40 }, { CCI_REG8(0x3ccc), 0x40 },
+ { CCI_REG8(0x3ccd), 0x40 }, { CCI_REG8(0x3cce), 0x40 },
+ { CCI_REG8(0x3ccf), 0x40 }, { CCI_REG8(0x3cd0), 0x40 },
+ { CCI_REG8(0x3cd1), 0x40 }, { CCI_REG8(0x3cd2), 0x40 },
+ { CCI_REG8(0x3cd3), 0x40 }, { CCI_REG8(0x3cd4), 0x40 },
+ { CCI_REG8(0x3cd5), 0x40 }, { CCI_REG8(0x3cd6), 0x40 },
+ { CCI_REG8(0x3cd7), 0x40 }, { CCI_REG8(0x3cd8), 0x40 },
+ { CCI_REG8(0x3cd9), 0x40 }, { CCI_REG8(0x3cda), 0x40 },
+ { CCI_REG8(0x3cdb), 0x40 }, { CCI_REG8(0x3cdc), 0x40 },
+ { CCI_REG8(0x3cdd), 0x40 }, { CCI_REG8(0x3cde), 0x40 },
+ { CCI_REG8(0x3cdf), 0x40 }, { CCI_REG8(0x3ce0), 0x40 },
+ { CCI_REG8(0x3ce1), 0x40 }, { CCI_REG8(0x3ce2), 0x40 },
+ { CCI_REG8(0x3ce3), 0x40 }, { CCI_REG8(0x3ce4), 0x40 },
+ { CCI_REG8(0x3ce5), 0x40 }, { CCI_REG8(0x3ce6), 0x40 },
+ { CCI_REG8(0x3ce7), 0x40 }, { CCI_REG8(0x3ce8), 0x40 },
+ { CCI_REG8(0x3ce9), 0x40 }, { CCI_REG8(0x3cea), 0x40 },
+ { CCI_REG8(0x3ceb), 0x40 }, { CCI_REG8(0x3cec), 0x40 },
+ { CCI_REG8(0x3ced), 0x40 }, { CCI_REG8(0x3cee), 0x40 },
+ { CCI_REG8(0x3cef), 0x40 }, { CCI_REG8(0x3cf0), 0x40 },
+ { CCI_REG8(0x3cf1), 0x40 }, { CCI_REG8(0x3cf2), 0x40 },
+ { CCI_REG8(0x3cf3), 0x40 }, { CCI_REG8(0x3cf4), 0x40 },
+ { CCI_REG8(0x3cf5), 0x40 }, { CCI_REG8(0x3cf6), 0x40 },
+ { CCI_REG8(0x3cf7), 0x40 }, { CCI_REG8(0x3cf8), 0x40 },
+ { CCI_REG8(0x3cf9), 0x40 }, { CCI_REG8(0x3cfa), 0x40 },
+ { CCI_REG8(0x3cfb), 0x40 }, { CCI_REG8(0x3cfc), 0x40 },
+ { CCI_REG8(0x3cfd), 0x40 }, { CCI_REG8(0x3cfe), 0x40 },
+ { CCI_REG8(0x3cff), 0x40 }, { CCI_REG8(0x3d00), 0x40 },
+ { CCI_REG8(0x3d01), 0x40 }, { CCI_REG8(0x3d02), 0x40 },
+ { CCI_REG8(0x3d03), 0x40 }, { CCI_REG8(0x3d04), 0x40 },
+ { CCI_REG8(0x3d05), 0x40 }, { CCI_REG8(0x3d06), 0x40 },
+ { CCI_REG8(0x3d07), 0x40 }, { CCI_REG8(0x3d08), 0x40 },
+ { CCI_REG8(0x3d09), 0x40 }, { CCI_REG8(0x3d0a), 0x40 },
+ { CCI_REG8(0x3d0b), 0xcd }, { CCI_REG8(0x3d0c), 0xcd },
+ { CCI_REG8(0x3d0d), 0xcd }, { CCI_REG8(0x3d0e), 0xcd },
+ { CCI_REG8(0x3d0f), 0xcd }, { CCI_REG8(0x3d10), 0xcd },
+ { CCI_REG8(0x3d11), 0xcd }, { CCI_REG8(0x3d12), 0xcd },
+ { CCI_REG8(0x3d13), 0xcd }, { CCI_REG8(0x3d14), 0xcd },
+ { CCI_REG8(0x3d15), 0xcd }, { CCI_REG8(0x3d16), 0xcd },
+ { CCI_REG8(0x3d17), 0xcd }, { CCI_REG8(0x3d18), 0xcd },
+ { CCI_REG8(0x3d19), 0xcd }, { CCI_REG8(0x3d1a), 0xcd },
+ { CCI_REG8(0x3d1b), 0xcd }, { CCI_REG8(0x3d1c), 0xcd },
+ { CCI_REG8(0x3d1d), 0xcd }, { CCI_REG8(0x3d1e), 0xcd },
+ { CCI_REG8(0x3d1f), 0xcd }, { CCI_REG8(0x3d20), 0xcd },
+ { CCI_REG8(0x3d21), 0xcd }, { CCI_REG8(0x3d22), 0xcd },
+ { CCI_REG8(0x3d23), 0xcd }, { CCI_REG8(0x3d24), 0xcd },
+ { CCI_REG8(0x3d25), 0xcd }, { CCI_REG8(0x3d26), 0xcd },
+ { CCI_REG8(0x3d27), 0xcd }, { CCI_REG8(0x3d28), 0xcd },
+ { CCI_REG8(0x3d29), 0xcd }, { CCI_REG8(0x3d2a), 0xcd },
+ { CCI_REG8(0x3d2b), 0xcd }, { CCI_REG8(0x3d2c), 0xcd },
+ { CCI_REG8(0x3d2d), 0xcd }, { CCI_REG8(0x3d2e), 0xcd },
+ { CCI_REG8(0x3d2f), 0xcd }, { CCI_REG8(0x3d30), 0xcd },
+ { CCI_REG8(0x3d31), 0xcd }, { CCI_REG8(0x3d32), 0xcd },
+ { CCI_REG8(0x3d33), 0xcd }, { CCI_REG8(0x3d34), 0xcd },
+ { CCI_REG8(0x3d35), 0xcd }, { CCI_REG8(0x3d36), 0xcd },
+ { CCI_REG8(0x3d37), 0xcd }, { CCI_REG8(0x3d38), 0xcd },
+ { CCI_REG8(0x3d39), 0xcd }, { CCI_REG8(0x3d3a), 0xcd },
+ { CCI_REG8(0x3d3b), 0xcd }, { CCI_REG8(0x3d3c), 0xcd },
+ { CCI_REG8(0x3d3d), 0xcd }, { CCI_REG8(0x3d3e), 0xcd },
+ { CCI_REG8(0x3d3f), 0xcd }, { CCI_REG8(0x3d40), 0xcd },
+ { CCI_REG8(0x3d41), 0xcd }, { CCI_REG8(0x3d42), 0xcd },
+ { CCI_REG8(0x3d43), 0xcd }, { CCI_REG8(0x3d44), 0xcd },
+ { CCI_REG8(0x3d45), 0xcd }, { CCI_REG8(0x3d46), 0xcd },
+ { CCI_REG8(0x3d47), 0xcd }, { CCI_REG8(0x3d48), 0xcd },
+ { CCI_REG8(0x3d49), 0xcd }, { CCI_REG8(0x3d4a), 0xcd },
+ { CCI_REG8(0x3d4b), 0xcd }, { CCI_REG8(0x3d4c), 0xcd },
+ { CCI_REG8(0x3d4d), 0xcd }, { CCI_REG8(0x3d4e), 0xcd },
+ { CCI_REG8(0x3d4f), 0xcd }, { CCI_REG8(0x3d50), 0xcd },
+ { CCI_REG8(0x3d51), 0xcd }, { CCI_REG8(0x3d52), 0xcd },
+ { CCI_REG8(0x3d53), 0xcd }, { CCI_REG8(0x3d54), 0xcd },
+ { CCI_REG8(0x3d55), 0xcd }, { CCI_REG8(0x3d56), 0xcd },
+ { CCI_REG8(0x3d57), 0xcd }, { CCI_REG8(0x3d58), 0xcd },
+ { CCI_REG8(0x3d59), 0xcd }, { CCI_REG8(0x3d5a), 0xcd },
+ { CCI_REG8(0x3d5b), 0xcd }, { CCI_REG8(0x3d5c), 0xcd },
+ { CCI_REG8(0x3d5d), 0xcd }, { CCI_REG8(0x3d5e), 0xcd },
+ { CCI_REG8(0x3d5f), 0xcd }, { CCI_REG8(0x3d60), 0xcd },
+ { CCI_REG8(0x3d61), 0xcd }, { CCI_REG8(0x3d62), 0xcd },
+ { CCI_REG8(0x3d63), 0xcd }, { CCI_REG8(0x3d64), 0xcd },
+ { CCI_REG8(0x3d65), 0x40 }, { CCI_REG8(0x3d66), 0x40 },
+ { CCI_REG8(0x3d67), 0x40 }, { CCI_REG8(0x3d68), 0x40 },
+ { CCI_REG8(0x3d69), 0x40 }, { CCI_REG8(0x3d6a), 0x40 },
+ { CCI_REG8(0x3d6b), 0x40 }, { CCI_REG8(0x3d6c), 0x40 },
+ { CCI_REG8(0x3d6d), 0x40 }, { CCI_REG8(0x3d6e), 0x40 },
+ { CCI_REG8(0x3d6f), 0x40 }, { CCI_REG8(0x3d70), 0x40 },
+ { CCI_REG8(0x3d71), 0x40 }, { CCI_REG8(0x3d72), 0x40 },
+ { CCI_REG8(0x3d73), 0x40 }, { CCI_REG8(0x3d74), 0x40 },
+ { CCI_REG8(0x3d75), 0x40 }, { CCI_REG8(0x3d76), 0x40 },
+ { CCI_REG8(0x3d77), 0x40 }, { CCI_REG8(0x3d78), 0x40 },
+ { CCI_REG8(0x3d79), 0x40 }, { CCI_REG8(0x3d7a), 0x40 },
+ { CCI_REG8(0x3d7b), 0x40 }, { CCI_REG8(0x3d7c), 0x40 },
+ { CCI_REG8(0x3d7d), 0x40 }, { CCI_REG8(0x3d7e), 0x40 },
+ { CCI_REG8(0x3d7f), 0x40 }, { CCI_REG8(0x3d80), 0x40 },
+ { CCI_REG8(0x3d81), 0x40 }, { CCI_REG8(0x3d82), 0x40 },
+ { CCI_REG8(0x3d83), 0x40 }, { CCI_REG8(0x3d84), 0x40 },
+ { CCI_REG8(0x3d85), 0x40 }, { CCI_REG8(0x3d86), 0x40 },
+ { CCI_REG8(0x3d87), 0x40 }, { CCI_REG8(0x3d88), 0x40 },
+ { CCI_REG8(0x3d89), 0x40 }, { CCI_REG8(0x3d8a), 0x40 },
+ { CCI_REG8(0x3d8b), 0x40 }, { CCI_REG8(0x3d8c), 0x40 },
+ { CCI_REG8(0x3d8d), 0x40 }, { CCI_REG8(0x3d8e), 0x40 },
+ { CCI_REG8(0x3d8f), 0x40 }, { CCI_REG8(0x3d90), 0x40 },
+ { CCI_REG8(0x3d91), 0x40 }, { CCI_REG8(0x3d92), 0x40 },
+ { CCI_REG8(0x3d93), 0x40 }, { CCI_REG8(0x3d94), 0x40 },
+ { CCI_REG8(0x3d95), 0x40 }, { CCI_REG8(0x3d96), 0x40 },
+ { CCI_REG8(0x3d97), 0x40 }, { CCI_REG8(0x3d98), 0x40 },
+ { CCI_REG8(0x3d99), 0x40 }, { CCI_REG8(0x3d9a), 0x40 },
+ { CCI_REG8(0x3d9b), 0x40 }, { CCI_REG8(0x3d9c), 0x40 },
+ { CCI_REG8(0x3d9d), 0x40 }, { CCI_REG8(0x3d9e), 0x40 },
+ { CCI_REG8(0x3d9f), 0x40 }, { CCI_REG8(0x3da0), 0x40 },
+ { CCI_REG8(0x3da1), 0x40 }, { CCI_REG8(0x3da2), 0x40 },
+ { CCI_REG8(0x3da3), 0x40 }, { CCI_REG8(0x3da4), 0x40 },
+ { CCI_REG8(0x3da5), 0x40 }, { CCI_REG8(0x3da6), 0x40 },
+ { CCI_REG8(0x3da7), 0x40 }, { CCI_REG8(0x3da8), 0x40 },
+ { CCI_REG8(0x3da9), 0x40 }, { CCI_REG8(0x3daa), 0x40 },
+ { CCI_REG8(0x3dab), 0x40 }, { CCI_REG8(0x3dac), 0x40 },
+ { CCI_REG8(0x3dad), 0x40 }, { CCI_REG8(0x3dae), 0x40 },
+ { CCI_REG8(0x3daf), 0x40 }, { CCI_REG8(0x3db0), 0x40 },
+ { CCI_REG8(0x3db1), 0x40 }, { CCI_REG8(0x3db2), 0x40 },
+ { CCI_REG8(0x3db3), 0x40 }, { CCI_REG8(0x3db4), 0x40 },
+ { CCI_REG8(0x3db5), 0x40 }, { CCI_REG8(0x3db6), 0x40 },
+ { CCI_REG8(0x3db7), 0x40 }, { CCI_REG8(0x3db8), 0x40 },
+ { CCI_REG8(0x3db9), 0x40 }, { CCI_REG8(0x3dba), 0x40 },
+ { CCI_REG8(0x3dbb), 0x40 }, { CCI_REG8(0x3dbc), 0x40 },
+ { CCI_REG8(0x3dbd), 0x40 }, { CCI_REG8(0x3dbe), 0x40 },
+ { CCI_REG8(0x3dbf), 0xcd }, { CCI_REG8(0x3dc0), 0xcd },
+ { CCI_REG8(0x3dc1), 0xcd }, { CCI_REG8(0x3dc2), 0xcd },
+ { CCI_REG8(0x3dc3), 0xcd }, { CCI_REG8(0x3dc4), 0xcd },
+ { CCI_REG8(0x3dc5), 0xcd }, { CCI_REG8(0x3dc6), 0xcd },
+ { CCI_REG8(0x3dc7), 0xcd }, { CCI_REG8(0x3dc8), 0xcd },
+ { CCI_REG8(0x3dc9), 0xcd }, { CCI_REG8(0x3dca), 0xcd },
+ { CCI_REG8(0x3dcb), 0xcd }, { CCI_REG8(0x3dcc), 0xcd },
+ { CCI_REG8(0x3dcd), 0xcd }, { CCI_REG8(0x3dce), 0xcd },
+ { CCI_REG8(0x3dcf), 0xcd }, { CCI_REG8(0x3dd0), 0xcd },
+ { CCI_REG8(0x3dd1), 0xcd }, { CCI_REG8(0x3dd2), 0xcd },
+ { CCI_REG8(0x3dd3), 0xcd }, { CCI_REG8(0x3dd4), 0xcd },
+ { CCI_REG8(0x3dd5), 0xcd }, { CCI_REG8(0x3dd6), 0xcd },
+ { CCI_REG8(0x3dd7), 0xcd }, { CCI_REG8(0x3dd8), 0xcd },
+ { CCI_REG8(0x3dd9), 0xcd }, { CCI_REG8(0x3dda), 0xcd },
+ { CCI_REG8(0x3ddb), 0xcd }, { CCI_REG8(0x3ddc), 0xcd },
+ { CCI_REG8(0x3ddd), 0xcd }, { CCI_REG8(0x3dde), 0xcd },
+ { CCI_REG8(0x3ddf), 0xcd }, { CCI_REG8(0x3de0), 0xcd },
+ { CCI_REG8(0x3de1), 0xcd }, { CCI_REG8(0x3de2), 0xcd },
+ { CCI_REG8(0x3de3), 0xcd }, { CCI_REG8(0x3de4), 0xcd },
+ { CCI_REG8(0x3de5), 0xcd }, { CCI_REG8(0x3de6), 0xcd },
+ { CCI_REG8(0x3de7), 0xcd }, { CCI_REG8(0x3de8), 0xcd },
+ { CCI_REG8(0x3de9), 0xcd }, { CCI_REG8(0x3dea), 0xcd },
+ { CCI_REG8(0x3deb), 0xcd }, { CCI_REG8(0x3dec), 0xcd },
+ { CCI_REG8(0x3ded), 0xcd }, { CCI_REG8(0x3dee), 0xcd },
+ { CCI_REG8(0x3def), 0xcd }, { CCI_REG8(0x3df0), 0xcd },
+ { CCI_REG8(0x3df1), 0xcd }, { CCI_REG8(0x3df2), 0xcd },
+ { CCI_REG8(0x3df3), 0xcd }, { CCI_REG8(0x3df4), 0xcd },
+ { CCI_REG8(0x3df5), 0xcd }, { CCI_REG8(0x3df6), 0xcd },
+ { CCI_REG8(0x3df7), 0xcd }, { CCI_REG8(0x3df8), 0xcd },
+ { CCI_REG8(0x3df9), 0xcd }, { CCI_REG8(0x3dfa), 0xcd },
+ { CCI_REG8(0x3dfb), 0xcd }, { CCI_REG8(0x3dfc), 0xcd },
+ { CCI_REG8(0x3dfd), 0xcd }, { CCI_REG8(0x3dfe), 0xcd },
+ { CCI_REG8(0x3dff), 0xcd }, { CCI_REG8(0x3e00), 0xcd },
+ { CCI_REG8(0x3e01), 0xcd }, { CCI_REG8(0x3e02), 0xcd },
+ { CCI_REG8(0x3e03), 0xcd }, { CCI_REG8(0x3e04), 0xcd },
+ { CCI_REG8(0x3e05), 0xcd }, { CCI_REG8(0x3e06), 0xcd },
+ { CCI_REG8(0x3e07), 0xcd }, { CCI_REG8(0x3e08), 0xcd },
+ { CCI_REG8(0x3e09), 0xcd }, { CCI_REG8(0x3e0a), 0xcd },
+ { CCI_REG8(0x3e0b), 0xcd }, { CCI_REG8(0x3e0c), 0xcd },
+ { CCI_REG8(0x3e0d), 0xcd }, { CCI_REG8(0x3e0e), 0xcd },
+ { CCI_REG8(0x3e0f), 0xcd }, { CCI_REG8(0x3e10), 0xcd },
+ { CCI_REG8(0x3e11), 0xcd }, { CCI_REG8(0x3e12), 0xcd },
+ { CCI_REG8(0x3e13), 0xcd }, { CCI_REG8(0x3e14), 0xcd },
+ { CCI_REG8(0x3e15), 0xcd }, { CCI_REG8(0x3e16), 0xcd },
+ { CCI_REG8(0x3e17), 0xcd }, { CCI_REG8(0x3e18), 0xcd },
+ { CCI_REG8(0x3e19), 0xcd }, { CCI_REG8(0x3e1a), 0xcd },
+ { CCI_REG8(0x3e1b), 0xcd }, { CCI_REG8(0x3e1c), 0xcd },
+ { CCI_REG8(0x3e1d), 0xcd }, { CCI_REG8(0x3e1e), 0xcd },
+ { CCI_REG8(0x3e1f), 0xcd }, { CCI_REG8(0x3e20), 0xcd },
+ { CCI_REG8(0x3e21), 0xcd }, { CCI_REG8(0x3e22), 0xcd },
+ { CCI_REG8(0x3e23), 0xcd }, { CCI_REG8(0x3e24), 0xcd },
+ { CCI_REG8(0x3e25), 0xcd }, { CCI_REG8(0x3e26), 0xcd },
+ { CCI_REG8(0x3e27), 0xcd }, { CCI_REG8(0x3e28), 0xcd },
+ { CCI_REG8(0x3e29), 0xcd }, { CCI_REG8(0x3e2a), 0xcd },
+ { CCI_REG8(0x3e2b), 0xcd }, { CCI_REG8(0x3e2c), 0xcd },
+ { CCI_REG8(0x3e2d), 0xcd }, { CCI_REG8(0x3e2e), 0xcd },
+ { CCI_REG8(0x3e2f), 0xcd }, { CCI_REG8(0x3e30), 0xcd },
+ { CCI_REG8(0x3e31), 0xcd }, { CCI_REG8(0x3e32), 0xcd },
+ { CCI_REG8(0x3e33), 0xcd }, { CCI_REG8(0x3e34), 0xcd },
+ { CCI_REG8(0x3e35), 0xcd }, { CCI_REG8(0x3e36), 0xcd },
+ { CCI_REG8(0x3e37), 0xcd }, { CCI_REG8(0x3e38), 0xcd },
+ { CCI_REG8(0x3e39), 0xcd }, { CCI_REG8(0x3e3a), 0xcd },
+ { CCI_REG8(0x3e3b), 0xcd }, { CCI_REG8(0x3e3c), 0xcd },
+ { CCI_REG8(0x3e3d), 0xcd }, { CCI_REG8(0x3e3e), 0xcd },
+ { CCI_REG8(0x3e3f), 0xcd }, { CCI_REG8(0x3e40), 0xcd },
+ { CCI_REG8(0x3e41), 0xcd }, { CCI_REG8(0x3e42), 0xcd },
+ { CCI_REG8(0x3e43), 0xcd }, { CCI_REG8(0x3e44), 0xcd },
+ { CCI_REG8(0x3e45), 0xcd }, { CCI_REG8(0x3e46), 0xcd },
+ { CCI_REG8(0x3e47), 0xcd }, { CCI_REG8(0x3e48), 0xcd },
+ { CCI_REG8(0x3e49), 0xcd }, { CCI_REG8(0x3e4a), 0xcd },
+ { CCI_REG8(0x3e4b), 0xcd }, { CCI_REG8(0x3e4c), 0xcd },
+ { CCI_REG8(0x3e4d), 0xcd }, { CCI_REG8(0x3e4e), 0xcd },
+ { CCI_REG8(0x3e4f), 0xcd }, { CCI_REG8(0x3e50), 0xcd },
+ { CCI_REG8(0x3e51), 0xcd }, { CCI_REG8(0x3e52), 0xcd },
+ { CCI_REG8(0x3e53), 0xcd }, { CCI_REG8(0x3e54), 0xcd },
+ { CCI_REG8(0x3e55), 0xcd }, { CCI_REG8(0x3e56), 0xcd },
+ { CCI_REG8(0x3e57), 0xcd }, { CCI_REG8(0x3e58), 0xcd },
+ { CCI_REG8(0x3e59), 0xcd }, { CCI_REG8(0x3e5a), 0xcd },
+ { CCI_REG8(0x3e5b), 0xcd }, { CCI_REG8(0x3e5c), 0xcd },
+ { CCI_REG8(0x3e5d), 0xcd }, { CCI_REG8(0x3e5e), 0xcd },
+ { CCI_REG8(0x3e5f), 0xcd }, { CCI_REG8(0x3e60), 0xcd },
+ { CCI_REG8(0x3e61), 0xcd }, { CCI_REG8(0x3e62), 0xcd },
+ { CCI_REG8(0x3e63), 0xcd }, { CCI_REG8(0x3e64), 0xcd },
+ { CCI_REG8(0x3e65), 0xcd }, { CCI_REG8(0x3e66), 0xcd },
+ { CCI_REG8(0x3e67), 0xcd }, { CCI_REG8(0x3e68), 0xcd },
+ { CCI_REG8(0x3e69), 0xcd }, { CCI_REG8(0x3e6a), 0xcd },
+ { CCI_REG8(0x3e6b), 0xcd }, { CCI_REG8(0x3e6c), 0xcd },
+ { CCI_REG8(0x3e6d), 0xcd }, { CCI_REG8(0x3e6e), 0xcd },
+ { CCI_REG8(0x3e6f), 0xcd }, { CCI_REG8(0x3e70), 0xcd },
+ { CCI_REG8(0x3e71), 0xcd }, { CCI_REG8(0x3e72), 0xcd },
+ { CCI_REG8(0x3e73), 0xcd }, { CCI_REG8(0x3e74), 0xcd },
+ { CCI_REG8(0x3e75), 0xcd }, { CCI_REG8(0x3e76), 0xcd },
+ { CCI_REG8(0x3e77), 0xcd }, { CCI_REG8(0x3e78), 0xcd },
+ { CCI_REG8(0x3e79), 0xcd }, { CCI_REG8(0x3e7a), 0xcd },
+ { CCI_REG8(0x3e7b), 0xcd }, { CCI_REG8(0x3e7c), 0xcd },
+ { CCI_REG8(0x3e7d), 0xcd }, { CCI_REG8(0x3e7e), 0xcd },
+ { CCI_REG8(0x3e7f), 0xcd }, { CCI_REG8(0x3e80), 0xcd },
+ { CCI_REG8(0x3e81), 0xcd }, { CCI_REG8(0x3e82), 0xcd },
+ { CCI_REG8(0x3e83), 0xcd }, { CCI_REG8(0x3e84), 0xcd },
+ { CCI_REG8(0x3e85), 0xcd }, { CCI_REG8(0x3e86), 0xcd },
+ { CCI_REG8(0x3e87), 0xcd }, { CCI_REG8(0x3e88), 0xcd },
+ { CCI_REG8(0x3e89), 0xcd }, { CCI_REG8(0x3e8a), 0xcd },
+ { CCI_REG8(0x3e8b), 0xcd }, { CCI_REG8(0x3e8c), 0xcd },
+ { CCI_REG8(0x3e8d), 0xcd }, { CCI_REG8(0x3e8e), 0xcd },
+ { CCI_REG8(0x3e8f), 0xcd }, { CCI_REG8(0x3e90), 0xcd },
+ { CCI_REG8(0x3e91), 0xcd }, { CCI_REG8(0x3e92), 0xcd },
+ { CCI_REG8(0x3e93), 0xcd }, { CCI_REG8(0x3e94), 0xcd },
+ { CCI_REG8(0x3e95), 0xcd }, { CCI_REG8(0x3e96), 0xcd },
+ { CCI_REG8(0x3e97), 0xcd }, { CCI_REG8(0x3e98), 0xcd },
+ { CCI_REG8(0x3e99), 0xcd }, { CCI_REG8(0x3e9a), 0xcd },
+ { CCI_REG8(0x3e9b), 0xcd }, { CCI_REG8(0x3e9c), 0xcd },
+ { CCI_REG8(0x3e9d), 0xcd }, { CCI_REG8(0x3e9e), 0xcd },
+ { CCI_REG8(0x3e9f), 0xcd }, { CCI_REG8(0xfff9), 0x06 },
+ { CCI_REG8(0xc03f), 0x01 }, { CCI_REG8(0xc03e), 0x08 },
+ { CCI_REG8(0xc02c), 0xff }, { CCI_REG8(0xc005), 0x06 },
+ { CCI_REG8(0xc006), 0x30 }, { CCI_REG8(0xc007), 0xc0 },
+ { CCI_REG8(0xc027), 0x01 }, { CCI_REG8(0x30c0), 0x05 },
+ { CCI_REG8(0x30c1), 0x9f }, { CCI_REG8(0x30c2), 0x06 },
+ { CCI_REG8(0x30c3), 0x5f }, { CCI_REG8(0x30c4), 0x80 },
+ { CCI_REG8(0x30c5), 0x08 }, { CCI_REG8(0x30c6), 0x39 },
+ { CCI_REG8(0x30c7), 0x00 }, { CCI_REG8(0xc046), 0x20 },
+ { CCI_REG8(0xc043), 0x01 }, { CCI_REG8(0xc04b), 0x01 },
+ { CCI_REG8(0x0102), 0x01 }, { CCI_REG8(0x0100), 0x00 },
+ { CCI_REG8(0x0102), 0x00 }, { CCI_REG8(0x3015), 0xf0 },
+ { CCI_REG8(0x3018), 0xf0 }, { CCI_REG8(0x301c), 0xf0 },
+ { CCI_REG8(0x301d), 0xf6 }, { CCI_REG8(0x301e), 0xf1 }
+};
+
+static const struct cci_reg_sequence ov64a40_9248x6944[] = {
+ { CCI_REG8(0x0305), 0x98 }, { CCI_REG8(0x0306), 0x04 },
+ { CCI_REG8(0x0307), 0x01 }, { CCI_REG8(0x4837), 0x1a },
+ { CCI_REG8(0x4888), 0x10 }, { CCI_REG8(0x4860), 0x00 },
+ { CCI_REG8(0x4850), 0x43 }, { CCI_REG8(0x480C), 0x92 },
+ { CCI_REG8(0x5001), 0x21 }
+};
+
+static const struct cci_reg_sequence ov64a40_8000x6000[] = {
+ { CCI_REG8(0x0305), 0x98 }, { CCI_REG8(0x0306), 0x04 },
+ { CCI_REG8(0x0307), 0x01 }, { CCI_REG8(0x4837), 0x1a },
+ { CCI_REG8(0x4888), 0x10 }, { CCI_REG8(0x4860), 0x00 },
+ { CCI_REG8(0x4850), 0x43 }, { CCI_REG8(0x480C), 0x92 },
+ { CCI_REG8(0x5001), 0x21 }
+};
+
+static const struct cci_reg_sequence ov64a40_4624_3472[] = {
+ { CCI_REG8(0x034b), 0x02 }, { CCI_REG8(0x3504), 0x08 },
+ { CCI_REG8(0x360d), 0x82 }, { CCI_REG8(0x368a), 0x2e },
+ { CCI_REG8(0x3712), 0x50 }, { CCI_REG8(0x3822), 0x00 },
+ { CCI_REG8(0x3827), 0x40 }, { CCI_REG8(0x383d), 0x08 },
+ { CCI_REG8(0x383f), 0x00 }, { CCI_REG8(0x384c), 0x02 },
+ { CCI_REG8(0x384d), 0xba }, { CCI_REG8(0x3852), 0x00 },
+ { CCI_REG8(0x3856), 0x08 }, { CCI_REG8(0x3857), 0x08 },
+ { CCI_REG8(0x3858), 0x10 }, { CCI_REG8(0x3859), 0x10 },
+ { CCI_REG8(0x4016), 0x0f }, { CCI_REG8(0x4018), 0x03 },
+ { CCI_REG8(0x4504), 0x1e }, { CCI_REG8(0x4523), 0x41 },
+ { CCI_REG8(0x45c0), 0x01 }, { CCI_REG8(0x4641), 0x12 },
+ { CCI_REG8(0x4643), 0x0c }, { CCI_REG8(0x4915), 0x02 },
+ { CCI_REG8(0x4916), 0x1d }, { CCI_REG8(0x4a15), 0x02 },
+ { CCI_REG8(0x4a16), 0x1d }, { CCI_REG8(0x3703), 0x72 },
+ { CCI_REG8(0x3709), 0xe6 }, { CCI_REG8(0x3a60), 0x68 },
+ { CCI_REG8(0x3a6f), 0x68 }, { CCI_REG8(0x3a5e), 0xdc },
+ { CCI_REG8(0x3a6d), 0xdc }, { CCI_REG8(0x3721), 0xc9 },
+ { CCI_REG8(0x5250), 0x06 }, { CCI_REG8(0x527a), 0x00 },
+ { CCI_REG8(0x527b), 0x65 }, { CCI_REG8(0x527c), 0x00 },
+ { CCI_REG8(0x527d), 0x82 }, { CCI_REG8(0x5280), 0x24 },
+ { CCI_REG8(0x5281), 0x40 }, { CCI_REG8(0x5282), 0x1b },
+ { CCI_REG8(0x5283), 0x40 }, { CCI_REG8(0x5284), 0x24 },
+ { CCI_REG8(0x5285), 0x40 }, { CCI_REG8(0x5286), 0x1b },
+ { CCI_REG8(0x5287), 0x40 }, { CCI_REG8(0x5200), 0x24 },
+ { CCI_REG8(0x5201), 0x40 }, { CCI_REG8(0x5202), 0x1b },
+ { CCI_REG8(0x5203), 0x40 }, { CCI_REG8(0x481b), 0x35 },
+ { CCI_REG8(0x4862), 0x25 }, { CCI_REG8(0x3400), 0x00 },
+ { CCI_REG8(0x3421), 0x23 }, { CCI_REG8(0x3422), 0xfc },
+ { CCI_REG8(0x3423), 0x07 }, { CCI_REG8(0x3424), 0x01 },
+ { CCI_REG8(0x3425), 0x04 }, { CCI_REG8(0x3426), 0x50 },
+ { CCI_REG8(0x3427), 0x55 }, { CCI_REG8(0x3428), 0x15 },
+ { CCI_REG8(0x3429), 0x00 }, { CCI_REG8(0x3025), 0x03 },
+ { CCI_REG8(0x5250), 0x06 }, { CCI_REG8(0x0305), 0x98 },
+ { CCI_REG8(0x0306), 0x04 }, { CCI_REG8(0x0307), 0x01 },
+ { CCI_REG8(0x4837), 0x1a }, { CCI_REG8(0x4888), 0x10 },
+ { CCI_REG8(0x4860), 0x00 }, { CCI_REG8(0x4850), 0x43 },
+ { CCI_REG8(0x480C), 0x92 }, { CCI_REG8(0x5001), 0x21 }
+};
+
+static const struct cci_reg_sequence ov64a40_3840x2160[] = {
+ { CCI_REG8(0x034a), 0x05 }, { CCI_REG8(0x034b), 0x05 },
+ { CCI_REG8(0x3504), 0x08 }, { CCI_REG8(0x360d), 0x82 },
+ { CCI_REG8(0x368a), 0x2e }, { CCI_REG8(0x3712), 0x50 },
+ { CCI_REG8(0x3822), 0x00 }, { CCI_REG8(0x3827), 0x40 },
+ { CCI_REG8(0x383d), 0x08 }, { CCI_REG8(0x383f), 0x00 },
+ { CCI_REG8(0x384c), 0x02 }, { CCI_REG8(0x384d), 0xba },
+ { CCI_REG8(0x3852), 0x00 }, { CCI_REG8(0x3856), 0x08 },
+ { CCI_REG8(0x3857), 0x08 }, { CCI_REG8(0x3858), 0x10 },
+ { CCI_REG8(0x3859), 0x10 }, { CCI_REG8(0x4016), 0x0f },
+ { CCI_REG8(0x4018), 0x03 }, { CCI_REG8(0x4504), 0x1e },
+ { CCI_REG8(0x4523), 0x41 }, { CCI_REG8(0x45c0), 0x01 },
+ { CCI_REG8(0x4641), 0x12 }, { CCI_REG8(0x4643), 0x0c },
+ { CCI_REG8(0x4915), 0x02 }, { CCI_REG8(0x4916), 0x1d },
+ { CCI_REG8(0x4a15), 0x02 }, { CCI_REG8(0x4a16), 0x1d },
+ { CCI_REG8(0x3703), 0x72 }, { CCI_REG8(0x3709), 0xe6 },
+ { CCI_REG8(0x3a60), 0x68 }, { CCI_REG8(0x3a6f), 0x68 },
+ { CCI_REG8(0x3a5e), 0xdc }, { CCI_REG8(0x3a6d), 0xdc },
+ { CCI_REG8(0x3721), 0xc9 }, { CCI_REG8(0x5250), 0x06 },
+ { CCI_REG8(0x527a), 0x00 }, { CCI_REG8(0x527b), 0x65 },
+ { CCI_REG8(0x527c), 0x00 }, { CCI_REG8(0x527d), 0x82 },
+ { CCI_REG8(0x5280), 0x24 }, { CCI_REG8(0x5281), 0x40 },
+ { CCI_REG8(0x5282), 0x1b }, { CCI_REG8(0x5283), 0x40 },
+ { CCI_REG8(0x5284), 0x24 }, { CCI_REG8(0x5285), 0x40 },
+ { CCI_REG8(0x5286), 0x1b }, { CCI_REG8(0x5287), 0x40 },
+ { CCI_REG8(0x5200), 0x24 }, { CCI_REG8(0x5201), 0x40 },
+ { CCI_REG8(0x5202), 0x1b }, { CCI_REG8(0x5203), 0x40 },
+ { CCI_REG8(0x481b), 0x35 }, { CCI_REG8(0x4862), 0x25 },
+ { CCI_REG8(0x3400), 0x00 }, { CCI_REG8(0x3421), 0x23 },
+ { CCI_REG8(0x3422), 0xfc }, { CCI_REG8(0x3423), 0x07 },
+ { CCI_REG8(0x3424), 0x01 }, { CCI_REG8(0x3425), 0x04 },
+ { CCI_REG8(0x3426), 0x50 }, { CCI_REG8(0x3427), 0x55 },
+ { CCI_REG8(0x3428), 0x15 }, { CCI_REG8(0x3429), 0x00 },
+ { CCI_REG8(0x3025), 0x03 }, { CCI_REG8(0x5250), 0x06 },
+ { CCI_REG8(0x0305), 0x98 }, { CCI_REG8(0x0306), 0x04 },
+ { CCI_REG8(0x0345), 0x90 }, { CCI_REG8(0x0307), 0x01 },
+ { CCI_REG8(0x4837), 0x1a }, { CCI_REG8(0x4888), 0x10 },
+ { CCI_REG8(0x4860), 0x00 }, { CCI_REG8(0x4850), 0x43 },
+ { CCI_REG8(0x480C), 0x92 }, { CCI_REG8(0x5001), 0x21 },
+ { CCI_REG8(0x5000), 0x01 }
+};
+
+static const struct cci_reg_sequence ov64a40_2312_1736[] = {
+ { CCI_REG8(0x034b), 0x02 }, { CCI_REG8(0x3504), 0x08 },
+ { CCI_REG8(0x360d), 0x82 }, { CCI_REG8(0x368a), 0x2e },
+ { CCI_REG8(0x3712), 0x00 }, { CCI_REG8(0x3822), 0x08 },
+ { CCI_REG8(0x3827), 0x40 }, { CCI_REG8(0x383d), 0x04 },
+ { CCI_REG8(0x383f), 0x00 }, { CCI_REG8(0x384c), 0x01 },
+ { CCI_REG8(0x384d), 0x12 }, { CCI_REG8(0x3852), 0x00 },
+ { CCI_REG8(0x3856), 0x04 }, { CCI_REG8(0x3857), 0x04 },
+ { CCI_REG8(0x3858), 0x08 }, { CCI_REG8(0x3859), 0x08 },
+ { CCI_REG8(0x4016), 0x07 }, { CCI_REG8(0x4018), 0x01 },
+ { CCI_REG8(0x4504), 0x00 }, { CCI_REG8(0x4523), 0x00 },
+ { CCI_REG8(0x45c0), 0x01 }, { CCI_REG8(0x4641), 0x24 },
+ { CCI_REG8(0x4643), 0x0c }, { CCI_REG8(0x4837), 0x0b },
+ { CCI_REG8(0x4915), 0x02 }, { CCI_REG8(0x4916), 0x1d },
+ { CCI_REG8(0x4a15), 0x02 }, { CCI_REG8(0x4a16), 0x1d },
+ { CCI_REG8(0x5000), 0x55 }, { CCI_REG8(0x5001), 0x00 },
+ { CCI_REG8(0x5002), 0x35 }, { CCI_REG8(0x5004), 0xc0 },
+ { CCI_REG8(0x5068), 0x02 }, { CCI_REG8(0x3703), 0x6a },
+ { CCI_REG8(0x3709), 0xa3 }, { CCI_REG8(0x3a60), 0x60 },
+ { CCI_REG8(0x3a6f), 0x60 }, { CCI_REG8(0x3a5e), 0x99 },
+ { CCI_REG8(0x3a6d), 0x99 }, { CCI_REG8(0x3721), 0xc1 },
+ { CCI_REG8(0x5250), 0x06 }, { CCI_REG8(0x527a), 0x00 },
+ { CCI_REG8(0x527b), 0x65 }, { CCI_REG8(0x527c), 0x00 },
+ { CCI_REG8(0x527d), 0x82 }, { CCI_REG8(0x5280), 0x24 },
+ { CCI_REG8(0x5281), 0x40 }, { CCI_REG8(0x5282), 0x1b },
+ { CCI_REG8(0x5283), 0x40 }, { CCI_REG8(0x5284), 0x24 },
+ { CCI_REG8(0x5285), 0x40 }, { CCI_REG8(0x5286), 0x1b },
+ { CCI_REG8(0x5287), 0x40 }, { CCI_REG8(0x5200), 0x24 },
+ { CCI_REG8(0x5201), 0x40 }, { CCI_REG8(0x5202), 0x1b },
+ { CCI_REG8(0x5203), 0x40 }, { CCI_REG8(0x3684), 0x05 },
+ { CCI_REG8(0x481b), 0x20 }, { CCI_REG8(0x51b0), 0x38 },
+ { CCI_REG8(0x51b3), 0x0e }, { CCI_REG8(0x51b5), 0x04 },
+ { CCI_REG8(0x51b6), 0x00 }, { CCI_REG8(0x51b7), 0x00 },
+ { CCI_REG8(0x51b9), 0x70 }, { CCI_REG8(0x51bb), 0x10 },
+ { CCI_REG8(0x51bc), 0x00 }, { CCI_REG8(0x51bd), 0x00 },
+ { CCI_REG8(0x51b0), 0x38 }, { CCI_REG8(0x54b0), 0x38 },
+ { CCI_REG8(0x54b3), 0x0e }, { CCI_REG8(0x54b5), 0x04 },
+ { CCI_REG8(0x54b6), 0x00 }, { CCI_REG8(0x54b7), 0x00 },
+ { CCI_REG8(0x54b9), 0x70 }, { CCI_REG8(0x54bb), 0x10 },
+ { CCI_REG8(0x54bc), 0x00 }, { CCI_REG8(0x54bd), 0x00 },
+ { CCI_REG8(0x57b0), 0x38 }, { CCI_REG8(0x57b3), 0x0e },
+ { CCI_REG8(0x57b5), 0x04 }, { CCI_REG8(0x57b6), 0x00 },
+ { CCI_REG8(0x57b7), 0x00 }, { CCI_REG8(0x57b9), 0x70 },
+ { CCI_REG8(0x57bb), 0x10 }, { CCI_REG8(0x57bc), 0x00 },
+ { CCI_REG8(0x57bd), 0x00 }, { CCI_REG8(0x0305), 0x98 },
+ { CCI_REG8(0x0306), 0x04 }, { CCI_REG8(0x0307), 0x01 },
+ { CCI_REG8(0x4837), 0x1a }, { CCI_REG8(0x4888), 0x10 },
+ { CCI_REG8(0x4860), 0x00 }, { CCI_REG8(0x4850), 0x43 },
+ { CCI_REG8(0x480C), 0x92 }
+};
+
+static const struct cci_reg_sequence ov64a40_1920x1080[] = {
+ { CCI_REG8(0x034b), 0x02 }, { CCI_REG8(0x3504), 0x08 },
+ { CCI_REG8(0x360d), 0x82 }, { CCI_REG8(0x368a), 0x2e },
+ { CCI_REG8(0x3712), 0x00 }, { CCI_REG8(0x3822), 0x08 },
+ { CCI_REG8(0x3827), 0x40 }, { CCI_REG8(0x383d), 0x04 },
+ { CCI_REG8(0x383f), 0x00 }, { CCI_REG8(0x384c), 0x01 },
+ { CCI_REG8(0x384d), 0x12 }, { CCI_REG8(0x3852), 0x00 },
+ { CCI_REG8(0x3856), 0x04 }, { CCI_REG8(0x3857), 0x04 },
+ { CCI_REG8(0x3858), 0x08 }, { CCI_REG8(0x3859), 0x08 },
+ { CCI_REG8(0x4016), 0x07 }, { CCI_REG8(0x4018), 0x01 },
+ { CCI_REG8(0x4504), 0x00 }, { CCI_REG8(0x4523), 0x00 },
+ { CCI_REG8(0x45c0), 0x01 }, { CCI_REG8(0x4641), 0x24 },
+ { CCI_REG8(0x4643), 0x0c }, { CCI_REG8(0x4837), 0x0b },
+ { CCI_REG8(0x4915), 0x02 }, { CCI_REG8(0x4916), 0x1d },
+ { CCI_REG8(0x4a15), 0x02 }, { CCI_REG8(0x4a16), 0x1d },
+ { CCI_REG8(0x5000), 0x55 }, { CCI_REG8(0x5001), 0x00 },
+ { CCI_REG8(0x5002), 0x35 }, { CCI_REG8(0x5004), 0xc0 },
+ { CCI_REG8(0x5068), 0x02 }, { CCI_REG8(0x3703), 0x6a },
+ { CCI_REG8(0x3709), 0xa3 }, { CCI_REG8(0x3a60), 0x60 },
+ { CCI_REG8(0x3a6f), 0x60 }, { CCI_REG8(0x3a5e), 0x99 },
+ { CCI_REG8(0x3a6d), 0x99 }, { CCI_REG8(0x3721), 0xc1 },
+ { CCI_REG8(0x5250), 0x06 }, { CCI_REG8(0x527a), 0x00 },
+ { CCI_REG8(0x527b), 0x65 }, { CCI_REG8(0x527c), 0x00 },
+ { CCI_REG8(0x527d), 0x82 }, { CCI_REG8(0x5280), 0x24 },
+ { CCI_REG8(0x5281), 0x40 }, { CCI_REG8(0x5282), 0x1b },
+ { CCI_REG8(0x5283), 0x40 }, { CCI_REG8(0x5284), 0x24 },
+ { CCI_REG8(0x5285), 0x40 }, { CCI_REG8(0x5286), 0x1b },
+ { CCI_REG8(0x5287), 0x40 }, { CCI_REG8(0x5200), 0x24 },
+ { CCI_REG8(0x5201), 0x40 }, { CCI_REG8(0x5202), 0x1b },
+ { CCI_REG8(0x5203), 0x40 }, { CCI_REG8(0x3684), 0x05 },
+ { CCI_REG8(0x481b), 0x20 }, { CCI_REG8(0x51b0), 0x38 },
+ { CCI_REG8(0x51b3), 0x0e }, { CCI_REG8(0x51b5), 0x04 },
+ { CCI_REG8(0x51b6), 0x00 }, { CCI_REG8(0x51b7), 0x00 },
+ { CCI_REG8(0x51b9), 0x70 }, { CCI_REG8(0x51bb), 0x10 },
+ { CCI_REG8(0x51bc), 0x00 }, { CCI_REG8(0x51bd), 0x00 },
+ { CCI_REG8(0x51b0), 0x38 }, { CCI_REG8(0x54b0), 0x38 },
+ { CCI_REG8(0x54b3), 0x0e }, { CCI_REG8(0x54b5), 0x04 },
+ { CCI_REG8(0x54b6), 0x00 }, { CCI_REG8(0x54b7), 0x00 },
+ { CCI_REG8(0x54b9), 0x70 }, { CCI_REG8(0x54bb), 0x10 },
+ { CCI_REG8(0x54bc), 0x00 }, { CCI_REG8(0x54bd), 0x00 },
+ { CCI_REG8(0x57b0), 0x38 }, { CCI_REG8(0x57b3), 0x0e },
+ { CCI_REG8(0x57b5), 0x04 }, { CCI_REG8(0x57b6), 0x00 },
+ { CCI_REG8(0x57b7), 0x00 }, { CCI_REG8(0x57b9), 0x70 },
+ { CCI_REG8(0x57bb), 0x10 }, { CCI_REG8(0x57bc), 0x00 },
+ { CCI_REG8(0x57bd), 0x00 }, { CCI_REG8(0x0305), 0x98 },
+ { CCI_REG8(0x0306), 0x04 }, { CCI_REG8(0x0307), 0x01 },
+ { CCI_REG8(0x4837), 0x1a }, { CCI_REG8(0x4888), 0x10 },
+ { CCI_REG8(0x4860), 0x00 }, { CCI_REG8(0x4850), 0x43 },
+ { CCI_REG8(0x480C), 0x92 }
+};
+
+/* 456MHz MIPI link frequency with 24MHz input clock. */
+static const struct cci_reg_sequence ov64a40_pll_config[] = {
+ { OV64A40_PLL1_PRE_DIV0, 0x88 },
+ { OV64A40_PLL1_PRE_DIV, 0x02 },
+ { OV64A40_PLL1_MULTIPLIER, 0x0098 },
+ { OV64A40_PLL1_M_DIV, 0x01 },
+ { OV64A40_PLL2_SEL_BAK_SA1, 0x00 },
+ { OV64A40_PLL2_PRE_DIV, 0x12 },
+ { OV64A40_PLL2_MULTIPLIER, 0x0190 },
+ { OV64A40_PLL2_PRE_DIV0, 0xd7 },
+ { OV64A40_PLL2_DIVSP, 0x00 },
+ { OV64A40_PLL2_DIVDAC, 0x00 },
+ { OV64A40_PLL2_DACPREDIV, 0x00 }
+};
+
+struct ov64a40_reglist {
+ unsigned int num_regs;
+ const struct cci_reg_sequence *regvals;
+};
+
+struct ov64a40_subsampling {
+ unsigned int x_odd_inc;
+ unsigned int x_even_inc;
+ unsigned int y_odd_inc;
+ unsigned int y_even_inc;
+ bool vbin;
+ bool hbin;
+};
+
+static struct ov64a40_mode {
+ unsigned int width;
+ unsigned int height;
+ struct ov64a40_timings {
+ unsigned int vts;
+ unsigned int ppl;
+ } timings_default[OV64A40_NUM_LINK_FREQ];
+ const struct ov64a40_reglist reglist;
+ struct v4l2_rect analogue_crop;
+ struct v4l2_rect digital_crop;
+ struct ov64a40_subsampling subsampling;
+} ov64a40_modes[] = {
+ /* Full resolution */
+ {
+ .width = 9248,
+ .height = 6944,
+ .timings_default = {
+ /* 2.6 FPS */
+ [OV64A40_LINK_FREQ_456M_ID] = {
+ .vts = 7072,
+ .ppl = 4072,
+ },
+ /* 2 FPS */
+ [OV64A40_LINK_FREQ_360M_ID] = {
+ .vts = 7072,
+ .ppl = 5248,
+ },
+ },
+ .reglist = {
+ .num_regs = ARRAY_SIZE(ov64a40_9248x6944),
+ .regvals = ov64a40_9248x6944,
+ },
+ .analogue_crop = {
+ .left = 0,
+ .top = 0,
+ .width = 9280,
+ .height = 6976,
+ },
+ .digital_crop = {
+ .left = 17,
+ .top = 16,
+ .width = 9248,
+ .height = 6944,
+ },
+ .subsampling = {
+ .x_odd_inc = 1,
+ .x_even_inc = 1,
+ .y_odd_inc = 1,
+ .y_even_inc = 1,
+ .vbin = false,
+ .hbin = false,
+ },
+ },
+ /* Analogue crop + digital crop */
+ {
+ .width = 8000,
+ .height = 6000,
+ .timings_default = {
+ /* 3.0 FPS */
+ [OV64A40_LINK_FREQ_456M_ID] = {
+ .vts = 6400,
+ .ppl = 3848,
+ },
+ /* 2.5 FPS */
+ [OV64A40_LINK_FREQ_360M_ID] = {
+ .vts = 6304,
+ .ppl = 4736,
+ },
+ },
+ .reglist = {
+ .num_regs = ARRAY_SIZE(ov64a40_8000x6000),
+ .regvals = ov64a40_8000x6000,
+ },
+ .analogue_crop = {
+ .left = 624,
+ .top = 472,
+ .width = 8048,
+ .height = 6032,
+ },
+ .digital_crop = {
+ .left = 17,
+ .top = 16,
+ .width = 8000,
+ .height = 6000,
+ },
+ .subsampling = {
+ .x_odd_inc = 1,
+ .x_even_inc = 1,
+ .y_odd_inc = 1,
+ .y_even_inc = 1,
+ .vbin = false,
+ .hbin = false,
+ },
+ },
+ /* 2x2 downscaled */
+ {
+ .width = 4624,
+ .height = 3472,
+ .timings_default = {
+ /* 10 FPS */
+ [OV64A40_LINK_FREQ_456M_ID] = {
+ .vts = 3533,
+ .ppl = 2112,
+ },
+ /* 7 FPS */
+ [OV64A40_LINK_FREQ_360M_ID] = {
+ .vts = 3939,
+ .ppl = 2720,
+ },
+ },
+ .reglist = {
+ .num_regs = ARRAY_SIZE(ov64a40_4624_3472),
+ .regvals = ov64a40_4624_3472,
+ },
+ .analogue_crop = {
+ .left = 0,
+ .top = 0,
+ .width = 9280,
+ .height = 6976,
+ },
+ .digital_crop = {
+ .left = 9,
+ .top = 8,
+ .width = 4624,
+ .height = 3472,
+ },
+ .subsampling = {
+ .x_odd_inc = 3,
+ .x_even_inc = 1,
+ .y_odd_inc = 1,
+ .y_even_inc = 1,
+ .vbin = true,
+ .hbin = false,
+ },
+ },
+ /* Analogue crop + 2x2 downscale + digital crop */
+ {
+ .width = 3840,
+ .height = 2160,
+ .timings_default = {
+ /* 20 FPS */
+ [OV64A40_LINK_FREQ_456M_ID] = {
+ .vts = 2218,
+ .ppl = 1690,
+ },
+ /* 15 FPS */
+ [OV64A40_LINK_FREQ_360M_ID] = {
+ .vts = 2270,
+ .ppl = 2202,
+ },
+ },
+ .reglist = {
+ .num_regs = ARRAY_SIZE(ov64a40_3840x2160),
+ .regvals = ov64a40_3840x2160,
+ },
+ .analogue_crop = {
+ .left = 784,
+ .top = 1312,
+ .width = 7712,
+ .height = 4352,
+ },
+ .digital_crop = {
+ .left = 9,
+ .top = 8,
+ .width = 3840,
+ .height = 2160,
+ },
+ .subsampling = {
+ .x_odd_inc = 3,
+ .x_even_inc = 1,
+ .y_odd_inc = 1,
+ .y_even_inc = 1,
+ .vbin = true,
+ .hbin = false,
+ },
+ },
+ /* 4x4 downscaled */
+ {
+ .width = 2312,
+ .height = 1736,
+ .timings_default = {
+ /* 30 FPS */
+ [OV64A40_LINK_FREQ_456M_ID] = {
+ .vts = 1998,
+ .ppl = 1248,
+ },
+ /* 25 FPS */
+ [OV64A40_LINK_FREQ_360M_ID] = {
+ .vts = 1994,
+ .ppl = 1504,
+ },
+ },
+ .reglist = {
+ .num_regs = ARRAY_SIZE(ov64a40_2312_1736),
+ .regvals = ov64a40_2312_1736,
+ },
+ .analogue_crop = {
+ .left = 0,
+ .top = 0,
+ .width = 9280,
+ .height = 6976,
+ },
+ .digital_crop = {
+ .left = 5,
+ .top = 4,
+ .width = 2312,
+ .height = 1736,
+ },
+ .subsampling = {
+ .x_odd_inc = 3,
+ .x_even_inc = 1,
+ .y_odd_inc = 3,
+ .y_even_inc = 1,
+ .vbin = true,
+ .hbin = true,
+ },
+ },
+ /* Analogue crop + 4x4 downscale + digital crop */
+ {
+ .width = 1920,
+ .height = 1080,
+ .timings_default = {
+ /* 60 FPS */
+ [OV64A40_LINK_FREQ_456M_ID] = {
+ .vts = 1397,
+ .ppl = 880,
+ },
+ /* 45 FPS */
+ [OV64A40_LINK_FREQ_360M_ID] = {
+ .vts = 1216,
+ .ppl = 1360,
+ },
+ },
+ .reglist = {
+ .num_regs = ARRAY_SIZE(ov64a40_1920x1080),
+ .regvals = ov64a40_1920x1080,
+ },
+ .analogue_crop = {
+ .left = 784,
+ .top = 1312,
+ .width = 7712,
+ .height = 4352,
+ },
+ .digital_crop = {
+ .left = 7,
+ .top = 6,
+ .width = 1920,
+ .height = 1080,
+ },
+ .subsampling = {
+ .x_odd_inc = 3,
+ .x_even_inc = 1,
+ .y_odd_inc = 3,
+ .y_even_inc = 1,
+ .vbin = true,
+ .hbin = true,
+ },
+ },
+};
+
+struct ov64a40 {
+ struct device *dev;
+
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+
+ struct regmap *cci;
+
+ struct ov64a40_mode *mode;
+
+ struct clk *xclk;
+
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(ov64a40_supply_names)];
+
+ s64 *link_frequencies;
+ unsigned int num_link_frequencies;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hflip;
+};
+
+static inline struct ov64a40 *sd_to_ov64a40(struct v4l2_subdev *sd)
+{
+ return container_of_const(sd, struct ov64a40, sd);
+}
+
+static const struct ov64a40_timings *
+ov64a40_get_timings(struct ov64a40 *ov64a40, unsigned int link_freq_index)
+{
+ s64 link_freq = ov64a40->link_frequencies[link_freq_index];
+ unsigned int timings_index = link_freq == OV64A40_LINK_FREQ_360M
+ ? OV64A40_LINK_FREQ_360M_ID
+ : OV64A40_LINK_FREQ_456M_ID;
+
+ return &ov64a40->mode->timings_default[timings_index];
+}
+
+static int ov64a40_program_geometry(struct ov64a40 *ov64a40)
+{
+ struct ov64a40_mode *mode = ov64a40->mode;
+ struct v4l2_rect *anacrop = &mode->analogue_crop;
+ struct v4l2_rect *digicrop = &mode->digital_crop;
+ const struct ov64a40_timings *timings;
+ int ret = 0;
+
+ /* Analogue crop. */
+ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL0,
+ anacrop->left, &ret);
+ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL2,
+ anacrop->top, &ret);
+ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL4,
+ anacrop->width + anacrop->left - 1, &ret);
+ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL6,
+ anacrop->height + anacrop->top - 1, &ret);
+
+ /* ISP windowing. */
+ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL10,
+ digicrop->left, &ret);
+ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL12,
+ digicrop->top, &ret);
+ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL8,
+ digicrop->width, &ret);
+ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRLA,
+ digicrop->height, &ret);
+
+ /* Total timings. */
+ timings = ov64a40_get_timings(ov64a40, ov64a40->link_freq->cur.val);
+ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRLC, timings->ppl, &ret);
+ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRLE, timings->vts, &ret);
+
+ return ret;
+}
+
+static int ov64a40_program_subsampling(struct ov64a40 *ov64a40)
+{
+ struct ov64a40_subsampling *subsampling = &ov64a40->mode->subsampling;
+ int ret = 0;
+
+ /* Skipping configuration */
+ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL14,
+ OV64A40_SKIPPING_CONFIG(subsampling->x_odd_inc,
+ subsampling->x_even_inc), &ret);
+ cci_write(ov64a40->cci, OV64A40_REG_TIMING_CTRL15,
+ OV64A40_SKIPPING_CONFIG(subsampling->y_odd_inc,
+ subsampling->y_even_inc), &ret);
+
+ /* Binning configuration */
+ cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_20,
+ OV64A40_TIMING_CTRL_20_VBIN,
+ subsampling->vbin ? OV64A40_TIMING_CTRL_20_VBIN : 0,
+ &ret);
+ cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_21,
+ OV64A40_TIMING_CTRL_21_HBIN_CONF,
+ subsampling->hbin ?
+ OV64A40_TIMING_CTRL_21_HBIN_CONF : 0, &ret);
+
+ return ret;
+}
+
+static int ov64a40_start_streaming(struct ov64a40 *ov64a40,
+ struct v4l2_subdev_state *state)
+{
+ const struct ov64a40_reglist *reglist = &ov64a40->mode->reglist;
+ const struct ov64a40_timings *timings;
+ unsigned long delay;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(ov64a40->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = cci_multi_reg_write(ov64a40->cci, ov64a40_init,
+ ARRAY_SIZE(ov64a40_init), NULL);
+ if (ret)
+ goto error_power_off;
+
+ ret = cci_multi_reg_write(ov64a40->cci, reglist->regvals,
+ reglist->num_regs, NULL);
+ if (ret)
+ goto error_power_off;
+
+ ret = ov64a40_program_geometry(ov64a40);
+ if (ret)
+ goto error_power_off;
+
+ ret = ov64a40_program_subsampling(ov64a40);
+ if (ret)
+ goto error_power_off;
+
+ ret = __v4l2_ctrl_handler_setup(&ov64a40->ctrl_handler);
+ if (ret)
+ goto error_power_off;
+
+ ret = cci_write(ov64a40->cci, OV64A40_REG_SMIA,
+ OV64A40_REG_SMIA_STREAMING, NULL);
+ if (ret)
+ goto error_power_off;
+
+ /* Link frequency and flips cannot change while streaming. */
+ __v4l2_ctrl_grab(ov64a40->link_freq, true);
+ __v4l2_ctrl_grab(ov64a40->vflip, true);
+ __v4l2_ctrl_grab(ov64a40->hflip, true);
+
+ /* delay: max(4096 xclk pulses, 150usec) + exposure time */
+ timings = ov64a40_get_timings(ov64a40, ov64a40->link_freq->cur.val);
+ delay = DIV_ROUND_UP(4096, OV64A40_XCLK_FREQ / 1000 / 1000);
+ delay = max(delay, 150ul);
+
+ /* The sensor has an internal x4 multiplier on the line length. */
+ delay += DIV_ROUND_UP(timings->ppl * 4 * ov64a40->exposure->cur.val,
+ OV64A40_PIXEL_RATE / 1000 / 1000);
+ fsleep(delay);
+
+ return 0;
+
+error_power_off:
+ pm_runtime_mark_last_busy(ov64a40->dev);
+ pm_runtime_put_autosuspend(ov64a40->dev);
+
+ return ret;
+}
+
+static int ov64a40_stop_streaming(struct ov64a40 *ov64a40,
+ struct v4l2_subdev_state *state)
+{
+ cci_update_bits(ov64a40->cci, OV64A40_REG_SMIA, BIT(0), 0, NULL);
+ pm_runtime_mark_last_busy(ov64a40->dev);
+ pm_runtime_put_autosuspend(ov64a40->dev);
+
+ __v4l2_ctrl_grab(ov64a40->link_freq, false);
+ __v4l2_ctrl_grab(ov64a40->vflip, false);
+ __v4l2_ctrl_grab(ov64a40->hflip, false);
+
+ return 0;
+}
+
+static int ov64a40_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd);
+ struct v4l2_subdev_state *state;
+ int ret;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+ if (enable)
+ ret = ov64a40_start_streaming(ov64a40, state);
+ else
+ ret = ov64a40_stop_streaming(ov64a40, state);
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops ov64a40_video_ops = {
+ .s_stream = ov64a40_set_stream,
+};
+
+static u32 ov64a40_mbus_code(struct ov64a40 *ov64a40)
+{
+ unsigned int index = ov64a40->hflip->val << 1 | ov64a40->vflip->val;
+
+ return ov64a40_mbus_codes[index];
+}
+
+static void ov64a40_update_pad_fmt(struct ov64a40 *ov64a40,
+ struct ov64a40_mode *mode,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ fmt->code = ov64a40_mbus_code(ov64a40);
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_RAW;
+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ fmt->xfer_func = V4L2_XFER_FUNC_NONE;
+ fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
+}
+
+static int ov64a40_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ format = v4l2_subdev_state_get_format(state, 0);
+ ov64a40_update_pad_fmt(ov64a40, &ov64a40_modes[0], format);
+
+ crop = v4l2_subdev_state_get_crop(state, 0);
+ crop->top = OV64A40_PIXEL_ARRAY_TOP;
+ crop->left = OV64A40_PIXEL_ARRAY_LEFT;
+ crop->width = OV64A40_PIXEL_ARRAY_WIDTH;
+ crop->height = OV64A40_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+}
+
+static int ov64a40_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd);
+
+ if (code->index)
+ return -EINVAL;
+
+ code->code = ov64a40_mbus_code(ov64a40);
+
+ return 0;
+}
+
+static int ov64a40_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd);
+ struct ov64a40_mode *mode;
+ u32 code;
+
+ if (fse->index >= ARRAY_SIZE(ov64a40_modes))
+ return -EINVAL;
+
+ code = ov64a40_mbus_code(ov64a40);
+ if (fse->code != code)
+ return -EINVAL;
+
+ mode = &ov64a40_modes[fse->index];
+ fse->min_width = mode->width;
+ fse->max_width = mode->width;
+ fse->min_height = mode->height;
+ fse->max_height = mode->height;
+
+ return 0;
+}
+
+static int ov64a40_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *v4l2_subdev_state_get_crop(state, 0);
+
+ return 0;
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = OV64A40_NATIVE_WIDTH;
+ sel->r.height = OV64A40_NATIVE_HEIGHT;
+
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = OV64A40_PIXEL_ARRAY_TOP;
+ sel->r.left = OV64A40_PIXEL_ARRAY_LEFT;
+ sel->r.width = OV64A40_PIXEL_ARRAY_WIDTH;
+ sel->r.height = OV64A40_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int ov64a40_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd);
+ struct v4l2_mbus_framefmt *format;
+ struct ov64a40_mode *mode;
+
+ mode = v4l2_find_nearest_size(ov64a40_modes,
+ ARRAY_SIZE(ov64a40_modes),
+ width, height,
+ fmt->format.width, fmt->format.height);
+
+ ov64a40_update_pad_fmt(ov64a40, mode, &fmt->format);
+
+ format = v4l2_subdev_state_get_format(state, 0);
+ if (ov64a40->mode == mode && format->code == fmt->format.code)
+ return 0;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ const struct ov64a40_timings *timings;
+ int vblank_max, vblank_def;
+ int hblank_val;
+ int exp_max;
+
+ ov64a40->mode = mode;
+ *v4l2_subdev_state_get_crop(state, 0) = mode->analogue_crop;
+
+ /* Update control limits according to the new mode. */
+ timings = ov64a40_get_timings(ov64a40,
+ ov64a40->link_freq->cur.val);
+ vblank_max = OV64A40_VTS_MAX - mode->height;
+ vblank_def = timings->vts - mode->height;
+ __v4l2_ctrl_modify_range(ov64a40->vblank, OV64A40_VBLANK_MIN,
+ vblank_max, 1, vblank_def);
+ __v4l2_ctrl_s_ctrl(ov64a40->vblank, vblank_def);
+
+ exp_max = timings->vts - OV64A40_EXPOSURE_MARGIN;
+ __v4l2_ctrl_modify_range(ov64a40->exposure,
+ OV64A40_EXPOSURE_MIN, exp_max,
+ 1, OV64A40_EXPOSURE_MIN);
+
+ hblank_val = timings->ppl * 4 - mode->width;
+ __v4l2_ctrl_modify_range(ov64a40->hblank,
+ hblank_val, hblank_val, 1, hblank_val);
+ }
+
+ *format = fmt->format;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops ov64a40_pad_ops = {
+ .enum_mbus_code = ov64a40_enum_mbus_code,
+ .enum_frame_size = ov64a40_enum_frame_size,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = ov64a40_set_format,
+ .get_selection = ov64a40_get_selection,
+};
+
+static const struct v4l2_subdev_core_ops ov64a40_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_ops ov64a40_subdev_ops = {
+ .core = &ov64a40_core_ops,
+ .video = &ov64a40_video_ops,
+ .pad = &ov64a40_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops ov64a40_internal_ops = {
+ .init_state = ov64a40_init_state,
+};
+
+static int ov64a40_power_on(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd);
+ int ret;
+
+ ret = clk_prepare_enable(ov64a40->xclk);
+ if (ret)
+ return ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ov64a40_supply_names),
+ ov64a40->supplies);
+ if (ret) {
+ clk_disable_unprepare(ov64a40->xclk);
+ dev_err(dev, "Failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ gpiod_set_value_cansleep(ov64a40->reset_gpio, 0);
+
+ fsleep(5000);
+
+ return 0;
+}
+
+static int ov64a40_power_off(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov64a40 *ov64a40 = sd_to_ov64a40(sd);
+
+ gpiod_set_value_cansleep(ov64a40->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(ov64a40_supply_names),
+ ov64a40->supplies);
+ clk_disable_unprepare(ov64a40->xclk);
+
+ return 0;
+}
+
+static int ov64a40_link_freq_config(struct ov64a40 *ov64a40, int link_freq_id)
+{
+ s64 link_frequency;
+ int ret = 0;
+
+ /* Default 456MHz with 24MHz input clock. */
+ cci_multi_reg_write(ov64a40->cci, ov64a40_pll_config,
+ ARRAY_SIZE(ov64a40_pll_config), &ret);
+
+ /* Decrease the PLL1 multiplier to obtain 360MHz mipi link frequency. */
+ link_frequency = ov64a40->link_frequencies[link_freq_id];
+ if (link_frequency == OV64A40_LINK_FREQ_360M)
+ cci_write(ov64a40->cci, OV64A40_PLL1_MULTIPLIER, 0x0078, &ret);
+
+ return ret;
+}
+
+static int ov64a40_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov64a40 *ov64a40 = container_of(ctrl->handler, struct ov64a40,
+ ctrl_handler);
+ int pm_status;
+ int ret = 0;
+
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ int exp_max = ov64a40->mode->height + ctrl->val
+ - OV64A40_EXPOSURE_MARGIN;
+ int exp_val = min(ov64a40->exposure->cur.val, exp_max);
+
+ __v4l2_ctrl_modify_range(ov64a40->exposure,
+ ov64a40->exposure->minimum,
+ exp_max, 1, exp_val);
+ }
+
+ pm_status = pm_runtime_get_if_active(ov64a40->dev, true);
+ if (!pm_status)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ ret = cci_write(ov64a40->cci, OV64A40_REG_MEC_LONG_EXPO,
+ ctrl->val, NULL);
+ break;
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = cci_write(ov64a40->cci, OV64A40_REG_MEC_LONG_GAIN,
+ ctrl->val << 1, NULL);
+ break;
+ case V4L2_CID_VBLANK: {
+ int vts = ctrl->val + ov64a40->mode->height;
+
+ cci_write(ov64a40->cci, OV64A40_REG_TIMINGS_VTS_LOW, vts, &ret);
+ cci_write(ov64a40->cci, OV64A40_REG_TIMINGS_VTS_MID,
+ (vts >> 8), &ret);
+ cci_write(ov64a40->cci, OV64A40_REG_TIMINGS_VTS_HIGH,
+ (vts >> 16), &ret);
+ break;
+ }
+ case V4L2_CID_VFLIP:
+ ret = cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_20,
+ OV64A40_TIMING_CTRL_20_VFLIP,
+ ctrl->val << 2,
+ NULL);
+ break;
+ case V4L2_CID_HFLIP:
+ ret = cci_update_bits(ov64a40->cci, OV64A40_REG_TIMING_CTRL_21,
+ OV64A40_TIMING_CTRL_21_HFLIP,
+ ctrl->val ? 0
+ : OV64A40_TIMING_CTRL_21_HFLIP,
+ NULL);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = cci_write(ov64a40->cci, OV64A40_REG_TEST_PATTERN,
+ ov64a40_test_pattern_val[ctrl->val], NULL);
+ break;
+ case V4L2_CID_LINK_FREQ:
+ ret = ov64a40_link_freq_config(ov64a40, ctrl->val);
+ break;
+ default:
+ dev_err(ov64a40->dev, "Unhandled control: %#x\n", ctrl->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (pm_status > 0) {
+ pm_runtime_mark_last_busy(ov64a40->dev);
+ pm_runtime_put_autosuspend(ov64a40->dev);
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov64a40_ctrl_ops = {
+ .s_ctrl = ov64a40_set_ctrl,
+};
+
+static int ov64a40_init_controls(struct ov64a40 *ov64a40)
+{
+ int exp_max, hblank_val, vblank_max, vblank_def;
+ struct v4l2_ctrl_handler *hdlr = &ov64a40->ctrl_handler;
+ struct v4l2_fwnode_device_properties props;
+ const struct ov64a40_timings *timings;
+ int ret;
+
+ ret = v4l2_ctrl_handler_init(hdlr, 11);
+ if (ret)
+ return ret;
+
+ v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, V4L2_CID_PIXEL_RATE,
+ OV64A40_PIXEL_RATE, OV64A40_PIXEL_RATE, 1,
+ OV64A40_PIXEL_RATE);
+
+ ov64a40->link_freq =
+ v4l2_ctrl_new_int_menu(hdlr, &ov64a40_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ ov64a40->num_link_frequencies - 1,
+ 0, ov64a40->link_frequencies);
+
+ v4l2_ctrl_new_std_menu_items(hdlr, &ov64a40_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(ov64a40_test_pattern_menu) - 1,
+ 0, 0, ov64a40_test_pattern_menu);
+
+ timings = ov64a40_get_timings(ov64a40, 0);
+ exp_max = timings->vts - OV64A40_EXPOSURE_MARGIN;
+ ov64a40->exposure = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ OV64A40_EXPOSURE_MIN, exp_max, 1,
+ OV64A40_EXPOSURE_MIN);
+
+ hblank_val = timings->ppl * 4 - ov64a40->mode->width;
+ ov64a40->hblank = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops,
+ V4L2_CID_HBLANK, hblank_val,
+ hblank_val, 1, hblank_val);
+ if (ov64a40->hblank)
+ ov64a40->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ vblank_def = timings->vts - ov64a40->mode->height;
+ vblank_max = OV64A40_VTS_MAX - ov64a40->mode->height;
+ ov64a40->vblank = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops,
+ V4L2_CID_VBLANK, OV64A40_VBLANK_MIN,
+ vblank_max, 1, vblank_def);
+
+ v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ OV64A40_ANA_GAIN_MIN, OV64A40_ANA_GAIN_MAX, 1,
+ OV64A40_ANA_GAIN_DEFAULT);
+
+ ov64a40->hflip = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ if (ov64a40->hflip)
+ ov64a40->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ ov64a40->vflip = v4l2_ctrl_new_std(hdlr, &ov64a40_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ if (ov64a40->vflip)
+ ov64a40->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ if (hdlr->error) {
+ ret = hdlr->error;
+ dev_err(ov64a40->dev, "control init failed: %d\n", ret);
+ goto error_free_hdlr;
+ }
+
+ ret = v4l2_fwnode_device_parse(ov64a40->dev, &props);
+ if (ret)
+ goto error_free_hdlr;
+
+ ret = v4l2_ctrl_new_fwnode_properties(hdlr, &ov64a40_ctrl_ops,
+ &props);
+ if (ret)
+ goto error_free_hdlr;
+
+ ov64a40->sd.ctrl_handler = hdlr;
+
+ return 0;
+
+error_free_hdlr:
+ v4l2_ctrl_handler_free(hdlr);
+ return ret;
+}
+
+static int ov64a40_identify(struct ov64a40 *ov64a40)
+{
+ int ret;
+ u64 id;
+
+ ret = cci_read(ov64a40->cci, OV64A40_REG_CHIP_ID, &id, NULL);
+ if (ret) {
+ dev_err(ov64a40->dev, "Failed to read chip id: %d\n", ret);
+ return ret;
+ }
+
+ if (id != OV64A40_CHIP_ID) {
+ dev_err(ov64a40->dev, "chip id mismatch: %#llx\n", id);
+ return -ENODEV;
+ }
+
+ dev_dbg(ov64a40->dev, "OV64A40 chip identified: %#llx\n", id);
+
+ return 0;
+}
+
+static int ov64a40_parse_dt(struct ov64a40 *ov64a40)
+{
+ struct v4l2_fwnode_endpoint v4l2_fwnode = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ struct fwnode_handle *endpoint;
+ unsigned int i;
+ int ret;
+
+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(ov64a40->dev),
+ NULL);
+ if (!endpoint) {
+ dev_err(ov64a40->dev, "Failed to find endpoint\n");
+ return -EINVAL;
+ }
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &v4l2_fwnode);
+ fwnode_handle_put(endpoint);
+ if (ret) {
+ dev_err(ov64a40->dev, "Failed to parse endpoint\n");
+ return ret;
+ }
+
+ if (v4l2_fwnode.bus.mipi_csi2.num_data_lanes != 2) {
+ dev_err(ov64a40->dev, "Unsupported number of data lanes: %u\n",
+ v4l2_fwnode.bus.mipi_csi2.num_data_lanes);
+ v4l2_fwnode_endpoint_free(&v4l2_fwnode);
+ return -EINVAL;
+ }
+
+ if (!v4l2_fwnode.nr_of_link_frequencies) {
+ dev_warn(ov64a40->dev, "no link frequencies defined\n");
+ v4l2_fwnode_endpoint_free(&v4l2_fwnode);
+ return -EINVAL;
+ }
+
+ if (v4l2_fwnode.nr_of_link_frequencies > 2) {
+ dev_warn(ov64a40->dev,
+ "Unsupported number of link frequencies\n");
+ v4l2_fwnode_endpoint_free(&v4l2_fwnode);
+ return -EINVAL;
+ }
+
+ ov64a40->link_frequencies =
+ devm_kcalloc(ov64a40->dev, v4l2_fwnode.nr_of_link_frequencies,
+ sizeof(v4l2_fwnode.link_frequencies[0]),
+ GFP_KERNEL);
+ if (!ov64a40->link_frequencies) {
+ v4l2_fwnode_endpoint_free(&v4l2_fwnode);
+ return -ENOMEM;
+ }
+ ov64a40->num_link_frequencies = v4l2_fwnode.nr_of_link_frequencies;
+
+ for (i = 0; i < v4l2_fwnode.nr_of_link_frequencies; ++i) {
+ if (v4l2_fwnode.link_frequencies[i] != OV64A40_LINK_FREQ_360M &&
+ v4l2_fwnode.link_frequencies[i] != OV64A40_LINK_FREQ_456M) {
+ dev_err(ov64a40->dev,
+ "Unsupported link frequency %lld\n",
+ v4l2_fwnode.link_frequencies[i]);
+ v4l2_fwnode_endpoint_free(&v4l2_fwnode);
+ return -EINVAL;
+ }
+
+ ov64a40->link_frequencies[i] = v4l2_fwnode.link_frequencies[i];
+ }
+
+ v4l2_fwnode_endpoint_free(&v4l2_fwnode);
+
+ return 0;
+}
+
+static int ov64a40_get_regulators(struct ov64a40 *ov64a40)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov64a40->sd);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ov64a40_supply_names); i++)
+ ov64a40->supplies[i].supply = ov64a40_supply_names[i];
+
+ return devm_regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(ov64a40_supply_names),
+ ov64a40->supplies);
+}
+
+static int ov64a40_probe(struct i2c_client *client)
+{
+ struct ov64a40 *ov64a40;
+ u32 xclk_freq;
+ int ret;
+
+ ov64a40 = devm_kzalloc(&client->dev, sizeof(*ov64a40), GFP_KERNEL);
+ if (!ov64a40)
+ return -ENOMEM;
+
+ ov64a40->dev = &client->dev;
+ v4l2_i2c_subdev_init(&ov64a40->sd, client, &ov64a40_subdev_ops);
+
+ ov64a40->cci = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(ov64a40->cci)) {
+ dev_err(&client->dev, "Failed to initialize CCI\n");
+ return PTR_ERR(ov64a40->cci);
+ }
+
+ ov64a40->xclk = devm_clk_get(&client->dev, NULL);
+ if (IS_ERR(ov64a40->xclk))
+ return dev_err_probe(&client->dev, PTR_ERR(ov64a40->xclk),
+ "Failed to get clock\n");
+
+ xclk_freq = clk_get_rate(ov64a40->xclk);
+ if (xclk_freq != OV64A40_XCLK_FREQ) {
+ dev_err(&client->dev, "Unsupported xclk frequency %u\n",
+ xclk_freq);
+ return -EINVAL;
+ }
+
+ ret = ov64a40_get_regulators(ov64a40);
+ if (ret)
+ return ret;
+
+ ov64a40->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(ov64a40->reset_gpio))
+ return dev_err_probe(&client->dev, PTR_ERR(ov64a40->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ ret = ov64a40_parse_dt(ov64a40);
+ if (ret)
+ return ret;
+
+ ret = ov64a40_power_on(&client->dev);
+ if (ret)
+ return ret;
+
+ ret = ov64a40_identify(ov64a40);
+ if (ret)
+ goto error_poweroff;
+
+ ov64a40->mode = &ov64a40_modes[0];
+
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_get_noresume(&client->dev);
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev, 1000);
+ pm_runtime_use_autosuspend(&client->dev);
+
+ ret = ov64a40_init_controls(ov64a40);
+ if (ret)
+ goto error_poweroff;
+
+ /* Initialize subdev */
+ ov64a40->sd.internal_ops = &ov64a40_internal_ops;
+ ov64a40->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE
+ | V4L2_SUBDEV_FL_HAS_EVENTS;
+ ov64a40->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ ov64a40->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&ov64a40->sd.entity, 1, &ov64a40->pad);
+ if (ret) {
+ dev_err(&client->dev, "failed to init entity pads: %d\n", ret);
+ goto error_handler_free;
+ }
+
+ ov64a40->sd.state_lock = ov64a40->ctrl_handler.lock;
+ ret = v4l2_subdev_init_finalize(&ov64a40->sd);
+ if (ret < 0) {
+ dev_err(&client->dev, "subdev init error: %d\n", ret);
+ goto error_media_entity;
+ }
+
+ ret = v4l2_async_register_subdev_sensor(&ov64a40->sd);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "failed to register sensor sub-device: %d\n", ret);
+ goto error_subdev_cleanup;
+ }
+
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+
+ return 0;
+
+error_subdev_cleanup:
+ v4l2_subdev_cleanup(&ov64a40->sd);
+error_media_entity:
+ media_entity_cleanup(&ov64a40->sd.entity);
+error_handler_free:
+ v4l2_ctrl_handler_free(ov64a40->sd.ctrl_handler);
+error_poweroff:
+ ov64a40_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+ return ret;
+}
+
+static void ov64a40_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_async_unregister_subdev(sd);
+ v4l2_subdev_cleanup(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ ov64a40_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+}
+
+static const struct of_device_id ov64a40_of_ids[] = {
+ { .compatible = "ovti,ov64a40" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ov64a40_of_ids);
+
+static const struct dev_pm_ops ov64a40_pm_ops = {
+ SET_RUNTIME_PM_OPS(ov64a40_power_off, ov64a40_power_on, NULL)
+};
+
+static struct i2c_driver ov64a40_i2c_driver = {
+ .driver = {
+ .name = "ov64a40",
+ .of_match_table = ov64a40_of_ids,
+ .pm = &ov64a40_pm_ops,
+ },
+ .probe = ov64a40_probe,
+ .remove = ov64a40_remove,
+};
+
+module_i2c_driver(ov64a40_i2c_driver);
+
+MODULE_AUTHOR("Jacopo Mondi <[email protected]>");
+MODULE_DESCRIPTION("OmniVision OV64A40 sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 1ad07935f046..b65befb22a79 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -197,7 +197,7 @@ struct ov6650 {
struct clk *clk;
bool half_scale; /* scale down output by 2 */
struct v4l2_rect rect; /* sensor cropping window */
- struct v4l2_fract tpf; /* as requested with s_frame_interval */
+ struct v4l2_fract tpf; /* as requested with set_frame_interval */
u32 code;
};
@@ -476,7 +476,7 @@ static int ov6650_get_selection(struct v4l2_subdev *sd,
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
/* pre-select try crop rectangle */
- rect = &sd_state->pads->try_crop;
+ rect = v4l2_subdev_state_get_crop(sd_state, 0);
} else {
/* pre-select active crop rectangle */
@@ -531,8 +531,10 @@ static int ov6650_set_selection(struct v4l2_subdev *sd,
ov6650_bind_align_crop_rectangle(&sel->r);
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- struct v4l2_rect *crop = &sd_state->pads->try_crop;
- struct v4l2_mbus_framefmt *mf = &sd_state->pads->try_fmt;
+ struct v4l2_rect *crop =
+ v4l2_subdev_state_get_crop(sd_state, 0);
+ struct v4l2_mbus_framefmt *mf =
+ v4l2_subdev_state_get_format(sd_state, 0);
/* detect current pad config scaling factor */
bool half_scale = !is_unscaled_ok(mf->width, mf->height, crop);
@@ -588,9 +590,12 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd,
/* update media bus format code and frame size */
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf->width = sd_state->pads->try_fmt.width;
- mf->height = sd_state->pads->try_fmt.height;
- mf->code = sd_state->pads->try_fmt.code;
+ struct v4l2_mbus_framefmt *try_fmt =
+ v4l2_subdev_state_get_format(sd_state, 0);
+
+ mf->width = try_fmt->width;
+ mf->height = try_fmt->height;
+ mf->code = try_fmt->code;
} else {
mf->width = priv->rect.width >> priv->half_scale;
@@ -717,23 +722,26 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
}
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- crop = &sd_state->pads->try_crop;
+ crop = v4l2_subdev_state_get_crop(sd_state, 0);
else
crop = &priv->rect;
half_scale = !is_unscaled_ok(mf->width, mf->height, crop);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ struct v4l2_mbus_framefmt *try_fmt =
+ v4l2_subdev_state_get_format(sd_state, 0);
+
/* store new mbus frame format code and size in pad config */
- sd_state->pads->try_fmt.width = crop->width >> half_scale;
- sd_state->pads->try_fmt.height = crop->height >> half_scale;
- sd_state->pads->try_fmt.code = mf->code;
+ try_fmt->width = crop->width >> half_scale;
+ try_fmt->height = crop->height >> half_scale;
+ try_fmt->code = mf->code;
/* return default mbus frame format updated with pad config */
*mf = ov6650_def_fmt;
- mf->width = sd_state->pads->try_fmt.width;
- mf->height = sd_state->pads->try_fmt.height;
- mf->code = sd_state->pads->try_fmt.code;
+ mf->width = try_fmt->width;
+ mf->height = try_fmt->height;
+ mf->code = try_fmt->code;
} else {
int ret = 0;
@@ -791,12 +799,20 @@ static int ov6650_enum_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int ov6650_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
+static int ov6650_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
ival->interval = priv->tpf;
dev_dbg(&client->dev, "Frame interval: %u/%u s\n",
@@ -805,14 +821,22 @@ static int ov6650_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int ov6650_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
+static int ov6650_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov6650 *priv = to_ov6650(client);
struct v4l2_fract *tpf = &ival->interval;
int div, ret;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (tpf->numerator == 0 || tpf->denominator == 0)
div = 1; /* Reset to full rate */
else
@@ -998,8 +1022,6 @@ static int ov6650_get_mbus_config(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops ov6650_video_ops = {
.s_stream = ov6650_s_stream,
- .g_frame_interval = ov6650_g_frame_interval,
- .s_frame_interval = ov6650_s_frame_interval,
};
static const struct v4l2_subdev_pad_ops ov6650_pad_ops = {
@@ -1009,6 +1031,8 @@ static const struct v4l2_subdev_pad_ops ov6650_pad_ops = {
.set_selection = ov6650_set_selection,
.get_fmt = ov6650_get_fmt,
.set_fmt = ov6650_set_fmt,
+ .get_frame_interval = ov6650_get_frame_interval,
+ .set_frame_interval = ov6650_set_frame_interval,
.get_mbus_config = ov6650_get_mbus_config,
};
diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c
index 6582cc0e2384..30f61e04ecaf 100644
--- a/drivers/media/i2c/ov7251.c
+++ b/drivers/media/i2c/ov7251.c
@@ -1139,7 +1139,7 @@ __ov7251_get_pad_format(struct ov7251 *ov7251,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&ov7251->sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov7251->fmt;
default:
@@ -1169,7 +1169,7 @@ __ov7251_get_pad_crop(struct ov7251 *ov7251,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&ov7251->sd, sd_state, pad);
+ return v4l2_subdev_state_get_crop(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov7251->crop;
default:
@@ -1282,8 +1282,8 @@ exit:
return ret;
}
-static int ov7251_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state)
+static int ov7251_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = {
.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
@@ -1386,10 +1386,18 @@ err_power_down:
}
static int ov7251_get_frame_interval(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval *fi)
{
struct ov7251 *ov7251 = to_ov7251(subdev);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(&ov7251->lock);
fi->interval = ov7251->current_mode->timeperframe;
mutex_unlock(&ov7251->lock);
@@ -1398,12 +1406,20 @@ static int ov7251_get_frame_interval(struct v4l2_subdev *subdev,
}
static int ov7251_set_frame_interval(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval *fi)
{
struct ov7251 *ov7251 = to_ov7251(subdev);
const struct ov7251_mode_info *new_mode;
int ret = 0;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(&ov7251->lock);
new_mode = ov7251_find_mode_by_ival(ov7251, &fi->interval);
@@ -1436,18 +1452,17 @@ exit:
static const struct v4l2_subdev_video_ops ov7251_video_ops = {
.s_stream = ov7251_s_stream,
- .g_frame_interval = ov7251_get_frame_interval,
- .s_frame_interval = ov7251_set_frame_interval,
};
static const struct v4l2_subdev_pad_ops ov7251_subdev_pad_ops = {
- .init_cfg = ov7251_entity_init_cfg,
.enum_mbus_code = ov7251_enum_mbus_code,
.enum_frame_size = ov7251_enum_frame_size,
.enum_frame_interval = ov7251_enum_frame_ival,
.get_fmt = ov7251_get_format,
.set_fmt = ov7251_set_format,
.get_selection = ov7251_get_selection,
+ .get_frame_interval = ov7251_get_frame_interval,
+ .set_frame_interval = ov7251_set_frame_interval,
};
static const struct v4l2_subdev_ops ov7251_subdev_ops = {
@@ -1455,6 +1470,10 @@ static const struct v4l2_subdev_ops ov7251_subdev_ops = {
.pad = &ov7251_subdev_pad_ops,
};
+static const struct v4l2_subdev_internal_ops ov7251_internal_ops = {
+ .init_state = ov7251_init_state,
+};
+
static int ov7251_check_hwcfg(struct ov7251 *ov7251)
{
struct fwnode_handle *fwnode = dev_fwnode(ov7251->dev);
@@ -1693,6 +1712,7 @@ static int ov7251_probe(struct i2c_client *client)
}
v4l2_i2c_subdev_init(&ov7251->sd, client, &ov7251_subdev_ops);
+ ov7251->sd.internal_ops = &ov7251_internal_ops;
ov7251->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
ov7251->pad.flags = MEDIA_PAD_FL_SOURCE;
ov7251->sd.dev = &client->dev;
@@ -1750,7 +1770,7 @@ static int ov7251_probe(struct i2c_client *client)
goto free_entity;
}
- ov7251_entity_init_cfg(&ov7251->sd, NULL);
+ ov7251_init_state(&ov7251->sd, NULL);
return 0;
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index 172483597c54..0cb96b6c9990 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -1112,8 +1112,7 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL);
if (ret)
return ret;
- mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state,
- format->pad);
+ mbus_fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
*mbus_fmt = format->format;
return 0;
}
@@ -1141,7 +1140,7 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mbus_fmt;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ mbus_fmt = v4l2_subdev_state_get_format(sd_state, 0);
format->format = *mbus_fmt;
return 0;
} else {
@@ -1155,23 +1154,37 @@ static int ov7670_get_fmt(struct v4l2_subdev *sd,
* Implement G/S_PARM. There is a "high quality" mode we could try
* to do someday; for now, we just do the frame rate tweak.
*/
-static int ov7670_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
+static int ov7670_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
{
struct ov7670_info *info = to_state(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
info->devtype->get_framerate(sd, &ival->interval);
return 0;
}
-static int ov7670_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
+static int ov7670_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
{
struct v4l2_fract *tpf = &ival->interval;
struct ov7670_info *info = to_state(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
return info->devtype->set_framerate(sd, tpf);
}
@@ -1707,7 +1720,7 @@ static void ov7670_get_default_format(struct v4l2_subdev *sd,
static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *format =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
+ v4l2_subdev_state_get_format(fh->state, 0);
ov7670_get_default_format(sd, format);
@@ -1729,22 +1742,18 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = {
#endif
};
-static const struct v4l2_subdev_video_ops ov7670_video_ops = {
- .s_frame_interval = ov7670_s_frame_interval,
- .g_frame_interval = ov7670_g_frame_interval,
-};
-
static const struct v4l2_subdev_pad_ops ov7670_pad_ops = {
.enum_frame_interval = ov7670_enum_frame_interval,
.enum_frame_size = ov7670_enum_frame_size,
.enum_mbus_code = ov7670_enum_mbus_code,
.get_fmt = ov7670_get_fmt,
.set_fmt = ov7670_set_fmt,
+ .get_frame_interval = ov7670_get_frame_interval,
+ .set_frame_interval = ov7670_set_frame_interval,
};
static const struct v4l2_subdev_ops ov7670_ops = {
.core = &ov7670_core_ops,
- .video = &ov7670_video_ops,
.pad = &ov7670_pad_ops,
};
diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
index 7618b58a7ad0..3e36a55274ef 100644
--- a/drivers/media/i2c/ov772x.c
+++ b/drivers/media/i2c/ov772x.c
@@ -717,26 +717,42 @@ static int ov772x_set_frame_rate(struct ov772x_priv *priv,
return 0;
}
-static int ov772x_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
+static int ov772x_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
{
struct ov772x_priv *priv = to_ov772x(sd);
struct v4l2_fract *tpf = &ival->interval;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
tpf->numerator = 1;
tpf->denominator = priv->fps;
return 0;
}
-static int ov772x_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
+static int ov772x_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
{
struct ov772x_priv *priv = to_ov772x(sd);
struct v4l2_fract *tpf = &ival->interval;
unsigned int fps;
int ret = 0;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(&priv->lock);
if (priv->streaming) {
@@ -1220,7 +1236,7 @@ static int ov772x_set_fmt(struct v4l2_subdev *sd,
mf->xfer_func = V4L2_XFER_FUNC_DEFAULT;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sd_state->pads->try_fmt = *mf;
+ *v4l2_subdev_state_get_format(sd_state, 0) = *mf;
return 0;
}
@@ -1349,8 +1365,6 @@ static int ov772x_enum_mbus_code(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
.s_stream = ov772x_s_stream,
- .s_frame_interval = ov772x_s_frame_interval,
- .g_frame_interval = ov772x_g_frame_interval,
};
static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = {
@@ -1359,6 +1373,8 @@ static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = {
.get_selection = ov772x_get_selection,
.get_fmt = ov772x_get_fmt,
.set_fmt = ov772x_set_fmt,
+ .get_frame_interval = ov772x_get_frame_interval,
+ .set_frame_interval = ov772x_set_frame_interval,
};
static const struct v4l2_subdev_ops ov772x_subdev_ops = {
diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
index 356a45e65b81..47b1b14d8796 100644
--- a/drivers/media/i2c/ov7740.c
+++ b/drivers/media/i2c/ov7740.c
@@ -638,34 +638,8 @@ err_unlock:
return ret;
}
-static int ov7740_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
-{
- struct v4l2_fract *tpf = &ival->interval;
-
-
- tpf->numerator = 1;
- tpf->denominator = 60;
-
- return 0;
-}
-
-static int ov7740_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
-{
- struct v4l2_fract *tpf = &ival->interval;
-
-
- tpf->numerator = 1;
- tpf->denominator = 60;
-
- return 0;
-}
-
static const struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {
.s_stream = ov7740_set_stream,
- .s_frame_interval = ov7740_s_frame_interval,
- .g_frame_interval = ov7740_g_frame_interval,
};
static const struct reg_sequence ov7740_format_yuyv[] = {
@@ -812,8 +786,7 @@ static int ov7740_set_fmt(struct v4l2_subdev *sd,
if (ret)
goto error;
- mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state,
- format->pad);
+ mbus_fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
*mbus_fmt = format->format;
mutex_unlock(&ov7740->mutex);
return 0;
@@ -843,7 +816,7 @@ static int ov7740_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&ov7740->mutex);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- mbus_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ mbus_fmt = v4l2_subdev_state_get_format(sd_state, 0);
format->format = *mbus_fmt;
} else {
format->format = ov7740->format;
@@ -853,12 +826,26 @@ static int ov7740_get_fmt(struct v4l2_subdev *sd,
return 0;
}
+static int ov7740_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
+{
+ struct v4l2_fract *tpf = &ival->interval;
+
+ tpf->numerator = 1;
+ tpf->denominator = 60;
+
+ return 0;
+}
+
static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = {
.enum_frame_interval = ov7740_enum_frame_interval,
.enum_frame_size = ov7740_enum_frame_size,
.enum_mbus_code = ov7740_enum_mbus_code,
.get_fmt = ov7740_get_fmt,
.set_fmt = ov7740_set_fmt,
+ .get_frame_interval = ov7740_get_frame_interval,
+ .set_frame_interval = ov7740_get_frame_interval,
};
static const struct v4l2_subdev_ops ov7740_subdev_ops = {
@@ -883,7 +870,7 @@ static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
struct v4l2_mbus_framefmt *format =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
+ v4l2_subdev_state_get_format(fh->state, 0);
mutex_lock(&ov7740->mutex);
ov7740_get_default_format(sd, format);
diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c
index a0f673a24e52..6ffe10e57b5b 100644
--- a/drivers/media/i2c/ov8856.c
+++ b/drivers/media/i2c/ov8856.c
@@ -2134,7 +2134,7 @@ static int ov8856_set_format(struct v4l2_subdev *sd,
mutex_lock(&ov8856->mutex);
ov8856_update_pad_format(ov8856, mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
} else {
ov8856->cur_mode = mode;
__v4l2_ctrl_s_ctrl(ov8856->link_freq, mode->link_freq_index);
@@ -2172,9 +2172,8 @@ static int ov8856_get_format(struct v4l2_subdev *sd,
mutex_lock(&ov8856->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&ov8856->sd,
- sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
else
ov8856_update_pad_format(ov8856, ov8856->cur_mode, &fmt->format);
@@ -2225,7 +2224,7 @@ static int ov8856_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&ov8856->mutex);
ov8856_update_pad_format(ov8856, &ov8856->priv_lane->supported_modes[0],
- v4l2_subdev_get_try_format(sd, fh->state, 0));
+ v4l2_subdev_state_get_format(fh->state, 0));
mutex_unlock(&ov8856->mutex);
return 0;
diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c
index 4d9fd76e2f60..174c65f76886 100644
--- a/drivers/media/i2c/ov8858.c
+++ b/drivers/media/i2c/ov8858.c
@@ -1333,7 +1333,7 @@ static int ov8858_start_stream(struct ov8858 *ov8858,
if (ret)
return ret;
- format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
mode = v4l2_find_nearest_size(ov8858_modes, ARRAY_SIZE(ov8858_modes),
width, height, format->width,
format->height);
@@ -1428,7 +1428,7 @@ static int ov8858_set_fmt(struct v4l2_subdev *sd,
fmt->format.field = V4L2_FIELD_NONE;
/* Store the format in the current subdev state. */
- *v4l2_subdev_get_pad_format(sd, state, 0) = fmt->format;
+ *v4l2_subdev_state_get_format(state, 0) = fmt->format;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
@@ -1476,8 +1476,8 @@ static int ov8858_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
-static int ov8858_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int ov8858_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
const struct ov8858_mode *def_mode = &ov8858_modes[0];
struct v4l2_subdev_format fmt = {
@@ -1494,7 +1494,6 @@ static int ov8858_init_cfg(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_pad_ops ov8858_pad_ops = {
- .init_cfg = ov8858_init_cfg,
.enum_mbus_code = ov8858_enum_mbus_code,
.enum_frame_size = ov8858_enum_frame_sizes,
.get_fmt = v4l2_subdev_get_fmt,
@@ -1512,6 +1511,10 @@ static const struct v4l2_subdev_ops ov8858_subdev_ops = {
.pad = &ov8858_pad_ops,
};
+static const struct v4l2_subdev_internal_ops ov8858_internal_ops = {
+ .init_state = ov8858_init_state,
+};
+
/* ----------------------------------------------------------------------------
* Controls handling
*/
@@ -1547,7 +1550,7 @@ static int ov8858_set_ctrl(struct v4l2_ctrl *ctrl)
* - by the driver when s_ctrl is called in the s_stream(1) call path
*/
state = v4l2_subdev_get_locked_active_state(&ov8858->subdev);
- format = v4l2_subdev_get_pad_format(&ov8858->subdev, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
/* Propagate change of current control to all related controls */
switch (ctrl->id) {
@@ -1899,6 +1902,7 @@ static int ov8858_probe(struct i2c_client *client)
"Failed to get powerdown gpio\n");
v4l2_i2c_subdev_init(&ov8858->subdev, client, &ov8858_subdev_ops);
+ ov8858->subdev.internal_ops = &ov8858_internal_ops;
ret = ov8858_configure_regulators(ov8858);
if (ret)
diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c
index f2213c6158d3..95ffe7536aa6 100644
--- a/drivers/media/i2c/ov8865.c
+++ b/drivers/media/i2c/ov8865.c
@@ -2640,33 +2640,8 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable)
return 0;
}
-static int ov8865_g_frame_interval(struct v4l2_subdev *subdev,
- struct v4l2_subdev_frame_interval *interval)
-{
- struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev);
- const struct ov8865_mode *mode;
- unsigned int framesize;
- unsigned int fps;
-
- mutex_lock(&sensor->mutex);
-
- mode = sensor->state.mode;
- framesize = mode->hts * (mode->output_size_y +
- sensor->ctrls.vblank->val);
- fps = DIV_ROUND_CLOSEST(sensor->ctrls.pixel_rate->val, framesize);
-
- interval->interval.numerator = 1;
- interval->interval.denominator = fps;
-
- mutex_unlock(&sensor->mutex);
-
- return 0;
-}
-
static const struct v4l2_subdev_video_ops ov8865_subdev_video_ops = {
.s_stream = ov8865_s_stream,
- .g_frame_interval = ov8865_g_frame_interval,
- .s_frame_interval = ov8865_g_frame_interval,
};
/* Subdev Pad Operations */
@@ -2710,8 +2685,8 @@ static int ov8865_get_fmt(struct v4l2_subdev *subdev,
mutex_lock(&sensor->mutex);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *mbus_format = *v4l2_subdev_get_try_format(subdev, sd_state,
- format->pad);
+ *mbus_format = *v4l2_subdev_state_get_format(sd_state,
+ format->pad);
else
ov8865_mbus_format_fill(mbus_format, sensor->state.mbus_code,
sensor->state.mode);
@@ -2765,7 +2740,7 @@ static int ov8865_set_fmt(struct v4l2_subdev *subdev,
ov8865_mbus_format_fill(mbus_format, mbus_code, mode);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *v4l2_subdev_get_try_format(subdev, sd_state, format->pad) =
+ *v4l2_subdev_state_get_format(sd_state, format->pad) =
*mbus_format;
else if (sensor->state.mode != mode ||
sensor->state.mbus_code != mbus_code)
@@ -2818,7 +2793,7 @@ __ov8865_get_pad_crop(struct ov8865_sensor *sensor,
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- *r = *v4l2_subdev_get_try_crop(&sensor->subdev, state, pad);
+ *r = *v4l2_subdev_state_get_crop(state, pad);
break;
case V4L2_SUBDEV_FORMAT_ACTIVE:
r->height = mode->output_size_y;
@@ -2862,6 +2837,37 @@ static int ov8865_get_selection(struct v4l2_subdev *subdev,
return 0;
}
+static int ov8865_get_frame_interval(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *interval)
+{
+ struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev);
+ const struct ov8865_mode *mode;
+ unsigned int framesize;
+ unsigned int fps;
+
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ mutex_lock(&sensor->mutex);
+
+ mode = sensor->state.mode;
+ framesize = mode->hts * (mode->output_size_y +
+ sensor->ctrls.vblank->val);
+ fps = DIV_ROUND_CLOSEST(sensor->ctrls.pixel_rate->val, framesize);
+
+ interval->interval.numerator = 1;
+ interval->interval.denominator = fps;
+
+ mutex_unlock(&sensor->mutex);
+
+ return 0;
+}
+
static const struct v4l2_subdev_pad_ops ov8865_subdev_pad_ops = {
.enum_mbus_code = ov8865_enum_mbus_code,
.get_fmt = ov8865_get_fmt,
@@ -2869,6 +2875,8 @@ static const struct v4l2_subdev_pad_ops ov8865_subdev_pad_ops = {
.enum_frame_size = ov8865_enum_frame_size,
.get_selection = ov8865_get_selection,
.set_selection = ov8865_get_selection,
+ .get_frame_interval = ov8865_get_frame_interval,
+ .set_frame_interval = ov8865_get_frame_interval,
};
static const struct v4l2_subdev_ops ov8865_subdev_ops = {
diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c
index bf6dfce1b5dd..251a4b534914 100644
--- a/drivers/media/i2c/ov9282.c
+++ b/drivers/media/i2c/ov9282.c
@@ -814,7 +814,7 @@ static int ov9282_get_pad_format(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *framefmt;
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *framefmt;
} else {
ov9282_fill_pad_format(ov9282, ov9282->cur_mode, ov9282->code,
@@ -860,7 +860,7 @@ static int ov9282_set_pad_format(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *framefmt;
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
} else {
ret = ov9282_update_controls(ov9282, mode, fmt);
@@ -876,14 +876,14 @@ static int ov9282_set_pad_format(struct v4l2_subdev *sd,
}
/**
- * ov9282_init_pad_cfg() - Initialize sub-device pad configuration
+ * ov9282_init_state() - Initialize sub-device state
* @sd: pointer to ov9282 V4L2 sub-device structure
* @sd_state: V4L2 sub-device configuration
*
* Return: 0 if successful, error code otherwise.
*/
-static int ov9282_init_pad_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int ov9282_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct ov9282 *ov9282 = to_ov9282(sd);
struct v4l2_subdev_format fmt = { 0 };
@@ -902,7 +902,7 @@ __ov9282_get_pad_crop(struct ov9282 *ov9282,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&ov9282->sd, sd_state, pad);
+ return v4l2_subdev_state_get_crop(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &ov9282->cur_mode->crop;
}
@@ -1192,7 +1192,6 @@ static const struct v4l2_subdev_video_ops ov9282_video_ops = {
};
static const struct v4l2_subdev_pad_ops ov9282_pad_ops = {
- .init_cfg = ov9282_init_pad_cfg,
.enum_mbus_code = ov9282_enum_mbus_code,
.enum_frame_size = ov9282_enum_frame_size,
.get_fmt = ov9282_get_pad_format,
@@ -1206,6 +1205,10 @@ static const struct v4l2_subdev_ops ov9282_subdev_ops = {
.pad = &ov9282_pad_ops,
};
+static const struct v4l2_subdev_internal_ops ov9282_internal_ops = {
+ .init_state = ov9282_init_state,
+};
+
/**
* ov9282_power_on() - Sensor power on sequence
* @dev: pointer to i2c device
@@ -1394,6 +1397,7 @@ static int ov9282_probe(struct i2c_client *client)
/* Initialize subdev */
v4l2_i2c_subdev_init(&ov9282->sd, client, &ov9282_subdev_ops);
+ ov9282->sd.internal_ops = &ov9282_internal_ops;
v4l2_i2c_subdev_set_name(&ov9282->sd, client,
device_get_match_data(ov9282->dev), NULL);
diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c
index cbaea049531d..e9a52a8a9dc0 100644
--- a/drivers/media/i2c/ov9640.c
+++ b/drivers/media/i2c/ov9640.c
@@ -547,8 +547,6 @@ static int ov9640_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return ov9640_s_fmt(sd, mf);
- sd_state->pads->try_fmt = *mf;
-
return 0;
}
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index da1ab5135eaa..66cd0e9ddc9a 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -1101,11 +1101,19 @@ static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd,
return 0;
}
-static int ov965x_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int ov965x_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct ov965x *ov965x = to_ov965x(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(&ov965x->lock);
fi->interval = ov965x->fiv->interval;
mutex_unlock(&ov965x->lock);
@@ -1148,12 +1156,20 @@ static int __ov965x_set_frame_interval(struct ov965x *ov965x,
return 0;
}
-static int ov965x_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int ov965x_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct ov965x *ov965x = to_ov965x(sd);
int ret;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n",
fi->interval.numerator, fi->interval.denominator);
@@ -1172,7 +1188,7 @@ static int ov965x_get_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ mf = v4l2_subdev_state_get_format(sd_state, 0);
fmt->format = *mf;
return 0;
}
@@ -1233,8 +1249,7 @@ static int ov965x_set_fmt(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
if (sd_state) {
- mf = v4l2_subdev_get_try_format(sd, sd_state,
- fmt->pad);
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*mf = fmt->format;
}
} else {
@@ -1363,7 +1378,7 @@ static int ov965x_s_stream(struct v4l2_subdev *sd, int on)
static int ov965x_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *mf =
- v4l2_subdev_get_try_format(sd, fh->state, 0);
+ v4l2_subdev_state_get_format(fh->state, 0);
ov965x_get_default_format(mf);
return 0;
@@ -1374,12 +1389,12 @@ static const struct v4l2_subdev_pad_ops ov965x_pad_ops = {
.enum_frame_size = ov965x_enum_frame_sizes,
.get_fmt = ov965x_get_fmt,
.set_fmt = ov965x_set_fmt,
+ .get_frame_interval = ov965x_get_frame_interval,
+ .set_frame_interval = ov965x_set_frame_interval,
};
static const struct v4l2_subdev_video_ops ov965x_video_ops = {
.s_stream = ov965x_s_stream,
- .g_frame_interval = ov965x_g_frame_interval,
- .s_frame_interval = ov965x_s_frame_interval,
};
diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c
index ee3315299605..d99728597431 100644
--- a/drivers/media/i2c/ov9734.c
+++ b/drivers/media/i2c/ov9734.c
@@ -697,7 +697,7 @@ static int ov9734_set_format(struct v4l2_subdev *sd,
mutex_lock(&ov9734->mutex);
ov9734_update_pad_format(mode, &fmt->format);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format;
} else {
ov9734->cur_mode = mode;
__v4l2_ctrl_s_ctrl(ov9734->link_freq, mode->link_freq_index);
@@ -730,9 +730,8 @@ static int ov9734_get_format(struct v4l2_subdev *sd,
mutex_lock(&ov9734->mutex);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(&ov9734->sd,
- sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
else
ov9734_update_pad_format(ov9734->cur_mode, &fmt->format);
@@ -777,7 +776,7 @@ static int ov9734_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_lock(&ov9734->mutex);
ov9734_update_pad_format(&supported_modes[0],
- v4l2_subdev_get_try_format(sd, fh->state, 0));
+ v4l2_subdev_state_get_format(fh->state, 0));
mutex_unlock(&ov9734->mutex);
return 0;
@@ -894,6 +893,7 @@ static void ov9734_remove(struct i2c_client *client)
media_entity_cleanup(&sd->entity);
v4l2_ctrl_handler_free(sd->ctrl_handler);
pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
mutex_destroy(&ov9734->mutex);
}
@@ -939,13 +939,6 @@ static int ov9734_probe(struct i2c_client *client)
goto probe_error_v4l2_ctrl_handler_free;
}
- ret = v4l2_async_register_subdev_sensor(&ov9734->sd);
- if (ret < 0) {
- dev_err(&client->dev, "failed to register V4L2 subdev: %d",
- ret);
- goto probe_error_media_entity_cleanup;
- }
-
/*
* Device is already turned on by i2c-core with ACPI domain PM.
* Enable runtime PM and turn off the device.
@@ -954,9 +947,18 @@ static int ov9734_probe(struct i2c_client *client)
pm_runtime_enable(&client->dev);
pm_runtime_idle(&client->dev);
+ ret = v4l2_async_register_subdev_sensor(&ov9734->sd);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed to register V4L2 subdev: %d",
+ ret);
+ goto probe_error_media_entity_cleanup_pm;
+ }
+
return 0;
-probe_error_media_entity_cleanup:
+probe_error_media_entity_cleanup_pm:
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
media_entity_cleanup(&ov9734->sd.entity);
probe_error_v4l2_ctrl_handler_free:
diff --git a/drivers/media/i2c/rj54n1cb0c.c b/drivers/media/i2c/rj54n1cb0c.c
index b430046f9e2a..a59db10153cd 100644
--- a/drivers/media/i2c/rj54n1cb0c.c
+++ b/drivers/media/i2c/rj54n1cb0c.c
@@ -1008,10 +1008,8 @@ static int rj54n1_set_fmt(struct v4l2_subdev *sd,
v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align,
&mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0);
- if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sd_state->pads->try_fmt = *mf;
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
- }
/*
* Verify if the sensor has just been powered on. TODO: replace this
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index ed5b10731a14..af8d01f78c32 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -819,7 +819,6 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state,
struct v4l2_subdev_format *fmt,
const struct s5c73m3_frame_size **fs)
{
- struct v4l2_subdev *sd = &state->sensor_sd;
u32 code;
switch (fmt->pad) {
@@ -841,10 +840,8 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state,
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
*fs = state->oif_pix_size[RES_ISP];
else
- *fs = s5c73m3_find_frame_size(
- v4l2_subdev_get_try_format(sd, sd_state,
- OIF_ISP_PAD),
- RES_ISP);
+ *fs = s5c73m3_find_frame_size(v4l2_subdev_state_get_format(sd_state, OIF_ISP_PAD),
+ RES_ISP);
break;
}
@@ -869,11 +866,19 @@ static void s5c73m3_try_format(struct s5c73m3 *state,
s5c73m3_fill_mbus_fmt(&fmt->format, *fs, code);
}
-static int s5c73m3_oif_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int s5c73m3_oif_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (fi->pad != OIF_SOURCE_PAD)
return -EINVAL;
@@ -918,12 +923,20 @@ static int __s5c73m3_set_frame_interval(struct s5c73m3 *state,
return 0;
}
-static int s5c73m3_oif_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int s5c73m3_oif_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct s5c73m3 *state = oif_sd_to_s5c73m3(sd);
int ret;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (fi->pad != OIF_SOURCE_PAD)
return -EINVAL;
@@ -990,8 +1003,8 @@ static int s5c73m3_get_fmt(struct v4l2_subdev *sd,
u32 code;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
return 0;
}
@@ -1025,8 +1038,8 @@ static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd,
u32 code;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
return 0;
}
@@ -1069,7 +1082,7 @@ static int s5c73m3_set_fmt(struct v4l2_subdev *sd,
s5c73m3_try_format(state, sd_state, fmt, &frame_size);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*mf = fmt->format;
} else {
switch (fmt->pad) {
@@ -1108,11 +1121,11 @@ static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd,
s5c73m3_oif_try_format(state, sd_state, fmt, &frame_size);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*mf = fmt->format;
if (fmt->pad == OIF_ISP_PAD) {
- mf = v4l2_subdev_get_try_format(sd, sd_state,
- OIF_SOURCE_PAD);
+ mf = v4l2_subdev_state_get_format(sd_state,
+ OIF_SOURCE_PAD);
mf->width = fmt->format.width;
mf->height = fmt->format.height;
}
@@ -1260,8 +1273,8 @@ static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd,
if (fse->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, sd_state,
- OIF_ISP_PAD);
+ mf = v4l2_subdev_state_get_format(sd_state,
+ OIF_ISP_PAD);
w = mf->width;
h = mf->height;
@@ -1316,11 +1329,11 @@ static int s5c73m3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, fh->state, S5C73M3_ISP_PAD);
+ mf = v4l2_subdev_state_get_format(fh->state, S5C73M3_ISP_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
S5C73M3_ISP_FMT);
- mf = v4l2_subdev_get_try_format(sd, fh->state, S5C73M3_JPEG_PAD);
+ mf = v4l2_subdev_state_get_format(fh->state, S5C73M3_JPEG_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1],
S5C73M3_JPEG_FMT);
@@ -1331,15 +1344,15 @@ static int s5c73m3_oif_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, fh->state, OIF_ISP_PAD);
+ mf = v4l2_subdev_state_get_format(fh->state, OIF_ISP_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
S5C73M3_ISP_FMT);
- mf = v4l2_subdev_get_try_format(sd, fh->state, OIF_JPEG_PAD);
+ mf = v4l2_subdev_state_get_format(fh->state, OIF_JPEG_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1],
S5C73M3_JPEG_FMT);
- mf = v4l2_subdev_get_try_format(sd, fh->state, OIF_SOURCE_PAD);
+ mf = v4l2_subdev_state_get_format(fh->state, OIF_SOURCE_PAD);
s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1],
S5C73M3_ISP_FMT);
return 0;
@@ -1500,6 +1513,8 @@ static const struct v4l2_subdev_pad_ops s5c73m3_oif_pad_ops = {
.enum_frame_interval = s5c73m3_oif_enum_frame_interval,
.get_fmt = s5c73m3_oif_get_fmt,
.set_fmt = s5c73m3_oif_set_fmt,
+ .get_frame_interval = s5c73m3_oif_get_frame_interval,
+ .set_frame_interval = s5c73m3_oif_set_frame_interval,
.get_frame_desc = s5c73m3_oif_get_frame_desc,
.set_frame_desc = s5c73m3_oif_set_frame_desc,
};
@@ -1511,8 +1526,6 @@ static const struct v4l2_subdev_core_ops s5c73m3_oif_core_ops = {
static const struct v4l2_subdev_video_ops s5c73m3_oif_video_ops = {
.s_stream = s5c73m3_oif_s_stream,
- .g_frame_interval = s5c73m3_oif_g_frame_interval,
- .s_frame_interval = s5c73m3_oif_s_frame_interval,
};
static const struct v4l2_subdev_ops oif_subdev_ops = {
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 67da2045f543..de079d2c9282 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -1118,11 +1118,19 @@ out:
return ret;
}
-static int s5k5baf_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int s5k5baf_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct s5k5baf *state = to_s5k5baf(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(&state->lock);
fi->interval.numerator = state->fiv;
fi->interval.denominator = 10000;
@@ -1131,8 +1139,8 @@ static int s5k5baf_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static void s5k5baf_set_frame_interval(struct s5k5baf *state,
- struct v4l2_subdev_frame_interval *fi)
+static void __s5k5baf_set_frame_interval(struct s5k5baf *state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct v4l2_fract *i = &fi->interval;
@@ -1155,13 +1163,21 @@ static void s5k5baf_set_frame_interval(struct s5k5baf *state,
state->fiv);
}
-static int s5k5baf_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int s5k5baf_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct s5k5baf *state = to_s5k5baf(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(&state->lock);
- s5k5baf_set_frame_interval(state, fi);
+ __s5k5baf_set_frame_interval(state, fi);
mutex_unlock(&state->lock);
return 0;
}
@@ -1273,7 +1289,7 @@ static int s5k5baf_get_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *mf;
return 0;
}
@@ -1307,7 +1323,7 @@ static int s5k5baf_set_fmt(struct v4l2_subdev *sd,
mf->field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = *mf;
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) = *mf;
return 0;
}
@@ -1379,11 +1395,11 @@ static int s5k5baf_get_selection(struct v4l2_subdev *sd,
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
if (rtype == R_COMPOSE)
- sel->r = *v4l2_subdev_get_try_compose(sd, sd_state,
- sel->pad);
+ sel->r = *v4l2_subdev_state_get_compose(sd_state,
+ sel->pad);
else
- sel->r = *v4l2_subdev_get_try_crop(sd, sd_state,
- sel->pad);
+ sel->r = *v4l2_subdev_state_get_crop(sd_state,
+ sel->pad);
return 0;
}
@@ -1472,14 +1488,11 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd,
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
rects = (struct v4l2_rect * []) {
- &s5k5baf_cis_rect,
- v4l2_subdev_get_try_crop(sd, sd_state,
- PAD_CIS),
- v4l2_subdev_get_try_compose(sd, sd_state,
- PAD_CIS),
- v4l2_subdev_get_try_crop(sd, sd_state,
- PAD_OUT)
- };
+ &s5k5baf_cis_rect,
+ v4l2_subdev_state_get_crop(sd_state, PAD_CIS),
+ v4l2_subdev_state_get_compose(sd_state, PAD_CIS),
+ v4l2_subdev_state_get_crop(sd_state, PAD_OUT)
+ };
s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
return 0;
}
@@ -1529,11 +1542,11 @@ static const struct v4l2_subdev_pad_ops s5k5baf_pad_ops = {
.set_fmt = s5k5baf_set_fmt,
.get_selection = s5k5baf_get_selection,
.set_selection = s5k5baf_set_selection,
+ .get_frame_interval = s5k5baf_get_frame_interval,
+ .set_frame_interval = s5k5baf_set_frame_interval,
};
static const struct v4l2_subdev_video_ops s5k5baf_video_ops = {
- .g_frame_interval = s5k5baf_g_frame_interval,
- .s_frame_interval = s5k5baf_s_frame_interval,
.s_stream = s5k5baf_s_stream,
};
@@ -1696,22 +1709,22 @@ static int s5k5baf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, fh->state, PAD_CIS);
+ mf = v4l2_subdev_state_get_format(fh->state, PAD_CIS);
s5k5baf_try_cis_format(mf);
if (s5k5baf_is_cis_subdev(sd))
return 0;
- mf = v4l2_subdev_get_try_format(sd, fh->state, PAD_OUT);
+ mf = v4l2_subdev_state_get_format(fh->state, PAD_OUT);
mf->colorspace = s5k5baf_formats[0].colorspace;
mf->code = s5k5baf_formats[0].code;
mf->width = s5k5baf_cis_rect.width;
mf->height = s5k5baf_cis_rect.height;
mf->field = V4L2_FIELD_NONE;
- *v4l2_subdev_get_try_crop(sd, fh->state, PAD_CIS) = s5k5baf_cis_rect;
- *v4l2_subdev_get_try_compose(sd, fh->state, PAD_CIS) = s5k5baf_cis_rect;
- *v4l2_subdev_get_try_crop(sd, fh->state, PAD_OUT) = s5k5baf_cis_rect;
+ *v4l2_subdev_state_get_crop(fh->state, PAD_CIS) = s5k5baf_cis_rect;
+ *v4l2_subdev_state_get_compose(fh->state, PAD_CIS) = s5k5baf_cis_rect;
+ *v4l2_subdev_state_get_crop(fh->state, PAD_OUT) = s5k5baf_cis_rect;
return 0;
}
diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c
index b3560c8f8b41..0c2674115b7b 100644
--- a/drivers/media/i2c/s5k6a3.c
+++ b/drivers/media/i2c/s5k6a3.c
@@ -127,8 +127,7 @@ static struct v4l2_mbus_framefmt *__s5k6a3_get_format(
u32 pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return sd_state ? v4l2_subdev_get_try_format(&sensor->subdev,
- sd_state, pad) : NULL;
+ return sd_state ? v4l2_subdev_state_get_format(sd_state, pad) : NULL;
return &sensor->format;
}
@@ -174,9 +173,8 @@ static const struct v4l2_subdev_pad_ops s5k6a3_pad_ops = {
static int s5k6a3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd,
- fh->state,
- 0);
+ struct v4l2_mbus_framefmt *format = v4l2_subdev_state_get_format(fh->state,
+ 0);
*format = s5k6a3_formats[0];
format->width = S5K6A3_DEFAULT_WIDTH;
diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c
index c106e7a7d1f4..897eaa669b86 100644
--- a/drivers/media/i2c/saa6752hs.c
+++ b/drivers/media/i2c/saa6752hs.c
@@ -594,10 +594,8 @@ static int saa6752hs_set_fmt(struct v4l2_subdev *sd,
f->field = V4L2_FIELD_INTERLACED;
f->colorspace = V4L2_COLORSPACE_SMPTE170M;
- if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sd_state->pads->try_fmt = *f;
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
- }
/*
FIXME: translate and round width/height into EMPRESS
diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c
index fa27638edc07..f250640729ca 100644
--- a/drivers/media/i2c/st-mipid02.c
+++ b/drivers/media/i2c/st-mipid02.c
@@ -16,25 +16,27 @@
#include <linux/module.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
+#include <media/mipi-csi2.h>
#include <media/v4l2-async.h>
+#include <media/v4l2-cci.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
-#define MIPID02_CLK_LANE_WR_REG1 0x01
-#define MIPID02_CLK_LANE_REG1 0x02
-#define MIPID02_CLK_LANE_REG3 0x04
-#define MIPID02_DATA_LANE0_REG1 0x05
-#define MIPID02_DATA_LANE0_REG2 0x06
-#define MIPID02_DATA_LANE1_REG1 0x09
-#define MIPID02_DATA_LANE1_REG2 0x0a
-#define MIPID02_MODE_REG1 0x14
-#define MIPID02_MODE_REG2 0x15
-#define MIPID02_DATA_ID_RREG 0x17
-#define MIPID02_DATA_SELECTION_CTRL 0x19
-#define MIPID02_PIX_WIDTH_CTRL 0x1e
-#define MIPID02_PIX_WIDTH_CTRL_EMB 0x1f
+#define MIPID02_CLK_LANE_WR_REG1 CCI_REG8(0x01)
+#define MIPID02_CLK_LANE_REG1 CCI_REG8(0x02)
+#define MIPID02_CLK_LANE_REG3 CCI_REG8(0x04)
+#define MIPID02_DATA_LANE0_REG1 CCI_REG8(0x05)
+#define MIPID02_DATA_LANE0_REG2 CCI_REG8(0x06)
+#define MIPID02_DATA_LANE1_REG1 CCI_REG8(0x09)
+#define MIPID02_DATA_LANE1_REG2 CCI_REG8(0x0a)
+#define MIPID02_MODE_REG1 CCI_REG8(0x14)
+#define MIPID02_MODE_REG2 CCI_REG8(0x15)
+#define MIPID02_DATA_ID_RREG CCI_REG8(0x17)
+#define MIPID02_DATA_SELECTION_CTRL CCI_REG8(0x19)
+#define MIPID02_PIX_WIDTH_CTRL CCI_REG8(0x1e)
+#define MIPID02_PIX_WIDTH_CTRL_EMB CCI_REG8(0x1f)
/* Bits definition for MIPID02_CLK_LANE_REG1 */
#define CLK_ENABLE BIT(0)
@@ -68,7 +70,7 @@ static const u32 mipid02_supported_fmt_codes[] = {
MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE,
MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YVYU8_2X8,
MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8,
- MEDIA_BUS_FMT_JPEG_1X8
+ MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_JPEG_1X8
};
/* regulator supplies */
@@ -88,12 +90,12 @@ struct mipid02_dev {
struct i2c_client *i2c_client;
struct regulator_bulk_data supplies[MIPID02_NUM_SUPPLIES];
struct v4l2_subdev sd;
+ struct regmap *regmap;
struct media_pad pad[MIPID02_PAD_NB];
struct clk *xclk;
struct gpio_desc *reset_gpio;
/* endpoints info */
struct v4l2_fwnode_endpoint rx;
- u64 link_frequency;
struct v4l2_fwnode_endpoint tx;
/* remote source */
struct v4l2_async_notifier notifier;
@@ -110,10 +112,6 @@ struct mipid02_dev {
u8 pix_width_ctrl;
u8 pix_width_ctrl_emb;
} r;
- /* lock to protect all members below */
- struct mutex lock;
- bool streaming;
- struct v4l2_mbus_framefmt fmt;
};
static int bpp_from_code(__u32 code)
@@ -123,6 +121,7 @@ static int bpp_from_code(__u32 code)
case MEDIA_BUS_FMT_SGBRG8_1X8:
case MEDIA_BUS_FMT_SGRBG8_1X8:
case MEDIA_BUS_FMT_SRGGB8_1X8:
+ case MEDIA_BUS_FMT_Y8_1X8:
return 8;
case MEDIA_BUS_FMT_SBGGR10_1X10:
case MEDIA_BUS_FMT_SGBRG10_1X10:
@@ -160,17 +159,18 @@ static u8 data_type_from_code(__u32 code)
case MEDIA_BUS_FMT_SGBRG8_1X8:
case MEDIA_BUS_FMT_SGRBG8_1X8:
case MEDIA_BUS_FMT_SRGGB8_1X8:
- return 0x2a;
+ case MEDIA_BUS_FMT_Y8_1X8:
+ return MIPI_CSI2_DT_RAW8;
case MEDIA_BUS_FMT_SBGGR10_1X10:
case MEDIA_BUS_FMT_SGBRG10_1X10:
case MEDIA_BUS_FMT_SGRBG10_1X10:
case MEDIA_BUS_FMT_SRGGB10_1X10:
- return 0x2b;
+ return MIPI_CSI2_DT_RAW10;
case MEDIA_BUS_FMT_SBGGR12_1X12:
case MEDIA_BUS_FMT_SGBRG12_1X12:
case MEDIA_BUS_FMT_SGRBG12_1X12:
case MEDIA_BUS_FMT_SRGGB12_1X12:
- return 0x2c;
+ return MIPI_CSI2_DT_RAW12;
case MEDIA_BUS_FMT_YUYV8_1X16:
case MEDIA_BUS_FMT_YVYU8_1X16:
case MEDIA_BUS_FMT_UYVY8_1X16:
@@ -179,30 +179,18 @@ static u8 data_type_from_code(__u32 code)
case MEDIA_BUS_FMT_YVYU8_2X8:
case MEDIA_BUS_FMT_UYVY8_2X8:
case MEDIA_BUS_FMT_VYUY8_2X8:
- return 0x1e;
+ return MIPI_CSI2_DT_YUV422_8B;
case MEDIA_BUS_FMT_BGR888_1X24:
- return 0x24;
+ return MIPI_CSI2_DT_RGB888;
case MEDIA_BUS_FMT_RGB565_1X16:
case MEDIA_BUS_FMT_RGB565_2X8_LE:
case MEDIA_BUS_FMT_RGB565_2X8_BE:
- return 0x22;
+ return MIPI_CSI2_DT_RGB565;
default:
return 0;
}
}
-static void init_format(struct v4l2_mbus_framefmt *fmt)
-{
- fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8;
- fmt->field = V4L2_FIELD_NONE;
- fmt->colorspace = V4L2_COLORSPACE_SRGB;
- fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB);
- fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
- fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB);
- fmt->width = 640;
- fmt->height = 480;
-}
-
static __u32 get_fmt_code(__u32 code)
{
unsigned int i;
@@ -238,62 +226,6 @@ static inline struct mipid02_dev *to_mipid02_dev(struct v4l2_subdev *sd)
return container_of(sd, struct mipid02_dev, sd);
}
-static int mipid02_read_reg(struct mipid02_dev *bridge, u16 reg, u8 *val)
-{
- struct i2c_client *client = bridge->i2c_client;
- struct i2c_msg msg[2];
- u8 buf[2];
- int ret;
-
- buf[0] = reg >> 8;
- buf[1] = reg & 0xff;
-
- msg[0].addr = client->addr;
- msg[0].flags = client->flags;
- msg[0].buf = buf;
- msg[0].len = sizeof(buf);
-
- msg[1].addr = client->addr;
- msg[1].flags = client->flags | I2C_M_RD;
- msg[1].buf = val;
- msg[1].len = 1;
-
- ret = i2c_transfer(client->adapter, msg, 2);
- if (ret < 0) {
- dev_dbg(&client->dev, "%s: %x i2c_transfer, reg: %x => %d\n",
- __func__, client->addr, reg, ret);
- return ret;
- }
-
- return 0;
-}
-
-static int mipid02_write_reg(struct mipid02_dev *bridge, u16 reg, u8 val)
-{
- struct i2c_client *client = bridge->i2c_client;
- struct i2c_msg msg;
- u8 buf[3];
- int ret;
-
- buf[0] = reg >> 8;
- buf[1] = reg & 0xff;
- buf[2] = val;
-
- msg.addr = client->addr;
- msg.flags = client->flags;
- msg.buf = buf;
- msg.len = sizeof(buf);
-
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (ret < 0) {
- dev_dbg(&client->dev, "%s: i2c_transfer, reg: %x => %d\n",
- __func__, reg, ret);
- return ret;
- }
-
- return 0;
-}
-
static int mipid02_get_regulators(struct mipid02_dev *bridge)
{
unsigned int i;
@@ -358,73 +290,44 @@ static void mipid02_set_power_off(struct mipid02_dev *bridge)
static int mipid02_detect(struct mipid02_dev *bridge)
{
- u8 reg;
+ u64 reg;
/*
* There is no version registers. Just try to read register
* MIPID02_CLK_LANE_WR_REG1.
*/
- return mipid02_read_reg(bridge, MIPID02_CLK_LANE_WR_REG1, &reg);
-}
-
-static u32 mipid02_get_link_freq_from_cid_link_freq(struct mipid02_dev *bridge,
- struct v4l2_subdev *subdev)
-{
- struct v4l2_querymenu qm = {.id = V4L2_CID_LINK_FREQ, };
- struct v4l2_ctrl *ctrl;
- int ret;
-
- ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_LINK_FREQ);
- if (!ctrl)
- return 0;
- qm.index = v4l2_ctrl_g_ctrl(ctrl);
-
- ret = v4l2_querymenu(subdev->ctrl_handler, &qm);
- if (ret)
- return 0;
-
- return qm.value;
-}
-
-static u32 mipid02_get_link_freq_from_cid_pixel_rate(struct mipid02_dev *bridge,
- struct v4l2_subdev *subdev)
-{
- struct v4l2_fwnode_endpoint *ep = &bridge->rx;
- struct v4l2_ctrl *ctrl;
- u32 pixel_clock;
- u32 bpp = bpp_from_code(bridge->fmt.code);
-
- ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE);
- if (!ctrl)
- return 0;
- pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl);
-
- return pixel_clock * bpp / (2 * ep->bus.mipi_csi2.num_data_lanes);
+ return cci_read(bridge->regmap, MIPID02_CLK_LANE_WR_REG1, &reg, NULL);
}
/*
* We need to know link frequency to setup clk_lane_reg1 timings. Link frequency
- * will be computed using connected device V4L2_CID_PIXEL_RATE, bit per pixel
+ * will be retrieve from connected device via v4l2_get_link_freq, bit per pixel
* and number of lanes.
*/
-static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge)
+static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge,
+ struct v4l2_mbus_framefmt *fmt)
{
struct i2c_client *client = bridge->i2c_client;
struct v4l2_subdev *subdev = bridge->s_subdev;
- u32 link_freq;
-
- link_freq = mipid02_get_link_freq_from_cid_link_freq(bridge, subdev);
- if (!link_freq) {
- link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge,
- subdev);
- if (!link_freq) {
- dev_err(&client->dev, "Failed to get link frequency");
- return -EINVAL;
- }
+ struct v4l2_fwnode_endpoint *ep = &bridge->rx;
+ u32 bpp = bpp_from_code(fmt->code);
+ /*
+ * clk_lane_reg1 requires 4 times the unit interval time, and bitrate
+ * is twice the link frequency, hence ui_4 = 1000000000 * 4 / 2
+ */
+ u64 ui_4 = 2000000000;
+ s64 link_freq;
+
+ link_freq = v4l2_get_link_freq(subdev->ctrl_handler, bpp,
+ 2 * ep->bus.mipi_csi2.num_data_lanes);
+ if (link_freq < 0) {
+ dev_err(&client->dev, "Failed to get link frequency");
+ return -EINVAL;
}
- dev_dbg(&client->dev, "detect link_freq = %d Hz", link_freq);
- bridge->r.clk_lane_reg1 |= (2000000000 / link_freq) << 2;
+ dev_dbg(&client->dev, "detect link_freq = %lld Hz", link_freq);
+ do_div(ui_4, link_freq);
+ bridge->r.clk_lane_reg1 |= ui_4 << 2;
return 0;
}
@@ -479,7 +382,8 @@ static int mipid02_configure_data1_lane(struct mipid02_dev *bridge, int nb,
return 0;
}
-static int mipid02_configure_from_rx(struct mipid02_dev *bridge)
+static int mipid02_configure_from_rx(struct mipid02_dev *bridge,
+ struct v4l2_mbus_framefmt *fmt)
{
struct v4l2_fwnode_endpoint *ep = &bridge->rx;
bool are_lanes_swap = ep->bus.mipi_csi2.data_lanes[0] == 2;
@@ -504,7 +408,7 @@ static int mipid02_configure_from_rx(struct mipid02_dev *bridge)
bridge->r.mode_reg1 |= are_lanes_swap ? MODE_DATA_SWAP : 0;
bridge->r.mode_reg1 |= (nb - 1) << 1;
- return mipid02_configure_from_rx_speed(bridge);
+ return mipid02_configure_from_rx_speed(bridge, fmt);
}
static int mipid02_configure_from_tx(struct mipid02_dev *bridge)
@@ -524,16 +428,17 @@ static int mipid02_configure_from_tx(struct mipid02_dev *bridge)
return 0;
}
-static int mipid02_configure_from_code(struct mipid02_dev *bridge)
+static int mipid02_configure_from_code(struct mipid02_dev *bridge,
+ struct v4l2_mbus_framefmt *fmt)
{
u8 data_type;
bridge->r.data_id_rreg = 0;
- if (bridge->fmt.code != MEDIA_BUS_FMT_JPEG_1X8) {
+ if (fmt->code != MEDIA_BUS_FMT_JPEG_1X8) {
bridge->r.data_selection_ctrl |= SELECTION_MANUAL_DATA;
- data_type = data_type_from_code(bridge->fmt.code);
+ data_type = data_type_from_code(fmt->code);
if (!data_type)
return -EINVAL;
bridge->r.data_id_rreg = data_type;
@@ -555,13 +460,9 @@ static int mipid02_stream_disable(struct mipid02_dev *bridge)
goto error;
/* Disable all lanes */
- ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, 0);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, 0);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, 0);
+ cci_write(bridge->regmap, MIPID02_CLK_LANE_REG1, 0, &ret);
+ cci_write(bridge->regmap, MIPID02_DATA_LANE0_REG1, 0, &ret);
+ cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG1, 0, &ret);
if (ret)
goto error;
error:
@@ -574,69 +475,52 @@ error:
static int mipid02_stream_enable(struct mipid02_dev *bridge)
{
struct i2c_client *client = bridge->i2c_client;
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_framefmt *fmt;
int ret = -EINVAL;
if (!bridge->s_subdev)
goto error;
memset(&bridge->r, 0, sizeof(bridge->r));
+
+ state = v4l2_subdev_lock_and_get_active_state(&bridge->sd);
+ fmt = v4l2_subdev_state_get_format(state, MIPID02_SINK_0);
+
/* build registers content */
- ret = mipid02_configure_from_rx(bridge);
+ ret = mipid02_configure_from_rx(bridge, fmt);
if (ret)
goto error;
ret = mipid02_configure_from_tx(bridge);
if (ret)
goto error;
- ret = mipid02_configure_from_code(bridge);
+ ret = mipid02_configure_from_code(bridge, fmt);
if (ret)
goto error;
+ v4l2_subdev_unlock_state(state);
+
/* write mipi registers */
- ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1,
- bridge->r.clk_lane_reg1);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG3, CLK_MIPI_CSI);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1,
- bridge->r.data_lane0_reg1);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG2,
- DATA_MIPI_CSI);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1,
- bridge->r.data_lane1_reg1);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG2,
- DATA_MIPI_CSI);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_MODE_REG1,
- MODE_NO_BYPASS | bridge->r.mode_reg1);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_MODE_REG2,
- bridge->r.mode_reg2);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_DATA_ID_RREG,
- bridge->r.data_id_rreg);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_DATA_SELECTION_CTRL,
- bridge->r.data_selection_ctrl);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL,
- bridge->r.pix_width_ctrl);
- if (ret)
- goto error;
- ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL_EMB,
- bridge->r.pix_width_ctrl_emb);
+ cci_write(bridge->regmap, MIPID02_CLK_LANE_REG1,
+ bridge->r.clk_lane_reg1, &ret);
+ cci_write(bridge->regmap, MIPID02_CLK_LANE_REG3, CLK_MIPI_CSI, &ret);
+ cci_write(bridge->regmap, MIPID02_DATA_LANE0_REG1,
+ bridge->r.data_lane0_reg1, &ret);
+ cci_write(bridge->regmap, MIPID02_DATA_LANE0_REG2, DATA_MIPI_CSI, &ret);
+ cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG1,
+ bridge->r.data_lane1_reg1, &ret);
+ cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG2, DATA_MIPI_CSI, &ret);
+ cci_write(bridge->regmap, MIPID02_MODE_REG1,
+ MODE_NO_BYPASS | bridge->r.mode_reg1, &ret);
+ cci_write(bridge->regmap, MIPID02_MODE_REG2, bridge->r.mode_reg2, &ret);
+ cci_write(bridge->regmap, MIPID02_DATA_ID_RREG, bridge->r.data_id_rreg,
+ &ret);
+ cci_write(bridge->regmap, MIPID02_DATA_SELECTION_CTRL,
+ bridge->r.data_selection_ctrl, &ret);
+ cci_write(bridge->regmap, MIPID02_PIX_WIDTH_CTRL,
+ bridge->r.pix_width_ctrl, &ret);
+ cci_write(bridge->regmap, MIPID02_PIX_WIDTH_CTRL_EMB,
+ bridge->r.pix_width_ctrl_emb, &ret);
if (ret)
goto error;
@@ -659,31 +543,43 @@ static int mipid02_s_stream(struct v4l2_subdev *sd, int enable)
struct i2c_client *client = bridge->i2c_client;
int ret = 0;
- dev_dbg(&client->dev, "%s : requested %d / current = %d", __func__,
- enable, bridge->streaming);
- mutex_lock(&bridge->lock);
-
- if (bridge->streaming == enable)
- goto out;
+ dev_dbg(&client->dev, "%s : requested %d\n", __func__, enable);
ret = enable ? mipid02_stream_enable(bridge) :
mipid02_stream_disable(bridge);
- if (!ret)
- bridge->streaming = enable;
-
-out:
- dev_dbg(&client->dev, "%s current now = %d / %d", __func__,
- bridge->streaming, ret);
- mutex_unlock(&bridge->lock);
+ if (ret)
+ dev_err(&client->dev, "failed to stream %s (%d)\n",
+ enable ? "enable" : "disable", ret);
return ret;
}
+static const struct v4l2_mbus_framefmt default_fmt = {
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+ .quantization = V4L2_QUANTIZATION_FULL_RANGE,
+ .xfer_func = V4L2_XFER_FUNC_DEFAULT,
+ .width = 640,
+ .height = 480,
+};
+
+static int mipid02_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ *v4l2_subdev_state_get_format(state, MIPID02_SINK_0) = default_fmt;
+ /* MIPID02_SINK_1 isn't supported yet */
+ *v4l2_subdev_state_get_format(state, MIPID02_SOURCE) = default_fmt;
+
+ return 0;
+}
+
static int mipid02_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- struct mipid02_dev *bridge = to_mipid02_dev(sd);
+ struct v4l2_mbus_framefmt *sink_fmt;
int ret = 0;
switch (code->pad) {
@@ -694,10 +590,13 @@ static int mipid02_enum_mbus_code(struct v4l2_subdev *sd,
code->code = mipid02_supported_fmt_codes[code->index];
break;
case MIPID02_SOURCE:
- if (code->index == 0)
- code->code = serial_to_parallel_code(bridge->fmt.code);
- else
+ if (code->index == 0) {
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ MIPID02_SINK_0);
+ code->code = serial_to_parallel_code(sink_fmt->code);
+ } else {
ret = -EINVAL;
+ }
break;
default:
ret = -EINVAL;
@@ -706,117 +605,38 @@ static int mipid02_enum_mbus_code(struct v4l2_subdev *sd,
return ret;
}
-static int mipid02_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
- struct mipid02_dev *bridge = to_mipid02_dev(sd);
- struct i2c_client *client = bridge->i2c_client;
- struct v4l2_mbus_framefmt *fmt;
-
- dev_dbg(&client->dev, "%s probe %d", __func__, format->pad);
-
- if (format->pad >= MIPID02_PAD_NB)
- return -EINVAL;
- /* second CSI-2 pad not yet supported */
- if (format->pad == MIPID02_SINK_1)
- return -EINVAL;
-
- if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt = v4l2_subdev_get_try_format(&bridge->sd, sd_state,
- format->pad);
- else
- fmt = &bridge->fmt;
-
- mutex_lock(&bridge->lock);
-
- *mbus_fmt = *fmt;
- /* code may need to be converted for source */
- if (format->pad == MIPID02_SOURCE)
- mbus_fmt->code = serial_to_parallel_code(mbus_fmt->code);
-
- mutex_unlock(&bridge->lock);
-
- return 0;
-}
-
-static void mipid02_set_fmt_source(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct mipid02_dev *bridge = to_mipid02_dev(sd);
-
- /* source pad mirror sink pad */
- if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- format->format = bridge->fmt;
- else
- format->format = *v4l2_subdev_get_try_format(sd, sd_state,
- MIPID02_SINK_0);
-
- /* but code may need to be converted */
- format->format.code = serial_to_parallel_code(format->format.code);
-
- /* only apply format for V4L2_SUBDEV_FORMAT_TRY case */
- if (format->which != V4L2_SUBDEV_FORMAT_TRY)
- return;
-
- *v4l2_subdev_get_try_format(sd, sd_state, MIPID02_SOURCE) =
- format->format;
-}
-
-static void mipid02_set_fmt_sink(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct mipid02_dev *bridge = to_mipid02_dev(sd);
- struct v4l2_mbus_framefmt *fmt;
-
- format->format.code = get_fmt_code(format->format.code);
-
- if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
- else
- fmt = &bridge->fmt;
-
- *fmt = format->format;
-
- /* Propagate the format change to the source pad */
- mipid02_set_fmt_source(sd, sd_state, format);
-}
-
static int mipid02_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
+ struct v4l2_subdev_format *fmt)
{
struct mipid02_dev *bridge = to_mipid02_dev(sd);
struct i2c_client *client = bridge->i2c_client;
- int ret = 0;
+ struct v4l2_mbus_framefmt *pad_fmt;
- dev_dbg(&client->dev, "%s for %d", __func__, format->pad);
+ dev_dbg(&client->dev, "%s for %d", __func__, fmt->pad);
- if (format->pad >= MIPID02_PAD_NB)
- return -EINVAL;
/* second CSI-2 pad not yet supported */
- if (format->pad == MIPID02_SINK_1)
+ if (fmt->pad == MIPID02_SINK_1)
return -EINVAL;
- mutex_lock(&bridge->lock);
+ pad_fmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
+ fmt->format.code = get_fmt_code(fmt->format.code);
- if (bridge->streaming) {
- ret = -EBUSY;
- goto error;
- }
+ /* code may need to be converted */
+ if (fmt->pad == MIPID02_SOURCE)
+ fmt->format.code = serial_to_parallel_code(fmt->format.code);
- if (format->pad == MIPID02_SOURCE)
- mipid02_set_fmt_source(sd, sd_state, format);
- else
- mipid02_set_fmt_sink(sd, sd_state, format);
+ *pad_fmt = fmt->format;
-error:
- mutex_unlock(&bridge->lock);
+ /* Propagate the format to the source pad in case of sink pad update */
+ if (fmt->pad == MIPID02_SINK_0) {
+ pad_fmt = v4l2_subdev_state_get_format(sd_state,
+ MIPID02_SOURCE);
+ *pad_fmt = fmt->format;
+ pad_fmt->code = serial_to_parallel_code(fmt->format.code);
+ }
- return ret;
+ return 0;
}
static const struct v4l2_subdev_video_ops mipid02_video_ops = {
@@ -825,7 +645,7 @@ static const struct v4l2_subdev_video_ops mipid02_video_ops = {
static const struct v4l2_subdev_pad_ops mipid02_pad_ops = {
.enum_mbus_code = mipid02_enum_mbus_code,
- .get_fmt = mipid02_get_fmt,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = mipid02_set_fmt,
};
@@ -834,6 +654,10 @@ static const struct v4l2_subdev_ops mipid02_subdev_ops = {
.pad = &mipid02_pad_ops,
};
+static const struct v4l2_subdev_internal_ops mipid02_subdev_internal_ops = {
+ .init_state = mipid02_init_state,
+};
+
static const struct media_entity_operations mipid02_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -993,8 +817,6 @@ static int mipid02_probe(struct i2c_client *client)
if (!bridge)
return -ENOMEM;
- init_format(&bridge->fmt);
-
bridge->i2c_client = client;
v4l2_i2c_subdev_init(&bridge->sd, client, &mipid02_subdev_ops);
@@ -1026,9 +848,15 @@ static int mipid02_probe(struct i2c_client *client)
return ret;
}
- mutex_init(&bridge->lock);
+ /* Initialise the regmap for further cci access */
+ bridge->regmap = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(bridge->regmap))
+ return dev_err_probe(dev, PTR_ERR(bridge->regmap),
+ "failed to get cci regmap\n");
+
bridge->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
bridge->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ bridge->sd.internal_ops = &mipid02_subdev_internal_ops;
bridge->sd.entity.ops = &mipid02_subdev_entity_ops;
bridge->pad[0].flags = MEDIA_PAD_FL_SINK;
bridge->pad[1].flags = MEDIA_PAD_FL_SINK;
@@ -1037,7 +865,13 @@ static int mipid02_probe(struct i2c_client *client)
bridge->pad);
if (ret) {
dev_err(&client->dev, "pads init failed %d", ret);
- goto mutex_cleanup;
+ return ret;
+ }
+
+ ret = v4l2_subdev_init_finalize(&bridge->sd);
+ if (ret < 0) {
+ dev_err(dev, "subdev init error: %d\n", ret);
+ goto entity_cleanup;
}
/* enable clock, power and reset device if available */
@@ -1081,8 +915,6 @@ power_off:
mipid02_set_power_off(bridge);
entity_cleanup:
media_entity_cleanup(&bridge->sd.entity);
-mutex_cleanup:
- mutex_destroy(&bridge->lock);
return ret;
}
@@ -1097,7 +929,6 @@ static void mipid02_remove(struct i2c_client *client)
v4l2_async_unregister_subdev(&bridge->sd);
mipid02_set_power_off(bridge);
media_entity_cleanup(&bridge->sd.entity);
- mutex_destroy(&bridge->lock);
}
static const struct of_device_id mipid02_dt_ids[] = {
diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/st-vgxy61.c
index 5dbfb04b3124..e4d37a197724 100644
--- a/drivers/media/i2c/st-vgxy61.c
+++ b/drivers/media/i2c/st-vgxy61.c
@@ -21,6 +21,7 @@
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
@@ -780,8 +781,7 @@ static int vgxy61_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&sensor->lock);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
- format->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
else
fmt = &sensor->fmt;
@@ -1289,7 +1289,7 @@ static int vgxy61_set_fmt(struct v4l2_subdev *sd,
goto out;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ fmt = v4l2_subdev_state_get_format(sd_state, 0);
*fmt = format->format;
} else if (sensor->current_mode != new_mode ||
sensor->fmt.code != format->format.code) {
@@ -1323,8 +1323,8 @@ out:
return ret;
}
-static int vgxy61_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int vgxy61_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct vgxy61_dev *sensor = to_vgxy61_dev(sd);
struct v4l2_subdev_format fmt = { 0 };
@@ -1403,6 +1403,7 @@ static int vgxy61_init_controls(struct vgxy61_dev *sensor)
const struct v4l2_ctrl_ops *ops = &vgxy61_ctrl_ops;
struct v4l2_ctrl_handler *hdl = &sensor->ctrl_handler;
const struct vgxy61_mode_info *cur_mode = sensor->current_mode;
+ struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl *ctrl;
int ret;
@@ -1457,6 +1458,14 @@ static int vgxy61_init_controls(struct vgxy61_dev *sensor)
goto free_ctrls;
}
+ ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &props);
+ if (ret)
+ goto free_ctrls;
+
+ ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props);
+ if (ret)
+ goto free_ctrls;
+
sensor->sd.ctrl_handler = hdl;
return 0;
@@ -1465,12 +1474,16 @@ free_ctrls:
return ret;
}
+static const struct v4l2_subdev_core_ops vgxy61_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
static const struct v4l2_subdev_video_ops vgxy61_video_ops = {
.s_stream = vgxy61_s_stream,
};
static const struct v4l2_subdev_pad_ops vgxy61_pad_ops = {
- .init_cfg = vgxy61_init_cfg,
.enum_mbus_code = vgxy61_enum_mbus_code,
.get_fmt = vgxy61_get_fmt,
.set_fmt = vgxy61_set_fmt,
@@ -1479,10 +1492,15 @@ static const struct v4l2_subdev_pad_ops vgxy61_pad_ops = {
};
static const struct v4l2_subdev_ops vgxy61_subdev_ops = {
+ .core = &vgxy61_core_ops,
.video = &vgxy61_video_ops,
.pad = &vgxy61_pad_ops,
};
+static const struct v4l2_subdev_internal_ops vgxy61_internal_ops = {
+ .init_state = vgxy61_init_state,
+};
+
static const struct media_entity_operations vgxy61_subdev_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -1843,7 +1861,9 @@ static int vgxy61_probe(struct i2c_client *client)
device_property_read_bool(dev, "st,strobe-gpios-polarity");
v4l2_i2c_subdev_init(&sensor->sd, client, &vgxy61_subdev_ops);
- sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sensor->sd.internal_ops = &vgxy61_internal_ops;
+ sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
sensor->sd.entity.ops = &vgxy61_subdev_entity_ops;
sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c
index ce612a47ba84..106de4271d2e 100644
--- a/drivers/media/i2c/tc358746.c
+++ b/drivers/media/i2c/tc358746.c
@@ -427,7 +427,7 @@ static int tc358746_apply_misc_config(struct tc358746 *tc358746)
sink_state = v4l2_subdev_lock_and_get_active_state(sd);
- mbusfmt = v4l2_subdev_get_pad_format(sd, sink_state, TC358746_SINK);
+ mbusfmt = v4l2_subdev_state_get_format(sink_state, TC358746_SINK);
fmt = tc358746_get_format_by_code(TC358746_SINK, mbusfmt->code);
/* Self defined CSI user data type id's are not supported yet */
@@ -740,15 +740,15 @@ err_out:
return v4l2_subdev_call(src, video, s_stream, 0);
}
-static int tc358746_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int tc358746_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_pad_format(sd, state, TC358746_SINK);
+ fmt = v4l2_subdev_state_get_format(state, TC358746_SINK);
*fmt = tc358746_def_fmt;
- fmt = v4l2_subdev_get_pad_format(sd, state, TC358746_SOURCE);
+ fmt = v4l2_subdev_state_get_format(state, TC358746_SOURCE);
*fmt = tc358746_def_fmt;
fmt->code = tc358746_src_mbus_code(tc358746_def_fmt.code);
@@ -781,7 +781,7 @@ static int tc358746_set_fmt(struct v4l2_subdev *sd,
if (format->pad == TC358746_SOURCE)
return v4l2_subdev_get_fmt(sd, sd_state, format);
- sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, TC358746_SINK);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, TC358746_SINK);
fmt = tc358746_get_format_by_code(format->pad, format->format.code);
if (IS_ERR(fmt)) {
@@ -800,7 +800,7 @@ static int tc358746_set_fmt(struct v4l2_subdev *sd,
*sink_fmt = format->format;
- src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, TC358746_SOURCE);
+ src_fmt = v4l2_subdev_state_get_format(sd_state, TC358746_SOURCE);
*src_fmt = *sink_fmt;
src_fmt->code = tc358746_src_mbus_code(sink_fmt->code);
@@ -905,7 +905,7 @@ tc358746_link_validate(struct v4l2_subdev *sd, struct media_link *link,
return err;
sink_state = v4l2_subdev_lock_and_get_active_state(sd);
- mbusfmt = v4l2_subdev_get_pad_format(sd, sink_state, TC358746_SINK);
+ mbusfmt = v4l2_subdev_state_get_format(sink_state, TC358746_SINK);
/* Check the FIFO settings */
fmt = tc358746_get_format_by_code(TC358746_SINK, mbusfmt->code);
@@ -1038,7 +1038,6 @@ static const struct v4l2_subdev_video_ops tc358746_video_ops = {
};
static const struct v4l2_subdev_pad_ops tc358746_pad_ops = {
- .init_cfg = tc358746_init_cfg,
.enum_mbus_code = tc358746_enum_mbus_code,
.set_fmt = tc358746_set_fmt,
.get_fmt = v4l2_subdev_get_fmt,
@@ -1052,6 +1051,10 @@ static const struct v4l2_subdev_ops tc358746_ops = {
.pad = &tc358746_pad_ops,
};
+static const struct v4l2_subdev_internal_ops tc358746_internal_ops = {
+ .init_state = tc358746_init_state,
+};
+
static const struct media_entity_operations tc358746_entity_ops = {
.get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
.link_validate = v4l2_subdev_link_validate,
@@ -1282,6 +1285,7 @@ tc358746_init_subdev(struct tc358746 *tc358746, struct i2c_client *client)
int err;
v4l2_i2c_subdev_init(sd, client, &tc358746_ops);
+ sd->internal_ops = &tc358746_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
sd->entity.ops = &tc358746_entity_ops;
diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
index 325e99125941..1ea703a9909f 100644
--- a/drivers/media/i2c/tda1997x.c
+++ b/drivers/media/i2c/tda1997x.c
@@ -1734,13 +1734,13 @@ static const struct v4l2_subdev_video_ops tda1997x_video_ops = {
* v4l2_subdev_pad_ops
*/
-static int tda1997x_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int tda1997x_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct tda1997x_state *state = to_state(sd);
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ mf = v4l2_subdev_state_get_format(sd_state, 0);
mf->code = state->mbus_codes[0];
return 0;
@@ -1792,7 +1792,7 @@ static int tda1997x_get_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
format->format.code = fmt->code;
} else
format->format.code = state->mbus_code;
@@ -1826,7 +1826,7 @@ static int tda1997x_set_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
*fmt = format->format;
} else {
int ret = tda1997x_setup_format(state, format->format.code);
@@ -1925,7 +1925,6 @@ static int tda1997x_enum_dv_timings(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_pad_ops tda1997x_pad_ops = {
- .init_cfg = tda1997x_init_cfg,
.enum_mbus_code = tda1997x_enum_mbus_code,
.get_fmt = tda1997x_get_format,
.set_fmt = tda1997x_set_format,
@@ -2047,6 +2046,10 @@ static const struct v4l2_subdev_ops tda1997x_subdev_ops = {
.pad = &tda1997x_pad_ops,
};
+static const struct v4l2_subdev_internal_ops tda1997x_internal_ops = {
+ .init_state = tda1997x_init_state,
+};
+
/* -----------------------------------------------------------------------------
* v4l2_controls
*/
@@ -2588,6 +2591,7 @@ static int tda1997x_probe(struct i2c_client *client)
/* initialize subdev */
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &tda1997x_subdev_ops);
+ sd->internal_ops = &tda1997x_internal_ops;
snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
id->name, i2c_adapter_id(client->adapter),
client->addr);
diff --git a/drivers/media/i2c/thp7312.c b/drivers/media/i2c/thp7312.c
new file mode 100644
index 000000000000..2806887514dc
--- /dev/null
+++ b/drivers/media/i2c/thp7312.c
@@ -0,0 +1,2256 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021 THine Electronics, Inc.
+ * Copyright (C) 2023 Ideas on Board Oy
+ */
+
+#include <asm/unaligned.h>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/spi-nor.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#include <uapi/linux/thp7312.h>
+
+/* ISP registers */
+
+#define THP7312_REG_FIRMWARE_VERSION_1 CCI_REG8(0xf000)
+#define THP7312_REG_CAMERA_STATUS CCI_REG8(0xf001)
+#define THP7312_REG_FIRMWARE_VERSION_2 CCI_REG8(0xf005)
+#define THP7312_REG_SET_OUTPUT_ENABLE CCI_REG8(0xf008)
+#define THP7312_OUTPUT_ENABLE 0x01
+#define THP7312_OUTPUT_DISABLE 0x00
+#define THP7312_REG_SET_OUTPUT_COLOR_COMPRESSION CCI_REG8(0xf009)
+#define THP7312_REG_SET_OUTPUT_COLOR_UYVY 0x00
+#define THP7312_REG_SET_OUTPUT_COLOR_YUY2 0x04
+#define THP7312_REG_FLIP_MIRROR CCI_REG8(0xf00c)
+#define THP7312_REG_FLIP_MIRROR_FLIP BIT(0)
+#define THP7312_REG_FLIP_MIRROR_MIRROR BIT(1)
+#define THP7312_REG_VIDEO_IMAGE_SIZE CCI_REG8(0xf00d)
+#define THP7312_VIDEO_IMAGE_SIZE_640x360 0x52
+#define THP7312_VIDEO_IMAGE_SIZE_640x460 0x03
+#define THP7312_VIDEO_IMAGE_SIZE_1280x720 0x0a
+#define THP7312_VIDEO_IMAGE_SIZE_1920x1080 0x0b
+#define THP7312_VIDEO_IMAGE_SIZE_3840x2160 0x0d
+#define THP7312_VIDEO_IMAGE_SIZE_4160x3120 0x14
+#define THP7312_VIDEO_IMAGE_SIZE_2016x1512 0x20
+#define THP7312_VIDEO_IMAGE_SIZE_2048x1536 0x21
+#define THP7312_REG_VIDEO_FRAME_RATE_MODE CCI_REG8(0xf00f)
+#define THP7312_VIDEO_FRAME_RATE_MODE1 0x80
+#define THP7312_VIDEO_FRAME_RATE_MODE2 0x81
+#define THP7312_VIDEO_FRAME_RATE_MODE3 0x82
+#define THP7312_REG_SET_DRIVING_MODE CCI_REG8(0xf010)
+#define THP7312_REG_DRIVING_MODE_STATUS CCI_REG8(0xf011)
+#define THP7312_REG_JPEG_COMPRESSION_FACTOR CCI_REG8(0xf01b)
+#define THP7312_REG_AE_EXPOSURE_COMPENSATION CCI_REG8(0xf022)
+#define THP7312_REG_AE_FLICKER_MODE CCI_REG8(0xf023)
+#define THP7312_AE_FLICKER_MODE_50 0x00
+#define THP7312_AE_FLICKER_MODE_60 0x01
+#define THP7312_AE_FLICKER_MODE_DISABLE 0x80
+#define THP7312_REG_AE_FIX_FRAME_RATE CCI_REG8(0xf02e)
+#define THP7312_REG_MANUAL_WB_RED_GAIN CCI_REG8(0xf036)
+#define THP7312_REG_MANUAL_WB_BLUE_GAIN CCI_REG8(0xf037)
+#define THP7312_REG_WB_MODE CCI_REG8(0xf039)
+#define THP7312_WB_MODE_AUTO 0x00
+#define THP7312_WB_MODE_MANUAL 0x11
+#define THP7312_REG_MANUAL_FOCUS_POSITION CCI_REG16(0xf03c)
+#define THP7312_REG_AF_CONTROL CCI_REG8(0xf040)
+#define THP7312_REG_AF_CONTROL_AF 0x01
+#define THP7312_REG_AF_CONTROL_MANUAL 0x10
+#define THP7312_REG_AF_CONTROL_LOCK 0x80
+#define THP7312_REG_AF_SETTING CCI_REG8(0xf041)
+#define THP7312_REG_AF_SETTING_ONESHOT_CONTRAST 0x00
+#define THP7312_REG_AF_SETTING_ONESHOT_PDAF 0x40
+#define THP7312_REG_AF_SETTING_ONESHOT_HYBRID 0x80
+#define THP7312_REG_AF_SETTING_CONTINUOUS_CONTRAST 0x30
+#define THP7312_REG_AF_SETTING_CONTINUOUS_PDAF 0x70
+#define THP7312_REG_AF_SETTING_CONTINUOUS_HYBRID 0xf0
+#define THP7312_REG_AF_SUPPORT CCI_REG8(0xf043)
+#define THP7312_AF_SUPPORT_PDAF BIT(1)
+#define THP7312_AF_SUPPORT_CONTRAST BIT(0)
+#define THP7312_REG_SATURATION CCI_REG8(0xf052)
+#define THP7312_REG_SHARPNESS CCI_REG8(0xf053)
+#define THP7312_REG_BRIGHTNESS CCI_REG8(0xf056)
+#define THP7312_REG_CONTRAST CCI_REG8(0xf057)
+#define THP7312_REG_NOISE_REDUCTION CCI_REG8(0xf059)
+#define THP7312_REG_NOISE_REDUCTION_FIXED BIT(7)
+
+#define TH7312_REG_CUSTOM_MIPI_SET CCI_REG8(0xf0f6)
+#define TH7312_REG_CUSTOM_MIPI_STATUS CCI_REG8(0xf0f7)
+#define TH7312_REG_CUSTOM_MIPI_RD CCI_REG8(0xf0f8)
+#define TH7312_REG_CUSTOM_MIPI_TD CCI_REG8(0xf0f9)
+
+/*
+ * Firmware update registers. Those use a different address space than the
+ * normal operation ISP registers.
+ */
+
+#define THP7312_REG_FW_DRIVABILITY CCI_REG32(0xd65c)
+#define THP7312_REG_FW_DEST_BANK_ADDR CCI_REG32(0xff08)
+#define THP7312_REG_FW_VERIFY_RESULT CCI_REG8(0xff60)
+#define THP7312_REG_FW_RESET_FLASH CCI_REG8(0xff61)
+#define THP7312_REG_FW_MEMORY_IO_SETTING CCI_REG8(0xff62)
+#define THP7312_FW_MEMORY_IO_GPIO0 1
+#define THP7312_FW_MEMORY_IO_GPIO1 0
+#define THP7312_REG_FW_CRC_RESULT CCI_REG32(0xff64)
+#define THP7312_REG_FW_STATUS CCI_REG8(0xfffc)
+
+#define THP7312_FW_VERSION(major, minor) (((major) << 8) | (minor))
+#define THP7312_FW_VERSION_MAJOR(v) ((v) >> 8)
+#define THP7312_FW_VERSION_MINOR(v) ((v) & 0xff)
+
+enum thp7312_focus_method {
+ THP7312_FOCUS_METHOD_CONTRAST,
+ THP7312_FOCUS_METHOD_PDAF,
+ THP7312_FOCUS_METHOD_HYBRID,
+};
+
+/*
+ * enum thp7312_focus_state - State of the focus handler
+ *
+ * @THP7312_FOCUS_STATE_MANUAL: Manual focus, controlled through the
+ * V4L2_CID_FOCUS_ABSOLUTE control
+ * @THP7312_FOCUS_STATE_AUTO: Continuous auto-focus
+ * @THP7312_FOCUS_STATE_LOCKED: Lock the focus to a fixed position. This state
+ * is entered when switching from auto to manual mode.
+ * @THP7312_FOCUS_STATE_ONESHOT: One-shot auto-focus
+ *
+ * Valid transitions are as follow:
+ *
+ * digraph fsm {
+ * node [shape=circle];
+ *
+ * manual [label="MANUAL"];
+ * auto [label="AUTO"];
+ * locked [label="LOCKED"];
+ * oneshot [label="ONESHOT"];
+ *
+ * manual -> auto [label="FOCUS_AUTO <- true"]
+ * locked -> auto [label="FOCUS_AUTO <- true"]
+ * oneshot -> auto [label="FOCUS_AUTO <- true"]
+ * auto -> locked [label="FOCUS_AUTO <- false"]
+ *
+ * locked -> manual [label="FOCUS_ABSOLUTE <- *"]
+ * oneshot -> manual [label="FOCUS_ABSOLUTE <- *"]
+ *
+ * manual -> oneshot [label="FOCUS_START <- *"]
+ * locked -> oneshot [label="FOCUS_START <- *"]
+ * }
+ */
+enum thp7312_focus_state {
+ THP7312_FOCUS_STATE_MANUAL,
+ THP7312_FOCUS_STATE_AUTO,
+ THP7312_FOCUS_STATE_LOCKED,
+ THP7312_FOCUS_STATE_ONESHOT,
+};
+
+enum thp7312_boot_mode {
+ THP7312_BOOT_MODE_2WIRE_SLAVE = 0,
+ THP7312_BOOT_MODE_SPI_MASTER = 1,
+};
+
+struct thp7312_frame_rate {
+ u32 fps;
+ u32 link_freq;
+ u8 reg_frame_rate_mode;
+};
+
+struct thp7312_mode_info {
+ u32 width;
+ u32 height;
+ u8 reg_image_size;
+ const struct thp7312_frame_rate *rates;
+};
+
+static const u32 thp7312_colour_fmts[] = {
+ MEDIA_BUS_FMT_YUYV8_1X16,
+};
+
+/* regulator supplies */
+static const char * const thp7312_supply_name[] = {
+ "vddcore",
+ "vhtermrx",
+ "vddtx",
+ "vddhost",
+ "vddcmos",
+ "vddgpio-0",
+ "vddgpio-1",
+};
+
+static const struct thp7312_mode_info thp7312_mode_info_data[] = {
+ {
+ .width = 1920,
+ .height = 1080,
+ .reg_image_size = THP7312_VIDEO_IMAGE_SIZE_1920x1080,
+ .rates = (const struct thp7312_frame_rate[]) {
+ { 30, 300000000, 0x81 },
+ { 60, 387500000, 0x82 },
+ { 0 }
+ },
+ }, {
+ .width = 2048,
+ .height = 1536,
+ .reg_image_size = THP7312_VIDEO_IMAGE_SIZE_2048x1536,
+ .rates = (const struct thp7312_frame_rate[]) {
+ { 30, 300000000, 0x81 },
+ { 0 }
+ }
+ }, {
+ .width = 3840,
+ .height = 2160,
+ .reg_image_size = THP7312_VIDEO_IMAGE_SIZE_3840x2160,
+ .rates = (const struct thp7312_frame_rate[]) {
+ { 30, 600000000, 0x81 },
+ { 0 }
+ },
+ }, {
+ .width = 4160,
+ .height = 3120,
+ .reg_image_size = THP7312_VIDEO_IMAGE_SIZE_4160x3120,
+ .rates = (const struct thp7312_frame_rate[]) {
+ { 20, 600000000, 0x81 },
+ { 0 }
+ },
+ },
+};
+
+struct thp7312_device;
+
+struct thp7312_sensor_info {
+ const char *model;
+};
+
+struct thp7312_sensor {
+ const struct thp7312_sensor_info *info;
+ u8 lane_remap;
+};
+
+struct thp7312_device {
+ struct device *dev;
+ struct regmap *regmap;
+
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(thp7312_supply_name)];
+ struct clk *iclk;
+
+ u8 lane_remap;
+
+ struct thp7312_sensor sensors[1];
+
+ enum thp7312_boot_mode boot_mode;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ bool ctrls_applied;
+
+ s64 link_freq;
+
+ struct {
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ };
+
+ struct {
+ struct v4l2_ctrl *focus_auto;
+ struct v4l2_ctrl *focus_absolute;
+ struct v4l2_ctrl *focus_start;
+ struct v4l2_ctrl *focus_method;
+ };
+
+ enum thp7312_focus_state focus_state;
+
+ struct {
+ struct v4l2_ctrl *noise_reduction_auto;
+ struct v4l2_ctrl *noise_reduction_absolute;
+ };
+
+ /* Lock to protect fw_cancel */
+ struct mutex fw_lock;
+ struct fw_upload *fwl;
+ u8 *fw_write_buf;
+ bool fw_cancel;
+
+ u16 fw_version;
+};
+
+static const struct thp7312_sensor_info thp7312_sensor_info[] = {
+ {
+ .model = "sony,imx258",
+ },
+};
+
+static inline struct thp7312_device *to_thp7312_dev(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct thp7312_device, sd);
+}
+
+static const struct thp7312_mode_info *
+thp7312_find_mode(unsigned int width, unsigned int height, bool nearest)
+{
+ const struct thp7312_mode_info *mode;
+
+ mode = v4l2_find_nearest_size(thp7312_mode_info_data,
+ ARRAY_SIZE(thp7312_mode_info_data),
+ width, height, width, height);
+
+ if (!nearest && (mode->width != width || mode->height != height))
+ return NULL;
+
+ return mode;
+}
+
+static const struct thp7312_frame_rate *
+thp7312_find_rate(const struct thp7312_mode_info *mode, unsigned int fps,
+ bool nearest)
+{
+ const struct thp7312_frame_rate *best_rate = NULL;
+ const struct thp7312_frame_rate *rate;
+ unsigned int best_delta = UINT_MAX;
+
+ if (!mode)
+ return NULL;
+
+ for (rate = mode->rates; rate->fps && best_delta; ++rate) {
+ unsigned int delta = abs(rate->fps - fps);
+
+ if (delta <= best_delta) {
+ best_delta = delta;
+ best_rate = rate;
+ }
+ }
+
+ if (!nearest && best_delta)
+ return NULL;
+
+ return best_rate;
+}
+
+/* -----------------------------------------------------------------------------
+ * Device Access & Configuration
+ */
+
+#define thp7312_read_poll_timeout(dev, addr, val, cond, sleep_us, timeout_us) \
+({ \
+ int __ret, __err; \
+ __ret = read_poll_timeout(cci_read, __err, __err || (cond), sleep_us, \
+ timeout_us, false, (dev)->regmap, addr, \
+ &(val), NULL); \
+ __ret ? : __err; \
+})
+
+static int thp7312_map_data_lanes(u8 *lane_remap, const u8 *lanes, u8 num_lanes)
+{
+ u8 used_lanes = 0;
+ u8 val = 0;
+ unsigned int i;
+
+ /*
+ * The value that we write to the register is the index in the
+ * data-lanes array, so we need to do a conversion. Do this in the same
+ * pass as validating data-lanes.
+ */
+ for (i = 0; i < num_lanes; i++) {
+ if (lanes[i] < 1 || lanes[i] > 4)
+ return -EINVAL;
+
+ if (used_lanes & (BIT(lanes[i])))
+ return -EINVAL;
+
+ used_lanes |= BIT(lanes[i]);
+
+ /*
+ * data-lanes is 1-indexed while the field position in the
+ * register is 0-indexed.
+ */
+ val |= i << ((lanes[i] - 1) * 2);
+ }
+
+ *lane_remap = val;
+
+ return 0;
+}
+
+static int thp7312_set_mipi_lanes(struct thp7312_device *thp7312)
+{
+ struct device *dev = thp7312->dev;
+ int ret = 0;
+ u64 val;
+
+ cci_write(thp7312->regmap, TH7312_REG_CUSTOM_MIPI_RD,
+ thp7312->sensors[0].lane_remap, &ret);
+ cci_write(thp7312->regmap, TH7312_REG_CUSTOM_MIPI_TD,
+ thp7312->lane_remap, &ret);
+ cci_write(thp7312->regmap, TH7312_REG_CUSTOM_MIPI_SET, 1, &ret);
+
+ if (ret)
+ return ret;
+
+ ret = thp7312_read_poll_timeout(thp7312, TH7312_REG_CUSTOM_MIPI_STATUS,
+ val, val == 0x00, 100000, 2000000);
+ if (ret) {
+ dev_err(dev, "Failed to poll MIPI lane status: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int thp7312_change_mode(struct thp7312_device *thp7312,
+ const struct thp7312_mode_info *mode,
+ const struct thp7312_frame_rate *rate)
+{
+ struct device *dev = thp7312->dev;
+ u64 val = 0;
+ int ret;
+
+ ret = thp7312_read_poll_timeout(thp7312, THP7312_REG_CAMERA_STATUS, val,
+ val == 0x80, 20000, 200000);
+ if (ret < 0) {
+ dev_err(dev, "%s(): failed to poll ISP: %d\n", __func__, ret);
+ return ret;
+ }
+
+ cci_write(thp7312->regmap, THP7312_REG_VIDEO_IMAGE_SIZE,
+ mode->reg_image_size, &ret);
+ cci_write(thp7312->regmap, THP7312_REG_VIDEO_FRAME_RATE_MODE,
+ rate->reg_frame_rate_mode, &ret);
+ cci_write(thp7312->regmap, THP7312_REG_JPEG_COMPRESSION_FACTOR, 0x5e,
+ &ret);
+ cci_write(thp7312->regmap, THP7312_REG_SET_DRIVING_MODE, 0x01, &ret);
+
+ if (ret)
+ return ret;
+
+ ret = thp7312_read_poll_timeout(thp7312, THP7312_REG_DRIVING_MODE_STATUS,
+ val, val == 0x01, 20000, 100000);
+ if (ret < 0) {
+ dev_err(dev, "%s(): failed\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int thp7312_set_framefmt(struct thp7312_device *thp7312,
+ struct v4l2_mbus_framefmt *format)
+{
+ u8 val;
+
+ switch (format->code) {
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ /* YUV422, UYVY */
+ val = THP7312_REG_SET_OUTPUT_COLOR_UYVY;
+ break;
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ /* YUV422, YUYV */
+ val = THP7312_REG_SET_OUTPUT_COLOR_YUY2;
+ break;
+ default:
+ /* Should never happen */
+ return -EINVAL;
+ }
+
+ return cci_write(thp7312->regmap,
+ THP7312_REG_SET_OUTPUT_COLOR_COMPRESSION, val, NULL);
+}
+
+static int thp7312_init_mode(struct thp7312_device *thp7312,
+ struct v4l2_subdev_state *sd_state)
+{
+ const struct thp7312_mode_info *mode;
+ const struct thp7312_frame_rate *rate;
+ struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_fract *interval;
+ int ret;
+
+ /*
+ * TODO: The mode and rate should be cached in the subdev state, once
+ * support for extending states will be available.
+ */
+ fmt = v4l2_subdev_state_get_format(sd_state, 0);
+ interval = v4l2_subdev_state_get_interval(sd_state, 0);
+
+ mode = thp7312_find_mode(fmt->width, fmt->height, false);
+ rate = thp7312_find_rate(mode, interval->denominator, false);
+
+ if (WARN_ON(!mode || !rate))
+ return -EINVAL;
+
+ ret = thp7312_set_framefmt(thp7312, fmt);
+ if (ret)
+ return ret;
+
+ return thp7312_change_mode(thp7312, mode, rate);
+}
+
+static int thp7312_stream_enable(struct thp7312_device *thp7312, bool enable)
+{
+ return cci_write(thp7312->regmap, THP7312_REG_SET_OUTPUT_ENABLE,
+ enable ? THP7312_OUTPUT_ENABLE : THP7312_OUTPUT_DISABLE,
+ NULL);
+}
+
+static int thp7312_check_status_stream_mode(struct thp7312_device *thp7312)
+{
+ struct device *dev = thp7312->dev;
+ u64 status = 0;
+ int ret;
+
+ while (status != 0x80) {
+ ret = cci_read(thp7312->regmap, THP7312_REG_CAMERA_STATUS,
+ &status, NULL);
+ if (ret)
+ return ret;
+
+ if (status == 0x80) {
+ dev_dbg(dev, "Camera initialization done\n");
+ return 0;
+ }
+
+ if (status != 0x00) {
+ dev_err(dev, "Invalid camera status %llx\n", status);
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "Camera initializing...\n");
+ usleep_range(70000, 80000);
+ }
+
+ return 0;
+}
+
+static void thp7312_reset(struct thp7312_device *thp7312)
+{
+ unsigned long rate;
+
+ gpiod_set_value_cansleep(thp7312->reset_gpio, 1);
+
+ /*
+ * The minimum reset duration is 8 clock cycles, make it 10 to provide
+ * a safety margin.
+ */
+ rate = clk_get_rate(thp7312->iclk);
+ fsleep(DIV_ROUND_UP(10 * USEC_PER_SEC, rate));
+
+ gpiod_set_value_cansleep(thp7312->reset_gpio, 0);
+
+ /*
+ * TODO: The documentation states that the device needs 2ms to
+ * initialize after reset is deasserted. It then proceeds to load the
+ * firmware from the flash memory, which takes an unspecified amount of
+ * time. Check if this delay could be reduced.
+ */
+ fsleep(300000);
+}
+
+/* -----------------------------------------------------------------------------
+ * Power Management
+ */
+
+static void __thp7312_power_off(struct thp7312_device *thp7312)
+{
+ regulator_bulk_disable(ARRAY_SIZE(thp7312->supplies), thp7312->supplies);
+ clk_disable_unprepare(thp7312->iclk);
+}
+
+static void thp7312_power_off(struct thp7312_device *thp7312)
+{
+ __thp7312_power_off(thp7312);
+}
+
+static int __thp7312_power_on(struct thp7312_device *thp7312)
+{
+ struct device *dev = thp7312->dev;
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(thp7312->supplies),
+ thp7312->supplies);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare_enable(thp7312->iclk);
+ if (ret < 0) {
+ dev_err(dev, "clk prepare enable failed\n");
+ regulator_bulk_disable(ARRAY_SIZE(thp7312->supplies),
+ thp7312->supplies);
+ return ret;
+ }
+
+ /*
+ * We cannot assume that turning off and on again will reset, so do a
+ * software reset on power up.
+ */
+ thp7312_reset(thp7312);
+
+ return 0;
+}
+
+static int thp7312_power_on(struct thp7312_device *thp7312)
+{
+ int ret;
+
+ ret = __thp7312_power_on(thp7312);
+ if (ret < 0)
+ return ret;
+
+ ret = thp7312_check_status_stream_mode(thp7312);
+ if (ret < 0)
+ goto error;
+
+ ret = thp7312_set_mipi_lanes(thp7312);
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ thp7312_power_off(thp7312);
+ return ret;
+}
+
+static int __maybe_unused thp7312_pm_runtime_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct thp7312_device *thp7312 = to_thp7312_dev(sd);
+
+ thp7312_power_off(thp7312);
+
+ thp7312->ctrls_applied = false;
+
+ return 0;
+}
+
+static int __maybe_unused thp7312_pm_runtime_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct thp7312_device *thp7312 = to_thp7312_dev(sd);
+
+ return thp7312_power_on(thp7312);
+}
+
+static const struct dev_pm_ops thp7312_pm_ops = {
+ SET_RUNTIME_PM_OPS(thp7312_pm_runtime_suspend,
+ thp7312_pm_runtime_resume, NULL)
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdev Operations
+ */
+
+static bool thp7312_find_bus_code(u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(thp7312_colour_fmts); ++i) {
+ if (thp7312_colour_fmts[i] == code)
+ return true;
+ }
+
+ return false;
+}
+
+static int thp7312_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(thp7312_colour_fmts))
+ return -EINVAL;
+
+ code->code = thp7312_colour_fmts[code->index];
+
+ return 0;
+}
+
+static int thp7312_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (!thp7312_find_bus_code(fse->code))
+ return -EINVAL;
+
+ if (fse->index >= ARRAY_SIZE(thp7312_mode_info_data))
+ return -EINVAL;
+
+ fse->min_width = thp7312_mode_info_data[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->min_height = thp7312_mode_info_data[fse->index].height;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static int thp7312_enum_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ const struct thp7312_frame_rate *rate;
+ const struct thp7312_mode_info *mode;
+ unsigned int index = fie->index;
+
+ if (!thp7312_find_bus_code(fie->code))
+ return -EINVAL;
+
+ mode = thp7312_find_mode(fie->width, fie->height, false);
+ if (!mode)
+ return -EINVAL;
+
+ for (rate = mode->rates; rate->fps; ++rate, --index) {
+ if (!index) {
+ fie->interval.numerator = 1;
+ fie->interval.denominator = rate->fps;
+
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int thp7312_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *format)
+{
+ struct thp7312_device *thp7312 = to_thp7312_dev(sd);
+ struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
+ struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_fract *interval;
+ const struct thp7312_mode_info *mode;
+
+ if (!thp7312_find_bus_code(mbus_fmt->code))
+ mbus_fmt->code = thp7312_colour_fmts[0];
+
+ mode = thp7312_find_mode(mbus_fmt->width, mbus_fmt->height, true);
+
+ fmt = v4l2_subdev_state_get_format(sd_state, 0);
+
+ fmt->code = mbus_fmt->code;
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
+
+ *mbus_fmt = *fmt;
+
+ interval = v4l2_subdev_state_get_interval(sd_state, 0);
+ interval->numerator = 1;
+ interval->denominator = mode->rates[0].fps;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ thp7312->link_freq = mode->rates[0].link_freq;
+
+ return 0;
+}
+
+static int thp7312_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct thp7312_device *thp7312 = to_thp7312_dev(sd);
+ const struct thp7312_mode_info *mode;
+ const struct thp7312_frame_rate *rate;
+ const struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_fract *interval;
+ unsigned int fps;
+
+ /* Avoid divisions by 0, pick the highest frame if the interval is 0. */
+ fps = fi->interval.numerator
+ ? DIV_ROUND_CLOSEST(fi->interval.denominator, fi->interval.numerator)
+ : UINT_MAX;
+
+ fmt = v4l2_subdev_state_get_format(sd_state, 0);
+ mode = thp7312_find_mode(fmt->width, fmt->height, false);
+ rate = thp7312_find_rate(mode, fps, true);
+
+ interval = v4l2_subdev_state_get_interval(sd_state, 0);
+ interval->numerator = 1;
+ interval->denominator = rate->fps;
+
+ if (fi->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ thp7312->link_freq = rate->link_freq;
+
+ fi->interval = *interval;
+
+ return 0;
+}
+
+static int thp7312_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct thp7312_device *thp7312 = to_thp7312_dev(sd);
+ struct v4l2_subdev_state *sd_state;
+ int ret;
+
+ sd_state = v4l2_subdev_lock_and_get_active_state(sd);
+
+ if (!enable) {
+ thp7312_stream_enable(thp7312, false);
+
+ pm_runtime_mark_last_busy(thp7312->dev);
+ pm_runtime_put_autosuspend(thp7312->dev);
+
+ v4l2_subdev_unlock_state(sd_state);
+
+ return 0;
+ }
+
+ ret = pm_runtime_resume_and_get(thp7312->dev);
+ if (ret)
+ goto finish_unlock;
+
+ ret = thp7312_init_mode(thp7312, sd_state);
+ if (ret)
+ goto finish_pm;
+
+ if (!thp7312->ctrls_applied) {
+ ret = __v4l2_ctrl_handler_setup(&thp7312->ctrl_handler);
+ if (ret)
+ goto finish_pm;
+
+ thp7312->ctrls_applied = true;
+ }
+
+ ret = thp7312_stream_enable(thp7312, true);
+ if (ret)
+ goto finish_pm;
+
+ goto finish_unlock;
+
+finish_pm:
+ pm_runtime_mark_last_busy(thp7312->dev);
+ pm_runtime_put_autosuspend(thp7312->dev);
+finish_unlock:
+ v4l2_subdev_unlock_state(sd_state);
+
+ return ret;
+}
+
+static int thp7312_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ const struct thp7312_mode_info *default_mode = &thp7312_mode_info_data[0];
+ struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_fract *interval;
+
+ fmt = v4l2_subdev_state_get_format(sd_state, 0);
+ interval = v4l2_subdev_state_get_interval(sd_state, 0);
+
+ /*
+ * default init sequence initialize thp7312 to
+ * YUV422 YUYV VGA@30fps
+ */
+ fmt->code = MEDIA_BUS_FMT_YUYV8_1X16;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
+ fmt->width = default_mode->width;
+ fmt->height = default_mode->height;
+ fmt->field = V4L2_FIELD_NONE;
+
+ interval->numerator = 1;
+ interval->denominator = default_mode->rates[0].fps;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops thp7312_core_ops = {
+ .log_status = v4l2_ctrl_subdev_log_status,
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops thp7312_video_ops = {
+ .s_stream = thp7312_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops thp7312_pad_ops = {
+ .enum_mbus_code = thp7312_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = thp7312_set_fmt,
+ .get_frame_interval = v4l2_subdev_get_frame_interval,
+ .set_frame_interval = thp7312_set_frame_interval,
+ .enum_frame_size = thp7312_enum_frame_size,
+ .enum_frame_interval = thp7312_enum_frame_interval,
+};
+
+static const struct v4l2_subdev_ops thp7312_subdev_ops = {
+ .core = &thp7312_core_ops,
+ .video = &thp7312_video_ops,
+ .pad = &thp7312_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops thp7312_internal_ops = {
+ .init_state = thp7312_init_state,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Control Operations
+ */
+
+static inline struct thp7312_device *to_thp7312_from_ctrl(struct v4l2_ctrl *ctrl)
+{
+ return container_of(ctrl->handler, struct thp7312_device, ctrl_handler);
+}
+
+/* 0: 3000cm, 18: 8cm */
+static const u16 thp7312_focus_values[] = {
+ 3000, 1000, 600, 450, 350,
+ 290, 240, 200, 170, 150,
+ 140, 130, 120, 110, 100,
+ 93, 87, 83, 80,
+};
+
+static int thp7312_set_focus(struct thp7312_device *thp7312)
+{
+ enum thp7312_focus_state new_state = thp7312->focus_state;
+ bool continuous;
+ u8 af_control;
+ u8 af_setting;
+ int ret = 0;
+
+ /* Start by programming the manual focus position if it has changed. */
+ if (thp7312->focus_absolute->is_new) {
+ unsigned int value;
+
+ value = thp7312_focus_values[thp7312->focus_absolute->val];
+
+ ret = cci_write(thp7312->regmap,
+ THP7312_REG_MANUAL_FOCUS_POSITION, value, NULL);
+ if (ret)
+ return ret;
+ }
+
+ /* Calculate the new focus state. */
+ switch (thp7312->focus_state) {
+ case THP7312_FOCUS_STATE_MANUAL:
+ default:
+ if (thp7312->focus_auto->val)
+ new_state = THP7312_FOCUS_STATE_AUTO;
+ else if (thp7312->focus_start->is_new)
+ new_state = THP7312_FOCUS_STATE_ONESHOT;
+ break;
+
+ case THP7312_FOCUS_STATE_AUTO:
+ if (!thp7312->focus_auto->val)
+ new_state = THP7312_FOCUS_STATE_LOCKED;
+ break;
+
+ case THP7312_FOCUS_STATE_LOCKED:
+ if (thp7312->focus_auto->val)
+ new_state = THP7312_FOCUS_STATE_AUTO;
+ else if (thp7312->focus_start->is_new)
+ new_state = THP7312_FOCUS_STATE_ONESHOT;
+ else if (thp7312->focus_absolute->is_new)
+ new_state = THP7312_FOCUS_STATE_MANUAL;
+ break;
+
+ case THP7312_FOCUS_STATE_ONESHOT:
+ if (thp7312->focus_auto->val)
+ new_state = THP7312_FOCUS_STATE_AUTO;
+ else if (thp7312->focus_start->is_new)
+ new_state = THP7312_FOCUS_STATE_ONESHOT;
+ else if (thp7312->focus_absolute->is_new)
+ new_state = THP7312_FOCUS_STATE_MANUAL;
+ break;
+ }
+
+ /*
+ * If neither the state nor the focus method has changed, and no new
+ * one-shot focus is requested, there's nothing new to program to the
+ * hardware.
+ */
+ if (thp7312->focus_state == new_state &&
+ !thp7312->focus_method->is_new && !thp7312->focus_start->is_new)
+ return 0;
+
+ continuous = new_state == THP7312_FOCUS_STATE_MANUAL ||
+ new_state == THP7312_FOCUS_STATE_ONESHOT;
+
+ switch (thp7312->focus_method->val) {
+ case THP7312_FOCUS_METHOD_CONTRAST:
+ default:
+ af_setting = continuous
+ ? THP7312_REG_AF_SETTING_CONTINUOUS_CONTRAST
+ : THP7312_REG_AF_SETTING_ONESHOT_CONTRAST;
+ break;
+ case THP7312_FOCUS_METHOD_PDAF:
+ af_setting = continuous
+ ? THP7312_REG_AF_SETTING_CONTINUOUS_PDAF
+ : THP7312_REG_AF_SETTING_ONESHOT_PDAF;
+ break;
+ case THP7312_FOCUS_METHOD_HYBRID:
+ af_setting = continuous
+ ? THP7312_REG_AF_SETTING_CONTINUOUS_HYBRID
+ : THP7312_REG_AF_SETTING_ONESHOT_HYBRID;
+ break;
+ }
+
+ switch (new_state) {
+ case THP7312_FOCUS_STATE_MANUAL:
+ default:
+ af_control = THP7312_REG_AF_CONTROL_MANUAL;
+ break;
+ case THP7312_FOCUS_STATE_AUTO:
+ case THP7312_FOCUS_STATE_ONESHOT:
+ af_control = THP7312_REG_AF_CONTROL_AF;
+ break;
+ case THP7312_FOCUS_STATE_LOCKED:
+ af_control = THP7312_REG_AF_CONTROL_LOCK;
+ break;
+ }
+
+ cci_write(thp7312->regmap, THP7312_REG_AF_SETTING, af_setting, &ret);
+
+ if (new_state == THP7312_FOCUS_STATE_MANUAL &&
+ (thp7312->focus_state == THP7312_FOCUS_STATE_AUTO ||
+ thp7312->focus_state == THP7312_FOCUS_STATE_ONESHOT)) {
+ /* When switching to manual state, lock AF first. */
+ cci_write(thp7312->regmap, THP7312_REG_AF_CONTROL,
+ THP7312_REG_AF_CONTROL_LOCK, &ret);
+ }
+
+ cci_write(thp7312->regmap, THP7312_REG_AF_CONTROL, af_control, &ret);
+
+ if (ret)
+ return ret;
+
+ thp7312->focus_state = new_state;
+
+ return 0;
+}
+
+static int thp7312_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct thp7312_device *thp7312 = to_thp7312_from_ctrl(ctrl);
+ int ret = 0;
+ u8 value;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+ return -EINVAL;
+
+ if (!pm_runtime_get_if_active(thp7312->dev, true))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ cci_write(thp7312->regmap, THP7312_REG_BRIGHTNESS,
+ ctrl->val + 10, &ret);
+ break;
+
+ case V4L2_CID_THP7312_LOW_LIGHT_COMPENSATION:
+ /* 0 = Auto adjust frame rate, 1 = Fix frame rate */
+ cci_write(thp7312->regmap, THP7312_REG_AE_FIX_FRAME_RATE,
+ ctrl->val ? 0 : 1, &ret);
+ break;
+
+ case V4L2_CID_FOCUS_AUTO:
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ case V4L2_CID_AUTO_FOCUS_START:
+ case V4L2_CID_THP7312_AUTO_FOCUS_METHOD:
+ ret = thp7312_set_focus(thp7312);
+ break;
+
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ value = (thp7312->hflip->val ? THP7312_REG_FLIP_MIRROR_MIRROR : 0)
+ | (thp7312->vflip->val ? THP7312_REG_FLIP_MIRROR_FLIP : 0);
+
+ cci_write(thp7312->regmap, THP7312_REG_FLIP_MIRROR, value, &ret);
+ break;
+
+ case V4L2_CID_THP7312_NOISE_REDUCTION_AUTO:
+ case V4L2_CID_THP7312_NOISE_REDUCTION_ABSOLUTE:
+ value = thp7312->noise_reduction_auto->val ? 0
+ : THP7312_REG_NOISE_REDUCTION_FIXED |
+ thp7312->noise_reduction_absolute->val;
+
+ cci_write(thp7312->regmap, THP7312_REG_NOISE_REDUCTION, value,
+ &ret);
+ break;
+
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ value = ctrl->val ? THP7312_WB_MODE_AUTO : THP7312_WB_MODE_MANUAL;
+
+ cci_write(thp7312->regmap, THP7312_REG_WB_MODE, value, &ret);
+ break;
+
+ case V4L2_CID_RED_BALANCE:
+ cci_write(thp7312->regmap, THP7312_REG_MANUAL_WB_RED_GAIN,
+ ctrl->val, &ret);
+ break;
+
+ case V4L2_CID_BLUE_BALANCE:
+ cci_write(thp7312->regmap, THP7312_REG_MANUAL_WB_BLUE_GAIN,
+ ctrl->val, &ret);
+ break;
+
+ case V4L2_CID_AUTO_EXPOSURE_BIAS:
+ cci_write(thp7312->regmap, THP7312_REG_AE_EXPOSURE_COMPENSATION,
+ ctrl->val, &ret);
+ break;
+
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ if (ctrl->val == V4L2_CID_POWER_LINE_FREQUENCY_60HZ) {
+ value = THP7312_AE_FLICKER_MODE_60;
+ } else if (ctrl->val == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) {
+ value = THP7312_AE_FLICKER_MODE_50;
+ } else {
+ if (thp7312->fw_version == THP7312_FW_VERSION(40, 3)) {
+ /* THP7312_AE_FLICKER_MODE_DISABLE is not supported */
+ value = THP7312_AE_FLICKER_MODE_50;
+ } else {
+ value = THP7312_AE_FLICKER_MODE_DISABLE;
+ }
+ }
+
+ cci_write(thp7312->regmap, THP7312_REG_AE_FLICKER_MODE,
+ value, &ret);
+ break;
+
+ case V4L2_CID_SATURATION:
+ cci_write(thp7312->regmap, THP7312_REG_SATURATION,
+ ctrl->val, &ret);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ cci_write(thp7312->regmap, THP7312_REG_CONTRAST,
+ ctrl->val, &ret);
+ break;
+
+ case V4L2_CID_SHARPNESS:
+ cci_write(thp7312->regmap, THP7312_REG_SHARPNESS,
+ ctrl->val, &ret);
+ break;
+
+ default:
+ break;
+ }
+
+ pm_runtime_mark_last_busy(thp7312->dev);
+ pm_runtime_put_autosuspend(thp7312->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops thp7312_ctrl_ops = {
+ .s_ctrl = thp7312_s_ctrl,
+};
+
+/*
+ * Refer to Documentation/userspace-api/media/drivers/thp7312.rst for details.
+ */
+static const struct v4l2_ctrl_config thp7312_ctrl_focus_method_cdaf = {
+ .ops = &thp7312_ctrl_ops,
+ .id = V4L2_CID_THP7312_AUTO_FOCUS_METHOD,
+ .name = "Auto-Focus Method",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = THP7312_FOCUS_METHOD_CONTRAST,
+ .def = THP7312_FOCUS_METHOD_CONTRAST,
+ .max = THP7312_FOCUS_METHOD_CONTRAST,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config thp7312_ctrl_focus_method_pdaf = {
+ .ops = &thp7312_ctrl_ops,
+ .id = V4L2_CID_THP7312_AUTO_FOCUS_METHOD,
+ .name = "Auto-Focus Method",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = THP7312_FOCUS_METHOD_CONTRAST,
+ .def = THP7312_FOCUS_METHOD_HYBRID,
+ .max = THP7312_FOCUS_METHOD_HYBRID,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config thp7312_v4l2_ctrls_custom[] = {
+ {
+ .ops = &thp7312_ctrl_ops,
+ .id = V4L2_CID_THP7312_LOW_LIGHT_COMPENSATION,
+ .name = "Low Light Compensation",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .def = 1,
+ .max = 1,
+ .step = 1,
+ }, {
+ .ops = &thp7312_ctrl_ops,
+ .id = V4L2_CID_THP7312_NOISE_REDUCTION_AUTO,
+ .name = "Noise Reduction Auto",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .def = 1,
+ .max = 1,
+ .step = 1,
+ }, {
+ .ops = &thp7312_ctrl_ops,
+ .id = V4L2_CID_THP7312_NOISE_REDUCTION_ABSOLUTE,
+ .name = "Noise Reduction Level",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0,
+ .def = 0,
+ .max = 10,
+ .step = 1,
+ },
+};
+
+static const s64 exp_bias_qmenu[] = {
+ -2000, -1667, -1333, -1000, -667, -333, 0, 333, 667, 1000, 1333, 1667, 2000
+};
+
+static int thp7312_init_controls(struct thp7312_device *thp7312)
+{
+ struct v4l2_ctrl_handler *hdl = &thp7312->ctrl_handler;
+ struct device *dev = thp7312->dev;
+ struct v4l2_fwnode_device_properties props;
+ struct v4l2_ctrl *link_freq;
+ unsigned int num_controls;
+ unsigned int i;
+ u8 af_support;
+ int ret;
+
+ /*
+ * Check what auto-focus methods the connected sensor supports, if any.
+ * Firmwares before v90.03 didn't expose the AF_SUPPORT register,
+ * consider both CDAF and PDAF as supported in that case.
+ */
+ if (thp7312->fw_version >= THP7312_FW_VERSION(90, 3)) {
+ u64 val;
+
+ ret = cci_read(thp7312->regmap, THP7312_REG_AF_SUPPORT, &val,
+ NULL);
+ if (ret)
+ return ret;
+
+ af_support = val & (THP7312_AF_SUPPORT_PDAF |
+ THP7312_AF_SUPPORT_CONTRAST);
+ } else {
+ af_support = THP7312_AF_SUPPORT_PDAF
+ | THP7312_AF_SUPPORT_CONTRAST;
+ }
+
+ num_controls = 14 + ARRAY_SIZE(thp7312_v4l2_ctrls_custom)
+ + (af_support ? 4 : 0);
+
+ v4l2_ctrl_handler_init(hdl, num_controls);
+
+ if (af_support) {
+ const struct v4l2_ctrl_config *af_method;
+
+ af_method = af_support & THP7312_AF_SUPPORT_PDAF
+ ? &thp7312_ctrl_focus_method_pdaf
+ : &thp7312_ctrl_focus_method_cdaf;
+
+ thp7312->focus_state = THP7312_FOCUS_STATE_MANUAL;
+
+ thp7312->focus_auto =
+ v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops,
+ V4L2_CID_FOCUS_AUTO,
+ 0, 1, 1, 1);
+ thp7312->focus_absolute =
+ v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops,
+ V4L2_CID_FOCUS_ABSOLUTE,
+ 0, ARRAY_SIZE(thp7312_focus_values),
+ 1, 0);
+ thp7312->focus_method =
+ v4l2_ctrl_new_custom(hdl, af_method, NULL);
+ thp7312->focus_start =
+ v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops,
+ V4L2_CID_AUTO_FOCUS_START,
+ 1, 1, 1, 1);
+
+ v4l2_ctrl_cluster(4, &thp7312->focus_auto);
+ }
+
+ v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 1);
+ /* 32: 1x, 255: 7.95x */
+ v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_RED_BALANCE,
+ 32, 255, 1, 64);
+ /* 32: 1x, 255: 7.95x */
+ v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_BLUE_BALANCE,
+ 32, 255, 1, 50);
+
+ v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_BRIGHTNESS,
+ -10, 10, 1, 0);
+ v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_SATURATION,
+ 0, 31, 1, 10);
+ v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_CONTRAST,
+ 0, 20, 1, 10);
+ v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops, V4L2_CID_SHARPNESS,
+ 0, 31, 1, 8);
+
+ thp7312->hflip = v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ thp7312->vflip = v4l2_ctrl_new_std(hdl, &thp7312_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ v4l2_ctrl_cluster(2, &thp7312->hflip);
+
+ v4l2_ctrl_new_int_menu(hdl, &thp7312_ctrl_ops,
+ V4L2_CID_AUTO_EXPOSURE_BIAS,
+ ARRAY_SIZE(exp_bias_qmenu) - 1,
+ ARRAY_SIZE(exp_bias_qmenu) / 2, exp_bias_qmenu);
+
+ v4l2_ctrl_new_std_menu(hdl, &thp7312_ctrl_ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
+
+ thp7312->link_freq = thp7312_mode_info_data[0].rates[0].link_freq;
+
+ link_freq = v4l2_ctrl_new_int_menu(hdl, &thp7312_ctrl_ops,
+ V4L2_CID_LINK_FREQ, 0, 0,
+ &thp7312->link_freq);
+
+ /* Set properties from fwnode (e.g. rotation, orientation). */
+ ret = v4l2_fwnode_device_parse(dev, &props);
+ if (ret) {
+ dev_err(dev, "Failed to parse fwnode: %d\n", ret);
+ goto error;
+ }
+
+ ret = v4l2_ctrl_new_fwnode_properties(hdl, &thp7312_ctrl_ops, &props);
+ if (ret) {
+ dev_err(dev, "Failed to create new v4l2 ctrl for fwnode properties: %d\n", ret);
+ goto error;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(thp7312_v4l2_ctrls_custom); i++) {
+ const struct v4l2_ctrl_config *ctrl_cfg =
+ &thp7312_v4l2_ctrls_custom[i];
+ struct v4l2_ctrl *ctrl;
+
+ ctrl = v4l2_ctrl_new_custom(hdl, ctrl_cfg, NULL);
+
+ if (ctrl_cfg->id == V4L2_CID_THP7312_NOISE_REDUCTION_AUTO)
+ thp7312->noise_reduction_auto = ctrl;
+ else if (ctrl_cfg->id == V4L2_CID_THP7312_NOISE_REDUCTION_ABSOLUTE)
+ thp7312->noise_reduction_absolute = ctrl;
+ }
+
+ v4l2_ctrl_cluster(2, &thp7312->noise_reduction_auto);
+
+ if (hdl->error) {
+ dev_err(dev, "v4l2_ctrl_handler error\n");
+ ret = hdl->error;
+ goto error;
+ }
+
+ link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ return ret;
+
+error:
+ v4l2_ctrl_handler_free(hdl);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Firmware Update
+ */
+
+/*
+ * The firmware data is made of 128kB of RAM firmware, followed by a
+ * variable-size "header". Both are stored in flash memory.
+ */
+#define THP7312_FW_RAM_SIZE (128 * 1024)
+#define THP7312_FW_MIN_SIZE (THP7312_FW_RAM_SIZE + 4)
+#define THP7312_FW_MAX_SIZE (THP7312_FW_RAM_SIZE + 64 * 1024)
+
+/*
+ * Data is first uploaded to the THP7312 128kB SRAM, and then written to flash.
+ * The SRAM is exposed over I2C as 32kB banks, and up to 4kB of data can be
+ * transferred in a single I2C write.
+ */
+#define THP7312_RAM_BANK_SIZE (32 * 1024)
+#define THP7312_FW_DOWNLOAD_UNIT (4 * 1024)
+
+#define THP7312_FLASH_MEMORY_ERASE_TIMEOUT 40
+
+#define THP7312_FLASH_MAX_REG_READ_SIZE 10
+#define THP7312_FLASH_MAX_REG_DATA_SIZE 10
+
+static const u8 thp7312_cmd_config_flash_mem_if[] = {
+ 0xd5, 0x18, 0x00, 0x00, 0x00, 0x80
+};
+
+static const u8 thp7312_cmd_write_to_reg[] = {
+ 0xd5, 0x0c, 0x80, 0x00, 0x00, 0x00
+};
+
+static const u8 thp7312_cmd_read_reg[] = {
+ 0xd5, 0x04
+};
+
+/*
+ * THP7312 Write data from RAM to Flash Memory
+ * Command ID FF700F
+ * Format: FF700F AA AA AA BB BB BB
+ * AA AA AA: destination start address
+ * BB BB BB: (write size - 1)
+ * Source address always starts from 0
+ */
+static const u8 thp7312_cmd_write_ram_to_flash[] = { 0xff, 0x70, 0x0f };
+
+/*
+ * THP7312 Calculate CRC command
+ * Command ID: FF70 09
+ * Format: FF70 09 AA AA AA BB BB BB
+ * AA AA AA: Start address of calculation
+ * BB BB BB: (calculate size - 1)
+ */
+static const u8 thp7312_cmd_calc_crc[] = { 0xff, 0x70, 0x09 };
+
+static const u8 thp7312_jedec_rdid[] = { SPINOR_OP_RDID, 0x00, 0x00, 0x00 };
+static const u8 thp7312_jedec_rdsr[] = { SPINOR_OP_RDSR, 0x00, 0x00, 0x00 };
+static const u8 thp7312_jedec_wen[] = { SPINOR_OP_WREN };
+
+static int thp7312_read_firmware_version(struct thp7312_device *thp7312)
+{
+ u64 val = 0;
+ int ret = 0;
+ u8 major;
+ u8 minor;
+
+ cci_read(thp7312->regmap, THP7312_REG_FIRMWARE_VERSION_1, &val, &ret);
+ major = val;
+
+ cci_read(thp7312->regmap, THP7312_REG_FIRMWARE_VERSION_2, &val, &ret);
+ minor = val;
+
+ thp7312->fw_version = THP7312_FW_VERSION(major, minor);
+ return ret;
+}
+
+static int thp7312_write_buf(struct thp7312_device *thp7312,
+ const u8 *write_buf, u16 write_size)
+{
+ struct i2c_client *client = to_i2c_client(thp7312->dev);
+ int ret;
+
+ ret = i2c_master_send(client, write_buf, write_size);
+ return ret >= 0 ? 0 : ret;
+}
+
+static int __thp7312_flash_reg_write(struct thp7312_device *thp7312,
+ const u8 *write_buf, u16 write_size)
+{
+ struct device *dev = thp7312->dev;
+ u8 temp_write_buf[THP7312_FLASH_MAX_REG_DATA_SIZE + 2];
+ int ret;
+
+ if (write_size > THP7312_FLASH_MAX_REG_DATA_SIZE) {
+ dev_err(dev, "%s: Write size error size = %d\n",
+ __func__, write_size);
+ return -EINVAL;
+ }
+
+ ret = thp7312_write_buf(thp7312, thp7312_cmd_config_flash_mem_if,
+ sizeof(thp7312_cmd_config_flash_mem_if));
+ if (ret < 0) {
+ dev_err(dev, "%s: Failed to config flash memory IF: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ temp_write_buf[0] = 0xd5;
+ temp_write_buf[1] = 0x00;
+ memcpy((temp_write_buf + 2), write_buf, write_size);
+ ret = thp7312_write_buf(thp7312, temp_write_buf, write_size + 2);
+ if (ret < 0)
+ return ret;
+
+ thp7312_write_buf(thp7312, thp7312_cmd_write_to_reg,
+ sizeof(thp7312_cmd_write_to_reg));
+
+ return 0;
+}
+
+static int __thp7312_flash_reg_read(struct thp7312_device *thp7312,
+ const u8 *write_buf, u16 write_size,
+ u8 *read_buf, u16 read_size)
+{
+ struct i2c_client *client = to_i2c_client(thp7312->dev);
+ struct i2c_msg msgs[2];
+ int ret;
+
+ ret = __thp7312_flash_reg_write(thp7312, write_buf, write_size);
+ if (ret)
+ return ret;
+
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = sizeof(thp7312_cmd_read_reg),
+ msgs[0].buf = (u8 *)thp7312_cmd_read_reg;
+
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = read_size;
+ msgs[1].buf = read_buf;
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ return ret >= 0 ? 0 : ret;
+}
+
+#define thp7312_flash_reg_write(thp7312, wrbuf) \
+ __thp7312_flash_reg_write(thp7312, wrbuf, sizeof(wrbuf))
+
+#define thp7312_flash_reg_read(thp7312, wrbuf, rdbuf) \
+ __thp7312_flash_reg_read(thp7312, wrbuf, sizeof(wrbuf), \
+ rdbuf, sizeof(rdbuf))
+
+static enum fw_upload_err thp7312_fw_prepare_config(struct thp7312_device *thp7312)
+{
+ struct device *dev = thp7312->dev;
+ int ret;
+
+ ret = cci_write(thp7312->regmap, THP7312_REG_FW_MEMORY_IO_SETTING,
+ THP7312_FW_MEMORY_IO_GPIO0, NULL);
+ if (ret) {
+ dev_err(dev, "Failed to set flash memory I/O\n");
+ return FW_UPLOAD_ERR_HW_ERROR;
+ }
+
+ /* Set max drivability. */
+ ret = cci_write(thp7312->regmap, THP7312_REG_FW_DRIVABILITY, 0x00777777,
+ NULL);
+ if (ret) {
+ dev_err(dev, "Failed to set drivability: %d\n", ret);
+ return FW_UPLOAD_ERR_HW_ERROR;
+ }
+
+ return FW_UPLOAD_ERR_NONE;
+}
+
+static enum fw_upload_err thp7312_fw_prepare_check(struct thp7312_device *thp7312)
+{
+ struct device *dev = thp7312->dev;
+ u8 read_buf[3] = { 0 };
+ int ret;
+
+ /* Get JEDEC ID */
+ ret = thp7312_flash_reg_read(thp7312, thp7312_jedec_rdid, read_buf);
+ if (ret) {
+ dev_err(dev, "Failed to get JEDEC ID: %d\n", ret);
+ return FW_UPLOAD_ERR_HW_ERROR;
+ }
+
+ dev_dbg(dev, "Flash Memory: JEDEC ID = 0x%x 0x%x 0x%x\n",
+ read_buf[0], read_buf[1], read_buf[2]);
+
+ return FW_UPLOAD_ERR_NONE;
+}
+
+static enum fw_upload_err thp7312_fw_prepare_reset(struct thp7312_device *thp7312)
+{
+ struct device *dev = thp7312->dev;
+ int ret;
+
+ ret = cci_write(thp7312->regmap, THP7312_REG_FW_RESET_FLASH, 0x81, NULL);
+ if (ret) {
+ dev_err(dev, "Failed to reset flash memory: %d\n", ret);
+ return FW_UPLOAD_ERR_HW_ERROR;
+ }
+
+ return FW_UPLOAD_ERR_NONE;
+}
+
+/* TODO: Erase only the amount of blocks necessary */
+static enum fw_upload_err thp7312_flash_erase(struct thp7312_device *thp7312)
+{
+ struct device *dev = thp7312->dev;
+ u8 read_buf[1] = { 0 };
+ unsigned int i;
+ u8 block;
+ int ret;
+
+ for (block = 0; block < 3; block++) {
+ const u8 jedec_se[] = { SPINOR_OP_SE, block, 0x00, 0x00 };
+
+ ret = thp7312_flash_reg_write(thp7312, thp7312_jedec_wen);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable flash for writing\n");
+ return FW_UPLOAD_ERR_RW_ERROR;
+ }
+
+ ret = thp7312_flash_reg_write(thp7312, jedec_se);
+ if (ret < 0) {
+ dev_err(dev, "Failed to erase flash sector\n");
+ return FW_UPLOAD_ERR_RW_ERROR;
+ }
+
+ for (i = 0; i < THP7312_FLASH_MEMORY_ERASE_TIMEOUT; i++) {
+ usleep_range(100000, 101000);
+ thp7312_flash_reg_read(thp7312, thp7312_jedec_rdsr,
+ read_buf);
+
+ /* Check Busy bit. Busy == 0x0 means erase complete. */
+ if (!(read_buf[0] & SR_WIP))
+ break;
+ }
+
+ if (i == THP7312_FLASH_MEMORY_ERASE_TIMEOUT)
+ return FW_UPLOAD_ERR_TIMEOUT;
+ }
+
+ thp7312_flash_reg_read(thp7312, thp7312_jedec_rdsr, read_buf);
+
+ /* Check WEL bit. */
+ if (read_buf[0] & SR_WEL)
+ return FW_UPLOAD_ERR_HW_ERROR;
+
+ return FW_UPLOAD_ERR_NONE;
+}
+
+static enum fw_upload_err
+thp7312_write_download_data_by_unit(struct thp7312_device *thp7312,
+ unsigned int addr, const u8 *data,
+ unsigned int size)
+{
+ struct device *dev = thp7312->dev;
+ u8 *write_buf = thp7312->fw_write_buf;
+ int ret;
+
+ dev_dbg(dev, "%s: addr = 0x%04x, data = 0x%p, size = %u\n",
+ __func__, addr, data, size);
+
+ write_buf[0] = (addr >> 8) & 0xff;
+ write_buf[1] = (addr >> 0) & 0xff;
+ memcpy(&write_buf[2], data, size);
+
+ /*
+ * THP7312 Firmware download to RAM
+ * Command ID (address to download): 0x0000 - 0x7fff
+ * Format:: 0000 XX XX XX ........ XX
+ */
+ ret = thp7312_write_buf(thp7312, write_buf, size + 2);
+ if (ret < 0)
+ dev_err(dev, "Unit transfer ERROR %s(): ret = %d\n", __func__, ret);
+
+ return ret >= 0 ? FW_UPLOAD_ERR_NONE : FW_UPLOAD_ERR_RW_ERROR;
+}
+
+static enum fw_upload_err thp7312_fw_load_to_ram(struct thp7312_device *thp7312,
+ const u8 *data, u32 size)
+{
+ struct device *dev = thp7312->dev;
+ enum fw_upload_err ret;
+ unsigned int num_banks;
+ unsigned int i, j;
+
+ num_banks = DIV_ROUND_UP(size, THP7312_RAM_BANK_SIZE);
+
+ dev_dbg(dev, "%s: loading %u bytes in SRAM (%u banks)\n", __func__,
+ size, num_banks);
+
+ for (i = 0; i < num_banks; i++) {
+ const u32 bank_addr = 0x10000000 | (i * THP7312_RAM_BANK_SIZE);
+ unsigned int bank_size;
+ unsigned int num_chunks;
+
+ ret = cci_write(thp7312->regmap, THP7312_REG_FW_DEST_BANK_ADDR,
+ bank_addr, NULL);
+ if (ret)
+ return FW_UPLOAD_ERR_HW_ERROR;
+
+ bank_size = min_t(u32, size, THP7312_RAM_BANK_SIZE);
+ num_chunks = DIV_ROUND_UP(bank_size, THP7312_FW_DOWNLOAD_UNIT);
+
+ dev_dbg(dev, "%s: loading %u bytes in SRAM bank %u (%u chunks)\n",
+ __func__, bank_size, i, num_chunks);
+
+ for (j = 0 ; j < num_chunks; j++) {
+ unsigned int chunk_addr;
+ unsigned int chunk_size;
+
+ chunk_addr = j * THP7312_FW_DOWNLOAD_UNIT;
+ chunk_size = min_t(u32, size, THP7312_FW_DOWNLOAD_UNIT);
+
+ ret = thp7312_write_download_data_by_unit(thp7312, chunk_addr,
+ data, chunk_size);
+ if (ret != FW_UPLOAD_ERR_NONE) {
+ dev_err(dev, "Unit transfer ERROR at bank transfer %s(): %d\n",
+ __func__, j);
+ return ret;
+ }
+
+ data += chunk_size;
+ size -= chunk_size;
+ }
+ }
+
+ return FW_UPLOAD_ERR_NONE;
+}
+
+static enum fw_upload_err thp7312_fw_write_to_flash(struct thp7312_device *thp7312,
+ u32 dest, u32 write_size)
+{
+ u8 command[sizeof(thp7312_cmd_write_ram_to_flash) + 6];
+ static const u32 cmd_size = sizeof(thp7312_cmd_write_ram_to_flash);
+ u64 val;
+ int ret;
+
+ memcpy(command, thp7312_cmd_write_ram_to_flash, cmd_size);
+
+ command[cmd_size] = (dest & 0xff0000) >> 16;
+ command[cmd_size + 1] = (dest & 0x00ff00) >> 8;
+ command[cmd_size + 2] = (dest & 0x0000ff);
+ command[cmd_size + 3] = ((write_size - 1) & 0xff0000) >> 16;
+ command[cmd_size + 4] = ((write_size - 1) & 0x00ff00) >> 8;
+ command[cmd_size + 5] = ((write_size - 1) & 0x0000ff);
+
+ ret = thp7312_write_buf(thp7312, command, sizeof(command));
+ if (ret < 0)
+ return FW_UPLOAD_ERR_RW_ERROR;
+
+ usleep_range(8000000, 8100000);
+
+ ret = cci_read(thp7312->regmap, THP7312_REG_FW_VERIFY_RESULT, &val,
+ NULL);
+ if (ret < 0)
+ return FW_UPLOAD_ERR_RW_ERROR;
+
+ return val ? FW_UPLOAD_ERR_HW_ERROR : FW_UPLOAD_ERR_NONE;
+}
+
+static enum fw_upload_err thp7312_fw_check_crc(struct thp7312_device *thp7312,
+ const u8 *fw_data, u32 fw_size)
+{
+ struct device *dev = thp7312->dev;
+ u16 header_size = fw_size - THP7312_FW_RAM_SIZE;
+ u8 command[sizeof(thp7312_cmd_calc_crc) + 6];
+ static const u32 cmd_size = sizeof(thp7312_cmd_calc_crc);
+ u32 size = THP7312_FW_RAM_SIZE - 4;
+ u32 fw_crc;
+ u64 crc;
+ int ret;
+
+ memcpy(command, thp7312_cmd_calc_crc, cmd_size);
+
+ command[cmd_size] = 0;
+ command[cmd_size + 1] = (header_size >> 8) & 0xff;
+ command[cmd_size + 2] = header_size & 0xff;
+
+ command[cmd_size + 3] = (size >> 16) & 0xff;
+ command[cmd_size + 4] = (size >> 8) & 0xff;
+ command[cmd_size + 5] = size & 0xff;
+
+ ret = thp7312_write_buf(thp7312, command, sizeof(command));
+ if (ret < 0)
+ return FW_UPLOAD_ERR_RW_ERROR;
+
+ usleep_range(2000000, 2100000);
+
+ fw_crc = get_unaligned_be32(&fw_data[fw_size - 4]);
+
+ ret = cci_read(thp7312->regmap, THP7312_REG_FW_CRC_RESULT, &crc, NULL);
+ if (ret < 0)
+ return FW_UPLOAD_ERR_RW_ERROR;
+
+ if (fw_crc != crc) {
+ dev_err(dev, "CRC mismatch: firmware 0x%08x, flash 0x%08llx\n",
+ fw_crc, crc);
+ return FW_UPLOAD_ERR_HW_ERROR;
+ }
+
+ return FW_UPLOAD_ERR_NONE;
+}
+
+static enum fw_upload_err thp7312_fw_prepare(struct fw_upload *fw_upload,
+ const u8 *data, u32 size)
+{
+ struct thp7312_device *thp7312 = fw_upload->dd_handle;
+ struct device *dev = thp7312->dev;
+ enum fw_upload_err ret;
+
+ mutex_lock(&thp7312->fw_lock);
+ thp7312->fw_cancel = false;
+ mutex_unlock(&thp7312->fw_lock);
+
+ if (size < THP7312_FW_MIN_SIZE || size > THP7312_FW_MAX_SIZE) {
+ dev_err(dev, "%s: Invalid firmware size %d; must be between %d and %d\n",
+ __func__, size, THP7312_FW_MIN_SIZE, THP7312_FW_MAX_SIZE);
+ return FW_UPLOAD_ERR_INVALID_SIZE;
+ }
+
+ ret = thp7312_fw_prepare_config(thp7312);
+ if (ret != FW_UPLOAD_ERR_NONE)
+ return ret;
+
+ ret = thp7312_fw_prepare_check(thp7312);
+ if (ret != FW_UPLOAD_ERR_NONE)
+ return ret;
+
+ ret = thp7312_fw_prepare_reset(thp7312);
+ if (ret != FW_UPLOAD_ERR_NONE)
+ return ret;
+
+ mutex_lock(&thp7312->fw_lock);
+ ret = thp7312->fw_cancel ? FW_UPLOAD_ERR_CANCELED : FW_UPLOAD_ERR_NONE;
+ mutex_unlock(&thp7312->fw_lock);
+
+ return ret;
+}
+
+static enum fw_upload_err thp7312_fw_write(struct fw_upload *fw_upload,
+ const u8 *data, u32 offset,
+ u32 size, u32 *written)
+{
+ struct thp7312_device *thp7312 = fw_upload->dd_handle;
+ struct device *dev = thp7312->dev;
+ u16 header_size = size - THP7312_FW_RAM_SIZE;
+ enum fw_upload_err ret;
+ bool cancel;
+
+ mutex_lock(&thp7312->fw_lock);
+ cancel = thp7312->fw_cancel;
+ mutex_unlock(&thp7312->fw_lock);
+
+ if (cancel)
+ return FW_UPLOAD_ERR_CANCELED;
+
+ ret = thp7312_flash_erase(thp7312);
+ if (ret != FW_UPLOAD_ERR_NONE)
+ return ret;
+
+ ret = thp7312_fw_load_to_ram(thp7312, data, THP7312_FW_RAM_SIZE);
+ if (ret != FW_UPLOAD_ERR_NONE)
+ return ret;
+
+ ret = thp7312_fw_write_to_flash(thp7312, 0, 0x1ffff);
+ if (ret != FW_UPLOAD_ERR_NONE)
+ return ret;
+
+ ret = thp7312_fw_load_to_ram(thp7312, data + THP7312_FW_RAM_SIZE, header_size);
+ if (ret != FW_UPLOAD_ERR_NONE)
+ return ret;
+
+ ret = thp7312_fw_write_to_flash(thp7312, 0x20000, header_size - 1);
+ if (ret != FW_UPLOAD_ERR_NONE)
+ return ret;
+
+ ret = thp7312_fw_check_crc(thp7312, data, size);
+ if (ret != FW_UPLOAD_ERR_NONE)
+ return ret;
+
+ dev_info(dev, "Successfully wrote firmware\n");
+
+ *written = size;
+ return FW_UPLOAD_ERR_NONE;
+}
+
+static enum fw_upload_err thp7312_fw_poll_complete(struct fw_upload *fw_upload)
+{
+ return FW_UPLOAD_ERR_NONE;
+}
+
+/*
+ * This may be called asynchronously with an on-going update. All other
+ * functions are called sequentially in a single thread. To avoid contention on
+ * register accesses, only update the cancel_request flag. Other functions will
+ * check this flag and handle the cancel request synchronously.
+ */
+static void thp7312_fw_cancel(struct fw_upload *fw_upload)
+{
+ struct thp7312_device *thp7312 = fw_upload->dd_handle;
+
+ mutex_lock(&thp7312->fw_lock);
+ thp7312->fw_cancel = true;
+ mutex_unlock(&thp7312->fw_lock);
+}
+
+static const struct fw_upload_ops thp7312_fw_upload_ops = {
+ .prepare = thp7312_fw_prepare,
+ .write = thp7312_fw_write,
+ .poll_complete = thp7312_fw_poll_complete,
+ .cancel = thp7312_fw_cancel,
+};
+
+static int thp7312_register_flash_mode(struct thp7312_device *thp7312)
+{
+ struct device *dev = thp7312->dev;
+ struct fw_upload *fwl;
+ u64 val;
+ int ret;
+
+ dev_info(dev, "booted in flash mode\n");
+
+ mutex_init(&thp7312->fw_lock);
+
+ thp7312->fw_write_buf = devm_kzalloc(dev, THP7312_FW_DOWNLOAD_UNIT + 2,
+ GFP_KERNEL);
+ if (!thp7312->fw_write_buf)
+ return -ENOMEM;
+
+ ret = __thp7312_power_on(thp7312);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to power on\n");
+
+ ret = cci_read(thp7312->regmap, THP7312_REG_FW_STATUS, &val, NULL);
+ if (ret) {
+ dev_err_probe(dev, ret, "Camera status read failed\n");
+ goto error;
+ }
+
+ fwl = firmware_upload_register(THIS_MODULE, dev, "thp7312-firmware",
+ &thp7312_fw_upload_ops, thp7312);
+ if (IS_ERR(fwl)) {
+ ret = PTR_ERR(fwl);
+ dev_err_probe(dev, ret, "Failed to register firmware upload\n");
+ goto error;
+ }
+
+ thp7312->fwl = fwl;
+ return 0;
+
+error:
+ __thp7312_power_off(thp7312);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Probe & Remove
+ */
+
+static int thp7312_get_regulators(struct thp7312_device *thp7312)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(thp7312->supplies); i++)
+ thp7312->supplies[i].supply = thp7312_supply_name[i];
+
+ return devm_regulator_bulk_get(thp7312->dev,
+ ARRAY_SIZE(thp7312->supplies),
+ thp7312->supplies);
+}
+
+static int thp7312_sensor_parse_dt(struct thp7312_device *thp7312,
+ struct fwnode_handle *node)
+{
+ struct device *dev = thp7312->dev;
+ struct thp7312_sensor *sensor;
+ const char *model;
+ u8 data_lanes[4];
+ u32 values[4];
+ unsigned int i;
+ u32 reg;
+ int ret;
+
+ /* Retrieve the sensor index from the reg property. */
+ ret = fwnode_property_read_u32(node, "reg", &reg);
+ if (ret < 0) {
+ dev_err(dev, "'reg' property missing in sensor node\n");
+ return -EINVAL;
+ }
+
+ if (reg >= ARRAY_SIZE(thp7312->sensors)) {
+ dev_err(dev, "Out-of-bounds 'reg' value %u\n", reg);
+ return -EINVAL;
+ }
+
+ sensor = &thp7312->sensors[reg];
+ if (sensor->info) {
+ dev_err(dev, "Duplicate entry for sensor %u\n", reg);
+ return -EINVAL;
+ }
+
+ ret = fwnode_property_read_string(node, "thine,model", &model);
+ if (ret < 0) {
+ dev_err(dev, "'thine,model' property missing in sensor node\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(thp7312_sensor_info); i++) {
+ const struct thp7312_sensor_info *info =
+ &thp7312_sensor_info[i];
+
+ if (!strcmp(info->model, model)) {
+ sensor->info = info;
+ break;
+ }
+ }
+
+ if (!sensor->info) {
+ dev_err(dev, "Unsupported sensor model %s\n", model);
+ return -EINVAL;
+ }
+
+ ret = fwnode_property_read_u32_array(node, "data-lanes", values,
+ ARRAY_SIZE(values));
+ if (ret < 0) {
+ dev_err(dev, "Failed to read property data-lanes: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(data_lanes); ++i)
+ data_lanes[i] = values[i];
+
+ ret = thp7312_map_data_lanes(&sensor->lane_remap, data_lanes,
+ ARRAY_SIZE(data_lanes));
+ if (ret) {
+ dev_err(dev, "Invalid sensor@%u data-lanes value\n", reg);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int thp7312_parse_dt(struct thp7312_device *thp7312)
+{
+ struct v4l2_fwnode_endpoint ep = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY,
+ };
+ struct device *dev = thp7312->dev;
+ struct fwnode_handle *endpoint;
+ struct fwnode_handle *sensors;
+ unsigned int num_sensors = 0;
+ struct fwnode_handle *node;
+ int ret;
+
+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
+ if (!endpoint)
+ return dev_err_probe(dev, -EINVAL, "Endpoint node not found\n");
+
+ ret = v4l2_fwnode_endpoint_parse(endpoint, &ep);
+ fwnode_handle_put(endpoint);
+ if (ret)
+ return dev_err_probe(dev, ret, "Could not parse endpoint\n");
+
+ ret = thp7312_map_data_lanes(&thp7312->lane_remap,
+ ep.bus.mipi_csi2.data_lanes,
+ ep.bus.mipi_csi2.num_data_lanes);
+ if (ret) {
+ dev_err(dev, "Invalid data-lanes value\n");
+ return ret;
+ }
+
+ /*
+ * The thine,boot-mode property is optional and default to
+ * THP7312_BOOT_MODE_SPI_MASTER (1).
+ */
+ thp7312->boot_mode = THP7312_BOOT_MODE_SPI_MASTER;
+ ret = device_property_read_u32(dev, "thine,boot-mode",
+ &thp7312->boot_mode);
+ if (ret && ret != -EINVAL)
+ return dev_err_probe(dev, ret, "Property '%s' is invalid\n",
+ "thine,boot-mode");
+
+ if (thp7312->boot_mode != THP7312_BOOT_MODE_2WIRE_SLAVE &&
+ thp7312->boot_mode != THP7312_BOOT_MODE_SPI_MASTER)
+ return dev_err_probe(dev, -EINVAL, "Invalid '%s' value %u\n",
+ "thine,boot-mode", thp7312->boot_mode);
+
+ /* Sensors */
+ sensors = device_get_named_child_node(dev, "sensors");
+ if (!sensors) {
+ dev_err(dev, "'sensors' child node not found\n");
+ return -EINVAL;
+ }
+
+ fwnode_for_each_available_child_node(sensors, node) {
+ if (fwnode_name_eq(node, "sensor")) {
+ if (!thp7312_sensor_parse_dt(thp7312, node))
+ num_sensors++;
+ }
+ }
+
+ fwnode_handle_put(sensors);
+
+ if (!num_sensors) {
+ dev_err(dev, "No sensor found\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int thp7312_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct thp7312_device *thp7312;
+ int ret;
+
+ thp7312 = devm_kzalloc(dev, sizeof(*thp7312), GFP_KERNEL);
+ if (!thp7312)
+ return -ENOMEM;
+
+ thp7312->dev = dev;
+
+ thp7312->regmap = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(thp7312->regmap))
+ return dev_err_probe(dev, PTR_ERR(thp7312->regmap),
+ "Unable to initialize I2C\n");
+
+ ret = thp7312_parse_dt(thp7312);
+ if (ret < 0)
+ return ret;
+
+ ret = thp7312_get_regulators(thp7312);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get regulators\n");
+
+ thp7312->iclk = devm_clk_get(dev, NULL);
+ if (IS_ERR(thp7312->iclk))
+ return dev_err_probe(dev, PTR_ERR(thp7312->iclk),
+ "Failed to get iclk\n");
+
+ thp7312->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(thp7312->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(thp7312->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ if (thp7312->boot_mode == THP7312_BOOT_MODE_2WIRE_SLAVE)
+ return thp7312_register_flash_mode(thp7312);
+
+ v4l2_i2c_subdev_init(&thp7312->sd, client, &thp7312_subdev_ops);
+ thp7312->sd.internal_ops = &thp7312_internal_ops;
+ thp7312->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+ thp7312->pad.flags = MEDIA_PAD_FL_SOURCE;
+ thp7312->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ ret = media_entity_pads_init(&thp7312->sd.entity, 1, &thp7312->pad);
+ if (ret)
+ return ret;
+
+ /*
+ * Enable power management. The driver supports runtime PM, but needs to
+ * work when runtime PM is disabled in the kernel. To that end, power
+ * the device manually here.
+ */
+ ret = thp7312_power_on(thp7312);
+ if (ret)
+ goto err_entity_cleanup;
+
+ ret = thp7312_read_firmware_version(thp7312);
+ if (ret < 0) {
+ dev_err(dev, "Camera is not found\n");
+ goto err_power_off;
+ }
+
+ ret = thp7312_init_controls(thp7312);
+ if (ret) {
+ dev_err(dev, "Failed to initialize controls\n");
+ goto err_power_off;
+ }
+
+ thp7312->sd.ctrl_handler = &thp7312->ctrl_handler;
+ thp7312->sd.state_lock = thp7312->ctrl_handler.lock;
+
+ ret = v4l2_subdev_init_finalize(&thp7312->sd);
+ if (ret < 0) {
+ dev_err(dev, "Subdev active state initialization failed\n");
+ goto err_free_ctrls;
+ }
+
+ /*
+ * Enable runtime PM with autosuspend. As the device has been powered
+ * manually, mark it as active, and increase the usage count without
+ * resuming the device.
+ */
+ pm_runtime_set_active(dev);
+ pm_runtime_get_noresume(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+
+ ret = v4l2_async_register_subdev(&thp7312->sd);
+ if (ret < 0) {
+ dev_err(dev, "Subdev registration failed\n");
+ goto err_pm;
+ }
+
+ /*
+ * Decrease the PM usage count. The device will get suspended after the
+ * autosuspend delay, turning the power off.
+ */
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ dev_info(dev, "THP7312 firmware version %02u.%02u\n",
+ THP7312_FW_VERSION_MAJOR(thp7312->fw_version),
+ THP7312_FW_VERSION_MINOR(thp7312->fw_version));
+
+ return 0;
+
+err_pm:
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
+ v4l2_subdev_cleanup(&thp7312->sd);
+err_free_ctrls:
+ v4l2_ctrl_handler_free(&thp7312->ctrl_handler);
+err_power_off:
+ thp7312_power_off(thp7312);
+err_entity_cleanup:
+ media_entity_cleanup(&thp7312->sd.entity);
+ return ret;
+}
+
+static void thp7312_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct thp7312_device *thp7312 = to_thp7312_dev(sd);
+
+ if (thp7312->boot_mode == THP7312_BOOT_MODE_2WIRE_SLAVE) {
+ firmware_upload_unregister(thp7312->fwl);
+ __thp7312_power_off(thp7312);
+ return;
+ }
+
+ v4l2_async_unregister_subdev(&thp7312->sd);
+ v4l2_subdev_cleanup(&thp7312->sd);
+ media_entity_cleanup(&thp7312->sd.entity);
+ v4l2_ctrl_handler_free(&thp7312->ctrl_handler);
+
+ /*
+ * Disable runtime PM. In case runtime PM is disabled in the kernel,
+ * make sure to turn power off manually.
+ */
+ pm_runtime_disable(thp7312->dev);
+ if (!pm_runtime_status_suspended(thp7312->dev))
+ thp7312_power_off(thp7312);
+ pm_runtime_set_suspended(thp7312->dev);
+}
+
+static const struct of_device_id thp7312_dt_ids[] = {
+ { .compatible = "thine,thp7312" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, thp7312_dt_ids);
+
+static struct i2c_driver thp7312_i2c_driver = {
+ .driver = {
+ .name = "thp7312",
+ .pm = &thp7312_pm_ops,
+ .of_match_table = thp7312_dt_ids,
+ },
+ .probe = thp7312_probe,
+ .remove = thp7312_remove,
+};
+
+module_i2c_driver(thp7312_i2c_driver);
+
+MODULE_DESCRIPTION("THP7312 MIPI Camera Subdev Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index c37f605cb75f..5a561e5bf659 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -738,20 +738,20 @@ static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl)
return err;
}
-/**
- * tvp514x_g_frame_interval() - V4L2 decoder interface handler
- * @sd: pointer to standard V4L2 sub-device structure
- * @ival: pointer to a v4l2_subdev_frame_interval structure
- *
- * Returns the decoder's video CAPTURE parameters.
- */
static int
-tvp514x_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
+tvp514x_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
enum tvp514x_std current_std;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
/* get the current standard */
current_std = decoder->current_std;
@@ -762,22 +762,21 @@ tvp514x_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-/**
- * tvp514x_s_frame_interval() - V4L2 decoder interface handler
- * @sd: pointer to standard V4L2 sub-device structure
- * @ival: pointer to a v4l2_subdev_frame_interval structure
- *
- * Configures the decoder to use the input parameters, if possible. If
- * not possible, returns the appropriate error code.
- */
static int
-tvp514x_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *ival)
+tvp514x_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *ival)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
struct v4l2_fract *timeperframe;
enum tvp514x_std current_std;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
timeperframe = &ival->interval;
@@ -940,8 +939,6 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
.s_std = tvp514x_s_std,
.s_routing = tvp514x_s_routing,
.querystd = tvp514x_querystd,
- .g_frame_interval = tvp514x_g_frame_interval,
- .s_frame_interval = tvp514x_s_frame_interval,
.s_stream = tvp514x_s_stream,
};
@@ -949,6 +946,8 @@ static const struct v4l2_subdev_pad_ops tvp514x_pad_ops = {
.enum_mbus_code = tvp514x_enum_mbus_code,
.get_fmt = tvp514x_get_pad_format,
.set_fmt = tvp514x_set_pad_format,
+ .get_frame_interval = tvp514x_get_frame_interval,
+ .set_frame_interval = tvp514x_set_frame_interval,
};
static const struct v4l2_subdev_ops tvp514x_ops = {
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index e543b3f7a4d8..9fc586cfdcd8 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1035,7 +1035,7 @@ tvp5150_get_pad_crop(struct tvp5150 *decoder,
return &decoder->rect;
case V4L2_SUBDEV_FORMAT_TRY:
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
- return v4l2_subdev_get_try_crop(&decoder->sd, sd_state, pad);
+ return v4l2_subdev_state_get_crop(sd_state, pad);
#else
return ERR_PTR(-EINVAL);
#endif
@@ -1209,8 +1209,8 @@ static int tvp5150_get_mbus_config(struct v4l2_subdev *sd,
/****************************************************************************
V4L2 subdev pad ops
****************************************************************************/
-static int tvp5150_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int tvp5150_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct tvp5150 *decoder = to_tvp5150(sd);
v4l2_std_id std;
@@ -1722,7 +1722,6 @@ static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
};
static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = {
- .init_cfg = tvp5150_init_cfg,
.enum_mbus_code = tvp5150_enum_mbus_code,
.enum_frame_size = tvp5150_enum_frame_size,
.set_fmt = tvp5150_fill_fmt,
@@ -1741,6 +1740,7 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
};
static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
+ .init_state = tvp5150_init_state,
.registered = tvp5150_registered,
.open = tvp5150_open,
.close = tvp5150_close,
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index a2d7bc799849..30831b4b56d6 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -791,7 +791,7 @@ static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = {
/*
* tvp7002_enum_mbus_code() - Enum supported digital video format on pad
* @sd: pointer to standard V4L2 sub-device structure
- * @cfg: pad configuration
+ * @sd_state: V4L2 subdev state
* @code: pointer to subdev enum mbus code struct
*
* Enumerate supported digital video formats for pad.
@@ -813,7 +813,7 @@ tvp7002_enum_mbus_code(struct v4l2_subdev *sd,
/*
* tvp7002_get_pad_format() - get video format on pad
* @sd: pointer to standard V4L2 sub-device structure
- * @cfg: pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to subdev format struct
*
* get video format for pad.
@@ -837,7 +837,7 @@ tvp7002_get_pad_format(struct v4l2_subdev *sd,
/*
* tvp7002_set_pad_format() - set video format on pad
* @sd: pointer to standard V4L2 sub-device structure
- * @cfg: pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to subdev format struct
*
* set video format for pad.
diff --git a/drivers/media/i2c/tw9900.c b/drivers/media/i2c/tw9900.c
new file mode 100644
index 000000000000..bc7623ec46e5
--- /dev/null
+++ b/drivers/media/i2c/tw9900.c
@@ -0,0 +1,781 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the Techwell TW9900 multi-standard video decoder.
+ *
+ * Copyright (C) 2018 Fuzhou Rockchip Electronics Co., Ltd.
+ * Copyright (C) 2020 Maxime Chevallier <[email protected]>
+ * Copyright (C) 2023 Mehdi Djait <[email protected]>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-subdev.h>
+
+#define TW9900_REG_CHIP_ID 0x00
+#define TW9900_REG_CHIP_STATUS 0x01
+#define TW9900_REG_CHIP_STATUS_VDLOSS BIT(7)
+#define TW9900_REG_CHIP_STATUS_HLOCK BIT(6)
+#define TW9900_REG_OUT_FMT_CTL 0x03
+#define TW9900_REG_OUT_FMT_CTL_STANDBY 0xA7
+#define TW9900_REG_OUT_FMT_CTL_STREAMING 0xA0
+#define TW9900_REG_CKHY_HSDLY 0x04
+#define TW9900_REG_OUT_CTRL_I 0x05
+#define TW9900_REG_ANALOG_CTL 0x06
+#define TW9900_REG_CROP_HI 0x07
+#define TW9900_REG_VDELAY_LO 0x08
+#define TW9900_REG_VACTIVE_LO 0x09
+#define TW9900_REG_HACTIVE_LO 0x0B
+#define TW9900_REG_CNTRL1 0x0C
+#define TW9900_REG_BRIGHT_CTL 0x10
+#define TW9900_REG_CONTRAST_CTL 0x11
+#define TW9900_REG_VBI_CNTL 0x19
+#define TW9900_REG_ANAL_CTL_II 0x1A
+#define TW9900_REG_OUT_CTRL_II 0x1B
+#define TW9900_REG_STD 0x1C
+#define TW9900_REG_STD_AUTO_PROGRESS BIT(7)
+#define TW9900_STDNOW_MASK GENMASK(6, 4)
+#define TW9900_REG_STDR 0x1D
+#define TW9900_REG_MISSCNT 0x26
+#define TW9900_REG_MISC_CTL_II 0x2F
+#define TW9900_REG_VVBI 0x55
+
+#define TW9900_CHIP_ID 0x00
+#define TW9900_STD_NTSC_M 0
+#define TW9900_STD_PAL_BDGHI 1
+#define TW9900_STD_AUTO 7
+
+#define TW9900_VIDEO_POLL_TRIES 20
+
+struct regval {
+ u8 addr;
+ u8 val;
+};
+
+struct tw9900_mode {
+ u32 width;
+ u32 height;
+ u32 std;
+ const struct regval *reg_list;
+ int n_regs;
+};
+
+struct tw9900 {
+ struct i2c_client *client;
+ struct gpio_desc *reset_gpio;
+ struct regulator *regulator;
+
+ struct v4l2_subdev subdev;
+ struct v4l2_ctrl_handler hdl;
+ struct media_pad pad;
+
+ /* Serialize access to hardware and global state. */
+ struct mutex mutex;
+
+ bool streaming;
+ const struct tw9900_mode *cur_mode;
+};
+
+#define to_tw9900(sd) container_of(sd, struct tw9900, subdev)
+
+static const struct regval tw9900_init_regs[] = {
+ { TW9900_REG_MISC_CTL_II, 0xE6 },
+ { TW9900_REG_MISSCNT, 0x24 },
+ { TW9900_REG_OUT_FMT_CTL, 0xA7 },
+ { TW9900_REG_ANAL_CTL_II, 0x0A },
+ { TW9900_REG_VDELAY_LO, 0x19 },
+ { TW9900_REG_STD, 0x00 },
+ { TW9900_REG_VACTIVE_LO, 0xF0 },
+ { TW9900_REG_STD, 0x07 },
+ { TW9900_REG_CKHY_HSDLY, 0x00 },
+ { TW9900_REG_ANALOG_CTL, 0x80 },
+ { TW9900_REG_CNTRL1, 0xDC },
+ { TW9900_REG_OUT_CTRL_I, 0x98 },
+};
+
+static const struct regval tw9900_pal_regs[] = {
+ { TW9900_REG_STD, 0x01 },
+};
+
+static const struct regval tw9900_ntsc_regs[] = {
+ { TW9900_REG_OUT_FMT_CTL, 0xA4 },
+ { TW9900_REG_VDELAY_LO, 0x12 },
+ { TW9900_REG_VACTIVE_LO, 0xF0 },
+ { TW9900_REG_CROP_HI, 0x02 },
+ { TW9900_REG_HACTIVE_LO, 0xD0 },
+ { TW9900_REG_VBI_CNTL, 0x01 },
+ { TW9900_REG_STD, 0x00 },
+};
+
+static const struct tw9900_mode supported_modes[] = {
+ {
+ .width = 720,
+ .height = 480,
+ .std = V4L2_STD_NTSC,
+ .reg_list = tw9900_ntsc_regs,
+ .n_regs = ARRAY_SIZE(tw9900_ntsc_regs),
+ },
+ {
+ .width = 720,
+ .height = 576,
+ .std = V4L2_STD_PAL,
+ .reg_list = tw9900_pal_regs,
+ .n_regs = ARRAY_SIZE(tw9900_pal_regs),
+ },
+};
+
+static int tw9900_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, reg, val);
+ if (ret < 0)
+ dev_err(&client->dev, "write reg error: %d\n", ret);
+
+ return ret;
+}
+
+static int tw9900_write_array(struct i2c_client *client,
+ const struct regval *regs, int n_regs)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < n_regs; i++) {
+ ret = tw9900_write_reg(client, regs[i].addr, regs[i].val);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tw9900_read_reg(struct i2c_client *client, u8 reg)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0)
+ dev_err(&client->dev, "read reg error: %d\n", ret);
+
+ return ret;
+}
+
+static void tw9900_fill_fmt(const struct tw9900_mode *mode,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->quantization = V4L2_QUANTIZATION_DEFAULT;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SMPTE170M);
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SMPTE170M);
+}
+
+static int tw9900_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct tw9900 *tw9900 = to_tw9900(sd);
+ struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
+
+ mutex_lock(&tw9900->mutex);
+ tw9900_fill_fmt(tw9900->cur_mode, mbus_fmt);
+ mutex_unlock(&tw9900->mutex);
+
+ return 0;
+}
+
+static int tw9900_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct tw9900 *tw9900 = to_tw9900(sd);
+ struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
+
+ mutex_lock(&tw9900->mutex);
+
+ if (tw9900->streaming) {
+ mutex_unlock(&tw9900->mutex);
+ return -EBUSY;
+ }
+
+ tw9900_fill_fmt(tw9900->cur_mode, mbus_fmt);
+
+ mutex_unlock(&tw9900->mutex);
+
+ return 0;
+}
+
+static int tw9900_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index > 0)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_UYVY8_2X8;
+
+ return 0;
+}
+
+static int tw9900_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct tw9900 *tw9900 = container_of(ctrl->handler, struct tw9900, hdl);
+ int ret;
+
+ if (pm_runtime_suspended(&tw9900->client->dev))
+ return 0;
+
+ /* v4l2_ctrl_lock() locks tw9900->mutex. */
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ret = tw9900_write_reg(tw9900->client, TW9900_REG_BRIGHT_CTL,
+ (u8)ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ ret = tw9900_write_reg(tw9900->client, TW9900_REG_CONTRAST_CTL,
+ (u8)ctrl->val);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int tw9900_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct tw9900 *tw9900 = to_tw9900(sd);
+ struct i2c_client *client = tw9900->client;
+ int ret;
+
+ mutex_lock(&tw9900->mutex);
+
+ if (tw9900->streaming == on) {
+ mutex_unlock(&tw9900->mutex);
+ return 0;
+ }
+
+ mutex_unlock(&tw9900->mutex);
+
+ if (on) {
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&tw9900->mutex);
+
+ ret = __v4l2_ctrl_handler_setup(sd->ctrl_handler);
+ if (ret)
+ goto err_unlock;
+
+ ret = tw9900_write_array(tw9900->client,
+ tw9900->cur_mode->reg_list,
+ tw9900->cur_mode->n_regs);
+ if (ret)
+ goto err_unlock;
+
+ ret = tw9900_write_reg(client, TW9900_REG_OUT_FMT_CTL,
+ TW9900_REG_OUT_FMT_CTL_STREAMING);
+ if (ret)
+ goto err_unlock;
+
+ tw9900->streaming = on;
+
+ mutex_unlock(&tw9900->mutex);
+
+ } else {
+ mutex_lock(&tw9900->mutex);
+
+ ret = tw9900_write_reg(client, TW9900_REG_OUT_FMT_CTL,
+ TW9900_REG_OUT_FMT_CTL_STANDBY);
+ if (ret)
+ goto err_unlock;
+
+ tw9900->streaming = on;
+
+ mutex_unlock(&tw9900->mutex);
+
+ pm_runtime_put(&client->dev);
+ }
+
+ return 0;
+
+err_unlock:
+ mutex_unlock(&tw9900->mutex);
+ pm_runtime_put(&client->dev);
+
+ return ret;
+}
+
+static int tw9900_subscribe_event(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ switch (sub->type) {
+ case V4L2_EVENT_SOURCE_CHANGE:
+ return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
+ case V4L2_EVENT_CTRL:
+ return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tw9900_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct tw9900 *tw9900 = to_tw9900(sd);
+ const struct tw9900_mode *mode = NULL;
+ int i;
+
+ if (!(std & (V4L2_STD_NTSC | V4L2_STD_PAL)))
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(supported_modes); i++)
+ if (supported_modes[i].std & std)
+ mode = &supported_modes[i];
+ if (!mode)
+ return -EINVAL;
+
+ mutex_lock(&tw9900->mutex);
+ tw9900->cur_mode = mode;
+ mutex_unlock(&tw9900->mutex);
+
+ return 0;
+}
+
+static int tw9900_get_stream_std(struct tw9900 *tw9900,
+ v4l2_std_id *std)
+{
+ int cur_std, ret;
+
+ lockdep_assert_held(&tw9900->mutex);
+
+ ret = tw9900_read_reg(tw9900->client, TW9900_REG_STD);
+ if (ret < 0) {
+ *std = V4L2_STD_UNKNOWN;
+ return ret;
+ }
+
+ cur_std = FIELD_GET(TW9900_STDNOW_MASK, ret);
+ switch (cur_std) {
+ case TW9900_STD_NTSC_M:
+ *std = V4L2_STD_NTSC;
+ break;
+ case TW9900_STD_PAL_BDGHI:
+ *std = V4L2_STD_PAL;
+ break;
+ case TW9900_STD_AUTO:
+ *std = V4L2_STD_UNKNOWN;
+ break;
+ default:
+ *std = V4L2_STD_UNKNOWN;
+ break;
+ }
+
+ return 0;
+}
+
+static int tw9900_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct tw9900 *tw9900 = to_tw9900(sd);
+
+ mutex_lock(&tw9900->mutex);
+ *std = tw9900->cur_mode->std;
+ mutex_unlock(&tw9900->mutex);
+
+ return 0;
+}
+
+static int tw9900_start_autodetect(struct tw9900 *tw9900)
+{
+ int ret;
+
+ lockdep_assert_held(&tw9900->mutex);
+
+ ret = tw9900_write_reg(tw9900->client, TW9900_REG_STDR,
+ BIT(TW9900_STD_NTSC_M) |
+ BIT(TW9900_STD_PAL_BDGHI));
+ if (ret)
+ return ret;
+
+ ret = tw9900_write_reg(tw9900->client, TW9900_REG_STD,
+ TW9900_STD_AUTO);
+ if (ret)
+ return ret;
+
+ ret = tw9900_write_reg(tw9900->client, TW9900_REG_STDR,
+ BIT(TW9900_STD_NTSC_M) |
+ BIT(TW9900_STD_PAL_BDGHI) |
+ BIT(TW9900_STD_AUTO));
+ if (ret)
+ return ret;
+
+ /*
+ * Autodetect takes a while to start, and during the starting sequence
+ * the autodetection status is reported as done.
+ */
+ msleep(30);
+
+ return 0;
+}
+
+static int tw9900_detect_done(struct tw9900 *tw9900, bool *done)
+{
+ int ret;
+
+ lockdep_assert_held(&tw9900->mutex);
+
+ ret = tw9900_read_reg(tw9900->client, TW9900_REG_STD);
+ if (ret < 0)
+ return ret;
+
+ *done = !(ret & TW9900_REG_STD_AUTO_PROGRESS);
+
+ return 0;
+}
+
+static int tw9900_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ struct tw9900 *tw9900 = to_tw9900(sd);
+ bool done = false;
+ int i, ret;
+
+ mutex_lock(&tw9900->mutex);
+
+ if (tw9900->streaming) {
+ mutex_unlock(&tw9900->mutex);
+ return -EBUSY;
+ }
+
+ mutex_unlock(&tw9900->mutex);
+
+ ret = pm_runtime_resume_and_get(&tw9900->client->dev);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&tw9900->mutex);
+
+ ret = tw9900_start_autodetect(tw9900);
+ if (ret)
+ goto out_unlock;
+
+ for (i = 0; i < TW9900_VIDEO_POLL_TRIES; i++) {
+ ret = tw9900_detect_done(tw9900, &done);
+ if (ret)
+ goto out_unlock;
+
+ if (done)
+ break;
+
+ msleep(20);
+ }
+
+ if (!done) {
+ ret = -ETIMEDOUT;
+ goto out_unlock;
+ }
+
+ ret = tw9900_get_stream_std(tw9900, std);
+
+out_unlock:
+ mutex_unlock(&tw9900->mutex);
+ pm_runtime_put(&tw9900->client->dev);
+
+ return ret;
+}
+
+static int tw9900_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+ *std = V4L2_STD_NTSC | V4L2_STD_PAL;
+
+ return 0;
+}
+
+static int tw9900_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+ struct tw9900 *tw9900 = to_tw9900(sd);
+ int ret;
+
+ mutex_lock(&tw9900->mutex);
+
+ if (tw9900->streaming) {
+ mutex_unlock(&tw9900->mutex);
+ return -EBUSY;
+ }
+
+ mutex_unlock(&tw9900->mutex);
+
+ *status = V4L2_IN_ST_NO_SIGNAL;
+
+ ret = pm_runtime_resume_and_get(&tw9900->client->dev);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&tw9900->mutex);
+ ret = tw9900_read_reg(tw9900->client, TW9900_REG_CHIP_STATUS);
+ mutex_unlock(&tw9900->mutex);
+
+ pm_runtime_put(&tw9900->client->dev);
+
+ if (ret < 0)
+ return ret;
+
+ *status = ret & TW9900_REG_CHIP_STATUS_HLOCK ? 0 : V4L2_IN_ST_NO_SIGNAL;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops tw9900_core_ops = {
+ .subscribe_event = tw9900_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops tw9900_video_ops = {
+ .s_std = tw9900_s_std,
+ .g_std = tw9900_g_std,
+ .querystd = tw9900_querystd,
+ .g_tvnorms = tw9900_g_tvnorms,
+ .g_input_status = tw9900_g_input_status,
+ .s_stream = tw9900_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops tw9900_pad_ops = {
+ .enum_mbus_code = tw9900_enum_mbus_code,
+ .get_fmt = tw9900_get_fmt,
+ .set_fmt = tw9900_set_fmt,
+};
+
+static const struct v4l2_subdev_ops tw9900_subdev_ops = {
+ .core = &tw9900_core_ops,
+ .video = &tw9900_video_ops,
+ .pad = &tw9900_pad_ops,
+};
+
+static const struct v4l2_ctrl_ops tw9900_ctrl_ops = {
+ .s_ctrl = tw9900_s_ctrl,
+};
+
+static int tw9900_check_id(struct tw9900 *tw9900,
+ struct i2c_client *client)
+{
+ struct device *dev = &tw9900->client->dev;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(&tw9900->client->dev);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&tw9900->mutex);
+ ret = tw9900_read_reg(client, TW9900_CHIP_ID);
+ mutex_unlock(&tw9900->mutex);
+
+ pm_runtime_put(&tw9900->client->dev);
+
+ if (ret < 0)
+ return ret;
+
+ if (ret != TW9900_CHIP_ID) {
+ dev_err(dev, "Unexpected decoder id %#x\n", ret);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int tw9900_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct tw9900 *tw9900 = to_tw9900(sd);
+ int ret;
+
+ mutex_lock(&tw9900->mutex);
+
+ if (tw9900->reset_gpio)
+ gpiod_set_value_cansleep(tw9900->reset_gpio, 1);
+
+ ret = regulator_enable(tw9900->regulator);
+ if (ret < 0) {
+ mutex_unlock(&tw9900->mutex);
+ return ret;
+ }
+
+ usleep_range(50000, 52000);
+
+ if (tw9900->reset_gpio)
+ gpiod_set_value_cansleep(tw9900->reset_gpio, 0);
+
+ usleep_range(1000, 2000);
+
+ ret = tw9900_write_array(tw9900->client, tw9900_init_regs,
+ ARRAY_SIZE(tw9900_init_regs));
+
+ mutex_unlock(&tw9900->mutex);
+
+ /* This sleep is needed for the Horizontal Sync PLL to lock. */
+ msleep(300);
+
+ return ret;
+}
+
+static int tw9900_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct tw9900 *tw9900 = to_tw9900(sd);
+
+ mutex_lock(&tw9900->mutex);
+
+ if (tw9900->reset_gpio)
+ gpiod_set_value_cansleep(tw9900->reset_gpio, 1);
+
+ regulator_disable(tw9900->regulator);
+
+ mutex_unlock(&tw9900->mutex);
+
+ return 0;
+}
+
+static int tw9900_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct v4l2_ctrl_handler *hdl;
+ struct tw9900 *tw9900;
+ int ret = 0;
+
+ tw9900 = devm_kzalloc(dev, sizeof(*tw9900), GFP_KERNEL);
+ if (!tw9900)
+ return -ENOMEM;
+
+ tw9900->client = client;
+ tw9900->cur_mode = &supported_modes[0];
+
+ tw9900->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(tw9900->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(tw9900->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ tw9900->regulator = devm_regulator_get(&tw9900->client->dev, "vdd");
+ if (IS_ERR(tw9900->regulator))
+ return dev_err_probe(dev, PTR_ERR(tw9900->regulator),
+ "Failed to get power regulator\n");
+
+ v4l2_i2c_subdev_init(&tw9900->subdev, client, &tw9900_subdev_ops);
+ tw9900->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
+
+ mutex_init(&tw9900->mutex);
+
+ hdl = &tw9900->hdl;
+
+ ret = v4l2_ctrl_handler_init(hdl, 2);
+ if (ret)
+ goto err_destory_mutex;
+
+ hdl->lock = &tw9900->mutex;
+
+ v4l2_ctrl_new_std(hdl, &tw9900_ctrl_ops, V4L2_CID_BRIGHTNESS,
+ -128, 127, 1, 0);
+ v4l2_ctrl_new_std(hdl, &tw9900_ctrl_ops, V4L2_CID_CONTRAST,
+ 0, 255, 1, 0x60);
+
+ tw9900->subdev.ctrl_handler = hdl;
+ if (hdl->error) {
+ ret = hdl->error;
+ goto err_free_handler;
+ }
+
+ tw9900->pad.flags = MEDIA_PAD_FL_SOURCE;
+ tw9900->subdev.entity.function = MEDIA_ENT_F_DV_DECODER;
+
+ ret = media_entity_pads_init(&tw9900->subdev.entity, 1, &tw9900->pad);
+ if (ret < 0)
+ goto err_free_handler;
+
+ pm_runtime_set_suspended(dev);
+ pm_runtime_enable(dev);
+
+ ret = tw9900_check_id(tw9900, client);
+ if (ret)
+ goto err_disable_pm;
+
+ ret = v4l2_async_register_subdev(&tw9900->subdev);
+ if (ret) {
+ dev_err(dev, "v4l2 async register subdev failed\n");
+ goto err_disable_pm;
+ }
+
+ return 0;
+
+err_disable_pm:
+ pm_runtime_disable(dev);
+ media_entity_cleanup(&tw9900->subdev.entity);
+err_free_handler:
+ v4l2_ctrl_handler_free(hdl);
+err_destory_mutex:
+ mutex_destroy(&tw9900->mutex);
+
+ return ret;
+}
+
+static void tw9900_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct tw9900 *tw9900 = to_tw9900(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
+
+ pm_runtime_disable(&client->dev);
+
+ mutex_destroy(&tw9900->mutex);
+}
+
+static const struct dev_pm_ops tw9900_pm_ops = {
+ .runtime_suspend = tw9900_runtime_suspend,
+ .runtime_resume = tw9900_runtime_resume,
+};
+
+static const struct i2c_device_id tw9900_id[] = {
+ { "tw9900", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tw9900_id);
+
+static const struct of_device_id tw9900_of_match[] = {
+ { .compatible = "techwell,tw9900" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tw9900_of_match);
+
+static struct i2c_driver tw9900_i2c_driver = {
+ .driver = {
+ .name = "tw9900",
+ .pm = &tw9900_pm_ops,
+ .of_match_table = tw9900_of_match,
+ },
+ .probe = tw9900_probe,
+ .remove = tw9900_remove,
+ .id_table = tw9900_id,
+};
+
+module_i2c_driver(tw9900_i2c_driver);
+
+MODULE_DESCRIPTION("tw9900 decoder driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c
index 477a64d8f8ab..905af98c7d53 100644
--- a/drivers/media/i2c/tw9910.c
+++ b/drivers/media/i2c/tw9910.c
@@ -829,8 +829,6 @@ static int tw9910_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return tw9910_s_fmt(sd, mf);
- sd_state->pads->try_fmt = *mf;
-
return 0;
}
diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c
index 178bd06cc2ed..56dbe07a1c99 100644
--- a/drivers/media/i2c/video-i2c.c
+++ b/drivers/media/i2c/video-i2c.c
@@ -405,9 +405,10 @@ static int queue_setup(struct vb2_queue *vq,
{
struct video_i2c_data *data = vb2_get_drv_priv(vq);
unsigned int size = data->chip->buffer_size;
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
- if (vq->num_buffers + *nbuffers < 2)
- *nbuffers = 2;
+ if (q_num_bufs + *nbuffers < 2)
+ *nbuffers = 2 - q_num_bufs;
if (*nplanes)
return sizes[0] < size ? -EINVAL : 0;
@@ -794,7 +795,7 @@ static int video_i2c_probe(struct i2c_client *client)
queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
queue->drv_priv = data;
queue->buf_struct_size = sizeof(struct video_i2c_buffer);
- queue->min_buffers_needed = 1;
+ queue->min_queued_buffers = 1;
queue->ops = &video_i2c_video_qops;
queue->mem_ops = &vb2_vmalloc_memops;
diff --git a/drivers/media/mc/Kconfig b/drivers/media/mc/Kconfig
index 375b09612981..c82b07d2ef36 100644
--- a/drivers/media/mc/Kconfig
+++ b/drivers/media/mc/Kconfig
@@ -11,10 +11,3 @@ config MEDIA_CONTROLLER_DVB
Enable the media controller API support for DVB.
This is currently experimental.
-
-config MEDIA_CONTROLLER_REQUEST_API
- bool
- depends on MEDIA_CONTROLLER
- help
- This option enables the Request API for the Media controller and V4L2
- interfaces. It is currently needed by a few stateless codec drivers.
diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c
index 8cee956e38d4..c0dd4ae57227 100644
--- a/drivers/media/mc/mc-device.c
+++ b/drivers/media/mc/mc-device.c
@@ -372,16 +372,12 @@ static long media_device_get_topology(struct media_device *mdev, void *arg)
static long media_device_request_alloc(struct media_device *mdev, void *arg)
{
-#ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API
int *alloc_fd = arg;
if (!mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue)
return -ENOTTY;
return media_request_alloc(mdev, alloc_fd);
-#else
- return -ENOTTY;
-#endif
}
static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd)
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 09a193bb87df..511f013cc338 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -1536,13 +1536,11 @@ static void buf_cleanup(struct vb2_buffer *vb)
static int start_streaming(struct vb2_queue *q, unsigned int count)
{
- int ret = 1;
int seqnr = 0;
struct bttv_buffer *buf;
struct bttv *btv = vb2_get_drv_priv(q);
- ret = check_alloc_btres_lock(btv, RESOURCE_VIDEO_STREAM);
- if (ret == 0) {
+ if (!check_alloc_btres_lock(btv, RESOURCE_VIDEO_STREAM)) {
if (btv->field_count)
seqnr++;
while (!list_empty(&btv->capture)) {
@@ -1553,7 +1551,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
vb2_buffer_done(&buf->vbuf.vb2_buf,
VB2_BUF_STATE_QUEUED);
}
- return !ret;
+ return -EBUSY;
}
if (!vb2_is_streaming(&btv->vbiq)) {
init_irqreg(btv);
@@ -2774,6 +2772,27 @@ bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
return;
wakeup->vbuf.vb2_buf.timestamp = ktime_get_ns();
wakeup->vbuf.sequence = btv->field_count >> 1;
+
+ /*
+ * Ugly hack for backwards compatibility.
+ * Some applications expect that the last 4 bytes of
+ * the VBI data contains the sequence number.
+ *
+ * This makes it possible to associate the VBI data
+ * with the video frame if you use read() to get the
+ * VBI data.
+ */
+ if (vb2_fileio_is_active(wakeup->vbuf.vb2_buf.vb2_queue)) {
+ u32 *vaddr = vb2_plane_vaddr(&wakeup->vbuf.vb2_buf, 0);
+ unsigned long size =
+ vb2_get_plane_payload(&wakeup->vbuf.vb2_buf, 0) / 4;
+
+ if (vaddr && size) {
+ vaddr += size - 1;
+ *vaddr = wakeup->vbuf.sequence;
+ }
+ }
+
vb2_buffer_done(&wakeup->vbuf.vb2_buf, state);
if (btv->field_count == 0)
btor(BT848_INT_VSYNC, BT848_INT_MASK);
@@ -3094,7 +3113,7 @@ static int vdev_init(struct bttv *btv, struct video_device *vfd,
q->gfp_flags = __GFP_DMA32;
q->buf_struct_size = sizeof(struct bttv_buffer);
q->lock = &btv->lock;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->dev = &btv->c.pci->dev;
err = vb2_queue_init(q);
if (err)
diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c
index ab213e51ec95..e489a3acb4b9 100644
--- a/drivers/media/pci/bt8xx/bttv-vbi.c
+++ b/drivers/media/pci/bt8xx/bttv-vbi.c
@@ -123,14 +123,12 @@ static void buf_cleanup_vbi(struct vb2_buffer *vb)
static int start_streaming_vbi(struct vb2_queue *q, unsigned int count)
{
- int ret;
int seqnr = 0;
struct bttv_buffer *buf;
struct bttv *btv = vb2_get_drv_priv(q);
btv->framedrop = 0;
- ret = check_alloc_btres_lock(btv, RESOURCE_VBI);
- if (ret == 0) {
+ if (!check_alloc_btres_lock(btv, RESOURCE_VBI)) {
if (btv->field_count)
seqnr++;
while (!list_empty(&btv->vcapture)) {
@@ -141,13 +139,13 @@ static int start_streaming_vbi(struct vb2_queue *q, unsigned int count)
vb2_buffer_done(&buf->vbuf.vb2_buf,
VB2_BUF_STATE_QUEUED);
}
- return !ret;
+ return -EBUSY;
}
if (!vb2_is_streaming(&btv->capq)) {
init_irqreg(btv);
btv->field_count = 0;
}
- return !ret;
+ return 0;
}
static void stop_streaming_vbi(struct vb2_queue *q)
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c
index 26bf58d17a3d..77ba08ace29f 100644
--- a/drivers/media/pci/cobalt/cobalt-v4l2.c
+++ b/drivers/media/pci/cobalt/cobalt-v4l2.c
@@ -1260,7 +1260,7 @@ static int cobalt_node_register(struct cobalt *cobalt, int node)
q->ops = &cobalt_qops;
q->mem_ops = &vb2_dma_sg_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->lock = &s->lock;
q->dev = &cobalt->pci_dev->dev;
vdev->queue = q;
diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c
index 597472754c4c..acc6418db425 100644
--- a/drivers/media/pci/cx18/cx18-streams.c
+++ b/drivers/media/pci/cx18/cx18-streams.c
@@ -104,6 +104,7 @@ static int cx18_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], struct device *alloc_devs[])
{
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
struct cx18_stream *s = vb2_get_drv_priv(vq);
struct cx18 *cx = s->cx;
unsigned int szimage;
@@ -121,8 +122,8 @@ static int cx18_queue_setup(struct vb2_queue *vq,
* Let's request at least three buffers: two for the
* DMA engine and one for userspace.
*/
- if (vq->num_buffers + *nbuffers < 3)
- *nbuffers = 3 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 3)
+ *nbuffers = 3 - q_num_bufs;
if (*nplanes) {
if (*nplanes != 1 || sizes[0] < szimage)
@@ -286,7 +287,7 @@ static int cx18_stream_init(struct cx18 *cx, int type)
s->vidq.ops = &cx18_vb2_qops;
s->vidq.mem_ops = &vb2_vmalloc_memops;
s->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- s->vidq.min_buffers_needed = 2;
+ s->vidq.min_queued_buffers = 2;
s->vidq.gfp_flags = GFP_DMA32;
s->vidq.dev = &cx->pci_dev->dev;
s->vidq.lock = &cx->serialize_lock;
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index 434677bd4ad1..fdb96f80c036 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -1525,7 +1525,7 @@ int cx23885_417_register(struct cx23885_dev *dev)
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
q->gfp_flags = GFP_DMA32;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct cx23885_buffer);
q->ops = &cx23885_qops;
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 7551ca4a322a..3d01cdc4c7f3 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -2667,7 +2667,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
q->gfp_flags = GFP_DMA32;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->drv_priv = port;
q->buf_struct_size = sizeof(struct cx23885_buffer);
q->ops = &dvb_qops;
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 9af2c5596121..42fdcf992e48 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -1321,7 +1321,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
q->gfp_flags = GFP_DMA32;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct cx23885_buffer);
q->ops = &cx23885_video_qops;
@@ -1338,7 +1338,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
q->gfp_flags = GFP_DMA32;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct cx23885_buffer);
q->ops = &cx23885_vbi_qops;
diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c
index 1b80c990cb94..0bee4b728a60 100644
--- a/drivers/media/pci/cx25821/cx25821-video.c
+++ b/drivers/media/pci/cx25821/cx25821-video.c
@@ -730,7 +730,7 @@ int cx25821_video_register(struct cx25821_dev *dev)
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
q->io_modes |= is_output ? VB2_WRITE : VB2_READ;
q->gfp_flags = GFP_DMA32;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->drv_priv = chan;
q->buf_struct_size = sizeof(struct cx25821_buffer);
q->ops = &cx25821_video_qops;
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
index c1b41a9283c1..d55df8fdb3b6 100644
--- a/drivers/media/pci/cx88/cx88-blackbird.c
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
@@ -1195,7 +1195,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
q->gfp_flags = GFP_DMA32;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct cx88_buffer);
q->ops = &blackbird_qops;
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
index 2087f2491c42..b33b3a5e32ec 100644
--- a/drivers/media/pci/cx88/cx88-dvb.c
+++ b/drivers/media/pci/cx88/cx88-dvb.c
@@ -1776,7 +1776,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
q->gfp_flags = GFP_DMA32;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct cx88_buffer);
q->ops = &dvb_qops;
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index c0ef03ed74f9..cefb6b25e921 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -1411,7 +1411,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
q->gfp_flags = GFP_DMA32;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct cx88_buffer);
q->ops = &cx8800_video_qops;
@@ -1428,7 +1428,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
q->gfp_flags = GFP_DMA32;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->drv_priv = dev;
q->buf_struct_size = sizeof(struct cx88_buffer);
q->ops = &cx8800_vbi_qops;
diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c
index 91733ab9f58c..363badab7cf0 100644
--- a/drivers/media/pci/ddbridge/ddbridge-main.c
+++ b/drivers/media/pci/ddbridge/ddbridge-main.c
@@ -238,7 +238,7 @@ fail:
ddb_unmap(dev);
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
- return -1;
+ return stat;
}
/****************************************************************************/
diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c
index 548156b199cc..dff853e73fdc 100644
--- a/drivers/media/pci/dt3155/dt3155.c
+++ b/drivers/media/pci/dt3155/dt3155.c
@@ -128,8 +128,6 @@ dt3155_queue_setup(struct vb2_queue *vq,
struct dt3155_priv *pd = vb2_get_drv_priv(vq);
unsigned size = pd->width * pd->height;
- if (vq->num_buffers + *nbuffers < 2)
- *nbuffers = 2 - vq->num_buffers;
if (*num_planes)
return sizes[0] < size ? -EINVAL : 0;
*num_planes = 1;
@@ -519,7 +517,7 @@ static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pd->vidq.ops = &q_ops;
pd->vidq.mem_ops = &vb2_dma_contig_memops;
pd->vidq.drv_priv = pd;
- pd->vidq.min_buffers_needed = 2;
+ pd->vidq.min_queued_buffers = 2;
pd->vidq.gfp_flags = GFP_DMA32;
pd->vidq.lock = &pd->mux; /* for locking v4l2_file_operations */
pd->vidq.dev = &pdev->dev;
diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c
index e38198e259c0..f980e3125a7b 100644
--- a/drivers/media/pci/intel/ipu-bridge.c
+++ b/drivers/media/pci/intel/ipu-bridge.c
@@ -53,7 +53,7 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = {
/* Omnivision ov8856 */
IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000),
/* Omnivision ov2740 */
- IPU_SENSOR_CONFIG("INT3474", 1, 360000000),
+ IPU_SENSOR_CONFIG("INT3474", 1, 180000000),
/* Hynix hi556 */
IPU_SENSOR_CONFIG("INT3537", 1, 437000000),
/* Omnivision ov13b10 */
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
index 5dd69a251b6a..ed08bf4178f0 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -1205,23 +1205,16 @@ static int cio2_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
};
/* Initialize try_fmt */
- format = v4l2_subdev_get_try_format(sd, fh->state, CIO2_PAD_SINK);
+ format = v4l2_subdev_state_get_format(fh->state, CIO2_PAD_SINK);
*format = fmt_default;
/* same as sink */
- format = v4l2_subdev_get_try_format(sd, fh->state, CIO2_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(fh->state, CIO2_PAD_SOURCE);
*format = fmt_default;
return 0;
}
-/*
- * cio2_subdev_get_fmt - Handle get format by pads subdev method
- * @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad config
- * @fmt: pointer to v4l2 subdev format structure
- * return -EINVAL or zero on success
- */
static int cio2_subdev_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
@@ -1231,8 +1224,8 @@ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd,
mutex_lock(&q->subdev_lock);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
- fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
else
fmt->format = q->subdev_fmt;
@@ -1241,13 +1234,6 @@ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd,
return 0;
}
-/*
- * cio2_subdev_set_fmt - Handle set format by pads subdev method
- * @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad config
- * @fmt: pointer to v4l2 subdev format structure
- * return -EINVAL or zero on success
- */
static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
@@ -1265,7 +1251,7 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
return cio2_subdev_get_fmt(sd, sd_state, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- mbus = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ mbus = v4l2_subdev_state_get_format(sd_state, fmt->pad);
else
mbus = &q->subdev_fmt;
@@ -1603,7 +1589,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q)
vbq->mem_ops = &vb2_dma_sg_memops;
vbq->buf_struct_size = sizeof(struct cio2_buffer);
vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- vbq->min_buffers_needed = 1;
+ vbq->min_queued_buffers = 1;
vbq->drv_priv = cio2;
vbq->lock = &q->lock;
r = vb2_queue_init(vbq);
diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c
index 2a6b828fd8dd..15b905f66ab7 100644
--- a/drivers/media/pci/intel/ivsc/mei_csi.c
+++ b/drivers/media/pci/intel/ivsc/mei_csi.c
@@ -338,7 +338,7 @@ mei_csi_get_pad_format(struct v4l2_subdev *sd,
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &csi->format_mbus[pad];
default:
@@ -346,8 +346,8 @@ mei_csi_get_pad_format(struct v4l2_subdev *sd,
}
}
-static int mei_csi_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int mei_csi_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *mbusformat;
struct mei_csi *csi = sd_to_csi(sd);
@@ -356,7 +356,7 @@ static int mei_csi_init_cfg(struct v4l2_subdev *sd,
mutex_lock(&csi->lock);
for (i = 0; i < sd->entity.num_pads; i++) {
- mbusformat = v4l2_subdev_get_try_format(sd, sd_state, i);
+ mbusformat = v4l2_subdev_state_get_format(sd_state, i);
*mbusformat = mei_csi_format_mbus_default;
}
@@ -554,7 +554,6 @@ static const struct v4l2_subdev_video_ops mei_csi_video_ops = {
};
static const struct v4l2_subdev_pad_ops mei_csi_pad_ops = {
- .init_cfg = mei_csi_init_cfg,
.get_fmt = mei_csi_get_fmt,
.set_fmt = mei_csi_set_fmt,
};
@@ -564,6 +563,10 @@ static const struct v4l2_subdev_ops mei_csi_subdev_ops = {
.pad = &mei_csi_pad_ops,
};
+static const struct v4l2_subdev_internal_ops mei_csi_internal_ops = {
+ .init_state = mei_csi_init_state,
+};
+
static const struct media_entity_operations mei_csi_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -645,47 +648,66 @@ static int mei_csi_parse_firmware(struct mei_csi *csi)
};
struct device *dev = &csi->cldev->dev;
struct v4l2_async_connection *asd;
- struct fwnode_handle *fwnode;
- struct fwnode_handle *ep;
+ struct fwnode_handle *sink_ep, *source_ep;
int ret;
- ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
- if (!ep) {
- dev_err(dev, "not connected to subdevice\n");
+ sink_ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
+ if (!sink_ep) {
+ dev_err(dev, "can't obtain sink endpoint\n");
return -EINVAL;
}
- ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep);
+ v4l2_async_subdev_nf_init(&csi->notifier, &csi->subdev);
+ csi->notifier.ops = &mei_csi_notify_ops;
+
+ ret = v4l2_fwnode_endpoint_parse(sink_ep, &v4l2_ep);
if (ret) {
- dev_err(dev, "could not parse v4l2 endpoint\n");
- fwnode_handle_put(ep);
- return -EINVAL;
+ dev_err(dev, "could not parse v4l2 sink endpoint\n");
+ goto out_nf_cleanup;
}
- fwnode = fwnode_graph_get_remote_endpoint(ep);
- fwnode_handle_put(ep);
+ csi->nr_of_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes;
- v4l2_async_subdev_nf_init(&csi->notifier, &csi->subdev);
- csi->notifier.ops = &mei_csi_notify_ops;
+ source_ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 1, 0, 0);
+ if (!source_ep) {
+ ret = -ENOTCONN;
+ dev_err(dev, "can't obtain source endpoint\n");
+ goto out_nf_cleanup;
+ }
- asd = v4l2_async_nf_add_fwnode(&csi->notifier, fwnode,
- struct v4l2_async_connection);
- if (IS_ERR(asd)) {
- fwnode_handle_put(fwnode);
- return PTR_ERR(asd);
+ ret = v4l2_fwnode_endpoint_parse(source_ep, &v4l2_ep);
+ fwnode_handle_put(source_ep);
+ if (ret) {
+ dev_err(dev, "could not parse v4l2 source endpoint\n");
+ goto out_nf_cleanup;
}
- ret = v4l2_fwnode_endpoint_alloc_parse(fwnode, &v4l2_ep);
- fwnode_handle_put(fwnode);
- if (ret)
- return ret;
- csi->nr_of_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes;
+ if (csi->nr_of_lanes != v4l2_ep.bus.mipi_csi2.num_data_lanes) {
+ ret = -EINVAL;
+ dev_err(dev,
+ "the number of lanes does not match (%u vs. %u)\n",
+ csi->nr_of_lanes, v4l2_ep.bus.mipi_csi2.num_data_lanes);
+ goto out_nf_cleanup;
+ }
+
+ asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, sink_ep,
+ struct v4l2_async_connection);
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
+ goto out_nf_cleanup;
+ }
ret = v4l2_async_nf_register(&csi->notifier);
if (ret)
- v4l2_async_nf_cleanup(&csi->notifier);
+ goto out_nf_cleanup;
+
+ fwnode_handle_put(sink_ep);
- v4l2_fwnode_endpoint_free(&v4l2_ep);
+ return 0;
+
+out_nf_cleanup:
+ v4l2_async_nf_cleanup(&csi->notifier);
+ fwnode_handle_put(sink_ep);
return ret;
}
@@ -728,6 +750,7 @@ static int mei_csi_probe(struct mei_cl_device *cldev,
csi->subdev.dev = &cldev->dev;
v4l2_subdev_init(&csi->subdev, &mei_csi_subdev_ops);
+ csi->subdev.internal_ops = &mei_csi_internal_ops;
v4l2_set_subdevdata(&csi->subdev, csi);
csi->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h
index ce3a7ca51736..a6ffa99e16bc 100644
--- a/drivers/media/pci/ivtv/ivtv-driver.h
+++ b/drivers/media/pci/ivtv/ivtv-driver.h
@@ -619,6 +619,7 @@ struct ivtv {
u32 hw_flags; /* hardware description of the board */
v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */
struct v4l2_subdev *sd_video; /* controlling video decoder subdev */
+ bool sd_video_is_streaming; /* is video already streaming? */
struct v4l2_subdev *sd_audio; /* controlling audio subdev */
struct v4l2_subdev *sd_muxer; /* controlling audio muxer subdev */
resource_size_t base_addr; /* PCI resource base address */
diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c
index 13d7d55e6594..af9e6235c74d 100644
--- a/drivers/media/pci/ivtv/ivtv-streams.c
+++ b/drivers/media/pci/ivtv/ivtv-streams.c
@@ -623,10 +623,12 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
/* Avoid tinny audio problem - ensure audio clocks are going */
v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1);
/* Avoid unpredictable PCI bus hang - disable video clocks */
- v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
+ if (itv->sd_video_is_streaming)
+ v4l2_subdev_call(itv->sd_video, video, s_stream, 0);
ivtv_msleep_timeout(300, 0);
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
v4l2_subdev_call(itv->sd_video, video, s_stream, 1);
+ itv->sd_video_is_streaming = true;
}
/* begin_capture */
diff --git a/drivers/media/pci/mgb4/mgb4_vin.c b/drivers/media/pci/mgb4/mgb4_vin.c
index d72b07b87cd1..2cd78c539889 100644
--- a/drivers/media/pci/mgb4/mgb4_vin.c
+++ b/drivers/media/pci/mgb4/mgb4_vin.c
@@ -849,7 +849,7 @@ struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id)
vindev->queue.mem_ops = &vb2_dma_sg_memops;
vindev->queue.gfp_flags = GFP_DMA32;
vindev->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- vindev->queue.min_buffers_needed = 2;
+ vindev->queue.min_queued_buffers = 2;
vindev->queue.drv_priv = vindev;
vindev->queue.lock = &vindev->lock;
vindev->queue.dev = dev;
diff --git a/drivers/media/pci/mgb4/mgb4_vout.c b/drivers/media/pci/mgb4/mgb4_vout.c
index 857fc7bbd21a..241353ee77a5 100644
--- a/drivers/media/pci/mgb4/mgb4_vout.c
+++ b/drivers/media/pci/mgb4/mgb4_vout.c
@@ -523,7 +523,7 @@ struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id)
voutdev->queue.mem_ops = &vb2_dma_sg_memops;
voutdev->queue.gfp_flags = GFP_DMA32;
voutdev->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- voutdev->queue.min_buffers_needed = 2;
+ voutdev->queue.min_queued_buffers = 2;
voutdev->queue.drv_priv = voutdev;
voutdev->queue.lock = &voutdev->lock;
voutdev->queue.dev = dev;
diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
index d85bfbb77a25..557985ba25db 100644
--- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
+++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
@@ -293,12 +293,13 @@ static int netup_unidvb_queue_setup(struct vb2_queue *vq,
struct device *alloc_devs[])
{
struct netup_dma *dma = vb2_get_drv_priv(vq);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
dev_dbg(&dma->ndev->pci_dev->dev, "%s()\n", __func__);
*nplanes = 1;
- if (vq->num_buffers + *nbuffers < VIDEO_MAX_FRAME)
- *nbuffers = VIDEO_MAX_FRAME - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < VIDEO_MAX_FRAME)
+ *nbuffers = VIDEO_MAX_FRAME - q_num_bufs;
sizes[0] = PAGE_ALIGN(NETUP_DMA_PACKETS_COUNT * 188);
dev_dbg(&dma->ndev->pci_dev->dev, "%s() nbuffers=%d sizes[0]=%d\n",
__func__, *nbuffers, sizes[0]);
diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c
index 197ed8978102..8b1aae4b6319 100644
--- a/drivers/media/pci/tw5864/tw5864-video.c
+++ b/drivers/media/pci/tw5864/tw5864-video.c
@@ -1114,7 +1114,7 @@ static int tw5864_video_input_init(struct tw5864_input *input, int video_nr)
input->vidq.gfp_flags = 0;
input->vidq.buf_struct_size = sizeof(struct tw5864_buf);
input->vidq.lock = &input->lock;
- input->vidq.min_buffers_needed = 2;
+ input->vidq.min_queued_buffers = 2;
input->vidq.dev = &input->root->pci->dev;
ret = vb2_queue_init(&input->vidq);
if (ret)
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c
index 773a18702d36..cdf5d733b863 100644
--- a/drivers/media/pci/tw68/tw68-video.c
+++ b/drivers/media/pci/tw68/tw68-video.c
@@ -360,13 +360,14 @@ static int tw68_queue_setup(struct vb2_queue *q,
unsigned int sizes[], struct device *alloc_devs[])
{
struct tw68_dev *dev = vb2_get_drv_priv(q);
- unsigned tot_bufs = q->num_buffers + *num_buffers;
+ unsigned int q_num_bufs = vb2_get_num_buffers(q);
+ unsigned int tot_bufs = q_num_bufs + *num_buffers;
unsigned size = (dev->fmt->depth * dev->width * dev->height) >> 3;
if (tot_bufs < 2)
tot_bufs = 2;
tot_bufs = tw68_buffer_count(size, tot_bufs);
- *num_buffers = tot_bufs - q->num_buffers;
+ *num_buffers = tot_bufs - q_num_bufs;
/*
* We allow create_bufs, but only if the sizeimage is >= as the
* current sizeimage. The tw68_buffer_count calculation becomes quite
@@ -951,7 +952,7 @@ int tw68_video_init2(struct tw68_dev *dev, int video_nr)
dev->vidq.gfp_flags = __GFP_DMA32 | __GFP_KSWAPD_RECLAIM;
dev->vidq.buf_struct_size = sizeof(struct tw68_buf);
dev->vidq.lock = &dev->lock;
- dev->vidq.min_buffers_needed = 2;
+ dev->vidq.min_queued_buffers = 2;
dev->vidq.dev = &dev->pci->dev;
ret = vb2_queue_init(&dev->vidq);
if (ret)
diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c
index 3ebf7a2c95f0..63be95fce83d 100644
--- a/drivers/media/pci/tw686x/tw686x-video.c
+++ b/drivers/media/pci/tw686x/tw686x-video.c
@@ -423,6 +423,7 @@ static int tw686x_queue_setup(struct vb2_queue *vq,
unsigned int sizes[], struct device *alloc_devs[])
{
struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
unsigned int szimage =
(vc->width * vc->height * vc->format->depth) >> 3;
@@ -430,8 +431,8 @@ static int tw686x_queue_setup(struct vb2_queue *vq,
* Let's request at least three buffers: two for the
* DMA engine and one for userspace.
*/
- if (vq->num_buffers + *nbuffers < 3)
- *nbuffers = 3 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 3)
+ *nbuffers = 3 - q_num_bufs;
if (*nplanes) {
if (*nplanes != 1 || sizes[0] < szimage)
@@ -1221,7 +1222,7 @@ int tw686x_video_init(struct tw686x_dev *dev)
vc->vidq.ops = &tw686x_video_qops;
vc->vidq.mem_ops = dev->dma_ops->mem_ops;
vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- vc->vidq.min_buffers_needed = 2;
+ vc->vidq.min_queued_buffers = 2;
vc->vidq.lock = &vc->vb_mutex;
vc->vidq.gfp_flags = dev->dma_mode != TW686X_DMA_MODE_MEMCPY ?
GFP_DMA32 : 0;
diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c
index fa672cc8bc67..5c05e64c71a9 100644
--- a/drivers/media/pci/zoran/zoran_driver.c
+++ b/drivers/media/pci/zoran/zoran_driver.c
@@ -749,8 +749,8 @@ static int zr_vb2_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsi
zr->buf_in_reserve = 0;
- if (*nbuffers < vq->min_buffers_needed)
- *nbuffers = vq->min_buffers_needed;
+ if (*nbuffers < vq->min_queued_buffers)
+ *nbuffers = vq->min_queued_buffers;
if (*nplanes) {
if (sizes[0] < size)
@@ -971,7 +971,7 @@ int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir)
vq->mem_ops = &vb2_dma_contig_memops;
vq->gfp_flags = GFP_DMA32;
vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- vq->min_buffers_needed = 9;
+ vq->min_queued_buffers = 9;
vq->lock = &zr->lock;
err = vb2_queue_init(vq);
if (err)
diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h
index 5a701f64289e..0246cf0ac3a8 100644
--- a/drivers/media/platform/amphion/vpu.h
+++ b/drivers/media/platform/amphion/vpu.h
@@ -154,7 +154,6 @@ struct vpu_core {
struct vpu_mbox tx_type;
struct vpu_mbox tx_data;
struct vpu_mbox rx;
- unsigned long cmd_seq;
wait_queue_head_t ack_wq;
struct completion cmp;
@@ -253,6 +252,8 @@ struct vpu_inst {
struct list_head cmd_q;
void *pending;
+ unsigned long cmd_seq;
+ atomic_long_t last_response_cmd;
struct vpu_inst_ops *ops;
const struct vpu_format *formats;
diff --git a/drivers/media/platform/amphion/vpu_cmds.c b/drivers/media/platform/amphion/vpu_cmds.c
index c2337812573e..5695f5c1cb3e 100644
--- a/drivers/media/platform/amphion/vpu_cmds.c
+++ b/drivers/media/platform/amphion/vpu_cmds.c
@@ -32,6 +32,7 @@ struct vpu_cmd_t {
struct vpu_cmd_request *request;
struct vpu_rpc_event *pkt;
unsigned long key;
+ atomic_long_t *last_response_cmd;
};
static struct vpu_cmd_request vpu_cmd_requests[] = {
@@ -115,6 +116,8 @@ static void vpu_free_cmd(struct vpu_cmd_t *cmd)
{
if (!cmd)
return;
+ if (cmd->last_response_cmd)
+ atomic_long_set(cmd->last_response_cmd, cmd->key);
vfree(cmd->pkt);
vfree(cmd);
}
@@ -172,7 +175,8 @@ static int vpu_request_cmd(struct vpu_inst *inst, u32 id, void *data,
return -ENOMEM;
mutex_lock(&core->cmd_lock);
- cmd->key = core->cmd_seq++;
+ cmd->key = ++inst->cmd_seq;
+ cmd->last_response_cmd = &inst->last_response_cmd;
if (key)
*key = cmd->key;
if (sync)
@@ -246,26 +250,12 @@ void vpu_clear_request(struct vpu_inst *inst)
static bool check_is_responsed(struct vpu_inst *inst, unsigned long key)
{
- struct vpu_core *core = inst->core;
- struct vpu_cmd_t *cmd;
- bool flag = true;
+ unsigned long last_response = atomic_long_read(&inst->last_response_cmd);
- mutex_lock(&core->cmd_lock);
- cmd = inst->pending;
- if (cmd && key == cmd->key) {
- flag = false;
- goto exit;
- }
- list_for_each_entry(cmd, &inst->cmd_q, list) {
- if (key == cmd->key) {
- flag = false;
- break;
- }
- }
-exit:
- mutex_unlock(&core->cmd_lock);
+ if (key <= last_response && (last_response - key) < (ULONG_MAX >> 1))
+ return true;
- return flag;
+ return false;
}
static int sync_session_response(struct vpu_inst *inst, unsigned long key, long timeout, int try)
diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c
index 1af6fc9460d4..3a2030d02e45 100644
--- a/drivers/media/platform/amphion/vpu_core.c
+++ b/drivers/media/platform/amphion/vpu_core.c
@@ -642,7 +642,7 @@ static int vpu_core_probe(struct platform_device *pdev)
return -ENODEV;
core->type = core->res->type;
- core->id = of_alias_get_id(dev->of_node, "vpu_core");
+ core->id = of_alias_get_id(dev->of_node, "vpu-core");
if (core->id < 0) {
dev_err(dev, "can't get vpu core id\n");
return core->id;
diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c
index 982c2c777484..940e5bda5fa3 100644
--- a/drivers/media/platform/amphion/vpu_dbg.c
+++ b/drivers/media/platform/amphion/vpu_dbg.c
@@ -87,7 +87,7 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
num = scnprintf(str, sizeof(str),
"output (%2d, %2d): fmt = %c%c%c%c %d x %d, %d;",
vb2_is_streaming(vq),
- vq->num_buffers,
+ vb2_get_num_buffers(vq),
inst->out_format.pixfmt,
inst->out_format.pixfmt >> 8,
inst->out_format.pixfmt >> 16,
@@ -111,7 +111,7 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
num = scnprintf(str, sizeof(str),
"capture(%2d, %2d): fmt = %c%c%c%c %d x %d, %d;",
vb2_is_streaming(vq),
- vq->num_buffers,
+ vb2_get_num_buffers(vq),
inst->cap_format.pixfmt,
inst->cap_format.pixfmt >> 8,
inst->cap_format.pixfmt >> 16,
@@ -139,12 +139,19 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
return 0;
vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
- for (i = 0; i < vq->num_buffers; i++) {
- struct vb2_buffer *vb = vq->bufs[i];
- struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ for (i = 0; i < vb2_get_num_buffers(vq); i++) {
+ struct vb2_buffer *vb;
+ struct vb2_v4l2_buffer *vbuf;
+
+ vb = vb2_get_buffer(vq, i);
+ if (!vb)
+ continue;
if (vb->state == VB2_BUF_STATE_DEQUEUED)
continue;
+
+ vbuf = to_vb2_v4l2_buffer(vb);
+
num = scnprintf(str, sizeof(str),
"output [%2d] state = %10s, %8s\n",
i, vb2_stat_name[vb->state],
@@ -154,12 +161,19 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
}
vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
- for (i = 0; i < vq->num_buffers; i++) {
- struct vb2_buffer *vb = vq->bufs[i];
- struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ for (i = 0; i < vb2_get_num_buffers(vq); i++) {
+ struct vb2_buffer *vb;
+ struct vb2_v4l2_buffer *vbuf;
+
+ vb = vb2_get_buffer(vq, i);
+ if (!vb)
+ continue;
if (vb->state == VB2_BUF_STATE_DEQUEUED)
continue;
+
+ vbuf = to_vb2_v4l2_buffer(vb);
+
num = scnprintf(str, sizeof(str),
"capture[%2d] state = %10s, %8s\n",
i, vb2_stat_name[vb->state],
diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c
index 0f6e4c666440..c88738e8fff7 100644
--- a/drivers/media/platform/amphion/vpu_v4l2.c
+++ b/drivers/media/platform/amphion/vpu_v4l2.c
@@ -439,7 +439,7 @@ int vpu_get_num_buffers(struct vpu_inst *inst, u32 type)
else
q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
- return q->num_buffers;
+ return vb2_get_num_buffers(q);
}
static void vpu_m2m_device_run(void *priv)
@@ -587,7 +587,7 @@ static int vpu_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
fmt->sizeimage[0], fmt->bytesperline[0],
fmt->sizeimage[1], fmt->bytesperline[1],
fmt->sizeimage[2], fmt->bytesperline[2],
- q->num_buffers);
+ vb2_get_num_buffers(q));
vb2_clear_last_buffer_dequeued(q);
ret = call_vop(inst, start, q->type);
if (ret)
@@ -649,7 +649,7 @@ static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_q
src_vq->mem_ops = &vb2_vmalloc_memops;
src_vq->drv_priv = inst;
src_vq->buf_struct_size = sizeof(struct vpu_vb2_buffer);
- src_vq->min_buffers_needed = 1;
+ src_vq->min_queued_buffers = 1;
src_vq->dev = inst->vpu->dev;
src_vq->lock = &inst->lock;
ret = vb2_queue_init(src_vq);
@@ -666,7 +666,7 @@ static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_q
dst_vq->mem_ops = &vb2_vmalloc_memops;
dst_vq->drv_priv = inst;
dst_vq->buf_struct_size = sizeof(struct vpu_vb2_buffer);
- dst_vq->min_buffers_needed = 1;
+ dst_vq->min_queued_buffers = 1;
dst_vq->dev = inst->vpu->dev;
dst_vq->lock = &inst->lock;
ret = vb2_queue_init(dst_vq);
@@ -716,6 +716,7 @@ int vpu_v4l2_open(struct file *file, struct vpu_inst *inst)
func = &vpu->decoder;
atomic_set(&inst->ref_count, 0);
+ atomic_long_set(&inst->last_response_cmd, 0);
vpu_inst_get(inst);
inst->vpu = vpu;
inst->core = vpu_request_core(vpu, inst->type);
diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c
index d08aa7f73d4f..fc6050e3be0d 100644
--- a/drivers/media/platform/aspeed/aspeed-video.c
+++ b/drivers/media/platform/aspeed/aspeed-video.c
@@ -2034,7 +2034,7 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
vbq->drv_priv = video;
vbq->buf_struct_size = sizeof(struct aspeed_video_buffer);
vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- vbq->min_buffers_needed = ASPEED_VIDEO_V4L2_MIN_BUF_REQ;
+ vbq->min_queued_buffers = ASPEED_VIDEO_V4L2_MIN_BUF_REQ;
rc = vb2_queue_init(vbq);
if (rc) {
diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
index 4046212d48b4..f8450a8ccda6 100644
--- a/drivers/media/platform/atmel/atmel-isi.c
+++ b/drivers/media/platform/atmel/atmel-isi.c
@@ -559,11 +559,13 @@ static const struct isi_format *find_format_by_fourcc(struct atmel_isi *isi,
static void isi_try_fse(struct atmel_isi *isi, const struct isi_format *isi_fmt,
struct v4l2_subdev_state *sd_state)
{
- int ret;
+ struct v4l2_rect *try_crop =
+ v4l2_subdev_state_get_crop(sd_state, 0);
struct v4l2_subdev_frame_size_enum fse = {
.code = isi_fmt->mbus_code,
.which = V4L2_SUBDEV_FORMAT_TRY,
};
+ int ret;
ret = v4l2_subdev_call(isi->entity.subdev, pad, enum_frame_size,
sd_state, &fse);
@@ -572,11 +574,11 @@ static void isi_try_fse(struct atmel_isi *isi, const struct isi_format *isi_fmt,
* just use the maximum ISI can receive.
*/
if (ret) {
- sd_state->pads->try_crop.width = MAX_SUPPORT_WIDTH;
- sd_state->pads->try_crop.height = MAX_SUPPORT_HEIGHT;
+ try_crop->width = MAX_SUPPORT_WIDTH;
+ try_crop->height = MAX_SUPPORT_HEIGHT;
} else {
- sd_state->pads->try_crop.width = fse.max_width;
- sd_state->pads->try_crop.height = fse.max_height;
+ try_crop->width = fse.max_width;
+ try_crop->height = fse.max_height;
}
}
@@ -587,6 +589,7 @@ static int isi_try_fmt(struct atmel_isi *isi, struct v4l2_format *f,
struct v4l2_pix_format *pixfmt = &f->fmt.pix;
struct v4l2_subdev_pad_config pad_cfg = {};
struct v4l2_subdev_state pad_state = {
+ .sd = isi->entity.subdev,
.pads = &pad_cfg,
};
struct v4l2_subdev_format format = {
@@ -1242,7 +1245,7 @@ static int atmel_isi_probe(struct platform_device *pdev)
q->ops = &isi_video_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->dev = &pdev->dev;
ret = vb2_queue_init(q);
diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
index 889f4fbbafb3..fead5426830e 100644
--- a/drivers/media/platform/cadence/cdns-csi2rx.c
+++ b/drivers/media/platform/cadence/cdns-csi2rx.c
@@ -406,20 +406,20 @@ static int csi2rx_set_fmt(struct v4l2_subdev *subdev,
format->format.field = V4L2_FIELD_NONE;
/* Set sink format */
- fmt = v4l2_subdev_get_pad_format(subdev, state, format->pad);
+ fmt = v4l2_subdev_state_get_format(state, format->pad);
*fmt = format->format;
/* Propagate to source formats */
for (i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) {
- fmt = v4l2_subdev_get_pad_format(subdev, state, i);
+ fmt = v4l2_subdev_state_get_format(state, i);
*fmt = format->format;
}
return 0;
}
-static int csi2rx_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *state)
+static int csi2rx_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state)
{
struct v4l2_subdev_format format = {
.pad = CSI2RX_PAD_SINK,
@@ -441,7 +441,6 @@ static int csi2rx_init_cfg(struct v4l2_subdev *subdev,
static const struct v4l2_subdev_pad_ops csi2rx_pad_ops = {
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = csi2rx_set_fmt,
- .init_cfg = csi2rx_init_cfg,
};
static const struct v4l2_subdev_video_ops csi2rx_video_ops = {
@@ -453,6 +452,10 @@ static const struct v4l2_subdev_ops csi2rx_subdev_ops = {
.pad = &csi2rx_pad_ops,
};
+static const struct v4l2_subdev_internal_ops csi2rx_internal_ops = {
+ .init_state = csi2rx_init_state,
+};
+
static const struct media_entity_operations csi2rx_media_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -663,6 +666,7 @@ static int csi2rx_probe(struct platform_device *pdev)
csi2rx->subdev.owner = THIS_MODULE;
csi2rx->subdev.dev = &pdev->dev;
v4l2_subdev_init(&csi2rx->subdev, &csi2rx_subdev_ops);
+ csi2rx->subdev.internal_ops = &csi2rx_internal_ops;
v4l2_set_subdevdata(&csi2rx->subdev, &pdev->dev);
snprintf(csi2rx->subdev.name, sizeof(csi2rx->subdev.name),
"%s.%s", KBUILD_MODNAME, dev_name(&pdev->dev));
diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c
index c115742f347f..3d98f91f1bee 100644
--- a/drivers/media/platform/cadence/cdns-csi2tx.c
+++ b/drivers/media/platform/cadence/cdns-csi2tx.c
@@ -176,8 +176,7 @@ __csi2tx_get_pad_format(struct v4l2_subdev *subdev,
struct csi2tx_priv *csi2tx = v4l2_subdev_to_csi2tx(subdev);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(subdev, sd_state,
- fmt->pad);
+ return v4l2_subdev_state_get_format(sd_state, fmt->pad);
return &csi2tx->pad_fmts[fmt->pad];
}
diff --git a/drivers/media/platform/chips-media/Kconfig b/drivers/media/platform/chips-media/Kconfig
index 57f8f8a22df8..ad350eb6b1fc 100644
--- a/drivers/media/platform/chips-media/Kconfig
+++ b/drivers/media/platform/chips-media/Kconfig
@@ -2,19 +2,5 @@
comment "Chips&Media media platform drivers"
-config VIDEO_CODA
- tristate "Chips&Media Coda multi-standard codec IP"
- depends on V4L_MEM2MEM_DRIVERS
- depends on VIDEO_DEV && OF && (ARCH_MXC || COMPILE_TEST)
- select SRAM
- select VIDEOBUF2_DMA_CONTIG
- select VIDEOBUF2_VMALLOC
- select V4L2_JPEG_HELPER
- select V4L2_MEM2MEM_DEV
- select GENERIC_ALLOCATOR
- help
- Coda is a range of video codec IPs that supports
- H.264, MPEG-4, and other video formats.
-
-config VIDEO_IMX_VDOA
- def_tristate VIDEO_CODA if SOC_IMX6Q || COMPILE_TEST
+source "drivers/media/platform/chips-media/coda/Kconfig"
+source "drivers/media/platform/chips-media/wave5/Kconfig"
diff --git a/drivers/media/platform/chips-media/Makefile b/drivers/media/platform/chips-media/Makefile
index bbb16425a875..6b5d99de8b54 100644
--- a/drivers/media/platform/chips-media/Makefile
+++ b/drivers/media/platform/chips-media/Makefile
@@ -1,6 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-coda-vpu-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg2.o coda-mpeg4.o coda-jpeg.o
-
-obj-$(CONFIG_VIDEO_CODA) += coda-vpu.o
-obj-$(CONFIG_VIDEO_IMX_VDOA) += imx-vdoa.o
+obj-y += coda/
+obj-y += wave5/
diff --git a/drivers/media/platform/chips-media/coda/Kconfig b/drivers/media/platform/chips-media/coda/Kconfig
new file mode 100644
index 000000000000..cb7b66c71380
--- /dev/null
+++ b/drivers/media/platform/chips-media/coda/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config VIDEO_CODA
+ tristate "Chips&Media Coda multi-standard codec IP"
+ depends on V4L_MEM2MEM_DRIVERS
+ depends on VIDEO_DEV && OF && (ARCH_MXC || COMPILE_TEST)
+ select SRAM
+ select VIDEOBUF2_DMA_CONTIG
+ select VIDEOBUF2_VMALLOC
+ select V4L2_JPEG_HELPER
+ select V4L2_MEM2MEM_DEV
+ select GENERIC_ALLOCATOR
+ help
+ Coda is a range of video codec IPs that supports
+ H.264, MPEG-4, and other video formats.
+
+config VIDEO_IMX_VDOA
+ def_tristate VIDEO_CODA if SOC_IMX6Q || COMPILE_TEST
diff --git a/drivers/media/platform/chips-media/coda/Makefile b/drivers/media/platform/chips-media/coda/Makefile
new file mode 100644
index 000000000000..bbb16425a875
--- /dev/null
+++ b/drivers/media/platform/chips-media/coda/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+coda-vpu-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg2.o coda-mpeg4.o coda-jpeg.o
+
+obj-$(CONFIG_VIDEO_CODA) += coda-vpu.o
+obj-$(CONFIG_VIDEO_IMX_VDOA) += imx-vdoa.o
diff --git a/drivers/media/platform/chips-media/coda-bit.c b/drivers/media/platform/chips-media/coda/coda-bit.c
index ed47d5bd8d61..ed47d5bd8d61 100644
--- a/drivers/media/platform/chips-media/coda-bit.c
+++ b/drivers/media/platform/chips-media/coda/coda-bit.c
diff --git a/drivers/media/platform/chips-media/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c
index cc4892129aaf..7da0194ec850 100644
--- a/drivers/media/platform/chips-media/coda-common.c
+++ b/drivers/media/platform/chips-media/coda/coda-common.c
@@ -794,7 +794,7 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f,
if (vb2_is_busy(vq)) {
v4l2_err(&ctx->dev->v4l2_dev, "%s: %s queue busy: %d\n",
- __func__, v4l2_type_names[f->type], vq->num_buffers);
+ __func__, v4l2_type_names[f->type], vb2_get_num_buffers(vq));
return -EBUSY;
}
@@ -2546,7 +2546,7 @@ static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq)
* would need to be reflected in job_ready(). Currently we expect all
* queues to have at least one buffer queued.
*/
- vq->min_buffers_needed = 1;
+ vq->min_queued_buffers = 1;
vq->dev = ctx->dev->dev;
return vb2_queue_init(vq);
diff --git a/drivers/media/platform/chips-media/coda-gdi.c b/drivers/media/platform/chips-media/coda/coda-gdi.c
index 59d65daca153..59d65daca153 100644
--- a/drivers/media/platform/chips-media/coda-gdi.c
+++ b/drivers/media/platform/chips-media/coda/coda-gdi.c
diff --git a/drivers/media/platform/chips-media/coda-h264.c b/drivers/media/platform/chips-media/coda/coda-h264.c
index 8bd0aa8af114..8bd0aa8af114 100644
--- a/drivers/media/platform/chips-media/coda-h264.c
+++ b/drivers/media/platform/chips-media/coda/coda-h264.c
diff --git a/drivers/media/platform/chips-media/coda-jpeg.c b/drivers/media/platform/chips-media/coda/coda-jpeg.c
index ba8f41002917..ba8f41002917 100644
--- a/drivers/media/platform/chips-media/coda-jpeg.c
+++ b/drivers/media/platform/chips-media/coda/coda-jpeg.c
diff --git a/drivers/media/platform/chips-media/coda-mpeg2.c b/drivers/media/platform/chips-media/coda/coda-mpeg2.c
index 6f3f6721d286..6f3f6721d286 100644
--- a/drivers/media/platform/chips-media/coda-mpeg2.c
+++ b/drivers/media/platform/chips-media/coda/coda-mpeg2.c
diff --git a/drivers/media/platform/chips-media/coda-mpeg4.c b/drivers/media/platform/chips-media/coda/coda-mpeg4.c
index 483a4fba1b4f..483a4fba1b4f 100644
--- a/drivers/media/platform/chips-media/coda-mpeg4.c
+++ b/drivers/media/platform/chips-media/coda/coda-mpeg4.c
diff --git a/drivers/media/platform/chips-media/coda.h b/drivers/media/platform/chips-media/coda/coda.h
index ddfd0a32c653..ddfd0a32c653 100644
--- a/drivers/media/platform/chips-media/coda.h
+++ b/drivers/media/platform/chips-media/coda/coda.h
diff --git a/drivers/media/platform/chips-media/coda_regs.h b/drivers/media/platform/chips-media/coda/coda_regs.h
index db81a904cf3f..db81a904cf3f 100644
--- a/drivers/media/platform/chips-media/coda_regs.h
+++ b/drivers/media/platform/chips-media/coda/coda_regs.h
diff --git a/drivers/media/platform/chips-media/imx-vdoa.c b/drivers/media/platform/chips-media/coda/imx-vdoa.c
index c3561fcecb98..c3561fcecb98 100644
--- a/drivers/media/platform/chips-media/imx-vdoa.c
+++ b/drivers/media/platform/chips-media/coda/imx-vdoa.c
diff --git a/drivers/media/platform/chips-media/imx-vdoa.h b/drivers/media/platform/chips-media/coda/imx-vdoa.h
index a62eab476d58..a62eab476d58 100644
--- a/drivers/media/platform/chips-media/imx-vdoa.h
+++ b/drivers/media/platform/chips-media/coda/imx-vdoa.h
diff --git a/drivers/media/platform/chips-media/trace.h b/drivers/media/platform/chips-media/coda/trace.h
index 19f98e6dafb9..abc6a01a74e9 100644
--- a/drivers/media/platform/chips-media/trace.h
+++ b/drivers/media/platform/chips-media/coda/trace.h
@@ -167,7 +167,7 @@ DEFINE_EVENT(coda_buf_class, coda_jpeg_done,
#endif /* __CODA_TRACE_H__ */
#undef TRACE_INCLUDE_PATH
-#define TRACE_INCLUDE_PATH ../../drivers/media/platform/chips-media
+#define TRACE_INCLUDE_PATH ../../drivers/media/platform/chips-media/coda
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE trace
diff --git a/drivers/media/platform/chips-media/wave5/Kconfig b/drivers/media/platform/chips-media/wave5/Kconfig
new file mode 100644
index 000000000000..f1bcef5177bd
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+config VIDEO_WAVE_VPU
+ tristate "Chips&Media Wave Codec Driver"
+ depends on V4L_MEM2MEM_DRIVERS
+ depends on VIDEO_DEV && OF
+ depends on ARCH_K3 || COMPILE_TEST
+ select VIDEOBUF2_DMA_CONTIG
+ select VIDEOBUF2_VMALLOC
+ select V4L2_MEM2MEM_DEV
+ select GENERIC_ALLOCATOR
+ help
+ Chips&Media stateful encoder and decoder driver.
+ The driver supports HEVC and H264 formats.
+ To compile this driver as modules, choose M here: the
+ modules will be called wave5.
diff --git a/drivers/media/platform/chips-media/wave5/Makefile b/drivers/media/platform/chips-media/wave5/Makefile
new file mode 100644
index 000000000000..3d738a03bd8e
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_VIDEO_WAVE_VPU) += wave5.o
+wave5-objs += wave5-hw.o \
+ wave5-vpuapi.o \
+ wave5-vdi.o \
+ wave5-vpu-dec.o \
+ wave5-vpu.o \
+ wave5-vpu-enc.o \
+ wave5-helper.o
diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c
new file mode 100644
index 000000000000..8433ecab230c
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave5 series multi-standard codec IP - decoder interface
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#include "wave5-helper.h"
+
+const char *state_to_str(enum vpu_instance_state state)
+{
+ switch (state) {
+ case VPU_INST_STATE_NONE:
+ return "NONE";
+ case VPU_INST_STATE_OPEN:
+ return "OPEN";
+ case VPU_INST_STATE_INIT_SEQ:
+ return "INIT_SEQ";
+ case VPU_INST_STATE_PIC_RUN:
+ return "PIC_RUN";
+ case VPU_INST_STATE_STOP:
+ return "STOP";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+void wave5_cleanup_instance(struct vpu_instance *inst)
+{
+ int i;
+
+ if (list_is_singular(&inst->list))
+ wave5_vdi_free_sram(inst->dev);
+
+ for (i = 0; i < inst->fbc_buf_count; i++)
+ wave5_vpu_dec_reset_framebuffer(inst, i);
+
+ wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf);
+ v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl);
+ if (inst->v4l2_fh.vdev) {
+ v4l2_fh_del(&inst->v4l2_fh);
+ v4l2_fh_exit(&inst->v4l2_fh);
+ }
+ list_del_init(&inst->list);
+ ida_free(&inst->dev->inst_ida, inst->id);
+ kfree(inst->codec_info);
+ kfree(inst);
+}
+
+int wave5_vpu_release_device(struct file *filp,
+ int (*close_func)(struct vpu_instance *inst, u32 *fail_res),
+ char *name)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data);
+
+ v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
+ if (inst->state != VPU_INST_STATE_NONE) {
+ u32 fail_res;
+ int ret;
+
+ ret = close_func(inst, &fail_res);
+ if (fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING) {
+ dev_err(inst->dev->dev, "%s close failed, device is still running\n",
+ name);
+ return -EBUSY;
+ }
+ if (ret && ret != -EIO) {
+ dev_err(inst->dev->dev, "%s close, fail: %d\n", name, ret);
+ return ret;
+ }
+ }
+
+ wave5_cleanup_instance(inst);
+
+ return 0;
+}
+
+int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq,
+ const struct vb2_ops *ops)
+{
+ struct vpu_instance *inst = priv;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->ops = ops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->buf_struct_size = sizeof(struct vpu_src_buffer);
+ src_vq->drv_priv = inst;
+ src_vq->lock = &inst->dev->dev_lock;
+ src_vq->dev = inst->dev->v4l2_dev.dev;
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->ops = ops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->buf_struct_size = sizeof(struct vpu_src_buffer);
+ dst_vq->drv_priv = inst;
+ dst_vq->lock = &inst->dev->dev_lock;
+ dst_vq->dev = inst->dev->v4l2_dev.dev;
+ ret = vb2_queue_init(dst_vq);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ bool is_decoder = inst->type == VPU_INST_TYPE_DEC;
+
+ dev_dbg(inst->dev->dev, "%s: [%s] type: %u id: %u | flags: %u\n", __func__,
+ is_decoder ? "decoder" : "encoder", sub->type, sub->id, sub->flags);
+
+ switch (sub->type) {
+ case V4L2_EVENT_EOS:
+ return v4l2_event_subscribe(fh, sub, 0, NULL);
+ case V4L2_EVENT_SOURCE_CHANGE:
+ if (is_decoder)
+ return v4l2_src_change_event_subscribe(fh, sub);
+ return -EINVAL;
+ case V4L2_EVENT_CTRL:
+ return v4l2_ctrl_subscribe_event(fh, sub);
+ default:
+ return -EINVAL;
+ }
+}
+
+int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ int i;
+
+ f->fmt.pix_mp.width = inst->src_fmt.width;
+ f->fmt.pix_mp.height = inst->src_fmt.height;
+ f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat;
+ f->fmt.pix_mp.field = inst->src_fmt.field;
+ f->fmt.pix_mp.flags = inst->src_fmt.flags;
+ f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes;
+ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
+ f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->src_fmt.plane_fmt[i].bytesperline;
+ f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->src_fmt.plane_fmt[i].sizeimage;
+ }
+
+ f->fmt.pix_mp.colorspace = inst->colorspace;
+ f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
+ f->fmt.pix_mp.quantization = inst->quantization;
+ f->fmt.pix_mp.xfer_func = inst->xfer_func;
+
+ return 0;
+}
+
+const struct vpu_format *wave5_find_vpu_fmt(unsigned int v4l2_pix_fmt,
+ const struct vpu_format fmt_list[MAX_FMTS])
+{
+ unsigned int index;
+
+ for (index = 0; index < MAX_FMTS; index++) {
+ if (fmt_list[index].v4l2_pix_fmt == v4l2_pix_fmt)
+ return &fmt_list[index];
+ }
+
+ return NULL;
+}
+
+const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx,
+ const struct vpu_format fmt_list[MAX_FMTS])
+{
+ if (idx >= MAX_FMTS)
+ return NULL;
+
+ if (!fmt_list[idx].v4l2_pix_fmt)
+ return NULL;
+
+ return &fmt_list[idx];
+}
+
+enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type)
+{
+ switch (v4l2_pix_fmt) {
+ case V4L2_PIX_FMT_H264:
+ return type == VPU_INST_TYPE_DEC ? W_AVC_DEC : W_AVC_ENC;
+ case V4L2_PIX_FMT_HEVC:
+ return type == VPU_INST_TYPE_DEC ? W_HEVC_DEC : W_HEVC_ENC;
+ default:
+ return STD_UNKNOWN;
+ }
+}
+
+void wave5_return_bufs(struct vb2_queue *q, u32 state)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct v4l2_ctrl_handler v4l2_ctrl_hdl = inst->v4l2_ctrl_hdl;
+ struct vb2_v4l2_buffer *vbuf;
+
+ for (;;) {
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ vbuf = v4l2_m2m_src_buf_remove(m2m_ctx);
+ else
+ vbuf = v4l2_m2m_dst_buf_remove(m2m_ctx);
+ if (!vbuf)
+ return;
+ v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, &v4l2_ctrl_hdl);
+ v4l2_m2m_buf_done(vbuf, state);
+ }
+}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.h b/drivers/media/platform/chips-media/wave5/wave5-helper.h
new file mode 100644
index 000000000000..6cee1c14d3ce
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-helper.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave5 series multi-standard codec IP - basic types
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE_HELPER_H__
+#define __WAVE_HELPER_H__
+
+#include "wave5-vpu.h"
+
+#define FMT_TYPES 2
+#define MAX_FMTS 12
+
+const char *state_to_str(enum vpu_instance_state state);
+void wave5_cleanup_instance(struct vpu_instance *inst);
+int wave5_vpu_release_device(struct file *filp,
+ int (*close_func)(struct vpu_instance *inst, u32 *fail_res),
+ char *name);
+int wave5_vpu_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq,
+ const struct vb2_ops *ops);
+int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub);
+int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f);
+const struct vpu_format *wave5_find_vpu_fmt(unsigned int v4l2_pix_fmt,
+ const struct vpu_format fmt_list[MAX_FMTS]);
+const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx,
+ const struct vpu_format fmt_list[MAX_FMTS]);
+enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type);
+void wave5_return_bufs(struct vb2_queue *q, u32 state);
+#endif
diff --git a/drivers/media/platform/chips-media/wave5/wave5-hw.c b/drivers/media/platform/chips-media/wave5/wave5-hw.c
new file mode 100644
index 000000000000..f1e022fb148e
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-hw.c
@@ -0,0 +1,2551 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave5 series multi-standard codec IP - wave5 backend logic
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#include <linux/iopoll.h>
+#include <linux/bitfield.h>
+#include "wave5-vpu.h"
+#include "wave5.h"
+#include "wave5-regdefine.h"
+
+#define FIO_TIMEOUT 10000000
+#define FIO_CTRL_READY BIT(31)
+#define FIO_CTRL_WRITE BIT(16)
+#define VPU_BUSY_CHECK_TIMEOUT 10000000
+#define QUEUE_REPORT_MASK 0xffff
+
+/* Encoder support fields */
+#define FEATURE_HEVC10BIT_ENC BIT(3)
+#define FEATURE_AVC10BIT_ENC BIT(11)
+#define FEATURE_AVC_ENCODER BIT(1)
+#define FEATURE_HEVC_ENCODER BIT(0)
+
+/* Decoder support fields */
+#define FEATURE_AVC_DECODER BIT(3)
+#define FEATURE_HEVC_DECODER BIT(2)
+
+#define FEATURE_BACKBONE BIT(16)
+#define FEATURE_VCORE_BACKBONE BIT(22)
+#define FEATURE_VCPU_BACKBONE BIT(28)
+
+#define REMAP_CTRL_MAX_SIZE_BITS ((W5_REMAP_MAX_SIZE >> 12) & 0x1ff)
+#define REMAP_CTRL_REGISTER_VALUE(index) ( \
+ (BIT(31) | (index << 12) | BIT(11) | REMAP_CTRL_MAX_SIZE_BITS) \
+)
+
+#define FASTIO_ADDRESS_MASK GENMASK(15, 0)
+#define SEQ_PARAM_PROFILE_MASK GENMASK(30, 24)
+
+static void _wave5_print_reg_err(struct vpu_device *vpu_dev, u32 reg_fail_reason,
+ const char *func);
+#define PRINT_REG_ERR(dev, reason) _wave5_print_reg_err((dev), (reason), __func__)
+
+static inline const char *cmd_to_str(int cmd, bool is_dec)
+{
+ switch (cmd) {
+ case W5_INIT_VPU:
+ return "W5_INIT_VPU";
+ case W5_WAKEUP_VPU:
+ return "W5_WAKEUP_VPU";
+ case W5_SLEEP_VPU:
+ return "W5_SLEEP_VPU";
+ case W5_CREATE_INSTANCE:
+ return "W5_CREATE_INSTANCE";
+ case W5_FLUSH_INSTANCE:
+ return "W5_FLUSH_INSTANCE";
+ case W5_DESTROY_INSTANCE:
+ return "W5_DESTROY_INSTANCE";
+ case W5_INIT_SEQ:
+ return "W5_INIT_SEQ";
+ case W5_SET_FB:
+ return "W5_SET_FB";
+ case W5_DEC_ENC_PIC:
+ if (is_dec)
+ return "W5_DEC_PIC";
+ return "W5_ENC_PIC";
+ case W5_ENC_SET_PARAM:
+ return "W5_ENC_SET_PARAM";
+ case W5_QUERY:
+ return "W5_QUERY";
+ case W5_UPDATE_BS:
+ return "W5_UPDATE_BS";
+ case W5_MAX_VPU_COMD:
+ return "W5_MAX_VPU_COMD";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static void _wave5_print_reg_err(struct vpu_device *vpu_dev, u32 reg_fail_reason,
+ const char *func)
+{
+ struct device *dev = vpu_dev->dev;
+ u32 reg_val;
+
+ switch (reg_fail_reason) {
+ case WAVE5_SYSERR_QUEUEING_FAIL:
+ reg_val = vpu_read_reg(vpu_dev, W5_RET_QUEUE_FAIL_REASON);
+ dev_dbg(dev, "%s: queueing failure: 0x%x\n", func, reg_val);
+ break;
+ case WAVE5_SYSERR_RESULT_NOT_READY:
+ dev_err(dev, "%s: result not ready: 0x%x\n", func, reg_fail_reason);
+ break;
+ case WAVE5_SYSERR_ACCESS_VIOLATION_HW:
+ dev_err(dev, "%s: access violation: 0x%x\n", func, reg_fail_reason);
+ break;
+ case WAVE5_SYSERR_WATCHDOG_TIMEOUT:
+ dev_err(dev, "%s: watchdog timeout: 0x%x\n", func, reg_fail_reason);
+ break;
+ case WAVE5_SYSERR_BUS_ERROR:
+ dev_err(dev, "%s: bus error: 0x%x\n", func, reg_fail_reason);
+ break;
+ case WAVE5_SYSERR_DOUBLE_FAULT:
+ dev_err(dev, "%s: double fault: 0x%x\n", func, reg_fail_reason);
+ break;
+ case WAVE5_SYSERR_VPU_STILL_RUNNING:
+ dev_err(dev, "%s: still running: 0x%x\n", func, reg_fail_reason);
+ break;
+ case WAVE5_SYSERR_VLC_BUF_FULL:
+ dev_err(dev, "%s: vlc buf full: 0x%x\n", func, reg_fail_reason);
+ break;
+ default:
+ dev_err(dev, "%s: failure:: 0x%x\n", func, reg_fail_reason);
+ break;
+ }
+}
+
+static int wave5_wait_fio_readl(struct vpu_device *vpu_dev, u32 addr, u32 val)
+{
+ u32 ctrl;
+ int ret;
+
+ ctrl = addr & 0xffff;
+ wave5_vdi_write_register(vpu_dev, W5_VPU_FIO_CTRL_ADDR, ctrl);
+ ret = read_poll_timeout(wave5_vdi_read_register, ctrl, ctrl & FIO_CTRL_READY,
+ 0, FIO_TIMEOUT, false, vpu_dev, W5_VPU_FIO_CTRL_ADDR);
+ if (ret)
+ return ret;
+
+ if (wave5_vdi_read_register(vpu_dev, W5_VPU_FIO_DATA) != val)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static void wave5_fio_writel(struct vpu_device *vpu_dev, unsigned int addr, unsigned int data)
+{
+ int ret;
+ unsigned int ctrl;
+
+ wave5_vdi_write_register(vpu_dev, W5_VPU_FIO_DATA, data);
+ ctrl = FIELD_GET(FASTIO_ADDRESS_MASK, addr);
+ ctrl |= FIO_CTRL_WRITE;
+ wave5_vdi_write_register(vpu_dev, W5_VPU_FIO_CTRL_ADDR, ctrl);
+ ret = read_poll_timeout(wave5_vdi_read_register, ctrl, ctrl & FIO_CTRL_READY, 0,
+ FIO_TIMEOUT, false, vpu_dev, W5_VPU_FIO_CTRL_ADDR);
+ if (ret)
+ dev_dbg_ratelimited(vpu_dev->dev, "FIO write timeout: addr=0x%x data=%x\n",
+ ctrl, data);
+}
+
+static int wave5_wait_bus_busy(struct vpu_device *vpu_dev, unsigned int addr)
+{
+ u32 gdi_status_check_value = 0x3f;
+
+ if (vpu_dev->product_code == WAVE521C_CODE ||
+ vpu_dev->product_code == WAVE521_CODE ||
+ vpu_dev->product_code == WAVE521E1_CODE)
+ gdi_status_check_value = 0x00ff1f3f;
+
+ return wave5_wait_fio_readl(vpu_dev, addr, gdi_status_check_value);
+}
+
+static int wave5_wait_vpu_busy(struct vpu_device *vpu_dev, unsigned int addr)
+{
+ u32 data;
+
+ return read_poll_timeout(wave5_vdi_read_register, data, data == 0,
+ 0, VPU_BUSY_CHECK_TIMEOUT, false, vpu_dev, addr);
+}
+
+static int wave5_wait_vcpu_bus_busy(struct vpu_device *vpu_dev, unsigned int addr)
+{
+ return wave5_wait_fio_readl(vpu_dev, addr, 0);
+}
+
+bool wave5_vpu_is_init(struct vpu_device *vpu_dev)
+{
+ return vpu_read_reg(vpu_dev, W5_VCPU_CUR_PC) != 0;
+}
+
+unsigned int wave5_vpu_get_product_id(struct vpu_device *vpu_dev)
+{
+ u32 val = vpu_read_reg(vpu_dev, W5_PRODUCT_NUMBER);
+
+ switch (val) {
+ case WAVE521C_CODE:
+ return PRODUCT_ID_521;
+ case WAVE521_CODE:
+ case WAVE521C_DUAL_CODE:
+ case WAVE521E1_CODE:
+ case WAVE511_CODE:
+ case WAVE517_CODE:
+ case WAVE537_CODE:
+ dev_err(vpu_dev->dev, "Unsupported product id (%x)\n", val);
+ break;
+ default:
+ dev_err(vpu_dev->dev, "Invalid product id (%x)\n", val);
+ break;
+ }
+
+ return PRODUCT_ID_NONE;
+}
+
+static void wave5_bit_issue_command(struct vpu_device *vpu_dev, struct vpu_instance *inst, u32 cmd)
+{
+ u32 instance_index;
+ u32 codec_mode;
+
+ if (inst) {
+ instance_index = inst->id;
+ codec_mode = inst->std;
+
+ vpu_write_reg(vpu_dev, W5_CMD_INSTANCE_INFO, (codec_mode << 16) |
+ (instance_index & 0xffff));
+ vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
+ }
+
+ vpu_write_reg(vpu_dev, W5_COMMAND, cmd);
+
+ if (inst) {
+ dev_dbg(vpu_dev->dev, "%s: cmd=0x%x (%s)\n", __func__, cmd,
+ cmd_to_str(cmd, inst->type == VPU_INST_TYPE_DEC));
+ } else {
+ dev_dbg(vpu_dev->dev, "%s: cmd=0x%x\n", __func__, cmd);
+ }
+
+ vpu_write_reg(vpu_dev, W5_VPU_HOST_INT_REQ, 1);
+}
+
+static int wave5_vpu_firmware_command_queue_error_check(struct vpu_device *dev, u32 *fail_res)
+{
+ u32 reason = 0;
+
+ /* Check if we were able to add a command into the VCPU QUEUE */
+ if (!vpu_read_reg(dev, W5_RET_SUCCESS)) {
+ reason = vpu_read_reg(dev, W5_RET_FAIL_REASON);
+ PRINT_REG_ERR(dev, reason);
+
+ /*
+ * The fail_res argument will be either NULL or 0.
+ * If the fail_res argument is NULL, then just return -EIO.
+ * Otherwise, assign the reason to fail_res, so that the
+ * calling function can use it.
+ */
+ if (fail_res)
+ *fail_res = reason;
+ else
+ return -EIO;
+
+ if (reason == WAVE5_SYSERR_VPU_STILL_RUNNING)
+ return -EBUSY;
+ }
+ return 0;
+}
+
+static int send_firmware_command(struct vpu_instance *inst, u32 cmd, bool check_success,
+ u32 *queue_status, u32 *fail_result)
+{
+ int ret;
+
+ wave5_bit_issue_command(inst->dev, inst, cmd);
+ ret = wave5_wait_vpu_busy(inst->dev, W5_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_warn(inst->dev->dev, "%s: command: '%s', timed out\n", __func__,
+ cmd_to_str(cmd, inst->type == VPU_INST_TYPE_DEC));
+ return -ETIMEDOUT;
+ }
+
+ if (queue_status)
+ *queue_status = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS);
+
+ /* In some cases we want to send multiple commands before checking
+ * whether they are queued properly
+ */
+ if (!check_success)
+ return 0;
+
+ return wave5_vpu_firmware_command_queue_error_check(inst->dev, fail_result);
+}
+
+static int wave5_send_query(struct vpu_device *vpu_dev, struct vpu_instance *inst,
+ enum query_opt query_opt)
+{
+ int ret;
+
+ vpu_write_reg(vpu_dev, W5_QUERY_OPTION, query_opt);
+ vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
+ wave5_bit_issue_command(vpu_dev, inst, W5_QUERY);
+
+ ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_warn(vpu_dev->dev, "command: 'W5_QUERY', timed out opt=0x%x\n", query_opt);
+ return ret;
+ }
+
+ return wave5_vpu_firmware_command_queue_error_check(vpu_dev, NULL);
+}
+
+static int setup_wave5_properties(struct device *dev)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+ struct vpu_attr *p_attr = &vpu_dev->attr;
+ u32 reg_val;
+ u8 *str;
+ int ret;
+ u32 hw_config_def0, hw_config_def1, hw_config_feature;
+
+ ret = wave5_send_query(vpu_dev, NULL, GET_VPU_INFO);
+ if (ret)
+ return ret;
+
+ reg_val = vpu_read_reg(vpu_dev, W5_RET_PRODUCT_NAME);
+ str = (u8 *)&reg_val;
+ p_attr->product_name[0] = str[3];
+ p_attr->product_name[1] = str[2];
+ p_attr->product_name[2] = str[1];
+ p_attr->product_name[3] = str[0];
+ p_attr->product_name[4] = 0;
+
+ p_attr->product_id = wave5_vpu_get_product_id(vpu_dev);
+ p_attr->product_version = vpu_read_reg(vpu_dev, W5_RET_PRODUCT_VERSION);
+ p_attr->fw_version = vpu_read_reg(vpu_dev, W5_RET_FW_VERSION);
+ p_attr->customer_id = vpu_read_reg(vpu_dev, W5_RET_CUSTOMER_ID);
+ hw_config_def0 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF0);
+ hw_config_def1 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF1);
+ hw_config_feature = vpu_read_reg(vpu_dev, W5_RET_CONF_FEATURE);
+
+ p_attr->support_hevc10bit_enc = FIELD_GET(FEATURE_HEVC10BIT_ENC, hw_config_feature);
+ p_attr->support_avc10bit_enc = FIELD_GET(FEATURE_AVC10BIT_ENC, hw_config_feature);
+
+ p_attr->support_decoders = FIELD_GET(FEATURE_AVC_DECODER, hw_config_def1) << STD_AVC;
+ p_attr->support_decoders |= FIELD_GET(FEATURE_HEVC_DECODER, hw_config_def1) << STD_HEVC;
+ p_attr->support_encoders = FIELD_GET(FEATURE_AVC_ENCODER, hw_config_def1) << STD_AVC;
+ p_attr->support_encoders |= FIELD_GET(FEATURE_HEVC_ENCODER, hw_config_def1) << STD_HEVC;
+
+ p_attr->support_backbone = FIELD_GET(FEATURE_BACKBONE, hw_config_def0);
+ p_attr->support_vcpu_backbone = FIELD_GET(FEATURE_VCPU_BACKBONE, hw_config_def0);
+ p_attr->support_vcore_backbone = FIELD_GET(FEATURE_VCORE_BACKBONE, hw_config_def0);
+
+ return 0;
+}
+
+int wave5_vpu_get_version(struct vpu_device *vpu_dev, u32 *revision)
+{
+ u32 reg_val;
+ int ret;
+
+ ret = wave5_send_query(vpu_dev, NULL, GET_VPU_INFO);
+ if (ret)
+ return ret;
+
+ reg_val = vpu_read_reg(vpu_dev, W5_RET_FW_VERSION);
+ if (revision) {
+ *revision = reg_val;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static void remap_page(struct vpu_device *vpu_dev, dma_addr_t code_base, u32 index)
+{
+ vpu_write_reg(vpu_dev, W5_VPU_REMAP_CTRL, REMAP_CTRL_REGISTER_VALUE(index));
+ vpu_write_reg(vpu_dev, W5_VPU_REMAP_VADDR, index * W5_REMAP_MAX_SIZE);
+ vpu_write_reg(vpu_dev, W5_VPU_REMAP_PADDR, code_base + index * W5_REMAP_MAX_SIZE);
+}
+
+int wave5_vpu_init(struct device *dev, u8 *fw, size_t size)
+{
+ struct vpu_buf *common_vb;
+ dma_addr_t code_base, temp_base;
+ u32 code_size, temp_size;
+ u32 i, reg_val, reason_code;
+ int ret;
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ common_vb = &vpu_dev->common_mem;
+
+ code_base = common_vb->daddr;
+ /* ALIGN TO 4KB */
+ code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff);
+ if (code_size < size * 2)
+ return -EINVAL;
+
+ temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET;
+ temp_size = WAVE5_TEMPBUF_SIZE;
+
+ ret = wave5_vdi_write_memory(vpu_dev, common_vb, 0, fw, size);
+ if (ret < 0) {
+ dev_err(vpu_dev->dev, "VPU init, Writing firmware to common buffer, fail: %d\n",
+ ret);
+ return ret;
+ }
+
+ vpu_write_reg(vpu_dev, W5_PO_CONF, 0);
+
+ /* clear registers */
+
+ for (i = W5_CMD_REG_BASE; i < W5_CMD_REG_END; i += 4)
+ vpu_write_reg(vpu_dev, i, 0x00);
+
+ remap_page(vpu_dev, code_base, W5_REMAP_INDEX0);
+ remap_page(vpu_dev, code_base, W5_REMAP_INDEX1);
+
+ vpu_write_reg(vpu_dev, W5_ADDR_CODE_BASE, code_base);
+ vpu_write_reg(vpu_dev, W5_CODE_SIZE, code_size);
+ vpu_write_reg(vpu_dev, W5_CODE_PARAM, (WAVE5_UPPER_PROC_AXI_ID << 4) | 0);
+ vpu_write_reg(vpu_dev, W5_ADDR_TEMP_BASE, temp_base);
+ vpu_write_reg(vpu_dev, W5_TEMP_SIZE, temp_size);
+
+ /* These register must be reset explicitly */
+ vpu_write_reg(vpu_dev, W5_HW_OPTION, 0);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
+ vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
+
+ /* Encoder interrupt */
+ reg_val = BIT(INT_WAVE5_ENC_SET_PARAM);
+ reg_val |= BIT(INT_WAVE5_ENC_PIC);
+ reg_val |= BIT(INT_WAVE5_BSBUF_FULL);
+ /* Decoder interrupt */
+ reg_val |= BIT(INT_WAVE5_INIT_SEQ);
+ reg_val |= BIT(INT_WAVE5_DEC_PIC);
+ reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY);
+ vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val);
+
+ reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0);
+ if (FIELD_GET(FEATURE_BACKBONE, reg_val)) {
+ reg_val = ((WAVE5_PROC_AXI_ID << 28) |
+ (WAVE5_PRP_AXI_ID << 24) |
+ (WAVE5_FBD_Y_AXI_ID << 20) |
+ (WAVE5_FBC_Y_AXI_ID << 16) |
+ (WAVE5_FBD_C_AXI_ID << 12) |
+ (WAVE5_FBC_C_AXI_ID << 8) |
+ (WAVE5_PRI_AXI_ID << 4) |
+ WAVE5_SEC_AXI_ID);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val);
+ }
+
+ vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
+ vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU);
+ vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1);
+ ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(vpu_dev->dev, "VPU init(W5_VPU_REMAP_CORE_START) timeout\n");
+ return ret;
+ }
+
+ ret = wave5_vpu_firmware_command_queue_error_check(vpu_dev, &reason_code);
+ if (ret)
+ return ret;
+
+ return setup_wave5_properties(dev);
+}
+
+int wave5_vpu_build_up_dec_param(struct vpu_instance *inst,
+ struct dec_open_param *param)
+{
+ int ret;
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ p_dec_info->cycle_per_tick = 256;
+ if (vpu_dev->sram_buf.size) {
+ p_dec_info->sec_axi_info.use_bit_enable = 1;
+ p_dec_info->sec_axi_info.use_ip_enable = 1;
+ p_dec_info->sec_axi_info.use_lf_row_enable = 1;
+ }
+ switch (inst->std) {
+ case W_HEVC_DEC:
+ p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_HEVC;
+ break;
+ case W_AVC_DEC:
+ p_dec_info->seq_change_mask = SEQ_CHANGE_ENABLE_ALL_AVC;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ p_dec_info->vb_work.size = WAVE521DEC_WORKBUF_SIZE;
+ ret = wave5_vdi_allocate_dma_memory(inst->dev, &p_dec_info->vb_work);
+ if (ret)
+ return ret;
+
+ vpu_write_reg(inst->dev, W5_CMD_DEC_VCORE_INFO, 1);
+
+ wave5_vdi_clear_memory(inst->dev, &p_dec_info->vb_work);
+
+ vpu_write_reg(inst->dev, W5_ADDR_WORK_BASE, p_dec_info->vb_work.daddr);
+ vpu_write_reg(inst->dev, W5_WORK_SIZE, p_dec_info->vb_work.size);
+
+ vpu_write_reg(inst->dev, W5_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr);
+ vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size);
+
+ vpu_write_reg(inst->dev, W5_CMD_DEC_BS_START_ADDR, p_dec_info->stream_buf_start_addr);
+ vpu_write_reg(inst->dev, W5_CMD_DEC_BS_SIZE, p_dec_info->stream_buf_size);
+
+ /* NOTE: SDMA reads MSB first */
+ vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, BITSTREAM_ENDIANNESS_BIG_ENDIAN);
+ /* This register must be reset explicitly */
+ vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0);
+ vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1));
+
+ ret = send_firmware_command(inst, W5_CREATE_INSTANCE, true, NULL, NULL);
+ if (ret) {
+ wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_work);
+ return ret;
+ }
+
+ p_dec_info->product_code = vpu_read_reg(inst->dev, W5_PRODUCT_NUMBER);
+
+ return 0;
+}
+
+int wave5_vpu_hw_flush_instance(struct vpu_instance *inst)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ u32 instance_queue_count, report_queue_count;
+ u32 reg_val = 0;
+ u32 fail_res = 0;
+ int ret;
+
+ ret = send_firmware_command(inst, W5_FLUSH_INSTANCE, true, &reg_val, &fail_res);
+ if (ret)
+ return ret;
+
+ instance_queue_count = (reg_val >> 16) & 0xff;
+ report_queue_count = (reg_val & QUEUE_REPORT_MASK);
+ if (instance_queue_count != 0 || report_queue_count != 0) {
+ dev_warn(inst->dev->dev,
+ "FLUSH_INSTANCE cmd didn't reset the amount of queued commands & reports");
+ }
+
+ /* reset our local copy of the counts */
+ p_dec_info->instance_queue_count = 0;
+ p_dec_info->report_queue_count = 0;
+
+ return 0;
+}
+
+static u32 get_bitstream_options(struct dec_info *info)
+{
+ u32 bs_option = BSOPTION_ENABLE_EXPLICIT_END;
+
+ if (info->stream_endflag)
+ bs_option |= BSOPTION_HIGHLIGHT_STREAM_END;
+ return bs_option;
+}
+
+int wave5_vpu_dec_init_seq(struct vpu_instance *inst)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ u32 cmd_option = INIT_SEQ_NORMAL;
+ u32 reg_val, fail_res;
+ int ret;
+
+ if (!inst->codec_info)
+ return -EINVAL;
+
+ vpu_write_reg(inst->dev, W5_BS_RD_PTR, p_dec_info->stream_rd_ptr);
+ vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr);
+
+ vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info));
+
+ vpu_write_reg(inst->dev, W5_COMMAND_OPTION, cmd_option);
+ vpu_write_reg(inst->dev, W5_CMD_DEC_USER_MASK, p_dec_info->user_data_enable);
+
+ ret = send_firmware_command(inst, W5_INIT_SEQ, true, &reg_val, &fail_res);
+ if (ret)
+ return ret;
+
+ p_dec_info->instance_queue_count = (reg_val >> 16) & 0xff;
+ p_dec_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK);
+
+ dev_dbg(inst->dev->dev, "%s: init seq sent (queue %u : %u)\n", __func__,
+ p_dec_info->instance_queue_count, p_dec_info->report_queue_count);
+
+ return 0;
+}
+
+static void wave5_get_dec_seq_result(struct vpu_instance *inst, struct dec_initial_info *info)
+{
+ u32 reg_val;
+ u32 profile_compatibility_flag;
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+
+ p_dec_info->stream_rd_ptr = wave5_dec_get_rd_ptr(inst);
+ info->rd_ptr = p_dec_info->stream_rd_ptr;
+
+ p_dec_info->frame_display_flag = vpu_read_reg(inst->dev, W5_RET_DEC_DISP_IDC);
+
+ reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_SIZE);
+ info->pic_width = ((reg_val >> 16) & 0xffff);
+ info->pic_height = (reg_val & 0xffff);
+ info->min_frame_buffer_count = vpu_read_reg(inst->dev, W5_RET_DEC_NUM_REQUIRED_FB);
+
+ reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_CROP_LEFT_RIGHT);
+ info->pic_crop_rect.left = (reg_val >> 16) & 0xffff;
+ info->pic_crop_rect.right = reg_val & 0xffff;
+ reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_CROP_TOP_BOTTOM);
+ info->pic_crop_rect.top = (reg_val >> 16) & 0xffff;
+ info->pic_crop_rect.bottom = reg_val & 0xffff;
+
+ reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_COLOR_SAMPLE_INFO);
+ info->luma_bitdepth = reg_val & 0xf;
+ info->chroma_bitdepth = (reg_val >> 4) & 0xf;
+
+ reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_SEQ_PARAM);
+ profile_compatibility_flag = (reg_val >> 12) & 0xff;
+ info->profile = (reg_val >> 24) & 0x1f;
+
+ if (inst->std == W_HEVC_DEC) {
+ /* guessing profile */
+ if (!info->profile) {
+ if ((profile_compatibility_flag & 0x06) == 0x06)
+ info->profile = HEVC_PROFILE_MAIN; /* main profile */
+ else if (profile_compatibility_flag & 0x04)
+ info->profile = HEVC_PROFILE_MAIN10; /* main10 profile */
+ else if (profile_compatibility_flag & 0x08)
+ /* main still picture profile */
+ info->profile = HEVC_PROFILE_STILLPICTURE;
+ else
+ info->profile = HEVC_PROFILE_MAIN; /* for old version HM */
+ }
+ } else if (inst->std == W_AVC_DEC) {
+ info->profile = FIELD_GET(SEQ_PARAM_PROFILE_MASK, reg_val);
+ }
+
+ info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE);
+ info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE);
+ p_dec_info->vlc_buf_size = info->vlc_buf_size;
+ p_dec_info->param_buf_size = info->param_buf_size;
+}
+
+int wave5_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info)
+{
+ int ret;
+ u32 reg_val;
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+
+ vpu_write_reg(inst->dev, W5_CMD_DEC_ADDR_REPORT_BASE, p_dec_info->user_data_buf_addr);
+ vpu_write_reg(inst->dev, W5_CMD_DEC_REPORT_SIZE, p_dec_info->user_data_buf_size);
+ vpu_write_reg(inst->dev, W5_CMD_DEC_REPORT_PARAM, REPORT_PARAM_ENDIANNESS_BIG_ENDIAN);
+
+ /* send QUERY cmd */
+ ret = wave5_send_query(inst->dev, inst, GET_RESULT);
+ if (ret)
+ return ret;
+
+ reg_val = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS);
+
+ p_dec_info->instance_queue_count = (reg_val >> 16) & 0xff;
+ p_dec_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK);
+
+ dev_dbg(inst->dev->dev, "%s: init seq complete (queue %u : %u)\n", __func__,
+ p_dec_info->instance_queue_count, p_dec_info->report_queue_count);
+
+ /* this is not a fatal error, set ret to -EIO but don't return immediately */
+ if (vpu_read_reg(inst->dev, W5_RET_DEC_DECODING_SUCCESS) != 1) {
+ info->seq_init_err_reason = vpu_read_reg(inst->dev, W5_RET_DEC_ERR_INFO);
+ ret = -EIO;
+ }
+
+ wave5_get_dec_seq_result(inst, info);
+
+ return ret;
+}
+
+int wave5_vpu_dec_register_framebuffer(struct vpu_instance *inst, struct frame_buffer *fb_arr,
+ enum tiled_map_type map_type, unsigned int count)
+{
+ int ret;
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ struct dec_initial_info *init_info = &p_dec_info->initial_info;
+ size_t remain, idx, j, i, cnt_8_chunk, size;
+ u32 start_no, end_no;
+ u32 reg_val, cbcr_interleave, nv21, pic_size;
+ u32 addr_y, addr_cb, addr_cr;
+ u32 mv_col_size, frame_width, frame_height, fbc_y_tbl_size, fbc_c_tbl_size;
+ struct vpu_buf vb_buf;
+ bool justified = WTL_RIGHT_JUSTIFIED;
+ u32 format_no = WTL_PIXEL_8BIT;
+ u32 color_format = 0;
+ u32 pixel_order = 1;
+ u32 bwb_flag = (map_type == LINEAR_FRAME_MAP) ? 1 : 0;
+
+ cbcr_interleave = inst->cbcr_interleave;
+ nv21 = inst->nv21;
+ mv_col_size = 0;
+ fbc_y_tbl_size = 0;
+ fbc_c_tbl_size = 0;
+
+ if (map_type >= COMPRESSED_FRAME_MAP) {
+ cbcr_interleave = 0;
+ nv21 = 0;
+
+ switch (inst->std) {
+ case W_HEVC_DEC:
+ mv_col_size = WAVE5_DEC_HEVC_BUF_SIZE(init_info->pic_width,
+ init_info->pic_height);
+ break;
+ case W_AVC_DEC:
+ mv_col_size = WAVE5_DEC_AVC_BUF_SIZE(init_info->pic_width,
+ init_info->pic_height);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC) {
+ size = ALIGN(ALIGN(mv_col_size, 16), BUFFER_MARGIN) + BUFFER_MARGIN;
+ ret = wave5_vdi_allocate_array(inst->dev, p_dec_info->vb_mv, count, size);
+ if (ret)
+ goto free_mv_buffers;
+ }
+
+ frame_width = init_info->pic_width;
+ frame_height = init_info->pic_height;
+ fbc_y_tbl_size = ALIGN(WAVE5_FBC_LUMA_TABLE_SIZE(frame_width, frame_height), 16);
+ fbc_c_tbl_size = ALIGN(WAVE5_FBC_CHROMA_TABLE_SIZE(frame_width, frame_height), 16);
+
+ size = ALIGN(fbc_y_tbl_size, BUFFER_MARGIN) + BUFFER_MARGIN;
+ ret = wave5_vdi_allocate_array(inst->dev, p_dec_info->vb_fbc_y_tbl, count, size);
+ if (ret)
+ goto free_fbc_y_tbl_buffers;
+
+ size = ALIGN(fbc_c_tbl_size, BUFFER_MARGIN) + BUFFER_MARGIN;
+ ret = wave5_vdi_allocate_array(inst->dev, p_dec_info->vb_fbc_c_tbl, count, size);
+ if (ret)
+ goto free_fbc_c_tbl_buffers;
+
+ pic_size = (init_info->pic_width << 16) | (init_info->pic_height);
+
+ vb_buf.size = (p_dec_info->vlc_buf_size * VLC_BUF_NUM) +
+ (p_dec_info->param_buf_size * COMMAND_QUEUE_DEPTH);
+ vb_buf.daddr = 0;
+
+ if (vb_buf.size != p_dec_info->vb_task.size) {
+ wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task);
+ ret = wave5_vdi_allocate_dma_memory(inst->dev, &vb_buf);
+ if (ret)
+ goto free_fbc_c_tbl_buffers;
+
+ p_dec_info->vb_task = vb_buf;
+ }
+
+ vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF,
+ p_dec_info->vb_task.daddr);
+ vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE, vb_buf.size);
+ } else {
+ pic_size = (init_info->pic_width << 16) | (init_info->pic_height);
+
+ if (inst->output_format == FORMAT_422)
+ color_format = 1;
+ }
+ vpu_write_reg(inst->dev, W5_PIC_SIZE, pic_size);
+
+ reg_val = (bwb_flag << 28) |
+ (pixel_order << 23) |
+ (justified << 22) |
+ (format_no << 20) |
+ (color_format << 19) |
+ (nv21 << 17) |
+ (cbcr_interleave << 16) |
+ (fb_arr[0].stride);
+ vpu_write_reg(inst->dev, W5_COMMON_PIC_INFO, reg_val);
+
+ remain = count;
+ cnt_8_chunk = DIV_ROUND_UP(count, 8);
+ idx = 0;
+ for (j = 0; j < cnt_8_chunk; j++) {
+ reg_val = (j == cnt_8_chunk - 1) << 4 | ((j == 0) << 3);
+ vpu_write_reg(inst->dev, W5_SFB_OPTION, reg_val);
+ start_no = j * 8;
+ end_no = start_no + ((remain >= 8) ? 8 : remain) - 1;
+
+ vpu_write_reg(inst->dev, W5_SET_FB_NUM, (start_no << 8) | end_no);
+
+ for (i = 0; i < 8 && i < remain; i++) {
+ addr_y = fb_arr[i + start_no].buf_y;
+ addr_cb = fb_arr[i + start_no].buf_cb;
+ addr_cr = fb_arr[i + start_no].buf_cr;
+ vpu_write_reg(inst->dev, W5_ADDR_LUMA_BASE0 + (i << 4), addr_y);
+ vpu_write_reg(inst->dev, W5_ADDR_CB_BASE0 + (i << 4), addr_cb);
+ if (map_type >= COMPRESSED_FRAME_MAP) {
+ /* luma FBC offset table */
+ vpu_write_reg(inst->dev, W5_ADDR_FBC_Y_OFFSET0 + (i << 4),
+ p_dec_info->vb_fbc_y_tbl[idx].daddr);
+ /* chroma FBC offset table */
+ vpu_write_reg(inst->dev, W5_ADDR_FBC_C_OFFSET0 + (i << 4),
+ p_dec_info->vb_fbc_c_tbl[idx].daddr);
+ vpu_write_reg(inst->dev, W5_ADDR_MV_COL0 + (i << 2),
+ p_dec_info->vb_mv[idx].daddr);
+ } else {
+ vpu_write_reg(inst->dev, W5_ADDR_CR_BASE0 + (i << 4), addr_cr);
+ vpu_write_reg(inst->dev, W5_ADDR_FBC_C_OFFSET0 + (i << 4), 0);
+ vpu_write_reg(inst->dev, W5_ADDR_MV_COL0 + (i << 2), 0);
+ }
+ idx++;
+ }
+ remain -= i;
+
+ ret = send_firmware_command(inst, W5_SET_FB, false, NULL, NULL);
+ if (ret)
+ goto free_buffers;
+ }
+
+ reg_val = vpu_read_reg(inst->dev, W5_RET_SUCCESS);
+ if (!reg_val) {
+ ret = -EIO;
+ goto free_buffers;
+ }
+
+ return 0;
+
+free_buffers:
+ wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task);
+free_fbc_c_tbl_buffers:
+ for (i = 0; i < count; i++)
+ wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_fbc_c_tbl[i]);
+free_fbc_y_tbl_buffers:
+ for (i = 0; i < count; i++)
+ wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_fbc_y_tbl[i]);
+free_mv_buffers:
+ for (i = 0; i < count; i++)
+ wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_mv[i]);
+ return ret;
+}
+
+int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res)
+{
+ u32 reg_val;
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int ret;
+
+ vpu_write_reg(inst->dev, W5_BS_RD_PTR, p_dec_info->stream_rd_ptr);
+ vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr);
+
+ vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info));
+
+ /* secondary AXI */
+ reg_val = p_dec_info->sec_axi_info.use_bit_enable |
+ (p_dec_info->sec_axi_info.use_ip_enable << 9) |
+ (p_dec_info->sec_axi_info.use_lf_row_enable << 15);
+ vpu_write_reg(inst->dev, W5_USE_SEC_AXI, reg_val);
+
+ /* set attributes of user buffer */
+ vpu_write_reg(inst->dev, W5_CMD_DEC_USER_MASK, p_dec_info->user_data_enable);
+
+ vpu_write_reg(inst->dev, W5_COMMAND_OPTION, DEC_PIC_NORMAL);
+ vpu_write_reg(inst->dev, W5_CMD_DEC_TEMPORAL_ID_PLUS1,
+ (p_dec_info->target_spatial_id << 9) |
+ (p_dec_info->temp_id_select_mode << 8) | p_dec_info->target_temp_id);
+ vpu_write_reg(inst->dev, W5_CMD_SEQ_CHANGE_ENABLE_FLAG, p_dec_info->seq_change_mask);
+ /* When reordering is disabled we force the latency of the framebuffers */
+ vpu_write_reg(inst->dev, W5_CMD_DEC_FORCE_FB_LATENCY_PLUS1, !p_dec_info->reorder_enable);
+
+ ret = send_firmware_command(inst, W5_DEC_ENC_PIC, true, &reg_val, fail_res);
+ if (ret == -ETIMEDOUT)
+ return ret;
+
+ p_dec_info->instance_queue_count = (reg_val >> 16) & 0xff;
+ p_dec_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK);
+
+ dev_dbg(inst->dev->dev, "%s: dec pic sent (queue %u : %u)\n", __func__,
+ p_dec_info->instance_queue_count, p_dec_info->report_queue_count);
+
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int wave5_vpu_dec_get_result(struct vpu_instance *inst, struct dec_output_info *result)
+{
+ int ret;
+ u32 index, nal_unit_type, reg_val, sub_layer_info;
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ vpu_write_reg(inst->dev, W5_CMD_DEC_ADDR_REPORT_BASE, p_dec_info->user_data_buf_addr);
+ vpu_write_reg(inst->dev, W5_CMD_DEC_REPORT_SIZE, p_dec_info->user_data_buf_size);
+ vpu_write_reg(inst->dev, W5_CMD_DEC_REPORT_PARAM, REPORT_PARAM_ENDIANNESS_BIG_ENDIAN);
+
+ /* send QUERY cmd */
+ ret = wave5_send_query(vpu_dev, inst, GET_RESULT);
+ if (ret)
+ return ret;
+
+ reg_val = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS);
+
+ p_dec_info->instance_queue_count = (reg_val >> 16) & 0xff;
+ p_dec_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK);
+
+ dev_dbg(inst->dev->dev, "%s: dec pic complete (queue %u : %u)\n", __func__,
+ p_dec_info->instance_queue_count, p_dec_info->report_queue_count);
+
+ reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_TYPE);
+
+ nal_unit_type = (reg_val >> 4) & 0x3f;
+
+ if (inst->std == W_HEVC_DEC) {
+ if (reg_val & 0x04)
+ result->pic_type = PIC_TYPE_B;
+ else if (reg_val & 0x02)
+ result->pic_type = PIC_TYPE_P;
+ else if (reg_val & 0x01)
+ result->pic_type = PIC_TYPE_I;
+ else
+ result->pic_type = PIC_TYPE_MAX;
+ if ((nal_unit_type == 19 || nal_unit_type == 20) && result->pic_type == PIC_TYPE_I)
+ /* IDR_W_RADL, IDR_N_LP */
+ result->pic_type = PIC_TYPE_IDR;
+ } else if (inst->std == W_AVC_DEC) {
+ if (reg_val & 0x04)
+ result->pic_type = PIC_TYPE_B;
+ else if (reg_val & 0x02)
+ result->pic_type = PIC_TYPE_P;
+ else if (reg_val & 0x01)
+ result->pic_type = PIC_TYPE_I;
+ else
+ result->pic_type = PIC_TYPE_MAX;
+ if (nal_unit_type == 5 && result->pic_type == PIC_TYPE_I)
+ result->pic_type = PIC_TYPE_IDR;
+ }
+ index = vpu_read_reg(inst->dev, W5_RET_DEC_DISPLAY_INDEX);
+ result->index_frame_display = index;
+ index = vpu_read_reg(inst->dev, W5_RET_DEC_DECODED_INDEX);
+ result->index_frame_decoded = index;
+ result->index_frame_decoded_for_tiled = index;
+
+ sub_layer_info = vpu_read_reg(inst->dev, W5_RET_DEC_SUB_LAYER_INFO);
+ result->temporal_id = sub_layer_info & 0x7;
+
+ if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC) {
+ result->decoded_poc = -1;
+ if (result->index_frame_decoded >= 0 ||
+ result->index_frame_decoded == DECODED_IDX_FLAG_SKIP)
+ result->decoded_poc = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_POC);
+ }
+
+ result->sequence_changed = vpu_read_reg(inst->dev, W5_RET_DEC_NOTIFICATION);
+ reg_val = vpu_read_reg(inst->dev, W5_RET_DEC_PIC_SIZE);
+ result->dec_pic_width = reg_val >> 16;
+ result->dec_pic_height = reg_val & 0xffff;
+
+ if (result->sequence_changed) {
+ memcpy((void *)&p_dec_info->new_seq_info, (void *)&p_dec_info->initial_info,
+ sizeof(struct dec_initial_info));
+ wave5_get_dec_seq_result(inst, &p_dec_info->new_seq_info);
+ }
+
+ result->dec_host_cmd_tick = vpu_read_reg(inst->dev, W5_RET_DEC_HOST_CMD_TICK);
+ result->dec_decode_end_tick = vpu_read_reg(inst->dev, W5_RET_DEC_DECODING_ENC_TICK);
+
+ if (!p_dec_info->first_cycle_check) {
+ result->frame_cycle =
+ (result->dec_decode_end_tick - result->dec_host_cmd_tick) *
+ p_dec_info->cycle_per_tick;
+ vpu_dev->last_performance_cycles = result->dec_decode_end_tick;
+ p_dec_info->first_cycle_check = true;
+ } else if (result->index_frame_decoded_for_tiled != -1) {
+ result->frame_cycle =
+ (result->dec_decode_end_tick - vpu_dev->last_performance_cycles) *
+ p_dec_info->cycle_per_tick;
+ vpu_dev->last_performance_cycles = result->dec_decode_end_tick;
+ if (vpu_dev->last_performance_cycles < result->dec_host_cmd_tick)
+ result->frame_cycle =
+ (result->dec_decode_end_tick - result->dec_host_cmd_tick) *
+ p_dec_info->cycle_per_tick;
+ }
+
+ /* no remaining command. reset frame cycle. */
+ if (p_dec_info->instance_queue_count == 0 && p_dec_info->report_queue_count == 0)
+ p_dec_info->first_cycle_check = false;
+
+ return 0;
+}
+
+int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size)
+{
+ struct vpu_buf *common_vb;
+ dma_addr_t code_base, temp_base;
+ dma_addr_t old_code_base, temp_size;
+ u32 code_size, reason_code;
+ u32 reg_val;
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ common_vb = &vpu_dev->common_mem;
+
+ code_base = common_vb->daddr;
+ /* ALIGN TO 4KB */
+ code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff);
+ if (code_size < size * 2)
+ return -EINVAL;
+ temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET;
+ temp_size = WAVE5_TEMPBUF_SIZE;
+
+ old_code_base = vpu_read_reg(vpu_dev, W5_VPU_REMAP_PADDR);
+
+ if (old_code_base != code_base + W5_REMAP_INDEX1 * W5_REMAP_MAX_SIZE) {
+ int ret;
+
+ ret = wave5_vdi_write_memory(vpu_dev, common_vb, 0, fw, size);
+ if (ret < 0) {
+ dev_err(vpu_dev->dev,
+ "VPU init, Writing firmware to common buffer, fail: %d\n", ret);
+ return ret;
+ }
+
+ vpu_write_reg(vpu_dev, W5_PO_CONF, 0);
+
+ ret = wave5_vpu_reset(dev, SW_RESET_ON_BOOT);
+ if (ret < 0) {
+ dev_err(vpu_dev->dev, "VPU init, Resetting the VPU, fail: %d\n", ret);
+ return ret;
+ }
+
+ remap_page(vpu_dev, code_base, W5_REMAP_INDEX0);
+ remap_page(vpu_dev, code_base, W5_REMAP_INDEX1);
+
+ vpu_write_reg(vpu_dev, W5_ADDR_CODE_BASE, code_base);
+ vpu_write_reg(vpu_dev, W5_CODE_SIZE, code_size);
+ vpu_write_reg(vpu_dev, W5_CODE_PARAM, (WAVE5_UPPER_PROC_AXI_ID << 4) | 0);
+ vpu_write_reg(vpu_dev, W5_ADDR_TEMP_BASE, temp_base);
+ vpu_write_reg(vpu_dev, W5_TEMP_SIZE, temp_size);
+
+ /* These register must be reset explicitly */
+ vpu_write_reg(vpu_dev, W5_HW_OPTION, 0);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
+ vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
+
+ /* Encoder interrupt */
+ reg_val = BIT(INT_WAVE5_ENC_SET_PARAM);
+ reg_val |= BIT(INT_WAVE5_ENC_PIC);
+ reg_val |= BIT(INT_WAVE5_BSBUF_FULL);
+ /* Decoder interrupt */
+ reg_val |= BIT(INT_WAVE5_INIT_SEQ);
+ reg_val |= BIT(INT_WAVE5_DEC_PIC);
+ reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY);
+ vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val);
+
+ reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0);
+ if (FIELD_GET(FEATURE_BACKBONE, reg_val)) {
+ reg_val = ((WAVE5_PROC_AXI_ID << 28) |
+ (WAVE5_PRP_AXI_ID << 24) |
+ (WAVE5_FBD_Y_AXI_ID << 20) |
+ (WAVE5_FBC_Y_AXI_ID << 16) |
+ (WAVE5_FBD_C_AXI_ID << 12) |
+ (WAVE5_FBC_C_AXI_ID << 8) |
+ (WAVE5_PRI_AXI_ID << 4) |
+ WAVE5_SEC_AXI_ID);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val);
+ }
+
+ vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
+ vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU);
+ vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1);
+
+ ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(vpu_dev->dev, "VPU reinit(W5_VPU_REMAP_CORE_START) timeout\n");
+ return ret;
+ }
+
+ ret = wave5_vpu_firmware_command_queue_error_check(vpu_dev, &reason_code);
+ if (ret)
+ return ret;
+ }
+
+ return setup_wave5_properties(dev);
+}
+
+static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code,
+ size_t size)
+{
+ u32 reg_val;
+ struct vpu_buf *common_vb;
+ dma_addr_t code_base;
+ u32 code_size, reason_code;
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+ int ret;
+
+ if (i_sleep_wake) {
+ ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS);
+ if (ret)
+ return ret;
+
+ /*
+ * Declare who has ownership for the host interface access
+ * 1 = VPU
+ * 0 = Host processor
+ */
+ vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
+ vpu_write_reg(vpu_dev, W5_COMMAND, W5_SLEEP_VPU);
+ /* Send an interrupt named HOST to the VPU */
+ vpu_write_reg(vpu_dev, W5_VPU_HOST_INT_REQ, 1);
+
+ ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS);
+ if (ret)
+ return ret;
+
+ ret = wave5_vpu_firmware_command_queue_error_check(vpu_dev, &reason_code);
+ if (ret)
+ return ret;
+ } else { /* restore */
+ common_vb = &vpu_dev->common_mem;
+
+ code_base = common_vb->daddr;
+ /* ALIGN TO 4KB */
+ code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff);
+ if (code_size < size * 2) {
+ dev_err(dev, "size too small\n");
+ return -EINVAL;
+ }
+
+ /* Power on without DEBUG mode */
+ vpu_write_reg(vpu_dev, W5_PO_CONF, 0);
+
+ remap_page(vpu_dev, code_base, W5_REMAP_INDEX0);
+ remap_page(vpu_dev, code_base, W5_REMAP_INDEX1);
+
+ vpu_write_reg(vpu_dev, W5_ADDR_CODE_BASE, code_base);
+ vpu_write_reg(vpu_dev, W5_CODE_SIZE, code_size);
+ vpu_write_reg(vpu_dev, W5_CODE_PARAM, (WAVE5_UPPER_PROC_AXI_ID << 4) | 0);
+
+ /* These register must be reset explicitly */
+ vpu_write_reg(vpu_dev, W5_HW_OPTION, 0);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
+ vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
+
+ /* Encoder interrupt */
+ reg_val = BIT(INT_WAVE5_ENC_SET_PARAM);
+ reg_val |= BIT(INT_WAVE5_ENC_PIC);
+ reg_val |= BIT(INT_WAVE5_BSBUF_FULL);
+ /* Decoder interrupt */
+ reg_val |= BIT(INT_WAVE5_INIT_SEQ);
+ reg_val |= BIT(INT_WAVE5_DEC_PIC);
+ reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY);
+ vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val);
+
+ reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0);
+ if (FIELD_GET(FEATURE_BACKBONE, reg_val)) {
+ reg_val = ((WAVE5_PROC_AXI_ID << 28) |
+ (WAVE5_PRP_AXI_ID << 24) |
+ (WAVE5_FBD_Y_AXI_ID << 20) |
+ (WAVE5_FBC_Y_AXI_ID << 16) |
+ (WAVE5_FBD_C_AXI_ID << 12) |
+ (WAVE5_FBC_C_AXI_ID << 8) |
+ (WAVE5_PRI_AXI_ID << 4) |
+ WAVE5_SEC_AXI_ID);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val);
+ }
+
+ vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
+ vpu_write_reg(vpu_dev, W5_COMMAND, W5_WAKEUP_VPU);
+ /* Start VPU after settings */
+ vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1);
+
+ ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_BUSY_STATUS);
+ if (ret) {
+ dev_err(vpu_dev->dev, "VPU wakeup(W5_VPU_REMAP_CORE_START) timeout\n");
+ return ret;
+ }
+
+ return wave5_vpu_firmware_command_queue_error_check(vpu_dev, &reason_code);
+ }
+
+ return 0;
+}
+
+int wave5_vpu_reset(struct device *dev, enum sw_reset_mode reset_mode)
+{
+ u32 val = 0;
+ int ret = 0;
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+ struct vpu_attr *p_attr = &vpu_dev->attr;
+ /* VPU doesn't send response. force to set BUSY flag to 0. */
+ vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 0);
+
+ if (reset_mode == SW_RESET_SAFETY) {
+ ret = wave5_vpu_sleep_wake(dev, true, NULL, 0);
+ if (ret)
+ return ret;
+ }
+
+ val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0);
+ if ((val >> 16) & 0x1)
+ p_attr->support_backbone = true;
+ if ((val >> 22) & 0x1)
+ p_attr->support_vcore_backbone = true;
+ if ((val >> 28) & 0x1)
+ p_attr->support_vcpu_backbone = true;
+
+ /* waiting for completion of bus transaction */
+ if (p_attr->support_backbone) {
+ dev_dbg(dev, "%s: backbone supported\n", __func__);
+
+ if (p_attr->support_vcore_backbone) {
+ if (p_attr->support_vcpu_backbone) {
+ /* step1 : disable request */
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCPU, 0xFF);
+
+ /* step2 : waiting for completion of bus transaction */
+ ret = wave5_wait_vcpu_bus_busy(vpu_dev,
+ W5_BACKBONE_BUS_STATUS_VCPU);
+ if (ret) {
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCPU, 0x00);
+ return ret;
+ }
+ }
+ /* step1 : disable request */
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCORE0, 0x7);
+
+ /* step2 : waiting for completion of bus transaction */
+ if (wave5_wait_bus_busy(vpu_dev, W5_BACKBONE_BUS_STATUS_VCORE0)) {
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCORE0, 0x00);
+ return -EBUSY;
+ }
+ } else {
+ /* step1 : disable request */
+ wave5_fio_writel(vpu_dev, W5_COMBINED_BACKBONE_BUS_CTRL, 0x7);
+
+ /* step2 : waiting for completion of bus transaction */
+ if (wave5_wait_bus_busy(vpu_dev, W5_COMBINED_BACKBONE_BUS_STATUS)) {
+ wave5_fio_writel(vpu_dev, W5_COMBINED_BACKBONE_BUS_CTRL, 0x00);
+ return -EBUSY;
+ }
+ }
+ } else {
+ dev_dbg(dev, "%s: backbone NOT supported\n", __func__);
+ /* step1 : disable request */
+ wave5_fio_writel(vpu_dev, W5_GDI_BUS_CTRL, 0x100);
+
+ /* step2 : waiting for completion of bus transaction */
+ ret = wave5_wait_bus_busy(vpu_dev, W5_GDI_BUS_STATUS);
+ if (ret) {
+ wave5_fio_writel(vpu_dev, W5_GDI_BUS_CTRL, 0x00);
+ return ret;
+ }
+ }
+
+ switch (reset_mode) {
+ case SW_RESET_ON_BOOT:
+ case SW_RESET_FORCE:
+ case SW_RESET_SAFETY:
+ val = W5_RST_BLOCK_ALL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (val) {
+ vpu_write_reg(vpu_dev, W5_VPU_RESET_REQ, val);
+
+ ret = wave5_wait_vpu_busy(vpu_dev, W5_VPU_RESET_STATUS);
+ if (ret) {
+ vpu_write_reg(vpu_dev, W5_VPU_RESET_REQ, 0);
+ return ret;
+ }
+ vpu_write_reg(vpu_dev, W5_VPU_RESET_REQ, 0);
+ }
+ /* step3 : must clear GDI_BUS_CTRL after done SW_RESET */
+ if (p_attr->support_backbone) {
+ if (p_attr->support_vcore_backbone) {
+ if (p_attr->support_vcpu_backbone)
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCPU, 0x00);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_BUS_CTRL_VCORE0, 0x00);
+ } else {
+ wave5_fio_writel(vpu_dev, W5_COMBINED_BACKBONE_BUS_CTRL, 0x00);
+ }
+ } else {
+ wave5_fio_writel(vpu_dev, W5_GDI_BUS_CTRL, 0x00);
+ }
+ if (reset_mode == SW_RESET_SAFETY || reset_mode == SW_RESET_FORCE)
+ ret = wave5_vpu_sleep_wake(dev, false, NULL, 0);
+
+ return ret;
+}
+
+int wave5_vpu_dec_finish_seq(struct vpu_instance *inst, u32 *fail_res)
+{
+ return send_firmware_command(inst, W5_DESTROY_INSTANCE, true, NULL, fail_res);
+}
+
+int wave5_vpu_dec_set_bitstream_flag(struct vpu_instance *inst, bool eos)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+
+ p_dec_info->stream_endflag = eos ? 1 : 0;
+ vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info));
+ vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr);
+
+ return send_firmware_command(inst, W5_UPDATE_BS, true, NULL, NULL);
+}
+
+int wave5_dec_clr_disp_flag(struct vpu_instance *inst, unsigned int index)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int ret;
+
+ vpu_write_reg(inst->dev, W5_CMD_DEC_CLR_DISP_IDC, BIT(index));
+ vpu_write_reg(inst->dev, W5_CMD_DEC_SET_DISP_IDC, 0);
+
+ ret = wave5_send_query(inst->dev, inst, UPDATE_DISP_FLAG);
+ if (ret)
+ return ret;
+
+ p_dec_info->frame_display_flag = vpu_read_reg(inst->dev, W5_RET_DEC_DISP_IDC);
+
+ return 0;
+}
+
+int wave5_dec_set_disp_flag(struct vpu_instance *inst, unsigned int index)
+{
+ int ret;
+
+ vpu_write_reg(inst->dev, W5_CMD_DEC_CLR_DISP_IDC, 0);
+ vpu_write_reg(inst->dev, W5_CMD_DEC_SET_DISP_IDC, BIT(index));
+
+ ret = wave5_send_query(inst->dev, inst, UPDATE_DISP_FLAG);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int wave5_vpu_clear_interrupt(struct vpu_instance *inst, u32 flags)
+{
+ u32 interrupt_reason;
+
+ interrupt_reason = vpu_read_reg(inst->dev, W5_VPU_VINT_REASON_USR);
+ interrupt_reason &= ~flags;
+ vpu_write_reg(inst->dev, W5_VPU_VINT_REASON_USR, interrupt_reason);
+
+ return 0;
+}
+
+dma_addr_t wave5_dec_get_rd_ptr(struct vpu_instance *inst)
+{
+ int ret;
+
+ ret = wave5_send_query(inst->dev, inst, GET_BS_RD_PTR);
+ if (ret)
+ return inst->codec_info->dec_info.stream_rd_ptr;
+
+ return vpu_read_reg(inst->dev, W5_RET_QUERY_DEC_BS_RD_PTR);
+}
+
+int wave5_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr)
+{
+ int ret;
+
+ vpu_write_reg(inst->dev, W5_RET_QUERY_DEC_SET_BS_RD_PTR, addr);
+
+ ret = wave5_send_query(inst->dev, inst, SET_BS_RD_PTR);
+
+ return ret;
+}
+
+/************************************************************************/
+/* ENCODER functions */
+/************************************************************************/
+
+int wave5_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst,
+ struct enc_open_param *open_param)
+{
+ int ret;
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ u32 reg_val;
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+ dma_addr_t buffer_addr;
+ size_t buffer_size;
+
+ p_enc_info->cycle_per_tick = 256;
+ if (vpu_dev->sram_buf.size) {
+ p_enc_info->sec_axi_info.use_enc_rdo_enable = 1;
+ p_enc_info->sec_axi_info.use_enc_lf_enable = 1;
+ }
+
+ p_enc_info->vb_work.size = WAVE521ENC_WORKBUF_SIZE;
+ ret = wave5_vdi_allocate_dma_memory(vpu_dev, &p_enc_info->vb_work);
+ if (ret) {
+ memset(&p_enc_info->vb_work, 0, sizeof(p_enc_info->vb_work));
+ return ret;
+ }
+
+ wave5_vdi_clear_memory(vpu_dev, &p_enc_info->vb_work);
+
+ vpu_write_reg(inst->dev, W5_ADDR_WORK_BASE, p_enc_info->vb_work.daddr);
+ vpu_write_reg(inst->dev, W5_WORK_SIZE, p_enc_info->vb_work.size);
+
+ vpu_write_reg(inst->dev, W5_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr);
+ vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size);
+
+ reg_val = (open_param->line_buf_int_en << 6) | BITSTREAM_ENDIANNESS_BIG_ENDIAN;
+ vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, reg_val);
+ vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0);
+ vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1));
+
+ /* This register must be reset explicitly */
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SRC_OPTIONS, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_VCORE_INFO, 1);
+
+ ret = send_firmware_command(inst, W5_CREATE_INSTANCE, true, NULL, NULL);
+ if (ret)
+ goto free_vb_work;
+
+ buffer_addr = open_param->bitstream_buffer;
+ buffer_size = open_param->bitstream_buffer_size;
+ p_enc_info->stream_rd_ptr = buffer_addr;
+ p_enc_info->stream_wr_ptr = buffer_addr;
+ p_enc_info->line_buf_int_en = open_param->line_buf_int_en;
+ p_enc_info->stream_buf_start_addr = buffer_addr;
+ p_enc_info->stream_buf_size = buffer_size;
+ p_enc_info->stream_buf_end_addr = buffer_addr + buffer_size;
+ p_enc_info->stride = 0;
+ p_enc_info->initial_info_obtained = false;
+ p_enc_info->product_code = vpu_read_reg(inst->dev, W5_PRODUCT_NUMBER);
+
+ return 0;
+free_vb_work:
+ if (wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_work))
+ memset(&p_enc_info->vb_work, 0, sizeof(p_enc_info->vb_work));
+ return ret;
+}
+
+static void wave5_set_enc_crop_info(u32 codec, struct enc_wave_param *param, int rot_mode,
+ int src_width, int src_height)
+{
+ int aligned_width = (codec == W_HEVC_ENC) ? ALIGN(src_width, 32) : ALIGN(src_width, 16);
+ int aligned_height = (codec == W_HEVC_ENC) ? ALIGN(src_height, 32) : ALIGN(src_height, 16);
+ int pad_right, pad_bot;
+ int crop_right, crop_left, crop_top, crop_bot;
+ int prp_mode = rot_mode >> 1; /* remove prp_enable bit */
+
+ if (codec == W_HEVC_ENC &&
+ (!rot_mode || prp_mode == 14)) /* prp_mode 14 : hor_mir && ver_mir && rot_180 */
+ return;
+
+ pad_right = aligned_width - src_width;
+ pad_bot = aligned_height - src_height;
+
+ if (param->conf_win_right > 0)
+ crop_right = param->conf_win_right + pad_right;
+ else
+ crop_right = pad_right;
+
+ if (param->conf_win_bot > 0)
+ crop_bot = param->conf_win_bot + pad_bot;
+ else
+ crop_bot = pad_bot;
+
+ crop_top = param->conf_win_top;
+ crop_left = param->conf_win_left;
+
+ param->conf_win_top = crop_top;
+ param->conf_win_left = crop_left;
+ param->conf_win_bot = crop_bot;
+ param->conf_win_right = crop_right;
+
+ switch (prp_mode) {
+ case 0:
+ return;
+ case 1:
+ case 15:
+ param->conf_win_top = crop_right;
+ param->conf_win_left = crop_top;
+ param->conf_win_bot = crop_left;
+ param->conf_win_right = crop_bot;
+ break;
+ case 2:
+ case 12:
+ param->conf_win_top = crop_bot;
+ param->conf_win_left = crop_right;
+ param->conf_win_bot = crop_top;
+ param->conf_win_right = crop_left;
+ break;
+ case 3:
+ case 13:
+ param->conf_win_top = crop_left;
+ param->conf_win_left = crop_bot;
+ param->conf_win_bot = crop_right;
+ param->conf_win_right = crop_top;
+ break;
+ case 4:
+ case 10:
+ param->conf_win_top = crop_bot;
+ param->conf_win_bot = crop_top;
+ break;
+ case 8:
+ case 6:
+ param->conf_win_left = crop_right;
+ param->conf_win_right = crop_left;
+ break;
+ case 5:
+ case 11:
+ param->conf_win_top = crop_left;
+ param->conf_win_left = crop_top;
+ param->conf_win_bot = crop_right;
+ param->conf_win_right = crop_bot;
+ break;
+ case 7:
+ case 9:
+ param->conf_win_top = crop_right;
+ param->conf_win_left = crop_bot;
+ param->conf_win_bot = crop_left;
+ param->conf_win_right = crop_top;
+ break;
+ default:
+ WARN(1, "Invalid prp_mode: %d, must be in range of 1 - 15\n", prp_mode);
+ }
+}
+
+int wave5_vpu_enc_init_seq(struct vpu_instance *inst)
+{
+ u32 reg_val = 0, rot_mir_mode, fixed_cu_size_mode = 0x7;
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ struct enc_open_param *p_open_param = &p_enc_info->open_param;
+ struct enc_wave_param *p_param = &p_open_param->wave_param;
+
+ /*
+ * OPT_COMMON:
+ * the last SET_PARAM command should be called with OPT_COMMON
+ */
+ rot_mir_mode = 0;
+ if (p_enc_info->rotation_enable) {
+ switch (p_enc_info->rotation_angle) {
+ case 0:
+ rot_mir_mode |= NONE_ROTATE;
+ break;
+ case 90:
+ rot_mir_mode |= ROT_CLOCKWISE_90;
+ break;
+ case 180:
+ rot_mir_mode |= ROT_CLOCKWISE_180;
+ break;
+ case 270:
+ rot_mir_mode |= ROT_CLOCKWISE_270;
+ break;
+ }
+ }
+
+ if (p_enc_info->mirror_enable) {
+ switch (p_enc_info->mirror_direction) {
+ case MIRDIR_NONE:
+ rot_mir_mode |= NONE_ROTATE;
+ break;
+ case MIRDIR_VER:
+ rot_mir_mode |= MIR_VER_FLIP;
+ break;
+ case MIRDIR_HOR:
+ rot_mir_mode |= MIR_HOR_FLIP;
+ break;
+ case MIRDIR_HOR_VER:
+ rot_mir_mode |= MIR_HOR_VER_FLIP;
+ break;
+ }
+ }
+
+ wave5_set_enc_crop_info(inst->std, p_param, rot_mir_mode, p_open_param->pic_width,
+ p_open_param->pic_height);
+
+ /* SET_PARAM + COMMON */
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SET_PARAM_OPTION, OPT_COMMON);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SRC_SIZE, p_open_param->pic_height << 16
+ | p_open_param->pic_width);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MAP_ENDIAN, VDI_LITTLE_ENDIAN);
+
+ reg_val = p_param->profile |
+ (p_param->level << 3) |
+ (p_param->internal_bit_depth << 14);
+ if (inst->std == W_HEVC_ENC)
+ reg_val |= (p_param->tier << 12) |
+ (p_param->tmvp_enable << 23) |
+ (p_param->sao_enable << 24) |
+ (p_param->skip_intra_trans << 25) |
+ (p_param->strong_intra_smooth_enable << 27) |
+ (p_param->en_still_picture << 30);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_SPS_PARAM, reg_val);
+
+ reg_val = (p_param->lossless_enable) |
+ (p_param->const_intra_pred_flag << 1) |
+ (p_param->lf_cross_slice_boundary_enable << 2) |
+ (p_param->wpp_enable << 4) |
+ (p_param->disable_deblk << 5) |
+ ((p_param->beta_offset_div2 & 0xF) << 6) |
+ ((p_param->tc_offset_div2 & 0xF) << 10) |
+ ((p_param->chroma_cb_qp_offset & 0x1F) << 14) |
+ ((p_param->chroma_cr_qp_offset & 0x1F) << 19) |
+ (p_param->transform8x8_enable << 29) |
+ (p_param->entropy_coding_mode << 30);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_PPS_PARAM, reg_val);
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_GOP_PARAM, p_param->gop_preset_idx);
+
+ if (inst->std == W_AVC_ENC)
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM, p_param->intra_qp |
+ ((p_param->intra_period & 0x7ff) << 6) |
+ ((p_param->avc_idr_period & 0x7ff) << 17));
+ else if (inst->std == W_HEVC_ENC)
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM,
+ p_param->decoding_refresh_type | (p_param->intra_qp << 3) |
+ (p_param->intra_period << 16));
+
+ reg_val = (p_param->rdo_skip << 2) |
+ (p_param->lambda_scaling_enable << 3) |
+ (fixed_cu_size_mode << 5) |
+ (p_param->intra_nx_n_enable << 8) |
+ (p_param->max_num_merge << 18);
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RDO_PARAM, reg_val);
+
+ if (inst->std == W_AVC_ENC)
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_REFRESH,
+ p_param->intra_mb_refresh_arg << 16 | p_param->intra_mb_refresh_mode);
+ else if (inst->std == W_HEVC_ENC)
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_REFRESH,
+ p_param->intra_refresh_arg << 16 | p_param->intra_refresh_mode);
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_FRAME_RATE, p_open_param->frame_rate_info);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_TARGET_RATE, p_open_param->bit_rate);
+
+ reg_val = p_open_param->rc_enable |
+ (p_param->hvs_qp_enable << 2) |
+ (p_param->hvs_qp_scale << 4) |
+ ((p_param->initial_rc_qp & 0x3F) << 14) |
+ (p_open_param->vbv_buffer_size << 20);
+ if (inst->std == W_AVC_ENC)
+ reg_val |= (p_param->mb_level_rc_enable << 1);
+ else if (inst->std == W_HEVC_ENC)
+ reg_val |= (p_param->cu_level_rc_enable << 1);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_PARAM, reg_val);
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_WEIGHT_PARAM,
+ p_param->rc_weight_buf << 8 | p_param->rc_weight_param);
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_MIN_MAX_QP, p_param->min_qp_i |
+ (p_param->max_qp_i << 6) | (p_param->hvs_max_delta_qp << 12));
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_INTER_MIN_MAX_QP, p_param->min_qp_p |
+ (p_param->max_qp_p << 6) | (p_param->min_qp_b << 12) |
+ (p_param->max_qp_b << 18));
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_BIT_RATIO_LAYER_0_3, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_RC_BIT_RATIO_LAYER_4_7, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_ROT_PARAM, rot_mir_mode);
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_BG_PARAM, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_LAMBDA_ADDR, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CONF_WIN_TOP_BOT,
+ p_param->conf_win_bot << 16 | p_param->conf_win_top);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CONF_WIN_LEFT_RIGHT,
+ p_param->conf_win_right << 16 | p_param->conf_win_left);
+
+ if (inst->std == W_AVC_ENC)
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INDEPENDENT_SLICE,
+ p_param->avc_slice_arg << 16 | p_param->avc_slice_mode);
+ else if (inst->std == W_HEVC_ENC)
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INDEPENDENT_SLICE,
+ p_param->independ_slice_mode_arg << 16 |
+ p_param->independ_slice_mode);
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_USER_SCALING_LIST_ADDR, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_NUM_UNITS_IN_TICK, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_TIME_SCALE, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_NUM_TICKS_POC_DIFF_ONE, 0);
+
+ if (inst->std == W_HEVC_ENC) {
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_PU04, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_PU08, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_PU16, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_PU32, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_CU08, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_CU16, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_CUSTOM_MD_CU32, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_DEPENDENT_SLICE,
+ p_param->depend_slice_mode_arg << 16 | p_param->depend_slice_mode);
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_NR_PARAM, 0);
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_NR_WEIGHT,
+ p_param->nr_intra_weight_y |
+ (p_param->nr_intra_weight_cb << 5) |
+ (p_param->nr_intra_weight_cr << 10) |
+ (p_param->nr_inter_weight_y << 15) |
+ (p_param->nr_inter_weight_cb << 20) |
+ (p_param->nr_inter_weight_cr << 25));
+ }
+ vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_VUI_HRD_PARAM, 0);
+
+ return send_firmware_command(inst, W5_ENC_SET_PARAM, true, NULL, NULL);
+}
+
+int wave5_vpu_enc_get_seq_info(struct vpu_instance *inst, struct enc_initial_info *info)
+{
+ int ret;
+ u32 reg_val;
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+
+ /* send QUERY cmd */
+ ret = wave5_send_query(inst->dev, inst, GET_RESULT);
+ if (ret)
+ return ret;
+
+ dev_dbg(inst->dev->dev, "%s: init seq\n", __func__);
+
+ reg_val = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS);
+
+ p_enc_info->instance_queue_count = (reg_val >> 16) & 0xff;
+ p_enc_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK);
+
+ if (vpu_read_reg(inst->dev, W5_RET_ENC_ENCODING_SUCCESS) != 1) {
+ info->seq_init_err_reason = vpu_read_reg(inst->dev, W5_RET_ENC_ERR_INFO);
+ ret = -EIO;
+ } else {
+ info->warn_info = vpu_read_reg(inst->dev, W5_RET_ENC_WARN_INFO);
+ }
+
+ info->min_frame_buffer_count = vpu_read_reg(inst->dev, W5_RET_ENC_NUM_REQUIRED_FB);
+ info->min_src_frame_count = vpu_read_reg(inst->dev, W5_RET_ENC_MIN_SRC_BUF_NUM);
+ info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE);
+ info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE);
+ p_enc_info->vlc_buf_size = info->vlc_buf_size;
+ p_enc_info->param_buf_size = info->param_buf_size;
+
+ return ret;
+}
+
+static u32 calculate_luma_stride(u32 width, u32 bit_depth)
+{
+ return ALIGN(ALIGN(width, 16) * ((bit_depth > 8) ? 5 : 4), 32);
+}
+
+static u32 calculate_chroma_stride(u32 width, u32 bit_depth)
+{
+ return ALIGN(ALIGN(width / 2, 16) * ((bit_depth > 8) ? 5 : 4), 32);
+}
+
+int wave5_vpu_enc_register_framebuffer(struct device *dev, struct vpu_instance *inst,
+ struct frame_buffer *fb_arr, enum tiled_map_type map_type,
+ unsigned int count)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+ int ret = 0;
+ u32 stride;
+ u32 start_no, end_no;
+ size_t remain, idx, j, i, cnt_8_chunk;
+ u32 reg_val = 0, pic_size = 0, mv_col_size, fbc_y_tbl_size, fbc_c_tbl_size;
+ u32 sub_sampled_size = 0;
+ u32 luma_stride, chroma_stride;
+ u32 buf_height = 0, buf_width = 0;
+ u32 bit_depth;
+ bool avc_encoding = (inst->std == W_AVC_ENC);
+ struct vpu_buf vb_mv = {0};
+ struct vpu_buf vb_fbc_y_tbl = {0};
+ struct vpu_buf vb_fbc_c_tbl = {0};
+ struct vpu_buf vb_sub_sam_buf = {0};
+ struct vpu_buf vb_task = {0};
+ struct enc_open_param *p_open_param;
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+
+ p_open_param = &p_enc_info->open_param;
+ mv_col_size = 0;
+ fbc_y_tbl_size = 0;
+ fbc_c_tbl_size = 0;
+ stride = p_enc_info->stride;
+ bit_depth = p_open_param->wave_param.internal_bit_depth;
+
+ if (avc_encoding) {
+ buf_width = ALIGN(p_open_param->pic_width, 16);
+ buf_height = ALIGN(p_open_param->pic_height, 16);
+
+ if ((p_enc_info->rotation_angle || p_enc_info->mirror_direction) &&
+ !(p_enc_info->rotation_angle == 180 &&
+ p_enc_info->mirror_direction == MIRDIR_HOR_VER)) {
+ buf_width = ALIGN(p_open_param->pic_width, 16);
+ buf_height = ALIGN(p_open_param->pic_height, 16);
+ }
+
+ if (p_enc_info->rotation_angle == 90 || p_enc_info->rotation_angle == 270) {
+ buf_width = ALIGN(p_open_param->pic_height, 16);
+ buf_height = ALIGN(p_open_param->pic_width, 16);
+ }
+ } else {
+ buf_width = ALIGN(p_open_param->pic_width, 8);
+ buf_height = ALIGN(p_open_param->pic_height, 8);
+
+ if ((p_enc_info->rotation_angle || p_enc_info->mirror_direction) &&
+ !(p_enc_info->rotation_angle == 180 &&
+ p_enc_info->mirror_direction == MIRDIR_HOR_VER)) {
+ buf_width = ALIGN(p_open_param->pic_width, 32);
+ buf_height = ALIGN(p_open_param->pic_height, 32);
+ }
+
+ if (p_enc_info->rotation_angle == 90 || p_enc_info->rotation_angle == 270) {
+ buf_width = ALIGN(p_open_param->pic_height, 32);
+ buf_height = ALIGN(p_open_param->pic_width, 32);
+ }
+ }
+
+ pic_size = (buf_width << 16) | buf_height;
+
+ if (avc_encoding) {
+ mv_col_size = WAVE5_ENC_AVC_BUF_SIZE(buf_width, buf_height);
+ vb_mv.daddr = 0;
+ vb_mv.size = ALIGN(mv_col_size * count, BUFFER_MARGIN) + BUFFER_MARGIN;
+ } else {
+ mv_col_size = WAVE5_ENC_HEVC_BUF_SIZE(buf_width, buf_height);
+ mv_col_size = ALIGN(mv_col_size, 16);
+ vb_mv.daddr = 0;
+ vb_mv.size = ALIGN(mv_col_size * count, BUFFER_MARGIN) + BUFFER_MARGIN;
+ }
+
+ ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_mv);
+ if (ret)
+ return ret;
+
+ p_enc_info->vb_mv = vb_mv;
+
+ fbc_y_tbl_size = ALIGN(WAVE5_FBC_LUMA_TABLE_SIZE(buf_width, buf_height), 16);
+ fbc_c_tbl_size = ALIGN(WAVE5_FBC_CHROMA_TABLE_SIZE(buf_width, buf_height), 16);
+
+ vb_fbc_y_tbl.daddr = 0;
+ vb_fbc_y_tbl.size = ALIGN(fbc_y_tbl_size * count, BUFFER_MARGIN) + BUFFER_MARGIN;
+ ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_fbc_y_tbl);
+ if (ret)
+ goto free_vb_fbc_y_tbl;
+
+ p_enc_info->vb_fbc_y_tbl = vb_fbc_y_tbl;
+
+ vb_fbc_c_tbl.daddr = 0;
+ vb_fbc_c_tbl.size = ALIGN(fbc_c_tbl_size * count, BUFFER_MARGIN) + BUFFER_MARGIN;
+ ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_fbc_c_tbl);
+ if (ret)
+ goto free_vb_fbc_c_tbl;
+
+ p_enc_info->vb_fbc_c_tbl = vb_fbc_c_tbl;
+
+ if (avc_encoding)
+ sub_sampled_size = WAVE5_SUBSAMPLED_ONE_SIZE_AVC(buf_width, buf_height);
+ else
+ sub_sampled_size = WAVE5_SUBSAMPLED_ONE_SIZE(buf_width, buf_height);
+ vb_sub_sam_buf.size = ALIGN(sub_sampled_size * count, BUFFER_MARGIN) + BUFFER_MARGIN;
+ vb_sub_sam_buf.daddr = 0;
+ ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_sub_sam_buf);
+ if (ret)
+ goto free_vb_sam_buf;
+
+ p_enc_info->vb_sub_sam_buf = vb_sub_sam_buf;
+
+ vb_task.size = (p_enc_info->vlc_buf_size * VLC_BUF_NUM) +
+ (p_enc_info->param_buf_size * COMMAND_QUEUE_DEPTH);
+ vb_task.daddr = 0;
+ if (p_enc_info->vb_task.size == 0) {
+ ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_task);
+ if (ret)
+ goto free_vb_task;
+
+ p_enc_info->vb_task = vb_task;
+
+ vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF,
+ p_enc_info->vb_task.daddr);
+ vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE, vb_task.size);
+ }
+
+ /* set sub-sampled buffer base addr */
+ vpu_write_reg(inst->dev, W5_ADDR_SUB_SAMPLED_FB_BASE, vb_sub_sam_buf.daddr);
+ /* set sub-sampled buffer size for one frame */
+ vpu_write_reg(inst->dev, W5_SUB_SAMPLED_ONE_FB_SIZE, sub_sampled_size);
+
+ vpu_write_reg(inst->dev, W5_PIC_SIZE, pic_size);
+
+ /* set stride of luma/chroma for compressed buffer */
+ if ((p_enc_info->rotation_angle || p_enc_info->mirror_direction) &&
+ !(p_enc_info->rotation_angle == 180 &&
+ p_enc_info->mirror_direction == MIRDIR_HOR_VER)) {
+ luma_stride = calculate_luma_stride(buf_width, bit_depth);
+ chroma_stride = calculate_chroma_stride(buf_width / 2, bit_depth);
+ } else {
+ luma_stride = calculate_luma_stride(p_open_param->pic_width, bit_depth);
+ chroma_stride = calculate_chroma_stride(p_open_param->pic_width / 2, bit_depth);
+ }
+
+ vpu_write_reg(inst->dev, W5_FBC_STRIDE, luma_stride << 16 | chroma_stride);
+ vpu_write_reg(inst->dev, W5_COMMON_PIC_INFO, stride);
+
+ remain = count;
+ cnt_8_chunk = DIV_ROUND_UP(count, 8);
+ idx = 0;
+ for (j = 0; j < cnt_8_chunk; j++) {
+ reg_val = (j == cnt_8_chunk - 1) << 4 | ((j == 0) << 3);
+ vpu_write_reg(inst->dev, W5_SFB_OPTION, reg_val);
+ start_no = j * 8;
+ end_no = start_no + ((remain >= 8) ? 8 : remain) - 1;
+
+ vpu_write_reg(inst->dev, W5_SET_FB_NUM, (start_no << 8) | end_no);
+
+ for (i = 0; i < 8 && i < remain; i++) {
+ vpu_write_reg(inst->dev, W5_ADDR_LUMA_BASE0 + (i << 4), fb_arr[i +
+ start_no].buf_y);
+ vpu_write_reg(inst->dev, W5_ADDR_CB_BASE0 + (i << 4),
+ fb_arr[i + start_no].buf_cb);
+ /* luma FBC offset table */
+ vpu_write_reg(inst->dev, W5_ADDR_FBC_Y_OFFSET0 + (i << 4),
+ vb_fbc_y_tbl.daddr + idx * fbc_y_tbl_size);
+ /* chroma FBC offset table */
+ vpu_write_reg(inst->dev, W5_ADDR_FBC_C_OFFSET0 + (i << 4),
+ vb_fbc_c_tbl.daddr + idx * fbc_c_tbl_size);
+
+ vpu_write_reg(inst->dev, W5_ADDR_MV_COL0 + (i << 2),
+ vb_mv.daddr + idx * mv_col_size);
+ idx++;
+ }
+ remain -= i;
+
+ ret = send_firmware_command(inst, W5_SET_FB, false, NULL, NULL);
+ if (ret)
+ goto free_vb_mem;
+ }
+
+ ret = wave5_vpu_firmware_command_queue_error_check(vpu_dev, NULL);
+ if (ret)
+ goto free_vb_mem;
+
+ return ret;
+
+free_vb_mem:
+ wave5_vdi_free_dma_memory(vpu_dev, &vb_task);
+free_vb_task:
+ wave5_vdi_free_dma_memory(vpu_dev, &vb_sub_sam_buf);
+free_vb_sam_buf:
+ wave5_vdi_free_dma_memory(vpu_dev, &vb_fbc_c_tbl);
+free_vb_fbc_c_tbl:
+ wave5_vdi_free_dma_memory(vpu_dev, &vb_fbc_y_tbl);
+free_vb_fbc_y_tbl:
+ wave5_vdi_free_dma_memory(vpu_dev, &vb_mv);
+ return ret;
+}
+
+int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res)
+{
+ u32 src_frame_format;
+ u32 reg_val = 0;
+ u32 src_stride_c = 0;
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ struct frame_buffer *p_src_frame = option->source_frame;
+ struct enc_open_param *p_open_param = &p_enc_info->open_param;
+ bool justified = WTL_RIGHT_JUSTIFIED;
+ u32 format_no = WTL_PIXEL_8BIT;
+ int ret;
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_BS_START_ADDR, option->pic_stream_buffer_addr);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_BS_SIZE, option->pic_stream_buffer_size);
+ p_enc_info->stream_buf_start_addr = option->pic_stream_buffer_addr;
+ p_enc_info->stream_buf_size = option->pic_stream_buffer_size;
+ p_enc_info->stream_buf_end_addr =
+ option->pic_stream_buffer_addr + option->pic_stream_buffer_size;
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_AXI_SEL, DEFAULT_SRC_AXI);
+ /* secondary AXI */
+ reg_val = (p_enc_info->sec_axi_info.use_enc_rdo_enable << 11) |
+ (p_enc_info->sec_axi_info.use_enc_lf_enable << 15);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_USE_SEC_AXI, reg_val);
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_REPORT_PARAM, 0);
+
+ /*
+ * CODEOPT_ENC_VCL is used to implicitly encode header/headers to generate bitstream.
+ * (use ENC_PUT_VIDEO_HEADER for give_command to encode only a header)
+ */
+ if (option->code_option.implicit_header_encode)
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_CODE_OPTION,
+ CODEOPT_ENC_HEADER_IMPLICIT | CODEOPT_ENC_VCL |
+ (option->code_option.encode_aud << 5) |
+ (option->code_option.encode_eos << 6) |
+ (option->code_option.encode_eob << 7));
+ else
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_CODE_OPTION,
+ option->code_option.implicit_header_encode |
+ (option->code_option.encode_vcl << 1) |
+ (option->code_option.encode_vps << 2) |
+ (option->code_option.encode_sps << 3) |
+ (option->code_option.encode_pps << 4) |
+ (option->code_option.encode_aud << 5) |
+ (option->code_option.encode_eos << 6) |
+ (option->code_option.encode_eob << 7));
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_PIC_PARAM, 0);
+
+ if (option->src_end_flag)
+ /* no more source images. */
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_PIC_IDX, 0xFFFFFFFF);
+ else
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_PIC_IDX, option->src_idx);
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_ADDR_Y, p_src_frame->buf_y);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_ADDR_U, p_src_frame->buf_cb);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_ADDR_V, p_src_frame->buf_cr);
+
+ switch (p_open_param->src_format) {
+ case FORMAT_420:
+ case FORMAT_422:
+ case FORMAT_YUYV:
+ case FORMAT_YVYU:
+ case FORMAT_UYVY:
+ case FORMAT_VYUY:
+ justified = WTL_LEFT_JUSTIFIED;
+ format_no = WTL_PIXEL_8BIT;
+ src_stride_c = inst->cbcr_interleave ? p_src_frame->stride :
+ (p_src_frame->stride / 2);
+ src_stride_c = (p_open_param->src_format == FORMAT_422) ? src_stride_c * 2 :
+ src_stride_c;
+ break;
+ case FORMAT_420_P10_16BIT_MSB:
+ case FORMAT_422_P10_16BIT_MSB:
+ case FORMAT_YUYV_P10_16BIT_MSB:
+ case FORMAT_YVYU_P10_16BIT_MSB:
+ case FORMAT_UYVY_P10_16BIT_MSB:
+ case FORMAT_VYUY_P10_16BIT_MSB:
+ justified = WTL_RIGHT_JUSTIFIED;
+ format_no = WTL_PIXEL_16BIT;
+ src_stride_c = inst->cbcr_interleave ? p_src_frame->stride :
+ (p_src_frame->stride / 2);
+ src_stride_c = (p_open_param->src_format ==
+ FORMAT_422_P10_16BIT_MSB) ? src_stride_c * 2 : src_stride_c;
+ break;
+ case FORMAT_420_P10_16BIT_LSB:
+ case FORMAT_422_P10_16BIT_LSB:
+ case FORMAT_YUYV_P10_16BIT_LSB:
+ case FORMAT_YVYU_P10_16BIT_LSB:
+ case FORMAT_UYVY_P10_16BIT_LSB:
+ case FORMAT_VYUY_P10_16BIT_LSB:
+ justified = WTL_LEFT_JUSTIFIED;
+ format_no = WTL_PIXEL_16BIT;
+ src_stride_c = inst->cbcr_interleave ? p_src_frame->stride :
+ (p_src_frame->stride / 2);
+ src_stride_c = (p_open_param->src_format ==
+ FORMAT_422_P10_16BIT_LSB) ? src_stride_c * 2 : src_stride_c;
+ break;
+ case FORMAT_420_P10_32BIT_MSB:
+ case FORMAT_422_P10_32BIT_MSB:
+ case FORMAT_YUYV_P10_32BIT_MSB:
+ case FORMAT_YVYU_P10_32BIT_MSB:
+ case FORMAT_UYVY_P10_32BIT_MSB:
+ case FORMAT_VYUY_P10_32BIT_MSB:
+ justified = WTL_RIGHT_JUSTIFIED;
+ format_no = WTL_PIXEL_32BIT;
+ src_stride_c = inst->cbcr_interleave ? p_src_frame->stride :
+ ALIGN(p_src_frame->stride / 2, 16) * BIT(inst->cbcr_interleave);
+ src_stride_c = (p_open_param->src_format ==
+ FORMAT_422_P10_32BIT_MSB) ? src_stride_c * 2 : src_stride_c;
+ break;
+ case FORMAT_420_P10_32BIT_LSB:
+ case FORMAT_422_P10_32BIT_LSB:
+ case FORMAT_YUYV_P10_32BIT_LSB:
+ case FORMAT_YVYU_P10_32BIT_LSB:
+ case FORMAT_UYVY_P10_32BIT_LSB:
+ case FORMAT_VYUY_P10_32BIT_LSB:
+ justified = WTL_LEFT_JUSTIFIED;
+ format_no = WTL_PIXEL_32BIT;
+ src_stride_c = inst->cbcr_interleave ? p_src_frame->stride :
+ ALIGN(p_src_frame->stride / 2, 16) * BIT(inst->cbcr_interleave);
+ src_stride_c = (p_open_param->src_format ==
+ FORMAT_422_P10_32BIT_LSB) ? src_stride_c * 2 : src_stride_c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ src_frame_format = (inst->cbcr_interleave << 1) | (inst->nv21);
+ switch (p_open_param->packed_format) {
+ case PACKED_YUYV:
+ src_frame_format = 4;
+ break;
+ case PACKED_YVYU:
+ src_frame_format = 5;
+ break;
+ case PACKED_UYVY:
+ src_frame_format = 6;
+ break;
+ case PACKED_VYUY:
+ src_frame_format = 7;
+ break;
+ default:
+ break;
+ }
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_STRIDE,
+ (p_src_frame->stride << 16) | src_stride_c);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_FORMAT, src_frame_format |
+ (format_no << 3) | (justified << 5) | (PIC_SRC_ENDIANNESS_BIG_ENDIAN << 6));
+
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_CUSTOM_MAP_OPTION_ADDR, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_CUSTOM_MAP_OPTION_PARAM, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_LONGTERM_PIC, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_WP_PIXEL_SIGMA_Y, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_WP_PIXEL_SIGMA_C, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_WP_PIXEL_MEAN_Y, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_WP_PIXEL_MEAN_C, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_PREFIX_SEI_INFO, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_PREFIX_SEI_NAL_ADDR, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SUFFIX_SEI_INFO, 0);
+ vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SUFFIX_SEI_NAL_ADDR, 0);
+
+ ret = send_firmware_command(inst, W5_DEC_ENC_PIC, true, &reg_val, fail_res);
+ if (ret == -ETIMEDOUT)
+ return ret;
+
+ p_enc_info->instance_queue_count = (reg_val >> 16) & 0xff;
+ p_enc_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK);
+
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int wave5_vpu_enc_get_result(struct vpu_instance *inst, struct enc_output_info *result)
+{
+ int ret;
+ u32 encoding_success;
+ u32 reg_val;
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = wave5_send_query(inst->dev, inst, GET_RESULT);
+ if (ret)
+ return ret;
+
+ dev_dbg(inst->dev->dev, "%s: enc pic complete\n", __func__);
+
+ reg_val = vpu_read_reg(inst->dev, W5_RET_QUEUE_STATUS);
+
+ p_enc_info->instance_queue_count = (reg_val >> 16) & 0xff;
+ p_enc_info->report_queue_count = (reg_val & QUEUE_REPORT_MASK);
+
+ encoding_success = vpu_read_reg(inst->dev, W5_RET_ENC_ENCODING_SUCCESS);
+ if (!encoding_success) {
+ result->error_reason = vpu_read_reg(inst->dev, W5_RET_ENC_ERR_INFO);
+ return -EIO;
+ }
+
+ result->warn_info = vpu_read_reg(inst->dev, W5_RET_ENC_WARN_INFO);
+
+ reg_val = vpu_read_reg(inst->dev, W5_RET_ENC_PIC_TYPE);
+ result->pic_type = reg_val & 0xFFFF;
+
+ result->enc_vcl_nut = vpu_read_reg(inst->dev, W5_RET_ENC_VCL_NUT);
+ /*
+ * To get the reconstructed frame use the following index on
+ * inst->frame_buf
+ */
+ result->recon_frame_index = vpu_read_reg(inst->dev, W5_RET_ENC_PIC_IDX);
+ result->enc_pic_byte = vpu_read_reg(inst->dev, W5_RET_ENC_PIC_BYTE);
+ result->enc_src_idx = vpu_read_reg(inst->dev, W5_RET_ENC_USED_SRC_IDX);
+ p_enc_info->stream_wr_ptr = vpu_read_reg(inst->dev, W5_RET_ENC_WR_PTR);
+ p_enc_info->stream_rd_ptr = vpu_read_reg(inst->dev, W5_RET_ENC_RD_PTR);
+
+ result->bitstream_buffer = vpu_read_reg(inst->dev, W5_RET_ENC_RD_PTR);
+ result->rd_ptr = p_enc_info->stream_rd_ptr;
+ result->wr_ptr = p_enc_info->stream_wr_ptr;
+
+ /*result for header only(no vcl) encoding */
+ if (result->recon_frame_index == RECON_IDX_FLAG_HEADER_ONLY)
+ result->bitstream_size = result->enc_pic_byte;
+ else if (result->recon_frame_index < 0)
+ result->bitstream_size = 0;
+ else
+ result->bitstream_size = result->enc_pic_byte;
+
+ result->enc_host_cmd_tick = vpu_read_reg(inst->dev, W5_RET_ENC_HOST_CMD_TICK);
+ result->enc_encode_end_tick = vpu_read_reg(inst->dev, W5_RET_ENC_ENCODING_END_TICK);
+
+ if (!p_enc_info->first_cycle_check) {
+ result->frame_cycle = (result->enc_encode_end_tick - result->enc_host_cmd_tick) *
+ p_enc_info->cycle_per_tick;
+ p_enc_info->first_cycle_check = true;
+ } else {
+ result->frame_cycle =
+ (result->enc_encode_end_tick - vpu_dev->last_performance_cycles) *
+ p_enc_info->cycle_per_tick;
+ if (vpu_dev->last_performance_cycles < result->enc_host_cmd_tick)
+ result->frame_cycle = (result->enc_encode_end_tick -
+ result->enc_host_cmd_tick) * p_enc_info->cycle_per_tick;
+ }
+ vpu_dev->last_performance_cycles = result->enc_encode_end_tick;
+
+ return 0;
+}
+
+int wave5_vpu_enc_finish_seq(struct vpu_instance *inst, u32 *fail_res)
+{
+ return send_firmware_command(inst, W5_DESTROY_INSTANCE, true, NULL, fail_res);
+}
+
+static bool wave5_vpu_enc_check_common_param_valid(struct vpu_instance *inst,
+ struct enc_open_param *open_param)
+{
+ bool low_delay = true;
+ struct enc_wave_param *param = &open_param->wave_param;
+ struct vpu_device *vpu_dev = inst->dev;
+ struct device *dev = vpu_dev->dev;
+ u32 num_ctu_row = (open_param->pic_height + 64 - 1) / 64;
+ u32 num_ctu_col = (open_param->pic_width + 64 - 1) / 64;
+ u32 ctu_sz = num_ctu_col * num_ctu_row;
+
+ if (inst->std == W_HEVC_ENC && low_delay &&
+ param->decoding_refresh_type == DEC_REFRESH_TYPE_CRA) {
+ dev_warn(dev,
+ "dec_refresh_type(CRA) shouldn't be used together with low delay GOP\n");
+ dev_warn(dev, "Suggested configuration parameter: decoding refresh type (IDR)\n");
+ param->decoding_refresh_type = 2;
+ }
+
+ if (param->wpp_enable && param->independ_slice_mode) {
+ unsigned int num_ctb_in_width = ALIGN(open_param->pic_width, 64) >> 6;
+
+ if (param->independ_slice_mode_arg % num_ctb_in_width) {
+ dev_err(dev, "independ_slice_mode_arg %u must be a multiple of %u\n",
+ param->independ_slice_mode_arg, num_ctb_in_width);
+ return false;
+ }
+ }
+
+ /* multi-slice & wpp */
+ if (param->wpp_enable && param->depend_slice_mode) {
+ dev_err(dev, "wpp_enable && depend_slice_mode cannot be used simultaneously\n");
+ return false;
+ }
+
+ if (!param->independ_slice_mode && param->depend_slice_mode) {
+ dev_err(dev, "depend_slice_mode requires independ_slice_mode\n");
+ return false;
+ } else if (param->independ_slice_mode &&
+ param->depend_slice_mode == DEPEND_SLICE_MODE_RECOMMENDED &&
+ param->independ_slice_mode_arg < param->depend_slice_mode_arg) {
+ dev_err(dev, "independ_slice_mode_arg: %u must be smaller than %u\n",
+ param->independ_slice_mode_arg, param->depend_slice_mode_arg);
+ return false;
+ }
+
+ if (param->independ_slice_mode && param->independ_slice_mode_arg > 65535) {
+ dev_err(dev, "independ_slice_mode_arg: %u must be smaller than 65535\n",
+ param->independ_slice_mode_arg);
+ return false;
+ }
+
+ if (param->depend_slice_mode && param->depend_slice_mode_arg > 65535) {
+ dev_err(dev, "depend_slice_mode_arg: %u must be smaller than 65535\n",
+ param->depend_slice_mode_arg);
+ return false;
+ }
+
+ if (param->conf_win_top % 2) {
+ dev_err(dev, "conf_win_top: %u, must be a multiple of 2\n", param->conf_win_top);
+ return false;
+ }
+
+ if (param->conf_win_bot % 2) {
+ dev_err(dev, "conf_win_bot: %u, must be a multiple of 2\n", param->conf_win_bot);
+ return false;
+ }
+
+ if (param->conf_win_left % 2) {
+ dev_err(dev, "conf_win_left: %u, must be a multiple of 2\n", param->conf_win_left);
+ return false;
+ }
+
+ if (param->conf_win_right % 2) {
+ dev_err(dev, "conf_win_right: %u, Must be a multiple of 2\n",
+ param->conf_win_right);
+ return false;
+ }
+
+ if (param->lossless_enable && open_param->rc_enable) {
+ dev_err(dev, "option rate_control cannot be used with lossless_coding\n");
+ return false;
+ }
+
+ if (param->lossless_enable && !param->skip_intra_trans) {
+ dev_err(dev, "option intra_trans_skip must be enabled with lossless_coding\n");
+ return false;
+ }
+
+ /* intra refresh */
+ if (param->intra_refresh_mode && param->intra_refresh_arg == 0) {
+ dev_err(dev, "Invalid refresh argument, mode: %u, refresh: %u must be > 0\n",
+ param->intra_refresh_mode, param->intra_refresh_arg);
+ return false;
+ }
+ switch (param->intra_refresh_mode) {
+ case REFRESH_MODE_CTU_ROWS:
+ if (param->intra_mb_refresh_arg > num_ctu_row)
+ goto invalid_refresh_argument;
+ break;
+ case REFRESH_MODE_CTU_COLUMNS:
+ if (param->intra_refresh_arg > num_ctu_col)
+ goto invalid_refresh_argument;
+ break;
+ case REFRESH_MODE_CTU_STEP_SIZE:
+ if (param->intra_refresh_arg > ctu_sz)
+ goto invalid_refresh_argument;
+ break;
+ case REFRESH_MODE_CTUS:
+ if (param->intra_refresh_arg > ctu_sz)
+ goto invalid_refresh_argument;
+ if (param->lossless_enable) {
+ dev_err(dev, "mode: %u cannot be used lossless_enable",
+ param->intra_refresh_mode);
+ return false;
+ }
+ };
+ return true;
+
+invalid_refresh_argument:
+ dev_err(dev, "Invalid refresh argument, mode: %u, refresh: %u > W(%u)xH(%u)\n",
+ param->intra_refresh_mode, param->intra_refresh_arg,
+ num_ctu_row, num_ctu_col);
+ return false;
+}
+
+static bool wave5_vpu_enc_check_param_valid(struct vpu_device *vpu_dev,
+ struct enc_open_param *open_param)
+{
+ struct enc_wave_param *param = &open_param->wave_param;
+
+ if (open_param->rc_enable) {
+ if (param->min_qp_i > param->max_qp_i || param->min_qp_p > param->max_qp_p ||
+ param->min_qp_b > param->max_qp_b) {
+ dev_err(vpu_dev->dev, "Configuration failed because min_qp is greater than max_qp\n");
+ dev_err(vpu_dev->dev, "Suggested configuration parameters: min_qp = max_qp\n");
+ return false;
+ }
+
+ if (open_param->bit_rate <= (int)open_param->frame_rate_info) {
+ dev_err(vpu_dev->dev,
+ "enc_bit_rate: %u must be greater than the frame_rate: %u\n",
+ open_param->bit_rate, (int)open_param->frame_rate_info);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int wave5_vpu_enc_check_open_param(struct vpu_instance *inst, struct enc_open_param *open_param)
+{
+ u32 pic_width;
+ u32 pic_height;
+ s32 product_id = inst->dev->product;
+ struct vpu_attr *p_attr = &inst->dev->attr;
+ struct enc_wave_param *param;
+
+ if (!open_param)
+ return -EINVAL;
+
+ param = &open_param->wave_param;
+ pic_width = open_param->pic_width;
+ pic_height = open_param->pic_height;
+
+ if (inst->id >= MAX_NUM_INSTANCE) {
+ dev_err(inst->dev->dev, "Too many simultaneous instances: %d (max: %u)\n",
+ inst->id, MAX_NUM_INSTANCE);
+ return -EOPNOTSUPP;
+ }
+
+ if (inst->std != W_HEVC_ENC &&
+ !(inst->std == W_AVC_ENC && product_id == PRODUCT_ID_521)) {
+ dev_err(inst->dev->dev, "Unsupported encoder-codec & product combination\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (param->internal_bit_depth == 10) {
+ if (inst->std == W_HEVC_ENC && !p_attr->support_hevc10bit_enc) {
+ dev_err(inst->dev->dev,
+ "Flag support_hevc10bit_enc must be set to encode 10bit HEVC\n");
+ return -EOPNOTSUPP;
+ } else if (inst->std == W_AVC_ENC && !p_attr->support_avc10bit_enc) {
+ dev_err(inst->dev->dev,
+ "Flag support_avc10bit_enc must be set to encode 10bit AVC\n");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ if (!open_param->frame_rate_info) {
+ dev_err(inst->dev->dev, "No frame rate information.\n");
+ return -EINVAL;
+ }
+
+ if (open_param->bit_rate > MAX_BIT_RATE) {
+ dev_err(inst->dev->dev, "Invalid encoding bit-rate: %u (valid: 0-%u)\n",
+ open_param->bit_rate, MAX_BIT_RATE);
+ return -EINVAL;
+ }
+
+ if (pic_width < W5_MIN_ENC_PIC_WIDTH || pic_width > W5_MAX_ENC_PIC_WIDTH ||
+ pic_height < W5_MIN_ENC_PIC_HEIGHT || pic_height > W5_MAX_ENC_PIC_HEIGHT) {
+ dev_err(inst->dev->dev, "Invalid encoding dimension: %ux%u\n",
+ pic_width, pic_height);
+ return -EINVAL;
+ }
+
+ if (param->profile) {
+ if (inst->std == W_HEVC_ENC) {
+ if ((param->profile != HEVC_PROFILE_MAIN ||
+ (param->profile == HEVC_PROFILE_MAIN &&
+ param->internal_bit_depth > 8)) &&
+ (param->profile != HEVC_PROFILE_MAIN10 ||
+ (param->profile == HEVC_PROFILE_MAIN10 &&
+ param->internal_bit_depth < 10)) &&
+ param->profile != HEVC_PROFILE_STILLPICTURE) {
+ dev_err(inst->dev->dev,
+ "Invalid HEVC encoding profile: %u (bit-depth: %u)\n",
+ param->profile, param->internal_bit_depth);
+ return -EINVAL;
+ }
+ } else if (inst->std == W_AVC_ENC) {
+ if ((param->internal_bit_depth > 8 &&
+ param->profile != H264_PROFILE_HIGH10)) {
+ dev_err(inst->dev->dev,
+ "Invalid AVC encoding profile: %u (bit-depth: %u)\n",
+ param->profile, param->internal_bit_depth);
+ return -EINVAL;
+ }
+ }
+ }
+
+ if (param->decoding_refresh_type > DEC_REFRESH_TYPE_IDR) {
+ dev_err(inst->dev->dev, "Invalid decoding refresh type: %u (valid: 0-2)\n",
+ param->decoding_refresh_type);
+ return -EINVAL;
+ }
+
+ if (param->intra_refresh_mode > REFRESH_MODE_CTUS) {
+ dev_err(inst->dev->dev, "Invalid intra refresh mode: %d (valid: 0-4)\n",
+ param->intra_refresh_mode);
+ return -EINVAL;
+ }
+
+ if (inst->std == W_HEVC_ENC && param->independ_slice_mode &&
+ param->depend_slice_mode > DEPEND_SLICE_MODE_BOOST) {
+ dev_err(inst->dev->dev,
+ "Can't combine slice modes: independent and fast dependent for HEVC\n");
+ return -EINVAL;
+ }
+
+ if (!param->disable_deblk) {
+ if (param->beta_offset_div2 < -6 || param->beta_offset_div2 > 6) {
+ dev_err(inst->dev->dev, "Invalid beta offset: %d (valid: -6-6)\n",
+ param->beta_offset_div2);
+ return -EINVAL;
+ }
+
+ if (param->tc_offset_div2 < -6 || param->tc_offset_div2 > 6) {
+ dev_err(inst->dev->dev, "Invalid tc offset: %d (valid: -6-6)\n",
+ param->tc_offset_div2);
+ return -EINVAL;
+ }
+ }
+
+ if (param->intra_qp > MAX_INTRA_QP) {
+ dev_err(inst->dev->dev,
+ "Invalid intra quantization parameter: %u (valid: 0-%u)\n",
+ param->intra_qp, MAX_INTRA_QP);
+ return -EINVAL;
+ }
+
+ if (open_param->rc_enable) {
+ if (param->min_qp_i > MAX_INTRA_QP || param->max_qp_i > MAX_INTRA_QP ||
+ param->min_qp_p > MAX_INTRA_QP || param->max_qp_p > MAX_INTRA_QP ||
+ param->min_qp_b > MAX_INTRA_QP || param->max_qp_b > MAX_INTRA_QP) {
+ dev_err(inst->dev->dev,
+ "Invalid quantization parameter min/max values: "
+ "I: %u-%u, P: %u-%u, B: %u-%u (valid for each: 0-%u)\n",
+ param->min_qp_i, param->max_qp_i, param->min_qp_p, param->max_qp_p,
+ param->min_qp_b, param->max_qp_b, MAX_INTRA_QP);
+ return -EINVAL;
+ }
+
+ if (param->hvs_qp_enable && param->hvs_max_delta_qp > MAX_HVS_MAX_DELTA_QP) {
+ dev_err(inst->dev->dev,
+ "Invalid HVS max delta quantization parameter: %u (valid: 0-%u)\n",
+ param->hvs_max_delta_qp, MAX_HVS_MAX_DELTA_QP);
+ return -EINVAL;
+ }
+
+ if (open_param->vbv_buffer_size < MIN_VBV_BUFFER_SIZE ||
+ open_param->vbv_buffer_size > MAX_VBV_BUFFER_SIZE) {
+ dev_err(inst->dev->dev, "VBV buffer size: %u (valid: %u-%u)\n",
+ open_param->vbv_buffer_size, MIN_VBV_BUFFER_SIZE,
+ MAX_VBV_BUFFER_SIZE);
+ return -EINVAL;
+ }
+ }
+
+ if (!wave5_vpu_enc_check_common_param_valid(inst, open_param))
+ return -EINVAL;
+
+ if (!wave5_vpu_enc_check_param_valid(inst->dev, open_param))
+ return -EINVAL;
+
+ if (param->chroma_cb_qp_offset < -12 || param->chroma_cb_qp_offset > 12) {
+ dev_err(inst->dev->dev,
+ "Invalid chroma Cb quantization parameter offset: %d (valid: -12-12)\n",
+ param->chroma_cb_qp_offset);
+ return -EINVAL;
+ }
+
+ if (param->chroma_cr_qp_offset < -12 || param->chroma_cr_qp_offset > 12) {
+ dev_err(inst->dev->dev,
+ "Invalid chroma Cr quantization parameter offset: %d (valid: -12-12)\n",
+ param->chroma_cr_qp_offset);
+ return -EINVAL;
+ }
+
+ if (param->intra_refresh_mode == REFRESH_MODE_CTU_STEP_SIZE && !param->intra_refresh_arg) {
+ dev_err(inst->dev->dev,
+ "Intra refresh mode CTU step-size requires an argument\n");
+ return -EINVAL;
+ }
+
+ if (inst->std == W_HEVC_ENC) {
+ if (param->nr_intra_weight_y > MAX_INTRA_WEIGHT ||
+ param->nr_intra_weight_cb > MAX_INTRA_WEIGHT ||
+ param->nr_intra_weight_cr > MAX_INTRA_WEIGHT) {
+ dev_err(inst->dev->dev,
+ "Invalid intra weight Y(%u) Cb(%u) Cr(%u) (valid: %u)\n",
+ param->nr_intra_weight_y, param->nr_intra_weight_cb,
+ param->nr_intra_weight_cr, MAX_INTRA_WEIGHT);
+ return -EINVAL;
+ }
+
+ if (param->nr_inter_weight_y > MAX_INTER_WEIGHT ||
+ param->nr_inter_weight_cb > MAX_INTER_WEIGHT ||
+ param->nr_inter_weight_cr > MAX_INTER_WEIGHT) {
+ dev_err(inst->dev->dev,
+ "Invalid inter weight Y(%u) Cb(%u) Cr(%u) (valid: %u)\n",
+ param->nr_inter_weight_y, param->nr_inter_weight_cb,
+ param->nr_inter_weight_cr, MAX_INTER_WEIGHT);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-regdefine.h b/drivers/media/platform/chips-media/wave5/wave5-regdefine.h
new file mode 100644
index 000000000000..a15c6b2c3d8b
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-regdefine.h
@@ -0,0 +1,732 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave5 series multi-standard codec IP - wave5 register definitions
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE5_REGISTER_DEFINE_H__
+#define __WAVE5_REGISTER_DEFINE_H__
+
+enum W5_VPU_COMMAND {
+ W5_INIT_VPU = 0x0001,
+ W5_WAKEUP_VPU = 0x0002,
+ W5_SLEEP_VPU = 0x0004,
+ W5_CREATE_INSTANCE = 0x0008, /* queuing command */
+ W5_FLUSH_INSTANCE = 0x0010,
+ W5_DESTROY_INSTANCE = 0x0020, /* queuing command */
+ W5_INIT_SEQ = 0x0040, /* queuing command */
+ W5_SET_FB = 0x0080,
+ W5_DEC_ENC_PIC = 0x0100, /* queuing command */
+ W5_ENC_SET_PARAM = 0x0200, /* queuing command */
+ W5_QUERY = 0x4000,
+ W5_UPDATE_BS = 0x8000,
+ W5_MAX_VPU_COMD = 0x10000,
+};
+
+enum query_opt {
+ GET_VPU_INFO = 0,
+ SET_WRITE_PROT = 1,
+ GET_RESULT = 2,
+ UPDATE_DISP_FLAG = 3,
+ GET_BW_REPORT = 4,
+ GET_BS_RD_PTR = 5, /* for decoder */
+ GET_BS_WR_PTR = 6, /* for encoder */
+ GET_SRC_BUF_FLAG = 7, /* for encoder */
+ SET_BS_RD_PTR = 8, /* for decoder */
+ GET_DEBUG_INFO = 0x61,
+};
+
+#define W5_REG_BASE 0x00000000
+#define W5_CMD_REG_BASE 0x00000100
+#define W5_CMD_REG_END 0x00000200
+
+/*
+ * COMMON
+ *
+ * ----
+ *
+ * Power on configuration
+ * PO_DEBUG_MODE [0] 1 - power on with debug mode
+ * USE_PO_CONF [3] 1 - use power-on-configuration
+ */
+#define W5_PO_CONF (W5_REG_BASE + 0x0000)
+#define W5_VCPU_CUR_PC (W5_REG_BASE + 0x0004)
+#define W5_VCPU_CUR_LR (W5_REG_BASE + 0x0008)
+#define W5_VPU_PDBG_STEP_MASK_V (W5_REG_BASE + 0x000C)
+#define W5_VPU_PDBG_CTRL (W5_REG_BASE + 0x0010) /* v_cpu debugger ctrl register */
+#define W5_VPU_PDBG_IDX_REG (W5_REG_BASE + 0x0014) /* v_cpu debugger index register */
+#define W5_VPU_PDBG_WDATA_REG (W5_REG_BASE + 0x0018) /* v_cpu debugger write data reg */
+#define W5_VPU_PDBG_RDATA_REG (W5_REG_BASE + 0x001C) /* v_cpu debugger read data reg */
+
+#define W5_VPU_FIO_CTRL_ADDR (W5_REG_BASE + 0x0020)
+#define W5_VPU_FIO_DATA (W5_REG_BASE + 0x0024)
+#define W5_VPU_VINT_REASON_USR (W5_REG_BASE + 0x0030)
+#define W5_VPU_VINT_REASON_CLR (W5_REG_BASE + 0x0034)
+#define W5_VPU_HOST_INT_REQ (W5_REG_BASE + 0x0038)
+#define W5_VPU_VINT_CLEAR (W5_REG_BASE + 0x003C)
+#define W5_VPU_HINT_CLEAR (W5_REG_BASE + 0x0040)
+#define W5_VPU_VPU_INT_STS (W5_REG_BASE + 0x0044)
+#define W5_VPU_VINT_ENABLE (W5_REG_BASE + 0x0048)
+#define W5_VPU_VINT_REASON (W5_REG_BASE + 0x004C)
+#define W5_VPU_RESET_REQ (W5_REG_BASE + 0x0050)
+#define W5_RST_BLOCK_CCLK(_core) BIT((_core))
+#define W5_RST_BLOCK_CCLK_ALL (0xff)
+#define W5_RST_BLOCK_BCLK(_core) (0x100 << (_core))
+#define W5_RST_BLOCK_BCLK_ALL (0xff00)
+#define W5_RST_BLOCK_ACLK(_core) (0x10000 << (_core))
+#define W5_RST_BLOCK_ACLK_ALL (0xff0000)
+#define W5_RST_BLOCK_VCPU_ALL (0x3f000000)
+#define W5_RST_BLOCK_ALL (0x3fffffff)
+#define W5_VPU_RESET_STATUS (W5_REG_BASE + 0x0054)
+
+#define W5_VCPU_RESTART (W5_REG_BASE + 0x0058)
+#define W5_VPU_CLK_MASK (W5_REG_BASE + 0x005C)
+
+/* REMAP_CTRL
+ * PAGE SIZE: [8:0] 0x001 - 4K
+ * 0x002 - 8K
+ * 0x004 - 16K
+ * ...
+ * 0x100 - 1M
+ * REGION ATTR1 [10] 0 - normal
+ * 1 - make bus error for the region
+ * REGION ATTR2 [11] 0 - normal
+ * 1 - bypass region
+ * REMAP INDEX [15:12] - 0 ~ 3
+ * ENDIAN [19:16] - NOTE: Currently not supported in this driver
+ * AXI-ID [23:20] - upper AXI-ID
+ * BUS_ERROR [29] 0 - bypass
+ * 1 - make BUS_ERROR for unmapped region
+ * BYPASS_ALL [30] 1 - bypass all
+ * ENABLE [31] 1 - update control register[30:16]
+ */
+#define W5_VPU_REMAP_CTRL (W5_REG_BASE + 0x0060)
+#define W5_VPU_REMAP_VADDR (W5_REG_BASE + 0x0064)
+#define W5_VPU_REMAP_PADDR (W5_REG_BASE + 0x0068)
+#define W5_VPU_REMAP_CORE_START (W5_REG_BASE + 0x006C)
+#define W5_VPU_BUSY_STATUS (W5_REG_BASE + 0x0070)
+#define W5_VPU_HALT_STATUS (W5_REG_BASE + 0x0074)
+#define W5_VPU_VCPU_STATUS (W5_REG_BASE + 0x0078)
+#define W5_VPU_RET_PRODUCT_VERSION (W5_REG_BASE + 0x0094)
+/*
+ * assign vpu_config0 = {conf_map_converter_reg, // [31]
+ * conf_map_converter_sig, // [30]
+ * 8'd0, // [29:22]
+ * conf_std_switch_en, // [21]
+ * conf_bg_detect, // [20]
+ * conf_3dnr_en, // [19]
+ * conf_one_axi_en, // [18]
+ * conf_sec_axi_en, // [17]
+ * conf_bus_info, // [16]
+ * conf_afbc_en, // [15]
+ * conf_afbc_version_id, // [14:12]
+ * conf_fbc_en, // [11]
+ * conf_fbc_version_id, // [10:08]
+ * conf_scaler_en, // [07]
+ * conf_scaler_version_id, // [06:04]
+ * conf_bwb_en, // [03]
+ * 3'd0}; // [02:00]
+ */
+#define W5_VPU_RET_VPU_CONFIG0 (W5_REG_BASE + 0x0098)
+/*
+ * assign vpu_config1 = {4'd0, // [31:28]
+ * conf_perf_timer_en, // [27]
+ * conf_multi_core_en, // [26]
+ * conf_gcu_en, // [25]
+ * conf_cu_report, // [24]
+ * 4'd0, // [23:20]
+ * conf_vcore_id_3, // [19]
+ * conf_vcore_id_2, // [18]
+ * conf_vcore_id_1, // [17]
+ * conf_vcore_id_0, // [16]
+ * conf_bwb_opt, // [15]
+ * 7'd0, // [14:08]
+ * conf_cod_std_en_reserved_7, // [7]
+ * conf_cod_std_en_reserved_6, // [6]
+ * conf_cod_std_en_reserved_5, // [5]
+ * conf_cod_std_en_reserved_4, // [4]
+ * conf_cod_std_en_reserved_3, // [3]
+ * conf_cod_std_en_reserved_2, // [2]
+ * conf_cod_std_en_vp9, // [1]
+ * conf_cod_std_en_hevc}; // [0]
+ * }
+ */
+#define W5_VPU_RET_VPU_CONFIG1 (W5_REG_BASE + 0x009C)
+
+#define W5_VPU_DBG_REG0 (W5_REG_BASE + 0x00f0)
+#define W5_VPU_DBG_REG1 (W5_REG_BASE + 0x00f4)
+#define W5_VPU_DBG_REG2 (W5_REG_BASE + 0x00f8)
+#define W5_VPU_DBG_REG3 (W5_REG_BASE + 0x00fc)
+
+/************************************************************************/
+/* PRODUCT INFORMATION */
+/************************************************************************/
+#define W5_PRODUCT_NAME (W5_REG_BASE + 0x1040)
+#define W5_PRODUCT_NUMBER (W5_REG_BASE + 0x1044)
+
+/************************************************************************/
+/* DECODER/ENCODER COMMON */
+/************************************************************************/
+#define W5_COMMAND (W5_REG_BASE + 0x0100)
+#define W5_COMMAND_OPTION (W5_REG_BASE + 0x0104)
+#define W5_QUERY_OPTION (W5_REG_BASE + 0x0104)
+#define W5_RET_SUCCESS (W5_REG_BASE + 0x0108)
+#define W5_RET_FAIL_REASON (W5_REG_BASE + 0x010C)
+#define W5_RET_QUEUE_FAIL_REASON (W5_REG_BASE + 0x0110)
+#define W5_CMD_INSTANCE_INFO (W5_REG_BASE + 0x0110)
+
+#define W5_RET_QUEUE_STATUS (W5_REG_BASE + 0x01E0)
+#define W5_RET_BS_EMPTY_INST (W5_REG_BASE + 0x01E4)
+#define W5_RET_QUEUE_CMD_DONE_INST (W5_REG_BASE + 0x01E8)
+#define W5_RET_STAGE0_INSTANCE_INFO (W5_REG_BASE + 0x01EC)
+#define W5_RET_STAGE1_INSTANCE_INFO (W5_REG_BASE + 0x01F0)
+#define W5_RET_STAGE2_INSTANCE_INFO (W5_REG_BASE + 0x01F4)
+
+#define W5_RET_SEQ_DONE_INSTANCE_INFO (W5_REG_BASE + 0x01FC)
+
+#define W5_BS_OPTION (W5_REG_BASE + 0x0120)
+
+/* return info when QUERY (GET_RESULT) for en/decoder */
+#define W5_RET_VLC_BUF_SIZE (W5_REG_BASE + 0x01B0)
+/* return info when QUERY (GET_RESULT) for en/decoder */
+#define W5_RET_PARAM_BUF_SIZE (W5_REG_BASE + 0x01B4)
+
+/* set when SET_FB for en/decoder */
+#define W5_CMD_SET_FB_ADDR_TASK_BUF (W5_REG_BASE + 0x01D4)
+#define W5_CMD_SET_FB_TASK_BUF_SIZE (W5_REG_BASE + 0x01D8)
+/************************************************************************/
+/* INIT_VPU - COMMON */
+/************************************************************************/
+/* note: W5_ADDR_CODE_BASE should be aligned to 4KB */
+#define W5_ADDR_CODE_BASE (W5_REG_BASE + 0x0110)
+#define W5_CODE_SIZE (W5_REG_BASE + 0x0114)
+#define W5_CODE_PARAM (W5_REG_BASE + 0x0118)
+#define W5_ADDR_TEMP_BASE (W5_REG_BASE + 0x011C)
+#define W5_TEMP_SIZE (W5_REG_BASE + 0x0120)
+#define W5_HW_OPTION (W5_REG_BASE + 0x012C)
+#define W5_SEC_AXI_PARAM (W5_REG_BASE + 0x0180)
+
+/************************************************************************/
+/* CREATE_INSTANCE - COMMON */
+/************************************************************************/
+#define W5_ADDR_WORK_BASE (W5_REG_BASE + 0x0114)
+#define W5_WORK_SIZE (W5_REG_BASE + 0x0118)
+#define W5_CMD_DEC_BS_START_ADDR (W5_REG_BASE + 0x011C)
+#define W5_CMD_DEC_BS_SIZE (W5_REG_BASE + 0x0120)
+#define W5_CMD_BS_PARAM (W5_REG_BASE + 0x0124)
+#define W5_CMD_ADDR_SEC_AXI (W5_REG_BASE + 0x0130)
+#define W5_CMD_SEC_AXI_SIZE (W5_REG_BASE + 0x0134)
+#define W5_CMD_EXT_ADDR (W5_REG_BASE + 0x0138)
+#define W5_CMD_NUM_CQ_DEPTH_M1 (W5_REG_BASE + 0x013C)
+#define W5_CMD_ERR_CONCEAL (W5_REG_BASE + 0x0140)
+
+/************************************************************************/
+/* DECODER - INIT_SEQ */
+/************************************************************************/
+#define W5_BS_RD_PTR (W5_REG_BASE + 0x0118)
+#define W5_BS_WR_PTR (W5_REG_BASE + 0x011C)
+/************************************************************************/
+/* SET_FRAME_BUF */
+/************************************************************************/
+/* SET_FB_OPTION 0x00 REGISTER FRAMEBUFFERS
+ * 0x01 UPDATE FRAMEBUFFER, just one framebuffer(linear, fbc and mvcol)
+ */
+#define W5_SFB_OPTION (W5_REG_BASE + 0x0104)
+#define W5_COMMON_PIC_INFO (W5_REG_BASE + 0x0118)
+#define W5_PIC_SIZE (W5_REG_BASE + 0x011C)
+#define W5_SET_FB_NUM (W5_REG_BASE + 0x0120)
+#define W5_EXTRA_PIC_INFO (W5_REG_BASE + 0x0124)
+
+#define W5_ADDR_LUMA_BASE0 (W5_REG_BASE + 0x0134)
+#define W5_ADDR_CB_BASE0 (W5_REG_BASE + 0x0138)
+#define W5_ADDR_CR_BASE0 (W5_REG_BASE + 0x013C)
+/* compression offset table for luma */
+#define W5_ADDR_FBC_Y_OFFSET0 (W5_REG_BASE + 0x013C)
+/* compression offset table for chroma */
+#define W5_ADDR_FBC_C_OFFSET0 (W5_REG_BASE + 0x0140)
+#define W5_ADDR_LUMA_BASE1 (W5_REG_BASE + 0x0144)
+#define W5_ADDR_CB_ADDR1 (W5_REG_BASE + 0x0148)
+#define W5_ADDR_CR_ADDR1 (W5_REG_BASE + 0x014C)
+/* compression offset table for luma */
+#define W5_ADDR_FBC_Y_OFFSET1 (W5_REG_BASE + 0x014C)
+/* compression offset table for chroma */
+#define W5_ADDR_FBC_C_OFFSET1 (W5_REG_BASE + 0x0150)
+#define W5_ADDR_LUMA_BASE2 (W5_REG_BASE + 0x0154)
+#define W5_ADDR_CB_ADDR2 (W5_REG_BASE + 0x0158)
+#define W5_ADDR_CR_ADDR2 (W5_REG_BASE + 0x015C)
+/* compression offset table for luma */
+#define W5_ADDR_FBC_Y_OFFSET2 (W5_REG_BASE + 0x015C)
+/* compression offset table for chroma */
+#define W5_ADDR_FBC_C_OFFSET2 (W5_REG_BASE + 0x0160)
+#define W5_ADDR_LUMA_BASE3 (W5_REG_BASE + 0x0164)
+#define W5_ADDR_CB_ADDR3 (W5_REG_BASE + 0x0168)
+#define W5_ADDR_CR_ADDR3 (W5_REG_BASE + 0x016C)
+/* compression offset table for luma */
+#define W5_ADDR_FBC_Y_OFFSET3 (W5_REG_BASE + 0x016C)
+/* compression offset table for chroma */
+#define W5_ADDR_FBC_C_OFFSET3 (W5_REG_BASE + 0x0170)
+#define W5_ADDR_LUMA_BASE4 (W5_REG_BASE + 0x0174)
+#define W5_ADDR_CB_ADDR4 (W5_REG_BASE + 0x0178)
+#define W5_ADDR_CR_ADDR4 (W5_REG_BASE + 0x017C)
+/* compression offset table for luma */
+#define W5_ADDR_FBC_Y_OFFSET4 (W5_REG_BASE + 0x017C)
+/* compression offset table for chroma */
+#define W5_ADDR_FBC_C_OFFSET4 (W5_REG_BASE + 0x0180)
+#define W5_ADDR_LUMA_BASE5 (W5_REG_BASE + 0x0184)
+#define W5_ADDR_CB_ADDR5 (W5_REG_BASE + 0x0188)
+#define W5_ADDR_CR_ADDR5 (W5_REG_BASE + 0x018C)
+/* compression offset table for luma */
+#define W5_ADDR_FBC_Y_OFFSET5 (W5_REG_BASE + 0x018C)
+/* compression offset table for chroma */
+#define W5_ADDR_FBC_C_OFFSET5 (W5_REG_BASE + 0x0190)
+#define W5_ADDR_LUMA_BASE6 (W5_REG_BASE + 0x0194)
+#define W5_ADDR_CB_ADDR6 (W5_REG_BASE + 0x0198)
+#define W5_ADDR_CR_ADDR6 (W5_REG_BASE + 0x019C)
+/* compression offset table for luma */
+#define W5_ADDR_FBC_Y_OFFSET6 (W5_REG_BASE + 0x019C)
+/* compression offset table for chroma */
+#define W5_ADDR_FBC_C_OFFSET6 (W5_REG_BASE + 0x01A0)
+#define W5_ADDR_LUMA_BASE7 (W5_REG_BASE + 0x01A4)
+#define W5_ADDR_CB_ADDR7 (W5_REG_BASE + 0x01A8)
+#define W5_ADDR_CR_ADDR7 (W5_REG_BASE + 0x01AC)
+/* compression offset table for luma */
+#define W5_ADDR_FBC_Y_OFFSET7 (W5_REG_BASE + 0x01AC)
+/* compression offset table for chroma */
+#define W5_ADDR_FBC_C_OFFSET7 (W5_REG_BASE + 0x01B0)
+#define W5_ADDR_MV_COL0 (W5_REG_BASE + 0x01B4)
+#define W5_ADDR_MV_COL1 (W5_REG_BASE + 0x01B8)
+#define W5_ADDR_MV_COL2 (W5_REG_BASE + 0x01BC)
+#define W5_ADDR_MV_COL3 (W5_REG_BASE + 0x01C0)
+#define W5_ADDR_MV_COL4 (W5_REG_BASE + 0x01C4)
+#define W5_ADDR_MV_COL5 (W5_REG_BASE + 0x01C8)
+#define W5_ADDR_MV_COL6 (W5_REG_BASE + 0x01CC)
+#define W5_ADDR_MV_COL7 (W5_REG_BASE + 0x01D0)
+
+/* UPDATE_FB */
+/* CMD_SET_FB_STRIDE [15:0] - FBC framebuffer stride
+ * [31:15] - linear framebuffer stride
+ */
+#define W5_CMD_SET_FB_STRIDE (W5_REG_BASE + 0x0118)
+#define W5_CMD_SET_FB_INDEX (W5_REG_BASE + 0x0120)
+#define W5_ADDR_LUMA_BASE (W5_REG_BASE + 0x0134)
+#define W5_ADDR_CB_BASE (W5_REG_BASE + 0x0138)
+#define W5_ADDR_CR_BASE (W5_REG_BASE + 0x013C)
+#define W5_ADDR_MV_COL (W5_REG_BASE + 0x0140)
+#define W5_ADDR_FBC_Y_BASE (W5_REG_BASE + 0x0144)
+#define W5_ADDR_FBC_C_BASE (W5_REG_BASE + 0x0148)
+#define W5_ADDR_FBC_Y_OFFSET (W5_REG_BASE + 0x014C)
+#define W5_ADDR_FBC_C_OFFSET (W5_REG_BASE + 0x0150)
+
+/************************************************************************/
+/* DECODER - DEC_PIC */
+/************************************************************************/
+#define W5_CMD_DEC_VCORE_INFO (W5_REG_BASE + 0x0194)
+/* sequence change enable mask register
+ * CMD_SEQ_CHANGE_ENABLE_FLAG [5] profile_idc
+ * [16] pic_width/height_in_luma_sample
+ * [19] sps_max_dec_pic_buffering, max_num_reorder, max_latency_increase
+ */
+#define W5_CMD_SEQ_CHANGE_ENABLE_FLAG (W5_REG_BASE + 0x0128)
+#define W5_CMD_DEC_USER_MASK (W5_REG_BASE + 0x012C)
+#define W5_CMD_DEC_TEMPORAL_ID_PLUS1 (W5_REG_BASE + 0x0130)
+#define W5_CMD_DEC_FORCE_FB_LATENCY_PLUS1 (W5_REG_BASE + 0x0134)
+#define W5_USE_SEC_AXI (W5_REG_BASE + 0x0150)
+
+/************************************************************************/
+/* DECODER - QUERY : GET_VPU_INFO */
+/************************************************************************/
+#define W5_RET_FW_VERSION (W5_REG_BASE + 0x0118)
+#define W5_RET_PRODUCT_NAME (W5_REG_BASE + 0x011C)
+#define W5_RET_PRODUCT_VERSION (W5_REG_BASE + 0x0120)
+#define W5_RET_STD_DEF0 (W5_REG_BASE + 0x0124)
+#define W5_RET_STD_DEF1 (W5_REG_BASE + 0x0128)
+#define W5_RET_CONF_FEATURE (W5_REG_BASE + 0x012C)
+#define W5_RET_CONF_DATE (W5_REG_BASE + 0x0130)
+#define W5_RET_CONF_REVISION (W5_REG_BASE + 0x0134)
+#define W5_RET_CONF_TYPE (W5_REG_BASE + 0x0138)
+#define W5_RET_PRODUCT_ID (W5_REG_BASE + 0x013C)
+#define W5_RET_CUSTOMER_ID (W5_REG_BASE + 0x0140)
+
+/************************************************************************/
+/* DECODER - QUERY : GET_RESULT */
+/************************************************************************/
+#define W5_CMD_DEC_ADDR_REPORT_BASE (W5_REG_BASE + 0x0114)
+#define W5_CMD_DEC_REPORT_SIZE (W5_REG_BASE + 0x0118)
+#define W5_CMD_DEC_REPORT_PARAM (W5_REG_BASE + 0x011C)
+
+#define W5_RET_DEC_BS_RD_PTR (W5_REG_BASE + 0x011C)
+#define W5_RET_DEC_SEQ_PARAM (W5_REG_BASE + 0x0120)
+#define W5_RET_DEC_COLOR_SAMPLE_INFO (W5_REG_BASE + 0x0124)
+#define W5_RET_DEC_ASPECT_RATIO (W5_REG_BASE + 0x0128)
+#define W5_RET_DEC_BIT_RATE (W5_REG_BASE + 0x012C)
+#define W5_RET_DEC_FRAME_RATE_NR (W5_REG_BASE + 0x0130)
+#define W5_RET_DEC_FRAME_RATE_DR (W5_REG_BASE + 0x0134)
+#define W5_RET_DEC_NUM_REQUIRED_FB (W5_REG_BASE + 0x0138)
+#define W5_RET_DEC_NUM_REORDER_DELAY (W5_REG_BASE + 0x013C)
+#define W5_RET_DEC_SUB_LAYER_INFO (W5_REG_BASE + 0x0140)
+#define W5_RET_DEC_NOTIFICATION (W5_REG_BASE + 0x0144)
+/*
+ * USER_DATA_FLAGS for HEVC/H264 only.
+ * Bits:
+ * [1] - User data buffer full boolean
+ * [2] - VUI parameter flag
+ * [4] - Pic_timing SEI flag
+ * [5] - 1st user_data_registed_itu_t_t35 prefix SEI flag
+ * [6] - user_data_unregistered prefix SEI flag
+ * [7] - 1st user_data_registed_itu_t_t35 suffix SEI flag
+ * [8] - user_data_unregistered suffix SEI flag
+ * [10]- mastering_display_color_volume prefix SEI flag
+ * [11]- chroma_resampling_display_color_volume prefix SEI flag
+ * [12]- knee_function_info SEI flag
+ * [13]- tone_mapping_info prefix SEI flag
+ * [14]- film_grain_characteristics_info prefix SEI flag
+ * [15]- content_light_level_info prefix SEI flag
+ * [16]- color_remapping_info prefix SEI flag
+ * [28]- 2nd user_data_registed_itu_t_t35 prefix SEI flag
+ * [29]- 3rd user_data_registed_itu_t_t35 prefix SEI flag
+ * [30]- 2nd user_data_registed_itu_t_t35 suffix SEI flag
+ * [31]- 3rd user_data_registed_itu_t_t35 suffix SEI flag
+ */
+#define W5_RET_DEC_USERDATA_IDC (W5_REG_BASE + 0x0148)
+#define W5_RET_DEC_PIC_SIZE (W5_REG_BASE + 0x014C)
+#define W5_RET_DEC_CROP_TOP_BOTTOM (W5_REG_BASE + 0x0150)
+#define W5_RET_DEC_CROP_LEFT_RIGHT (W5_REG_BASE + 0x0154)
+/*
+ * #define W5_RET_DEC_AU_START_POS (W5_REG_BASE + 0x0158)
+ * => Access unit (AU) Bitstream start position
+ * #define W5_RET_DEC_AU_END_POS (W5_REG_BASE + 0x015C)
+ * => Access unit (AU) Bitstream end position
+ */
+
+/*
+ * Decoded picture type:
+ * reg_val & 0x7 => picture type
+ * (reg_val >> 4) & 0x3f => VCL NAL unit type
+ * (reg_val >> 31) & 0x1 => output_flag
+ * 16 << ((reg_val >> 10) & 0x3) => ctu_size
+ */
+#define W5_RET_DEC_PIC_TYPE (W5_REG_BASE + 0x0160)
+#define W5_RET_DEC_PIC_POC (W5_REG_BASE + 0x0164)
+/*
+ * #define W5_RET_DEC_RECOVERY_POINT (W5_REG_BASE + 0x0168)
+ * => HEVC recovery point
+ * reg_val & 0xff => number of signed recovery picture order counts
+ * (reg_val >> 16) & 0x1 => exact match flag
+ * (reg_val >> 17) & 0x1 => broken link flag
+ * (reg_val >> 18) & 0x1 => exist flag
+ */
+#define W5_RET_DEC_DEBUG_INDEX (W5_REG_BASE + 0x016C)
+#define W5_RET_DEC_DECODED_INDEX (W5_REG_BASE + 0x0170)
+#define W5_RET_DEC_DISPLAY_INDEX (W5_REG_BASE + 0x0174)
+/*
+ * #define W5_RET_DEC_REALLOC_INDEX (W5_REG_BASE + 0x0178)
+ * => display picture index in decoded picture buffer
+ * reg_val & 0xf => display picture index for FBC buffer (by reordering)
+ */
+#define W5_RET_DEC_DISP_IDC (W5_REG_BASE + 0x017C)
+/*
+ * #define W5_RET_DEC_ERR_CTB_NUM (W5_REG_BASE + 0x0180)
+ * => Number of error CTUs
+ * reg_val >> 16 => erroneous CTUs in bitstream
+ * reg_val & 0xffff => total CTUs in bitstream
+ *
+ * #define W5_RET_DEC_PIC_PARAM (W5_REG_BASE + 0x01A0)
+ * => Bitstream sequence/picture parameter information (AV1 only)
+ * reg_val & 0x1 => intrabc tool enable
+ * (reg_val >> 1) & 0x1 => screen content tools enable
+ */
+#define W5_RET_DEC_HOST_CMD_TICK (W5_REG_BASE + 0x01B8)
+/*
+ * #define W5_RET_DEC_SEEK_START_TICK (W5_REG_BASE + 0x01BC)
+ * #define W5_RET_DEC_SEEK_END_TICK (W5_REG_BASE + 0x01C0)
+ * => Start and end ticks for seeking slices of the picture
+ * #define W5_RET_DEC_PARSING_START_TICK (W5_REG_BASE + 0x01C4)
+ * #define W5_RET_DEC_PARSING_END_TICK (W5_REG_BASE + 0x01C8)
+ * => Start and end ticks for parsing slices of the picture
+ * #define W5_RET_DEC_DECODING_START_TICK (W5_REG_BASE + 0x01CC)
+ * => Start tick for decoding slices of the picture
+ */
+#define W5_RET_DEC_DECODING_ENC_TICK (W5_REG_BASE + 0x01D0)
+#define W5_RET_DEC_WARN_INFO (W5_REG_BASE + 0x01D4)
+#define W5_RET_DEC_ERR_INFO (W5_REG_BASE + 0x01D8)
+#define W5_RET_DEC_DECODING_SUCCESS (W5_REG_BASE + 0x01DC)
+
+/************************************************************************/
+/* DECODER - FLUSH_INSTANCE */
+/************************************************************************/
+#define W5_CMD_FLUSH_INST_OPT (W5_REG_BASE + 0x104)
+
+/************************************************************************/
+/* DECODER - QUERY : UPDATE_DISP_FLAG */
+/************************************************************************/
+#define W5_CMD_DEC_SET_DISP_IDC (W5_REG_BASE + 0x0118)
+#define W5_CMD_DEC_CLR_DISP_IDC (W5_REG_BASE + 0x011C)
+
+/************************************************************************/
+/* DECODER - QUERY : SET_BS_RD_PTR */
+/************************************************************************/
+#define W5_RET_QUERY_DEC_SET_BS_RD_PTR (W5_REG_BASE + 0x011C)
+
+/************************************************************************/
+/* DECODER - QUERY : GET_BS_RD_PTR */
+/************************************************************************/
+#define W5_RET_QUERY_DEC_BS_RD_PTR (W5_REG_BASE + 0x011C)
+
+/************************************************************************/
+/* QUERY : GET_DEBUG_INFO */
+/************************************************************************/
+#define W5_RET_QUERY_DEBUG_PRI_REASON (W5_REG_BASE + 0x114)
+
+/************************************************************************/
+/* GDI register for debugging */
+/************************************************************************/
+#define W5_GDI_BASE 0x8800
+#define W5_GDI_BUS_CTRL (W5_GDI_BASE + 0x0F0)
+#define W5_GDI_BUS_STATUS (W5_GDI_BASE + 0x0F4)
+
+#define W5_BACKBONE_BASE_VCPU 0xFE00
+#define W5_BACKBONE_BUS_CTRL_VCPU (W5_BACKBONE_BASE_VCPU + 0x010)
+#define W5_BACKBONE_BUS_STATUS_VCPU (W5_BACKBONE_BASE_VCPU + 0x014)
+#define W5_BACKBONE_PROG_AXI_ID (W5_BACKBONE_BASE_VCPU + 0x00C)
+
+#define W5_BACKBONE_PROC_EXT_ADDR (W5_BACKBONE_BASE_VCPU + 0x0C0)
+#define W5_BACKBONE_AXI_PARAM (W5_BACKBONE_BASE_VCPU + 0x0E0)
+
+#define W5_BACKBONE_BASE_VCORE0 0x8E00
+#define W5_BACKBONE_BUS_CTRL_VCORE0 (W5_BACKBONE_BASE_VCORE0 + 0x010)
+#define W5_BACKBONE_BUS_STATUS_VCORE0 (W5_BACKBONE_BASE_VCORE0 + 0x014)
+
+#define W5_BACKBONE_BASE_VCORE1 0x9E00 /* for dual-core product */
+#define W5_BACKBONE_BUS_CTRL_VCORE1 (W5_BACKBONE_BASE_VCORE1 + 0x010)
+#define W5_BACKBONE_BUS_STATUS_VCORE1 (W5_BACKBONE_BASE_VCORE1 + 0x014)
+
+#define W5_COMBINED_BACKBONE_BASE 0xFE00
+#define W5_COMBINED_BACKBONE_BUS_CTRL (W5_COMBINED_BACKBONE_BASE + 0x010)
+#define W5_COMBINED_BACKBONE_BUS_STATUS (W5_COMBINED_BACKBONE_BASE + 0x014)
+
+/************************************************************************/
+/* */
+/* for ENCODER */
+/* */
+/************************************************************************/
+#define W5_RET_STAGE3_INSTANCE_INFO (W5_REG_BASE + 0x1F8)
+/************************************************************************/
+/* ENCODER - CREATE_INSTANCE */
+/************************************************************************/
+/* 0x114 ~ 0x124 : defined above (CREATE_INSTANCE COMMON) */
+#define W5_CMD_ENC_VCORE_INFO (W5_REG_BASE + 0x0194)
+#define W5_CMD_ENC_SRC_OPTIONS (W5_REG_BASE + 0x0128)
+
+/************************************************************************/
+/* ENCODER - SET_FB */
+/************************************************************************/
+#define W5_FBC_STRIDE (W5_REG_BASE + 0x128)
+#define W5_ADDR_SUB_SAMPLED_FB_BASE (W5_REG_BASE + 0x12C)
+#define W5_SUB_SAMPLED_ONE_FB_SIZE (W5_REG_BASE + 0x130)
+
+/************************************************************************/
+/* ENCODER - ENC_SET_PARAM (COMMON & CHANGE_PARAM) */
+/************************************************************************/
+#define W5_CMD_ENC_SEQ_SET_PARAM_OPTION (W5_REG_BASE + 0x104)
+#define W5_CMD_ENC_SEQ_SET_PARAM_ENABLE (W5_REG_BASE + 0x118)
+#define W5_CMD_ENC_SEQ_SRC_SIZE (W5_REG_BASE + 0x11C)
+#define W5_CMD_ENC_SEQ_CUSTOM_MAP_ENDIAN (W5_REG_BASE + 0x120)
+#define W5_CMD_ENC_SEQ_SPS_PARAM (W5_REG_BASE + 0x124)
+#define W5_CMD_ENC_SEQ_PPS_PARAM (W5_REG_BASE + 0x128)
+#define W5_CMD_ENC_SEQ_GOP_PARAM (W5_REG_BASE + 0x12C)
+#define W5_CMD_ENC_SEQ_INTRA_PARAM (W5_REG_BASE + 0x130)
+#define W5_CMD_ENC_SEQ_CONF_WIN_TOP_BOT (W5_REG_BASE + 0x134)
+#define W5_CMD_ENC_SEQ_CONF_WIN_LEFT_RIGHT (W5_REG_BASE + 0x138)
+#define W5_CMD_ENC_SEQ_RDO_PARAM (W5_REG_BASE + 0x13C)
+#define W5_CMD_ENC_SEQ_INDEPENDENT_SLICE (W5_REG_BASE + 0x140)
+#define W5_CMD_ENC_SEQ_DEPENDENT_SLICE (W5_REG_BASE + 0x144)
+#define W5_CMD_ENC_SEQ_INTRA_REFRESH (W5_REG_BASE + 0x148)
+#define W5_CMD_ENC_SEQ_INPUT_SRC_PARAM (W5_REG_BASE + 0x14C)
+
+#define W5_CMD_ENC_SEQ_RC_FRAME_RATE (W5_REG_BASE + 0x150)
+#define W5_CMD_ENC_SEQ_RC_TARGET_RATE (W5_REG_BASE + 0x154)
+#define W5_CMD_ENC_SEQ_RC_PARAM (W5_REG_BASE + 0x158)
+#define W5_CMD_ENC_SEQ_RC_MIN_MAX_QP (W5_REG_BASE + 0x15C)
+#define W5_CMD_ENC_SEQ_RC_BIT_RATIO_LAYER_0_3 (W5_REG_BASE + 0x160)
+#define W5_CMD_ENC_SEQ_RC_BIT_RATIO_LAYER_4_7 (W5_REG_BASE + 0x164)
+#define W5_CMD_ENC_SEQ_RC_INTER_MIN_MAX_QP (W5_REG_BASE + 0x168)
+#define W5_CMD_ENC_SEQ_RC_WEIGHT_PARAM (W5_REG_BASE + 0x16C)
+
+#define W5_CMD_ENC_SEQ_ROT_PARAM (W5_REG_BASE + 0x170)
+#define W5_CMD_ENC_SEQ_NUM_UNITS_IN_TICK (W5_REG_BASE + 0x174)
+#define W5_CMD_ENC_SEQ_TIME_SCALE (W5_REG_BASE + 0x178)
+#define W5_CMD_ENC_SEQ_NUM_TICKS_POC_DIFF_ONE (W5_REG_BASE + 0x17C)
+
+#define W5_CMD_ENC_SEQ_CUSTOM_MD_PU04 (W5_REG_BASE + 0x184)
+#define W5_CMD_ENC_SEQ_CUSTOM_MD_PU08 (W5_REG_BASE + 0x188)
+#define W5_CMD_ENC_SEQ_CUSTOM_MD_PU16 (W5_REG_BASE + 0x18C)
+#define W5_CMD_ENC_SEQ_CUSTOM_MD_PU32 (W5_REG_BASE + 0x190)
+#define W5_CMD_ENC_SEQ_CUSTOM_MD_CU08 (W5_REG_BASE + 0x194)
+#define W5_CMD_ENC_SEQ_CUSTOM_MD_CU16 (W5_REG_BASE + 0x198)
+#define W5_CMD_ENC_SEQ_CUSTOM_MD_CU32 (W5_REG_BASE + 0x19C)
+#define W5_CMD_ENC_SEQ_NR_PARAM (W5_REG_BASE + 0x1A0)
+#define W5_CMD_ENC_SEQ_NR_WEIGHT (W5_REG_BASE + 0x1A4)
+#define W5_CMD_ENC_SEQ_BG_PARAM (W5_REG_BASE + 0x1A8)
+#define W5_CMD_ENC_SEQ_CUSTOM_LAMBDA_ADDR (W5_REG_BASE + 0x1AC)
+#define W5_CMD_ENC_SEQ_USER_SCALING_LIST_ADDR (W5_REG_BASE + 0x1B0)
+#define W5_CMD_ENC_SEQ_VUI_HRD_PARAM (W5_REG_BASE + 0x180)
+#define W5_CMD_ENC_SEQ_VUI_RBSP_ADDR (W5_REG_BASE + 0x1B8)
+#define W5_CMD_ENC_SEQ_HRD_RBSP_ADDR (W5_REG_BASE + 0x1BC)
+
+/************************************************************************/
+/* ENCODER - ENC_SET_PARAM (CUSTOM_GOP) */
+/************************************************************************/
+#define W5_CMD_ENC_CUSTOM_GOP_PARAM (W5_REG_BASE + 0x11C)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_0 (W5_REG_BASE + 0x120)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_1 (W5_REG_BASE + 0x124)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_2 (W5_REG_BASE + 0x128)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_3 (W5_REG_BASE + 0x12C)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_4 (W5_REG_BASE + 0x130)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_5 (W5_REG_BASE + 0x134)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_6 (W5_REG_BASE + 0x138)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_7 (W5_REG_BASE + 0x13C)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_8 (W5_REG_BASE + 0x140)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_9 (W5_REG_BASE + 0x144)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_10 (W5_REG_BASE + 0x148)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_11 (W5_REG_BASE + 0x14C)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_12 (W5_REG_BASE + 0x150)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_13 (W5_REG_BASE + 0x154)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_14 (W5_REG_BASE + 0x158)
+#define W5_CMD_ENC_CUSTOM_GOP_PIC_PARAM_15 (W5_REG_BASE + 0x15C)
+
+/************************************************************************/
+/* ENCODER - ENC_PIC */
+/************************************************************************/
+#define W5_CMD_ENC_BS_START_ADDR (W5_REG_BASE + 0x118)
+#define W5_CMD_ENC_BS_SIZE (W5_REG_BASE + 0x11C)
+#define W5_CMD_ENC_PIC_USE_SEC_AXI (W5_REG_BASE + 0x124)
+#define W5_CMD_ENC_PIC_REPORT_PARAM (W5_REG_BASE + 0x128)
+
+#define W5_CMD_ENC_PIC_CUSTOM_MAP_OPTION_PARAM (W5_REG_BASE + 0x138)
+#define W5_CMD_ENC_PIC_CUSTOM_MAP_OPTION_ADDR (W5_REG_BASE + 0x13C)
+#define W5_CMD_ENC_PIC_SRC_PIC_IDX (W5_REG_BASE + 0x144)
+#define W5_CMD_ENC_PIC_SRC_ADDR_Y (W5_REG_BASE + 0x148)
+#define W5_CMD_ENC_PIC_SRC_ADDR_U (W5_REG_BASE + 0x14C)
+#define W5_CMD_ENC_PIC_SRC_ADDR_V (W5_REG_BASE + 0x150)
+#define W5_CMD_ENC_PIC_SRC_STRIDE (W5_REG_BASE + 0x154)
+#define W5_CMD_ENC_PIC_SRC_FORMAT (W5_REG_BASE + 0x158)
+#define W5_CMD_ENC_PIC_SRC_AXI_SEL (W5_REG_BASE + 0x160)
+#define W5_CMD_ENC_PIC_CODE_OPTION (W5_REG_BASE + 0x164)
+#define W5_CMD_ENC_PIC_PIC_PARAM (W5_REG_BASE + 0x168)
+#define W5_CMD_ENC_PIC_LONGTERM_PIC (W5_REG_BASE + 0x16C)
+#define W5_CMD_ENC_PIC_WP_PIXEL_SIGMA_Y (W5_REG_BASE + 0x170)
+#define W5_CMD_ENC_PIC_WP_PIXEL_SIGMA_C (W5_REG_BASE + 0x174)
+#define W5_CMD_ENC_PIC_WP_PIXEL_MEAN_Y (W5_REG_BASE + 0x178)
+#define W5_CMD_ENC_PIC_WP_PIXEL_MEAN_C (W5_REG_BASE + 0x17C)
+#define W5_CMD_ENC_PIC_CF50_Y_OFFSET_TABLE_ADDR (W5_REG_BASE + 0x190)
+#define W5_CMD_ENC_PIC_CF50_CB_OFFSET_TABLE_ADDR (W5_REG_BASE + 0x194)
+#define W5_CMD_ENC_PIC_CF50_CR_OFFSET_TABLE_ADDR (W5_REG_BASE + 0x198)
+#define W5_CMD_ENC_PIC_PREFIX_SEI_NAL_ADDR (W5_REG_BASE + 0x180)
+#define W5_CMD_ENC_PIC_PREFIX_SEI_INFO (W5_REG_BASE + 0x184)
+#define W5_CMD_ENC_PIC_SUFFIX_SEI_NAL_ADDR (W5_REG_BASE + 0x188)
+#define W5_CMD_ENC_PIC_SUFFIX_SEI_INFO (W5_REG_BASE + 0x18c)
+
+/************************************************************************/
+/* ENCODER - QUERY (GET_RESULT) */
+/************************************************************************/
+#define W5_RET_ENC_NUM_REQUIRED_FB (W5_REG_BASE + 0x11C)
+#define W5_RET_ENC_MIN_SRC_BUF_NUM (W5_REG_BASE + 0x120)
+#define W5_RET_ENC_PIC_TYPE (W5_REG_BASE + 0x124)
+/*
+ * #define W5_RET_ENC_PIC_POC (W5_REG_BASE + 0x128)
+ * => picture order count value of current encoded picture
+ */
+#define W5_RET_ENC_PIC_IDX (W5_REG_BASE + 0x12C)
+/*
+ * #define W5_RET_ENC_PIC_SLICE_NUM (W5_REG_BASE + 0x130)
+ * reg_val & 0xffff = total independent slice segment number (16 bits)
+ * (reg_val >> 16) & 0xffff = total dependent slice segment number (16 bits)
+ *
+ * #define W5_RET_ENC_PIC_SKIP (W5_REG_BASE + 0x134)
+ * reg_val & 0xfe = picture skip flag (7 bits)
+ *
+ * #define W5_RET_ENC_PIC_NUM_INTRA (W5_REG_BASE + 0x138)
+ * => number of intra blocks in 8x8 (32 bits)
+ *
+ * #define W5_RET_ENC_PIC_NUM_MERGE (W5_REG_BASE + 0x13C)
+ * => number of merge blocks in 8x8 (32 bits)
+ *
+ * #define W5_RET_ENC_PIC_NUM_SKIP (W5_REG_BASE + 0x144)
+ * => number of skip blocks in 8x8 (32 bits)
+ *
+ * #define W5_RET_ENC_PIC_AVG_CTU_QP (W5_REG_BASE + 0x148)
+ * => Average CTU QP value (32 bits)
+ */
+#define W5_RET_ENC_PIC_BYTE (W5_REG_BASE + 0x14C)
+/*
+ * #define W5_RET_ENC_GOP_PIC_IDX (W5_REG_BASE + 0x150)
+ * => picture index in group of pictures
+ */
+#define W5_RET_ENC_USED_SRC_IDX (W5_REG_BASE + 0x154)
+/*
+ * #define W5_RET_ENC_PIC_NUM (W5_REG_BASE + 0x158)
+ * => encoded picture number
+ */
+#define W5_RET_ENC_VCL_NUT (W5_REG_BASE + 0x15C)
+/*
+ * Only for H264:
+ * #define W5_RET_ENC_PIC_DIST_LOW (W5_REG_BASE + 0x164)
+ * => lower 32 bits of the sum of squared difference between source Y picture
+ * and reconstructed Y picture
+ * #define W5_RET_ENC_PIC_DIST_HIGH (W5_REG_BASE + 0x168)
+ * => upper 32 bits of the sum of squared difference between source Y picture
+ * and reconstructed Y picture
+ */
+#define W5_RET_ENC_PIC_MAX_LATENCY_PICS (W5_REG_BASE + 0x16C)
+
+#define W5_RET_ENC_HOST_CMD_TICK (W5_REG_BASE + 0x1B8)
+/*
+ * #define W5_RET_ENC_PREPARE_START_TICK (W5_REG_BASE + 0x1BC)
+ * #define W5_RET_ENC_PREPARE_END_TICK (W5_REG_BASE + 0x1C0)
+ * => Start and end ticks for preparing slices of the picture
+ * #define W5_RET_ENC_PROCESSING_START_TICK (W5_REG_BASE + 0x1C4)
+ * #define W5_RET_ENC_PROCESSING_END_TICK (W5_REG_BASE + 0x1C8)
+ * => Start and end ticks for processing slices of the picture
+ * #define W5_RET_ENC_ENCODING_START_TICK (W5_REG_BASE + 0x1CC)
+ * => Start tick for encoding slices of the picture
+ */
+#define W5_RET_ENC_ENCODING_END_TICK (W5_REG_BASE + 0x1D0)
+
+#define W5_RET_ENC_WARN_INFO (W5_REG_BASE + 0x1D4)
+#define W5_RET_ENC_ERR_INFO (W5_REG_BASE + 0x1D8)
+#define W5_RET_ENC_ENCODING_SUCCESS (W5_REG_BASE + 0x1DC)
+
+/************************************************************************/
+/* ENCODER - QUERY (GET_BS_WR_PTR) */
+/************************************************************************/
+#define W5_RET_ENC_RD_PTR (W5_REG_BASE + 0x114)
+#define W5_RET_ENC_WR_PTR (W5_REG_BASE + 0x118)
+#define W5_CMD_ENC_REASON_SEL (W5_REG_BASE + 0x11C)
+
+/************************************************************************/
+/* ENCODER - QUERY (GET_BW_REPORT) */
+/************************************************************************/
+#define RET_QUERY_BW_PRP_AXI_READ (W5_REG_BASE + 0x118)
+#define RET_QUERY_BW_PRP_AXI_WRITE (W5_REG_BASE + 0x11C)
+#define RET_QUERY_BW_FBD_Y_AXI_READ (W5_REG_BASE + 0x120)
+#define RET_QUERY_BW_FBC_Y_AXI_WRITE (W5_REG_BASE + 0x124)
+#define RET_QUERY_BW_FBD_C_AXI_READ (W5_REG_BASE + 0x128)
+#define RET_QUERY_BW_FBC_C_AXI_WRITE (W5_REG_BASE + 0x12C)
+#define RET_QUERY_BW_PRI_AXI_READ (W5_REG_BASE + 0x130)
+#define RET_QUERY_BW_PRI_AXI_WRITE (W5_REG_BASE + 0x134)
+#define RET_QUERY_BW_SEC_AXI_READ (W5_REG_BASE + 0x138)
+#define RET_QUERY_BW_SEC_AXI_WRITE (W5_REG_BASE + 0x13C)
+#define RET_QUERY_BW_PROC_AXI_READ (W5_REG_BASE + 0x140)
+#define RET_QUERY_BW_PROC_AXI_WRITE (W5_REG_BASE + 0x144)
+#define RET_QUERY_BW_BWB_AXI_WRITE (W5_REG_BASE + 0x148)
+#define W5_CMD_BW_OPTION (W5_REG_BASE + 0x14C)
+
+/************************************************************************/
+/* ENCODER - QUERY (GET_SRC_FLAG) */
+/************************************************************************/
+#define W5_RET_RELEASED_SRC_INSTANCE (W5_REG_BASE + 0x1EC)
+
+#define W5_ENC_PIC_SUB_FRAME_SYNC_IF (W5_REG_BASE + 0x0300)
+
+#endif /* __WAVE5_REGISTER_DEFINE_H__ */
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vdi.c b/drivers/media/platform/chips-media/wave5/wave5-vdi.c
new file mode 100644
index 000000000000..3809f70bc0b4
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-vdi.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave5 series multi-standard codec IP - low level access functions
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#include <linux/bug.h>
+#include "wave5-vdi.h"
+#include "wave5-vpu.h"
+#include "wave5-regdefine.h"
+#include <linux/delay.h>
+
+static int wave5_vdi_allocate_common_memory(struct device *dev)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ if (!vpu_dev->common_mem.vaddr) {
+ int ret;
+
+ vpu_dev->common_mem.size = SIZE_COMMON;
+ ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vpu_dev->common_mem);
+ if (ret) {
+ dev_err(dev, "unable to allocate common buffer\n");
+ return ret;
+ }
+ }
+
+ dev_dbg(dev, "[VDI] common_mem: daddr=%pad size=%zu vaddr=0x%p\n",
+ &vpu_dev->common_mem.daddr, vpu_dev->common_mem.size, vpu_dev->common_mem.vaddr);
+
+ return 0;
+}
+
+int wave5_vdi_init(struct device *dev)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = wave5_vdi_allocate_common_memory(dev);
+ if (ret < 0) {
+ dev_err(dev, "[VDI] failed to get vpu common buffer from driver\n");
+ return ret;
+ }
+
+ if (!PRODUCT_CODE_W_SERIES(vpu_dev->product_code)) {
+ WARN_ONCE(1, "unsupported product code: 0x%x\n", vpu_dev->product_code);
+ return -EOPNOTSUPP;
+ }
+
+ /* if BIT processor is not running. */
+ if (wave5_vdi_read_register(vpu_dev, W5_VCPU_CUR_PC) == 0) {
+ int i;
+
+ for (i = 0; i < 64; i++)
+ wave5_vdi_write_register(vpu_dev, (i * 4) + 0x100, 0x0);
+ }
+
+ dev_dbg(dev, "[VDI] driver initialized successfully\n");
+
+ return 0;
+}
+
+int wave5_vdi_release(struct device *dev)
+{
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ vpu_dev->vdb_register = NULL;
+ wave5_vdi_free_dma_memory(vpu_dev, &vpu_dev->common_mem);
+
+ return 0;
+}
+
+void wave5_vdi_write_register(struct vpu_device *vpu_dev, u32 addr, u32 data)
+{
+ writel(data, vpu_dev->vdb_register + addr);
+}
+
+unsigned int wave5_vdi_read_register(struct vpu_device *vpu_dev, u32 addr)
+{
+ return readl(vpu_dev->vdb_register + addr);
+}
+
+int wave5_vdi_clear_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb)
+{
+ if (!vb || !vb->vaddr) {
+ dev_err(vpu_dev->dev, "%s: unable to clear unmapped buffer\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(vb->vaddr, 0, vb->size);
+ return vb->size;
+}
+
+int wave5_vdi_write_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb, size_t offset,
+ u8 *data, size_t len)
+{
+ if (!vb || !vb->vaddr) {
+ dev_err(vpu_dev->dev, "%s: unable to write to unmapped buffer\n", __func__);
+ return -EINVAL;
+ }
+
+ if (offset > vb->size || len > vb->size || offset + len > vb->size) {
+ dev_err(vpu_dev->dev, "%s: buffer too small\n", __func__);
+ return -ENOSPC;
+ }
+
+ memcpy(vb->vaddr + offset, data, len);
+
+ return len;
+}
+
+int wave5_vdi_allocate_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb)
+{
+ void *vaddr;
+ dma_addr_t daddr;
+
+ if (!vb->size) {
+ dev_err(vpu_dev->dev, "%s: requested size==0\n", __func__);
+ return -EINVAL;
+ }
+
+ vaddr = dma_alloc_coherent(vpu_dev->dev, vb->size, &daddr, GFP_KERNEL);
+ if (!vaddr)
+ return -ENOMEM;
+ vb->vaddr = vaddr;
+ vb->daddr = daddr;
+
+ return 0;
+}
+
+int wave5_vdi_free_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb)
+{
+ if (vb->size == 0)
+ return -EINVAL;
+
+ if (!vb->vaddr)
+ dev_err(vpu_dev->dev, "%s: requested free of unmapped buffer\n", __func__);
+ else
+ dma_free_coherent(vpu_dev->dev, vb->size, vb->vaddr, vb->daddr);
+
+ memset(vb, 0, sizeof(*vb));
+
+ return 0;
+}
+
+int wave5_vdi_allocate_array(struct vpu_device *vpu_dev, struct vpu_buf *array, unsigned int count,
+ size_t size)
+{
+ struct vpu_buf vb_buf;
+ int i, ret = 0;
+
+ vb_buf.size = size;
+
+ for (i = 0; i < count; i++) {
+ if (array[i].size == size)
+ continue;
+
+ if (array[i].size != 0)
+ wave5_vdi_free_dma_memory(vpu_dev, &array[i]);
+
+ ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_buf);
+ if (ret)
+ return -ENOMEM;
+ array[i] = vb_buf;
+ }
+
+ for (i = count; i < MAX_REG_FRAME; i++)
+ wave5_vdi_free_dma_memory(vpu_dev, &array[i]);
+
+ return 0;
+}
+
+void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev)
+{
+ struct vpu_buf *vb = &vpu_dev->sram_buf;
+
+ if (!vpu_dev->sram_pool || !vpu_dev->sram_size)
+ return;
+
+ if (!vb->vaddr) {
+ vb->size = vpu_dev->sram_size;
+ vb->vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, vb->size,
+ &vb->daddr);
+ if (!vb->vaddr)
+ vb->size = 0;
+ }
+
+ dev_dbg(vpu_dev->dev, "%s: sram daddr: %pad, size: %zu, vaddr: 0x%p\n",
+ __func__, &vb->daddr, vb->size, vb->vaddr);
+}
+
+void wave5_vdi_free_sram(struct vpu_device *vpu_dev)
+{
+ struct vpu_buf *vb = &vpu_dev->sram_buf;
+
+ if (!vb->size || !vb->vaddr)
+ return;
+
+ if (vb->vaddr)
+ gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr,
+ vb->size);
+
+ memset(vb, 0, sizeof(*vb));
+}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vdi.h b/drivers/media/platform/chips-media/wave5/wave5-vdi.h
new file mode 100644
index 000000000000..3984ef3f1f96
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-vdi.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave5 series multi-standard codec IP - low level access functions
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#ifndef _VDI_H_
+#define _VDI_H_
+
+#include "wave5-vpuconfig.h"
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+
+/************************************************************************/
+/* COMMON REGISTERS */
+/************************************************************************/
+#define VPU_PRODUCT_CODE_REGISTER 0x1044
+
+/* system register write */
+#define vpu_write_reg(VPU_INST, ADDR, DATA) wave5_vdi_write_register(VPU_INST, ADDR, DATA)
+/* system register read */
+#define vpu_read_reg(CORE, ADDR) wave5_vdi_read_register(CORE, ADDR)
+
+struct vpu_buf {
+ size_t size;
+ dma_addr_t daddr;
+ void *vaddr;
+};
+
+int wave5_vdi_init(struct device *dev);
+int wave5_vdi_release(struct device *dev); //this function may be called only at system off.
+
+#endif //#ifndef _VDI_H_
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
new file mode 100644
index 000000000000..ef227af72348
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
@@ -0,0 +1,1932 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave5 series multi-standard codec IP - decoder interface
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#include "wave5-helper.h"
+
+#define VPU_DEC_DEV_NAME "C&M Wave5 VPU decoder"
+#define VPU_DEC_DRV_NAME "wave5-dec"
+
+#define DEFAULT_SRC_SIZE(width, height) ({ \
+ (width) * (height) / 8 * 3; \
+})
+
+static const struct vpu_format dec_fmt_list[FMT_TYPES][MAX_FMTS] = {
+ [VPU_FMT_TYPE_CODEC] = {
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_H264,
+ .max_width = 8192,
+ .min_width = 32,
+ .max_height = 4320,
+ .min_height = 32,
+ },
+ },
+ [VPU_FMT_TYPE_RAW] = {
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV12,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV21,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV16,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV61,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M,
+ .max_width = 8192,
+ .min_width = 8,
+ .max_height = 4320,
+ .min_height = 8,
+ },
+ }
+};
+
+/*
+ * Make sure that the state switch is allowed and add logging for debugging
+ * purposes
+ */
+static int switch_state(struct vpu_instance *inst, enum vpu_instance_state state)
+{
+ switch (state) {
+ case VPU_INST_STATE_NONE:
+ break;
+ case VPU_INST_STATE_OPEN:
+ if (inst->state != VPU_INST_STATE_NONE)
+ goto invalid_state_switch;
+ goto valid_state_switch;
+ case VPU_INST_STATE_INIT_SEQ:
+ if (inst->state != VPU_INST_STATE_OPEN && inst->state != VPU_INST_STATE_STOP)
+ goto invalid_state_switch;
+ goto valid_state_switch;
+ case VPU_INST_STATE_PIC_RUN:
+ if (inst->state != VPU_INST_STATE_INIT_SEQ)
+ goto invalid_state_switch;
+ goto valid_state_switch;
+ case VPU_INST_STATE_STOP:
+ goto valid_state_switch;
+ }
+invalid_state_switch:
+ WARN(1, "Invalid state switch from %s to %s.\n",
+ state_to_str(inst->state), state_to_str(state));
+ return -EINVAL;
+valid_state_switch:
+ dev_dbg(inst->dev->dev, "Switch state from %s to %s.\n",
+ state_to_str(inst->state), state_to_str(state));
+ inst->state = state;
+ return 0;
+}
+
+static int wave5_vpu_dec_set_eos_on_firmware(struct vpu_instance *inst)
+{
+ int ret;
+
+ ret = wave5_vpu_dec_update_bitstream_buffer(inst, 0);
+ if (ret) {
+ /*
+ * To set the EOS flag, a command is sent to the firmware.
+ * That command may never return (timeout) or may report an error.
+ */
+ dev_err(inst->dev->dev,
+ "Setting EOS for the bitstream, fail: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static bool wave5_last_src_buffer_consumed(struct v4l2_m2m_ctx *m2m_ctx)
+{
+ struct vpu_src_buffer *vpu_buf;
+
+ if (!m2m_ctx->last_src_buf)
+ return false;
+
+ vpu_buf = wave5_to_vpu_src_buf(m2m_ctx->last_src_buf);
+ return vpu_buf->consumed;
+}
+
+static void wave5_handle_src_buffer(struct vpu_instance *inst, dma_addr_t rd_ptr)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct v4l2_m2m_buffer *buf, *n;
+ size_t consumed_bytes = 0;
+
+ if (rd_ptr >= inst->last_rd_ptr) {
+ consumed_bytes = rd_ptr - inst->last_rd_ptr;
+ } else {
+ size_t rd_offs = rd_ptr - inst->bitstream_vbuf.daddr;
+ size_t last_rd_offs = inst->last_rd_ptr - inst->bitstream_vbuf.daddr;
+
+ consumed_bytes = rd_offs + (inst->bitstream_vbuf.size - last_rd_offs);
+ }
+
+ inst->last_rd_ptr = rd_ptr;
+ consumed_bytes += inst->remaining_consumed_bytes;
+
+ dev_dbg(inst->dev->dev, "%s: %zu bytes of bitstream was consumed", __func__,
+ consumed_bytes);
+
+ v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
+ struct vb2_v4l2_buffer *src_buf = &buf->vb;
+ size_t src_size = vb2_get_plane_payload(&src_buf->vb2_buf, 0);
+
+ if (src_size > consumed_bytes)
+ break;
+
+ dev_dbg(inst->dev->dev, "%s: removing src buffer %i",
+ __func__, src_buf->vb2_buf.index);
+ src_buf = v4l2_m2m_src_buf_remove(m2m_ctx);
+ inst->timestamp = src_buf->vb2_buf.timestamp;
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+ consumed_bytes -= src_size;
+
+ /* Handle the case the last bitstream buffer has been picked */
+ if (src_buf == m2m_ctx->last_src_buf) {
+ int ret;
+
+ m2m_ctx->last_src_buf = NULL;
+ ret = wave5_vpu_dec_set_eos_on_firmware(inst);
+ if (ret)
+ dev_warn(inst->dev->dev,
+ "Setting EOS for the bitstream, fail: %d\n", ret);
+ break;
+ }
+ }
+
+ inst->remaining_consumed_bytes = consumed_bytes;
+}
+
+static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width,
+ unsigned int height)
+{
+ switch (pix_mp->pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ pix_mp->width = round_up(width, 32);
+ pix_mp->height = round_up(height, 16);
+ pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
+ pix_mp->plane_fmt[0].sizeimage = width * height * 3 / 2;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_NV16:
+ case V4L2_PIX_FMT_NV61:
+ pix_mp->width = round_up(width, 32);
+ pix_mp->height = round_up(height, 16);
+ pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
+ pix_mp->plane_fmt[0].sizeimage = width * height * 2;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ pix_mp->width = round_up(width, 32);
+ pix_mp->height = round_up(height, 16);
+ pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
+ pix_mp->plane_fmt[0].sizeimage = width * height;
+ pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2;
+ pix_mp->plane_fmt[1].sizeimage = width * height / 4;
+ pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2;
+ pix_mp->plane_fmt[2].sizeimage = width * height / 4;
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV21M:
+ pix_mp->width = round_up(width, 32);
+ pix_mp->height = round_up(height, 16);
+ pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
+ pix_mp->plane_fmt[0].sizeimage = width * height;
+ pix_mp->plane_fmt[1].bytesperline = round_up(width, 32);
+ pix_mp->plane_fmt[1].sizeimage = width * height / 2;
+ break;
+ case V4L2_PIX_FMT_YUV422M:
+ pix_mp->width = round_up(width, 32);
+ pix_mp->height = round_up(height, 16);
+ pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
+ pix_mp->plane_fmt[0].sizeimage = width * height;
+ pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2;
+ pix_mp->plane_fmt[1].sizeimage = width * height / 2;
+ pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2;
+ pix_mp->plane_fmt[2].sizeimage = width * height / 2;
+ break;
+ case V4L2_PIX_FMT_NV16M:
+ case V4L2_PIX_FMT_NV61M:
+ pix_mp->width = round_up(width, 32);
+ pix_mp->height = round_up(height, 16);
+ pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
+ pix_mp->plane_fmt[0].sizeimage = width * height;
+ pix_mp->plane_fmt[1].bytesperline = round_up(width, 32);
+ pix_mp->plane_fmt[1].sizeimage = width * height;
+ break;
+ default:
+ pix_mp->width = width;
+ pix_mp->height = height;
+ pix_mp->plane_fmt[0].bytesperline = 0;
+ pix_mp->plane_fmt[0].sizeimage = max(DEFAULT_SRC_SIZE(width, height),
+ pix_mp->plane_fmt[0].sizeimage);
+ break;
+ }
+}
+
+static int start_decode(struct vpu_instance *inst, u32 *fail_res)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ int ret = 0;
+
+ ret = wave5_vpu_dec_start_one_frame(inst, fail_res);
+ if (ret) {
+ struct vb2_v4l2_buffer *src_buf;
+
+ src_buf = v4l2_m2m_src_buf_remove(m2m_ctx);
+ if (src_buf)
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+ switch_state(inst, VPU_INST_STATE_STOP);
+
+ dev_dbg(inst->dev->dev, "%s: pic run failed / finish job", __func__);
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
+ }
+
+ return ret;
+}
+
+static void flag_last_buffer_done(struct vpu_instance *inst)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct vb2_v4l2_buffer *vb;
+ int i;
+
+ lockdep_assert_held(&inst->state_spinlock);
+
+ vb = v4l2_m2m_dst_buf_remove(m2m_ctx);
+ if (!vb) {
+ m2m_ctx->is_draining = true;
+ m2m_ctx->next_buf_last = true;
+ return;
+ }
+
+ for (i = 0; i < vb->vb2_buf.num_planes; i++)
+ vb2_set_plane_payload(&vb->vb2_buf, i, 0);
+ vb->field = V4L2_FIELD_NONE;
+
+ v4l2_m2m_last_buffer_done(m2m_ctx, vb);
+}
+
+static void send_eos_event(struct vpu_instance *inst)
+{
+ static const struct v4l2_event vpu_event_eos = {
+ .type = V4L2_EVENT_EOS
+ };
+
+ lockdep_assert_held(&inst->state_spinlock);
+
+ v4l2_event_queue_fh(&inst->v4l2_fh, &vpu_event_eos);
+ inst->eos = false;
+}
+
+static int handle_dynamic_resolution_change(struct vpu_instance *inst)
+{
+ struct v4l2_fh *fh = &inst->v4l2_fh;
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+
+ static const struct v4l2_event vpu_event_src_ch = {
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
+ };
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ struct dec_initial_info *initial_info = &inst->codec_info->dec_info.initial_info;
+
+ lockdep_assert_held(&inst->state_spinlock);
+
+ dev_dbg(inst->dev->dev, "%s: rd_ptr %pad", __func__, &initial_info->rd_ptr);
+
+ dev_dbg(inst->dev->dev, "%s: width: %u height: %u profile: %u | minbuffer: %u\n",
+ __func__, initial_info->pic_width, initial_info->pic_height,
+ initial_info->profile, initial_info->min_frame_buffer_count);
+
+ inst->needs_reallocation = true;
+ inst->fbc_buf_count = initial_info->min_frame_buffer_count + 1;
+ if (inst->fbc_buf_count != v4l2_m2m_num_dst_bufs_ready(m2m_ctx)) {
+ struct v4l2_ctrl *ctrl;
+
+ ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE);
+ if (ctrl)
+ v4l2_ctrl_s_ctrl(ctrl, inst->fbc_buf_count);
+ }
+
+ if (p_dec_info->initial_info_obtained) {
+ inst->conf_win.left = initial_info->pic_crop_rect.left;
+ inst->conf_win.top = initial_info->pic_crop_rect.top;
+ inst->conf_win.width = initial_info->pic_width -
+ initial_info->pic_crop_rect.left - initial_info->pic_crop_rect.right;
+ inst->conf_win.height = initial_info->pic_height -
+ initial_info->pic_crop_rect.top - initial_info->pic_crop_rect.bottom;
+
+ wave5_update_pix_fmt(&inst->src_fmt, initial_info->pic_width,
+ initial_info->pic_height);
+ wave5_update_pix_fmt(&inst->dst_fmt, initial_info->pic_width,
+ initial_info->pic_height);
+ }
+
+ v4l2_event_queue_fh(fh, &vpu_event_src_ch);
+
+ return 0;
+}
+
+static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct dec_output_info dec_info;
+ int ret;
+ struct vb2_v4l2_buffer *dec_buf = NULL;
+ struct vb2_v4l2_buffer *disp_buf = NULL;
+ struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx);
+ struct queue_status_info q_status;
+
+ dev_dbg(inst->dev->dev, "%s: Fetch output info from firmware.", __func__);
+
+ ret = wave5_vpu_dec_get_output_info(inst, &dec_info);
+ if (ret) {
+ dev_warn(inst->dev->dev, "%s: could not get output info.", __func__);
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
+ return;
+ }
+
+ dev_dbg(inst->dev->dev, "%s: rd_ptr %pad wr_ptr %pad", __func__, &dec_info.rd_ptr,
+ &dec_info.wr_ptr);
+ wave5_handle_src_buffer(inst, dec_info.rd_ptr);
+
+ dev_dbg(inst->dev->dev, "%s: dec_info dec_idx %i disp_idx %i", __func__,
+ dec_info.index_frame_decoded, dec_info.index_frame_display);
+
+ if (!vb2_is_streaming(dst_vq)) {
+ dev_dbg(inst->dev->dev, "%s: capture is not streaming..", __func__);
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
+ return;
+ }
+
+ /* Remove decoded buffer from the ready queue now that it has been
+ * decoded.
+ */
+ if (dec_info.index_frame_decoded >= 0) {
+ struct vb2_buffer *vb = vb2_get_buffer(dst_vq,
+ dec_info.index_frame_decoded);
+ if (vb) {
+ dec_buf = to_vb2_v4l2_buffer(vb);
+ dec_buf->vb2_buf.timestamp = inst->timestamp;
+ } else {
+ dev_warn(inst->dev->dev, "%s: invalid decoded frame index %i",
+ __func__, dec_info.index_frame_decoded);
+ }
+ }
+
+ if (dec_info.index_frame_display >= 0) {
+ disp_buf = v4l2_m2m_dst_buf_remove_by_idx(m2m_ctx, dec_info.index_frame_display);
+ if (!disp_buf)
+ dev_warn(inst->dev->dev, "%s: invalid display frame index %i",
+ __func__, dec_info.index_frame_display);
+ }
+
+ /* If there is anything to display, do that now */
+ if (disp_buf) {
+ struct vpu_dst_buffer *dst_vpu_buf = wave5_to_vpu_dst_buf(disp_buf);
+
+ if (inst->dst_fmt.num_planes == 1) {
+ vb2_set_plane_payload(&disp_buf->vb2_buf, 0,
+ inst->dst_fmt.plane_fmt[0].sizeimage);
+ } else if (inst->dst_fmt.num_planes == 2) {
+ vb2_set_plane_payload(&disp_buf->vb2_buf, 0,
+ inst->dst_fmt.plane_fmt[0].sizeimage);
+ vb2_set_plane_payload(&disp_buf->vb2_buf, 1,
+ inst->dst_fmt.plane_fmt[1].sizeimage);
+ } else if (inst->dst_fmt.num_planes == 3) {
+ vb2_set_plane_payload(&disp_buf->vb2_buf, 0,
+ inst->dst_fmt.plane_fmt[0].sizeimage);
+ vb2_set_plane_payload(&disp_buf->vb2_buf, 1,
+ inst->dst_fmt.plane_fmt[1].sizeimage);
+ vb2_set_plane_payload(&disp_buf->vb2_buf, 2,
+ inst->dst_fmt.plane_fmt[2].sizeimage);
+ }
+
+ /* TODO implement interlace support */
+ disp_buf->field = V4L2_FIELD_NONE;
+ dst_vpu_buf->display = true;
+ v4l2_m2m_buf_done(disp_buf, VB2_BUF_STATE_DONE);
+
+ dev_dbg(inst->dev->dev, "%s: frame_cycle %8u (payload %lu)\n",
+ __func__, dec_info.frame_cycle,
+ vb2_get_plane_payload(&disp_buf->vb2_buf, 0));
+ }
+
+ if ((dec_info.index_frame_display == DISPLAY_IDX_FLAG_SEQ_END ||
+ dec_info.sequence_changed)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&inst->state_spinlock, flags);
+ if (!v4l2_m2m_has_stopped(m2m_ctx)) {
+ switch_state(inst, VPU_INST_STATE_STOP);
+
+ if (dec_info.sequence_changed)
+ handle_dynamic_resolution_change(inst);
+ else
+ send_eos_event(inst);
+
+ flag_last_buffer_done(inst);
+ }
+ spin_unlock_irqrestore(&inst->state_spinlock, flags);
+ }
+
+ /*
+ * During a resolution change and while draining, the firmware may flush
+ * the reorder queue regardless of having a matching decoding operation
+ * pending. Only terminate the job if there are no more IRQ coming.
+ */
+ wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status);
+ if (q_status.report_queue_count == 0 &&
+ (q_status.instance_queue_count == 0 || dec_info.sequence_changed)) {
+ dev_dbg(inst->dev->dev, "%s: finishing job.\n", __func__);
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
+ }
+}
+
+static int wave5_vpu_dec_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, VPU_DEC_DRV_NAME, sizeof(cap->driver));
+ strscpy(cap->card, VPU_DEC_DRV_NAME, sizeof(cap->card));
+
+ return 0;
+}
+
+static int wave5_vpu_dec_enum_framesizes(struct file *f, void *fh, struct v4l2_frmsizeenum *fsize)
+{
+ const struct vpu_format *vpu_fmt;
+
+ if (fsize->index)
+ return -EINVAL;
+
+ vpu_fmt = wave5_find_vpu_fmt(fsize->pixel_format, dec_fmt_list[VPU_FMT_TYPE_CODEC]);
+ if (!vpu_fmt) {
+ vpu_fmt = wave5_find_vpu_fmt(fsize->pixel_format, dec_fmt_list[VPU_FMT_TYPE_RAW]);
+ if (!vpu_fmt)
+ return -EINVAL;
+ }
+
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ fsize->stepwise.min_width = vpu_fmt->min_width;
+ fsize->stepwise.max_width = vpu_fmt->max_width;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.min_height = vpu_fmt->min_height;
+ fsize->stepwise.max_height = vpu_fmt->max_height;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
+static int wave5_vpu_dec_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ const struct vpu_format *vpu_fmt;
+
+ vpu_fmt = wave5_find_vpu_fmt_by_idx(f->index, dec_fmt_list[VPU_FMT_TYPE_RAW]);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ f->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ f->flags = 0;
+
+ return 0;
+}
+
+static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ const struct vpu_format *vpu_fmt;
+ int width, height;
+
+ dev_dbg(inst->dev->dev,
+ "%s: fourcc: %u width: %u height: %u nm planes: %u colorspace: %u field: %u\n",
+ __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.num_planes, f->fmt.pix_mp.colorspace, f->fmt.pix_mp.field);
+
+ vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, dec_fmt_list[VPU_FMT_TYPE_RAW]);
+ if (!vpu_fmt) {
+ width = inst->dst_fmt.width;
+ height = inst->dst_fmt.height;
+ f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat;
+ f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes;
+ } else {
+ const struct v4l2_format_info *info = v4l2_format_info(vpu_fmt->v4l2_pix_fmt);
+
+ width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width);
+ height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height);
+ f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt;
+ f->fmt.pix_mp.num_planes = info->mem_planes;
+ }
+
+ if (p_dec_info->initial_info_obtained) {
+ width = inst->dst_fmt.width;
+ height = inst->dst_fmt.height;
+ }
+
+ wave5_update_pix_fmt(&f->fmt.pix_mp, width, height);
+ f->fmt.pix_mp.flags = 0;
+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ f->fmt.pix_mp.colorspace = inst->colorspace;
+ f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
+ f->fmt.pix_mp.quantization = inst->quantization;
+ f->fmt.pix_mp.xfer_func = inst->xfer_func;
+
+ return 0;
+}
+
+static int wave5_vpu_dec_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ int i, ret;
+
+ dev_dbg(inst->dev->dev,
+ "%s: fourcc: %u width: %u height: %u num_planes: %u colorspace: %u field: %u\n",
+ __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.num_planes, f->fmt.pix_mp.colorspace, f->fmt.pix_mp.field);
+
+ ret = wave5_vpu_dec_try_fmt_cap(file, fh, f);
+ if (ret)
+ return ret;
+
+ inst->dst_fmt.width = f->fmt.pix_mp.width;
+ inst->dst_fmt.height = f->fmt.pix_mp.height;
+ inst->dst_fmt.pixelformat = f->fmt.pix_mp.pixelformat;
+ inst->dst_fmt.field = f->fmt.pix_mp.field;
+ inst->dst_fmt.flags = f->fmt.pix_mp.flags;
+ inst->dst_fmt.num_planes = f->fmt.pix_mp.num_planes;
+ for (i = 0; i < inst->dst_fmt.num_planes; i++) {
+ inst->dst_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline;
+ inst->dst_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
+
+ if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
+ inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12M) {
+ inst->cbcr_interleave = true;
+ inst->nv21 = false;
+ inst->output_format = FORMAT_420;
+ } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
+ inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV21M) {
+ inst->cbcr_interleave = true;
+ inst->nv21 = true;
+ inst->output_format = FORMAT_420;
+ } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV16 ||
+ inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV16M) {
+ inst->cbcr_interleave = true;
+ inst->nv21 = false;
+ inst->output_format = FORMAT_422;
+ } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV61 ||
+ inst->dst_fmt.pixelformat == V4L2_PIX_FMT_NV61M) {
+ inst->cbcr_interleave = true;
+ inst->nv21 = true;
+ inst->output_format = FORMAT_422;
+ } else if (inst->dst_fmt.pixelformat == V4L2_PIX_FMT_YUV422P ||
+ inst->dst_fmt.pixelformat == V4L2_PIX_FMT_YUV422M) {
+ inst->cbcr_interleave = false;
+ inst->nv21 = false;
+ inst->output_format = FORMAT_422;
+ } else {
+ inst->cbcr_interleave = false;
+ inst->nv21 = false;
+ inst->output_format = FORMAT_420;
+ }
+
+ return 0;
+}
+
+static int wave5_vpu_dec_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ int i;
+
+ f->fmt.pix_mp.width = inst->dst_fmt.width;
+ f->fmt.pix_mp.height = inst->dst_fmt.height;
+ f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat;
+ f->fmt.pix_mp.field = inst->dst_fmt.field;
+ f->fmt.pix_mp.flags = inst->dst_fmt.flags;
+ f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes;
+ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
+ f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->dst_fmt.plane_fmt[i].bytesperline;
+ f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->dst_fmt.plane_fmt[i].sizeimage;
+ }
+
+ f->fmt.pix_mp.colorspace = inst->colorspace;
+ f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
+ f->fmt.pix_mp.quantization = inst->quantization;
+ f->fmt.pix_mp.xfer_func = inst->xfer_func;
+
+ return 0;
+}
+
+static int wave5_vpu_dec_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
+
+ dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index);
+
+ vpu_fmt = wave5_find_vpu_fmt_by_idx(f->index, dec_fmt_list[VPU_FMT_TYPE_CODEC]);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ f->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION | V4L2_FMT_FLAG_COMPRESSED;
+
+ return 0;
+}
+
+static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
+
+ dev_dbg(inst->dev->dev,
+ "%s: fourcc: %u width: %u height: %u num_planes: %u colorspace: %u field: %u\n",
+ __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.num_planes, f->fmt.pix_mp.colorspace, f->fmt.pix_mp.field);
+
+ vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, dec_fmt_list[VPU_FMT_TYPE_CODEC]);
+ if (!vpu_fmt) {
+ f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat;
+ f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes;
+ wave5_update_pix_fmt(&f->fmt.pix_mp, inst->src_fmt.width, inst->src_fmt.height);
+ } else {
+ int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width);
+ int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height);
+
+ f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt;
+ f->fmt.pix_mp.num_planes = 1;
+ wave5_update_pix_fmt(&f->fmt.pix_mp, width, height);
+ }
+
+ f->fmt.pix_mp.flags = 0;
+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ int i, ret;
+
+ dev_dbg(inst->dev->dev,
+ "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n",
+ __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field);
+
+ ret = wave5_vpu_dec_try_fmt_out(file, fh, f);
+ if (ret)
+ return ret;
+
+ inst->std = wave5_to_vpu_std(f->fmt.pix_mp.pixelformat, inst->type);
+ if (inst->std == STD_UNKNOWN) {
+ dev_warn(inst->dev->dev, "unsupported pixelformat: %.4s\n",
+ (char *)&f->fmt.pix_mp.pixelformat);
+ return -EINVAL;
+ }
+
+ inst->src_fmt.width = f->fmt.pix_mp.width;
+ inst->src_fmt.height = f->fmt.pix_mp.height;
+ inst->src_fmt.pixelformat = f->fmt.pix_mp.pixelformat;
+ inst->src_fmt.field = f->fmt.pix_mp.field;
+ inst->src_fmt.flags = f->fmt.pix_mp.flags;
+ inst->src_fmt.num_planes = f->fmt.pix_mp.num_planes;
+ for (i = 0; i < inst->src_fmt.num_planes; i++) {
+ inst->src_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline;
+ inst->src_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
+
+ inst->colorspace = f->fmt.pix_mp.colorspace;
+ inst->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+ inst->quantization = f->fmt.pix_mp.quantization;
+ inst->xfer_func = f->fmt.pix_mp.xfer_func;
+
+ wave5_update_pix_fmt(&inst->dst_fmt, f->fmt.pix_mp.width, f->fmt.pix_mp.height);
+
+ return 0;
+}
+
+static int wave5_vpu_dec_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+
+ dev_dbg(inst->dev->dev, "%s: type: %u | target: %u\n", __func__, s->type, s->target);
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ case V4L2_SEL_TGT_COMPOSE_PADDED:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = inst->dst_fmt.width;
+ s->r.height = inst->dst_fmt.height;
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ s->r.left = 0;
+ s->r.top = 0;
+ if (inst->state > VPU_INST_STATE_OPEN) {
+ s->r = inst->conf_win;
+ } else {
+ s->r.width = inst->src_fmt.width;
+ s->r.height = inst->src_fmt.height;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wave5_vpu_dec_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (s->target != V4L2_SEL_TGT_COMPOSE)
+ return -EINVAL;
+
+ dev_dbg(inst->dev->dev, "V4L2_SEL_TGT_COMPOSE w: %u h: %u\n",
+ s->r.width, s->r.height);
+
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = inst->dst_fmt.width;
+ s->r.height = inst->dst_fmt.height;
+
+ return 0;
+}
+
+static int wave5_vpu_dec_stop(struct vpu_instance *inst)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+
+ spin_lock_irqsave(&inst->state_spinlock, flags);
+
+ if (m2m_ctx->is_draining) {
+ ret = -EBUSY;
+ goto unlock_and_return;
+ }
+
+ if (inst->state != VPU_INST_STATE_NONE) {
+ /*
+ * Temporarily release the state_spinlock so that subsequent
+ * calls do not block on a mutex while inside this spinlock.
+ */
+ spin_unlock_irqrestore(&inst->state_spinlock, flags);
+ ret = wave5_vpu_dec_set_eos_on_firmware(inst);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&inst->state_spinlock, flags);
+ /*
+ * TODO eliminate this check by using a separate check for
+ * draining triggered by a resolution change.
+ */
+ if (m2m_ctx->is_draining) {
+ ret = -EBUSY;
+ goto unlock_and_return;
+ }
+ }
+
+ /*
+ * Used to remember the EOS state after the streamoff/on transition on
+ * the capture queue.
+ */
+ inst->eos = true;
+
+ if (m2m_ctx->has_stopped)
+ goto unlock_and_return;
+
+ m2m_ctx->last_src_buf = v4l2_m2m_last_src_buf(m2m_ctx);
+ m2m_ctx->is_draining = true;
+
+ /*
+ * Deferred to device run in case it wasn't in the ring buffer
+ * yet. In other case, we have to send the EOS signal to the
+ * firmware so that any pending PIC_RUN ends without new
+ * bitstream buffer.
+ */
+ if (m2m_ctx->last_src_buf)
+ goto unlock_and_return;
+
+ if (inst->state == VPU_INST_STATE_NONE) {
+ send_eos_event(inst);
+ flag_last_buffer_done(inst);
+ }
+
+unlock_and_return:
+ spin_unlock_irqrestore(&inst->state_spinlock, flags);
+ return ret;
+}
+
+static int wave5_vpu_dec_start(struct vpu_instance *inst)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx);
+
+ spin_lock_irqsave(&inst->state_spinlock, flags);
+
+ if (m2m_ctx->is_draining) {
+ ret = -EBUSY;
+ goto unlock_and_return;
+ }
+
+ if (m2m_ctx->has_stopped)
+ m2m_ctx->has_stopped = false;
+
+ vb2_clear_last_buffer_dequeued(dst_vq);
+ inst->eos = false;
+
+unlock_and_return:
+ spin_unlock_irqrestore(&inst->state_spinlock, flags);
+ return ret;
+}
+
+static int wave5_vpu_dec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ int ret;
+
+ dev_dbg(inst->dev->dev, "decoder command: %u\n", dc->cmd);
+
+ ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
+ if (ret)
+ return ret;
+
+ switch (dc->cmd) {
+ case V4L2_DEC_CMD_STOP:
+ ret = wave5_vpu_dec_stop(inst);
+ /* Just in case we don't have anything to decode anymore */
+ v4l2_m2m_try_schedule(m2m_ctx);
+ break;
+ case V4L2_DEC_CMD_START:
+ ret = wave5_vpu_dec_start(inst);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ioctl_ops wave5_vpu_dec_ioctl_ops = {
+ .vidioc_querycap = wave5_vpu_dec_querycap,
+ .vidioc_enum_framesizes = wave5_vpu_dec_enum_framesizes,
+
+ .vidioc_enum_fmt_vid_cap = wave5_vpu_dec_enum_fmt_cap,
+ .vidioc_s_fmt_vid_cap_mplane = wave5_vpu_dec_s_fmt_cap,
+ .vidioc_g_fmt_vid_cap_mplane = wave5_vpu_dec_g_fmt_cap,
+ .vidioc_try_fmt_vid_cap_mplane = wave5_vpu_dec_try_fmt_cap,
+
+ .vidioc_enum_fmt_vid_out = wave5_vpu_dec_enum_fmt_out,
+ .vidioc_s_fmt_vid_out_mplane = wave5_vpu_dec_s_fmt_out,
+ .vidioc_g_fmt_vid_out_mplane = wave5_vpu_g_fmt_out,
+ .vidioc_try_fmt_vid_out_mplane = wave5_vpu_dec_try_fmt_out,
+
+ .vidioc_g_selection = wave5_vpu_dec_g_selection,
+ .vidioc_s_selection = wave5_vpu_dec_s_selection,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ /*
+ * Firmware does not support CREATE_BUFS for CAPTURE queue. Since
+ * there is no immediate use-case for supporting CREATE_BUFS on
+ * just the OUTPUT queue, disable CREATE_BUFS altogether.
+ */
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
+ .vidioc_decoder_cmd = wave5_vpu_dec_decoder_cmd,
+
+ .vidioc_subscribe_event = wave5_vpu_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static int wave5_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_pix_format_mplane inst_format =
+ (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt;
+
+ dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n", __func__,
+ *num_buffers, *num_planes, q->type);
+
+ *num_planes = inst_format.num_planes;
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ sizes[0] = inst_format.plane_fmt[0].sizeimage;
+ dev_dbg(inst->dev->dev, "%s: size[0]: %u\n", __func__, sizes[0]);
+ } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (*num_buffers < inst->fbc_buf_count)
+ *num_buffers = inst->fbc_buf_count;
+
+ if (*num_planes == 1) {
+ if (inst->output_format == FORMAT_422)
+ sizes[0] = inst_format.width * inst_format.height * 2;
+ else
+ sizes[0] = inst_format.width * inst_format.height * 3 / 2;
+ dev_dbg(inst->dev->dev, "%s: size[0]: %u\n", __func__, sizes[0]);
+ } else if (*num_planes == 2) {
+ sizes[0] = inst_format.width * inst_format.height;
+ if (inst->output_format == FORMAT_422)
+ sizes[1] = inst_format.width * inst_format.height;
+ else
+ sizes[1] = inst_format.width * inst_format.height / 2;
+ dev_dbg(inst->dev->dev, "%s: size[0]: %u | size[1]: %u\n",
+ __func__, sizes[0], sizes[1]);
+ } else if (*num_planes == 3) {
+ sizes[0] = inst_format.width * inst_format.height;
+ if (inst->output_format == FORMAT_422) {
+ sizes[1] = inst_format.width * inst_format.height / 2;
+ sizes[2] = inst_format.width * inst_format.height / 2;
+ } else {
+ sizes[1] = inst_format.width * inst_format.height / 4;
+ sizes[2] = inst_format.width * inst_format.height / 4;
+ }
+ dev_dbg(inst->dev->dev, "%s: size[0]: %u | size[1]: %u | size[2]: %u\n",
+ __func__, sizes[0], sizes[1], sizes[2]);
+ }
+ }
+
+ return 0;
+}
+
+static int wave5_prepare_fb(struct vpu_instance *inst)
+{
+ int linear_num;
+ int non_linear_num;
+ int fb_stride = 0, fb_height = 0;
+ int luma_size, chroma_size;
+ int ret, i;
+ struct v4l2_m2m_buffer *buf, *n;
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+
+ linear_num = v4l2_m2m_num_dst_bufs_ready(m2m_ctx);
+ non_linear_num = inst->fbc_buf_count;
+
+ for (i = 0; i < non_linear_num; i++) {
+ struct frame_buffer *frame = &inst->frame_buf[i];
+ struct vpu_buf *vframe = &inst->frame_vbuf[i];
+
+ fb_stride = inst->dst_fmt.width;
+ fb_height = ALIGN(inst->dst_fmt.height, 32);
+ luma_size = fb_stride * fb_height;
+
+ chroma_size = ALIGN(fb_stride / 2, 16) * fb_height;
+
+ if (vframe->size == (luma_size + chroma_size))
+ continue;
+
+ if (vframe->size)
+ wave5_vpu_dec_reset_framebuffer(inst, i);
+
+ vframe->size = luma_size + chroma_size;
+ ret = wave5_vdi_allocate_dma_memory(inst->dev, vframe);
+ if (ret) {
+ dev_dbg(inst->dev->dev,
+ "%s: Allocating FBC buf of size %zu, fail: %d\n",
+ __func__, vframe->size, ret);
+ return ret;
+ }
+
+ frame->buf_y = vframe->daddr;
+ frame->buf_cb = vframe->daddr + luma_size;
+ frame->buf_cr = (dma_addr_t)-1;
+ frame->size = vframe->size;
+ frame->width = inst->src_fmt.width;
+ frame->stride = fb_stride;
+ frame->map_type = COMPRESSED_FRAME_MAP;
+ frame->update_fb_info = true;
+ }
+ /* In case the count has reduced, clean up leftover framebuffer memory */
+ for (i = non_linear_num; i < MAX_REG_FRAME; i++) {
+ ret = wave5_vpu_dec_reset_framebuffer(inst, i);
+ if (ret)
+ break;
+ }
+
+ for (i = 0; i < linear_num; i++) {
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx);
+ struct vb2_buffer *vb = vb2_get_buffer(dst_vq, i);
+ struct frame_buffer *frame = &inst->frame_buf[non_linear_num + i];
+ dma_addr_t buf_addr_y = 0, buf_addr_cb = 0, buf_addr_cr = 0;
+ u32 buf_size = 0;
+ u32 fb_stride = inst->dst_fmt.width;
+ u32 luma_size = fb_stride * inst->dst_fmt.height;
+ u32 chroma_size;
+
+ if (inst->output_format == FORMAT_422)
+ chroma_size = fb_stride * inst->dst_fmt.height / 2;
+ else
+ chroma_size = fb_stride * inst->dst_fmt.height / 4;
+
+ if (inst->dst_fmt.num_planes == 1) {
+ buf_size = vb2_plane_size(vb, 0);
+ buf_addr_y = vb2_dma_contig_plane_dma_addr(vb, 0);
+ buf_addr_cb = buf_addr_y + luma_size;
+ buf_addr_cr = buf_addr_cb + chroma_size;
+ } else if (inst->dst_fmt.num_planes == 2) {
+ buf_size = vb2_plane_size(vb, 0) +
+ vb2_plane_size(vb, 1);
+ buf_addr_y = vb2_dma_contig_plane_dma_addr(vb, 0);
+ buf_addr_cb = vb2_dma_contig_plane_dma_addr(vb, 1);
+ buf_addr_cr = buf_addr_cb + chroma_size;
+ } else if (inst->dst_fmt.num_planes == 3) {
+ buf_size = vb2_plane_size(vb, 0) +
+ vb2_plane_size(vb, 1) +
+ vb2_plane_size(vb, 2);
+ buf_addr_y = vb2_dma_contig_plane_dma_addr(vb, 0);
+ buf_addr_cb = vb2_dma_contig_plane_dma_addr(vb, 1);
+ buf_addr_cr = vb2_dma_contig_plane_dma_addr(vb, 2);
+ }
+
+ frame->buf_y = buf_addr_y;
+ frame->buf_cb = buf_addr_cb;
+ frame->buf_cr = buf_addr_cr;
+ frame->size = buf_size;
+ frame->width = inst->src_fmt.width;
+ frame->stride = fb_stride;
+ frame->map_type = LINEAR_FRAME_MAP;
+ frame->update_fb_info = true;
+ }
+
+ ret = wave5_vpu_dec_register_frame_buffer_ex(inst, non_linear_num, linear_num,
+ fb_stride, inst->dst_fmt.height);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: vpu_dec_register_frame_buffer_ex fail: %d",
+ __func__, ret);
+ return ret;
+ }
+
+ /*
+ * Mark all frame buffers as out of display, to avoid using them before
+ * the application have them queued.
+ */
+ for (i = 0; i < v4l2_m2m_num_dst_bufs_ready(m2m_ctx); i++) {
+ ret = wave5_vpu_dec_set_disp_flag(inst, i);
+ if (ret) {
+ dev_dbg(inst->dev->dev,
+ "%s: Setting display flag of buf index: %u, fail: %d\n",
+ __func__, i, ret);
+ }
+ }
+
+ v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) {
+ struct vb2_v4l2_buffer *vbuf = &buf->vb;
+
+ ret = wave5_vpu_dec_clr_disp_flag(inst, vbuf->vb2_buf.index);
+ if (ret)
+ dev_dbg(inst->dev->dev,
+ "%s: Clearing display flag of buf index: %u, fail: %d\n",
+ __func__, i, ret);
+ }
+
+ return 0;
+}
+
+static int write_to_ringbuffer(struct vpu_instance *inst, void *buffer, size_t buffer_size,
+ struct vpu_buf *ring_buffer, dma_addr_t wr_ptr)
+{
+ size_t size;
+ size_t offset = wr_ptr - ring_buffer->daddr;
+ int ret;
+
+ if (wr_ptr + buffer_size > ring_buffer->daddr + ring_buffer->size) {
+ size = ring_buffer->daddr + ring_buffer->size - wr_ptr;
+ ret = wave5_vdi_write_memory(inst->dev, ring_buffer, offset, (u8 *)buffer, size);
+ if (ret < 0)
+ return ret;
+
+ ret = wave5_vdi_write_memory(inst->dev, ring_buffer, 0, (u8 *)buffer + size,
+ buffer_size - size);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = wave5_vdi_write_memory(inst->dev, ring_buffer, offset, (u8 *)buffer,
+ buffer_size);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fill_ringbuffer(struct vpu_instance *inst)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct v4l2_m2m_buffer *buf, *n;
+ int ret;
+
+ if (m2m_ctx->last_src_buf) {
+ struct vpu_src_buffer *vpu_buf = wave5_to_vpu_src_buf(m2m_ctx->last_src_buf);
+
+ if (vpu_buf->consumed) {
+ dev_dbg(inst->dev->dev, "last src buffer already written\n");
+ return 0;
+ }
+ }
+
+ v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
+ struct vb2_v4l2_buffer *vbuf = &buf->vb;
+ struct vpu_src_buffer *vpu_buf = wave5_to_vpu_src_buf(vbuf);
+ struct vpu_buf *ring_buffer = &inst->bitstream_vbuf;
+ size_t src_size = vb2_get_plane_payload(&vbuf->vb2_buf, 0);
+ void *src_buf = vb2_plane_vaddr(&vbuf->vb2_buf, 0);
+ dma_addr_t rd_ptr = 0;
+ dma_addr_t wr_ptr = 0;
+ size_t remain_size = 0;
+
+ if (vpu_buf->consumed) {
+ dev_dbg(inst->dev->dev, "already copied src buf (%u) to the ring buffer\n",
+ vbuf->vb2_buf.index);
+ continue;
+ }
+
+ if (!src_buf) {
+ dev_dbg(inst->dev->dev,
+ "%s: Acquiring kernel pointer to src buf (%u), fail\n",
+ __func__, vbuf->vb2_buf.index);
+ break;
+ }
+
+ ret = wave5_vpu_dec_get_bitstream_buffer(inst, &rd_ptr, &wr_ptr, &remain_size);
+ if (ret) {
+ /* Unable to acquire the mutex */
+ dev_err(inst->dev->dev, "Getting the bitstream buffer, fail: %d\n",
+ ret);
+ return ret;
+ }
+
+ dev_dbg(inst->dev->dev, "%s: rd_ptr %pad wr_ptr %pad", __func__, &rd_ptr, &wr_ptr);
+
+ if (remain_size < src_size) {
+ dev_dbg(inst->dev->dev,
+ "%s: remaining size: %zu < source size: %zu for src buf (%u)\n",
+ __func__, remain_size, src_size, vbuf->vb2_buf.index);
+ break;
+ }
+
+ ret = write_to_ringbuffer(inst, src_buf, src_size, ring_buffer, wr_ptr);
+ if (ret) {
+ dev_err(inst->dev->dev, "Write src buf (%u) to ring buffer, fail: %d\n",
+ vbuf->vb2_buf.index, ret);
+ return ret;
+ }
+
+ ret = wave5_vpu_dec_update_bitstream_buffer(inst, src_size);
+ if (ret) {
+ dev_dbg(inst->dev->dev,
+ "update_bitstream_buffer fail: %d for src buf (%u)\n",
+ ret, vbuf->vb2_buf.index);
+ break;
+ }
+
+ vpu_buf->consumed = true;
+
+ /* Don't write buffers passed the last one while draining. */
+ if (v4l2_m2m_is_last_draining_src_buf(m2m_ctx, vbuf)) {
+ dev_dbg(inst->dev->dev, "last src buffer written to the ring buffer\n");
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void wave5_vpu_dec_buf_queue_src(struct vb2_buffer *vb)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vpu_src_buffer *vpu_buf = wave5_to_vpu_src_buf(vbuf);
+
+ vpu_buf->consumed = false;
+ vbuf->sequence = inst->queued_src_buf_num++;
+
+ v4l2_m2m_buf_queue(m2m_ctx, vbuf);
+}
+
+static void wave5_vpu_dec_buf_queue_dst(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+
+ vbuf->sequence = inst->queued_dst_buf_num++;
+
+ if (inst->state == VPU_INST_STATE_PIC_RUN) {
+ struct vpu_dst_buffer *vpu_buf = wave5_to_vpu_dst_buf(vbuf);
+ int ret;
+
+ /*
+ * The buffer is already registered just clear the display flag
+ * to let the firmware know it can be used.
+ */
+ vpu_buf->display = false;
+ ret = wave5_vpu_dec_clr_disp_flag(inst, vb->index);
+ if (ret) {
+ dev_dbg(inst->dev->dev,
+ "%s: Clearing the display flag of buffer index: %u, fail: %d\n",
+ __func__, vb->index, ret);
+ }
+ }
+
+ if (vb2_is_streaming(vb->vb2_queue) && v4l2_m2m_dst_buf_is_last(m2m_ctx)) {
+ unsigned int i;
+
+ for (i = 0; i < vb->num_planes; i++)
+ vb2_set_plane_payload(vb, i, 0);
+
+ vbuf->field = V4L2_FIELD_NONE;
+
+ send_eos_event(inst);
+ v4l2_m2m_last_buffer_done(m2m_ctx, vbuf);
+ } else {
+ v4l2_m2m_buf_queue(m2m_ctx, vbuf);
+ }
+}
+
+static void wave5_vpu_dec_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
+
+ dev_dbg(inst->dev->dev, "%s: type: %4u index: %4u size: ([0]=%4lu, [1]=%4lu, [2]=%4lu)\n",
+ __func__, vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0),
+ vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2));
+
+ if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ wave5_vpu_dec_buf_queue_src(vb);
+ else if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ wave5_vpu_dec_buf_queue_dst(vb);
+}
+
+static int wave5_vpu_dec_allocate_ring_buffer(struct vpu_instance *inst)
+{
+ int ret;
+ struct vpu_buf *ring_buffer = &inst->bitstream_vbuf;
+
+ ring_buffer->size = ALIGN(inst->src_fmt.plane_fmt[0].sizeimage, 1024) * 4;
+ ret = wave5_vdi_allocate_dma_memory(inst->dev, ring_buffer);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: allocate ring buffer of size %zu fail: %d\n",
+ __func__, ring_buffer->size, ret);
+ return ret;
+ }
+
+ inst->last_rd_ptr = ring_buffer->daddr;
+
+ return 0;
+}
+
+static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ int ret = 0;
+
+ dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type);
+
+ v4l2_m2m_update_start_streaming_state(m2m_ctx, q);
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && inst->state == VPU_INST_STATE_NONE) {
+ struct dec_open_param open_param;
+
+ memset(&open_param, 0, sizeof(struct dec_open_param));
+
+ ret = wave5_vpu_dec_allocate_ring_buffer(inst);
+ if (ret)
+ goto return_buffers;
+
+ open_param.bitstream_buffer = inst->bitstream_vbuf.daddr;
+ open_param.bitstream_buffer_size = inst->bitstream_vbuf.size;
+
+ ret = wave5_vpu_dec_open(inst, &open_param);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: decoder opening, fail: %d\n",
+ __func__, ret);
+ goto free_bitstream_vbuf;
+ }
+
+ ret = switch_state(inst, VPU_INST_STATE_OPEN);
+ if (ret)
+ goto free_bitstream_vbuf;
+ } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ struct dec_initial_info *initial_info =
+ &inst->codec_info->dec_info.initial_info;
+
+ if (inst->state == VPU_INST_STATE_STOP)
+ ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ);
+ if (ret)
+ goto return_buffers;
+
+ if (inst->state == VPU_INST_STATE_INIT_SEQ) {
+ if (initial_info->luma_bitdepth != 8) {
+ dev_info(inst->dev->dev, "%s: no support for %d bit depth",
+ __func__, initial_info->luma_bitdepth);
+ ret = -EINVAL;
+ goto return_buffers;
+ }
+ }
+ }
+
+ return ret;
+
+free_bitstream_vbuf:
+ wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf);
+return_buffers:
+ wave5_return_bufs(q, VB2_BUF_STATE_QUEUED);
+ return ret;
+}
+
+static int streamoff_output(struct vb2_queue *q)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct vb2_v4l2_buffer *buf;
+ int ret;
+ dma_addr_t new_rd_ptr;
+
+ while ((buf = v4l2_m2m_src_buf_remove(m2m_ctx))) {
+ dev_dbg(inst->dev->dev, "%s: (Multiplanar) buf type %4u | index %4u\n",
+ __func__, buf->vb2_buf.type, buf->vb2_buf.index);
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+ }
+
+ ret = wave5_vpu_flush_instance(inst);
+ if (ret)
+ return ret;
+
+ /* Reset the ring buffer information */
+ new_rd_ptr = wave5_vpu_dec_get_rd_ptr(inst);
+ inst->last_rd_ptr = new_rd_ptr;
+ inst->codec_info->dec_info.stream_rd_ptr = new_rd_ptr;
+ inst->codec_info->dec_info.stream_wr_ptr = new_rd_ptr;
+
+ if (v4l2_m2m_has_stopped(m2m_ctx))
+ send_eos_event(inst);
+
+ /* streamoff on output cancels any draining operation */
+ inst->eos = false;
+
+ return 0;
+}
+
+static int streamoff_capture(struct vb2_queue *q)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct vb2_v4l2_buffer *buf;
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < v4l2_m2m_num_dst_bufs_ready(m2m_ctx); i++) {
+ ret = wave5_vpu_dec_set_disp_flag(inst, i);
+ if (ret)
+ dev_dbg(inst->dev->dev,
+ "%s: Setting display flag of buf index: %u, fail: %d\n",
+ __func__, i, ret);
+ }
+
+ while ((buf = v4l2_m2m_dst_buf_remove(m2m_ctx))) {
+ u32 plane;
+
+ dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n",
+ __func__, buf->vb2_buf.type, buf->vb2_buf.index);
+
+ for (plane = 0; plane < inst->dst_fmt.num_planes; plane++)
+ vb2_set_plane_payload(&buf->vb2_buf, plane, 0);
+
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+ }
+
+ if (inst->needs_reallocation) {
+ wave5_vpu_dec_give_command(inst, DEC_RESET_FRAMEBUF_INFO, NULL);
+ inst->needs_reallocation = false;
+ }
+
+ if (v4l2_m2m_has_stopped(m2m_ctx)) {
+ ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ bool check_cmd = TRUE;
+
+ dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type);
+
+ while (check_cmd) {
+ struct queue_status_info q_status;
+ struct dec_output_info dec_output_info;
+
+ wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status);
+
+ if (q_status.report_queue_count == 0)
+ break;
+
+ if (wave5_vpu_wait_interrupt(inst, VPU_DEC_TIMEOUT) < 0)
+ break;
+
+ if (wave5_vpu_dec_get_output_info(inst, &dec_output_info))
+ dev_dbg(inst->dev->dev, "Getting decoding results from fw, fail\n");
+ }
+
+ v4l2_m2m_update_stop_streaming_state(m2m_ctx, q);
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ streamoff_output(q);
+ else
+ streamoff_capture(q);
+}
+
+static const struct vb2_ops wave5_vpu_dec_vb2_ops = {
+ .queue_setup = wave5_vpu_dec_queue_setup,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .buf_queue = wave5_vpu_dec_buf_queue,
+ .start_streaming = wave5_vpu_dec_start_streaming,
+ .stop_streaming = wave5_vpu_dec_stop_streaming,
+};
+
+static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt,
+ struct v4l2_pix_format_mplane *dst_fmt)
+{
+ unsigned int dst_pix_fmt = dec_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt;
+ const struct v4l2_format_info *dst_fmt_info = v4l2_format_info(dst_pix_fmt);
+
+ src_fmt->pixelformat = dec_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt;
+ src_fmt->field = V4L2_FIELD_NONE;
+ src_fmt->flags = 0;
+ src_fmt->num_planes = 1;
+ wave5_update_pix_fmt(src_fmt, 720, 480);
+
+ dst_fmt->pixelformat = dst_pix_fmt;
+ dst_fmt->field = V4L2_FIELD_NONE;
+ dst_fmt->flags = 0;
+ dst_fmt->num_planes = dst_fmt_info->mem_planes;
+ wave5_update_pix_fmt(dst_fmt, 736, 480);
+}
+
+static int wave5_vpu_dec_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+ return wave5_vpu_queue_init(priv, src_vq, dst_vq, &wave5_vpu_dec_vb2_ops);
+}
+
+static const struct vpu_instance_ops wave5_vpu_dec_inst_ops = {
+ .finish_process = wave5_vpu_dec_finish_decode,
+};
+
+static int initialize_sequence(struct vpu_instance *inst)
+{
+ struct dec_initial_info initial_info;
+ int ret = 0;
+
+ memset(&initial_info, 0, sizeof(struct dec_initial_info));
+
+ ret = wave5_vpu_dec_issue_seq_init(inst);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: wave5_vpu_dec_issue_seq_init, fail: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (wave5_vpu_wait_interrupt(inst, VPU_DEC_TIMEOUT) < 0)
+ dev_dbg(inst->dev->dev, "%s: failed to call vpu_wait_interrupt()\n", __func__);
+
+ ret = wave5_vpu_dec_complete_seq_init(inst, &initial_info);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: vpu_dec_complete_seq_init, fail: %d, reason: %u\n",
+ __func__, ret, initial_info.seq_init_err_reason);
+ wave5_handle_src_buffer(inst, initial_info.rd_ptr);
+ return ret;
+ }
+
+ handle_dynamic_resolution_change(inst);
+
+ return 0;
+}
+
+static bool wave5_is_draining_or_eos(struct vpu_instance *inst)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+
+ lockdep_assert_held(&inst->state_spinlock);
+ return m2m_ctx->is_draining || inst->eos;
+}
+
+static void wave5_vpu_dec_device_run(void *priv)
+{
+ struct vpu_instance *inst = priv;
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct queue_status_info q_status;
+ u32 fail_res = 0;
+ int ret = 0;
+
+ dev_dbg(inst->dev->dev, "%s: Fill the ring buffer with new bitstream data", __func__);
+
+ ret = fill_ringbuffer(inst);
+ if (ret) {
+ dev_warn(inst->dev->dev, "Filling ring buffer failed\n");
+ goto finish_job_and_return;
+ }
+
+ switch (inst->state) {
+ case VPU_INST_STATE_OPEN:
+ ret = initialize_sequence(inst);
+ if (ret) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&inst->state_spinlock, flags);
+ if (wave5_is_draining_or_eos(inst) &&
+ wave5_last_src_buffer_consumed(m2m_ctx)) {
+ struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx);
+
+ switch_state(inst, VPU_INST_STATE_STOP);
+
+ if (vb2_is_streaming(dst_vq))
+ send_eos_event(inst);
+ else
+ handle_dynamic_resolution_change(inst);
+
+ flag_last_buffer_done(inst);
+ }
+ spin_unlock_irqrestore(&inst->state_spinlock, flags);
+ } else {
+ switch_state(inst, VPU_INST_STATE_INIT_SEQ);
+ }
+
+ break;
+
+ case VPU_INST_STATE_INIT_SEQ:
+ /*
+ * Do this early, preparing the fb can trigger an IRQ before
+ * we had a chance to switch, which leads to an invalid state
+ * change.
+ */
+ switch_state(inst, VPU_INST_STATE_PIC_RUN);
+
+ /*
+ * During DRC, the picture decoding remains pending, so just leave the job
+ * active until this decode operation completes.
+ */
+ wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status);
+
+ /*
+ * The sequence must be analyzed first to calculate the proper
+ * size of the auxiliary buffers.
+ */
+ ret = wave5_prepare_fb(inst);
+ if (ret) {
+ dev_warn(inst->dev->dev, "Framebuffer preparation, fail: %d\n", ret);
+ switch_state(inst, VPU_INST_STATE_STOP);
+ break;
+ }
+
+ if (q_status.instance_queue_count) {
+ dev_dbg(inst->dev->dev, "%s: leave with active job", __func__);
+ return;
+ }
+
+ fallthrough;
+ case VPU_INST_STATE_PIC_RUN:
+ ret = start_decode(inst, &fail_res);
+ if (ret) {
+ dev_err(inst->dev->dev,
+ "Frame decoding on m2m context (%p), fail: %d (result: %d)\n",
+ m2m_ctx, ret, fail_res);
+ break;
+ }
+ /* Return so that we leave this job active */
+ dev_dbg(inst->dev->dev, "%s: leave with active job", __func__);
+ return;
+ default:
+ WARN(1, "Execution of a job in state %s illegal.\n", state_to_str(inst->state));
+ break;
+ }
+
+finish_job_and_return:
+ dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__);
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
+}
+
+static void wave5_vpu_dec_job_abort(void *priv)
+{
+ struct vpu_instance *inst = priv;
+ int ret;
+
+ ret = switch_state(inst, VPU_INST_STATE_STOP);
+ if (ret)
+ return;
+
+ ret = wave5_vpu_dec_set_eos_on_firmware(inst);
+ if (ret)
+ dev_warn(inst->dev->dev,
+ "Setting EOS for the bitstream, fail: %d\n", ret);
+}
+
+static int wave5_vpu_dec_job_ready(void *priv)
+{
+ struct vpu_instance *inst = priv;
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&inst->state_spinlock, flags);
+
+ switch (inst->state) {
+ case VPU_INST_STATE_NONE:
+ dev_dbg(inst->dev->dev, "Decoder must be open to start queueing M2M jobs!\n");
+ break;
+ case VPU_INST_STATE_OPEN:
+ if (wave5_is_draining_or_eos(inst) || !v4l2_m2m_has_stopped(m2m_ctx) ||
+ v4l2_m2m_num_src_bufs_ready(m2m_ctx) > 0) {
+ ret = 1;
+ break;
+ }
+
+ dev_dbg(inst->dev->dev,
+ "Decoder must be draining or >= 1 OUTPUT queue buffer must be queued!\n");
+ break;
+ case VPU_INST_STATE_INIT_SEQ:
+ case VPU_INST_STATE_PIC_RUN:
+ if (!m2m_ctx->cap_q_ctx.q.streaming) {
+ dev_dbg(inst->dev->dev, "CAPTURE queue must be streaming to queue jobs!\n");
+ break;
+ } else if (v4l2_m2m_num_dst_bufs_ready(m2m_ctx) < (inst->fbc_buf_count - 1)) {
+ dev_dbg(inst->dev->dev,
+ "No capture buffer ready to decode!\n");
+ break;
+ } else if (!wave5_is_draining_or_eos(inst) &&
+ !v4l2_m2m_num_src_bufs_ready(m2m_ctx)) {
+ dev_dbg(inst->dev->dev,
+ "No bitstream data to decode!\n");
+ break;
+ }
+ ret = 1;
+ break;
+ case VPU_INST_STATE_STOP:
+ dev_dbg(inst->dev->dev, "Decoder is stopped, not running.\n");
+ break;
+ }
+
+ spin_unlock_irqrestore(&inst->state_spinlock, flags);
+
+ return ret;
+}
+
+static const struct v4l2_m2m_ops wave5_vpu_dec_m2m_ops = {
+ .device_run = wave5_vpu_dec_device_run,
+ .job_abort = wave5_vpu_dec_job_abort,
+ .job_ready = wave5_vpu_dec_job_ready,
+};
+
+static int wave5_vpu_open_dec(struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ struct vpu_device *dev = video_drvdata(filp);
+ struct vpu_instance *inst = NULL;
+ struct v4l2_m2m_ctx *m2m_ctx;
+ int ret = 0;
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+
+ inst->dev = dev;
+ inst->type = VPU_INST_TYPE_DEC;
+ inst->ops = &wave5_vpu_dec_inst_ops;
+
+ spin_lock_init(&inst->state_spinlock);
+
+ inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL);
+ if (!inst->codec_info)
+ return -ENOMEM;
+
+ v4l2_fh_init(&inst->v4l2_fh, vdev);
+ filp->private_data = &inst->v4l2_fh;
+ v4l2_fh_add(&inst->v4l2_fh);
+
+ INIT_LIST_HEAD(&inst->list);
+ list_add_tail(&inst->list, &dev->instances);
+
+ inst->v4l2_m2m_dev = inst->dev->v4l2_m2m_dec_dev;
+ inst->v4l2_fh.m2m_ctx =
+ v4l2_m2m_ctx_init(inst->v4l2_m2m_dev, inst, wave5_vpu_dec_queue_init);
+ if (IS_ERR(inst->v4l2_fh.m2m_ctx)) {
+ ret = PTR_ERR(inst->v4l2_fh.m2m_ctx);
+ goto cleanup_inst;
+ }
+ m2m_ctx = inst->v4l2_fh.m2m_ctx;
+
+ v4l2_m2m_set_src_buffered(m2m_ctx, true);
+ v4l2_m2m_set_dst_buffered(m2m_ctx, true);
+ /*
+ * We use the M2M job queue to ensure synchronization of steps where
+ * needed, as IOCTLs can occur at anytime and we need to run commands on
+ * the firmware in a specified order.
+ * In order to initialize the sequence on the firmware within an M2M
+ * job, the M2M framework needs to be able to queue jobs before
+ * the CAPTURE queue has been started, because we need the results of the
+ * initialization to properly prepare the CAPTURE queue with the correct
+ * amount of buffers.
+ * By setting ignore_cap_streaming to true the m2m framework will call
+ * job_ready as soon as the OUTPUT queue is streaming, instead of
+ * waiting until both the CAPTURE and OUTPUT queues are streaming.
+ */
+ m2m_ctx->ignore_cap_streaming = true;
+
+ v4l2_ctrl_handler_init(&inst->v4l2_ctrl_hdl, 10);
+ v4l2_ctrl_new_std(&inst->v4l2_ctrl_hdl, NULL,
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 1);
+
+ if (inst->v4l2_ctrl_hdl.error) {
+ ret = -ENODEV;
+ goto cleanup_inst;
+ }
+
+ inst->v4l2_fh.ctrl_handler = &inst->v4l2_ctrl_hdl;
+ v4l2_ctrl_handler_setup(&inst->v4l2_ctrl_hdl);
+
+ wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt);
+ inst->colorspace = V4L2_COLORSPACE_REC709;
+ inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ inst->quantization = V4L2_QUANTIZATION_DEFAULT;
+ inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+ init_completion(&inst->irq_done);
+
+ inst->id = ida_alloc(&inst->dev->inst_ida, GFP_KERNEL);
+ if (inst->id < 0) {
+ dev_warn(inst->dev->dev, "Allocating instance ID, fail: %d\n", inst->id);
+ ret = inst->id;
+ goto cleanup_inst;
+ }
+
+ wave5_vdi_allocate_sram(inst->dev);
+
+ return 0;
+
+cleanup_inst:
+ wave5_cleanup_instance(inst);
+ return ret;
+}
+
+static int wave5_vpu_dec_release(struct file *filp)
+{
+ return wave5_vpu_release_device(filp, wave5_vpu_dec_close, "decoder");
+}
+
+static const struct v4l2_file_operations wave5_vpu_dec_fops = {
+ .owner = THIS_MODULE,
+ .open = wave5_vpu_open_dec,
+ .release = wave5_vpu_dec_release,
+ .unlocked_ioctl = video_ioctl2,
+ .poll = v4l2_m2m_fop_poll,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+int wave5_vpu_dec_register_device(struct vpu_device *dev)
+{
+ struct video_device *vdev_dec;
+ int ret;
+
+ vdev_dec = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_dec), GFP_KERNEL);
+ if (!vdev_dec)
+ return -ENOMEM;
+
+ dev->v4l2_m2m_dec_dev = v4l2_m2m_init(&wave5_vpu_dec_m2m_ops);
+ if (IS_ERR(dev->v4l2_m2m_dec_dev)) {
+ ret = PTR_ERR(dev->v4l2_m2m_dec_dev);
+ dev_err(dev->dev, "v4l2_m2m_init, fail: %d\n", ret);
+ return -EINVAL;
+ }
+
+ dev->video_dev_dec = vdev_dec;
+
+ strscpy(vdev_dec->name, VPU_DEC_DEV_NAME, sizeof(vdev_dec->name));
+ vdev_dec->fops = &wave5_vpu_dec_fops;
+ vdev_dec->ioctl_ops = &wave5_vpu_dec_ioctl_ops;
+ vdev_dec->release = video_device_release_empty;
+ vdev_dec->v4l2_dev = &dev->v4l2_dev;
+ vdev_dec->vfl_dir = VFL_DIR_M2M;
+ vdev_dec->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+ vdev_dec->lock = &dev->dev_lock;
+
+ ret = video_register_device(vdev_dec, VFL_TYPE_VIDEO, -1);
+ if (ret)
+ return ret;
+
+ video_set_drvdata(vdev_dec, dev);
+
+ return 0;
+}
+
+void wave5_vpu_dec_unregister_device(struct vpu_device *dev)
+{
+ video_unregister_device(dev->video_dev_dec);
+ if (dev->v4l2_m2m_dec_dev)
+ v4l2_m2m_release(dev->v4l2_m2m_dec_dev);
+}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
new file mode 100644
index 000000000000..f29cfa3af94a
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
@@ -0,0 +1,1794 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave5 series multi-standard codec IP - encoder interface
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#include "wave5-helper.h"
+
+#define VPU_ENC_DEV_NAME "C&M Wave5 VPU encoder"
+#define VPU_ENC_DRV_NAME "wave5-enc"
+
+static const struct vpu_format enc_fmt_list[FMT_TYPES][MAX_FMTS] = {
+ [VPU_FMT_TYPE_CODEC] = {
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_HEVC,
+ .max_width = W5_MAX_ENC_PIC_WIDTH,
+ .min_width = W5_MIN_ENC_PIC_WIDTH,
+ .max_height = W5_MAX_ENC_PIC_HEIGHT,
+ .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_H264,
+ .max_width = W5_MAX_ENC_PIC_WIDTH,
+ .min_width = W5_MIN_ENC_PIC_WIDTH,
+ .max_height = W5_MAX_ENC_PIC_HEIGHT,
+ .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ },
+ },
+ [VPU_FMT_TYPE_RAW] = {
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420,
+ .max_width = W5_MAX_ENC_PIC_WIDTH,
+ .min_width = W5_MIN_ENC_PIC_WIDTH,
+ .max_height = W5_MAX_ENC_PIC_HEIGHT,
+ .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV12,
+ .max_width = W5_MAX_ENC_PIC_WIDTH,
+ .min_width = W5_MIN_ENC_PIC_WIDTH,
+ .max_height = W5_MAX_ENC_PIC_HEIGHT,
+ .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV21,
+ .max_width = W5_MAX_ENC_PIC_WIDTH,
+ .min_width = W5_MIN_ENC_PIC_WIDTH,
+ .max_height = W5_MAX_ENC_PIC_HEIGHT,
+ .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M,
+ .max_width = W5_MAX_ENC_PIC_WIDTH,
+ .min_width = W5_MIN_ENC_PIC_WIDTH,
+ .max_height = W5_MAX_ENC_PIC_HEIGHT,
+ .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV12M,
+ .max_width = W5_MAX_ENC_PIC_WIDTH,
+ .min_width = W5_MIN_ENC_PIC_WIDTH,
+ .max_height = W5_MAX_ENC_PIC_HEIGHT,
+ .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV21M,
+ .max_width = W5_MAX_ENC_PIC_WIDTH,
+ .min_width = W5_MIN_ENC_PIC_WIDTH,
+ .max_height = W5_MAX_ENC_PIC_HEIGHT,
+ .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ },
+ }
+};
+
+static int switch_state(struct vpu_instance *inst, enum vpu_instance_state state)
+{
+ switch (state) {
+ case VPU_INST_STATE_NONE:
+ goto invalid_state_switch;
+ case VPU_INST_STATE_OPEN:
+ if (inst->state != VPU_INST_STATE_NONE)
+ goto invalid_state_switch;
+ break;
+ case VPU_INST_STATE_INIT_SEQ:
+ if (inst->state != VPU_INST_STATE_OPEN && inst->state != VPU_INST_STATE_STOP)
+ goto invalid_state_switch;
+ break;
+ case VPU_INST_STATE_PIC_RUN:
+ if (inst->state != VPU_INST_STATE_INIT_SEQ)
+ goto invalid_state_switch;
+ break;
+ case VPU_INST_STATE_STOP:
+ break;
+ };
+
+ dev_dbg(inst->dev->dev, "Switch state from %s to %s.\n",
+ state_to_str(inst->state), state_to_str(state));
+ inst->state = state;
+ return 0;
+
+invalid_state_switch:
+ WARN(1, "Invalid state switch from %s to %s.\n",
+ state_to_str(inst->state), state_to_str(state));
+ return -EINVAL;
+}
+
+static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width,
+ unsigned int height)
+{
+ switch (pix_mp->pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ pix_mp->width = width;
+ pix_mp->height = height;
+ pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
+ pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height * 3 / 2;
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ pix_mp->width = width;
+ pix_mp->height = height;
+ pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
+ pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height;
+ pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2;
+ pix_mp->plane_fmt[1].sizeimage = round_up(width, 32) * height / 4;
+ pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2;
+ pix_mp->plane_fmt[2].sizeimage = round_up(width, 32) * height / 4;
+ break;
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV21M:
+ pix_mp->width = width;
+ pix_mp->height = height;
+ pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
+ pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height;
+ pix_mp->plane_fmt[1].bytesperline = round_up(width, 32);
+ pix_mp->plane_fmt[1].sizeimage = round_up(width, 32) * height / 2;
+ break;
+ default:
+ pix_mp->width = width;
+ pix_mp->height = height;
+ pix_mp->plane_fmt[0].bytesperline = 0;
+ pix_mp->plane_fmt[0].sizeimage = width * height / 8 * 3;
+ break;
+ }
+}
+
+static int start_encode(struct vpu_instance *inst, u32 *fail_res)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ int ret;
+ struct vb2_v4l2_buffer *src_buf;
+ struct vb2_v4l2_buffer *dst_buf;
+ struct frame_buffer frame_buf;
+ struct enc_param pic_param;
+ u32 stride = ALIGN(inst->dst_fmt.width, 32);
+ u32 luma_size = (stride * inst->dst_fmt.height);
+ u32 chroma_size = ((stride / 2) * (inst->dst_fmt.height / 2));
+
+ memset(&pic_param, 0, sizeof(struct enc_param));
+ memset(&frame_buf, 0, sizeof(struct frame_buffer));
+
+ dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx);
+ if (!dst_buf) {
+ dev_dbg(inst->dev->dev, "%s: No destination buffer found\n", __func__);
+ return -EAGAIN;
+ }
+
+ pic_param.pic_stream_buffer_addr =
+ vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+ pic_param.pic_stream_buffer_size =
+ vb2_plane_size(&dst_buf->vb2_buf, 0);
+
+ src_buf = v4l2_m2m_next_src_buf(m2m_ctx);
+ if (!src_buf) {
+ dev_dbg(inst->dev->dev, "%s: No source buffer found\n", __func__);
+ if (m2m_ctx->is_draining)
+ pic_param.src_end_flag = 1;
+ else
+ return -EAGAIN;
+ } else {
+ if (inst->src_fmt.num_planes == 1) {
+ frame_buf.buf_y =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+ frame_buf.buf_cb = frame_buf.buf_y + luma_size;
+ frame_buf.buf_cr = frame_buf.buf_cb + chroma_size;
+ } else if (inst->src_fmt.num_planes == 2) {
+ frame_buf.buf_y =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+ frame_buf.buf_cb =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 1);
+ frame_buf.buf_cr = frame_buf.buf_cb + chroma_size;
+ } else if (inst->src_fmt.num_planes == 3) {
+ frame_buf.buf_y =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
+ frame_buf.buf_cb =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 1);
+ frame_buf.buf_cr =
+ vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 2);
+ }
+ frame_buf.stride = stride;
+ pic_param.src_idx = src_buf->vb2_buf.index;
+ }
+
+ pic_param.source_frame = &frame_buf;
+ pic_param.code_option.implicit_header_encode = 1;
+ pic_param.code_option.encode_aud = inst->encode_aud;
+ ret = wave5_vpu_enc_start_one_frame(inst, &pic_param, fail_res);
+ if (ret) {
+ if (*fail_res == WAVE5_SYSERR_QUEUEING_FAIL)
+ return -EINVAL;
+
+ dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame fail: %d\n",
+ __func__, ret);
+ src_buf = v4l2_m2m_src_buf_remove(m2m_ctx);
+ if (!src_buf) {
+ dev_dbg(inst->dev->dev,
+ "%s: Removing src buf failed, the queue is empty\n",
+ __func__);
+ return -EINVAL;
+ }
+ dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx);
+ if (!dst_buf) {
+ dev_dbg(inst->dev->dev,
+ "%s: Removing dst buf failed, the queue is empty\n",
+ __func__);
+ return -EINVAL;
+ }
+ switch_state(inst, VPU_INST_STATE_STOP);
+ dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+ } else {
+ dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_start_one_frame success\n",
+ __func__);
+ /*
+ * Remove the source buffer from the ready-queue now and finish
+ * it in the videobuf2 framework once the index is returned by the
+ * firmware in finish_encode
+ */
+ if (src_buf)
+ v4l2_m2m_src_buf_remove_by_idx(m2m_ctx, src_buf->vb2_buf.index);
+ }
+
+ return 0;
+}
+
+static void wave5_vpu_enc_finish_encode(struct vpu_instance *inst)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ int ret;
+ struct enc_output_info enc_output_info;
+ struct vb2_v4l2_buffer *src_buf = NULL;
+ struct vb2_v4l2_buffer *dst_buf = NULL;
+
+ ret = wave5_vpu_enc_get_output_info(inst, &enc_output_info);
+ if (ret) {
+ dev_dbg(inst->dev->dev,
+ "%s: vpu_enc_get_output_info fail: %d reason: %u | info: %u\n",
+ __func__, ret, enc_output_info.error_reason, enc_output_info.warn_info);
+ return;
+ }
+
+ dev_dbg(inst->dev->dev,
+ "%s: pic_type %i recon_idx %i src_idx %i pic_byte %u pts %llu\n",
+ __func__, enc_output_info.pic_type, enc_output_info.recon_frame_index,
+ enc_output_info.enc_src_idx, enc_output_info.enc_pic_byte, enc_output_info.pts);
+
+ /*
+ * The source buffer will not be found in the ready-queue as it has been
+ * dropped after sending of the encode firmware command, locate it in
+ * the videobuf2 queue directly
+ */
+ if (enc_output_info.enc_src_idx >= 0) {
+ struct vb2_buffer *vb = vb2_get_buffer(v4l2_m2m_get_src_vq(m2m_ctx),
+ enc_output_info.enc_src_idx);
+ if (vb->state != VB2_BUF_STATE_ACTIVE)
+ dev_warn(inst->dev->dev,
+ "%s: encoded buffer (%d) was not in ready queue %i.",
+ __func__, enc_output_info.enc_src_idx, vb->state);
+ else
+ src_buf = to_vb2_v4l2_buffer(vb);
+
+ if (src_buf) {
+ inst->timestamp = src_buf->vb2_buf.timestamp;
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+ } else {
+ dev_warn(inst->dev->dev, "%s: no source buffer with index: %d found\n",
+ __func__, enc_output_info.enc_src_idx);
+ }
+ }
+
+ dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx);
+ if (enc_output_info.recon_frame_index == RECON_IDX_FLAG_ENC_END) {
+ static const struct v4l2_event vpu_event_eos = {
+ .type = V4L2_EVENT_EOS
+ };
+
+ if (!WARN_ON(!dst_buf)) {
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
+ dst_buf->field = V4L2_FIELD_NONE;
+ v4l2_m2m_last_buffer_done(m2m_ctx, dst_buf);
+ }
+
+ v4l2_event_queue_fh(&inst->v4l2_fh, &vpu_event_eos);
+
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
+ } else {
+ if (!dst_buf) {
+ dev_warn(inst->dev->dev, "No bitstream buffer.");
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
+ return;
+ }
+
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, enc_output_info.bitstream_size);
+
+ dst_buf->vb2_buf.timestamp = inst->timestamp;
+ dst_buf->field = V4L2_FIELD_NONE;
+ if (enc_output_info.pic_type == PIC_TYPE_I) {
+ if (enc_output_info.enc_vcl_nut == 19 ||
+ enc_output_info.enc_vcl_nut == 20)
+ dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+ else
+ dst_buf->flags |= V4L2_BUF_FLAG_PFRAME;
+ } else if (enc_output_info.pic_type == PIC_TYPE_P) {
+ dst_buf->flags |= V4L2_BUF_FLAG_PFRAME;
+ } else if (enc_output_info.pic_type == PIC_TYPE_B) {
+ dst_buf->flags |= V4L2_BUF_FLAG_BFRAME;
+ }
+
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+
+ dev_dbg(inst->dev->dev, "%s: frame_cycle %8u\n",
+ __func__, enc_output_info.frame_cycle);
+
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
+ }
+}
+
+static int wave5_vpu_enc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, VPU_ENC_DRV_NAME, sizeof(cap->driver));
+ strscpy(cap->card, VPU_ENC_DRV_NAME, sizeof(cap->card));
+
+ return 0;
+}
+
+static int wave5_vpu_enc_enum_framesizes(struct file *f, void *fh, struct v4l2_frmsizeenum *fsize)
+{
+ const struct vpu_format *vpu_fmt;
+
+ if (fsize->index)
+ return -EINVAL;
+
+ vpu_fmt = wave5_find_vpu_fmt(fsize->pixel_format, enc_fmt_list[VPU_FMT_TYPE_CODEC]);
+ if (!vpu_fmt) {
+ vpu_fmt = wave5_find_vpu_fmt(fsize->pixel_format, enc_fmt_list[VPU_FMT_TYPE_RAW]);
+ if (!vpu_fmt)
+ return -EINVAL;
+ }
+
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ fsize->stepwise.min_width = vpu_fmt->min_width;
+ fsize->stepwise.max_width = vpu_fmt->max_width;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.min_height = vpu_fmt->min_height;
+ fsize->stepwise.max_height = vpu_fmt->max_height;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
+static int wave5_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
+
+ dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index);
+
+ vpu_fmt = wave5_find_vpu_fmt_by_idx(f->index, enc_fmt_list[VPU_FMT_TYPE_CODEC]);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ f->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ f->flags = 0;
+
+ return 0;
+}
+
+static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
+
+ dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n",
+ __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field);
+
+ vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]);
+ if (!vpu_fmt) {
+ f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat;
+ f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes;
+ wave5_update_pix_fmt(&f->fmt.pix_mp, inst->dst_fmt.width, inst->dst_fmt.height);
+ } else {
+ int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width);
+ int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height);
+
+ f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt;
+ f->fmt.pix_mp.num_planes = 1;
+ wave5_update_pix_fmt(&f->fmt.pix_mp, width, height);
+ }
+
+ f->fmt.pix_mp.flags = 0;
+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ f->fmt.pix_mp.colorspace = inst->colorspace;
+ f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
+ f->fmt.pix_mp.quantization = inst->quantization;
+ f->fmt.pix_mp.xfer_func = inst->xfer_func;
+
+ return 0;
+}
+
+static int wave5_vpu_enc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ int i, ret;
+
+ dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n",
+ __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field);
+
+ ret = wave5_vpu_enc_try_fmt_cap(file, fh, f);
+ if (ret)
+ return ret;
+
+ inst->std = wave5_to_vpu_std(f->fmt.pix_mp.pixelformat, inst->type);
+ if (inst->std == STD_UNKNOWN) {
+ dev_warn(inst->dev->dev, "unsupported pixelformat: %.4s\n",
+ (char *)&f->fmt.pix_mp.pixelformat);
+ return -EINVAL;
+ }
+
+ inst->dst_fmt.width = f->fmt.pix_mp.width;
+ inst->dst_fmt.height = f->fmt.pix_mp.height;
+ inst->dst_fmt.pixelformat = f->fmt.pix_mp.pixelformat;
+ inst->dst_fmt.field = f->fmt.pix_mp.field;
+ inst->dst_fmt.flags = f->fmt.pix_mp.flags;
+ inst->dst_fmt.num_planes = f->fmt.pix_mp.num_planes;
+ for (i = 0; i < inst->dst_fmt.num_planes; i++) {
+ inst->dst_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline;
+ inst->dst_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
+
+ return 0;
+}
+
+static int wave5_vpu_enc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ int i;
+
+ f->fmt.pix_mp.width = inst->dst_fmt.width;
+ f->fmt.pix_mp.height = inst->dst_fmt.height;
+ f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat;
+ f->fmt.pix_mp.field = inst->dst_fmt.field;
+ f->fmt.pix_mp.flags = inst->dst_fmt.flags;
+ f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes;
+ for (i = 0; i < f->fmt.pix_mp.num_planes; i++) {
+ f->fmt.pix_mp.plane_fmt[i].bytesperline = inst->dst_fmt.plane_fmt[i].bytesperline;
+ f->fmt.pix_mp.plane_fmt[i].sizeimage = inst->dst_fmt.plane_fmt[i].sizeimage;
+ }
+
+ f->fmt.pix_mp.colorspace = inst->colorspace;
+ f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
+ f->fmt.pix_mp.quantization = inst->quantization;
+ f->fmt.pix_mp.xfer_func = inst->xfer_func;
+
+ return 0;
+}
+
+static int wave5_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
+
+ dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index);
+
+ vpu_fmt = wave5_find_vpu_fmt_by_idx(f->index, enc_fmt_list[VPU_FMT_TYPE_RAW]);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ f->pixelformat = vpu_fmt->v4l2_pix_fmt;
+ f->flags = 0;
+
+ return 0;
+}
+
+static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
+
+ dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n",
+ __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field);
+
+ vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_RAW]);
+ if (!vpu_fmt) {
+ f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat;
+ f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes;
+ wave5_update_pix_fmt(&f->fmt.pix_mp, inst->src_fmt.width, inst->src_fmt.height);
+ } else {
+ int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width);
+ int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height);
+ const struct v4l2_format_info *info = v4l2_format_info(vpu_fmt->v4l2_pix_fmt);
+
+ f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt;
+ f->fmt.pix_mp.num_planes = info->mem_planes;
+ wave5_update_pix_fmt(&f->fmt.pix_mp, width, height);
+ }
+
+ f->fmt.pix_mp.flags = 0;
+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ int i, ret;
+
+ dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n",
+ __func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.num_planes, f->fmt.pix_mp.field);
+
+ ret = wave5_vpu_enc_try_fmt_out(file, fh, f);
+ if (ret)
+ return ret;
+
+ inst->src_fmt.width = f->fmt.pix_mp.width;
+ inst->src_fmt.height = f->fmt.pix_mp.height;
+ inst->src_fmt.pixelformat = f->fmt.pix_mp.pixelformat;
+ inst->src_fmt.field = f->fmt.pix_mp.field;
+ inst->src_fmt.flags = f->fmt.pix_mp.flags;
+ inst->src_fmt.num_planes = f->fmt.pix_mp.num_planes;
+ for (i = 0; i < inst->src_fmt.num_planes; i++) {
+ inst->src_fmt.plane_fmt[i].bytesperline = f->fmt.pix_mp.plane_fmt[i].bytesperline;
+ inst->src_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ }
+
+ if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M) {
+ inst->cbcr_interleave = true;
+ inst->nv21 = false;
+ } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
+ inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M) {
+ inst->cbcr_interleave = true;
+ inst->nv21 = true;
+ } else {
+ inst->cbcr_interleave = false;
+ inst->nv21 = false;
+ }
+
+ inst->colorspace = f->fmt.pix_mp.colorspace;
+ inst->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
+ inst->quantization = f->fmt.pix_mp.quantization;
+ inst->xfer_func = f->fmt.pix_mp.xfer_func;
+
+ wave5_update_pix_fmt(&inst->dst_fmt, f->fmt.pix_mp.width, f->fmt.pix_mp.height);
+
+ return 0;
+}
+
+static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+
+ dev_dbg(inst->dev->dev, "%s: type: %u | target: %u\n", __func__, s->type, s->target);
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = inst->dst_fmt.width;
+ s->r.height = inst->dst_fmt.height;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ if (s->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ dev_dbg(inst->dev->dev, "%s: V4L2_SEL_TGT_CROP width: %u | height: %u\n",
+ __func__, s->r.width, s->r.height);
+
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = inst->src_fmt.width;
+ s->r.height = inst->src_fmt.height;
+
+ return 0;
+}
+
+static int wave5_vpu_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ int ret;
+
+ ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
+ if (ret)
+ return ret;
+
+ if (!wave5_vpu_both_queues_are_streaming(inst))
+ return 0;
+
+ switch (ec->cmd) {
+ case V4L2_ENC_CMD_STOP:
+ if (m2m_ctx->is_draining)
+ return -EBUSY;
+
+ if (m2m_ctx->has_stopped)
+ return 0;
+
+ m2m_ctx->last_src_buf = v4l2_m2m_last_src_buf(m2m_ctx);
+ m2m_ctx->is_draining = true;
+ break;
+ case V4L2_ENC_CMD_START:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wave5_vpu_enc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+
+ dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, a->type);
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+
+ a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+ a->parm.output.timeperframe.numerator = 1;
+ a->parm.output.timeperframe.denominator = inst->frame_rate;
+
+ dev_dbg(inst->dev->dev, "%s: numerator: %u | denominator: %u\n",
+ __func__, a->parm.output.timeperframe.numerator,
+ a->parm.output.timeperframe.denominator);
+
+ return 0;
+}
+
+static int wave5_vpu_enc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+ struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+
+ dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, a->type);
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return -EINVAL;
+
+ a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+ if (a->parm.output.timeperframe.denominator && a->parm.output.timeperframe.numerator) {
+ inst->frame_rate = a->parm.output.timeperframe.denominator /
+ a->parm.output.timeperframe.numerator;
+ } else {
+ a->parm.output.timeperframe.numerator = 1;
+ a->parm.output.timeperframe.denominator = inst->frame_rate;
+ }
+
+ dev_dbg(inst->dev->dev, "%s: numerator: %u | denominator: %u\n",
+ __func__, a->parm.output.timeperframe.numerator,
+ a->parm.output.timeperframe.denominator);
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops wave5_vpu_enc_ioctl_ops = {
+ .vidioc_querycap = wave5_vpu_enc_querycap,
+ .vidioc_enum_framesizes = wave5_vpu_enc_enum_framesizes,
+
+ .vidioc_enum_fmt_vid_cap = wave5_vpu_enc_enum_fmt_cap,
+ .vidioc_s_fmt_vid_cap_mplane = wave5_vpu_enc_s_fmt_cap,
+ .vidioc_g_fmt_vid_cap_mplane = wave5_vpu_enc_g_fmt_cap,
+ .vidioc_try_fmt_vid_cap_mplane = wave5_vpu_enc_try_fmt_cap,
+
+ .vidioc_enum_fmt_vid_out = wave5_vpu_enc_enum_fmt_out,
+ .vidioc_s_fmt_vid_out_mplane = wave5_vpu_enc_s_fmt_out,
+ .vidioc_g_fmt_vid_out_mplane = wave5_vpu_g_fmt_out,
+ .vidioc_try_fmt_vid_out_mplane = wave5_vpu_enc_try_fmt_out,
+
+ .vidioc_g_selection = wave5_vpu_enc_g_selection,
+ .vidioc_s_selection = wave5_vpu_enc_s_selection,
+
+ .vidioc_g_parm = wave5_vpu_enc_g_parm,
+ .vidioc_s_parm = wave5_vpu_enc_s_parm,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
+ .vidioc_encoder_cmd = wave5_vpu_enc_encoder_cmd,
+
+ .vidioc_subscribe_event = wave5_vpu_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static int wave5_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vpu_instance *inst = wave5_ctrl_to_vpu_inst(ctrl);
+
+ dev_dbg(inst->dev->dev, "%s: name: %s | value: %d\n", __func__, ctrl->name, ctrl->val);
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_AU_DELIMITER:
+ inst->encode_aud = ctrl->val;
+ break;
+ case V4L2_CID_HFLIP:
+ inst->mirror_direction |= (ctrl->val << 1);
+ break;
+ case V4L2_CID_VFLIP:
+ inst->mirror_direction |= ctrl->val;
+ break;
+ case V4L2_CID_ROTATE:
+ inst->rot_angle = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
+ inst->vbv_buf_size = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
+ inst->rc_mode = 0;
+ break;
+ case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
+ inst->rc_mode = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ inst->bit_rate = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ inst->enc_param.avc_idr_period = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+ inst->enc_param.independ_slice_mode = ctrl->val;
+ inst->enc_param.avc_slice_mode = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+ inst->enc_param.independ_slice_mode_arg = ctrl->val;
+ inst->enc_param.avc_slice_arg = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+ inst->rc_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
+ inst->enc_param.mb_level_rc_enable = ctrl->val;
+ inst->enc_param.cu_level_rc_enable = ctrl->val;
+ inst->enc_param.hvs_qp_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN:
+ inst->enc_param.profile = HEVC_PROFILE_MAIN;
+ inst->bit_depth = 8;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE:
+ inst->enc_param.profile = HEVC_PROFILE_STILLPICTURE;
+ inst->enc_param.en_still_picture = 1;
+ inst->bit_depth = 8;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10:
+ inst->enc_param.profile = HEVC_PROFILE_MAIN10;
+ inst->bit_depth = 10;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_1:
+ inst->enc_param.level = 10 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_2:
+ inst->enc_param.level = 20 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1:
+ inst->enc_param.level = 21 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_3:
+ inst->enc_param.level = 30 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1:
+ inst->enc_param.level = 31 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_4:
+ inst->enc_param.level = 40 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1:
+ inst->enc_param.level = 41 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_5:
+ inst->enc_param.level = 50 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1:
+ inst->enc_param.level = 51 * 3;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2:
+ inst->enc_param.level = 52 * 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
+ inst->enc_param.min_qp_i = ctrl->val;
+ inst->enc_param.min_qp_p = ctrl->val;
+ inst->enc_param.min_qp_b = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
+ inst->enc_param.max_qp_i = ctrl->val;
+ inst->enc_param.max_qp_p = ctrl->val;
+ inst->enc_param.max_qp_b = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP:
+ inst->enc_param.intra_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED:
+ inst->enc_param.disable_deblk = 1;
+ inst->enc_param.sao_enable = 0;
+ inst->enc_param.lf_cross_slice_boundary_enable = 0;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED:
+ inst->enc_param.disable_deblk = 0;
+ inst->enc_param.sao_enable = 1;
+ inst->enc_param.lf_cross_slice_boundary_enable = 1;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY:
+ inst->enc_param.disable_deblk = 0;
+ inst->enc_param.sao_enable = 1;
+ inst->enc_param.lf_cross_slice_boundary_enable = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2:
+ inst->enc_param.beta_offset_div2 = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2:
+ inst->enc_param.tc_offset_div2 = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE:
+ inst->enc_param.decoding_refresh_type = 0;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA:
+ inst->enc_param.decoding_refresh_type = 1;
+ break;
+ case V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR:
+ inst->enc_param.decoding_refresh_type = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD:
+ inst->enc_param.intra_period = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU:
+ inst->enc_param.lossless_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED:
+ inst->enc_param.const_intra_pred_flag = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT:
+ inst->enc_param.wpp_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING:
+ inst->enc_param.strong_intra_smooth_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1:
+ inst->enc_param.max_num_merge = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION:
+ inst->enc_param.tmvp_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+ inst->enc_param.profile = H264_PROFILE_BP;
+ inst->bit_depth = 8;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ inst->enc_param.profile = H264_PROFILE_MP;
+ inst->bit_depth = 8;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+ inst->enc_param.profile = H264_PROFILE_EXTENDED;
+ inst->bit_depth = 8;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ inst->enc_param.profile = H264_PROFILE_HP;
+ inst->bit_depth = 8;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
+ inst->enc_param.profile = H264_PROFILE_HIGH10;
+ inst->bit_depth = 10;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
+ inst->enc_param.profile = H264_PROFILE_HIGH422;
+ inst->bit_depth = 10;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
+ inst->enc_param.profile = H264_PROFILE_HIGH444;
+ inst->bit_depth = 10;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+ inst->enc_param.level = 10;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+ inst->enc_param.level = 9;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+ inst->enc_param.level = 11;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+ inst->enc_param.level = 12;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+ inst->enc_param.level = 13;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+ inst->enc_param.level = 20;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+ inst->enc_param.level = 21;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+ inst->enc_param.level = 22;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+ inst->enc_param.level = 30;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+ inst->enc_param.level = 31;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+ inst->enc_param.level = 32;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+ inst->enc_param.level = 40;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+ inst->enc_param.level = 41;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+ inst->enc_param.level = 42;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+ inst->enc_param.level = 50;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+ inst->enc_param.level = 51;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+ inst->enc_param.min_qp_i = ctrl->val;
+ inst->enc_param.min_qp_p = ctrl->val;
+ inst->enc_param.min_qp_b = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+ inst->enc_param.max_qp_i = ctrl->val;
+ inst->enc_param.max_qp_p = ctrl->val;
+ inst->enc_param.max_qp_b = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+ inst->enc_param.intra_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED:
+ inst->enc_param.disable_deblk = 1;
+ inst->enc_param.lf_cross_slice_boundary_enable = 1;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED:
+ inst->enc_param.disable_deblk = 0;
+ inst->enc_param.lf_cross_slice_boundary_enable = 1;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY:
+ inst->enc_param.disable_deblk = 0;
+ inst->enc_param.lf_cross_slice_boundary_enable = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+ inst->enc_param.beta_offset_div2 = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+ inst->enc_param.tc_offset_div2 = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+ inst->enc_param.transform8x8_enable = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION:
+ inst->enc_param.const_intra_pred_flag = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET:
+ inst->enc_param.chroma_cb_qp_offset = ctrl->val;
+ inst->enc_param.chroma_cr_qp_offset = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+ inst->enc_param.intra_period = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+ inst->enc_param.entropy_coding_mode = ctrl->val;
+ break;
+ case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops wave5_vpu_enc_ctrl_ops = {
+ .s_ctrl = wave5_vpu_enc_s_ctrl,
+};
+
+static int wave5_vpu_enc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_pix_format_mplane inst_format =
+ (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt;
+ unsigned int i;
+
+ dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n", __func__,
+ *num_buffers, *num_planes, q->type);
+
+ if (*num_planes) {
+ if (inst_format.num_planes != *num_planes)
+ return -EINVAL;
+
+ for (i = 0; i < *num_planes; i++) {
+ if (sizes[i] < inst_format.plane_fmt[i].sizeimage)
+ return -EINVAL;
+ }
+ } else {
+ *num_planes = inst_format.num_planes;
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst_format.plane_fmt[i].sizeimage;
+ dev_dbg(inst->dev->dev, "%s: size[%u]: %u\n", __func__, i, sizes[i]);
+ }
+ }
+
+ dev_dbg(inst->dev->dev, "%s: size: %u\n", __func__, sizes[0]);
+
+ return 0;
+}
+
+static void wave5_vpu_enc_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+
+ dev_dbg(inst->dev->dev, "%s: type: %4u index: %4u size: ([0]=%4lu, [1]=%4lu, [2]=%4lu)\n",
+ __func__, vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0),
+ vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2));
+
+ if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ vbuf->sequence = inst->queued_src_buf_num++;
+ else
+ vbuf->sequence = inst->queued_dst_buf_num++;
+
+ v4l2_m2m_buf_queue(m2m_ctx, vbuf);
+}
+
+static void wave5_set_enc_openparam(struct enc_open_param *open_param,
+ struct vpu_instance *inst)
+{
+ struct enc_wave_param input = inst->enc_param;
+ u32 num_ctu_row = ALIGN(inst->dst_fmt.height, 64) / 64;
+ u32 num_mb_row = ALIGN(inst->dst_fmt.height, 16) / 16;
+
+ open_param->wave_param.gop_preset_idx = PRESET_IDX_IPP_SINGLE;
+ open_param->wave_param.hvs_qp_scale = 2;
+ open_param->wave_param.hvs_max_delta_qp = 10;
+ open_param->wave_param.skip_intra_trans = 1;
+ open_param->wave_param.intra_nx_n_enable = 1;
+ open_param->wave_param.nr_intra_weight_y = 7;
+ open_param->wave_param.nr_intra_weight_cb = 7;
+ open_param->wave_param.nr_intra_weight_cr = 7;
+ open_param->wave_param.nr_inter_weight_y = 4;
+ open_param->wave_param.nr_inter_weight_cb = 4;
+ open_param->wave_param.nr_inter_weight_cr = 4;
+ open_param->wave_param.rdo_skip = 1;
+ open_param->wave_param.lambda_scaling_enable = 1;
+
+ open_param->line_buf_int_en = true;
+ open_param->pic_width = inst->dst_fmt.width;
+ open_param->pic_height = inst->dst_fmt.height;
+ open_param->frame_rate_info = inst->frame_rate;
+ open_param->rc_enable = inst->rc_enable;
+ if (inst->rc_enable) {
+ open_param->wave_param.initial_rc_qp = -1;
+ open_param->wave_param.rc_weight_param = 16;
+ open_param->wave_param.rc_weight_buf = 128;
+ }
+ open_param->wave_param.mb_level_rc_enable = input.mb_level_rc_enable;
+ open_param->wave_param.cu_level_rc_enable = input.cu_level_rc_enable;
+ open_param->wave_param.hvs_qp_enable = input.hvs_qp_enable;
+ open_param->bit_rate = inst->bit_rate;
+ open_param->vbv_buffer_size = inst->vbv_buf_size;
+ if (inst->rc_mode == 0)
+ open_param->vbv_buffer_size = 3000;
+ open_param->wave_param.profile = input.profile;
+ open_param->wave_param.en_still_picture = input.en_still_picture;
+ open_param->wave_param.level = input.level;
+ open_param->wave_param.internal_bit_depth = inst->bit_depth;
+ open_param->wave_param.intra_qp = input.intra_qp;
+ open_param->wave_param.min_qp_i = input.min_qp_i;
+ open_param->wave_param.max_qp_i = input.max_qp_i;
+ open_param->wave_param.min_qp_p = input.min_qp_p;
+ open_param->wave_param.max_qp_p = input.max_qp_p;
+ open_param->wave_param.min_qp_b = input.min_qp_b;
+ open_param->wave_param.max_qp_b = input.max_qp_b;
+ open_param->wave_param.disable_deblk = input.disable_deblk;
+ open_param->wave_param.lf_cross_slice_boundary_enable =
+ input.lf_cross_slice_boundary_enable;
+ open_param->wave_param.tc_offset_div2 = input.tc_offset_div2;
+ open_param->wave_param.beta_offset_div2 = input.beta_offset_div2;
+ open_param->wave_param.decoding_refresh_type = input.decoding_refresh_type;
+ open_param->wave_param.intra_period = input.intra_period;
+ if (inst->std == W_HEVC_ENC) {
+ if (input.intra_period == 0) {
+ open_param->wave_param.decoding_refresh_type = DEC_REFRESH_TYPE_IDR;
+ open_param->wave_param.intra_period = input.avc_idr_period;
+ }
+ } else {
+ open_param->wave_param.avc_idr_period = input.avc_idr_period;
+ }
+ open_param->wave_param.entropy_coding_mode = input.entropy_coding_mode;
+ open_param->wave_param.lossless_enable = input.lossless_enable;
+ open_param->wave_param.const_intra_pred_flag = input.const_intra_pred_flag;
+ open_param->wave_param.wpp_enable = input.wpp_enable;
+ open_param->wave_param.strong_intra_smooth_enable = input.strong_intra_smooth_enable;
+ open_param->wave_param.max_num_merge = input.max_num_merge;
+ open_param->wave_param.tmvp_enable = input.tmvp_enable;
+ open_param->wave_param.transform8x8_enable = input.transform8x8_enable;
+ open_param->wave_param.chroma_cb_qp_offset = input.chroma_cb_qp_offset;
+ open_param->wave_param.chroma_cr_qp_offset = input.chroma_cr_qp_offset;
+ open_param->wave_param.independ_slice_mode = input.independ_slice_mode;
+ open_param->wave_param.independ_slice_mode_arg = input.independ_slice_mode_arg;
+ open_param->wave_param.avc_slice_mode = input.avc_slice_mode;
+ open_param->wave_param.avc_slice_arg = input.avc_slice_arg;
+ open_param->wave_param.intra_mb_refresh_mode = input.intra_mb_refresh_mode;
+ if (input.intra_mb_refresh_mode != REFRESH_MB_MODE_NONE) {
+ if (num_mb_row >= input.intra_mb_refresh_arg)
+ open_param->wave_param.intra_mb_refresh_arg =
+ num_mb_row / input.intra_mb_refresh_arg;
+ else
+ open_param->wave_param.intra_mb_refresh_arg = num_mb_row;
+ }
+ open_param->wave_param.intra_refresh_mode = input.intra_refresh_mode;
+ if (input.intra_refresh_mode != 0) {
+ if (num_ctu_row >= input.intra_refresh_arg)
+ open_param->wave_param.intra_refresh_arg =
+ num_ctu_row / input.intra_refresh_arg;
+ else
+ open_param->wave_param.intra_refresh_arg = num_ctu_row;
+ }
+}
+
+static int initialize_sequence(struct vpu_instance *inst)
+{
+ struct enc_initial_info initial_info;
+ struct v4l2_ctrl *ctrl;
+ int ret;
+
+ ret = wave5_vpu_enc_issue_seq_init(inst);
+ if (ret) {
+ dev_err(inst->dev->dev, "%s: wave5_vpu_enc_issue_seq_init, fail: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (wave5_vpu_wait_interrupt(inst, VPU_ENC_TIMEOUT) < 0) {
+ dev_err(inst->dev->dev, "%s: wave5_vpu_wait_interrupt failed\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = wave5_vpu_enc_complete_seq_init(inst, &initial_info);
+ if (ret)
+ return ret;
+
+ dev_dbg(inst->dev->dev, "%s: min_frame_buffer: %u | min_source_buffer: %u\n",
+ __func__, initial_info.min_frame_buffer_count,
+ initial_info.min_src_frame_count);
+ inst->min_src_buf_count = initial_info.min_src_frame_count +
+ COMMAND_QUEUE_DEPTH;
+
+ ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT);
+ if (ctrl)
+ v4l2_ctrl_s_ctrl(ctrl, inst->min_src_buf_count);
+
+ inst->fbc_buf_count = initial_info.min_frame_buffer_count;
+
+ return 0;
+}
+
+static int prepare_fb(struct vpu_instance *inst)
+{
+ u32 fb_stride = ALIGN(inst->dst_fmt.width, 32);
+ u32 fb_height = ALIGN(inst->dst_fmt.height, 32);
+ int i, ret = 0;
+
+ for (i = 0; i < inst->fbc_buf_count; i++) {
+ u32 luma_size = fb_stride * fb_height;
+ u32 chroma_size = ALIGN(fb_stride / 2, 16) * fb_height;
+
+ inst->frame_vbuf[i].size = luma_size + chroma_size;
+ ret = wave5_vdi_allocate_dma_memory(inst->dev, &inst->frame_vbuf[i]);
+ if (ret < 0) {
+ dev_err(inst->dev->dev, "%s: failed to allocate FBC buffer %zu\n",
+ __func__, inst->frame_vbuf[i].size);
+ goto free_buffers;
+ }
+
+ inst->frame_buf[i].buf_y = inst->frame_vbuf[i].daddr;
+ inst->frame_buf[i].buf_cb = (dma_addr_t)-1;
+ inst->frame_buf[i].buf_cr = (dma_addr_t)-1;
+ inst->frame_buf[i].update_fb_info = true;
+ inst->frame_buf[i].size = inst->frame_vbuf[i].size;
+ }
+
+ ret = wave5_vpu_enc_register_frame_buffer(inst, inst->fbc_buf_count, fb_stride,
+ fb_height, COMPRESSED_FRAME_MAP);
+ if (ret) {
+ dev_err(inst->dev->dev,
+ "%s: wave5_vpu_enc_register_frame_buffer, fail: %d\n",
+ __func__, ret);
+ goto free_buffers;
+ }
+
+ return 0;
+free_buffers:
+ for (i = 0; i < inst->fbc_buf_count; i++)
+ wave5_vpu_dec_reset_framebuffer(inst, i);
+ return ret;
+}
+
+static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ int ret = 0;
+
+ v4l2_m2m_update_start_streaming_state(m2m_ctx, q);
+
+ if (inst->state == VPU_INST_STATE_NONE && q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ struct enc_open_param open_param;
+
+ memset(&open_param, 0, sizeof(struct enc_open_param));
+
+ wave5_set_enc_openparam(&open_param, inst);
+
+ ret = wave5_vpu_enc_open(inst, &open_param);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: wave5_vpu_enc_open, fail: %d\n",
+ __func__, ret);
+ goto return_buffers;
+ }
+
+ if (inst->mirror_direction) {
+ wave5_vpu_enc_give_command(inst, ENABLE_MIRRORING, NULL);
+ wave5_vpu_enc_give_command(inst, SET_MIRROR_DIRECTION,
+ &inst->mirror_direction);
+ }
+ if (inst->rot_angle) {
+ wave5_vpu_enc_give_command(inst, ENABLE_ROTATION, NULL);
+ wave5_vpu_enc_give_command(inst, SET_ROTATION_ANGLE, &inst->rot_angle);
+ }
+
+ ret = switch_state(inst, VPU_INST_STATE_OPEN);
+ if (ret)
+ goto return_buffers;
+ }
+ if (inst->state == VPU_INST_STATE_OPEN && m2m_ctx->cap_q_ctx.q.streaming) {
+ ret = initialize_sequence(inst);
+ if (ret) {
+ dev_warn(inst->dev->dev, "Sequence not found: %d\n", ret);
+ goto return_buffers;
+ }
+ ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ);
+ if (ret)
+ goto return_buffers;
+ /*
+ * The sequence must be analyzed first to calculate the proper
+ * size of the auxiliary buffers.
+ */
+ ret = prepare_fb(inst);
+ if (ret) {
+ dev_warn(inst->dev->dev, "Framebuffer preparation, fail: %d\n", ret);
+ goto return_buffers;
+ }
+
+ ret = switch_state(inst, VPU_INST_STATE_PIC_RUN);
+ }
+ if (ret)
+ goto return_buffers;
+
+ return 0;
+return_buffers:
+ wave5_return_bufs(q, VB2_BUF_STATE_QUEUED);
+ return ret;
+}
+
+static void streamoff_output(struct vpu_instance *inst, struct vb2_queue *q)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct vb2_v4l2_buffer *buf;
+
+ while ((buf = v4l2_m2m_src_buf_remove(m2m_ctx))) {
+ dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n",
+ __func__, buf->vb2_buf.type, buf->vb2_buf.index);
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+ }
+}
+
+static void streamoff_capture(struct vpu_instance *inst, struct vb2_queue *q)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ struct vb2_v4l2_buffer *buf;
+
+ while ((buf = v4l2_m2m_dst_buf_remove(m2m_ctx))) {
+ dev_dbg(inst->dev->dev, "%s: buf type %4u | index %4u\n",
+ __func__, buf->vb2_buf.type, buf->vb2_buf.index);
+ vb2_set_plane_payload(&buf->vb2_buf, 0, 0);
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+ }
+
+ v4l2_m2m_clear_state(m2m_ctx);
+}
+
+static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q)
+{
+ struct vpu_instance *inst = vb2_get_drv_priv(q);
+ bool check_cmd = true;
+
+ /*
+ * Note that we don't need m2m_ctx->next_buf_last for this driver, so we
+ * don't call v4l2_m2m_update_stop_streaming_state().
+ */
+
+ dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type);
+
+ if (wave5_vpu_both_queues_are_streaming(inst))
+ switch_state(inst, VPU_INST_STATE_STOP);
+
+ while (check_cmd) {
+ struct queue_status_info q_status;
+ struct enc_output_info enc_output_info;
+
+ wave5_vpu_enc_give_command(inst, ENC_GET_QUEUE_STATUS, &q_status);
+
+ if (q_status.report_queue_count == 0)
+ break;
+
+ if (wave5_vpu_wait_interrupt(inst, VPU_ENC_TIMEOUT) < 0)
+ break;
+
+ if (wave5_vpu_enc_get_output_info(inst, &enc_output_info))
+ dev_dbg(inst->dev->dev, "Getting encoding results from fw, fail\n");
+ }
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ streamoff_output(inst, q);
+ else
+ streamoff_capture(inst, q);
+}
+
+static const struct vb2_ops wave5_vpu_enc_vb2_ops = {
+ .queue_setup = wave5_vpu_enc_queue_setup,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .buf_queue = wave5_vpu_enc_buf_queue,
+ .start_streaming = wave5_vpu_enc_start_streaming,
+ .stop_streaming = wave5_vpu_enc_stop_streaming,
+};
+
+static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt,
+ struct v4l2_pix_format_mplane *dst_fmt)
+{
+ unsigned int src_pix_fmt = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt;
+ const struct v4l2_format_info *src_fmt_info = v4l2_format_info(src_pix_fmt);
+
+ src_fmt->pixelformat = src_pix_fmt;
+ src_fmt->field = V4L2_FIELD_NONE;
+ src_fmt->flags = 0;
+ src_fmt->num_planes = src_fmt_info->mem_planes;
+ wave5_update_pix_fmt(src_fmt, 416, 240);
+
+ dst_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt;
+ dst_fmt->field = V4L2_FIELD_NONE;
+ dst_fmt->flags = 0;
+ dst_fmt->num_planes = 1;
+ wave5_update_pix_fmt(dst_fmt, 416, 240);
+}
+
+static int wave5_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+ return wave5_vpu_queue_init(priv, src_vq, dst_vq, &wave5_vpu_enc_vb2_ops);
+}
+
+static const struct vpu_instance_ops wave5_vpu_enc_inst_ops = {
+ .finish_process = wave5_vpu_enc_finish_encode,
+};
+
+static void wave5_vpu_enc_device_run(void *priv)
+{
+ struct vpu_instance *inst = priv;
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ u32 fail_res = 0;
+ int ret = 0;
+
+ switch (inst->state) {
+ case VPU_INST_STATE_PIC_RUN:
+ ret = start_encode(inst, &fail_res);
+ if (ret) {
+ if (ret == -EINVAL)
+ dev_err(inst->dev->dev,
+ "Frame encoding on m2m context (%p), fail: %d (res: %d)\n",
+ m2m_ctx, ret, fail_res);
+ else if (ret == -EAGAIN)
+ dev_dbg(inst->dev->dev, "Missing buffers for encode, try again\n");
+ break;
+ }
+ dev_dbg(inst->dev->dev, "%s: leave with active job", __func__);
+ return;
+ default:
+ WARN(1, "Execution of a job in state %s is invalid.\n",
+ state_to_str(inst->state));
+ break;
+ }
+ dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__);
+ v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
+}
+
+static int wave5_vpu_enc_job_ready(void *priv)
+{
+ struct vpu_instance *inst = priv;
+ struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+
+ switch (inst->state) {
+ case VPU_INST_STATE_NONE:
+ dev_dbg(inst->dev->dev, "Encoder must be open to start queueing M2M jobs!\n");
+ return false;
+ case VPU_INST_STATE_PIC_RUN:
+ if (m2m_ctx->is_draining || v4l2_m2m_num_src_bufs_ready(m2m_ctx)) {
+ dev_dbg(inst->dev->dev, "Encoder ready for a job, state: %s\n",
+ state_to_str(inst->state));
+ return true;
+ }
+ fallthrough;
+ default:
+ dev_dbg(inst->dev->dev,
+ "Encoder not ready for a job, state: %s, %s draining, %d src bufs ready\n",
+ state_to_str(inst->state), m2m_ctx->is_draining ? "is" : "is not",
+ v4l2_m2m_num_src_bufs_ready(m2m_ctx));
+ break;
+ }
+ return false;
+}
+
+static const struct v4l2_m2m_ops wave5_vpu_enc_m2m_ops = {
+ .device_run = wave5_vpu_enc_device_run,
+ .job_ready = wave5_vpu_enc_job_ready,
+};
+
+static int wave5_vpu_open_enc(struct file *filp)
+{
+ struct video_device *vdev = video_devdata(filp);
+ struct vpu_device *dev = video_drvdata(filp);
+ struct vpu_instance *inst = NULL;
+ struct v4l2_ctrl_handler *v4l2_ctrl_hdl;
+ int ret = 0;
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst)
+ return -ENOMEM;
+ v4l2_ctrl_hdl = &inst->v4l2_ctrl_hdl;
+
+ inst->dev = dev;
+ inst->type = VPU_INST_TYPE_ENC;
+ inst->ops = &wave5_vpu_enc_inst_ops;
+
+ inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL);
+ if (!inst->codec_info)
+ return -ENOMEM;
+
+ v4l2_fh_init(&inst->v4l2_fh, vdev);
+ filp->private_data = &inst->v4l2_fh;
+ v4l2_fh_add(&inst->v4l2_fh);
+
+ INIT_LIST_HEAD(&inst->list);
+ list_add_tail(&inst->list, &dev->instances);
+
+ inst->v4l2_m2m_dev = inst->dev->v4l2_m2m_enc_dev;
+ inst->v4l2_fh.m2m_ctx =
+ v4l2_m2m_ctx_init(inst->v4l2_m2m_dev, inst, wave5_vpu_enc_queue_init);
+ if (IS_ERR(inst->v4l2_fh.m2m_ctx)) {
+ ret = PTR_ERR(inst->v4l2_fh.m2m_ctx);
+ goto cleanup_inst;
+ }
+ v4l2_m2m_set_src_buffered(inst->v4l2_fh.m2m_ctx, true);
+
+ v4l2_ctrl_handler_init(v4l2_ctrl_hdl, 50);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, 0,
+ V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, 0,
+ V4L2_MPEG_VIDEO_HEVC_LEVEL_1);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
+ 0, 63, 1, 8);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
+ 0, 63, 1, 51);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
+ 0, 63, 1, 30);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE,
+ V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0,
+ V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2,
+ -6, 6, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2,
+ -6, 6, 1, 0);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE,
+ V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR, 0,
+ V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD,
+ 0, 2047, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING,
+ 0, 1, 1, 1);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1,
+ 1, 2, 1, 2);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION,
+ 0, 1, 1, 1);
+
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE, 0,
+ V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ V4L2_MPEG_VIDEO_H264_LEVEL_5_1, 0,
+ V4L2_MPEG_VIDEO_H264_LEVEL_1_0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+ 0, 63, 1, 8);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+ 0, 63, 1, 51);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+ 0, 63, 1, 30);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0,
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
+ -6, 6, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
+ -6, 6, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
+ 0, 1, 1, 1);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET,
+ -12, 12, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+ 0, 2047, 1, 0);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
+ V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, 0,
+ V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_AU_DELIMITER,
+ 0, 1, 1, 1);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_HFLIP,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_ROTATE,
+ 0, 270, 90, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_VBV_SIZE,
+ 10, 3000, 1, 1000);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ 0, 700000000, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ 0, 2047, 1, 0);
+ v4l2_ctrl_new_std_menu(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+ V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB, 0,
+ V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
+ 0, 0xFFFF, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 1);
+
+ if (v4l2_ctrl_hdl->error) {
+ ret = -ENODEV;
+ goto cleanup_inst;
+ }
+
+ inst->v4l2_fh.ctrl_handler = v4l2_ctrl_hdl;
+ v4l2_ctrl_handler_setup(v4l2_ctrl_hdl);
+
+ wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt);
+ inst->colorspace = V4L2_COLORSPACE_REC709;
+ inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ inst->quantization = V4L2_QUANTIZATION_DEFAULT;
+ inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ inst->frame_rate = 30;
+
+ init_completion(&inst->irq_done);
+
+ inst->id = ida_alloc(&inst->dev->inst_ida, GFP_KERNEL);
+ if (inst->id < 0) {
+ dev_warn(inst->dev->dev, "Allocating instance ID, fail: %d\n", inst->id);
+ ret = inst->id;
+ goto cleanup_inst;
+ }
+
+ wave5_vdi_allocate_sram(inst->dev);
+
+ return 0;
+
+cleanup_inst:
+ wave5_cleanup_instance(inst);
+ return ret;
+}
+
+static int wave5_vpu_enc_release(struct file *filp)
+{
+ return wave5_vpu_release_device(filp, wave5_vpu_enc_close, "encoder");
+}
+
+static const struct v4l2_file_operations wave5_vpu_enc_fops = {
+ .owner = THIS_MODULE,
+ .open = wave5_vpu_open_enc,
+ .release = wave5_vpu_enc_release,
+ .unlocked_ioctl = video_ioctl2,
+ .poll = v4l2_m2m_fop_poll,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+int wave5_vpu_enc_register_device(struct vpu_device *dev)
+{
+ struct video_device *vdev_enc;
+ int ret;
+
+ vdev_enc = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_enc), GFP_KERNEL);
+ if (!vdev_enc)
+ return -ENOMEM;
+
+ dev->v4l2_m2m_enc_dev = v4l2_m2m_init(&wave5_vpu_enc_m2m_ops);
+ if (IS_ERR(dev->v4l2_m2m_enc_dev)) {
+ ret = PTR_ERR(dev->v4l2_m2m_enc_dev);
+ dev_err(dev->dev, "v4l2_m2m_init, fail: %d\n", ret);
+ return -EINVAL;
+ }
+
+ dev->video_dev_enc = vdev_enc;
+
+ strscpy(vdev_enc->name, VPU_ENC_DEV_NAME, sizeof(vdev_enc->name));
+ vdev_enc->fops = &wave5_vpu_enc_fops;
+ vdev_enc->ioctl_ops = &wave5_vpu_enc_ioctl_ops;
+ vdev_enc->release = video_device_release_empty;
+ vdev_enc->v4l2_dev = &dev->v4l2_dev;
+ vdev_enc->vfl_dir = VFL_DIR_M2M;
+ vdev_enc->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+ vdev_enc->lock = &dev->dev_lock;
+
+ ret = video_register_device(vdev_enc, VFL_TYPE_VIDEO, -1);
+ if (ret)
+ return ret;
+
+ video_set_drvdata(vdev_enc, dev);
+
+ return 0;
+}
+
+void wave5_vpu_enc_unregister_device(struct vpu_device *dev)
+{
+ video_unregister_device(dev->video_dev_enc);
+ if (dev->v4l2_m2m_enc_dev)
+ v4l2_m2m_release(dev->v4l2_m2m_enc_dev);
+}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c
new file mode 100644
index 000000000000..bfe4caa79cc9
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave5 series multi-standard codec IP - platform driver
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include "wave5-vpu.h"
+#include "wave5-regdefine.h"
+#include "wave5-vpuconfig.h"
+#include "wave5.h"
+
+#define VPU_PLATFORM_DEVICE_NAME "vdec"
+#define VPU_CLK_NAME "vcodec"
+
+#define WAVE5_IS_ENC BIT(0)
+#define WAVE5_IS_DEC BIT(1)
+
+struct wave5_match_data {
+ int flags;
+ const char *fw_name;
+};
+
+int wave5_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout)
+{
+ int ret;
+
+ ret = wait_for_completion_timeout(&inst->irq_done,
+ msecs_to_jiffies(timeout));
+ if (!ret)
+ return -ETIMEDOUT;
+
+ reinit_completion(&inst->irq_done);
+
+ return 0;
+}
+
+static irqreturn_t wave5_vpu_irq_thread(int irq, void *dev_id)
+{
+ u32 seq_done;
+ u32 cmd_done;
+ u32 irq_reason;
+ struct vpu_instance *inst;
+ struct vpu_device *dev = dev_id;
+
+ if (wave5_vdi_read_register(dev, W5_VPU_VPU_INT_STS)) {
+ irq_reason = wave5_vdi_read_register(dev, W5_VPU_VINT_REASON);
+ wave5_vdi_write_register(dev, W5_VPU_VINT_REASON_CLR, irq_reason);
+ wave5_vdi_write_register(dev, W5_VPU_VINT_CLEAR, 0x1);
+
+ list_for_each_entry(inst, &dev->instances, list) {
+ seq_done = wave5_vdi_read_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO);
+ cmd_done = wave5_vdi_read_register(dev, W5_RET_QUEUE_CMD_DONE_INST);
+
+ if (irq_reason & BIT(INT_WAVE5_INIT_SEQ) ||
+ irq_reason & BIT(INT_WAVE5_ENC_SET_PARAM)) {
+ if (seq_done & BIT(inst->id)) {
+ seq_done &= ~BIT(inst->id);
+ wave5_vdi_write_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO,
+ seq_done);
+ complete(&inst->irq_done);
+ }
+ }
+
+ if (irq_reason & BIT(INT_WAVE5_DEC_PIC) ||
+ irq_reason & BIT(INT_WAVE5_ENC_PIC)) {
+ if (cmd_done & BIT(inst->id)) {
+ cmd_done &= ~BIT(inst->id);
+ wave5_vdi_write_register(dev, W5_RET_QUEUE_CMD_DONE_INST,
+ cmd_done);
+ inst->ops->finish_process(inst);
+ }
+ }
+
+ wave5_vpu_clear_interrupt(inst, irq_reason);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int wave5_vpu_load_firmware(struct device *dev, const char *fw_name,
+ u32 *revision)
+{
+ const struct firmware *fw;
+ int ret;
+ unsigned int product_id;
+
+ ret = request_firmware(&fw, fw_name, dev);
+ if (ret) {
+ dev_err(dev, "request_firmware, fail: %d\n", ret);
+ return ret;
+ }
+
+ ret = wave5_vpu_init_with_bitcode(dev, (u8 *)fw->data, fw->size);
+ if (ret) {
+ dev_err(dev, "vpu_init_with_bitcode, fail: %d\n", ret);
+ release_firmware(fw);
+ return ret;
+ }
+ release_firmware(fw);
+
+ ret = wave5_vpu_get_version_info(dev, revision, &product_id);
+ if (ret) {
+ dev_err(dev, "vpu_get_version_info fail: %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "%s: enum product_id: %08x, fw revision: %u\n",
+ __func__, product_id, *revision);
+
+ return 0;
+}
+
+static int wave5_vpu_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct vpu_device *dev;
+ const struct wave5_match_data *match_data;
+ u32 fw_revision;
+
+ match_data = device_get_match_data(&pdev->dev);
+ if (!match_data) {
+ dev_err(&pdev->dev, "missing device match data\n");
+ return -EINVAL;
+ }
+
+ /* physical addresses limited to 32 bits */
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to set DMA mask: %d\n", ret);
+ return ret;
+ }
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->vdb_register = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(dev->vdb_register))
+ return PTR_ERR(dev->vdb_register);
+ ida_init(&dev->inst_ida);
+
+ mutex_init(&dev->dev_lock);
+ mutex_init(&dev->hw_lock);
+ dev_set_drvdata(&pdev->dev, dev);
+ dev->dev = &pdev->dev;
+
+ ret = devm_clk_bulk_get_all(&pdev->dev, &dev->clks);
+
+ /* continue without clock, assume externally managed */
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "Getting clocks, fail: %d\n", ret);
+ ret = 0;
+ }
+ dev->num_clks = ret;
+
+ ret = clk_bulk_prepare_enable(dev->num_clks, dev->clks);
+ if (ret) {
+ dev_err(&pdev->dev, "Enabling clocks, fail: %d\n", ret);
+ return ret;
+ }
+
+ ret = of_property_read_u32(pdev->dev.of_node, "sram-size",
+ &dev->sram_size);
+ if (ret) {
+ dev_warn(&pdev->dev, "sram-size not found\n");
+ dev->sram_size = 0;
+ }
+
+ dev->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
+ if (!dev->sram_pool)
+ dev_warn(&pdev->dev, "sram node not found\n");
+
+ dev->product_code = wave5_vdi_read_register(dev, VPU_PRODUCT_CODE_REGISTER);
+ ret = wave5_vdi_init(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "wave5_vdi_init, fail: %d\n", ret);
+ goto err_clk_dis;
+ }
+ dev->product = wave5_vpu_get_product_id(dev);
+
+ INIT_LIST_HEAD(&dev->instances);
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "v4l2_device_register, fail: %d\n", ret);
+ goto err_vdi_release;
+ }
+
+ if (match_data->flags & WAVE5_IS_DEC) {
+ ret = wave5_vpu_dec_register_device(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "wave5_vpu_dec_register_device, fail: %d\n", ret);
+ goto err_v4l2_unregister;
+ }
+ }
+ if (match_data->flags & WAVE5_IS_ENC) {
+ ret = wave5_vpu_enc_register_device(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "wave5_vpu_enc_register_device, fail: %d\n", ret);
+ goto err_dec_unreg;
+ }
+ }
+
+ dev->irq = platform_get_irq(pdev, 0);
+ if (dev->irq < 0) {
+ dev_err(&pdev->dev, "failed to get irq resource\n");
+ ret = -ENXIO;
+ goto err_enc_unreg;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, dev->irq, NULL,
+ wave5_vpu_irq_thread, IRQF_ONESHOT, "vpu_irq", dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Register interrupt handler, fail: %d\n", ret);
+ goto err_enc_unreg;
+ }
+
+ ret = wave5_vpu_load_firmware(&pdev->dev, match_data->fw_name, &fw_revision);
+ if (ret) {
+ dev_err(&pdev->dev, "wave5_vpu_load_firmware, fail: %d\n", ret);
+ goto err_enc_unreg;
+ }
+
+ dev_info(&pdev->dev, "Added wave5 driver with caps: %s %s\n",
+ (match_data->flags & WAVE5_IS_ENC) ? "'ENCODE'" : "",
+ (match_data->flags & WAVE5_IS_DEC) ? "'DECODE'" : "");
+ dev_info(&pdev->dev, "Product Code: 0x%x\n", dev->product_code);
+ dev_info(&pdev->dev, "Firmware Revision: %u\n", fw_revision);
+ return 0;
+
+err_enc_unreg:
+ if (match_data->flags & WAVE5_IS_ENC)
+ wave5_vpu_enc_unregister_device(dev);
+err_dec_unreg:
+ if (match_data->flags & WAVE5_IS_DEC)
+ wave5_vpu_dec_unregister_device(dev);
+err_v4l2_unregister:
+ v4l2_device_unregister(&dev->v4l2_dev);
+err_vdi_release:
+ wave5_vdi_release(&pdev->dev);
+err_clk_dis:
+ clk_bulk_disable_unprepare(dev->num_clks, dev->clks);
+
+ return ret;
+}
+
+static int wave5_vpu_remove(struct platform_device *pdev)
+{
+ struct vpu_device *dev = dev_get_drvdata(&pdev->dev);
+
+ mutex_destroy(&dev->dev_lock);
+ mutex_destroy(&dev->hw_lock);
+ clk_bulk_disable_unprepare(dev->num_clks, dev->clks);
+ wave5_vpu_enc_unregister_device(dev);
+ wave5_vpu_dec_unregister_device(dev);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ wave5_vdi_release(&pdev->dev);
+ ida_destroy(&dev->inst_ida);
+
+ return 0;
+}
+
+static const struct wave5_match_data ti_wave521c_data = {
+ .flags = WAVE5_IS_ENC | WAVE5_IS_DEC,
+ .fw_name = "cnm/wave521c_k3_codec_fw.bin",
+};
+
+static const struct of_device_id wave5_dt_ids[] = {
+ { .compatible = "ti,k3-j721s2-wave521c", .data = &ti_wave521c_data },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, wave5_dt_ids);
+
+static struct platform_driver wave5_vpu_driver = {
+ .driver = {
+ .name = VPU_PLATFORM_DEVICE_NAME,
+ .of_match_table = of_match_ptr(wave5_dt_ids),
+ },
+ .probe = wave5_vpu_probe,
+ .remove = wave5_vpu_remove,
+};
+
+module_platform_driver(wave5_vpu_driver);
+MODULE_DESCRIPTION("chips&media VPU V4L2 driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.h b/drivers/media/platform/chips-media/wave5/wave5-vpu.h
new file mode 100644
index 000000000000..32b7fd3730b5
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.h
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave5 series multi-standard codec IP - basic types
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+#ifndef __VPU_DRV_H__
+#define __VPU_DRV_H__
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-vmalloc.h>
+#include "wave5-vpuconfig.h"
+#include "wave5-vpuapi.h"
+
+#define VPU_BUF_SYNC_TO_DEVICE 0
+#define VPU_BUF_SYNC_FROM_DEVICE 1
+
+struct vpu_src_buffer {
+ struct v4l2_m2m_buffer v4l2_m2m_buf;
+ struct list_head list;
+ bool consumed;
+};
+
+struct vpu_dst_buffer {
+ struct v4l2_m2m_buffer v4l2_m2m_buf;
+ bool display;
+};
+
+enum vpu_fmt_type {
+ VPU_FMT_TYPE_CODEC = 0,
+ VPU_FMT_TYPE_RAW = 1
+};
+
+struct vpu_format {
+ unsigned int v4l2_pix_fmt;
+ unsigned int max_width;
+ unsigned int min_width;
+ unsigned int max_height;
+ unsigned int min_height;
+};
+
+static inline struct vpu_instance *wave5_to_vpu_inst(struct v4l2_fh *vfh)
+{
+ return container_of(vfh, struct vpu_instance, v4l2_fh);
+}
+
+static inline struct vpu_instance *wave5_ctrl_to_vpu_inst(struct v4l2_ctrl *vctrl)
+{
+ return container_of(vctrl->handler, struct vpu_instance, v4l2_ctrl_hdl);
+}
+
+static inline struct vpu_src_buffer *wave5_to_vpu_src_buf(struct vb2_v4l2_buffer *vbuf)
+{
+ return container_of(vbuf, struct vpu_src_buffer, v4l2_m2m_buf.vb);
+}
+
+static inline struct vpu_dst_buffer *wave5_to_vpu_dst_buf(struct vb2_v4l2_buffer *vbuf)
+{
+ return container_of(vbuf, struct vpu_dst_buffer, v4l2_m2m_buf.vb);
+}
+
+int wave5_vpu_wait_interrupt(struct vpu_instance *inst, unsigned int timeout);
+
+int wave5_vpu_dec_register_device(struct vpu_device *dev);
+void wave5_vpu_dec_unregister_device(struct vpu_device *dev);
+int wave5_vpu_enc_register_device(struct vpu_device *dev);
+void wave5_vpu_enc_unregister_device(struct vpu_device *dev);
+static inline bool wave5_vpu_both_queues_are_streaming(struct vpu_instance *inst)
+{
+ struct vb2_queue *vq_cap =
+ v4l2_m2m_get_vq(inst->v4l2_fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+ struct vb2_queue *vq_out =
+ v4l2_m2m_get_vq(inst->v4l2_fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+
+ return vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out);
+}
+
+#endif
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c
new file mode 100644
index 000000000000..1a3efb638dde
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c
@@ -0,0 +1,960 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Wave5 series multi-standard codec IP - helper functions
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#include <linux/bug.h>
+#include "wave5-vpuapi.h"
+#include "wave5-regdefine.h"
+#include "wave5.h"
+
+#define DECODE_ALL_TEMPORAL_LAYERS 0
+#define DECODE_ALL_SPATIAL_LAYERS 0
+
+static int wave5_initialize_vpu(struct device *dev, u8 *code, size_t size)
+{
+ int ret;
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ if (wave5_vpu_is_init(vpu_dev)) {
+ wave5_vpu_re_init(dev, (void *)code, size);
+ ret = -EBUSY;
+ goto err_out;
+ }
+
+ ret = wave5_vpu_reset(dev, SW_RESET_ON_BOOT);
+ if (ret)
+ goto err_out;
+
+ ret = wave5_vpu_init(dev, (void *)code, size);
+
+err_out:
+ mutex_unlock(&vpu_dev->hw_lock);
+ return ret;
+}
+
+int wave5_vpu_init_with_bitcode(struct device *dev, u8 *bitcode, size_t size)
+{
+ if (!bitcode || size == 0)
+ return -EINVAL;
+
+ return wave5_initialize_vpu(dev, bitcode, size);
+}
+
+int wave5_vpu_flush_instance(struct vpu_instance *inst)
+{
+ int ret = 0;
+ int retry = 0;
+
+ ret = mutex_lock_interruptible(&inst->dev->hw_lock);
+ if (ret)
+ return ret;
+ do {
+ /*
+ * Repeat the FLUSH command until the firmware reports that the
+ * VPU isn't running anymore
+ */
+ ret = wave5_vpu_hw_flush_instance(inst);
+ if (ret < 0 && ret != -EBUSY) {
+ dev_warn(inst->dev->dev, "Flush of %s instance with id: %d fail: %d\n",
+ inst->type == VPU_INST_TYPE_DEC ? "DECODER" : "ENCODER", inst->id,
+ ret);
+ mutex_unlock(&inst->dev->hw_lock);
+ return ret;
+ }
+ if (ret == -EBUSY && retry++ >= MAX_FIRMWARE_CALL_RETRY) {
+ dev_warn(inst->dev->dev, "Flush of %s instance with id: %d timed out!\n",
+ inst->type == VPU_INST_TYPE_DEC ? "DECODER" : "ENCODER", inst->id);
+ mutex_unlock(&inst->dev->hw_lock);
+ return -ETIMEDOUT;
+ }
+ } while (ret != 0);
+ mutex_unlock(&inst->dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_get_version_info(struct device *dev, u32 *revision, unsigned int *product_id)
+{
+ int ret;
+ struct vpu_device *vpu_dev = dev_get_drvdata(dev);
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ if (!wave5_vpu_is_init(vpu_dev)) {
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ if (product_id)
+ *product_id = vpu_dev->product;
+ ret = wave5_vpu_get_version(vpu_dev, revision);
+
+err_out:
+ mutex_unlock(&vpu_dev->hw_lock);
+ return ret;
+}
+
+static int wave5_check_dec_open_param(struct vpu_instance *inst, struct dec_open_param *param)
+{
+ if (inst->id >= MAX_NUM_INSTANCE) {
+ dev_err(inst->dev->dev, "Too many simultaneous instances: %d (max: %u)\n",
+ inst->id, MAX_NUM_INSTANCE);
+ return -EOPNOTSUPP;
+ }
+
+ if (param->bitstream_buffer % 8) {
+ dev_err(inst->dev->dev,
+ "Bitstream buffer must be aligned to a multiple of 8\n");
+ return -EINVAL;
+ }
+
+ if (param->bitstream_buffer_size % 1024 ||
+ param->bitstream_buffer_size < MIN_BITSTREAM_BUFFER_SIZE) {
+ dev_err(inst->dev->dev,
+ "Bitstream buffer size must be aligned to a multiple of 1024 and have a minimum size of %d\n",
+ MIN_BITSTREAM_BUFFER_SIZE);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int wave5_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param *open_param)
+{
+ struct dec_info *p_dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+ dma_addr_t buffer_addr;
+ size_t buffer_size;
+
+ ret = wave5_check_dec_open_param(inst, open_param);
+ if (ret)
+ return ret;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ if (!wave5_vpu_is_init(vpu_dev)) {
+ mutex_unlock(&vpu_dev->hw_lock);
+ return -ENODEV;
+ }
+
+ p_dec_info = &inst->codec_info->dec_info;
+ memcpy(&p_dec_info->open_param, open_param, sizeof(struct dec_open_param));
+
+ buffer_addr = open_param->bitstream_buffer;
+ buffer_size = open_param->bitstream_buffer_size;
+ p_dec_info->stream_wr_ptr = buffer_addr;
+ p_dec_info->stream_rd_ptr = buffer_addr;
+ p_dec_info->stream_buf_start_addr = buffer_addr;
+ p_dec_info->stream_buf_size = buffer_size;
+ p_dec_info->stream_buf_end_addr = buffer_addr + buffer_size;
+ p_dec_info->reorder_enable = TRUE;
+ p_dec_info->temp_id_select_mode = TEMPORAL_ID_MODE_ABSOLUTE;
+ p_dec_info->target_temp_id = DECODE_ALL_TEMPORAL_LAYERS;
+ p_dec_info->target_spatial_id = DECODE_ALL_SPATIAL_LAYERS;
+
+ ret = wave5_vpu_build_up_dec_param(inst, open_param);
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+static int reset_auxiliary_buffers(struct vpu_instance *inst, unsigned int index)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+
+ if (index >= MAX_REG_FRAME)
+ return 1;
+
+ if (p_dec_info->vb_mv[index].size == 0 && p_dec_info->vb_fbc_y_tbl[index].size == 0 &&
+ p_dec_info->vb_fbc_c_tbl[index].size == 0)
+ return 1;
+
+ wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_mv[index]);
+ wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_fbc_y_tbl[index]);
+ wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_fbc_c_tbl[index]);
+
+ return 0;
+}
+
+int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int ret;
+ int retry = 0;
+ struct vpu_device *vpu_dev = inst->dev;
+ int i;
+
+ *fail_res = 0;
+ if (!inst->codec_info)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ do {
+ ret = wave5_vpu_dec_finish_seq(inst, fail_res);
+ if (ret < 0 && *fail_res != WAVE5_SYSERR_VPU_STILL_RUNNING) {
+ dev_warn(inst->dev->dev, "dec_finish_seq timed out\n");
+ goto unlock_and_return;
+ }
+
+ if (*fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING &&
+ retry++ >= MAX_FIRMWARE_CALL_RETRY) {
+ ret = -ETIMEDOUT;
+ goto unlock_and_return;
+ }
+ } while (ret != 0);
+
+ dev_dbg(inst->dev->dev, "%s: dec_finish_seq complete\n", __func__);
+
+ wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_work);
+
+ for (i = 0 ; i < MAX_REG_FRAME; i++) {
+ ret = reset_auxiliary_buffers(inst, i);
+ if (ret) {
+ ret = 0;
+ break;
+ }
+ }
+
+ wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_task);
+
+unlock_and_return:
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_dec_issue_seq_init(struct vpu_instance *inst)
+{
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave5_vpu_dec_init_seq(inst);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_dec_complete_seq_init(struct vpu_instance *inst, struct dec_initial_info *info)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave5_vpu_dec_get_seq_info(inst, info);
+ if (!ret)
+ p_dec_info->initial_info_obtained = true;
+
+ info->rd_ptr = wave5_dec_get_rd_ptr(inst);
+ info->wr_ptr = p_dec_info->stream_wr_ptr;
+
+ p_dec_info->initial_info = *info;
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_dec_register_frame_buffer_ex(struct vpu_instance *inst, int num_of_decoding_fbs,
+ int num_of_display_fbs, int stride, int height)
+{
+ struct dec_info *p_dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+ struct frame_buffer *fb;
+
+ if (num_of_decoding_fbs >= WAVE5_MAX_FBS || num_of_display_fbs >= WAVE5_MAX_FBS)
+ return -EINVAL;
+
+ p_dec_info = &inst->codec_info->dec_info;
+ p_dec_info->num_of_decoding_fbs = num_of_decoding_fbs;
+ p_dec_info->num_of_display_fbs = num_of_display_fbs;
+ p_dec_info->stride = stride;
+
+ if (!p_dec_info->initial_info_obtained)
+ return -EINVAL;
+
+ if (stride < p_dec_info->initial_info.pic_width || (stride % 8 != 0) ||
+ height < p_dec_info->initial_info.pic_height)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ fb = inst->frame_buf;
+ ret = wave5_vpu_dec_register_framebuffer(inst, &fb[p_dec_info->num_of_decoding_fbs],
+ LINEAR_FRAME_MAP, p_dec_info->num_of_display_fbs);
+ if (ret)
+ goto err_out;
+
+ ret = wave5_vpu_dec_register_framebuffer(inst, &fb[0], COMPRESSED_FRAME_MAP,
+ p_dec_info->num_of_decoding_fbs);
+
+err_out:
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_dec_get_bitstream_buffer(struct vpu_instance *inst, dma_addr_t *prd_ptr,
+ dma_addr_t *pwr_ptr, size_t *size)
+{
+ struct dec_info *p_dec_info;
+ dma_addr_t rd_ptr;
+ dma_addr_t wr_ptr;
+ int room;
+ struct vpu_device *vpu_dev = inst->dev;
+ int ret;
+
+ p_dec_info = &inst->codec_info->dec_info;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+ rd_ptr = wave5_dec_get_rd_ptr(inst);
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ wr_ptr = p_dec_info->stream_wr_ptr;
+
+ if (wr_ptr < rd_ptr)
+ room = rd_ptr - wr_ptr;
+ else
+ room = (p_dec_info->stream_buf_end_addr - wr_ptr) +
+ (rd_ptr - p_dec_info->stream_buf_start_addr);
+ room--;
+
+ if (prd_ptr)
+ *prd_ptr = rd_ptr;
+ if (pwr_ptr)
+ *pwr_ptr = wr_ptr;
+ if (size)
+ *size = room;
+
+ return 0;
+}
+
+int wave5_vpu_dec_update_bitstream_buffer(struct vpu_instance *inst, size_t size)
+{
+ struct dec_info *p_dec_info;
+ dma_addr_t wr_ptr;
+ dma_addr_t rd_ptr;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ if (!inst->codec_info)
+ return -EINVAL;
+
+ p_dec_info = &inst->codec_info->dec_info;
+ wr_ptr = p_dec_info->stream_wr_ptr;
+ rd_ptr = p_dec_info->stream_rd_ptr;
+
+ if (size > 0) {
+ if (wr_ptr < rd_ptr && rd_ptr <= wr_ptr + size)
+ return -EINVAL;
+
+ wr_ptr += size;
+
+ if (wr_ptr > p_dec_info->stream_buf_end_addr) {
+ u32 room = wr_ptr - p_dec_info->stream_buf_end_addr;
+
+ wr_ptr = p_dec_info->stream_buf_start_addr;
+ wr_ptr += room;
+ } else if (wr_ptr == p_dec_info->stream_buf_end_addr) {
+ wr_ptr = p_dec_info->stream_buf_start_addr;
+ }
+
+ p_dec_info->stream_wr_ptr = wr_ptr;
+ p_dec_info->stream_rd_ptr = rd_ptr;
+ }
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+ ret = wave5_vpu_dec_set_bitstream_flag(inst, (size == 0));
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_dec_start_one_frame(struct vpu_instance *inst, u32 *res_fail)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ if (p_dec_info->stride == 0) /* this means frame buffers have not been registered. */
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave5_vpu_decode(inst, res_fail);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr, int update_wr_ptr)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave5_dec_set_rd_ptr(inst, addr);
+
+ p_dec_info->stream_rd_ptr = addr;
+ if (update_wr_ptr)
+ p_dec_info->stream_wr_ptr = addr;
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+dma_addr_t wave5_vpu_dec_get_rd_ptr(struct vpu_instance *inst)
+{
+ int ret;
+ dma_addr_t rd_ptr;
+
+ ret = mutex_lock_interruptible(&inst->dev->hw_lock);
+ if (ret)
+ return ret;
+
+ rd_ptr = wave5_dec_get_rd_ptr(inst);
+
+ mutex_unlock(&inst->dev->hw_lock);
+
+ return rd_ptr;
+}
+
+int wave5_vpu_dec_get_output_info(struct vpu_instance *inst, struct dec_output_info *info)
+{
+ struct dec_info *p_dec_info;
+ int ret;
+ struct vpu_rect rect_info;
+ u32 val;
+ u32 decoded_index;
+ u32 disp_idx;
+ u32 max_dec_index;
+ struct vpu_device *vpu_dev = inst->dev;
+ struct dec_output_info *disp_info;
+
+ if (!info)
+ return -EINVAL;
+
+ p_dec_info = &inst->codec_info->dec_info;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ memset(info, 0, sizeof(*info));
+
+ ret = wave5_vpu_dec_get_result(inst, info);
+ if (ret) {
+ info->rd_ptr = p_dec_info->stream_rd_ptr;
+ info->wr_ptr = p_dec_info->stream_wr_ptr;
+ goto err_out;
+ }
+
+ decoded_index = info->index_frame_decoded;
+
+ /* calculate display frame region */
+ val = 0;
+ rect_info.left = 0;
+ rect_info.right = 0;
+ rect_info.top = 0;
+ rect_info.bottom = 0;
+
+ if (decoded_index < WAVE5_MAX_FBS) {
+ if (inst->std == W_HEVC_DEC || inst->std == W_AVC_DEC)
+ rect_info = p_dec_info->initial_info.pic_crop_rect;
+
+ if (inst->std == W_HEVC_DEC)
+ p_dec_info->dec_out_info[decoded_index].decoded_poc = info->decoded_poc;
+
+ p_dec_info->dec_out_info[decoded_index].rc_decoded = rect_info;
+ }
+ info->rc_decoded = rect_info;
+
+ disp_idx = info->index_frame_display;
+ if (info->index_frame_display >= 0 && info->index_frame_display < WAVE5_MAX_FBS) {
+ disp_info = &p_dec_info->dec_out_info[disp_idx];
+ if (info->index_frame_display != info->index_frame_decoded) {
+ /*
+ * when index_frame_decoded < 0, and index_frame_display >= 0
+ * info->dec_pic_width and info->dec_pic_height are still valid
+ * but those of p_dec_info->dec_out_info[disp_idx] are invalid in VP9
+ */
+ info->disp_pic_width = disp_info->dec_pic_width;
+ info->disp_pic_height = disp_info->dec_pic_height;
+ } else {
+ info->disp_pic_width = info->dec_pic_width;
+ info->disp_pic_height = info->dec_pic_height;
+ }
+
+ info->rc_display = disp_info->rc_decoded;
+
+ } else {
+ info->rc_display.left = 0;
+ info->rc_display.right = 0;
+ info->rc_display.top = 0;
+ info->rc_display.bottom = 0;
+ info->disp_pic_width = 0;
+ info->disp_pic_height = 0;
+ }
+
+ p_dec_info->stream_rd_ptr = wave5_dec_get_rd_ptr(inst);
+ p_dec_info->frame_display_flag = vpu_read_reg(vpu_dev, W5_RET_DEC_DISP_IDC);
+
+ val = p_dec_info->num_of_decoding_fbs; //fb_offset
+
+ max_dec_index = (p_dec_info->num_of_decoding_fbs > p_dec_info->num_of_display_fbs) ?
+ p_dec_info->num_of_decoding_fbs : p_dec_info->num_of_display_fbs;
+
+ if (info->index_frame_display >= 0 &&
+ info->index_frame_display < (int)max_dec_index)
+ info->disp_frame = inst->frame_buf[val + info->index_frame_display];
+
+ info->rd_ptr = p_dec_info->stream_rd_ptr;
+ info->wr_ptr = p_dec_info->stream_wr_ptr;
+ info->frame_display_flag = p_dec_info->frame_display_flag;
+
+ info->sequence_no = p_dec_info->initial_info.sequence_no;
+ if (decoded_index < WAVE5_MAX_FBS)
+ p_dec_info->dec_out_info[decoded_index] = *info;
+
+ if (disp_idx < WAVE5_MAX_FBS)
+ info->disp_frame.sequence_no = info->sequence_no;
+
+ if (info->sequence_changed) {
+ memcpy((void *)&p_dec_info->initial_info, (void *)&p_dec_info->new_seq_info,
+ sizeof(struct dec_initial_info));
+ p_dec_info->initial_info.sequence_no++;
+ }
+
+err_out:
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_dec_clr_disp_flag(struct vpu_instance *inst, int index)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ if (index >= p_dec_info->num_of_display_fbs)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+ ret = wave5_dec_clr_disp_flag(inst, index);
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_dec_set_disp_flag(struct vpu_instance *inst, int index)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int ret = 0;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ if (index >= p_dec_info->num_of_display_fbs)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+ ret = wave5_dec_set_disp_flag(inst, index);
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_dec_reset_framebuffer(struct vpu_instance *inst, unsigned int index)
+{
+ if (index >= MAX_REG_FRAME)
+ return -EINVAL;
+
+ if (inst->frame_vbuf[index].size == 0)
+ return -EINVAL;
+
+ wave5_vdi_free_dma_memory(inst->dev, &inst->frame_vbuf[index]);
+
+ return 0;
+}
+
+int wave5_vpu_dec_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter)
+{
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ int ret = 0;
+
+ switch (cmd) {
+ case DEC_GET_QUEUE_STATUS: {
+ struct queue_status_info *queue_info = parameter;
+
+ queue_info->instance_queue_count = p_dec_info->instance_queue_count;
+ queue_info->report_queue_count = p_dec_info->report_queue_count;
+ break;
+ }
+ case DEC_RESET_FRAMEBUF_INFO: {
+ int i;
+
+ for (i = 0; i < MAX_REG_FRAME; i++) {
+ ret = wave5_vpu_dec_reset_framebuffer(inst, i);
+ if (ret)
+ break;
+ }
+
+ for (i = 0; i < MAX_REG_FRAME; i++) {
+ ret = reset_auxiliary_buffers(inst, i);
+ if (ret)
+ break;
+ }
+
+ wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task);
+ break;
+ }
+ case DEC_GET_SEQ_INFO: {
+ struct dec_initial_info *seq_info = parameter;
+
+ *seq_info = p_dec_info->initial_info;
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+int wave5_vpu_enc_open(struct vpu_instance *inst, struct enc_open_param *open_param)
+{
+ struct enc_info *p_enc_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = wave5_vpu_enc_check_open_param(inst, open_param);
+ if (ret)
+ return ret;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ if (!wave5_vpu_is_init(vpu_dev)) {
+ mutex_unlock(&vpu_dev->hw_lock);
+ return -ENODEV;
+ }
+
+ p_enc_info = &inst->codec_info->enc_info;
+ p_enc_info->open_param = *open_param;
+
+ ret = wave5_vpu_build_up_enc_param(vpu_dev->dev, inst, open_param);
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ int ret;
+ int retry = 0;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ *fail_res = 0;
+ if (!inst->codec_info)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ do {
+ ret = wave5_vpu_enc_finish_seq(inst, fail_res);
+ if (ret < 0 && *fail_res != WAVE5_SYSERR_VPU_STILL_RUNNING) {
+ dev_warn(inst->dev->dev, "enc_finish_seq timed out\n");
+ mutex_unlock(&vpu_dev->hw_lock);
+ return ret;
+ }
+
+ if (*fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING &&
+ retry++ >= MAX_FIRMWARE_CALL_RETRY) {
+ mutex_unlock(&vpu_dev->hw_lock);
+ return -ETIMEDOUT;
+ }
+ } while (ret != 0);
+
+ dev_dbg(inst->dev->dev, "%s: enc_finish_seq complete\n", __func__);
+
+ wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_work);
+
+ if (inst->std == W_HEVC_ENC || inst->std == W_AVC_ENC) {
+ wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_sub_sam_buf);
+ wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_mv);
+ wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_fbc_y_tbl);
+ wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_fbc_c_tbl);
+ }
+
+ wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_task);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return 0;
+}
+
+int wave5_vpu_enc_register_frame_buffer(struct vpu_instance *inst, unsigned int num,
+ unsigned int stride, int height,
+ enum tiled_map_type map_type)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+ unsigned int size_luma, size_chroma;
+ int i;
+
+ if (p_enc_info->stride)
+ return -EINVAL;
+
+ if (!p_enc_info->initial_info_obtained)
+ return -EINVAL;
+
+ if (num < p_enc_info->initial_info.min_frame_buffer_count)
+ return -EINVAL;
+
+ if (stride == 0 || stride % 8 != 0)
+ return -EINVAL;
+
+ if (height <= 0)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ p_enc_info->num_frame_buffers = num;
+ p_enc_info->stride = stride;
+
+ size_luma = stride * height;
+ size_chroma = ALIGN(stride / 2, 16) * height;
+
+ for (i = 0; i < num; i++) {
+ if (!inst->frame_buf[i].update_fb_info)
+ continue;
+
+ inst->frame_buf[i].update_fb_info = false;
+ inst->frame_buf[i].stride = stride;
+ inst->frame_buf[i].height = height;
+ inst->frame_buf[i].map_type = COMPRESSED_FRAME_MAP;
+ inst->frame_buf[i].buf_y_size = size_luma;
+ inst->frame_buf[i].buf_cb = inst->frame_buf[i].buf_y + size_luma;
+ inst->frame_buf[i].buf_cb_size = size_chroma;
+ inst->frame_buf[i].buf_cr_size = 0;
+ }
+
+ ret = wave5_vpu_enc_register_framebuffer(inst->dev->dev, inst, &inst->frame_buf[0],
+ COMPRESSED_FRAME_MAP,
+ p_enc_info->num_frame_buffers);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+static int wave5_check_enc_param(struct vpu_instance *inst, struct enc_param *param)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+
+ if (!param)
+ return -EINVAL;
+
+ if (!param->source_frame)
+ return -EINVAL;
+
+ if (p_enc_info->open_param.bit_rate == 0 && inst->std == W_HEVC_ENC) {
+ if (param->pic_stream_buffer_addr % 16 || param->pic_stream_buffer_size == 0)
+ return -EINVAL;
+ }
+ if (param->pic_stream_buffer_addr % 8 || param->pic_stream_buffer_size == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+int wave5_vpu_enc_start_one_frame(struct vpu_instance *inst, struct enc_param *param, u32 *fail_res)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ *fail_res = 0;
+
+ if (p_enc_info->stride == 0) /* this means frame buffers have not been registered. */
+ return -EINVAL;
+
+ ret = wave5_check_enc_param(inst, param);
+ if (ret)
+ return ret;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ p_enc_info->pts_map[param->src_idx] = param->pts;
+
+ ret = wave5_vpu_encode(inst, param, fail_res);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_enc_get_output_info(struct vpu_instance *inst, struct enc_output_info *info)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave5_vpu_enc_get_result(inst, info);
+ if (ret) {
+ info->pts = 0;
+ goto unlock;
+ }
+
+ if (info->recon_frame_index >= 0)
+ info->pts = p_enc_info->pts_map[info->enc_src_idx];
+
+unlock:
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_enc_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+
+ switch (cmd) {
+ case ENABLE_ROTATION:
+ p_enc_info->rotation_enable = true;
+ break;
+ case ENABLE_MIRRORING:
+ p_enc_info->mirror_enable = true;
+ break;
+ case SET_MIRROR_DIRECTION: {
+ enum mirror_direction mir_dir;
+
+ mir_dir = *(enum mirror_direction *)parameter;
+ if (mir_dir != MIRDIR_NONE && mir_dir != MIRDIR_HOR &&
+ mir_dir != MIRDIR_VER && mir_dir != MIRDIR_HOR_VER)
+ return -EINVAL;
+ p_enc_info->mirror_direction = mir_dir;
+ break;
+ }
+ case SET_ROTATION_ANGLE: {
+ int angle;
+
+ angle = *(int *)parameter;
+ if (angle && angle != 90 && angle != 180 && angle != 270)
+ return -EINVAL;
+ if (p_enc_info->initial_info_obtained && (angle == 90 || angle == 270))
+ return -EINVAL;
+ p_enc_info->rotation_angle = angle;
+ break;
+ }
+ case ENC_GET_QUEUE_STATUS: {
+ struct queue_status_info *queue_info = parameter;
+
+ queue_info->instance_queue_count = p_enc_info->instance_queue_count;
+ queue_info->report_queue_count = p_enc_info->report_queue_count;
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int wave5_vpu_enc_issue_seq_init(struct vpu_instance *inst)
+{
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave5_vpu_enc_init_seq(inst);
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return ret;
+}
+
+int wave5_vpu_enc_complete_seq_init(struct vpu_instance *inst, struct enc_initial_info *info)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ int ret;
+ struct vpu_device *vpu_dev = inst->dev;
+
+ if (!info)
+ return -EINVAL;
+
+ ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
+ if (ret)
+ return ret;
+
+ ret = wave5_vpu_enc_get_seq_info(inst, info);
+ if (ret) {
+ p_enc_info->initial_info_obtained = false;
+ mutex_unlock(&vpu_dev->hw_lock);
+ return ret;
+ }
+
+ p_enc_info->initial_info_obtained = true;
+ p_enc_info->initial_info = *info;
+
+ mutex_unlock(&vpu_dev->hw_lock);
+
+ return 0;
+}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
new file mode 100644
index 000000000000..352f6e904e50
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
@@ -0,0 +1,870 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave5 series multi-standard codec IP - helper definitions
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#ifndef VPUAPI_H_INCLUDED
+#define VPUAPI_H_INCLUDED
+
+#include <linux/idr.h>
+#include <linux/genalloc.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-ctrls.h>
+#include "wave5-vpuerror.h"
+#include "wave5-vpuconfig.h"
+#include "wave5-vdi.h"
+
+enum product_id {
+ PRODUCT_ID_521,
+ PRODUCT_ID_511,
+ PRODUCT_ID_517,
+ PRODUCT_ID_NONE,
+};
+
+struct vpu_attr;
+
+enum vpu_instance_type {
+ VPU_INST_TYPE_DEC = 0,
+ VPU_INST_TYPE_ENC = 1
+};
+
+enum vpu_instance_state {
+ VPU_INST_STATE_NONE = 0,
+ VPU_INST_STATE_OPEN = 1,
+ VPU_INST_STATE_INIT_SEQ = 2,
+ VPU_INST_STATE_PIC_RUN = 3,
+ VPU_INST_STATE_STOP = 4
+};
+
+/* Maximum available on hardware. */
+#define WAVE5_MAX_FBS 32
+
+#define MAX_REG_FRAME (WAVE5_MAX_FBS * 2)
+
+#define WAVE5_DEC_HEVC_BUF_SIZE(_w, _h) (DIV_ROUND_UP(_w, 64) * DIV_ROUND_UP(_h, 64) * 256 + 64)
+#define WAVE5_DEC_AVC_BUF_SIZE(_w, _h) ((((ALIGN(_w, 256) / 16) * (ALIGN(_h, 16) / 16)) + 16) * 80)
+
+#define WAVE5_FBC_LUMA_TABLE_SIZE(_w, _h) (ALIGN(_h, 64) * ALIGN(_w, 256) / 32)
+#define WAVE5_FBC_CHROMA_TABLE_SIZE(_w, _h) (ALIGN((_h), 64) * ALIGN((_w) / 2, 256) / 32)
+#define WAVE5_ENC_AVC_BUF_SIZE(_w, _h) (ALIGN(_w, 64) * ALIGN(_h, 64) / 32)
+#define WAVE5_ENC_HEVC_BUF_SIZE(_w, _h) (ALIGN(_w, 64) / 64 * ALIGN(_h, 64) / 64 * 128)
+
+/*
+ * common struct and definition
+ */
+enum cod_std {
+ STD_AVC = 0,
+ STD_HEVC = 12,
+ STD_MAX
+};
+
+enum wave_std {
+ W_HEVC_DEC = 0x00,
+ W_HEVC_ENC = 0x01,
+ W_AVC_DEC = 0x02,
+ W_AVC_ENC = 0x03,
+ STD_UNKNOWN = 0xFF
+};
+
+enum set_param_option {
+ OPT_COMMON = 0, /* SET_PARAM command option for encoding sequence */
+ OPT_CUSTOM_GOP = 1, /* SET_PARAM command option for setting custom GOP */
+ OPT_CUSTOM_HEADER = 2, /* SET_PARAM command option for setting custom VPS/SPS/PPS */
+ OPT_VUI = 3, /* SET_PARAM command option for encoding VUI */
+ OPT_CHANGE_PARAM = 0x10,
+};
+
+/************************************************************************/
+/* PROFILE & LEVEL */
+/************************************************************************/
+/* HEVC */
+#define HEVC_PROFILE_MAIN 1
+#define HEVC_PROFILE_MAIN10 2
+#define HEVC_PROFILE_STILLPICTURE 3
+#define HEVC_PROFILE_MAIN10_STILLPICTURE 2
+
+/* H.264 profile for encoder*/
+#define H264_PROFILE_BP 1
+#define H264_PROFILE_MP 2
+#define H264_PROFILE_EXTENDED 3
+#define H264_PROFILE_HP 4
+#define H264_PROFILE_HIGH10 5
+#define H264_PROFILE_HIGH422 6
+#define H264_PROFILE_HIGH444 7
+
+/************************************************************************/
+/* error codes */
+/************************************************************************/
+
+/************************************************************************/
+/* utility macros */
+/************************************************************************/
+
+/* Initialize sequence firmware command mode */
+#define INIT_SEQ_NORMAL 1
+
+/* Decode firmware command mode */
+#define DEC_PIC_NORMAL 0
+
+/* bit_alloc_mode */
+#define BIT_ALLOC_MODE_FIXED_RATIO 2
+
+/* bit_rate */
+#define MAX_BIT_RATE 700000000
+
+/* decoding_refresh_type */
+#define DEC_REFRESH_TYPE_NON_IRAP 0
+#define DEC_REFRESH_TYPE_CRA 1
+#define DEC_REFRESH_TYPE_IDR 2
+
+/* depend_slice_mode */
+#define DEPEND_SLICE_MODE_RECOMMENDED 1
+#define DEPEND_SLICE_MODE_BOOST 2
+#define DEPEND_SLICE_MODE_FAST 3
+
+/* hvs_max_delta_qp */
+#define MAX_HVS_MAX_DELTA_QP 51
+
+/* intra_refresh_mode */
+#define REFRESH_MODE_CTU_ROWS 1
+#define REFRESH_MODE_CTU_COLUMNS 2
+#define REFRESH_MODE_CTU_STEP_SIZE 3
+#define REFRESH_MODE_CTUS 4
+
+/* intra_mb_refresh_mode */
+#define REFRESH_MB_MODE_NONE 0
+#define REFRESH_MB_MODE_CTU_ROWS 1
+#define REFRESH_MB_MODE_CTU_COLUMNS 2
+#define REFRESH_MB_MODE_CTU_STEP_SIZE 3
+
+/* intra_qp */
+#define MAX_INTRA_QP 63
+
+/* nr_inter_weight_* */
+#define MAX_INTER_WEIGHT 31
+
+/* nr_intra_weight_* */
+#define MAX_INTRA_WEIGHT 31
+
+/* nr_noise_sigma_* */
+#define MAX_NOISE_SIGMA 255
+
+/* bitstream_buffer_size */
+#define MIN_BITSTREAM_BUFFER_SIZE 1024
+#define MIN_BITSTREAM_BUFFER_SIZE_WAVE521 (1024 * 64)
+
+/* vbv_buffer_size */
+#define MIN_VBV_BUFFER_SIZE 10
+#define MAX_VBV_BUFFER_SIZE 3000
+
+#define BUFFER_MARGIN 4096
+
+#define MAX_FIRMWARE_CALL_RETRY 10
+
+#define VDI_LITTLE_ENDIAN 0x0
+
+/*
+ * Parameters of DEC_SET_SEQ_CHANGE_MASK
+ */
+#define SEQ_CHANGE_ENABLE_PROFILE BIT(5)
+#define SEQ_CHANGE_ENABLE_SIZE BIT(16)
+#define SEQ_CHANGE_ENABLE_BITDEPTH BIT(18)
+#define SEQ_CHANGE_ENABLE_DPB_COUNT BIT(19)
+#define SEQ_CHANGE_ENABLE_ASPECT_RATIO BIT(21)
+#define SEQ_CHANGE_ENABLE_VIDEO_SIGNAL BIT(23)
+#define SEQ_CHANGE_ENABLE_VUI_TIMING_INFO BIT(29)
+
+#define SEQ_CHANGE_ENABLE_ALL_HEVC (SEQ_CHANGE_ENABLE_PROFILE | \
+ SEQ_CHANGE_ENABLE_SIZE | \
+ SEQ_CHANGE_ENABLE_BITDEPTH | \
+ SEQ_CHANGE_ENABLE_DPB_COUNT)
+
+#define SEQ_CHANGE_ENABLE_ALL_AVC (SEQ_CHANGE_ENABLE_SIZE | \
+ SEQ_CHANGE_ENABLE_BITDEPTH | \
+ SEQ_CHANGE_ENABLE_DPB_COUNT | \
+ SEQ_CHANGE_ENABLE_ASPECT_RATIO | \
+ SEQ_CHANGE_ENABLE_VIDEO_SIGNAL | \
+ SEQ_CHANGE_ENABLE_VUI_TIMING_INFO)
+
+#define DISPLAY_IDX_FLAG_SEQ_END -1
+#define DISPLAY_IDX_FLAG_NO_FB -3
+#define DECODED_IDX_FLAG_NO_FB -1
+#define DECODED_IDX_FLAG_SKIP -2
+
+#define RECON_IDX_FLAG_ENC_END -1
+#define RECON_IDX_FLAG_ENC_DELAY -2
+#define RECON_IDX_FLAG_HEADER_ONLY -3
+#define RECON_IDX_FLAG_CHANGE_PARAM -4
+
+enum codec_command {
+ ENABLE_ROTATION,
+ ENABLE_MIRRORING,
+ SET_MIRROR_DIRECTION,
+ SET_ROTATION_ANGLE,
+ DEC_GET_QUEUE_STATUS,
+ ENC_GET_QUEUE_STATUS,
+ DEC_RESET_FRAMEBUF_INFO,
+ DEC_GET_SEQ_INFO,
+};
+
+enum mirror_direction {
+ MIRDIR_NONE, /* no mirroring */
+ MIRDIR_VER, /* vertical mirroring */
+ MIRDIR_HOR, /* horizontal mirroring */
+ MIRDIR_HOR_VER /* horizontal and vertical mirroring */
+};
+
+enum frame_buffer_format {
+ FORMAT_ERR = -1,
+ FORMAT_420 = 0, /* 8bit */
+ FORMAT_422, /* 8bit */
+ FORMAT_224, /* 8bit */
+ FORMAT_444, /* 8bit */
+ FORMAT_400, /* 8bit */
+
+ /* little endian perspective */
+ /* | addr 0 | addr 1 | */
+ FORMAT_420_P10_16BIT_MSB = 5, /* lsb |000000xx|xxxxxxxx | msb */
+ FORMAT_420_P10_16BIT_LSB, /* lsb |xxxxxxx |xx000000 | msb */
+ FORMAT_420_P10_32BIT_MSB, /* lsb |00xxxxxxxxxxxxxxxxxxxxxxxxxxx| msb */
+ FORMAT_420_P10_32BIT_LSB, /* lsb |xxxxxxxxxxxxxxxxxxxxxxxxxxx00| msb */
+
+ /* 4:2:2 packed format */
+ /* little endian perspective */
+ /* | addr 0 | addr 1 | */
+ FORMAT_422_P10_16BIT_MSB, /* lsb |000000xx |xxxxxxxx | msb */
+ FORMAT_422_P10_16BIT_LSB, /* lsb |xxxxxxxx |xx000000 | msb */
+ FORMAT_422_P10_32BIT_MSB, /* lsb |00xxxxxxxxxxxxxxxxxxxxxxxxxxx| msb */
+ FORMAT_422_P10_32BIT_LSB, /* lsb |xxxxxxxxxxxxxxxxxxxxxxxxxxx00| msb */
+
+ FORMAT_YUYV, /* 8bit packed format : Y0U0Y1V0 Y2U1Y3V1 ... */
+ FORMAT_YUYV_P10_16BIT_MSB,
+ FORMAT_YUYV_P10_16BIT_LSB,
+ FORMAT_YUYV_P10_32BIT_MSB,
+ FORMAT_YUYV_P10_32BIT_LSB,
+
+ FORMAT_YVYU, /* 8bit packed format : Y0V0Y1U0 Y2V1Y3U1 ... */
+ FORMAT_YVYU_P10_16BIT_MSB,
+ FORMAT_YVYU_P10_16BIT_LSB,
+ FORMAT_YVYU_P10_32BIT_MSB,
+ FORMAT_YVYU_P10_32BIT_LSB,
+
+ FORMAT_UYVY, /* 8bit packed format : U0Y0V0Y1 U1Y2V1Y3 ... */
+ FORMAT_UYVY_P10_16BIT_MSB,
+ FORMAT_UYVY_P10_16BIT_LSB,
+ FORMAT_UYVY_P10_32BIT_MSB,
+ FORMAT_UYVY_P10_32BIT_LSB,
+
+ FORMAT_VYUY, /* 8bit packed format : V0Y0U0Y1 V1Y2U1Y3 ... */
+ FORMAT_VYUY_P10_16BIT_MSB,
+ FORMAT_VYUY_P10_16BIT_LSB,
+ FORMAT_VYUY_P10_32BIT_MSB,
+ FORMAT_VYUY_P10_32BIT_LSB,
+
+ FORMAT_MAX,
+};
+
+enum packed_format_num {
+ NOT_PACKED = 0,
+ PACKED_YUYV,
+ PACKED_YVYU,
+ PACKED_UYVY,
+ PACKED_VYUY,
+};
+
+enum wave5_interrupt_bit {
+ INT_WAVE5_INIT_VPU = 0,
+ INT_WAVE5_WAKEUP_VPU = 1,
+ INT_WAVE5_SLEEP_VPU = 2,
+ INT_WAVE5_CREATE_INSTANCE = 3,
+ INT_WAVE5_FLUSH_INSTANCE = 4,
+ INT_WAVE5_DESTROY_INSTANCE = 5,
+ INT_WAVE5_INIT_SEQ = 6,
+ INT_WAVE5_SET_FRAMEBUF = 7,
+ INT_WAVE5_DEC_PIC = 8,
+ INT_WAVE5_ENC_PIC = 8,
+ INT_WAVE5_ENC_SET_PARAM = 9,
+ INT_WAVE5_DEC_QUERY = 14,
+ INT_WAVE5_BSBUF_EMPTY = 15,
+ INT_WAVE5_BSBUF_FULL = 15,
+};
+
+enum pic_type {
+ PIC_TYPE_I = 0,
+ PIC_TYPE_P = 1,
+ PIC_TYPE_B = 2,
+ PIC_TYPE_IDR = 5, /* H.264/H.265 IDR (Instantaneous Decoder Refresh) picture */
+ PIC_TYPE_MAX /* no meaning */
+};
+
+enum sw_reset_mode {
+ SW_RESET_SAFETY,
+ SW_RESET_FORCE,
+ SW_RESET_ON_BOOT
+};
+
+enum tiled_map_type {
+ LINEAR_FRAME_MAP = 0, /* linear frame map type */
+ COMPRESSED_FRAME_MAP = 17, /* compressed frame map type*/
+};
+
+enum temporal_id_mode {
+ TEMPORAL_ID_MODE_ABSOLUTE,
+ TEMPORAL_ID_MODE_RELATIVE,
+};
+
+struct vpu_attr {
+ u32 product_id;
+ char product_name[8]; /* product name in ascii code */
+ u32 product_version;
+ u32 fw_version;
+ u32 customer_id;
+ u32 support_decoders; /* bitmask */
+ u32 support_encoders; /* bitmask */
+ u32 support_backbone: 1;
+ u32 support_avc10bit_enc: 1;
+ u32 support_hevc10bit_enc: 1;
+ u32 support_vcore_backbone: 1;
+ u32 support_vcpu_backbone: 1;
+};
+
+struct frame_buffer {
+ dma_addr_t buf_y;
+ dma_addr_t buf_cb;
+ dma_addr_t buf_cr;
+ unsigned int buf_y_size;
+ unsigned int buf_cb_size;
+ unsigned int buf_cr_size;
+ enum tiled_map_type map_type;
+ unsigned int stride; /* horizontal stride for the given frame buffer */
+ unsigned int width; /* width of the given frame buffer */
+ unsigned int height; /* height of the given frame buffer */
+ size_t size; /* size of the given frame buffer */
+ unsigned int sequence_no;
+ bool update_fb_info;
+};
+
+struct vpu_rect {
+ unsigned int left; /* horizontal pixel offset from left edge */
+ unsigned int top; /* vertical pixel offset from top edge */
+ unsigned int right; /* horizontal pixel offset from right edge */
+ unsigned int bottom; /* vertical pixel offset from bottom edge */
+};
+
+/*
+ * decode struct and definition
+ */
+
+struct dec_open_param {
+ dma_addr_t bitstream_buffer;
+ size_t bitstream_buffer_size;
+};
+
+struct dec_initial_info {
+ u32 pic_width;
+ u32 pic_height;
+ struct vpu_rect pic_crop_rect;
+ u32 min_frame_buffer_count; /* between 1 to 16 */
+
+ u32 profile;
+ u32 luma_bitdepth; /* bit-depth of the luma sample */
+ u32 chroma_bitdepth; /* bit-depth of the chroma sample */
+ u32 seq_init_err_reason;
+ dma_addr_t rd_ptr; /* read pointer of bitstream buffer */
+ dma_addr_t wr_ptr; /* write pointer of bitstream buffer */
+ u32 sequence_no;
+ u32 vlc_buf_size;
+ u32 param_buf_size;
+};
+
+struct dec_output_info {
+ /**
+ * This is a frame buffer index for the picture to be displayed at the moment
+ * among frame buffers which are registered using vpu_dec_register_frame_buffer().
+ * Frame data that will be displayed is stored in the frame buffer with this index
+ * When there is no display delay, this index is always the equal to
+ * index_frame_decoded, however, if displaying is delayed (for display
+ * reordering in AVC or B-frames in VC1), this index might be different to
+ * index_frame_decoded. By checking this index, HOST applications can easily figure
+ * out whether sequence decoding has been finished or not.
+ *
+ * -3(0xFFFD) or -2(0xFFFE) : when a display output cannot be given due to picture
+ * reordering or skip option
+ * -1(0xFFFF) : when there is no more output for display at the end of sequence
+ * decoding
+ */
+ s32 index_frame_display;
+ /**
+ * This is the frame buffer index of the decoded picture among the frame buffers which were
+ * registered using vpu_dec_register_frame_buffer(). The currently decoded frame is stored
+ * into the frame buffer specified by this index.
+ *
+ * -2 : indicates that no decoded output is generated because decoder meets EOS
+ * (end of sequence) or skip
+ * -1 : indicates that the decoder fails to decode a picture because there is no available
+ * frame buffer
+ */
+ s32 index_frame_decoded;
+ s32 index_frame_decoded_for_tiled;
+ u32 nal_type;
+ unsigned int pic_type;
+ struct vpu_rect rc_display;
+ unsigned int disp_pic_width;
+ unsigned int disp_pic_height;
+ struct vpu_rect rc_decoded;
+ u32 dec_pic_width;
+ u32 dec_pic_height;
+ s32 decoded_poc;
+ int temporal_id; /* temporal ID of the picture */
+ dma_addr_t rd_ptr; /* stream buffer read pointer for the current decoder instance */
+ dma_addr_t wr_ptr; /* stream buffer write pointer for the current decoder instance */
+ struct frame_buffer disp_frame;
+ u32 frame_display_flag; /* it reports a frame buffer flag to be displayed */
+ /**
+ * this variable reports that sequence has been changed while H.264/AVC stream decoding.
+ * if it is 1, HOST application can get the new sequence information by calling
+ * vpu_dec_get_initial_info() or wave5_vpu_dec_issue_seq_init().
+ *
+ * for H.265/HEVC decoder, each bit has a different meaning as follows.
+ *
+ * sequence_changed[5] : it indicates that the profile_idc has been changed
+ * sequence_changed[16] : it indicates that the resolution has been changed
+ * sequence_changed[19] : it indicates that the required number of frame buffer has
+ * been changed.
+ */
+ unsigned int frame_cycle; /* reports the number of cycles for processing a frame */
+ u32 sequence_no;
+
+ u32 dec_host_cmd_tick; /* tick of DEC_PIC command for the picture */
+ u32 dec_decode_end_tick; /* end tick of decoding slices of the picture */
+
+ u32 sequence_changed;
+};
+
+struct queue_status_info {
+ u32 instance_queue_count;
+ u32 report_queue_count;
+};
+
+/*
+ * encode struct and definition
+ */
+
+#define MAX_NUM_TEMPORAL_LAYER 7
+#define MAX_NUM_SPATIAL_LAYER 3
+#define MAX_GOP_NUM 8
+
+struct custom_gop_pic_param {
+ u32 pic_type; /* picture type of nth picture in the custom GOP */
+ u32 poc_offset; /* POC of nth picture in the custom GOP */
+ u32 pic_qp; /* quantization parameter of nth picture in the custom GOP */
+ u32 use_multi_ref_p; /* use multiref pic for P picture. valid only if PIC_TYPE is P */
+ u32 ref_poc_l0; /* POC of reference L0 of nth picture in the custom GOP */
+ u32 ref_poc_l1; /* POC of reference L1 of nth picture in the custom GOP */
+ s32 temporal_id; /* temporal ID of nth picture in the custom GOP */
+};
+
+struct enc_wave_param {
+ /*
+ * profile indicator (HEVC only)
+ *
+ * 0 : the firmware determines a profile according to the internal_bit_depth
+ * 1 : main profile
+ * 2 : main10 profile
+ * 3 : main still picture profile
+ * In the AVC encoder, a profile cannot be set by the host application.
+ * The firmware decides it based on internal_bit_depth.
+ * profile = HIGH (bitdepth 8) profile = HIGH10 (bitdepth 10)
+ */
+ u32 profile;
+ u32 level; /* level indicator (level * 10) */
+ u32 internal_bit_depth: 4; /* 8/10 */
+ u32 gop_preset_idx: 4; /* 0 - 9 */
+ u32 decoding_refresh_type: 2; /* 0=non-IRAP, 1=CRA, 2=IDR */
+ u32 intra_qp; /* quantization parameter of intra picture */
+ u32 intra_period; /* period of intra picture in GOP size */
+ u32 conf_win_top; /* top offset of conformance window */
+ u32 conf_win_bot; /* bottom offset of conformance window */
+ u32 conf_win_left; /* left offset of conformance window */
+ u32 conf_win_right; /* right offset of conformance window */
+ u32 intra_refresh_mode: 3;
+ /*
+ * Argument for intra_ctu_refresh_mode.
+ *
+ * Depending on intra_refresh_mode, it can mean one of the following:
+ * - intra_ctu_refresh_mode (1) -> number of consecutive CTU rows
+ * - intra_ctu_refresh_mode (2) -> the number of consecutive CTU columns
+ * - intra_ctu_refresh_mode (3) -> step size in CTU
+ * - intra_ctu_refresh_mode (4) -> number of intra ct_us to be encoded in a picture
+ */
+ u32 intra_refresh_arg;
+ /*
+ * 0 : custom setting
+ * 1 : recommended encoder parameters (slow encoding speed, highest picture quality)
+ * 2 : boost mode (normal encoding speed, moderate picture quality)
+ * 3 : fast mode (fast encoding speed, low picture quality)
+ */
+ u32 depend_slice_mode : 2;
+ u32 depend_slice_mode_arg;
+ u32 independ_slice_mode : 1; /* 0=no-multi-slice, 1=slice-in-ctu-number*/
+ u32 independ_slice_mode_arg;
+ u32 max_num_merge: 2;
+ s32 beta_offset_div2: 4; /* sets beta_offset_div2 for deblocking filter */
+ s32 tc_offset_div2: 4; /* sets tc_offset_div3 for deblocking filter */
+ u32 hvs_qp_scale: 4; /* QP scaling factor for CU QP adjust if hvs_qp_scale_enable is 1 */
+ u32 hvs_max_delta_qp; /* maximum delta QP for HVS */
+ s32 chroma_cb_qp_offset; /* the value of chroma(cb) QP offset */
+ s32 chroma_cr_qp_offset; /* the value of chroma(cr) QP offset */
+ s32 initial_rc_qp;
+ u32 nr_intra_weight_y;
+ u32 nr_intra_weight_cb; /* weight to cb noise level for intra picture (0 ~ 31) */
+ u32 nr_intra_weight_cr; /* weight to cr noise level for intra picture (0 ~ 31) */
+ u32 nr_inter_weight_y;
+ u32 nr_inter_weight_cb; /* weight to cb noise level for inter picture (0 ~ 31) */
+ u32 nr_inter_weight_cr; /* weight to cr noise level for inter picture (0 ~ 31) */
+ u32 min_qp_i; /* minimum QP of I picture for rate control */
+ u32 max_qp_i; /* maximum QP of I picture for rate control */
+ u32 min_qp_p; /* minimum QP of P picture for rate control */
+ u32 max_qp_p; /* maximum QP of P picture for rate control */
+ u32 min_qp_b; /* minimum QP of B picture for rate control */
+ u32 max_qp_b; /* maximum QP of B picture for rate control */
+ u32 avc_idr_period; /* period of IDR picture (0 ~ 1024). 0 - implies an infinite period */
+ u32 avc_slice_arg; /* the number of MB for a slice when avc_slice_mode is set with 1 */
+ u32 intra_mb_refresh_mode: 2; /* 0=none, 1=row, 2=column, 3=step-size-in-mb */
+ /**
+ * Argument for intra_mb_refresh_mode.
+ *
+ * intra_mb_refresh_mode (1) -> number of consecutive MB rows
+ * intra_mb_refresh_mode (2) ->the number of consecutive MB columns
+ * intra_mb_refresh_mode (3) -> step size in MB
+ */
+ u32 intra_mb_refresh_arg;
+ u32 rc_weight_param;
+ u32 rc_weight_buf;
+
+ /* flags */
+ u32 en_still_picture: 1; /* still picture profile */
+ u32 tier: 1; /* 0=main, 1=high */
+ u32 avc_slice_mode: 1; /* 0=none, 1=slice-in-mb-number */
+ u32 entropy_coding_mode: 1; /* 0=CAVLC, 1=CABAC */
+ u32 lossless_enable: 1; /* enable lossless encoding */
+ u32 const_intra_pred_flag: 1; /* enable constrained intra prediction */
+ u32 tmvp_enable: 1; /* enable temporal motion vector prediction */
+ u32 wpp_enable: 1;
+ u32 disable_deblk: 1; /* disable in-loop deblocking filtering */
+ u32 lf_cross_slice_boundary_enable: 1;
+ u32 skip_intra_trans: 1;
+ u32 sao_enable: 1; /* enable SAO (sample adaptive offset) */
+ u32 intra_nx_n_enable: 1; /* enables intra nx_n p_us */
+ u32 cu_level_rc_enable: 1; /* enable CU level rate control */
+ u32 hvs_qp_enable: 1; /* enable CU QP adjustment for subjective quality enhancement */
+ u32 strong_intra_smooth_enable: 1; /* enable strong intra smoothing */
+ u32 rdo_skip: 1; /* skip RDO (rate distortion optimization) */
+ u32 lambda_scaling_enable: 1; /* enable lambda scaling using custom GOP */
+ u32 transform8x8_enable: 1; /* enable 8x8 intra prediction and 8x8 transform */
+ u32 mb_level_rc_enable: 1; /* enable MB-level rate control */
+};
+
+struct enc_open_param {
+ dma_addr_t bitstream_buffer;
+ unsigned int bitstream_buffer_size;
+ u32 pic_width; /* width of a picture to be encoded in unit of sample */
+ u32 pic_height; /* height of a picture to be encoded in unit of sample */
+ u32 frame_rate_info;/* desired fps */
+ u32 vbv_buffer_size;
+ u32 bit_rate; /* target bitrate in bps */
+ struct enc_wave_param wave_param;
+ enum packed_format_num packed_format; /* <<vpuapi_h_packed_format_num>> */
+ enum frame_buffer_format src_format;
+ bool line_buf_int_en;
+ u32 rc_enable : 1; /* rate control */
+};
+
+struct enc_initial_info {
+ u32 min_frame_buffer_count; /* minimum number of frame buffers */
+ u32 min_src_frame_count; /* minimum number of source buffers */
+ u32 seq_init_err_reason;
+ u32 warn_info;
+ u32 vlc_buf_size; /* size of task buffer */
+ u32 param_buf_size; /* size of task buffer */
+};
+
+/*
+ * Flags to encode NAL units explicitly
+ */
+struct enc_code_opt {
+ u32 implicit_header_encode: 1;
+ u32 encode_vcl: 1;
+ u32 encode_vps: 1;
+ u32 encode_sps: 1;
+ u32 encode_pps: 1;
+ u32 encode_aud: 1;
+ u32 encode_eos: 1;
+ u32 encode_eob: 1;
+ u32 encode_vui: 1;
+};
+
+struct enc_param {
+ struct frame_buffer *source_frame;
+ u32 pic_stream_buffer_addr;
+ u64 pic_stream_buffer_size;
+ u32 src_idx; /* source frame buffer index */
+ struct enc_code_opt code_option;
+ u64 pts; /* presentation timestamp (PTS) of the input source */
+ bool src_end_flag;
+};
+
+struct enc_output_info {
+ u32 bitstream_buffer;
+ u32 bitstream_size; /* byte size of encoded bitstream */
+ u32 pic_type: 2; /* <<vpuapi_h_pic_type>> */
+ s32 recon_frame_index;
+ dma_addr_t rd_ptr;
+ dma_addr_t wr_ptr;
+ u32 enc_pic_byte; /* number of encoded picture bytes */
+ s32 enc_src_idx; /* source buffer index of the currently encoded picture */
+ u32 enc_vcl_nut;
+ u32 error_reason; /* error reason of the currently encoded picture */
+ u32 warn_info; /* warning information on the currently encoded picture */
+ unsigned int frame_cycle; /* param for reporting the cycle number of encoding one frame*/
+ u64 pts;
+ u32 enc_host_cmd_tick; /* tick of ENC_PIC command for the picture */
+ u32 enc_encode_end_tick; /* end tick of encoding slices of the picture */
+};
+
+enum enc_pic_code_option {
+ CODEOPT_ENC_HEADER_IMPLICIT = BIT(0),
+ CODEOPT_ENC_VCL = BIT(1), /* flag to encode VCL nal unit explicitly */
+};
+
+enum gop_preset_idx {
+ PRESET_IDX_CUSTOM_GOP = 0, /* user defined GOP structure */
+ PRESET_IDX_ALL_I = 1, /* all intra, gopsize = 1 */
+ PRESET_IDX_IPP = 2, /* consecutive P, cyclic gopsize = 1 */
+ PRESET_IDX_IBBB = 3, /* consecutive B, cyclic gopsize = 1 */
+ PRESET_IDX_IBPBP = 4, /* gopsize = 2 */
+ PRESET_IDX_IBBBP = 5, /* gopsize = 4 */
+ PRESET_IDX_IPPPP = 6, /* consecutive P, cyclic gopsize = 4 */
+ PRESET_IDX_IBBBB = 7, /* consecutive B, cyclic gopsize = 4 */
+ PRESET_IDX_RA_IB = 8, /* random access, cyclic gopsize = 8 */
+ PRESET_IDX_IPP_SINGLE = 9, /* consecutive P, cyclic gopsize = 1, with single ref */
+};
+
+struct sec_axi_info {
+ u32 use_ip_enable;
+ u32 use_bit_enable;
+ u32 use_lf_row_enable: 1;
+ u32 use_enc_rdo_enable: 1;
+ u32 use_enc_lf_enable: 1;
+};
+
+struct dec_info {
+ struct dec_open_param open_param;
+ struct dec_initial_info initial_info;
+ struct dec_initial_info new_seq_info; /* temporal new sequence information */
+ u32 stream_wr_ptr;
+ u32 stream_rd_ptr;
+ u32 frame_display_flag;
+ dma_addr_t stream_buf_start_addr;
+ dma_addr_t stream_buf_end_addr;
+ u32 stream_buf_size;
+ struct vpu_buf vb_mv[MAX_REG_FRAME];
+ struct vpu_buf vb_fbc_y_tbl[MAX_REG_FRAME];
+ struct vpu_buf vb_fbc_c_tbl[MAX_REG_FRAME];
+ unsigned int num_of_decoding_fbs: 7;
+ unsigned int num_of_display_fbs: 7;
+ unsigned int stride;
+ struct sec_axi_info sec_axi_info;
+ dma_addr_t user_data_buf_addr;
+ u32 user_data_enable;
+ u32 user_data_buf_size;
+ struct vpu_buf vb_work;
+ struct vpu_buf vb_task;
+ struct dec_output_info dec_out_info[WAVE5_MAX_FBS];
+ u32 seq_change_mask;
+ enum temporal_id_mode temp_id_select_mode;
+ u32 target_temp_id;
+ u32 target_spatial_id;
+ u32 instance_queue_count;
+ u32 report_queue_count;
+ u32 cycle_per_tick;
+ u32 product_code;
+ u32 vlc_buf_size;
+ u32 param_buf_size;
+ bool initial_info_obtained;
+ bool reorder_enable;
+ bool first_cycle_check;
+ u32 stream_endflag: 1;
+};
+
+struct enc_info {
+ struct enc_open_param open_param;
+ struct enc_initial_info initial_info;
+ u32 stream_rd_ptr;
+ u32 stream_wr_ptr;
+ dma_addr_t stream_buf_start_addr;
+ dma_addr_t stream_buf_end_addr;
+ u32 stream_buf_size;
+ unsigned int num_frame_buffers;
+ unsigned int stride;
+ bool rotation_enable;
+ bool mirror_enable;
+ enum mirror_direction mirror_direction;
+ unsigned int rotation_angle;
+ bool initial_info_obtained;
+ struct sec_axi_info sec_axi_info;
+ bool line_buf_int_en;
+ struct vpu_buf vb_work;
+ struct vpu_buf vb_mv; /* col_mv buffer */
+ struct vpu_buf vb_fbc_y_tbl; /* FBC luma table buffer */
+ struct vpu_buf vb_fbc_c_tbl; /* FBC chroma table buffer */
+ struct vpu_buf vb_sub_sam_buf; /* sub-sampled buffer for ME */
+ struct vpu_buf vb_task;
+ u64 cur_pts; /* current timestamp in 90_k_hz */
+ u64 pts_map[32]; /* PTS mapped with source frame index */
+ u32 instance_queue_count;
+ u32 report_queue_count;
+ bool first_cycle_check;
+ u32 cycle_per_tick;
+ u32 product_code;
+ u32 vlc_buf_size;
+ u32 param_buf_size;
+};
+
+struct vpu_device {
+ struct device *dev;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_m2m_dev *v4l2_m2m_dec_dev;
+ struct v4l2_m2m_dev *v4l2_m2m_enc_dev;
+ struct list_head instances;
+ struct video_device *video_dev_dec;
+ struct video_device *video_dev_enc;
+ struct mutex dev_lock; /* lock for the src, dst v4l2 queues */
+ struct mutex hw_lock; /* lock hw configurations */
+ int irq;
+ enum product_id product;
+ struct vpu_attr attr;
+ struct vpu_buf common_mem;
+ u32 last_performance_cycles;
+ u32 sram_size;
+ struct gen_pool *sram_pool;
+ struct vpu_buf sram_buf;
+ void __iomem *vdb_register;
+ u32 product_code;
+ struct ida inst_ida;
+ struct clk_bulk_data *clks;
+ int num_clks;
+};
+
+struct vpu_instance;
+
+struct vpu_instance_ops {
+ void (*finish_process)(struct vpu_instance *inst);
+};
+
+struct vpu_instance {
+ struct list_head list;
+ struct v4l2_fh v4l2_fh;
+ struct v4l2_m2m_dev *v4l2_m2m_dev;
+ struct v4l2_ctrl_handler v4l2_ctrl_hdl;
+ struct vpu_device *dev;
+ struct completion irq_done;
+
+ struct v4l2_pix_format_mplane src_fmt;
+ struct v4l2_pix_format_mplane dst_fmt;
+ enum v4l2_colorspace colorspace;
+ enum v4l2_xfer_func xfer_func;
+ enum v4l2_ycbcr_encoding ycbcr_enc;
+ enum v4l2_quantization quantization;
+
+ enum vpu_instance_state state;
+ enum vpu_instance_type type;
+ const struct vpu_instance_ops *ops;
+ spinlock_t state_spinlock; /* This protects the instance state */
+
+ enum wave_std std;
+ s32 id;
+ union {
+ struct enc_info enc_info;
+ struct dec_info dec_info;
+ } *codec_info;
+ struct frame_buffer frame_buf[MAX_REG_FRAME];
+ struct vpu_buf frame_vbuf[MAX_REG_FRAME];
+ u32 fbc_buf_count;
+ u32 queued_src_buf_num;
+ u32 queued_dst_buf_num;
+ struct list_head avail_src_bufs;
+ struct list_head avail_dst_bufs;
+ struct v4l2_rect conf_win;
+ u64 timestamp;
+ enum frame_buffer_format output_format;
+ bool cbcr_interleave;
+ bool nv21;
+ bool eos;
+ struct vpu_buf bitstream_vbuf;
+ dma_addr_t last_rd_ptr;
+ size_t remaining_consumed_bytes;
+ bool needs_reallocation;
+
+ unsigned int min_src_buf_count;
+ unsigned int rot_angle;
+ unsigned int mirror_direction;
+ unsigned int bit_depth;
+ unsigned int frame_rate;
+ unsigned int vbv_buf_size;
+ unsigned int rc_mode;
+ unsigned int rc_enable;
+ unsigned int bit_rate;
+ unsigned int encode_aud;
+ struct enc_wave_param enc_param;
+};
+
+void wave5_vdi_write_register(struct vpu_device *vpu_dev, u32 addr, u32 data);
+u32 wave5_vdi_read_register(struct vpu_device *vpu_dev, u32 addr);
+int wave5_vdi_clear_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb);
+int wave5_vdi_allocate_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb);
+int wave5_vdi_allocate_array(struct vpu_device *vpu_dev, struct vpu_buf *array, unsigned int count,
+ size_t size);
+int wave5_vdi_write_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb, size_t offset,
+ u8 *data, size_t len);
+int wave5_vdi_free_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb);
+void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev);
+void wave5_vdi_free_sram(struct vpu_device *vpu_dev);
+
+int wave5_vpu_init_with_bitcode(struct device *dev, u8 *bitcode, size_t size);
+int wave5_vpu_flush_instance(struct vpu_instance *inst);
+int wave5_vpu_get_version_info(struct device *dev, u32 *revision, unsigned int *product_id);
+int wave5_vpu_dec_open(struct vpu_instance *inst, struct dec_open_param *open_param);
+int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res);
+int wave5_vpu_dec_issue_seq_init(struct vpu_instance *inst);
+int wave5_vpu_dec_complete_seq_init(struct vpu_instance *inst, struct dec_initial_info *info);
+int wave5_vpu_dec_register_frame_buffer_ex(struct vpu_instance *inst, int num_of_decoding_fbs,
+ int num_of_display_fbs, int stride, int height);
+int wave5_vpu_dec_start_one_frame(struct vpu_instance *inst, u32 *res_fail);
+int wave5_vpu_dec_get_output_info(struct vpu_instance *inst, struct dec_output_info *info);
+int wave5_vpu_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr, int update_wr_ptr);
+dma_addr_t wave5_vpu_dec_get_rd_ptr(struct vpu_instance *inst);
+int wave5_vpu_dec_reset_framebuffer(struct vpu_instance *inst, unsigned int index);
+int wave5_vpu_dec_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter);
+int wave5_vpu_dec_get_bitstream_buffer(struct vpu_instance *inst, dma_addr_t *prd_ptr,
+ dma_addr_t *pwr_ptr, size_t *size);
+int wave5_vpu_dec_update_bitstream_buffer(struct vpu_instance *inst, size_t size);
+int wave5_vpu_dec_clr_disp_flag(struct vpu_instance *inst, int index);
+int wave5_vpu_dec_set_disp_flag(struct vpu_instance *inst, int index);
+
+int wave5_vpu_enc_open(struct vpu_instance *inst, struct enc_open_param *open_param);
+int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res);
+int wave5_vpu_enc_issue_seq_init(struct vpu_instance *inst);
+int wave5_vpu_enc_complete_seq_init(struct vpu_instance *inst, struct enc_initial_info *info);
+int wave5_vpu_enc_register_frame_buffer(struct vpu_instance *inst, unsigned int num,
+ unsigned int stride, int height,
+ enum tiled_map_type map_type);
+int wave5_vpu_enc_start_one_frame(struct vpu_instance *inst, struct enc_param *param,
+ u32 *fail_res);
+int wave5_vpu_enc_get_output_info(struct vpu_instance *inst, struct enc_output_info *info);
+int wave5_vpu_enc_give_command(struct vpu_instance *inst, enum codec_command cmd, void *parameter);
+
+#endif
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h
new file mode 100644
index 000000000000..d9751eedb0f9
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave5 series multi-standard codec IP - product config definitions
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#ifndef _VPU_CONFIG_H_
+#define _VPU_CONFIG_H_
+
+#define WAVE517_CODE 0x5170
+#define WAVE537_CODE 0x5370
+#define WAVE511_CODE 0x5110
+#define WAVE521_CODE 0x5210
+#define WAVE521C_CODE 0x521c
+#define WAVE521C_DUAL_CODE 0x521d // wave521 dual core
+#define WAVE521E1_CODE 0x5211
+
+#define PRODUCT_CODE_W_SERIES(x) ({ \
+ int c = x; \
+ ((c) == WAVE517_CODE || (c) == WAVE537_CODE || \
+ (c) == WAVE511_CODE || (c) == WAVE521_CODE || \
+ (c) == WAVE521E1_CODE || (c) == WAVE521C_CODE || \
+ (c) == WAVE521C_DUAL_CODE); \
+})
+
+#define WAVE517_WORKBUF_SIZE (2 * 1024 * 1024)
+#define WAVE521ENC_WORKBUF_SIZE (128 * 1024) //HEVC 128K, AVC 40K
+#define WAVE521DEC_WORKBUF_SIZE (1784 * 1024)
+
+#define MAX_NUM_INSTANCE 32
+
+#define W5_MIN_ENC_PIC_WIDTH 256
+#define W5_MIN_ENC_PIC_HEIGHT 128
+#define W5_MAX_ENC_PIC_WIDTH 8192
+#define W5_MAX_ENC_PIC_HEIGHT 8192
+
+// application specific configuration
+#define VPU_ENC_TIMEOUT 60000
+#define VPU_DEC_TIMEOUT 60000
+
+// for WAVE encoder
+#define USE_SRC_PRP_AXI 0
+#define USE_SRC_PRI_AXI 1
+#define DEFAULT_SRC_AXI USE_SRC_PRP_AXI
+
+/************************************************************************/
+/* VPU COMMON MEMORY */
+/************************************************************************/
+#define VLC_BUF_NUM (2)
+
+#define COMMAND_QUEUE_DEPTH (2)
+
+#define W5_REMAP_INDEX0 0
+#define W5_REMAP_INDEX1 1
+#define W5_REMAP_MAX_SIZE (1024 * 1024)
+
+#define WAVE5_MAX_CODE_BUF_SIZE (2 * 1024 * 1024)
+#define WAVE5_TEMPBUF_OFFSET WAVE5_MAX_CODE_BUF_SIZE
+#define WAVE5_TEMPBUF_SIZE (1024 * 1024)
+
+#define SIZE_COMMON (WAVE5_MAX_CODE_BUF_SIZE + WAVE5_TEMPBUF_SIZE)
+
+//=====4. VPU REPORT MEMORY ======================//
+
+#define WAVE5_UPPER_PROC_AXI_ID 0x0
+
+#define WAVE5_PROC_AXI_ID 0x0
+#define WAVE5_PRP_AXI_ID 0x0
+#define WAVE5_FBD_Y_AXI_ID 0x0
+#define WAVE5_FBC_Y_AXI_ID 0x0
+#define WAVE5_FBD_C_AXI_ID 0x0
+#define WAVE5_FBC_C_AXI_ID 0x0
+#define WAVE5_SEC_AXI_ID 0x0
+#define WAVE5_PRI_AXI_ID 0x0
+
+#endif /* _VPU_CONFIG_H_ */
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuerror.h b/drivers/media/platform/chips-media/wave5/wave5-vpuerror.h
new file mode 100644
index 000000000000..905d5c34fd4e
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuerror.h
@@ -0,0 +1,292 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave5 series multi-standard codec IP - error values
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#ifndef ERROR_CODE_H_INCLUDED
+#define ERROR_CODE_H_INCLUDED
+
+/*
+ * WAVE5
+ */
+
+/************************************************************************/
+/* WAVE5 COMMON SYSTEM ERROR (FAIL_REASON) */
+/************************************************************************/
+#define WAVE5_SYSERR_QUEUEING_FAIL 0x00000001
+#define WAVE5_SYSERR_ACCESS_VIOLATION_HW 0x00000040
+#define WAVE5_SYSERR_BUS_ERROR 0x00000200
+#define WAVE5_SYSERR_DOUBLE_FAULT 0x00000400
+#define WAVE5_SYSERR_RESULT_NOT_READY 0x00000800
+#define WAVE5_SYSERR_VPU_STILL_RUNNING 0x00001000
+#define WAVE5_SYSERR_UNKNOWN_CMD 0x00002000
+#define WAVE5_SYSERR_UNKNOWN_CODEC_STD 0x00004000
+#define WAVE5_SYSERR_UNKNOWN_QUERY_OPTION 0x00008000
+#define WAVE5_SYSERR_VLC_BUF_FULL 0x00010000
+#define WAVE5_SYSERR_WATCHDOG_TIMEOUT 0x00020000
+#define WAVE5_SYSERR_VCPU_TIMEOUT 0x00080000
+#define WAVE5_SYSERR_TEMP_SEC_BUF_OVERFLOW 0x00200000
+#define WAVE5_SYSERR_NEED_MORE_TASK_BUF 0x00400000
+#define WAVE5_SYSERR_PRESCAN_ERR 0x00800000
+#define WAVE5_SYSERR_ENC_GBIN_OVERCONSUME 0x01000000
+#define WAVE5_SYSERR_ENC_MAX_ZERO_DETECT 0x02000000
+#define WAVE5_SYSERR_ENC_LVL_FIRST_ERROR 0x04000000
+#define WAVE5_SYSERR_ENC_EG_RANGE_OVER 0x08000000
+#define WAVE5_SYSERR_ENC_IRB_FRAME_DROP 0x10000000
+#define WAVE5_SYSERR_INPLACE_V 0x20000000
+#define WAVE5_SYSERR_FATAL_VPU_HANGUP 0xf0000000
+
+/************************************************************************/
+/* WAVE5 COMMAND QUEUE ERROR (FAIL_REASON) */
+/************************************************************************/
+#define WAVE5_CMDQ_ERR_NOT_QUEABLE_CMD 0x00000001
+#define WAVE5_CMDQ_ERR_SKIP_MODE_ENABLE 0x00000002
+#define WAVE5_CMDQ_ERR_INST_FLUSHING 0x00000003
+#define WAVE5_CMDQ_ERR_INST_INACTIVE 0x00000004
+#define WAVE5_CMDQ_ERR_QUEUE_FAIL 0x00000005
+#define WAVE5_CMDQ_ERR_CMD_BUF_FULL 0x00000006
+
+/************************************************************************/
+/* WAVE5 ERROR ON DECODER (ERR_INFO) */
+/************************************************************************/
+// HEVC
+#define HEVC_SPSERR_SEQ_PARAMETER_SET_ID 0x00001000
+#define HEVC_SPSERR_CHROMA_FORMAT_IDC 0x00001001
+#define HEVC_SPSERR_PIC_WIDTH_IN_LUMA_SAMPLES 0x00001002
+#define HEVC_SPSERR_PIC_HEIGHT_IN_LUMA_SAMPLES 0x00001003
+#define HEVC_SPSERR_CONF_WIN_LEFT_OFFSET 0x00001004
+#define HEVC_SPSERR_CONF_WIN_RIGHT_OFFSET 0x00001005
+#define HEVC_SPSERR_CONF_WIN_TOP_OFFSET 0x00001006
+#define HEVC_SPSERR_CONF_WIN_BOTTOM_OFFSET 0x00001007
+#define HEVC_SPSERR_BIT_DEPTH_LUMA_MINUS8 0x00001008
+#define HEVC_SPSERR_BIT_DEPTH_CHROMA_MINUS8 0x00001009
+#define HEVC_SPSERR_LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4 0x0000100A
+#define HEVC_SPSERR_SPS_MAX_DEC_PIC_BUFFERING 0x0000100B
+#define HEVC_SPSERR_SPS_MAX_NUM_REORDER_PICS 0x0000100C
+#define HEVC_SPSERR_SPS_MAX_LATENCY_INCREASE 0x0000100D
+#define HEVC_SPSERR_LOG2_MIN_LUMA_CODING_BLOCK_SIZE_MINUS3 0x0000100E
+#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE 0x0000100F
+#define HEVC_SPSERR_LOG2_MIN_TRANSFORM_BLOCK_SIZE_MINUS2 0x00001010
+#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_TRANSFORM_BLOCK_SIZE 0x00001011
+#define HEVC_SPSERR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTER 0x00001012
+#define HEVC_SPSERR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA 0x00001013
+#define HEVC_SPSERR_SCALING_LIST 0x00001014
+#define HEVC_SPSERR_LOG2_DIFF_MIN_PCM_LUMA_CODING_BLOCK_SIZE_MINUS3 0x00001015
+#define HEVC_SPSERR_LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE 0x00001016
+#define HEVC_SPSERR_NUM_SHORT_TERM_REF_PIC_SETS 0x00001017
+#define HEVC_SPSERR_NUM_LONG_TERM_REF_PICS_SPS 0x00001018
+#define HEVC_SPSERR_GBU_PARSING_ERROR 0x00001019
+#define HEVC_SPSERR_EXTENSION_FLAG 0x0000101A
+#define HEVC_SPSERR_VUI_ERROR 0x0000101B
+#define HEVC_SPSERR_ACTIVATE_SPS 0x0000101C
+#define HEVC_SPSERR_PROFILE_SPACE 0x0000101D
+#define HEVC_PPSERR_PPS_PIC_PARAMETER_SET_ID 0x00002000
+#define HEVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID 0x00002001
+#define HEVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1 0x00002002
+#define HEVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1 0x00002003
+#define HEVC_PPSERR_INIT_QP_MINUS26 0x00002004
+#define HEVC_PPSERR_DIFF_CU_QP_DELTA_DEPTH 0x00002005
+#define HEVC_PPSERR_PPS_CB_QP_OFFSET 0x00002006
+#define HEVC_PPSERR_PPS_CR_QP_OFFSET 0x00002007
+#define HEVC_PPSERR_NUM_TILE_COLUMNS_MINUS1 0x00002008
+#define HEVC_PPSERR_NUM_TILE_ROWS_MINUS1 0x00002009
+#define HEVC_PPSERR_COLUMN_WIDTH_MINUS1 0x0000200A
+#define HEVC_PPSERR_ROW_HEIGHT_MINUS1 0x0000200B
+#define HEVC_PPSERR_PPS_BETA_OFFSET_DIV2 0x0000200C
+#define HEVC_PPSERR_PPS_TC_OFFSET_DIV2 0x0000200D
+#define HEVC_PPSERR_SCALING_LIST 0x0000200E
+#define HEVC_PPSERR_LOG2_PARALLEL_MERGE_LEVEL_MINUS2 0x0000200F
+#define HEVC_PPSERR_NUM_TILE_COLUMNS_RANGE_OUT 0x00002010
+#define HEVC_PPSERR_NUM_TILE_ROWS_RANGE_OUT 0x00002011
+#define HEVC_PPSERR_MORE_RBSP_DATA_ERROR 0x00002012
+#define HEVC_PPSERR_PPS_PIC_PARAMETER_SET_ID_RANGE_OUT 0x00002013
+#define HEVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID_RANGE_OUT 0x00002014
+#define HEVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002015
+#define HEVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002016
+#define HEVC_PPSERR_PPS_CB_QP_OFFSET_RANGE_OUT 0x00002017
+#define HEVC_PPSERR_PPS_CR_QP_OFFSET_RANGE_OUT 0x00002018
+#define HEVC_PPSERR_COLUMN_WIDTH_MINUS1_RANGE_OUT 0x00002019
+#define HEVC_PPSERR_ROW_HEIGHT_MINUS1_RANGE_OUT 0x00002020
+#define HEVC_PPSERR_PPS_BETA_OFFSET_DIV2_RANGE_OUT 0x00002021
+#define HEVC_PPSERR_PPS_TC_OFFSET_DIV2_RANGE_OUT 0x00002022
+#define HEVC_SHERR_SLICE_PIC_PARAMETER_SET_ID 0x00003000
+#define HEVC_SHERR_ACTIVATE_PPS 0x00003001
+#define HEVC_SHERR_ACTIVATE_SPS 0x00003002
+#define HEVC_SHERR_SLICE_TYPE 0x00003003
+#define HEVC_SHERR_FIRST_SLICE_IS_DEPENDENT_SLICE 0x00003004
+#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET_SPS_FLAG 0x00003005
+#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET 0x00003006
+#define HEVC_SHERR_SHORT_TERM_REF_PIC_SET_IDX 0x00003007
+#define HEVC_SHERR_NUM_LONG_TERM_SPS 0x00003008
+#define HEVC_SHERR_NUM_LONG_TERM_PICS 0x00003009
+#define HEVC_SHERR_LT_IDX_SPS_IS_OUT_OF_RANGE 0x0000300A
+#define HEVC_SHERR_DELTA_POC_MSB_CYCLE_LT 0x0000300B
+#define HEVC_SHERR_NUM_REF_IDX_L0_ACTIVE_MINUS1 0x0000300C
+#define HEVC_SHERR_NUM_REF_IDX_L1_ACTIVE_MINUS1 0x0000300D
+#define HEVC_SHERR_COLLOCATED_REF_IDX 0x0000300E
+#define HEVC_SHERR_PRED_WEIGHT_TABLE 0x0000300F
+#define HEVC_SHERR_FIVE_MINUS_MAX_NUM_MERGE_CAND 0x00003010
+#define HEVC_SHERR_SLICE_QP_DELTA 0x00003011
+#define HEVC_SHERR_SLICE_QP_DELTA_IS_OUT_OF_RANGE 0x00003012
+#define HEVC_SHERR_SLICE_CB_QP_OFFSET 0x00003013
+#define HEVC_SHERR_SLICE_CR_QP_OFFSET 0x00003014
+#define HEVC_SHERR_SLICE_BETA_OFFSET_DIV2 0x00003015
+#define HEVC_SHERR_SLICE_TC_OFFSET_DIV2 0x00003016
+#define HEVC_SHERR_NUM_ENTRY_POINT_OFFSETS 0x00003017
+#define HEVC_SHERR_OFFSET_LEN_MINUS1 0x00003018
+#define HEVC_SHERR_SLICE_SEGMENT_HEADER_EXTENSION_LENGTH 0x00003019
+#define HEVC_SHERR_WRONG_POC_IN_STILL_PICTURE_PROFILE 0x0000301A
+#define HEVC_SHERR_SLICE_TYPE_ERROR_IN_STILL_PICTURE_PROFILE 0x0000301B
+#define HEVC_SHERR_PPS_ID_NOT_EQUAL_PREV_VALUE 0x0000301C
+#define HEVC_SPECERR_OVER_PICTURE_WIDTH_SIZE 0x00004000
+#define HEVC_SPECERR_OVER_PICTURE_HEIGHT_SIZE 0x00004001
+#define HEVC_SPECERR_OVER_CHROMA_FORMAT 0x00004002
+#define HEVC_SPECERR_OVER_BIT_DEPTH 0x00004003
+#define HEVC_SPECERR_OVER_BUFFER_OVER_FLOW 0x00004004
+#define HEVC_SPECERR_OVER_WRONG_BUFFER_ACCESS 0x00004005
+#define HEVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND 0x00005000
+#define HEVC_ETCERR_DEC_PIC_VCL_NOT_FOUND 0x00005001
+#define HEVC_ETCERR_NO_VALID_SLICE_IN_AU 0x00005002
+#define HEVC_ETCERR_INPLACE_V 0x0000500F
+
+// AVC
+#define AVC_SPSERR_SEQ_PARAMETER_SET_ID 0x00001000
+#define AVC_SPSERR_CHROMA_FORMAT_IDC 0x00001001
+#define AVC_SPSERR_PIC_WIDTH_IN_LUMA_SAMPLES 0x00001002
+#define AVC_SPSERR_PIC_HEIGHT_IN_LUMA_SAMPLES 0x00001003
+#define AVC_SPSERR_CONF_WIN_LEFT_OFFSET 0x00001004
+#define AVC_SPSERR_CONF_WIN_RIGHT_OFFSET 0x00001005
+#define AVC_SPSERR_CONF_WIN_TOP_OFFSET 0x00001006
+#define AVC_SPSERR_CONF_WIN_BOTTOM_OFFSET 0x00001007
+#define AVC_SPSERR_BIT_DEPTH_LUMA_MINUS8 0x00001008
+#define AVC_SPSERR_BIT_DEPTH_CHROMA_MINUS8 0x00001009
+#define AVC_SPSERR_SPS_MAX_DEC_PIC_BUFFERING 0x0000100B
+#define AVC_SPSERR_SPS_MAX_NUM_REORDER_PICS 0x0000100C
+#define AVC_SPSERR_SCALING_LIST 0x00001014
+#define AVC_SPSERR_GBU_PARSING_ERROR 0x00001019
+#define AVC_SPSERR_VUI_ERROR 0x0000101B
+#define AVC_SPSERR_ACTIVATE_SPS 0x0000101C
+#define AVC_PPSERR_PPS_PIC_PARAMETER_SET_ID 0x00002000
+#define AVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID 0x00002001
+#define AVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1 0x00002002
+#define AVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1 0x00002003
+#define AVC_PPSERR_INIT_QP_MINUS26 0x00002004
+#define AVC_PPSERR_PPS_CB_QP_OFFSET 0x00002006
+#define AVC_PPSERR_PPS_CR_QP_OFFSET 0x00002007
+#define AVC_PPSERR_SCALING_LIST 0x0000200E
+#define AVC_PPSERR_MORE_RBSP_DATA_ERROR 0x00002012
+#define AVC_PPSERR_PPS_PIC_PARAMETER_SET_ID_RANGE_OUT 0x00002013
+#define AVC_PPSERR_PPS_SEQ_PARAMETER_SET_ID_RANGE_OUT 0x00002014
+#define AVC_PPSERR_NUM_REF_IDX_L0_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002015
+#define AVC_PPSERR_NUM_REF_IDX_L1_DEFAULT_ACTIVE_MINUS1_RANGE_OUT 0x00002016
+#define AVC_PPSERR_PPS_CB_QP_OFFSET_RANGE_OUT 0x00002017
+#define AVC_PPSERR_PPS_CR_QP_OFFSET_RANGE_OUT 0x00002018
+#define AVC_SHERR_SLICE_PIC_PARAMETER_SET_ID 0x00003000
+#define AVC_SHERR_ACTIVATE_PPS 0x00003001
+#define AVC_SHERR_ACTIVATE_SPS 0x00003002
+#define AVC_SHERR_SLICE_TYPE 0x00003003
+#define AVC_SHERR_FIRST_MB_IN_SLICE 0x00003004
+#define AVC_SHERR_RPLM 0x00003006
+#define AVC_SHERR_LT_IDX_SPS_IS_OUT_OF_RANGE 0x0000300A
+#define AVC_SHERR_NUM_REF_IDX_L0_ACTIVE_MINUS1 0x0000300C
+#define AVC_SHERR_NUM_REF_IDX_L1_ACTIVE_MINUS1 0x0000300D
+#define AVC_SHERR_PRED_WEIGHT_TABLE 0x0000300F
+#define AVC_SHERR_SLICE_QP_DELTA 0x00003011
+#define AVC_SHERR_SLICE_BETA_OFFSET_DIV2 0x00003015
+#define AVC_SHERR_SLICE_TC_OFFSET_DIV2 0x00003016
+#define AVC_SHERR_DISABLE_DEBLOCK_FILTER_IDC 0x00003017
+#define AVC_SPECERR_OVER_PICTURE_WIDTH_SIZE 0x00004000
+#define AVC_SPECERR_OVER_PICTURE_HEIGHT_SIZE 0x00004001
+#define AVC_SPECERR_OVER_CHROMA_FORMAT 0x00004002
+#define AVC_SPECERR_OVER_BIT_DEPTH 0x00004003
+#define AVC_SPECERR_OVER_BUFFER_OVER_FLOW 0x00004004
+#define AVC_SPECERR_OVER_WRONG_BUFFER_ACCESS 0x00004005
+#define AVC_ETCERR_INIT_SEQ_SPS_NOT_FOUND 0x00005000
+#define AVC_ETCERR_DEC_PIC_VCL_NOT_FOUND 0x00005001
+#define AVC_ETCERR_NO_VALID_SLICE_IN_AU 0x00005002
+#define AVC_ETCERR_ASO 0x00005004
+#define AVC_ETCERR_FMO 0x00005005
+#define AVC_ETCERR_INPLACE_V 0x0000500F
+
+/************************************************************************/
+/* WAVE5 WARNING ON DECODER (WARN_INFO) */
+/************************************************************************/
+// HEVC
+#define HEVC_SPSWARN_MAX_SUB_LAYERS_MINUS1 0x00000001
+#define HEVC_SPSWARN_GENERAL_RESERVED_ZERO_44BITS 0x00000002
+#define HEVC_SPSWARN_RESERVED_ZERO_2BITS 0x00000004
+#define HEVC_SPSWARN_SUB_LAYER_RESERVED_ZERO_44BITS 0x00000008
+#define HEVC_SPSWARN_GENERAL_LEVEL_IDC 0x00000010
+#define HEVC_SPSWARN_SPS_MAX_DEC_PIC_BUFFERING_VALUE_OVER 0x00000020
+#define HEVC_SPSWARN_RBSP_TRAILING_BITS 0x00000040
+#define HEVC_SPSWARN_ST_RPS_UE_ERROR 0x00000080
+#define HEVC_SPSWARN_EXTENSION_FLAG 0x01000000
+#define HEVC_SPSWARN_REPLACED_WITH_PREV_SPS 0x02000000
+#define HEVC_PPSWARN_RBSP_TRAILING_BITS 0x00000100
+#define HEVC_PPSWARN_REPLACED_WITH_PREV_PPS 0x00000200
+#define HEVC_SHWARN_FIRST_SLICE_SEGMENT_IN_PIC_FLAG 0x00001000
+#define HEVC_SHWARN_NO_OUTPUT_OF_PRIOR_PICS_FLAG 0x00002000
+#define HEVC_SHWARN_PIC_OUTPUT_FLAG 0x00004000
+#define HEVC_SHWARN_DUPLICATED_SLICE_SEGMENT 0x00008000
+#define HEVC_ETCWARN_INIT_SEQ_VCL_NOT_FOUND 0x00010000
+#define HEVC_ETCWARN_MISSING_REFERENCE_PICTURE 0x00020000
+#define HEVC_ETCWARN_WRONG_TEMPORAL_ID 0x00040000
+#define HEVC_ETCWARN_ERROR_PICTURE_IS_REFERENCED 0x00080000
+#define HEVC_SPECWARN_OVER_PROFILE 0x00100000
+#define HEVC_SPECWARN_OVER_LEVEL 0x00200000
+#define HEVC_PRESWARN_PARSING_ERR 0x04000000
+#define HEVC_PRESWARN_MVD_OUT_OF_RANGE 0x08000000
+#define HEVC_PRESWARN_CU_QP_DELTA_VAL_OUT_OF_RANGE 0x09000000
+#define HEVC_PRESWARN_COEFF_LEVEL_REMAINING_OUT_OF_RANGE 0x0A000000
+#define HEVC_PRESWARN_PCM_ERR 0x0B000000
+#define HEVC_PRESWARN_OVERCONSUME 0x0C000000
+#define HEVC_PRESWARN_END_OF_SUBSET_ONE_BIT_ERR 0x10000000
+#define HEVC_PRESWARN_END_OF_SLICE_SEGMENT_FLAG 0x20000000
+
+// AVC
+#define AVC_SPSWARN_RESERVED_ZERO_2BITS 0x00000004
+#define AVC_SPSWARN_GENERAL_LEVEL_IDC 0x00000010
+#define AVC_SPSWARN_RBSP_TRAILING_BITS 0x00000040
+#define AVC_PPSWARN_RBSP_TRAILING_BITS 0x00000100
+#define AVC_SHWARN_NO_OUTPUT_OF_PRIOR_PICS_FLAG 0x00002000
+#define AVC_ETCWARN_INIT_SEQ_VCL_NOT_FOUND 0x00010000
+#define AVC_ETCWARN_MISSING_REFERENCE_PICTURE 0x00020000
+#define AVC_ETCWARN_ERROR_PICTURE_IS_REFERENCED 0x00080000
+#define AVC_SPECWARN_OVER_PROFILE 0x00100000
+#define AVC_SPECWARN_OVER_LEVEL 0x00200000
+#define AVC_PRESWARN_MVD_RANGE_OUT 0x00400000
+#define AVC_PRESWARN_MB_QPD_RANGE_OUT 0x00500000
+#define AVC_PRESWARN_COEFF_RANGE_OUT 0x00600000
+#define AVC_PRESWARN_MV_RANGE_OUT 0x00700000
+#define AVC_PRESWARN_MB_SKIP_RUN_RANGE_OUT 0x00800000
+#define AVC_PRESWARN_MB_TYPE_RANGE_OUT 0x00900000
+#define AVC_PRESWARN_SUB_MB_TYPE_RANGE_OUT 0x00A00000
+#define AVC_PRESWARN_CBP_RANGE_OUT 0x00B00000
+#define AVC_PRESWARN_INTRA_CHROMA_PRED_MODE_RANGE_OUT 0x00C00000
+#define AVC_PRESWARN_REF_IDX_RANGE_OUT 0x00D00000
+#define AVC_PRESWARN_COEFF_TOKEN_RANGE_OUT 0x00E00000
+#define AVC_PRESWARN_TOTAL_ZERO_RANGE_OUT 0x00F00000
+#define AVC_PRESWARN_RUN_BEFORE_RANGE_OUT 0x01000000
+#define AVC_PRESWARN_OVERCONSUME 0x01100000
+#define AVC_PRESWARN_MISSING_SLICE 0x01200000
+
+/************************************************************************/
+/* WAVE5 ERROR ON ENCODER (ERR_INFO) */
+/************************************************************************/
+
+/************************************************************************/
+/* WAVE5 WARNING ON ENCODER (WARN_INFO) */
+/************************************************************************/
+#define WAVE5_ETCWARN_FORCED_SPLIT_BY_CU8X8 0x000000001
+
+/************************************************************************/
+/* WAVE5 debug info (PRI_REASON) */
+/************************************************************************/
+#define WAVE5_DEC_VCORE_VCE_HANGUP 0x0001
+#define WAVE5_DEC_VCORE_UNDETECTED_SYNTAX_ERR 0x0002
+#define WAVE5_DEC_VCORE_MIB_BUSY 0x0003
+#define WAVE5_DEC_VCORE_VLC_BUSY 0x0004
+
+#endif /* ERROR_CODE_H_INCLUDED */
diff --git a/drivers/media/platform/chips-media/wave5/wave5.h b/drivers/media/platform/chips-media/wave5/wave5.h
new file mode 100644
index 000000000000..063028eccd3b
--- /dev/null
+++ b/drivers/media/platform/chips-media/wave5/wave5.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Wave5 series multi-standard codec IP - wave5 backend definitions
+ *
+ * Copyright (C) 2021-2023 CHIPS&MEDIA INC
+ */
+
+#ifndef __WAVE5_FUNCTION_H__
+#define __WAVE5_FUNCTION_H__
+
+#define WAVE5_SUBSAMPLED_ONE_SIZE(_w, _h) (ALIGN((_w) / 4, 16) * ALIGN((_h) / 4, 8))
+#define WAVE5_SUBSAMPLED_ONE_SIZE_AVC(_w, _h) (ALIGN((_w) / 4, 32) * ALIGN((_h) / 4, 4))
+
+/*
+ * Bitstream buffer option: Explicit End
+ * When set to 1 the VPU assumes that the bitstream has at least one frame and
+ * will read until the end of the bitstream buffer.
+ * When set to 0 the VPU will not read the last few bytes.
+ * This option can be set anytime but cannot be cleared during processing.
+ * It can be set to force finish decoding even though there is not enough
+ * bitstream data for a full frame.
+ */
+#define BSOPTION_ENABLE_EXPLICIT_END BIT(0)
+#define BSOPTION_HIGHLIGHT_STREAM_END BIT(1)
+
+/*
+ * Currently the driver only supports hardware with little endian but for source
+ * picture format, the bitstream and the report parameter the hardware works
+ * with the opposite endianness, thus hard-code big endian for the register
+ * writes
+ */
+#define PIC_SRC_ENDIANNESS_BIG_ENDIAN 0xf
+#define BITSTREAM_ENDIANNESS_BIG_ENDIAN 0xf
+#define REPORT_PARAM_ENDIANNESS_BIG_ENDIAN 0xf
+
+#define WTL_RIGHT_JUSTIFIED 0
+#define WTL_LEFT_JUSTIFIED 1
+#define WTL_PIXEL_8BIT 0
+#define WTL_PIXEL_16BIT 1
+#define WTL_PIXEL_32BIT 2
+
+/* Mirror & rotation modes of the PRP (pre-processing) module */
+#define NONE_ROTATE 0x0
+#define ROT_CLOCKWISE_90 0x3
+#define ROT_CLOCKWISE_180 0x5
+#define ROT_CLOCKWISE_270 0x7
+#define MIR_HOR_FLIP 0x11
+#define MIR_VER_FLIP 0x9
+#define MIR_HOR_VER_FLIP (MIR_HOR_FLIP | MIR_VER_FLIP)
+
+bool wave5_vpu_is_init(struct vpu_device *vpu_dev);
+
+unsigned int wave5_vpu_get_product_id(struct vpu_device *vpu_dev);
+
+int wave5_vpu_get_version(struct vpu_device *vpu_dev, u32 *revision);
+
+int wave5_vpu_init(struct device *dev, u8 *fw, size_t size);
+
+int wave5_vpu_reset(struct device *dev, enum sw_reset_mode reset_mode);
+
+int wave5_vpu_build_up_dec_param(struct vpu_instance *inst, struct dec_open_param *param);
+
+int wave5_vpu_dec_set_bitstream_flag(struct vpu_instance *inst, bool eos);
+
+int wave5_vpu_hw_flush_instance(struct vpu_instance *inst);
+
+int wave5_vpu_dec_register_framebuffer(struct vpu_instance *inst,
+ struct frame_buffer *fb_arr, enum tiled_map_type map_type,
+ unsigned int count);
+
+int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size);
+
+int wave5_vpu_dec_init_seq(struct vpu_instance *inst);
+
+int wave5_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info);
+
+int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res);
+
+int wave5_vpu_dec_get_result(struct vpu_instance *inst, struct dec_output_info *result);
+
+int wave5_vpu_dec_finish_seq(struct vpu_instance *inst, u32 *fail_res);
+
+int wave5_dec_clr_disp_flag(struct vpu_instance *inst, unsigned int index);
+
+int wave5_dec_set_disp_flag(struct vpu_instance *inst, unsigned int index);
+
+int wave5_vpu_clear_interrupt(struct vpu_instance *inst, u32 flags);
+
+dma_addr_t wave5_dec_get_rd_ptr(struct vpu_instance *inst);
+
+int wave5_dec_set_rd_ptr(struct vpu_instance *inst, dma_addr_t addr);
+
+/***< WAVE5 encoder >******/
+
+int wave5_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst,
+ struct enc_open_param *open_param);
+
+int wave5_vpu_enc_init_seq(struct vpu_instance *inst);
+
+int wave5_vpu_enc_get_seq_info(struct vpu_instance *inst, struct enc_initial_info *info);
+
+int wave5_vpu_enc_register_framebuffer(struct device *dev, struct vpu_instance *inst,
+ struct frame_buffer *fb_arr, enum tiled_map_type map_type,
+ unsigned int count);
+
+int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res);
+
+int wave5_vpu_enc_get_result(struct vpu_instance *inst, struct enc_output_info *result);
+
+int wave5_vpu_enc_finish_seq(struct vpu_instance *inst, u32 *fail_res);
+
+int wave5_vpu_enc_check_open_param(struct vpu_instance *inst, struct enc_open_param *open_param);
+
+#endif /* __WAVE5_FUNCTION_H__ */
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index 7194f88edc0f..ac48658e2de4 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -598,12 +598,11 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
goto end;
vq = v4l2_m2m_get_vq(fh->m2m_ctx, buf->type);
- if (buf->index >= vq->num_buffers) {
- dev_err(ctx->jpeg->dev, "buffer index out of range\n");
+ vb = vb2_get_buffer(vq, buf->index);
+ if (!vb) {
+ dev_err(ctx->jpeg->dev, "buffer not found\n");
return -EINVAL;
}
-
- vb = vq->bufs[buf->index];
jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
jpeg_src_buf->bs_size = buf->m.planes[0].bytesused;
@@ -1021,13 +1020,13 @@ static void mtk_jpeg_dec_device_run(void *priv)
if (ret < 0)
goto dec_end;
- schedule_delayed_work(&jpeg->job_timeout_work,
- msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
-
mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs);
if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, &dst_buf->vb2_buf, &fb))
goto dec_end;
+ schedule_delayed_work(&jpeg->job_timeout_work,
+ msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
+
spin_lock_irqsave(&jpeg->hw_lock, flags);
mtk_jpeg_dec_reset(jpeg->reg_base);
mtk_jpeg_dec_set_config(jpeg->reg_base,
@@ -1403,7 +1402,6 @@ static void mtk_jpeg_remove(struct platform_device *pdev)
{
struct mtk_jpeg_dev *jpeg = platform_get_drvdata(pdev);
- cancel_delayed_work_sync(&jpeg->job_timeout_work);
pm_runtime_disable(&pdev->dev);
video_unregister_device(jpeg->vdev);
v4l2_m2m_release(jpeg->m2m_dev);
@@ -1750,9 +1748,6 @@ retry_select:
v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
- schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work,
- msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
-
mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs);
if (mtk_jpeg_set_dec_dst(ctx,
&jpeg_src_buf->dec_param,
@@ -1762,6 +1757,9 @@ retry_select:
goto setdst_end;
}
+ schedule_delayed_work(&comp_jpeg[hw_id]->job_timeout_work,
+ msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
+
spin_lock_irqsave(&comp_jpeg[hw_id]->hw_lock, flags);
ctx->total_frame_num++;
mtk_jpeg_dec_reset(comp_jpeg[hw_id]->reg_base);
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
index cc44be10fdb7..94f4ed78523b 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
@@ -208,13 +208,17 @@ static int mdp_probe(struct platform_device *pdev)
goto err_destroy_job_wq;
}
- mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_SCP);
- if (WARN_ON(!mm_pdev)) {
- dev_err(&pdev->dev, "Could not get scp device\n");
- ret = -ENODEV;
- goto err_destroy_clock_wq;
+ mdp->scp = scp_get(pdev);
+ if (!mdp->scp) {
+ mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_SCP);
+ if (WARN_ON(!mm_pdev)) {
+ dev_err(&pdev->dev, "Could not get scp device\n");
+ ret = -ENODEV;
+ goto err_destroy_clock_wq;
+ }
+ mdp->scp = platform_get_drvdata(mm_pdev);
}
- mdp->scp = platform_get_drvdata(mm_pdev);
+
mdp->rproc_handle = scp_get_rproc(mdp->scp);
dev_dbg(&pdev->dev, "MDP rproc_handle: %pK", mdp->rproc_handle);
diff --git a/drivers/media/platform/mediatek/vcodec/Kconfig b/drivers/media/platform/mediatek/vcodec/Kconfig
index 74b00eb1bc97..bc8292232530 100644
--- a/drivers/media/platform/mediatek/vcodec/Kconfig
+++ b/drivers/media/platform/mediatek/vcodec/Kconfig
@@ -24,7 +24,6 @@ config VIDEO_MEDIATEK_VCODEC
select V4L2_H264
select V4L2_VP9
select MEDIA_CONTROLLER
- select MEDIA_CONTROLLER_REQUEST_API
help
Mediatek video codec driver provides HW capability to
encode and decode in a range of video formats on MT8173
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c
index 91ed576d6821..ba742f0e391d 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c
@@ -208,36 +208,14 @@ static int vidioc_vdec_dqbuf(struct file *file, void *priv,
return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
}
-static int mtk_vcodec_dec_get_chip_name(void *priv)
-{
- struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv);
- struct device *dev = &ctx->dev->plat_dev->dev;
-
- if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-dec"))
- return 8173;
- else if (of_device_is_compatible(dev->of_node, "mediatek,mt8183-vcodec-dec"))
- return 8183;
- else if (of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-dec"))
- return 8192;
- else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-dec"))
- return 8195;
- else if (of_device_is_compatible(dev->of_node, "mediatek,mt8186-vcodec-dec"))
- return 8186;
- else if (of_device_is_compatible(dev->of_node, "mediatek,mt8188-vcodec-dec"))
- return 8188;
- else
- return 8173;
-}
-
static int vidioc_vdec_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv);
struct device *dev = &ctx->dev->plat_dev->dev;
- int platform_name = mtk_vcodec_dec_get_chip_name(priv);
strscpy(cap->driver, dev->driver->name, sizeof(cap->driver));
- snprintf(cap->card, sizeof(cap->card), "MT%d video decoder", platform_name);
+ snprintf(cap->card, sizeof(cap->card), "MT%d video decoder", ctx->dev->chip_name);
return 0;
}
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
index 0a89ce452ac3..f47c98faf068 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
@@ -326,6 +326,26 @@ static const struct v4l2_file_operations mtk_vcodec_fops = {
.mmap = v4l2_m2m_fop_mmap,
};
+static void mtk_vcodec_dec_get_chip_name(struct mtk_vcodec_dec_dev *vdec_dev)
+{
+ struct device *dev = &vdec_dev->plat_dev->dev;
+
+ if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-dec"))
+ vdec_dev->chip_name = MTK_VDEC_MT8173;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8183-vcodec-dec"))
+ vdec_dev->chip_name = MTK_VDEC_MT8183;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-dec"))
+ vdec_dev->chip_name = MTK_VDEC_MT8192;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-dec"))
+ vdec_dev->chip_name = MTK_VDEC_MT8195;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8186-vcodec-dec"))
+ vdec_dev->chip_name = MTK_VDEC_MT8186;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8188-vcodec-dec"))
+ vdec_dev->chip_name = MTK_VDEC_MT8188;
+ else
+ vdec_dev->chip_name = MTK_VDEC_INVAL;
+}
+
static int mtk_vcodec_probe(struct platform_device *pdev)
{
struct mtk_vcodec_dec_dev *dev;
@@ -341,6 +361,12 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&dev->ctx_list);
dev->plat_dev = pdev;
+ mtk_vcodec_dec_get_chip_name(dev);
+ if (dev->chip_name == MTK_VDEC_INVAL) {
+ dev_err(&pdev->dev, "Failed to get decoder chip name");
+ return -EINVAL;
+ }
+
dev->vdec_pdata = of_device_get_match_data(&pdev->dev);
if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu",
&rproc_phandle)) {
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
index 7e36b2c69b7d..849b89dd205c 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h
@@ -18,6 +18,16 @@
#define IS_VDEC_LAT_ARCH(hw_arch) ((hw_arch) >= MTK_VDEC_LAT_SINGLE_CORE)
#define IS_VDEC_INNER_RACING(capability) ((capability) & MTK_VCODEC_INNER_RACING)
+enum mtk_vcodec_dec_chip_name {
+ MTK_VDEC_INVAL = 0,
+ MTK_VDEC_MT8173 = 8173,
+ MTK_VDEC_MT8183 = 8183,
+ MTK_VDEC_MT8186 = 8186,
+ MTK_VDEC_MT8188 = 8188,
+ MTK_VDEC_MT8192 = 8192,
+ MTK_VDEC_MT8195 = 8195,
+};
+
/*
* enum mtk_vdec_format_types - Structure used to get supported
* format types according to decoder capability
@@ -249,6 +259,8 @@ struct mtk_vcodec_dec_ctx {
* @vdec_racing_info: record register value
* @dec_racing_info_mutex: mutex lock used for inner racing mode
* @dbgfs: debug log related information
+ *
+ * @chip_name: used to distinguish platforms and select the correct codec configuration values
*/
struct mtk_vcodec_dec_dev {
struct v4l2_device v4l2_dev;
@@ -289,6 +301,8 @@ struct mtk_vcodec_dec_dev {
/* Protects access to vdec_racing_info data */
struct mutex dec_racing_info_mutex;
struct mtk_vcodec_dbgfs dbgfs;
+
+ enum mtk_vcodec_dec_chip_name chip_name;
};
static inline struct mtk_vcodec_dec_ctx *fh_to_dec_ctx(struct v4l2_fh *fh)
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
index e29c9c58f3da..d54b3833790d 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
@@ -58,6 +58,15 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = {
},
{
.cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+ .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
+ .def = V4L2_MPEG_VIDEO_H264_LEVEL_4_1,
+ .max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+ },
+ .codec_type = V4L2_PIX_FMT_H264_SLICE,
+ },
+ {
+ .cfg = {
.id = V4L2_CID_STATELESS_H264_DECODE_MODE,
.min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED,
.def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED,
@@ -100,7 +109,17 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = {
.id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
.min = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
.def = V4L2_MPEG_VIDEO_VP9_PROFILE_0,
- .max = V4L2_MPEG_VIDEO_VP9_PROFILE_3,
+ .max = V4L2_MPEG_VIDEO_VP9_PROFILE_2,
+ .menu_skip_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_1),
+ },
+ .codec_type = V4L2_PIX_FMT_VP9_FRAME,
+ },
+ {
+ .cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_VP9_LEVEL,
+ .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0,
+ .def = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0,
+ .max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1,
},
.codec_type = V4L2_PIX_FMT_VP9_FRAME,
},
@@ -140,6 +159,16 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = {
},
{
.cfg = {
+ .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
+ .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
+ .def = V4L2_MPEG_VIDEO_HEVC_LEVEL_4,
+ .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1,
+ },
+ .codec_type = V4L2_PIX_FMT_HEVC_SLICE,
+ },
+
+ {
+ .cfg = {
.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
@@ -519,6 +548,141 @@ static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = {
.s_ctrl = mtk_vdec_s_ctrl,
};
+static void mtk_vcodec_dec_fill_h264_level(struct v4l2_ctrl_config *cfg,
+ struct mtk_vcodec_dec_ctx *ctx)
+{
+ switch (ctx->dev->chip_name) {
+ case MTK_VDEC_MT8192:
+ case MTK_VDEC_MT8188:
+ cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_5_2;
+ break;
+ case MTK_VDEC_MT8195:
+ cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0;
+ break;
+ case MTK_VDEC_MT8183:
+ case MTK_VDEC_MT8186:
+ cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
+ break;
+ default:
+ cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
+ break;
+ };
+}
+
+static void mtk_vcodec_dec_fill_h264_profile(struct v4l2_ctrl_config *cfg,
+ struct mtk_vcodec_dec_ctx *ctx)
+{
+ switch (ctx->dev->chip_name) {
+ case MTK_VDEC_MT8188:
+ case MTK_VDEC_MT8195:
+ cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
+ break;
+ default:
+ cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
+ break;
+ };
+}
+
+static void mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config *cfg,
+ struct mtk_vcodec_dec_ctx *ctx)
+{
+ switch (ctx->dev->chip_name) {
+ case MTK_VDEC_MT8188:
+ cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1;
+ break;
+ case MTK_VDEC_MT8195:
+ cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2;
+ break;
+ default:
+ cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_4;
+ break;
+ };
+}
+
+static void mtk_vcodec_dec_fill_h265_profile(struct v4l2_ctrl_config *cfg,
+ struct mtk_vcodec_dec_ctx *ctx)
+{
+ switch (ctx->dev->chip_name) {
+ case MTK_VDEC_MT8188:
+ case MTK_VDEC_MT8195:
+ cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10;
+ break;
+ default:
+ cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE;
+ break;
+ };
+}
+
+static void mtk_vcodec_dec_fill_vp9_level(struct v4l2_ctrl_config *cfg,
+ struct mtk_vcodec_dec_ctx *ctx)
+{
+ switch (ctx->dev->chip_name) {
+ case MTK_VDEC_MT8192:
+ case MTK_VDEC_MT8188:
+ cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_1;
+ break;
+ case MTK_VDEC_MT8195:
+ cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_2;
+ break;
+ case MTK_VDEC_MT8186:
+ cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_1;
+ break;
+ default:
+ cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0;
+ break;
+ };
+}
+
+static void mtk_vcodec_dec_fill_vp9_profile(struct v4l2_ctrl_config *cfg,
+ struct mtk_vcodec_dec_ctx *ctx)
+{
+ switch (ctx->dev->chip_name) {
+ case MTK_VDEC_MT8188:
+ case MTK_VDEC_MT8195:
+ cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_2;
+ break;
+ default:
+ cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_1;
+ break;
+ };
+}
+
+static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg,
+ struct mtk_vcodec_dec_ctx *ctx)
+{
+ switch (cfg->id) {
+ case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+ mtk_vcodec_dec_fill_h264_level(cfg, ctx);
+ mtk_v4l2_vdec_dbg(3, ctx, "h264 supported level: %lld %lld", cfg->max, cfg->def);
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
+ mtk_vcodec_dec_fill_h265_level(cfg, ctx);
+ mtk_v4l2_vdec_dbg(3, ctx, "h265 supported level: %lld %lld", cfg->max, cfg->def);
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
+ mtk_vcodec_dec_fill_vp9_level(cfg, ctx);
+ mtk_v4l2_vdec_dbg(3, ctx, "vp9 supported level: %lld %lld", cfg->max, cfg->def);
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+ mtk_vcodec_dec_fill_h264_profile(cfg, ctx);
+ mtk_v4l2_vdec_dbg(3, ctx, "h264 supported profile: %lld %lld", cfg->max,
+ cfg->menu_skip_mask);
+ break;
+ case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
+ mtk_vcodec_dec_fill_h265_profile(cfg, ctx);
+ mtk_v4l2_vdec_dbg(3, ctx, "h265 supported profile: %lld %lld", cfg->max,
+ cfg->menu_skip_mask);
+ break;
+ case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
+ mtk_vcodec_dec_fill_vp9_profile(cfg, ctx);
+ mtk_v4l2_vdec_dbg(3, ctx, "vp9 supported profile: %lld %lld", cfg->max,
+ cfg->menu_skip_mask);
+ break;
+ default:
+ break;
+ };
+}
+
static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_dec_ctx *ctx)
{
unsigned int i;
@@ -532,6 +696,8 @@ static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_dec_ctx *ctx)
for (i = 0; i < NUM_CTRLS; i++) {
struct v4l2_ctrl_config cfg = mtk_stateless_controls[i].cfg;
cfg.ops = &mtk_vcodec_dec_ctrl_ops;
+
+ mtk_vcodec_dec_reset_controls(&cfg, ctx);
v4l2_ctrl_new_custom(&ctx->ctrl_hdl, &cfg, NULL);
if (ctx->ctrl_hdl.error) {
mtk_v4l2_vdec_err(ctx, "Adding control %d failed %d", i,
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
index e393e3e668f8..69d37b93bd35 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c
@@ -1695,13 +1695,8 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst
return -EINVAL;
/* update internal buffer's width/height */
- for (i = 0; i < vq->num_buffers; i++) {
- if (vb == vq->bufs[i]) {
- instance->dpb[i].width = w;
- instance->dpb[i].height = h;
- break;
- }
- }
+ instance->dpb[vb->index].width = w;
+ instance->dpb[vb->index].height = h;
/*
* get buffer's width/height from instance
diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c
index eb381fa6e7d1..181884e798fd 100644
--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c
@@ -912,7 +912,7 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count)
return 0;
err_start_stream:
- for (i = 0; i < q->num_buffers; ++i) {
+ for (i = 0; i < vb2_get_num_buffers(q); ++i) {
struct vb2_buffer *buf = vb2_get_buffer(q, i);
/*
diff --git a/drivers/media/platform/microchip/microchip-csi2dc.c b/drivers/media/platform/microchip/microchip-csi2dc.c
index 988c1cc1d8b6..fee73260bb1e 100644
--- a/drivers/media/platform/microchip/microchip-csi2dc.c
+++ b/drivers/media/platform/microchip/microchip-csi2dc.c
@@ -232,8 +232,8 @@ static int csi2dc_get_fmt(struct v4l2_subdev *csi2dc_sd,
struct v4l2_mbus_framefmt *v4l2_try_fmt;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- v4l2_try_fmt = v4l2_subdev_get_try_format(csi2dc_sd, sd_state,
- format->pad);
+ v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state,
+ format->pad);
format->format = *v4l2_try_fmt;
return 0;
@@ -281,13 +281,12 @@ static int csi2dc_set_fmt(struct v4l2_subdev *csi2dc_sd,
req_fmt->format.field = V4L2_FIELD_NONE;
if (req_fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- v4l2_try_fmt = v4l2_subdev_get_try_format(csi2dc_sd, sd_state,
- req_fmt->pad);
+ v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state,
+ req_fmt->pad);
*v4l2_try_fmt = req_fmt->format;
/* Trying on the sink pad makes the source pad change too */
- v4l2_try_fmt = v4l2_subdev_get_try_format(csi2dc_sd,
- sd_state,
- CSI2DC_PAD_SOURCE);
+ v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state,
+ CSI2DC_PAD_SOURCE);
*v4l2_try_fmt = req_fmt->format;
/* if we are just trying, we are done */
@@ -436,11 +435,11 @@ static int csi2dc_s_stream(struct v4l2_subdev *csi2dc_sd, int enable)
return ret;
}
-static int csi2dc_init_cfg(struct v4l2_subdev *csi2dc_sd,
- struct v4l2_subdev_state *sd_state)
+static int csi2dc_init_state(struct v4l2_subdev *csi2dc_sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *v4l2_try_fmt =
- v4l2_subdev_get_try_format(csi2dc_sd, sd_state, 0);
+ v4l2_subdev_state_get_format(sd_state, 0);
v4l2_try_fmt->height = 480;
v4l2_try_fmt->width = 640;
@@ -462,7 +461,6 @@ static const struct v4l2_subdev_pad_ops csi2dc_pad_ops = {
.enum_mbus_code = csi2dc_enum_mbus_code,
.set_fmt = csi2dc_set_fmt,
.get_fmt = csi2dc_get_fmt,
- .init_cfg = csi2dc_init_cfg,
};
static const struct v4l2_subdev_video_ops csi2dc_video_ops = {
@@ -474,6 +472,10 @@ static const struct v4l2_subdev_ops csi2dc_subdev_ops = {
.video = &csi2dc_video_ops,
};
+static const struct v4l2_subdev_internal_ops csi2dc_internal_ops = {
+ .init_state = csi2dc_init_state,
+};
+
static int csi2dc_async_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *subdev,
struct v4l2_async_connection *asd)
@@ -678,6 +680,7 @@ static int csi2dc_probe(struct platform_device *pdev)
}
v4l2_subdev_init(&csi2dc->csi2dc_sd, &csi2dc_subdev_ops);
+ csi2dc->csi2dc_sd.internal_ops = &csi2dc_internal_ops;
csi2dc->csi2dc_sd.owner = THIS_MODULE;
csi2dc->csi2dc_sd.dev = dev;
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 1f8528844497..f3a5cbacadbe 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -851,38 +851,6 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
return 0;
}
-static void isc_try_fse(struct isc_device *isc,
- struct v4l2_subdev_state *sd_state)
-{
- struct v4l2_subdev_frame_size_enum fse = {
- .which = V4L2_SUBDEV_FORMAT_TRY,
- };
- int ret;
-
- /*
- * If we do not know yet which format the subdev is using, we cannot
- * do anything.
- */
- if (!isc->config.sd_format)
- return;
-
- fse.code = isc->try_config.sd_format->mbus_code;
-
- ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
- sd_state, &fse);
- /*
- * Attempt to obtain format size from subdev. If not available,
- * just use the maximum ISC can receive.
- */
- if (ret) {
- sd_state->pads->try_crop.width = isc->max_width;
- sd_state->pads->try_crop.height = isc->max_height;
- } else {
- sd_state->pads->try_crop.width = fse.max_width;
- sd_state->pads->try_crop.height = fse.max_height;
- }
-}
-
static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f)
{
struct v4l2_pix_format *pixfmt = &f->fmt.pix;
@@ -944,10 +912,6 @@ static int isc_validate(struct isc_device *isc)
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
.pad = isc->remote_pad,
};
- struct v4l2_subdev_pad_config pad_cfg = {};
- struct v4l2_subdev_state pad_state = {
- .pads = &pad_cfg,
- };
/* Get current format from subdev */
ret = v4l2_subdev_call(isc->current_subdev->sd, pad, get_fmt, NULL,
@@ -1008,9 +972,6 @@ static int isc_validate(struct isc_device *isc)
if (ret)
return ret;
- /* Obtain frame sizes if possible to have crop requirements ready */
- isc_try_fse(isc, &pad_state);
-
/* Configure ISC pipeline for the config */
ret = isc_try_configure_pipeline(isc);
if (ret)
@@ -1819,7 +1780,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &isc->lock;
- q->min_buffers_needed = 1;
+ q->min_queued_buffers = 1;
q->dev = isc->dev;
ret = vb2_queue_init(q);
diff --git a/drivers/media/platform/microchip/microchip-isc-scaler.c b/drivers/media/platform/microchip/microchip-isc-scaler.c
index 0f29a32d15ce..e83463543e21 100644
--- a/drivers/media/platform/microchip/microchip-isc-scaler.c
+++ b/drivers/media/platform/microchip/microchip-isc-scaler.c
@@ -33,8 +33,8 @@ static int isc_scaler_get_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *v4l2_try_fmt;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- v4l2_try_fmt = v4l2_subdev_get_try_format(sd, sd_state,
- format->pad);
+ v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state,
+ format->pad);
format->format = *v4l2_try_fmt;
return 0;
@@ -74,12 +74,12 @@ static int isc_scaler_set_fmt(struct v4l2_subdev *sd,
req_fmt->format.code = fmt->mbus_code;
if (req_fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- v4l2_try_fmt = v4l2_subdev_get_try_format(sd, sd_state,
- req_fmt->pad);
+ v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state,
+ req_fmt->pad);
*v4l2_try_fmt = req_fmt->format;
/* Trying on the sink pad makes the source pad change too */
- v4l2_try_fmt = v4l2_subdev_get_try_format(sd, sd_state,
- ISC_SCALER_PAD_SOURCE);
+ v4l2_try_fmt = v4l2_subdev_state_get_format(sd_state,
+ ISC_SCALER_PAD_SOURCE);
*v4l2_try_fmt = req_fmt->format;
v4l_bound_align_image(&v4l2_try_fmt->width,
@@ -145,17 +145,17 @@ static int isc_scaler_g_sel(struct v4l2_subdev *sd,
return 0;
}
-static int isc_scaler_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int isc_scaler_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *v4l2_try_fmt =
- v4l2_subdev_get_try_format(sd, sd_state, 0);
+ v4l2_subdev_state_get_format(sd_state, 0);
struct v4l2_rect *try_crop;
struct isc_device *isc = container_of(sd, struct isc_device, scaler_sd);
*v4l2_try_fmt = isc->scaler_format[ISC_SCALER_PAD_SOURCE];
- try_crop = v4l2_subdev_get_try_crop(sd, sd_state, 0);
+ try_crop = v4l2_subdev_state_get_crop(sd_state, 0);
try_crop->top = 0;
try_crop->left = 0;
@@ -170,7 +170,6 @@ static const struct v4l2_subdev_pad_ops isc_scaler_pad_ops = {
.set_fmt = isc_scaler_set_fmt,
.get_fmt = isc_scaler_get_fmt,
.get_selection = isc_scaler_g_sel,
- .init_cfg = isc_scaler_init_cfg,
};
static const struct media_entity_operations isc_scaler_entity_ops = {
@@ -181,11 +180,16 @@ static const struct v4l2_subdev_ops xisc_scaler_subdev_ops = {
.pad = &isc_scaler_pad_ops,
};
+static const struct v4l2_subdev_internal_ops isc_scaler_internal_ops = {
+ .init_state = isc_scaler_init_state,
+};
+
int isc_scaler_init(struct isc_device *isc)
{
int ret;
v4l2_subdev_init(&isc->scaler_sd, &xisc_scaler_subdev_ops);
+ isc->scaler_sd.internal_ops = &isc_scaler_internal_ops;
isc->scaler_sd.owner = THIS_MODULE;
isc->scaler_sd.dev = isc->dev;
diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c
index b9e6782f59b4..a1fcb616b256 100644
--- a/drivers/media/platform/nuvoton/npcm-video.c
+++ b/drivers/media/platform/nuvoton/npcm-video.c
@@ -26,7 +26,6 @@
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/sched.h>
-#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/v4l2-controls.h>
#include <linux/videodev2.h>
@@ -120,7 +119,7 @@ struct npcm_video {
struct mutex video_lock; /* v4l2 and videobuf2 lock */
struct list_head buffers;
- spinlock_t lock; /* buffer list lock */
+ struct mutex buffer_lock; /* buffer list lock */
unsigned long flags;
unsigned int sequence;
@@ -393,7 +392,7 @@ static void npcm_video_free_diff_table(struct npcm_video *video)
struct rect_list *tmp;
unsigned int i;
- for (i = 0; i < video->queue.num_buffers; i++) {
+ for (i = 0; i < vb2_get_num_buffers(&video->queue); i++) {
head = &video->list[i];
list_for_each_safe(pos, nx, head) {
tmp = list_entry(pos, struct rect_list, list);
@@ -782,7 +781,6 @@ static int npcm_video_start_frame(struct npcm_video *video)
{
struct npcm_video_buffer *buf;
struct regmap *vcd = video->vcd_regmap;
- unsigned long flags;
unsigned int val;
int ret;
@@ -798,17 +796,17 @@ static int npcm_video_start_frame(struct npcm_video *video)
return -EBUSY;
}
- spin_lock_irqsave(&video->lock, flags);
+ mutex_lock(&video->buffer_lock);
buf = list_first_entry_or_null(&video->buffers,
struct npcm_video_buffer, link);
if (!buf) {
- spin_unlock_irqrestore(&video->lock, flags);
+ mutex_unlock(&video->buffer_lock);
dev_dbg(video->dev, "No empty buffers; skip capture frame\n");
return 0;
}
set_bit(VIDEO_CAPTURING, &video->flags);
- spin_unlock_irqrestore(&video->lock, flags);
+ mutex_unlock(&video->buffer_lock);
npcm_video_vcd_state_machine_reset(video);
@@ -834,14 +832,13 @@ static void npcm_video_bufs_done(struct npcm_video *video,
enum vb2_buffer_state state)
{
struct npcm_video_buffer *buf;
- unsigned long flags;
- spin_lock_irqsave(&video->lock, flags);
+ mutex_lock(&video->buffer_lock);
list_for_each_entry(buf, &video->buffers, link)
vb2_buffer_done(&buf->vb.vb2_buf, state);
INIT_LIST_HEAD(&video->buffers);
- spin_unlock_irqrestore(&video->lock, flags);
+ mutex_unlock(&video->buffer_lock);
}
static void npcm_video_get_diff_rect(struct npcm_video *video, unsigned int index)
@@ -1071,12 +1068,12 @@ static irqreturn_t npcm_video_irq(int irq, void *arg)
if (status & VCD_STAT_DONE) {
regmap_write(vcd, VCD_INTE, 0);
- spin_lock(&video->lock);
+ mutex_lock(&video->buffer_lock);
clear_bit(VIDEO_CAPTURING, &video->flags);
buf = list_first_entry_or_null(&video->buffers,
struct npcm_video_buffer, link);
if (!buf) {
- spin_unlock(&video->lock);
+ mutex_unlock(&video->buffer_lock);
return IRQ_NONE;
}
@@ -1093,7 +1090,7 @@ static irqreturn_t npcm_video_irq(int irq, void *arg)
size = npcm_video_hextile(video, index, dma_addr, addr);
break;
default:
- spin_unlock(&video->lock);
+ mutex_unlock(&video->buffer_lock);
return IRQ_NONE;
}
@@ -1104,7 +1101,7 @@ static irqreturn_t npcm_video_irq(int irq, void *arg)
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
list_del(&buf->link);
- spin_unlock(&video->lock);
+ mutex_unlock(&video->buffer_lock);
if (npcm_video_start_frame(video))
dev_err(video->dev, "Failed to capture next frame\n");
@@ -1508,13 +1505,12 @@ static void npcm_video_buf_queue(struct vb2_buffer *vb)
struct npcm_video *video = vb2_get_drv_priv(vb->vb2_queue);
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct npcm_video_buffer *nvb = to_npcm_video_buffer(vbuf);
- unsigned long flags;
bool empty;
- spin_lock_irqsave(&video->lock, flags);
+ mutex_lock(&video->buffer_lock);
empty = list_empty(&video->buffers);
list_add_tail(&nvb->link, &video->buffers);
- spin_unlock_irqrestore(&video->lock, flags);
+ mutex_unlock(&video->buffer_lock);
if (test_bit(VIDEO_STREAMING, &video->flags) &&
!test_bit(VIDEO_CAPTURING, &video->flags) && empty) {
@@ -1616,7 +1612,7 @@ static int npcm_video_setup_video(struct npcm_video *video)
vbq->drv_priv = video;
vbq->buf_struct_size = sizeof(struct npcm_video_buffer);
vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- vbq->min_buffers_needed = 3;
+ vbq->min_queued_buffers = 3;
rc = vb2_queue_init(vbq);
if (rc) {
@@ -1744,8 +1740,8 @@ static int npcm_video_probe(struct platform_device *pdev)
return -ENOMEM;
video->dev = &pdev->dev;
- spin_lock_init(&video->lock);
mutex_init(&video->video_lock);
+ mutex_init(&video->buffer_lock);
INIT_LIST_HEAD(&video->buffers);
regs = devm_platform_ioremap_resource(pdev, 0);
diff --git a/drivers/media/platform/nvidia/tegra-vde/Kconfig b/drivers/media/platform/nvidia/tegra-vde/Kconfig
index f7454823bbbb..2fe13f39c95b 100644
--- a/drivers/media/platform/nvidia/tegra-vde/Kconfig
+++ b/drivers/media/platform/nvidia/tegra-vde/Kconfig
@@ -6,7 +6,6 @@ config VIDEO_TEGRA_VDE
select DMA_SHARED_BUFFER
select IOMMU_IOVA
select MEDIA_CONTROLLER
- select MEDIA_CONTROLLER_REQUEST_API
select SRAM
select VIDEOBUF2_DMA_CONTIG
select VIDEOBUF2_DMA_SG
diff --git a/drivers/media/platform/nvidia/tegra-vde/v4l2.c b/drivers/media/platform/nvidia/tegra-vde/v4l2.c
index bd8c207d5b54..0f48ce6f243e 100644
--- a/drivers/media/platform/nvidia/tegra-vde/v4l2.c
+++ b/drivers/media/platform/nvidia/tegra-vde/v4l2.c
@@ -813,7 +813,7 @@ static int tegra_open(struct file *file)
struct tegra_ctx *ctx;
int err;
- ctx = kzalloc(offsetof(struct tegra_ctx, ctrls[ARRAY_SIZE(ctrl_cfgs)]),
+ ctx = kzalloc(struct_size(ctx, ctrls, ARRAY_SIZE(ctrl_cfgs)),
GFP_KERNEL);
if (!ctx)
return -ENOMEM;
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index 6cb20b45e0a1..db8ff5f5c4d3 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -954,7 +954,7 @@ static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable)
state = v4l2_subdev_lock_and_get_active_state(sd);
- format = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, CSIS_PAD_SINK);
csis_fmt = find_csis_format(format->code);
ret = mipi_csis_calculate_params(csis, csis_fmt);
@@ -1002,7 +1002,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index > 0)
return -EINVAL;
- fmt = v4l2_subdev_get_pad_format(sd, sd_state, code->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, code->pad);
code->code = fmt->code;
return 0;
}
@@ -1069,7 +1069,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
&sdformat->format.height, 1,
CSIS_MAX_PIX_HEIGHT, 0, 0);
- fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
fmt->code = csis_fmt->code;
fmt->width = sdformat->format.width;
@@ -1083,7 +1083,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
sdformat->format = *fmt;
/* Propagate the format from sink to source. */
- fmt = v4l2_subdev_get_pad_format(sd, sd_state, CSIS_PAD_SOURCE);
+ fmt = v4l2_subdev_state_get_format(sd_state, CSIS_PAD_SOURCE);
*fmt = sdformat->format;
/* The format on the source pad might change due to unpacking. */
@@ -1104,7 +1104,7 @@ static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
return -EINVAL;
state = v4l2_subdev_lock_and_get_active_state(sd);
- fmt = v4l2_subdev_get_pad_format(sd, state, CSIS_PAD_SOURCE);
+ fmt = v4l2_subdev_state_get_format(state, CSIS_PAD_SOURCE);
csis_fmt = find_csis_format(fmt->code);
v4l2_subdev_unlock_state(state);
@@ -1122,8 +1122,8 @@ static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
return 0;
}
-static int mipi_csis_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int mipi_csis_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = {
.pad = CSIS_PAD_SINK,
@@ -1163,7 +1163,6 @@ static const struct v4l2_subdev_video_ops mipi_csis_video_ops = {
};
static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = {
- .init_cfg = mipi_csis_init_cfg,
.enum_mbus_code = mipi_csis_enum_mbus_code,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = mipi_csis_set_fmt,
@@ -1176,6 +1175,10 @@ static const struct v4l2_subdev_ops mipi_csis_subdev_ops = {
.pad = &mipi_csis_pad_ops,
};
+static const struct v4l2_subdev_internal_ops mipi_csis_internal_ops = {
+ .init_state = mipi_csis_init_state,
+};
+
/* -----------------------------------------------------------------------------
* Media entity operations
*/
@@ -1350,6 +1353,7 @@ static int mipi_csis_subdev_init(struct mipi_csis_device *csis)
int ret;
v4l2_subdev_init(sd, &mipi_csis_subdev_ops);
+ sd->internal_ops = &mipi_csis_internal_ops;
sd->owner = THIS_MODULE;
snprintf(sd->name, sizeof(sd->name), "csis-%s",
dev_name(csis->dev));
@@ -1435,24 +1439,18 @@ static int mipi_csis_probe(struct platform_device *pdev)
/* Reset PHY and enable the clocks. */
mipi_csis_phy_reset(csis);
- ret = mipi_csis_clk_enable(csis);
- if (ret < 0) {
- dev_err(csis->dev, "failed to enable clocks: %d\n", ret);
- return ret;
- }
-
/* Now that the hardware is initialized, request the interrupt. */
ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0,
dev_name(dev), csis);
if (ret) {
dev_err(dev, "Interrupt request failed\n");
- goto err_disable_clock;
+ return ret;
}
/* Initialize and register the subdev. */
ret = mipi_csis_subdev_init(csis);
if (ret < 0)
- goto err_disable_clock;
+ return ret;
platform_set_drvdata(pdev, &csis->sd);
@@ -1486,8 +1484,6 @@ err_cleanup:
v4l2_async_nf_unregister(&csis->notifier);
v4l2_async_nf_cleanup(&csis->notifier);
v4l2_async_unregister_subdev(&csis->sd);
-err_disable_clock:
- mipi_csis_clk_disable(csis);
return ret;
}
@@ -1502,9 +1498,10 @@ static void mipi_csis_remove(struct platform_device *pdev)
v4l2_async_nf_cleanup(&csis->notifier);
v4l2_async_unregister_subdev(&csis->sd);
+ if (!pm_runtime_enabled(&pdev->dev))
+ mipi_csis_runtime_suspend(&pdev->dev);
+
pm_runtime_disable(&pdev->dev);
- mipi_csis_runtime_suspend(&pdev->dev);
- mipi_csis_clk_disable(csis);
v4l2_subdev_cleanup(&csis->sd);
media_entity_cleanup(&csis->sd.entity);
pm_runtime_set_suspended(&pdev->dev);
diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
index 15049c6aab37..9566ff738818 100644
--- a/drivers/media/platform/nxp/imx7-media-csi.c
+++ b/drivers/media/platform/nxp/imx7-media-csi.c
@@ -3,31 +3,46 @@
* V4L2 Capture CSI Subdev for Freescale i.MX6UL/L / i.MX7 SOC
*
* Copyright (c) 2019 Linaro Ltd
- *
*/
#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/container_of.h>
#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
#include <linux/math.h>
-#include <linux/mfd/syscon.h>
#include <linux/minmax.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/of_graph.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
-#include <linux/regmap.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/timekeeping.h>
#include <linux/types.h>
+#include <media/media-device.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-fwnode.h>
+#include <media/v4l2-fh.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mc.h>
#include <media/v4l2-subdev.h>
+#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-v4l2.h>
#define IMX7_CSI_PAD_SINK 0
#define IMX7_CSI_PAD_SRC 1
@@ -542,8 +557,8 @@ static void imx7_csi_configure(struct imx7_csi *csi,
} else {
const struct v4l2_mbus_framefmt *sink_fmt;
- sink_fmt = v4l2_subdev_get_pad_format(&csi->sd, sd_state,
- IMX7_CSI_PAD_SINK);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ IMX7_CSI_PAD_SINK);
cr1 = BIT_SOF_POL | BIT_REDGE | BIT_HSYNC_POL | BIT_FCC
| BIT_MCLKDIV(1) | BIT_MCLKEN;
@@ -1245,6 +1260,7 @@ static int imx7_csi_video_queue_setup(struct vb2_queue *vq,
struct device *alloc_devs[])
{
struct imx7_csi *csi = vb2_get_drv_priv(vq);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
struct v4l2_pix_format *pix = &csi->vdev_fmt;
unsigned int count = *nbuffers;
@@ -1254,14 +1270,14 @@ static int imx7_csi_video_queue_setup(struct vb2_queue *vq,
if (*nplanes) {
if (*nplanes != 1 || sizes[0] < pix->sizeimage)
return -EINVAL;
- count += vq->num_buffers;
+ count += q_num_bufs;
}
count = min_t(__u32, IMX7_CSI_VIDEO_MEM_LIMIT / pix->sizeimage, count);
if (*nplanes)
- *nbuffers = (count < vq->num_buffers) ? 0 :
- count - vq->num_buffers;
+ *nbuffers = (count < q_num_bufs) ? 0 :
+ count - q_num_bufs;
else
*nbuffers = count;
@@ -1675,7 +1691,7 @@ static int imx7_csi_video_init(struct imx7_csi *csi)
vq->mem_ops = &vb2_dma_contig_memops;
vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
vq->lock = &csi->vdev_mutex;
- vq->min_buffers_needed = 2;
+ vq->min_queued_buffers = 2;
vq->dev = csi->dev;
ret = vb2_queue_init(vq);
@@ -1728,8 +1744,8 @@ out_unlock:
return ret;
}
-static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int imx7_csi_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
const struct imx7_csi_pixfmt *cc;
int i;
@@ -1738,7 +1754,7 @@ static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
struct v4l2_mbus_framefmt *mf =
- v4l2_subdev_get_pad_format(sd, sd_state, i);
+ v4l2_subdev_state_get_format(sd_state, i);
mf->code = IMX7_CSI_DEF_MBUS_CODE;
mf->width = IMX7_CSI_DEF_PIX_WIDTH;
@@ -1762,7 +1778,7 @@ static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *in_fmt;
int ret = 0;
- in_fmt = v4l2_subdev_get_pad_format(sd, sd_state, IMX7_CSI_PAD_SINK);
+ in_fmt = v4l2_subdev_state_get_format(sd_state, IMX7_CSI_PAD_SINK);
switch (code->pad) {
case IMX7_CSI_PAD_SINK:
@@ -1841,7 +1857,7 @@ static void imx7_csi_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *in_fmt;
u32 code;
- in_fmt = v4l2_subdev_get_pad_format(sd, sd_state, IMX7_CSI_PAD_SINK);
+ in_fmt = v4l2_subdev_state_get_format(sd_state, IMX7_CSI_PAD_SINK);
switch (sdformat->pad) {
case IMX7_CSI_PAD_SRC:
@@ -1891,7 +1907,7 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
imx7_csi_try_fmt(sd, sd_state, sdformat, &cc);
- fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
*fmt = sdformat->format;
@@ -1902,8 +1918,8 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
format.format = sdformat->format;
imx7_csi_try_fmt(sd, sd_state, &format, &outcc);
- outfmt = v4l2_subdev_get_pad_format(sd, sd_state,
- IMX7_CSI_PAD_SRC);
+ outfmt = v4l2_subdev_state_get_format(sd_state,
+ IMX7_CSI_PAD_SRC);
*outfmt = format.format;
}
@@ -2005,7 +2021,6 @@ static const struct v4l2_subdev_video_ops imx7_csi_video_ops = {
};
static const struct v4l2_subdev_pad_ops imx7_csi_pad_ops = {
- .init_cfg = imx7_csi_init_cfg,
.enum_mbus_code = imx7_csi_enum_mbus_code,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = imx7_csi_set_fmt,
@@ -2018,6 +2033,7 @@ static const struct v4l2_subdev_ops imx7_csi_subdev_ops = {
};
static const struct v4l2_subdev_internal_ops imx7_csi_internal_ops = {
+ .init_state = imx7_csi_init_state,
.registered = imx7_csi_registered,
.unregistered = imx7_csi_unregistered,
};
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
index 792f031e032a..575f17337388 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
@@ -58,7 +58,7 @@ static int mxc_isi_crossbar_gasket_enable(struct mxc_isi_crossbar *xbar,
return -EINVAL;
}
- fmt = v4l2_subdev_state_get_stream_format(state, port, 0);
+ fmt = v4l2_subdev_state_get_format(state, port, 0);
if (!fmt)
return -EINVAL;
@@ -176,8 +176,8 @@ mxc_isi_crossbar_xlate_streams(struct mxc_isi_crossbar *xbar,
return sd;
}
-static int mxc_isi_crossbar_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int mxc_isi_crossbar_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct mxc_isi_crossbar *xbar = to_isi_crossbar(sd);
struct v4l2_subdev_krouting routing = { };
@@ -281,8 +281,7 @@ static int mxc_isi_crossbar_set_fmt(struct v4l2_subdev *sd,
* Set the format on the sink stream and propagate it to the source
* streams.
*/
- sink_fmt = v4l2_subdev_state_get_stream_format(state, fmt->pad,
- fmt->stream);
+ sink_fmt = v4l2_subdev_state_get_format(state, fmt->pad, fmt->stream);
if (!sink_fmt)
return -EINVAL;
@@ -296,8 +295,9 @@ static int mxc_isi_crossbar_set_fmt(struct v4l2_subdev *sd,
route->sink_stream != fmt->stream)
continue;
- source_fmt = v4l2_subdev_state_get_stream_format(state, route->source_pad,
- route->source_stream);
+ source_fmt = v4l2_subdev_state_get_format(state,
+ route->source_pad,
+ route->source_stream);
if (!source_fmt)
return -EINVAL;
@@ -404,7 +404,6 @@ static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_pad_ops mxc_isi_crossbar_subdev_pad_ops = {
- .init_cfg = mxc_isi_crossbar_init_cfg,
.enum_mbus_code = mxc_isi_crossbar_enum_mbus_code,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = mxc_isi_crossbar_set_fmt,
@@ -417,6 +416,10 @@ static const struct v4l2_subdev_ops mxc_isi_crossbar_subdev_ops = {
.pad = &mxc_isi_crossbar_subdev_pad_ops,
};
+static const struct v4l2_subdev_internal_ops mxc_isi_crossbar_internal_ops = {
+ .init_state = mxc_isi_crossbar_init_state,
+};
+
static const struct media_entity_operations mxc_isi_cross_entity_ops = {
.get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
.link_validate = v4l2_subdev_link_validate,
@@ -438,6 +441,7 @@ int mxc_isi_crossbar_init(struct mxc_isi_dev *isi)
xbar->isi = isi;
v4l2_subdev_init(sd, &mxc_isi_crossbar_subdev_ops);
+ sd->internal_ops = &mxc_isi_crossbar_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
strscpy(sd->name, "crossbar", sizeof(sd->name));
sd->dev = isi->dev;
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c
index 6709ab7ea1f3..5e8a177da054 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-debug.c
@@ -22,10 +22,11 @@ static inline u32 mxc_isi_read(struct mxc_isi_pipe *pipe, u32 reg)
static int mxc_isi_debug_dump_regs_show(struct seq_file *m, void *p)
{
#define MXC_ISI_DEBUG_REG(name) { name, #name }
- static const struct {
+ struct debug_regs {
u32 offset;
const char * const name;
- } registers[] = {
+ };
+ static const struct debug_regs registers[] = {
MXC_ISI_DEBUG_REG(CHNL_CTRL),
MXC_ISI_DEBUG_REG(CHNL_IMG_CTRL),
MXC_ISI_DEBUG_REG(CHNL_OUT_BUF_CTRL),
@@ -67,6 +68,16 @@ static int mxc_isi_debug_dump_regs_show(struct seq_file *m, void *p)
MXC_ISI_DEBUG_REG(CHNL_SCL_IMG_CFG),
MXC_ISI_DEBUG_REG(CHNL_FLOW_CTRL),
};
+ /* These registers contain the upper 4 bits of 36-bit DMA addresses. */
+ static const struct debug_regs registers_36bit_dma[] = {
+ MXC_ISI_DEBUG_REG(CHNL_Y_BUF1_XTND_ADDR),
+ MXC_ISI_DEBUG_REG(CHNL_U_BUF1_XTND_ADDR),
+ MXC_ISI_DEBUG_REG(CHNL_V_BUF1_XTND_ADDR),
+ MXC_ISI_DEBUG_REG(CHNL_Y_BUF2_XTND_ADDR),
+ MXC_ISI_DEBUG_REG(CHNL_U_BUF2_XTND_ADDR),
+ MXC_ISI_DEBUG_REG(CHNL_V_BUF2_XTND_ADDR),
+ MXC_ISI_DEBUG_REG(CHNL_IN_BUF_XTND_ADDR),
+ };
struct mxc_isi_pipe *pipe = m->private;
unsigned int i;
@@ -77,10 +88,20 @@ static int mxc_isi_debug_dump_regs_show(struct seq_file *m, void *p)
seq_printf(m, "--- ISI pipe %u registers ---\n", pipe->id);
for (i = 0; i < ARRAY_SIZE(registers); ++i)
- seq_printf(m, "%20s[0x%02x]: 0x%08x\n",
+ seq_printf(m, "%21s[0x%02x]: 0x%08x\n",
registers[i].name, registers[i].offset,
mxc_isi_read(pipe, registers[i].offset));
+ if (pipe->isi->pdata->has_36bit_dma) {
+ for (i = 0; i < ARRAY_SIZE(registers_36bit_dma); ++i) {
+ const struct debug_regs *reg = &registers_36bit_dma[i];
+
+ seq_printf(m, "%21s[0x%02x]: 0x%08x\n",
+ reg->name, reg->offset,
+ mxc_isi_read(pipe, reg->offset));
+ }
+ }
+
pm_runtime_put(pipe->isi->dev);
return 0;
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c
index 65d20e9bae69..d76eb58deb09 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c
@@ -263,10 +263,10 @@ int mxc_isi_pipe_enable(struct mxc_isi_pipe *pipe)
/* Configure the pipeline. */
state = v4l2_subdev_lock_and_get_active_state(sd);
- sink_fmt = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SINK);
- src_fmt = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SOURCE);
- compose = v4l2_subdev_get_try_compose(sd, state, MXC_ISI_PIPE_PAD_SINK);
- crop = *v4l2_subdev_get_try_crop(sd, state, MXC_ISI_PIPE_PAD_SOURCE);
+ sink_fmt = v4l2_subdev_state_get_format(state, MXC_ISI_PIPE_PAD_SINK);
+ src_fmt = v4l2_subdev_state_get_format(state, MXC_ISI_PIPE_PAD_SOURCE);
+ compose = v4l2_subdev_state_get_compose(state, MXC_ISI_PIPE_PAD_SINK);
+ crop = *v4l2_subdev_state_get_crop(state, MXC_ISI_PIPE_PAD_SOURCE);
sink_info = mxc_isi_bus_format_by_code(sink_fmt->code,
MXC_ISI_PIPE_PAD_SINK);
@@ -322,7 +322,7 @@ mxc_isi_pipe_get_pad_format(struct mxc_isi_pipe *pipe,
struct v4l2_subdev_state *state,
unsigned int pad)
{
- return v4l2_subdev_get_try_format(&pipe->sd, state, pad);
+ return v4l2_subdev_state_get_format(state, pad);
}
static struct v4l2_rect *
@@ -330,7 +330,7 @@ mxc_isi_pipe_get_pad_crop(struct mxc_isi_pipe *pipe,
struct v4l2_subdev_state *state,
unsigned int pad)
{
- return v4l2_subdev_get_try_crop(&pipe->sd, state, pad);
+ return v4l2_subdev_state_get_crop(state, pad);
}
static struct v4l2_rect *
@@ -338,11 +338,11 @@ mxc_isi_pipe_get_pad_compose(struct mxc_isi_pipe *pipe,
struct v4l2_subdev_state *state,
unsigned int pad)
{
- return v4l2_subdev_get_try_compose(&pipe->sd, state, pad);
+ return v4l2_subdev_state_get_compose(state, pad);
}
-static int mxc_isi_pipe_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int mxc_isi_pipe_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct mxc_isi_pipe *pipe = to_isi_pipe(sd);
struct v4l2_mbus_framefmt *fmt_source;
@@ -682,7 +682,6 @@ static int mxc_isi_pipe_set_selection(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_pad_ops mxc_isi_pipe_subdev_pad_ops = {
- .init_cfg = mxc_isi_pipe_init_cfg,
.enum_mbus_code = mxc_isi_pipe_enum_mbus_code,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = mxc_isi_pipe_set_fmt,
@@ -694,6 +693,10 @@ static const struct v4l2_subdev_ops mxc_isi_pipe_subdev_ops = {
.pad = &mxc_isi_pipe_subdev_pad_ops,
};
+static const struct v4l2_subdev_internal_ops mxc_isi_pipe_internal_ops = {
+ .init_state = mxc_isi_pipe_init_state,
+};
+
/* -----------------------------------------------------------------------------
* IRQ handling
*/
@@ -767,6 +770,7 @@ int mxc_isi_pipe_init(struct mxc_isi_dev *isi, unsigned int id)
sd = &pipe->sd;
v4l2_subdev_init(sd, &mxc_isi_pipe_subdev_ops);
+ sd->internal_ops = &mxc_isi_pipe_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, sizeof(sd->name), "mxc_isi.%d", pipe->id);
sd->dev = isi->dev;
@@ -832,8 +836,8 @@ int mxc_isi_pipe_acquire(struct mxc_isi_pipe *pipe,
int ret;
state = v4l2_subdev_lock_and_get_active_state(sd);
- sink_fmt = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SINK);
- src_fmt = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SOURCE);
+ sink_fmt = v4l2_subdev_state_get_format(state, MXC_ISI_PIPE_PAD_SINK);
+ src_fmt = v4l2_subdev_state_get_format(state, MXC_ISI_PIPE_PAD_SOURCE);
v4l2_subdev_unlock_state(state);
sink_info = mxc_isi_bus_format_by_code(sink_fmt->code,
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
index 10840c9a0912..4091f1c0e78b 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
@@ -713,7 +713,7 @@ static int mxc_isi_video_validate_format(struct mxc_isi_video *video)
info = mxc_isi_format_by_fourcc(video->pix.pixelformat,
MXC_ISI_VIDEO_CAP);
- format = v4l2_subdev_get_try_format(sd, state, MXC_ISI_PIPE_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, MXC_ISI_PIPE_PAD_SOURCE);
if (format->code != info->mbus_code ||
format->width != video->pix.width ||
@@ -1453,7 +1453,7 @@ int mxc_isi_video_register(struct mxc_isi_pipe *pipe,
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct mxc_isi_buffer);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->lock = &video->lock;
q->dev = pipe->isi->dev;
diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
index ed048f73c982..ba2e81f24965 100644
--- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
+++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
@@ -296,7 +296,7 @@ static int imx8mq_mipi_csi_calc_hs_settle(struct csi_state *state,
/* Calculate the line rate from the pixel rate. */
- fmt = v4l2_subdev_get_pad_format(&state->sd, sd_state, MIPI_CSI2_PAD_SINK);
+ fmt = v4l2_subdev_state_get_format(sd_state, MIPI_CSI2_PAD_SINK);
csi2_fmt = find_csi2_format(fmt->code);
link_freq = v4l2_get_link_freq(state->src_sd->ctrl_handler,
@@ -437,14 +437,15 @@ unlock:
return ret;
}
-static int imx8mq_mipi_csi_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int imx8mq_mipi_csi_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *fmt_sink;
struct v4l2_mbus_framefmt *fmt_source;
- fmt_sink = v4l2_subdev_get_pad_format(sd, sd_state, MIPI_CSI2_PAD_SINK);
- fmt_source = v4l2_subdev_get_pad_format(sd, sd_state, MIPI_CSI2_PAD_SOURCE);
+ fmt_sink = v4l2_subdev_state_get_format(sd_state, MIPI_CSI2_PAD_SINK);
+ fmt_source = v4l2_subdev_state_get_format(sd_state,
+ MIPI_CSI2_PAD_SOURCE);
fmt_sink->code = MEDIA_BUS_FMT_SGBRG10_1X10;
fmt_sink->width = MIPI_CSI2_DEF_PIX_WIDTH;
@@ -477,7 +478,7 @@ static int imx8mq_mipi_csi_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index > 0)
return -EINVAL;
- fmt = v4l2_subdev_get_pad_format(sd, sd_state, code->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, code->pad);
code->code = fmt->code;
return 0;
}
@@ -514,7 +515,7 @@ static int imx8mq_mipi_csi_set_fmt(struct v4l2_subdev *sd,
if (!csi2_fmt)
csi2_fmt = &imx8mq_mipi_csi_formats[0];
- fmt = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
fmt->code = csi2_fmt->code;
fmt->width = sdformat->format.width;
@@ -523,7 +524,7 @@ static int imx8mq_mipi_csi_set_fmt(struct v4l2_subdev *sd,
sdformat->format = *fmt;
/* Propagate the format from sink to source. */
- fmt = v4l2_subdev_get_pad_format(sd, sd_state, MIPI_CSI2_PAD_SOURCE);
+ fmt = v4l2_subdev_state_get_format(sd_state, MIPI_CSI2_PAD_SOURCE);
*fmt = sdformat->format;
return 0;
@@ -534,7 +535,6 @@ static const struct v4l2_subdev_video_ops imx8mq_mipi_csi_video_ops = {
};
static const struct v4l2_subdev_pad_ops imx8mq_mipi_csi_pad_ops = {
- .init_cfg = imx8mq_mipi_csi_init_cfg,
.enum_mbus_code = imx8mq_mipi_csi_enum_mbus_code,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = imx8mq_mipi_csi_set_fmt,
@@ -545,6 +545,10 @@ static const struct v4l2_subdev_ops imx8mq_mipi_csi_subdev_ops = {
.pad = &imx8mq_mipi_csi_pad_ops,
};
+static const struct v4l2_subdev_internal_ops imx8mq_mipi_csi_internal_ops = {
+ .init_state = imx8mq_mipi_csi_init_state,
+};
+
/* -----------------------------------------------------------------------------
* Media entity operations
*/
@@ -759,6 +763,7 @@ static int imx8mq_mipi_csi_subdev_init(struct csi_state *state)
int ret;
v4l2_subdev_init(sd, &imx8mq_mipi_csi_subdev_ops);
+ sd->internal_ops = &imx8mq_mipi_csi_internal_ops;
sd->owner = THIS_MODULE;
snprintf(sd->name, sizeof(sd->name), "%s %s",
MIPI_CSI2_SUBDEV_NAME, dev_name(state->dev));
diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.c b/drivers/media/platform/qcom/camss/camss-csid-gen2.c
index 05ff5fa8095a..b11de4797cca 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c
@@ -21,7 +21,6 @@
* interface support. As a result of that it has an
* alternate register layout.
*/
-#define IS_LITE (csid->id >= 2 ? 1 : 0)
#define CSID_HW_VERSION 0x0
#define HW_VERSION_STEPPING 0
@@ -35,13 +34,13 @@
#define CSID_CSI2_RX_IRQ_MASK 0x24
#define CSID_CSI2_RX_IRQ_CLEAR 0x28
-#define CSID_CSI2_RDIN_IRQ_STATUS(rdi) ((IS_LITE ? 0x30 : 0x40) \
+#define CSID_CSI2_RDIN_IRQ_STATUS(rdi) ((csid_is_lite(csid) ? 0x30 : 0x40) \
+ 0x10 * (rdi))
-#define CSID_CSI2_RDIN_IRQ_MASK(rdi) ((IS_LITE ? 0x34 : 0x44) \
+#define CSID_CSI2_RDIN_IRQ_MASK(rdi) ((csid_is_lite(csid) ? 0x34 : 0x44) \
+ 0x10 * (rdi))
-#define CSID_CSI2_RDIN_IRQ_CLEAR(rdi) ((IS_LITE ? 0x38 : 0x48) \
+#define CSID_CSI2_RDIN_IRQ_CLEAR(rdi) ((csid_is_lite(csid) ? 0x38 : 0x48) \
+ 0x10 * (rdi))
-#define CSID_CSI2_RDIN_IRQ_SET(rdi) ((IS_LITE ? 0x3C : 0x4C) \
+#define CSID_CSI2_RDIN_IRQ_SET(rdi) ((csid_is_lite(csid) ? 0x3C : 0x4C) \
+ 0x10 * (rdi))
#define CSID_TOP_IRQ_STATUS 0x70
@@ -73,7 +72,7 @@
#define CGC_MODE_DYNAMIC_GATING 0
#define CGC_MODE_ALWAYS_ON 1
-#define CSID_RDI_CFG0(rdi) ((IS_LITE ? 0x200 : 0x300) \
+#define CSID_RDI_CFG0(rdi) ((csid_is_lite(csid) ? 0x200 : 0x300) \
+ 0x100 * (rdi))
#define RDI_CFG0_BYTE_CNTR_EN 0
#define RDI_CFG0_FORMAT_MEASURE_EN 1
@@ -98,32 +97,32 @@
#define RDI_CFG0_PACKING_FORMAT 30
#define RDI_CFG0_ENABLE 31
-#define CSID_RDI_CFG1(rdi) ((IS_LITE ? 0x204 : 0x304)\
+#define CSID_RDI_CFG1(rdi) ((csid_is_lite(csid) ? 0x204 : 0x304)\
+ 0x100 * (rdi))
#define RDI_CFG1_TIMESTAMP_STB_SEL 0
-#define CSID_RDI_CTRL(rdi) ((IS_LITE ? 0x208 : 0x308)\
+#define CSID_RDI_CTRL(rdi) ((csid_is_lite(csid) ? 0x208 : 0x308)\
+ 0x100 * (rdi))
#define RDI_CTRL_HALT_CMD 0
#define HALT_CMD_HALT_AT_FRAME_BOUNDARY 0
#define HALT_CMD_RESUME_AT_FRAME_BOUNDARY 1
#define RDI_CTRL_HALT_MODE 2
-#define CSID_RDI_FRM_DROP_PATTERN(rdi) ((IS_LITE ? 0x20C : 0x30C)\
+#define CSID_RDI_FRM_DROP_PATTERN(rdi) ((csid_is_lite(csid) ? 0x20C : 0x30C)\
+ 0x100 * (rdi))
-#define CSID_RDI_FRM_DROP_PERIOD(rdi) ((IS_LITE ? 0x210 : 0x310)\
+#define CSID_RDI_FRM_DROP_PERIOD(rdi) ((csid_is_lite(csid) ? 0x210 : 0x310)\
+ 0x100 * (rdi))
-#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi) ((IS_LITE ? 0x214 : 0x314)\
+#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi) ((csid_is_lite(csid) ? 0x214 : 0x314)\
+ 0x100 * (rdi))
-#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi) ((IS_LITE ? 0x218 : 0x318)\
+#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi) ((csid_is_lite(csid) ? 0x218 : 0x318)\
+ 0x100 * (rdi))
-#define CSID_RDI_RPP_PIX_DROP_PATTERN(rdi) ((IS_LITE ? 0x224 : 0x324)\
+#define CSID_RDI_RPP_PIX_DROP_PATTERN(rdi) ((csid_is_lite(csid) ? 0x224 : 0x324)\
+ 0x100 * (rdi))
-#define CSID_RDI_RPP_PIX_DROP_PERIOD(rdi) ((IS_LITE ? 0x228 : 0x328)\
+#define CSID_RDI_RPP_PIX_DROP_PERIOD(rdi) ((csid_is_lite(csid) ? 0x228 : 0x328)\
+ 0x100 * (rdi))
-#define CSID_RDI_RPP_LINE_DROP_PATTERN(rdi) ((IS_LITE ? 0x22C : 0x32C)\
+#define CSID_RDI_RPP_LINE_DROP_PATTERN(rdi) ((csid_is_lite(csid) ? 0x22C : 0x32C)\
+ 0x100 * (rdi))
-#define CSID_RDI_RPP_LINE_DROP_PERIOD(rdi) ((IS_LITE ? 0x230 : 0x330)\
+#define CSID_RDI_RPP_LINE_DROP_PERIOD(rdi) ((csid_is_lite(csid) ? 0x230 : 0x330)\
+ 0x100 * (rdi))
#define CSID_TPG_CTRL 0x600
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index 95873f988f7e..eb27d69e89a1 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -263,7 +263,7 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
/*
* __csid_get_format - Get pointer to format structure
* @csid: CSID device
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad: pad from which format is requested
* @which: TRY or ACTIVE format
*
@@ -276,8 +276,7 @@ __csid_get_format(struct csid_device *csid,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csid->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
return &csid->fmt[pad];
}
@@ -285,7 +284,7 @@ __csid_get_format(struct csid_device *csid,
/*
* csid_try_format - Handle try format by pad subdev method
* @csid: CSID device
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad: pad on which format is requested
* @fmt: pointer to v4l2 format structure
* @which: wanted subdev format
@@ -353,7 +352,7 @@ static void csid_try_format(struct csid_device *csid,
/*
* csid_enum_mbus_code - Handle pixel format enumeration
* @sd: CSID V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @code: pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
@@ -394,7 +393,7 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,
/*
* csid_enum_frame_size - Handle frame size enumeration
* @sd: CSID V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fse: pointer to v4l2_subdev_frame_size_enum structure
* return -EINVAL or zero on success
*/
@@ -431,7 +430,7 @@ static int csid_enum_frame_size(struct v4l2_subdev *sd,
/*
* csid_get_format - Handle get format by pads subdev method
* @sd: CSID V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
*
* Return -EINVAL or zero on success
@@ -455,7 +454,7 @@ static int csid_get_format(struct v4l2_subdev *sd,
/*
* csid_set_format - Handle set format by pads subdev method
* @sd: CSID V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
*
* Return -EINVAL or zero on success
@@ -897,3 +896,8 @@ void msm_csid_unregister_entity(struct csid_device *csid)
media_entity_cleanup(&csid->subdev.entity);
v4l2_ctrl_handler_free(&csid->ctrls);
}
+
+inline bool csid_is_lite(struct csid_device *csid)
+{
+ return csid->camss->res->csid_res[csid->id].is_lite;
+}
diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index 30d94eb2eb04..fddccb69da13 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -215,5 +215,12 @@ extern const struct csid_hw_ops csid_ops_4_1;
extern const struct csid_hw_ops csid_ops_4_7;
extern const struct csid_hw_ops csid_ops_gen2;
+/*
+ * csid_is_lite - Check if CSID is CSID lite.
+ * @csid: CSID Device
+ *
+ * Return whether CSID is CSID lite
+ */
+bool csid_is_lite(struct csid_device *csid);
#endif /* QC_MSM_CAMSS_CSID_H */
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
index edd573606a6a..264c99efeae8 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -312,7 +312,7 @@ static int csiphy_set_stream(struct v4l2_subdev *sd, int enable)
/*
* __csiphy_get_format - Get pointer to format structure
* @csiphy: CSIPHY device
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad: pad from which format is requested
* @which: TRY or ACTIVE format
*
@@ -325,8 +325,7 @@ __csiphy_get_format(struct csiphy_device *csiphy,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csiphy->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
return &csiphy->fmt[pad];
}
@@ -334,7 +333,7 @@ __csiphy_get_format(struct csiphy_device *csiphy,
/*
* csiphy_try_format - Handle try format by pad subdev method
* @csiphy: CSIPHY device
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad: pad on which format is requested
* @fmt: pointer to v4l2 format structure
* @which: wanted subdev format
@@ -381,7 +380,7 @@ static void csiphy_try_format(struct csiphy_device *csiphy,
/*
* csiphy_enum_mbus_code - Handle pixel format enumeration
* @sd: CSIPHY V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @code: pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
@@ -414,7 +413,7 @@ static int csiphy_enum_mbus_code(struct v4l2_subdev *sd,
/*
* csiphy_enum_frame_size - Handle frame size enumeration
* @sd: CSIPHY V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fse: pointer to v4l2_subdev_frame_size_enum structure
* return -EINVAL or zero on success
*/
@@ -451,7 +450,7 @@ static int csiphy_enum_frame_size(struct v4l2_subdev *sd,
/*
* csiphy_get_format - Handle get format by pads subdev method
* @sd: CSIPHY V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
*
* Return -EINVAL or zero on success
@@ -475,7 +474,7 @@ static int csiphy_get_format(struct v4l2_subdev *sd,
/*
* csiphy_set_format - Handle set format by pads subdev method
* @sd: CSIPHY V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
*
* Return -EINVAL or zero on success
diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
index be9d2f0a10c1..a12dcc7ff438 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.c
+++ b/drivers/media/platform/qcom/camss/camss-ispif.c
@@ -270,7 +270,7 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id)
unsigned long time;
u32 val;
- if (vfe_id > camss->res->vfe_num - 1) {
+ if (vfe_id >= camss->res->vfe_num) {
dev_err(camss->dev,
"Error: asked reset for invalid VFE%d\n", vfe_id);
return -ENOENT;
@@ -866,7 +866,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
/*
* __ispif_get_format - Get pointer to format structure
* @ispif: ISPIF line
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad: pad from which format is requested
* @which: TRY or ACTIVE format
*
@@ -879,8 +879,7 @@ __ispif_get_format(struct ispif_line *line,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&line->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
return &line->fmt[pad];
}
@@ -888,7 +887,7 @@ __ispif_get_format(struct ispif_line *line,
/*
* ispif_try_format - Handle try format by pad subdev method
* @ispif: ISPIF line
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad: pad on which format is requested
* @fmt: pointer to v4l2 format structure
* @which: wanted subdev format
@@ -936,7 +935,7 @@ static void ispif_try_format(struct ispif_line *line,
/*
* ispif_enum_mbus_code - Handle pixel format enumeration
* @sd: ISPIF V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @code: pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
@@ -969,7 +968,7 @@ static int ispif_enum_mbus_code(struct v4l2_subdev *sd,
/*
* ispif_enum_frame_size - Handle frame size enumeration
* @sd: ISPIF V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fse: pointer to v4l2_subdev_frame_size_enum structure
* return -EINVAL or zero on success
*/
@@ -1006,7 +1005,7 @@ static int ispif_enum_frame_size(struct v4l2_subdev *sd,
/*
* ispif_get_format - Handle get format by pads subdev method
* @sd: ISPIF V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
*
* Return -EINVAL or zero on success
@@ -1030,7 +1029,7 @@ static int ispif_get_format(struct v4l2_subdev *sd,
/*
* ispif_set_format - Handle set format by pads subdev method
* @sd: ISPIF V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
*
* Return -EINVAL or zero on success
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c
index 0b211fed1276..795ac3815339 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-170.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c
@@ -628,42 +628,6 @@ out_unlock:
}
/*
- * vfe_pm_domain_off - Disable power domains specific to this VFE.
- * @vfe: VFE Device
- */
-static void vfe_pm_domain_off(struct vfe_device *vfe)
-{
- struct camss *camss = vfe->camss;
-
- if (vfe->id >= camss->res->vfe_num)
- return;
-
- device_link_del(camss->genpd_link[vfe->id]);
-}
-
-/*
- * vfe_pm_domain_on - Enable power domains specific to this VFE.
- * @vfe: VFE Device
- */
-static int vfe_pm_domain_on(struct vfe_device *vfe)
-{
- struct camss *camss = vfe->camss;
- enum vfe_line_id id = vfe->id;
-
- if (id >= camss->res->vfe_num)
- return 0;
-
- camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id],
- DL_FLAG_STATELESS |
- DL_FLAG_PM_RUNTIME |
- DL_FLAG_RPM_ACTIVE);
- if (!camss->genpd_link[id])
- return -EINVAL;
-
- return 0;
-}
-
-/*
* vfe_queue_buffer - Add empty buffer
* @vid: Video device structure
* @buf: Buffer to be enqueued
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
index 2911e4126e7a..ef6b34c915df 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
@@ -936,7 +936,7 @@ static irqreturn_t vfe_isr(int irq, void *dev)
* vfe_pm_domain_off - Disable power domains specific to this VFE.
* @vfe: VFE Device
*/
-static void vfe_pm_domain_off(struct vfe_device *vfe)
+static void vfe_4_1_pm_domain_off(struct vfe_device *vfe)
{
/* nop */
}
@@ -945,7 +945,7 @@ static void vfe_pm_domain_off(struct vfe_device *vfe)
* vfe_pm_domain_on - Enable power domains specific to this VFE.
* @vfe: VFE Device
*/
-static int vfe_pm_domain_on(struct vfe_device *vfe)
+static int vfe_4_1_pm_domain_on(struct vfe_device *vfe)
{
return 0;
}
@@ -999,8 +999,8 @@ const struct vfe_hw_ops vfe_ops_4_1 = {
.hw_version = vfe_hw_version,
.isr_read = vfe_isr_read,
.isr = vfe_isr,
- .pm_domain_off = vfe_pm_domain_off,
- .pm_domain_on = vfe_pm_domain_on,
+ .pm_domain_off = vfe_4_1_pm_domain_off,
+ .pm_domain_on = vfe_4_1_pm_domain_on,
.reg_update_clear = vfe_reg_update_clear,
.reg_update = vfe_reg_update,
.subdev_init = vfe_subdev_init,
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
index b65ed0fef595..7655d22a9fda 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
@@ -1103,42 +1103,6 @@ static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
}
-/*
- * vfe_pm_domain_off - Disable power domains specific to this VFE.
- * @vfe: VFE Device
- */
-static void vfe_pm_domain_off(struct vfe_device *vfe)
-{
- struct camss *camss;
-
- if (!vfe)
- return;
-
- camss = vfe->camss;
-
- device_link_del(camss->genpd_link[vfe->id]);
-}
-
-/*
- * vfe_pm_domain_on - Enable power domains specific to this VFE.
- * @vfe: VFE Device
- */
-static int vfe_pm_domain_on(struct vfe_device *vfe)
-{
- struct camss *camss = vfe->camss;
- enum vfe_line_id id = vfe->id;
-
- camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], DL_FLAG_STATELESS |
- DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
-
- if (!camss->genpd_link[id]) {
- dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", id);
- return -EINVAL;
- }
-
- return 0;
-}
-
static void vfe_violation_read(struct vfe_device *vfe)
{
u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
index 7b3805177f03..f52fa30f3853 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
@@ -1093,37 +1093,6 @@ static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1)
writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD);
}
-/*
- * vfe_pm_domain_off - Disable power domains specific to this VFE.
- * @vfe: VFE Device
- */
-static void vfe_pm_domain_off(struct vfe_device *vfe)
-{
- struct camss *camss = vfe->camss;
-
- device_link_del(camss->genpd_link[vfe->id]);
-}
-
-/*
- * vfe_pm_domain_on - Enable power domains specific to this VFE.
- * @vfe: VFE Device
- */
-static int vfe_pm_domain_on(struct vfe_device *vfe)
-{
- struct camss *camss = vfe->camss;
- enum vfe_line_id id = vfe->id;
-
- camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], DL_FLAG_STATELESS |
- DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
-
- if (!camss->genpd_link[id]) {
- dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", id);
- return -EINVAL;
- }
-
- return 0;
-}
-
static void vfe_violation_read(struct vfe_device *vfe)
{
u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-480.c b/drivers/media/platform/qcom/camss/camss-vfe-480.c
index f2368b77fc6d..dc2735476c82 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-480.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-480.c
@@ -15,31 +15,28 @@
#include "camss.h"
#include "camss-vfe.h"
-/* VFE 2/3 are lite and have a different register layout */
-#define IS_LITE (vfe->id >= 2 ? 1 : 0)
-
#define VFE_HW_VERSION (0x00)
-#define VFE_GLOBAL_RESET_CMD (IS_LITE ? 0x0c : 0x1c)
-#define GLOBAL_RESET_HW_AND_REG (IS_LITE ? BIT(1) : BIT(0))
+#define VFE_GLOBAL_RESET_CMD (vfe_is_lite(vfe) ? 0x0c : 0x1c)
+#define GLOBAL_RESET_HW_AND_REG (vfe_is_lite(vfe) ? BIT(1) : BIT(0))
-#define VFE_REG_UPDATE_CMD (IS_LITE ? 0x20 : 0x34)
+#define VFE_REG_UPDATE_CMD (vfe_is_lite(vfe) ? 0x20 : 0x34)
static inline int reg_update_rdi(struct vfe_device *vfe, int n)
{
- return IS_LITE ? BIT(n) : BIT(1 + (n));
+ return vfe_is_lite(vfe) ? BIT(n) : BIT(1 + (n));
}
#define REG_UPDATE_RDI reg_update_rdi
-#define VFE_IRQ_CMD (IS_LITE ? 0x24 : 0x38)
+#define VFE_IRQ_CMD (vfe_is_lite(vfe) ? 0x24 : 0x38)
#define IRQ_CMD_GLOBAL_CLEAR BIT(0)
-#define VFE_IRQ_MASK(n) ((IS_LITE ? 0x28 : 0x3c) + (n) * 4)
-#define IRQ_MASK_0_RESET_ACK (IS_LITE ? BIT(17) : BIT(0))
-#define IRQ_MASK_0_BUS_TOP_IRQ (IS_LITE ? BIT(4) : BIT(7))
-#define VFE_IRQ_CLEAR(n) ((IS_LITE ? 0x34 : 0x48) + (n) * 4)
-#define VFE_IRQ_STATUS(n) ((IS_LITE ? 0x40 : 0x54) + (n) * 4)
+#define VFE_IRQ_MASK(n) ((vfe_is_lite(vfe) ? 0x28 : 0x3c) + (n) * 4)
+#define IRQ_MASK_0_RESET_ACK (vfe_is_lite(vfe) ? BIT(17) : BIT(0))
+#define IRQ_MASK_0_BUS_TOP_IRQ (vfe_is_lite(vfe) ? BIT(4) : BIT(7))
+#define VFE_IRQ_CLEAR(n) ((vfe_is_lite(vfe) ? 0x34 : 0x48) + (n) * 4)
+#define VFE_IRQ_STATUS(n) ((vfe_is_lite(vfe) ? 0x40 : 0x54) + (n) * 4)
-#define BUS_REG_BASE (IS_LITE ? 0x1a00 : 0xaa00)
+#define BUS_REG_BASE (vfe_is_lite(vfe) ? 0x1a00 : 0xaa00)
#define VFE_BUS_WM_CGC_OVERRIDE (BUS_REG_BASE + 0x08)
#define WM_CGC_OVERRIDE_ALL (0x3FFFFFF)
@@ -49,13 +46,13 @@ static inline int reg_update_rdi(struct vfe_device *vfe, int n)
#define VFE_BUS_IRQ_MASK(n) (BUS_REG_BASE + 0x18 + (n) * 4)
static inline int bus_irq_mask_0_rdi_rup(struct vfe_device *vfe, int n)
{
- return IS_LITE ? BIT(n) : BIT(3 + (n));
+ return vfe_is_lite(vfe) ? BIT(n) : BIT(3 + (n));
}
#define BUS_IRQ_MASK_0_RDI_RUP bus_irq_mask_0_rdi_rup
static inline int bus_irq_mask_0_comp_done(struct vfe_device *vfe, int n)
{
- return IS_LITE ? BIT(4 + (n)) : BIT(6 + (n));
+ return vfe_is_lite(vfe) ? BIT(4 + (n)) : BIT(6 + (n));
}
#define BUS_IRQ_MASK_0_COMP_DONE bus_irq_mask_0_comp_done
@@ -90,8 +87,8 @@ static inline int bus_irq_mask_0_comp_done(struct vfe_device *vfe, int n)
/* for titan 480, each bus client is hardcoded to a specific path
* and each bus client is part of a hardcoded "comp group"
*/
-#define RDI_WM(n) ((IS_LITE ? 0 : 23) + (n))
-#define RDI_COMP_GROUP(n) ((IS_LITE ? 0 : 11) + (n))
+#define RDI_WM(n) ((vfe_is_lite(vfe) ? 0 : 23) + (n))
+#define RDI_COMP_GROUP(n) ((vfe_is_lite(vfe) ? 0 : 11) + (n))
#define MAX_VFE_OUTPUT_LINES 4
@@ -453,42 +450,6 @@ out_unlock:
}
/*
- * vfe_pm_domain_off - Disable power domains specific to this VFE.
- * @vfe: VFE Device
- */
-static void vfe_pm_domain_off(struct vfe_device *vfe)
-{
- struct camss *camss = vfe->camss;
-
- if (vfe->id >= camss->res->vfe_num)
- return;
-
- device_link_del(camss->genpd_link[vfe->id]);
-}
-
-/*
- * vfe_pm_domain_on - Enable power domains specific to this VFE.
- * @vfe: VFE Device
- */
-static int vfe_pm_domain_on(struct vfe_device *vfe)
-{
- struct camss *camss = vfe->camss;
- enum vfe_line_id id = vfe->id;
-
- if (id >= camss->res->vfe_num)
- return 0;
-
- camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id],
- DL_FLAG_STATELESS |
- DL_FLAG_PM_RUNTIME |
- DL_FLAG_RPM_ACTIVE);
- if (!camss->genpd_link[id])
- return -EINVAL;
-
- return 0;
-}
-
-/*
* vfe_queue_buffer - Add empty buffer
* @vid: Video device structure
* @buf: Buffer to be enqueued
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 4839e2cedfe5..2062be668f49 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -14,6 +14,7 @@
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/spinlock_types.h>
#include <linux/spinlock.h>
@@ -474,6 +475,40 @@ void vfe_isr_reset_ack(struct vfe_device *vfe)
complete(&vfe->reset_complete);
}
+/*
+ * vfe_pm_domain_off - Disable power domains specific to this VFE.
+ * @vfe: VFE Device
+ */
+void vfe_pm_domain_off(struct vfe_device *vfe)
+{
+ if (!vfe->genpd)
+ return;
+
+ device_link_del(vfe->genpd_link);
+ vfe->genpd_link = NULL;
+}
+
+/*
+ * vfe_pm_domain_on - Enable power domains specific to this VFE.
+ * @vfe: VFE Device
+ */
+int vfe_pm_domain_on(struct vfe_device *vfe)
+{
+ struct camss *camss = vfe->camss;
+
+ if (!vfe->genpd)
+ return 0;
+
+ vfe->genpd_link = device_link_add(camss->dev, vfe->genpd,
+ DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (!vfe->genpd_link)
+ return -EINVAL;
+
+ return 0;
+}
+
static int vfe_match_clock_names(struct vfe_device *vfe,
struct camss_clock *clock)
{
@@ -815,7 +850,7 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable)
/*
* __vfe_get_format - Get pointer to format structure
* @line: VFE line
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad: pad from which format is requested
* @which: TRY or ACTIVE format
*
@@ -828,8 +863,7 @@ __vfe_get_format(struct vfe_line *line,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&line->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
return &line->fmt[pad];
}
@@ -837,7 +871,7 @@ __vfe_get_format(struct vfe_line *line,
/*
* __vfe_get_compose - Get pointer to compose selection structure
* @line: VFE line
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @which: TRY or ACTIVE format
*
* Return pointer to TRY or ACTIVE compose rectangle structure
@@ -848,8 +882,8 @@ __vfe_get_compose(struct vfe_line *line,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_compose(&line->subdev, sd_state,
- MSM_VFE_PAD_SINK);
+ return v4l2_subdev_state_get_compose(sd_state,
+ MSM_VFE_PAD_SINK);
return &line->compose;
}
@@ -857,7 +891,7 @@ __vfe_get_compose(struct vfe_line *line,
/*
* __vfe_get_crop - Get pointer to crop selection structure
* @line: VFE line
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @which: TRY or ACTIVE format
*
* Return pointer to TRY or ACTIVE crop rectangle structure
@@ -868,8 +902,7 @@ __vfe_get_crop(struct vfe_line *line,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&line->subdev, sd_state,
- MSM_VFE_PAD_SRC);
+ return v4l2_subdev_state_get_crop(sd_state, MSM_VFE_PAD_SRC);
return &line->crop;
}
@@ -877,7 +910,7 @@ __vfe_get_crop(struct vfe_line *line,
/*
* vfe_try_format - Handle try format by pad subdev method
* @line: VFE line
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad: pad on which format is requested
* @fmt: pointer to v4l2 format structure
* @which: wanted subdev format
@@ -938,7 +971,7 @@ static void vfe_try_format(struct vfe_line *line,
/*
* vfe_try_compose - Handle try compose selection by pad subdev method
* @line: VFE line
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @rect: pointer to v4l2 rect structure
* @which: wanted subdev format
*/
@@ -977,7 +1010,7 @@ static void vfe_try_compose(struct vfe_line *line,
/*
* vfe_try_crop - Handle try crop selection by pad subdev method
* @line: VFE line
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @rect: pointer to v4l2 rect structure
* @which: wanted subdev format
*/
@@ -1020,7 +1053,7 @@ static void vfe_try_crop(struct vfe_line *line,
/*
* vfe_enum_mbus_code - Handle pixel format enumeration
* @sd: VFE V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @code: pointer to v4l2_subdev_mbus_code_enum structure
*
* return -EINVAL or zero on success
@@ -1054,7 +1087,7 @@ static int vfe_enum_mbus_code(struct v4l2_subdev *sd,
/*
* vfe_enum_frame_size - Handle frame size enumeration
* @sd: VFE V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fse: pointer to v4l2_subdev_frame_size_enum structure
*
* Return -EINVAL or zero on success
@@ -1092,7 +1125,7 @@ static int vfe_enum_frame_size(struct v4l2_subdev *sd,
/*
* vfe_get_format - Handle get format by pads subdev method
* @sd: VFE V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
*
* Return -EINVAL or zero on success
@@ -1120,7 +1153,7 @@ static int vfe_set_selection(struct v4l2_subdev *sd,
/*
* vfe_set_format - Handle set format by pads subdev method
* @sd: VFE V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
*
* Return -EINVAL or zero on success
@@ -1171,7 +1204,7 @@ static int vfe_set_format(struct v4l2_subdev *sd,
/*
* vfe_get_selection - Handle get selection by pads subdev method
* @sd: VFE V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @sel: pointer to v4l2 subdev selection structure
*
* Return -EINVAL or zero on success
@@ -1241,7 +1274,7 @@ static int vfe_get_selection(struct v4l2_subdev *sd,
/*
* vfe_set_selection - Handle set selection by pads subdev method
* @sd: VFE V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @sel: pointer to v4l2 subdev selection structure
*
* Return -EINVAL or zero on success
@@ -1347,6 +1380,34 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
if (!res->line_num)
return -EINVAL;
+ /* Power domain */
+
+ if (res->pd_name) {
+ vfe->genpd = dev_pm_domain_attach_by_name(camss->dev,
+ res->pd_name);
+ if (IS_ERR(vfe->genpd)) {
+ ret = PTR_ERR(vfe->genpd);
+ return ret;
+ }
+ }
+
+ if (!vfe->genpd && res->has_pd) {
+ /*
+ * Legacy magic index.
+ * Requires
+ * power-domain = <VFE_X>,
+ * <VFE_Y>,
+ * <TITAN_TOP>
+ * id must correspondng to the index of the VFE which must
+ * come before the TOP GDSC. VFE Lite has no individually
+ * collapasible domain which is why id < vfe_num is a valid
+ * check.
+ */
+ vfe->genpd = dev_pm_domain_attach_by_id(camss->dev, id);
+ if (IS_ERR(vfe->genpd))
+ return PTR_ERR(vfe->genpd);
+ }
+
vfe->line_num = res->line_num;
vfe->ops->subdev_init(dev, vfe);
@@ -1470,6 +1531,19 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
}
/*
+ * msm_vfe_genpd_cleanup - Cleanup VFE genpd linkages
+ * @vfe: VFE device
+ */
+void msm_vfe_genpd_cleanup(struct vfe_device *vfe)
+{
+ if (vfe->genpd_link)
+ device_link_del(vfe->genpd_link);
+
+ if (vfe->genpd)
+ dev_pm_domain_detach(vfe->genpd, true);
+}
+
+/*
* vfe_link_setup - Setup VFE connections
* @entity: Pointer to media entity structure
* @local: Pointer to local pad
@@ -1663,3 +1737,8 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe)
media_entity_cleanup(&sd->entity);
}
}
+
+bool vfe_is_lite(struct vfe_device *vfe)
+{
+ return vfe->camss->res->vfe_res[vfe->id].is_lite;
+}
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 09baded0dcdd..0572c9b08e11 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -150,6 +150,8 @@ struct vfe_device {
const struct vfe_hw_ops_gen1 *ops_gen1;
struct vfe_isr_ops isr_ops;
struct camss_video_ops video_ops;
+ struct device *genpd;
+ struct device_link *genpd_link;
};
struct camss_subdev_resources;
@@ -157,6 +159,8 @@ struct camss_subdev_resources;
int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
const struct camss_subdev_resources *res, u8 id);
+void msm_vfe_genpd_cleanup(struct vfe_device *vfe);
+
int msm_vfe_register_entities(struct vfe_device *vfe,
struct v4l2_device *v4l2_dev);
@@ -201,6 +205,18 @@ int vfe_reset(struct vfe_device *vfe);
*/
int vfe_disable(struct vfe_line *line);
+/*
+ * vfe_pm_domain_off - Disable power domains specific to this VFE.
+ * @vfe: VFE Device
+ */
+void vfe_pm_domain_off(struct vfe_device *vfe);
+
+/*
+ * vfe_pm_domain_on - Enable power domains specific to this VFE.
+ * @vfe: VFE Device
+ */
+int vfe_pm_domain_on(struct vfe_device *vfe);
+
extern const struct vfe_hw_ops vfe_ops_4_1;
extern const struct vfe_hw_ops vfe_ops_4_7;
extern const struct vfe_hw_ops vfe_ops_4_8;
@@ -210,4 +226,14 @@ extern const struct vfe_hw_ops vfe_ops_480;
int vfe_get(struct vfe_device *vfe);
void vfe_put(struct vfe_device *vfe);
+/*
+ * vfe_is_lite - Return if VFE is VFE lite.
+ * @vfe: VFE Device
+ *
+ * Some VFE lites have a different register layout.
+ *
+ * Return whether VFE is VFE lite
+ */
+bool vfe_is_lite(struct vfe_device *vfe);
+
#endif /* QC_MSM_CAMSS_VFE_H */
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 8e78dd8d5961..58f4be660290 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -278,6 +278,7 @@ static const struct camss_subdev_resources vfe_res_8x96[] = {
.reg = { "vfe0" },
.interrupt = { "vfe0" },
.line_num = 3,
+ .has_pd = true,
.ops = &vfe_ops_4_7
},
@@ -298,6 +299,7 @@ static const struct camss_subdev_resources vfe_res_8x96[] = {
.reg = { "vfe1" },
.interrupt = { "vfe1" },
.line_num = 3,
+ .has_pd = true,
.ops = &vfe_ops_4_7
}
};
@@ -468,6 +470,7 @@ static const struct camss_subdev_resources vfe_res_660[] = {
.reg = { "vfe0" },
.interrupt = { "vfe0" },
.line_num = 3,
+ .has_pd = true,
.ops = &vfe_ops_4_8
},
@@ -491,6 +494,7 @@ static const struct camss_subdev_resources vfe_res_660[] = {
.reg = { "vfe1" },
.interrupt = { "vfe1" },
.line_num = 3,
+ .has_pd = true,
.ops = &vfe_ops_4_8
}
};
@@ -634,6 +638,7 @@ static const struct camss_subdev_resources csid_res_845[] = {
{ 384000000 } },
.reg = { "csid2" },
.interrupt = { "csid2" },
+ .is_lite = true,
.ops = &csid_ops_gen2
}
};
@@ -658,6 +663,7 @@ static const struct camss_subdev_resources vfe_res_845[] = {
.reg = { "vfe0" },
.interrupt = { "vfe0" },
.line_num = 4,
+ .has_pd = true,
.ops = &vfe_ops_170
},
@@ -680,6 +686,7 @@ static const struct camss_subdev_resources vfe_res_845[] = {
.reg = { "vfe1" },
.interrupt = { "vfe1" },
.line_num = 4,
+ .has_pd = true,
.ops = &vfe_ops_170
},
@@ -700,6 +707,7 @@ static const struct camss_subdev_resources vfe_res_845[] = {
{ 384000000 } },
.reg = { "vfe_lite" },
.interrupt = { "vfe_lite" },
+ .is_lite = true,
.line_num = 4,
.ops = &vfe_ops_170
}
@@ -805,6 +813,7 @@ static const struct camss_subdev_resources csid_res_8250[] = {
{ 0 } },
.reg = { "csid2" },
.interrupt = { "csid2" },
+ .is_lite = true,
.ops = &csid_ops_gen2
},
/* CSID3 */
@@ -817,6 +826,7 @@ static const struct camss_subdev_resources csid_res_8250[] = {
{ 0 } },
.reg = { "csid3" },
.interrupt = { "csid3" },
+ .is_lite = true,
.ops = &csid_ops_gen2
}
};
@@ -839,7 +849,9 @@ static const struct camss_subdev_resources vfe_res_8250[] = {
{ 0 } },
.reg = { "vfe0" },
.interrupt = { "vfe0" },
+ .pd_name = "ife0",
.line_num = 3,
+ .has_pd = true,
.ops = &vfe_ops_480
},
/* VFE1 */
@@ -859,7 +871,9 @@ static const struct camss_subdev_resources vfe_res_8250[] = {
{ 0 } },
.reg = { "vfe1" },
.interrupt = { "vfe1" },
+ .pd_name = "ife1",
.line_num = 3,
+ .has_pd = true,
.ops = &vfe_ops_480
},
/* VFE2 (lite) */
@@ -878,6 +892,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = {
{ 0 } },
.reg = { "vfe_lite0" },
.interrupt = { "vfe_lite0" },
+ .is_lite = true,
.line_num = 4,
.ops = &vfe_ops_480
},
@@ -897,6 +912,7 @@ static const struct camss_subdev_resources vfe_res_8250[] = {
{ 0 } },
.reg = { "vfe_lite1" },
.interrupt = { "vfe_lite1" },
+ .is_lite = true,
.line_num = 4,
.ops = &vfe_ops_480
},
@@ -1196,7 +1212,7 @@ static int camss_init_subdevices(struct camss *camss)
}
/* note: SM8250 requires VFE to be initialized before CSID */
- for (i = 0; i < camss->vfe_total_num; i++) {
+ for (i = 0; i < camss->res->vfe_num; i++) {
ret = msm_vfe_subdev_init(camss, &camss->vfe[i],
&res->vfe_res[i], i);
if (ret < 0) {
@@ -1268,7 +1284,7 @@ static int camss_register_entities(struct camss *camss)
goto err_reg_ispif;
}
- for (i = 0; i < camss->vfe_total_num; i++) {
+ for (i = 0; i < camss->res->vfe_num; i++) {
ret = msm_vfe_register_entities(&camss->vfe[i],
&camss->v4l2_dev);
if (ret < 0) {
@@ -1340,7 +1356,7 @@ static int camss_register_entities(struct camss *camss)
}
} else {
for (i = 0; i < camss->res->csid_num; i++)
- for (k = 0; k < camss->vfe_total_num; k++)
+ for (k = 0; k < camss->res->vfe_num; k++)
for (j = 0; j < camss->vfe[k].line_num; j++) {
struct v4l2_subdev *csid = &camss->csid[i].subdev;
struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev;
@@ -1364,7 +1380,7 @@ static int camss_register_entities(struct camss *camss)
return 0;
err_link:
- i = camss->vfe_total_num;
+ i = camss->res->vfe_num;
err_reg_vfe:
for (i--; i >= 0; i--)
msm_vfe_unregister_entities(&camss->vfe[i]);
@@ -1403,7 +1419,7 @@ static void camss_unregister_entities(struct camss *camss)
msm_ispif_unregister_entities(camss->ispif);
- for (i = 0; i < camss->vfe_total_num; i++)
+ for (i = 0; i < camss->res->vfe_num; i++)
msm_vfe_unregister_entities(&camss->vfe[i]);
}
@@ -1478,7 +1494,9 @@ static const struct media_device_ops camss_media_ops = {
static int camss_configure_pd(struct camss *camss)
{
+ const struct camss_resources *res = camss->res;
struct device *dev = camss->dev;
+ int vfepd_num;
int i;
int ret;
@@ -1498,45 +1516,60 @@ static int camss_configure_pd(struct camss *camss)
if (camss->genpd_num == 1)
return 0;
- camss->genpd = devm_kmalloc_array(dev, camss->genpd_num,
- sizeof(*camss->genpd), GFP_KERNEL);
- if (!camss->genpd)
- return -ENOMEM;
+ /* count the # of VFEs which have flagged power-domain */
+ for (vfepd_num = i = 0; i < camss->res->vfe_num; i++) {
+ if (res->vfe_res[i].has_pd)
+ vfepd_num++;
+ }
- camss->genpd_link = devm_kmalloc_array(dev, camss->genpd_num,
- sizeof(*camss->genpd_link),
- GFP_KERNEL);
- if (!camss->genpd_link)
- return -ENOMEM;
+ /*
+ * If the number of power-domains is greater than the number of VFEs
+ * then the additional power-domain is for the entire CAMSS block.
+ */
+ if (!(camss->genpd_num > vfepd_num))
+ return 0;
/*
- * VFE power domains are in the beginning of the list, and while all
- * power domains should be attached, only if TITAN_TOP power domain is
- * found in the list, it should be linked over here.
+ * If a power-domain name is defined try to use it.
+ * It is possible we are running a new kernel with an old dtb so
+ * fallback to indexes even if a pd_name is defined but not found.
*/
- for (i = 0; i < camss->genpd_num; i++) {
- camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i);
- if (IS_ERR(camss->genpd[i])) {
- ret = PTR_ERR(camss->genpd[i]);
+ if (camss->res->pd_name) {
+ camss->genpd = dev_pm_domain_attach_by_name(camss->dev,
+ camss->res->pd_name);
+ if (IS_ERR(camss->genpd)) {
+ ret = PTR_ERR(camss->genpd);
goto fail_pm;
}
}
- if (i > camss->res->vfe_num) {
- camss->genpd_link[i - 1] = device_link_add(camss->dev, camss->genpd[i - 1],
- DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
- DL_FLAG_RPM_ACTIVE);
- if (!camss->genpd_link[i - 1]) {
- ret = -EINVAL;
- goto fail_pm;
- }
+ if (!camss->genpd) {
+ /*
+ * Legacy magic index. TITAN_TOP GDSC must be the last
+ * item in the power-domain list.
+ */
+ camss->genpd = dev_pm_domain_attach_by_id(camss->dev,
+ camss->genpd_num - 1);
+ }
+ if (IS_ERR_OR_NULL(camss->genpd)) {
+ if (!camss->genpd)
+ ret = -ENODEV;
+ else
+ ret = PTR_ERR(camss->genpd);
+ goto fail_pm;
+ }
+ camss->genpd_link = device_link_add(camss->dev, camss->genpd,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (!camss->genpd_link) {
+ ret = -EINVAL;
+ goto fail_pm;
}
return 0;
fail_pm:
- for (--i ; i >= 0; i--)
- dev_pm_domain_detach(camss->genpd[i], true);
+ dev_pm_domain_detach(camss->genpd, true);
return ret;
}
@@ -1558,18 +1591,25 @@ static int camss_icc_get(struct camss *camss)
return 0;
}
-static void camss_genpd_cleanup(struct camss *camss)
+static void camss_genpd_subdevice_cleanup(struct camss *camss)
{
int i;
+ for (i = 0; i < camss->res->vfe_num; i++)
+ msm_vfe_genpd_cleanup(&camss->vfe[i]);
+}
+
+static void camss_genpd_cleanup(struct camss *camss)
+{
if (camss->genpd_num == 1)
return;
- if (camss->genpd_num > camss->res->vfe_num)
- device_link_del(camss->genpd_link[camss->genpd_num - 1]);
+ camss_genpd_subdevice_cleanup(camss);
+
+ if (camss->genpd_link)
+ device_link_del(camss->genpd_link);
- for (i = 0; i < camss->genpd_num; i++)
- dev_pm_domain_detach(camss->genpd[i], true);
+ dev_pm_domain_detach(camss->genpd, true);
}
/*
@@ -1612,8 +1652,7 @@ static int camss_probe(struct platform_device *pdev)
return -ENOMEM;
}
- camss->vfe_total_num = camss->res->vfe_num + camss->res->vfe_lite_num;
- camss->vfe = devm_kcalloc(dev, camss->vfe_total_num,
+ camss->vfe = devm_kcalloc(dev, camss->res->vfe_num,
sizeof(*camss->vfe), GFP_KERNEL);
if (!camss->vfe)
return -ENOMEM;
@@ -1771,12 +1810,12 @@ static const struct camss_resources sdm845_resources = {
.vfe_res = vfe_res_845,
.csiphy_num = ARRAY_SIZE(csiphy_res_845),
.csid_num = ARRAY_SIZE(csid_res_845),
- .vfe_num = 2,
- .vfe_lite_num = 1,
+ .vfe_num = ARRAY_SIZE(vfe_res_845),
};
static const struct camss_resources sm8250_resources = {
.version = CAMSS_8250,
+ .pd_name = "top",
.csiphy_res = csiphy_res_8250,
.csid_res = csid_res_8250,
.vfe_res = vfe_res_8250,
@@ -1784,8 +1823,7 @@ static const struct camss_resources sm8250_resources = {
.icc_path_num = ARRAY_SIZE(icc_res_sm8250),
.csiphy_num = ARRAY_SIZE(csiphy_res_8250),
.csid_num = ARRAY_SIZE(csid_res_8250),
- .vfe_num = 2,
- .vfe_lite_num = 2,
+ .vfe_num = ARRAY_SIZE(vfe_res_8250),
};
static const struct of_device_id camss_dt_match[] = {
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 8acad7321c09..a0c2dcc779f0 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -48,7 +48,10 @@ struct camss_subdev_resources {
u32 clock_rate[CAMSS_RES_MAX][CAMSS_RES_MAX];
char *reg[CAMSS_RES_MAX];
char *interrupt[CAMSS_RES_MAX];
+ char *pd_name;
u8 line_num;
+ bool has_pd;
+ bool is_lite;
const void *ops;
};
@@ -83,6 +86,7 @@ enum icc_count {
struct camss_resources {
enum camss_version version;
+ const char *pd_name;
const struct camss_subdev_resources *csiphy_res;
const struct camss_subdev_resources *csid_res;
const struct camss_subdev_resources *ispif_res;
@@ -92,7 +96,6 @@ struct camss_resources {
const unsigned int csiphy_num;
const unsigned int csid_num;
const unsigned int vfe_num;
- const unsigned int vfe_lite_num;
};
struct camss {
@@ -106,11 +109,10 @@ struct camss {
struct vfe_device *vfe;
atomic_t ref_count;
int genpd_num;
- struct device **genpd;
- struct device_link **genpd_link;
+ struct device *genpd;
+ struct device_link *genpd_link;
struct icc_path *icc_path[ICC_SM8250_COUNT];
const struct camss_resources *res;
- unsigned int vfe_total_num;
};
struct camss_camera_interface {
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 9cffe975581b..a712dd4f02a5 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -881,6 +881,10 @@ static const struct venus_resources sc7280_res = {
.vmem_size = 0,
.vmem_addr = 0,
.dma_mask = 0xe0000000 - 1,
+ .cp_start = 0,
+ .cp_size = 0x25800000,
+ .cp_nonpixel_start = 0x1000000,
+ .cp_nonpixel_size = 0x24800000,
.fwname = "qcom/vpu-2.0/venus.mbn",
};
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index dbf305cec120..29130a9441e7 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -1641,7 +1641,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->drv_priv = inst;
src_vq->buf_struct_size = sizeof(struct venus_buffer);
src_vq->allow_zero_bytesused = 1;
- src_vq->min_buffers_needed = 0;
+ src_vq->min_queued_buffers = 0;
src_vq->dev = inst->core->dev;
src_vq->lock = &inst->ctx_q_lock;
ret = vb2_queue_init(src_vq);
@@ -1656,7 +1656,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->drv_priv = inst;
dst_vq->buf_struct_size = sizeof(struct venus_buffer);
dst_vq->allow_zero_bytesused = 1;
- dst_vq->min_buffers_needed = 0;
+ dst_vq->min_queued_buffers = 0;
dst_vq->dev = inst->core->dev;
dst_vq->lock = &inst->ctx_q_lock;
return vb2_queue_init(dst_vq);
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index 44b13696cf82..3ec2fb8d9fab 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -1398,7 +1398,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->drv_priv = inst;
src_vq->buf_struct_size = sizeof(struct venus_buffer);
src_vq->allow_zero_bytesused = 1;
- src_vq->min_buffers_needed = 1;
+ src_vq->min_queued_buffers = 1;
src_vq->dev = inst->core->dev;
src_vq->lock = &inst->ctx_q_lock;
if (inst->core->res->hfi_version == HFI_VERSION_1XX)
@@ -1415,7 +1415,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->drv_priv = inst;
dst_vq->buf_struct_size = sizeof(struct venus_buffer);
dst_vq->allow_zero_bytesused = 1;
- dst_vq->min_buffers_needed = 1;
+ dst_vq->min_queued_buffers = 1;
dst_vq->dev = inst->core->dev;
dst_vq->lock = &inst->ctx_q_lock;
return vb2_queue_init(dst_vq);
diff --git a/drivers/media/platform/renesas/rcar-isp.c b/drivers/media/platform/renesas/rcar-isp.c
index 19a005d83733..530d65fc546b 100644
--- a/drivers/media/platform/renesas/rcar-isp.c
+++ b/drivers/media/platform/renesas/rcar-isp.c
@@ -282,7 +282,7 @@ static int risp_set_pad_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
isp->mf = format->format;
} else {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ framefmt = v4l2_subdev_state_get_format(sd_state, 0);
*framefmt = format->format;
}
@@ -302,7 +302,7 @@ static int risp_get_pad_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
format->format = isp->mf;
else
- format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
+ format->format = *v4l2_subdev_state_get_format(sd_state, 0);
mutex_unlock(&isp->lock);
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
index 66fe553a00e7..582d5e35db0e 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
@@ -1185,7 +1185,7 @@ static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
priv->mf = format->format;
} else {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ framefmt = v4l2_subdev_state_get_format(sd_state, 0);
*framefmt = format->format;
}
@@ -1205,7 +1205,7 @@ static int rcsi2_get_pad_format(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
format->format = priv->mf;
else
- format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
+ format->format = *v4l2_subdev_state_get_format(sd_state, 0);
mutex_unlock(&priv->lock);
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
index 2a77353f10b5..e2c40abc6d3d 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
@@ -1559,7 +1559,7 @@ int rvin_dma_register(struct rvin_dev *vin, int irq)
q->ops = &rvin_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 4;
+ q->min_queued_buffers = 4;
q->dev = vin->dev;
ret = vb2_queue_init(q);
diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c
index 292c5bf9e50c..f21d05054341 100644
--- a/drivers/media/platform/renesas/rcar_drif.c
+++ b/drivers/media/platform/renesas/rcar_drif.c
@@ -424,10 +424,11 @@ static int rcar_drif_queue_setup(struct vb2_queue *vq,
unsigned int sizes[], struct device *alloc_devs[])
{
struct rcar_drif_sdr *sdr = vb2_get_drv_priv(vq);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
/* Need at least 16 buffers */
- if (vq->num_buffers + *num_buffers < 16)
- *num_buffers = 16 - vq->num_buffers;
+ if (q_num_bufs + *num_buffers < 16)
+ *num_buffers = 16 - q_num_bufs;
*num_planes = 1;
sizes[0] = PAGE_ALIGN(sdr->fmt->buffersize);
diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c
index 2562b30acfb9..167760276796 100644
--- a/drivers/media/platform/renesas/renesas-ceu.c
+++ b/drivers/media/platform/renesas/renesas-ceu.c
@@ -1399,7 +1399,7 @@ static int ceu_notify_complete(struct v4l2_async_notifier *notifier)
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct ceu_buffer);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->lock = &ceudev->mlock;
q->dev = ceudev->v4l2_dev.dev;
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index ad2bd71037ab..d20f4eff93a4 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -250,7 +250,7 @@ static int rzg2l_csi2_calc_mbps(struct rzg2l_csi2 *csi2)
}
state = v4l2_subdev_lock_and_get_active_state(&csi2->subdev);
- fmt = v4l2_subdev_get_pad_format(&csi2->subdev, state, RZG2L_CSI2_SINK);
+ fmt = v4l2_subdev_state_get_format(state, RZG2L_CSI2_SINK);
format = rzg2l_csi2_code_to_fmt(fmt->code);
v4l2_subdev_unlock_state(state);
@@ -500,13 +500,13 @@ static int rzg2l_csi2_set_format(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *src_format;
struct v4l2_mbus_framefmt *sink_format;
- src_format = v4l2_subdev_get_pad_format(sd, state, RZG2L_CSI2_SOURCE);
+ src_format = v4l2_subdev_state_get_format(state, RZG2L_CSI2_SOURCE);
if (fmt->pad == RZG2L_CSI2_SOURCE) {
fmt->format = *src_format;
return 0;
}
- sink_format = v4l2_subdev_get_pad_format(sd, state, RZG2L_CSI2_SINK);
+ sink_format = v4l2_subdev_state_get_format(state, RZG2L_CSI2_SINK);
if (!rzg2l_csi2_code_to_fmt(fmt->format.code))
sink_format->code = rzg2l_csi2_formats[0].code;
@@ -530,8 +530,8 @@ static int rzg2l_csi2_set_format(struct v4l2_subdev *sd,
return 0;
}
-static int rzg2l_csi2_init_config(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int rzg2l_csi2_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = { .pad = RZG2L_CSI2_SINK, };
@@ -582,7 +582,6 @@ static const struct v4l2_subdev_video_ops rzg2l_csi2_video_ops = {
static const struct v4l2_subdev_pad_ops rzg2l_csi2_pad_ops = {
.enum_mbus_code = rzg2l_csi2_enum_mbus_code,
- .init_cfg = rzg2l_csi2_init_config,
.enum_frame_size = rzg2l_csi2_enum_frame_size,
.set_fmt = rzg2l_csi2_set_format,
.get_fmt = v4l2_subdev_get_fmt,
@@ -593,6 +592,10 @@ static const struct v4l2_subdev_ops rzg2l_csi2_subdev_ops = {
.pad = &rzg2l_csi2_pad_ops,
};
+static const struct v4l2_subdev_internal_ops rzg2l_csi2_internal_ops = {
+ .init_state = rzg2l_csi2_init_state,
+};
+
/* -----------------------------------------------------------------------------
* Async handling and registration of subdevices and links.
*/
@@ -777,6 +780,7 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
csi2->subdev.dev = &pdev->dev;
v4l2_subdev_init(&csi2->subdev, &rzg2l_csi2_subdev_ops);
+ csi2->subdev.internal_ops = &rzg2l_csi2_internal_ops;
v4l2_set_subdevdata(&csi2->subdev, &pdev->dev);
snprintf(csi2->subdev.name, sizeof(csi2->subdev.name),
"csi-%s", dev_name(&pdev->dev));
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
index 4dcd2faff5bb..9f351a05893e 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
@@ -39,7 +39,7 @@ struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru)
struct v4l2_mbus_framefmt *fmt;
state = v4l2_subdev_lock_and_get_active_state(&cru->ip.subdev);
- fmt = v4l2_subdev_get_pad_format(&cru->ip.subdev, state, 1);
+ fmt = v4l2_subdev_state_get_format(state, 1);
v4l2_subdev_unlock_state(state);
return fmt;
@@ -108,13 +108,13 @@ static int rzg2l_cru_ip_set_format(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *src_format;
struct v4l2_mbus_framefmt *sink_format;
- src_format = v4l2_subdev_get_pad_format(sd, state, RZG2L_CRU_IP_SOURCE);
+ src_format = v4l2_subdev_state_get_format(state, RZG2L_CRU_IP_SOURCE);
if (fmt->pad == RZG2L_CRU_IP_SOURCE) {
fmt->format = *src_format;
return 0;
}
- sink_format = v4l2_subdev_get_pad_format(sd, state, fmt->pad);
+ sink_format = v4l2_subdev_state_get_format(state, fmt->pad);
if (!rzg2l_cru_ip_code_to_fmt(fmt->format.code))
sink_format->code = rzg2l_cru_ip_formats[0].code;
@@ -168,8 +168,8 @@ static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-static int rzg2l_cru_ip_init_config(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int rzg2l_cru_ip_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = { .pad = RZG2L_CRU_IP_SINK, };
@@ -192,7 +192,6 @@ static const struct v4l2_subdev_video_ops rzg2l_cru_ip_video_ops = {
static const struct v4l2_subdev_pad_ops rzg2l_cru_ip_pad_ops = {
.enum_mbus_code = rzg2l_cru_ip_enum_mbus_code,
.enum_frame_size = rzg2l_cru_ip_enum_frame_size,
- .init_cfg = rzg2l_cru_ip_init_config,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = rzg2l_cru_ip_set_format,
};
@@ -202,6 +201,10 @@ static const struct v4l2_subdev_ops rzg2l_cru_ip_subdev_ops = {
.pad = &rzg2l_cru_ip_pad_ops,
};
+static const struct v4l2_subdev_internal_ops rzg2l_cru_ip_internal_ops = {
+ .init_state = rzg2l_cru_ip_init_state,
+};
+
static const struct media_entity_operations rzg2l_cru_ip_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -213,6 +216,7 @@ int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru)
ip->subdev.dev = cru->dev;
v4l2_subdev_init(&ip->subdev, &rzg2l_cru_ip_subdev_ops);
+ ip->subdev.internal_ops = &rzg2l_cru_ip_internal_ops;
v4l2_set_subdevdata(&ip->subdev, cru);
snprintf(ip->subdev.name, sizeof(ip->subdev.name),
"cru-ip-%s", dev_name(cru->dev));
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index e6eedd65b71d..d0ffa90bc656 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -767,7 +767,7 @@ int rzg2l_cru_dma_register(struct rzg2l_cru_dev *cru)
q->ops = &rzg2l_cru_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 4;
+ q->min_queued_buffers = 4;
q->dev = cru->dev;
ret = vb2_queue_init(q);
diff --git a/drivers/media/platform/renesas/sh_vou.c b/drivers/media/platform/renesas/sh_vou.c
index f792aedc9d82..1e74dd601c2b 100644
--- a/drivers/media/platform/renesas/sh_vou.c
+++ b/drivers/media/platform/renesas/sh_vou.c
@@ -1297,7 +1297,7 @@ static int sh_vou_probe(struct platform_device *pdev)
q->ops = &sh_vou_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->lock = &vou_dev->fop_lock;
q->dev = &pdev->dev;
ret = vb2_queue_init(q);
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_brx.c b/drivers/media/platform/renesas/vsp1/vsp1_brx.c
index 89385b4cabe5..a8535c6e2c46 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_brx.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_brx.c
@@ -100,7 +100,7 @@ static struct v4l2_rect *brx_get_compose(struct vsp1_brx *brx,
struct v4l2_subdev_state *sd_state,
unsigned int pad)
{
- return v4l2_subdev_get_try_compose(&brx->entity.subdev, sd_state, pad);
+ return v4l2_subdev_state_get_compose(sd_state, pad);
}
static void brx_try_format(struct vsp1_brx *brx,
@@ -136,29 +136,28 @@ static int brx_set_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_format *fmt)
{
struct vsp1_brx *brx = to_brx(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
int ret = 0;
mutex_lock(&brx->entity.lock);
- config = vsp1_entity_get_pad_config(&brx->entity, sd_state,
- fmt->which);
- if (!config) {
+ state = vsp1_entity_get_state(&brx->entity, sd_state, fmt->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
- brx_try_format(brx, config, fmt->pad, &fmt->format);
+ brx_try_format(brx, state, fmt->pad, &fmt->format);
- format = vsp1_entity_get_pad_format(&brx->entity, config, fmt->pad);
+ format = vsp1_entity_get_pad_format(&brx->entity, state, fmt->pad);
*format = fmt->format;
/* Reset the compose rectangle. */
if (fmt->pad != brx->entity.source_pad) {
struct v4l2_rect *compose;
- compose = brx_get_compose(brx, config, fmt->pad);
+ compose = brx_get_compose(brx, state, fmt->pad);
compose->left = 0;
compose->top = 0;
compose->width = format->width;
@@ -171,7 +170,7 @@ static int brx_set_format(struct v4l2_subdev *subdev,
for (i = 0; i <= brx->entity.source_pad; ++i) {
format = vsp1_entity_get_pad_format(&brx->entity,
- config, i);
+ state, i);
format->code = fmt->format.code;
}
}
@@ -186,7 +185,7 @@ static int brx_get_selection(struct v4l2_subdev *subdev,
struct v4l2_subdev_selection *sel)
{
struct vsp1_brx *brx = to_brx(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
if (sel->pad == brx->entity.source_pad)
return -EINVAL;
@@ -200,13 +199,13 @@ static int brx_get_selection(struct v4l2_subdev *subdev,
return 0;
case V4L2_SEL_TGT_COMPOSE:
- config = vsp1_entity_get_pad_config(&brx->entity, sd_state,
- sel->which);
- if (!config)
+ state = vsp1_entity_get_state(&brx->entity, sd_state,
+ sel->which);
+ if (!state)
return -EINVAL;
mutex_lock(&brx->entity.lock);
- sel->r = *brx_get_compose(brx, config, sel->pad);
+ sel->r = *brx_get_compose(brx, state, sel->pad);
mutex_unlock(&brx->entity.lock);
return 0;
@@ -220,7 +219,7 @@ static int brx_set_selection(struct v4l2_subdev *subdev,
struct v4l2_subdev_selection *sel)
{
struct vsp1_brx *brx = to_brx(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *compose;
int ret = 0;
@@ -233,9 +232,8 @@ static int brx_set_selection(struct v4l2_subdev *subdev,
mutex_lock(&brx->entity.lock);
- config = vsp1_entity_get_pad_config(&brx->entity, sd_state,
- sel->which);
- if (!config) {
+ state = vsp1_entity_get_state(&brx->entity, sd_state, sel->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
@@ -244,7 +242,7 @@ static int brx_set_selection(struct v4l2_subdev *subdev,
* The compose rectangle top left corner must be inside the output
* frame.
*/
- format = vsp1_entity_get_pad_format(&brx->entity, config,
+ format = vsp1_entity_get_pad_format(&brx->entity, state,
brx->entity.source_pad);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
@@ -253,11 +251,11 @@ static int brx_set_selection(struct v4l2_subdev *subdev,
* Scaling isn't supported, the compose rectangle size must be identical
* to the sink format size.
*/
- format = vsp1_entity_get_pad_format(&brx->entity, config, sel->pad);
+ format = vsp1_entity_get_pad_format(&brx->entity, state, sel->pad);
sel->r.width = format->width;
sel->r.height = format->height;
- compose = brx_get_compose(brx, config, sel->pad);
+ compose = brx_get_compose(brx, state, sel->pad);
*compose = sel->r;
done:
@@ -266,7 +264,6 @@ done:
}
static const struct v4l2_subdev_pad_ops brx_pad_ops = {
- .init_cfg = vsp1_entity_init_cfg,
.enum_mbus_code = brx_enum_mbus_code,
.enum_frame_size = brx_enum_frame_size,
.get_fmt = vsp1_subdev_get_pad_format,
@@ -293,7 +290,7 @@ static void brx_configure_stream(struct vsp1_entity *entity,
unsigned int flags;
unsigned int i;
- format = vsp1_entity_get_pad_format(&brx->entity, brx->entity.config,
+ format = vsp1_entity_get_pad_format(&brx->entity, brx->entity.state,
brx->entity.source_pad);
/*
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_clu.c b/drivers/media/platform/renesas/vsp1/vsp1_clu.c
index c5217fee24f1..625776a9bda4 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_clu.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_clu.c
@@ -155,7 +155,6 @@ static int clu_set_format(struct v4l2_subdev *subdev,
*/
static const struct v4l2_subdev_pad_ops clu_pad_ops = {
- .init_cfg = vsp1_entity_init_cfg,
.enum_mbus_code = clu_enum_mbus_code,
.enum_frame_size = clu_enum_frame_size,
.get_fmt = vsp1_subdev_get_pad_format,
@@ -182,8 +181,7 @@ static void clu_configure_stream(struct vsp1_entity *entity,
* The yuv_mode can't be changed during streaming. Cache it internally
* for future runtime configuration calls.
*/
- format = vsp1_entity_get_pad_format(&clu->entity,
- clu->entity.config,
+ format = vsp1_entity_get_pad_format(&clu->entity, clu->entity.state,
CLU_PAD_SINK);
clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32;
}
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c
index c31f05a80bb5..0a5a7f9cc870 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c
@@ -101,27 +101,26 @@ void vsp1_entity_configure_partition(struct vsp1_entity *entity,
*/
/**
- * vsp1_entity_get_pad_config - Get the pad configuration for an entity
+ * vsp1_entity_get_state - Get the subdev state for an entity
* @entity: the entity
* @sd_state: the TRY state
- * @which: configuration selector (ACTIVE or TRY)
+ * @which: state selector (ACTIVE or TRY)
*
* When called with which set to V4L2_SUBDEV_FORMAT_ACTIVE the caller must hold
* the entity lock to access the returned configuration.
*
- * Return the pad configuration requested by the which argument. The TRY
- * configuration is passed explicitly to the function through the cfg argument
- * and simply returned when requested. The ACTIVE configuration comes from the
- * entity structure.
+ * Return the subdev state requested by the which argument. The TRY state is
+ * passed explicitly to the function through the sd_state argument and simply
+ * returned when requested. The ACTIVE state comes from the entity structure.
*/
struct v4l2_subdev_state *
-vsp1_entity_get_pad_config(struct vsp1_entity *entity,
- struct v4l2_subdev_state *sd_state,
- enum v4l2_subdev_format_whence which)
+vsp1_entity_get_state(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *sd_state,
+ enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_ACTIVE:
- return entity->config;
+ return entity->state;
case V4L2_SUBDEV_FORMAT_TRY:
default:
return sd_state;
@@ -142,7 +141,7 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
struct v4l2_subdev_state *sd_state,
unsigned int pad)
{
- return v4l2_subdev_get_try_format(&entity->subdev, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
}
/**
@@ -163,46 +162,18 @@ vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
{
switch (target) {
case V4L2_SEL_TGT_COMPOSE:
- return v4l2_subdev_get_try_compose(&entity->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_compose(sd_state, pad);
case V4L2_SEL_TGT_CROP:
- return v4l2_subdev_get_try_crop(&entity->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_crop(sd_state, pad);
default:
return NULL;
}
}
/*
- * vsp1_entity_init_cfg - Initialize formats on all pads
- * @subdev: V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
- *
- * Initialize all pad formats with default values in the given pad config. This
- * function can be used as a handler for the subdev pad::init_cfg operation.
- */
-int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state)
-{
- unsigned int pad;
-
- for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) {
- struct v4l2_subdev_format format = {
- .pad = pad,
- .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
- : V4L2_SUBDEV_FORMAT_ACTIVE,
- };
-
- v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &format);
- }
-
- return 0;
-}
-
-/*
* vsp1_subdev_get_pad_format - Subdev pad get_fmt handler
* @subdev: V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: V4L2 subdev format
*
* This function implements the subdev get_fmt pad operation. It can be used as
@@ -213,14 +184,14 @@ int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_format *fmt)
{
struct vsp1_entity *entity = to_vsp1_entity(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
- config = vsp1_entity_get_pad_config(entity, sd_state, fmt->which);
- if (!config)
+ state = vsp1_entity_get_state(entity, sd_state, fmt->which);
+ if (!state)
return -EINVAL;
mutex_lock(&entity->lock);
- fmt->format = *vsp1_entity_get_pad_format(entity, config, fmt->pad);
+ fmt->format = *vsp1_entity_get_pad_format(entity, state, fmt->pad);
mutex_unlock(&entity->lock);
return 0;
@@ -229,7 +200,7 @@ int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
/*
* vsp1_subdev_enum_mbus_code - Subdev pad enum_mbus_code handler
* @subdev: V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @code: Media bus code enumeration
* @codes: Array of supported media bus codes
* @ncodes: Number of supported media bus codes
@@ -252,7 +223,7 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
code->code = codes[code->index];
} else {
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
/*
@@ -262,13 +233,12 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
if (code->index)
return -EINVAL;
- config = vsp1_entity_get_pad_config(entity, sd_state,
- code->which);
- if (!config)
+ state = vsp1_entity_get_state(entity, sd_state, code->which);
+ if (!state)
return -EINVAL;
mutex_lock(&entity->lock);
- format = vsp1_entity_get_pad_format(entity, config, 0);
+ format = vsp1_entity_get_pad_format(entity, state, 0);
code->code = format->code;
mutex_unlock(&entity->lock);
}
@@ -279,7 +249,7 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
/*
* vsp1_subdev_enum_frame_size - Subdev pad enum_frame_size handler
* @subdev: V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fse: Frame size enumeration
* @min_width: Minimum image width
* @min_height: Minimum image height
@@ -298,15 +268,15 @@ int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
unsigned int max_width, unsigned int max_height)
{
struct vsp1_entity *entity = to_vsp1_entity(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
int ret = 0;
- config = vsp1_entity_get_pad_config(entity, sd_state, fse->which);
- if (!config)
+ state = vsp1_entity_get_state(entity, sd_state, fse->which);
+ if (!state)
return -EINVAL;
- format = vsp1_entity_get_pad_format(entity, config, fse->pad);
+ format = vsp1_entity_get_pad_format(entity, state, fse->pad);
mutex_lock(&entity->lock);
@@ -339,7 +309,7 @@ done:
/*
* vsp1_subdev_set_pad_format - Subdev pad set_fmt handler
* @subdev: V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: V4L2 subdev format
* @codes: Array of supported media bus codes
* @ncodes: Number of supported media bus codes
@@ -362,7 +332,7 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
unsigned int max_width, unsigned int max_height)
{
struct vsp1_entity *entity = to_vsp1_entity(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *selection;
unsigned int i;
@@ -370,13 +340,13 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
mutex_lock(&entity->lock);
- config = vsp1_entity_get_pad_config(entity, sd_state, fmt->which);
- if (!config) {
+ state = vsp1_entity_get_state(entity, sd_state, fmt->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
- format = vsp1_entity_get_pad_format(entity, config, fmt->pad);
+ format = vsp1_entity_get_pad_format(entity, state, fmt->pad);
if (fmt->pad == entity->source_pad) {
/* The output format can't be modified. */
@@ -404,18 +374,18 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
fmt->format = *format;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(entity, config, entity->source_pad);
+ format = vsp1_entity_get_pad_format(entity, state, entity->source_pad);
*format = fmt->format;
/* Reset the crop and compose rectangles. */
- selection = vsp1_entity_get_pad_selection(entity, config, fmt->pad,
+ selection = vsp1_entity_get_pad_selection(entity, state, fmt->pad,
V4L2_SEL_TGT_CROP);
selection->left = 0;
selection->top = 0;
selection->width = format->width;
selection->height = format->height;
- selection = vsp1_entity_get_pad_selection(entity, config, fmt->pad,
+ selection = vsp1_entity_get_pad_selection(entity, state, fmt->pad,
V4L2_SEL_TGT_COMPOSE);
selection->left = 0;
selection->top = 0;
@@ -427,6 +397,29 @@ done:
return ret;
}
+static int vsp1_entity_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state)
+{
+ unsigned int pad;
+
+ /* Initialize all pad formats with default values. */
+ for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) {
+ struct v4l2_subdev_format format = {
+ .pad = pad,
+ .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
+ : V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+
+ v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &format);
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops vsp1_entity_internal_ops = {
+ .init_state = vsp1_entity_init_state,
+};
+
/* -----------------------------------------------------------------------------
* Media Operations
*/
@@ -661,6 +654,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
/* Initialize the V4L2 subdev. */
subdev = &entity->subdev;
v4l2_subdev_init(subdev, ops);
+ subdev->internal_ops = &vsp1_entity_internal_ops;
subdev->entity.function = function;
subdev->entity.ops = &vsp1->media_ops;
@@ -669,21 +663,21 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
snprintf(subdev->name, sizeof(subdev->name), "%s %s",
dev_name(vsp1->dev), name);
- vsp1_entity_init_cfg(subdev, NULL);
+ vsp1_entity_init_state(subdev, NULL);
/*
- * Allocate the pad configuration to store formats and selection
+ * Allocate the subdev state to store formats and selection
* rectangles.
*/
/*
* FIXME: Drop this call, drivers are not supposed to use
* __v4l2_subdev_state_alloc().
*/
- entity->config = __v4l2_subdev_state_alloc(&entity->subdev,
- "vsp1:config->lock", &key);
- if (IS_ERR(entity->config)) {
+ entity->state = __v4l2_subdev_state_alloc(&entity->subdev,
+ "vsp1:state->lock", &key);
+ if (IS_ERR(entity->state)) {
media_entity_cleanup(&entity->subdev.entity);
- return PTR_ERR(entity->config);
+ return PTR_ERR(entity->state);
}
return 0;
@@ -695,6 +689,6 @@ void vsp1_entity_destroy(struct vsp1_entity *entity)
entity->ops->destroy(entity);
if (entity->subdev.ctrl_handler)
v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
- __v4l2_subdev_state_free(entity->config);
+ __v4l2_subdev_state_free(entity->state);
media_entity_cleanup(&entity->subdev.entity);
}
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.h b/drivers/media/platform/renesas/vsp1/vsp1_entity.h
index 17f98a6a972e..735f32dde4b5 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.h
@@ -115,9 +115,9 @@ struct vsp1_entity {
unsigned int sink_pad;
struct v4l2_subdev subdev;
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
- struct mutex lock; /* Protects the pad config */
+ struct mutex lock; /* Protects the state */
};
static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev)
@@ -135,9 +135,9 @@ int vsp1_entity_link_setup(struct media_entity *entity,
const struct media_pad *remote, u32 flags);
struct v4l2_subdev_state *
-vsp1_entity_get_pad_config(struct vsp1_entity *entity,
- struct v4l2_subdev_state *sd_state,
- enum v4l2_subdev_format_whence which);
+vsp1_entity_get_state(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *sd_state,
+ enum v4l2_subdev_format_whence which);
struct v4l2_mbus_framefmt *
vsp1_entity_get_pad_format(struct vsp1_entity *entity,
struct v4l2_subdev_state *sd_state,
@@ -146,8 +146,6 @@ struct v4l2_rect *
vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
struct v4l2_subdev_state *sd_state,
unsigned int pad, unsigned int target);
-int vsp1_entity_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state);
void vsp1_entity_route_setup(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c
index e6492deb0a64..40c571a987ef 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c
@@ -140,9 +140,9 @@ static void hgo_configure_stream(struct vsp1_entity *entity,
unsigned int hratio;
unsigned int vratio;
- crop = vsp1_entity_get_pad_selection(entity, entity->config,
+ crop = vsp1_entity_get_pad_selection(entity, entity->state,
HISTO_PAD_SINK, V4L2_SEL_TGT_CROP);
- compose = vsp1_entity_get_pad_selection(entity, entity->config,
+ compose = vsp1_entity_get_pad_selection(entity, entity->state,
HISTO_PAD_SINK,
V4L2_SEL_TGT_COMPOSE);
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgt.c b/drivers/media/platform/renesas/vsp1/vsp1_hgt.c
index aa1c718e0453..8281b86874ab 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_hgt.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_hgt.c
@@ -139,9 +139,9 @@ static void hgt_configure_stream(struct vsp1_entity *entity,
u8 upper;
unsigned int i;
- crop = vsp1_entity_get_pad_selection(entity, entity->config,
+ crop = vsp1_entity_get_pad_selection(entity, entity->state,
HISTO_PAD_SINK, V4L2_SEL_TGT_CROP);
- compose = vsp1_entity_get_pad_selection(entity, entity->config,
+ compose = vsp1_entity_get_pad_selection(entity, entity->state,
HISTO_PAD_SINK,
V4L2_SEL_TGT_COMPOSE);
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c
index f22449dd654c..71155282ca11 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c
@@ -203,7 +203,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
struct v4l2_subdev_selection *sel)
{
struct vsp1_histogram *histo = subdev_to_histo(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
int ret = 0;
@@ -213,9 +213,8 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
mutex_lock(&histo->entity.lock);
- config = vsp1_entity_get_pad_config(&histo->entity, sd_state,
- sel->which);
- if (!config) {
+ state = vsp1_entity_get_state(&histo->entity, sd_state, sel->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
@@ -223,7 +222,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
- crop = vsp1_entity_get_pad_selection(&histo->entity, config,
+ crop = vsp1_entity_get_pad_selection(&histo->entity, state,
HISTO_PAD_SINK,
V4L2_SEL_TGT_CROP);
sel->r.left = 0;
@@ -234,7 +233,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT:
- format = vsp1_entity_get_pad_format(&histo->entity, config,
+ format = vsp1_entity_get_pad_format(&histo->entity, state,
HISTO_PAD_SINK);
sel->r.left = 0;
sel->r.top = 0;
@@ -244,7 +243,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
case V4L2_SEL_TGT_COMPOSE:
case V4L2_SEL_TGT_CROP:
- sel->r = *vsp1_entity_get_pad_selection(&histo->entity, config,
+ sel->r = *vsp1_entity_get_pad_selection(&histo->entity, state,
sel->pad, sel->target);
break;
@@ -346,7 +345,7 @@ static int histo_set_selection(struct v4l2_subdev *subdev,
struct v4l2_subdev_selection *sel)
{
struct vsp1_histogram *histo = subdev_to_histo(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
int ret;
if (sel->pad != HISTO_PAD_SINK)
@@ -354,17 +353,16 @@ static int histo_set_selection(struct v4l2_subdev *subdev,
mutex_lock(&histo->entity.lock);
- config = vsp1_entity_get_pad_config(&histo->entity, sd_state,
- sel->which);
- if (!config) {
+ state = vsp1_entity_get_state(&histo->entity, sd_state, sel->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
if (sel->target == V4L2_SEL_TGT_CROP)
- ret = histo_set_crop(subdev, config, sel);
+ ret = histo_set_crop(subdev, state, sel);
else if (sel->target == V4L2_SEL_TGT_COMPOSE)
- ret = histo_set_compose(subdev, config, sel);
+ ret = histo_set_compose(subdev, state, sel);
else
ret = -EINVAL;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hsit.c b/drivers/media/platform/renesas/vsp1/vsp1_hsit.c
index 361a870380c2..bc1299c29ac9 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_hsit.c
@@ -66,20 +66,19 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_format *fmt)
{
struct vsp1_hsit *hsit = to_hsit(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
int ret = 0;
mutex_lock(&hsit->entity.lock);
- config = vsp1_entity_get_pad_config(&hsit->entity, sd_state,
- fmt->which);
- if (!config) {
+ state = vsp1_entity_get_state(&hsit->entity, sd_state, fmt->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
- format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad);
+ format = vsp1_entity_get_pad_format(&hsit->entity, state, fmt->pad);
if (fmt->pad == HSIT_PAD_SOURCE) {
/*
@@ -102,7 +101,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
fmt->format = *format;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&hsit->entity, config,
+ format = vsp1_entity_get_pad_format(&hsit->entity, state,
HSIT_PAD_SOURCE);
*format = fmt->format;
format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
@@ -114,7 +113,6 @@ done:
}
static const struct v4l2_subdev_pad_ops hsit_pad_ops = {
- .init_cfg = vsp1_entity_init_cfg,
.enum_mbus_code = hsit_enum_mbus_code,
.enum_frame_size = hsit_enum_frame_size,
.get_fmt = vsp1_subdev_get_pad_format,
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lif.c b/drivers/media/platform/renesas/vsp1/vsp1_lif.c
index 0ab2e0c70474..b1d21a54837b 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_lif.c
@@ -68,7 +68,6 @@ static int lif_set_format(struct v4l2_subdev *subdev,
}
static const struct v4l2_subdev_pad_ops lif_pad_ops = {
- .init_cfg = vsp1_entity_init_cfg,
.enum_mbus_code = lif_enum_mbus_code,
.enum_frame_size = lif_enum_frame_size,
.get_fmt = vsp1_subdev_get_pad_format,
@@ -94,7 +93,7 @@ static void lif_configure_stream(struct vsp1_entity *entity,
unsigned int obth;
unsigned int lbth;
- format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
+ format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.state,
LIF_PAD_SOURCE);
switch (entity->vsp1->version & VI6_IP_VERSION_MODEL_MASK) {
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lut.c b/drivers/media/platform/renesas/vsp1/vsp1_lut.c
index ac6802a325f5..451d24ab0b56 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_lut.c
@@ -131,7 +131,6 @@ static int lut_set_format(struct v4l2_subdev *subdev,
*/
static const struct v4l2_subdev_pad_ops lut_pad_ops = {
- .init_cfg = vsp1_entity_init_cfg,
.enum_mbus_code = lut_enum_mbus_code,
.enum_frame_size = lut_enum_frame_size,
.get_fmt = vsp1_subdev_get_pad_format,
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c
index ea12c3f12c92..c47579efc65f 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c
@@ -81,10 +81,10 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
/* Format */
sink_format = vsp1_entity_get_pad_format(&rpf->entity,
- rpf->entity.config,
+ rpf->entity.state,
RWPF_PAD_SINK);
source_format = vsp1_entity_get_pad_format(&rpf->entity,
- rpf->entity.config,
+ rpf->entity.state,
RWPF_PAD_SOURCE);
infmt = VI6_RPF_INFMT_CIPM
@@ -158,7 +158,7 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
const struct v4l2_rect *compose;
compose = vsp1_entity_get_pad_selection(pipe->brx,
- pipe->brx->config,
+ pipe->brx->state,
rpf->brx_input,
V4L2_SEL_TGT_COMPOSE);
left = compose->left;
@@ -302,7 +302,7 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
* offsets are needed, as planes 2 and 3 always have identical
* strides.
*/
- crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.config);
+ crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.state);
/*
* Partition Algorithm Control
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c
index e0f87c8103ca..09fb6ffa14e2 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c
@@ -19,8 +19,7 @@
struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
struct v4l2_subdev_state *sd_state)
{
- return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, sd_state,
- RWPF_PAD_SINK);
+ return v4l2_subdev_state_get_crop(sd_state, RWPF_PAD_SINK);
}
/* -----------------------------------------------------------------------------
@@ -62,15 +61,14 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_format *fmt)
{
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
int ret = 0;
mutex_lock(&rwpf->entity.lock);
- config = vsp1_entity_get_pad_config(&rwpf->entity, sd_state,
- fmt->which);
- if (!config) {
+ state = vsp1_entity_get_state(&rwpf->entity, sd_state, fmt->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
@@ -81,7 +79,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
- format = vsp1_entity_get_pad_format(&rwpf->entity, config, fmt->pad);
+ format = vsp1_entity_get_pad_format(&rwpf->entity, state, fmt->pad);
if (fmt->pad == RWPF_PAD_SOURCE) {
/*
@@ -107,7 +105,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
struct v4l2_rect *crop;
/* Update the sink crop rectangle. */
- crop = vsp1_rwpf_get_crop(rwpf, config);
+ crop = vsp1_rwpf_get_crop(rwpf, state);
crop->left = 0;
crop->top = 0;
crop->width = fmt->format.width;
@@ -115,7 +113,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
}
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+ format = vsp1_entity_get_pad_format(&rwpf->entity, state,
RWPF_PAD_SOURCE);
*format = fmt->format;
@@ -134,7 +132,7 @@ static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
struct v4l2_subdev_selection *sel)
{
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
int ret = 0;
@@ -147,20 +145,19 @@ static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
mutex_lock(&rwpf->entity.lock);
- config = vsp1_entity_get_pad_config(&rwpf->entity, sd_state,
- sel->which);
- if (!config) {
+ state = vsp1_entity_get_state(&rwpf->entity, sd_state, sel->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- sel->r = *vsp1_rwpf_get_crop(rwpf, config);
+ sel->r = *vsp1_rwpf_get_crop(rwpf, state);
break;
case V4L2_SEL_TGT_CROP_BOUNDS:
- format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+ format = vsp1_entity_get_pad_format(&rwpf->entity, state,
RWPF_PAD_SINK);
sel->r.left = 0;
sel->r.top = 0;
@@ -183,7 +180,7 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
struct v4l2_subdev_selection *sel)
{
struct vsp1_rwpf *rwpf = to_rwpf(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
int ret = 0;
@@ -200,15 +197,14 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
mutex_lock(&rwpf->entity.lock);
- config = vsp1_entity_get_pad_config(&rwpf->entity, sd_state,
- sel->which);
- if (!config) {
+ state = vsp1_entity_get_state(&rwpf->entity, sd_state, sel->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
/* Make sure the crop rectangle is entirely contained in the image. */
- format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+ format = vsp1_entity_get_pad_format(&rwpf->entity, state,
RWPF_PAD_SINK);
/*
@@ -229,11 +225,11 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
sel->r.height = min_t(unsigned int, sel->r.height,
format->height - sel->r.top);
- crop = vsp1_rwpf_get_crop(rwpf, config);
+ crop = vsp1_rwpf_get_crop(rwpf, state);
*crop = sel->r;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&rwpf->entity, config,
+ format = vsp1_entity_get_pad_format(&rwpf->entity, state,
RWPF_PAD_SOURCE);
format->width = crop->width;
format->height = crop->height;
@@ -244,7 +240,6 @@ done:
}
static const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops = {
- .init_cfg = vsp1_entity_init_cfg,
.enum_mbus_code = vsp1_rwpf_enum_mbus_code,
.enum_frame_size = vsp1_rwpf_enum_frame_size,
.get_fmt = vsp1_subdev_get_pad_format,
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_sru.c b/drivers/media/platform/renesas/vsp1/vsp1_sru.c
index b614a2aea461..11e008aa9f20 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_sru.c
@@ -123,16 +123,15 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_frame_size_enum *fse)
{
struct vsp1_sru *sru = to_sru(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
int ret = 0;
- config = vsp1_entity_get_pad_config(&sru->entity, sd_state,
- fse->which);
- if (!config)
+ state = vsp1_entity_get_state(&sru->entity, sd_state, fse->which);
+ if (!state)
return -EINVAL;
- format = vsp1_entity_get_pad_format(&sru->entity, config, SRU_PAD_SINK);
+ format = vsp1_entity_get_pad_format(&sru->entity, state, SRU_PAD_SINK);
mutex_lock(&sru->entity.lock);
@@ -221,31 +220,30 @@ static int sru_set_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_format *fmt)
{
struct vsp1_sru *sru = to_sru(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
int ret = 0;
mutex_lock(&sru->entity.lock);
- config = vsp1_entity_get_pad_config(&sru->entity, sd_state,
- fmt->which);
- if (!config) {
+ state = vsp1_entity_get_state(&sru->entity, sd_state, fmt->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
- sru_try_format(sru, config, fmt->pad, &fmt->format);
+ sru_try_format(sru, state, fmt->pad, &fmt->format);
- format = vsp1_entity_get_pad_format(&sru->entity, config, fmt->pad);
+ format = vsp1_entity_get_pad_format(&sru->entity, state, fmt->pad);
*format = fmt->format;
if (fmt->pad == SRU_PAD_SINK) {
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&sru->entity, config,
+ format = vsp1_entity_get_pad_format(&sru->entity, state,
SRU_PAD_SOURCE);
*format = fmt->format;
- sru_try_format(sru, config, SRU_PAD_SOURCE, format);
+ sru_try_format(sru, state, SRU_PAD_SOURCE, format);
}
done:
@@ -254,7 +252,6 @@ done:
}
static const struct v4l2_subdev_pad_ops sru_pad_ops = {
- .init_cfg = vsp1_entity_init_cfg,
.enum_mbus_code = sru_enum_mbus_code,
.enum_frame_size = sru_enum_frame_size,
.get_fmt = vsp1_subdev_get_pad_format,
@@ -280,9 +277,9 @@ static void sru_configure_stream(struct vsp1_entity *entity,
struct v4l2_mbus_framefmt *output;
u32 ctrl0;
- input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+ input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
SRU_PAD_SINK);
- output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+ output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
SRU_PAD_SOURCE);
if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
@@ -310,9 +307,9 @@ static unsigned int sru_max_width(struct vsp1_entity *entity,
struct v4l2_mbus_framefmt *input;
struct v4l2_mbus_framefmt *output;
- input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+ input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
SRU_PAD_SINK);
- output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+ output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
SRU_PAD_SOURCE);
/*
@@ -336,9 +333,9 @@ static void sru_partition(struct vsp1_entity *entity,
struct v4l2_mbus_framefmt *input;
struct v4l2_mbus_framefmt *output;
- input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+ input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
SRU_PAD_SINK);
- output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config,
+ output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
SRU_PAD_SOURCE);
/* Adapt if SRUx2 is enabled. */
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_uds.c b/drivers/media/platform/renesas/vsp1/vsp1_uds.c
index 1c290cda005a..d89f1197b86c 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_uds.c
@@ -128,17 +128,15 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_frame_size_enum *fse)
{
struct vsp1_uds *uds = to_uds(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
int ret = 0;
- config = vsp1_entity_get_pad_config(&uds->entity, sd_state,
- fse->which);
- if (!config)
+ state = vsp1_entity_get_state(&uds->entity, sd_state, fse->which);
+ if (!state)
return -EINVAL;
- format = vsp1_entity_get_pad_format(&uds->entity, config,
- UDS_PAD_SINK);
+ format = vsp1_entity_get_pad_format(&uds->entity, state, UDS_PAD_SINK);
mutex_lock(&uds->entity.lock);
@@ -205,31 +203,30 @@ static int uds_set_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_format *fmt)
{
struct vsp1_uds *uds = to_uds(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
int ret = 0;
mutex_lock(&uds->entity.lock);
- config = vsp1_entity_get_pad_config(&uds->entity, sd_state,
- fmt->which);
- if (!config) {
+ state = vsp1_entity_get_state(&uds->entity, sd_state, fmt->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
- uds_try_format(uds, config, fmt->pad, &fmt->format);
+ uds_try_format(uds, state, fmt->pad, &fmt->format);
- format = vsp1_entity_get_pad_format(&uds->entity, config, fmt->pad);
+ format = vsp1_entity_get_pad_format(&uds->entity, state, fmt->pad);
*format = fmt->format;
if (fmt->pad == UDS_PAD_SINK) {
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&uds->entity, config,
+ format = vsp1_entity_get_pad_format(&uds->entity, state,
UDS_PAD_SOURCE);
*format = fmt->format;
- uds_try_format(uds, config, UDS_PAD_SOURCE, format);
+ uds_try_format(uds, state, UDS_PAD_SOURCE, format);
}
done:
@@ -242,7 +239,6 @@ done:
*/
static const struct v4l2_subdev_pad_ops uds_pad_ops = {
- .init_cfg = vsp1_entity_init_cfg,
.enum_mbus_code = uds_enum_mbus_code,
.enum_frame_size = uds_enum_frame_size,
.get_fmt = vsp1_subdev_get_pad_format,
@@ -269,9 +265,9 @@ static void uds_configure_stream(struct vsp1_entity *entity,
unsigned int vscale;
bool multitap;
- input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+ input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
UDS_PAD_SINK);
- output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+ output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
UDS_PAD_SOURCE);
hscale = uds_compute_ratio(input->width, output->width);
@@ -314,7 +310,7 @@ static void uds_configure_partition(struct vsp1_entity *entity,
struct vsp1_partition *partition = pipe->partition;
const struct v4l2_mbus_framefmt *output;
- output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+ output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
UDS_PAD_SOURCE);
/* Input size clipping. */
@@ -339,9 +335,9 @@ static unsigned int uds_max_width(struct vsp1_entity *entity,
const struct v4l2_mbus_framefmt *input;
unsigned int hscale;
- input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+ input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
UDS_PAD_SINK);
- output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+ output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
UDS_PAD_SOURCE);
hscale = output->width / input->width;
@@ -381,9 +377,9 @@ static void uds_partition(struct vsp1_entity *entity,
partition->uds_sink = *window;
partition->uds_source = *window;
- input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+ input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
UDS_PAD_SINK);
- output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config,
+ output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
UDS_PAD_SOURCE);
partition->uds_sink.width = window->width * input->width
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_uif.c b/drivers/media/platform/renesas/vsp1/vsp1_uif.c
index 83d7f17df80e..f66936a28a2a 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_uif.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_uif.c
@@ -86,7 +86,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev,
struct v4l2_subdev_selection *sel)
{
struct vsp1_uif *uif = to_uif(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
int ret = 0;
@@ -95,9 +95,8 @@ static int uif_get_selection(struct v4l2_subdev *subdev,
mutex_lock(&uif->entity.lock);
- config = vsp1_entity_get_pad_config(&uif->entity, sd_state,
- sel->which);
- if (!config) {
+ state = vsp1_entity_get_state(&uif->entity, sd_state, sel->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
@@ -105,7 +104,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT:
- format = vsp1_entity_get_pad_format(&uif->entity, config,
+ format = vsp1_entity_get_pad_format(&uif->entity, state,
UIF_PAD_SINK);
sel->r.left = 0;
sel->r.top = 0;
@@ -114,7 +113,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev,
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *vsp1_entity_get_pad_selection(&uif->entity, config,
+ sel->r = *vsp1_entity_get_pad_selection(&uif->entity, state,
sel->pad, sel->target);
break;
@@ -133,7 +132,7 @@ static int uif_set_selection(struct v4l2_subdev *subdev,
struct v4l2_subdev_selection *sel)
{
struct vsp1_uif *uif = to_uif(subdev);
- struct v4l2_subdev_state *config;
+ struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *selection;
int ret = 0;
@@ -144,15 +143,14 @@ static int uif_set_selection(struct v4l2_subdev *subdev,
mutex_lock(&uif->entity.lock);
- config = vsp1_entity_get_pad_config(&uif->entity, sd_state,
- sel->which);
- if (!config) {
+ state = vsp1_entity_get_state(&uif->entity, sd_state, sel->which);
+ if (!state) {
ret = -EINVAL;
goto done;
}
/* The crop rectangle must be inside the input frame. */
- format = vsp1_entity_get_pad_format(&uif->entity, config, UIF_PAD_SINK);
+ format = vsp1_entity_get_pad_format(&uif->entity, state, UIF_PAD_SINK);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
@@ -162,7 +160,7 @@ static int uif_set_selection(struct v4l2_subdev *subdev,
format->height - sel->r.top);
/* Store the crop rectangle. */
- selection = vsp1_entity_get_pad_selection(&uif->entity, config,
+ selection = vsp1_entity_get_pad_selection(&uif->entity, state,
sel->pad, V4L2_SEL_TGT_CROP);
*selection = sel->r;
@@ -176,7 +174,6 @@ done:
*/
static const struct v4l2_subdev_pad_ops uif_pad_ops = {
- .init_cfg = vsp1_entity_init_cfg,
.enum_mbus_code = uif_enum_mbus_code,
.enum_frame_size = uif_enum_frame_size,
.get_fmt = vsp1_subdev_get_pad_format,
@@ -206,7 +203,7 @@ static void uif_configure_stream(struct vsp1_entity *entity,
vsp1_uif_write(uif, dlb, VI6_UIF_DISCOM_DOCMPMR,
VI6_UIF_DISCOM_DOCMPMR_SEL(9));
- crop = vsp1_entity_get_pad_selection(entity, entity->config,
+ crop = vsp1_entity_get_pad_selection(entity, entity->state,
UIF_PAD_SINK, V4L2_SEL_TGT_CROP);
left = crop->left;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c
index e9d5027761bb..5a9cb0e5640e 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_video.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c
@@ -198,7 +198,7 @@ static void vsp1_video_calculate_partition(struct vsp1_pipeline *pipe,
* at the WPF sink.
*/
format = vsp1_entity_get_pad_format(&pipe->output->entity,
- pipe->output->entity.config,
+ pipe->output->entity.state,
RWPF_PAD_SINK);
/* A single partition simply processes the output size in full. */
@@ -263,7 +263,7 @@ static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
* at the WPF sink.
*/
format = vsp1_entity_get_pad_format(&pipe->output->entity,
- pipe->output->entity.config,
+ pipe->output->entity.state,
RWPF_PAD_SINK);
div_size = format->width;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c
index cab4445eca69..9693aeab1cac 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c
@@ -66,10 +66,10 @@ static int vsp1_wpf_set_rotation(struct vsp1_rwpf *wpf, unsigned int rotation)
}
sink_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.config,
+ wpf->entity.state,
RWPF_PAD_SINK);
source_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.config,
+ wpf->entity.state,
RWPF_PAD_SOURCE);
mutex_lock(&wpf->entity.lock);
@@ -246,10 +246,10 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
int ret;
sink_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.config,
+ wpf->entity.state,
RWPF_PAD_SINK);
source_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.config,
+ wpf->entity.state,
RWPF_PAD_SOURCE);
/* Format */
@@ -384,7 +384,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
unsigned int i;
sink_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.config,
+ wpf->entity.state,
RWPF_PAD_SINK);
width = sink_format->width;
height = sink_format->height;
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 81508ed5abf3..662c81b6d0b5 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -5,7 +5,9 @@
*/
#include <linux/pm_runtime.h>
+#include <linux/scatterlist.h>
+#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mem2mem.h>
@@ -15,6 +17,26 @@
#include "rga-hw.h"
#include "rga.h"
+static ssize_t fill_descriptors(struct rga_dma_desc *desc, size_t max_desc,
+ struct sg_table *sgt)
+{
+ struct sg_dma_page_iter iter;
+ struct rga_dma_desc *tmp = desc;
+ size_t n_desc = 0;
+ dma_addr_t addr;
+
+ for_each_sgtable_dma_page(sgt, &iter, 0) {
+ if (n_desc > max_desc)
+ return -EINVAL;
+ addr = sg_page_iter_dma_address(&iter);
+ tmp->addr = lower_32_bits(addr);
+ tmp++;
+ n_desc++;
+ }
+
+ return n_desc;
+}
+
static int
rga_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
@@ -22,28 +44,105 @@ rga_queue_setup(struct vb2_queue *vq,
{
struct rga_ctx *ctx = vb2_get_drv_priv(vq);
struct rga_frame *f = rga_get_frame(ctx, vq->type);
+ const struct v4l2_pix_format_mplane *pix_fmt;
+ int i;
if (IS_ERR(f))
return PTR_ERR(f);
- if (*nplanes)
- return sizes[0] < f->size ? -EINVAL : 0;
+ pix_fmt = &f->pix;
+
+ if (*nplanes) {
+ if (*nplanes != pix_fmt->num_planes)
+ return -EINVAL;
+
+ for (i = 0; i < pix_fmt->num_planes; i++)
+ if (sizes[i] < pix_fmt->plane_fmt[i].sizeimage)
+ return -EINVAL;
+
+ return 0;
+ }
+
+ *nplanes = pix_fmt->num_planes;
+
+ for (i = 0; i < pix_fmt->num_planes; i++)
+ sizes[i] = pix_fmt->plane_fmt[i].sizeimage;
+
+ return 0;
+}
+
+static int rga_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct rga_vb_buffer *rbuf = vb_to_rga(vbuf);
+ struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct rockchip_rga *rga = ctx->rga;
+ struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
+ size_t n_desc = 0;
- sizes[0] = f->size;
- *nplanes = 1;
+ n_desc = DIV_ROUND_UP(f->size, PAGE_SIZE);
+
+ rbuf->n_desc = n_desc;
+ rbuf->dma_desc = dma_alloc_coherent(rga->dev,
+ rbuf->n_desc * sizeof(*rbuf->dma_desc),
+ &rbuf->dma_desc_pa, GFP_KERNEL);
+ if (!rbuf->dma_desc)
+ return -ENOMEM;
return 0;
}
+static int get_plane_offset(struct rga_frame *f, int plane)
+{
+ if (plane == 0)
+ return 0;
+ if (plane == 1)
+ return f->width * f->height;
+ if (plane == 2)
+ return f->width * f->height + (f->width * f->height / f->fmt->uv_factor);
+
+ return -EINVAL;
+}
+
static int rga_buf_prepare(struct vb2_buffer *vb)
{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct rga_vb_buffer *rbuf = vb_to_rga(vbuf);
struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type);
+ ssize_t n_desc = 0;
+ size_t curr_desc = 0;
+ int i;
+ const struct v4l2_format_info *info;
+ unsigned int offsets[VIDEO_MAX_PLANES];
if (IS_ERR(f))
return PTR_ERR(f);
- vb2_set_plane_payload(vb, 0, f->size);
+ for (i = 0; i < vb->num_planes; i++) {
+ vb2_set_plane_payload(vb, i, f->pix.plane_fmt[i].sizeimage);
+
+ /* Create local MMU table for RGA */
+ n_desc = fill_descriptors(&rbuf->dma_desc[curr_desc],
+ rbuf->n_desc - curr_desc,
+ vb2_dma_sg_plane_desc(vb, i));
+ if (n_desc < 0) {
+ v4l2_err(&ctx->rga->v4l2_dev,
+ "Failed to map video buffer to RGA\n");
+ return n_desc;
+ }
+ offsets[i] = curr_desc << PAGE_SHIFT;
+ curr_desc += n_desc;
+ }
+
+ /* Fill the remaining planes */
+ info = v4l2_format_info(f->fmt->fourcc);
+ for (i = info->mem_planes; i < info->comp_planes; i++)
+ offsets[i] = get_plane_offset(f, i);
+
+ rbuf->offset.y_off = offsets[0];
+ rbuf->offset.u_off = offsets[1];
+ rbuf->offset.v_off = offsets[2];
return 0;
}
@@ -56,6 +155,17 @@ static void rga_buf_queue(struct vb2_buffer *vb)
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
}
+static void rga_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct rga_vb_buffer *rbuf = vb_to_rga(vbuf);
+ struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct rockchip_rga *rga = ctx->rga;
+
+ dma_free_coherent(rga->dev, rbuf->n_desc * sizeof(*rbuf->dma_desc),
+ rbuf->dma_desc, rbuf->dma_desc_pa);
+}
+
static void rga_buf_return_buffers(struct vb2_queue *q,
enum vb2_buffer_state state)
{
@@ -99,50 +209,12 @@ static void rga_buf_stop_streaming(struct vb2_queue *q)
const struct vb2_ops rga_qops = {
.queue_setup = rga_queue_setup,
+ .buf_init = rga_buf_init,
.buf_prepare = rga_buf_prepare,
.buf_queue = rga_buf_queue,
+ .buf_cleanup = rga_buf_cleanup,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.start_streaming = rga_buf_start_streaming,
.stop_streaming = rga_buf_stop_streaming,
};
-
-/* RGA MMU is a 1-Level MMU, so it can't be used through the IOMMU API.
- * We use it more like a scatter-gather list.
- */
-void rga_buf_map(struct vb2_buffer *vb)
-{
- struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- struct rockchip_rga *rga = ctx->rga;
- struct sg_table *sgt;
- struct scatterlist *sgl;
- unsigned int *pages;
- unsigned int address, len, i, p;
- unsigned int mapped_size = 0;
-
- if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- pages = rga->src_mmu_pages;
- else
- pages = rga->dst_mmu_pages;
-
- /* Create local MMU table for RGA */
- sgt = vb2_plane_cookie(vb, 0);
-
- for_each_sg(sgt->sgl, sgl, sgt->nents, i) {
- len = sg_dma_len(sgl) >> PAGE_SHIFT;
- address = sg_phys(sgl);
-
- for (p = 0; p < len; p++) {
- dma_addr_t phys = address +
- ((dma_addr_t)p << PAGE_SHIFT);
-
- pages[mapped_size + p] = phys;
- }
-
- mapped_size += len;
- }
-
- /* sync local MMU table for RGA */
- dma_sync_single_for_device(rga->dev, virt_to_phys(pages),
- 8 * PAGE_SIZE, DMA_BIDIRECTIONAL);
-}
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c
index aaa96f256356..11c3d7234757 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -16,12 +16,6 @@ enum e_rga_start_pos {
RB = 3,
};
-struct rga_addr_offset {
- unsigned int y_off;
- unsigned int u_off;
- unsigned int v_off;
-};
-
struct rga_corners_addr_offset {
struct rga_addr_offset left_top;
struct rga_addr_offset right_top;
@@ -43,13 +37,13 @@ static unsigned int rga_get_scaling(unsigned int src, unsigned int dst)
}
static struct rga_corners_addr_offset
-rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y,
- unsigned int w, unsigned int h)
+rga_get_addr_offset(struct rga_frame *frm, struct rga_addr_offset *offset,
+ unsigned int x, unsigned int y, unsigned int w, unsigned int h)
{
struct rga_corners_addr_offset offsets;
struct rga_addr_offset *lt, *lb, *rt, *rb;
unsigned int x_div = 0,
- y_div = 0, uv_stride = 0, pixel_width = 0, uv_factor = 0;
+ y_div = 0, uv_stride = 0, pixel_width = 0;
lt = &offsets.left_top;
lb = &offsets.left_bottom;
@@ -58,14 +52,12 @@ rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y,
x_div = frm->fmt->x_div;
y_div = frm->fmt->y_div;
- uv_factor = frm->fmt->uv_factor;
uv_stride = frm->stride / x_div;
pixel_width = frm->stride / frm->width;
- lt->y_off = y * frm->stride + x * pixel_width;
- lt->u_off =
- frm->width * frm->height + (y / y_div) * uv_stride + x / x_div;
- lt->v_off = lt->u_off + frm->width * frm->height / uv_factor;
+ lt->y_off = offset->y_off + y * frm->stride + x * pixel_width;
+ lt->u_off = offset->u_off + (y / y_div) * uv_stride + x / x_div;
+ lt->v_off = offset->v_off + (y / y_div) * uv_stride + x / x_div;
lb->y_off = lt->y_off + (h - 1) * frm->stride;
lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride;
@@ -119,40 +111,40 @@ static struct rga_addr_offset *rga_lookup_draw_pos(struct
return NULL;
}
-static void rga_cmd_set_src_addr(struct rga_ctx *ctx, void *mmu_pages)
+static void rga_cmd_set_src_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
{
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
unsigned int reg;
reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG;
- dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+ dest[reg >> 2] = dma_addr >> 4;
reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
dest[reg >> 2] |= 0x7;
}
-static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, void *mmu_pages)
+static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
{
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
unsigned int reg;
reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG;
- dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+ dest[reg >> 2] = dma_addr >> 4;
reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
dest[reg >> 2] |= 0x7 << 4;
}
-static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, void *mmu_pages)
+static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, dma_addr_t dma_addr)
{
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
unsigned int reg;
reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG;
- dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4;
+ dest[reg >> 2] = dma_addr >> 4;
reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG;
dest[reg >> 2] |= 0x7 << 8;
@@ -163,7 +155,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
struct rockchip_rga *rga = ctx->rga;
u32 *dest = rga->cmdbuf_virt;
unsigned int scale_dst_w, scale_dst_h;
- unsigned int src_h, src_w, src_x, src_y, dst_h, dst_w, dst_x, dst_y;
+ unsigned int src_h, src_w, dst_h, dst_w;
union rga_src_info src_info;
union rga_dst_info dst_info;
union rga_src_x_factor x_factor;
@@ -173,18 +165,10 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
union rga_dst_vir_info dst_vir_info;
union rga_dst_act_info dst_act_info;
- struct rga_addr_offset *dst_offset;
- struct rga_corners_addr_offset offsets;
- struct rga_corners_addr_offset src_offsets;
-
src_h = ctx->in.crop.height;
src_w = ctx->in.crop.width;
- src_x = ctx->in.crop.left;
- src_y = ctx->in.crop.top;
dst_h = ctx->out.crop.height;
dst_w = ctx->out.crop.width;
- dst_x = ctx->out.crop.left;
- dst_y = ctx->out.crop.top;
src_info.val = dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2];
dst_info.val = dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2];
@@ -312,18 +296,37 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
dst_act_info.data.act_height = dst_h - 1;
dst_act_info.data.act_width = dst_w - 1;
- /*
- * Calculate the source framebuffer base address with offset pixel.
- */
- src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y,
- src_w, src_h);
+ dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val;
+ dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val;
+ dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val;
+ dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val;
+
+ dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val;
+
+ dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val;
+ dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val;
+
+ dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val;
+}
+
+static void rga_cmd_set_src_info(struct rga_ctx *ctx,
+ struct rga_addr_offset *offset)
+{
+ struct rga_corners_addr_offset src_offsets;
+ struct rockchip_rga *rga = ctx->rga;
+ u32 *dest = rga->cmdbuf_virt;
+ unsigned int src_h, src_w, src_x, src_y;
+
+ src_h = ctx->in.crop.height;
+ src_w = ctx->in.crop.width;
+ src_x = ctx->in.crop.left;
+ src_y = ctx->in.crop.top;
/*
- * Configure the dest framebuffer base address with pixel offset.
+ * Calculate the source framebuffer base address with offset pixel.
*/
- offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h);
- dst_offset = rga_lookup_draw_pos(&offsets, src_info.data.rot_mode,
- src_info.data.mir_mode);
+ src_offsets = rga_get_addr_offset(&ctx->in, offset,
+ src_x, src_y, src_w, src_h);
dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
src_offsets.left_top.y_off;
@@ -331,13 +334,49 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
src_offsets.left_top.u_off;
dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
src_offsets.left_top.v_off;
+}
- dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val;
- dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val;
- dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val;
- dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val;
+static void rga_cmd_set_dst_info(struct rga_ctx *ctx,
+ struct rga_addr_offset *offset)
+{
+ struct rga_addr_offset *dst_offset;
+ struct rga_corners_addr_offset offsets;
+ struct rockchip_rga *rga = ctx->rga;
+ u32 *dest = rga->cmdbuf_virt;
+ unsigned int dst_h, dst_w, dst_x, dst_y;
+ unsigned int mir_mode = 0;
+ unsigned int rot_mode = 0;
- dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val;
+ dst_h = ctx->out.crop.height;
+ dst_w = ctx->out.crop.width;
+ dst_x = ctx->out.crop.left;
+ dst_y = ctx->out.crop.top;
+
+ if (ctx->vflip)
+ mir_mode |= RGA_SRC_MIRR_MODE_X;
+ if (ctx->hflip)
+ mir_mode |= RGA_SRC_MIRR_MODE_Y;
+
+ switch (ctx->rotate) {
+ case 90:
+ rot_mode = RGA_SRC_ROT_MODE_90_DEGREE;
+ break;
+ case 180:
+ rot_mode = RGA_SRC_ROT_MODE_180_DEGREE;
+ break;
+ case 270:
+ rot_mode = RGA_SRC_ROT_MODE_270_DEGREE;
+ break;
+ default:
+ rot_mode = RGA_SRC_ROT_MODE_0_DEGREE;
+ break;
+ }
+
+ /*
+ * Configure the dest framebuffer base address with pixel offset.
+ */
+ offsets = rga_get_addr_offset(&ctx->out, offset, dst_x, dst_y, dst_w, dst_h);
+ dst_offset = rga_lookup_draw_pos(&offsets, mir_mode, rot_mode);
dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
dst_offset->y_off;
@@ -345,11 +384,6 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx)
dst_offset->u_off;
dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] =
dst_offset->v_off;
-
- dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val;
- dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val;
-
- dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val;
}
static void rga_cmd_set_mode(struct rga_ctx *ctx)
@@ -375,22 +409,25 @@ static void rga_cmd_set_mode(struct rga_ctx *ctx)
dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val;
}
-static void rga_cmd_set(struct rga_ctx *ctx)
+static void rga_cmd_set(struct rga_ctx *ctx,
+ struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
{
struct rockchip_rga *rga = ctx->rga;
memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4);
- rga_cmd_set_src_addr(ctx, rga->src_mmu_pages);
+ rga_cmd_set_src_addr(ctx, src->dma_desc_pa);
/*
* Due to hardware bug,
* src1 mmu also should be configured when using alpha blending.
*/
- rga_cmd_set_src1_addr(ctx, rga->dst_mmu_pages);
+ rga_cmd_set_src1_addr(ctx, dst->dma_desc_pa);
- rga_cmd_set_dst_addr(ctx, rga->dst_mmu_pages);
+ rga_cmd_set_dst_addr(ctx, dst->dma_desc_pa);
rga_cmd_set_mode(ctx);
+ rga_cmd_set_src_info(ctx, &src->offset);
+ rga_cmd_set_dst_info(ctx, &dst->offset);
rga_cmd_set_trans_info(ctx);
rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy);
@@ -400,11 +437,12 @@ static void rga_cmd_set(struct rga_ctx *ctx)
PAGE_SIZE, DMA_BIDIRECTIONAL);
}
-void rga_hw_start(struct rockchip_rga *rga)
+void rga_hw_start(struct rockchip_rga *rga,
+ struct rga_vb_buffer *src, struct rga_vb_buffer *dst)
{
struct rga_ctx *ctx = rga->curr;
- rga_cmd_set(ctx);
+ rga_cmd_set(ctx, src, dst);
rga_write(rga, RGA_SYS_CTRL, 0x00);
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index f1c532a5802a..00fdfa9e10bc 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -45,10 +45,7 @@ static void device_run(void *prv)
src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
- rga_buf_map(&src->vb2_buf);
- rga_buf_map(&dst->vb2_buf);
-
- rga_hw_start(rga);
+ rga_hw_start(rga, vb_to_rga(src), vb_to_rga(dst));
spin_unlock_irqrestore(&rga->ctrl_lock, flags);
}
@@ -96,12 +93,13 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
struct rga_ctx *ctx = priv;
int ret;
- src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
src_vq->drv_priv = ctx;
src_vq->ops = &rga_qops;
src_vq->mem_ops = &vb2_dma_sg_memops;
- src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->gfp_flags = __GFP_DMA32;
+ src_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->rga->mutex;
src_vq->dev = ctx->rga->v4l2_dev.dev;
@@ -110,12 +108,13 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
if (ret)
return ret;
- dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
dst_vq->drv_priv = ctx;
dst_vq->ops = &rga_qops;
dst_vq->mem_ops = &vb2_dma_sg_memops;
- dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->gfp_flags = __GFP_DMA32;
+ dst_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->rga->mutex;
dst_vq->dev = ctx->rga->v4l2_dev.dev;
@@ -184,7 +183,7 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
static struct rga_fmt formats[] = {
{
.fourcc = V4L2_PIX_FMT_ARGB32,
- .color_swap = RGA_COLOR_RB_SWAP,
+ .color_swap = RGA_COLOR_ALPHA_SWAP,
.hw_format = RGA_COLOR_FMT_ABGR8888,
.depth = 32,
.uv_factor = 1,
@@ -192,17 +191,8 @@ static struct rga_fmt formats[] = {
.x_div = 1,
},
{
- .fourcc = V4L2_PIX_FMT_XRGB32,
- .color_swap = RGA_COLOR_RB_SWAP,
- .hw_format = RGA_COLOR_FMT_XBGR8888,
- .depth = 32,
- .uv_factor = 1,
- .y_div = 1,
- .x_div = 1,
- },
- {
.fourcc = V4L2_PIX_FMT_ABGR32,
- .color_swap = RGA_COLOR_ALPHA_SWAP,
+ .color_swap = RGA_COLOR_RB_SWAP,
.hw_format = RGA_COLOR_FMT_ABGR8888,
.depth = 32,
.uv_factor = 1,
@@ -211,7 +201,7 @@ static struct rga_fmt formats[] = {
},
{
.fourcc = V4L2_PIX_FMT_XBGR32,
- .color_swap = RGA_COLOR_ALPHA_SWAP,
+ .color_swap = RGA_COLOR_RB_SWAP,
.hw_format = RGA_COLOR_FMT_XBGR8888,
.depth = 32,
.uv_factor = 1,
@@ -291,6 +281,15 @@ static struct rga_fmt formats[] = {
.x_div = 1,
},
{
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .color_swap = RGA_COLOR_NONE_SWAP,
+ .hw_format = RGA_COLOR_FMT_YUV420SP,
+ .depth = 12,
+ .uv_factor = 4,
+ .y_div = 2,
+ .x_div = 1,
+ },
+ {
.fourcc = V4L2_PIX_FMT_NV16,
.color_swap = RGA_COLOR_NONE_SWAP,
.hw_format = RGA_COLOR_FMT_YUV422SP,
@@ -330,12 +329,12 @@ static struct rga_fmt formats[] = {
#define NUM_FORMATS ARRAY_SIZE(formats)
-static struct rga_fmt *rga_fmt_find(struct v4l2_format *f)
+static struct rga_fmt *rga_fmt_find(u32 pixelformat)
{
unsigned int i;
for (i = 0; i < NUM_FORMATS; i++) {
- if (formats[i].fourcc == f->fmt.pix.pixelformat)
+ if (formats[i].fourcc == pixelformat)
return &formats[i];
}
return NULL;
@@ -354,14 +353,11 @@ static struct rga_frame def_frame = {
struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type)
{
- switch (type) {
- case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (V4L2_TYPE_IS_OUTPUT(type))
return &ctx->in;
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (V4L2_TYPE_IS_CAPTURE(type))
return &ctx->out;
- default:
- return ERR_PTR(-EINVAL);
- }
+ return ERR_PTR(-EINVAL);
}
static int rga_open(struct file *file)
@@ -378,6 +374,11 @@ static int rga_open(struct file *file)
ctx->in = def_frame;
ctx->out = def_frame;
+ v4l2_fill_pixfmt_mp(&ctx->in.pix,
+ ctx->in.fmt->fourcc, ctx->out.width, ctx->out.height);
+ v4l2_fill_pixfmt_mp(&ctx->out.pix,
+ ctx->out.fmt->fourcc, ctx->out.width, ctx->out.height);
+
if (mutex_lock_interruptible(&rga->mutex)) {
kfree(ctx);
return -ERESTARTSYS;
@@ -458,6 +459,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
{
+ struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
struct rga_ctx *ctx = prv;
struct vb2_queue *vq;
struct rga_frame *frm;
@@ -469,58 +471,43 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
if (IS_ERR(frm))
return PTR_ERR(frm);
- f->fmt.pix.width = frm->width;
- f->fmt.pix.height = frm->height;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.pixelformat = frm->fmt->fourcc;
- f->fmt.pix.bytesperline = frm->stride;
- f->fmt.pix.sizeimage = frm->size;
- f->fmt.pix.colorspace = frm->colorspace;
+ v4l2_fill_pixfmt_mp(pix_fmt, frm->fmt->fourcc, frm->width, frm->height);
+
+ pix_fmt->field = V4L2_FIELD_NONE;
+ pix_fmt->colorspace = frm->colorspace;
return 0;
}
static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f)
{
+ struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
struct rga_fmt *fmt;
- fmt = rga_fmt_find(f);
- if (!fmt) {
+ fmt = rga_fmt_find(pix_fmt->pixelformat);
+ if (!fmt)
fmt = &formats[0];
- f->fmt.pix.pixelformat = fmt->fourcc;
- }
-
- f->fmt.pix.field = V4L2_FIELD_NONE;
- if (f->fmt.pix.width > MAX_WIDTH)
- f->fmt.pix.width = MAX_WIDTH;
- if (f->fmt.pix.height > MAX_HEIGHT)
- f->fmt.pix.height = MAX_HEIGHT;
+ pix_fmt->width = clamp(pix_fmt->width,
+ (u32)MIN_WIDTH, (u32)MAX_WIDTH);
+ pix_fmt->height = clamp(pix_fmt->height,
+ (u32)MIN_HEIGHT, (u32)MAX_HEIGHT);
- if (f->fmt.pix.width < MIN_WIDTH)
- f->fmt.pix.width = MIN_WIDTH;
- if (f->fmt.pix.height < MIN_HEIGHT)
- f->fmt.pix.height = MIN_HEIGHT;
-
- if (fmt->hw_format >= RGA_COLOR_FMT_YUV422SP)
- f->fmt.pix.bytesperline = f->fmt.pix.width;
- else
- f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
-
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * (f->fmt.pix.width * fmt->depth) >> 3;
+ v4l2_fill_pixfmt_mp(pix_fmt, fmt->fourcc, pix_fmt->width, pix_fmt->height);
+ pix_fmt->field = V4L2_FIELD_NONE;
return 0;
}
static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
{
+ struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp;
struct rga_ctx *ctx = prv;
struct rockchip_rga *rga = ctx->rga;
struct vb2_queue *vq;
struct rga_frame *frm;
- struct rga_fmt *fmt;
int ret = 0;
+ int i;
/* Adjust all values accordingly to the hardware capabilities
* and chosen format.
@@ -536,15 +523,14 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
frm = rga_get_frame(ctx, f->type);
if (IS_ERR(frm))
return PTR_ERR(frm);
- fmt = rga_fmt_find(f);
- if (!fmt)
- return -EINVAL;
- frm->width = f->fmt.pix.width;
- frm->height = f->fmt.pix.height;
- frm->size = f->fmt.pix.sizeimage;
- frm->fmt = fmt;
- frm->stride = f->fmt.pix.bytesperline;
- frm->colorspace = f->fmt.pix.colorspace;
+ frm->width = pix_fmt->width;
+ frm->height = pix_fmt->height;
+ frm->size = 0;
+ for (i = 0; i < pix_fmt->num_planes; i++)
+ frm->size += pix_fmt->plane_fmt[i].sizeimage;
+ frm->fmt = rga_fmt_find(pix_fmt->pixelformat);
+ frm->stride = pix_fmt->plane_fmt[0].bytesperline;
+ frm->colorspace = pix_fmt->colorspace;
/* Reset crop settings */
frm->crop.left = 0;
@@ -552,6 +538,21 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
frm->crop.width = frm->width;
frm->crop.height = frm->height;
+ frm->pix = *pix_fmt;
+
+ v4l2_dbg(debug, 1, &rga->v4l2_dev,
+ "[%s] fmt - %p4cc %dx%d (stride %d, sizeimage %d)\n",
+ V4L2_TYPE_IS_OUTPUT(f->type) ? "OUTPUT" : "CAPTURE",
+ &frm->fmt->fourcc, frm->width, frm->height,
+ frm->stride, frm->size);
+
+ for (i = 0; i < pix_fmt->num_planes; i++) {
+ v4l2_dbg(debug, 1, &rga->v4l2_dev,
+ "plane[%d]: size %d, bytesperline %d\n",
+ i, pix_fmt->plane_fmt[i].sizeimage,
+ pix_fmt->plane_fmt[i].bytesperline);
+ }
+
return 0;
}
@@ -569,21 +570,21 @@ static int vidioc_g_selection(struct file *file, void *prv,
switch (s->target) {
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
- if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (!V4L2_TYPE_IS_CAPTURE(s->type))
return -EINVAL;
break;
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
- if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ if (!V4L2_TYPE_IS_OUTPUT(s->type))
return -EINVAL;
break;
case V4L2_SEL_TGT_COMPOSE:
- if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (!V4L2_TYPE_IS_CAPTURE(s->type))
return -EINVAL;
use_frame = true;
break;
case V4L2_SEL_TGT_CROP:
- if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ if (!V4L2_TYPE_IS_OUTPUT(s->type))
return -EINVAL;
use_frame = true;
break;
@@ -621,7 +622,7 @@ static int vidioc_s_selection(struct file *file, void *prv,
* COMPOSE target is only valid for capture buffer type, return
* error for output buffer type
*/
- if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (!V4L2_TYPE_IS_CAPTURE(s->type))
return -EINVAL;
break;
case V4L2_SEL_TGT_CROP:
@@ -629,7 +630,7 @@ static int vidioc_s_selection(struct file *file, void *prv,
* CROP target is only valid for output buffer type, return
* error for capture buffer type
*/
- if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ if (!V4L2_TYPE_IS_OUTPUT(s->type))
return -EINVAL;
break;
/*
@@ -662,14 +663,14 @@ static const struct v4l2_ioctl_ops rga_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt,
+ .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
+ .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
.vidioc_enum_fmt_vid_out = vidioc_enum_fmt,
- .vidioc_g_fmt_vid_out = vidioc_g_fmt,
- .vidioc_try_fmt_vid_out = vidioc_try_fmt,
- .vidioc_s_fmt_vid_out = vidioc_s_fmt,
+ .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
+ .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
+ .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt,
.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
@@ -696,7 +697,7 @@ static const struct video_device rga_videodev = {
.minor = -1,
.release = video_device_release,
.vfl_dir = VFL_DIR_M2M,
- .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+ .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
};
static int rga_enable_clocks(struct rockchip_rga *rga)
@@ -836,6 +837,12 @@ static int rga_probe(struct platform_device *pdev)
goto err_put_clk;
}
+ ret = dma_set_mask_and_coherent(rga->dev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(rga->dev, "32-bit DMA not supported");
+ goto err_put_clk;
+ }
+
ret = v4l2_device_register(&pdev->dev, &rga->v4l2_dev);
if (ret)
goto err_put_clk;
@@ -881,26 +888,13 @@ static int rga_probe(struct platform_device *pdev)
goto rel_m2m;
}
- rga->src_mmu_pages =
- (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
- if (!rga->src_mmu_pages) {
- ret = -ENOMEM;
- goto free_dma;
- }
- rga->dst_mmu_pages =
- (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
- if (!rga->dst_mmu_pages) {
- ret = -ENOMEM;
- goto free_src_pages;
- }
-
def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
def_frame.size = def_frame.stride * def_frame.height;
ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
if (ret) {
v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
- goto free_dst_pages;
+ goto free_dma;
}
v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n",
@@ -908,10 +902,6 @@ static int rga_probe(struct platform_device *pdev)
return 0;
-free_dst_pages:
- free_pages((unsigned long)rga->dst_mmu_pages, 3);
-free_src_pages:
- free_pages((unsigned long)rga->src_mmu_pages, 3);
free_dma:
dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
@@ -934,9 +924,6 @@ static void rga_remove(struct platform_device *pdev)
dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt,
rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE);
- free_pages((unsigned long)rga->src_mmu_pages, 3);
- free_pages((unsigned long)rga->dst_mmu_pages, 3);
-
v4l2_info(&rga->v4l2_dev, "Removing\n");
v4l2_m2m_release(rga->m2m_dev);
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 5fa9d2f366dc..3502dff6055c 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -34,12 +34,17 @@ struct rga_frame {
/* Image format */
struct rga_fmt *fmt;
+ struct v4l2_pix_format_mplane pix;
/* Variables that can calculated once and reused */
u32 stride;
u32 size;
};
+struct rga_dma_desc {
+ u32 addr;
+};
+
struct rockchip_rga_version {
u32 major;
u32 minor;
@@ -81,15 +86,36 @@ struct rockchip_rga {
struct rga_ctx *curr;
dma_addr_t cmdbuf_phy;
void *cmdbuf_virt;
- unsigned int *src_mmu_pages;
- unsigned int *dst_mmu_pages;
};
+struct rga_addr_offset {
+ unsigned int y_off;
+ unsigned int u_off;
+ unsigned int v_off;
+};
+
+struct rga_vb_buffer {
+ struct vb2_v4l2_buffer vb_buf;
+ struct list_head queue;
+
+ /* RGA MMU mapping for this buffer */
+ struct rga_dma_desc *dma_desc;
+ dma_addr_t dma_desc_pa;
+ size_t n_desc;
+
+ /* Plane offsets of this buffer into the mapping */
+ struct rga_addr_offset offset;
+};
+
+static inline struct rga_vb_buffer *vb_to_rga(struct vb2_v4l2_buffer *vb)
+{
+ return container_of(vb, struct rga_vb_buffer, vb_buf);
+}
+
struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type);
/* RGA Buffers Manage */
extern const struct vb2_ops rga_qops;
-void rga_buf_map(struct vb2_buffer *vb);
/* RGA Hardware */
static inline void rga_write(struct rockchip_rga *rga, u32 reg, u32 value)
@@ -110,6 +136,7 @@ static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask)
rga_write(rga, reg, temp);
};
-void rga_hw_start(struct rockchip_rga *rga);
+void rga_hw_start(struct rockchip_rga *rga,
+ struct rga_vb_buffer *src, struct rga_vb_buffer *dst);
#endif
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
index c6d7e01c8949..aebd3c12020b 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
@@ -1431,7 +1431,7 @@ static int rkisp1_register_capture(struct rkisp1_capture *cap)
q->ops = &rkisp1_vb2_ops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct rkisp1_buffer);
- q->min_buffers_needed = RKISP1_MIN_BUFFERS_NEEDED;
+ q->min_queued_buffers = RKISP1_MIN_BUFFERS_NEEDED;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &node->vlock;
q->dev = cap->rkisp1->dev;
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
index 1e7cea1bea5e..4b6b28c05b89 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
@@ -61,6 +61,14 @@ struct dentry;
RKISP1_CIF_ISP_EXP_END | \
RKISP1_CIF_ISP_HIST_MEASURE_RDY)
+/* IRQ lines */
+enum rkisp1_irq_line {
+ RKISP1_IRQ_ISP = 0,
+ RKISP1_IRQ_MI,
+ RKISP1_IRQ_MIPI,
+ RKISP1_NUM_IRQS,
+};
+
/* enum for the resizer pads */
enum rkisp1_rsz_pad {
RKISP1_RSZ_PAD_SINK,
@@ -417,13 +425,13 @@ struct rkisp1_debug {
unsigned long stats_error;
unsigned long stop_timeout[2];
unsigned long frame_drop[2];
+ unsigned long complete_frames;
};
/*
* struct rkisp1_device - ISP platform device
*
* @base_addr: base register address
- * @irq: the irq number
* @dev: a pointer to the struct device
* @clk_size: number of clocks
* @clks: array of clocks
@@ -441,6 +449,7 @@ struct rkisp1_debug {
* @stream_lock: serializes {start/stop}_streaming callbacks between the capture devices.
* @debug: debug params to be exposed on debugfs
* @info: version-specific ISP information
+ * @irqs: IRQ line numbers
*/
struct rkisp1_device {
void __iomem *base_addr;
@@ -461,6 +470,7 @@ struct rkisp1_device {
struct mutex stream_lock; /* serialize {start/stop}_streaming cb between capture devices */
struct rkisp1_debug debug;
const struct rkisp1_info *info;
+ int irqs[RKISP1_NUM_IRQS];
};
/*
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c
index 6e17b2817e61..b6e47e2f1b94 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c
@@ -125,8 +125,20 @@ static void rkisp1_csi_disable(struct rkisp1_csi *csi)
struct rkisp1_device *rkisp1 = csi->rkisp1;
u32 val;
- /* Mask and clear interrupts. */
+ /* Mask MIPI interrupts. */
rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, 0);
+
+ /* Flush posted writes */
+ rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC);
+
+ /*
+ * Wait until the IRQ handler has ended. The IRQ handler may get called
+ * even after this, but it will return immediately as the MIPI
+ * interrupts have been masked.
+ */
+ synchronize_irq(rkisp1->irqs[RKISP1_IRQ_MIPI]);
+
+ /* Clear MIPI interrupt status */
rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, ~0);
val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL);
@@ -242,8 +254,8 @@ static int rkisp1_csi_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index)
return -EINVAL;
- sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state,
- RKISP1_CSI_PAD_SINK);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_CSI_PAD_SINK);
code->code = sink_fmt->code;
return 0;
@@ -270,15 +282,13 @@ static int rkisp1_csi_enum_mbus_code(struct v4l2_subdev *sd,
return -EINVAL;
}
-static int rkisp1_csi_init_config(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int rkisp1_csi_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
- sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state,
- RKISP1_CSI_PAD_SINK);
- src_fmt = v4l2_subdev_get_pad_format(sd, sd_state,
- RKISP1_CSI_PAD_SRC);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SINK);
+ src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SRC);
sink_fmt->width = RKISP1_DEFAULT_WIDTH;
sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
@@ -301,7 +311,7 @@ static int rkisp1_csi_set_fmt(struct v4l2_subdev *sd,
if (fmt->pad == RKISP1_CSI_PAD_SRC)
return v4l2_subdev_get_fmt(sd, sd_state, fmt);
- sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SINK);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SINK);
sink_fmt->code = fmt->format.code;
@@ -321,7 +331,7 @@ static int rkisp1_csi_set_fmt(struct v4l2_subdev *sd,
fmt->format = *sink_fmt;
/* Propagate the format to the source pad. */
- src_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SRC);
+ src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SRC);
*src_fmt = *sink_fmt;
return 0;
@@ -374,7 +384,7 @@ static int rkisp1_csi_s_stream(struct v4l2_subdev *sd, int enable)
return -EINVAL;
sd_state = v4l2_subdev_lock_and_get_active_state(sd);
- sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state, RKISP1_CSI_PAD_SINK);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_CSI_PAD_SINK);
format = rkisp1_mbus_info_get_by_code(sink_fmt->code);
v4l2_subdev_unlock_state(sd_state);
@@ -407,7 +417,6 @@ static const struct v4l2_subdev_video_ops rkisp1_csi_video_ops = {
static const struct v4l2_subdev_pad_ops rkisp1_csi_pad_ops = {
.enum_mbus_code = rkisp1_csi_enum_mbus_code,
- .init_cfg = rkisp1_csi_init_config,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = rkisp1_csi_set_fmt,
};
@@ -417,6 +426,10 @@ static const struct v4l2_subdev_ops rkisp1_csi_ops = {
.pad = &rkisp1_csi_pad_ops,
};
+static const struct v4l2_subdev_internal_ops rkisp1_csi_internal_ops = {
+ .init_state = rkisp1_csi_init_state,
+};
+
int rkisp1_csi_register(struct rkisp1_device *rkisp1)
{
struct rkisp1_csi *csi = &rkisp1->csi;
@@ -428,6 +441,7 @@ int rkisp1_csi_register(struct rkisp1_device *rkisp1)
sd = &csi->sd;
v4l2_subdev_init(sd, &rkisp1_csi_ops);
+ sd->internal_ops = &rkisp1_csi_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->entity.ops = &rkisp1_csi_media_ops;
sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c
index 71df3dc95e6f..79cda589d935 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c
@@ -92,6 +92,10 @@ static int rkisp1_debug_dump_isp_regs_show(struct seq_file *m, void *p)
RKISP1_DEBUG_REG(ISP_FLAGS_SHD),
RKISP1_DEBUG_REG(ISP_RIS),
RKISP1_DEBUG_REG(ISP_ERR),
+ RKISP1_DEBUG_SHD_REG(ISP_IS_H_OFFS),
+ RKISP1_DEBUG_SHD_REG(ISP_IS_V_OFFS),
+ RKISP1_DEBUG_SHD_REG(ISP_IS_H_SIZE),
+ RKISP1_DEBUG_SHD_REG(ISP_IS_V_SIZE),
{ /* Sentinel */ },
};
struct rkisp1_device *rkisp1 = m->private;
@@ -217,6 +221,8 @@ void rkisp1_debug_init(struct rkisp1_device *rkisp1)
&debug->frame_drop[RKISP1_MAINPATH]);
debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir,
&debug->frame_drop[RKISP1_SELFPATH]);
+ debugfs_create_ulong("complete_frames", 0444, debug->debugfs_dir,
+ &debug->complete_frames);
debugfs_create_file("input_status", 0444, debug->debugfs_dir, rkisp1,
&rkisp1_debug_input_status_fops);
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
index c41abd2833f1..f96f821a7b50 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
@@ -114,6 +114,7 @@
struct rkisp1_isr_data {
const char *name;
irqreturn_t (*isr)(int irq, void *ctx);
+ u32 line_mask;
};
/* ----------------------------------------------------------------------------
@@ -442,17 +443,25 @@ error:
static irqreturn_t rkisp1_isr(int irq, void *ctx)
{
+ irqreturn_t ret = IRQ_NONE;
+
/*
* Call rkisp1_capture_isr() first to handle the frame that
* potentially completed using the current frame_sequence number before
* it is potentially incremented by rkisp1_isp_isr() in the vertical
* sync.
*/
- rkisp1_capture_isr(irq, ctx);
- rkisp1_isp_isr(irq, ctx);
- rkisp1_csi_isr(irq, ctx);
- return IRQ_HANDLED;
+ if (rkisp1_capture_isr(irq, ctx) == IRQ_HANDLED)
+ ret = IRQ_HANDLED;
+
+ if (rkisp1_isp_isr(irq, ctx) == IRQ_HANDLED)
+ ret = IRQ_HANDLED;
+
+ if (rkisp1_csi_isr(irq, ctx) == IRQ_HANDLED)
+ ret = IRQ_HANDLED;
+
+ return ret;
}
static const char * const px30_isp_clks[] = {
@@ -463,9 +472,9 @@ static const char * const px30_isp_clks[] = {
};
static const struct rkisp1_isr_data px30_isp_isrs[] = {
- { "isp", rkisp1_isp_isr },
- { "mi", rkisp1_capture_isr },
- { "mipi", rkisp1_csi_isr },
+ { "isp", rkisp1_isp_isr, BIT(RKISP1_IRQ_ISP) },
+ { "mi", rkisp1_capture_isr, BIT(RKISP1_IRQ_MI) },
+ { "mipi", rkisp1_csi_isr, BIT(RKISP1_IRQ_MIPI) },
};
static const struct rkisp1_info px30_isp_info = {
@@ -484,7 +493,7 @@ static const char * const rk3399_isp_clks[] = {
};
static const struct rkisp1_isr_data rk3399_isp_isrs[] = {
- { NULL, rkisp1_isr },
+ { NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) | BIT(RKISP1_IRQ_MIPI) },
};
static const struct rkisp1_info rk3399_isp_info = {
@@ -535,6 +544,9 @@ static int rkisp1_probe(struct platform_device *pdev)
if (IS_ERR(rkisp1->base_addr))
return PTR_ERR(rkisp1->base_addr);
+ for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il)
+ rkisp1->irqs[il] = -1;
+
for (i = 0; i < info->isr_size; i++) {
irq = info->isrs[i].name
? platform_get_irq_byname(pdev, info->isrs[i].name)
@@ -542,7 +554,12 @@ static int rkisp1_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED,
+ for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) {
+ if (info->isrs[i].line_mask & BIT(il))
+ rkisp1->irqs[il] = irq;
+ }
+
+ ret = devm_request_irq(dev, irq, info->isrs[i].isr, 0,
dev_driver_string(dev), dev);
if (ret) {
dev_err(dev, "request irq failed: %d\n", ret);
@@ -582,7 +599,7 @@ static int rkisp1_probe(struct platform_device *pdev)
ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev);
if (ret)
- goto err_pm_runtime_disable;
+ goto err_media_dev_cleanup;
ret = media_device_register(&rkisp1->media_dev);
if (ret) {
@@ -617,6 +634,8 @@ err_unreg_media_dev:
media_device_unregister(&rkisp1->media_dev);
err_unreg_v4l2_dev:
v4l2_device_unregister(&rkisp1->v4l2_dev);
+err_media_dev_cleanup:
+ media_device_cleanup(&rkisp1->media_dev);
err_pm_runtime_disable:
pm_runtime_disable(&pdev->dev);
return ret;
@@ -637,6 +656,8 @@ static void rkisp1_remove(struct platform_device *pdev)
media_device_unregister(&rkisp1->media_dev);
v4l2_device_unregister(&rkisp1->v4l2_dev);
+ media_device_cleanup(&rkisp1->media_dev);
+
pm_runtime_disable(&pdev->dev);
}
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
index 88ca8b2283b7..f00873d31c42 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
@@ -66,8 +66,8 @@ static void rkisp1_config_ism(struct rkisp1_isp *isp,
struct v4l2_subdev_state *sd_state)
{
const struct v4l2_rect *src_crop =
- v4l2_subdev_get_pad_crop(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
+ v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
struct rkisp1_device *rkisp1 = isp->rkisp1;
u32 val;
@@ -102,12 +102,12 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp,
const struct v4l2_mbus_framefmt *sink_frm;
const struct v4l2_rect *sink_crop;
- sink_frm = v4l2_subdev_get_pad_format(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
- sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
- src_frm = v4l2_subdev_get_pad_format(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
+ sink_frm = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
+ src_frm = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
sink_fmt = rkisp1_mbus_info_get_by_code(sink_frm->code);
src_fmt = rkisp1_mbus_info_get_by_code(src_frm->code);
@@ -201,8 +201,8 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp,
} else {
struct v4l2_mbus_framefmt *src_frm;
- src_frm = v4l2_subdev_get_pad_format(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
+ src_frm = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
rkisp1_params_pre_configure(&rkisp1->params, sink_fmt->bayer_pat,
src_frm->quantization,
src_frm->ycbcr_enc);
@@ -254,11 +254,25 @@ static void rkisp1_isp_stop(struct rkisp1_isp *isp)
* ISP(mi) stop in mi frame end -> Stop ISP(mipi) ->
* Stop ISP(isp) ->wait for ISP isp off
*/
- /* stop and clear MI and ISP interrupts */
- rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, 0);
- rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, ~0);
+ /* Mask MI and ISP interrupts */
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, 0);
rkisp1_write(rkisp1, RKISP1_CIF_MI_IMSC, 0);
+
+ /* Flush posted writes */
+ rkisp1_read(rkisp1, RKISP1_CIF_MI_IMSC);
+
+ /*
+ * Wait until the IRQ handler has ended. The IRQ handler may get called
+ * even after this, but it will return immediately as the MI and ISP
+ * interrupts have been masked.
+ */
+ synchronize_irq(rkisp1->irqs[RKISP1_IRQ_ISP]);
+ if (rkisp1->irqs[RKISP1_IRQ_ISP] != rkisp1->irqs[RKISP1_IRQ_MI])
+ synchronize_irq(rkisp1->irqs[RKISP1_IRQ_MI]);
+
+ /* Clear MI and ISP interrupt status */
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, ~0);
rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, ~0);
/* stop ISP */
@@ -318,8 +332,8 @@ static void rkisp1_isp_start(struct rkisp1_isp *isp,
RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE;
rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val);
- src_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
+ src_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
src_info = rkisp1_mbus_info_get_by_code(src_fmt->code);
if (src_info->pixel_enc != V4L2_PIXEL_ENC_BAYER)
@@ -409,15 +423,15 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-static int rkisp1_isp_init_config(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int rkisp1_isp_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
struct v4l2_rect *sink_crop, *src_crop;
/* Video. */
- sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
sink_fmt->width = RKISP1_DEFAULT_WIDTH;
sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
sink_fmt->field = V4L2_FIELD_NONE;
@@ -427,15 +441,15 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd,
sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
- sink_crop = v4l2_subdev_get_pad_crop(sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
sink_crop->width = RKISP1_DEFAULT_WIDTH;
sink_crop->height = RKISP1_DEFAULT_HEIGHT;
sink_crop->left = 0;
sink_crop->top = 0;
- src_fmt = v4l2_subdev_get_pad_format(sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
+ src_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
*src_fmt = *sink_fmt;
src_fmt->code = RKISP1_DEF_SRC_PAD_FMT;
src_fmt->colorspace = V4L2_COLORSPACE_SRGB;
@@ -443,15 +457,15 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd,
src_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE;
- src_crop = v4l2_subdev_get_pad_crop(sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
+ src_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
*src_crop = *sink_crop;
/* Parameters and statistics. */
- sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state,
- RKISP1_ISP_PAD_SINK_PARAMS);
- src_fmt = v4l2_subdev_get_pad_format(sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_STATS);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SINK_PARAMS);
+ src_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_STATS);
sink_fmt->width = 0;
sink_fmt->height = 0;
sink_fmt->field = V4L2_FIELD_NONE;
@@ -472,12 +486,12 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
const struct v4l2_rect *src_crop;
bool set_csc;
- sink_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
- src_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
- src_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
+ src_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
+ src_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
/*
* Media bus code. The ISP can operate in pass-through mode (Bayer in,
@@ -570,10 +584,10 @@ static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp,
const struct v4l2_rect *sink_crop;
struct v4l2_rect *src_crop;
- src_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
- sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
+ src_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
src_crop->left = ALIGN(r->left, 2);
src_crop->width = ALIGN(r->width, 2);
@@ -584,8 +598,8 @@ static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp,
*r = *src_crop;
/* Propagate to out format */
- src_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
+ src_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
rkisp1_isp_set_src_fmt(isp, sd_state, src_fmt);
}
@@ -596,10 +610,10 @@ static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp,
struct v4l2_rect *sink_crop, *src_crop;
const struct v4l2_mbus_framefmt *sink_fmt;
- sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
- sink_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
sink_crop->left = ALIGN(r->left, 2);
sink_crop->width = ALIGN(r->width, 2);
@@ -610,8 +624,8 @@ static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp,
*r = *sink_crop;
/* Propagate to out crop */
- src_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SOURCE_VIDEO);
+ src_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SOURCE_VIDEO);
rkisp1_isp_set_src_crop(isp, sd_state, src_crop);
}
@@ -624,8 +638,8 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
struct v4l2_rect *sink_crop;
bool is_yuv;
- sink_fmt = v4l2_subdev_get_pad_format(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
sink_fmt->code = format->code;
mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) {
@@ -673,8 +687,8 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
*format = *sink_fmt;
/* Propagate to in crop */
- sink_crop = v4l2_subdev_get_pad_crop(&isp->sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
rkisp1_isp_set_sink_crop(isp, sd_state, sink_crop);
}
@@ -689,7 +703,8 @@ static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd,
else if (fmt->pad == RKISP1_ISP_PAD_SOURCE_VIDEO)
rkisp1_isp_set_src_fmt(isp, sd_state, &fmt->format);
else
- fmt->format = *v4l2_subdev_get_pad_format(sd, sd_state, fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(sd_state,
+ fmt->pad);
return 0;
}
@@ -709,19 +724,19 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd,
if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_pad_format(sd, sd_state, sel->pad);
+ fmt = v4l2_subdev_state_get_format(sd_state, sel->pad);
sel->r.height = fmt->height;
sel->r.width = fmt->width;
sel->r.left = 0;
sel->r.top = 0;
} else {
- sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state,
- RKISP1_ISP_PAD_SINK_VIDEO);
+ sel->r = *v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_ISP_PAD_SINK_VIDEO);
}
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, sel->pad);
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad);
break;
default:
@@ -768,7 +783,6 @@ static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = {
.enum_frame_size = rkisp1_isp_enum_frame_size,
.get_selection = rkisp1_isp_get_selection,
.set_selection = rkisp1_isp_set_selection,
- .init_cfg = rkisp1_isp_init_config,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = rkisp1_isp_set_fmt,
.link_validate = v4l2_subdev_link_validate_default,
@@ -879,6 +893,10 @@ static const struct v4l2_subdev_ops rkisp1_isp_ops = {
.pad = &rkisp1_isp_pad_ops,
};
+static const struct v4l2_subdev_internal_ops rkisp1_isp_internal_ops = {
+ .init_state = rkisp1_isp_init_state,
+};
+
int rkisp1_isp_register(struct rkisp1_device *rkisp1)
{
struct rkisp1_isp *isp = &rkisp1->isp;
@@ -889,6 +907,7 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1)
isp->rkisp1 = rkisp1;
v4l2_subdev_init(sd, &rkisp1_isp_ops);
+ sd->internal_ops = &rkisp1_isp_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
sd->entity.ops = &rkisp1_isp_media_ops;
sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
@@ -933,6 +952,7 @@ void rkisp1_isp_unregister(struct rkisp1_device *rkisp1)
return;
v4l2_device_unregister_subdev(&isp->sd);
+ v4l2_subdev_cleanup(&isp->sd);
media_entity_cleanup(&isp->sd.entity);
}
@@ -989,6 +1009,8 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx)
if (status & RKISP1_CIF_ISP_FRAME) {
u32 isp_ris;
+ rkisp1->debug.complete_frames++;
+
/* New frame from the sensor received */
isp_ris = rkisp1_read(rkisp1, RKISP1_CIF_ISP_RIS);
if (isp_ris & RKISP1_STATS_MEAS_MASK)
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
index 350f452e676f..bea69a0d766a 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
@@ -172,12 +172,9 @@
#define RKISP1_CIF_MI_FRAME(stream) BIT((stream)->id)
#define RKISP1_CIF_MI_MBLK_LINE BIT(2)
#define RKISP1_CIF_MI_FILL_MP_Y BIT(3)
-#define RKISP1_CIF_MI_WRAP_MP_Y BIT(4)
-#define RKISP1_CIF_MI_WRAP_MP_CB BIT(5)
-#define RKISP1_CIF_MI_WRAP_MP_CR BIT(6)
-#define RKISP1_CIF_MI_WRAP_SP_Y BIT(7)
-#define RKISP1_CIF_MI_WRAP_SP_CB BIT(8)
-#define RKISP1_CIF_MI_WRAP_SP_CR BIT(9)
+#define RKISP1_CIF_MI_WRAP_Y(stream) BIT(4 + (stream)->id * 3)
+#define RKISP1_CIF_MI_WRAP_CB(stream) BIT(5 + (stream)->id * 3)
+#define RKISP1_CIF_MI_WRAP_CR(stream) BIT(6 + (stream)->id * 3)
#define RKISP1_CIF_MI_DMA_READY BIT(11)
/* MI_STATUS */
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
index 28ecc7347d54..a8e377701302 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
@@ -142,10 +142,8 @@ static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz,
struct v4l2_rect *sink_crop;
u32 dc_ctrl;
- sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
- sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
if (sink_crop->width == sink_fmt->width &&
sink_crop->height == sink_fmt->height &&
@@ -275,10 +273,8 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz,
struct v4l2_area src_y, src_c;
struct v4l2_rect sink_c;
- sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
- src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state,
- RKISP1_RSZ_PAD_SRC);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
+ src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SRC);
sink_yuv_info = rkisp1_rsz_get_yuv_mbus_info(sink_fmt->code);
src_yuv_info = rkisp1_rsz_get_yuv_mbus_info(src_fmt->code);
@@ -292,8 +288,7 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz,
return;
}
- sink_y = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
+ sink_y = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK);
sink_c.width = sink_y->width / sink_yuv_info->hdiv;
sink_c.height = sink_y->height / sink_yuv_info->vdiv;
@@ -335,12 +330,8 @@ static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd,
{
struct rkisp1_resizer *rsz =
container_of(sd, struct rkisp1_resizer, sd);
- struct v4l2_subdev_pad_config dummy_cfg;
- struct v4l2_subdev_state pad_state = {
- .pads = &dummy_cfg
- };
- u32 pad = code->pad;
- int ret;
+ unsigned int index = code->index;
+ unsigned int i;
if (code->pad == RKISP1_RSZ_PAD_SRC) {
/* supported mbus codes on the src are the same as in the capture */
@@ -360,25 +351,38 @@ static int rkisp1_rsz_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
- /* supported mbus codes on the sink pad are the same as isp src pad */
- code->pad = RKISP1_ISP_PAD_SOURCE_VIDEO;
- ret = v4l2_subdev_call(&rsz->rkisp1->isp.sd, pad, enum_mbus_code,
- &pad_state, code);
+ /*
+ * Supported mbus codes on the sink pad are the same as on the ISP
+ * source pad.
+ */
+ for (i = 0; ; i++) {
+ const struct rkisp1_mbus_info *fmt =
+ rkisp1_mbus_info_get_by_index(i);
+
+ if (!fmt)
+ break;
- /* restore pad */
- code->pad = pad;
- code->flags = 0;
- return ret;
+ if (!(fmt->direction & RKISP1_ISP_SD_SRC))
+ continue;
+
+ if (!index) {
+ code->code = fmt->mbus_code;
+ return 0;
+ }
+
+ index--;
+ }
+
+ return -EINVAL;
}
-static int rkisp1_rsz_init_config(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int rkisp1_rsz_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
struct v4l2_rect *sink_crop;
- sink_fmt = v4l2_subdev_get_pad_format(sd, sd_state,
- RKISP1_RSZ_PAD_SRC);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SRC);
sink_fmt->width = RKISP1_DEFAULT_WIDTH;
sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
sink_fmt->field = V4L2_FIELD_NONE;
@@ -388,15 +392,13 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd,
sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
sink_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE;
- sink_crop = v4l2_subdev_get_try_crop(sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK);
sink_crop->width = RKISP1_DEFAULT_WIDTH;
sink_crop->height = RKISP1_DEFAULT_HEIGHT;
sink_crop->left = 0;
sink_crop->top = 0;
- src_fmt = v4l2_subdev_get_pad_format(sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
+ src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
*src_fmt = *sink_fmt;
/* NOTE: there is no crop in the source pad, only in the sink */
@@ -411,10 +413,8 @@ static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz,
const struct rkisp1_mbus_info *sink_mbus_info;
struct v4l2_mbus_framefmt *src_fmt, *sink_fmt;
- sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
- src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state,
- RKISP1_RSZ_PAD_SRC);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
+ src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SRC);
sink_mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
@@ -441,10 +441,8 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz,
struct v4l2_mbus_framefmt *sink_fmt;
struct v4l2_rect *sink_crop;
- sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
- sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK);
/* Not crop for MP bayer raw data */
mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
@@ -478,12 +476,9 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz,
struct v4l2_rect *sink_crop;
bool is_yuv;
- sink_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
- src_fmt = v4l2_subdev_get_pad_format(&rsz->sd, sd_state,
- RKISP1_RSZ_PAD_SRC);
- sink_crop = v4l2_subdev_get_pad_crop(&rsz->sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK);
+ src_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SRC);
+ sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK);
if (rsz->id == RKISP1_SELFPATH)
sink_fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
@@ -573,8 +568,8 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
- mf_sink = v4l2_subdev_get_pad_format(sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
+ mf_sink = v4l2_subdev_state_get_format(sd_state,
+ RKISP1_RSZ_PAD_SINK);
sel->r.height = mf_sink->height;
sel->r.width = mf_sink->width;
sel->r.left = 0;
@@ -582,8 +577,8 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state,
- RKISP1_RSZ_PAD_SINK);
+ sel->r = *v4l2_subdev_state_get_crop(sd_state,
+ RKISP1_RSZ_PAD_SINK);
break;
default:
@@ -620,7 +615,6 @@ static const struct v4l2_subdev_pad_ops rkisp1_rsz_pad_ops = {
.enum_mbus_code = rkisp1_rsz_enum_mbus_code,
.get_selection = rkisp1_rsz_get_selection,
.set_selection = rkisp1_rsz_set_selection,
- .init_cfg = rkisp1_rsz_init_config,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = rkisp1_rsz_set_fmt,
.link_validate = v4l2_subdev_link_validate_default,
@@ -667,6 +661,10 @@ static const struct v4l2_subdev_ops rkisp1_rsz_ops = {
.pad = &rkisp1_rsz_pad_ops,
};
+static const struct v4l2_subdev_internal_ops rkisp1_rsz_internal_ops = {
+ .init_state = rkisp1_rsz_init_state,
+};
+
static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz)
{
if (!rsz->rkisp1)
@@ -696,6 +694,7 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz)
}
v4l2_subdev_init(sd, &rkisp1_rsz_ops);
+ sd->internal_ops = &rkisp1_rsz_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->entity.ops = &rkisp1_rsz_media_ops;
sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h
index 1ea5fa1bf3c8..b9777e07fb6d 100644
--- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h
+++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h
@@ -26,7 +26,6 @@
#include "gsc-regs.h"
-#define CONFIG_VB2_GSC_DMA_CONTIG 1
#define GSC_MODULE_NAME "exynos-gsc"
#define GSC_SHUTDOWN_TIMEOUT ((100*HZ)/1000)
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c
index a0d43bf892e6..05cafba1c728 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c
@@ -1479,7 +1479,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *mf;
return 0;
}
@@ -1534,7 +1534,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
mf->colorspace = V4L2_COLORSPACE_JPEG;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*mf = fmt->format;
return 0;
}
@@ -1604,10 +1604,10 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
return 0;
case V4L2_SEL_TGT_CROP:
- try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
+ try_sel = v4l2_subdev_state_get_crop(sd_state, sel->pad);
break;
case V4L2_SEL_TGT_COMPOSE:
- try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad);
+ try_sel = v4l2_subdev_state_get_compose(sd_state, sel->pad);
f = &ctx->d_frame;
break;
default:
@@ -1651,10 +1651,10 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
+ try_sel = v4l2_subdev_state_get_crop(sd_state, sel->pad);
break;
case V4L2_SEL_TGT_COMPOSE:
- try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad);
+ try_sel = v4l2_subdev_state_get_compose(sd_state, sel->pad);
f = &ctx->d_frame;
break;
default:
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-core.c b/drivers/media/platform/samsung/exynos4-is/fimc-core.c
index 97908778e1c8..0be687b01ce5 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-core.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-core.c
@@ -814,7 +814,7 @@ err:
fimc_clk_put(fimc);
dev_err(&fimc->pdev->dev, "failed to get clock: %s\n",
fimc_clocks[i]);
- return -ENXIO;
+ return ret;
}
#ifdef CONFIG_PM
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c
index bef6e9b4a25e..44363c4241d5 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c
@@ -57,7 +57,6 @@ static int fimc_is_i2c_probe(struct platform_device *pdev)
strscpy(i2c_adap->name, "exynos4x12-isp-i2c", sizeof(i2c_adap->name));
i2c_adap->owner = THIS_MODULE;
i2c_adap->algo = &fimc_is_i2c_algorithm;
- i2c_adap->class = I2C_CLASS_SPD;
platform_set_drvdata(pdev, isp_i2c);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp.c b/drivers/media/platform/samsung/exynos4-is/fimc-isp.c
index b85986e50f46..3c5d7bee2655 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp.c
@@ -126,7 +126,7 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf = &fmt->format;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- *mf = *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ *mf = *v4l2_subdev_state_get_format(sd_state, fmt->pad);
return 0;
}
@@ -172,9 +172,8 @@ static void __isp_subdev_try_format(struct fimc_isp *isp,
mf->code = MEDIA_BUS_FMT_SGRBG10_1X10;
} else {
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- format = v4l2_subdev_get_try_format(&isp->subdev,
- sd_state,
- FIMC_ISP_SD_PAD_SINK);
+ format = v4l2_subdev_state_get_format(sd_state,
+ FIMC_ISP_SD_PAD_SINK);
else
format = &isp->sink_fmt;
@@ -207,7 +206,7 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
__isp_subdev_try_format(isp, sd_state, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*mf = fmt->format;
/* Propagate format to the source pads */
@@ -220,8 +219,8 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
format.pad = pad;
__isp_subdev_try_format(isp, sd_state,
&format);
- mf = v4l2_subdev_get_try_format(sd, sd_state,
- pad);
+ mf = v4l2_subdev_state_get_format(sd_state,
+ pad);
*mf = format.format;
}
}
@@ -374,18 +373,17 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd,
.field = V4L2_FIELD_NONE,
};
- format = v4l2_subdev_get_try_format(sd, fh->state,
- FIMC_ISP_SD_PAD_SINK);
+ format = v4l2_subdev_state_get_format(fh->state, FIMC_ISP_SD_PAD_SINK);
*format = fmt;
- format = v4l2_subdev_get_try_format(sd, fh->state,
- FIMC_ISP_SD_PAD_SRC_FIFO);
+ format = v4l2_subdev_state_get_format(fh->state,
+ FIMC_ISP_SD_PAD_SRC_FIFO);
fmt.width = DEFAULT_PREVIEW_STILL_WIDTH;
fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT;
*format = fmt;
- format = v4l2_subdev_get_try_format(sd, fh->state,
- FIMC_ISP_SD_PAD_SRC_DMA);
+ format = v4l2_subdev_state_get_format(fh->state,
+ FIMC_ISP_SD_PAD_SRC_DMA);
*format = fmt;
return 0;
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
index 9396b10b5b1c..7898c9bebb04 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
@@ -574,16 +574,14 @@ static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc,
struct v4l2_rect *rect;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sink_fmt = v4l2_subdev_get_try_format(&fimc->subdev,
- sd_state,
- FLITE_SD_PAD_SINK);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state,
+ FLITE_SD_PAD_SINK);
mf->code = sink_fmt->code;
mf->colorspace = sink_fmt->colorspace;
- rect = v4l2_subdev_get_try_crop(&fimc->subdev,
- sd_state,
- FLITE_SD_PAD_SINK);
+ rect = v4l2_subdev_state_get_crop(sd_state,
+ FLITE_SD_PAD_SINK);
} else {
mf->code = sink->fmt->mbus_code;
mf->colorspace = sink->fmt->colorspace;
@@ -1021,7 +1019,7 @@ static struct v4l2_mbus_framefmt *__fimc_lite_subdev_get_try_fmt(
if (pad != FLITE_SD_PAD_SINK)
pad = FLITE_SD_PAD_SOURCE_DMA;
- return v4l2_subdev_get_try_format(sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
}
static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
@@ -1129,7 +1127,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- sel->r = *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad);
return 0;
}
@@ -1166,7 +1164,7 @@ static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
fimc_lite_try_crop(fimc, &sel->r);
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad) = sel->r;
+ *v4l2_subdev_state_get_crop(sd_state, sel->pad) = sel->r;
} else {
unsigned long flags;
spin_lock_irqsave(&fimc->slock, flags);
diff --git a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c
index 686ca8753ba2..aae8a8b2c0f4 100644
--- a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c
@@ -569,8 +569,7 @@ static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return sd_state ? v4l2_subdev_get_try_format(&state->sd,
- sd_state, 0) : NULL;
+ return sd_state ? v4l2_subdev_state_get_format(sd_state, 0) : NULL;
return &state->format;
}
diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c
index 0f5b3845d7b9..be58260ea67e 100644
--- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c
@@ -1216,7 +1216,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf = &fmt->format;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
fmt->format = *mf;
return 0;
}
@@ -1305,7 +1305,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
__camif_subdev_try_format(camif, mf, fmt->pad);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*mf = fmt->format;
mutex_unlock(&camif->lock);
return 0;
@@ -1357,7 +1357,7 @@ static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd,
return -EINVAL;
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- sel->r = *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad);
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad);
return 0;
}
@@ -1445,7 +1445,7 @@ static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd,
__camif_try_crop(camif, &sel->r);
if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
- *v4l2_subdev_get_try_crop(sd, sd_state, sel->pad) = sel->r;
+ *v4l2_subdev_state_get_crop(sd_state, sel->pad) = sel->r;
} else {
unsigned long flags;
unsigned int i;
diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
new file mode 100644
index 000000000000..24e669d8ea29
--- /dev/null
+++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v12.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Register definition file for Samsung MFC V12.x Interface (FIMV) driver
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ */
+
+#ifndef _REGS_MFC_V12_H
+#define _REGS_MFC_V12_H
+
+#include <linux/sizes.h>
+#include "regs-mfc-v10.h"
+
+/* MFCv12 Context buffer sizes */
+#define MFC_CTX_BUF_SIZE_V12 (30 * SZ_1K)
+#define MFC_H264_DEC_CTX_BUF_SIZE_V12 (2 * SZ_1M)
+#define MFC_OTHER_DEC_CTX_BUF_SIZE_V12 (30 * SZ_1K)
+#define MFC_H264_ENC_CTX_BUF_SIZE_V12 (100 * SZ_1K)
+#define MFC_HEVC_ENC_CTX_BUF_SIZE_V12 (40 * SZ_1K)
+#define MFC_OTHER_ENC_CTX_BUF_SIZE_V12 (25 * SZ_1K)
+
+/* MFCv12 variant defines */
+#define MAX_FW_SIZE_V12 (SZ_1M)
+#define MAX_CPB_SIZE_V12 (7 * SZ_1M)
+#define MFC_VERSION_V12 0xC0
+#define MFC_NUM_PORTS_V12 1
+#define S5P_FIMV_CODEC_VP9_ENC 27
+#define MFC_CHROMA_PAD_BYTES_V12 256
+#define S5P_FIMV_D_ALIGN_PLANE_SIZE_V12 256
+
+/* Encoder buffer size for MFCv12 */
+#define ENC_V120_BASE_SIZE(x, y) \
+ ((((x) + 3) * ((y) + 3) * 8) \
+ + ((((y) * 64) + 2304) * ((x) + 7) / 8))
+
+#define ENC_V120_H264_ME_SIZE(x, y) \
+ ALIGN((ENC_V120_BASE_SIZE(x, y) \
+ + (DIV_ROUND_UP((x) * (y), 64) * 32)), 256)
+
+#define ENC_V120_MPEG4_ME_SIZE(x, y) \
+ ALIGN((ENC_V120_BASE_SIZE(x, y) \
+ + (DIV_ROUND_UP((x) * (y), 128) * 16)), 256)
+
+#define ENC_V120_VP8_ME_SIZE(x, y) \
+ ALIGN(ENC_V120_BASE_SIZE((x), (y)), 256)
+
+#define ENC_V120_HEVC_ME_SIZE(x, y) \
+ ALIGN(((((x) + 3) * ((y) + 3) * 32) \
+ + ((((y) * 128) + 2304) * ((x) + 3) / 4)), 256)
+
+#endif /*_REGS_MFC_V12_H*/
diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
index 4a7adfdaa359..50f9bf0603c1 100644
--- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
+++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h
@@ -24,6 +24,7 @@
#define S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7 0xfa70
#define S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7 0xfa74
+#define S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR_V7 0xfa78
#define S5P_FIMV_E_VP8_OPTIONS_V7 0xfdb0
#define S5P_FIMV_E_VP8_FILTER_OPTIONS_V7 0xfdb4
diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
index 162e3c7e920f..0ef9eb2dff22 100644
--- a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
+++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h
@@ -17,13 +17,16 @@
#define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8 0xf108
#define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8 0xf144
#define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8 0xf148
+#define S5P_FIMV_D_THIRD_PLANE_DPB_SIZE_V8 0xf14C
#define S5P_FIMV_D_MV_BUFFER_SIZE_V8 0xf150
#define S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8 0xf138
#define S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8 0xf13c
+#define S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE_V8 0xf140
#define S5P_FIMV_D_FIRST_PLANE_DPB_V8 0xf160
#define S5P_FIMV_D_SECOND_PLANE_DPB_V8 0xf260
+#define S5P_FIMV_D_THIRD_PLANE_DPB_V8 0xf360
#define S5P_FIMV_D_MV_BUFFER_V8 0xf460
#define S5P_FIMV_D_NUM_MV_V8 0xf134
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
index e30e54935d79..fbb047eadf5a 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
@@ -604,6 +604,8 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
s5p_mfc_clock_off();
wake_up(&ctx->queue);
+ if (ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
+ set_work_bit_irqsave(ctx);
s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
} else {
WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
@@ -790,6 +792,8 @@ static int s5p_mfc_open(struct file *file)
INIT_LIST_HEAD(&ctx->dst_queue);
ctx->src_queue_cnt = 0;
ctx->dst_queue_cnt = 0;
+ ctx->is_422 = 0;
+ ctx->is_10bit = 0;
/* Get context number */
ctx->num = 0;
while (dev->ctx[ctx->num]) {
@@ -863,7 +867,7 @@ static int s5p_mfc_open(struct file *file)
q->io_modes = VB2_MMAP;
q->ops = get_dec_queue_ops();
} else if (vdev == dev->vfd_enc) {
- q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
q->ops = get_enc_queue_ops();
} else {
ret = -ENOENT;
@@ -890,7 +894,7 @@ static int s5p_mfc_open(struct file *file)
q->io_modes = VB2_MMAP;
q->ops = get_dec_queue_ops();
} else if (vdev == dev->vfd_enc) {
- q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
q->ops = get_enc_queue_ops();
} else {
ret = -ENOENT;
@@ -1660,6 +1664,31 @@ static struct s5p_mfc_variant mfc_drvdata_v10 = {
.fw_name[0] = "s5p-mfc-v10.fw",
};
+static struct s5p_mfc_buf_size_v6 mfc_buf_size_v12 = {
+ .dev_ctx = MFC_CTX_BUF_SIZE_V12,
+ .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V12,
+ .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V12,
+ .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V12,
+ .hevc_enc_ctx = MFC_HEVC_ENC_CTX_BUF_SIZE_V12,
+ .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V12,
+};
+
+static struct s5p_mfc_buf_size buf_size_v12 = {
+ .fw = MAX_FW_SIZE_V12,
+ .cpb = MAX_CPB_SIZE_V12,
+ .priv = &mfc_buf_size_v12,
+};
+
+static struct s5p_mfc_variant mfc_drvdata_v12 = {
+ .version = MFC_VERSION_V12,
+ .version_bit = MFC_V12_BIT,
+ .port_num = MFC_NUM_PORTS_V12,
+ .buf_size = &buf_size_v12,
+ .fw_name[0] = "s5p-mfc-v12.fw",
+ .clk_names = {"mfc"},
+ .num_clocks = 1,
+};
+
static const struct of_device_id exynos_mfc_match[] = {
{
.compatible = "samsung,mfc-v5",
@@ -1682,6 +1711,9 @@ static const struct of_device_id exynos_mfc_match[] = {
}, {
.compatible = "samsung,mfc-v10",
.data = &mfc_drvdata_v10,
+ }, {
+ .compatible = "tesla,fsd-mfc",
+ .data = &mfc_drvdata_v12,
},
{},
};
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
index 5304f42c8c72..59450b324f7d 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h
@@ -19,7 +19,7 @@
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>
#include "regs-mfc.h"
-#include "regs-mfc-v10.h"
+#include "regs-mfc-v12.h"
#define S5P_MFC_NAME "s5p-mfc"
@@ -56,6 +56,7 @@
#define MFC_NO_INSTANCE_SET -1
#define MFC_ENC_CAP_PLANE_COUNT 1
#define MFC_ENC_OUT_PLANE_COUNT 2
+#define VB2_MAX_PLANE_COUNT 3
#define STUFF_BYTE 4
#define MFC_MAX_CTRLS 128
@@ -181,6 +182,7 @@ struct s5p_mfc_buf {
struct {
size_t luma;
size_t chroma;
+ size_t chroma_1;
} raw;
size_t stream;
} cookie;
@@ -621,6 +623,10 @@ struct s5p_mfc_codec_ops {
* v4l2 control framework
* @ctrl_handler: handler for v4l2 framework
* @scratch_buf_size: scratch buffer size
+ * @is_10bit: state to check 10bit support
+ * @is_422: state to check YUV422 10bit format
+ * @chroma_size_1: size of a chroma third plane
+ * @stride: size of stride for all planes
*/
struct s5p_mfc_ctx {
struct s5p_mfc_dev *dev;
@@ -657,6 +663,7 @@ struct s5p_mfc_ctx {
int luma_size;
int chroma_size;
+ int chroma_size_1;
int mv_size;
unsigned long consumed_stream;
@@ -720,6 +727,9 @@ struct s5p_mfc_ctx {
struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS];
struct v4l2_ctrl_handler ctrl_handler;
size_t scratch_buf_size;
+ int is_10bit;
+ int is_422;
+ int stride[VB2_MAX_PLANE_COUNT];
};
/*
@@ -771,22 +781,27 @@ void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq);
#define HAS_PORTNUM(dev) (dev ? (dev->variant ? \
(dev->variant->port_num ? 1 : 0) : 0) : 0)
#define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0)
-#define IS_MFCV6_PLUS(dev) (dev->variant->version >= 0x60 ? 1 : 0)
-#define IS_MFCV7_PLUS(dev) (dev->variant->version >= 0x70 ? 1 : 0)
-#define IS_MFCV8_PLUS(dev) (dev->variant->version >= 0x80 ? 1 : 0)
-#define IS_MFCV10(dev) (dev->variant->version >= 0xA0 ? 1 : 0)
-#define FW_HAS_E_MIN_SCRATCH_BUF(dev) (IS_MFCV10(dev))
+#define IS_MFCV6_PLUS(dev) ((dev)->variant->version >= 0x60)
+#define IS_MFCV7_PLUS(dev) ((dev)->variant->version >= 0x70)
+#define IS_MFCV8_PLUS(dev) ((dev)->variant->version >= 0x80)
+#define IS_MFCV10_PLUS(dev) ((dev)->variant->version >= 0xA0)
+#define IS_MFCV12(dev) ((dev)->variant->version >= 0xC0)
+#define FW_HAS_E_MIN_SCRATCH_BUF(dev) (IS_MFCV10_PLUS(dev))
#define MFC_V5_BIT BIT(0)
#define MFC_V6_BIT BIT(1)
#define MFC_V7_BIT BIT(2)
#define MFC_V8_BIT BIT(3)
#define MFC_V10_BIT BIT(5)
+#define MFC_V12_BIT BIT(7)
#define MFC_V5PLUS_BITS (MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | \
- MFC_V8_BIT | MFC_V10_BIT)
+ MFC_V8_BIT | MFC_V10_BIT | MFC_V12_BIT)
#define MFC_V6PLUS_BITS (MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT | \
- MFC_V10_BIT)
-#define MFC_V7PLUS_BITS (MFC_V7_BIT | MFC_V8_BIT | MFC_V10_BIT)
+ MFC_V10_BIT | MFC_V12_BIT)
+#define MFC_V7PLUS_BITS (MFC_V7_BIT | MFC_V8_BIT | MFC_V10_BIT | \
+ MFC_V12_BIT)
+
+#define MFC_V10PLUS_BITS (MFC_V10_BIT | MFC_V12_BIT)
#endif /* S5P_MFC_COMMON_H_ */
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c
index 6d3c92045c05..503487f34a80 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c
@@ -51,8 +51,14 @@ int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
* into kernel. */
mfc_debug_enter();
- if (dev->fw_get_done)
- return 0;
+ /* In case of MFC v12, RET_SYS_INIT response from hardware fails due to
+ * incorrect firmware transfer and therefore it is not able to initialize
+ * the hardware. This causes failed response for SYS_INIT command when
+ * MFC runs for second time. So, load the MFC v12 firmware for each run.
+ */
+ if (!IS_MFCV12(dev))
+ if (dev->fw_get_done)
+ return 0;
for (i = MFC_FW_MAX_VERSIONS - 1; i >= 0; i--) {
if (!dev->variant->fw_name[i])
@@ -130,7 +136,7 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev)
mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4));
/* check bus reset control before reset */
- if (dev->risc_on)
+ if (dev->risc_on && !IS_MFCV12(dev))
if (s5p_mfc_bus_reset(dev))
return -EIO;
/* Reset
@@ -236,7 +242,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
else
mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
- if (IS_MFCV10(dev))
+ if (IS_MFCV10_PLUS(dev))
mfc_write(dev, 0x0, S5P_FIMV_MFC_CLOCK_OFF_V10);
mfc_debug(2, "Will now wait for completion of firmware transfer\n");
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
index 268ffe4da53c..3957f28d4547 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
@@ -57,6 +57,20 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V6PLUS_BITS,
},
{
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .codec_mode = S5P_MFC_CODEC_NONE,
+ .type = MFC_FMT_RAW,
+ .num_planes = 3,
+ .versions = MFC_V12_BIT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU420M,
+ .codec_mode = S5P_MFC_CODEC_NONE,
+ .type = MFC_FMT_RAW,
+ .num_planes = 3,
+ .versions = MFC_V12_BIT
+ },
+ {
.fourcc = V4L2_PIX_FMT_H264,
.codec_mode = S5P_MFC_CODEC_H264_DEC,
.type = MFC_FMT_DEC,
@@ -146,7 +160,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_FIMV_CODEC_HEVC_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
- .versions = MFC_V10_BIT,
+ .versions = MFC_V10PLUS_BITS,
.flags = V4L2_FMT_FLAG_DYN_RESOLUTION |
V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM,
},
@@ -155,7 +169,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_FIMV_CODEC_VP9_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
- .versions = MFC_V10_BIT,
+ .versions = MFC_V10PLUS_BITS,
.flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
},
};
@@ -355,14 +369,19 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
pix_mp->width = ctx->buf_width;
pix_mp->height = ctx->buf_height;
pix_mp->field = V4L2_FIELD_NONE;
- pix_mp->num_planes = 2;
+ pix_mp->num_planes = ctx->dst_fmt->num_planes;
/* Set pixelformat to the format in which MFC
outputs the decoded frame */
pix_mp->pixelformat = ctx->dst_fmt->fourcc;
- pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+ pix_mp->plane_fmt[0].bytesperline = ctx->stride[0];
pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
- pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+ pix_mp->plane_fmt[1].bytesperline = ctx->stride[1];
pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M) {
+ pix_mp->plane_fmt[2].bytesperline = ctx->stride[2];
+ pix_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
+ }
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
/* This is run on OUTPUT
The buffer contains compressed image
@@ -920,6 +939,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct v4l2_format_info *format;
/* Video output for decoding (source)
* this can be set after getting an instance */
@@ -936,7 +956,13 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
} else if (ctx->state == MFCINST_HEAD_PARSED &&
vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
/* Output plane count is 2 - one for Y and one for CbCr */
- *plane_count = 2;
+ format = v4l2_format_info(ctx->dst_fmt->fourcc);
+ if (!format) {
+ mfc_err("invalid format\n");
+ return -EINVAL;
+ }
+ *plane_count = format->comp_planes;
+
/* Setup buffer count */
if (*buf_count < ctx->pb_count)
*buf_count = ctx->pb_count;
@@ -955,14 +981,18 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
psize[0] = ctx->luma_size;
psize[1] = ctx->chroma_size;
-
+ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M)
+ psize[2] = ctx->chroma_size_1;
if (IS_MFCV6_PLUS(dev))
alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
else
alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
- } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
- ctx->state == MFCINST_INIT) {
+ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M)
+ alloc_devs[2] = ctx->dev->mem_dev[BANK_L_CTX];
+ } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && ctx->state == MFCINST_INIT) {
psize[0] = ctx->dec_src_buf_size;
alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
} else {
@@ -994,12 +1024,24 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
mfc_err("Plane buffer (CAPTURE) is too small\n");
return -EINVAL;
}
+ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M) {
+ if (vb2_plane_size(vb, 2) < ctx->chroma_size_1) {
+ mfc_err("Plane buffer (CAPTURE) is too small\n");
+ return -EINVAL;
+ }
+ }
i = vb->index;
ctx->dst_bufs[i].b = vbuf;
ctx->dst_bufs[i].cookie.raw.luma =
vb2_dma_contig_plane_dma_addr(vb, 0);
ctx->dst_bufs[i].cookie.raw.chroma =
vb2_dma_contig_plane_dma_addr(vb, 1);
+ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M) {
+ ctx->dst_bufs[i].cookie.raw.chroma_1 =
+ vb2_dma_contig_plane_dma_addr(vb, 2);
+ }
ctx->dst_bufs_cnt++;
} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
if (IS_ERR_OR_NULL(ERR_PTR(
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
index 4b4c129c09e7..ef8bb40b9712 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
@@ -60,6 +60,20 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V6PLUS_BITS,
},
{
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .codec_mode = S5P_MFC_CODEC_NONE,
+ .type = MFC_FMT_RAW,
+ .num_planes = 3,
+ .versions = MFC_V12_BIT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU420M,
+ .codec_mode = S5P_MFC_CODEC_NONE,
+ .type = MFC_FMT_RAW,
+ .num_planes = 3,
+ .versions = MFC_V12_BIT,
+ },
+ {
.fourcc = V4L2_PIX_FMT_H264,
.codec_mode = S5P_MFC_CODEC_H264_ENC,
.type = MFC_FMT_ENC,
@@ -92,7 +106,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_FIMV_CODEC_HEVC_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
- .versions = MFC_V10_BIT,
+ .versions = MFC_V10PLUS_BITS,
},
};
@@ -1150,7 +1164,6 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_enc_params *p = &ctx->enc_params;
struct s5p_mfc_buf *dst_mb;
- unsigned int enc_pb_count;
if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) {
if (!list_empty(&ctx->dst_queue)) {
@@ -1172,14 +1185,12 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
set_work_bit_irqsave(ctx);
s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
} else {
- enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops,
- get_enc_dpb_count, dev);
- if (ctx->pb_count < enc_pb_count)
- ctx->pb_count = enc_pb_count;
+ ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_enc_dpb_count, dev);
if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) {
ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops,
get_e_min_scratch_buf_size, dev);
- ctx->bank1.size += ctx->scratch_buf_size;
+ if (!IS_MFCV12(dev))
+ ctx->bank1.size += ctx->scratch_buf_size;
}
ctx->state = MFCINST_HEAD_PRODUCED;
}
@@ -1192,14 +1203,20 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf *dst_mb;
struct s5p_mfc_buf *src_mb;
- unsigned long src_y_addr, src_c_addr, dst_addr;
+ unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr;
unsigned int dst_size;
src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1);
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M)
+ src_c_1_addr =
+ vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 2);
+ else
+ src_c_1_addr = 0;
s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx,
- src_y_addr, src_c_addr);
+ src_y_addr, src_c_addr, src_c_1_addr);
dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
@@ -1214,8 +1231,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf *mb_entry;
- unsigned long enc_y_addr = 0, enc_c_addr = 0;
- unsigned long mb_y_addr, mb_c_addr;
+ unsigned long enc_y_addr = 0, enc_c_addr = 0, enc_c_1_addr = 0;
+ unsigned long mb_y_addr, mb_c_addr, mb_c_1_addr;
int slice_type;
unsigned int strm_size;
bool src_ready;
@@ -1228,18 +1245,26 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
if (slice_type >= 0) {
s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx,
- &enc_y_addr, &enc_c_addr);
+ &enc_y_addr, &enc_c_addr, &enc_c_1_addr);
list_for_each_entry(mb_entry, &ctx->src_queue, list) {
mb_y_addr = vb2_dma_contig_plane_dma_addr(
&mb_entry->b->vb2_buf, 0);
mb_c_addr = vb2_dma_contig_plane_dma_addr(
&mb_entry->b->vb2_buf, 1);
- if ((enc_y_addr == mb_y_addr) &&
- (enc_c_addr == mb_c_addr)) {
+ if (ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YUV420M ||
+ ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M)
+ mb_c_1_addr = vb2_dma_contig_plane_dma_addr
+ (&mb_entry->b->vb2_buf, 2);
+ else
+ mb_c_1_addr = 0;
+ if (enc_y_addr == mb_y_addr && enc_c_addr == mb_c_addr && enc_c_1_addr
+ == mb_c_1_addr) {
list_del(&mb_entry->list);
ctx->src_queue_cnt--;
vb2_buffer_done(&mb_entry->b->vb2_buf,
- VB2_BUF_STATE_DONE);
+ VB2_BUF_STATE_DONE);
break;
}
}
@@ -1248,20 +1273,27 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
&mb_entry->b->vb2_buf, 0);
mb_c_addr = vb2_dma_contig_plane_dma_addr(
&mb_entry->b->vb2_buf, 1);
- if ((enc_y_addr == mb_y_addr) &&
- (enc_c_addr == mb_c_addr)) {
+ if (ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YUV420M ||
+ ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+ mb_c_1_addr = vb2_dma_contig_plane_dma_addr(&
+ mb_entry->b->vb2_buf, 2);
+ else
+ mb_c_1_addr = 0;
+ if (enc_y_addr == mb_y_addr && enc_c_addr == mb_c_addr && enc_c_1_addr
+ == mb_c_1_addr) {
list_del(&mb_entry->list);
ctx->ref_queue_cnt--;
vb2_buffer_done(&mb_entry->b->vb2_buf,
- VB2_BUF_STATE_DONE);
+ VB2_BUF_STATE_DONE);
break;
}
}
}
if (ctx->src_queue_cnt > 0 && (ctx->state == MFCINST_RUNNING ||
- ctx->state == MFCINST_FINISHING)) {
+ ctx->state == MFCINST_FINISHING)) {
mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
- list);
+ list);
if (mb_entry->flags & MFC_BUF_FLAG_USED) {
list_del(&mb_entry->list);
ctx->src_queue_cnt--;
@@ -1380,10 +1412,15 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
- pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+ pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0];
pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
- pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+ pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1];
pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M) {
+ pix_fmt_mp->plane_fmt[2].bytesperline = ctx->stride[2];
+ pix_fmt_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
+ }
} else {
mfc_err("invalid buf type\n");
return -EINVAL;
@@ -1420,9 +1457,12 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
mfc_err("Unsupported format by this MFC version.\n");
return -EINVAL;
}
-
- v4l_bound_align_image(&pix_fmt_mp->width, 8, 1920, 1,
- &pix_fmt_mp->height, 4, 1080, 1, 0);
+ if (IS_MFCV12(dev))
+ v4l_bound_align_image(&pix_fmt_mp->width, 8, 3840, 1, &pix_fmt_mp
+ ->height, 4, 2160, 1, 0);
+ else
+ v4l_bound_align_image(&pix_fmt_mp->width, 8, 1920, 1, &pix_fmt_mp
+ ->height, 4, 1080, 1, 0);
} else {
mfc_err("invalid buf type\n");
return -EINVAL;
@@ -1467,9 +1507,14 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx);
pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
- pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
+ pix_fmt_mp->plane_fmt[0].bytesperline = ctx->stride[0];
pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
- pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
+ pix_fmt_mp->plane_fmt[1].bytesperline = ctx->stride[1];
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M) {
+ pix_fmt_mp->plane_fmt[2].bytesperline = ctx->stride[2];
+ pix_fmt_mp->plane_fmt[2].sizeimage = ctx->chroma_size_1;
+ }
ctx->src_bufs_cnt = 0;
ctx->output_state = QUEUE_FREE;
@@ -1489,9 +1534,10 @@ static int vidioc_reqbufs(struct file *file, void *priv,
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
int ret = 0;
- /* if memory is not mmp or userptr return error */
+ /* if memory is not mmp or userptr or dmabuf return error */
if ((reqbufs->memory != V4L2_MEMORY_MMAP) &&
- (reqbufs->memory != V4L2_MEMORY_USERPTR))
+ (reqbufs->memory != V4L2_MEMORY_USERPTR) &&
+ (reqbufs->memory != V4L2_MEMORY_DMABUF))
return -EINVAL;
if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
if (reqbufs->count == 0) {
@@ -1514,14 +1560,6 @@ static int vidioc_reqbufs(struct file *file, void *priv,
}
ctx->capture_state = QUEUE_BUFS_REQUESTED;
- ret = s5p_mfc_hw_call(ctx->dev->mfc_ops,
- alloc_codec_buffers, ctx);
- if (ret) {
- mfc_err("Failed to allocate encoding buffers\n");
- reqbufs->count = 0;
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- return -ENOMEM;
- }
} else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
if (reqbufs->count == 0) {
mfc_debug(2, "Freeing buffers\n");
@@ -1537,15 +1575,13 @@ static int vidioc_reqbufs(struct file *file, void *priv,
return -EINVAL;
}
- if (IS_MFCV6_PLUS(dev)) {
+ if (IS_MFCV6_PLUS(dev) && (!IS_MFCV12(dev))) {
/* Check for min encoder buffers */
if (ctx->pb_count &&
(reqbufs->count < ctx->pb_count)) {
reqbufs->count = ctx->pb_count;
mfc_debug(2, "Minimum %d output buffers needed\n",
ctx->pb_count);
- } else {
- ctx->pb_count = reqbufs->count;
}
}
@@ -1568,9 +1604,10 @@ static int vidioc_querybuf(struct file *file, void *priv,
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
int ret = 0;
- /* if memory is not mmp or userptr return error */
+ /* if memory is not mmp or userptr or dmabuf return error */
if ((buf->memory != V4L2_MEMORY_MMAP) &&
- (buf->memory != V4L2_MEMORY_USERPTR))
+ (buf->memory != V4L2_MEMORY_USERPTR) &&
+ (buf->memory != V4L2_MEMORY_DMABUF))
return -EINVAL;
if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
if (ctx->state != MFCINST_GOT_INST) {
@@ -2413,10 +2450,18 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
psize[0] = ctx->luma_size;
psize[1] = ctx->chroma_size;
+ if (ctx->src_fmt && (ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M))
+ psize[2] = ctx->chroma_size_1;
if (IS_MFCV6_PLUS(dev)) {
alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
+ if (ctx->src_fmt && (ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M))
+ alloc_devs[2] = ctx->dev->mem_dev[BANK_L_CTX];
} else {
alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
alloc_devs[1] = ctx->dev->mem_dev[BANK_R_CTX];
@@ -2455,6 +2500,11 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb)
vb2_dma_contig_plane_dma_addr(vb, 0);
ctx->src_bufs[i].cookie.raw.chroma =
vb2_dma_contig_plane_dma_addr(vb, 1);
+ if (ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M)
+ ctx->src_bufs[i].cookie.raw.chroma_1 =
+ vb2_dma_contig_plane_dma_addr(vb, 2);
ctx->src_bufs_cnt++;
} else {
mfc_err("invalid queue type: %d\n", vq->type);
@@ -2492,6 +2542,12 @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
mfc_err("plane size is too small for output\n");
return -EINVAL;
}
+ if ((ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M ||
+ ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) &&
+ (vb2_plane_size(vb, 2) < ctx->chroma_size_1)) {
+ mfc_err("plane size is too small for output\n");
+ return -EINVAL;
+ }
} else {
mfc_err("invalid queue type: %d\n", vq->type);
return -EINVAL;
@@ -2513,11 +2569,11 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
S5P_MFC_R2H_CMD_SEQ_DONE_RET,
0);
}
-
- if (ctx->src_bufs_cnt < ctx->pb_count) {
- mfc_err("Need minimum %d OUTPUT buffers\n",
- ctx->pb_count);
- return -ENOBUFS;
+ if (q->memory != V4L2_MEMORY_DMABUF) {
+ if (ctx->src_bufs_cnt < ctx->pb_count) {
+ mfc_err("Need minimum %d OUTPUT buffers\n", ctx->pb_count);
+ return -ENOBUFS;
+ }
}
}
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
index b9831275f3ab..7c5e851c8191 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h
@@ -166,9 +166,9 @@ struct s5p_mfc_regs {
void __iomem *d_decoded_third_addr;/* only v7 */
void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */
void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */
- void __iomem *d_min_scratch_buffer_size; /* v10 */
- void __iomem *d_static_buffer_addr; /* v10 */
- void __iomem *d_static_buffer_size; /* v10 */
+ void __iomem *d_min_scratch_buffer_size; /* v10 and v12 */
+ void __iomem *d_static_buffer_addr; /* v10 and v12 */
+ void __iomem *d_static_buffer_size; /* v10 and v12 */
/* encoder registers */
void __iomem *e_frame_width;
@@ -268,7 +268,7 @@ struct s5p_mfc_regs {
void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
- void __iomem *e_min_scratch_buffer_size; /* v10 */
+ void __iomem *e_min_scratch_buffer_size; /* v10 and v12 */
void __iomem *e_num_t_layer; /* v10 */
void __iomem *e_hier_qp_layer0; /* v10 */
void __iomem *e_hier_bit_rate_layer0; /* v10 */
@@ -293,9 +293,11 @@ struct s5p_mfc_hw_ops {
int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx,
unsigned long addr, unsigned int size);
void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
- unsigned long y_addr, unsigned long c_addr);
+ unsigned long y_addr, unsigned long c_addr,
+ unsigned long c_1_addr);
void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
- unsigned long *y_addr, unsigned long *c_addr);
+ unsigned long *y_addr, unsigned long *c_addr,
+ unsigned long *c_1_addr);
void (*try_run)(struct s5p_mfc_dev *dev);
void (*clear_int_flags)(struct s5p_mfc_dev *dev);
int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev);
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
index 28a06dc343fd..fcfaf125a5a1 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c
@@ -516,7 +516,8 @@ static int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx,
}
static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
- unsigned long y_addr, unsigned long c_addr)
+ unsigned long y_addr, unsigned long c_addr,
+ unsigned long c_1_addr)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -525,7 +526,8 @@ static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
}
static void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx,
- unsigned long *y_addr, unsigned long *c_addr)
+ unsigned long *y_addr, unsigned long *c_addr,
+ unsigned long *c_1_addr)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -1210,7 +1212,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
if (list_empty(&ctx->src_queue)) {
/* send null frame */
s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->dma_base[BANK_R_CTX],
- dev->dma_base[BANK_R_CTX]);
+ dev->dma_base[BANK_R_CTX], 0);
src_mb = NULL;
} else {
src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
@@ -1220,7 +1222,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
/* send null frame */
s5p_mfc_set_enc_frame_buffer_v5(ctx,
dev->dma_base[BANK_R_CTX],
- dev->dma_base[BANK_R_CTX]);
+ dev->dma_base[BANK_R_CTX], 0);
ctx->state = MFCINST_FINISHING;
} else {
src_y_addr = vb2_dma_contig_plane_dma_addr(
@@ -1228,7 +1230,7 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
src_c_addr = vb2_dma_contig_plane_dma_addr(
&src_mb->b->vb2_buf, 1);
s5p_mfc_set_enc_frame_buffer_v5(ctx, src_y_addr,
- src_c_addr);
+ src_c_addr, 0);
if (src_mb->flags & MFC_BUF_FLAG_EOS)
ctx->state = MFCINST_FINISHING;
}
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
index c0df5ac9fcff..fd945211d28e 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c
@@ -60,21 +60,23 @@ static void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx)
static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
- unsigned int mb_width, mb_height;
+ unsigned int mb_width, mb_height, width64, height32;
unsigned int lcu_width = 0, lcu_height = 0;
int ret;
mb_width = MB_WIDTH(ctx->img_width);
mb_height = MB_HEIGHT(ctx->img_height);
+ width64 = ALIGN(ctx->img_width, 64);
+ height32 = ALIGN(ctx->img_height, 32);
if (ctx->type == MFCINST_DECODER) {
mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n",
ctx->luma_size, ctx->chroma_size, ctx->mv_size);
mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count);
} else if (ctx->type == MFCINST_ENCODER) {
- if (IS_MFCV10(dev)) {
+ if (IS_MFCV10_PLUS(dev))
ctx->tmv_buffer_size = 0;
- } else if (IS_MFCV8_PLUS(dev))
+ else if (IS_MFCV8_PLUS(dev))
ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 *
ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V8(mb_width, mb_height),
S5P_FIMV_TMV_BUFFER_ALIGN_V6);
@@ -82,7 +84,39 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 *
ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height),
S5P_FIMV_TMV_BUFFER_ALIGN_V6);
- if (IS_MFCV10(dev)) {
+ if (IS_MFCV12(dev)) {
+ lcu_width = S5P_MFC_LCU_WIDTH(ctx->img_width);
+ lcu_height = S5P_MFC_LCU_HEIGHT(ctx->img_height);
+ if (ctx->codec_mode == S5P_FIMV_CODEC_HEVC_ENC && ctx->is_10bit) {
+ ctx->luma_dpb_size =
+ width64 * height32 +
+ ALIGN(DIV_ROUND_UP(lcu_width * 32, 4), 16) * height32 + 128;
+ if (ctx->is_422)
+ ctx->chroma_dpb_size =
+ ctx->luma_dpb_size;
+ else
+ ctx->chroma_dpb_size =
+ width64 * height32 / 2 +
+ ALIGN(DIV_ROUND_UP(lcu_width *
+ 32, 4), 16) * height32 / 2 + 128;
+ } else if (ctx->codec_mode == S5P_FIMV_CODEC_VP9_ENC && ctx->is_10bit) {
+ ctx->luma_dpb_size =
+ ALIGN(ctx->img_width * 2, 128) * height32 + 64;
+ ctx->chroma_dpb_size =
+ ALIGN(ctx->img_width * 2, 128) * height32 / 2 + 64;
+ } else {
+ ctx->luma_dpb_size =
+ width64 * height32 + 64;
+ if (ctx->is_422)
+ ctx->chroma_dpb_size =
+ ctx->luma_dpb_size;
+ else
+ ctx->chroma_dpb_size =
+ width64 * height32 / 2 + 64;
+ }
+ ctx->luma_dpb_size = ALIGN(ctx->luma_dpb_size + 256, SZ_2K);
+ ctx->chroma_dpb_size = ALIGN(ctx->chroma_dpb_size + 256, SZ_2K);
+ } else if (IS_MFCV10_PLUS(dev)) {
lcu_width = S5P_MFC_LCU_WIDTH(ctx->img_width);
lcu_height = S5P_MFC_LCU_HEIGHT(ctx->img_height);
if (ctx->codec_mode != S5P_FIMV_CODEC_HEVC_ENC) {
@@ -133,7 +167,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
switch (ctx->codec_mode) {
case S5P_MFC_CODEC_H264_DEC:
case S5P_MFC_CODEC_H264_MVC_DEC:
- if (IS_MFCV10(dev))
+ if (IS_MFCV10_PLUS(dev))
mfc_debug(2, "Use min scratch buffer size\n");
else if (IS_MFCV8_PLUS(dev))
ctx->scratch_buf_size =
@@ -152,7 +186,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
(ctx->mv_count * ctx->mv_size);
break;
case S5P_MFC_CODEC_MPEG4_DEC:
- if (IS_MFCV10(dev))
+ if (IS_MFCV10_PLUS(dev))
mfc_debug(2, "Use min scratch buffer size\n");
else if (IS_MFCV7_PLUS(dev)) {
ctx->scratch_buf_size =
@@ -172,7 +206,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
break;
case S5P_MFC_CODEC_VC1RCV_DEC:
case S5P_MFC_CODEC_VC1_DEC:
- if (IS_MFCV10(dev))
+ if (IS_MFCV10_PLUS(dev))
mfc_debug(2, "Use min scratch buffer size\n");
else
ctx->scratch_buf_size =
@@ -189,7 +223,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->bank2.size = 0;
break;
case S5P_MFC_CODEC_H263_DEC:
- if (IS_MFCV10(dev))
+ if (IS_MFCV10_PLUS(dev))
mfc_debug(2, "Use min scratch buffer size\n");
else
ctx->scratch_buf_size =
@@ -201,7 +235,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->bank1.size = ctx->scratch_buf_size;
break;
case S5P_MFC_CODEC_VP8_DEC:
- if (IS_MFCV10(dev))
+ if (IS_MFCV10_PLUS(dev))
mfc_debug(2, "Use min scratch buffer size\n");
else if (IS_MFCV8_PLUS(dev))
ctx->scratch_buf_size =
@@ -230,7 +264,11 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
DEC_VP9_STATIC_BUFFER_SIZE;
break;
case S5P_MFC_CODEC_H264_ENC:
- if (IS_MFCV10(dev)) {
+ if (IS_MFCV12(dev)) {
+ mfc_debug(2, "Use min scratch buffer size\n");
+ ctx->me_buffer_size =
+ ENC_V120_H264_ME_SIZE(mb_width, mb_height);
+ } else if (IS_MFCV10_PLUS(dev)) {
mfc_debug(2, "Use min scratch buffer size\n");
ctx->me_buffer_size =
ALIGN(ENC_V100_H264_ME_SIZE(mb_width, mb_height), 16);
@@ -254,7 +292,11 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
break;
case S5P_MFC_CODEC_MPEG4_ENC:
case S5P_MFC_CODEC_H263_ENC:
- if (IS_MFCV10(dev)) {
+ if (IS_MFCV12(dev)) {
+ mfc_debug(2, "Use min scratch buffer size\n");
+ ctx->me_buffer_size =
+ ENC_V120_MPEG4_ME_SIZE(mb_width, mb_height);
+ } else if (IS_MFCV10_PLUS(dev)) {
mfc_debug(2, "Use min scratch buffer size\n");
ctx->me_buffer_size =
ALIGN(ENC_V100_MPEG4_ME_SIZE(mb_width,
@@ -265,7 +307,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
mb_width,
mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
- S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
+ S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
ctx->bank1.size =
ctx->scratch_buf_size + ctx->tmv_buffer_size +
(ctx->pb_count * (ctx->luma_dpb_size +
@@ -273,7 +315,11 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->bank2.size = 0;
break;
case S5P_MFC_CODEC_VP8_ENC:
- if (IS_MFCV10(dev)) {
+ if (IS_MFCV12(dev)) {
+ mfc_debug(2, "Use min scratch buffer size\n");
+ ctx->me_buffer_size =
+ ENC_V120_VP8_ME_SIZE(mb_width, mb_height);
+ } else if (IS_MFCV10_PLUS(dev)) {
mfc_debug(2, "Use min scratch buffer size\n");
ctx->me_buffer_size =
ALIGN(ENC_V100_VP8_ME_SIZE(mb_width, mb_height),
@@ -297,9 +343,13 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->bank2.size = 0;
break;
case S5P_MFC_CODEC_HEVC_ENC:
+ if (IS_MFCV12(dev))
+ ctx->me_buffer_size =
+ ENC_V120_HEVC_ME_SIZE(lcu_width, lcu_height);
+ else
+ ctx->me_buffer_size =
+ ALIGN(ENC_V100_HEVC_ME_SIZE(lcu_width, lcu_height), 16);
mfc_debug(2, "Use min scratch buffer size\n");
- ctx->me_buffer_size =
- ALIGN(ENC_V100_HEVC_ME_SIZE(lcu_width, lcu_height), 16);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256);
ctx->bank1.size =
ctx->scratch_buf_size + ctx->tmv_buffer_size +
@@ -438,30 +488,48 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx)
struct s5p_mfc_dev *dev = ctx->dev;
ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6);
ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6);
+ ctx->chroma_size_1 = 0;
mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n"
"buffer dimensions: %dx%d\n", ctx->img_width,
ctx->img_height, ctx->buf_width, ctx->buf_height);
- ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height);
- ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1));
+ switch (ctx->dst_fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV21M:
+ ctx->stride[0] = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6);
+ ctx->stride[1] = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6);
+ ctx->luma_size = calc_plane(ctx->stride[0], ctx->img_height);
+ ctx->chroma_size = calc_plane(ctx->stride[1], (ctx->img_height / 2));
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YVU420M:
+ ctx->stride[0] = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6);
+ ctx->stride[1] = ALIGN(ctx->img_width / 2, S5P_FIMV_NV12MT_HALIGN_V6);
+ ctx->stride[2] = ALIGN(ctx->img_width / 2, S5P_FIMV_NV12MT_HALIGN_V6);
+ ctx->luma_size = calc_plane(ctx->stride[0], ctx->img_height);
+ ctx->chroma_size = calc_plane(ctx->stride[1], (ctx->img_height / 2));
+ ctx->chroma_size_1 = calc_plane(ctx->stride[2], (ctx->img_height / 2));
+ break;
+ }
+
if (IS_MFCV8_PLUS(ctx->dev)) {
/* MFCv8 needs additional 64 bytes for luma,chroma dpb*/
ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
+ ctx->chroma_size_1 += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
}
if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) {
- if (IS_MFCV10(dev)) {
- ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V10(ctx->img_width,
- ctx->img_height);
- } else {
- ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width,
- ctx->img_height);
- }
+ if (IS_MFCV12(dev))
+ ctx->mv_size = S5P_MFC_DEC_MV_SIZE(ctx->img_width, ctx->img_height, 1024);
+ else if (IS_MFCV10_PLUS(dev))
+ ctx->mv_size = S5P_MFC_DEC_MV_SIZE(ctx->img_width, ctx->img_height, 512);
+ else
+ ctx->mv_size = S5P_MFC_DEC_MV_SIZE(ctx->img_width, ctx->img_height, 128);
+
} else if (ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) {
- ctx->mv_size = s5p_mfc_dec_hevc_mv_size(ctx->img_width,
- ctx->img_height);
+ ctx->mv_size = s5p_mfc_dec_hevc_mv_size(ctx->img_width, ctx->img_height);
ctx->mv_size = ALIGN(ctx->mv_size, 32);
} else {
ctx->mv_size = 0;
@@ -475,14 +543,40 @@ static void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx)
mb_width = MB_WIDTH(ctx->img_width);
mb_height = MB_HEIGHT(ctx->img_height);
- ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6);
- ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256);
- ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
-
- /* MFCv7 needs pad bytes for Luma and Chroma */
- if (IS_MFCV7_PLUS(ctx->dev)) {
+ if (IS_MFCV12(ctx->dev)) {
+ switch (ctx->src_fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12M:
+ case V4L2_PIX_FMT_NV21M:
+ ctx->stride[0] = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6);
+ ctx->stride[1] = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6);
+ ctx->luma_size = ctx->stride[0] * ALIGN(ctx->img_height, 16);
+ ctx->chroma_size = ctx->stride[0] * ALIGN(ctx->img_height / 2, 16);
+ break;
+ case V4L2_PIX_FMT_YUV420M:
+ case V4L2_PIX_FMT_YVU420M:
+ ctx->stride[0] = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6);
+ ctx->stride[1] = ALIGN(ctx->img_width / 2, S5P_FIMV_NV12M_HALIGN_V6);
+ ctx->stride[2] = ALIGN(ctx->img_width / 2, S5P_FIMV_NV12M_HALIGN_V6);
+ ctx->luma_size = ctx->stride[0] * ALIGN(ctx->img_height, 16);
+ ctx->chroma_size = ctx->stride[1] * ALIGN(ctx->img_height / 2, 16);
+ ctx->chroma_size_1 = ctx->stride[2] * ALIGN(ctx->img_height / 2, 16);
+ break;
+ }
ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
- ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V7;
+ ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V12;
+ ctx->chroma_size_1 += MFC_CHROMA_PAD_BYTES_V12;
+ } else {
+ ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6);
+ ctx->stride[0] = ctx->buf_width;
+ ctx->stride[1] = ctx->buf_width;
+ ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256);
+ ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
+ ctx->chroma_size_1 = 0;
+ /* MFCv7 needs pad bytes for Luma and Chroma */
+ if (IS_MFCV7_PLUS(ctx->dev)) {
+ ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
+ ctx->chroma_size += MFC_LUMA_PAD_BYTES_V7;
+ }
}
}
@@ -529,15 +623,18 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
writel(ctx->total_dpb_count, mfc_regs->d_num_dpb);
writel(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
writel(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
-
+ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M)
+ writel(ctx->chroma_size_1, mfc_regs->d_third_plane_dpb_size);
writel(buf_addr1, mfc_regs->d_scratch_buffer_addr);
writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
if (IS_MFCV8_PLUS(dev)) {
- writel(ctx->img_width,
- mfc_regs->d_first_plane_dpb_stride_size);
- writel(ctx->img_width,
- mfc_regs->d_second_plane_dpb_stride_size);
+ writel(ctx->stride[0], mfc_regs->d_first_plane_dpb_stride_size);
+ writel(ctx->stride[1], mfc_regs->d_second_plane_dpb_stride_size);
+ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M)
+ writel(ctx->stride[2], mfc_regs->d_third_plane_dpb_stride_size);
}
buf_addr1 += ctx->scratch_buf_size;
@@ -566,6 +663,13 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
ctx->dst_bufs[i].cookie.raw.chroma);
writel(ctx->dst_bufs[i].cookie.raw.chroma,
mfc_regs->d_second_plane_dpb + i * 4);
+ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->dst_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M) {
+ mfc_debug(2, "\tChroma_1 %d: %zx\n", i, ctx
+ ->dst_bufs[i].cookie.raw.chroma_1);
+ writel(ctx->dst_bufs[i].cookie.raw.chroma_1, mfc_regs->d_third_plane_dpb +
+ i * 4);
+ }
}
if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC ||
@@ -624,20 +728,24 @@ static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
}
static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
- unsigned long y_addr, unsigned long c_addr)
+ unsigned long y_addr, unsigned long c_addr,
+ unsigned long c_1_addr)
{
struct s5p_mfc_dev *dev = ctx->dev;
const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
writel(y_addr, mfc_regs->e_source_first_plane_addr);
writel(c_addr, mfc_regs->e_source_second_plane_addr);
+ writel(c_1_addr, mfc_regs->e_source_third_plane_addr);
mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr);
mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr);
+ mfc_debug(2, "enc src cr buf addr: 0x%08lx\n", c_1_addr);
}
static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
- unsigned long *y_addr, unsigned long *c_addr)
+ unsigned long *y_addr, unsigned long *c_addr,
+ unsigned long *c_1_addr)
{
struct s5p_mfc_dev *dev = ctx->dev;
const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
@@ -645,12 +753,17 @@ static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
*y_addr = readl(mfc_regs->e_encoded_source_first_plane_addr);
*c_addr = readl(mfc_regs->e_encoded_source_second_plane_addr);
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M)
+ *c_1_addr = readl(mfc_regs->e_encoded_source_third_plane_addr);
+ else
+ *c_1_addr = 0;
enc_recon_y_addr = readl(mfc_regs->e_recon_luma_dpb_addr);
enc_recon_c_addr = readl(mfc_regs->e_recon_chroma_dpb_addr);
mfc_debug(2, "recon y addr: 0x%08lx y_addr: 0x%08lx\n", enc_recon_y_addr, *y_addr);
- mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr);
+ mfc_debug(2, "recon c addr: 0x%08lx c_addr: 0x%08lx\n", enc_recon_c_addr, *c_addr);
}
/* Set encoding ref & codec buffer */
@@ -668,7 +781,7 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1);
- if (IS_MFCV10(dev)) {
+ if (IS_MFCV10_PLUS(dev)) {
/* start address of per buffer is aligned */
for (i = 0; i < ctx->pb_count; i++) {
writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i));
@@ -827,6 +940,20 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
writel(reg, mfc_regs->e_enc_options);
/* 0: NV12(CbCr), 1: NV21(CrCb) */
writel(0x0, mfc_regs->pixel_format);
+ } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YVU420M) {
+ /* 0: Linear, 1: 2D tiled*/
+ reg = readl(mfc_regs->e_enc_options);
+ reg &= ~(0x1 << 7);
+ writel(reg, mfc_regs->e_enc_options);
+ /* 2: YV12(CrCb), 3: I420(CrCb) */
+ writel(0x2, mfc_regs->pixel_format);
+ } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M) {
+ /* 0: Linear, 1: 2D tiled*/
+ reg = readl(mfc_regs->e_enc_options);
+ reg &= ~(0x1 << 7);
+ writel(reg, mfc_regs->e_enc_options);
+ /* 2: YV12(CrCb), 3: I420(CrCb) */
+ writel(0x3, mfc_regs->pixel_format);
}
/* memory structure recon. frame */
@@ -865,10 +992,24 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
/* reaction coefficient */
if (p->rc_frame) {
- if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */
- writel(1, mfc_regs->e_rc_mode);
- else /* loose CBR */
- writel(2, mfc_regs->e_rc_mode);
+ if (IS_MFCV12(dev)) {
+ /* loose CBR */
+ if (p->rc_reaction_coeff < LOOSE_CBR_MAX)
+ writel(1, mfc_regs->e_rc_mode);
+ /* tight CBR */
+ else if (p->rc_reaction_coeff < TIGHT_CBR_MAX)
+ writel(0, mfc_regs->e_rc_mode);
+ /* VBR */
+ else
+ writel(2, mfc_regs->e_rc_mode);
+ } else {
+ /* tight CBR */
+ if (p->rc_reaction_coeff < TIGHT_CBR_MAX)
+ writel(1, mfc_regs->e_rc_mode);
+ /* loose CBR */
+ else
+ writel(2, mfc_regs->e_rc_mode);
+ }
}
/* seq header ctrl */
@@ -930,6 +1071,18 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
reg |= ((p->num_b_frame & 0x3) << 16);
writel(reg, mfc_regs->e_gop_config);
+ /* UHD encoding case */
+ if (ctx->img_width == 3840 && ctx->img_height == 2160) {
+ if (p_h264->level < 51) {
+ mfc_debug(2, "Set Level 5.1 for UHD\n");
+ p_h264->level = 51;
+ }
+ if (p_h264->profile != 0x2) {
+ mfc_debug(2, "Set High profile for UHD\n");
+ p_h264->profile = 0x2;
+ }
+ }
+
/* profile & level */
reg = 0;
/** level */
@@ -1637,8 +1790,12 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
else
writel(reg, mfc_regs->d_dec_options);
- /* 0: NV12(CbCr), 1: NV21(CrCb) */
- if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
+ /* 0: NV12(CbCr), 1: NV21(CrCb), 2: YV12(CrCb), 3: I420(CbCr) */
+ if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YUV420M)
+ writel(0x3, mfc_regs->pixel_format);
+ else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_YVU420M)
+ writel(0x2, mfc_regs->pixel_format);
+ else if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
writel(0x1, mfc_regs->pixel_format);
else
writel(0x0, mfc_regs->pixel_format);
@@ -1722,8 +1879,11 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
/* Set stride lengths for v7 & above */
if (IS_MFCV7_PLUS(dev)) {
- writel(ctx->img_width, mfc_regs->e_source_first_plane_stride);
- writel(ctx->img_width, mfc_regs->e_source_second_plane_stride);
+ writel(ctx->stride[0], mfc_regs->e_source_first_plane_stride);
+ writel(ctx->stride[1], mfc_regs->e_source_second_plane_stride);
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M)
+ writel(ctx->stride[2], mfc_regs->e_source_third_plane_stride);
}
writel(ctx->inst_no, mfc_regs->instance_id);
@@ -1832,7 +1992,7 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf *dst_mb;
struct s5p_mfc_buf *src_mb;
- unsigned long src_y_addr, src_c_addr, dst_addr;
+ unsigned long src_y_addr, src_c_addr, src_c_1_addr, dst_addr;
/*
unsigned int src_y_size, src_c_size;
*/
@@ -1850,22 +2010,28 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
if (list_empty(&ctx->src_queue)) {
/* send null frame */
- s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0);
+ s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0, 0);
src_mb = NULL;
} else {
src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
src_mb->flags |= MFC_BUF_FLAG_USED;
if (src_mb->b->vb2_buf.planes[0].bytesused == 0) {
- s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0);
+ s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0, 0);
ctx->state = MFCINST_FINISHING;
} else {
src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1);
+ if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_YUV420M || ctx->src_fmt->fourcc ==
+ V4L2_PIX_FMT_YVU420M)
+ src_c_1_addr = vb2_dma_contig_plane_dma_addr
+ (&src_mb->b->vb2_buf, 2);
+ else
+ src_c_1_addr = 0;
mfc_debug(2, "enc src y addr: 0x%08lx\n", src_y_addr);
mfc_debug(2, "enc src c addr: 0x%08lx\n", src_c_addr);
- s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr);
+ s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr, src_c_1_addr);
if (src_mb->flags & MFC_BUF_FLAG_EOS)
ctx->state = MFCINST_FINISHING;
}
@@ -1944,6 +2110,13 @@ static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx)
struct s5p_mfc_dev *dev = ctx->dev;
int ret;
+ ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, alloc_codec_buffers, ctx);
+ if (ret) {
+ mfc_err("Failed to allocate encoding buffers\n");
+ return -ENOMEM;
+ }
+ mfc_debug(2, "Allocated Internal Encoding Buffers\n");
+
dev->curr_ctx = ctx->num;
ret = s5p_mfc_set_enc_ref_buffer_v6(ctx);
if (ret) {
@@ -2387,10 +2560,9 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
R(e_source_first_plane_stride, S5P_FIMV_E_SOURCE_FIRST_STRIDE_V7);
R(e_source_second_plane_stride, S5P_FIMV_E_SOURCE_SECOND_STRIDE_V7);
R(e_source_third_plane_stride, S5P_FIMV_E_SOURCE_THIRD_STRIDE_V7);
- R(e_encoded_source_first_plane_addr,
- S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7);
- R(e_encoded_source_second_plane_addr,
- S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7);
+ R(e_encoded_source_first_plane_addr, S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7);
+ R(e_encoded_source_second_plane_addr, S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7);
+ R(e_encoded_source_third_plane_addr, S5P_FIMV_E_ENCODED_SOURCE_THIRD_ADDR_V7);
R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7);
if (!IS_MFCV8_PLUS(dev))
@@ -2405,16 +2577,17 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
R(d_cpb_buffer_offset, S5P_FIMV_D_CPB_BUFFER_OFFSET_V8);
R(d_first_plane_dpb_size, S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8);
R(d_second_plane_dpb_size, S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8);
+ R(d_third_plane_dpb_size, S5P_FIMV_D_THIRD_PLANE_DPB_SIZE_V8);
R(d_scratch_buffer_addr, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V8);
R(d_scratch_buffer_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V8);
- R(d_first_plane_dpb_stride_size,
- S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8);
- R(d_second_plane_dpb_stride_size,
- S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8);
+ R(d_first_plane_dpb_stride_size, S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8);
+ R(d_second_plane_dpb_stride_size, S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8);
+ R(d_third_plane_dpb_stride_size, S5P_FIMV_D_THIRD_PLANE_DPB_STRIDE_SIZE_V8);
R(d_mv_buffer_size, S5P_FIMV_D_MV_BUFFER_SIZE_V8);
R(d_num_mv, S5P_FIMV_D_NUM_MV_V8);
R(d_first_plane_dpb, S5P_FIMV_D_FIRST_PLANE_DPB_V8);
R(d_second_plane_dpb, S5P_FIMV_D_SECOND_PLANE_DPB_V8);
+ R(d_third_plane_dpb, S5P_FIMV_D_THIRD_PLANE_DPB_V8);
R(d_mv_buffer, S5P_FIMV_D_MV_BUFFER_V8);
R(d_init_buffer_options, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V8);
R(d_available_dpb_flag_lower, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V8);
@@ -2455,7 +2628,7 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
R(e_h264_options, S5P_FIMV_E_H264_OPTIONS_V8);
R(e_min_scratch_buffer_size, S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8);
- if (!IS_MFCV10(dev))
+ if (!IS_MFCV10_PLUS(dev))
goto done;
/* Initialize registers used in MFC v10 only.
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h
index e4dd03c5454c..94ecb0e6e7c7 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h
@@ -19,10 +19,8 @@
#define MB_WIDTH(x_size) DIV_ROUND_UP(x_size, 16)
#define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, 16)
-#define S5P_MFC_DEC_MV_SIZE_V6(x, y) (MB_WIDTH(x) * \
- (((MB_HEIGHT(y)+1)/2)*2) * 64 + 128)
-#define S5P_MFC_DEC_MV_SIZE_V10(x, y) (MB_WIDTH(x) * \
- (((MB_HEIGHT(y)+1)/2)*2) * 64 + 512)
+#define S5P_MFC_DEC_MV_SIZE(x, y, offset) (MB_WIDTH(x) * \
+ (((MB_HEIGHT(y) + 1) / 2) * 2) * 64 + (offset))
#define S5P_MFC_LCU_WIDTH(x_size) DIV_ROUND_UP(x_size, 32)
#define S5P_MFC_LCU_HEIGHT(y_size) DIV_ROUND_UP(y_size, 32)
@@ -42,6 +40,7 @@
#define ENC_H264_LEVEL_MAX 42
#define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 16) - 1)
#define FRAME_DELTA_H264_H263 1
+#define LOOSE_CBR_MAX 5
#define TIGHT_CBR_MAX 10
#define ENC_HEVC_RC_FRAME_RATE_MAX ((1 << 16) - 1)
#define ENC_HEVC_QP_INDEX_MIN -12
diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c
index 3a848ca32a0e..161a5c0fbc4e 100644
--- a/drivers/media/platform/st/sti/hva/hva-v4l2.c
+++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c
@@ -569,14 +569,11 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
struct vb2_buffer *vb2_buf;
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, buf->type);
-
- if (buf->index >= vq->num_buffers) {
- dev_dbg(dev, "%s buffer index %d out of range (%d)\n",
- ctx->name, buf->index, vq->num_buffers);
+ vb2_buf = vb2_get_buffer(vq, buf->index);
+ if (!vb2_buf) {
+ dev_dbg(dev, "%s buffer index %d not found\n", ctx->name, buf->index);
return -EINVAL;
}
-
- vb2_buf = vb2_get_buffer(vq, buf->index);
stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf));
stream->bytesused = buf->bytesused;
}
@@ -1145,7 +1142,7 @@ static int hva_queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
src_vq->buf_struct_size = sizeof(struct hva_frame);
- src_vq->min_buffers_needed = MIN_FRAMES;
+ src_vq->min_queued_buffers = MIN_FRAMES;
src_vq->dev = ctx->hva_dev->dev;
ret = queue_init(ctx, src_vq);
@@ -1154,7 +1151,7 @@ static int hva_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
dst_vq->buf_struct_size = sizeof(struct hva_stream);
- dst_vq->min_buffers_needed = MIN_STREAMS;
+ dst_vq->min_queued_buffers = MIN_STREAMS;
dst_vq->dev = ctx->hva_dev->dev;
return queue_init(ctx, dst_vq);
diff --git a/drivers/media/platform/st/stm32/Kconfig b/drivers/media/platform/st/stm32/Kconfig
index b22dd4753496..9df9a2a17728 100644
--- a/drivers/media/platform/st/stm32/Kconfig
+++ b/drivers/media/platform/st/stm32/Kconfig
@@ -16,6 +16,22 @@ config VIDEO_STM32_DCMI
To compile this driver as a module, choose M here: the module
will be called stm32-dcmi.
+config VIDEO_STM32_DCMIPP
+ tristate "STM32 Digital Camera Memory Interface Pixel Processor (DCMIPP) support"
+ depends on V4L_PLATFORM_DRIVERS
+ depends on VIDEO_DEV
+ depends on ARCH_STM32 || COMPILE_TEST
+ select MEDIA_CONTROLLER
+ select VIDEOBUF2_DMA_CONTIG
+ select VIDEO_V4L2_SUBDEV_API
+ select V4L2_FWNODE
+ help
+ This module makes the STM32 Digital Camera Memory Interface
+ Pixel Processor (DCMIPP) available as a v4l2 device.
+
+ To compile this driver as a module, choose M here: the module
+ will be called stm32-dcmipp.
+
# Mem2mem drivers
config VIDEO_STM32_DMA2D
tristate "STM32 Chrom-Art Accelerator (DMA2D)"
diff --git a/drivers/media/platform/st/stm32/Makefile b/drivers/media/platform/st/stm32/Makefile
index 896ef98a73ab..7ed8297b9b19 100644
--- a/drivers/media/platform/st/stm32/Makefile
+++ b/drivers/media/platform/st/stm32/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_VIDEO_STM32_DCMI) += stm32-dcmi.o
+obj-$(CONFIG_VIDEO_STM32_DCMIPP) += stm32-dcmipp/
stm32-dma2d-objs := dma2d/dma2d.o dma2d/dma2d-hw.o
obj-$(CONFIG_VIDEO_STM32_DMA2D) += stm32-dma2d.o
diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 8cb4fdcae137..c4610e305546 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
@@ -1890,7 +1889,6 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
static int dcmi_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- const struct of_device_id *match = NULL;
struct v4l2_fwnode_endpoint ep = { .bus_type = 0 };
struct stm32_dcmi *dcmi;
struct vb2_queue *q;
@@ -1899,12 +1897,6 @@ static int dcmi_probe(struct platform_device *pdev)
struct clk *mclk;
int ret = 0;
- match = of_match_device(of_match_ptr(stm32_dcmi_of_match), &pdev->dev);
- if (!match) {
- dev_err(&pdev->dev, "Could not find a match in devicetree\n");
- return -ENODEV;
- }
-
dcmi = devm_kzalloc(&pdev->dev, sizeof(struct stm32_dcmi), GFP_KERNEL);
if (!dcmi)
return -ENOMEM;
@@ -2039,7 +2031,7 @@ static int dcmi_probe(struct platform_device *pdev)
q->ops = &dcmi_video_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->allow_cache_hints = 1;
q->dev = &pdev->dev;
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/Makefile b/drivers/media/platform/st/stm32/stm32-dcmipp/Makefile
new file mode 100644
index 000000000000..8920d9388a21
--- /dev/null
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+stm32-dcmipp-y := dcmipp-core.o dcmipp-common.o dcmipp-parallel.o dcmipp-byteproc.o dcmipp-bytecap.o
+
+obj-$(CONFIG_VIDEO_STM32_DCMIPP) += stm32-dcmipp.o
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
new file mode 100644
index 000000000000..9f768f011fa2
--- /dev/null
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
@@ -0,0 +1,956 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for STM32 Digital Camera Memory Interface Pixel Processor
+ *
+ * Copyright (C) STMicroelectronics SA 2023
+ * Authors: Hugues Fruchet <[email protected]>
+ * Alain Volmat <[email protected]>
+ * for STMicroelectronics.
+ */
+
+#include <linux/iopoll.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "dcmipp-common.h"
+
+#define DCMIPP_PRSR 0x1f8
+#define DCMIPP_CMIER 0x3f0
+#define DCMIPP_CMIER_P0FRAMEIE BIT(9)
+#define DCMIPP_CMIER_P0VSYNCIE BIT(10)
+#define DCMIPP_CMIER_P0OVRIE BIT(15)
+#define DCMIPP_CMIER_P0ALL (DCMIPP_CMIER_P0VSYNCIE |\
+ DCMIPP_CMIER_P0FRAMEIE |\
+ DCMIPP_CMIER_P0OVRIE)
+#define DCMIPP_CMSR1 0x3f4
+#define DCMIPP_CMSR2 0x3f8
+#define DCMIPP_CMSR2_P0FRAMEF BIT(9)
+#define DCMIPP_CMSR2_P0VSYNCF BIT(10)
+#define DCMIPP_CMSR2_P0OVRF BIT(15)
+#define DCMIPP_CMFCR 0x3fc
+#define DCMIPP_P0FSCR 0x404
+#define DCMIPP_P0FSCR_PIPEN BIT(31)
+#define DCMIPP_P0FCTCR 0x500
+#define DCMIPP_P0FCTCR_CPTREQ BIT(3)
+#define DCMIPP_P0DCCNTR 0x5b0
+#define DCMIPP_P0DCLMTR 0x5b4
+#define DCMIPP_P0DCLMTR_ENABLE BIT(31)
+#define DCMIPP_P0DCLMTR_LIMIT_MASK GENMASK(23, 0)
+#define DCMIPP_P0PPM0AR1 0x5c4
+#define DCMIPP_P0SR 0x5f8
+#define DCMIPP_P0SR_CPTACT BIT(23)
+
+struct dcmipp_bytecap_pix_map {
+ unsigned int code;
+ u32 pixelformat;
+};
+
+#define PIXMAP_MBUS_PFMT(mbus, fmt) \
+ { \
+ .code = MEDIA_BUS_FMT_##mbus, \
+ .pixelformat = V4L2_PIX_FMT_##fmt \
+ }
+
+static const struct dcmipp_bytecap_pix_map dcmipp_bytecap_pix_map_list[] = {
+ PIXMAP_MBUS_PFMT(RGB565_2X8_LE, RGB565),
+ PIXMAP_MBUS_PFMT(YUYV8_2X8, YUYV),
+ PIXMAP_MBUS_PFMT(YVYU8_2X8, YVYU),
+ PIXMAP_MBUS_PFMT(UYVY8_2X8, UYVY),
+ PIXMAP_MBUS_PFMT(VYUY8_2X8, VYUY),
+ PIXMAP_MBUS_PFMT(Y8_1X8, GREY),
+ PIXMAP_MBUS_PFMT(SBGGR8_1X8, SBGGR8),
+ PIXMAP_MBUS_PFMT(SGBRG8_1X8, SGBRG8),
+ PIXMAP_MBUS_PFMT(SGRBG8_1X8, SGRBG8),
+ PIXMAP_MBUS_PFMT(SRGGB8_1X8, SRGGB8),
+ PIXMAP_MBUS_PFMT(JPEG_1X8, JPEG),
+};
+
+static const struct dcmipp_bytecap_pix_map *
+dcmipp_bytecap_pix_map_by_pixelformat(u32 pixelformat)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dcmipp_bytecap_pix_map_list); i++) {
+ if (dcmipp_bytecap_pix_map_list[i].pixelformat == pixelformat)
+ return &dcmipp_bytecap_pix_map_list[i];
+ }
+
+ return NULL;
+}
+
+struct dcmipp_buf {
+ struct vb2_v4l2_buffer vb;
+ bool prepared;
+ dma_addr_t addr;
+ size_t size;
+ struct list_head list;
+};
+
+enum dcmipp_state {
+ DCMIPP_STOPPED = 0,
+ DCMIPP_WAIT_FOR_BUFFER,
+ DCMIPP_RUNNING,
+};
+
+struct dcmipp_bytecap_device {
+ struct dcmipp_ent_device ved;
+ struct video_device vdev;
+ struct device *dev;
+ struct v4l2_pix_format format;
+ struct vb2_queue queue;
+ struct list_head buffers;
+ /*
+ * Protects concurrent calls of buf queue / irq handler
+ * and buffer handling related variables / lists
+ */
+ spinlock_t irqlock;
+ /* mutex used as vdev and queue lock */
+ struct mutex lock;
+ u32 sequence;
+ struct media_pipeline pipe;
+ struct v4l2_subdev *s_subdev;
+
+ enum dcmipp_state state;
+
+ /*
+ * DCMIPP driver is handling 2 buffers
+ * active: buffer into which DCMIPP is currently writing into
+ * next: buffer given to the DCMIPP and which will become
+ * automatically active on next VSYNC
+ */
+ struct dcmipp_buf *active, *next;
+
+ void __iomem *regs;
+
+ u32 cmier;
+ u32 cmsr2;
+
+ struct {
+ u32 errors;
+ u32 limit;
+ u32 overrun;
+ u32 buffers;
+ u32 vsync;
+ u32 frame;
+ u32 it;
+ u32 underrun;
+ u32 nactive;
+ } count;
+};
+
+static const struct v4l2_pix_format fmt_default = {
+ .width = DCMIPP_FMT_WIDTH_DEFAULT,
+ .height = DCMIPP_FMT_HEIGHT_DEFAULT,
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .field = V4L2_FIELD_NONE,
+ .bytesperline = DCMIPP_FMT_WIDTH_DEFAULT * 2,
+ .sizeimage = DCMIPP_FMT_WIDTH_DEFAULT * DCMIPP_FMT_HEIGHT_DEFAULT * 2,
+ .colorspace = DCMIPP_COLORSPACE_DEFAULT,
+ .ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT,
+ .quantization = DCMIPP_QUANTIZATION_DEFAULT,
+ .xfer_func = DCMIPP_XFER_FUNC_DEFAULT,
+};
+
+static int dcmipp_bytecap_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, DCMIPP_PDEV_NAME, sizeof(cap->driver));
+ strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card));
+
+ return 0;
+}
+
+static int dcmipp_bytecap_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct dcmipp_bytecap_device *vcap = video_drvdata(file);
+
+ f->fmt.pix = vcap->format;
+
+ return 0;
+}
+
+static int dcmipp_bytecap_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct dcmipp_bytecap_device *vcap = video_drvdata(file);
+ struct v4l2_pix_format *format = &f->fmt.pix;
+ const struct dcmipp_bytecap_pix_map *vpix;
+ u32 in_w, in_h;
+
+ /* Don't accept a pixelformat that is not on the table */
+ vpix = dcmipp_bytecap_pix_map_by_pixelformat(format->pixelformat);
+ if (!vpix)
+ format->pixelformat = fmt_default.pixelformat;
+
+ /* Adjust width & height */
+ in_w = format->width;
+ in_h = format->height;
+ v4l_bound_align_image(&format->width, DCMIPP_FRAME_MIN_WIDTH,
+ DCMIPP_FRAME_MAX_WIDTH, 0, &format->height,
+ DCMIPP_FRAME_MIN_HEIGHT, DCMIPP_FRAME_MAX_HEIGHT,
+ 0, 0);
+ if (format->width != in_w || format->height != in_h)
+ dev_dbg(vcap->dev, "resolution updated: %dx%d -> %dx%d\n",
+ in_w, in_h, format->width, format->height);
+
+ if (format->pixelformat == V4L2_PIX_FMT_JPEG) {
+ format->bytesperline = format->width;
+ format->sizeimage = format->bytesperline * format->height;
+ } else {
+ v4l2_fill_pixfmt(format, format->pixelformat,
+ format->width, format->height);
+ }
+
+ if (format->field == V4L2_FIELD_ANY)
+ format->field = fmt_default.field;
+
+ dcmipp_colorimetry_clamp(format);
+
+ return 0;
+}
+
+static int dcmipp_bytecap_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct dcmipp_bytecap_device *vcap = video_drvdata(file);
+ int ret;
+
+ /* Do not change the format while stream is on */
+ if (vb2_is_busy(&vcap->queue))
+ return -EBUSY;
+
+ ret = dcmipp_bytecap_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ dev_dbg(vcap->dev, "%s: format update: old:%ux%u (0x%p4cc, %u, %u, %u, %u) new:%ux%d (0x%p4cc, %u, %u, %u, %u)\n",
+ vcap->vdev.name,
+ /* old */
+ vcap->format.width, vcap->format.height,
+ &vcap->format.pixelformat, vcap->format.colorspace,
+ vcap->format.quantization, vcap->format.xfer_func,
+ vcap->format.ycbcr_enc,
+ /* new */
+ f->fmt.pix.width, f->fmt.pix.height,
+ &f->fmt.pix.pixelformat, f->fmt.pix.colorspace,
+ f->fmt.pix.quantization, f->fmt.pix.xfer_func,
+ f->fmt.pix.ycbcr_enc);
+
+ vcap->format = f->fmt.pix;
+
+ return 0;
+}
+
+static int dcmipp_bytecap_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ const struct dcmipp_bytecap_pix_map *vpix;
+ unsigned int index = f->index;
+ unsigned int i;
+
+ if (f->mbus_code) {
+ /*
+ * If a media bus code is specified, only enumerate formats
+ * compatible with it.
+ */
+ for (i = 0; i < ARRAY_SIZE(dcmipp_bytecap_pix_map_list); i++) {
+ vpix = &dcmipp_bytecap_pix_map_list[i];
+ if (vpix->code != f->mbus_code)
+ continue;
+
+ if (index == 0)
+ break;
+
+ index--;
+ }
+
+ if (i == ARRAY_SIZE(dcmipp_bytecap_pix_map_list))
+ return -EINVAL;
+ } else {
+ /* Otherwise, enumerate all formats. */
+ if (f->index >= ARRAY_SIZE(dcmipp_bytecap_pix_map_list))
+ return -EINVAL;
+
+ vpix = &dcmipp_bytecap_pix_map_list[f->index];
+ }
+
+ f->pixelformat = vpix->pixelformat;
+
+ return 0;
+}
+
+static int dcmipp_bytecap_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ const struct dcmipp_bytecap_pix_map *vpix;
+
+ if (fsize->index)
+ return -EINVAL;
+
+ /* Only accept code in the pix map table */
+ vpix = dcmipp_bytecap_pix_map_by_pixelformat(fsize->pixel_format);
+ if (!vpix)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ fsize->stepwise.min_width = DCMIPP_FRAME_MIN_WIDTH;
+ fsize->stepwise.max_width = DCMIPP_FRAME_MAX_WIDTH;
+ fsize->stepwise.min_height = DCMIPP_FRAME_MIN_HEIGHT;
+ fsize->stepwise.max_height = DCMIPP_FRAME_MAX_HEIGHT;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
+static const struct v4l2_file_operations dcmipp_bytecap_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap,
+};
+
+static const struct v4l2_ioctl_ops dcmipp_bytecap_ioctl_ops = {
+ .vidioc_querycap = dcmipp_bytecap_querycap,
+
+ .vidioc_g_fmt_vid_cap = dcmipp_bytecap_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = dcmipp_bytecap_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = dcmipp_bytecap_try_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = dcmipp_bytecap_enum_fmt_vid_cap,
+ .vidioc_enum_framesizes = dcmipp_bytecap_enum_framesizes,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+static int dcmipp_pipeline_s_stream(struct dcmipp_bytecap_device *vcap,
+ int state)
+{
+ struct media_pad *pad;
+ int ret;
+
+ /*
+ * Get source subdev - since link is IMMUTABLE, pointer is cached
+ * within the dcmipp_bytecap_device structure
+ */
+ if (!vcap->s_subdev) {
+ pad = media_pad_remote_pad_first(&vcap->vdev.entity.pads[0]);
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ return -EINVAL;
+ vcap->s_subdev = media_entity_to_v4l2_subdev(pad->entity);
+ }
+
+ ret = v4l2_subdev_call(vcap->s_subdev, video, s_stream, state);
+ if (ret < 0) {
+ dev_err(vcap->dev, "failed to %s streaming (%d)\n",
+ state ? "start" : "stop", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void dcmipp_start_capture(struct dcmipp_bytecap_device *vcap,
+ struct dcmipp_buf *buf)
+{
+ /* Set buffer address */
+ reg_write(vcap, DCMIPP_P0PPM0AR1, buf->addr);
+
+ /* Set buffer size */
+ reg_write(vcap, DCMIPP_P0DCLMTR, DCMIPP_P0DCLMTR_ENABLE |
+ ((buf->size / 4) & DCMIPP_P0DCLMTR_LIMIT_MASK));
+
+ /* Capture request */
+ reg_set(vcap, DCMIPP_P0FCTCR, DCMIPP_P0FCTCR_CPTREQ);
+}
+
+static void dcmipp_bytecap_all_buffers_done(struct dcmipp_bytecap_device *vcap,
+ enum vb2_buffer_state state)
+{
+ struct dcmipp_buf *buf, *node;
+
+ list_for_each_entry_safe(buf, node, &vcap->buffers, list) {
+ list_del_init(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ }
+}
+
+static int dcmipp_bytecap_start_streaming(struct vb2_queue *vq,
+ unsigned int count)
+{
+ struct dcmipp_bytecap_device *vcap = vb2_get_drv_priv(vq);
+ struct media_entity *entity = &vcap->vdev.entity;
+ struct dcmipp_buf *buf;
+ int ret;
+
+ vcap->sequence = 0;
+ memset(&vcap->count, 0, sizeof(vcap->count));
+
+ ret = pm_runtime_resume_and_get(vcap->dev);
+ if (ret < 0) {
+ dev_err(vcap->dev, "%s: Failed to start streaming, cannot get sync (%d)\n",
+ __func__, ret);
+ goto err_buffer_done;
+ }
+
+ ret = media_pipeline_start(entity->pads, &vcap->pipe);
+ if (ret) {
+ dev_dbg(vcap->dev, "%s: Failed to start streaming, media pipeline start error (%d)\n",
+ __func__, ret);
+ goto err_pm_put;
+ }
+
+ ret = dcmipp_pipeline_s_stream(vcap, 1);
+ if (ret)
+ goto err_media_pipeline_stop;
+
+ spin_lock_irq(&vcap->irqlock);
+
+ /* Enable pipe at the end of programming */
+ reg_set(vcap, DCMIPP_P0FSCR, DCMIPP_P0FSCR_PIPEN);
+
+ /*
+ * vb2 framework guarantee that we have at least 'min_queued_buffers'
+ * buffers in the list at this moment
+ */
+ vcap->next = list_first_entry(&vcap->buffers, typeof(*buf), list);
+ dev_dbg(vcap->dev, "Start with next [%d] %p phy=%pad\n",
+ vcap->next->vb.vb2_buf.index, vcap->next, &vcap->next->addr);
+
+ dcmipp_start_capture(vcap, vcap->next);
+
+ /* Enable interruptions */
+ vcap->cmier |= DCMIPP_CMIER_P0ALL;
+ reg_set(vcap, DCMIPP_CMIER, vcap->cmier);
+
+ vcap->state = DCMIPP_RUNNING;
+
+ spin_unlock_irq(&vcap->irqlock);
+
+ return 0;
+
+err_media_pipeline_stop:
+ media_pipeline_stop(entity->pads);
+err_pm_put:
+ pm_runtime_put(vcap->dev);
+err_buffer_done:
+ spin_lock_irq(&vcap->irqlock);
+ /*
+ * Return all buffers to vb2 in QUEUED state.
+ * This will give ownership back to userspace
+ */
+ dcmipp_bytecap_all_buffers_done(vcap, VB2_BUF_STATE_QUEUED);
+ vcap->active = NULL;
+ spin_unlock_irq(&vcap->irqlock);
+
+ return ret;
+}
+
+static void dcmipp_dump_status(struct dcmipp_bytecap_device *vcap)
+{
+ struct device *dev = vcap->dev;
+
+ dev_dbg(dev, "[DCMIPP_PRSR] =%#10.8x\n", reg_read(vcap, DCMIPP_PRSR));
+ dev_dbg(dev, "[DCMIPP_P0SR] =%#10.8x\n", reg_read(vcap, DCMIPP_P0SR));
+ dev_dbg(dev, "[DCMIPP_P0DCCNTR]=%#10.8x\n",
+ reg_read(vcap, DCMIPP_P0DCCNTR));
+ dev_dbg(dev, "[DCMIPP_CMSR1] =%#10.8x\n", reg_read(vcap, DCMIPP_CMSR1));
+ dev_dbg(dev, "[DCMIPP_CMSR2] =%#10.8x\n", reg_read(vcap, DCMIPP_CMSR2));
+}
+
+/*
+ * Stop the stream engine. Any remaining buffers in the stream queue are
+ * dequeued and passed on to the vb2 framework marked as STATE_ERROR.
+ */
+static void dcmipp_bytecap_stop_streaming(struct vb2_queue *vq)
+{
+ struct dcmipp_bytecap_device *vcap = vb2_get_drv_priv(vq);
+ int ret;
+ u32 status;
+
+ dcmipp_pipeline_s_stream(vcap, 0);
+
+ /* Stop the media pipeline */
+ media_pipeline_stop(vcap->vdev.entity.pads);
+
+ /* Disable interruptions */
+ reg_clear(vcap, DCMIPP_CMIER, vcap->cmier);
+
+ /* Stop capture */
+ reg_clear(vcap, DCMIPP_P0FCTCR, DCMIPP_P0FCTCR_CPTREQ);
+
+ /* Wait until CPTACT become 0 */
+ ret = readl_relaxed_poll_timeout(vcap->regs + DCMIPP_P0SR, status,
+ !(status & DCMIPP_P0SR_CPTACT),
+ 20 * USEC_PER_MSEC,
+ 1000 * USEC_PER_MSEC);
+ if (ret)
+ dev_warn(vcap->dev, "Timeout when stopping\n");
+
+ /* Disable pipe */
+ reg_clear(vcap, DCMIPP_P0FSCR, DCMIPP_P0FSCR_PIPEN);
+
+ spin_lock_irq(&vcap->irqlock);
+
+ /* Return all queued buffers to vb2 in ERROR state */
+ dcmipp_bytecap_all_buffers_done(vcap, VB2_BUF_STATE_ERROR);
+ INIT_LIST_HEAD(&vcap->buffers);
+
+ vcap->active = NULL;
+ vcap->state = DCMIPP_STOPPED;
+
+ spin_unlock_irq(&vcap->irqlock);
+
+ dcmipp_dump_status(vcap);
+
+ pm_runtime_put(vcap->dev);
+
+ if (vcap->count.errors)
+ dev_warn(vcap->dev, "Some errors found while streaming: errors=%d (overrun=%d, limit=%d, nactive=%d), underrun=%d, buffers=%d\n",
+ vcap->count.errors, vcap->count.overrun,
+ vcap->count.limit, vcap->count.nactive,
+ vcap->count.underrun, vcap->count.buffers);
+}
+
+static int dcmipp_bytecap_buf_prepare(struct vb2_buffer *vb)
+{
+ struct dcmipp_bytecap_device *vcap = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct dcmipp_buf *buf = container_of(vbuf, struct dcmipp_buf, vb);
+ unsigned long size;
+
+ size = vcap->format.sizeimage;
+
+ if (vb2_plane_size(vb, 0) < size) {
+ dev_err(vcap->dev, "%s data will not fit into plane (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, 0, size);
+
+ if (!buf->prepared) {
+ /* Get memory addresses */
+ buf->addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
+ buf->size = vb2_plane_size(&buf->vb.vb2_buf, 0);
+ buf->prepared = true;
+
+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size);
+
+ dev_dbg(vcap->dev, "Setup [%d] phy=%pad size=%zu\n",
+ vb->index, &buf->addr, buf->size);
+ }
+
+ return 0;
+}
+
+static void dcmipp_bytecap_buf_queue(struct vb2_buffer *vb2_buf)
+{
+ struct dcmipp_bytecap_device *vcap =
+ vb2_get_drv_priv(vb2_buf->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2_buf);
+ struct dcmipp_buf *buf = container_of(vbuf, struct dcmipp_buf, vb);
+
+ dev_dbg(vcap->dev, "Queue [%d] %p phy=%pad\n", buf->vb.vb2_buf.index,
+ buf, &buf->addr);
+
+ spin_lock_irq(&vcap->irqlock);
+ list_add_tail(&buf->list, &vcap->buffers);
+
+ if (vcap->state == DCMIPP_WAIT_FOR_BUFFER) {
+ vcap->next = buf;
+ dev_dbg(vcap->dev, "Restart with next [%d] %p phy=%pad\n",
+ buf->vb.vb2_buf.index, buf, &buf->addr);
+
+ dcmipp_start_capture(vcap, buf);
+
+ vcap->state = DCMIPP_RUNNING;
+ }
+
+ spin_unlock_irq(&vcap->irqlock);
+}
+
+static int dcmipp_bytecap_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers,
+ unsigned int *nplanes,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct dcmipp_bytecap_device *vcap = vb2_get_drv_priv(vq);
+ unsigned int size;
+
+ size = vcap->format.sizeimage;
+
+ /* Make sure the image size is large enough */
+ if (*nplanes)
+ return sizes[0] < vcap->format.sizeimage ? -EINVAL : 0;
+
+ *nplanes = 1;
+ sizes[0] = vcap->format.sizeimage;
+
+ dev_dbg(vcap->dev, "Setup queue, count=%d, size=%d\n",
+ *nbuffers, size);
+
+ return 0;
+}
+
+static int dcmipp_bytecap_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct dcmipp_buf *buf = container_of(vbuf, struct dcmipp_buf, vb);
+
+ INIT_LIST_HEAD(&buf->list);
+
+ return 0;
+}
+
+static const struct vb2_ops dcmipp_bytecap_qops = {
+ .start_streaming = dcmipp_bytecap_start_streaming,
+ .stop_streaming = dcmipp_bytecap_stop_streaming,
+ .buf_init = dcmipp_bytecap_buf_init,
+ .buf_prepare = dcmipp_bytecap_buf_prepare,
+ .buf_queue = dcmipp_bytecap_buf_queue,
+ .queue_setup = dcmipp_bytecap_queue_setup,
+ /*
+ * Since q->lock is set we can use the standard
+ * vb2_ops_wait_prepare/finish helper functions.
+ */
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static void dcmipp_bytecap_release(struct video_device *vdev)
+{
+ struct dcmipp_bytecap_device *vcap =
+ container_of(vdev, struct dcmipp_bytecap_device, vdev);
+
+ dcmipp_pads_cleanup(vcap->ved.pads);
+ mutex_destroy(&vcap->lock);
+
+ kfree(vcap);
+}
+
+void dcmipp_bytecap_ent_release(struct dcmipp_ent_device *ved)
+{
+ struct dcmipp_bytecap_device *vcap =
+ container_of(ved, struct dcmipp_bytecap_device, ved);
+
+ media_entity_cleanup(ved->ent);
+ vb2_video_unregister_device(&vcap->vdev);
+}
+
+static void dcmipp_buffer_done(struct dcmipp_bytecap_device *vcap,
+ struct dcmipp_buf *buf,
+ size_t bytesused,
+ int err)
+{
+ struct vb2_v4l2_buffer *vbuf;
+
+ list_del_init(&buf->list);
+
+ vbuf = &buf->vb;
+
+ vbuf->sequence = vcap->sequence++;
+ vbuf->field = V4L2_FIELD_NONE;
+ vbuf->vb2_buf.timestamp = ktime_get_ns();
+ vb2_set_plane_payload(&vbuf->vb2_buf, 0, bytesused);
+ vb2_buffer_done(&vbuf->vb2_buf,
+ err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+ dev_dbg(vcap->dev, "Done [%d] %p phy=%pad\n", buf->vb.vb2_buf.index,
+ buf, &buf->addr);
+ vcap->count.buffers++;
+}
+
+/* irqlock must be held */
+static void
+dcmipp_bytecap_set_next_frame_or_stop(struct dcmipp_bytecap_device *vcap)
+{
+ if (!vcap->next && list_is_singular(&vcap->buffers)) {
+ /*
+ * If there is no available buffer (none or a single one in the
+ * list while two are expected), stop the capture (effective
+ * for next frame). On-going frame capture will continue until
+ * FRAME END but no further capture will be done.
+ */
+ reg_clear(vcap, DCMIPP_P0FCTCR, DCMIPP_P0FCTCR_CPTREQ);
+
+ dev_dbg(vcap->dev, "Capture restart is deferred to next buffer queueing\n");
+ vcap->next = NULL;
+ vcap->state = DCMIPP_WAIT_FOR_BUFFER;
+ return;
+ }
+
+ /* If we don't have buffer yet, pick the one after active */
+ if (!vcap->next)
+ vcap->next = list_next_entry(vcap->active, list);
+
+ /*
+ * Set buffer address
+ * This register is shadowed and will be taken into
+ * account on next VSYNC (start of next frame)
+ */
+ reg_write(vcap, DCMIPP_P0PPM0AR1, vcap->next->addr);
+ dev_dbg(vcap->dev, "Write [%d] %p phy=%pad\n",
+ vcap->next->vb.vb2_buf.index, vcap->next, &vcap->next->addr);
+}
+
+/* irqlock must be held */
+static void dcmipp_bytecap_process_frame(struct dcmipp_bytecap_device *vcap,
+ size_t bytesused)
+{
+ int err = 0;
+ struct dcmipp_buf *buf = vcap->active;
+
+ if (!buf) {
+ vcap->count.nactive++;
+ vcap->count.errors++;
+ return;
+ }
+
+ if (bytesused > buf->size) {
+ dev_dbg(vcap->dev, "frame larger than expected (%zu > %zu)\n",
+ bytesused, buf->size);
+ /* Clip to buffer size and return buffer to V4L2 in error */
+ bytesused = buf->size;
+ vcap->count.limit++;
+ vcap->count.errors++;
+ err = -EOVERFLOW;
+ }
+
+ dcmipp_buffer_done(vcap, buf, bytesused, err);
+ vcap->active = NULL;
+}
+
+static irqreturn_t dcmipp_bytecap_irq_thread(int irq, void *arg)
+{
+ struct dcmipp_bytecap_device *vcap =
+ container_of(arg, struct dcmipp_bytecap_device, ved);
+ size_t bytesused = 0;
+ u32 cmsr2;
+
+ spin_lock_irq(&vcap->irqlock);
+
+ cmsr2 = vcap->cmsr2 & vcap->cmier;
+
+ /*
+ * If we have an overrun, a frame-end will probably not be generated,
+ * in that case the active buffer will be recycled as next buffer by
+ * the VSYNC handler
+ */
+ if (cmsr2 & DCMIPP_CMSR2_P0OVRF) {
+ vcap->count.errors++;
+ vcap->count.overrun++;
+ }
+
+ if (cmsr2 & DCMIPP_CMSR2_P0FRAMEF) {
+ vcap->count.frame++;
+
+ /* Read captured buffer size */
+ bytesused = reg_read(vcap, DCMIPP_P0DCCNTR);
+ dcmipp_bytecap_process_frame(vcap, bytesused);
+ }
+
+ if (cmsr2 & DCMIPP_CMSR2_P0VSYNCF) {
+ vcap->count.vsync++;
+ if (vcap->state == DCMIPP_WAIT_FOR_BUFFER) {
+ vcap->count.underrun++;
+ goto out;
+ }
+
+ /*
+ * On VSYNC, the previously set next buffer is going to become
+ * active thanks to the shadowing mechanism of the DCMIPP. In
+ * most of the cases, since a FRAMEEND has already come,
+ * pointer next is NULL since active is reset during the
+ * FRAMEEND handling. However, in case of framerate adjustment,
+ * there are more VSYNC than FRAMEEND. Thus we recycle the
+ * active (but not used) buffer and put it back into next.
+ */
+ swap(vcap->active, vcap->next);
+ dcmipp_bytecap_set_next_frame_or_stop(vcap);
+ }
+
+out:
+ spin_unlock_irq(&vcap->irqlock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dcmipp_bytecap_irq_callback(int irq, void *arg)
+{
+ struct dcmipp_bytecap_device *vcap =
+ container_of(arg, struct dcmipp_bytecap_device, ved);
+
+ /* Store interrupt status register */
+ vcap->cmsr2 = reg_read(vcap, DCMIPP_CMSR2) & vcap->cmier;
+ vcap->count.it++;
+
+ /* Clear interrupt */
+ reg_write(vcap, DCMIPP_CMFCR, vcap->cmsr2);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static int dcmipp_bytecap_link_validate(struct media_link *link)
+{
+ struct media_entity *entity = link->sink->entity;
+ struct video_device *vd = media_entity_to_video_device(entity);
+ struct dcmipp_bytecap_device *vcap = container_of(vd,
+ struct dcmipp_bytecap_device, vdev);
+ struct v4l2_subdev *source_sd =
+ media_entity_to_v4l2_subdev(link->source->entity);
+ struct v4l2_subdev_format source_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .pad = link->source->index,
+ };
+ const struct dcmipp_bytecap_pix_map *vpix;
+ int ret;
+
+ ret = v4l2_subdev_call(source_sd, pad, get_fmt, NULL, &source_fmt);
+ if (ret < 0)
+ return 0;
+
+ if (source_fmt.format.width != vcap->format.width ||
+ source_fmt.format.height != vcap->format.height) {
+ dev_err(vcap->dev, "Wrong width or height %ux%u (%ux%u expected)\n",
+ vcap->format.width, vcap->format.height,
+ source_fmt.format.width, source_fmt.format.height);
+ return -EINVAL;
+ }
+
+ vpix = dcmipp_bytecap_pix_map_by_pixelformat(vcap->format.pixelformat);
+ if (source_fmt.format.code != vpix->code) {
+ dev_err(vcap->dev, "Wrong mbus_code 0x%x, (0x%x expected)\n",
+ vpix->code, source_fmt.format.code);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct media_entity_operations dcmipp_bytecap_entity_ops = {
+ .link_validate = dcmipp_bytecap_link_validate,
+};
+
+struct dcmipp_ent_device *dcmipp_bytecap_ent_init(struct device *dev,
+ const char *entity_name,
+ struct v4l2_device *v4l2_dev,
+ void __iomem *regs)
+{
+ struct dcmipp_bytecap_device *vcap;
+ struct video_device *vdev;
+ struct vb2_queue *q;
+ const unsigned long pad_flag = MEDIA_PAD_FL_SINK;
+ int ret = 0;
+
+ /* Allocate the dcmipp_bytecap_device struct */
+ vcap = kzalloc(sizeof(*vcap), GFP_KERNEL);
+ if (!vcap)
+ return ERR_PTR(-ENOMEM);
+
+ /* Allocate the pads */
+ vcap->ved.pads = dcmipp_pads_init(1, &pad_flag);
+ if (IS_ERR(vcap->ved.pads)) {
+ ret = PTR_ERR(vcap->ved.pads);
+ goto err_free_vcap;
+ }
+
+ /* Initialize the media entity */
+ vcap->vdev.entity.name = entity_name;
+ vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L;
+ vcap->vdev.entity.ops = &dcmipp_bytecap_entity_ops;
+ ret = media_entity_pads_init(&vcap->vdev.entity, 1, vcap->ved.pads);
+ if (ret)
+ goto err_clean_pads;
+
+ /* Initialize the lock */
+ mutex_init(&vcap->lock);
+
+ /* Initialize the vb2 queue */
+ q = &vcap->queue;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
+ q->lock = &vcap->lock;
+ q->drv_priv = vcap;
+ q->buf_struct_size = sizeof(struct dcmipp_buf);
+ q->ops = &dcmipp_bytecap_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_queued_buffers = 1;
+ q->dev = dev;
+
+ /* DCMIPP requires 16 bytes aligned buffers */
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32) & ~0x0f);
+ if (ret) {
+ dev_err(dev, "Failed to set DMA mask\n");
+ goto err_mutex_destroy;
+ }
+
+ ret = vb2_queue_init(q);
+ if (ret) {
+ dev_err(dev, "%s: vb2 queue init failed (err=%d)\n",
+ entity_name, ret);
+ goto err_clean_m_ent;
+ }
+
+ /* Initialize buffer list and its lock */
+ INIT_LIST_HEAD(&vcap->buffers);
+ spin_lock_init(&vcap->irqlock);
+
+ /* Set default frame format */
+ vcap->format = fmt_default;
+
+ /* Fill the dcmipp_ent_device struct */
+ vcap->ved.ent = &vcap->vdev.entity;
+ vcap->ved.handler = dcmipp_bytecap_irq_callback;
+ vcap->ved.thread_fn = dcmipp_bytecap_irq_thread;
+ vcap->dev = dev;
+ vcap->regs = regs;
+
+ /* Initialize the video_device struct */
+ vdev = &vcap->vdev;
+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_IO_MC;
+ vdev->release = dcmipp_bytecap_release;
+ vdev->fops = &dcmipp_bytecap_fops;
+ vdev->ioctl_ops = &dcmipp_bytecap_ioctl_ops;
+ vdev->lock = &vcap->lock;
+ vdev->queue = q;
+ vdev->v4l2_dev = v4l2_dev;
+ strscpy(vdev->name, entity_name, sizeof(vdev->name));
+ video_set_drvdata(vdev, &vcap->ved);
+
+ /* Register the video_device with the v4l2 and the media framework */
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ dev_err(dev, "%s: video register failed (err=%d)\n",
+ vcap->vdev.name, ret);
+ goto err_clean_m_ent;
+ }
+
+ return &vcap->ved;
+
+err_clean_m_ent:
+ media_entity_cleanup(&vcap->vdev.entity);
+err_mutex_destroy:
+ mutex_destroy(&vcap->lock);
+err_clean_pads:
+ dcmipp_pads_cleanup(vcap->ved.pads);
+err_free_vcap:
+ kfree(vcap);
+
+ return ERR_PTR(ret);
+}
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
new file mode 100644
index 000000000000..5a361ad6b023
--- /dev/null
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-byteproc.c
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for STM32 Digital Camera Memory Interface Pixel Processor
+ *
+ * Copyright (C) STMicroelectronics SA 2023
+ * Authors: Hugues Fruchet <[email protected]>
+ * Alain Volmat <[email protected]>
+ * for STMicroelectronics.
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-rect.h>
+#include <media/v4l2-subdev.h>
+
+#include "dcmipp-common.h"
+
+#define DCMIPP_P0FCTCR 0x500
+#define DCMIPP_P0FCTCR_FRATE_MASK GENMASK(1, 0)
+#define DCMIPP_P0SCSTR 0x504
+#define DCMIPP_P0SCSTR_HSTART_SHIFT 0
+#define DCMIPP_P0SCSTR_VSTART_SHIFT 16
+#define DCMIPP_P0SCSZR 0x508
+#define DCMIPP_P0SCSZR_ENABLE BIT(31)
+#define DCMIPP_P0SCSZR_HSIZE_SHIFT 0
+#define DCMIPP_P0SCSZR_VSIZE_SHIFT 16
+#define DCMIPP_P0PPCR 0x5c0
+#define DCMIPP_P0PPCR_BSM_1_2 0x1
+#define DCMIPP_P0PPCR_BSM_1_4 0x2
+#define DCMIPP_P0PPCR_BSM_2_4 0x3
+#define DCMIPP_P0PPCR_BSM_MASK GENMASK(8, 7)
+#define DCMIPP_P0PPCR_BSM_SHIFT 0x7
+#define DCMIPP_P0PPCR_LSM BIT(10)
+#define DCMIPP_P0PPCR_OELS BIT(11)
+
+#define IS_SINK(pad) (!(pad))
+#define IS_SRC(pad) ((pad))
+
+struct dcmipp_byteproc_pix_map {
+ unsigned int code;
+ unsigned int bpp;
+};
+
+#define PIXMAP_MBUS_BPP(mbus, byteperpixel) \
+ { \
+ .code = MEDIA_BUS_FMT_##mbus, \
+ .bpp = byteperpixel, \
+ }
+static const struct dcmipp_byteproc_pix_map dcmipp_byteproc_pix_map_list[] = {
+ PIXMAP_MBUS_BPP(RGB565_2X8_LE, 2),
+ PIXMAP_MBUS_BPP(YUYV8_2X8, 2),
+ PIXMAP_MBUS_BPP(YVYU8_2X8, 2),
+ PIXMAP_MBUS_BPP(UYVY8_2X8, 2),
+ PIXMAP_MBUS_BPP(VYUY8_2X8, 2),
+ PIXMAP_MBUS_BPP(Y8_1X8, 1),
+ PIXMAP_MBUS_BPP(SBGGR8_1X8, 1),
+ PIXMAP_MBUS_BPP(SGBRG8_1X8, 1),
+ PIXMAP_MBUS_BPP(SGRBG8_1X8, 1),
+ PIXMAP_MBUS_BPP(SRGGB8_1X8, 1),
+ PIXMAP_MBUS_BPP(JPEG_1X8, 1),
+};
+
+static const struct dcmipp_byteproc_pix_map *
+dcmipp_byteproc_pix_map_by_code(u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dcmipp_byteproc_pix_map_list); i++) {
+ if (dcmipp_byteproc_pix_map_list[i].code == code)
+ return &dcmipp_byteproc_pix_map_list[i];
+ }
+
+ return NULL;
+}
+
+struct dcmipp_byteproc_device {
+ struct dcmipp_ent_device ved;
+ struct v4l2_subdev sd;
+ struct device *dev;
+ void __iomem *regs;
+ bool streaming;
+};
+
+static const struct v4l2_mbus_framefmt fmt_default = {
+ .width = DCMIPP_FMT_WIDTH_DEFAULT,
+ .height = DCMIPP_FMT_HEIGHT_DEFAULT,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = DCMIPP_COLORSPACE_DEFAULT,
+ .ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT,
+ .quantization = DCMIPP_QUANTIZATION_DEFAULT,
+ .xfer_func = DCMIPP_XFER_FUNC_DEFAULT,
+};
+
+static const struct v4l2_rect crop_min = {
+ .width = DCMIPP_FRAME_MIN_WIDTH,
+ .height = DCMIPP_FRAME_MIN_HEIGHT,
+ .top = 0,
+ .left = 0,
+};
+
+static void dcmipp_byteproc_adjust_crop(struct v4l2_rect *r,
+ struct v4l2_rect *compose)
+{
+ /* Disallow rectangles smaller than the minimal one. */
+ v4l2_rect_set_min_size(r, &crop_min);
+ v4l2_rect_map_inside(r, compose);
+}
+
+static void dcmipp_byteproc_adjust_compose(struct v4l2_rect *r,
+ const struct v4l2_mbus_framefmt *fmt)
+{
+ r->top = 0;
+ r->left = 0;
+
+ /* Compose is not possible for JPEG or Bayer formats */
+ if (fmt->code == MEDIA_BUS_FMT_JPEG_1X8 ||
+ fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
+ fmt->code == MEDIA_BUS_FMT_SGBRG8_1X8 ||
+ fmt->code == MEDIA_BUS_FMT_SGRBG8_1X8 ||
+ fmt->code == MEDIA_BUS_FMT_SRGGB8_1X8) {
+ r->width = fmt->width;
+ r->height = fmt->height;
+ return;
+ }
+
+ /* Adjust height - we can only perform 1/2 decimation */
+ if (r->height <= (fmt->height / 2))
+ r->height = fmt->height / 2;
+ else
+ r->height = fmt->height;
+
+ /* Adjust width /2 or /4 for 8bits formats and /2 for 16bits formats */
+ if (fmt->code == MEDIA_BUS_FMT_Y8_1X8 && r->width <= (fmt->width / 4))
+ r->width = fmt->width / 4;
+ else if (r->width <= (fmt->width / 2))
+ r->width = fmt->width / 2;
+ else
+ r->width = fmt->width;
+}
+
+static void dcmipp_byteproc_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
+{
+ const struct dcmipp_byteproc_pix_map *vpix;
+
+ /* Only accept code in the pix map table */
+ vpix = dcmipp_byteproc_pix_map_by_code(fmt->code);
+ if (!vpix)
+ fmt->code = fmt_default.code;
+
+ fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH,
+ DCMIPP_FRAME_MAX_WIDTH) & ~1;
+ fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT,
+ DCMIPP_FRAME_MAX_HEIGHT) & ~1;
+
+ if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE)
+ fmt->field = fmt_default.field;
+
+ dcmipp_colorimetry_clamp(fmt);
+}
+
+static int dcmipp_byteproc_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ unsigned int i;
+
+ for (i = 0; i < sd->entity.num_pads; i++) {
+ struct v4l2_mbus_framefmt *mf;
+ struct v4l2_rect *r;
+
+ mf = v4l2_subdev_state_get_format(sd_state, i);
+ *mf = fmt_default;
+
+ if (IS_SINK(i))
+ r = v4l2_subdev_state_get_compose(sd_state, i);
+ else
+ r = v4l2_subdev_state_get_crop(sd_state, i);
+
+ r->top = 0;
+ r->left = 0;
+ r->width = DCMIPP_FMT_WIDTH_DEFAULT;
+ r->height = DCMIPP_FMT_HEIGHT_DEFAULT;
+ }
+
+ return 0;
+}
+
+static int
+dcmipp_byteproc_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ const struct dcmipp_byteproc_pix_map *vpix;
+ struct v4l2_mbus_framefmt *sink_fmt;
+
+ if (IS_SINK(code->pad)) {
+ if (code->index >= ARRAY_SIZE(dcmipp_byteproc_pix_map_list))
+ return -EINVAL;
+ vpix = &dcmipp_byteproc_pix_map_list[code->index];
+ code->code = vpix->code;
+ } else {
+ /* byteproc doesn't support transformation on format */
+ if (code->index > 0)
+ return -EINVAL;
+
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
+ code->code = sink_fmt->code;
+ }
+
+ return 0;
+}
+
+static int
+dcmipp_byteproc_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct v4l2_rect *compose;
+
+ if (fse->index)
+ return -EINVAL;
+
+ fse->min_width = DCMIPP_FRAME_MIN_WIDTH;
+ fse->min_height = DCMIPP_FRAME_MIN_HEIGHT;
+
+ if (IS_SINK(fse->pad)) {
+ fse->max_width = DCMIPP_FRAME_MAX_WIDTH;
+ fse->max_height = DCMIPP_FRAME_MAX_HEIGHT;
+ } else {
+ compose = v4l2_subdev_state_get_compose(sd_state, 0);
+ fse->max_width = compose->width;
+ fse->max_height = compose->height;
+ }
+
+ return 0;
+}
+
+static int dcmipp_byteproc_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *mf;
+ struct v4l2_rect *crop, *compose;
+
+ if (byteproc->streaming)
+ return -EBUSY;
+
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
+
+ crop = v4l2_subdev_state_get_crop(sd_state, 1);
+ compose = v4l2_subdev_state_get_compose(sd_state, 0);
+
+ if (IS_SRC(fmt->pad)) {
+ fmt->format = *v4l2_subdev_state_get_format(sd_state, 0);
+ fmt->format.width = crop->width;
+ fmt->format.height = crop->height;
+ } else {
+ dcmipp_byteproc_adjust_fmt(&fmt->format);
+ crop->top = 0;
+ crop->left = 0;
+ crop->width = fmt->format.width;
+ crop->height = fmt->format.height;
+ *compose = *crop;
+ /* Set the same format on SOURCE pad as well */
+ *v4l2_subdev_state_get_format(sd_state, 1) = fmt->format;
+ }
+ *mf = fmt->format;
+
+ return 0;
+}
+
+static int dcmipp_byteproc_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *s)
+{
+ struct v4l2_mbus_framefmt *sink_fmt;
+ struct v4l2_rect *crop, *compose;
+
+ /*
+ * In the HW, the decimation block is located prior to the crop hence:
+ * Compose is done on the sink pad
+ * Crop is done on the src pad
+ */
+ if (IS_SINK(s->pad) &&
+ (s->target == V4L2_SEL_TGT_CROP ||
+ s->target == V4L2_SEL_TGT_CROP_BOUNDS ||
+ s->target == V4L2_SEL_TGT_CROP_DEFAULT))
+ return -EINVAL;
+
+ if (IS_SRC(s->pad) &&
+ (s->target == V4L2_SEL_TGT_COMPOSE ||
+ s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS ||
+ s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT))
+ return -EINVAL;
+
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
+ crop = v4l2_subdev_state_get_crop(sd_state, 1);
+ compose = v4l2_subdev_state_get_compose(sd_state, 0);
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP:
+ s->r = *crop;
+ break;
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ s->r = *compose;
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ s->r = *compose;
+ break;
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ s->r.top = 0;
+ s->r.left = 0;
+ s->r.width = sink_fmt->width;
+ s->r.height = sink_fmt->height;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int dcmipp_byteproc_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *s)
+{
+ struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *mf;
+ struct v4l2_rect *crop, *compose;
+
+ /*
+ * In the HW, the decimation block is located prior to the crop hence:
+ * Compose is done on the sink pad
+ * Crop is done on the src pad
+ */
+ if ((s->target == V4L2_SEL_TGT_CROP ||
+ s->target == V4L2_SEL_TGT_CROP_BOUNDS ||
+ s->target == V4L2_SEL_TGT_CROP_DEFAULT) && IS_SINK(s->pad))
+ return -EINVAL;
+
+ if ((s->target == V4L2_SEL_TGT_COMPOSE ||
+ s->target == V4L2_SEL_TGT_COMPOSE_BOUNDS ||
+ s->target == V4L2_SEL_TGT_COMPOSE_DEFAULT) && IS_SRC(s->pad))
+ return -EINVAL;
+
+ crop = v4l2_subdev_state_get_crop(sd_state, 1);
+ compose = v4l2_subdev_state_get_compose(sd_state, 0);
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP:
+ dcmipp_byteproc_adjust_crop(&s->r, compose);
+
+ *crop = s->r;
+ mf = v4l2_subdev_state_get_format(sd_state, 1);
+ mf->width = s->r.width;
+ mf->height = s->r.height;
+
+ dev_dbg(byteproc->dev, "s_selection: crop %ux%u@(%u,%u)\n",
+ crop->width, crop->height, crop->left, crop->top);
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ mf = v4l2_subdev_state_get_format(sd_state, 0);
+ dcmipp_byteproc_adjust_compose(&s->r, mf);
+ *compose = s->r;
+ *crop = s->r;
+
+ mf = v4l2_subdev_state_get_format(sd_state, 1);
+ mf->width = s->r.width;
+ mf->height = s->r.height;
+
+ dev_dbg(byteproc->dev, "s_selection: compose %ux%u@(%u,%u)\n",
+ compose->width, compose->height,
+ compose->left, compose->top);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops dcmipp_byteproc_pad_ops = {
+ .enum_mbus_code = dcmipp_byteproc_enum_mbus_code,
+ .enum_frame_size = dcmipp_byteproc_enum_frame_size,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = dcmipp_byteproc_set_fmt,
+ .get_selection = dcmipp_byteproc_get_selection,
+ .set_selection = dcmipp_byteproc_set_selection,
+};
+
+static int dcmipp_byteproc_configure_scale_crop
+ (struct dcmipp_byteproc_device *byteproc)
+{
+ const struct dcmipp_byteproc_pix_map *vpix;
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_framefmt *sink_fmt;
+ u32 hprediv, vprediv;
+ struct v4l2_rect *compose, *crop;
+ u32 val = 0;
+
+ state = v4l2_subdev_lock_and_get_active_state(&byteproc->sd);
+ sink_fmt = v4l2_subdev_state_get_format(state, 0);
+ compose = v4l2_subdev_state_get_compose(state, 0);
+ crop = v4l2_subdev_state_get_crop(state, 1);
+ v4l2_subdev_unlock_state(state);
+
+ /* find output format bpp */
+ vpix = dcmipp_byteproc_pix_map_by_code(sink_fmt->code);
+ if (!vpix)
+ return -EINVAL;
+
+ /* clear decimation/crop */
+ reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_BSM_MASK);
+ reg_clear(byteproc, DCMIPP_P0PPCR, DCMIPP_P0PPCR_LSM);
+ reg_write(byteproc, DCMIPP_P0SCSTR, 0);
+ reg_write(byteproc, DCMIPP_P0SCSZR, 0);
+
+ /* Ignore decimation/crop with JPEG */
+ if (vpix->code == MEDIA_BUS_FMT_JPEG_1X8)
+ return 0;
+
+ /* decimation */
+ hprediv = sink_fmt->width / compose->width;
+ if (hprediv == 4)
+ val |= DCMIPP_P0PPCR_BSM_1_4 << DCMIPP_P0PPCR_BSM_SHIFT;
+ else if ((vpix->code == MEDIA_BUS_FMT_Y8_1X8) && (hprediv == 2))
+ val |= DCMIPP_P0PPCR_BSM_1_2 << DCMIPP_P0PPCR_BSM_SHIFT;
+ else if (hprediv == 2)
+ val |= DCMIPP_P0PPCR_BSM_2_4 << DCMIPP_P0PPCR_BSM_SHIFT;
+
+ vprediv = sink_fmt->height / compose->height;
+ if (vprediv == 2)
+ val |= DCMIPP_P0PPCR_LSM | DCMIPP_P0PPCR_OELS;
+
+ /* decimate using bytes and lines skipping */
+ if (val) {
+ reg_set(byteproc, DCMIPP_P0PPCR, val);
+
+ dev_dbg(byteproc->dev, "decimate to %dx%d [prediv=%dx%d]\n",
+ compose->width, compose->height,
+ hprediv, vprediv);
+ }
+
+ dev_dbg(byteproc->dev, "crop to %dx%d\n", crop->width, crop->height);
+
+ /* expressed in 32-bits words on X axis, lines on Y axis */
+ reg_write(byteproc, DCMIPP_P0SCSTR,
+ (((crop->left * vpix->bpp) / 4) <<
+ DCMIPP_P0SCSTR_HSTART_SHIFT) |
+ (crop->top << DCMIPP_P0SCSTR_VSTART_SHIFT));
+ reg_write(byteproc, DCMIPP_P0SCSZR,
+ DCMIPP_P0SCSZR_ENABLE |
+ (((crop->width * vpix->bpp) / 4) <<
+ DCMIPP_P0SCSZR_HSIZE_SHIFT) |
+ (crop->height << DCMIPP_P0SCSZR_VSIZE_SHIFT));
+
+ return 0;
+}
+
+static int dcmipp_byteproc_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
+ struct v4l2_subdev *s_subdev;
+ struct media_pad *pad;
+ int ret = 0;
+
+ /* Get source subdev */
+ pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ return -EINVAL;
+ s_subdev = media_entity_to_v4l2_subdev(pad->entity);
+
+ if (enable) {
+ ret = dcmipp_byteproc_configure_scale_crop(byteproc);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_call(s_subdev, video, s_stream, enable);
+ if (ret < 0) {
+ dev_err(byteproc->dev,
+ "failed to start source subdev streaming (%d)\n",
+ ret);
+ return ret;
+ }
+ } else {
+ ret = v4l2_subdev_call(s_subdev, video, s_stream, enable);
+ if (ret < 0) {
+ dev_err(byteproc->dev,
+ "failed to stop source subdev streaming (%d)\n",
+ ret);
+ return ret;
+ }
+ }
+
+ byteproc->streaming = enable;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops dcmipp_byteproc_video_ops = {
+ .s_stream = dcmipp_byteproc_s_stream,
+};
+
+static const struct v4l2_subdev_ops dcmipp_byteproc_ops = {
+ .pad = &dcmipp_byteproc_pad_ops,
+ .video = &dcmipp_byteproc_video_ops,
+};
+
+static void dcmipp_byteproc_release(struct v4l2_subdev *sd)
+{
+ struct dcmipp_byteproc_device *byteproc = v4l2_get_subdevdata(sd);
+
+ kfree(byteproc);
+}
+
+static const struct v4l2_subdev_internal_ops dcmipp_byteproc_int_ops = {
+ .init_state = dcmipp_byteproc_init_state,
+ .release = dcmipp_byteproc_release,
+};
+
+void dcmipp_byteproc_ent_release(struct dcmipp_ent_device *ved)
+{
+ struct dcmipp_byteproc_device *byteproc =
+ container_of(ved, struct dcmipp_byteproc_device, ved);
+
+ dcmipp_ent_sd_unregister(ved, &byteproc->sd);
+}
+
+struct dcmipp_ent_device *
+dcmipp_byteproc_ent_init(struct device *dev, const char *entity_name,
+ struct v4l2_device *v4l2_dev, void __iomem *regs)
+{
+ struct dcmipp_byteproc_device *byteproc;
+ const unsigned long pads_flag[] = {
+ MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE,
+ };
+ int ret;
+
+ /* Allocate the byteproc struct */
+ byteproc = kzalloc(sizeof(*byteproc), GFP_KERNEL);
+ if (!byteproc)
+ return ERR_PTR(-ENOMEM);
+
+ byteproc->regs = regs;
+
+ /* Initialize ved and sd */
+ ret = dcmipp_ent_sd_register(&byteproc->ved, &byteproc->sd,
+ v4l2_dev, entity_name,
+ MEDIA_ENT_F_PROC_VIDEO_SCALER,
+ ARRAY_SIZE(pads_flag), pads_flag,
+ &dcmipp_byteproc_int_ops,
+ &dcmipp_byteproc_ops,
+ NULL, NULL);
+ if (ret) {
+ kfree(byteproc);
+ return ERR_PTR(ret);
+ }
+
+ byteproc->dev = dev;
+
+ return &byteproc->ved;
+}
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.c
new file mode 100644
index 000000000000..562933e08d62
--- /dev/null
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for STM32 Digital Camera Memory Interface Pixel Processor
+ *
+ * Copyright (C) STMicroelectronics SA 2023
+ * Authors: Hugues Fruchet <[email protected]>
+ * Alain Volmat <[email protected]>
+ * for STMicroelectronics.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include "dcmipp-common.h"
+
+/* Helper function to allocate and initialize pads */
+struct media_pad *dcmipp_pads_init(u16 num_pads, const unsigned long *pads_flags)
+{
+ struct media_pad *pads;
+ unsigned int i;
+
+ /* Allocate memory for the pads */
+ pads = kcalloc(num_pads, sizeof(*pads), GFP_KERNEL);
+ if (!pads)
+ return ERR_PTR(-ENOMEM);
+
+ /* Initialize the pads */
+ for (i = 0; i < num_pads; i++) {
+ pads[i].index = i;
+ pads[i].flags = pads_flags[i];
+ }
+
+ return pads;
+}
+
+static const struct media_entity_operations dcmipp_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+int dcmipp_ent_sd_register(struct dcmipp_ent_device *ved,
+ struct v4l2_subdev *sd,
+ struct v4l2_device *v4l2_dev,
+ const char *const name,
+ u32 function,
+ u16 num_pads,
+ const unsigned long *pads_flag,
+ const struct v4l2_subdev_internal_ops *sd_int_ops,
+ const struct v4l2_subdev_ops *sd_ops,
+ irq_handler_t handler,
+ irq_handler_t thread_fn)
+{
+ int ret;
+
+ /* Allocate the pads. Should be released from the sd_int_op release */
+ ved->pads = dcmipp_pads_init(num_pads, pads_flag);
+ if (IS_ERR(ved->pads))
+ return PTR_ERR(ved->pads);
+
+ /* Fill the dcmipp_ent_device struct */
+ ved->ent = &sd->entity;
+
+ /* Initialize the subdev */
+ v4l2_subdev_init(sd, sd_ops);
+ sd->internal_ops = sd_int_ops;
+ sd->entity.function = function;
+ sd->entity.ops = &dcmipp_entity_ops;
+ sd->owner = THIS_MODULE;
+ strscpy(sd->name, name, sizeof(sd->name));
+ v4l2_set_subdevdata(sd, ved);
+
+ /* Expose this subdev to user space */
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ if (sd->ctrl_handler)
+ sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+
+ /* Initialize the media entity */
+ ret = media_entity_pads_init(&sd->entity, num_pads, ved->pads);
+ if (ret)
+ goto err_clean_pads;
+
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret < 0)
+ goto err_clean_m_ent;
+
+ /* Register the subdev with the v4l2 and the media framework */
+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
+ if (ret) {
+ dev_err(v4l2_dev->dev,
+ "%s: subdev register failed (err=%d)\n",
+ name, ret);
+ goto err_clean_m_ent;
+ }
+
+ ved->handler = handler;
+ ved->thread_fn = thread_fn;
+
+ return 0;
+
+err_clean_m_ent:
+ media_entity_cleanup(&sd->entity);
+err_clean_pads:
+ dcmipp_pads_cleanup(ved->pads);
+ return ret;
+}
+
+void
+dcmipp_ent_sd_unregister(struct dcmipp_ent_device *ved, struct v4l2_subdev *sd)
+{
+ media_entity_cleanup(ved->ent);
+ v4l2_device_unregister_subdev(sd);
+}
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.h b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.h
new file mode 100644
index 000000000000..7a7cf43baf24
--- /dev/null
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-common.h
@@ -0,0 +1,217 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Driver for STM32 Digital Camera Memory Interface Pixel Processor
+ *
+ * Copyright (C) STMicroelectronics SA 2023
+ * Authors: Hugues Fruchet <[email protected]>
+ * Alain Volmat <[email protected]>
+ * for STMicroelectronics.
+ */
+
+#ifndef _DCMIPP_COMMON_H_
+#define _DCMIPP_COMMON_H_
+
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <media/media-device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#define DCMIPP_PDEV_NAME "dcmipp"
+
+#define DCMIPP_FRAME_MAX_WIDTH 4096
+#define DCMIPP_FRAME_MAX_HEIGHT 2160
+#define DCMIPP_FRAME_MIN_WIDTH 16
+#define DCMIPP_FRAME_MIN_HEIGHT 16
+
+#define DCMIPP_FMT_WIDTH_DEFAULT 640
+#define DCMIPP_FMT_HEIGHT_DEFAULT 480
+
+#define DCMIPP_COLORSPACE_DEFAULT V4L2_COLORSPACE_REC709
+#define DCMIPP_YCBCR_ENC_DEFAULT V4L2_YCBCR_ENC_DEFAULT
+#define DCMIPP_QUANTIZATION_DEFAULT V4L2_QUANTIZATION_DEFAULT
+#define DCMIPP_XFER_FUNC_DEFAULT V4L2_XFER_FUNC_DEFAULT
+
+/**
+ * dcmipp_colorimetry_clamp() - Adjust colorimetry parameters
+ *
+ * @fmt: the pointer to struct v4l2_pix_format or
+ * struct v4l2_mbus_framefmt
+ *
+ * Entities must check if colorimetry given by the userspace is valid, if not
+ * then set them as DEFAULT
+ */
+#define dcmipp_colorimetry_clamp(fmt) \
+do { \
+ if ((fmt)->colorspace == V4L2_COLORSPACE_DEFAULT || \
+ (fmt)->colorspace > V4L2_COLORSPACE_DCI_P3) { \
+ (fmt)->colorspace = DCMIPP_COLORSPACE_DEFAULT; \
+ (fmt)->ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT; \
+ (fmt)->quantization = DCMIPP_QUANTIZATION_DEFAULT; \
+ (fmt)->xfer_func = DCMIPP_XFER_FUNC_DEFAULT; \
+ } \
+ if ((fmt)->ycbcr_enc > V4L2_YCBCR_ENC_SMPTE240M) \
+ (fmt)->ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT; \
+ if ((fmt)->quantization > V4L2_QUANTIZATION_LIM_RANGE) \
+ (fmt)->quantization = DCMIPP_QUANTIZATION_DEFAULT; \
+ if ((fmt)->xfer_func > V4L2_XFER_FUNC_SMPTE2084) \
+ (fmt)->xfer_func = DCMIPP_XFER_FUNC_DEFAULT; \
+} while (0)
+
+/**
+ * struct dcmipp_ent_device - core struct that represents a node in the topology
+ *
+ * @ent: the pointer to struct media_entity for the node
+ * @pads: the list of pads of the node
+ * @bus: struct v4l2_mbus_config_parallel describing input bus
+ * @bus_type: type of input bus (parallel or BT656)
+ * @handler: irq handler dedicated to the subdev
+ * @handler_ret: value returned by the irq handler
+ * @thread_fn: threaded irq handler
+ *
+ * The DCMIPP provides a single IRQ line and a IRQ status registers for all
+ * subdevs, hence once the main irq handler (registered at probe time) is
+ * called, it will chain calls to the irq handler of each the subdevs of the
+ * pipelines, using the handler/handler_ret/thread_fn variables.
+ *
+ * Each node of the topology must create a dcmipp_ent_device struct.
+ * Depending on the node it will be of an instance of v4l2_subdev or
+ * video_device struct where both contains a struct media_entity.
+ * Those structures should embedded the dcmipp_ent_device struct through
+ * v4l2_set_subdevdata() and video_set_drvdata() respectivaly, allowing the
+ * dcmipp_ent_device struct to be retrieved from the corresponding struct
+ * media_entity
+ */
+struct dcmipp_ent_device {
+ struct media_entity *ent;
+ struct media_pad *pads;
+
+ /* Parallel input device */
+ struct v4l2_mbus_config_parallel bus;
+ enum v4l2_mbus_type bus_type;
+ irq_handler_t handler;
+ irqreturn_t handler_ret;
+ irq_handler_t thread_fn;
+};
+
+/**
+ * dcmipp_pads_init - initialize pads
+ *
+ * @num_pads: number of pads to initialize
+ * @pads_flags: flags to use in each pad
+ *
+ * Helper functions to allocate/initialize pads
+ */
+struct media_pad *dcmipp_pads_init(u16 num_pads,
+ const unsigned long *pads_flags);
+
+/**
+ * dcmipp_pads_cleanup - free pads
+ *
+ * @pads: pointer to the pads
+ *
+ * Helper function to free the pads initialized with dcmipp_pads_init
+ */
+static inline void dcmipp_pads_cleanup(struct media_pad *pads)
+{
+ kfree(pads);
+}
+
+/**
+ * dcmipp_ent_sd_register - initialize and register a subdev node
+ *
+ * @ved: the dcmipp_ent_device struct to be initialize
+ * @sd: the v4l2_subdev struct to be initialize and registered
+ * @v4l2_dev: the v4l2 device to register the v4l2_subdev
+ * @name: name of the sub-device. Please notice that the name must be
+ * unique.
+ * @function: media entity function defined by MEDIA_ENT_F_* macros
+ * @num_pads: number of pads to initialize
+ * @pads_flag: flags to use in each pad
+ * @sd_int_ops: pointer to &struct v4l2_subdev_internal_ops
+ * @sd_ops: pointer to &struct v4l2_subdev_ops.
+ * @handler: func pointer of the irq handler
+ * @thread_fn: func pointer of the threaded irq handler
+ *
+ * Helper function initialize and register the struct dcmipp_ent_device and
+ * struct v4l2_subdev which represents a subdev node in the topology
+ */
+int dcmipp_ent_sd_register(struct dcmipp_ent_device *ved,
+ struct v4l2_subdev *sd,
+ struct v4l2_device *v4l2_dev,
+ const char *const name,
+ u32 function,
+ u16 num_pads,
+ const unsigned long *pads_flag,
+ const struct v4l2_subdev_internal_ops *sd_int_ops,
+ const struct v4l2_subdev_ops *sd_ops,
+ irq_handler_t handler,
+ irq_handler_t thread_fn);
+
+/**
+ * dcmipp_ent_sd_unregister - cleanup and unregister a subdev node
+ *
+ * @ved: the dcmipp_ent_device struct to be cleaned up
+ * @sd: the v4l2_subdev struct to be unregistered
+ *
+ * Helper function cleanup and unregister the struct dcmipp_ent_device and
+ * struct v4l2_subdev which represents a subdev node in the topology
+ */
+void dcmipp_ent_sd_unregister(struct dcmipp_ent_device *ved,
+ struct v4l2_subdev *sd);
+
+#define reg_write(device, reg, val) \
+ (__reg_write((device)->dev, (device)->regs, (reg), (val)))
+#define reg_read(device, reg) \
+ (__reg_read((device)->dev, (device)->regs, (reg)))
+#define reg_set(device, reg, mask) \
+ (__reg_set((device)->dev, (device)->regs, (reg), (mask)))
+#define reg_clear(device, reg, mask) \
+ (__reg_clear((device)->dev, (device)->regs, (reg), (mask)))
+
+static inline u32 __reg_read(struct device *dev, void __iomem *base, u32 reg)
+{
+ u32 val = readl_relaxed(base + reg);
+
+ dev_dbg(dev, "RD 0x%x %#10.8x\n", reg, val);
+ return val;
+}
+
+static inline void __reg_write(struct device *dev, void __iomem *base, u32 reg,
+ u32 val)
+{
+ dev_dbg(dev, "WR 0x%x %#10.8x\n", reg, val);
+ writel_relaxed(val, base + reg);
+}
+
+static inline void __reg_set(struct device *dev, void __iomem *base, u32 reg,
+ u32 mask)
+{
+ dev_dbg(dev, "SET 0x%x %#10.8x\n", reg, mask);
+ __reg_write(dev, base, reg, readl_relaxed(base + reg) | mask);
+}
+
+static inline void __reg_clear(struct device *dev, void __iomem *base, u32 reg,
+ u32 mask)
+{
+ dev_dbg(dev, "CLR 0x%x %#10.8x\n", reg, mask);
+ __reg_write(dev, base, reg, readl_relaxed(base + reg) & ~mask);
+}
+
+/* DCMIPP subdev init / release entry points */
+struct dcmipp_ent_device *dcmipp_par_ent_init(struct device *dev,
+ const char *entity_name,
+ struct v4l2_device *v4l2_dev,
+ void __iomem *regs);
+void dcmipp_par_ent_release(struct dcmipp_ent_device *ved);
+struct dcmipp_ent_device *
+dcmipp_byteproc_ent_init(struct device *dev, const char *entity_name,
+ struct v4l2_device *v4l2_dev, void __iomem *regs);
+void dcmipp_byteproc_ent_release(struct dcmipp_ent_device *ved);
+struct dcmipp_ent_device *dcmipp_bytecap_ent_init(struct device *dev,
+ const char *entity_name,
+ struct v4l2_device *v4l2_dev,
+ void __iomem *regs);
+void dcmipp_bytecap_ent_release(struct dcmipp_ent_device *ved);
+
+#endif
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c
new file mode 100644
index 000000000000..32c6619be9a2
--- /dev/null
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c
@@ -0,0 +1,604 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for STM32 Digital Camera Memory Interface Pixel Processor
+ *
+ * Copyright (C) STMicroelectronics SA 2023
+ * Authors: Hugues Fruchet <[email protected]>
+ * Alain Volmat <[email protected]>
+ * for STMicroelectronics.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/reset.h>
+#include <media/media-device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#include "dcmipp-common.h"
+
+#define DCMIPP_MDEV_MODEL_NAME "DCMIPP MDEV"
+
+#define DCMIPP_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \
+ .src_ent = src, \
+ .src_pad = srcpad, \
+ .sink_ent = sink, \
+ .sink_pad = sinkpad, \
+ .flags = link_flags, \
+}
+
+struct dcmipp_device {
+ /* The platform device */
+ struct platform_device pdev;
+ struct device *dev;
+
+ /* Hardware resources */
+ void __iomem *regs;
+ struct clk *kclk;
+
+ /* The pipeline configuration */
+ const struct dcmipp_pipeline_config *pipe_cfg;
+
+ /* The Associated media_device parent */
+ struct media_device mdev;
+
+ /* Internal v4l2 parent device*/
+ struct v4l2_device v4l2_dev;
+
+ /* Entities */
+ struct dcmipp_ent_device **entity;
+
+ struct v4l2_async_notifier notifier;
+};
+
+static inline struct dcmipp_device *
+notifier_to_dcmipp(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct dcmipp_device, notifier);
+}
+
+/* Structure which describes individual configuration for each entity */
+struct dcmipp_ent_config {
+ const char *name;
+ struct dcmipp_ent_device *(*init)
+ (struct device *dev, const char *entity_name,
+ struct v4l2_device *v4l2_dev, void __iomem *regs);
+ void (*release)(struct dcmipp_ent_device *ved);
+};
+
+/* Structure which describes links between entities */
+struct dcmipp_ent_link {
+ unsigned int src_ent;
+ u16 src_pad;
+ unsigned int sink_ent;
+ u16 sink_pad;
+ u32 flags;
+};
+
+/* Structure which describes the whole topology */
+struct dcmipp_pipeline_config {
+ const struct dcmipp_ent_config *ents;
+ size_t num_ents;
+ const struct dcmipp_ent_link *links;
+ size_t num_links;
+};
+
+/* --------------------------------------------------------------------------
+ * Topology Configuration
+ */
+
+static const struct dcmipp_ent_config stm32mp13_ent_config[] = {
+ {
+ .name = "dcmipp_parallel",
+ .init = dcmipp_par_ent_init,
+ .release = dcmipp_par_ent_release,
+ },
+ {
+ .name = "dcmipp_dump_postproc",
+ .init = dcmipp_byteproc_ent_init,
+ .release = dcmipp_byteproc_ent_release,
+ },
+ {
+ .name = "dcmipp_dump_capture",
+ .init = dcmipp_bytecap_ent_init,
+ .release = dcmipp_bytecap_ent_release,
+ },
+};
+
+#define ID_PARALLEL 0
+#define ID_DUMP_BYTEPROC 1
+#define ID_DUMP_CAPTURE 2
+
+static const struct dcmipp_ent_link stm32mp13_ent_links[] = {
+ DCMIPP_ENT_LINK(ID_PARALLEL, 1, ID_DUMP_BYTEPROC, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+ DCMIPP_ENT_LINK(ID_DUMP_BYTEPROC, 1, ID_DUMP_CAPTURE, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+};
+
+static const struct dcmipp_pipeline_config stm32mp13_pipe_cfg = {
+ .ents = stm32mp13_ent_config,
+ .num_ents = ARRAY_SIZE(stm32mp13_ent_config),
+ .links = stm32mp13_ent_links,
+ .num_links = ARRAY_SIZE(stm32mp13_ent_links)
+};
+
+#define LINK_FLAG_TO_STR(f) ((f) == 0 ? "" :\
+ (f) == MEDIA_LNK_FL_ENABLED ? "ENABLED" :\
+ (f) == MEDIA_LNK_FL_IMMUTABLE ? "IMMUTABLE" :\
+ (f) == (MEDIA_LNK_FL_ENABLED |\
+ MEDIA_LNK_FL_IMMUTABLE) ?\
+ "ENABLED, IMMUTABLE" :\
+ "UNKNOWN")
+
+static int dcmipp_create_links(struct dcmipp_device *dcmipp)
+{
+ unsigned int i;
+ int ret;
+
+ /* Initialize the links between entities */
+ for (i = 0; i < dcmipp->pipe_cfg->num_links; i++) {
+ const struct dcmipp_ent_link *link =
+ &dcmipp->pipe_cfg->links[i];
+ struct dcmipp_ent_device *ved_src =
+ dcmipp->entity[link->src_ent];
+ struct dcmipp_ent_device *ved_sink =
+ dcmipp->entity[link->sink_ent];
+
+ dev_dbg(dcmipp->dev, "Create link \"%s\":%d -> %d:\"%s\" [%s]\n",
+ dcmipp->pipe_cfg->ents[link->src_ent].name,
+ link->src_pad, link->sink_pad,
+ dcmipp->pipe_cfg->ents[link->sink_ent].name,
+ LINK_FLAG_TO_STR(link->flags));
+
+ ret = media_create_pad_link(ved_src->ent, link->src_pad,
+ ved_sink->ent, link->sink_pad,
+ link->flags);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dcmipp_graph_init(struct dcmipp_device *dcmipp);
+
+static int dcmipp_create_subdevs(struct dcmipp_device *dcmipp)
+{
+ int ret, i;
+
+ /* Call all subdev inits */
+ for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) {
+ const char *name = dcmipp->pipe_cfg->ents[i].name;
+
+ dev_dbg(dcmipp->dev, "add subdev %s\n", name);
+ dcmipp->entity[i] =
+ dcmipp->pipe_cfg->ents[i].init(dcmipp->dev, name,
+ &dcmipp->v4l2_dev,
+ dcmipp->regs);
+ if (IS_ERR(dcmipp->entity[i])) {
+ dev_err(dcmipp->dev, "failed to init subdev %s\n",
+ name);
+ ret = PTR_ERR(dcmipp->entity[i]);
+ goto err_init_entity;
+ }
+ }
+
+ /* Initialize links */
+ ret = dcmipp_create_links(dcmipp);
+ if (ret)
+ goto err_init_entity;
+
+ ret = dcmipp_graph_init(dcmipp);
+ if (ret < 0)
+ goto err_init_entity;
+
+ return 0;
+
+err_init_entity:
+ while (i > 0)
+ dcmipp->pipe_cfg->ents[i - 1].release(dcmipp->entity[i - 1]);
+ return ret;
+}
+
+static const struct of_device_id dcmipp_of_match[] = {
+ { .compatible = "st,stm32mp13-dcmipp", .data = &stm32mp13_pipe_cfg },
+ { /* end node */ },
+};
+MODULE_DEVICE_TABLE(of, dcmipp_of_match);
+
+static irqreturn_t dcmipp_irq_thread(int irq, void *arg)
+{
+ struct dcmipp_device *dcmipp = arg;
+ struct dcmipp_ent_device *ved;
+ unsigned int i;
+
+ /* Call irq thread of each entities of pipeline */
+ for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) {
+ ved = dcmipp->entity[i];
+ if (ved->thread_fn && ved->handler_ret == IRQ_WAKE_THREAD)
+ ved->thread_fn(irq, ved);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dcmipp_irq_callback(int irq, void *arg)
+{
+ struct dcmipp_device *dcmipp = arg;
+ struct dcmipp_ent_device *ved;
+ irqreturn_t ret = IRQ_HANDLED;
+ unsigned int i;
+
+ /* Call irq handler of each entities of pipeline */
+ for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++) {
+ ved = dcmipp->entity[i];
+ if (ved->handler)
+ ved->handler_ret = ved->handler(irq, ved);
+ else if (ved->thread_fn)
+ ved->handler_ret = IRQ_WAKE_THREAD;
+ else
+ ved->handler_ret = IRQ_HANDLED;
+ if (ved->handler_ret != IRQ_HANDLED)
+ ret = ved->handler_ret;
+ }
+
+ return ret;
+}
+
+static int dcmipp_graph_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_connection *asd)
+{
+ struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier);
+ unsigned int ret;
+ int src_pad;
+ struct dcmipp_ent_device *sink;
+ struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_PARALLEL };
+ struct fwnode_handle *ep;
+
+ dev_dbg(dcmipp->dev, "Subdev \"%s\" bound\n", subdev->name);
+
+ /*
+ * Link this sub-device to DCMIPP, it could be
+ * a parallel camera sensor or a CSI-2 to parallel bridge
+ */
+ src_pad = media_entity_get_fwnode_pad(&subdev->entity,
+ subdev->fwnode,
+ MEDIA_PAD_FL_SOURCE);
+
+ /* Get bus characteristics from devicetree */
+ ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dcmipp->dev), 0, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+ if (!ep) {
+ dev_err(dcmipp->dev, "Could not find the endpoint\n");
+ return -ENODEV;
+ }
+
+ /* Check for parallel bus-type first, then bt656 */
+ ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+ if (ret) {
+ vep.bus_type = V4L2_MBUS_BT656;
+ ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+ if (ret) {
+ dev_err(dcmipp->dev, "Could not parse the endpoint\n");
+ fwnode_handle_put(ep);
+ return ret;
+ }
+ }
+
+ fwnode_handle_put(ep);
+
+ if (vep.bus.parallel.bus_width == 0) {
+ dev_err(dcmipp->dev, "Invalid parallel interface bus-width\n");
+ return -ENODEV;
+ }
+
+ /* Only 8 bits bus width supported with BT656 bus */
+ if (vep.bus_type == V4L2_MBUS_BT656 &&
+ vep.bus.parallel.bus_width != 8) {
+ dev_err(dcmipp->dev, "BT656 bus conflicts with %u bits bus width (8 bits required)\n",
+ vep.bus.parallel.bus_width);
+ return -ENODEV;
+ }
+
+ /* Parallel input device detected, connect it to parallel subdev */
+ sink = dcmipp->entity[ID_PARALLEL];
+ sink->bus.flags = vep.bus.parallel.flags;
+ sink->bus.bus_width = vep.bus.parallel.bus_width;
+ sink->bus.data_shift = vep.bus.parallel.data_shift;
+ sink->bus_type = vep.bus_type;
+ ret = media_create_pad_link(&subdev->entity, src_pad, sink->ent, 0,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret) {
+ dev_err(dcmipp->dev, "Failed to create media pad link with subdev \"%s\"\n",
+ subdev->name);
+ return ret;
+ }
+
+ dev_dbg(dcmipp->dev, "DCMIPP is now linked to \"%s\"\n", subdev->name);
+
+ return 0;
+}
+
+static void dcmipp_graph_notify_unbind(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_connection *asd)
+{
+ struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier);
+
+ dev_dbg(dcmipp->dev, "Removing %s\n", sd->name);
+}
+
+static int dcmipp_graph_notify_complete(struct v4l2_async_notifier *notifier)
+{
+ struct dcmipp_device *dcmipp = notifier_to_dcmipp(notifier);
+ int ret;
+
+ /* Register the media device */
+ ret = media_device_register(&dcmipp->mdev);
+ if (ret) {
+ dev_err(dcmipp->mdev.dev,
+ "media device register failed (err=%d)\n", ret);
+ return ret;
+ }
+
+ /* Expose all subdev's nodes*/
+ ret = v4l2_device_register_subdev_nodes(&dcmipp->v4l2_dev);
+ if (ret) {
+ dev_err(dcmipp->mdev.dev,
+ "dcmipp subdev nodes registration failed (err=%d)\n",
+ ret);
+ media_device_unregister(&dcmipp->mdev);
+ return ret;
+ }
+
+ dev_dbg(dcmipp->dev, "Notify complete !\n");
+
+ return 0;
+}
+
+static const struct v4l2_async_notifier_operations dcmipp_graph_notify_ops = {
+ .bound = dcmipp_graph_notify_bound,
+ .unbind = dcmipp_graph_notify_unbind,
+ .complete = dcmipp_graph_notify_complete,
+};
+
+static int dcmipp_graph_init(struct dcmipp_device *dcmipp)
+{
+ struct v4l2_async_connection *asd;
+ struct fwnode_handle *ep;
+ int ret;
+
+ ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dcmipp->dev), 0, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+ if (!ep) {
+ dev_err(dcmipp->dev, "Failed to get next endpoint\n");
+ return -EINVAL;
+ }
+
+ v4l2_async_nf_init(&dcmipp->notifier, &dcmipp->v4l2_dev);
+
+ asd = v4l2_async_nf_add_fwnode_remote(&dcmipp->notifier, ep,
+ struct v4l2_async_connection);
+
+ fwnode_handle_put(ep);
+
+ if (IS_ERR(asd)) {
+ dev_err(dcmipp->dev, "Failed to add fwnode remote subdev\n");
+ return PTR_ERR(asd);
+ }
+
+ dcmipp->notifier.ops = &dcmipp_graph_notify_ops;
+
+ ret = v4l2_async_nf_register(&dcmipp->notifier);
+ if (ret < 0) {
+ dev_err(dcmipp->dev, "Failed to register notifier\n");
+ v4l2_async_nf_cleanup(&dcmipp->notifier);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dcmipp_probe(struct platform_device *pdev)
+{
+ struct dcmipp_device *dcmipp;
+ struct clk *kclk;
+ const struct dcmipp_pipeline_config *pipe_cfg;
+ struct reset_control *rstc;
+ int irq;
+ int ret;
+
+ dcmipp = devm_kzalloc(&pdev->dev, sizeof(*dcmipp), GFP_KERNEL);
+ if (!dcmipp)
+ return -ENOMEM;
+
+ dcmipp->dev = &pdev->dev;
+
+ pipe_cfg = device_get_match_data(dcmipp->dev);
+ if (!pipe_cfg) {
+ dev_err(&pdev->dev, "Can't get device data\n");
+ return -ENODEV;
+ }
+ dcmipp->pipe_cfg = pipe_cfg;
+
+ platform_set_drvdata(pdev, dcmipp);
+
+ /* Get hardware resources from devicetree */
+ rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+ if (IS_ERR(rstc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(rstc),
+ "Could not get reset control\n");
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ if (irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Could not get irq\n");
+ return irq ? irq : -ENXIO;
+ }
+
+ dcmipp->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+ if (IS_ERR(dcmipp->regs)) {
+ dev_err(&pdev->dev, "Could not map registers\n");
+ return PTR_ERR(dcmipp->regs);
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, dcmipp_irq_callback,
+ dcmipp_irq_thread, IRQF_ONESHOT,
+ dev_name(&pdev->dev), dcmipp);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
+ return ret;
+ }
+
+ /* Reset device */
+ ret = reset_control_assert(rstc);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to assert the reset line\n");
+ return ret;
+ }
+
+ usleep_range(3000, 5000);
+
+ ret = reset_control_deassert(rstc);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to deassert the reset line\n");
+ return ret;
+ }
+
+ kclk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(kclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(kclk),
+ "Unable to get kclk\n");
+ dcmipp->kclk = kclk;
+
+ dcmipp->entity = devm_kcalloc(&pdev->dev, dcmipp->pipe_cfg->num_ents,
+ sizeof(*dcmipp->entity), GFP_KERNEL);
+ if (!dcmipp->entity)
+ return -ENOMEM;
+
+ /* Register the v4l2 struct */
+ ret = v4l2_device_register(&pdev->dev, &dcmipp->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "v4l2 device register failed (err=%d)\n", ret);
+ return ret;
+ }
+
+ /* Link the media device within the v4l2_device */
+ dcmipp->v4l2_dev.mdev = &dcmipp->mdev;
+
+ /* Initialize media device */
+ strscpy(dcmipp->mdev.model, DCMIPP_MDEV_MODEL_NAME,
+ sizeof(dcmipp->mdev.model));
+ dcmipp->mdev.dev = &pdev->dev;
+ media_device_init(&dcmipp->mdev);
+
+ /* Initialize subdevs */
+ ret = dcmipp_create_subdevs(dcmipp);
+ if (ret) {
+ media_device_cleanup(&dcmipp->mdev);
+ v4l2_device_unregister(&dcmipp->v4l2_dev);
+ return ret;
+ }
+
+ pm_runtime_enable(dcmipp->dev);
+
+ dev_info(&pdev->dev, "Probe done");
+
+ return 0;
+}
+
+static int dcmipp_remove(struct platform_device *pdev)
+{
+ struct dcmipp_device *dcmipp = platform_get_drvdata(pdev);
+ unsigned int i;
+
+ pm_runtime_disable(&pdev->dev);
+
+ v4l2_async_nf_unregister(&dcmipp->notifier);
+ v4l2_async_nf_cleanup(&dcmipp->notifier);
+
+ for (i = 0; i < dcmipp->pipe_cfg->num_ents; i++)
+ dcmipp->pipe_cfg->ents[i].release(dcmipp->entity[i]);
+
+ media_device_unregister(&dcmipp->mdev);
+ media_device_cleanup(&dcmipp->mdev);
+
+ v4l2_device_unregister(&dcmipp->v4l2_dev);
+
+ return 0;
+}
+
+static int dcmipp_runtime_suspend(struct device *dev)
+{
+ struct dcmipp_device *dcmipp = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(dcmipp->kclk);
+
+ return 0;
+}
+
+static int dcmipp_runtime_resume(struct device *dev)
+{
+ struct dcmipp_device *dcmipp = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(dcmipp->kclk);
+ if (ret)
+ dev_err(dev, "%s: Failed to prepare_enable kclk\n", __func__);
+
+ return ret;
+}
+
+static int dcmipp_suspend(struct device *dev)
+{
+ /* disable clock */
+ pm_runtime_force_suspend(dev);
+
+ /* change pinctrl state */
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static int dcmipp_resume(struct device *dev)
+{
+ /* restore pinctl default state */
+ pinctrl_pm_select_default_state(dev);
+
+ /* clock enable */
+ pm_runtime_force_resume(dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops dcmipp_pm_ops = {
+ SYSTEM_SLEEP_PM_OPS(dcmipp_suspend, dcmipp_resume)
+ RUNTIME_PM_OPS(dcmipp_runtime_suspend, dcmipp_runtime_resume, NULL)
+};
+
+static struct platform_driver dcmipp_pdrv = {
+ .probe = dcmipp_probe,
+ .remove = dcmipp_remove,
+ .driver = {
+ .name = DCMIPP_PDEV_NAME,
+ .of_match_table = dcmipp_of_match,
+ .pm = pm_ptr(&dcmipp_pm_ops),
+ },
+};
+
+module_platform_driver(dcmipp_pdrv);
+
+MODULE_AUTHOR("Hugues Fruchet <[email protected]>");
+MODULE_AUTHOR("Alain Volmat <[email protected]>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 Digital Camera Memory Interface with Pixel Processor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c
new file mode 100644
index 000000000000..62c5c3331cfe
--- /dev/null
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-parallel.c
@@ -0,0 +1,440 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for STM32 Digital Camera Memory Interface Pixel Processor
+ *
+ * Copyright (C) STMicroelectronics SA 2023
+ * Authors: Hugues Fruchet <[email protected]>
+ * Alain Volmat <[email protected]>
+ * for STMicroelectronics.
+ */
+
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-subdev.h>
+
+#include "dcmipp-common.h"
+
+#define DCMIPP_PRCR 0x104
+#define DCMIPP_PRCR_FORMAT_SHIFT 16
+#define DCMIPP_PRCR_FORMAT_YUV422 0x1e
+#define DCMIPP_PRCR_FORMAT_RGB565 0x22
+#define DCMIPP_PRCR_FORMAT_RAW8 0x2a
+#define DCMIPP_PRCR_FORMAT_G8 0x4a
+#define DCMIPP_PRCR_FORMAT_BYTE_STREAM 0x5a
+#define DCMIPP_PRCR_ESS BIT(4)
+#define DCMIPP_PRCR_PCKPOL BIT(5)
+#define DCMIPP_PRCR_HSPOL BIT(6)
+#define DCMIPP_PRCR_VSPOL BIT(7)
+#define DCMIPP_PRCR_ENABLE BIT(14)
+#define DCMIPP_PRCR_SWAPCYCLES BIT(25)
+
+#define DCMIPP_PRESCR 0x108
+#define DCMIPP_PRESUR 0x10c
+
+#define IS_SINK(pad) (!(pad))
+#define IS_SRC(pad) ((pad))
+
+struct dcmipp_par_pix_map {
+ unsigned int code_sink;
+ unsigned int code_src;
+ u8 prcr_format;
+ u8 prcr_swapcycles;
+};
+
+#define PIXMAP_SINK_SRC_PRCR_SWAP(sink, src, prcr, swap) \
+ { \
+ .code_sink = MEDIA_BUS_FMT_##sink, \
+ .code_src = MEDIA_BUS_FMT_##src, \
+ .prcr_format = DCMIPP_PRCR_FORMAT_##prcr, \
+ .prcr_swapcycles = swap, \
+ }
+static const struct dcmipp_par_pix_map dcmipp_par_pix_map_list[] = {
+ /* RGB565 */
+ PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_LE, RGB565_2X8_LE, RGB565, 1),
+ PIXMAP_SINK_SRC_PRCR_SWAP(RGB565_2X8_BE, RGB565_2X8_LE, RGB565, 0),
+ /* YUV422 */
+ PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, YUYV8_2X8, YUV422, 1),
+ PIXMAP_SINK_SRC_PRCR_SWAP(YUYV8_2X8, UYVY8_2X8, YUV422, 0),
+ PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_2X8, UYVY8_2X8, YUV422, 1),
+ PIXMAP_SINK_SRC_PRCR_SWAP(UYVY8_2X8, YUYV8_2X8, YUV422, 0),
+ PIXMAP_SINK_SRC_PRCR_SWAP(YVYU8_2X8, YVYU8_2X8, YUV422, 1),
+ PIXMAP_SINK_SRC_PRCR_SWAP(VYUY8_2X8, VYUY8_2X8, YUV422, 1),
+ /* GREY */
+ PIXMAP_SINK_SRC_PRCR_SWAP(Y8_1X8, Y8_1X8, G8, 0),
+ /* Raw Bayer */
+ PIXMAP_SINK_SRC_PRCR_SWAP(SBGGR8_1X8, SBGGR8_1X8, RAW8, 0),
+ PIXMAP_SINK_SRC_PRCR_SWAP(SGBRG8_1X8, SGBRG8_1X8, RAW8, 0),
+ PIXMAP_SINK_SRC_PRCR_SWAP(SGRBG8_1X8, SGRBG8_1X8, RAW8, 0),
+ PIXMAP_SINK_SRC_PRCR_SWAP(SRGGB8_1X8, SRGGB8_1X8, RAW8, 0),
+ /* JPEG */
+ PIXMAP_SINK_SRC_PRCR_SWAP(JPEG_1X8, JPEG_1X8, BYTE_STREAM, 0),
+};
+
+/*
+ * Search through the pix_map table, skipping two consecutive entry with the
+ * same code
+ */
+static inline const struct dcmipp_par_pix_map *dcmipp_par_pix_map_by_index
+ (unsigned int index,
+ unsigned int pad)
+{
+ unsigned int i = 0;
+ u32 prev_code = 0, cur_code;
+
+ while (i < ARRAY_SIZE(dcmipp_par_pix_map_list)) {
+ if (IS_SRC(pad))
+ cur_code = dcmipp_par_pix_map_list[i].code_src;
+ else
+ cur_code = dcmipp_par_pix_map_list[i].code_sink;
+
+ if (cur_code == prev_code) {
+ i++;
+ continue;
+ }
+ prev_code = cur_code;
+
+ if (index == 0)
+ break;
+ i++;
+ index--;
+ }
+
+ if (i >= ARRAY_SIZE(dcmipp_par_pix_map_list))
+ return NULL;
+
+ return &dcmipp_par_pix_map_list[i];
+}
+
+static inline const struct dcmipp_par_pix_map *dcmipp_par_pix_map_by_code
+ (u32 code_sink, u32 code_src)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dcmipp_par_pix_map_list); i++) {
+ if ((dcmipp_par_pix_map_list[i].code_sink == code_sink &&
+ dcmipp_par_pix_map_list[i].code_src == code_src) ||
+ (dcmipp_par_pix_map_list[i].code_sink == code_src &&
+ dcmipp_par_pix_map_list[i].code_src == code_sink) ||
+ (dcmipp_par_pix_map_list[i].code_sink == code_sink &&
+ code_src == 0) ||
+ (code_sink == 0 &&
+ dcmipp_par_pix_map_list[i].code_src == code_src))
+ return &dcmipp_par_pix_map_list[i];
+ }
+ return NULL;
+}
+
+struct dcmipp_par_device {
+ struct dcmipp_ent_device ved;
+ struct v4l2_subdev sd;
+ struct device *dev;
+ void __iomem *regs;
+ bool streaming;
+};
+
+static const struct v4l2_mbus_framefmt fmt_default = {
+ .width = DCMIPP_FMT_WIDTH_DEFAULT,
+ .height = DCMIPP_FMT_HEIGHT_DEFAULT,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = DCMIPP_COLORSPACE_DEFAULT,
+ .ycbcr_enc = DCMIPP_YCBCR_ENC_DEFAULT,
+ .quantization = DCMIPP_QUANTIZATION_DEFAULT,
+ .xfer_func = DCMIPP_XFER_FUNC_DEFAULT,
+};
+
+static int dcmipp_par_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ unsigned int i;
+
+ for (i = 0; i < sd->entity.num_pads; i++) {
+ struct v4l2_mbus_framefmt *mf;
+
+ mf = v4l2_subdev_state_get_format(sd_state, i);
+ *mf = fmt_default;
+ }
+
+ return 0;
+}
+
+static int dcmipp_par_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ const struct dcmipp_par_pix_map *vpix =
+ dcmipp_par_pix_map_by_index(code->index, code->pad);
+
+ if (!vpix)
+ return -EINVAL;
+
+ code->code = IS_SRC(code->pad) ? vpix->code_src : vpix->code_sink;
+
+ return 0;
+}
+
+static int dcmipp_par_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ const struct dcmipp_par_pix_map *vpix;
+
+ if (fse->index)
+ return -EINVAL;
+
+ /* Only accept code in the pix map table */
+ vpix = dcmipp_par_pix_map_by_code(IS_SINK(fse->pad) ? fse->code : 0,
+ IS_SRC(fse->pad) ? fse->code : 0);
+ if (!vpix)
+ return -EINVAL;
+
+ fse->min_width = DCMIPP_FRAME_MIN_WIDTH;
+ fse->max_width = DCMIPP_FRAME_MAX_WIDTH;
+ fse->min_height = DCMIPP_FRAME_MIN_HEIGHT;
+ fse->max_height = DCMIPP_FRAME_MAX_HEIGHT;
+
+ return 0;
+}
+
+static void dcmipp_par_adjust_fmt(struct dcmipp_par_device *par,
+ struct v4l2_mbus_framefmt *fmt, __u32 pad)
+{
+ const struct dcmipp_par_pix_map *vpix;
+
+ /* Only accept code in the pix map table */
+ vpix = dcmipp_par_pix_map_by_code(IS_SINK(pad) ? fmt->code : 0,
+ IS_SRC(pad) ? fmt->code : 0);
+ if (!vpix)
+ fmt->code = fmt_default.code;
+
+ /* Exclude JPEG if BT656 bus is selected */
+ if (vpix && vpix->code_sink == MEDIA_BUS_FMT_JPEG_1X8 &&
+ par->ved.bus_type == V4L2_MBUS_BT656)
+ fmt->code = fmt_default.code;
+
+ fmt->width = clamp_t(u32, fmt->width, DCMIPP_FRAME_MIN_WIDTH,
+ DCMIPP_FRAME_MAX_WIDTH) & ~1;
+ fmt->height = clamp_t(u32, fmt->height, DCMIPP_FRAME_MIN_HEIGHT,
+ DCMIPP_FRAME_MAX_HEIGHT) & ~1;
+
+ if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE)
+ fmt->field = fmt_default.field;
+
+ dcmipp_colorimetry_clamp(fmt);
+}
+
+static int dcmipp_par_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct dcmipp_par_device *par = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ if (par->streaming)
+ return -EBUSY;
+
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
+
+ /* Set the new format */
+ dcmipp_par_adjust_fmt(par, &fmt->format, fmt->pad);
+
+ dev_dbg(par->dev, "%s: format update: old:%dx%d (0x%x, %d, %d, %d, %d) new:%dx%d (0x%x, %d, %d, %d, %d)\n",
+ par->sd.name,
+ /* old */
+ mf->width, mf->height, mf->code,
+ mf->colorspace, mf->quantization,
+ mf->xfer_func, mf->ycbcr_enc,
+ /* new */
+ fmt->format.width, fmt->format.height, fmt->format.code,
+ fmt->format.colorspace, fmt->format.quantization,
+ fmt->format.xfer_func, fmt->format.ycbcr_enc);
+
+ *mf = fmt->format;
+
+ /* When setting the sink format, report that format on the src pad */
+ if (IS_SINK(fmt->pad)) {
+ mf = v4l2_subdev_state_get_format(sd_state, 1);
+ *mf = fmt->format;
+ dcmipp_par_adjust_fmt(par, mf, 1);
+ }
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops dcmipp_par_pad_ops = {
+ .enum_mbus_code = dcmipp_par_enum_mbus_code,
+ .enum_frame_size = dcmipp_par_enum_frame_size,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = dcmipp_par_set_fmt,
+};
+
+static int dcmipp_par_configure(struct dcmipp_par_device *par)
+{
+ u32 val = 0;
+ const struct dcmipp_par_pix_map *vpix;
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_framefmt *sink_fmt;
+ struct v4l2_mbus_framefmt *src_fmt;
+
+ /* Set vertical synchronization polarity */
+ if (par->ved.bus.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+ val |= DCMIPP_PRCR_VSPOL;
+
+ /* Set horizontal synchronization polarity */
+ if (par->ved.bus.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+ val |= DCMIPP_PRCR_HSPOL;
+
+ /* Set pixel clock polarity */
+ if (par->ved.bus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ val |= DCMIPP_PRCR_PCKPOL;
+
+ /*
+ * BT656 embedded synchronisation bus mode.
+ *
+ * Default SAV/EAV mode is supported here with default codes
+ * SAV=0xff000080 & EAV=0xff00009d.
+ * With DCMIPP this means LSC=SAV=0x80 & LEC=EAV=0x9d.
+ */
+ if (par->ved.bus_type == V4L2_MBUS_BT656) {
+ val |= DCMIPP_PRCR_ESS;
+
+ /* Unmask all codes */
+ reg_write(par, DCMIPP_PRESUR, 0xffffffff);/* FEC:LEC:LSC:FSC */
+
+ /* Trig on LSC=0x80 & LEC=0x9d codes, ignore FSC and FEC */
+ reg_write(par, DCMIPP_PRESCR, 0xff9d80ff);/* FEC:LEC:LSC:FSC */
+ }
+
+ /* Set format */
+ state = v4l2_subdev_lock_and_get_active_state(&par->sd);
+ sink_fmt = v4l2_subdev_state_get_format(state, 0);
+ src_fmt = v4l2_subdev_state_get_format(state, 1);
+ v4l2_subdev_unlock_state(state);
+
+ vpix = dcmipp_par_pix_map_by_code(sink_fmt->code, src_fmt->code);
+ if (!vpix) {
+ dev_err(par->dev, "Invalid sink/src format configuration\n");
+ return -EINVAL;
+ }
+
+ val |= vpix->prcr_format << DCMIPP_PRCR_FORMAT_SHIFT;
+
+ /* swap cycles */
+ if (vpix->prcr_swapcycles)
+ val |= DCMIPP_PRCR_SWAPCYCLES;
+
+ reg_write(par, DCMIPP_PRCR, val);
+
+ return 0;
+}
+
+static int dcmipp_par_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct dcmipp_par_device *par =
+ container_of(sd, struct dcmipp_par_device, sd);
+ struct v4l2_subdev *s_subdev;
+ struct media_pad *pad;
+ int ret = 0;
+
+ /* Get source subdev */
+ pad = media_pad_remote_pad_first(&sd->entity.pads[0]);
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ return -EINVAL;
+ s_subdev = media_entity_to_v4l2_subdev(pad->entity);
+
+ if (enable) {
+ ret = dcmipp_par_configure(par);
+ if (ret)
+ return ret;
+
+ /* Enable parallel interface */
+ reg_set(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE);
+
+ ret = v4l2_subdev_call(s_subdev, video, s_stream, enable);
+ if (ret < 0) {
+ dev_err(par->dev,
+ "failed to start source subdev streaming (%d)\n",
+ ret);
+ return ret;
+ }
+ } else {
+ ret = v4l2_subdev_call(s_subdev, video, s_stream, enable);
+ if (ret < 0) {
+ dev_err(par->dev,
+ "failed to stop source subdev streaming (%d)\n",
+ ret);
+ return ret;
+ }
+
+ /* Disable parallel interface */
+ reg_clear(par, DCMIPP_PRCR, DCMIPP_PRCR_ENABLE);
+ }
+
+ par->streaming = enable;
+
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops dcmipp_par_video_ops = {
+ .s_stream = dcmipp_par_s_stream,
+};
+
+static const struct v4l2_subdev_ops dcmipp_par_ops = {
+ .pad = &dcmipp_par_pad_ops,
+ .video = &dcmipp_par_video_ops,
+};
+
+static void dcmipp_par_release(struct v4l2_subdev *sd)
+{
+ struct dcmipp_par_device *par =
+ container_of(sd, struct dcmipp_par_device, sd);
+
+ kfree(par);
+}
+
+static const struct v4l2_subdev_internal_ops dcmipp_par_int_ops = {
+ .init_state = dcmipp_par_init_state,
+ .release = dcmipp_par_release,
+};
+
+void dcmipp_par_ent_release(struct dcmipp_ent_device *ved)
+{
+ struct dcmipp_par_device *par =
+ container_of(ved, struct dcmipp_par_device, ved);
+
+ dcmipp_ent_sd_unregister(ved, &par->sd);
+}
+
+struct dcmipp_ent_device *dcmipp_par_ent_init(struct device *dev,
+ const char *entity_name,
+ struct v4l2_device *v4l2_dev,
+ void __iomem *regs)
+{
+ struct dcmipp_par_device *par;
+ const unsigned long pads_flag[] = {
+ MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE,
+ };
+ int ret;
+
+ /* Allocate the par struct */
+ par = kzalloc(sizeof(*par), GFP_KERNEL);
+ if (!par)
+ return ERR_PTR(-ENOMEM);
+
+ par->regs = regs;
+
+ /* Initialize ved and sd */
+ ret = dcmipp_ent_sd_register(&par->ved, &par->sd, v4l2_dev,
+ entity_name, MEDIA_ENT_F_VID_IF_BRIDGE,
+ ARRAY_SIZE(pads_flag), pads_flag,
+ &dcmipp_par_int_ops, &dcmipp_par_ops,
+ NULL, NULL);
+ if (ret) {
+ kfree(par);
+ return ERR_PTR(ret);
+ }
+
+ par->dev = dev;
+
+ return &par->ved;
+}
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
index ad13d447d483..097a3a08ef7d 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
@@ -211,6 +211,7 @@ static int sun4i_csi_probe(struct platform_device *pdev)
/* Initialize subdev */
v4l2_subdev_init(subdev, &sun4i_csi_subdev_ops);
+ subdev->internal_ops = &sun4i_csi_subdev_internal_ops;
subdev->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
subdev->owner = THIS_MODULE;
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h
index 8eeed87bfb13..4e0c2df45d4d 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h
@@ -89,6 +89,7 @@ enum csi_subdev_pads {
};
extern const struct v4l2_subdev_ops sun4i_csi_subdev_ops;
+extern const struct v4l2_subdev_internal_ops sun4i_csi_subdev_internal_ops;
struct sun4i_csi_format {
u32 mbus;
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
index 95b5633b7914..d1371e130113 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
@@ -411,7 +411,7 @@ int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq)
for (i = 0; i < CSI_MAX_BUFFER; i++)
csi->current_buf[i] = NULL;
- q->min_buffers_needed = 3;
+ q->min_queued_buffers = 3;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
q->io_modes = VB2_MMAP | VB2_DMABUF;
q->lock = &csi->lock;
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c
index 48702134ccc5..744197b0fccb 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c
@@ -266,12 +266,12 @@ static const struct v4l2_mbus_framefmt sun4i_csi_pad_fmt_default = {
.xfer_func = V4L2_XFER_FUNC_DEFAULT,
};
-static int sun4i_csi_subdev_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state)
+static int sun4i_csi_subdev_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_try_format(subdev, sd_state, CSI_SUBDEV_SINK);
+ fmt = v4l2_subdev_state_get_format(sd_state, CSI_SUBDEV_SINK);
*fmt = sun4i_csi_pad_fmt_default;
return 0;
@@ -285,8 +285,7 @@ static int sun4i_csi_subdev_get_fmt(struct v4l2_subdev *subdev,
struct v4l2_mbus_framefmt *subdev_fmt;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- subdev_fmt = v4l2_subdev_get_try_format(subdev, sd_state,
- fmt->pad);
+ subdev_fmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
else
subdev_fmt = &csi->subdev_fmt;
@@ -303,8 +302,7 @@ static int sun4i_csi_subdev_set_fmt(struct v4l2_subdev *subdev,
struct v4l2_mbus_framefmt *subdev_fmt;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- subdev_fmt = v4l2_subdev_get_try_format(subdev, sd_state,
- fmt->pad);
+ subdev_fmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
else
subdev_fmt = &csi->subdev_fmt;
@@ -336,7 +334,6 @@ sun4i_csi_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
static const struct v4l2_subdev_pad_ops sun4i_csi_subdev_pad_ops = {
.link_validate = v4l2_subdev_link_validate_default,
- .init_cfg = sun4i_csi_subdev_init_cfg,
.get_fmt = sun4i_csi_subdev_get_fmt,
.set_fmt = sun4i_csi_subdev_set_fmt,
.enum_mbus_code = sun4i_csi_subdev_enum_mbus_code,
@@ -346,6 +343,10 @@ const struct v4l2_subdev_ops sun4i_csi_subdev_ops = {
.pad = &sun4i_csi_subdev_pad_ops,
};
+const struct v4l2_subdev_internal_ops sun4i_csi_subdev_internal_ops = {
+ .init_state = sun4i_csi_subdev_init_state,
+};
+
int sun4i_csi_v4l2_register(struct sun4i_csi *csi)
{
struct video_device *vdev = &csi->vdev;
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
index e573413123b9..d006d9dd0170 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_bridge.c
@@ -501,13 +501,13 @@ sun6i_csi_bridge_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format)
mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
}
-static int sun6i_csi_bridge_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *state)
+static int sun6i_csi_bridge_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state)
{
struct sun6i_csi_device *csi_dev = v4l2_get_subdevdata(subdev);
unsigned int pad = SUN6I_CSI_BRIDGE_PAD_SINK;
struct v4l2_mbus_framefmt *mbus_format =
- v4l2_subdev_get_try_format(subdev, state, pad);
+ v4l2_subdev_state_get_format(state, pad);
struct mutex *lock = &csi_dev->bridge.lock;
mutex_lock(lock);
@@ -547,8 +547,8 @@ static int sun6i_csi_bridge_get_fmt(struct v4l2_subdev *subdev,
mutex_lock(lock);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *mbus_format = *v4l2_subdev_get_try_format(subdev, state,
- format->pad);
+ *mbus_format = *v4l2_subdev_state_get_format(state,
+ format->pad);
else
*mbus_format = csi_dev->bridge.mbus_format;
@@ -570,7 +570,7 @@ static int sun6i_csi_bridge_set_fmt(struct v4l2_subdev *subdev,
sun6i_csi_bridge_mbus_format_prepare(mbus_format);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *v4l2_subdev_get_try_format(subdev, state, format->pad) =
+ *v4l2_subdev_state_get_format(state, format->pad) =
*mbus_format;
else
csi_dev->bridge.mbus_format = *mbus_format;
@@ -581,7 +581,6 @@ static int sun6i_csi_bridge_set_fmt(struct v4l2_subdev *subdev,
}
static const struct v4l2_subdev_pad_ops sun6i_csi_bridge_pad_ops = {
- .init_cfg = sun6i_csi_bridge_init_cfg,
.enum_mbus_code = sun6i_csi_bridge_enum_mbus_code,
.get_fmt = sun6i_csi_bridge_get_fmt,
.set_fmt = sun6i_csi_bridge_set_fmt,
@@ -592,6 +591,10 @@ static const struct v4l2_subdev_ops sun6i_csi_bridge_subdev_ops = {
.pad = &sun6i_csi_bridge_pad_ops,
};
+static const struct v4l2_subdev_internal_ops sun6i_csi_bridge_internal_ops = {
+ .init_state = sun6i_csi_bridge_init_state,
+};
+
/* Media Entity */
static const struct media_entity_operations sun6i_csi_bridge_entity_ops = {
@@ -782,6 +785,7 @@ int sun6i_csi_bridge_setup(struct sun6i_csi_device *csi_dev)
/* V4L2 Subdev */
v4l2_subdev_init(subdev, &sun6i_csi_bridge_subdev_ops);
+ subdev->internal_ops = &sun6i_csi_bridge_internal_ops;
strscpy(subdev->name, SUN6I_CSI_BRIDGE_NAME, sizeof(subdev->name));
subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
subdev->owner = THIS_MODULE;
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
index cf6aadbc130b..14c0dc827c52 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
@@ -1010,7 +1010,7 @@ int sun6i_csi_capture_setup(struct sun6i_csi_device *csi_dev)
queue->buf_struct_size = sizeof(struct sun6i_csi_buffer);
queue->ops = &sun6i_csi_capture_queue_ops;
queue->mem_ops = &vb2_dma_contig_memops;
- queue->min_buffers_needed = 2;
+ queue->min_queued_buffers = 2;
queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
queue->lock = &capture->lock;
queue->dev = csi_dev->dev;
diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
index 08d86c17b284..f9d4dc45b490 100644
--- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
+++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
@@ -305,13 +305,13 @@ sun6i_mipi_csi2_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format)
mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
}
-static int sun6i_mipi_csi2_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *state)
+static int sun6i_mipi_csi2_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state)
{
struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev);
unsigned int pad = SUN6I_MIPI_CSI2_PAD_SINK;
struct v4l2_mbus_framefmt *mbus_format =
- v4l2_subdev_get_try_format(subdev, state, pad);
+ v4l2_subdev_state_get_format(state, pad);
struct mutex *lock = &csi2_dev->bridge.lock;
mutex_lock(lock);
@@ -351,8 +351,8 @@ static int sun6i_mipi_csi2_get_fmt(struct v4l2_subdev *subdev,
mutex_lock(lock);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *mbus_format = *v4l2_subdev_get_try_format(subdev, state,
- format->pad);
+ *mbus_format = *v4l2_subdev_state_get_format(state,
+ format->pad);
else
*mbus_format = csi2_dev->bridge.mbus_format;
@@ -374,7 +374,7 @@ static int sun6i_mipi_csi2_set_fmt(struct v4l2_subdev *subdev,
sun6i_mipi_csi2_mbus_format_prepare(mbus_format);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *v4l2_subdev_get_try_format(subdev, state, format->pad) =
+ *v4l2_subdev_state_get_format(state, format->pad) =
*mbus_format;
else
csi2_dev->bridge.mbus_format = *mbus_format;
@@ -385,7 +385,6 @@ static int sun6i_mipi_csi2_set_fmt(struct v4l2_subdev *subdev,
}
static const struct v4l2_subdev_pad_ops sun6i_mipi_csi2_pad_ops = {
- .init_cfg = sun6i_mipi_csi2_init_cfg,
.enum_mbus_code = sun6i_mipi_csi2_enum_mbus_code,
.get_fmt = sun6i_mipi_csi2_get_fmt,
.set_fmt = sun6i_mipi_csi2_set_fmt,
@@ -396,6 +395,10 @@ static const struct v4l2_subdev_ops sun6i_mipi_csi2_subdev_ops = {
.pad = &sun6i_mipi_csi2_pad_ops,
};
+static const struct v4l2_subdev_internal_ops sun6i_mipi_csi2_internal_ops = {
+ .init_state = sun6i_mipi_csi2_init_state,
+};
+
/* Media Entity */
static const struct media_entity_operations sun6i_mipi_csi2_entity_ops = {
@@ -504,6 +507,7 @@ static int sun6i_mipi_csi2_bridge_setup(struct sun6i_mipi_csi2_device *csi2_dev)
/* V4L2 Subdev */
v4l2_subdev_init(subdev, &sun6i_mipi_csi2_subdev_ops);
+ subdev->internal_ops = &sun6i_mipi_csi2_internal_ops;
strscpy(subdev->name, SUN6I_MIPI_CSI2_NAME, sizeof(subdev->name));
subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
subdev->owner = THIS_MODULE;
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
index 14a1844812c0..4a5698eb12b7 100644
--- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
@@ -338,14 +338,14 @@ sun8i_a83t_mipi_csi2_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format)
mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
}
-static int sun8i_a83t_mipi_csi2_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *state)
+static int sun8i_a83t_mipi_csi2_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state)
{
struct sun8i_a83t_mipi_csi2_device *csi2_dev =
v4l2_get_subdevdata(subdev);
unsigned int pad = SUN8I_A83T_MIPI_CSI2_PAD_SINK;
struct v4l2_mbus_framefmt *mbus_format =
- v4l2_subdev_get_try_format(subdev, state, pad);
+ v4l2_subdev_state_get_format(state, pad);
struct mutex *lock = &csi2_dev->bridge.lock;
mutex_lock(lock);
@@ -387,8 +387,8 @@ static int sun8i_a83t_mipi_csi2_get_fmt(struct v4l2_subdev *subdev,
mutex_lock(lock);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *mbus_format = *v4l2_subdev_get_try_format(subdev, state,
- format->pad);
+ *mbus_format = *v4l2_subdev_state_get_format(state,
+ format->pad);
else
*mbus_format = csi2_dev->bridge.mbus_format;
@@ -411,7 +411,7 @@ static int sun8i_a83t_mipi_csi2_set_fmt(struct v4l2_subdev *subdev,
sun8i_a83t_mipi_csi2_mbus_format_prepare(mbus_format);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *v4l2_subdev_get_try_format(subdev, state, format->pad) =
+ *v4l2_subdev_state_get_format(state, format->pad) =
*mbus_format;
else
csi2_dev->bridge.mbus_format = *mbus_format;
@@ -422,7 +422,6 @@ static int sun8i_a83t_mipi_csi2_set_fmt(struct v4l2_subdev *subdev,
}
static const struct v4l2_subdev_pad_ops sun8i_a83t_mipi_csi2_pad_ops = {
- .init_cfg = sun8i_a83t_mipi_csi2_init_cfg,
.enum_mbus_code = sun8i_a83t_mipi_csi2_enum_mbus_code,
.get_fmt = sun8i_a83t_mipi_csi2_get_fmt,
.set_fmt = sun8i_a83t_mipi_csi2_set_fmt,
@@ -433,6 +432,10 @@ static const struct v4l2_subdev_ops sun8i_a83t_mipi_csi2_subdev_ops = {
.pad = &sun8i_a83t_mipi_csi2_pad_ops,
};
+static const struct v4l2_subdev_internal_ops sun8i_a83t_mipi_csi2_internal_ops = {
+ .init_state = sun8i_a83t_mipi_csi2_init_state,
+};
+
/* Media Entity */
static const struct media_entity_operations sun8i_a83t_mipi_csi2_entity_ops = {
@@ -542,6 +545,7 @@ sun8i_a83t_mipi_csi2_bridge_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
/* V4L2 Subdev */
v4l2_subdev_init(subdev, &sun8i_a83t_mipi_csi2_subdev_ops);
+ subdev->internal_ops = &sun8i_a83t_mipi_csi2_internal_ops;
strscpy(subdev->name, SUN8I_A83T_MIPI_CSI2_NAME, sizeof(subdev->name));
subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
subdev->owner = THIS_MODULE;
diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c
index 90ab1d77b6a5..954fabec27f6 100644
--- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c
+++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c
@@ -673,7 +673,7 @@ static int deinterlace_queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- src_vq->min_buffers_needed = 1;
+ src_vq->min_queued_buffers = 1;
src_vq->ops = &deinterlace_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
@@ -688,7 +688,7 @@ static int deinterlace_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- dst_vq->min_buffers_needed = 2;
+ dst_vq->min_queued_buffers = 2;
dst_vq->ops = &deinterlace_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
index 0b025ec91826..a12323ca89fa 100644
--- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
+++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
@@ -536,7 +536,7 @@ static int rotate_queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- src_vq->min_buffers_needed = 1;
+ src_vq->min_queued_buffers = 1;
src_vq->ops = &rotate_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
@@ -551,7 +551,7 @@ static int rotate_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- dst_vq->min_buffers_needed = 2;
+ dst_vq->min_queued_buffers = 2;
dst_vq->ops = &rotate_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.c b/drivers/media/platform/ti/am437x/am437x-vpfe.c
index 5fa2ea9025d9..77e12457d149 100644
--- a/drivers/media/platform/ti/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/ti/am437x/am437x-vpfe.c
@@ -1771,9 +1771,10 @@ static int vpfe_queue_setup(struct vb2_queue *vq,
{
struct vpfe_device *vpfe = vb2_get_drv_priv(vq);
unsigned size = vpfe->fmt.fmt.pix.sizeimage;
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
- if (vq->num_buffers + *nbuffers < 3)
- *nbuffers = 3 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 3)
+ *nbuffers = 3 - q_num_bufs;
if (*nplanes) {
if (sizes[0] < size)
@@ -2233,7 +2234,7 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe)
q->buf_struct_size = sizeof(struct vpfe_cap_buffer);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &vpfe->lock;
- q->min_buffers_needed = 1;
+ q->min_queued_buffers = 1;
q->dev = vpfe->pdev;
err = vb2_queue_init(q);
diff --git a/drivers/media/platform/ti/cal/cal-camerarx.c b/drivers/media/platform/ti/cal/cal-camerarx.c
index 1a4273bbe752..4afc2ad00330 100644
--- a/drivers/media/platform/ti/cal/cal-camerarx.c
+++ b/drivers/media/platform/ti/cal/cal-camerarx.c
@@ -57,7 +57,7 @@ static s64 cal_camerarx_get_ext_link_freq(struct cal_camerarx *phy)
state = v4l2_subdev_get_locked_active_state(&phy->subdev);
- fmt = v4l2_subdev_get_pad_format(&phy->subdev, state, CAL_CAMERARX_PAD_SINK);
+ fmt = v4l2_subdev_state_get_format(state, CAL_CAMERARX_PAD_SINK);
fmtinfo = cal_format_by_code(fmt->code);
if (!fmtinfo)
@@ -621,8 +621,6 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_mbus_code_enum *code)
{
- struct cal_camerarx *phy = to_cal_camerarx(sd);
-
/* No transcoding, source and sink codes must match. */
if (cal_rx_pad_is_source(code->pad)) {
struct v4l2_mbus_framefmt *fmt;
@@ -630,8 +628,8 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index > 0)
return -EINVAL;
- fmt = v4l2_subdev_get_pad_format(&phy->subdev, state,
- CAL_CAMERARX_PAD_SINK);
+ fmt = v4l2_subdev_state_get_format(state,
+ CAL_CAMERARX_PAD_SINK);
code->code = fmt->code;
} else {
if (code->index >= cal_num_formats)
@@ -656,8 +654,8 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
if (cal_rx_pad_is_source(fse->pad)) {
struct v4l2_mbus_framefmt *fmt;
- fmt = v4l2_subdev_get_pad_format(sd, state,
- CAL_CAMERARX_PAD_SINK);
+ fmt = v4l2_subdev_state_get_format(state,
+ CAL_CAMERARX_PAD_SINK);
if (fse->code != fmt->code)
return -EINVAL;
@@ -713,18 +711,18 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
/* Store the format and propagate it to the source pad. */
- fmt = v4l2_subdev_get_pad_format(sd, state, CAL_CAMERARX_PAD_SINK);
+ fmt = v4l2_subdev_state_get_format(state, CAL_CAMERARX_PAD_SINK);
*fmt = format->format;
- fmt = v4l2_subdev_get_pad_format(sd, state,
- CAL_CAMERARX_PAD_FIRST_SOURCE);
+ fmt = v4l2_subdev_state_get_format(state,
+ CAL_CAMERARX_PAD_FIRST_SOURCE);
*fmt = format->format;
return 0;
}
-static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state)
+static int cal_camerarx_sd_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
struct v4l2_subdev_format format = {
.which = state ? V4L2_SUBDEV_FORMAT_TRY
@@ -784,7 +782,6 @@ static const struct v4l2_subdev_video_ops cal_camerarx_video_ops = {
};
static const struct v4l2_subdev_pad_ops cal_camerarx_pad_ops = {
- .init_cfg = cal_camerarx_sd_init_cfg,
.enum_mbus_code = cal_camerarx_sd_enum_mbus_code,
.enum_frame_size = cal_camerarx_sd_enum_frame_size,
.get_fmt = v4l2_subdev_get_fmt,
@@ -797,6 +794,10 @@ static const struct v4l2_subdev_ops cal_camerarx_subdev_ops = {
.pad = &cal_camerarx_pad_ops,
};
+static const struct v4l2_subdev_internal_ops cal_camerarx_internal_ops = {
+ .init_state = cal_camerarx_sd_init_state,
+};
+
static struct media_entity_operations cal_camerarx_media_ops = {
.link_validate = v4l2_subdev_link_validate,
};
@@ -848,6 +849,7 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
/* Initialize the V4L2 subdev and media entity. */
sd = &phy->subdev;
v4l2_subdev_init(sd, &cal_camerarx_subdev_ops);
+ sd->internal_ops = &cal_camerarx_internal_ops;
sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
snprintf(sd->name, sizeof(sd->name), "CAMERARX%u", instance);
diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c
index a8abcd0fee17..e1ba5dfc217e 100644
--- a/drivers/media/platform/ti/cal/cal-video.c
+++ b/drivers/media/platform/ti/cal/cal-video.c
@@ -603,9 +603,10 @@ static int cal_queue_setup(struct vb2_queue *vq,
{
struct cal_ctx *ctx = vb2_get_drv_priv(vq);
unsigned int size = ctx->v_fmt.fmt.pix.sizeimage;
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
- if (vq->num_buffers + *nbuffers < 3)
- *nbuffers = 3 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 3)
+ *nbuffers = 3 - q_num_bufs;
if (*nplanes) {
if (sizes[0] < size)
@@ -697,7 +698,7 @@ static int cal_video_check_format(struct cal_ctx *ctx)
state = v4l2_subdev_lock_and_get_active_state(&ctx->phy->subdev);
- format = v4l2_subdev_get_pad_format(&ctx->phy->subdev, state, remote_pad->index);
+ format = v4l2_subdev_state_get_format(state, remote_pad->index);
if (!format) {
ret = -EINVAL;
goto out;
@@ -1009,7 +1010,7 @@ int cal_ctx_v4l2_init(struct cal_ctx *ctx)
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &ctx->mutex;
- q->min_buffers_needed = 3;
+ q->min_queued_buffers = 3;
q->dev = ctx->cal->dev;
ret = vb2_queue_init(q);
diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c
index 99fae8830c41..c31a5566fc5a 100644
--- a/drivers/media/platform/ti/davinci/vpif_capture.c
+++ b/drivers/media/platform/ti/davinci/vpif_capture.c
@@ -113,6 +113,7 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq,
struct channel_obj *ch = vb2_get_drv_priv(vq);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
unsigned size = common->fmt.fmt.pix.sizeimage;
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
vpif_dbg(2, debug, "vpif_buffer_setup\n");
@@ -122,8 +123,8 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq,
size = sizes[0];
}
- if (vq->num_buffers + *nbuffers < 3)
- *nbuffers = 3 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 3)
+ *nbuffers = 3 - q_num_bufs;
*nplanes = 1;
sizes[0] = size;
@@ -1428,7 +1429,7 @@ static int vpif_probe_complete(void)
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct vpif_cap_buffer);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 1;
+ q->min_queued_buffers = 1;
q->lock = &common->lock;
q->dev = vpif_dev;
diff --git a/drivers/media/platform/ti/davinci/vpif_display.c b/drivers/media/platform/ti/davinci/vpif_display.c
index f8ec2991c667..02ede1fe12cb 100644
--- a/drivers/media/platform/ti/davinci/vpif_display.c
+++ b/drivers/media/platform/ti/davinci/vpif_display.c
@@ -115,6 +115,7 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq,
struct channel_obj *ch = vb2_get_drv_priv(vq);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
unsigned size = common->fmt.fmt.pix.sizeimage;
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
if (*nplanes) {
if (sizes[0] < size)
@@ -122,8 +123,8 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq,
size = sizes[0];
}
- if (vq->num_buffers + *nbuffers < 3)
- *nbuffers = 3 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 3)
+ *nbuffers = 3 - q_num_bufs;
*nplanes = 1;
sizes[0] = size;
@@ -1168,7 +1169,7 @@ static int vpif_probe_complete(void)
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct vpif_disp_buffer);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 1;
+ q->min_queued_buffers = 1;
q->lock = &common->lock;
q->dev = vpif_dev;
err = vb2_queue_init(q);
diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c
index ada61391c8d2..59b30fc43144 100644
--- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c
+++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c
@@ -873,7 +873,7 @@ static int ti_csi2rx_init_vb2q(struct ti_csi2rx_dev *csi)
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->dev = dmaengine_get_dma_device(csi->dma.chan);
q->lock = &csi->mutex;
- q->min_buffers_needed = 1;
+ q->min_queued_buffers = 1;
ret = vb2_queue_init(q);
if (ret)
diff --git a/drivers/media/platform/ti/omap/omap_vout.c b/drivers/media/platform/ti/omap/omap_vout.c
index 4143274089c3..1c56b6a87ced 100644
--- a/drivers/media/platform/ti/omap/omap_vout.c
+++ b/drivers/media/platform/ti/omap/omap_vout.c
@@ -944,10 +944,11 @@ static int omap_vout_vb2_queue_setup(struct vb2_queue *vq,
struct device *alloc_devs[])
{
struct omap_vout_device *vout = vb2_get_drv_priv(vq);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
int size = vout->pix.sizeimage;
- if (is_rotation_enabled(vout) && vq->num_buffers + *nbufs > VRFB_NUM_BUFS) {
- *nbufs = VRFB_NUM_BUFS - vq->num_buffers;
+ if (is_rotation_enabled(vout) && q_num_bufs + *nbufs > VRFB_NUM_BUFS) {
+ *nbufs = VRFB_NUM_BUFS - q_num_bufs;
if (*nbufs == 0)
return -EINVAL;
}
@@ -1403,7 +1404,7 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
vq->ops = &omap_vout_vb2_ops;
vq->mem_ops = &vb2_dma_contig_memops;
vq->lock = &vout->lock;
- vq->min_buffers_needed = 1;
+ vq->min_queued_buffers = 1;
vfd->queue = vq;
ret = vb2_queue_init(vq);
diff --git a/drivers/media/platform/ti/omap3isp/ispccdc.c b/drivers/media/platform/ti/omap3isp/ispccdc.c
index 2fe42aa91800..dd375c4e180d 100644
--- a/drivers/media/platform/ti/omap3isp/ispccdc.c
+++ b/drivers/media/platform/ti/omap3isp/ispccdc.c
@@ -1948,8 +1948,7 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ccdc->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
else
return &ccdc->formats[pad];
}
@@ -1960,8 +1959,8 @@ __ccdc_get_crop(struct isp_ccdc_device *ccdc,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&ccdc->subdev, sd_state,
- CCDC_PAD_SOURCE_OF);
+ return v4l2_subdev_state_get_crop(sd_state,
+ CCDC_PAD_SOURCE_OF);
else
return &ccdc->crop;
}
@@ -1969,7 +1968,7 @@ __ccdc_get_crop(struct isp_ccdc_device *ccdc,
/*
* ccdc_try_format - Try video format on a pad
* @ccdc: ISP CCDC device
- * @cfg : V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad: Pad number
* @fmt: Format
*/
@@ -2127,7 +2126,7 @@ static void ccdc_try_crop(struct isp_ccdc_device *ccdc,
/*
* ccdc_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @cfg : V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
@@ -2230,7 +2229,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
/*
* ccdc_get_selection - Retrieve a selection rectangle on a pad
* @sd: ISP CCDC V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @sel: Selection rectangle
*
* The only supported rectangles are the crop rectangles on the output formatter
@@ -2274,7 +2273,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd,
/*
* ccdc_set_selection - Set a selection rectangle on a pad
* @sd: ISP CCDC V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @sel: Selection rectangle
*
* The only supported rectangle is the actual crop rectangle on the output
@@ -2322,7 +2321,7 @@ static int ccdc_set_selection(struct v4l2_subdev *sd,
/*
* ccdc_get_format - Retrieve the video format on a pad
* @sd : ISP CCDC V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: Format
*
* Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
@@ -2346,7 +2345,7 @@ static int ccdc_get_format(struct v4l2_subdev *sd,
/*
* ccdc_set_format - Set the video format on a pad
* @sd : ISP CCDC V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: Format
*
* Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
diff --git a/drivers/media/platform/ti/omap3isp/ispccp2.c b/drivers/media/platform/ti/omap3isp/ispccp2.c
index da5f0176ec78..1204ee221c9e 100644
--- a/drivers/media/platform/ti/omap3isp/ispccp2.c
+++ b/drivers/media/platform/ti/omap3isp/ispccp2.c
@@ -614,7 +614,7 @@ static const unsigned int ccp2_fmts[] = {
/*
* __ccp2_get_format - helper function for getting ccp2 format
* @ccp2 : Pointer to ISP CCP2 device
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad : pad number
* @which : wanted subdev format
* return format structure or NULL on error
@@ -625,8 +625,7 @@ __ccp2_get_format(struct isp_ccp2_device *ccp2,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ccp2->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
else
return &ccp2->formats[pad];
}
@@ -634,7 +633,7 @@ __ccp2_get_format(struct isp_ccp2_device *ccp2,
/*
* ccp2_try_format - Handle try format by pad subdev method
* @ccp2 : Pointer to ISP CCP2 device
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad : pad num
* @fmt : pointer to v4l2 mbus format structure
* @which : wanted subdev format
@@ -689,7 +688,7 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2,
/*
* ccp2_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
@@ -750,7 +749,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd,
/*
* ccp2_get_format - Handle get format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt : pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
@@ -772,7 +771,7 @@ static int ccp2_get_format(struct v4l2_subdev *sd,
/*
* ccp2_set_format - Handle set format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt : pointer to v4l2 subdev format structure
* returns zero
*/
diff --git a/drivers/media/platform/ti/omap3isp/ispcsi2.c b/drivers/media/platform/ti/omap3isp/ispcsi2.c
index 0f9a54b11f98..ae574e1b6528 100644
--- a/drivers/media/platform/ti/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/ti/omap3isp/ispcsi2.c
@@ -834,8 +834,7 @@ __csi2_get_format(struct isp_csi2_device *csi2,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csi2->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
else
return &csi2->formats[pad];
}
@@ -894,7 +893,7 @@ csi2_try_format(struct isp_csi2_device *csi2,
/*
* csi2_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
@@ -968,7 +967,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
/*
* csi2_get_format - Handle get format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
@@ -990,7 +989,7 @@ static int csi2_get_format(struct v4l2_subdev *sd,
/*
* csi2_set_format - Handle set format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
diff --git a/drivers/media/platform/ti/omap3isp/isppreview.c b/drivers/media/platform/ti/omap3isp/isppreview.c
index 53aedec7990d..e383a57654de 100644
--- a/drivers/media/platform/ti/omap3isp/isppreview.c
+++ b/drivers/media/platform/ti/omap3isp/isppreview.c
@@ -1684,8 +1684,7 @@ __preview_get_format(struct isp_prev_device *prev,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&prev->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
else
return &prev->formats[pad];
}
@@ -1696,8 +1695,7 @@ __preview_get_crop(struct isp_prev_device *prev,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&prev->subdev, sd_state,
- PREV_PAD_SINK);
+ return v4l2_subdev_state_get_crop(sd_state, PREV_PAD_SINK);
else
return &prev->crop;
}
@@ -1724,7 +1722,7 @@ static const unsigned int preview_output_fmts[] = {
/*
* preview_try_format - Validate a format
* @prev: ISP preview engine
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad: pad number
* @fmt: format to be validated
* @which: try/active format selector
@@ -1863,7 +1861,7 @@ static void preview_try_crop(struct isp_prev_device *prev,
/*
* preview_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
@@ -1924,7 +1922,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
/*
* preview_get_selection - Retrieve a selection rectangle on a pad
* @sd: ISP preview V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @sel: Selection rectangle
*
* The only supported rectangles are the crop rectangles on the sink pad.
@@ -1967,7 +1965,7 @@ static int preview_get_selection(struct v4l2_subdev *sd,
/*
* preview_set_selection - Set a selection rectangle on a pad
* @sd: ISP preview V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @sel: Selection rectangle
*
* The only supported rectangle is the actual crop rectangle on the sink pad.
@@ -2015,7 +2013,7 @@ static int preview_set_selection(struct v4l2_subdev *sd,
/*
* preview_get_format - Handle get format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
@@ -2037,7 +2035,7 @@ static int preview_get_format(struct v4l2_subdev *sd,
/*
* preview_set_format - Handle set format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
diff --git a/drivers/media/platform/ti/omap3isp/ispresizer.c b/drivers/media/platform/ti/omap3isp/ispresizer.c
index ed2fb0c7a57e..87d821b02e5c 100644
--- a/drivers/media/platform/ti/omap3isp/ispresizer.c
+++ b/drivers/media/platform/ti/omap3isp/ispresizer.c
@@ -109,7 +109,7 @@ static const struct isprsz_coef filter_coefs = {
* __resizer_get_format - helper function for getting resizer format
* @res : pointer to resizer private structure
* @pad : pad number
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @which : wanted subdev format
* return zero
*/
@@ -119,7 +119,7 @@ __resizer_get_format(struct isp_res_device *res,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&res->subdev, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
else
return &res->formats[pad];
}
@@ -127,7 +127,7 @@ __resizer_get_format(struct isp_res_device *res,
/*
* __resizer_get_crop - helper function for getting resizer crop rectangle
* @res : pointer to resizer private structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @which : wanted subdev crop rectangle
*/
static struct v4l2_rect *
@@ -136,8 +136,7 @@ __resizer_get_crop(struct isp_res_device *res,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&res->subdev, sd_state,
- RESZ_PAD_SINK);
+ return v4l2_subdev_state_get_crop(sd_state, RESZ_PAD_SINK);
else
return &res->crop.request;
}
@@ -1215,7 +1214,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
/*
* resizer_get_selection - Retrieve a selection rectangle on a pad
* @sd: ISP resizer V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @sel: Selection rectangle
*
* The only supported rectangles are the crop rectangles on the sink pad.
@@ -1265,7 +1264,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd,
/*
* resizer_set_selection - Set a selection rectangle on a pad
* @sd: ISP resizer V4L2 subdevice
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @sel: Selection rectangle
*
* The only supported rectangle is the actual crop rectangle on the sink pad.
@@ -1369,7 +1368,7 @@ static unsigned int resizer_max_in_width(struct isp_res_device *res)
/*
* resizer_try_format - Handle try format by pad subdev method
* @res : ISP resizer device
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @pad : pad num
* @fmt : pointer to v4l2 format structure
* @which : wanted subdev format
@@ -1413,7 +1412,7 @@ static void resizer_try_format(struct isp_res_device *res,
/*
* resizer_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
@@ -1474,7 +1473,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
/*
* resizer_get_format - Handle get format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt : pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
@@ -1496,7 +1495,7 @@ static int resizer_get_format(struct v4l2_subdev *sd,
/*
* resizer_set_format - Handle set format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
+ * @sd_state: V4L2 subdev state
* @fmt : pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
diff --git a/drivers/media/platform/verisilicon/Kconfig b/drivers/media/platform/verisilicon/Kconfig
index e65b836b9d78..24b927d8f182 100644
--- a/drivers/media/platform/verisilicon/Kconfig
+++ b/drivers/media/platform/verisilicon/Kconfig
@@ -8,7 +8,6 @@ config VIDEO_HANTRO
depends on V4L_MEM2MEM_DRIVERS
depends on VIDEO_DEV
select MEDIA_CONTROLLER
- select MEDIA_CONTROLLER_REQUEST_API
select VIDEOBUF2_DMA_CONTIG
select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h
index 77aee9489516..6f5eb975d0e3 100644
--- a/drivers/media/platform/verisilicon/hantro.h
+++ b/drivers/media/platform/verisilicon/hantro.h
@@ -328,6 +328,8 @@ struct hantro_vp9_decoded_buffer_info {
/* Info needed when the decoded frame serves as a reference frame. */
unsigned short width;
unsigned short height;
+ size_t chroma_offset;
+ size_t mv_offset;
u32 bit_depth : 4;
};
@@ -469,11 +471,14 @@ hantro_get_dst_buf(struct hantro_ctx *ctx)
bool hantro_needs_postproc(const struct hantro_ctx *ctx,
const struct hantro_fmt *fmt);
+dma_addr_t
+hantro_postproc_get_dec_buf_addr(struct hantro_ctx *ctx, int index);
+
static inline dma_addr_t
hantro_get_dec_buf_addr(struct hantro_ctx *ctx, struct vb2_buffer *vb)
{
if (hantro_needs_postproc(ctx, ctx->vpu_dst_fmt))
- return ctx->postproc.dec_q[vb->index].dma;
+ return hantro_postproc_get_dec_buf_addr(ctx, vb->index);
return vb2_dma_contig_plane_dma_addr(vb, 0);
}
@@ -485,8 +490,8 @@ vb2_to_hantro_decoded_buf(struct vb2_buffer *buf)
void hantro_postproc_disable(struct hantro_ctx *ctx);
void hantro_postproc_enable(struct hantro_ctx *ctx);
+int hantro_postproc_init(struct hantro_ctx *ctx);
void hantro_postproc_free(struct hantro_ctx *ctx);
-int hantro_postproc_alloc(struct hantro_ctx *ctx);
int hanto_postproc_enum_framesizes(struct hantro_ctx *ctx,
struct v4l2_frmsizeenum *fsize);
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index a9fa05ac56a9..db3df6cc4513 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -235,8 +235,10 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
* The Kernel needs access to the JPEG destination buffer for the
* JPEG encoder to fill in the JPEG headers.
*/
- if (!ctx->is_encoder)
+ if (!ctx->is_encoder) {
dst_vq->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
+ dst_vq->max_num_buffers = MAX_POSTPROC_BUFFERS;
+ }
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
@@ -905,6 +907,8 @@ static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid)
if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) {
vpu->encoder = func;
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
} else {
vpu->decoder = func;
v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
diff --git a/drivers/media/platform/verisilicon/hantro_g2.c b/drivers/media/platform/verisilicon/hantro_g2.c
index ee5f14c5f8f2..b880a6849d58 100644
--- a/drivers/media/platform/verisilicon/hantro_g2.c
+++ b/drivers/media/platform/verisilicon/hantro_g2.c
@@ -8,6 +8,8 @@
#include "hantro_hw.h"
#include "hantro_g2_regs.h"
+#define G2_ALIGN 16
+
void hantro_g2_check_idle(struct hantro_dev *vpu)
{
int i;
@@ -42,3 +44,15 @@ irqreturn_t hantro_g2_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+
+size_t hantro_g2_chroma_offset(struct hantro_ctx *ctx)
+{
+ return ctx->dst_fmt.width * ctx->dst_fmt.height * ctx->bit_depth / 8;
+}
+
+size_t hantro_g2_motion_vectors_offset(struct hantro_ctx *ctx)
+{
+ size_t cr_offset = hantro_g2_chroma_offset(ctx);
+
+ return ALIGN((cr_offset * 3) / 2, G2_ALIGN);
+}
diff --git a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
index a9d4ac84a8d8..d3f8c33eb16c 100644
--- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
+++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
@@ -8,20 +8,6 @@
#include "hantro_hw.h"
#include "hantro_g2_regs.h"
-#define G2_ALIGN 16
-
-static size_t hantro_hevc_chroma_offset(struct hantro_ctx *ctx)
-{
- return ctx->dst_fmt.width * ctx->dst_fmt.height * ctx->bit_depth / 8;
-}
-
-static size_t hantro_hevc_motion_vectors_offset(struct hantro_ctx *ctx)
-{
- size_t cr_offset = hantro_hevc_chroma_offset(ctx);
-
- return ALIGN((cr_offset * 3) / 2, G2_ALIGN);
-}
-
static void prepare_tile_info_buffer(struct hantro_ctx *ctx)
{
struct hantro_dev *vpu = ctx->dev;
@@ -384,8 +370,8 @@ static int set_ref(struct hantro_ctx *ctx)
struct hantro_dev *vpu = ctx->dev;
struct vb2_v4l2_buffer *vb2_dst;
struct hantro_decoded_buffer *dst;
- size_t cr_offset = hantro_hevc_chroma_offset(ctx);
- size_t mv_offset = hantro_hevc_motion_vectors_offset(ctx);
+ size_t cr_offset = hantro_g2_chroma_offset(ctx);
+ size_t mv_offset = hantro_g2_motion_vectors_offset(ctx);
u32 max_ref_frames;
u16 dpb_longterm_e;
static const struct hantro_reg cur_poc[] = {
diff --git a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c
index 6fc4b555517f..342e543dee4c 100644
--- a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c
+++ b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c
@@ -16,8 +16,6 @@
#include "hantro_vp9.h"
#include "hantro_g2_regs.h"
-#define G2_ALIGN 16
-
enum hantro_ref_frames {
INTRA_FRAME = 0,
LAST_FRAME = 1,
@@ -90,22 +88,6 @@ static int start_prepare_run(struct hantro_ctx *ctx, const struct v4l2_ctrl_vp9_
return 0;
}
-static size_t chroma_offset(const struct hantro_ctx *ctx,
- const struct v4l2_ctrl_vp9_frame *dec_params)
-{
- int bytes_per_pixel = dec_params->bit_depth == 8 ? 1 : 2;
-
- return ctx->src_fmt.width * ctx->src_fmt.height * bytes_per_pixel;
-}
-
-static size_t mv_offset(const struct hantro_ctx *ctx,
- const struct v4l2_ctrl_vp9_frame *dec_params)
-{
- size_t cr_offset = chroma_offset(ctx, dec_params);
-
- return ALIGN((cr_offset * 3) / 2, G2_ALIGN);
-}
-
static struct hantro_decoded_buffer *
get_ref_buf(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
{
@@ -156,11 +138,13 @@ static void config_output(struct hantro_ctx *ctx,
luma_addr = hantro_get_dec_buf_addr(ctx, &dst->base.vb.vb2_buf);
hantro_write_addr(ctx->dev, G2_OUT_LUMA_ADDR, luma_addr);
- chroma_addr = luma_addr + chroma_offset(ctx, dec_params);
+ chroma_addr = luma_addr + hantro_g2_chroma_offset(ctx);
hantro_write_addr(ctx->dev, G2_OUT_CHROMA_ADDR, chroma_addr);
+ dst->vp9.chroma_offset = hantro_g2_chroma_offset(ctx);
- mv_addr = luma_addr + mv_offset(ctx, dec_params);
+ mv_addr = luma_addr + hantro_g2_motion_vectors_offset(ctx);
hantro_write_addr(ctx->dev, G2_OUT_MV_ADDR, mv_addr);
+ dst->vp9.mv_offset = hantro_g2_motion_vectors_offset(ctx);
}
struct hantro_vp9_ref_reg {
@@ -195,7 +179,7 @@ static void config_ref(struct hantro_ctx *ctx,
luma_addr = hantro_get_dec_buf_addr(ctx, &buf->base.vb.vb2_buf);
hantro_write_addr(ctx->dev, ref_reg->y_base, luma_addr);
- chroma_addr = luma_addr + chroma_offset(ctx, dec_params);
+ chroma_addr = luma_addr + buf->vp9.chroma_offset;
hantro_write_addr(ctx->dev, ref_reg->c_base, chroma_addr);
}
@@ -238,7 +222,7 @@ static void config_ref_registers(struct hantro_ctx *ctx,
config_ref(ctx, dst, &ref_regs[2], dec_params, dec_params->alt_frame_ts);
mv_addr = hantro_get_dec_buf_addr(ctx, &mv_ref->base.vb.vb2_buf) +
- mv_offset(ctx, dec_params);
+ mv_ref->vp9.mv_offset;
hantro_write_addr(ctx->dev, G2_REF_MV_ADDR(0), mv_addr);
hantro_reg_write(ctx->dev, &vp9_last_sign_bias,
diff --git a/drivers/media/platform/verisilicon/hantro_hw.h b/drivers/media/platform/verisilicon/hantro_hw.h
index 7f33f7b07ce4..9aec8a79acdc 100644
--- a/drivers/media/platform/verisilicon/hantro_hw.h
+++ b/drivers/media/platform/verisilicon/hantro_hw.h
@@ -40,6 +40,8 @@
#define AV1_MAX_FRAME_BUF_COUNT (V4L2_AV1_TOTAL_REFS_PER_FRAME + 1)
+#define MAX_POSTPROC_BUFFERS 64
+
struct hantro_dev;
struct hantro_ctx;
struct hantro_buf;
@@ -336,7 +338,7 @@ struct hantro_av1_dec_hw_ctx {
* @dec_q: References buffers, in decoder format.
*/
struct hantro_postproc_ctx {
- struct hantro_aux_buf dec_q[VB2_MAX_FRAME];
+ struct hantro_aux_buf dec_q[MAX_POSTPROC_BUFFERS];
};
/**
@@ -519,6 +521,9 @@ hantro_av1_mv_size(unsigned int width, unsigned int height)
return ALIGN(num_sbs * 384, 16) * 2 + 512;
}
+size_t hantro_g2_chroma_offset(struct hantro_ctx *ctx);
+size_t hantro_g2_motion_vectors_offset(struct hantro_ctx *ctx);
+
int hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx);
int rockchip_vpu2_mpeg2_dec_run(struct hantro_ctx *ctx);
void hantro_mpeg2_dec_copy_qtable(u8 *qtable,
diff --git a/drivers/media/platform/verisilicon/hantro_postproc.c b/drivers/media/platform/verisilicon/hantro_postproc.c
index 64d6fb852ae9..41e93176300b 100644
--- a/drivers/media/platform/verisilicon/hantro_postproc.c
+++ b/drivers/media/platform/verisilicon/hantro_postproc.c
@@ -177,9 +177,11 @@ static int hantro_postproc_g2_enum_framesizes(struct hantro_ctx *ctx,
void hantro_postproc_free(struct hantro_ctx *ctx)
{
struct hantro_dev *vpu = ctx->dev;
+ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+ struct vb2_queue *queue = &m2m_ctx->cap_q_ctx.q;
unsigned int i;
- for (i = 0; i < VB2_MAX_FRAME; ++i) {
+ for (i = 0; i < queue->max_num_buffers; ++i) {
struct hantro_aux_buf *priv = &ctx->postproc.dec_q[i];
if (priv->cpu) {
@@ -190,20 +192,17 @@ void hantro_postproc_free(struct hantro_ctx *ctx)
}
}
-int hantro_postproc_alloc(struct hantro_ctx *ctx)
+static unsigned int hantro_postproc_buffer_size(struct hantro_ctx *ctx)
{
- struct hantro_dev *vpu = ctx->dev;
- struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
- struct vb2_queue *cap_queue = &m2m_ctx->cap_q_ctx.q;
- unsigned int num_buffers = cap_queue->num_buffers;
struct v4l2_pix_format_mplane pix_mp;
const struct hantro_fmt *fmt;
- unsigned int i, buf_size;
+ unsigned int buf_size;
/* this should always pick native format */
fmt = hantro_get_default_fmt(ctx, false, ctx->bit_depth, HANTRO_AUTO_POSTPROC);
if (!fmt)
- return -EINVAL;
+ return 0;
+
v4l2_fill_pixfmt_mp(&pix_mp, fmt->fourcc, ctx->src_fmt.width,
ctx->src_fmt.height);
@@ -221,23 +220,77 @@ int hantro_postproc_alloc(struct hantro_ctx *ctx)
buf_size += hantro_av1_mv_size(pix_mp.width,
pix_mp.height);
- for (i = 0; i < num_buffers; ++i) {
- struct hantro_aux_buf *priv = &ctx->postproc.dec_q[i];
+ return buf_size;
+}
+
+static int hantro_postproc_alloc(struct hantro_ctx *ctx, int index)
+{
+ struct hantro_dev *vpu = ctx->dev;
+ struct hantro_aux_buf *priv = &ctx->postproc.dec_q[index];
+ unsigned int buf_size = hantro_postproc_buffer_size(ctx);
+
+ if (!buf_size)
+ return -EINVAL;
+
+ /*
+ * The buffers on this queue are meant as intermediate
+ * buffers for the decoder, so no mapping is needed.
+ */
+ priv->attrs = DMA_ATTR_NO_KERNEL_MAPPING;
+ priv->cpu = dma_alloc_attrs(vpu->dev, buf_size, &priv->dma,
+ GFP_KERNEL, priv->attrs);
+ if (!priv->cpu)
+ return -ENOMEM;
+ priv->size = buf_size;
+
+ return 0;
+}
- /*
- * The buffers on this queue are meant as intermediate
- * buffers for the decoder, so no mapping is needed.
- */
- priv->attrs = DMA_ATTR_NO_KERNEL_MAPPING;
- priv->cpu = dma_alloc_attrs(vpu->dev, buf_size, &priv->dma,
- GFP_KERNEL, priv->attrs);
- if (!priv->cpu)
- return -ENOMEM;
- priv->size = buf_size;
+int hantro_postproc_init(struct hantro_ctx *ctx)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
+ struct vb2_queue *cap_queue = &m2m_ctx->cap_q_ctx.q;
+ unsigned int num_buffers = vb2_get_num_buffers(cap_queue);
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < num_buffers; i++) {
+ ret = hantro_postproc_alloc(ctx, i);
+ if (ret)
+ return ret;
}
+
return 0;
}
+dma_addr_t
+hantro_postproc_get_dec_buf_addr(struct hantro_ctx *ctx, int index)
+{
+ struct hantro_aux_buf *priv = &ctx->postproc.dec_q[index];
+ unsigned int buf_size = hantro_postproc_buffer_size(ctx);
+ struct hantro_dev *vpu = ctx->dev;
+ int ret;
+
+ if (priv->size < buf_size && priv->cpu) {
+ /* buffer is too small, release it */
+ dma_free_attrs(vpu->dev, priv->size, priv->cpu,
+ priv->dma, priv->attrs);
+ priv->cpu = NULL;
+ }
+
+ if (!priv->cpu) {
+ /* buffer not already allocated, try getting a new one */
+ ret = hantro_postproc_alloc(ctx, index);
+ if (ret)
+ return 0;
+ }
+
+ if (!priv->cpu)
+ return 0;
+
+ return priv->dma;
+}
+
static void hantro_postproc_g1_disable(struct hantro_ctx *ctx)
{
struct hantro_dev *vpu = ctx->dev;
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index b3ae037a50f6..941fa23c211a 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -514,25 +514,14 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx,
return ret;
if (!ctx->is_encoder) {
- struct vb2_queue *peer_vq;
-
/*
* In order to support dynamic resolution change,
* the decoder admits a resolution change, as long
- * as the pixelformat remains. Can't be done if streaming.
- */
- if (vb2_is_streaming(vq) || (vb2_is_busy(vq) &&
- pix_mp->pixelformat != ctx->src_fmt.pixelformat))
- return -EBUSY;
- /*
- * Since format change on the OUTPUT queue will reset
- * the CAPTURE queue, we can't allow doing so
- * when the CAPTURE queue has buffers allocated.
+ * as the pixelformat remains.
*/
- peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
- V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
- if (vb2_is_busy(peer_vq))
+ if (vb2_is_streaming(vq) && pix_mp->pixelformat != ctx->src_fmt.pixelformat) {
return -EBUSY;
+ }
} else {
/*
* The encoder doesn't admit a format change if
@@ -577,15 +566,8 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx,
static int hantro_set_fmt_cap(struct hantro_ctx *ctx,
struct v4l2_pix_format_mplane *pix_mp)
{
- struct vb2_queue *vq;
int ret;
- /* Change not allowed if queue is busy. */
- vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
- V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
- if (vb2_is_busy(vq))
- return -EBUSY;
-
if (ctx->is_encoder) {
struct vb2_queue *peer_vq;
@@ -785,6 +767,9 @@ const struct v4l2_ioctl_ops hantro_ioctl_ops = {
.vidioc_g_selection = vidioc_g_selection,
.vidioc_s_selection = vidioc_s_selection,
+ .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd,
+ .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd,
+
.vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
.vidioc_encoder_cmd = vidioc_encoder_cmd,
};
@@ -933,7 +918,7 @@ static int hantro_start_streaming(struct vb2_queue *q, unsigned int count)
}
if (hantro_needs_postproc(ctx, ctx->vpu_dst_fmt)) {
- ret = hantro_postproc_alloc(ctx);
+ ret = hantro_postproc_init(ctx);
if (ret)
goto err_codec_exit;
}
diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c
index 5de6b6694f53..31e9e92e723e 100644
--- a/drivers/media/platform/video-mux.c
+++ b/drivers/media/platform/video-mux.c
@@ -89,10 +89,10 @@ static int video_mux_link_setup(struct media_entity *entity,
/* Propagate the active format to the source */
sd_state = v4l2_subdev_lock_and_get_active_state(sd);
- source_mbusformat = v4l2_subdev_get_pad_format(sd, sd_state,
- source_pad);
- *source_mbusformat = *v4l2_subdev_get_pad_format(sd, sd_state,
- vmux->active);
+ source_mbusformat = v4l2_subdev_state_get_format(sd_state,
+ source_pad);
+ *source_mbusformat = *v4l2_subdev_state_get_format(sd_state,
+ vmux->active);
v4l2_subdev_unlock_state(sd_state);
} else {
if (vmux->active != local->index)
@@ -154,11 +154,11 @@ static int video_mux_set_format(struct v4l2_subdev *sd,
struct media_pad *pad = &vmux->pads[sdformat->pad];
u16 source_pad = sd->entity.num_pads - 1;
- mbusformat = v4l2_subdev_get_pad_format(sd, sd_state, sdformat->pad);
+ mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
if (!mbusformat)
return -EINVAL;
- source_mbusformat = v4l2_subdev_get_pad_format(sd, sd_state, source_pad);
+ source_mbusformat = v4l2_subdev_state_get_format(sd_state, source_pad);
if (!source_mbusformat)
return -EINVAL;
@@ -268,8 +268,8 @@ static int video_mux_set_format(struct v4l2_subdev *sd,
/* Source pad mirrors active sink pad, no limitations on sink pads */
if ((pad->flags & MEDIA_PAD_FL_SOURCE) && vmux->active >= 0)
- sdformat->format = *v4l2_subdev_get_pad_format(sd, sd_state,
- vmux->active);
+ sdformat->format = *v4l2_subdev_state_get_format(sd_state,
+ vmux->active);
*mbusformat = sdformat->format;
@@ -282,8 +282,8 @@ static int video_mux_set_format(struct v4l2_subdev *sd,
return 0;
}
-static int video_mux_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int video_mux_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
struct v4l2_mbus_framefmt *mbusformat;
@@ -292,7 +292,7 @@ static int video_mux_init_cfg(struct v4l2_subdev *sd,
mutex_lock(&vmux->lock);
for (i = 0; i < sd->entity.num_pads; i++) {
- mbusformat = v4l2_subdev_get_pad_format(sd, sd_state, i);
+ mbusformat = v4l2_subdev_state_get_format(sd_state, i);
*mbusformat = video_mux_format_mbus_default;
}
@@ -302,7 +302,6 @@ static int video_mux_init_cfg(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_pad_ops video_mux_pad_ops = {
- .init_cfg = video_mux_init_cfg,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = video_mux_set_format,
};
@@ -312,6 +311,10 @@ static const struct v4l2_subdev_ops video_mux_subdev_ops = {
.video = &video_mux_subdev_video_ops,
};
+static const struct v4l2_subdev_internal_ops video_mux_internal_ops = {
+ .init_state = video_mux_init_state,
+};
+
static int video_mux_notify_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *sd,
struct v4l2_async_connection *asd)
@@ -400,6 +403,7 @@ static int video_mux_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, vmux);
v4l2_subdev_init(&vmux->subdev, &video_mux_subdev_ops);
+ vmux->subdev.internal_ops = &video_mux_internal_ops;
snprintf(vmux->subdev.name, sizeof(vmux->subdev.name), "%pOFn", np);
vmux->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
vmux->subdev.dev = dev;
diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
index 5b53745fe44e..f953d5474ae0 100644
--- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c
+++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
@@ -386,14 +386,6 @@ static void xcsi2rxss_log_counters(struct xcsi2rxss_state *state)
}
}
-/**
- * xcsi2rxss_log_status - Logs the status of the CSI-2 Receiver
- * @sd: Pointer to V4L2 subdevice structure
- *
- * This function prints the current status of Xilinx MIPI CSI-2
- *
- * Return: 0 on success
- */
static int xcsi2rxss_log_status(struct v4l2_subdev *sd)
{
struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
@@ -631,16 +623,6 @@ static irqreturn_t xcsi2rxss_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
-/**
- * xcsi2rxss_s_stream - It is used to start/stop the streaming.
- * @sd: V4L2 Sub device
- * @enable: Flag (True / False)
- *
- * This function controls the start or stop of streaming for the
- * Xilinx MIPI CSI-2 Rx Subsystem.
- *
- * Return: 0 on success, errors otherwise
- */
static int xcsi2rxss_s_stream(struct v4l2_subdev *sd, int enable)
{
struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
@@ -671,8 +653,7 @@ __xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&xcsi2rxss->subdev,
- sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &xcsi2rxss->format;
default:
@@ -680,18 +661,8 @@ __xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss,
}
}
-/**
- * xcsi2rxss_init_cfg - Initialise the pad format config to default
- * @sd: Pointer to V4L2 Sub device structure
- * @sd_state: Pointer to sub device state structure
- *
- * This function is used to initialize the pad format with the default
- * values.
- *
- * Return: 0 on success
- */
-static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int xcsi2rxss_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
struct v4l2_mbus_framefmt *format;
@@ -699,7 +670,7 @@ static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd,
mutex_lock(&xcsi2rxss->lock);
for (i = 0; i < XCSI_MEDIA_PADS; i++) {
- format = v4l2_subdev_get_try_format(sd, sd_state, i);
+ format = v4l2_subdev_state_get_format(sd_state, i);
*format = xcsi2rxss->default_format;
}
mutex_unlock(&xcsi2rxss->lock);
@@ -707,16 +678,6 @@ static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd,
return 0;
}
-/**
- * xcsi2rxss_get_format - Get the pad format
- * @sd: Pointer to V4L2 Sub device structure
- * @sd_state: Pointer to sub device state structure
- * @fmt: Pointer to pad level media bus format
- *
- * This function is used to get the pad format information.
- *
- * Return: 0 on success
- */
static int xcsi2rxss_get_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
@@ -732,19 +693,6 @@ static int xcsi2rxss_get_format(struct v4l2_subdev *sd,
return 0;
}
-/**
- * xcsi2rxss_set_format - This is used to set the pad format
- * @sd: Pointer to V4L2 Sub device structure
- * @sd_state: Pointer to sub device state structure
- * @fmt: Pointer to pad level media bus format
- *
- * This function is used to set the pad format. Since the pad format is fixed
- * in hardware, it can't be modified on run time. So when a format set is
- * requested by application, all parameters except the format type is saved
- * for the pad and the original pad format is sent back to the application.
- *
- * Return: 0 on success
- */
static int xcsi2rxss_set_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
@@ -789,14 +737,6 @@ static int xcsi2rxss_set_format(struct v4l2_subdev *sd,
return 0;
}
-/*
- * xcsi2rxss_enum_mbus_code - Handle pixel format enumeration
- * @sd: pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad configuration
- * @code: pointer to v4l2_subdev_mbus_code_enum structure
- *
- * Return: -EINVAL or zero on success
- */
static int xcsi2rxss_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
@@ -840,7 +780,6 @@ static const struct v4l2_subdev_video_ops xcsi2rxss_video_ops = {
};
static const struct v4l2_subdev_pad_ops xcsi2rxss_pad_ops = {
- .init_cfg = xcsi2rxss_init_cfg,
.get_fmt = xcsi2rxss_get_format,
.set_fmt = xcsi2rxss_set_format,
.enum_mbus_code = xcsi2rxss_enum_mbus_code,
@@ -853,6 +792,10 @@ static const struct v4l2_subdev_ops xcsi2rxss_ops = {
.pad = &xcsi2rxss_pad_ops
};
+static const struct v4l2_subdev_internal_ops xcsi2rxss_internal_ops = {
+ .init_state = xcsi2rxss_init_state,
+};
+
static int xcsi2rxss_parse_of(struct xcsi2rxss_state *xcsi2rxss)
{
struct device *dev = xcsi2rxss->dev;
@@ -1030,6 +973,7 @@ static int xcsi2rxss_probe(struct platform_device *pdev)
/* Initialize V4L2 subdevice and media entity */
subdev = &xcsi2rxss->subdev;
v4l2_subdev_init(subdev, &xcsi2rxss_ops);
+ subdev->internal_ops = &xcsi2rxss_internal_ops;
subdev->dev = dev;
strscpy(subdev->name, dev_name(dev), sizeof(subdev->name));
subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c
index 80353ca44402..e05e528ffc6f 100644
--- a/drivers/media/platform/xilinx/xilinx-tpg.c
+++ b/drivers/media/platform/xilinx/xilinx-tpg.c
@@ -256,8 +256,7 @@ __xtpg_get_pad_format(struct xtpg_device *xtpg,
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_format(&xtpg->xvip.subdev,
- sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
return &xtpg->formats[pad];
default:
@@ -326,7 +325,7 @@ static int xtpg_enum_frame_size(struct v4l2_subdev *subdev,
{
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_try_format(subdev, sd_state, fse->pad);
+ format = v4l2_subdev_state_get_format(sd_state, fse->pad);
if (fse->index || fse->code != format->code)
return -EINVAL;
@@ -354,11 +353,11 @@ static int xtpg_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
struct xtpg_device *xtpg = to_tpg(subdev);
struct v4l2_mbus_framefmt *format;
- format = v4l2_subdev_get_try_format(subdev, fh->state, 0);
+ format = v4l2_subdev_state_get_format(fh->state, 0);
*format = xtpg->default_format;
if (xtpg->npads == 2) {
- format = v4l2_subdev_get_try_format(subdev, fh->state, 1);
+ format = v4l2_subdev_state_get_format(fh->state, 1);
*format = xtpg->default_format;
}
diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c
index 5b214bf7f93a..f1574edd2b43 100644
--- a/drivers/media/platform/xilinx/xilinx-vip.c
+++ b/drivers/media/platform/xilinx/xilinx-vip.c
@@ -260,7 +260,7 @@ int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
if (code->index)
return -EINVAL;
- format = v4l2_subdev_get_try_format(subdev, sd_state, code->pad);
+ format = v4l2_subdev_state_get_format(sd_state, code->pad);
code->code = format->code;
@@ -295,7 +295,7 @@ int xvip_enum_frame_size(struct v4l2_subdev *subdev,
if (fse->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return -EINVAL;
- format = v4l2_subdev_get_try_format(subdev, sd_state, fse->pad);
+ format = v4l2_subdev_state_get_format(sd_state, fse->pad);
if (fse->index || fse->code != format->code)
return -EINVAL;
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
index 0034f615b466..de5bb9a08ea4 100644
--- a/drivers/media/rc/ir-hix5hd2.c
+++ b/drivers/media/rc/ir-hix5hd2.c
@@ -9,7 +9,9 @@
#include <linux/interrupt.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <media/rc-core.h>
@@ -251,7 +253,6 @@ static int hix5hd2_ir_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct hix5hd2_ir_priv *priv;
struct device_node *node = pdev->dev.of_node;
- const struct of_device_id *of_id;
const char *map_name;
int ret;
@@ -259,12 +260,11 @@ static int hix5hd2_ir_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
- of_id = of_match_device(hix5hd2_ir_table, dev);
- if (!of_id) {
+ priv->socdata = device_get_match_data(dev);
+ if (!priv->socdata) {
dev_err(dev, "Unable to initialize IR data\n");
return -ENODEV;
}
- priv->socdata = of_id->data;
priv->regmap = syscon_regmap_lookup_by_phandle(node,
"hisilicon,power-syscon");
diff --git a/drivers/media/rc/meson-ir-tx.c b/drivers/media/rc/meson-ir-tx.c
index 6355b79893fb..fded2c256f2a 100644
--- a/drivers/media/rc/meson-ir-tx.c
+++ b/drivers/media/rc/meson-ir-tx.c
@@ -305,7 +305,7 @@ static int meson_irtx_mod_clock_probe(struct meson_irtx *ir,
return 0;
}
-static int __init meson_irtx_probe(struct platform_device *pdev)
+static int meson_irtx_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct meson_irtx *ir;
@@ -333,20 +333,17 @@ static int __init meson_irtx_probe(struct platform_device *pdev)
spin_lock_init(&ir->lock);
ret = meson_irtx_mod_clock_probe(ir, &clk_nr);
- if (ret) {
- dev_err(dev, "modulator clock setup failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "modulator clock setup failed\n");
+
meson_irtx_setup(ir, clk_nr);
ret = devm_request_irq(dev, irq,
meson_irtx_irqhandler,
IRQF_TRIGGER_RISING,
DRIVER_NAME, ir);
- if (ret) {
- dev_err(dev, "irq request failed\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "irq request failed\n");
rc = rc_allocate_device(RC_DRIVER_IR_RAW_TX);
if (!rc)
@@ -360,25 +357,15 @@ static int __init meson_irtx_probe(struct platform_device *pdev)
rc->s_tx_carrier = meson_irtx_set_carrier;
rc->s_tx_duty_cycle = meson_irtx_set_duty_cycle;
- ret = rc_register_device(rc);
+ ret = devm_rc_register_device(dev, rc);
if (ret < 0) {
- dev_err(dev, "rc_dev registration failed\n");
rc_free_device(rc);
- return ret;
+ return dev_err_probe(dev, ret, "rc_dev registration failed\n");
}
- platform_set_drvdata(pdev, rc);
-
return 0;
}
-static void meson_irtx_remove(struct platform_device *pdev)
-{
- struct rc_dev *rc = platform_get_drvdata(pdev);
-
- rc_unregister_device(rc);
-}
-
static const struct of_device_id meson_irtx_dt_match[] = {
{
.compatible = "amlogic,meson-g12a-ir-tx",
@@ -388,14 +375,13 @@ static const struct of_device_id meson_irtx_dt_match[] = {
MODULE_DEVICE_TABLE(of, meson_irtx_dt_match);
static struct platform_driver meson_irtx_pd = {
- .remove_new = meson_irtx_remove,
+ .probe = meson_irtx_probe,
.driver = {
.name = DRIVER_NAME,
.of_match_table = meson_irtx_dt_match,
},
};
-
-module_platform_driver_probe(meson_irtx_pd, meson_irtx_probe);
+module_platform_driver(meson_irtx_pd);
MODULE_DESCRIPTION("Meson IR TX driver");
MODULE_AUTHOR("Viktor Prutyanov <[email protected]>");
diff --git a/drivers/media/rc/pwm-ir-tx.c b/drivers/media/rc/pwm-ir-tx.c
index c5f37c03af9c..fe368aebbc13 100644
--- a/drivers/media/rc/pwm-ir-tx.c
+++ b/drivers/media/rc/pwm-ir-tx.c
@@ -10,6 +10,8 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/hrtimer.h>
+#include <linux/completion.h>
#include <media/rc-core.h>
#define DRIVER_NAME "pwm-ir-tx"
@@ -17,8 +19,14 @@
struct pwm_ir {
struct pwm_device *pwm;
- unsigned int carrier;
- unsigned int duty_cycle;
+ struct hrtimer timer;
+ struct completion tx_done;
+ struct pwm_state *state;
+ u32 carrier;
+ u32 duty_cycle;
+ const unsigned int *txbuf;
+ unsigned int txbuf_len;
+ unsigned int txbuf_index;
};
static const struct of_device_id pwm_ir_of_match[] = {
@@ -49,8 +57,8 @@ static int pwm_ir_set_carrier(struct rc_dev *dev, u32 carrier)
return 0;
}
-static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf,
- unsigned int count)
+static int pwm_ir_tx_sleep(struct rc_dev *dev, unsigned int *txbuf,
+ unsigned int count)
{
struct pwm_ir *pwm_ir = dev->priv;
struct pwm_device *pwm = pwm_ir->pwm;
@@ -68,7 +76,7 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf,
for (i = 0; i < count; i++) {
state.enabled = !(i % 2);
- pwm_apply_state(pwm, &state);
+ pwm_apply_might_sleep(pwm, &state);
edge = ktime_add_us(edge, txbuf[i]);
delta = ktime_us_delta(edge, ktime_get());
@@ -77,11 +85,67 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf,
}
state.enabled = false;
- pwm_apply_state(pwm, &state);
+ pwm_apply_might_sleep(pwm, &state);
return count;
}
+static int pwm_ir_tx_atomic(struct rc_dev *dev, unsigned int *txbuf,
+ unsigned int count)
+{
+ struct pwm_ir *pwm_ir = dev->priv;
+ struct pwm_device *pwm = pwm_ir->pwm;
+ struct pwm_state state;
+
+ pwm_init_state(pwm, &state);
+
+ state.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, pwm_ir->carrier);
+ pwm_set_relative_duty_cycle(&state, pwm_ir->duty_cycle, 100);
+
+ pwm_ir->txbuf = txbuf;
+ pwm_ir->txbuf_len = count;
+ pwm_ir->txbuf_index = 0;
+ pwm_ir->state = &state;
+
+ hrtimer_start(&pwm_ir->timer, 0, HRTIMER_MODE_REL);
+
+ wait_for_completion(&pwm_ir->tx_done);
+
+ return count;
+}
+
+static enum hrtimer_restart pwm_ir_timer(struct hrtimer *timer)
+{
+ struct pwm_ir *pwm_ir = container_of(timer, struct pwm_ir, timer);
+ ktime_t now;
+
+ /*
+ * If we happen to hit an odd latency spike, loop through the
+ * pulses until we catch up.
+ */
+ do {
+ u64 ns;
+
+ pwm_ir->state->enabled = !(pwm_ir->txbuf_index % 2);
+ pwm_apply_atomic(pwm_ir->pwm, pwm_ir->state);
+
+ if (pwm_ir->txbuf_index >= pwm_ir->txbuf_len) {
+ complete(&pwm_ir->tx_done);
+
+ return HRTIMER_NORESTART;
+ }
+
+ ns = US_TO_NS(pwm_ir->txbuf[pwm_ir->txbuf_index]);
+ hrtimer_add_expires_ns(timer, ns);
+
+ pwm_ir->txbuf_index++;
+
+ now = timer->base->get_time();
+ } while (hrtimer_get_expires_tv64(timer) < now);
+
+ return HRTIMER_RESTART;
+}
+
static int pwm_ir_probe(struct platform_device *pdev)
{
struct pwm_ir *pwm_ir;
@@ -103,10 +167,19 @@ static int pwm_ir_probe(struct platform_device *pdev)
if (!rcdev)
return -ENOMEM;
+ if (pwm_might_sleep(pwm_ir->pwm)) {
+ dev_info(&pdev->dev, "TX will not be accurate as PWM device might sleep\n");
+ rcdev->tx_ir = pwm_ir_tx_sleep;
+ } else {
+ init_completion(&pwm_ir->tx_done);
+ hrtimer_init(&pwm_ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ pwm_ir->timer.function = pwm_ir_timer;
+ rcdev->tx_ir = pwm_ir_tx_atomic;
+ }
+
rcdev->priv = pwm_ir;
rcdev->driver_name = DRIVER_NAME;
rcdev->device_name = DEVICE_NAME;
- rcdev->tx_ir = pwm_ir_tx;
rcdev->s_tx_duty_cycle = pwm_ir_set_duty_cycle;
rcdev->s_tx_carrier = pwm_ir_set_carrier;
diff --git a/drivers/media/test-drivers/Kconfig b/drivers/media/test-drivers/Kconfig
index 459b433e9fae..5a5379524bde 100644
--- a/drivers/media/test-drivers/Kconfig
+++ b/drivers/media/test-drivers/Kconfig
@@ -12,7 +12,6 @@ config VIDEO_VIM2M
select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
select MEDIA_CONTROLLER
- select MEDIA_CONTROLLER_REQUEST_API
help
This is a virtual test device for the memory-to-memory driver
framework.
diff --git a/drivers/media/test-drivers/vicodec/Kconfig b/drivers/media/test-drivers/vicodec/Kconfig
index a7a828eec2a4..4ea0689c3abe 100644
--- a/drivers/media/test-drivers/vicodec/Kconfig
+++ b/drivers/media/test-drivers/vicodec/Kconfig
@@ -5,7 +5,6 @@ config VIDEO_VICODEC
select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
select MEDIA_CONTROLLER
- select MEDIA_CONTROLLER_REQUEST_API
help
Driver for a Virtual Codec
diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c
index 6f0e20df74e9..e13f5452b927 100644
--- a/drivers/media/test-drivers/vicodec/vicodec-core.c
+++ b/drivers/media/test-drivers/vicodec/vicodec-core.c
@@ -1240,6 +1240,12 @@ static int vicodec_decoder_cmd(struct file *file, void *fh,
struct vicodec_ctx *ctx = file2ctx(file);
int ret;
+ /*
+ * This ioctl should not be used with a stateless codec that doesn't
+ * support holding buffers and the associated flush command.
+ */
+ WARN_ON(ctx->is_stateless);
+
ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
if (ret < 0)
return ret;
@@ -1718,6 +1724,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
V4L2_BUF_TYPE_VIDEO_CAPTURE);
dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ dst_vq->max_num_buffers = 64;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &vicodec_qops;
@@ -2025,7 +2032,7 @@ static const struct v4l2_m2m_ops m2m_ops = {
static int register_instance(struct vicodec_dev *dev,
struct vicodec_dev_instance *dev_instance,
- const char *name, bool is_enc)
+ const char *name, bool is_enc, bool is_stateless)
{
struct video_device *vfd;
int ret;
@@ -2045,10 +2052,11 @@ static int register_instance(struct vicodec_dev *dev,
strscpy(vfd->name, name, sizeof(vfd->name));
vfd->device_caps = V4L2_CAP_STREAMING |
(multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
- if (is_enc) {
+ if (is_enc || is_stateless) {
v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
- } else {
+ }
+ if (!is_enc) {
v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
}
@@ -2107,17 +2115,17 @@ static int vicodec_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
ret = register_instance(dev, &dev->stateful_enc, "stateful-encoder",
- true);
+ true, false);
if (ret)
goto unreg_dev;
ret = register_instance(dev, &dev->stateful_dec, "stateful-decoder",
- false);
+ false, false);
if (ret)
goto unreg_sf_enc;
ret = register_instance(dev, &dev->stateless_dec, "stateless-decoder",
- false);
+ false, true);
if (ret)
goto unreg_sf_dec;
diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c
index aa944270e716..2a2d19d23bab 100644
--- a/drivers/media/test-drivers/vimc/vimc-capture.c
+++ b/drivers/media/test-drivers/vimc/vimc-capture.c
@@ -432,7 +432,7 @@ static struct vimc_ent_device *vimc_capture_add(struct vimc_device *vimc,
q->mem_ops = vimc_allocator == VIMC_ALLOCATOR_DMA_CONTIG
? &vb2_dma_contig_memops : &vb2_vmalloc_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->lock = &vcapture->lock;
q->dev = v4l2_dev->dev;
diff --git a/drivers/media/test-drivers/vimc/vimc-debayer.c b/drivers/media/test-drivers/vimc/vimc-debayer.c
index f671251fdf0e..d72ed086e00b 100644
--- a/drivers/media/test-drivers/vimc/vimc-debayer.c
+++ b/drivers/media/test-drivers/vimc/vimc-debayer.c
@@ -150,18 +150,18 @@ static bool vimc_debayer_src_code_is_valid(u32 code)
return false;
}
-static int vimc_debayer_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int vimc_debayer_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf;
unsigned int i;
- mf = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ mf = v4l2_subdev_state_get_format(sd_state, 0);
*mf = sink_fmt_default;
for (i = 1; i < sd->entity.num_pads; i++) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, i);
+ mf = v4l2_subdev_state_get_format(sd_state, i);
*mf = sink_fmt_default;
mf->code = vdebayer->src_code;
}
@@ -221,7 +221,7 @@ static int vimc_debayer_get_fmt(struct v4l2_subdev *sd,
/* Get the current sink format */
fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
- *v4l2_subdev_get_try_format(sd, sd_state, 0) :
+ *v4l2_subdev_state_get_format(sd_state, 0) :
vdebayer->sink_fmt;
/* Set the right code for the source pad */
@@ -267,8 +267,8 @@ static int vimc_debayer_set_fmt(struct v4l2_subdev *sd,
sink_fmt = &vdebayer->sink_fmt;
src_code = &vdebayer->src_code;
} else {
- sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
- src_code = &v4l2_subdev_get_try_format(sd, sd_state, 1)->code;
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
+ src_code = &v4l2_subdev_state_get_format(sd_state, 1)->code;
}
/*
@@ -307,7 +307,6 @@ static int vimc_debayer_set_fmt(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_pad_ops vimc_debayer_pad_ops = {
- .init_cfg = vimc_debayer_init_cfg,
.enum_mbus_code = vimc_debayer_enum_mbus_code,
.enum_frame_size = vimc_debayer_enum_frame_size,
.get_fmt = vimc_debayer_get_fmt,
@@ -395,6 +394,10 @@ static const struct v4l2_subdev_ops vimc_debayer_ops = {
.video = &vimc_debayer_video_ops,
};
+static const struct v4l2_subdev_internal_ops vimc_debayer_internal_ops = {
+ .init_state = vimc_debayer_init_state,
+};
+
static unsigned int vimc_debayer_get_val(const u8 *bytes,
const unsigned int n_bytes)
{
@@ -595,6 +598,8 @@ static struct vimc_ent_device *vimc_debayer_add(struct vimc_device *vimc,
if (ret)
goto err_free_hdl;
+ vdebayer->sd.internal_ops = &vimc_debayer_internal_ops;
+
vdebayer->ved.process_frame = vimc_debayer_process_frame;
vdebayer->ved.dev = vimc->mdev.dev;
vdebayer->mean_win_size = vimc_debayer_ctrl_mean_win_size.def;
diff --git a/drivers/media/test-drivers/vimc/vimc-scaler.c b/drivers/media/test-drivers/vimc/vimc-scaler.c
index b671774e2784..afe13d6af321 100644
--- a/drivers/media/test-drivers/vimc/vimc-scaler.c
+++ b/drivers/media/test-drivers/vimc/vimc-scaler.c
@@ -70,19 +70,19 @@ vimc_scaler_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt)
return r;
}
-static int vimc_scaler_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int vimc_scaler_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *mf;
struct v4l2_rect *r;
unsigned int i;
for (i = 0; i < sd->entity.num_pads; i++) {
- mf = v4l2_subdev_get_try_format(sd, sd_state, i);
+ mf = v4l2_subdev_state_get_format(sd_state, i);
*mf = fmt_default;
}
- r = v4l2_subdev_get_try_crop(sd, sd_state, VIMC_SCALER_SINK);
+ r = v4l2_subdev_state_get_crop(sd_state, VIMC_SCALER_SINK);
*r = crop_rect_default;
return 0;
@@ -138,7 +138,7 @@ vimc_scaler_pad_format(struct vimc_scaler_device *vscaler,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&vscaler->sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
else
return &vscaler->fmt[pad];
}
@@ -149,8 +149,7 @@ vimc_scaler_pad_crop(struct vimc_scaler_device *vscaler,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&vscaler->sd, sd_state,
- VIMC_SCALER_SINK);
+ return v4l2_subdev_state_get_crop(sd_state, VIMC_SCALER_SINK);
else
return &vscaler->crop_rect;
}
@@ -293,7 +292,6 @@ static int vimc_scaler_set_selection(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_pad_ops vimc_scaler_pad_ops = {
- .init_cfg = vimc_scaler_init_cfg,
.enum_mbus_code = vimc_scaler_enum_mbus_code,
.enum_frame_size = vimc_scaler_enum_frame_size,
.get_fmt = vimc_scaler_get_fmt,
@@ -348,6 +346,10 @@ static const struct v4l2_subdev_ops vimc_scaler_ops = {
.video = &vimc_scaler_video_ops,
};
+static const struct v4l2_subdev_internal_ops vimc_scaler_internal_ops = {
+ .init_state = vimc_scaler_init_state,
+};
+
static void vimc_scaler_fill_src_frame(const struct vimc_scaler_device *const vscaler,
const u8 *const sink_frame)
{
@@ -425,6 +427,8 @@ static struct vimc_ent_device *vimc_scaler_add(struct vimc_device *vimc,
return ERR_PTR(ret);
}
+ vscaler->sd.internal_ops = &vimc_scaler_internal_ops;
+
vscaler->ved.process_frame = vimc_scaler_process_frame;
vscaler->ved.dev = vimc->mdev.dev;
diff --git a/drivers/media/test-drivers/vimc/vimc-sensor.c b/drivers/media/test-drivers/vimc/vimc-sensor.c
index 41a3dce2d714..5e34b1aed95e 100644
--- a/drivers/media/test-drivers/vimc/vimc-sensor.c
+++ b/drivers/media/test-drivers/vimc/vimc-sensor.c
@@ -41,15 +41,15 @@ static const struct v4l2_mbus_framefmt fmt_default = {
.colorspace = V4L2_COLORSPACE_SRGB,
};
-static int vimc_sensor_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int vimc_sensor_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
unsigned int i;
for (i = 0; i < sd->entity.num_pads; i++) {
struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_get_try_format(sd, sd_state, i);
+ mf = v4l2_subdev_state_get_format(sd_state, i);
*mf = fmt_default;
}
@@ -100,7 +100,7 @@ static int vimc_sensor_get_fmt(struct v4l2_subdev *sd,
container_of(sd, struct vimc_sensor_device, sd);
fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
- *v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) :
+ *v4l2_subdev_state_get_format(sd_state, fmt->pad) :
vsensor->mbus_format;
return 0;
@@ -159,7 +159,7 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *sd,
mf = &vsensor->mbus_format;
} else {
- mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
}
/* Set the new format */
@@ -183,7 +183,6 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_pad_ops vimc_sensor_pad_ops = {
- .init_cfg = vimc_sensor_init_cfg,
.enum_mbus_code = vimc_sensor_enum_mbus_code,
.enum_frame_size = vimc_sensor_enum_frame_size,
.get_fmt = vimc_sensor_get_fmt,
@@ -294,6 +293,10 @@ static const struct v4l2_subdev_ops vimc_sensor_ops = {
.video = &vimc_sensor_video_ops,
};
+static const struct v4l2_subdev_internal_ops vimc_sensor_internal_ops = {
+ .init_state = vimc_sensor_init_state,
+};
+
static int vimc_sensor_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct vimc_sensor_device *vsensor =
@@ -429,6 +432,8 @@ static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc,
if (ret)
goto err_free_tpg;
+ vsensor->sd.internal_ops = &vimc_sensor_internal_ops;
+
vsensor->ved.process_frame = vimc_sensor_process_frame;
vsensor->ved.dev = vimc->mdev.dev;
diff --git a/drivers/media/test-drivers/visl/Kconfig b/drivers/media/test-drivers/visl/Kconfig
index 7508b904f196..37be9f267224 100644
--- a/drivers/media/test-drivers/visl/Kconfig
+++ b/drivers/media/test-drivers/visl/Kconfig
@@ -7,7 +7,6 @@ config VIDEO_VISL
select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
select MEDIA_CONTROLLER
- select MEDIA_CONTROLLER_REQUEST_API
select VIDEO_V4L2_TPG
help
diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c
index 9970dc739ca5..68dac896277b 100644
--- a/drivers/media/test-drivers/visl/visl-core.c
+++ b/drivers/media/test-drivers/visl/visl-core.c
@@ -211,6 +211,27 @@ const struct visl_ctrls visl_hevc_ctrls = {
.num_ctrls = ARRAY_SIZE(visl_hevc_ctrl_descs),
};
+static const struct visl_ctrl_desc visl_av1_ctrl_descs[] = {
+ {
+ .cfg.id = V4L2_CID_STATELESS_AV1_FRAME,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY,
+ .cfg.dims = { V4L2_AV1_MAX_TILE_COUNT },
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_AV1_SEQUENCE,
+ },
+ {
+ .cfg.id = V4L2_CID_STATELESS_AV1_FILM_GRAIN,
+ },
+};
+
+const struct visl_ctrls visl_av1_ctrls = {
+ .ctrls = visl_av1_ctrl_descs,
+ .num_ctrls = ARRAY_SIZE(visl_av1_ctrl_descs),
+};
+
struct v4l2_ctrl *visl_find_control(struct visl_ctx *ctx, u32 id)
{
struct v4l2_ctrl_handler *hdl = &ctx->hdl;
diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c
index 318d675e5668..f21260054e0f 100644
--- a/drivers/media/test-drivers/visl/visl-dec.c
+++ b/drivers/media/test-drivers/visl/visl-dec.c
@@ -13,12 +13,21 @@
#include "visl-trace-vp9.h"
#include "visl-trace-h264.h"
#include "visl-trace-hevc.h"
+#include "visl-trace-av1.h"
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <media/v4l2-mem2mem.h>
#include <media/tpg/v4l2-tpg.h>
+#define LAST_BUF_IDX (V4L2_AV1_REF_LAST_FRAME - V4L2_AV1_REF_LAST_FRAME)
+#define LAST2_BUF_IDX (V4L2_AV1_REF_LAST2_FRAME - V4L2_AV1_REF_LAST_FRAME)
+#define LAST3_BUF_IDX (V4L2_AV1_REF_LAST3_FRAME - V4L2_AV1_REF_LAST_FRAME)
+#define GOLDEN_BUF_IDX (V4L2_AV1_REF_GOLDEN_FRAME - V4L2_AV1_REF_LAST_FRAME)
+#define BWD_BUF_IDX (V4L2_AV1_REF_BWDREF_FRAME - V4L2_AV1_REF_LAST_FRAME)
+#define ALT2_BUF_IDX (V4L2_AV1_REF_ALTREF2_FRAME - V4L2_AV1_REF_LAST_FRAME)
+#define ALT_BUF_IDX (V4L2_AV1_REF_ALTREF_FRAME - V4L2_AV1_REF_LAST_FRAME)
+
static void *plane_vaddr(struct tpg_data *tpg, struct vb2_buffer *buf,
u32 p, u32 bpl[TPG_MAX_PLANES], u32 h)
{
@@ -152,6 +161,55 @@ static void visl_get_ref_frames(struct visl_ctx *ctx, u8 *buf,
break;
}
+
+ case VISL_CODEC_AV1: {
+ int idx_last = run->av1.frame->ref_frame_idx[LAST_BUF_IDX];
+ int idx_last2 = run->av1.frame->ref_frame_idx[LAST2_BUF_IDX];
+ int idx_last3 = run->av1.frame->ref_frame_idx[LAST3_BUF_IDX];
+ int idx_golden = run->av1.frame->ref_frame_idx[GOLDEN_BUF_IDX];
+ int idx_bwd = run->av1.frame->ref_frame_idx[BWD_BUF_IDX];
+ int idx_alt2 = run->av1.frame->ref_frame_idx[ALT2_BUF_IDX];
+ int idx_alt = run->av1.frame->ref_frame_idx[ALT_BUF_IDX];
+
+ struct vb2_buffer *ref_last =
+ vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_last]);
+ struct vb2_buffer *ref_last2 =
+ vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_last2]);
+ struct vb2_buffer *ref_last3 =
+ vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_last3]);
+ struct vb2_buffer *ref_golden =
+ vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_golden]);
+ struct vb2_buffer *ref_bwd =
+ vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_bwd]);
+ struct vb2_buffer *ref_alt2 =
+ vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_alt2]);
+ struct vb2_buffer *ref_alt =
+ vb2_find_buffer(cap_q, run->av1.frame->reference_frame_ts[idx_alt]);
+
+ scnprintf(buf, buflen,
+ "ref_last_ts: %llu, vb2_idx: %d\n"
+ "ref_last2_ts: %llu, vb2_idx: %d\n"
+ "ref_last3_ts: %llu, vb2_idx: %d\n"
+ "ref_golden_ts: %llu, vb2_idx: %d\n"
+ "ref_bwd_ts: %llu, vb2_idx: %d\n"
+ "ref_alt2_ts: %llu, vb2_idx: %d\n"
+ "ref_alt_ts: %llu, vb2_idx: %d\n",
+ run->av1.frame->reference_frame_ts[idx_last],
+ ref_last ? ref_last->index : -1,
+ run->av1.frame->reference_frame_ts[idx_last2],
+ ref_last2 ? ref_last2->index : -1,
+ run->av1.frame->reference_frame_ts[idx_last3],
+ ref_last3 ? ref_last3->index : -1,
+ run->av1.frame->reference_frame_ts[idx_golden],
+ ref_golden ? ref_golden->index : -1,
+ run->av1.frame->reference_frame_ts[idx_bwd],
+ ref_bwd ? ref_bwd->index : -1,
+ run->av1.frame->reference_frame_ts[idx_alt2],
+ ref_alt2 ? ref_alt2->index : -1,
+ run->av1.frame->reference_frame_ts[idx_alt],
+ ref_alt ? ref_alt->index : -1);
+ break;
+ }
}
}
@@ -287,16 +345,23 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
len = 0;
- for (i = 0; i < out_q->num_buffers; i++) {
+ for (i = 0; i < vb2_get_num_buffers(out_q); i++) {
char entry[] = "index: %u, state: %s, request_fd: %d, ";
u32 old_len = len;
- char *q_status = visl_get_vb2_state(out_q->bufs[i]->state);
+ struct vb2_buffer *vb2;
+ char *q_status;
+
+ vb2 = vb2_get_buffer(out_q, i);
+ if (!vb2)
+ continue;
+
+ q_status = visl_get_vb2_state(vb2->state);
len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
entry, i, q_status,
- to_vb2_v4l2_buffer(out_q->bufs[i])->request_fd);
+ to_vb2_v4l2_buffer(vb2)->request_fd);
- len += visl_fill_bytesused(to_vb2_v4l2_buffer(out_q->bufs[i]),
+ len += visl_fill_bytesused(to_vb2_v4l2_buffer(vb2),
&buf[len],
TPG_STR_BUF_SZ - len);
@@ -340,15 +405,22 @@ static void visl_tpg_fill(struct visl_ctx *ctx, struct visl_run *run)
frame_dprintk(ctx->dev, run->dst->sequence, "%s\n", buf);
len = 0;
- for (i = 0; i < cap_q->num_buffers; i++) {
+ for (i = 0; i < vb2_get_num_buffers(cap_q); i++) {
u32 old_len = len;
- char *q_status = visl_get_vb2_state(cap_q->bufs[i]->state);
+ struct vb2_buffer *vb2;
+ char *q_status;
+
+ vb2 = vb2_get_buffer(cap_q, i);
+ if (!vb2)
+ continue;
+
+ q_status = visl_get_vb2_state(vb2->state);
len += scnprintf(&buf[len], TPG_STR_BUF_SZ - len,
"index: %u, status: %s, timestamp: %llu, is_held: %d",
- cap_q->bufs[i]->index, q_status,
- cap_q->bufs[i]->timestamp,
- to_vb2_v4l2_buffer(cap_q->bufs[i])->is_held);
+ vb2->index, q_status,
+ vb2->timestamp,
+ to_vb2_v4l2_buffer(vb2)->is_held);
tpg_gen_text(&ctx->tpg, basep, line++ * line_height, 16, &buf[old_len]);
frame_dprintk(ctx->dev, run->dst->sequence, "%s", &buf[old_len]);
@@ -410,7 +482,13 @@ static void visl_trace_ctrls(struct visl_ctx *ctx, struct visl_run *run)
trace_v4l2_hevc_dpb_entry(&run->hevc.dpram->dpb[i]);
trace_v4l2_hevc_pred_weight_table(&run->hevc.spram->pred_weight_table);
- break;
+ break;
+ case VISL_CODEC_AV1:
+ trace_v4l2_ctrl_av1_sequence(run->av1.seq);
+ trace_v4l2_ctrl_av1_frame(run->av1.frame);
+ trace_v4l2_ctrl_av1_film_grain(run->av1.grain);
+ trace_v4l2_ctrl_av1_tile_group_entry(run->av1.tge);
+ break;
}
}
@@ -469,6 +547,12 @@ void visl_device_run(void *priv)
run.hevc.sm = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
run.hevc.dpram = visl_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
break;
+ case VISL_CODEC_AV1:
+ run.av1.seq = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_SEQUENCE);
+ run.av1.frame = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_FRAME);
+ run.av1.tge = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
+ run.av1.grain = visl_find_control_data(ctx, V4L2_CID_STATELESS_AV1_FILM_GRAIN);
+ break;
}
frame_dprintk(ctx->dev, run.dst->sequence,
diff --git a/drivers/media/test-drivers/visl/visl-dec.h b/drivers/media/test-drivers/visl/visl-dec.h
index 4a706a9de02e..c2c2ef3a8798 100644
--- a/drivers/media/test-drivers/visl/visl-dec.h
+++ b/drivers/media/test-drivers/visl/visl-dec.h
@@ -45,6 +45,13 @@ struct visl_hevc_run {
const struct v4l2_ctrl_hevc_decode_params *dpram;
};
+struct visl_av1_run {
+ const struct v4l2_ctrl_av1_sequence *seq;
+ const struct v4l2_ctrl_av1_frame *frame;
+ const struct v4l2_ctrl_av1_tile_group_entry *tge;
+ const struct v4l2_ctrl_av1_film_grain *grain;
+};
+
struct visl_run {
struct vb2_v4l2_buffer *src;
struct vb2_v4l2_buffer *dst;
@@ -56,6 +63,7 @@ struct visl_run {
struct visl_vp9_run vp9;
struct visl_h264_run h264;
struct visl_hevc_run hevc;
+ struct visl_av1_run av1;
};
};
diff --git a/drivers/media/test-drivers/visl/visl-trace-av1.h b/drivers/media/test-drivers/visl/visl-trace-av1.h
new file mode 100644
index 000000000000..09f205de53df
--- /dev/null
+++ b/drivers/media/test-drivers/visl/visl-trace-av1.h
@@ -0,0 +1,314 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(_VISL_TRACE_AV1_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _VISL_TRACE_AV1_H_
+
+#include <linux/tracepoint.h>
+#include "visl.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM visl_av1_controls
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_av1_seq_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_av1_sequence *s),
+ TP_ARGS(s),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_sequence, s)),
+ TP_fast_assign(__entry->s = *s;),
+ TP_printk("\nflags %s\nseq_profile: %u\norder_hint_bits: %u\nbit_depth: %u\n"
+ "max_frame_width_minus_1: %u\nmax_frame_height_minus_1: %u\n",
+ __print_flags(__entry->s.flags, "|",
+ {V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE, "STILL_PICTURE"},
+ {V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK, "USE_128X128_SUPERBLOCK"},
+ {V4L2_AV1_SEQUENCE_FLAG_ENABLE_FILTER_INTRA, "ENABLE_FILTER_INTRA"},
+ {V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTRA_EDGE_FILTER, "ENABLE_INTRA_EDGE_FILTER"},
+ {V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTERINTRA_COMPOUND, "ENABLE_INTERINTRA_COMPOUND"},
+ {V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND, "ENABLE_MASKED_COMPOUND"},
+ {V4L2_AV1_SEQUENCE_FLAG_ENABLE_WARPED_MOTION, "ENABLE_WARPED_MOTION"},
+ {V4L2_AV1_SEQUENCE_FLAG_ENABLE_DUAL_FILTER, "ENABLE_DUAL_FILTER"},
+ {V4L2_AV1_SEQUENCE_FLAG_ENABLE_ORDER_HINT, "ENABLE_ORDER_HINT"},
+ {V4L2_AV1_SEQUENCE_FLAG_ENABLE_JNT_COMP, "ENABLE_JNT_COMP"},
+ {V4L2_AV1_SEQUENCE_FLAG_ENABLE_REF_FRAME_MVS, "ENABLE_REF_FRAME_MVS"},
+ {V4L2_AV1_SEQUENCE_FLAG_ENABLE_SUPERRES, "ENABLE_SUPERRES"},
+ {V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF, "ENABLE_CDEF"},
+ {V4L2_AV1_SEQUENCE_FLAG_ENABLE_RESTORATION, "ENABLE_RESTORATION"},
+ {V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME, "MONO_CHROME"},
+ {V4L2_AV1_SEQUENCE_FLAG_COLOR_RANGE, "COLOR_RANGE"},
+ {V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X, "SUBSAMPLING_X"},
+ {V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y, "SUBSAMPLING_Y"},
+ {V4L2_AV1_SEQUENCE_FLAG_FILM_GRAIN_PARAMS_PRESENT, "FILM_GRAIN_PARAMS_PRESENT"},
+ {V4L2_AV1_SEQUENCE_FLAG_SEPARATE_UV_DELTA_Q, "SEPARATE_UV_DELTA_Q"}),
+ __entry->s.seq_profile,
+ __entry->s.order_hint_bits,
+ __entry->s.bit_depth,
+ __entry->s.max_frame_width_minus_1,
+ __entry->s.max_frame_height_minus_1
+ )
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_av1_tge_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_av1_tile_group_entry *t),
+ TP_ARGS(t),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_tile_group_entry, t)),
+ TP_fast_assign(__entry->t = *t;),
+ TP_printk("\ntile_offset: %u\n tile_size: %u\n tile_row: %u\ntile_col: %u\n",
+ __entry->t.tile_offset,
+ __entry->t.tile_size,
+ __entry->t.tile_row,
+ __entry->t.tile_col
+ )
+);
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_av1_frame_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_av1_frame *f),
+ TP_ARGS(f),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_frame, f)),
+ TP_fast_assign(__entry->f = *f;),
+ TP_printk("\ntile_info.flags: %s\ntile_info.context_update_tile_id: %u\n"
+ "tile_info.tile_cols: %u\ntile_info.tile_rows: %u\n"
+ "tile_info.mi_col_starts: %s\ntile_info.mi_row_starts: %s\n"
+ "tile_info.width_in_sbs_minus_1: %s\ntile_info.height_in_sbs_minus_1: %s\n"
+ "tile_info.tile_size_bytes: %u\nquantization.flags: %s\n"
+ "quantization.base_q_idx: %u\nquantization.delta_q_y_dc: %d\n"
+ "quantization.delta_q_u_dc: %d\nquantization.delta_q_u_ac: %d\n"
+ "quantization.delta_q_v_dc: %d\nquantization.delta_q_v_ac: %d\n"
+ "quantization.qm_y: %u\nquantization.qm_u: %u\nquantization.qm_v: %u\n"
+ "quantization.delta_q_res: %u\nsuperres_denom: %u\nsegmentation.flags: %s\n"
+ "segmentation.last_active_seg_id: %u\nsegmentation.feature_enabled:%s\n"
+ "loop_filter.flags: %s\nloop_filter.level: %s\nloop_filter.sharpness: %u\n"
+ "loop_filter.ref_deltas: %s\nloop_filter.mode_deltas: %s\n"
+ "loop_filter.delta_lf_res: %u\ncdef.damping_minus_3: %u\ncdef.bits: %u\n"
+ "cdef.y_pri_strength: %s\ncdef.y_sec_strength: %s\n"
+ "cdef.uv_pri_strength: %s\ncdef.uv_sec_strength:%s\nskip_mode_frame: %s\n"
+ "primary_ref_frame: %u\nloop_restoration.flags: %s\n"
+ "loop_restoration.lr_unit_shift: %u\nloop_restoration.lr_uv_shift: %u\n"
+ "loop_restoration.frame_restoration_type: %s\n"
+ "loop_restoration.loop_restoration_size: %s\nflags: %s\norder_hint: %u\n"
+ "upscaled_width: %u\nframe_width_minus_1: %u\nframe_height_minus_1: %u\n"
+ "render_width_minus_1: %u\nrender_height_minus_1: %u\ncurrent_frame_id: %u\n"
+ "buffer_removal_time: %s\norder_hints: %s\nreference_frame_ts: %s\n"
+ "ref_frame_idx: %s\nrefresh_frame_flags: %u\n",
+ __print_flags(__entry->f.tile_info.flags, "|",
+ {V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING, "UNIFORM_TILE_SPACING"}),
+ __entry->f.tile_info.context_update_tile_id,
+ __entry->f.tile_info.tile_cols,
+ __entry->f.tile_info.tile_rows,
+ __print_array(__entry->f.tile_info.mi_col_starts,
+ ARRAY_SIZE(__entry->f.tile_info.mi_col_starts),
+ sizeof(__entry->f.tile_info.mi_col_starts[0])),
+ __print_array(__entry->f.tile_info.mi_row_starts,
+ ARRAY_SIZE(__entry->f.tile_info.mi_row_starts),
+ sizeof(__entry->f.tile_info.mi_row_starts[0])),
+ __print_array(__entry->f.tile_info.width_in_sbs_minus_1,
+ ARRAY_SIZE(__entry->f.tile_info.width_in_sbs_minus_1),
+ sizeof(__entry->f.tile_info.width_in_sbs_minus_1[0])),
+ __print_array(__entry->f.tile_info.height_in_sbs_minus_1,
+ ARRAY_SIZE(__entry->f.tile_info.height_in_sbs_minus_1),
+ sizeof(__entry->f.tile_info.height_in_sbs_minus_1[0])),
+ __entry->f.tile_info.tile_size_bytes,
+ __print_flags(__entry->f.quantization.flags, "|",
+ {V4L2_AV1_QUANTIZATION_FLAG_DIFF_UV_DELTA, "DIFF_UV_DELTA"},
+ {V4L2_AV1_QUANTIZATION_FLAG_USING_QMATRIX, "USING_QMATRIX"},
+ {V4L2_AV1_QUANTIZATION_FLAG_DELTA_Q_PRESENT, "DELTA_Q_PRESENT"}),
+ __entry->f.quantization.base_q_idx,
+ __entry->f.quantization.delta_q_y_dc,
+ __entry->f.quantization.delta_q_u_dc,
+ __entry->f.quantization.delta_q_u_ac,
+ __entry->f.quantization.delta_q_v_dc,
+ __entry->f.quantization.delta_q_v_ac,
+ __entry->f.quantization.qm_y,
+ __entry->f.quantization.qm_u,
+ __entry->f.quantization.qm_v,
+ __entry->f.quantization.delta_q_res,
+ __entry->f.superres_denom,
+ __print_flags(__entry->f.segmentation.flags, "|",
+ {V4L2_AV1_SEGMENTATION_FLAG_ENABLED, "ENABLED"},
+ {V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP, "UPDATE_MAP"},
+ {V4L2_AV1_SEGMENTATION_FLAG_TEMPORAL_UPDATE, "TEMPORAL_UPDATE"},
+ {V4L2_AV1_SEGMENTATION_FLAG_UPDATE_DATA, "UPDATE_DATA"},
+ {V4L2_AV1_SEGMENTATION_FLAG_SEG_ID_PRE_SKIP, "SEG_ID_PRE_SKIP"}),
+ __entry->f.segmentation.last_active_seg_id,
+ __print_array(__entry->f.segmentation.feature_enabled,
+ ARRAY_SIZE(__entry->f.segmentation.feature_enabled),
+ sizeof(__entry->f.segmentation.feature_enabled[0])),
+ __print_flags(__entry->f.loop_filter.flags, "|",
+ {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_ENABLED, "DELTA_ENABLED"},
+ {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_UPDATE, "DELTA_UPDATE"},
+ {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_PRESENT, "DELTA_LF_PRESENT"},
+ {V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_MULTI, "DELTA_LF_MULTI"}),
+ __print_array(__entry->f.loop_filter.level,
+ ARRAY_SIZE(__entry->f.loop_filter.level),
+ sizeof(__entry->f.loop_filter.level[0])),
+ __entry->f.loop_filter.sharpness,
+ __print_array(__entry->f.loop_filter.ref_deltas,
+ ARRAY_SIZE(__entry->f.loop_filter.ref_deltas),
+ sizeof(__entry->f.loop_filter.ref_deltas[0])),
+ __print_array(__entry->f.loop_filter.mode_deltas,
+ ARRAY_SIZE(__entry->f.loop_filter.mode_deltas),
+ sizeof(__entry->f.loop_filter.mode_deltas[0])),
+ __entry->f.loop_filter.delta_lf_res,
+ __entry->f.cdef.damping_minus_3,
+ __entry->f.cdef.bits,
+ __print_array(__entry->f.cdef.y_pri_strength,
+ ARRAY_SIZE(__entry->f.cdef.y_pri_strength),
+ sizeof(__entry->f.cdef.y_pri_strength[0])),
+ __print_array(__entry->f.cdef.y_sec_strength,
+ ARRAY_SIZE(__entry->f.cdef.y_sec_strength),
+ sizeof(__entry->f.cdef.y_sec_strength[0])),
+ __print_array(__entry->f.cdef.uv_pri_strength,
+ ARRAY_SIZE(__entry->f.cdef.uv_pri_strength),
+ sizeof(__entry->f.cdef.uv_pri_strength[0])),
+ __print_array(__entry->f.cdef.uv_sec_strength,
+ ARRAY_SIZE(__entry->f.cdef.uv_sec_strength),
+ sizeof(__entry->f.cdef.uv_sec_strength[0])),
+ __print_array(__entry->f.skip_mode_frame,
+ ARRAY_SIZE(__entry->f.skip_mode_frame),
+ sizeof(__entry->f.skip_mode_frame[0])),
+ __entry->f.primary_ref_frame,
+ __print_flags(__entry->f.loop_restoration.flags, "|",
+ {V4L2_AV1_LOOP_RESTORATION_FLAG_USES_LR, "USES_LR"},
+ {V4L2_AV1_LOOP_RESTORATION_FLAG_USES_CHROMA_LR, "USES_CHROMA_LR"}),
+ __entry->f.loop_restoration.lr_unit_shift,
+ __entry->f.loop_restoration.lr_uv_shift,
+ __print_array(__entry->f.loop_restoration.frame_restoration_type,
+ ARRAY_SIZE(__entry->f.loop_restoration.frame_restoration_type),
+ sizeof(__entry->f.loop_restoration.frame_restoration_type[0])),
+ __print_array(__entry->f.loop_restoration.loop_restoration_size,
+ ARRAY_SIZE(__entry->f.loop_restoration.loop_restoration_size),
+ sizeof(__entry->f.loop_restoration.loop_restoration_size[0])),
+ __print_flags(__entry->f.flags, "|",
+ {V4L2_AV1_FRAME_FLAG_SHOW_FRAME, "SHOW_FRAME"},
+ {V4L2_AV1_FRAME_FLAG_SHOWABLE_FRAME, "SHOWABLE_FRAME"},
+ {V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE, "ERROR_RESILIENT_MODE"},
+ {V4L2_AV1_FRAME_FLAG_DISABLE_CDF_UPDATE, "DISABLE_CDF_UPDATE"},
+ {V4L2_AV1_FRAME_FLAG_ALLOW_SCREEN_CONTENT_TOOLS, "ALLOW_SCREEN_CONTENT_TOOLS"},
+ {V4L2_AV1_FRAME_FLAG_FORCE_INTEGER_MV, "FORCE_INTEGER_MV"},
+ {V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC, "ALLOW_INTRABC"},
+ {V4L2_AV1_FRAME_FLAG_USE_SUPERRES, "USE_SUPERRES"},
+ {V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV, "ALLOW_HIGH_PRECISION_MV"},
+ {V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE, "IS_MOTION_MODE_SWITCHABLE"},
+ {V4L2_AV1_FRAME_FLAG_USE_REF_FRAME_MVS, "USE_REF_FRAME_MVS"},
+ {V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF,
+ "DISABLE_FRAME_END_UPDATE_CDF"},
+ {V4L2_AV1_FRAME_FLAG_ALLOW_WARPED_MOTION, "ALLOW_WARPED_MOTION"},
+ {V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT, "REFERENCE_SELECT"},
+ {V4L2_AV1_FRAME_FLAG_REDUCED_TX_SET, "REDUCED_TX_SET"},
+ {V4L2_AV1_FRAME_FLAG_SKIP_MODE_ALLOWED, "SKIP_MODE_ALLOWED"},
+ {V4L2_AV1_FRAME_FLAG_SKIP_MODE_PRESENT, "SKIP_MODE_PRESENT"},
+ {V4L2_AV1_FRAME_FLAG_FRAME_SIZE_OVERRIDE, "FRAME_SIZE_OVERRIDE"},
+ {V4L2_AV1_FRAME_FLAG_BUFFER_REMOVAL_TIME_PRESENT, "BUFFER_REMOVAL_TIME_PRESENT"},
+ {V4L2_AV1_FRAME_FLAG_FRAME_REFS_SHORT_SIGNALING, "FRAME_REFS_SHORT_SIGNALING"}),
+ __entry->f.order_hint,
+ __entry->f.upscaled_width,
+ __entry->f.frame_width_minus_1,
+ __entry->f.frame_height_minus_1,
+ __entry->f.render_width_minus_1,
+ __entry->f.render_height_minus_1,
+ __entry->f.current_frame_id,
+ __print_array(__entry->f.buffer_removal_time,
+ ARRAY_SIZE(__entry->f.buffer_removal_time),
+ sizeof(__entry->f.buffer_removal_time[0])),
+ __print_array(__entry->f.order_hints,
+ ARRAY_SIZE(__entry->f.order_hints),
+ sizeof(__entry->f.order_hints[0])),
+ __print_array(__entry->f.reference_frame_ts,
+ ARRAY_SIZE(__entry->f.reference_frame_ts),
+ sizeof(__entry->f.reference_frame_ts[0])),
+ __print_array(__entry->f.ref_frame_idx,
+ ARRAY_SIZE(__entry->f.ref_frame_idx),
+ sizeof(__entry->f.ref_frame_idx[0])),
+ __entry->f.refresh_frame_flags
+ )
+);
+
+
+DECLARE_EVENT_CLASS(v4l2_ctrl_av1_film_grain_tmpl,
+ TP_PROTO(const struct v4l2_ctrl_av1_film_grain *f),
+ TP_ARGS(f),
+ TP_STRUCT__entry(__field_struct(struct v4l2_ctrl_av1_film_grain, f)),
+ TP_fast_assign(__entry->f = *f;),
+ TP_printk("\nflags %s\ncr_mult: %u\ngrain_seed: %u\n"
+ "film_grain_params_ref_idx: %u\nnum_y_points: %u\npoint_y_value: %s\n"
+ "point_y_scaling: %s\nnum_cb_points: %u\npoint_cb_value: %s\n"
+ "point_cb_scaling: %s\nnum_cr_points: %u\npoint_cr_value: %s\n"
+ "point_cr_scaling: %s\ngrain_scaling_minus_8: %u\nar_coeff_lag: %u\n"
+ "ar_coeffs_y_plus_128: %s\nar_coeffs_cb_plus_128: %s\n"
+ "ar_coeffs_cr_plus_128: %s\nar_coeff_shift_minus_6: %u\n"
+ "grain_scale_shift: %u\ncb_mult: %u\ncb_luma_mult: %u\ncr_luma_mult: %u\n"
+ "cb_offset: %u\ncr_offset: %u\n",
+ __print_flags(__entry->f.flags, "|",
+ {V4L2_AV1_FILM_GRAIN_FLAG_APPLY_GRAIN, "APPLY_GRAIN"},
+ {V4L2_AV1_FILM_GRAIN_FLAG_UPDATE_GRAIN, "UPDATE_GRAIN"},
+ {V4L2_AV1_FILM_GRAIN_FLAG_CHROMA_SCALING_FROM_LUMA, "CHROMA_SCALING_FROM_LUMA"},
+ {V4L2_AV1_FILM_GRAIN_FLAG_OVERLAP, "OVERLAP"},
+ {V4L2_AV1_FILM_GRAIN_FLAG_CLIP_TO_RESTRICTED_RANGE, "CLIP_TO_RESTRICTED_RANGE"}),
+ __entry->f.cr_mult,
+ __entry->f.grain_seed,
+ __entry->f.film_grain_params_ref_idx,
+ __entry->f.num_y_points,
+ __print_array(__entry->f.point_y_value,
+ ARRAY_SIZE(__entry->f.point_y_value),
+ sizeof(__entry->f.point_y_value[0])),
+ __print_array(__entry->f.point_y_scaling,
+ ARRAY_SIZE(__entry->f.point_y_scaling),
+ sizeof(__entry->f.point_y_scaling[0])),
+ __entry->f.num_cb_points,
+ __print_array(__entry->f.point_cb_value,
+ ARRAY_SIZE(__entry->f.point_cb_value),
+ sizeof(__entry->f.point_cb_value[0])),
+ __print_array(__entry->f.point_cb_scaling,
+ ARRAY_SIZE(__entry->f.point_cb_scaling),
+ sizeof(__entry->f.point_cb_scaling[0])),
+ __entry->f.num_cr_points,
+ __print_array(__entry->f.point_cr_value,
+ ARRAY_SIZE(__entry->f.point_cr_value),
+ sizeof(__entry->f.point_cr_value[0])),
+ __print_array(__entry->f.point_cr_scaling,
+ ARRAY_SIZE(__entry->f.point_cr_scaling),
+ sizeof(__entry->f.point_cr_scaling[0])),
+ __entry->f.grain_scaling_minus_8,
+ __entry->f.ar_coeff_lag,
+ __print_array(__entry->f.ar_coeffs_y_plus_128,
+ ARRAY_SIZE(__entry->f.ar_coeffs_y_plus_128),
+ sizeof(__entry->f.ar_coeffs_y_plus_128[0])),
+ __print_array(__entry->f.ar_coeffs_cb_plus_128,
+ ARRAY_SIZE(__entry->f.ar_coeffs_cb_plus_128),
+ sizeof(__entry->f.ar_coeffs_cb_plus_128[0])),
+ __print_array(__entry->f.ar_coeffs_cr_plus_128,
+ ARRAY_SIZE(__entry->f.ar_coeffs_cr_plus_128),
+ sizeof(__entry->f.ar_coeffs_cr_plus_128[0])),
+ __entry->f.ar_coeff_shift_minus_6,
+ __entry->f.grain_scale_shift,
+ __entry->f.cb_mult,
+ __entry->f.cb_luma_mult,
+ __entry->f.cr_luma_mult,
+ __entry->f.cb_offset,
+ __entry->f.cr_offset
+ )
+)
+
+DEFINE_EVENT(v4l2_ctrl_av1_seq_tmpl, v4l2_ctrl_av1_sequence,
+ TP_PROTO(const struct v4l2_ctrl_av1_sequence *s),
+ TP_ARGS(s)
+);
+
+DEFINE_EVENT(v4l2_ctrl_av1_frame_tmpl, v4l2_ctrl_av1_frame,
+ TP_PROTO(const struct v4l2_ctrl_av1_frame *f),
+ TP_ARGS(f)
+);
+
+DEFINE_EVENT(v4l2_ctrl_av1_tge_tmpl, v4l2_ctrl_av1_tile_group_entry,
+ TP_PROTO(const struct v4l2_ctrl_av1_tile_group_entry *t),
+ TP_ARGS(t)
+);
+
+DEFINE_EVENT(v4l2_ctrl_av1_film_grain_tmpl, v4l2_ctrl_av1_film_grain,
+ TP_PROTO(const struct v4l2_ctrl_av1_film_grain *f),
+ TP_ARGS(f)
+);
+
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH ../../drivers/media/test-drivers/visl
+#define TRACE_INCLUDE_FILE visl-trace-av1
+#include <trace/define_trace.h>
diff --git a/drivers/media/test-drivers/visl/visl-trace-points.c b/drivers/media/test-drivers/visl/visl-trace-points.c
index f7b866534f1e..321ff732c682 100644
--- a/drivers/media/test-drivers/visl/visl-trace-points.c
+++ b/drivers/media/test-drivers/visl/visl-trace-points.c
@@ -8,3 +8,4 @@
#include "visl-trace-vp9.h"
#include "visl-trace-h264.h"
#include "visl-trace-hevc.h"
+#include "visl-trace-av1.h"
diff --git a/drivers/media/test-drivers/visl/visl-video.c b/drivers/media/test-drivers/visl/visl-video.c
index 7cac6a6456eb..b9a4b44bd0ed 100644
--- a/drivers/media/test-drivers/visl/visl-video.c
+++ b/drivers/media/test-drivers/visl/visl-video.c
@@ -40,6 +40,9 @@ static void visl_set_current_codec(struct visl_ctx *ctx)
case V4L2_PIX_FMT_HEVC_SLICE:
ctx->current_codec = VISL_CODEC_HEVC;
break;
+ case V4L2_PIX_FMT_AV1_FRAME:
+ ctx->current_codec = VISL_CODEC_AV1;
+ break;
default:
dprintk(ctx->dev, "Warning: unsupported fourcc: %d\n", fourcc);
ctx->current_codec = VISL_CODEC_NONE;
@@ -218,6 +221,21 @@ const struct visl_coded_format_desc visl_coded_fmts[] = {
.num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
.decoded_fmts = visl_decoded_fmts,
},
+ {
+ .pixelformat = V4L2_PIX_FMT_AV1_FRAME,
+ .frmsize = {
+ .min_width = 64,
+ .max_width = 4096,
+ .step_width = 1,
+ .min_height = 64,
+ .max_height = 2304,
+ .step_height = 1,
+ },
+ .ctrls = &visl_av1_ctrls,
+ .num_decoded_fmts = ARRAY_SIZE(visl_decoded_fmts),
+ .decoded_fmts = visl_decoded_fmts,
+ },
+
};
const size_t num_coded_fmts = ARRAY_SIZE(visl_coded_fmts);
@@ -525,6 +543,9 @@ const struct v4l2_ioctl_ops visl_ioctl_ops = {
.vidioc_streamon = v4l2_m2m_ioctl_streamon,
.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+ .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd,
+ .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd,
+
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
diff --git a/drivers/media/test-drivers/visl/visl-video.h b/drivers/media/test-drivers/visl/visl-video.h
index 27ad70a558db..92e274894c20 100644
--- a/drivers/media/test-drivers/visl/visl-video.h
+++ b/drivers/media/test-drivers/visl/visl-video.h
@@ -17,6 +17,7 @@ extern const struct visl_ctrls visl_vp8_ctrls;
extern const struct visl_ctrls visl_vp9_ctrls;
extern const struct visl_ctrls visl_h264_ctrls;
extern const struct visl_ctrls visl_hevc_ctrls;
+extern const struct visl_ctrls visl_av1_ctrls;
int visl_queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq);
diff --git a/drivers/media/test-drivers/visl/visl.h b/drivers/media/test-drivers/visl/visl.h
index 31639f2e593d..c593b1337f11 100644
--- a/drivers/media/test-drivers/visl/visl.h
+++ b/drivers/media/test-drivers/visl/visl.h
@@ -127,6 +127,7 @@ enum visl_codec {
VISL_CODEC_VP9,
VISL_CODEC_H264,
VISL_CODEC_HEVC,
+ VISL_CODEC_AV1,
};
struct visl_blob {
diff --git a/drivers/media/test-drivers/vivid/Kconfig b/drivers/media/test-drivers/vivid/Kconfig
index 5b08a5ad291e..ec2e71d76965 100644
--- a/drivers/media/test-drivers/vivid/Kconfig
+++ b/drivers/media/test-drivers/vivid/Kconfig
@@ -10,7 +10,6 @@ config VIDEO_VIVID
select VIDEOBUF2_DMA_CONTIG
select VIDEO_V4L2_TPG
select MEDIA_CONTROLLER
- select MEDIA_CONTROLLER_REQUEST_API
help
Enables a virtual video driver. This driver emulates a webcam,
TV, S-Video and HDMI capture hardware, including VBI support for
diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c
index 394c9f81ea72..159c72cbb5bf 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.c
+++ b/drivers/media/test-drivers/vivid/vivid-core.c
@@ -861,7 +861,7 @@ static const struct media_device_ops vivid_media_ops = {
static int vivid_create_queue(struct vivid_dev *dev,
struct vb2_queue *q,
u32 buf_type,
- unsigned int min_buffers_needed,
+ unsigned int min_queued_buffers,
const struct vb2_ops *ops)
{
if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->multiplanar)
@@ -876,6 +876,20 @@ static int vivid_create_queue(struct vivid_dev *dev,
q->type = buf_type;
q->io_modes = VB2_MMAP | VB2_DMABUF;
q->io_modes |= V4L2_TYPE_IS_OUTPUT(buf_type) ? VB2_WRITE : VB2_READ;
+
+ /*
+ * The maximum number of buffers is 32768 if PAGE_SHIFT == 12,
+ * see also MAX_BUFFER_INDEX in videobuf2-core.c. It will be less if
+ * PAGE_SHIFT > 12, but then max_num_buffers will be clamped by
+ * videobuf2-core.c to MAX_BUFFER_INDEX.
+ */
+ if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ q->max_num_buffers = 64;
+ if (buf_type == V4L2_BUF_TYPE_SDR_CAPTURE)
+ q->max_num_buffers = 1024;
+ if (buf_type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ q->max_num_buffers = 32768;
+
if (allocators[dev->inst] != 1)
q->io_modes |= VB2_USERPTR;
q->drv_priv = dev;
@@ -884,7 +898,7 @@ static int vivid_create_queue(struct vivid_dev *dev,
q->mem_ops = allocators[dev->inst] == 1 ? &vb2_dma_contig_memops :
&vb2_vmalloc_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = supports_requests[dev->inst] ? 0 : min_buffers_needed;
+ q->min_queued_buffers = supports_requests[dev->inst] ? 0 : min_queued_buffers;
q->lock = &dev->mutex;
q->dev = dev->v4l2_dev.dev;
q->supports_requests = supports_requests[dev->inst];
diff --git a/drivers/media/test-drivers/vivid/vivid-meta-cap.c b/drivers/media/test-drivers/vivid/vivid-meta-cap.c
index 780f96860a6d..0a718d037e59 100644
--- a/drivers/media/test-drivers/vivid/vivid-meta-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-meta-cap.c
@@ -30,9 +30,6 @@ static int meta_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
sizes[0] = size;
}
- if (vq->num_buffers + *nbuffers < 2)
- *nbuffers = 2 - vq->num_buffers;
-
*nplanes = 1;
return 0;
}
diff --git a/drivers/media/test-drivers/vivid/vivid-meta-out.c b/drivers/media/test-drivers/vivid/vivid-meta-out.c
index 95835b52b58f..4a569a6e58be 100644
--- a/drivers/media/test-drivers/vivid/vivid-meta-out.c
+++ b/drivers/media/test-drivers/vivid/vivid-meta-out.c
@@ -18,6 +18,7 @@ static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
struct device *alloc_devs[])
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
unsigned int size = sizeof(struct vivid_meta_out_buf);
if (!vivid_is_webcam(dev))
@@ -30,8 +31,8 @@ static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
sizes[0] = size;
}
- if (vq->num_buffers + *nbuffers < 2)
- *nbuffers = 2 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 2)
+ *nbuffers = 2 - q_num_bufs;
*nplanes = 1;
return 0;
diff --git a/drivers/media/test-drivers/vivid/vivid-touch-cap.c b/drivers/media/test-drivers/vivid/vivid-touch-cap.c
index c7f6e23df51e..4b3c6ea0afde 100644
--- a/drivers/media/test-drivers/vivid/vivid-touch-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-touch-cap.c
@@ -13,6 +13,7 @@ static int touch_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
struct device *alloc_devs[])
{
struct vivid_dev *dev = vb2_get_drv_priv(vq);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
struct v4l2_pix_format *f = &dev->tch_format;
unsigned int size = f->sizeimage;
@@ -23,8 +24,8 @@ static int touch_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
sizes[0] = size;
}
- if (vq->num_buffers + *nbuffers < 2)
- *nbuffers = 2 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 2)
+ *nbuffers = 2 - q_num_bufs;
*nplanes = 1;
return 0;
diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c
index b65b02eeeb97..3840b3a664ac 100644
--- a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c
@@ -134,9 +134,6 @@ static int vbi_cap_queue_setup(struct vb2_queue *vq,
sizes[0] = size;
- if (vq->num_buffers + *nbuffers < 2)
- *nbuffers = 2 - vq->num_buffers;
-
*nplanes = 1;
return 0;
}
diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-out.c b/drivers/media/test-drivers/vivid/vivid-vbi-out.c
index cd56476902a2..434a10676417 100644
--- a/drivers/media/test-drivers/vivid/vivid-vbi-out.c
+++ b/drivers/media/test-drivers/vivid/vivid-vbi-out.c
@@ -30,9 +30,6 @@ static int vbi_out_queue_setup(struct vb2_queue *vq,
sizes[0] = size;
- if (vq->num_buffers + *nbuffers < 2)
- *nbuffers = 2 - vq->num_buffers;
-
*nplanes = 1;
return 0;
}
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
index 3a06df35a2d7..2804975fe278 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
@@ -117,9 +117,6 @@ static int vid_cap_queue_setup(struct vb2_queue *vq,
dev->fmt_cap->data_offset[p];
}
- if (vq->num_buffers + *nbuffers < 2)
- *nbuffers = 2 - vq->num_buffers;
-
*nplanes = buffers;
dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers);
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c
index 184a6df2c29f..1653b2988f7e 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-out.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c
@@ -73,12 +73,9 @@ static int vid_out_queue_setup(struct vb2_queue *vq,
vfmt->data_offset[p] : size;
}
- if (vq->num_buffers + *nbuffers < 2)
- *nbuffers = 2 - vq->num_buffers;
-
*nplanes = planes;
- dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers);
+ dprintk(dev, 1, "%s: count=%u\n", __func__, *nbuffers);
for (p = 0; p < planes; p++)
dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]);
return 0;
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index 462eb8423506..e24e655fb1db 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -482,12 +482,13 @@ static int airspy_queue_setup(struct vb2_queue *vq,
unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[])
{
struct airspy *s = vb2_get_drv_priv(vq);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers);
/* Need at least 8 buffers */
- if (vq->num_buffers + *nbuffers < 8)
- *nbuffers = 8 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 8)
+ *nbuffers = 8 - q_num_bufs;
*nplanes = 1;
sizes[0] = PAGE_ALIGN(s->buffersize);
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index fe4410a5e128..3b75d062e602 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1218,12 +1218,13 @@ static int queue_setup(struct vb2_queue *vq,
{
struct cx231xx *dev = vb2_get_drv_priv(vq);
unsigned int size = mpeglinesize * mpeglines;
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
dev->ts1.ts_packet_size = mpeglinesize;
dev->ts1.ts_packet_count = mpeglines;
- if (vq->num_buffers + *nbuffers < CX231XX_MIN_BUF)
- *nbuffers = CX231XX_MIN_BUF - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < CX231XX_MIN_BUF)
+ *nbuffers = CX231XX_MIN_BUF - q_num_bufs;
if (*nplanes)
return sizes[0] < size ? -EINVAL : 0;
@@ -1781,7 +1782,7 @@ int cx231xx_417_register(struct cx231xx *dev)
q->ops = &cx231xx_video_qops;
q->mem_ops = &vb2_vmalloc_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 1;
+ q->min_queued_buffers = 1;
q->lock = &dev->lock;
err = vb2_queue_init(q);
if (err)
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index 7b7e2a26ef93..d8312201694f 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -1023,6 +1023,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
if (!dev->video_mode.isoc_ctl.urb) {
dev_err(dev->dev,
"cannot alloc memory for usb buffers\n");
+ kfree(dma_q->p_left_data);
return -ENOMEM;
}
@@ -1032,6 +1033,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
dev_err(dev->dev,
"cannot allocate memory for usbtransfer\n");
kfree(dev->video_mode.isoc_ctl.urb);
+ kfree(dma_q->p_left_data);
return -ENOMEM;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index e23b8ccd79d4..8f347bbeeb32 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -714,11 +714,12 @@ static int queue_setup(struct vb2_queue *vq,
unsigned int sizes[], struct device *alloc_devs[])
{
struct cx231xx *dev = vb2_get_drv_priv(vq);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
dev->size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
- if (vq->num_buffers + *nbuffers < CX231XX_MIN_BUF)
- *nbuffers = CX231XX_MIN_BUF - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < CX231XX_MIN_BUF)
+ *nbuffers = CX231XX_MIN_BUF - q_num_bufs;
if (*nplanes)
return sizes[0] < dev->size ? -EINVAL : 0;
@@ -1810,7 +1811,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
q->ops = &cx231xx_video_qops;
q->mem_ops = &vb2_vmalloc_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 1;
+ q->min_queued_buffers = 1;
q->lock = &dev->lock;
ret = vb2_queue_init(q);
if (ret)
@@ -1870,7 +1871,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
q->ops = &cx231xx_vbi_qops;
q->mem_ops = &vb2_vmalloc_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 1;
+ q->min_queued_buffers = 1;
q->lock = &dev->lock;
ret = vb2_queue_init(q);
if (ret)
diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c
index deba5224cb8d..b5d8c6b75ae1 100644
--- a/drivers/media/usb/dvb-usb/cxusb-analog.c
+++ b/drivers/media/usb/dvb-usb/cxusb-analog.c
@@ -1632,7 +1632,7 @@ static int cxusb_medion_register_analog_video(struct dvb_usb_device *dvbdev)
cxdev->videoqueue.buf_struct_size =
sizeof(struct cxusb_medion_vbuffer);
cxdev->videoqueue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- cxdev->videoqueue.min_buffers_needed = 6;
+ cxdev->videoqueue.min_queued_buffers = 6;
cxdev->videoqueue.lock = &cxdev->dev_lock;
ret = vb2_queue_init(&cxdev->videoqueue);
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 25e0620deff1..4aef584e21da 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1607,7 +1607,8 @@ static int vidioc_g_parm(struct file *file, void *priv,
p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
if (dev->is_webcam) {
rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0,
- video, g_frame_interval, &ival);
+ pad, get_frame_interval, NULL,
+ &ival);
if (!rc)
p->parm.capture.timeperframe = ival.interval;
} else {
@@ -1639,7 +1640,8 @@ static int vidioc_s_parm(struct file *file, void *priv,
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
rc = v4l2_device_call_until_err(&dev->v4l2->v4l2_dev, 0,
- video, s_frame_interval, &ival);
+ pad, set_frame_interval, NULL,
+ &ival);
if (!rc)
p->parm.capture.timeperframe = ival.interval;
return rc;
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index 770714c34295..e8c8bdb9c40b 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -1257,7 +1257,7 @@ static int vidioc_g_parm(struct file *filp, void *priv,
{
struct gspca_dev *gspca_dev = video_drvdata(filp);
- parm->parm.capture.readbuffers = gspca_dev->queue.min_buffers_needed;
+ parm->parm.capture.readbuffers = gspca_dev->queue.min_queued_buffers;
if (!gspca_dev->sd_desc->get_streamparm)
return 0;
@@ -1273,7 +1273,7 @@ static int vidioc_s_parm(struct file *filp, void *priv,
{
struct gspca_dev *gspca_dev = video_drvdata(filp);
- parm->parm.capture.readbuffers = gspca_dev->queue.min_buffers_needed;
+ parm->parm.capture.readbuffers = gspca_dev->queue.min_queued_buffers;
if (!gspca_dev->sd_desc->set_streamparm) {
parm->parm.capture.capability = 0;
@@ -1517,7 +1517,7 @@ int gspca_dev_probe2(struct usb_interface *intf,
q->ops = &gspca_qops;
q->mem_ops = &vb2_vmalloc_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
q->lock = &gspca_dev->usb_lock;
ret = vb2_queue_init(q);
if (ret)
diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index 3e535be2c520..9c0ecd5f056c 100644
--- a/drivers/media/usb/hackrf/hackrf.c
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -753,12 +753,13 @@ static int hackrf_queue_setup(struct vb2_queue *vq,
unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[])
{
struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
dev_dbg(dev->dev, "nbuffers=%d\n", *nbuffers);
/* Need at least 8 buffers */
- if (vq->num_buffers + *nbuffers < 8)
- *nbuffers = 8 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 8)
+ *nbuffers = 8 - q_num_bufs;
*nplanes = 1;
sizes[0] = PAGE_ALIGN(dev->buffersize);
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c
index 14170a5d72b3..1764674de98b 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c
@@ -268,7 +268,8 @@ void pvr2_context_disconnect(struct pvr2_context *mp)
{
pvr2_hdw_disconnect(mp->hdw);
mp->disconnect_flag = !0;
- pvr2_context_notify(mp);
+ if (!pvr2_context_shutok())
+ pvr2_context_notify(mp);
}
diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c
index 4e966f6bf608..366f0e4a5dc0 100644
--- a/drivers/media/usb/stk1160/stk1160-video.c
+++ b/drivers/media/usb/stk1160/stk1160-video.c
@@ -107,8 +107,7 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len)
/*
* TODO: These stk1160_dbg are very spammy!
- * We should 1) check why we are getting them
- * and 2) add ratelimit.
+ * We should check why we are getting them.
*
* UPDATE: One of the reasons (the only one?) for getting these
* is incorrect standard (mismatch between expected and configured).
@@ -151,7 +150,7 @@ void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len)
/* Let the bug hunt begin! sanity checks! */
if (lencopy < 0) {
- stk1160_dbg("copy skipped: negative lencopy\n");
+ printk_ratelimited(KERN_DEBUG "copy skipped: negative lencopy\n");
return;
}
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c
index 1e30e05953dc..62a583040cd4 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -726,9 +726,10 @@ static int usbtv_queue_setup(struct vb2_queue *vq,
{
struct usbtv *usbtv = vb2_get_drv_priv(vq);
unsigned size = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
- if (vq->num_buffers + *nbuffers < 2)
- *nbuffers = 2 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 2)
+ *nbuffers = 2 - q_num_bufs;
if (*nplanes)
return sizes[0] < size ? -EINVAL : 0;
*nplanes = 1;
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 08fcd2ffa727..bbd90123a4e7 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2592,6 +2592,15 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+ /* Chicony Electronics Co., Ltd Integrated Camera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x04f2,
+ .idProduct = 0xb67c,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = UVC_PC_PROTOCOL_15,
+ .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 },
/* Chicony EasyCamera */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2994,6 +3003,15 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) },
+ /* SunplusIT Inc HD Camera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x2b7e,
+ .idProduct = 0xb752,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = UVC_PC_PROTOCOL_15,
+ .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 },
/* Lenovo Integrated Camera */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 28dde08ec6c5..7cbf4692bd87 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -1954,7 +1954,7 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream,
/* Check if the bandwidth is high enough. */
psize = uvc_endpoint_max_bpi(stream->dev->udev, ep);
- if (psize >= bandwidth && psize <= best_psize) {
+ if (psize >= bandwidth && psize < best_psize) {
altsetting = alts->desc.bAlternateSetting;
best_psize = psize;
best_ep = ep;
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 091e8cf4114b..3ec323bd528b 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -876,11 +876,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
if (sd->asc_list.next) {
list_for_each_entry_safe(asc, asc_tmp, &sd->asc_list,
asc_subdev_entry) {
- list_move(&asc->asc_entry,
- &asc->notifier->waiting_list);
-
v4l2_async_unbind_subdev_one(asc->notifier, asc);
- list_del(&asc->asc_subdev_entry);
}
}
diff --git a/drivers/media/v4l2-core/v4l2-cci.c b/drivers/media/v4l2-core/v4l2-cci.c
index bc2dbec019b0..10005c80f43b 100644
--- a/drivers/media/v4l2-core/v4l2-cci.c
+++ b/drivers/media/v4l2-core/v4l2-cci.c
@@ -18,6 +18,7 @@
int cci_read(struct regmap *map, u32 reg, u64 *val, int *err)
{
+ bool little_endian;
unsigned int len;
u8 buf[8];
int ret;
@@ -25,8 +26,9 @@ int cci_read(struct regmap *map, u32 reg, u64 *val, int *err)
if (err && *err)
return *err;
- len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
- reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
+ little_endian = reg & CCI_REG_LE;
+ len = CCI_REG_WIDTH_BYTES(reg);
+ reg = CCI_REG_ADDR(reg);
ret = regmap_bulk_read(map, reg, buf, len);
if (ret) {
@@ -40,16 +42,28 @@ int cci_read(struct regmap *map, u32 reg, u64 *val, int *err)
*val = buf[0];
break;
case 2:
- *val = get_unaligned_be16(buf);
+ if (little_endian)
+ *val = get_unaligned_le16(buf);
+ else
+ *val = get_unaligned_be16(buf);
break;
case 3:
- *val = get_unaligned_be24(buf);
+ if (little_endian)
+ *val = get_unaligned_le24(buf);
+ else
+ *val = get_unaligned_be24(buf);
break;
case 4:
- *val = get_unaligned_be32(buf);
+ if (little_endian)
+ *val = get_unaligned_le32(buf);
+ else
+ *val = get_unaligned_be32(buf);
break;
case 8:
- *val = get_unaligned_be64(buf);
+ if (little_endian)
+ *val = get_unaligned_le64(buf);
+ else
+ *val = get_unaligned_be64(buf);
break;
default:
dev_err(regmap_get_device(map), "Error invalid reg-width %u for reg 0x%04x\n",
@@ -68,6 +82,7 @@ EXPORT_SYMBOL_GPL(cci_read);
int cci_write(struct regmap *map, u32 reg, u64 val, int *err)
{
+ bool little_endian;
unsigned int len;
u8 buf[8];
int ret;
@@ -75,24 +90,37 @@ int cci_write(struct regmap *map, u32 reg, u64 val, int *err)
if (err && *err)
return *err;
- len = FIELD_GET(CCI_REG_WIDTH_MASK, reg);
- reg = FIELD_GET(CCI_REG_ADDR_MASK, reg);
+ little_endian = reg & CCI_REG_LE;
+ len = CCI_REG_WIDTH_BYTES(reg);
+ reg = CCI_REG_ADDR(reg);
switch (len) {
case 1:
buf[0] = val;
break;
case 2:
- put_unaligned_be16(val, buf);
+ if (little_endian)
+ put_unaligned_le16(val, buf);
+ else
+ put_unaligned_be16(val, buf);
break;
case 3:
- put_unaligned_be24(val, buf);
+ if (little_endian)
+ put_unaligned_le24(val, buf);
+ else
+ put_unaligned_be24(val, buf);
break;
case 4:
- put_unaligned_be32(val, buf);
+ if (little_endian)
+ put_unaligned_le32(val, buf);
+ else
+ put_unaligned_be32(val, buf);
break;
case 8:
- put_unaligned_be64(val, buf);
+ if (little_endian)
+ put_unaligned_le64(val, buf);
+ else
+ put_unaligned_be64(val, buf);
break;
default:
dev_err(regmap_get_device(map), "Error invalid reg-width %u for reg 0x%04x\n",
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 3a4b15a98e02..273d83de2a87 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -195,9 +195,9 @@ int v4l2_g_parm_cap(struct video_device *vdev,
if (vdev->device_caps & V4L2_CAP_READWRITE)
a->parm.capture.readbuffers = 2;
- if (v4l2_subdev_has_op(sd, video, g_frame_interval))
+ if (v4l2_subdev_has_op(sd, pad, get_frame_interval))
a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- ret = v4l2_subdev_call(sd, video, g_frame_interval, &ival);
+ ret = v4l2_subdev_call_state_active(sd, pad, get_frame_interval, &ival);
if (!ret)
a->parm.capture.timeperframe = ival.interval;
return ret;
@@ -222,9 +222,9 @@ int v4l2_s_parm_cap(struct video_device *vdev,
else
a->parm.capture.readbuffers = 0;
- if (v4l2_subdev_has_op(sd, video, g_frame_interval))
+ if (v4l2_subdev_has_op(sd, pad, get_frame_interval))
a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- ret = v4l2_subdev_call(sd, video, s_frame_interval, &ival);
+ ret = v4l2_subdev_call_state_active(sd, pad, set_frame_interval, &ival);
if (!ret)
a->parm.capture.timeperframe = ival.interval;
return ret;
@@ -254,6 +254,9 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGBX1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_ARGB2101010, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
/* YUV packed formats */
{ .format = V4L2_PIX_FMT_YUYV, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index f3bed37859a2..8c07400bd280 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -116,6 +116,9 @@ struct v4l2_format32 {
* @flags: additional buffer management attributes (ignored unless the
* queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability and
* configured for MMAP streaming I/O).
+ * @max_num_buffers: if V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS capability flag is set
+ * this field indicate the maximum possible number of buffers
+ * for this queue.
* @reserved: future extensions
*/
struct v4l2_create_buffers32 {
@@ -125,7 +128,8 @@ struct v4l2_create_buffers32 {
struct v4l2_format32 format;
__u32 capabilities;
__u32 flags;
- __u32 reserved[6];
+ __u32 max_num_buffers;
+ __u32 reserved[5];
};
static int get_v4l2_format32(struct v4l2_format *p64,
@@ -175,6 +179,9 @@ static int get_v4l2_create32(struct v4l2_create_buffers *p64,
return -EFAULT;
if (copy_from_user(&p64->flags, &p32->flags, sizeof(p32->flags)))
return -EFAULT;
+ if (copy_from_user(&p64->max_num_buffers, &p32->max_num_buffers,
+ sizeof(p32->max_num_buffers)))
+ return -EFAULT;
return get_v4l2_format32(&p64->format, &p32->format);
}
@@ -221,6 +228,7 @@ static int put_v4l2_create32(struct v4l2_create_buffers *p64,
offsetof(struct v4l2_create_buffers32, format)) ||
put_user(p64->capabilities, &p32->capabilities) ||
put_user(p64->flags, &p32->flags) ||
+ put_user(p64->max_num_buffers, &p32->max_num_buffers) ||
copy_to_user(p32->reserved, p64->reserved, sizeof(p64->reserved)))
return -EFAULT;
return put_v4l2_format32(&p64->format, &p32->format);
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index f81279492682..d13954bd31fd 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -642,11 +642,13 @@ static void determine_valid_ioctls(struct video_device *vdev)
SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd);
SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes);
SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals);
- if (ops->vidioc_g_selection) {
+ if (ops->vidioc_g_selection &&
+ !test_bit(_IOC_NR(VIDIOC_G_SELECTION), vdev->valid_ioctls)) {
__set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls);
__set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls);
}
- if (ops->vidioc_s_selection)
+ if (ops->vidioc_s_selection &&
+ !test_bit(_IOC_NR(VIDIOC_S_SELECTION), vdev->valid_ioctls))
__set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection);
SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection);
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 7f181fbbb140..89c7192148df 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -1179,7 +1179,9 @@ v4l2_async_nf_parse_fwnode_sensor(struct device *dev,
static const char * const led_props[] = { "led" };
static const struct v4l2_fwnode_int_props props[] = {
{ "flash-leds", led_props, ARRAY_SIZE(led_props) },
- { "lens-focus", NULL, 0 },
+ { "mipi-img-flash-leds", },
+ { "lens-focus", },
+ { "mipi-img-lens-focus", },
};
unsigned int i;
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 9b1de54ce379..33076af4dfdb 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -483,9 +483,9 @@ static void v4l_print_create_buffers(const void *arg, bool write_only)
{
const struct v4l2_create_buffers *p = arg;
- pr_cont("index=%d, count=%d, memory=%s, capabilities=0x%08x, ",
+ pr_cont("index=%d, count=%d, memory=%s, capabilities=0x%08x, max num buffers=%u",
p->index, p->count, prt_names(p->memory, v4l2_memory_names),
- p->capabilities);
+ p->capabilities, p->max_num_buffers);
v4l_print_format(&p->format, write_only);
}
@@ -2951,7 +2951,7 @@ void v4l_printk_ioctl(const char *prefix, unsigned int cmd)
type = "v4l2_int";
break;
case 'V':
- if (_IOC_NR(cmd) >= V4L2_IOCTLS) {
+ if (!v4l2_is_known_ioctl(cmd)) {
type = "v4l2";
break;
}
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index 0cc30397fbad..9e983176542b 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -301,9 +301,12 @@ static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev,
dprintk("Trying to schedule a job for m2m_ctx: %p\n", m2m_ctx);
- if (!m2m_ctx->out_q_ctx.q.streaming
- || !m2m_ctx->cap_q_ctx.q.streaming) {
- dprintk("Streaming needs to be on for both queues\n");
+ if (!m2m_ctx->out_q_ctx.q.streaming ||
+ (!m2m_ctx->cap_q_ctx.q.streaming && !m2m_ctx->ignore_cap_streaming)) {
+ if (!m2m_ctx->ignore_cap_streaming)
+ dprintk("Streaming needs to be on for both queues\n");
+ else
+ dprintk("Streaming needs to be on for the OUTPUT queue\n");
return;
}
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index be86b906c985..4c6198c48dd6 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -177,7 +177,7 @@ static int check_state(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
{
if (sd->flags & V4L2_SUBDEV_FL_STREAMS) {
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
- if (!v4l2_subdev_state_get_stream_format(state, pad, stream))
+ if (!v4l2_subdev_state_get_format(state, pad, stream))
return -EINVAL;
return 0;
#else
@@ -245,29 +245,6 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
sd->ops->pad->enum_frame_size(sd, state, fse);
}
-static inline int check_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
-{
- if (!fi)
- return -EINVAL;
-
- return check_pad(sd, fi->pad);
-}
-
-static int call_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
-{
- return check_frame_interval(sd, fi) ? :
- sd->ops->video->g_frame_interval(sd, fi);
-}
-
-static int call_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
-{
- return check_frame_interval(sd, fi) ? :
- sd->ops->video->s_frame_interval(sd, fi);
-}
-
static int call_enum_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_frame_interval_enum *fie)
@@ -307,6 +284,33 @@ static int call_set_selection(struct v4l2_subdev *sd,
sd->ops->pad->set_selection(sd, state, sel);
}
+static inline int check_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ if (!fi)
+ return -EINVAL;
+
+ return check_which(fi->which) ? : check_pad(sd, fi->pad) ? :
+ check_state(sd, state, fi->which, fi->pad, fi->stream);
+}
+
+static int call_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ return check_frame_interval(sd, state, fi) ? :
+ sd->ops->pad->get_frame_interval(sd, state, fi);
+}
+
+static int call_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ return check_frame_interval(sd, state, fi) ? :
+ sd->ops->pad->set_frame_interval(sd, state, fi);
+}
+
static int call_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
struct v4l2_mbus_frame_desc *fd)
{
@@ -479,6 +483,8 @@ static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
.enum_frame_interval = call_enum_frame_interval_state,
.get_selection = call_get_selection_state,
.set_selection = call_set_selection_state,
+ .get_frame_interval = call_get_frame_interval,
+ .set_frame_interval = call_set_frame_interval,
.get_edid = call_get_edid,
.set_edid = call_set_edid,
.dv_timings_cap = call_dv_timings_cap,
@@ -488,8 +494,6 @@ static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
};
static const struct v4l2_subdev_video_ops v4l2_subdev_call_video_wrappers = {
- .g_frame_interval = call_g_frame_interval,
- .s_frame_interval = call_s_frame_interval,
.s_stream = call_s_stream,
};
@@ -531,6 +535,17 @@ subdev_ioctl_get_state(struct v4l2_subdev *sd, struct v4l2_subdev_fh *subdev_fh,
case VIDIOC_SUBDEV_S_SELECTION:
which = ((struct v4l2_subdev_selection *)arg)->which;
break;
+ case VIDIOC_SUBDEV_G_FRAME_INTERVAL:
+ case VIDIOC_SUBDEV_S_FRAME_INTERVAL: {
+ struct v4l2_subdev_frame_interval *fi = arg;
+
+ if (!(subdev_fh->client_caps &
+ V4L2_SUBDEV_CLIENT_CAP_INTERVAL_USES_WHICH))
+ fi->which = V4L2_SUBDEV_FORMAT_ACTIVE;
+
+ which = fi->which;
+ break;
+ }
case VIDIOC_SUBDEV_G_ROUTING:
case VIDIOC_SUBDEV_S_ROUTING:
which = ((struct v4l2_subdev_routing *)arg)->which;
@@ -781,20 +796,20 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
fi->stream = 0;
memset(fi->reserved, 0, sizeof(fi->reserved));
- return v4l2_subdev_call(sd, video, g_frame_interval, arg);
+ return v4l2_subdev_call(sd, pad, get_frame_interval, state, fi);
}
case VIDIOC_SUBDEV_S_FRAME_INTERVAL: {
struct v4l2_subdev_frame_interval *fi = arg;
- if (ro_subdev)
- return -EPERM;
-
if (!client_supports_streams)
fi->stream = 0;
+ if (fi->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
+ return -EPERM;
+
memset(fi->reserved, 0, sizeof(fi->reserved));
- return v4l2_subdev_call(sd, video, s_frame_interval, arg);
+ return v4l2_subdev_call(sd, pad, set_frame_interval, state, fi);
}
case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
@@ -989,7 +1004,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
client_cap->capabilities &= ~V4L2_SUBDEV_CLIENT_CAP_STREAMS;
/* Filter out unsupported capabilities */
- client_cap->capabilities &= V4L2_SUBDEV_CLIENT_CAP_STREAMS;
+ client_cap->capabilities &= (V4L2_SUBDEV_CLIENT_CAP_STREAMS |
+ V4L2_SUBDEV_CLIENT_CAP_INTERVAL_USES_WHICH);
subdev_fh->client_caps = client_cap->capabilities;
@@ -1448,6 +1464,8 @@ __v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name,
else
state->lock = &state->_lock;
+ state->sd = sd;
+
/* Drivers that support streams do not need the legacy pad config */
if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS) && sd->entity.num_pads) {
state->pads = kvcalloc(sd->entity.num_pads,
@@ -1458,16 +1476,18 @@ __v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name,
}
}
- /*
- * There can be no race at this point, but we lock the state anyway to
- * satisfy lockdep checks.
- */
- v4l2_subdev_lock_state(state);
- ret = v4l2_subdev_call(sd, pad, init_cfg, state);
- v4l2_subdev_unlock_state(state);
+ if (sd->internal_ops && sd->internal_ops->init_state) {
+ /*
+ * There can be no race at this point, but we lock the state
+ * anyway to satisfy lockdep checks.
+ */
+ v4l2_subdev_lock_state(state);
+ ret = sd->internal_ops->init_state(sd, state);
+ v4l2_subdev_unlock_state(state);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- goto err;
+ if (ret)
+ goto err;
+ }
return state;
@@ -1517,7 +1537,8 @@ void v4l2_subdev_cleanup(struct v4l2_subdev *sd)
__v4l2_subdev_state_free(sd->active_state);
sd->active_state = NULL;
- if (list_empty(&sd->async_subdev_endpoint_list))
+ /* Uninitialised sub-device, bail out here. */
+ if (!sd->async_subdev_endpoint_list.next)
return;
list_for_each_entry_safe(ase, ase_tmp, &sd->async_subdev_endpoint_list,
@@ -1529,6 +1550,144 @@ void v4l2_subdev_cleanup(struct v4l2_subdev *sd)
}
EXPORT_SYMBOL_GPL(v4l2_subdev_cleanup);
+struct v4l2_mbus_framefmt *
+__v4l2_subdev_state_get_format(struct v4l2_subdev_state *state,
+ unsigned int pad, u32 stream)
+{
+ struct v4l2_subdev_stream_configs *stream_configs;
+ unsigned int i;
+
+ if (WARN_ON_ONCE(!state))
+ return NULL;
+
+ if (state->pads) {
+ if (stream)
+ return NULL;
+
+ if (pad >= state->sd->entity.num_pads)
+ return NULL;
+
+ return &state->pads[pad].format;
+ }
+
+ lockdep_assert_held(state->lock);
+
+ stream_configs = &state->stream_configs;
+
+ for (i = 0; i < stream_configs->num_configs; ++i) {
+ if (stream_configs->configs[i].pad == pad &&
+ stream_configs->configs[i].stream == stream)
+ return &stream_configs->configs[i].fmt;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_format);
+
+struct v4l2_rect *
+__v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad,
+ u32 stream)
+{
+ struct v4l2_subdev_stream_configs *stream_configs;
+ unsigned int i;
+
+ if (WARN_ON_ONCE(!state))
+ return NULL;
+
+ if (state->pads) {
+ if (stream)
+ return NULL;
+
+ if (pad >= state->sd->entity.num_pads)
+ return NULL;
+
+ return &state->pads[pad].crop;
+ }
+
+ lockdep_assert_held(state->lock);
+
+ stream_configs = &state->stream_configs;
+
+ for (i = 0; i < stream_configs->num_configs; ++i) {
+ if (stream_configs->configs[i].pad == pad &&
+ stream_configs->configs[i].stream == stream)
+ return &stream_configs->configs[i].crop;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_crop);
+
+struct v4l2_rect *
+__v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state,
+ unsigned int pad, u32 stream)
+{
+ struct v4l2_subdev_stream_configs *stream_configs;
+ unsigned int i;
+
+ if (WARN_ON_ONCE(!state))
+ return NULL;
+
+ if (state->pads) {
+ if (stream)
+ return NULL;
+
+ if (pad >= state->sd->entity.num_pads)
+ return NULL;
+
+ return &state->pads[pad].compose;
+ }
+
+ lockdep_assert_held(state->lock);
+
+ stream_configs = &state->stream_configs;
+
+ for (i = 0; i < stream_configs->num_configs; ++i) {
+ if (stream_configs->configs[i].pad == pad &&
+ stream_configs->configs[i].stream == stream)
+ return &stream_configs->configs[i].compose;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_compose);
+
+struct v4l2_fract *
+__v4l2_subdev_state_get_interval(struct v4l2_subdev_state *state,
+ unsigned int pad, u32 stream)
+{
+ struct v4l2_subdev_stream_configs *stream_configs;
+ unsigned int i;
+
+ if (WARN_ON(!state))
+ return NULL;
+
+ lockdep_assert_held(state->lock);
+
+ if (state->pads) {
+ if (stream)
+ return NULL;
+
+ if (pad >= state->sd->entity.num_pads)
+ return NULL;
+
+ return &state->pads[pad].interval;
+ }
+
+ lockdep_assert_held(state->lock);
+
+ stream_configs = &state->stream_configs;
+
+ for (i = 0; i < stream_configs->num_configs; ++i) {
+ if (stream_configs->configs[i].pad == pad &&
+ stream_configs->configs[i].stream == stream)
+ return &stream_configs->configs[i].interval;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(__v4l2_subdev_state_get_interval);
+
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
static int
@@ -1585,14 +1744,7 @@ int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
{
struct v4l2_mbus_framefmt *fmt;
- if (sd->flags & V4L2_SUBDEV_FL_STREAMS)
- fmt = v4l2_subdev_state_get_stream_format(state, format->pad,
- format->stream);
- else if (format->pad < sd->entity.num_pads && format->stream == 0)
- fmt = v4l2_subdev_get_pad_format(sd, state, format->pad);
- else
- fmt = NULL;
-
+ fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
if (!fmt)
return -EINVAL;
@@ -1602,6 +1754,22 @@ int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
}
EXPORT_SYMBOL_GPL(v4l2_subdev_get_fmt);
+int v4l2_subdev_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct v4l2_fract *interval;
+
+ interval = v4l2_subdev_state_get_interval(state, fi->pad, fi->stream);
+ if (!interval)
+ return -EINVAL;
+
+ fi->interval = *interval;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_get_frame_interval);
+
int v4l2_subdev_set_routing(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
const struct v4l2_subdev_krouting *routing)
@@ -1682,69 +1850,6 @@ int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd,
}
EXPORT_SYMBOL_GPL(v4l2_subdev_set_routing_with_fmt);
-struct v4l2_mbus_framefmt *
-v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state,
- unsigned int pad, u32 stream)
-{
- struct v4l2_subdev_stream_configs *stream_configs;
- unsigned int i;
-
- lockdep_assert_held(state->lock);
-
- stream_configs = &state->stream_configs;
-
- for (i = 0; i < stream_configs->num_configs; ++i) {
- if (stream_configs->configs[i].pad == pad &&
- stream_configs->configs[i].stream == stream)
- return &stream_configs->configs[i].fmt;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_format);
-
-struct v4l2_rect *
-v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state,
- unsigned int pad, u32 stream)
-{
- struct v4l2_subdev_stream_configs *stream_configs;
- unsigned int i;
-
- lockdep_assert_held(state->lock);
-
- stream_configs = &state->stream_configs;
-
- for (i = 0; i < stream_configs->num_configs; ++i) {
- if (stream_configs->configs[i].pad == pad &&
- stream_configs->configs[i].stream == stream)
- return &stream_configs->configs[i].crop;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_crop);
-
-struct v4l2_rect *
-v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state,
- unsigned int pad, u32 stream)
-{
- struct v4l2_subdev_stream_configs *stream_configs;
- unsigned int i;
-
- lockdep_assert_held(state->lock);
-
- stream_configs = &state->stream_configs;
-
- for (i = 0; i < stream_configs->num_configs; ++i) {
- if (stream_configs->configs[i].pad == pad &&
- stream_configs->configs[i].stream == stream)
- return &stream_configs->configs[i].compose;
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_compose);
-
int v4l2_subdev_routing_find_opposite_end(const struct v4l2_subdev_krouting *routing,
u32 pad, u32 stream, u32 *other_pad,
u32 *other_stream)
@@ -1789,8 +1894,7 @@ v4l2_subdev_state_get_opposite_stream_format(struct v4l2_subdev_state *state,
if (ret)
return NULL;
- return v4l2_subdev_state_get_stream_format(state, other_pad,
- other_stream);
+ return v4l2_subdev_state_get_format(state, other_pad, other_stream);
}
EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_opposite_stream_format);
diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c
index 0ff014a9d3cd..1b3183951bfe 100644
--- a/drivers/memory/tegra/tegra186.c
+++ b/drivers/memory/tegra/tegra186.c
@@ -114,9 +114,12 @@ static void tegra186_mc_client_sid_override(struct tegra_mc *mc,
static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev)
{
#if IS_ENABLED(CONFIG_IOMMU_API)
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
struct of_phandle_args args;
unsigned int i, index = 0;
+ u32 sid;
+
+ if (!tegra_dev_iommu_get_stream_id(dev, &sid))
+ return 0;
while (!of_parse_phandle_with_args(dev->of_node, "interconnects", "#interconnect-cells",
index, &args)) {
@@ -124,11 +127,10 @@ static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev)
for (i = 0; i < mc->soc->num_clients; i++) {
const struct tegra_mc_client *client = &mc->soc->clients[i];
- if (client->id == args.args[0]) {
- u32 sid = fwspec->ids[0] & MC_SID_STREAMID_OVERRIDE_MASK;
-
- tegra186_mc_client_sid_override(mc, client, sid);
- }
+ if (client->id == args.args[0])
+ tegra186_mc_client_sid_override(
+ mc, client,
+ sid & MC_SID_STREAMID_OVERRIDE_MASK);
}
}
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 925c19ee513b..e7a6e45b9fac 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1483,6 +1483,7 @@ config MFD_SYSCON
config MFD_TI_AM335X_TSCADC
tristate "TI ADC / Touch Screen chip support"
+ depends on ARCH_OMAP2PLUS || ARCH_K3 || COMPILE_TEST
select MFD_CORE
select REGMAP
select REGMAP_MMIO
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index eeeb62415f53..8f3ebe651eea 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -30,7 +30,7 @@ static void ab8500_power_off(void)
{
sigset_t old;
sigset_t all;
- static const char * const pss[] = {"ab8500_ac", "pm2301", "ab8500_usb"};
+ static const char * const pss[] = {"ab8500_ac", "ab8500_usb"};
int i;
bool charger_present = false;
union power_supply_propval val;
@@ -140,14 +140,12 @@ static int ab8500_sysctrl_probe(struct platform_device *pdev)
return 0;
}
-static int ab8500_sysctrl_remove(struct platform_device *pdev)
+static void ab8500_sysctrl_remove(struct platform_device *pdev)
{
sysctrl_dev = NULL;
if (pm_power_off == ab8500_power_off)
pm_power_off = NULL;
-
- return 0;
}
static const struct of_device_id ab8500_sysctrl_match[] = {
@@ -161,7 +159,7 @@ static struct platform_driver ab8500_sysctrl_driver = {
.of_match_table = ab8500_sysctrl_match,
},
.probe = ab8500_sysctrl_probe,
- .remove = ab8500_sysctrl_remove,
+ .remove_new = ab8500_sysctrl_remove,
};
static int __init ab8500_sysctrl_init(void)
diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c
index 79d393b602bf..603b1cd52785 100644
--- a/drivers/mfd/cros_ec_dev.c
+++ b/drivers/mfd/cros_ec_dev.c
@@ -288,13 +288,12 @@ failed:
return retval;
}
-static int ec_device_remove(struct platform_device *pdev)
+static void ec_device_remove(struct platform_device *pdev)
{
struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev);
mfd_remove_devices(ec->dev);
device_unregister(&ec->class_dev);
- return 0;
}
static const struct platform_device_id cros_ec_id[] = {
@@ -309,7 +308,7 @@ static struct platform_driver cros_ec_dev_driver = {
},
.id_table = cros_ec_id,
.probe = ec_device_probe,
- .remove = ec_device_remove,
+ .remove_new = ec_device_remove,
};
static int __init cros_ec_dev_init(void)
diff --git a/drivers/mfd/cs42l43-sdw.c b/drivers/mfd/cs42l43-sdw.c
index 7392b3d2e6b9..1d85bbf8cdd5 100644
--- a/drivers/mfd/cs42l43-sdw.c
+++ b/drivers/mfd/cs42l43-sdw.c
@@ -6,24 +6,23 @@
* Cirrus Logic International Semiconductor Ltd.
*/
+#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/mfd/cs42l43-regs.h>
#include <linux/module.h>
-#include <linux/device.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_registers.h>
#include <linux/soundwire/sdw_type.h>
#include "cs42l43.h"
-enum cs42l43_sdw_ports {
- CS42L43_DMIC_DEC_ASP_PORT = 1,
- CS42L43_SPK_TX_PORT,
- CS42L43_SPDIF_HP_PORT,
- CS42L43_SPK_RX_PORT,
- CS42L43_ASP_PORT,
-};
+#define CS42L43_SDW_PORT(port, chans) { \
+ .num = port, \
+ .max_ch = chans, \
+ .type = SDW_DPN_FULL, \
+ .max_word = 24, \
+}
static const struct regmap_config cs42l43_sdw_regmap = {
.reg_bits = 32,
@@ -42,65 +41,48 @@ static const struct regmap_config cs42l43_sdw_regmap = {
.num_reg_defaults = ARRAY_SIZE(cs42l43_reg_default),
};
+static const struct sdw_dpn_prop cs42l43_src_port_props[] = {
+ CS42L43_SDW_PORT(1, 4),
+ CS42L43_SDW_PORT(2, 2),
+ CS42L43_SDW_PORT(3, 2),
+ CS42L43_SDW_PORT(4, 2),
+};
+
+static const struct sdw_dpn_prop cs42l43_sink_port_props[] = {
+ CS42L43_SDW_PORT(5, 2),
+ CS42L43_SDW_PORT(6, 2),
+ CS42L43_SDW_PORT(7, 2),
+};
+
static int cs42l43_read_prop(struct sdw_slave *sdw)
{
struct sdw_slave_prop *prop = &sdw->prop;
struct device *dev = &sdw->dev;
- struct sdw_dpn_prop *dpn;
- unsigned long addr;
- int nval;
int i;
- u32 bit;
prop->use_domain_irq = true;
prop->paging_support = true;
prop->wake_capable = true;
- prop->source_ports = BIT(CS42L43_DMIC_DEC_ASP_PORT) | BIT(CS42L43_SPK_TX_PORT);
- prop->sink_ports = BIT(CS42L43_SPDIF_HP_PORT) |
- BIT(CS42L43_SPK_RX_PORT) | BIT(CS42L43_ASP_PORT);
prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY |
SDW_SCP_INT1_IMPL_DEF;
- nval = hweight32(prop->source_ports);
- prop->src_dpn_prop = devm_kcalloc(dev, nval, sizeof(*prop->src_dpn_prop),
- GFP_KERNEL);
+ for (i = 0; i < ARRAY_SIZE(cs42l43_src_port_props); i++)
+ prop->source_ports |= BIT(cs42l43_src_port_props[i].num);
+
+ prop->src_dpn_prop = devm_kmemdup(dev, cs42l43_src_port_props,
+ sizeof(cs42l43_src_port_props), GFP_KERNEL);
if (!prop->src_dpn_prop)
return -ENOMEM;
- i = 0;
- dpn = prop->src_dpn_prop;
- addr = prop->source_ports;
- for_each_set_bit(bit, &addr, 32) {
- dpn[i].num = bit;
- dpn[i].max_ch = 2;
- dpn[i].type = SDW_DPN_FULL;
- dpn[i].max_word = 24;
- i++;
- }
- /*
- * All ports are 2 channels max, except the first one,
- * CS42L43_DMIC_DEC_ASP_PORT.
- */
- dpn[CS42L43_DMIC_DEC_ASP_PORT].max_ch = 4;
+ for (i = 0; i < ARRAY_SIZE(cs42l43_sink_port_props); i++)
+ prop->sink_ports |= BIT(cs42l43_sink_port_props[i].num);
- nval = hweight32(prop->sink_ports);
- prop->sink_dpn_prop = devm_kcalloc(dev, nval, sizeof(*prop->sink_dpn_prop),
- GFP_KERNEL);
+ prop->sink_dpn_prop = devm_kmemdup(dev, cs42l43_sink_port_props,
+ sizeof(cs42l43_sink_port_props), GFP_KERNEL);
if (!prop->sink_dpn_prop)
return -ENOMEM;
- i = 0;
- dpn = prop->sink_dpn_prop;
- addr = prop->sink_ports;
- for_each_set_bit(bit, &addr, 32) {
- dpn[i].num = bit;
- dpn[i].max_ch = 2;
- dpn[i].type = SDW_DPN_FULL;
- dpn[i].max_word = 24;
- i++;
- }
-
return 0;
}
diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c
index 45da007d3e70..73a22107900c 100644
--- a/drivers/mfd/da9062-core.c
+++ b/drivers/mfd/da9062-core.c
@@ -588,16 +588,8 @@ static struct regmap_config da9062_regmap_config = {
.volatile_table = &da9062_aa_volatile_table,
};
-static const struct of_device_id da9062_dt_ids[] = {
- { .compatible = "dlg,da9061", .data = (void *)COMPAT_TYPE_DA9061, },
- { .compatible = "dlg,da9062", .data = (void *)COMPAT_TYPE_DA9062, },
- { }
-};
-MODULE_DEVICE_TABLE(of, da9062_dt_ids);
-
static int da9062_i2c_probe(struct i2c_client *i2c)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
struct da9062 *chip;
unsigned int irq_base = 0;
const struct mfd_cell *cell;
@@ -611,10 +603,7 @@ static int da9062_i2c_probe(struct i2c_client *i2c)
if (!chip)
return -ENOMEM;
- if (i2c->dev.of_node)
- chip->chip_type = (uintptr_t)of_device_get_match_data(&i2c->dev);
- else
- chip->chip_type = id->driver_data;
+ chip->chip_type = (uintptr_t)i2c_get_match_data(i2c);
i2c_set_clientdata(i2c, chip);
chip->dev = &i2c->dev;
@@ -714,10 +703,17 @@ static void da9062_i2c_remove(struct i2c_client *i2c)
regmap_del_irq_chip(i2c->irq, chip->regmap_irq);
}
+static const struct of_device_id da9062_dt_ids[] = {
+ { .compatible = "dlg,da9061", .data = (void *)COMPAT_TYPE_DA9061 },
+ { .compatible = "dlg,da9062", .data = (void *)COMPAT_TYPE_DA9062 },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da9062_dt_ids);
+
static const struct i2c_device_id da9062_i2c_id[] = {
{ "da9061", COMPAT_TYPE_DA9061 },
{ "da9062", COMPAT_TYPE_DA9062 },
- { },
+ { }
};
MODULE_DEVICE_TABLE(i2c, da9062_i2c_id);
diff --git a/drivers/mfd/exynos-lpass.c b/drivers/mfd/exynos-lpass.c
index 1506d8d352b1..e58990c85ed8 100644
--- a/drivers/mfd/exynos-lpass.c
+++ b/drivers/mfd/exynos-lpass.c
@@ -137,7 +137,7 @@ static int exynos_lpass_probe(struct platform_device *pdev)
return devm_of_platform_populate(dev);
}
-static int exynos_lpass_remove(struct platform_device *pdev)
+static void exynos_lpass_remove(struct platform_device *pdev)
{
struct exynos_lpass *lpass = platform_get_drvdata(pdev);
@@ -146,8 +146,6 @@ static int exynos_lpass_remove(struct platform_device *pdev)
if (!pm_runtime_status_suspended(&pdev->dev))
exynos_lpass_disable(lpass);
regmap_exit(lpass->top);
-
- return 0;
}
static int __maybe_unused exynos_lpass_suspend(struct device *dev)
@@ -187,7 +185,7 @@ static struct platform_driver exynos_lpass_driver = {
.of_match_table = exynos_lpass_of_match,
},
.probe = exynos_lpass_probe,
- .remove = exynos_lpass_remove,
+ .remove_new = exynos_lpass_remove,
};
module_platform_driver(exynos_lpass_driver);
diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c
index 089c2ce615b6..74f38bf3778f 100644
--- a/drivers/mfd/fsl-imx25-tsadc.c
+++ b/drivers/mfd/fsl-imx25-tsadc.c
@@ -194,11 +194,9 @@ err_irq:
return ret;
}
-static int mx25_tsadc_remove(struct platform_device *pdev)
+static void mx25_tsadc_remove(struct platform_device *pdev)
{
mx25_tsadc_unset_irq(pdev);
-
- return 0;
}
static const struct of_device_id mx25_tsadc_ids[] = {
@@ -213,7 +211,7 @@ static struct platform_driver mx25_tsadc_driver = {
.of_match_table = mx25_tsadc_ids,
},
.probe = mx25_tsadc_probe,
- .remove = mx25_tsadc_remove,
+ .remove_new = mx25_tsadc_remove,
};
module_platform_driver(mx25_tsadc_driver);
diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c
index 8feae8d8fd9d..042109304db4 100644
--- a/drivers/mfd/hi655x-pmic.c
+++ b/drivers/mfd/hi655x-pmic.c
@@ -144,13 +144,12 @@ static int hi655x_pmic_probe(struct platform_device *pdev)
return 0;
}
-static int hi655x_pmic_remove(struct platform_device *pdev)
+static void hi655x_pmic_remove(struct platform_device *pdev)
{
struct hi655x_pmic *pmic = platform_get_drvdata(pdev);
regmap_del_irq_chip(gpiod_to_irq(pmic->gpio), pmic->irq_data);
mfd_remove_devices(&pdev->dev);
- return 0;
}
static const struct of_device_id hi655x_pmic_match[] = {
@@ -165,7 +164,7 @@ static struct platform_driver hi655x_pmic_driver = {
.of_match_table = hi655x_pmic_match,
},
.probe = hi655x_pmic_probe,
- .remove = hi655x_pmic_remove,
+ .remove_new = hi655x_pmic_remove,
};
module_platform_driver(hi655x_pmic_driver);
diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c
index 212818aef93e..2a83f8678f1d 100644
--- a/drivers/mfd/intel-lpss-acpi.c
+++ b/drivers/mfd/intel-lpss-acpi.c
@@ -8,15 +8,20 @@
* Mika Westerberg <[email protected]>
*/
-#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/gfp_types.h>
#include <linux/ioport.h>
-#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/property.h>
+
#include <linux/pxa2xx_ssp.h>
+#include <asm/errno.h>
+
#include "intel-lpss.h"
static const struct property_entry spt_spi_properties[] = {
@@ -169,23 +174,20 @@ MODULE_DEVICE_TABLE(acpi, intel_lpss_acpi_ids);
static int intel_lpss_acpi_probe(struct platform_device *pdev)
{
+ const struct intel_lpss_platform_info *data;
struct intel_lpss_platform_info *info;
- const struct acpi_device_id *id;
int ret;
- id = acpi_match_device(intel_lpss_acpi_ids, &pdev->dev);
- if (!id)
+ data = device_get_match_data(&pdev->dev);
+ if (!data)
return -ENODEV;
- info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info),
- GFP_KERNEL);
+ info = devm_kmemdup(&pdev->dev, data, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
+ /* No need to check mem and irq here as intel_lpss_probe() does it for us */
info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!info->mem)
- return -ENODEV;
-
info->irq = platform_get_irq(pdev, 0);
ret = intel_lpss_probe(&pdev->dev, info);
@@ -198,23 +200,19 @@ static int intel_lpss_acpi_probe(struct platform_device *pdev)
return 0;
}
-static int intel_lpss_acpi_remove(struct platform_device *pdev)
+static void intel_lpss_acpi_remove(struct platform_device *pdev)
{
intel_lpss_remove(&pdev->dev);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
-static INTEL_LPSS_PM_OPS(intel_lpss_acpi_pm_ops);
-
static struct platform_driver intel_lpss_acpi_driver = {
.probe = intel_lpss_acpi_probe,
- .remove = intel_lpss_acpi_remove,
+ .remove_new = intel_lpss_acpi_remove,
.driver = {
.name = "intel-lpss",
.acpi_match_table = intel_lpss_acpi_ids,
- .pm = &intel_lpss_acpi_pm_ops,
+ .pm = pm_ptr(&intel_lpss_pm_ops),
},
};
@@ -224,3 +222,4 @@ MODULE_AUTHOR("Andy Shevchenko <[email protected]>");
MODULE_AUTHOR("Mika Westerberg <[email protected]>");
MODULE_DESCRIPTION("Intel LPSS ACPI driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(INTEL_LPSS);
diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c
index ae5759200622..4621d3950b8f 100644
--- a/drivers/mfd/intel-lpss-pci.c
+++ b/drivers/mfd/intel-lpss-pci.c
@@ -8,14 +8,19 @@
* Mika Westerberg <[email protected]>
*/
-#include <linux/ioport.h>
-#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/gfp_types.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
+
#include <linux/pxa2xx_ssp.h>
+#include <asm/errno.h>
+
#include "intel-lpss.h"
/* Some DSDTs have an unused GEXP ACPI device conflicting with I2C4 resources */
@@ -30,6 +35,7 @@ static const struct pci_device_id ignore_resource_conflicts_ids[] = {
static int intel_lpss_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
+ const struct intel_lpss_platform_info *data = (void *)id->driver_data;
struct intel_lpss_platform_info *info;
int ret;
@@ -37,13 +43,17 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev,
if (ret)
return ret;
- info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info),
- GFP_KERNEL);
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY);
+ if (ret < 0)
+ return ret;
+
+ info = devm_kmemdup(&pdev->dev, data, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
- info->mem = &pdev->resource[0];
- info->irq = pdev->irq;
+ /* No need to check mem and irq here as intel_lpss_probe() does it for us */
+ info->mem = pci_resource_n(pdev, 0);
+ info->irq = pci_irq_vector(pdev, 0);
if (pci_match_id(ignore_resource_conflicts_ids, pdev))
info->ignore_resource_conflicts = true;
@@ -72,8 +82,6 @@ static void intel_lpss_pci_remove(struct pci_dev *pdev)
intel_lpss_remove(&pdev->dev);
}
-static INTEL_LPSS_PM_OPS(intel_lpss_pci_pm_ops);
-
static const struct property_entry spt_spi_properties[] = {
PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_SPT_SSP),
{ }
@@ -584,7 +592,7 @@ static struct pci_driver intel_lpss_pci_driver = {
.probe = intel_lpss_pci_probe,
.remove = intel_lpss_pci_remove,
.driver = {
- .pm = &intel_lpss_pci_pm_ops,
+ .pm = pm_ptr(&intel_lpss_pm_ops),
},
};
@@ -594,3 +602,4 @@ MODULE_AUTHOR("Andy Shevchenko <[email protected]>");
MODULE_AUTHOR("Mika Westerberg <[email protected]>");
MODULE_DESCRIPTION("Intel LPSS PCI driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(INTEL_LPSS);
diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c
index 9591b354072a..eff423f7dd28 100644
--- a/drivers/mfd/intel-lpss.c
+++ b/drivers/mfd/intel-lpss.c
@@ -10,26 +10,34 @@
* Jarkko Nikula <[email protected]>
*/
-#include <linux/clk.h>
+#include <linux/array_size.h>
+#include <linux/bits.h>
#include <linux/clkdev.h>
+#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gfp_types.h>
#include <linux/idr.h>
#include <linux/io.h>
#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/pm.h>
#include <linux/pm_qos.h>
#include <linux/pm_runtime.h>
-#include <linux/property.h>
-#include <linux/seq_file.h>
+#include <linux/sprintf.h>
+#include <linux/types.h>
+
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/dma/idma64.h>
#include "intel-lpss.h"
+struct dentry;
+
#define LPSS_DEV_OFFSET 0x000
#define LPSS_DEV_SIZE 0x200
#define LPSS_PRIV_OFFSET 0x200
@@ -301,8 +309,8 @@ static int intel_lpss_register_clock_divider(struct intel_lpss *lpss,
snprintf(name, sizeof(name), "%s-div", devname);
tmp = clk_register_fractional_divider(NULL, name, __clk_get_name(tmp),
+ 0, lpss->priv, 1, 15, 16, 15,
CLK_FRAC_DIVIDER_POWER_OF_TWO_PS,
- lpss->priv, 1, 15, 16, 15, 0,
NULL);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
@@ -378,9 +386,12 @@ int intel_lpss_probe(struct device *dev,
struct intel_lpss *lpss;
int ret;
- if (!info || !info->mem || info->irq <= 0)
+ if (!info || !info->mem)
return -EINVAL;
+ if (info->irq < 0)
+ return info->irq;
+
lpss = devm_kzalloc(dev, sizeof(*lpss), GFP_KERNEL);
if (!lpss)
return -ENOMEM;
@@ -405,7 +416,7 @@ int intel_lpss_probe(struct device *dev,
intel_lpss_init_dev(lpss);
- lpss->devid = ida_simple_get(&intel_lpss_devid_ida, 0, 0, GFP_KERNEL);
+ lpss->devid = ida_alloc(&intel_lpss_devid_ida, GFP_KERNEL);
if (lpss->devid < 0)
return lpss->devid;
@@ -442,11 +453,11 @@ err_remove_ltr:
intel_lpss_unregister_clock(lpss);
err_clk_register:
- ida_simple_remove(&intel_lpss_devid_ida, lpss->devid);
+ ida_free(&intel_lpss_devid_ida, lpss->devid);
return ret;
}
-EXPORT_SYMBOL_GPL(intel_lpss_probe);
+EXPORT_SYMBOL_NS_GPL(intel_lpss_probe, INTEL_LPSS);
void intel_lpss_remove(struct device *dev)
{
@@ -456,11 +467,10 @@ void intel_lpss_remove(struct device *dev)
intel_lpss_debugfs_remove(lpss);
intel_lpss_ltr_hide(lpss);
intel_lpss_unregister_clock(lpss);
- ida_simple_remove(&intel_lpss_devid_ida, lpss->devid);
+ ida_free(&intel_lpss_devid_ida, lpss->devid);
}
-EXPORT_SYMBOL_GPL(intel_lpss_remove);
+EXPORT_SYMBOL_NS_GPL(intel_lpss_remove, INTEL_LPSS);
-#ifdef CONFIG_PM
static int resume_lpss_device(struct device *dev, void *data)
{
if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND))
@@ -469,7 +479,7 @@ static int resume_lpss_device(struct device *dev, void *data)
return 0;
}
-int intel_lpss_prepare(struct device *dev)
+static int intel_lpss_prepare(struct device *dev)
{
/*
* Resume both child devices before entering system sleep. This
@@ -478,9 +488,8 @@ int intel_lpss_prepare(struct device *dev)
device_for_each_child_reverse(dev, NULL, resume_lpss_device);
return 0;
}
-EXPORT_SYMBOL_GPL(intel_lpss_prepare);
-int intel_lpss_suspend(struct device *dev)
+static int intel_lpss_suspend(struct device *dev)
{
struct intel_lpss *lpss = dev_get_drvdata(dev);
unsigned int i;
@@ -499,9 +508,8 @@ int intel_lpss_suspend(struct device *dev)
return 0;
}
-EXPORT_SYMBOL_GPL(intel_lpss_suspend);
-int intel_lpss_resume(struct device *dev)
+static int intel_lpss_resume(struct device *dev)
{
struct intel_lpss *lpss = dev_get_drvdata(dev);
unsigned int i;
@@ -514,8 +522,12 @@ int intel_lpss_resume(struct device *dev)
return 0;
}
-EXPORT_SYMBOL_GPL(intel_lpss_resume);
-#endif
+
+EXPORT_NS_GPL_DEV_PM_OPS(intel_lpss_pm_ops, INTEL_LPSS) = {
+ .prepare = pm_sleep_ptr(&intel_lpss_prepare),
+ LATE_SYSTEM_SLEEP_PM_OPS(intel_lpss_suspend, intel_lpss_resume)
+ RUNTIME_PM_OPS(intel_lpss_suspend, intel_lpss_resume, NULL)
+};
static int __init intel_lpss_init(void)
{
diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h
index 062ce95b68b9..c1d72b117ed5 100644
--- a/drivers/mfd/intel-lpss.h
+++ b/drivers/mfd/intel-lpss.h
@@ -30,32 +30,6 @@ int intel_lpss_probe(struct device *dev,
const struct intel_lpss_platform_info *info);
void intel_lpss_remove(struct device *dev);
-#ifdef CONFIG_PM
-int intel_lpss_prepare(struct device *dev);
-int intel_lpss_suspend(struct device *dev);
-int intel_lpss_resume(struct device *dev);
-
-#ifdef CONFIG_PM_SLEEP
-#define INTEL_LPSS_SLEEP_PM_OPS \
- .prepare = intel_lpss_prepare, \
- SET_LATE_SYSTEM_SLEEP_PM_OPS(intel_lpss_suspend, intel_lpss_resume)
-#else
-#define INTEL_LPSS_SLEEP_PM_OPS
-#endif
-
-#define INTEL_LPSS_RUNTIME_PM_OPS \
- .runtime_suspend = intel_lpss_suspend, \
- .runtime_resume = intel_lpss_resume,
-
-#else /* !CONFIG_PM */
-#define INTEL_LPSS_SLEEP_PM_OPS
-#define INTEL_LPSS_RUNTIME_PM_OPS
-#endif /* CONFIG_PM */
-
-#define INTEL_LPSS_PM_OPS(name) \
-const struct dev_pm_ops name = { \
- INTEL_LPSS_SLEEP_PM_OPS \
- INTEL_LPSS_RUNTIME_PM_OPS \
-}
+extern const struct dev_pm_ops intel_lpss_pm_ops;
#endif /* __MFD_INTEL_LPSS_H */
diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c
index 33c6cfe9fe42..67af36a38913 100644
--- a/drivers/mfd/kempld-core.c
+++ b/drivers/mfd/kempld-core.c
@@ -535,7 +535,7 @@ static int kempld_probe(struct platform_device *pdev)
return kempld_detect_device(pld);
}
-static int kempld_remove(struct platform_device *pdev)
+static void kempld_remove(struct platform_device *pdev)
{
struct kempld_device_data *pld = platform_get_drvdata(pdev);
const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
@@ -544,8 +544,6 @@ static int kempld_remove(struct platform_device *pdev)
mfd_remove_devices(&pdev->dev);
pdata->release_hardware_mutex(pld);
-
- return 0;
}
#ifdef CONFIG_ACPI
@@ -563,7 +561,7 @@ static struct platform_driver kempld_driver = {
.acpi_match_table = ACPI_PTR(kempld_acpi_table),
},
.probe = kempld_probe,
- .remove = kempld_remove,
+ .remove_new = kempld_remove,
};
static const struct dmi_system_id kempld_dmi_table[] __initconst = {
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 1c9831b78cf9..3883e472b739 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -232,7 +232,7 @@ static int mcp_sa11x0_probe(struct platform_device *dev)
return ret;
}
-static int mcp_sa11x0_remove(struct platform_device *dev)
+static void mcp_sa11x0_remove(struct platform_device *dev)
{
struct mcp *mcp = platform_get_drvdata(dev);
struct mcp_sa11x0 *m = priv(mcp);
@@ -251,8 +251,6 @@ static int mcp_sa11x0_remove(struct platform_device *dev)
mcp_host_free(mcp);
release_mem_region(mem1->start, resource_size(mem1));
release_mem_region(mem0->start, resource_size(mem0));
-
- return 0;
}
static int mcp_sa11x0_suspend(struct device *dev)
@@ -288,7 +286,7 @@ static const struct dev_pm_ops mcp_sa11x0_pm_ops = {
static struct platform_driver mcp_sa11x0_driver = {
.probe = mcp_sa11x0_probe,
- .remove = mcp_sa11x0_remove,
+ .remove_new = mcp_sa11x0_remove,
.driver = {
.name = DRIVER_NAME,
.pm = pm_sleep_ptr(&mcp_sa11x0_pm_ops),
diff --git a/drivers/mfd/mxs-lradc.c b/drivers/mfd/mxs-lradc.c
index ec1b356562b9..73893890b50a 100644
--- a/drivers/mfd/mxs-lradc.c
+++ b/drivers/mfd/mxs-lradc.c
@@ -230,13 +230,11 @@ err_clk:
return ret;
}
-static int mxs_lradc_remove(struct platform_device *pdev)
+static void mxs_lradc_remove(struct platform_device *pdev)
{
struct mxs_lradc *lradc = platform_get_drvdata(pdev);
clk_disable_unprepare(lradc->clk);
-
- return 0;
}
static struct platform_driver mxs_lradc_driver = {
@@ -245,7 +243,7 @@ static struct platform_driver mxs_lradc_driver = {
.of_match_table = mxs_lradc_dt_ids,
},
.probe = mxs_lradc_probe,
- .remove = mxs_lradc_remove,
+ .remove_new = mxs_lradc_remove,
};
module_platform_driver(mxs_lradc_driver);
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 78f1bb55dbc0..ebc62033db16 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -816,13 +816,12 @@ static int usbhs_omap_remove_child(struct device *dev, void *data)
*
* Reverses the effect of usbhs_omap_probe().
*/
-static int usbhs_omap_remove(struct platform_device *pdev)
+static void usbhs_omap_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
/* remove children */
device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child);
- return 0;
}
static const struct dev_pm_ops usbhsomap_dev_pm_ops = {
@@ -845,7 +844,7 @@ static struct platform_driver usbhs_omap_driver = {
.of_match_table = usbhs_omap_dt_ids,
},
.probe = usbhs_omap_probe,
- .remove = usbhs_omap_remove,
+ .remove_new = usbhs_omap_remove,
};
MODULE_AUTHOR("Keshava Munegowda <[email protected]>");
diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c
index 906353735c78..b6303ddb013b 100644
--- a/drivers/mfd/omap-usb-tll.c
+++ b/drivers/mfd/omap-usb-tll.c
@@ -270,7 +270,7 @@ static int usbtll_omap_probe(struct platform_device *pdev)
*
* Reverses the effect of usbtll_omap_probe().
*/
-static int usbtll_omap_remove(struct platform_device *pdev)
+static void usbtll_omap_remove(struct platform_device *pdev)
{
struct usbtll_omap *tll = platform_get_drvdata(pdev);
int i;
@@ -287,7 +287,6 @@ static int usbtll_omap_remove(struct platform_device *pdev)
}
pm_runtime_disable(&pdev->dev);
- return 0;
}
static const struct of_device_id usbtll_omap_dt_ids[] = {
@@ -303,7 +302,7 @@ static struct platform_driver usbtll_omap_driver = {
.of_match_table = usbtll_omap_dt_ids,
},
.probe = usbtll_omap_probe,
- .remove = usbtll_omap_remove,
+ .remove_new = usbtll_omap_remove,
};
int omap_tll_init(struct usbhs_omap_platform_data *pdata)
diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c
index 191b1bc6141c..ab55906f91f9 100644
--- a/drivers/mfd/pcf50633-adc.c
+++ b/drivers/mfd/pcf50633-adc.c
@@ -218,7 +218,7 @@ static int pcf50633_adc_probe(struct platform_device *pdev)
return 0;
}
-static int pcf50633_adc_remove(struct platform_device *pdev)
+static void pcf50633_adc_remove(struct platform_device *pdev)
{
struct pcf50633_adc *adc = platform_get_drvdata(pdev);
int i, head;
@@ -236,8 +236,6 @@ static int pcf50633_adc_remove(struct platform_device *pdev)
kfree(adc->queue[i]);
mutex_unlock(&adc->queue_mutex);
-
- return 0;
}
static struct platform_driver pcf50633_adc_driver = {
@@ -245,7 +243,7 @@ static struct platform_driver pcf50633_adc_driver = {
.name = "pcf50633-adc",
},
.probe = pcf50633_adc_probe,
- .remove = pcf50633_adc_remove,
+ .remove_new = pcf50633_adc_remove,
};
module_platform_driver(pcf50633_adc_driver);
diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c
index 07c531bd1236..8b6285f687da 100644
--- a/drivers/mfd/qcom-pm8xxx.c
+++ b/drivers/mfd/qcom-pm8xxx.c
@@ -585,19 +585,17 @@ static int pm8xxx_remove_child(struct device *dev, void *unused)
return 0;
}
-static int pm8xxx_remove(struct platform_device *pdev)
+static void pm8xxx_remove(struct platform_device *pdev)
{
struct pm_irq_chip *chip = platform_get_drvdata(pdev);
device_for_each_child(&pdev->dev, NULL, pm8xxx_remove_child);
irq_domain_remove(chip->irqdomain);
-
- return 0;
}
static struct platform_driver pm8xxx_driver = {
.probe = pm8xxx_probe,
- .remove = pm8xxx_remove,
+ .remove_new = pm8xxx_remove,
.driver = {
.name = "pm8xxx-core",
.of_match_table = pm8xxx_id_table,
diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c
index 4549fa9f7d4b..eab5bf6cff10 100644
--- a/drivers/mfd/qcom-spmi-pmic.c
+++ b/drivers/mfd/qcom-spmi-pmic.c
@@ -53,6 +53,7 @@ static const struct of_device_id pmic_spmi_id_table[] = {
{ .compatible = "qcom,pm8901", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8909", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8916", .data = N_USIDS(2) },
+ { .compatible = "qcom,pm8937", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8941", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8950", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8994", .data = N_USIDS(2) },
diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c
index f62422740de2..6ff84b2600c5 100644
--- a/drivers/mfd/rave-sp.c
+++ b/drivers/mfd/rave-sp.c
@@ -471,17 +471,17 @@ static void rave_sp_receive_frame(struct rave_sp *sp,
rave_sp_receive_reply(sp, data, length);
}
-static int rave_sp_receive_buf(struct serdev_device *serdev,
- const unsigned char *buf, size_t size)
+static ssize_t rave_sp_receive_buf(struct serdev_device *serdev,
+ const u8 *buf, size_t size)
{
struct device *dev = &serdev->dev;
struct rave_sp *sp = dev_get_drvdata(dev);
struct rave_sp_deframer *deframer = &sp->deframer;
- const unsigned char *src = buf;
- const unsigned char *end = buf + size;
+ const u8 *src = buf;
+ const u8 *end = buf + size;
while (src < end) {
- const unsigned char byte = *src++;
+ const u8 byte = *src++;
switch (deframer->state) {
case RAVE_SP_EXPECT_SOF:
diff --git a/drivers/mfd/rk8xx-core.c b/drivers/mfd/rk8xx-core.c
index c47164a3ec1d..b1ffc3b9e2be 100644
--- a/drivers/mfd/rk8xx-core.c
+++ b/drivers/mfd/rk8xx-core.c
@@ -53,76 +53,68 @@ static const struct resource rk817_charger_resources[] = {
};
static const struct mfd_cell rk805s[] = {
- { .name = "rk808-clkout", .id = PLATFORM_DEVID_NONE, },
- { .name = "rk808-regulator", .id = PLATFORM_DEVID_NONE, },
- { .name = "rk805-pinctrl", .id = PLATFORM_DEVID_NONE, },
+ { .name = "rk808-clkout", },
+ { .name = "rk808-regulator", },
+ { .name = "rk805-pinctrl", },
{
.name = "rk808-rtc",
.num_resources = ARRAY_SIZE(rtc_resources),
.resources = &rtc_resources[0],
- .id = PLATFORM_DEVID_NONE,
},
{ .name = "rk805-pwrkey",
.num_resources = ARRAY_SIZE(rk805_key_resources),
.resources = &rk805_key_resources[0],
- .id = PLATFORM_DEVID_NONE,
},
};
static const struct mfd_cell rk806s[] = {
- { .name = "rk805-pinctrl", .id = PLATFORM_DEVID_AUTO, },
- { .name = "rk808-regulator", .id = PLATFORM_DEVID_AUTO, },
+ { .name = "rk805-pinctrl", },
+ { .name = "rk808-regulator", },
{
.name = "rk805-pwrkey",
.resources = rk806_pwrkey_resources,
.num_resources = ARRAY_SIZE(rk806_pwrkey_resources),
- .id = PLATFORM_DEVID_AUTO,
},
};
static const struct mfd_cell rk808s[] = {
- { .name = "rk808-clkout", .id = PLATFORM_DEVID_NONE, },
- { .name = "rk808-regulator", .id = PLATFORM_DEVID_NONE, },
+ { .name = "rk808-clkout", },
+ { .name = "rk808-regulator", },
{
.name = "rk808-rtc",
.num_resources = ARRAY_SIZE(rtc_resources),
.resources = rtc_resources,
- .id = PLATFORM_DEVID_NONE,
},
};
static const struct mfd_cell rk817s[] = {
- { .name = "rk808-clkout", .id = PLATFORM_DEVID_NONE, },
- { .name = "rk808-regulator", .id = PLATFORM_DEVID_NONE, },
+ { .name = "rk808-clkout", },
+ { .name = "rk808-regulator", },
{
.name = "rk805-pwrkey",
.num_resources = ARRAY_SIZE(rk817_pwrkey_resources),
.resources = &rk817_pwrkey_resources[0],
- .id = PLATFORM_DEVID_NONE,
},
{
.name = "rk808-rtc",
.num_resources = ARRAY_SIZE(rk817_rtc_resources),
.resources = &rk817_rtc_resources[0],
- .id = PLATFORM_DEVID_NONE,
},
- { .name = "rk817-codec", .id = PLATFORM_DEVID_NONE, },
+ { .name = "rk817-codec", },
{
.name = "rk817-charger",
.num_resources = ARRAY_SIZE(rk817_charger_resources),
.resources = &rk817_charger_resources[0],
- .id = PLATFORM_DEVID_NONE,
},
};
static const struct mfd_cell rk818s[] = {
- { .name = "rk808-clkout", .id = PLATFORM_DEVID_NONE, },
- { .name = "rk808-regulator", .id = PLATFORM_DEVID_NONE, },
+ { .name = "rk808-clkout", },
+ { .name = "rk808-regulator", },
{
.name = "rk808-rtc",
.num_resources = ARRAY_SIZE(rtc_resources),
.resources = rtc_resources,
- .id = PLATFORM_DEVID_NONE,
},
};
@@ -684,7 +676,7 @@ int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap
pre_init_reg[i].addr);
}
- ret = devm_mfd_add_devices(dev, 0, cells, nr_cells, NULL, 0,
+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, nr_cells, NULL, 0,
regmap_irq_get_domain(rk808->irq_data));
if (ret)
return dev_err_probe(dev, ret, "failed to add MFD devices\n");
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 28027982cf69..b3592982a83b 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -1667,7 +1667,7 @@ static void sm501_pci_remove(struct pci_dev *dev)
pci_disable_device(dev);
}
-static int sm501_plat_remove(struct platform_device *dev)
+static void sm501_plat_remove(struct platform_device *dev)
{
struct sm501_devdata *sm = platform_get_drvdata(dev);
@@ -1675,8 +1675,6 @@ static int sm501_plat_remove(struct platform_device *dev)
iounmap(sm->regs);
release_mem_region(sm->io_res->start, 0x100);
-
- return 0;
}
static const struct pci_device_id sm501_pci_tbl[] = {
@@ -1707,7 +1705,7 @@ static struct platform_driver sm501_plat_driver = {
.of_match_table = of_sm501_match_tbl,
},
.probe = sm501_plat_probe,
- .remove = sm501_plat_remove,
+ .remove_new = sm501_plat_remove,
.suspend = pm_sleep_ptr(sm501_plat_suspend),
.resume = pm_sleep_ptr(sm501_plat_resume),
};
diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c
index a656a1c186a8..9fd13d88950c 100644
--- a/drivers/mfd/stm32-timers.c
+++ b/drivers/mfd/stm32-timers.c
@@ -306,7 +306,7 @@ static int stm32_timers_probe(struct platform_device *pdev)
return ret;
}
-static int stm32_timers_remove(struct platform_device *pdev)
+static void stm32_timers_remove(struct platform_device *pdev)
{
struct stm32_timers *ddata = platform_get_drvdata(pdev);
@@ -316,8 +316,6 @@ static int stm32_timers_remove(struct platform_device *pdev)
*/
of_platform_depopulate(&pdev->dev);
stm32_timers_dma_remove(&pdev->dev, ddata);
-
- return 0;
}
static const struct of_device_id stm32_timers_of_match[] = {
@@ -328,7 +326,7 @@ MODULE_DEVICE_TABLE(of, stm32_timers_of_match);
static struct platform_driver stm32_timers_driver = {
.probe = stm32_timers_probe,
- .remove = stm32_timers_remove,
+ .remove_new = stm32_timers_remove,
.driver = {
.name = "stm32-timers",
.of_match_table = stm32_timers_of_match,
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index 57b29c325131..c9550368d9ea 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -105,6 +105,10 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res)
}
syscon_config.name = kasprintf(GFP_KERNEL, "%pOFn@%pa", np, &res.start);
+ if (!syscon_config.name) {
+ ret = -ENOMEM;
+ goto err_regmap;
+ }
syscon_config.reg_stride = reg_io_width;
syscon_config.val_bits = reg_io_width * 8;
syscon_config.max_register = resource_size(&res) - reg_io_width;
diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c
index b88eb70c17b3..4bbd542d753e 100644
--- a/drivers/mfd/ti_am335x_tscadc.c
+++ b/drivers/mfd/ti_am335x_tscadc.c
@@ -298,7 +298,7 @@ err_disable_clk:
return err;
}
-static int ti_tscadc_remove(struct platform_device *pdev)
+static void ti_tscadc_remove(struct platform_device *pdev)
{
struct ti_tscadc_dev *tscadc = platform_get_drvdata(pdev);
@@ -308,8 +308,6 @@ static int ti_tscadc_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
mfd_remove_devices(tscadc->dev);
-
- return 0;
}
static int __maybe_unused ti_tscadc_can_wakeup(struct device *dev, void *data)
@@ -381,7 +379,7 @@ static struct platform_driver ti_tscadc_driver = {
.of_match_table = ti_tscadc_dt_ids,
},
.probe = ti_tscadc_probe,
- .remove = ti_tscadc_remove,
+ .remove_new = ti_tscadc_remove,
};
diff --git a/drivers/mfd/tps65086.c b/drivers/mfd/tps65086.c
index 152179ee11ca..fdce81b33f60 100644
--- a/drivers/mfd/tps65086.c
+++ b/drivers/mfd/tps65086.c
@@ -36,6 +36,7 @@ static const struct regmap_config tps65086_regmap_config = {
.val_bits = 8,
.cache_type = REGCACHE_MAPLE,
.volatile_table = &tps65086_volatile_table,
+ .max_register = TPS65086_OC_STATUS,
};
static const struct regmap_irq tps65086_irqs[] = {
diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c
index 8f4210075913..f206a9c50e9d 100644
--- a/drivers/mfd/tps65911-comparator.c
+++ b/drivers/mfd/tps65911-comparator.c
@@ -140,15 +140,13 @@ static int tps65911_comparator_probe(struct platform_device *pdev)
return ret;
}
-static int tps65911_comparator_remove(struct platform_device *pdev)
+static void tps65911_comparator_remove(struct platform_device *pdev)
{
struct tps65910 *tps65910;
tps65910 = dev_get_drvdata(pdev->dev.parent);
device_remove_file(&pdev->dev, &dev_attr_comp2_threshold);
device_remove_file(&pdev->dev, &dev_attr_comp1_threshold);
-
- return 0;
}
static struct platform_driver tps65911_comparator_driver = {
@@ -156,7 +154,7 @@ static struct platform_driver tps65911_comparator_driver = {
.name = "tps65911-comparator",
},
.probe = tps65911_comparator_probe,
- .remove = tps65911_comparator_remove,
+ .remove_new = tps65911_comparator_remove,
};
static int __init tps65911_comparator_init(void)
diff --git a/drivers/mfd/tps6594-core.c b/drivers/mfd/tps6594-core.c
index 0fb9c5cf213a..783ee59901e8 100644
--- a/drivers/mfd/tps6594-core.c
+++ b/drivers/mfd/tps6594-core.c
@@ -433,6 +433,9 @@ int tps6594_device_init(struct tps6594 *tps, bool enable_crc)
tps6594_irq_chip.name = devm_kasprintf(dev, GFP_KERNEL, "%s-%ld-0x%02x",
dev->driver->name, tps->chip_id, tps->reg);
+ if (!tps6594_irq_chip.name)
+ return -ENOMEM;
+
ret = devm_regmap_add_irq_chip(dev, tps->regmap, tps->irq, IRQF_SHARED | IRQF_ONESHOT,
0, &tps6594_irq_chip, &tps->irq_data);
if (ret)
diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c
index 88002f8941e5..d436ddf661da 100644
--- a/drivers/mfd/twl4030-audio.c
+++ b/drivers/mfd/twl4030-audio.c
@@ -258,12 +258,10 @@ static int twl4030_audio_probe(struct platform_device *pdev)
return ret;
}
-static int twl4030_audio_remove(struct platform_device *pdev)
+static void twl4030_audio_remove(struct platform_device *pdev)
{
mfd_remove_devices(&pdev->dev);
twl4030_audio_dev = NULL;
-
- return 0;
}
static const struct of_device_id twl4030_audio_of_match[] = {
@@ -278,7 +276,7 @@ static struct platform_driver twl4030_audio_driver = {
.of_match_table = twl4030_audio_of_match,
},
.probe = twl4030_audio_probe,
- .remove = twl4030_audio_remove,
+ .remove_new = twl4030_audio_remove,
};
module_platform_driver(twl4030_audio_driver);
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index f9fce8408c2c..3c03681c124c 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -24,10 +24,10 @@
#include <linux/kthread.h>
#include <linux/mfd/twl.h>
#include <linux/platform_device.h>
-#include <linux/property.h>
#include <linux/suspend.h>
#include <linux/of.h>
#include <linux/irqdomain.h>
+#include <linux/of_device.h>
#include "twl-core.h"
@@ -368,10 +368,10 @@ int twl6030_init_irq(struct device *dev, int irq_num)
int nr_irqs;
int status;
u8 mask[3];
- const int *irq_tbl;
+ const struct of_device_id *of_id;
- irq_tbl = device_get_match_data(dev);
- if (!irq_tbl) {
+ of_id = of_match_device(twl6030_of_match, dev);
+ if (!of_id || !of_id->data) {
dev_err(dev, "Unknown TWL device model\n");
return -EINVAL;
}
@@ -409,7 +409,7 @@ int twl6030_init_irq(struct device *dev, int irq_num)
twl6030_irq->pm_nb.notifier_call = twl6030_irq_pm_notifier;
atomic_set(&twl6030_irq->wakeirqs, 0);
- twl6030_irq->irq_mapping_tbl = irq_tbl;
+ twl6030_irq->irq_mapping_tbl = of_id->data;
twl6030_irq->irq_domain =
irq_domain_add_linear(node, nr_irqs,
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index f37c4b8380ae..4fb291f0bf7c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -562,6 +562,18 @@ config TPS6594_PFSM
This driver can also be built as a module. If so, the module
will be called tps6594-pfsm.
+config NSM
+ tristate "Nitro (Enclaves) Security Module support"
+ depends on VIRTIO
+ select HW_RANDOM
+ help
+ This driver provides support for the Nitro Security Module
+ in AWS EC2 Nitro based Enclaves. The driver exposes a /dev/nsm
+ device user space can use to communicate with the hypervisor.
+
+ To compile this driver as a module, choose M here.
+ The module will be called nsm.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f2a4d1ff65d4..ea6ea5bbbc9c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -67,3 +67,4 @@ obj-$(CONFIG_TMR_MANAGER) += xilinx_tmr_manager.o
obj-$(CONFIG_TMR_INJECT) += xilinx_tmr_inject.o
obj-$(CONFIG_TPS6594_ESM) += tps6594-esm.o
obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o
+obj-$(CONFIG_NSM) += nsm.o
diff --git a/drivers/misc/bcm-vk/bcm_vk_tty.c b/drivers/misc/bcm-vk/bcm_vk_tty.c
index 2bce835ca43e..59bab76ff0a9 100644
--- a/drivers/misc/bcm-vk/bcm_vk_tty.c
+++ b/drivers/misc/bcm-vk/bcm_vk_tty.c
@@ -64,9 +64,9 @@ static void bcm_vk_tty_wq_handler(struct work_struct *work)
struct bcm_vk_tty *vktty;
int card_status;
int count;
- unsigned char c;
int i;
int wr;
+ u8 c;
card_status = vkread32(vk, BAR_0, BAR_CARD_STATUS);
if (BCM_VK_INTF_IS_DOWN(card_status))
@@ -192,7 +192,7 @@ static ssize_t bcm_vk_tty_write(struct tty_struct *tty, const u8 *buffer,
int index;
struct bcm_vk *vk;
struct bcm_vk_tty *vktty;
- int i;
+ size_t i;
index = tty->index;
vk = dev_get_drvdata(tty->dev);
diff --git a/drivers/misc/cardreader/Makefile b/drivers/misc/cardreader/Makefile
index 895128475d83..1e1bca6b0b22 100644
--- a/drivers/misc/cardreader/Makefile
+++ b/drivers/misc/cardreader/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_MISC_ALCOR_PCI) += alcor_pci.o
obj-$(CONFIG_MISC_RTSX_PCI) += rtsx_pci.o
-rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o rts5260.o rts5261.o rts5228.o
+rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o rts5260.o rts5261.o rts5228.o rts5264.o
obj-$(CONFIG_MISC_RTSX_USB) += rtsx_usb.o
diff --git a/drivers/misc/cardreader/rts5264.c b/drivers/misc/cardreader/rts5264.c
new file mode 100644
index 000000000000..8be4ed7d9d47
--- /dev/null
+++ b/drivers/misc/cardreader/rts5264.c
@@ -0,0 +1,886 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * Author:
+ * Ricky Wu <[email protected]>
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/rtsx_pci.h>
+
+#include "rts5264.h"
+#include "rtsx_pcr.h"
+
+static u8 rts5264_get_ic_version(struct rtsx_pcr *pcr)
+{
+ u8 val;
+
+ rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
+ return val & 0x0F;
+}
+
+static void rts5264_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
+{
+ u8 driving_3v3[4][3] = {
+ {0x88, 0x88, 0x88},
+ {0x77, 0x77, 0x77},
+ {0x99, 0x99, 0x99},
+ {0x66, 0x66, 0x66},
+ };
+ u8 driving_1v8[4][3] = {
+ {0x99, 0x99, 0x99},
+ {0x77, 0x77, 0x77},
+ {0xBB, 0xBB, 0xBB},
+ {0x65, 0x65, 0x65},
+ };
+ u8 (*driving)[3], drive_sel;
+
+ if (voltage == OUTPUT_3V3) {
+ driving = driving_3v3;
+ drive_sel = pcr->sd30_drive_sel_3v3;
+ } else {
+ driving = driving_1v8;
+ drive_sel = pcr->sd30_drive_sel_1v8;
+ }
+
+ rtsx_pci_write_register(pcr, SD30_CLK_DRIVE_SEL,
+ 0xFF, driving[drive_sel][0]);
+ rtsx_pci_write_register(pcr, SD30_CMD_DRIVE_SEL,
+ 0xFF, driving[drive_sel][1]);
+ rtsx_pci_write_register(pcr, SD30_DAT_DRIVE_SEL,
+ 0xFF, driving[drive_sel][2]);
+}
+
+static void rts5264_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime)
+{
+ /* Set relink_time to 0 */
+ rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
+ rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0);
+ rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
+ RELINK_TIME_MASK, 0);
+
+ if (pm_state == HOST_ENTER_S3)
+ rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3,
+ D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
+
+ if (!runtime) {
+ rtsx_pci_write_register(pcr, RTS5264_AUTOLOAD_CFG1,
+ CD_RESUME_EN_MASK, 0);
+ rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x00);
+ rtsx_pci_write_register(pcr, RTS5264_REG_PME_FORCE_CTL,
+ FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
+ } else {
+ rtsx_pci_write_register(pcr, RTS5264_REG_PME_FORCE_CTL,
+ FORCE_PM_CONTROL | FORCE_PM_VALUE, 0);
+ rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x01);
+ rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3,
+ D3_DELINK_MODE_EN, 0);
+ rtsx_pci_write_register(pcr, RTS5264_FW_CTL,
+ RTS5264_INFORM_RTD3_COLD, RTS5264_INFORM_RTD3_COLD);
+ rtsx_pci_write_register(pcr, RTS5264_AUTOLOAD_CFG4,
+ RTS5264_FORCE_PRSNT_LOW, RTS5264_FORCE_PRSNT_LOW);
+ }
+
+ rtsx_pci_write_register(pcr, RTS5264_REG_FPDCTL,
+ SSC_POWER_DOWN, SSC_POWER_DOWN);
+}
+
+static int rts5264_enable_auto_blink(struct rtsx_pcr *pcr)
+{
+ return rtsx_pci_write_register(pcr, OLT_LED_CTL,
+ LED_SHINE_MASK, LED_SHINE_EN);
+}
+
+static int rts5264_disable_auto_blink(struct rtsx_pcr *pcr)
+{
+ return rtsx_pci_write_register(pcr, OLT_LED_CTL,
+ LED_SHINE_MASK, LED_SHINE_DISABLE);
+}
+
+static int rts5264_turn_on_led(struct rtsx_pcr *pcr)
+{
+ return rtsx_pci_write_register(pcr, GPIO_CTL,
+ 0x02, 0x02);
+}
+
+static int rts5264_turn_off_led(struct rtsx_pcr *pcr)
+{
+ return rtsx_pci_write_register(pcr, GPIO_CTL,
+ 0x02, 0x00);
+}
+
+/* SD Pull Control Enable:
+ * SD_DAT[3:0] ==> pull up
+ * SD_CD ==> pull up
+ * SD_WP ==> pull up
+ * SD_CMD ==> pull up
+ * SD_CLK ==> pull down
+ */
+static const u32 rts5264_sd_pull_ctl_enable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+ RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
+ 0,
+};
+
+/* SD Pull Control Disable:
+ * SD_DAT[3:0] ==> pull down
+ * SD_CD ==> pull up
+ * SD_WP ==> pull down
+ * SD_CMD ==> pull down
+ * SD_CLK ==> pull down
+ */
+static const u32 rts5264_sd_pull_ctl_disable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+ RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
+ 0,
+};
+
+static int rts5264_sd_set_sample_push_timing_sd30(struct rtsx_pcr *pcr)
+{
+ rtsx_pci_write_register(pcr, SD_CFG1, SD_MODE_SELECT_MASK
+ | SD_ASYNC_FIFO_NOT_RST, SD_30_MODE | SD_ASYNC_FIFO_NOT_RST);
+ rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, CLK_LOW_FREQ);
+ rtsx_pci_write_register(pcr, CARD_CLK_SOURCE, 0xFF,
+ CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
+ rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0);
+
+ return 0;
+}
+
+static int rts5264_card_power_on(struct rtsx_pcr *pcr, int card)
+{
+ struct rtsx_cr_option *option = &pcr->option;
+
+ if (option->ocp_en)
+ rtsx_pci_enable_ocp(pcr);
+
+ rtsx_pci_write_register(pcr, REG_CRC_DUMMY_0,
+ CFG_SD_POW_AUTO_PD, CFG_SD_POW_AUTO_PD);
+
+ rtsx_pci_write_register(pcr, RTS5264_LDO1_CFG1,
+ RTS5264_LDO1_TUNE_MASK, RTS5264_LDO1_33);
+ rtsx_pci_write_register(pcr, RTS5264_LDO1233318_POW_CTL,
+ RTS5264_LDO1_POWERON, RTS5264_LDO1_POWERON);
+ rtsx_pci_write_register(pcr, RTS5264_LDO1233318_POW_CTL,
+ RTS5264_LDO3318_POWERON, RTS5264_LDO3318_POWERON);
+
+ msleep(20);
+
+ rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN);
+
+ /* Initialize SD_CFG1 register */
+ rtsx_pci_write_register(pcr, SD_CFG1, 0xFF,
+ SD_CLK_DIVIDE_128 | SD_20_MODE | SD_BUS_WIDTH_1BIT);
+ rtsx_pci_write_register(pcr, SD_SAMPLE_POINT_CTL,
+ 0xFF, SD20_RX_POS_EDGE);
+ rtsx_pci_write_register(pcr, SD_PUSH_POINT_CTL, 0xFF, 0);
+ rtsx_pci_write_register(pcr, CARD_STOP, SD_STOP | SD_CLR_ERR,
+ SD_STOP | SD_CLR_ERR);
+
+ /* Reset SD_CFG3 register */
+ rtsx_pci_write_register(pcr, SD_CFG3, SD30_CLK_END_EN, 0);
+ rtsx_pci_write_register(pcr, REG_SD_STOP_SDCLK_CFG,
+ SD30_CLK_STOP_CFG_EN | SD30_CLK_STOP_CFG1 |
+ SD30_CLK_STOP_CFG0, 0);
+
+ if (pcr->extra_caps & EXTRA_CAPS_SD_SDR50 ||
+ pcr->extra_caps & EXTRA_CAPS_SD_SDR104)
+ rts5264_sd_set_sample_push_timing_sd30(pcr);
+
+ return 0;
+}
+
+static int rts5264_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+ rtsx_pci_write_register(pcr, RTS5264_CARD_PWR_CTL,
+ RTS5264_PUPDC, RTS5264_PUPDC);
+
+ switch (voltage) {
+ case OUTPUT_3V3:
+ rtsx_pci_write_register(pcr, RTS5264_LDO1233318_POW_CTL,
+ RTS5264_TUNE_REF_LDO3318, RTS5264_TUNE_REF_LDO3318);
+ rtsx_pci_write_register(pcr, RTS5264_DV3318_CFG,
+ RTS5264_DV3318_TUNE_MASK, RTS5264_DV3318_33);
+ rtsx_pci_write_register(pcr, SD_PAD_CTL,
+ SD_IO_USING_1V8, 0);
+ break;
+ case OUTPUT_1V8:
+ rtsx_pci_write_register(pcr, RTS5264_LDO1233318_POW_CTL,
+ RTS5264_TUNE_REF_LDO3318, RTS5264_TUNE_REF_LDO3318_DFT);
+ rtsx_pci_write_register(pcr, RTS5264_DV3318_CFG,
+ RTS5264_DV3318_TUNE_MASK, RTS5264_DV3318_18);
+ rtsx_pci_write_register(pcr, SD_PAD_CTL,
+ SD_IO_USING_1V8, SD_IO_USING_1V8);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set pad drive */
+ rts5264_fill_driving(pcr, voltage);
+
+ return 0;
+}
+
+static void rts5264_stop_cmd(struct rtsx_pcr *pcr)
+{
+ rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD);
+ rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA);
+ rtsx_pci_write_register(pcr, DMACTL, DMA_RST, DMA_RST);
+ rtsx_pci_write_register(pcr, RBCTL, RB_FLUSH, RB_FLUSH);
+}
+
+static void rts5264_card_before_power_off(struct rtsx_pcr *pcr)
+{
+ rts5264_stop_cmd(pcr);
+ rts5264_switch_output_voltage(pcr, OUTPUT_3V3);
+}
+
+static int rts5264_card_power_off(struct rtsx_pcr *pcr, int card)
+{
+ int err = 0;
+
+ rts5264_card_before_power_off(pcr);
+ err = rtsx_pci_write_register(pcr, RTS5264_LDO1233318_POW_CTL,
+ RTS5264_LDO_POWERON_MASK, 0);
+
+ rtsx_pci_write_register(pcr, REG_CRC_DUMMY_0,
+ CFG_SD_POW_AUTO_PD, 0);
+ if (pcr->option.ocp_en)
+ rtsx_pci_disable_ocp(pcr);
+
+ return err;
+}
+
+static void rts5264_enable_ocp(struct rtsx_pcr *pcr)
+{
+ u8 mask = 0;
+ u8 val = 0;
+
+ rtsx_pci_write_register(pcr, RTS5264_LDO1_CFG0,
+ RTS5264_LDO1_OCP_EN | RTS5264_LDO1_OCP_LMT_EN,
+ RTS5264_LDO1_OCP_EN | RTS5264_LDO1_OCP_LMT_EN);
+ rtsx_pci_write_register(pcr, RTS5264_LDO2_CFG0,
+ RTS5264_LDO2_OCP_EN | RTS5264_LDO2_OCP_LMT_EN,
+ RTS5264_LDO2_OCP_EN | RTS5264_LDO2_OCP_LMT_EN);
+ rtsx_pci_write_register(pcr, RTS5264_LDO3_CFG0,
+ RTS5264_LDO3_OCP_EN | RTS5264_LDO3_OCP_LMT_EN,
+ RTS5264_LDO3_OCP_EN | RTS5264_LDO3_OCP_LMT_EN);
+ rtsx_pci_write_register(pcr, RTS5264_OVP_DET,
+ RTS5264_POW_VDET, RTS5264_POW_VDET);
+
+ mask = SD_OCP_INT_EN | SD_DETECT_EN;
+ mask |= SDVIO_OCP_INT_EN | SDVIO_DETECT_EN;
+ val = mask;
+ rtsx_pci_write_register(pcr, REG_OCPCTL, mask, val);
+
+ mask = SD_VDD3_OCP_INT_EN | SD_VDD3_DETECT_EN;
+ val = mask;
+ rtsx_pci_write_register(pcr, RTS5264_OCP_VDD3_CTL, mask, val);
+
+ mask = RTS5264_OVP_INT_EN | RTS5264_OVP_DETECT_EN;
+ val = mask;
+ rtsx_pci_write_register(pcr, RTS5264_OVP_CTL, mask, val);
+}
+
+static void rts5264_disable_ocp(struct rtsx_pcr *pcr)
+{
+ u8 mask = 0;
+
+ mask = SD_OCP_INT_EN | SD_DETECT_EN;
+ mask |= SDVIO_OCP_INT_EN | SDVIO_DETECT_EN;
+ rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
+
+ mask = SD_VDD3_OCP_INT_EN | SD_VDD3_DETECT_EN;
+ rtsx_pci_write_register(pcr, RTS5264_OCP_VDD3_CTL, mask, 0);
+
+ mask = RTS5264_OVP_INT_EN | RTS5264_OVP_DETECT_EN;
+ rtsx_pci_write_register(pcr, RTS5264_OVP_CTL, mask, 0);
+
+ rtsx_pci_write_register(pcr, RTS5264_LDO1_CFG0,
+ RTS5264_LDO1_OCP_EN | RTS5264_LDO1_OCP_LMT_EN, 0);
+ rtsx_pci_write_register(pcr, RTS5264_LDO2_CFG0,
+ RTS5264_LDO2_OCP_EN | RTS5264_LDO2_OCP_LMT_EN, 0);
+ rtsx_pci_write_register(pcr, RTS5264_LDO3_CFG0,
+ RTS5264_LDO3_OCP_EN | RTS5264_LDO3_OCP_LMT_EN, 0);
+ rtsx_pci_write_register(pcr, RTS5264_OVP_DET, RTS5264_POW_VDET, 0);
+}
+
+static void rts5264_init_ocp(struct rtsx_pcr *pcr)
+{
+ struct rtsx_cr_option *option = &pcr->option;
+
+ if (option->ocp_en) {
+ u8 mask, val;
+
+ rtsx_pci_write_register(pcr, RTS5264_LDO1_CFG0,
+ RTS5264_LDO1_OCP_THD_MASK, option->sd_800mA_ocp_thd);
+ rtsx_pci_write_register(pcr, RTS5264_LDO1_CFG0,
+ RTS5264_LDO1_OCP_LMT_THD_MASK,
+ RTS5264_LDO1_LMT_THD_2000);
+
+ rtsx_pci_write_register(pcr, RTS5264_LDO2_CFG0,
+ RTS5264_LDO2_OCP_THD_MASK, RTS5264_LDO2_OCP_THD_950);
+ rtsx_pci_write_register(pcr, RTS5264_LDO2_CFG0,
+ RTS5264_LDO2_OCP_LMT_THD_MASK,
+ RTS5264_LDO2_LMT_THD_2000);
+
+ rtsx_pci_write_register(pcr, RTS5264_LDO3_CFG0,
+ RTS5264_LDO3_OCP_THD_MASK, RTS5264_LDO3_OCP_THD_710);
+ rtsx_pci_write_register(pcr, RTS5264_LDO3_CFG0,
+ RTS5264_LDO3_OCP_LMT_THD_MASK,
+ RTS5264_LDO3_LMT_THD_1500);
+
+ rtsx_pci_write_register(pcr, RTS5264_OVP_DET,
+ RTS5264_TUNE_VROV_MASK, RTS5264_TUNE_VROV_1V6);
+
+ mask = SD_OCP_GLITCH_MASK | SDVIO_OCP_GLITCH_MASK;
+ val = pcr->hw_param.ocp_glitch;
+ rtsx_pci_write_register(pcr, REG_OCPGLITCH, mask, val);
+
+ } else {
+ rtsx_pci_write_register(pcr, RTS5264_LDO1_CFG0,
+ RTS5264_LDO1_OCP_EN | RTS5264_LDO1_OCP_LMT_EN, 0);
+ rtsx_pci_write_register(pcr, RTS5264_LDO2_CFG0,
+ RTS5264_LDO2_OCP_EN | RTS5264_LDO2_OCP_LMT_EN, 0);
+ rtsx_pci_write_register(pcr, RTS5264_LDO3_CFG0,
+ RTS5264_LDO3_OCP_EN | RTS5264_LDO3_OCP_LMT_EN, 0);
+ rtsx_pci_write_register(pcr, RTS5264_OVP_DET,
+ RTS5264_POW_VDET, 0);
+ }
+}
+
+static int rts5264_get_ocpstat2(struct rtsx_pcr *pcr, u8 *val)
+{
+ return rtsx_pci_read_register(pcr, RTS5264_OCP_VDD3_STS, val);
+}
+
+static int rts5264_get_ovpstat(struct rtsx_pcr *pcr, u8 *val)
+{
+ return rtsx_pci_read_register(pcr, RTS5264_OVP_STS, val);
+}
+
+static void rts5264_clear_ocpstat(struct rtsx_pcr *pcr)
+{
+ u8 mask = 0;
+ u8 val = 0;
+
+ mask = SD_OCP_INT_CLR | SD_OC_CLR;
+ mask |= SDVIO_OCP_INT_CLR | SDVIO_OC_CLR;
+ val = mask;
+ rtsx_pci_write_register(pcr, REG_OCPCTL, mask, val);
+ rtsx_pci_write_register(pcr, RTS5264_OCP_VDD3_CTL,
+ SD_VDD3_OCP_INT_CLR | SD_VDD3_OC_CLR,
+ SD_VDD3_OCP_INT_CLR | SD_VDD3_OC_CLR);
+ rtsx_pci_write_register(pcr, RTS5264_OVP_CTL,
+ RTS5264_OVP_INT_CLR | RTS5264_OVP_CLR,
+ RTS5264_OVP_INT_CLR | RTS5264_OVP_CLR);
+
+ udelay(1000);
+
+ rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
+ rtsx_pci_write_register(pcr, RTS5264_OCP_VDD3_CTL,
+ SD_VDD3_OCP_INT_CLR | SD_VDD3_OC_CLR, 0);
+ rtsx_pci_write_register(pcr, RTS5264_OVP_CTL,
+ RTS5264_OVP_INT_CLR | RTS5264_OVP_CLR, 0);
+}
+
+static void rts5264_process_ocp(struct rtsx_pcr *pcr)
+{
+ if (!pcr->option.ocp_en)
+ return;
+
+ rtsx_pci_get_ocpstat(pcr, &pcr->ocp_stat);
+ rts5264_get_ocpstat2(pcr, &pcr->ocp_stat2);
+ rts5264_get_ovpstat(pcr, &pcr->ovp_stat);
+
+ if ((pcr->ocp_stat & (SD_OC_NOW | SD_OC_EVER | SDVIO_OC_NOW | SDVIO_OC_EVER)) ||
+ (pcr->ocp_stat2 & (SD_VDD3_OC_NOW | SD_VDD3_OC_EVER)) ||
+ (pcr->ovp_stat & (RTS5264_OVP_NOW | RTS5264_OVP_EVER))) {
+ rts5264_clear_ocpstat(pcr);
+ rts5264_card_power_off(pcr, RTSX_SD_CARD);
+ rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0);
+ pcr->ocp_stat = 0;
+ pcr->ocp_stat2 = 0;
+ pcr->ovp_stat = 0;
+ }
+}
+
+static void rts5264_init_from_hw(struct rtsx_pcr *pcr)
+{
+ struct pci_dev *pdev = pcr->pci;
+ u32 lval1, lval2, i;
+ u16 setting_reg1, setting_reg2;
+ u8 valid, efuse_valid, tmp;
+
+ rtsx_pci_write_register(pcr, RTS5264_REG_PME_FORCE_CTL,
+ REG_EFUSE_POR | REG_EFUSE_POWER_MASK,
+ REG_EFUSE_POR | REG_EFUSE_POWERON);
+ udelay(1);
+ rtsx_pci_write_register(pcr, RTS5264_EFUSE_ADDR,
+ RTS5264_EFUSE_ADDR_MASK, 0x00);
+ rtsx_pci_write_register(pcr, RTS5264_EFUSE_CTL,
+ RTS5264_EFUSE_ENABLE | RTS5264_EFUSE_MODE_MASK,
+ RTS5264_EFUSE_ENABLE);
+
+ /* Wait transfer end */
+ for (i = 0; i < MAX_RW_REG_CNT; i++) {
+ rtsx_pci_read_register(pcr, RTS5264_EFUSE_CTL, &tmp);
+ if ((tmp & 0x80) == 0)
+ break;
+ }
+ rtsx_pci_read_register(pcr, RTS5264_EFUSE_READ_DATA, &tmp);
+ efuse_valid = ((tmp & 0x0C) >> 2);
+ pcr_dbg(pcr, "Load efuse valid: 0x%x\n", efuse_valid);
+
+ pci_read_config_dword(pdev, PCR_SETTING_REG2, &lval2);
+ pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, lval2);
+ /* 0x816 */
+ valid = (u8)((lval2 >> 16) & 0x03);
+
+ rtsx_pci_write_register(pcr, RTS5264_REG_PME_FORCE_CTL,
+ REG_EFUSE_POR, 0);
+ pcr_dbg(pcr, "Disable efuse por!\n");
+
+ if (efuse_valid == 2 || efuse_valid == 3) {
+ if (valid == 3) {
+ /* Bypass efuse */
+ setting_reg1 = PCR_SETTING_REG1;
+ setting_reg2 = PCR_SETTING_REG2;
+ } else {
+ /* Use efuse data */
+ setting_reg1 = PCR_SETTING_REG4;
+ setting_reg2 = PCR_SETTING_REG5;
+ }
+ } else if (efuse_valid == 0) {
+ // default
+ setting_reg1 = PCR_SETTING_REG1;
+ setting_reg2 = PCR_SETTING_REG2;
+ } else {
+ return;
+ }
+
+ pci_read_config_dword(pdev, setting_reg2, &lval2);
+ pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", setting_reg2, lval2);
+
+ if (!rts5264_vendor_setting_valid(lval2)) {
+ pcr_dbg(pcr, "skip fetch vendor setting\n");
+ return;
+ }
+
+ pcr->rtd3_en = rts5264_reg_to_rtd3(lval2);
+
+ if (rts5264_reg_check_reverse_socket(lval2))
+ pcr->flags |= PCR_REVERSE_SOCKET;
+
+ pci_read_config_dword(pdev, setting_reg1, &lval1);
+ pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", setting_reg1, lval1);
+
+ pcr->aspm_en = rts5264_reg_to_aspm(lval1);
+ pcr->sd30_drive_sel_1v8 = rts5264_reg_to_sd30_drive_sel_1v8(lval1);
+ pcr->sd30_drive_sel_3v3 = rts5264_reg_to_sd30_drive_sel_3v3(lval1);
+
+ if (setting_reg1 == PCR_SETTING_REG1) {
+ /* store setting */
+ rtsx_pci_write_register(pcr, 0xFF0C, 0xFF, (u8)(lval1 & 0xFF));
+ rtsx_pci_write_register(pcr, 0xFF0D, 0xFF, (u8)((lval1 >> 8) & 0xFF));
+ rtsx_pci_write_register(pcr, 0xFF0E, 0xFF, (u8)((lval1 >> 16) & 0xFF));
+ rtsx_pci_write_register(pcr, 0xFF0F, 0xFF, (u8)((lval1 >> 24) & 0xFF));
+ rtsx_pci_write_register(pcr, 0xFF10, 0xFF, (u8)(lval2 & 0xFF));
+ rtsx_pci_write_register(pcr, 0xFF11, 0xFF, (u8)((lval2 >> 8) & 0xFF));
+ rtsx_pci_write_register(pcr, 0xFF12, 0xFF, (u8)((lval2 >> 16) & 0xFF));
+
+ pci_write_config_dword(pdev, PCR_SETTING_REG4, lval1);
+ lval2 = lval2 & 0x00FFFFFF;
+ pci_write_config_dword(pdev, PCR_SETTING_REG5, lval2);
+ }
+}
+
+static void rts5264_init_from_cfg(struct rtsx_pcr *pcr)
+{
+ struct rtsx_cr_option *option = &pcr->option;
+
+ if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
+ | PM_L1_1_EN | PM_L1_2_EN))
+ rtsx_pci_disable_oobs_polling(pcr);
+ else
+ rtsx_pci_enable_oobs_polling(pcr);
+
+ rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0xFF, 0);
+
+ if (option->ltr_en) {
+ if (option->ltr_enabled)
+ rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
+ }
+}
+
+static int rts5264_extra_init_hw(struct rtsx_pcr *pcr)
+{
+ struct rtsx_cr_option *option = &pcr->option;
+
+ rtsx_pci_write_register(pcr, RTS5264_AUTOLOAD_CFG1,
+ CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
+ rtsx_pci_write_register(pcr, REG_VREF, PWD_SUSPND_EN, PWD_SUSPND_EN);
+
+ rts5264_init_from_cfg(pcr);
+ rts5264_init_from_hw(pcr);
+
+ /* power off efuse */
+ rtsx_pci_write_register(pcr, RTS5264_REG_PME_FORCE_CTL,
+ REG_EFUSE_POWER_MASK, REG_EFUSE_POWEROFF);
+ rtsx_pci_write_register(pcr, RTS5264_AUTOLOAD_CFG2,
+ RTS5264_CHIP_RST_N_SEL, 0);
+ rtsx_pci_write_register(pcr, RTS5264_REG_LDO12_CFG,
+ RTS5264_LDO12_SR_MASK, RTS5264_LDO12_SR_0_0_MS);
+ rtsx_pci_write_register(pcr, CDGW, 0xFF, 0x01);
+ rtsx_pci_write_register(pcr, RTS5264_CKMUX_MBIAS_PWR,
+ RTS5264_POW_CKMUX, RTS5264_POW_CKMUX);
+ rtsx_pci_write_register(pcr, RTS5264_CMD_OE_START_EARLY,
+ RTS5264_CMD_OE_EARLY_EN | RTS5264_CMD_OE_EARLY_CYCLE_MASK,
+ RTS5264_CMD_OE_EARLY_EN);
+ rtsx_pci_write_register(pcr, RTS5264_DAT_OE_START_EARLY,
+ RTS5264_DAT_OE_EARLY_EN | RTS5264_DAT_OE_EARLY_CYCLE_MASK,
+ RTS5264_DAT_OE_EARLY_EN);
+ rtsx_pci_write_register(pcr, SSC_DIV_N_0, 0xFF, 0x5D);
+
+ rtsx_pci_write_register(pcr, RTS5264_PWR_CUT,
+ RTS5264_CFG_MEM_PD, RTS5264_CFG_MEM_PD);
+ rtsx_pci_write_register(pcr, L1SUB_CONFIG1,
+ AUX_CLK_ACTIVE_SEL_MASK, MAC_CKSW_DONE);
+ rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, 0);
+ rtsx_pci_write_register(pcr, RTS5264_AUTOLOAD_CFG4,
+ RTS5264_AUX_CLK_16M_EN, 0);
+
+ /* Release PRSNT# */
+ rtsx_pci_write_register(pcr, RTS5264_AUTOLOAD_CFG4,
+ RTS5264_FORCE_PRSNT_LOW, 0);
+ rtsx_pci_write_register(pcr, PCLK_CTL,
+ PCLK_MODE_SEL, PCLK_MODE_SEL);
+
+ /* LED shine disabled, set initial shine cycle period */
+ rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x0F, 0x02);
+
+ /* Configure driving */
+ rts5264_fill_driving(pcr, OUTPUT_3V3);
+
+ if (pcr->flags & PCR_REVERSE_SOCKET)
+ rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x30);
+ else
+ rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00);
+
+ /*
+ * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
+ * to drive low, and we forcibly request clock.
+ */
+ if (option->force_clkreq_0)
+ rtsx_pci_write_register(pcr, PETXCFG,
+ FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
+ else
+ rtsx_pci_write_register(pcr, PETXCFG,
+ FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
+
+ rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFF);
+ rtsx_pci_write_register(pcr, RBCTL, U_AUTO_DMA_EN_MASK, 0);
+ rtsx_pci_write_register(pcr, RTS5264_AUTOLOAD_CFG4,
+ RTS5264_F_HIGH_RC_MASK, RTS5264_F_HIGH_RC_400K);
+
+ if (pcr->rtd3_en) {
+ rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x00);
+ rtsx_pci_write_register(pcr, RTS5264_REG_PME_FORCE_CTL,
+ FORCE_PM_CONTROL | FORCE_PM_VALUE, 0);
+ } else {
+ rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x00);
+ rtsx_pci_write_register(pcr, RTS5264_REG_PME_FORCE_CTL,
+ FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
+ }
+ rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, D3_DELINK_MODE_EN, 0x00);
+
+ /* Clear Enter RTD3_cold Information*/
+ rtsx_pci_write_register(pcr, RTS5264_FW_CTL,
+ RTS5264_INFORM_RTD3_COLD, 0);
+
+ return 0;
+}
+
+static void rts5264_enable_aspm(struct rtsx_pcr *pcr, bool enable)
+{
+ u8 val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
+ u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
+
+ if (pcr->aspm_enabled == enable)
+ return;
+
+ val |= (pcr->aspm_en & 0x02);
+ rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
+ pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_ASPMC, pcr->aspm_en);
+ pcr->aspm_enabled = enable;
+}
+
+static void rts5264_disable_aspm(struct rtsx_pcr *pcr, bool enable)
+{
+ u8 val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
+ u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
+
+ if (pcr->aspm_enabled == enable)
+ return;
+
+ pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_ASPMC, 0);
+ rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
+ rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
+ udelay(10);
+ pcr->aspm_enabled = enable;
+}
+
+static void rts5264_set_aspm(struct rtsx_pcr *pcr, bool enable)
+{
+ if (enable)
+ rts5264_enable_aspm(pcr, true);
+ else
+ rts5264_disable_aspm(pcr, false);
+}
+
+static void rts5264_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active)
+{
+ struct rtsx_cr_option *option = &(pcr->option);
+
+ u32 interrupt = rtsx_pci_readl(pcr, RTSX_BIPR);
+ int card_exist = (interrupt & SD_EXIST);
+ int aspm_L1_1, aspm_L1_2;
+ u8 val = 0;
+
+ aspm_L1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN);
+ aspm_L1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN);
+
+ if (active) {
+ /* Run, latency: 60us */
+ if (aspm_L1_1)
+ val = option->ltr_l1off_snooze_sspwrgate;
+ } else {
+ /* L1off, latency: 300us */
+ if (aspm_L1_2)
+ val = option->ltr_l1off_sspwrgate;
+ }
+
+ if (aspm_L1_1 || aspm_L1_2) {
+ if (rtsx_check_dev_flag(pcr,
+ LTR_L1SS_PWR_GATE_CHECK_CARD_EN)) {
+ if (card_exist)
+ val &= ~L1OFF_MBIAS2_EN_5250;
+ else
+ val |= L1OFF_MBIAS2_EN_5250;
+ }
+ }
+ rtsx_set_l1off_sub(pcr, val);
+}
+
+static const struct pcr_ops rts5264_pcr_ops = {
+ .turn_on_led = rts5264_turn_on_led,
+ .turn_off_led = rts5264_turn_off_led,
+ .extra_init_hw = rts5264_extra_init_hw,
+ .enable_auto_blink = rts5264_enable_auto_blink,
+ .disable_auto_blink = rts5264_disable_auto_blink,
+ .card_power_on = rts5264_card_power_on,
+ .card_power_off = rts5264_card_power_off,
+ .switch_output_voltage = rts5264_switch_output_voltage,
+ .force_power_down = rts5264_force_power_down,
+ .stop_cmd = rts5264_stop_cmd,
+ .set_aspm = rts5264_set_aspm,
+ .set_l1off_cfg_sub_d0 = rts5264_set_l1off_cfg_sub_d0,
+ .enable_ocp = rts5264_enable_ocp,
+ .disable_ocp = rts5264_disable_ocp,
+ .init_ocp = rts5264_init_ocp,
+ .process_ocp = rts5264_process_ocp,
+ .clear_ocpstat = rts5264_clear_ocpstat,
+};
+
+static inline u8 double_ssc_depth(u8 depth)
+{
+ return ((depth > 1) ? (depth - 1) : depth);
+}
+
+int rts5264_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
+ u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
+{
+ int err, clk;
+ u16 n;
+ u8 clk_divider, mcu_cnt, div;
+ static const u8 depth[] = {
+ [RTSX_SSC_DEPTH_4M] = RTS5264_SSC_DEPTH_4M,
+ [RTSX_SSC_DEPTH_2M] = RTS5264_SSC_DEPTH_2M,
+ [RTSX_SSC_DEPTH_1M] = RTS5264_SSC_DEPTH_1M,
+ [RTSX_SSC_DEPTH_500K] = RTS5264_SSC_DEPTH_512K,
+ };
+
+ if (initial_mode) {
+ /* We use 250k(around) here, in initial stage */
+ clk_divider = SD_CLK_DIVIDE_128;
+ card_clock = 30000000;
+ } else {
+ clk_divider = SD_CLK_DIVIDE_0;
+ }
+ err = rtsx_pci_write_register(pcr, SD_CFG1,
+ SD_CLK_DIVIDE_MASK, clk_divider);
+ if (err < 0)
+ return err;
+
+ card_clock /= 1000000;
+ pcr_dbg(pcr, "Switch card clock to %dMHz\n", card_clock);
+
+ clk = card_clock;
+ if (!initial_mode && double_clk)
+ clk = card_clock * 2;
+ pcr_dbg(pcr, "Internal SSC clock: %dMHz (cur_clock = %d)\n",
+ clk, pcr->cur_clock);
+
+ if (clk == pcr->cur_clock)
+ return 0;
+
+ if (pcr->ops->conv_clk_and_div_n)
+ n = pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
+ else
+ n = clk - 4;
+ if ((clk <= 4) || (n > 396))
+ return -EINVAL;
+
+ mcu_cnt = 125/clk + 3;
+ if (mcu_cnt > 15)
+ mcu_cnt = 15;
+
+ div = CLK_DIV_1;
+ while ((n < MIN_DIV_N_PCR - 4) && (div < CLK_DIV_8)) {
+ if (pcr->ops->conv_clk_and_div_n) {
+ int dbl_clk = pcr->ops->conv_clk_and_div_n(n,
+ DIV_N_TO_CLK) * 2;
+ n = pcr->ops->conv_clk_and_div_n(dbl_clk,
+ CLK_TO_DIV_N);
+ } else {
+ n = (n + 4) * 2 - 4;
+ }
+ div++;
+ }
+
+ n = (n / 2) - 1;
+ pcr_dbg(pcr, "n = %d, div = %d\n", n, div);
+
+ ssc_depth = depth[ssc_depth];
+ if (double_clk)
+ ssc_depth = double_ssc_depth(ssc_depth);
+
+ if (ssc_depth) {
+ if (div == CLK_DIV_2) {
+ if (ssc_depth > 1)
+ ssc_depth -= 1;
+ else
+ ssc_depth = RTS5264_SSC_DEPTH_8M;
+ } else if (div == CLK_DIV_4) {
+ if (ssc_depth > 2)
+ ssc_depth -= 2;
+ else
+ ssc_depth = RTS5264_SSC_DEPTH_8M;
+ } else if (div == CLK_DIV_8) {
+ if (ssc_depth > 3)
+ ssc_depth -= 3;
+ else
+ ssc_depth = RTS5264_SSC_DEPTH_8M;
+ }
+ } else {
+ ssc_depth = 0;
+ }
+ pcr_dbg(pcr, "ssc_depth = %d\n", ssc_depth);
+
+ rtsx_pci_init_cmd(pcr);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL,
+ CHANGE_CLK, CHANGE_CLK);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV,
+ 0xFF, (div << 4) | mcu_cnt);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2,
+ SSC_DEPTH_MASK, ssc_depth);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n);
+
+ if (is_version(pcr, 0x5264, IC_VER_A)) {
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS5264_CARD_CLK_SRC2,
+ RTS5264_REG_BIG_KVCO_A, 0);
+ } else {
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS5264_SYS_DUMMY_1,
+ RTS5264_REG_BIG_KVCO, 0);
+ }
+
+ if (vpclk) {
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
+ PHASE_NOT_RESET, 0);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK1_CTL,
+ PHASE_NOT_RESET, 0);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
+ PHASE_NOT_RESET, PHASE_NOT_RESET);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK1_CTL,
+ PHASE_NOT_RESET, PHASE_NOT_RESET);
+ }
+
+ err = rtsx_pci_send_cmd(pcr, 2000);
+ if (err < 0)
+ return err;
+
+ /* Wait SSC clock stable */
+ udelay(SSC_CLOCK_STABLE_WAIT);
+ err = rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, 0);
+ if (err < 0)
+ return err;
+
+ pcr->cur_clock = clk;
+ return 0;
+}
+
+void rts5264_init_params(struct rtsx_pcr *pcr)
+{
+ struct rtsx_cr_option *option = &pcr->option;
+ struct rtsx_hw_param *hw_param = &pcr->hw_param;
+ u8 val;
+
+ pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
+ pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
+ rtsx_pci_read_register(pcr, RTS5264_FW_STATUS, &val);
+ if (!(val & RTS5264_EXPRESS_LINK_FAIL_MASK))
+ pcr->extra_caps |= EXTRA_CAPS_SD_EXPRESS;
+ pcr->num_slots = 1;
+ pcr->ops = &rts5264_pcr_ops;
+
+ pcr->flags = 0;
+ pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
+ pcr->sd30_drive_sel_1v8 = 0x00;
+ pcr->sd30_drive_sel_3v3 = 0x00;
+ pcr->aspm_en = ASPM_L1_EN;
+ pcr->aspm_mode = ASPM_MODE_REG;
+ pcr->tx_initial_phase = SET_CLOCK_PHASE(24, 24, 11);
+ pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
+
+ pcr->ic_version = rts5264_get_ic_version(pcr);
+ pcr->sd_pull_ctl_enable_tbl = rts5264_sd_pull_ctl_enable_tbl;
+ pcr->sd_pull_ctl_disable_tbl = rts5264_sd_pull_ctl_disable_tbl;
+
+ pcr->reg_pm_ctrl3 = RTS5264_AUTOLOAD_CFG3;
+
+ option->dev_flags = (LTR_L1SS_PWR_GATE_CHECK_CARD_EN
+ | LTR_L1SS_PWR_GATE_EN);
+ option->ltr_en = true;
+
+ /* init latency of active, idle, L1OFF to 60us, 300us, 3ms */
+ option->ltr_active_latency = LTR_ACTIVE_LATENCY_DEF;
+ option->ltr_idle_latency = LTR_IDLE_LATENCY_DEF;
+ option->ltr_l1off_latency = LTR_L1OFF_LATENCY_DEF;
+ option->l1_snooze_delay = L1_SNOOZE_DELAY_DEF;
+ option->ltr_l1off_sspwrgate = 0x7F;
+ option->ltr_l1off_snooze_sspwrgate = 0x78;
+
+ option->ocp_en = 1;
+ hw_param->interrupt_en |= (SD_OC_INT_EN | SD_OVP_INT_EN);
+ hw_param->ocp_glitch = SD_OCP_GLITCH_800U | SDVIO_OCP_GLITCH_800U;
+ option->sd_800mA_ocp_thd = RTS5264_LDO1_OCP_THD_1150;
+}
diff --git a/drivers/misc/cardreader/rts5264.h b/drivers/misc/cardreader/rts5264.h
new file mode 100644
index 000000000000..e3cbbf2fe1a4
--- /dev/null
+++ b/drivers/misc/cardreader/rts5264.h
@@ -0,0 +1,278 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2018-2019 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * Author:
+ * Ricky Wu <[email protected]>
+ */
+#ifndef RTS5264_H
+#define RTS5264_H
+
+/*New add*/
+#define rts5264_vendor_setting_valid(reg) ((reg) & 0x010000)
+#define rts5264_reg_to_aspm(reg) \
+ (((~(reg) >> 28) & 0x02) | (((reg) >> 28) & 0x01))
+#define rts5264_reg_check_reverse_socket(reg) ((reg) & 0x04)
+#define rts5264_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 22) & 0x03)
+#define rts5264_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 16) & 0x03)
+#define rts5264_reg_to_rtd3(reg) ((reg) & 0x08)
+
+#define RTS5264_AUTOLOAD_CFG0 0xFF7B
+#define RTS5264_AUTOLOAD_CFG1 0xFF7C
+#define RTS5264_AUTOLOAD_CFG3 0xFF7E
+#define RTS5264_AUTOLOAD_CFG4 0xFF7F
+#define RTS5264_FORCE_PRSNT_LOW (1 << 6)
+#define RTS5264_AUX_CLK_16M_EN (1 << 5)
+#define RTS5264_F_HIGH_RC_MASK (1 << 4)
+#define RTS5264_F_HIGH_RC_1_6M (1 << 4)
+#define RTS5264_F_HIGH_RC_400K (0 << 4)
+
+/* SSC_CTL2 0xFC12 */
+#define RTS5264_SSC_DEPTH_MASK 0x07
+#define RTS5264_SSC_DEPTH_DISALBE 0x00
+#define RTS5264_SSC_DEPTH_8M 0x01
+#define RTS5264_SSC_DEPTH_4M 0x02
+#define RTS5264_SSC_DEPTH_2M 0x03
+#define RTS5264_SSC_DEPTH_1M 0x04
+#define RTS5264_SSC_DEPTH_512K 0x05
+#define RTS5264_SSC_DEPTH_256K 0x06
+#define RTS5264_SSC_DEPTH_128K 0x07
+
+#define RTS5264_CARD_CLK_SRC2 0xFC2F
+#define RTS5264_REG_BIG_KVCO_A 0x20
+
+/* efuse control register*/
+#define RTS5264_EFUSE_CTL 0xFC30
+#define RTS5264_EFUSE_ENABLE 0x80
+/* EFUSE_MODE: 0=READ 1=PROGRAM */
+#define RTS5264_EFUSE_MODE_MASK 0x40
+#define RTS5264_EFUSE_PROGRAM 0x40
+
+#define RTS5264_EFUSE_ADDR 0xFC31
+#define RTS5264_EFUSE_ADDR_MASK 0x3F
+
+#define RTS5264_EFUSE_WRITE_DATA 0xFC32
+#define RTS5264_EFUSE_READ_DATA 0xFC34
+
+#define RTS5264_SYS_DUMMY_1 0xFC35
+#define RTS5264_REG_BIG_KVCO 0x04
+
+/* DMACTL 0xFE2C */
+#define RTS5264_DMA_PACK_SIZE_MASK 0x70
+
+#define RTS5264_FW_CFG1 0xFF55
+#define RTS5264_SYS_CLK_SEL_MCU_CLK (0x01<<7)
+#define RTS5264_CRC_CLK_SEL_MCU_CLK (0x01<<6)
+#define RTS5264_FAKE_MCU_CLOCK_GATING (0x01<<5)
+#define RTS5264_MCU_BUS_SEL_MASK (0x01<<4)
+
+/* FW status register */
+#define RTS5264_FW_STATUS 0xFF56
+#define RTS5264_EXPRESS_LINK_FAIL_MASK (0x01<<7)
+
+/* FW control register */
+#define RTS5264_FW_CTL 0xFF5F
+#define RTS5264_INFORM_RTD3_COLD (0x01<<5)
+
+#define RTS5264_REG_FPDCTL 0xFF60
+
+#define RTS5264_REG_LDO12_CFG 0xFF6E
+#define RTS5264_LDO12_SR_MASK (0x03<<6)
+#define RTS5264_LDO12_SR_1_0_MS (0x03<<6)
+#define RTS5264_LDO12_SR_0_5_MS (0x02<<6)
+#define RTS5264_LDO12_SR_0_2_5_MS (0x01<<6)
+#define RTS5264_LDO12_SR_0_0_MS (0x00<<6)
+#define RTS5264_LDO12_VO_TUNE_MASK (0x07<<1)
+#define RTS5264_LDO12_115 (0x03<<1)
+#define RTS5264_LDO12_120 (0x04<<1)
+#define RTS5264_LDO12_125 (0x05<<1)
+#define RTS5264_LDO12_130 (0x06<<1)
+#define RTS5264_LDO12_135 (0x07<<1)
+
+/* LDO control register */
+#define RTS5264_CARD_PWR_CTL 0xFD50
+#define RTS5264_SD_CLK_ISO (0x01<<7)
+#define RTS5264_PAD_SD_DAT_FW_CTRL (0x01<<6)
+#define RTS5264_PUPDC (0x01<<5)
+#define RTS5264_SD_CMD_ISO (0x01<<4)
+
+#define RTS5264_OCP_VDD3_CTL 0xFD89
+#define SD_VDD3_DETECT_EN 0x08
+#define SD_VDD3_OCP_INT_EN 0x04
+#define SD_VDD3_OCP_INT_CLR 0x02
+#define SD_VDD3_OC_CLR 0x01
+
+#define RTS5264_OCP_VDD3_STS 0xFD8A
+#define SD_VDD3_OCP_DETECT 0x08
+#define SD_VDD3_OC_NOW 0x04
+#define SD_VDD3_OC_EVER 0x02
+
+#define RTS5264_OVP_CTL 0xFD8D
+#define RTS5264_OVP_TIME_MASK 0xF0
+#define RTS5264_OVP_TIME_DFT 0x50
+#define RTS5264_OVP_DETECT_EN 0x08
+#define RTS5264_OVP_INT_EN 0x04
+#define RTS5264_OVP_INT_CLR 0x02
+#define RTS5264_OVP_CLR 0x01
+
+#define RTS5264_OVP_STS 0xFD8E
+#define RTS5264_OVP_GLTCH_TIME_MASK 0xF0
+#define RTS5264_OVP_GLTCH_TIME_DFT 0x50
+#define RTS5264_VOVER_DET 0x08
+#define RTS5264_OVP_NOW 0x04
+#define RTS5264_OVP_EVER 0x02
+
+#define RTS5264_CMD_OE_START_EARLY 0xFDCB
+#define RTS5264_CMD_OE_EARLY_LEAVE 0x08
+#define RTS5264_CMD_OE_EARLY_CYCLE_MASK 0x06
+#define RTS5264_CMD_OE_EARLY_4CYCLE 0x06
+#define RTS5264_CMD_OE_EARLY_3CYCLE 0x04
+#define RTS5264_CMD_OE_EARLY_2CYCLE 0x02
+#define RTS5264_CMD_OE_EARLY_1CYCLE 0x00
+#define RTS5264_CMD_OE_EARLY_EN 0x01
+
+#define RTS5264_DAT_OE_START_EARLY 0xFDCC
+#define RTS5264_DAT_OE_EARLY_LEAVE 0x08
+#define RTS5264_DAT_OE_EARLY_CYCLE_MASK 0x06
+#define RTS5264_DAT_OE_EARLY_4CYCLE 0x06
+#define RTS5264_DAT_OE_EARLY_3CYCLE 0x04
+#define RTS5264_DAT_OE_EARLY_2CYCLE 0x02
+#define RTS5264_DAT_OE_EARLY_1CYCLE 0x00
+#define RTS5264_DAT_OE_EARLY_EN 0x01
+
+#define RTS5264_LDO1233318_POW_CTL 0xFF70
+#define RTS5264_TUNE_REF_LDO3318 (0x03<<6)
+#define RTS5264_TUNE_REF_LDO3318_DFT (0x02<<6)
+#define RTS5264_LDO3318_POWERON (0x01<<3)
+#define RTS5264_LDO3_POWERON (0x01<<2)
+#define RTS5264_LDO2_POWERON (0x01<<1)
+#define RTS5264_LDO1_POWERON (0x01<<0)
+#define RTS5264_LDO_POWERON_MASK (0x0F<<0)
+
+#define RTS5264_DV3318_CFG 0xFF71
+#define RTS5264_DV3318_TUNE_MASK (0x07<<4)
+#define RTS5264_DV3318_18 (0x02<<4)
+#define RTS5264_DV3318_19 (0x04<<4)
+#define RTS5264_DV3318_33 (0x07<<4)
+
+#define RTS5264_LDO1_CFG0 0xFF72
+#define RTS5264_LDO1_OCP_THD_MASK (0x07 << 5)
+#define RTS5264_LDO1_OCP_EN (0x01 << 4)
+#define RTS5264_LDO1_OCP_LMT_THD_MASK (0x03 << 2)
+#define RTS5264_LDO1_OCP_LMT_EN (0x01 << 1)
+
+#define RTS5264_LDO1_OCP_THD_850 (0x00<<5)
+#define RTS5264_LDO1_OCP_THD_950 (0x01<<5)
+#define RTS5264_LDO1_OCP_THD_1050 (0x02<<5)
+#define RTS5264_LDO1_OCP_THD_1100 (0x03<<5)
+#define RTS5264_LDO1_OCP_THD_1150 (0x04<<5)
+#define RTS5264_LDO1_OCP_THD_1200 (0x05<<5)
+#define RTS5264_LDO1_OCP_THD_1300 (0x06<<5)
+#define RTS5264_LDO1_OCP_THD_1350 (0x07<<5)
+
+#define RTS5264_LDO1_LMT_THD_1700 (0x00<<2)
+#define RTS5264_LDO1_LMT_THD_1800 (0x01<<2)
+#define RTS5264_LDO1_LMT_THD_1900 (0x02<<2)
+#define RTS5264_LDO1_LMT_THD_2000 (0x03<<2)
+
+#define RTS5264_LDO1_CFG1 0xFF73
+#define RTS5264_LDO1_TUNE_MASK (0x07<<1)
+#define RTS5264_LDO1_18 (0x05<<1)
+#define RTS5264_LDO1_33 (0x07<<1)
+#define RTS5264_LDO1_PWD_MASK (0x01<<0)
+
+#define RTS5264_LDO2_CFG0 0xFF74
+#define RTS5264_LDO2_OCP_THD_MASK (0x07<<5)
+#define RTS5264_LDO2_OCP_EN (0x01<<4)
+#define RTS5264_LDO2_OCP_LMT_THD_MASK (0x03<<2)
+#define RTS5264_LDO2_OCP_LMT_EN (0x01<<1)
+
+#define RTS5264_LDO2_OCP_THD_750 (0x00<<5)
+#define RTS5264_LDO2_OCP_THD_850 (0x01<<5)
+#define RTS5264_LDO2_OCP_THD_900 (0x02<<5)
+#define RTS5264_LDO2_OCP_THD_950 (0x03<<5)
+#define RTS5264_LDO2_OCP_THD_1050 (0x04<<5)
+#define RTS5264_LDO2_OCP_THD_1100 (0x05<<5)
+#define RTS5264_LDO2_OCP_THD_1150 (0x06<<5)
+#define RTS5264_LDO2_OCP_THD_1200 (0x07<<5)
+
+#define RTS5264_LDO2_LMT_THD_1700 (0x00<<2)
+#define RTS5264_LDO2_LMT_THD_1800 (0x01<<2)
+#define RTS5264_LDO2_LMT_THD_1900 (0x02<<2)
+#define RTS5264_LDO2_LMT_THD_2000 (0x03<<2)
+
+#define RTS5264_LDO2_CFG1 0xFF75
+#define RTS5264_LDO2_TUNE_MASK (0x07<<1)
+#define RTS5264_LDO2_18 (0x02<<1)
+#define RTS5264_LDO2_185 (0x03<<1)
+#define RTS5264_LDO2_19 (0x04<<1)
+#define RTS5264_LDO2_195 (0x05<<1)
+#define RTS5264_LDO2_33 (0x07<<1)
+#define RTS5264_LDO2_PWD_MASK (0x01<<0)
+
+#define RTS5264_LDO3_CFG0 0xFF76
+#define RTS5264_LDO3_OCP_THD_MASK (0x07<<5)
+#define RTS5264_LDO3_OCP_EN (0x01<<4)
+#define RTS5264_LDO3_OCP_LMT_THD_MASK (0x03<<2)
+#define RTS5264_LDO3_OCP_LMT_EN (0x01<<1)
+
+#define RTS5264_LDO3_OCP_THD_610 (0x00<<5)
+#define RTS5264_LDO3_OCP_THD_630 (0x01<<5)
+#define RTS5264_LDO3_OCP_THD_670 (0x02<<5)
+#define RTS5264_LDO3_OCP_THD_710 (0x03<<5)
+#define RTS5264_LDO3_OCP_THD_750 (0x04<<5)
+#define RTS5264_LDO3_OCP_THD_770 (0x05<<5)
+#define RTS5264_LDO3_OCP_THD_810 (0x06<<5)
+#define RTS5264_LDO3_OCP_THD_850 (0x07<<5)
+
+#define RTS5264_LDO3_LMT_THD_1200 (0x00<<2)
+#define RTS5264_LDO3_LMT_THD_1300 (0x01<<2)
+#define RTS5264_LDO3_LMT_THD_1400 (0x02<<2)
+#define RTS5264_LDO3_LMT_THD_1500 (0x03<<2)
+
+#define RTS5264_LDO3_CFG1 0xFF77
+#define RTS5264_LDO3_TUNE_MASK (0x07<<1)
+#define RTS5264_LDO3_12 (0x02<<1)
+#define RTS5264_LDO3_125 (0x03<<1)
+#define RTS5264_LDO3_13 (0x04<<1)
+#define RTS5264_LDO3_135 (0x05<<1)
+#define RTS5264_LDO3_33 (0x07<<1)
+#define RTS5264_LDO3_PWD_MASK (0x01<<0)
+
+#define RTS5264_REG_PME_FORCE_CTL 0xFF78
+#define FORCE_PM_CONTROL 0x20
+#define FORCE_PM_VALUE 0x10
+#define REG_EFUSE_BYPASS 0x08
+#define REG_EFUSE_POR 0x04
+#define REG_EFUSE_POWER_MASK 0x03
+#define REG_EFUSE_POWERON 0x03
+#define REG_EFUSE_POWEROFF 0x00
+
+#define RTS5264_PWR_CUT 0xFF81
+#define RTS5264_CFG_MEM_PD 0xF0
+
+#define RTS5264_OVP_DET 0xFF8A
+#define RTS5264_POW_VDET 0x04
+#define RTS5264_TUNE_VROV_MASK 0x03
+#define RTS5264_TUNE_VROV_2V 0x03
+#define RTS5264_TUNE_VROV_1V8 0x02
+#define RTS5264_TUNE_VROV_1V6 0x01
+#define RTS5264_TUNE_VROV_1V4 0x00
+
+#define RTS5264_CKMUX_MBIAS_PWR 0xFF8B
+#define RTS5264_NON_XTAL_SEL 0x80
+#define RTS5264_POW_CKMUX 0x40
+#define RTS5264_LVD_MASK 0x04
+#define RTS5264_POW_PSW_MASK 0x03
+#define RTS5264_POW_PSW_DFT 0x03
+
+/* Single LUN, support SD/SD EXPRESS */
+#define DEFAULT_SINGLE 0
+#define SD_LUN 1
+#define SD_EXPRESS_LUN 2
+
+int rts5264_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
+ u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk);
+
+#endif /* RTS5264_H */
diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index a30751ad3733..1a64364700eb 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -26,6 +26,7 @@
#include "rtsx_pcr.h"
#include "rts5261.h"
#include "rts5228.h"
+#include "rts5264.h"
static bool msi_en = true;
module_param(msi_en, bool, S_IRUGO | S_IWUSR);
@@ -54,6 +55,7 @@ static const struct pci_device_id rtsx_pci_ids[] = {
{ PCI_DEVICE(0x10EC, 0x5260), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5261), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5228), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+ { PCI_DEVICE(0x10EC, 0x5264), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ 0, }
};
@@ -714,6 +716,9 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
if (PCI_PID(pcr) == PID_5228)
return rts5228_pci_switch_clock(pcr, card_clock,
ssc_depth, initial_mode, double_clk, vpclk);
+ if (PCI_PID(pcr) == PID_5264)
+ return rts5264_pci_switch_clock(pcr, card_clock,
+ ssc_depth, initial_mode, double_clk, vpclk);
if (initial_mode) {
/* We use 250k(around) here, in initial stage */
@@ -987,7 +992,8 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
int_reg &= (pcr->bier | 0x7FFFFF);
- if (int_reg & SD_OC_INT)
+ if ((int_reg & SD_OC_INT) ||
+ ((int_reg & SD_OVP_INT) && (PCI_PID(pcr) == PID_5264)))
rtsx_pci_process_ocp_interrupt(pcr);
if (int_reg & SD_INT) {
@@ -1159,7 +1165,9 @@ void rtsx_pci_enable_oobs_polling(struct rtsx_pcr *pcr)
{
u16 val;
- if ((PCI_PID(pcr) != PID_525A) && (PCI_PID(pcr) != PID_5260)) {
+ if ((PCI_PID(pcr) != PID_525A) &&
+ (PCI_PID(pcr) != PID_5260) &&
+ (PCI_PID(pcr) != PID_5264)) {
rtsx_pci_read_phy_register(pcr, 0x01, &val);
val |= 1<<9;
rtsx_pci_write_phy_register(pcr, 0x01, val);
@@ -1175,7 +1183,9 @@ void rtsx_pci_disable_oobs_polling(struct rtsx_pcr *pcr)
{
u16 val;
- if ((PCI_PID(pcr) != PID_525A) && (PCI_PID(pcr) != PID_5260)) {
+ if ((PCI_PID(pcr) != PID_525A) &&
+ (PCI_PID(pcr) != PID_5260) &&
+ (PCI_PID(pcr) != PID_5264)) {
rtsx_pci_read_phy_register(pcr, 0x01, &val);
val &= ~(1<<9);
rtsx_pci_write_phy_register(pcr, 0x01, val);
@@ -1226,7 +1236,7 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
rtsx_pci_enable_bus_int(pcr);
/* Power on SSC */
- if (PCI_PID(pcr) == PID_5261) {
+ if ((PCI_PID(pcr) == PID_5261) || (PCI_PID(pcr) == PID_5264)) {
/* Gating real mcu clock */
err = rtsx_pci_write_register(pcr, RTS5261_FW_CFG1,
RTS5261_MCU_CLOCK_GATING, 0);
@@ -1270,6 +1280,11 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
else if (PCI_PID(pcr) == PID_5228)
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF,
RTS5228_SSC_DEPTH_2M);
+ else if (is_version(pcr, 0x5264, IC_VER_A))
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
+ else if (PCI_PID(pcr) == PID_5264)
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF,
+ RTS5264_SSC_DEPTH_2M);
else
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF, 0x12);
@@ -1305,6 +1320,7 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
case PID_5260:
case PID_5261:
case PID_5228:
+ case PID_5264:
rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 1, 1);
break;
default:
@@ -1404,6 +1420,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
case 0x5228:
rts5228_init_params(pcr);
break;
+
+ case 0x5264:
+ rts5264_init_params(pcr);
+ break;
}
pcr_dbg(pcr, "PID: 0x%04x, IC version: 0x%02x\n",
@@ -1544,7 +1564,7 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
pcr->pci = pcidev;
dev_set_drvdata(&pcidev->dev, handle);
- if (CHK_PCI_PID(pcr, 0x525A))
+ if ((CHK_PCI_PID(pcr, 0x525A)) || (CHK_PCI_PID(pcr, 0x5264)))
bar = 1;
len = pci_resource_len(pcidev, bar);
base = pci_resource_start(pcidev, bar);
diff --git a/drivers/misc/cardreader/rtsx_pcr.h b/drivers/misc/cardreader/rtsx_pcr.h
index 37d1f316ae17..9215d66de00c 100644
--- a/drivers/misc/cardreader/rtsx_pcr.h
+++ b/drivers/misc/cardreader/rtsx_pcr.h
@@ -74,6 +74,7 @@ void rtl8411b_init_params(struct rtsx_pcr *pcr);
void rts5260_init_params(struct rtsx_pcr *pcr);
void rts5261_init_params(struct rtsx_pcr *pcr);
void rts5228_init_params(struct rtsx_pcr *pcr);
+void rts5264_init_params(struct rtsx_pcr *pcr);
static inline u8 map_sd_drive(int idx)
{
diff --git a/drivers/misc/dw-xdata-pcie.c b/drivers/misc/dw-xdata-pcie.c
index 257c25da5199..efd0ca8cc925 100644
--- a/drivers/misc/dw-xdata-pcie.c
+++ b/drivers/misc/dw-xdata-pcie.c
@@ -333,7 +333,7 @@ static int dw_xdata_pcie_probe(struct pci_dev *pdev,
dw->pdev = pdev;
- id = ida_simple_get(&xdata_ida, 0, 0, GFP_KERNEL);
+ id = ida_alloc(&xdata_ida, GFP_KERNEL);
if (id < 0) {
dev_err(dev, "xData: unable to get id\n");
return id;
@@ -377,7 +377,7 @@ err_kfree_name:
kfree(dw->misc_dev.name);
err_ida_remove:
- ida_simple_remove(&xdata_ida, id);
+ ida_free(&xdata_ida, id);
return err;
}
@@ -396,7 +396,7 @@ static void dw_xdata_pcie_remove(struct pci_dev *pdev)
dw_xdata_stop(dw);
misc_deregister(&dw->misc_dev);
kfree(dw->misc_dev.name);
- ida_simple_remove(&xdata_ida, id);
+ ida_free(&xdata_ida, id);
}
static const struct pci_device_id dw_xdata_pcie_id_table[] = {
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index f61a80597a22..a5dcd7a13468 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -439,12 +439,9 @@ static int at24_read(void *priv, unsigned int off, void *val, size_t count)
if (off + count > at24->byte_len)
return -EINVAL;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
return ret;
- }
-
/*
* Read data from chip, protecting against concurrent updates
* from this host, but not from other I2C masters.
@@ -486,12 +483,9 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
if (off + count > at24->byte_len)
return -EINVAL;
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
return ret;
- }
-
/*
* Write data to chip, protecting against concurrent updates
* from this host, but not from other I2C masters.
@@ -563,6 +557,31 @@ static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len)
}
}
+static void at24_probe_temp_sensor(struct i2c_client *client)
+{
+ struct at24_data *at24 = i2c_get_clientdata(client);
+ struct i2c_board_info info = { .type = "jc42" };
+ int ret;
+ u8 val;
+
+ /*
+ * Byte 2 has value 11 for DDR3, earlier versions don't
+ * support the thermal sensor present flag
+ */
+ ret = at24_read(at24, 2, &val, 1);
+ if (ret || val != 11)
+ return;
+
+ /* Byte 32, bit 7 is set if temp sensor is present */
+ ret = at24_read(at24, 32, &val, 1);
+ if (ret || !(val & BIT(7)))
+ return;
+
+ info.addr = 0x18 | (client->addr & 7);
+
+ i2c_new_client_device(client->adapter, &info);
+}
+
static int at24_probe(struct i2c_client *client)
{
struct regmap_config regmap_config = { };
@@ -762,6 +781,10 @@ static int at24_probe(struct i2c_client *client)
}
}
+ /* If this a SPD EEPROM, probe for DDR3 thermal sensor */
+ if (cdata == &at24_data_spd)
+ at24_probe_temp_sensor(client);
+
pm_runtime_idle(dev);
if (writable)
diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c
index a1acd77130f2..21feebc3044c 100644
--- a/drivers/misc/eeprom/ee1004.c
+++ b/drivers/misc/eeprom/ee1004.c
@@ -31,6 +31,7 @@
* over performance.
*/
+#define EE1004_MAX_BUSSES 8
#define EE1004_ADDR_SET_PAGE 0x36
#define EE1004_NUM_PAGES 2
#define EE1004_PAGE_SIZE 256
@@ -42,9 +43,13 @@
* from page selection to end of read.
*/
static DEFINE_MUTEX(ee1004_bus_lock);
-static struct i2c_client *ee1004_set_page[EE1004_NUM_PAGES];
-static unsigned int ee1004_dev_count;
-static int ee1004_current_page;
+
+static struct ee1004_bus_data {
+ struct i2c_adapter *adap;
+ struct i2c_client *set_page[EE1004_NUM_PAGES];
+ unsigned int dev_count;
+ int current_page;
+} ee1004_bus_data[EE1004_MAX_BUSSES];
static const struct i2c_device_id ee1004_ids[] = {
{ "ee1004", 0 },
@@ -54,11 +59,29 @@ MODULE_DEVICE_TABLE(i2c, ee1004_ids);
/*-------------------------------------------------------------------------*/
-static int ee1004_get_current_page(void)
+static struct ee1004_bus_data *ee1004_get_bus_data(struct i2c_adapter *adap)
+{
+ int i;
+
+ for (i = 0; i < EE1004_MAX_BUSSES; i++)
+ if (ee1004_bus_data[i].adap == adap)
+ return ee1004_bus_data + i;
+
+ /* If not existent yet, create new entry */
+ for (i = 0; i < EE1004_MAX_BUSSES; i++)
+ if (!ee1004_bus_data[i].adap) {
+ ee1004_bus_data[i].adap = adap;
+ return ee1004_bus_data + i;
+ }
+
+ return NULL;
+}
+
+static int ee1004_get_current_page(struct ee1004_bus_data *bd)
{
int err;
- err = i2c_smbus_read_byte(ee1004_set_page[0]);
+ err = i2c_smbus_read_byte(bd->set_page[0]);
if (err == -ENXIO) {
/* Nack means page 1 is selected */
return 1;
@@ -72,28 +95,29 @@ static int ee1004_get_current_page(void)
return 0;
}
-static int ee1004_set_current_page(struct device *dev, int page)
+static int ee1004_set_current_page(struct i2c_client *client, int page)
{
+ struct ee1004_bus_data *bd = i2c_get_clientdata(client);
int ret;
- if (page == ee1004_current_page)
+ if (page == bd->current_page)
return 0;
/* Data is ignored */
- ret = i2c_smbus_write_byte(ee1004_set_page[page], 0x00);
+ ret = i2c_smbus_write_byte(bd->set_page[page], 0x00);
/*
* Don't give up just yet. Some memory modules will select the page
* but not ack the command. Check which page is selected now.
*/
- if (ret == -ENXIO && ee1004_get_current_page() == page)
+ if (ret == -ENXIO && ee1004_get_current_page(bd) == page)
ret = 0;
if (ret < 0) {
- dev_err(dev, "Failed to select page %d (%d)\n", page, ret);
+ dev_err(&client->dev, "Failed to select page %d (%d)\n", page, ret);
return ret;
}
- dev_dbg(dev, "Selected page %d\n", page);
- ee1004_current_page = page;
+ dev_dbg(&client->dev, "Selected page %d\n", page);
+ bd->current_page = page;
return 0;
}
@@ -106,7 +130,7 @@ static ssize_t ee1004_eeprom_read(struct i2c_client *client, char *buf,
page = offset >> EE1004_PAGE_SHIFT;
offset &= (1 << EE1004_PAGE_SHIFT) - 1;
- status = ee1004_set_current_page(&client->dev, page);
+ status = ee1004_set_current_page(client, page);
if (status)
return status;
@@ -158,17 +182,34 @@ static struct bin_attribute *ee1004_attrs[] = {
BIN_ATTRIBUTE_GROUPS(ee1004);
-static void ee1004_cleanup(int idx)
+static void ee1004_probe_temp_sensor(struct i2c_client *client)
{
- if (--ee1004_dev_count == 0)
- while (--idx >= 0) {
- i2c_unregister_device(ee1004_set_page[idx]);
- ee1004_set_page[idx] = NULL;
- }
+ struct i2c_board_info info = { .type = "jc42" };
+ u8 byte14;
+ int ret;
+
+ /* byte 14, bit 7 is set if temp sensor is present */
+ ret = ee1004_eeprom_read(client, &byte14, 14, 1);
+ if (ret != 1 || !(byte14 & BIT(7)))
+ return;
+
+ info.addr = 0x18 | (client->addr & 7);
+
+ i2c_new_client_device(client->adapter, &info);
+}
+
+static void ee1004_cleanup(int idx, struct ee1004_bus_data *bd)
+{
+ if (--bd->dev_count == 0) {
+ while (--idx >= 0)
+ i2c_unregister_device(bd->set_page[idx]);
+ memset(bd, 0, sizeof(struct ee1004_bus_data));
+ }
}
static int ee1004_probe(struct i2c_client *client)
{
+ struct ee1004_bus_data *bd;
int err, cnr = 0;
/* Make sure we can operate on this adapter */
@@ -178,9 +219,19 @@ static int ee1004_probe(struct i2c_client *client)
I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_READ_BYTE_DATA))
return -EPFNOSUPPORT;
- /* Use 2 dummy devices for page select command */
mutex_lock(&ee1004_bus_lock);
- if (++ee1004_dev_count == 1) {
+
+ bd = ee1004_get_bus_data(client->adapter);
+ if (!bd) {
+ mutex_unlock(&ee1004_bus_lock);
+ return dev_err_probe(&client->dev, -ENOSPC,
+ "Only %d busses supported", EE1004_MAX_BUSSES);
+ }
+
+ i2c_set_clientdata(client, bd);
+
+ if (++bd->dev_count == 1) {
+ /* Use 2 dummy devices for page select command */
for (cnr = 0; cnr < EE1004_NUM_PAGES; cnr++) {
struct i2c_client *cl;
@@ -189,21 +240,19 @@ static int ee1004_probe(struct i2c_client *client)
err = PTR_ERR(cl);
goto err_clients;
}
- ee1004_set_page[cnr] = cl;
+ bd->set_page[cnr] = cl;
}
/* Remember current page to avoid unneeded page select */
- err = ee1004_get_current_page();
+ err = ee1004_get_current_page(bd);
if (err < 0)
goto err_clients;
dev_dbg(&client->dev, "Currently selected page: %d\n", err);
- ee1004_current_page = err;
- } else if (client->adapter != ee1004_set_page[0]->adapter) {
- dev_err(&client->dev,
- "Driver only supports devices on a single I2C bus\n");
- err = -EOPNOTSUPP;
- goto err_clients;
+ bd->current_page = err;
}
+
+ ee1004_probe_temp_sensor(client);
+
mutex_unlock(&ee1004_bus_lock);
dev_info(&client->dev,
@@ -213,7 +262,7 @@ static int ee1004_probe(struct i2c_client *client)
return 0;
err_clients:
- ee1004_cleanup(cnr);
+ ee1004_cleanup(cnr, bd);
mutex_unlock(&ee1004_bus_lock);
return err;
@@ -221,9 +270,11 @@ static int ee1004_probe(struct i2c_client *client)
static void ee1004_remove(struct i2c_client *client)
{
+ struct ee1004_bus_data *bd = i2c_get_clientdata(client);
+
/* Remove page select clients if this is the last device */
mutex_lock(&ee1004_bus_lock);
- ee1004_cleanup(EE1004_NUM_PAGES);
+ ee1004_cleanup(EE1004_NUM_PAGES, bd);
mutex_unlock(&ee1004_bus_lock);
}
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
index 3882e97e96a7..c6eb27d46cb0 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
@@ -150,6 +150,7 @@ static int lis3lv02d_i2c_probe(struct i2c_client *client)
lis3_dev.init = lis3_i2c_init;
lis3_dev.read = lis3_i2c_read;
lis3_dev.write = lis3_i2c_write;
+ lis3_dev.reg_ctrl = lis3_reg_ctrl;
lis3_dev.irq = client->irq;
lis3_dev.ac = lis3lv02d_axis_map;
lis3_dev.pm_dev = &client->dev;
diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
index 37db142de413..67d9391f1855 100644
--- a/drivers/misc/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
@@ -3,6 +3,7 @@
config INTEL_MEI
tristate "Intel Management Engine Interface"
depends on X86 && PCI
+ default GENERIC_CPU || MCORE2 || MATOM || X86_GENERIC
help
The Intel Management Engine (Intel ME) provides Manageability,
Security and Media services for system containing Intel chipsets.
@@ -11,10 +12,11 @@ config INTEL_MEI
For more information see
<https://software.intel.com/en-us/manageability/>
+if INTEL_MEI
+
config INTEL_MEI_ME
tristate "ME Enabled Intel Chipsets"
- select INTEL_MEI
- depends on X86 && PCI
+ default y
help
MEI support for ME Enabled Intel chipsets.
@@ -38,8 +40,6 @@ config INTEL_MEI_ME
config INTEL_MEI_TXE
tristate "Intel Trusted Execution Environment with ME Interface"
- select INTEL_MEI
- depends on X86 && PCI
help
MEI Support for Trusted Execution Environment device on Intel SoCs
@@ -48,9 +48,7 @@ config INTEL_MEI_TXE
config INTEL_MEI_GSC
tristate "Intel MEI GSC embedded device"
- depends on INTEL_MEI
depends on INTEL_MEI_ME
- depends on X86 && PCI
depends on DRM_I915
help
Intel auxiliary driver for GSC devices embedded in Intel graphics devices.
@@ -60,6 +58,31 @@ config INTEL_MEI_GSC
tasks such as graphics card firmware update and security
tasks.
+config INTEL_MEI_VSC_HW
+ tristate "Intel visual sensing controller device transport driver"
+ depends on ACPI && SPI
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ Intel SPI transport driver between host and Intel visual sensing
+ controller (IVSC) device.
+
+ This driver can also be built as a module. If so, the module
+ will be called mei-vsc-hw.
+
+config INTEL_MEI_VSC
+ tristate "Intel visual sensing controller device with ME interface"
+ depends on INTEL_MEI_VSC_HW
+ help
+ Intel MEI over SPI driver for Intel visual sensing controller
+ (IVSC) device embedded in IA platform. It supports camera sharing
+ between IVSC for context sensing and IPU for typical media usage.
+ Select this config should enable transport layer for IVSC device.
+
+ This driver can also be built as a module. If so, the module
+ will be called mei-vsc.
+
source "drivers/misc/mei/hdcp/Kconfig"
source "drivers/misc/mei/pxp/Kconfig"
source "drivers/misc/mei/gsc_proxy/Kconfig"
+
+endif
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 14aee253ae48..6f9fdbf1a495 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -31,3 +31,10 @@ CFLAGS_mei-trace.o = -I$(src)
obj-$(CONFIG_INTEL_MEI_HDCP) += hdcp/
obj-$(CONFIG_INTEL_MEI_PXP) += pxp/
obj-$(CONFIG_INTEL_MEI_GSC_PROXY) += gsc_proxy/
+
+obj-$(CONFIG_INTEL_MEI_VSC_HW) += mei-vsc-hw.o
+mei-vsc-hw-y := vsc-tp.o
+mei-vsc-hw-y += vsc-fw-loader.o
+
+obj-$(CONFIG_INTEL_MEI_VSC) += mei-vsc.o
+mei-vsc-y := platform-vsc.o
diff --git a/drivers/misc/mei/gsc_proxy/Kconfig b/drivers/misc/mei/gsc_proxy/Kconfig
index 5f68d9f3d691..ac78b9d1eccd 100644
--- a/drivers/misc/mei/gsc_proxy/Kconfig
+++ b/drivers/misc/mei/gsc_proxy/Kconfig
@@ -3,7 +3,7 @@
#
config INTEL_MEI_GSC_PROXY
tristate "Intel GSC Proxy services of ME Interface"
- select INTEL_MEI_ME
+ depends on INTEL_MEI_ME
depends on DRM_I915
help
MEI Support for GSC Proxy Services on Intel platforms.
diff --git a/drivers/misc/mei/hdcp/Kconfig b/drivers/misc/mei/hdcp/Kconfig
index 54e1c9526909..9be312ec798d 100644
--- a/drivers/misc/mei/hdcp/Kconfig
+++ b/drivers/misc/mei/hdcp/Kconfig
@@ -3,7 +3,7 @@
#
config INTEL_MEI_HDCP
tristate "Intel HDCP2.2 services of ME Interface"
- select INTEL_MEI_ME
+ depends on INTEL_MEI_ME
depends on DRM_I915
help
MEI Support for HDCP2.2 Services on Intel platforms.
diff --git a/drivers/misc/mei/platform-vsc.c b/drivers/misc/mei/platform-vsc.c
new file mode 100644
index 000000000000..8d303c6c0000
--- /dev/null
+++ b/drivers/misc/mei/platform-vsc.c
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, Intel Corporation.
+ * Intel Visual Sensing Controller Interface Linux driver
+ */
+
+#include <linux/align.h>
+#include <linux/cache.h>
+#include <linux/cleanup.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include <linux/mei.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/overflow.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/timekeeping.h>
+#include <linux/types.h>
+
+#include <asm-generic/bug.h>
+#include <asm-generic/unaligned.h>
+
+#include "mei_dev.h"
+#include "vsc-tp.h"
+
+#define MEI_VSC_DRV_NAME "intel_vsc"
+
+#define MEI_VSC_MAX_MSG_SIZE 512
+
+#define MEI_VSC_POLL_DELAY_US (50 * USEC_PER_MSEC)
+#define MEI_VSC_POLL_TIMEOUT_US (200 * USEC_PER_MSEC)
+
+#define mei_dev_to_vsc_hw(dev) ((struct mei_vsc_hw *)((dev)->hw))
+
+struct mei_vsc_host_timestamp {
+ u64 realtime;
+ u64 boottime;
+};
+
+struct mei_vsc_hw {
+ struct vsc_tp *tp;
+
+ bool fw_ready;
+ bool host_ready;
+
+ atomic_t write_lock_cnt;
+
+ u32 rx_len;
+ u32 rx_hdr;
+
+ /* buffer for tx */
+ char tx_buf[MEI_VSC_MAX_MSG_SIZE + sizeof(struct mei_msg_hdr)] ____cacheline_aligned;
+ /* buffer for rx */
+ char rx_buf[MEI_VSC_MAX_MSG_SIZE + sizeof(struct mei_msg_hdr)] ____cacheline_aligned;
+};
+
+static int mei_vsc_read_helper(struct mei_vsc_hw *hw, u8 *buf,
+ u32 max_len)
+{
+ struct mei_vsc_host_timestamp ts = {
+ .realtime = ktime_to_ns(ktime_get_real()),
+ .boottime = ktime_to_ns(ktime_get_boottime()),
+ };
+
+ return vsc_tp_xfer(hw->tp, VSC_TP_CMD_READ, &ts, sizeof(ts),
+ buf, max_len);
+}
+
+static int mei_vsc_write_helper(struct mei_vsc_hw *hw, u8 *buf, u32 len)
+{
+ u8 status;
+
+ return vsc_tp_xfer(hw->tp, VSC_TP_CMD_WRITE, buf, len, &status,
+ sizeof(status));
+}
+
+static int mei_vsc_fw_status(struct mei_device *mei_dev,
+ struct mei_fw_status *fw_status)
+{
+ if (!fw_status)
+ return -EINVAL;
+
+ fw_status->count = 0;
+
+ return 0;
+}
+
+static inline enum mei_pg_state mei_vsc_pg_state(struct mei_device *mei_dev)
+{
+ return MEI_PG_OFF;
+}
+
+static void mei_vsc_intr_enable(struct mei_device *mei_dev)
+{
+ struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
+
+ vsc_tp_intr_enable(hw->tp);
+}
+
+static void mei_vsc_intr_disable(struct mei_device *mei_dev)
+{
+ struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
+
+ vsc_tp_intr_disable(hw->tp);
+}
+
+/* mei framework requires this ops */
+static void mei_vsc_intr_clear(struct mei_device *mei_dev)
+{
+}
+
+/* wait for pending irq handler */
+static void mei_vsc_synchronize_irq(struct mei_device *mei_dev)
+{
+ struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
+
+ vsc_tp_intr_synchronize(hw->tp);
+}
+
+static int mei_vsc_hw_config(struct mei_device *mei_dev)
+{
+ return 0;
+}
+
+static bool mei_vsc_host_is_ready(struct mei_device *mei_dev)
+{
+ struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
+
+ return hw->host_ready;
+}
+
+static bool mei_vsc_hw_is_ready(struct mei_device *mei_dev)
+{
+ struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
+
+ return hw->fw_ready;
+}
+
+static int mei_vsc_hw_start(struct mei_device *mei_dev)
+{
+ struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
+ int ret, rlen;
+ u8 buf;
+
+ hw->host_ready = true;
+
+ vsc_tp_intr_enable(hw->tp);
+
+ ret = read_poll_timeout(mei_vsc_read_helper, rlen,
+ rlen >= 0, MEI_VSC_POLL_DELAY_US,
+ MEI_VSC_POLL_TIMEOUT_US, true,
+ hw, &buf, sizeof(buf));
+ if (ret) {
+ dev_err(mei_dev->dev, "wait fw ready failed: %d\n", ret);
+ return ret;
+ }
+
+ hw->fw_ready = true;
+
+ return 0;
+}
+
+static bool mei_vsc_hbuf_is_ready(struct mei_device *mei_dev)
+{
+ struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
+
+ return atomic_read(&hw->write_lock_cnt) == 0;
+}
+
+static int mei_vsc_hbuf_empty_slots(struct mei_device *mei_dev)
+{
+ return MEI_VSC_MAX_MSG_SIZE / MEI_SLOT_SIZE;
+}
+
+static u32 mei_vsc_hbuf_depth(const struct mei_device *mei_dev)
+{
+ return MEI_VSC_MAX_MSG_SIZE / MEI_SLOT_SIZE;
+}
+
+static int mei_vsc_write(struct mei_device *mei_dev,
+ const void *hdr, size_t hdr_len,
+ const void *data, size_t data_len)
+{
+ struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
+ char *buf = hw->tx_buf;
+ int ret;
+
+ if (WARN_ON(!hdr || !IS_ALIGNED(hdr_len, 4)))
+ return -EINVAL;
+
+ if (!data || data_len > MEI_VSC_MAX_MSG_SIZE)
+ return -EINVAL;
+
+ atomic_inc(&hw->write_lock_cnt);
+
+ memcpy(buf, hdr, hdr_len);
+ memcpy(buf + hdr_len, data, data_len);
+
+ ret = mei_vsc_write_helper(hw, buf, hdr_len + data_len);
+
+ atomic_dec_if_positive(&hw->write_lock_cnt);
+
+ return ret < 0 ? ret : 0;
+}
+
+static inline u32 mei_vsc_read(const struct mei_device *mei_dev)
+{
+ struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
+ int ret;
+
+ ret = mei_vsc_read_helper(hw, hw->rx_buf, sizeof(hw->rx_buf));
+ if (ret < 0 || ret < sizeof(u32))
+ return 0;
+ hw->rx_len = ret;
+
+ hw->rx_hdr = get_unaligned_le32(hw->rx_buf);
+
+ return hw->rx_hdr;
+}
+
+static int mei_vsc_count_full_read_slots(struct mei_device *mei_dev)
+{
+ return MEI_VSC_MAX_MSG_SIZE / MEI_SLOT_SIZE;
+}
+
+static int mei_vsc_read_slots(struct mei_device *mei_dev, unsigned char *buf,
+ unsigned long len)
+{
+ struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
+ struct mei_msg_hdr *hdr;
+
+ hdr = (struct mei_msg_hdr *)&hw->rx_hdr;
+ if (len != hdr->length || hdr->length + sizeof(*hdr) != hw->rx_len)
+ return -EINVAL;
+
+ memcpy(buf, hw->rx_buf + sizeof(*hdr), len);
+
+ return 0;
+}
+
+static bool mei_vsc_pg_in_transition(struct mei_device *mei_dev)
+{
+ return mei_dev->pg_event >= MEI_PG_EVENT_WAIT &&
+ mei_dev->pg_event <= MEI_PG_EVENT_INTR_WAIT;
+}
+
+static bool mei_vsc_pg_is_enabled(struct mei_device *mei_dev)
+{
+ return false;
+}
+
+static int mei_vsc_hw_reset(struct mei_device *mei_dev, bool intr_enable)
+{
+ struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
+
+ vsc_tp_reset(hw->tp);
+
+ vsc_tp_intr_disable(hw->tp);
+
+ return vsc_tp_init(hw->tp, mei_dev->dev);
+}
+
+static const struct mei_hw_ops mei_vsc_hw_ops = {
+ .fw_status = mei_vsc_fw_status,
+ .pg_state = mei_vsc_pg_state,
+
+ .host_is_ready = mei_vsc_host_is_ready,
+ .hw_is_ready = mei_vsc_hw_is_ready,
+ .hw_reset = mei_vsc_hw_reset,
+ .hw_config = mei_vsc_hw_config,
+ .hw_start = mei_vsc_hw_start,
+
+ .pg_in_transition = mei_vsc_pg_in_transition,
+ .pg_is_enabled = mei_vsc_pg_is_enabled,
+
+ .intr_clear = mei_vsc_intr_clear,
+ .intr_enable = mei_vsc_intr_enable,
+ .intr_disable = mei_vsc_intr_disable,
+ .synchronize_irq = mei_vsc_synchronize_irq,
+
+ .hbuf_free_slots = mei_vsc_hbuf_empty_slots,
+ .hbuf_is_ready = mei_vsc_hbuf_is_ready,
+ .hbuf_depth = mei_vsc_hbuf_depth,
+ .write = mei_vsc_write,
+
+ .rdbuf_full_slots = mei_vsc_count_full_read_slots,
+ .read_hdr = mei_vsc_read,
+ .read = mei_vsc_read_slots,
+};
+
+static void mei_vsc_event_cb(void *context)
+{
+ struct mei_device *mei_dev = context;
+ struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev);
+ struct list_head cmpl_list;
+ s32 slots;
+ int ret;
+
+ if (mei_dev->dev_state == MEI_DEV_RESETTING ||
+ mei_dev->dev_state == MEI_DEV_INITIALIZING)
+ return;
+
+ INIT_LIST_HEAD(&cmpl_list);
+
+ guard(mutex)(&mei_dev->device_lock);
+
+ while (vsc_tp_need_read(hw->tp)) {
+ /* check slots available for reading */
+ slots = mei_count_full_read_slots(mei_dev);
+
+ ret = mei_irq_read_handler(mei_dev, &cmpl_list, &slots);
+ if (ret) {
+ if (ret != -ENODATA) {
+ if (mei_dev->dev_state != MEI_DEV_RESETTING &&
+ mei_dev->dev_state != MEI_DEV_POWER_DOWN)
+ schedule_work(&mei_dev->reset_work);
+ }
+
+ return;
+ }
+ }
+
+ mei_dev->hbuf_is_ready = mei_hbuf_is_ready(mei_dev);
+ ret = mei_irq_write_handler(mei_dev, &cmpl_list);
+ if (ret)
+ dev_err(mei_dev->dev, "dispatch write request failed: %d\n", ret);
+
+ mei_dev->hbuf_is_ready = mei_hbuf_is_ready(mei_dev);
+ mei_irq_compl_handler(mei_dev, &cmpl_list);
+}
+
+static int mei_vsc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mei_device *mei_dev;
+ struct mei_vsc_hw *hw;
+ struct vsc_tp *tp;
+ int ret;
+
+ tp = *(struct vsc_tp **)dev_get_platdata(dev);
+ if (!tp)
+ return dev_err_probe(dev, -ENODEV, "no platform data\n");
+
+ mei_dev = devm_kzalloc(dev, size_add(sizeof(*mei_dev), sizeof(*hw)),
+ GFP_KERNEL);
+ if (!mei_dev)
+ return -ENOMEM;
+
+ mei_device_init(mei_dev, dev, false, &mei_vsc_hw_ops);
+ mei_dev->fw_f_fw_ver_supported = 0;
+ mei_dev->kind = "ivsc";
+
+ hw = mei_dev_to_vsc_hw(mei_dev);
+ atomic_set(&hw->write_lock_cnt, 0);
+ hw->tp = tp;
+
+ platform_set_drvdata(pdev, mei_dev);
+
+ vsc_tp_register_event_cb(tp, mei_vsc_event_cb, mei_dev);
+
+ ret = mei_start(mei_dev);
+ if (ret) {
+ dev_err_probe(dev, ret, "init hw failed\n");
+ goto err_cancel;
+ }
+
+ ret = mei_register(mei_dev, dev);
+ if (ret)
+ goto err_stop;
+
+ pm_runtime_enable(mei_dev->dev);
+
+ return 0;
+
+err_stop:
+ mei_stop(mei_dev);
+
+err_cancel:
+ mei_cancel_work(mei_dev);
+
+ mei_disable_interrupts(mei_dev);
+
+ return ret;
+}
+
+static int mei_vsc_remove(struct platform_device *pdev)
+{
+ struct mei_device *mei_dev = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(mei_dev->dev);
+
+ mei_stop(mei_dev);
+
+ mei_disable_interrupts(mei_dev);
+
+ mei_deregister(mei_dev);
+
+ return 0;
+}
+
+static int mei_vsc_suspend(struct device *dev)
+{
+ struct mei_device *mei_dev = dev_get_drvdata(dev);
+
+ mei_stop(mei_dev);
+
+ return 0;
+}
+
+static int mei_vsc_resume(struct device *dev)
+{
+ struct mei_device *mei_dev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = mei_restart(mei_dev);
+ if (ret)
+ return ret;
+
+ /* start timer if stopped in suspend */
+ schedule_delayed_work(&mei_dev->timer_work, HZ);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(mei_vsc_pm_ops, mei_vsc_suspend, mei_vsc_resume);
+
+static const struct platform_device_id mei_vsc_id_table[] = {
+ { MEI_VSC_DRV_NAME },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, mei_vsc_id_table);
+
+static struct platform_driver mei_vsc_drv = {
+ .probe = mei_vsc_probe,
+ .remove = mei_vsc_remove,
+ .id_table = mei_vsc_id_table,
+ .driver = {
+ .name = MEI_VSC_DRV_NAME,
+ .pm = &mei_vsc_pm_ops,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+};
+module_platform_driver(mei_vsc_drv);
+
+MODULE_AUTHOR("Wentong Wu <[email protected]>");
+MODULE_AUTHOR("Zhifeng Wang <[email protected]>");
+MODULE_DESCRIPTION("Intel Visual Sensing Controller Interface");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(VSC_TP);
diff --git a/drivers/misc/mei/pxp/Kconfig b/drivers/misc/mei/pxp/Kconfig
index 4029b96afc04..e9219b61cd92 100644
--- a/drivers/misc/mei/pxp/Kconfig
+++ b/drivers/misc/mei/pxp/Kconfig
@@ -1,10 +1,9 @@
-
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2020, Intel Corporation. All rights reserved.
#
config INTEL_MEI_PXP
tristate "Intel PXP services of ME Interface"
- select INTEL_MEI_ME
+ depends on INTEL_MEI_ME
depends on DRM_I915
help
MEI Support for PXP Services on Intel platforms.
diff --git a/drivers/misc/mei/vsc-fw-loader.c b/drivers/misc/mei/vsc-fw-loader.c
new file mode 100644
index 000000000000..ffa4ccd96a10
--- /dev/null
+++ b/drivers/misc/mei/vsc-fw-loader.c
@@ -0,0 +1,770 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, Intel Corporation.
+ * Intel Visual Sensing Controller Transport Layer Linux driver
+ */
+
+#include <linux/acpi.h>
+#include <linux/align.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/firmware.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/string_helpers.h>
+#include <linux/types.h>
+
+#include <asm-generic/unaligned.h>
+
+#include "vsc-tp.h"
+
+#define VSC_MAGIC_NUM 0x49505343 /* IPSC */
+#define VSC_MAGIC_FW 0x49574653 /* IWFS */
+#define VSC_MAGIC_FILE 0x46564353 /* FVCS */
+
+#define VSC_ADDR_BASE 0xE0030000
+#define VSC_EFUSE_ADDR (VSC_ADDR_BASE + 0x038)
+#define VSC_STRAP_ADDR (VSC_ADDR_BASE + 0x100)
+
+#define VSC_MAINSTEPPING_VERSION_MASK GENMASK(7, 4)
+#define VSC_MAINSTEPPING_VERSION_A 0
+
+#define VSC_SUBSTEPPING_VERSION_MASK GENMASK(3, 0)
+#define VSC_SUBSTEPPING_VERSION_0 0
+#define VSC_SUBSTEPPING_VERSION_1 2
+
+#define VSC_BOOT_IMG_OPTION_MASK GENMASK(15, 0)
+
+#define VSC_SKU_CFG_LOCATION 0x5001A000
+#define VSC_SKU_MAX_SIZE 4100u
+
+#define VSC_ACE_IMG_CNT 2
+#define VSC_CSI_IMG_CNT 4
+#define VSC_IMG_CNT_MAX 6
+
+#define VSC_ROM_PKG_SIZE 256u
+#define VSC_FW_PKG_SIZE 512u
+
+#define VSC_IMAGE_DIR "intel/vsc/"
+
+#define VSC_CSI_IMAGE_NAME VSC_IMAGE_DIR "ivsc_fw.bin"
+#define VSC_ACE_IMAGE_NAME_FMT VSC_IMAGE_DIR "ivsc_pkg_%s_0.bin"
+#define VSC_CFG_IMAGE_NAME_FMT VSC_IMAGE_DIR "ivsc_skucfg_%s_0_1.bin"
+
+#define VSC_IMAGE_PATH_MAX_LEN 64
+
+#define VSC_SENSOR_NAME_MAX_LEN 16
+
+/* command id */
+enum {
+ VSC_CMD_QUERY = 0,
+ VSC_CMD_DL_SET = 1,
+ VSC_CMD_DL_START = 2,
+ VSC_CMD_DL_CONT = 3,
+ VSC_CMD_DUMP_MEM = 4,
+ VSC_CMD_GET_CONT = 8,
+ VSC_CMD_CAM_BOOT = 10,
+};
+
+/* command ack token */
+enum {
+ VSC_TOKEN_BOOTLOADER_REQ = 1,
+ VSC_TOKEN_DUMP_RESP = 4,
+ VSC_TOKEN_ERROR = 7,
+};
+
+/* image type */
+enum {
+ VSC_IMG_BOOTLOADER_TYPE = 1,
+ VSC_IMG_CSI_EM7D_TYPE,
+ VSC_IMG_CSI_SEM_TYPE,
+ VSC_IMG_CSI_RUNTIME_TYPE,
+ VSC_IMG_ACE_VISION_TYPE,
+ VSC_IMG_ACE_CFG_TYPE,
+ VSC_IMG_SKU_CFG_TYPE,
+};
+
+/* image fragments */
+enum {
+ VSC_IMG_BOOTLOADER_FRAG,
+ VSC_IMG_CSI_SEM_FRAG,
+ VSC_IMG_CSI_RUNTIME_FRAG,
+ VSC_IMG_ACE_VISION_FRAG,
+ VSC_IMG_ACE_CFG_FRAG,
+ VSC_IMG_CSI_EM7D_FRAG,
+ VSC_IMG_SKU_CFG_FRAG,
+ VSC_IMG_FRAG_MAX
+};
+
+struct vsc_rom_cmd {
+ __le32 magic;
+ __u8 cmd_id;
+ union {
+ /* download start */
+ struct {
+ __u8 img_type;
+ __le16 option;
+ __le32 img_len;
+ __le32 img_loc;
+ __le32 crc;
+ DECLARE_FLEX_ARRAY(__u8, res);
+ } __packed dl_start;
+ /* download set */
+ struct {
+ __u8 option;
+ __le16 img_cnt;
+ DECLARE_FLEX_ARRAY(__le32, payload);
+ } __packed dl_set;
+ /* download continue */
+ struct {
+ __u8 end_flag;
+ __le16 len;
+ /* 8 is the offset of payload */
+ __u8 payload[VSC_ROM_PKG_SIZE - 8];
+ } __packed dl_cont;
+ /* dump memory */
+ struct {
+ __u8 res;
+ __le16 len;
+ __le32 addr;
+ DECLARE_FLEX_ARRAY(__u8, payload);
+ } __packed dump_mem;
+ /* 5 is the offset of padding */
+ __u8 padding[VSC_ROM_PKG_SIZE - 5];
+ } data;
+};
+
+struct vsc_rom_cmd_ack {
+ __le32 magic;
+ __u8 token;
+ __u8 type;
+ __u8 res[2];
+ __u8 payload[];
+};
+
+struct vsc_fw_cmd {
+ __le32 magic;
+ __u8 cmd_id;
+ union {
+ struct {
+ __le16 option;
+ __u8 img_type;
+ __le32 img_len;
+ __le32 img_loc;
+ __le32 crc;
+ DECLARE_FLEX_ARRAY(__u8, res);
+ } __packed dl_start;
+ struct {
+ __le16 option;
+ __u8 img_cnt;
+ DECLARE_FLEX_ARRAY(__le32, payload);
+ } __packed dl_set;
+ struct {
+ __le32 addr;
+ __u8 len;
+ DECLARE_FLEX_ARRAY(__u8, payload);
+ } __packed dump_mem;
+ struct {
+ __u8 resv[3];
+ __le32 crc;
+ DECLARE_FLEX_ARRAY(__u8, payload);
+ } __packed boot;
+ /* 5 is the offset of padding */
+ __u8 padding[VSC_FW_PKG_SIZE - 5];
+ } data;
+};
+
+struct vsc_img {
+ __le32 magic;
+ __le32 option;
+ __le32 image_count;
+ __le32 image_location[VSC_IMG_CNT_MAX];
+};
+
+struct vsc_fw_sign {
+ __le32 magic;
+ __le32 image_size;
+ __u8 image[];
+};
+
+struct vsc_image_code_data {
+ /* fragment index */
+ u8 frag_index;
+ /* image type */
+ u8 image_type;
+};
+
+struct vsc_img_frag {
+ u8 type;
+ u32 location;
+ const u8 *data;
+ u32 size;
+};
+
+/**
+ * struct vsc_fw_loader - represent vsc firmware loader
+ * @dev: device used to request fimware
+ * @tp: transport layer used with the firmware loader
+ * @csi: CSI image
+ * @ace: ACE image
+ * @cfg: config image
+ * @tx_buf: tx buffer
+ * @rx_buf: rx buffer
+ * @option: command option
+ * @count: total image count
+ * @sensor_name: camera sensor name
+ * @frags: image fragments
+ */
+struct vsc_fw_loader {
+ struct device *dev;
+ struct vsc_tp *tp;
+
+ const struct firmware *csi;
+ const struct firmware *ace;
+ const struct firmware *cfg;
+
+ void *tx_buf;
+ void *rx_buf;
+
+ u16 option;
+ u16 count;
+
+ char sensor_name[VSC_SENSOR_NAME_MAX_LEN];
+
+ struct vsc_img_frag frags[VSC_IMG_FRAG_MAX];
+};
+
+static inline u32 vsc_sum_crc(void *data, size_t size)
+{
+ u32 crc = 0;
+ size_t i;
+
+ for (i = 0; i < size; i++)
+ crc += *((u8 *)data + i);
+
+ return crc;
+}
+
+/* get sensor name to construct image name */
+static int vsc_get_sensor_name(struct vsc_fw_loader *fw_loader,
+ struct device *dev)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER };
+ union acpi_object obj = {
+ .type = ACPI_TYPE_INTEGER,
+ .integer.value = 1,
+ };
+ struct acpi_object_list arg_list = {
+ .count = 1,
+ .pointer = &obj,
+ };
+ union acpi_object *ret_obj;
+ acpi_handle handle;
+ acpi_status status;
+ int ret = 0;
+
+ handle = ACPI_HANDLE(dev);
+ if (!handle)
+ return -EINVAL;
+
+ status = acpi_evaluate_object(handle, "SID", &arg_list, &buffer);
+ if (ACPI_FAILURE(status)) {
+ dev_err(dev, "can't evaluate SID method: %d\n", status);
+ return -ENODEV;
+ }
+
+ ret_obj = buffer.pointer;
+ if (!ret_obj) {
+ dev_err(dev, "can't locate ACPI buffer\n");
+ return -ENODEV;
+ }
+
+ if (ret_obj->type != ACPI_TYPE_STRING) {
+ dev_err(dev, "found non-string entry\n");
+ ret = -ENODEV;
+ goto out_free_buff;
+ }
+
+ /* string length excludes trailing NUL */
+ if (ret_obj->string.length >= sizeof(fw_loader->sensor_name)) {
+ dev_err(dev, "sensor name buffer too small\n");
+ ret = -EINVAL;
+ goto out_free_buff;
+ }
+
+ memcpy(fw_loader->sensor_name, ret_obj->string.pointer,
+ ret_obj->string.length);
+
+ string_lower(fw_loader->sensor_name, fw_loader->sensor_name);
+
+out_free_buff:
+ ACPI_FREE(buffer.pointer);
+
+ return ret;
+}
+
+static int vsc_identify_silicon(struct vsc_fw_loader *fw_loader)
+{
+ struct vsc_rom_cmd_ack *ack = fw_loader->rx_buf;
+ struct vsc_rom_cmd *cmd = fw_loader->tx_buf;
+ u8 version, sub_version;
+ int ret;
+
+ /* identify stepping information */
+ cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
+ cmd->cmd_id = VSC_CMD_DUMP_MEM;
+ cmd->data.dump_mem.addr = cpu_to_le32(VSC_EFUSE_ADDR);
+ cmd->data.dump_mem.len = cpu_to_le16(sizeof(__le32));
+ ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
+ if (ret)
+ return ret;
+ if (ack->token == VSC_TOKEN_ERROR)
+ return -EINVAL;
+
+ cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
+ cmd->cmd_id = VSC_CMD_GET_CONT;
+ ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
+ if (ret)
+ return ret;
+ if (ack->token != VSC_TOKEN_DUMP_RESP)
+ return -EINVAL;
+
+ version = FIELD_GET(VSC_MAINSTEPPING_VERSION_MASK, ack->payload[0]);
+ sub_version = FIELD_GET(VSC_SUBSTEPPING_VERSION_MASK, ack->payload[0]);
+
+ if (version != VSC_MAINSTEPPING_VERSION_A)
+ return -EINVAL;
+
+ if (sub_version != VSC_SUBSTEPPING_VERSION_0 &&
+ sub_version != VSC_SUBSTEPPING_VERSION_1)
+ return -EINVAL;
+
+ dev_info(fw_loader->dev, "silicon stepping version is %u:%u\n",
+ version, sub_version);
+
+ /* identify strap information */
+ cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
+ cmd->cmd_id = VSC_CMD_DUMP_MEM;
+ cmd->data.dump_mem.addr = cpu_to_le32(VSC_STRAP_ADDR);
+ cmd->data.dump_mem.len = cpu_to_le16(sizeof(__le32));
+ ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
+ if (ret)
+ return ret;
+ if (ack->token == VSC_TOKEN_ERROR)
+ return -EINVAL;
+
+ cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
+ cmd->cmd_id = VSC_CMD_GET_CONT;
+ ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
+ if (ret)
+ return ret;
+ if (ack->token != VSC_TOKEN_DUMP_RESP)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vsc_identify_csi_image(struct vsc_fw_loader *fw_loader)
+{
+ const struct firmware *image;
+ struct vsc_fw_sign *sign;
+ struct vsc_img *img;
+ unsigned int i;
+ int ret;
+
+ ret = request_firmware(&image, VSC_CSI_IMAGE_NAME, fw_loader->dev);
+ if (ret)
+ return ret;
+
+ img = (struct vsc_img *)image->data;
+ if (!img) {
+ ret = -ENOENT;
+ goto err_release_image;
+ }
+
+ if (le32_to_cpu(img->magic) != VSC_MAGIC_FILE) {
+ ret = -EINVAL;
+ goto err_release_image;
+ }
+
+ if (le32_to_cpu(img->image_count) != VSC_CSI_IMG_CNT) {
+ ret = -EINVAL;
+ goto err_release_image;
+ }
+ fw_loader->count += le32_to_cpu(img->image_count) - 1;
+
+ fw_loader->option =
+ FIELD_GET(VSC_BOOT_IMG_OPTION_MASK, le32_to_cpu(img->option));
+
+ sign = (struct vsc_fw_sign *)
+ (img->image_location + le32_to_cpu(img->image_count));
+
+ for (i = 0; i < VSC_CSI_IMG_CNT; i++) {
+ /* mapping from CSI image index to image code data */
+ static const struct vsc_image_code_data csi_image_map[] = {
+ { VSC_IMG_BOOTLOADER_FRAG, VSC_IMG_BOOTLOADER_TYPE },
+ { VSC_IMG_CSI_SEM_FRAG, VSC_IMG_CSI_SEM_TYPE },
+ { VSC_IMG_CSI_RUNTIME_FRAG, VSC_IMG_CSI_RUNTIME_TYPE },
+ { VSC_IMG_CSI_EM7D_FRAG, VSC_IMG_CSI_EM7D_TYPE },
+ };
+ struct vsc_img_frag *frag;
+
+ if ((u8 *)sign + sizeof(*sign) > image->data + image->size) {
+ ret = -EINVAL;
+ goto err_release_image;
+ }
+
+ if (le32_to_cpu(sign->magic) != VSC_MAGIC_FW) {
+ ret = -EINVAL;
+ goto err_release_image;
+ }
+
+ if (!le32_to_cpu(img->image_location[i])) {
+ ret = -EINVAL;
+ goto err_release_image;
+ }
+
+ frag = &fw_loader->frags[csi_image_map[i].frag_index];
+
+ frag->data = sign->image;
+ frag->size = le32_to_cpu(sign->image_size);
+ frag->location = le32_to_cpu(img->image_location[i]);
+ frag->type = csi_image_map[i].image_type;
+
+ sign = (struct vsc_fw_sign *)
+ (sign->image + le32_to_cpu(sign->image_size));
+ }
+
+ fw_loader->csi = image;
+
+ return 0;
+
+err_release_image:
+ release_firmware(image);
+
+ return ret;
+}
+
+static int vsc_identify_ace_image(struct vsc_fw_loader *fw_loader)
+{
+ char path[VSC_IMAGE_PATH_MAX_LEN];
+ const struct firmware *image;
+ struct vsc_fw_sign *sign;
+ struct vsc_img *img;
+ unsigned int i;
+ int ret;
+
+ snprintf(path, sizeof(path), VSC_ACE_IMAGE_NAME_FMT,
+ fw_loader->sensor_name);
+
+ ret = request_firmware(&image, path, fw_loader->dev);
+ if (ret)
+ return ret;
+
+ img = (struct vsc_img *)image->data;
+ if (!img) {
+ ret = -ENOENT;
+ goto err_release_image;
+ }
+
+ if (le32_to_cpu(img->magic) != VSC_MAGIC_FILE) {
+ ret = -EINVAL;
+ goto err_release_image;
+ }
+
+ if (le32_to_cpu(img->image_count) != VSC_ACE_IMG_CNT) {
+ ret = -EINVAL;
+ goto err_release_image;
+ }
+ fw_loader->count += le32_to_cpu(img->image_count);
+
+ sign = (struct vsc_fw_sign *)
+ (img->image_location + le32_to_cpu(img->image_count));
+
+ for (i = 0; i < VSC_ACE_IMG_CNT; i++) {
+ /* mapping from ACE image index to image code data */
+ static const struct vsc_image_code_data ace_image_map[] = {
+ { VSC_IMG_ACE_VISION_FRAG, VSC_IMG_ACE_VISION_TYPE },
+ { VSC_IMG_ACE_CFG_FRAG, VSC_IMG_ACE_CFG_TYPE },
+ };
+ struct vsc_img_frag *frag, *last_frag;
+ u8 frag_index;
+
+ if ((u8 *)sign + sizeof(*sign) > image->data + image->size) {
+ ret = -EINVAL;
+ goto err_release_image;
+ }
+
+ if (le32_to_cpu(sign->magic) != VSC_MAGIC_FW) {
+ ret = -EINVAL;
+ goto err_release_image;
+ }
+
+ frag_index = ace_image_map[i].frag_index;
+ frag = &fw_loader->frags[frag_index];
+
+ frag->data = sign->image;
+ frag->size = le32_to_cpu(sign->image_size);
+ frag->location = le32_to_cpu(img->image_location[i]);
+ frag->type = ace_image_map[i].image_type;
+
+ if (!frag->location) {
+ last_frag = &fw_loader->frags[frag_index - 1];
+ frag->location =
+ ALIGN(last_frag->location + last_frag->size, SZ_4K);
+ }
+
+ sign = (struct vsc_fw_sign *)
+ (sign->image + le32_to_cpu(sign->image_size));
+ }
+
+ fw_loader->ace = image;
+
+ return 0;
+
+err_release_image:
+ release_firmware(image);
+
+ return ret;
+}
+
+static int vsc_identify_cfg_image(struct vsc_fw_loader *fw_loader)
+{
+ struct vsc_img_frag *frag = &fw_loader->frags[VSC_IMG_SKU_CFG_FRAG];
+ char path[VSC_IMAGE_PATH_MAX_LEN];
+ const struct firmware *image;
+ u32 size;
+ int ret;
+
+ snprintf(path, sizeof(path), VSC_CFG_IMAGE_NAME_FMT,
+ fw_loader->sensor_name);
+
+ ret = request_firmware(&image, path, fw_loader->dev);
+ if (ret)
+ return ret;
+
+ /* identify image size */
+ if (image->size <= sizeof(u32) || image->size > VSC_SKU_MAX_SIZE) {
+ ret = -EINVAL;
+ goto err_release_image;
+ }
+
+ size = le32_to_cpu(*((__le32 *)image->data)) + sizeof(u32);
+ if (image->size != size) {
+ ret = -EINVAL;
+ goto err_release_image;
+ }
+
+ frag->data = image->data;
+ frag->size = image->size;
+ frag->type = VSC_IMG_SKU_CFG_TYPE;
+ frag->location = VSC_SKU_CFG_LOCATION;
+
+ fw_loader->cfg = image;
+
+ return 0;
+
+err_release_image:
+ release_firmware(image);
+
+ return ret;
+}
+
+static int vsc_download_bootloader(struct vsc_fw_loader *fw_loader)
+{
+ struct vsc_img_frag *frag = &fw_loader->frags[VSC_IMG_BOOTLOADER_FRAG];
+ struct vsc_rom_cmd_ack *ack = fw_loader->rx_buf;
+ struct vsc_rom_cmd *cmd = fw_loader->tx_buf;
+ u32 len, c_len;
+ size_t remain;
+ const u8 *p;
+ int ret;
+
+ cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
+ cmd->cmd_id = VSC_CMD_QUERY;
+ ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, ack, VSC_ROM_PKG_SIZE);
+ if (ret)
+ return ret;
+ if (ack->token != VSC_TOKEN_DUMP_RESP &&
+ ack->token != VSC_TOKEN_BOOTLOADER_REQ)
+ return -EINVAL;
+
+ cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
+ cmd->cmd_id = VSC_CMD_DL_START;
+ cmd->data.dl_start.option = cpu_to_le16(fw_loader->option);
+ cmd->data.dl_start.img_type = frag->type;
+ cmd->data.dl_start.img_len = cpu_to_le32(frag->size);
+ cmd->data.dl_start.img_loc = cpu_to_le32(frag->location);
+
+ c_len = offsetof(struct vsc_rom_cmd, data.dl_start.crc);
+ cmd->data.dl_start.crc = cpu_to_le32(vsc_sum_crc(cmd, c_len));
+
+ ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_ROM_PKG_SIZE);
+ if (ret)
+ return ret;
+
+ p = frag->data;
+ remain = frag->size;
+
+ /* download image data */
+ while (remain > 0) {
+ len = min(remain, sizeof(cmd->data.dl_cont.payload));
+
+ cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
+ cmd->cmd_id = VSC_CMD_DL_CONT;
+ cmd->data.dl_cont.len = cpu_to_le16(len);
+ cmd->data.dl_cont.end_flag = remain == len;
+ memcpy(cmd->data.dl_cont.payload, p, len);
+
+ ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_ROM_PKG_SIZE);
+ if (ret)
+ return ret;
+
+ p += len;
+ remain -= len;
+ }
+
+ return 0;
+}
+
+static int vsc_download_firmware(struct vsc_fw_loader *fw_loader)
+{
+ struct vsc_fw_cmd *cmd = fw_loader->tx_buf;
+ unsigned int i, index = 0;
+ u32 c_len;
+ int ret;
+
+ cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
+ cmd->cmd_id = VSC_CMD_DL_SET;
+ cmd->data.dl_set.img_cnt = cpu_to_le16(fw_loader->count);
+ put_unaligned_le16(fw_loader->option, &cmd->data.dl_set.option);
+
+ for (i = VSC_IMG_CSI_SEM_FRAG; i <= VSC_IMG_CSI_EM7D_FRAG; i++) {
+ struct vsc_img_frag *frag = &fw_loader->frags[i];
+
+ cmd->data.dl_set.payload[index++] = cpu_to_le32(frag->location);
+ cmd->data.dl_set.payload[index++] = cpu_to_le32(frag->size);
+ }
+
+ c_len = offsetof(struct vsc_fw_cmd, data.dl_set.payload[index]);
+ cmd->data.dl_set.payload[index] = cpu_to_le32(vsc_sum_crc(cmd, c_len));
+
+ ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_FW_PKG_SIZE);
+ if (ret)
+ return ret;
+
+ for (i = VSC_IMG_CSI_SEM_FRAG; i < VSC_IMG_FRAG_MAX; i++) {
+ struct vsc_img_frag *frag = &fw_loader->frags[i];
+ const u8 *p;
+ u32 remain;
+
+ cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
+ cmd->cmd_id = VSC_CMD_DL_START;
+ cmd->data.dl_start.img_type = frag->type;
+ cmd->data.dl_start.img_len = cpu_to_le32(frag->size);
+ cmd->data.dl_start.img_loc = cpu_to_le32(frag->location);
+ put_unaligned_le16(fw_loader->option, &cmd->data.dl_start.option);
+
+ c_len = offsetof(struct vsc_fw_cmd, data.dl_start.crc);
+ cmd->data.dl_start.crc = cpu_to_le32(vsc_sum_crc(cmd, c_len));
+
+ ret = vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_FW_PKG_SIZE);
+ if (ret)
+ return ret;
+
+ p = frag->data;
+ remain = frag->size;
+
+ /* download image data */
+ while (remain > 0) {
+ u32 len = min(remain, VSC_FW_PKG_SIZE);
+
+ memcpy(fw_loader->tx_buf, p, len);
+ memset(fw_loader->tx_buf + len, 0, VSC_FW_PKG_SIZE - len);
+
+ ret = vsc_tp_rom_xfer(fw_loader->tp, fw_loader->tx_buf,
+ NULL, VSC_FW_PKG_SIZE);
+ if (ret)
+ break;
+
+ p += len;
+ remain -= len;
+ }
+ }
+
+ cmd->magic = cpu_to_le32(VSC_MAGIC_NUM);
+ cmd->cmd_id = VSC_CMD_CAM_BOOT;
+
+ c_len = offsetof(struct vsc_fw_cmd, data.dl_start.crc);
+ cmd->data.boot.crc = cpu_to_le32(vsc_sum_crc(cmd, c_len));
+
+ return vsc_tp_rom_xfer(fw_loader->tp, cmd, NULL, VSC_FW_PKG_SIZE);
+}
+
+/**
+ * vsc_tp_init - init vsc_tp
+ * @tp: vsc_tp device handle
+ * @dev: device node for mei vsc device
+ * Return: 0 in case of success, negative value in case of error
+ */
+int vsc_tp_init(struct vsc_tp *tp, struct device *dev)
+{
+ struct vsc_fw_loader *fw_loader __free(kfree) = NULL;
+ void *tx_buf __free(kfree) = NULL;
+ void *rx_buf __free(kfree) = NULL;
+ int ret;
+
+ fw_loader = kzalloc(sizeof(*fw_loader), GFP_KERNEL);
+ if (!fw_loader)
+ return -ENOMEM;
+
+ tx_buf = kzalloc(VSC_FW_PKG_SIZE, GFP_KERNEL);
+ if (!tx_buf)
+ return -ENOMEM;
+
+ rx_buf = kzalloc(VSC_FW_PKG_SIZE, GFP_KERNEL);
+ if (!rx_buf)
+ return -ENOMEM;
+
+ fw_loader->tx_buf = tx_buf;
+ fw_loader->rx_buf = rx_buf;
+
+ fw_loader->tp = tp;
+ fw_loader->dev = dev;
+
+ ret = vsc_get_sensor_name(fw_loader, dev);
+ if (ret)
+ return ret;
+
+ ret = vsc_identify_silicon(fw_loader);
+ if (ret)
+ return ret;
+
+ ret = vsc_identify_csi_image(fw_loader);
+ if (ret)
+ return ret;
+
+ ret = vsc_identify_ace_image(fw_loader);
+ if (ret)
+ goto err_release_csi;
+
+ ret = vsc_identify_cfg_image(fw_loader);
+ if (ret)
+ goto err_release_ace;
+
+ ret = vsc_download_bootloader(fw_loader);
+ if (!ret)
+ ret = vsc_download_firmware(fw_loader);
+
+ release_firmware(fw_loader->cfg);
+
+err_release_ace:
+ release_firmware(fw_loader->ace);
+
+err_release_csi:
+ release_firmware(fw_loader->csi);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(vsc_tp_init, VSC_TP);
diff --git a/drivers/misc/mei/vsc-tp.c b/drivers/misc/mei/vsc-tp.c
new file mode 100644
index 000000000000..6f4a4be6ccb5
--- /dev/null
+++ b/drivers/misc/mei/vsc-tp.c
@@ -0,0 +1,555 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, Intel Corporation.
+ * Intel Visual Sensing Controller Transport Layer Linux driver
+ */
+
+#include <linux/acpi.h>
+#include <linux/cleanup.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+
+#include "vsc-tp.h"
+
+#define VSC_TP_RESET_PIN_TOGGLE_INTERVAL_MS 20
+#define VSC_TP_ROM_BOOTUP_DELAY_MS 10
+#define VSC_TP_ROM_XFER_POLL_TIMEOUT_US (500 * USEC_PER_MSEC)
+#define VSC_TP_ROM_XFER_POLL_DELAY_US (20 * USEC_PER_MSEC)
+#define VSC_TP_WAIT_FW_ASSERTED_TIMEOUT (2 * HZ)
+#define VSC_TP_MAX_XFER_COUNT 5
+
+#define VSC_TP_PACKET_SYNC 0x31
+#define VSC_TP_CRC_SIZE sizeof(u32)
+#define VSC_TP_MAX_MSG_SIZE 2048
+/* SPI xfer timeout size */
+#define VSC_TP_XFER_TIMEOUT_BYTES 700
+#define VSC_TP_PACKET_PADDING_SIZE 1
+#define VSC_TP_PACKET_SIZE(pkt) \
+ (sizeof(struct vsc_tp_packet) + le16_to_cpu((pkt)->len) + VSC_TP_CRC_SIZE)
+#define VSC_TP_MAX_PACKET_SIZE \
+ (sizeof(struct vsc_tp_packet) + VSC_TP_MAX_MSG_SIZE + VSC_TP_CRC_SIZE)
+#define VSC_TP_MAX_XFER_SIZE \
+ (VSC_TP_MAX_PACKET_SIZE + VSC_TP_XFER_TIMEOUT_BYTES)
+#define VSC_TP_NEXT_XFER_LEN(len, offset) \
+ (len + sizeof(struct vsc_tp_packet) + VSC_TP_CRC_SIZE - offset + VSC_TP_PACKET_PADDING_SIZE)
+
+struct vsc_tp_packet {
+ __u8 sync;
+ __u8 cmd;
+ __le16 len;
+ __le32 seq;
+ __u8 buf[] __counted_by(len);
+};
+
+struct vsc_tp {
+ /* do the actual data transfer */
+ struct spi_device *spi;
+
+ /* bind with mei framework */
+ struct platform_device *pdev;
+
+ struct gpio_desc *wakeuphost;
+ struct gpio_desc *resetfw;
+ struct gpio_desc *wakeupfw;
+
+ /* command sequence number */
+ u32 seq;
+
+ /* command buffer */
+ void *tx_buf;
+ void *rx_buf;
+
+ atomic_t assert_cnt;
+ wait_queue_head_t xfer_wait;
+
+ vsc_tp_event_cb_t event_notify;
+ void *event_notify_context;
+
+ /* used to protect command download */
+ struct mutex mutex;
+};
+
+/* GPIO resources */
+static const struct acpi_gpio_params wakeuphost_gpio = { 0, 0, false };
+static const struct acpi_gpio_params wakeuphostint_gpio = { 1, 0, false };
+static const struct acpi_gpio_params resetfw_gpio = { 2, 0, false };
+static const struct acpi_gpio_params wakeupfw = { 3, 0, false };
+
+static const struct acpi_gpio_mapping vsc_tp_acpi_gpios[] = {
+ { "wakeuphost-gpios", &wakeuphost_gpio, 1 },
+ { "wakeuphostint-gpios", &wakeuphostint_gpio, 1 },
+ { "resetfw-gpios", &resetfw_gpio, 1 },
+ { "wakeupfw-gpios", &wakeupfw, 1 },
+ {}
+};
+
+/* wakeup firmware and wait for response */
+static int vsc_tp_wakeup_request(struct vsc_tp *tp)
+{
+ int ret;
+
+ gpiod_set_value_cansleep(tp->wakeupfw, 0);
+
+ ret = wait_event_timeout(tp->xfer_wait,
+ atomic_read(&tp->assert_cnt) &&
+ gpiod_get_value_cansleep(tp->wakeuphost),
+ VSC_TP_WAIT_FW_ASSERTED_TIMEOUT);
+ if (!ret)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static void vsc_tp_wakeup_release(struct vsc_tp *tp)
+{
+ atomic_dec_if_positive(&tp->assert_cnt);
+
+ gpiod_set_value_cansleep(tp->wakeupfw, 1);
+}
+
+static int vsc_tp_dev_xfer(struct vsc_tp *tp, void *obuf, void *ibuf, size_t len)
+{
+ struct spi_message msg = { 0 };
+ struct spi_transfer xfer = {
+ .tx_buf = obuf,
+ .rx_buf = ibuf,
+ .len = len,
+ };
+
+ spi_message_init_with_transfers(&msg, &xfer, 1);
+
+ return spi_sync_locked(tp->spi, &msg);
+}
+
+static int vsc_tp_xfer_helper(struct vsc_tp *tp, struct vsc_tp_packet *pkt,
+ void *ibuf, u16 ilen)
+{
+ int ret, offset = 0, cpy_len, src_len, dst_len = sizeof(struct vsc_tp_packet);
+ int next_xfer_len = VSC_TP_PACKET_SIZE(pkt) + VSC_TP_XFER_TIMEOUT_BYTES;
+ u8 *src, *crc_src, *rx_buf = tp->rx_buf;
+ int count_down = VSC_TP_MAX_XFER_COUNT;
+ u32 recv_crc = 0, crc = ~0;
+ struct vsc_tp_packet ack;
+ u8 *dst = (u8 *)&ack;
+ bool synced = false;
+
+ do {
+ ret = vsc_tp_dev_xfer(tp, pkt, rx_buf, next_xfer_len);
+ if (ret)
+ return ret;
+ memset(pkt, 0, VSC_TP_MAX_XFER_SIZE);
+
+ if (synced) {
+ src = rx_buf;
+ src_len = next_xfer_len;
+ } else {
+ src = memchr(rx_buf, VSC_TP_PACKET_SYNC, next_xfer_len);
+ if (!src)
+ continue;
+ synced = true;
+ src_len = next_xfer_len - (src - rx_buf);
+ }
+
+ /* traverse received data */
+ while (src_len > 0) {
+ cpy_len = min(src_len, dst_len);
+ memcpy(dst, src, cpy_len);
+ crc_src = src;
+ src += cpy_len;
+ src_len -= cpy_len;
+ dst += cpy_len;
+ dst_len -= cpy_len;
+
+ if (offset < sizeof(ack)) {
+ offset += cpy_len;
+ crc = crc32(crc, crc_src, cpy_len);
+
+ if (!src_len)
+ continue;
+
+ if (le16_to_cpu(ack.len)) {
+ dst = ibuf;
+ dst_len = min(ilen, le16_to_cpu(ack.len));
+ } else {
+ dst = (u8 *)&recv_crc;
+ dst_len = sizeof(recv_crc);
+ }
+ } else if (offset < sizeof(ack) + le16_to_cpu(ack.len)) {
+ offset += cpy_len;
+ crc = crc32(crc, crc_src, cpy_len);
+
+ if (src_len) {
+ int remain = sizeof(ack) + le16_to_cpu(ack.len) - offset;
+
+ cpy_len = min(src_len, remain);
+ offset += cpy_len;
+ crc = crc32(crc, src, cpy_len);
+ src += cpy_len;
+ src_len -= cpy_len;
+ if (src_len) {
+ dst = (u8 *)&recv_crc;
+ dst_len = sizeof(recv_crc);
+ continue;
+ }
+ }
+ next_xfer_len = VSC_TP_NEXT_XFER_LEN(le16_to_cpu(ack.len), offset);
+ } else if (offset < sizeof(ack) + le16_to_cpu(ack.len) + VSC_TP_CRC_SIZE) {
+ offset += cpy_len;
+
+ if (src_len) {
+ /* terminate the traverse */
+ next_xfer_len = 0;
+ break;
+ }
+ next_xfer_len = VSC_TP_NEXT_XFER_LEN(le16_to_cpu(ack.len), offset);
+ }
+ }
+ } while (next_xfer_len > 0 && --count_down);
+
+ if (next_xfer_len > 0)
+ return -EAGAIN;
+
+ if (~recv_crc != crc || le32_to_cpu(ack.seq) != tp->seq) {
+ dev_err(&tp->spi->dev, "recv crc or seq error\n");
+ return -EINVAL;
+ }
+
+ if (ack.cmd == VSC_TP_CMD_ACK || ack.cmd == VSC_TP_CMD_NACK ||
+ ack.cmd == VSC_TP_CMD_BUSY) {
+ dev_err(&tp->spi->dev, "recv cmd ack error\n");
+ return -EAGAIN;
+ }
+
+ return min(le16_to_cpu(ack.len), ilen);
+}
+
+/**
+ * vsc_tp_xfer - transfer data to firmware
+ * @tp: vsc_tp device handle
+ * @cmd: the command to be sent to the device
+ * @obuf: the tx buffer to be sent to the device
+ * @olen: the length of tx buffer
+ * @ibuf: the rx buffer to receive from the device
+ * @ilen: the length of rx buffer
+ * Return: the length of received data in case of success,
+ * otherwise negative value
+ */
+int vsc_tp_xfer(struct vsc_tp *tp, u8 cmd, const void *obuf, size_t olen,
+ void *ibuf, size_t ilen)
+{
+ struct vsc_tp_packet *pkt = tp->tx_buf;
+ u32 crc;
+ int ret;
+
+ if (!obuf || !ibuf || olen > VSC_TP_MAX_MSG_SIZE)
+ return -EINVAL;
+
+ guard(mutex)(&tp->mutex);
+
+ pkt->sync = VSC_TP_PACKET_SYNC;
+ pkt->cmd = cmd;
+ pkt->len = cpu_to_le16(olen);
+ pkt->seq = cpu_to_le32(++tp->seq);
+ memcpy(pkt->buf, obuf, olen);
+
+ crc = ~crc32(~0, (u8 *)pkt, sizeof(pkt) + olen);
+ memcpy(pkt->buf + olen, &crc, sizeof(crc));
+
+ ret = vsc_tp_wakeup_request(tp);
+ if (unlikely(ret))
+ dev_err(&tp->spi->dev, "wakeup firmware failed ret: %d\n", ret);
+ else
+ ret = vsc_tp_xfer_helper(tp, pkt, ibuf, ilen);
+
+ vsc_tp_wakeup_release(tp);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(vsc_tp_xfer, VSC_TP);
+
+/**
+ * vsc_tp_rom_xfer - transfer data to rom code
+ * @tp: vsc_tp device handle
+ * @obuf: the data buffer to be sent to the device
+ * @ibuf: the buffer to receive data from the device
+ * @len: the length of tx buffer and rx buffer
+ * Return: 0 in case of success, negative value in case of error
+ */
+int vsc_tp_rom_xfer(struct vsc_tp *tp, const void *obuf, void *ibuf, size_t len)
+{
+ size_t words = len / sizeof(__be32);
+ int ret;
+
+ if (len % sizeof(__be32) || len > VSC_TP_MAX_MSG_SIZE)
+ return -EINVAL;
+
+ guard(mutex)(&tp->mutex);
+
+ /* rom xfer is big endian */
+ cpu_to_be32_array(tp->tx_buf, obuf, words);
+
+ ret = read_poll_timeout(gpiod_get_value_cansleep, ret,
+ !ret, VSC_TP_ROM_XFER_POLL_DELAY_US,
+ VSC_TP_ROM_XFER_POLL_TIMEOUT_US, false,
+ tp->wakeuphost);
+ if (ret) {
+ dev_err(&tp->spi->dev, "wait rom failed ret: %d\n", ret);
+ return ret;
+ }
+
+ ret = vsc_tp_dev_xfer(tp, tp->tx_buf, tp->rx_buf, len);
+ if (ret)
+ return ret;
+
+ if (ibuf)
+ cpu_to_be32_array(ibuf, tp->rx_buf, words);
+
+ return ret;
+}
+
+/**
+ * vsc_tp_reset - reset vsc transport layer
+ * @tp: vsc_tp device handle
+ */
+void vsc_tp_reset(struct vsc_tp *tp)
+{
+ disable_irq(tp->spi->irq);
+
+ /* toggle reset pin */
+ gpiod_set_value_cansleep(tp->resetfw, 0);
+ msleep(VSC_TP_RESET_PIN_TOGGLE_INTERVAL_MS);
+ gpiod_set_value_cansleep(tp->resetfw, 1);
+
+ /* wait for ROM */
+ msleep(VSC_TP_ROM_BOOTUP_DELAY_MS);
+
+ /*
+ * Set default host wakeup pin to non-active
+ * to avoid unexpected host irq interrupt.
+ */
+ gpiod_set_value_cansleep(tp->wakeupfw, 1);
+
+ atomic_set(&tp->assert_cnt, 0);
+
+ enable_irq(tp->spi->irq);
+}
+EXPORT_SYMBOL_NS_GPL(vsc_tp_reset, VSC_TP);
+
+/**
+ * vsc_tp_need_read - check if device has data to sent
+ * @tp: vsc_tp device handle
+ * Return: true if device has data to sent, otherwise false
+ */
+bool vsc_tp_need_read(struct vsc_tp *tp)
+{
+ if (!atomic_read(&tp->assert_cnt))
+ return false;
+ if (!gpiod_get_value_cansleep(tp->wakeuphost))
+ return false;
+ if (!gpiod_get_value_cansleep(tp->wakeupfw))
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL_NS_GPL(vsc_tp_need_read, VSC_TP);
+
+/**
+ * vsc_tp_register_event_cb - register a callback function to receive event
+ * @tp: vsc_tp device handle
+ * @event_cb: callback function
+ * @context: execution context of event callback
+ * Return: 0 in case of success, negative value in case of error
+ */
+int vsc_tp_register_event_cb(struct vsc_tp *tp, vsc_tp_event_cb_t event_cb,
+ void *context)
+{
+ tp->event_notify = event_cb;
+ tp->event_notify_context = context;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(vsc_tp_register_event_cb, VSC_TP);
+
+/**
+ * vsc_tp_intr_synchronize - synchronize vsc_tp interrupt
+ * @tp: vsc_tp device handle
+ */
+void vsc_tp_intr_synchronize(struct vsc_tp *tp)
+{
+ synchronize_irq(tp->spi->irq);
+}
+EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_synchronize, VSC_TP);
+
+/**
+ * vsc_tp_intr_enable - enable vsc_tp interrupt
+ * @tp: vsc_tp device handle
+ */
+void vsc_tp_intr_enable(struct vsc_tp *tp)
+{
+ enable_irq(tp->spi->irq);
+}
+EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_enable, VSC_TP);
+
+/**
+ * vsc_tp_intr_disable - disable vsc_tp interrupt
+ * @tp: vsc_tp device handle
+ */
+void vsc_tp_intr_disable(struct vsc_tp *tp)
+{
+ disable_irq(tp->spi->irq);
+}
+EXPORT_SYMBOL_NS_GPL(vsc_tp_intr_disable, VSC_TP);
+
+static irqreturn_t vsc_tp_isr(int irq, void *data)
+{
+ struct vsc_tp *tp = data;
+
+ atomic_inc(&tp->assert_cnt);
+
+ wake_up(&tp->xfer_wait);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t vsc_tp_thread_isr(int irq, void *data)
+{
+ struct vsc_tp *tp = data;
+
+ if (tp->event_notify)
+ tp->event_notify(tp->event_notify_context);
+
+ return IRQ_HANDLED;
+}
+
+static int vsc_tp_match_any(struct acpi_device *adev, void *data)
+{
+ struct acpi_device **__adev = data;
+
+ *__adev = adev;
+
+ return 1;
+}
+
+static int vsc_tp_probe(struct spi_device *spi)
+{
+ struct platform_device_info pinfo = { 0 };
+ struct device *dev = &spi->dev;
+ struct platform_device *pdev;
+ struct acpi_device *adev;
+ struct vsc_tp *tp;
+ int ret;
+
+ tp = devm_kzalloc(dev, sizeof(*tp), GFP_KERNEL);
+ if (!tp)
+ return -ENOMEM;
+
+ tp->tx_buf = devm_kzalloc(dev, VSC_TP_MAX_XFER_SIZE, GFP_KERNEL);
+ if (!tp->tx_buf)
+ return -ENOMEM;
+
+ tp->rx_buf = devm_kzalloc(dev, VSC_TP_MAX_XFER_SIZE, GFP_KERNEL);
+ if (!tp->rx_buf)
+ return -ENOMEM;
+
+ ret = devm_acpi_dev_add_driver_gpios(dev, vsc_tp_acpi_gpios);
+ if (ret)
+ return ret;
+
+ tp->wakeuphost = devm_gpiod_get(dev, "wakeuphost", GPIOD_IN);
+ if (IS_ERR(tp->wakeuphost))
+ return PTR_ERR(tp->wakeuphost);
+
+ tp->resetfw = devm_gpiod_get(dev, "resetfw", GPIOD_OUT_HIGH);
+ if (IS_ERR(tp->resetfw))
+ return PTR_ERR(tp->resetfw);
+
+ tp->wakeupfw = devm_gpiod_get(dev, "wakeupfw", GPIOD_OUT_HIGH);
+ if (IS_ERR(tp->wakeupfw))
+ return PTR_ERR(tp->wakeupfw);
+
+ atomic_set(&tp->assert_cnt, 0);
+ init_waitqueue_head(&tp->xfer_wait);
+ tp->spi = spi;
+
+ irq_set_status_flags(spi->irq, IRQ_DISABLE_UNLAZY);
+ ret = devm_request_threaded_irq(dev, spi->irq, vsc_tp_isr,
+ vsc_tp_thread_isr,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ dev_name(dev), tp);
+ if (ret)
+ return ret;
+
+ mutex_init(&tp->mutex);
+
+ /* only one child acpi device */
+ ret = acpi_dev_for_each_child(ACPI_COMPANION(dev),
+ vsc_tp_match_any, &adev);
+ if (!ret) {
+ ret = -ENODEV;
+ goto err_destroy_lock;
+ }
+ pinfo.fwnode = acpi_fwnode_handle(adev);
+
+ pinfo.name = "intel_vsc";
+ pinfo.data = &tp;
+ pinfo.size_data = sizeof(tp);
+ pinfo.id = PLATFORM_DEVID_NONE;
+
+ pdev = platform_device_register_full(&pinfo);
+ if (IS_ERR(pdev)) {
+ ret = PTR_ERR(pdev);
+ goto err_destroy_lock;
+ }
+
+ tp->pdev = pdev;
+ spi_set_drvdata(spi, tp);
+
+ return 0;
+
+err_destroy_lock:
+ mutex_destroy(&tp->mutex);
+
+ return ret;
+}
+
+static void vsc_tp_remove(struct spi_device *spi)
+{
+ struct vsc_tp *tp = spi_get_drvdata(spi);
+
+ platform_device_unregister(tp->pdev);
+
+ mutex_destroy(&tp->mutex);
+}
+
+static const struct acpi_device_id vsc_tp_acpi_ids[] = {
+ { "INTC1009" }, /* Raptor Lake */
+ { "INTC1058" }, /* Tiger Lake */
+ { "INTC1094" }, /* Alder Lake */
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, vsc_tp_acpi_ids);
+
+static struct spi_driver vsc_tp_driver = {
+ .probe = vsc_tp_probe,
+ .remove = vsc_tp_remove,
+ .driver = {
+ .name = "vsc-tp",
+ .acpi_match_table = vsc_tp_acpi_ids,
+ },
+};
+module_spi_driver(vsc_tp_driver);
+
+MODULE_AUTHOR("Wentong Wu <[email protected]>");
+MODULE_AUTHOR("Zhifeng Wang <[email protected]>");
+MODULE_DESCRIPTION("Intel Visual Sensing Controller Transport Layer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/mei/vsc-tp.h b/drivers/misc/mei/vsc-tp.h
new file mode 100644
index 000000000000..f9513ddc3e40
--- /dev/null
+++ b/drivers/misc/mei/vsc-tp.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2023, Intel Corporation.
+ * Intel Visual Sensing Controller Transport Layer Linux driver
+ */
+
+#ifndef _VSC_TP_H_
+#define _VSC_TP_H_
+
+#include <linux/types.h>
+
+#define VSC_TP_CMD_WRITE 0x01
+#define VSC_TP_CMD_READ 0x02
+
+#define VSC_TP_CMD_ACK 0x10
+#define VSC_TP_CMD_NACK 0x11
+#define VSC_TP_CMD_BUSY 0x12
+
+struct vsc_tp;
+
+/**
+ * typedef vsc_event_cb_t - event callback function signature
+ * @context: the execution context of who registered this callback
+ *
+ * The callback function is called in interrupt context and the data
+ * payload is only valid during the call. If the user needs access
+ * the data payload later, it must copy the payload.
+ */
+typedef void (*vsc_tp_event_cb_t)(void *context);
+
+int vsc_tp_rom_xfer(struct vsc_tp *tp, const void *obuf, void *ibuf,
+ size_t len);
+
+int vsc_tp_xfer(struct vsc_tp *tp, u8 cmd, const void *obuf, size_t olen,
+ void *ibuf, size_t ilen);
+
+int vsc_tp_register_event_cb(struct vsc_tp *tp, vsc_tp_event_cb_t event_cb,
+ void *context);
+
+void vsc_tp_intr_enable(struct vsc_tp *tp);
+void vsc_tp_intr_disable(struct vsc_tp *tp);
+void vsc_tp_intr_synchronize(struct vsc_tp *tp);
+
+void vsc_tp_reset(struct vsc_tp *tp);
+
+bool vsc_tp_need_read(struct vsc_tp *tp);
+
+int vsc_tp_init(struct vsc_tp *tp, struct device *dev);
+
+#endif
diff --git a/drivers/misc/nsm.c b/drivers/misc/nsm.c
new file mode 100644
index 000000000000..0eaa3b4484bd
--- /dev/null
+++ b/drivers/misc/nsm.c
@@ -0,0 +1,506 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Amazon Nitro Secure Module driver.
+ *
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * The Nitro Secure Module implements commands via CBOR over virtio.
+ * This driver exposes a raw message ioctls on /dev/nsm that user
+ * space can use to issue these commands.
+ */
+
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/hw_random.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/uio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio.h>
+#include <linux/wait.h>
+#include <uapi/linux/nsm.h>
+
+/* Timeout for NSM virtqueue respose in milliseconds. */
+#define NSM_DEFAULT_TIMEOUT_MSECS (120000) /* 2 minutes */
+
+/* Maximum length input data */
+struct nsm_data_req {
+ u32 len;
+ u8 data[NSM_REQUEST_MAX_SIZE];
+};
+
+/* Maximum length output data */
+struct nsm_data_resp {
+ u32 len;
+ u8 data[NSM_RESPONSE_MAX_SIZE];
+};
+
+/* Full NSM request/response message */
+struct nsm_msg {
+ struct nsm_data_req req;
+ struct nsm_data_resp resp;
+};
+
+struct nsm {
+ struct virtio_device *vdev;
+ struct virtqueue *vq;
+ struct mutex lock;
+ struct completion cmd_done;
+ struct miscdevice misc;
+ struct hwrng hwrng;
+ struct work_struct misc_init;
+ struct nsm_msg msg;
+};
+
+/* NSM device ID */
+static const struct virtio_device_id id_table[] = {
+ { VIRTIO_ID_NITRO_SEC_MOD, VIRTIO_DEV_ANY_ID },
+ { 0 },
+};
+
+static struct nsm *file_to_nsm(struct file *file)
+{
+ return container_of(file->private_data, struct nsm, misc);
+}
+
+static struct nsm *hwrng_to_nsm(struct hwrng *rng)
+{
+ return container_of(rng, struct nsm, hwrng);
+}
+
+#define CBOR_TYPE_MASK 0xE0
+#define CBOR_TYPE_MAP 0xA0
+#define CBOR_TYPE_TEXT 0x60
+#define CBOR_TYPE_ARRAY 0x40
+#define CBOR_HEADER_SIZE_SHORT 1
+
+#define CBOR_SHORT_SIZE_MAX_VALUE 23
+#define CBOR_LONG_SIZE_U8 24
+#define CBOR_LONG_SIZE_U16 25
+#define CBOR_LONG_SIZE_U32 26
+#define CBOR_LONG_SIZE_U64 27
+
+static bool cbor_object_is_array(const u8 *cbor_object, size_t cbor_object_size)
+{
+ if (cbor_object_size == 0 || cbor_object == NULL)
+ return false;
+
+ return (cbor_object[0] & CBOR_TYPE_MASK) == CBOR_TYPE_ARRAY;
+}
+
+static int cbor_object_get_array(u8 *cbor_object, size_t cbor_object_size, u8 **cbor_array)
+{
+ u8 cbor_short_size;
+ void *array_len_p;
+ u64 array_len;
+ u64 array_offset;
+
+ if (!cbor_object_is_array(cbor_object, cbor_object_size))
+ return -EFAULT;
+
+ cbor_short_size = (cbor_object[0] & 0x1F);
+
+ /* Decoding byte array length */
+ array_offset = CBOR_HEADER_SIZE_SHORT;
+ if (cbor_short_size >= CBOR_LONG_SIZE_U8)
+ array_offset += BIT(cbor_short_size - CBOR_LONG_SIZE_U8);
+
+ if (cbor_object_size < array_offset)
+ return -EFAULT;
+
+ array_len_p = &cbor_object[1];
+
+ switch (cbor_short_size) {
+ case CBOR_SHORT_SIZE_MAX_VALUE: /* short encoding */
+ array_len = cbor_short_size;
+ break;
+ case CBOR_LONG_SIZE_U8:
+ array_len = *(u8 *)array_len_p;
+ break;
+ case CBOR_LONG_SIZE_U16:
+ array_len = be16_to_cpup((__be16 *)array_len_p);
+ break;
+ case CBOR_LONG_SIZE_U32:
+ array_len = be32_to_cpup((__be32 *)array_len_p);
+ break;
+ case CBOR_LONG_SIZE_U64:
+ array_len = be64_to_cpup((__be64 *)array_len_p);
+ break;
+ }
+
+ if (cbor_object_size < array_offset)
+ return -EFAULT;
+
+ if (cbor_object_size - array_offset < array_len)
+ return -EFAULT;
+
+ if (array_len > INT_MAX)
+ return -EFAULT;
+
+ *cbor_array = cbor_object + array_offset;
+ return array_len;
+}
+
+/* Copy the request of a raw message to kernel space */
+static int fill_req_raw(struct nsm *nsm, struct nsm_data_req *req,
+ struct nsm_raw *raw)
+{
+ /* Verify the user input size. */
+ if (raw->request.len > sizeof(req->data))
+ return -EMSGSIZE;
+
+ /* Copy the request payload */
+ if (copy_from_user(req->data, u64_to_user_ptr(raw->request.addr),
+ raw->request.len))
+ return -EFAULT;
+
+ req->len = raw->request.len;
+
+ return 0;
+}
+
+/* Copy the response of a raw message back to user-space */
+static int parse_resp_raw(struct nsm *nsm, struct nsm_data_resp *resp,
+ struct nsm_raw *raw)
+{
+ /* Truncate any message that does not fit. */
+ raw->response.len = min_t(u64, raw->response.len, resp->len);
+
+ /* Copy the response content to user space */
+ if (copy_to_user(u64_to_user_ptr(raw->response.addr),
+ resp->data, raw->response.len))
+ return -EFAULT;
+
+ return 0;
+}
+
+/* Virtqueue interrupt handler */
+static void nsm_vq_callback(struct virtqueue *vq)
+{
+ struct nsm *nsm = vq->vdev->priv;
+
+ complete(&nsm->cmd_done);
+}
+
+/* Forward a message to the NSM device and wait for the response from it */
+static int nsm_sendrecv_msg_locked(struct nsm *nsm)
+{
+ struct device *dev = &nsm->vdev->dev;
+ struct scatterlist sg_in, sg_out;
+ struct nsm_msg *msg = &nsm->msg;
+ struct virtqueue *vq = nsm->vq;
+ unsigned int len;
+ void *queue_buf;
+ bool kicked;
+ int rc;
+
+ /* Initialize scatter-gather lists with request and response buffers. */
+ sg_init_one(&sg_out, msg->req.data, msg->req.len);
+ sg_init_one(&sg_in, msg->resp.data, sizeof(msg->resp.data));
+
+ init_completion(&nsm->cmd_done);
+ /* Add the request buffer (read by the device). */
+ rc = virtqueue_add_outbuf(vq, &sg_out, 1, msg->req.data, GFP_KERNEL);
+ if (rc)
+ return rc;
+
+ /* Add the response buffer (written by the device). */
+ rc = virtqueue_add_inbuf(vq, &sg_in, 1, msg->resp.data, GFP_KERNEL);
+ if (rc)
+ goto cleanup;
+
+ kicked = virtqueue_kick(vq);
+ if (!kicked) {
+ /* Cannot kick the virtqueue. */
+ rc = -EIO;
+ goto cleanup;
+ }
+
+ /* If the kick succeeded, wait for the device's response. */
+ if (!wait_for_completion_io_timeout(&nsm->cmd_done,
+ msecs_to_jiffies(NSM_DEFAULT_TIMEOUT_MSECS))) {
+ rc = -ETIMEDOUT;
+ goto cleanup;
+ }
+
+ queue_buf = virtqueue_get_buf(vq, &len);
+ if (!queue_buf || (queue_buf != msg->req.data)) {
+ dev_err(dev, "wrong request buffer.");
+ rc = -ENODATA;
+ goto cleanup;
+ }
+
+ queue_buf = virtqueue_get_buf(vq, &len);
+ if (!queue_buf || (queue_buf != msg->resp.data)) {
+ dev_err(dev, "wrong response buffer.");
+ rc = -ENODATA;
+ goto cleanup;
+ }
+
+ msg->resp.len = len;
+
+ rc = 0;
+
+cleanup:
+ if (rc) {
+ /* Clean the virtqueue. */
+ while (virtqueue_get_buf(vq, &len) != NULL)
+ ;
+ }
+
+ return rc;
+}
+
+static int fill_req_get_random(struct nsm *nsm, struct nsm_data_req *req)
+{
+ /*
+ * 69 # text(9)
+ * 47657452616E646F6D # "GetRandom"
+ */
+ const u8 request[] = { CBOR_TYPE_TEXT + strlen("GetRandom"),
+ 'G', 'e', 't', 'R', 'a', 'n', 'd', 'o', 'm' };
+
+ memcpy(req->data, request, sizeof(request));
+ req->len = sizeof(request);
+
+ return 0;
+}
+
+static int parse_resp_get_random(struct nsm *nsm, struct nsm_data_resp *resp,
+ void *out, size_t max)
+{
+ /*
+ * A1 # map(1)
+ * 69 # text(9) - Name of field
+ * 47657452616E646F6D # "GetRandom"
+ * A1 # map(1) - The field itself
+ * 66 # text(6)
+ * 72616E646F6D # "random"
+ * # The rest of the response is random data
+ */
+ const u8 response[] = { CBOR_TYPE_MAP + 1,
+ CBOR_TYPE_TEXT + strlen("GetRandom"),
+ 'G', 'e', 't', 'R', 'a', 'n', 'd', 'o', 'm',
+ CBOR_TYPE_MAP + 1,
+ CBOR_TYPE_TEXT + strlen("random"),
+ 'r', 'a', 'n', 'd', 'o', 'm' };
+ struct device *dev = &nsm->vdev->dev;
+ u8 *rand_data = NULL;
+ u8 *resp_ptr = resp->data;
+ u64 resp_len = resp->len;
+ int rc;
+
+ if ((resp->len < sizeof(response) + 1) ||
+ (memcmp(resp_ptr, response, sizeof(response)) != 0)) {
+ dev_err(dev, "Invalid response for GetRandom");
+ return -EFAULT;
+ }
+
+ resp_ptr += sizeof(response);
+ resp_len -= sizeof(response);
+
+ rc = cbor_object_get_array(resp_ptr, resp_len, &rand_data);
+ if (rc < 0) {
+ dev_err(dev, "GetRandom: Invalid CBOR encoding\n");
+ return rc;
+ }
+
+ rc = min_t(size_t, rc, max);
+ memcpy(out, rand_data, rc);
+
+ return rc;
+}
+
+/*
+ * HwRNG implementation
+ */
+static int nsm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+ struct nsm *nsm = hwrng_to_nsm(rng);
+ struct device *dev = &nsm->vdev->dev;
+ int rc = 0;
+
+ /* NSM always needs to wait for a response */
+ if (!wait)
+ return 0;
+
+ mutex_lock(&nsm->lock);
+
+ rc = fill_req_get_random(nsm, &nsm->msg.req);
+ if (rc != 0)
+ goto out;
+
+ rc = nsm_sendrecv_msg_locked(nsm);
+ if (rc != 0)
+ goto out;
+
+ rc = parse_resp_get_random(nsm, &nsm->msg.resp, data, max);
+ if (rc < 0)
+ goto out;
+
+ dev_dbg(dev, "RNG: returning rand bytes = %d", rc);
+out:
+ mutex_unlock(&nsm->lock);
+ return rc;
+}
+
+static long nsm_dev_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = u64_to_user_ptr((u64)arg);
+ struct nsm *nsm = file_to_nsm(file);
+ struct nsm_raw raw;
+ int r = 0;
+
+ if (cmd != NSM_IOCTL_RAW)
+ return -EINVAL;
+
+ if (_IOC_SIZE(cmd) != sizeof(raw))
+ return -EINVAL;
+
+ /* Copy user argument struct to kernel argument struct */
+ r = -EFAULT;
+ if (copy_from_user(&raw, argp, _IOC_SIZE(cmd)))
+ goto out;
+
+ mutex_lock(&nsm->lock);
+
+ /* Convert kernel argument struct to device request */
+ r = fill_req_raw(nsm, &nsm->msg.req, &raw);
+ if (r)
+ goto out;
+
+ /* Send message to NSM and read reply */
+ r = nsm_sendrecv_msg_locked(nsm);
+ if (r)
+ goto out;
+
+ /* Parse device response into kernel argument struct */
+ r = parse_resp_raw(nsm, &nsm->msg.resp, &raw);
+ if (r)
+ goto out;
+
+ /* Copy kernel argument struct back to user argument struct */
+ r = -EFAULT;
+ if (copy_to_user(argp, &raw, sizeof(raw)))
+ goto out;
+
+ r = 0;
+
+out:
+ mutex_unlock(&nsm->lock);
+ return r;
+}
+
+static int nsm_device_init_vq(struct virtio_device *vdev)
+{
+ struct virtqueue *vq = virtio_find_single_vq(vdev,
+ nsm_vq_callback, "nsm.vq.0");
+ struct nsm *nsm = vdev->priv;
+
+ if (IS_ERR(vq))
+ return PTR_ERR(vq);
+
+ nsm->vq = vq;
+
+ return 0;
+}
+
+static const struct file_operations nsm_dev_fops = {
+ .unlocked_ioctl = nsm_dev_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
+};
+
+/* Handler for probing the NSM device */
+static int nsm_device_probe(struct virtio_device *vdev)
+{
+ struct device *dev = &vdev->dev;
+ struct nsm *nsm;
+ int rc;
+
+ nsm = devm_kzalloc(&vdev->dev, sizeof(*nsm), GFP_KERNEL);
+ if (!nsm)
+ return -ENOMEM;
+
+ vdev->priv = nsm;
+ nsm->vdev = vdev;
+
+ rc = nsm_device_init_vq(vdev);
+ if (rc) {
+ dev_err(dev, "queue failed to initialize: %d.\n", rc);
+ goto err_init_vq;
+ }
+
+ mutex_init(&nsm->lock);
+
+ /* Register as hwrng provider */
+ nsm->hwrng = (struct hwrng) {
+ .read = nsm_rng_read,
+ .name = "nsm-hwrng",
+ .quality = 1000,
+ };
+
+ rc = hwrng_register(&nsm->hwrng);
+ if (rc) {
+ dev_err(dev, "RNG initialization error: %d.\n", rc);
+ goto err_hwrng;
+ }
+
+ /* Register /dev/nsm device node */
+ nsm->misc = (struct miscdevice) {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "nsm",
+ .fops = &nsm_dev_fops,
+ .mode = 0666,
+ };
+
+ rc = misc_register(&nsm->misc);
+ if (rc) {
+ dev_err(dev, "misc device registration error: %d.\n", rc);
+ goto err_misc;
+ }
+
+ return 0;
+
+err_misc:
+ hwrng_unregister(&nsm->hwrng);
+err_hwrng:
+ vdev->config->del_vqs(vdev);
+err_init_vq:
+ return rc;
+}
+
+/* Handler for removing the NSM device */
+static void nsm_device_remove(struct virtio_device *vdev)
+{
+ struct nsm *nsm = vdev->priv;
+
+ hwrng_unregister(&nsm->hwrng);
+
+ vdev->config->del_vqs(vdev);
+ misc_deregister(&nsm->misc);
+}
+
+/* NSM device configuration structure */
+static struct virtio_driver virtio_nsm_driver = {
+ .feature_table = 0,
+ .feature_table_size = 0,
+ .feature_table_legacy = 0,
+ .feature_table_size_legacy = 0,
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = nsm_device_probe,
+ .remove = nsm_device_remove,
+};
+
+module_virtio_driver(virtio_nsm_driver);
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio NSM driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index af519088732d..c38a6083f0a7 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -28,14 +28,14 @@
#define DRV_MODULE_NAME "pci-endpoint-test"
#define IRQ_TYPE_UNDEFINED -1
-#define IRQ_TYPE_LEGACY 0
+#define IRQ_TYPE_INTX 0
#define IRQ_TYPE_MSI 1
#define IRQ_TYPE_MSIX 2
#define PCI_ENDPOINT_TEST_MAGIC 0x0
#define PCI_ENDPOINT_TEST_COMMAND 0x4
-#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
+#define COMMAND_RAISE_INTX_IRQ BIT(0)
#define COMMAND_RAISE_MSI_IRQ BIT(1)
#define COMMAND_RAISE_MSIX_IRQ BIT(2)
#define COMMAND_READ BIT(3)
@@ -183,8 +183,8 @@ static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
bool res = true;
switch (type) {
- case IRQ_TYPE_LEGACY:
- irq = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY);
+ case IRQ_TYPE_INTX:
+ irq = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_INTX);
if (irq < 0)
dev_err(dev, "Failed to get Legacy interrupt\n");
break;
@@ -244,7 +244,7 @@ static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test)
fail:
switch (irq_type) {
- case IRQ_TYPE_LEGACY:
+ case IRQ_TYPE_INTX:
dev_err(dev, "Failed to request IRQ %d for Legacy\n",
pci_irq_vector(pdev, i));
break;
@@ -263,6 +263,15 @@ fail:
return false;
}
+static const u32 bar_test_pattern[] = {
+ 0xA0A0A0A0,
+ 0xA1A1A1A1,
+ 0xA2A2A2A2,
+ 0xA3A3A3A3,
+ 0xA4A4A4A4,
+ 0xA5A5A5A5,
+};
+
static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
enum pci_barno barno)
{
@@ -280,26 +289,27 @@ static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
size = 0x4;
for (j = 0; j < size; j += 4)
- pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0);
+ pci_endpoint_test_bar_writel(test, barno, j,
+ bar_test_pattern[barno]);
for (j = 0; j < size; j += 4) {
val = pci_endpoint_test_bar_readl(test, barno, j);
- if (val != 0xA0A0A0A0)
+ if (val != bar_test_pattern[barno])
return false;
}
return true;
}
-static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test)
+static bool pci_endpoint_test_intx_irq(struct pci_endpoint_test *test)
{
u32 val;
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
- IRQ_TYPE_LEGACY);
+ IRQ_TYPE_INTX);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 0);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
- COMMAND_RAISE_LEGACY_IRQ);
+ COMMAND_RAISE_INTX_IRQ);
val = wait_for_completion_timeout(&test->irq_raised,
msecs_to_jiffies(1000));
if (!val)
@@ -385,7 +395,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
if (use_dma)
flags |= FLAG_USE_DMA;
- if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
+ if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) {
dev_err(dev, "Invalid IRQ type option\n");
goto err;
}
@@ -521,7 +531,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
if (use_dma)
flags |= FLAG_USE_DMA;
- if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
+ if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) {
dev_err(dev, "Invalid IRQ type option\n");
goto err;
}
@@ -621,7 +631,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
if (use_dma)
flags |= FLAG_USE_DMA;
- if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
+ if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) {
dev_err(dev, "Invalid IRQ type option\n");
goto err;
}
@@ -691,7 +701,7 @@ static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
struct pci_dev *pdev = test->pdev;
struct device *dev = &pdev->dev;
- if (req_irq_type < IRQ_TYPE_LEGACY || req_irq_type > IRQ_TYPE_MSIX) {
+ if (req_irq_type < IRQ_TYPE_INTX || req_irq_type > IRQ_TYPE_MSIX) {
dev_err(dev, "Invalid IRQ type option\n");
return false;
}
@@ -737,8 +747,8 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
goto ret;
ret = pci_endpoint_test_bar(test, bar);
break;
- case PCITEST_LEGACY_IRQ:
- ret = pci_endpoint_test_legacy_irq(test);
+ case PCITEST_INTX_IRQ:
+ ret = pci_endpoint_test_intx_irq(test);
break;
case PCITEST_MSI:
case PCITEST_MSIX:
@@ -801,7 +811,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
test->irq_type = IRQ_TYPE_UNDEFINED;
if (no_msi)
- irq_type = IRQ_TYPE_LEGACY;
+ irq_type = IRQ_TYPE_INTX;
data = (struct pci_endpoint_test_data *)ent->driver_data;
if (data) {
@@ -860,7 +870,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, test);
- id = ida_simple_get(&pci_endpoint_test_ida, 0, 0, GFP_KERNEL);
+ id = ida_alloc(&pci_endpoint_test_ida, GFP_KERNEL);
if (id < 0) {
err = id;
dev_err(dev, "Unable to get id\n");
@@ -907,7 +917,7 @@ err_kfree_test_name:
kfree(test->name);
err_ida_remove:
- ida_simple_remove(&pci_endpoint_test_ida, id);
+ ida_free(&pci_endpoint_test_ida, id);
err_iounmap:
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
@@ -943,7 +953,7 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
misc_deregister(&test->miscdev);
kfree(misc_device->name);
kfree(test->name);
- ida_simple_remove(&pci_endpoint_test_ida, id);
+ ida_free(&pci_endpoint_test_ida, id);
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
if (test->bar[bar])
pci_iounmap(pdev, test->bar[bar]);
diff --git a/drivers/misc/pvpanic/pvpanic-mmio.c b/drivers/misc/pvpanic/pvpanic-mmio.c
index 9715798acce3..f3f2113a54a7 100644
--- a/drivers/misc/pvpanic/pvpanic-mmio.c
+++ b/drivers/misc/pvpanic/pvpanic-mmio.c
@@ -7,16 +7,15 @@
* Copyright (C) 2021 Oracle.
*/
+#include <linux/device.h>
+#include <linux/err.h>
#include <linux/io.h>
-#include <linux/kernel.h>
+#include <linux/ioport.h>
#include <linux/kexec.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/types.h>
-#include <linux/slab.h>
-
-#include <uapi/misc/pvpanic.h>
#include "pvpanic.h"
diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c
index 689af4c28c2a..9ad20e82785b 100644
--- a/drivers/misc/pvpanic/pvpanic-pci.c
+++ b/drivers/misc/pvpanic/pvpanic-pci.c
@@ -5,17 +5,13 @@
* Copyright (C) 2021 Oracle.
*/
-#include <linux/kernel.h>
+#include <linux/errno.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/types.h>
-#include <linux/slab.h>
-
-#include <uapi/misc/pvpanic.h>
#include "pvpanic.h"
-#define PCI_VENDOR_ID_REDHAT 0x1b36
#define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011
MODULE_AUTHOR("Mihai Carabas <[email protected]>");
diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c
index 305b367e0ce3..df3457ce1cb1 100644
--- a/drivers/misc/pvpanic/pvpanic.c
+++ b/drivers/misc/pvpanic/pvpanic.c
@@ -8,16 +8,20 @@
*/
#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gfp_types.h>
#include <linux/io.h>
-#include <linux/kernel.h>
#include <linux/kexec.h>
+#include <linux/kstrtox.h>
+#include <linux/limits.h>
+#include <linux/list.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/platform_device.h>
#include <linux/panic_notifier.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/sysfs.h>
#include <linux/types.h>
-#include <linux/cdev.h>
-#include <linux/list.h>
#include <uapi/misc/pvpanic.h>
diff --git a/drivers/misc/pvpanic/pvpanic.h b/drivers/misc/pvpanic/pvpanic.h
index 46ffb10438ad..a42fa760eed5 100644
--- a/drivers/misc/pvpanic/pvpanic.h
+++ b/drivers/misc/pvpanic/pvpanic.h
@@ -8,6 +8,11 @@
#ifndef PVPANIC_H_
#define PVPANIC_H_
+#include <linux/compiler_types.h>
+
+struct attribute_group;
+struct device;
+
int devm_pvpanic_probe(struct device *dev, void __iomem *base);
extern const struct attribute_group *pvpanic_dev_groups[];
diff --git a/drivers/misc/vmw_vmci/vmci_handle_array.c b/drivers/misc/vmw_vmci/vmci_handle_array.c
index de7fee7ead1b..681b3500125a 100644
--- a/drivers/misc/vmw_vmci/vmci_handle_array.c
+++ b/drivers/misc/vmw_vmci/vmci_handle_array.c
@@ -8,12 +8,6 @@
#include <linux/slab.h>
#include "vmci_handle_array.h"
-static size_t handle_arr_calc_size(u32 capacity)
-{
- return VMCI_HANDLE_ARRAY_HEADER_SIZE +
- capacity * sizeof(struct vmci_handle);
-}
-
struct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity)
{
struct vmci_handle_arr *array;
@@ -25,7 +19,7 @@ struct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity)
capacity = min((u32)VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY,
max_capacity);
- array = kmalloc(handle_arr_calc_size(capacity), GFP_ATOMIC);
+ array = kmalloc(struct_size(array, entries, capacity), GFP_ATOMIC);
if (!array)
return NULL;
@@ -51,8 +45,8 @@ int vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr,
struct vmci_handle_arr *new_array;
u32 capacity_bump = min(array->max_capacity - array->capacity,
array->capacity);
- size_t new_size = handle_arr_calc_size(array->capacity +
- capacity_bump);
+ size_t new_size = struct_size(array, entries,
+ size_add(array->capacity, capacity_bump));
if (array->size >= array->max_capacity)
return VMCI_ERROR_NO_MEM;
diff --git a/drivers/misc/vmw_vmci/vmci_handle_array.h b/drivers/misc/vmw_vmci/vmci_handle_array.h
index b0e6b1956014..27a38b97e8a8 100644
--- a/drivers/misc/vmw_vmci/vmci_handle_array.h
+++ b/drivers/misc/vmw_vmci/vmci_handle_array.h
@@ -20,14 +20,8 @@ struct vmci_handle_arr {
struct vmci_handle entries[] __counted_by(capacity);
};
-#define VMCI_HANDLE_ARRAY_HEADER_SIZE \
- offsetof(struct vmci_handle_arr, entries)
/* Select a default capacity that results in a 64 byte sized array */
#define VMCI_HANDLE_ARRAY_DEFAULT_CAPACITY 6
-/* Make sure that the max array size can be expressed by a u32 */
-#define VMCI_HANDLE_ARRAY_MAX_CAPACITY \
- ((U32_MAX - VMCI_HANDLE_ARRAY_HEADER_SIZE - 1) / \
- sizeof(struct vmci_handle))
struct vmci_handle_arr *vmci_handle_arr_create(u32 capacity, u32 max_capacity);
void vmci_handle_arr_destroy(struct vmci_handle_arr *array);
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 134c36edb6cf..32d49100dff5 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -400,6 +400,10 @@ struct mmc_blk_ioc_data {
struct mmc_ioc_cmd ic;
unsigned char *buf;
u64 buf_bytes;
+ unsigned int flags;
+#define MMC_BLK_IOC_DROP BIT(0) /* drop this mrq */
+#define MMC_BLK_IOC_SBC BIT(1) /* use mrq.sbc */
+
struct mmc_rpmb_data *rpmb;
};
@@ -465,7 +469,7 @@ static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr,
}
static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
- struct mmc_blk_ioc_data *idata)
+ struct mmc_blk_ioc_data **idatas, int i)
{
struct mmc_command cmd = {}, sbc = {};
struct mmc_data data = {};
@@ -475,10 +479,18 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
unsigned int busy_timeout_ms;
int err;
unsigned int target_part;
+ struct mmc_blk_ioc_data *idata = idatas[i];
+ struct mmc_blk_ioc_data *prev_idata = NULL;
if (!card || !md || !idata)
return -EINVAL;
+ if (idata->flags & MMC_BLK_IOC_DROP)
+ return 0;
+
+ if (idata->flags & MMC_BLK_IOC_SBC)
+ prev_idata = idatas[i - 1];
+
/*
* The RPMB accesses comes in from the character device, so we
* need to target these explicitly. Else we just target the
@@ -532,7 +544,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
return err;
}
- if (idata->rpmb) {
+ if (idata->rpmb || prev_idata) {
sbc.opcode = MMC_SET_BLOCK_COUNT;
/*
* We don't do any blockcount validation because the max size
@@ -540,6 +552,8 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
* 'Reliable Write' bit here.
*/
sbc.arg = data.blocks | (idata->ic.write_flag & BIT(31));
+ if (prev_idata)
+ sbc.arg = prev_idata->ic.arg;
sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
mrq.sbc = &sbc;
}
@@ -557,6 +571,15 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
mmc_wait_for_req(card->host, &mrq);
memcpy(&idata->ic.response, cmd.resp, sizeof(cmd.resp));
+ if (prev_idata) {
+ memcpy(&prev_idata->ic.response, sbc.resp, sizeof(sbc.resp));
+ if (sbc.error) {
+ dev_err(mmc_dev(card->host), "%s: sbc error %d\n",
+ __func__, sbc.error);
+ return sbc.error;
+ }
+ }
+
if (cmd.error) {
dev_err(mmc_dev(card->host), "%s: cmd error %d\n",
__func__, cmd.error);
@@ -1034,6 +1057,20 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
md->reset_done &= ~type;
}
+static void mmc_blk_check_sbc(struct mmc_queue_req *mq_rq)
+{
+ struct mmc_blk_ioc_data **idata = mq_rq->drv_op_data;
+ int i;
+
+ for (i = 1; i < mq_rq->ioc_count; i++) {
+ if (idata[i - 1]->ic.opcode == MMC_SET_BLOCK_COUNT &&
+ mmc_op_multi(idata[i]->ic.opcode)) {
+ idata[i - 1]->flags |= MMC_BLK_IOC_DROP;
+ idata[i]->flags |= MMC_BLK_IOC_SBC;
+ }
+ }
+}
+
/*
* The non-block commands come back from the block layer after it queued it and
* processed it with all other requests and then they get issued in this
@@ -1061,11 +1098,14 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
if (ret)
break;
}
+
+ mmc_blk_check_sbc(mq_rq);
+
fallthrough;
case MMC_DRV_OP_IOCTL_RPMB:
idata = mq_rq->drv_op_data;
for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) {
- ret = __mmc_blk_ioctl_cmd(card, md, idata[i]);
+ ret = __mmc_blk_ioctl_cmd(card, md, idata, i);
if (ret)
break;
}
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 2f51db4df1a8..cf396e8f34e9 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -119,13 +119,12 @@ void mmc_retune_enable(struct mmc_host *host)
/*
* Pause re-tuning for a small set of operations. The pause begins after the
- * next command and after first doing re-tuning.
+ * next command.
*/
void mmc_retune_pause(struct mmc_host *host)
{
if (!host->retune_paused) {
host->retune_paused = 1;
- mmc_retune_needed(host);
mmc_retune_hold(host);
}
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 705942edacc6..f410bee50132 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -136,6 +136,17 @@ static void mmc_set_erase_size(struct mmc_card *card)
mmc_init_erase(card);
}
+
+static void mmc_set_wp_grp_size(struct mmc_card *card)
+{
+ if (card->ext_csd.erase_group_def & 1)
+ card->wp_grp_size = card->ext_csd.hc_erase_size *
+ card->ext_csd.raw_hc_erase_gap_size;
+ else
+ card->wp_grp_size = card->csd.erase_size *
+ (card->csd.wp_grp_size + 1);
+}
+
/*
* Given a 128-bit response, decode to our card CSD structure.
*/
@@ -186,6 +197,7 @@ static int mmc_decode_csd(struct mmc_card *card)
b = UNSTUFF_BITS(resp, 37, 5);
csd->erase_size = (a + 1) * (b + 1);
csd->erase_size <<= csd->write_blkbits - 9;
+ csd->wp_grp_size = UNSTUFF_BITS(resp, 32, 5);
}
return 0;
@@ -613,11 +625,6 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
} else {
card->ext_csd.data_tag_unit_size = 0;
}
-
- card->ext_csd.max_packed_writes =
- ext_csd[EXT_CSD_MAX_PACKED_WRITES];
- card->ext_csd.max_packed_reads =
- ext_csd[EXT_CSD_MAX_PACKED_READS];
} else {
card->ext_csd.data_sector_size = 512;
}
@@ -790,6 +797,7 @@ MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9);
MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9);
+MMC_DEV_ATTR(wp_grp_size, "%u\n", card->wp_grp_size << 9);
MMC_DEV_ATTR(ffu_capable, "%d\n", card->ext_csd.ffu_capable);
MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
@@ -850,6 +858,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_date.attr,
&dev_attr_erase_size.attr,
&dev_attr_preferred_erase_size.attr,
+ &dev_attr_wp_grp_size.attr,
&dev_attr_fwrev.attr,
&dev_attr_ffu_capable.attr,
&dev_attr_hwrev.attr,
@@ -1764,7 +1773,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
mmc_set_erase_size(card);
}
}
-
+ mmc_set_wp_grp_size(card);
/*
* Ensure eMMC user default partition is enabled
*/
@@ -1822,8 +1831,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (err)
goto free_card;
-
- } else if (!mmc_card_hs400es(card)) {
+ } else if (mmc_card_hs400es(card)) {
+ if (host->ops->execute_hs400_tuning) {
+ err = host->ops->execute_hs400_tuning(host, card);
+ if (err)
+ goto free_card;
+ }
+ } else {
/* Select the desired bus width optionally */
err = mmc_select_bus_width(card);
if (err > 0 && mmc_card_hs(card)) {
diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c
index 0f6a563103fd..8f7f587a0025 100644
--- a/drivers/mmc/core/mmc_test.c
+++ b/drivers/mmc/core/mmc_test.c
@@ -1904,7 +1904,7 @@ static unsigned int mmc_test_rnd_num(unsigned int rnd_cnt)
}
static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
- unsigned long sz)
+ unsigned long sz, int secs, int force_retuning)
{
unsigned int dev_addr, cnt, rnd_addr, range1, range2, last_ea = 0, ea;
unsigned int ssz;
@@ -1921,7 +1921,7 @@ static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
for (cnt = 0; cnt < UINT_MAX; cnt++) {
ktime_get_ts64(&ts2);
ts = timespec64_sub(ts2, ts1);
- if (ts.tv_sec >= 10)
+ if (ts.tv_sec >= secs)
break;
ea = mmc_test_rnd_num(range1);
if (ea == last_ea)
@@ -1929,6 +1929,8 @@ static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
last_ea = ea;
dev_addr = rnd_addr + test->card->pref_erase * ea +
ssz * mmc_test_rnd_num(range2);
+ if (force_retuning)
+ mmc_retune_needed(test->card->host);
ret = mmc_test_area_io(test, sz, dev_addr, write, 0, 0);
if (ret)
return ret;
@@ -1953,24 +1955,35 @@ static int mmc_test_random_perf(struct mmc_test_card *test, int write)
*/
if (write) {
next = rnd_next;
- ret = mmc_test_rnd_perf(test, write, 0, sz);
+ ret = mmc_test_rnd_perf(test, write, 0, sz, 10, 0);
if (ret)
return ret;
rnd_next = next;
}
- ret = mmc_test_rnd_perf(test, write, 1, sz);
+ ret = mmc_test_rnd_perf(test, write, 1, sz, 10, 0);
if (ret)
return ret;
}
sz = t->max_tfr;
if (write) {
next = rnd_next;
- ret = mmc_test_rnd_perf(test, write, 0, sz);
+ ret = mmc_test_rnd_perf(test, write, 0, sz, 10, 0);
if (ret)
return ret;
rnd_next = next;
}
- return mmc_test_rnd_perf(test, write, 1, sz);
+ return mmc_test_rnd_perf(test, write, 1, sz, 10, 0);
+}
+
+static int mmc_test_retuning(struct mmc_test_card *test)
+{
+ if (!mmc_can_retune(test->card->host)) {
+ pr_info("%s: No retuning - test skipped\n",
+ mmc_hostname(test->card->host));
+ return RESULT_UNSUP_HOST;
+ }
+
+ return mmc_test_rnd_perf(test, 0, 0, 8192, 30, 1);
}
/*
@@ -2921,6 +2934,14 @@ static const struct mmc_test_case mmc_test_cases[] = {
.run = mmc_test_cmds_during_write_cmd23_nonblock,
.cleanup = mmc_test_area_cleanup,
},
+
+ {
+ .name = "Re-tuning reliability",
+ .prepare = mmc_test_area_prepare,
+ .run = mmc_test_retuning,
+ .cleanup = mmc_test_area_cleanup,
+ },
+
};
static DEFINE_MUTEX(mmc_test_lock);
diff --git a/drivers/mmc/core/sdio_uart.c b/drivers/mmc/core/sdio_uart.c
index ef38dcd3a887..575ebbce378e 100644
--- a/drivers/mmc/core/sdio_uart.c
+++ b/drivers/mmc/core/sdio_uart.c
@@ -178,11 +178,9 @@ static inline void sdio_uart_release_func(struct sdio_uart_port *port)
sdio_release_host(port->func);
}
-static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset)
+static inline u8 sdio_in(struct sdio_uart_port *port, int offset)
{
- unsigned char c;
- c = sdio_readb(port->func, port->regs_offset + offset, NULL);
- return c;
+ return sdio_readb(port->func, port->regs_offset + offset, NULL);
}
static inline void sdio_out(struct sdio_uart_port *port, int offset, int value)
@@ -192,8 +190,8 @@ static inline void sdio_out(struct sdio_uart_port *port, int offset, int value)
static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
{
- unsigned char status;
unsigned int ret;
+ u8 status;
/* FIXME: What stops this losing the delta bits and breaking
sdio_uart_check_modem_status ? */
@@ -354,15 +352,13 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port)
sdio_out(port, UART_IER, port->ier);
}
-static void sdio_uart_receive_chars(struct sdio_uart_port *port,
- unsigned int *status)
+static void sdio_uart_receive_chars(struct sdio_uart_port *port, u8 *status)
{
- unsigned int ch, flag;
int max_count = 256;
do {
- ch = sdio_in(port, UART_RX);
- flag = TTY_NORMAL;
+ u8 ch = sdio_in(port, UART_RX);
+ u8 flag = TTY_NORMAL;
port->icount.rx++;
if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
@@ -449,8 +445,8 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
{
- int status;
struct tty_struct *tty;
+ u8 status;
status = sdio_in(port, UART_MSR);
@@ -499,7 +495,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
static void sdio_uart_irq(struct sdio_func *func)
{
struct sdio_uart_port *port = sdio_get_drvdata(func);
- unsigned int iir, lsr;
+ u8 iir, lsr;
/*
* In a few places sdio_uart_irq() is called directly instead of
@@ -795,7 +791,7 @@ static unsigned int sdio_uart_chars_in_buffer(struct tty_struct *tty)
return kfifo_len(&port->xmit_fifo);
}
-static void sdio_uart_send_xchar(struct tty_struct *tty, char ch)
+static void sdio_uart_send_xchar(struct tty_struct *tty, u8 ch)
{
struct sdio_uart_port *port = tty->driver_data;
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 58bd5fe4cd25..81f2c4e05287 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -1026,14 +1026,15 @@ config MMC_SDHCI_XENON
config MMC_SDHCI_OMAP
tristate "TI SDHCI Controller Support"
+ depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST
depends on MMC_SDHCI_PLTFM && OF
select THERMAL
imply TI_SOC_THERMAL
select MMC_SDHCI_EXTERNAL_DMA if DMA_ENGINE
help
This selects the Secure Digital Host Controller Interface (SDHCI)
- support present in TI's DRA7 SOCs. The controller supports
- SD/MMC/SDIO devices.
+ support present in TI's Keystone/OMAP2+/DRA7 SOCs. The controller
+ supports SD/MMC/SDIO devices.
If you have a controller with this interface, say Y or M here.
@@ -1041,14 +1042,15 @@ config MMC_SDHCI_OMAP
config MMC_SDHCI_AM654
tristate "Support for the SDHCI Controller in TI's AM654 SOCs"
+ depends on ARCH_K3 || COMPILE_TEST
depends on MMC_SDHCI_PLTFM && OF
select MMC_SDHCI_IO_ACCESSORS
select MMC_CQHCI
select REGMAP_MMIO
help
This selects the Secure Digital Host Controller Interface (SDHCI)
- support present in TI's AM654 SOCs. The controller supports
- SD/MMC/SDIO devices.
+ support present in TI's AM65x/AM64x/AM62x/J721E SOCs. The controller
+ supports SD/MMC/SDIO devices.
If you have a controller with this interface, say Y or M here.
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index b0cccef4cfbf..b8dda8160c4e 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -15,7 +15,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/bio.h>
-#include <linux/dma-mapping.h>
+#include <linux/dma-direction.h>
#include <linux/crc7.h>
#include <linux/crc-itu-t.h>
#include <linux/scatterlist.h>
@@ -119,19 +119,14 @@ struct mmc_spi_host {
struct spi_transfer status;
struct spi_message readback;
- /* underlying DMA-aware controller, or null */
- struct device *dma_dev;
-
/* buffer used for commands and for message "overhead" */
struct scratch *data;
- dma_addr_t data_dma;
/* Specs say to write ones most of the time, even when the card
* has no need to read its input data; and many cards won't care.
* This is our source of those ones.
*/
void *ones;
- dma_addr_t ones_dma;
};
@@ -147,11 +142,8 @@ static inline int mmc_cs_off(struct mmc_spi_host *host)
return spi_setup(host->spi);
}
-static int
-mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)
+static int mmc_spi_readbytes(struct mmc_spi_host *host, unsigned int len)
{
- int status;
-
if (len > sizeof(*host->data)) {
WARN_ON(1);
return -EIO;
@@ -159,19 +151,7 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)
host->status.len = len;
- if (host->dma_dev)
- dma_sync_single_for_device(host->dma_dev,
- host->data_dma, sizeof(*host->data),
- DMA_FROM_DEVICE);
-
- status = spi_sync_locked(host->spi, &host->readback);
-
- if (host->dma_dev)
- dma_sync_single_for_cpu(host->dma_dev,
- host->data_dma, sizeof(*host->data),
- DMA_FROM_DEVICE);
-
- return status;
+ return spi_sync_locked(host->spi, &host->readback);
}
static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout,
@@ -506,23 +486,11 @@ mmc_spi_command_send(struct mmc_spi_host *host,
t = &host->t;
memset(t, 0, sizeof(*t));
t->tx_buf = t->rx_buf = data->status;
- t->tx_dma = t->rx_dma = host->data_dma;
t->len = cp - data->status;
t->cs_change = 1;
spi_message_add_tail(t, &host->m);
- if (host->dma_dev) {
- host->m.is_dma_mapped = 1;
- dma_sync_single_for_device(host->dma_dev,
- host->data_dma, sizeof(*host->data),
- DMA_BIDIRECTIONAL);
- }
status = spi_sync_locked(host->spi, &host->m);
-
- if (host->dma_dev)
- dma_sync_single_for_cpu(host->dma_dev,
- host->data_dma, sizeof(*host->data),
- DMA_BIDIRECTIONAL);
if (status < 0) {
dev_dbg(&host->spi->dev, " ... write returned %d\n", status);
cmd->error = status;
@@ -540,9 +508,6 @@ mmc_spi_command_send(struct mmc_spi_host *host,
* We always provide TX data for data and CRC. The MMC/SD protocol
* requires us to write ones; but Linux defaults to writing zeroes;
* so we explicitly initialize it to all ones on RX paths.
- *
- * We also handle DMA mapping, so the underlying SPI controller does
- * not need to (re)do it for each message.
*/
static void
mmc_spi_setup_data_message(
@@ -552,11 +517,8 @@ mmc_spi_setup_data_message(
{
struct spi_transfer *t;
struct scratch *scratch = host->data;
- dma_addr_t dma = host->data_dma;
spi_message_init(&host->m);
- if (dma)
- host->m.is_dma_mapped = 1;
/* for reads, readblock() skips 0xff bytes before finding
* the token; for writes, this transfer issues that token.
@@ -570,8 +532,6 @@ mmc_spi_setup_data_message(
else
scratch->data_token = SPI_TOKEN_SINGLE;
t->tx_buf = &scratch->data_token;
- if (dma)
- t->tx_dma = dma + offsetof(struct scratch, data_token);
spi_message_add_tail(t, &host->m);
}
@@ -581,7 +541,6 @@ mmc_spi_setup_data_message(
t = &host->t;
memset(t, 0, sizeof(*t));
t->tx_buf = host->ones;
- t->tx_dma = host->ones_dma;
/* length and actual buffer info are written later */
spi_message_add_tail(t, &host->m);
@@ -591,14 +550,9 @@ mmc_spi_setup_data_message(
if (direction == DMA_TO_DEVICE) {
/* the actual CRC may get written later */
t->tx_buf = &scratch->crc_val;
- if (dma)
- t->tx_dma = dma + offsetof(struct scratch, crc_val);
} else {
t->tx_buf = host->ones;
- t->tx_dma = host->ones_dma;
t->rx_buf = &scratch->crc_val;
- if (dma)
- t->rx_dma = dma + offsetof(struct scratch, crc_val);
}
spi_message_add_tail(t, &host->m);
@@ -621,10 +575,7 @@ mmc_spi_setup_data_message(
memset(t, 0, sizeof(*t));
t->len = (direction == DMA_TO_DEVICE) ? sizeof(scratch->status) : 1;
t->tx_buf = host->ones;
- t->tx_dma = host->ones_dma;
t->rx_buf = scratch->status;
- if (dma)
- t->rx_dma = dma + offsetof(struct scratch, status);
t->cs_change = 1;
spi_message_add_tail(t, &host->m);
}
@@ -653,23 +604,13 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
if (host->mmc->use_spi_crc)
scratch->crc_val = cpu_to_be16(crc_itu_t(0, t->tx_buf, t->len));
- if (host->dma_dev)
- dma_sync_single_for_device(host->dma_dev,
- host->data_dma, sizeof(*scratch),
- DMA_BIDIRECTIONAL);
status = spi_sync_locked(spi, &host->m);
-
if (status != 0) {
dev_dbg(&spi->dev, "write error (%d)\n", status);
return status;
}
- if (host->dma_dev)
- dma_sync_single_for_cpu(host->dma_dev,
- host->data_dma, sizeof(*scratch),
- DMA_BIDIRECTIONAL);
-
/*
* Get the transmission data-response reply. It must follow
* immediately after the data block we transferred. This reply
@@ -718,8 +659,6 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
}
t->tx_buf += t->len;
- if (host->dma_dev)
- t->tx_dma += t->len;
/* Return when not busy. If we didn't collect that status yet,
* we'll need some more I/O.
@@ -783,30 +722,12 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
}
leftover = status << 1;
- if (host->dma_dev) {
- dma_sync_single_for_device(host->dma_dev,
- host->data_dma, sizeof(*scratch),
- DMA_BIDIRECTIONAL);
- dma_sync_single_for_device(host->dma_dev,
- t->rx_dma, t->len,
- DMA_FROM_DEVICE);
- }
-
status = spi_sync_locked(spi, &host->m);
if (status < 0) {
dev_dbg(&spi->dev, "read error %d\n", status);
return status;
}
- if (host->dma_dev) {
- dma_sync_single_for_cpu(host->dma_dev,
- host->data_dma, sizeof(*scratch),
- DMA_BIDIRECTIONAL);
- dma_sync_single_for_cpu(host->dma_dev,
- t->rx_dma, t->len,
- DMA_FROM_DEVICE);
- }
-
if (bitshift) {
/* Walk through the data and the crc and do
* all the magic to get byte-aligned data.
@@ -841,8 +762,6 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
}
t->rx_buf += t->len;
- if (host->dma_dev)
- t->rx_dma += t->len;
return 0;
}
@@ -857,7 +776,6 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
struct mmc_data *data, u32 blk_size)
{
struct spi_device *spi = host->spi;
- struct device *dma_dev = host->dma_dev;
struct spi_transfer *t;
enum dma_data_direction direction = mmc_get_dma_dir(data);
struct scatterlist *sg;
@@ -884,31 +802,8 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
*/
for_each_sg(data->sg, sg, data->sg_len, n_sg) {
int status = 0;
- dma_addr_t dma_addr = 0;
void *kmap_addr;
unsigned length = sg->length;
- enum dma_data_direction dir = direction;
-
- /* set up dma mapping for controller drivers that might
- * use DMA ... though they may fall back to PIO
- */
- if (dma_dev) {
- /* never invalidate whole *shared* pages ... */
- if ((sg->offset != 0 || length != PAGE_SIZE)
- && dir == DMA_FROM_DEVICE)
- dir = DMA_BIDIRECTIONAL;
-
- dma_addr = dma_map_page(dma_dev, sg_page(sg), 0,
- PAGE_SIZE, dir);
- if (dma_mapping_error(dma_dev, dma_addr)) {
- data->error = -EFAULT;
- break;
- }
- if (direction == DMA_TO_DEVICE)
- t->tx_dma = dma_addr + sg->offset;
- else
- t->rx_dma = dma_addr + sg->offset;
- }
/* allow pio too; we don't allow highmem */
kmap_addr = kmap(sg_page(sg));
@@ -941,8 +836,6 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
if (direction == DMA_FROM_DEVICE)
flush_dcache_page(sg_page(sg));
kunmap(sg_page(sg));
- if (dma_dev)
- dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir);
if (status < 0) {
data->error = status;
@@ -977,21 +870,9 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
scratch->status[0] = SPI_TOKEN_STOP_TRAN;
host->early_status.tx_buf = host->early_status.rx_buf;
- host->early_status.tx_dma = host->early_status.rx_dma;
host->early_status.len = statlen;
- if (host->dma_dev)
- dma_sync_single_for_device(host->dma_dev,
- host->data_dma, sizeof(*scratch),
- DMA_BIDIRECTIONAL);
-
tmp = spi_sync_locked(spi, &host->m);
-
- if (host->dma_dev)
- dma_sync_single_for_cpu(host->dma_dev,
- host->data_dma, sizeof(*scratch),
- DMA_BIDIRECTIONAL);
-
if (tmp < 0) {
if (!data->error)
data->error = tmp;
@@ -1265,52 +1146,6 @@ mmc_spi_detect_irq(int irq, void *mmc)
return IRQ_HANDLED;
}
-#ifdef CONFIG_HAS_DMA
-static int mmc_spi_dma_alloc(struct mmc_spi_host *host)
-{
- struct spi_device *spi = host->spi;
- struct device *dev;
-
- if (!spi->master->dev.parent->dma_mask)
- return 0;
-
- dev = spi->master->dev.parent;
-
- host->ones_dma = dma_map_single(dev, host->ones, MMC_SPI_BLOCKSIZE,
- DMA_TO_DEVICE);
- if (dma_mapping_error(dev, host->ones_dma))
- return -ENOMEM;
-
- host->data_dma = dma_map_single(dev, host->data, sizeof(*host->data),
- DMA_BIDIRECTIONAL);
- if (dma_mapping_error(dev, host->data_dma)) {
- dma_unmap_single(dev, host->ones_dma, MMC_SPI_BLOCKSIZE,
- DMA_TO_DEVICE);
- return -ENOMEM;
- }
-
- dma_sync_single_for_cpu(dev, host->data_dma, sizeof(*host->data),
- DMA_BIDIRECTIONAL);
-
- host->dma_dev = dev;
- return 0;
-}
-
-static void mmc_spi_dma_free(struct mmc_spi_host *host)
-{
- if (!host->dma_dev)
- return;
-
- dma_unmap_single(host->dma_dev, host->ones_dma, MMC_SPI_BLOCKSIZE,
- DMA_TO_DEVICE);
- dma_unmap_single(host->dma_dev, host->data_dma, sizeof(*host->data),
- DMA_BIDIRECTIONAL);
-}
-#else
-static inline int mmc_spi_dma_alloc(struct mmc_spi_host *host) { return 0; }
-static inline void mmc_spi_dma_free(struct mmc_spi_host *host) {}
-#endif
-
static int mmc_spi_probe(struct spi_device *spi)
{
void *ones;
@@ -1402,24 +1237,17 @@ static int mmc_spi_probe(struct spi_device *spi)
host->powerup_msecs = 250;
}
- /* preallocate dma buffers */
+ /* Preallocate buffers */
host->data = kmalloc(sizeof(*host->data), GFP_KERNEL);
if (!host->data)
goto fail_nobuf1;
- status = mmc_spi_dma_alloc(host);
- if (status)
- goto fail_dma;
-
/* setup message for status/busy readback */
spi_message_init(&host->readback);
- host->readback.is_dma_mapped = (host->dma_dev != NULL);
spi_message_add_tail(&host->status, &host->readback);
host->status.tx_buf = host->ones;
- host->status.tx_dma = host->ones_dma;
host->status.rx_buf = &host->data->status;
- host->status.rx_dma = host->data_dma + offsetof(struct scratch, status);
host->status.cs_change = 1;
/* register card detect irq */
@@ -1464,9 +1292,8 @@ static int mmc_spi_probe(struct spi_device *spi)
if (!status)
has_ro = true;
- dev_info(&spi->dev, "SD/MMC host %s%s%s%s%s\n",
+ dev_info(&spi->dev, "SD/MMC host %s%s%s%s\n",
dev_name(&mmc->class_dev),
- host->dma_dev ? "" : ", no DMA",
has_ro ? "" : ", no WP",
(host->pdata && host->pdata->setpower)
? "" : ", no poweroff",
@@ -1477,8 +1304,6 @@ static int mmc_spi_probe(struct spi_device *spi)
fail_gpiod_request:
mmc_remove_host(mmc);
fail_glue_init:
- mmc_spi_dma_free(host);
-fail_dma:
kfree(host->data);
fail_nobuf1:
mmc_spi_put_pdata(spi);
@@ -1500,7 +1325,6 @@ static void mmc_spi_remove(struct spi_device *spi)
mmc_remove_host(mmc);
- mmc_spi_dma_free(host);
kfree(host->data);
kfree(host->ones);
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index e967cca7a16f..b790c3c3c8f9 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -273,6 +273,7 @@ static struct variant_data variant_stm32_sdmmc = {
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.stm32_idmabsize_mask = GENMASK(12, 5),
.stm32_idmabsize_align = BIT(5),
+ .supports_sdio_irq = true,
.busy_timeout = true,
.busy_detect = true,
.busy_detect_flag = MCI_STM32_BUSYD0,
@@ -300,6 +301,7 @@ static struct variant_data variant_stm32_sdmmcv2 = {
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.stm32_idmabsize_mask = GENMASK(16, 5),
.stm32_idmabsize_align = BIT(5),
+ .supports_sdio_irq = true,
.dma_lli = true,
.busy_timeout = true,
.busy_detect = true,
@@ -328,6 +330,7 @@ static struct variant_data variant_stm32_sdmmcv3 = {
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.stm32_idmabsize_mask = GENMASK(16, 6),
.stm32_idmabsize_align = BIT(6),
+ .supports_sdio_irq = true,
.dma_lli = true,
.busy_timeout = true,
.busy_detect = true,
@@ -421,8 +424,9 @@ void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
*/
static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
{
- /* Keep busy mode in DPSM if enabled */
- datactrl |= host->datactrl_reg & host->variant->busy_dpsm_flag;
+ /* Keep busy mode in DPSM and SDIO mask if enabled */
+ datactrl |= host->datactrl_reg & (host->variant->busy_dpsm_flag |
+ host->variant->datactrl_mask_sdio);
if (host->datactrl_reg != datactrl) {
host->datactrl_reg = datactrl;
@@ -1762,6 +1766,25 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void mmci_write_sdio_irq_bit(struct mmci_host *host, int enable)
+{
+ void __iomem *base = host->base;
+ u32 mask = readl_relaxed(base + MMCIMASK0);
+
+ if (enable)
+ writel_relaxed(mask | MCI_ST_SDIOITMASK, base + MMCIMASK0);
+ else
+ writel_relaxed(mask & ~MCI_ST_SDIOITMASK, base + MMCIMASK0);
+}
+
+static void mmci_signal_sdio_irq(struct mmci_host *host, u32 status)
+{
+ if (status & MCI_ST_SDIOIT) {
+ mmci_write_sdio_irq_bit(host, 0);
+ sdio_signal_irq(host->mmc);
+ }
+}
+
/*
* Handle completion of command and data transfers.
*/
@@ -1806,6 +1829,9 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
mmci_data_irq(host, host->data, status);
}
+ if (host->variant->supports_sdio_irq)
+ mmci_signal_sdio_irq(host, status);
+
/*
* Busy detection has been handled by mmci_cmd_irq() above.
* Clear the status bit to prevent polling in IRQ context.
@@ -2042,6 +2068,35 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
return ret;
}
+static void mmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+ struct mmci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ if (enable)
+ /* Keep the SDIO mode bit if SDIO irqs are enabled */
+ pm_runtime_get_sync(mmc_dev(mmc));
+
+ spin_lock_irqsave(&host->lock, flags);
+ mmci_write_sdio_irq_bit(host, enable);
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ if (!enable) {
+ pm_runtime_mark_last_busy(mmc_dev(mmc));
+ pm_runtime_put_autosuspend(mmc_dev(mmc));
+ }
+}
+
+static void mmci_ack_sdio_irq(struct mmc_host *mmc)
+{
+ struct mmci_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ mmci_write_sdio_irq_bit(host, 1);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
static struct mmc_host_ops mmci_ops = {
.request = mmci_request,
.pre_req = mmci_pre_request,
@@ -2317,6 +2372,16 @@ static int mmci_probe(struct amba_device *dev,
mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
}
+ if (variant->supports_sdio_irq && host->mmc->caps & MMC_CAP_SDIO_IRQ) {
+ mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
+
+ mmci_ops.enable_sdio_irq = mmci_enable_sdio_irq;
+ mmci_ops.ack_sdio_irq = mmci_ack_sdio_irq;
+
+ mmci_write_datactrlreg(host,
+ host->variant->datactrl_mask_sdio);
+ }
+
/* Variants with mandatory busy timeout in HW needs R1B responses. */
if (variant->busy_timeout)
mmc->caps |= MMC_CAP_NEED_RSP_BUSY;
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 34d9897c289b..a5eb4ced4d5d 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -331,6 +331,7 @@ enum mmci_busy_state {
* register.
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
* @dma_lli: true if variant has dma link list feature.
+ * @supports_sdio_irq: allow SD I/O card to interrupt the host
* @stm32_idmabsize_mask: stm32 sdmmc idma buffer size.
* @dma_flow_controller: use peripheral as flow controller for DMA.
*/
@@ -377,6 +378,7 @@ struct variant_data {
u32 start_err;
u32 opendrain;
u8 dma_lli:1;
+ bool supports_sdio_irq;
u32 stm32_idmabsize_mask;
u32 stm32_idmabsize_align;
bool dma_flow_controller;
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 97f7c3d4be6e..1634b1f5d201 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -252,12 +252,16 @@
#define MSDC_PAD_TUNE_DATWRDLY GENMASK(4, 0) /* RW */
#define MSDC_PAD_TUNE_DATRRDLY GENMASK(12, 8) /* RW */
+#define MSDC_PAD_TUNE_DATRRDLY2 GENMASK(12, 8) /* RW */
#define MSDC_PAD_TUNE_CMDRDLY GENMASK(20, 16) /* RW */
+#define MSDC_PAD_TUNE_CMDRDLY2 GENMASK(20, 16) /* RW */
#define MSDC_PAD_TUNE_CMDRRDLY GENMASK(26, 22) /* RW */
#define MSDC_PAD_TUNE_CLKTDLY GENMASK(31, 27) /* RW */
#define MSDC_PAD_TUNE_RXDLYSEL BIT(15) /* RW */
#define MSDC_PAD_TUNE_RD_SEL BIT(13) /* RW */
#define MSDC_PAD_TUNE_CMD_SEL BIT(21) /* RW */
+#define MSDC_PAD_TUNE_RD2_SEL BIT(13) /* RW */
+#define MSDC_PAD_TUNE_CMD2_SEL BIT(21) /* RW */
#define PAD_DS_TUNE_DLY_SEL BIT(0) /* RW */
#define PAD_DS_TUNE_DLY1 GENMASK(6, 2) /* RW */
@@ -325,7 +329,9 @@
#define DEFAULT_DEBOUNCE (8) /* 8 cycles CD debounce */
-#define PAD_DELAY_MAX 32 /* PAD delay cells */
+#define TUNING_REG2_FIXED_OFFEST 4
+#define PAD_DELAY_HALF 32 /* PAD delay cells */
+#define PAD_DELAY_FULL 64
/*--------------------------------------------------------------------------*/
/* Descriptor Structure */
/*--------------------------------------------------------------------------*/
@@ -461,6 +467,7 @@ struct msdc_host {
u32 hs400_ds_dly3;
u32 hs200_cmd_int_delay; /* cmd internal delay for HS200/SDR104 */
u32 hs400_cmd_int_delay; /* cmd internal delay for HS400 */
+ u32 tuning_step;
bool hs400_cmd_resp_sel_rising;
/* cmd response sample selection for HS400 */
bool hs400_mode; /* current eMMC will run at hs400 mode */
@@ -1149,9 +1156,11 @@ static void msdc_recheck_sdio_irq(struct msdc_host *host)
static void msdc_track_cmd_data(struct msdc_host *host, struct mmc_command *cmd)
{
- if (host->error)
- dev_dbg(host->dev, "%s: cmd=%d arg=%08X; host->error=0x%08X\n",
- __func__, cmd->opcode, cmd->arg, host->error);
+ if (host->error &&
+ ((!mmc_op_tuning(cmd->opcode) && !host->hs400_tuning) ||
+ cmd->error == -ETIMEDOUT))
+ dev_warn(host->dev, "%s: cmd=%d arg=%08X; host->error=0x%08X\n",
+ __func__, cmd->opcode, cmd->arg, host->error);
}
static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq)
@@ -1615,7 +1624,7 @@ static irqreturn_t msdc_cmdq_irq(struct msdc_host *host, u32 intsts)
}
if (cmd_err || dat_err) {
- dev_err(host->dev, "cmd_err = %d, dat_err =%d, intsts = 0x%x",
+ dev_err(host->dev, "cmd_err = %d, dat_err = %d, intsts = 0x%x",
cmd_err, dat_err, intsts);
}
@@ -1780,10 +1789,20 @@ static void msdc_init_hw(struct msdc_host *host)
DATA_K_VALUE_SEL);
sdr_set_bits(host->top_base + EMMC_TOP_CMD,
PAD_CMD_RD_RXDLY_SEL);
+ if (host->tuning_step > PAD_DELAY_HALF) {
+ sdr_set_bits(host->top_base + EMMC_TOP_CONTROL,
+ PAD_DAT_RD_RXDLY2_SEL);
+ sdr_set_bits(host->top_base + EMMC_TOP_CMD,
+ PAD_CMD_RD_RXDLY2_SEL);
+ }
} else {
sdr_set_bits(host->base + tune_reg,
MSDC_PAD_TUNE_RD_SEL |
MSDC_PAD_TUNE_CMD_SEL);
+ if (host->tuning_step > PAD_DELAY_HALF)
+ sdr_set_bits(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST,
+ MSDC_PAD_TUNE_RD2_SEL |
+ MSDC_PAD_TUNE_CMD2_SEL);
}
} else {
/* choose clock tune */
@@ -1925,24 +1944,24 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
msdc_set_mclk(host, ios->timing, ios->clock);
}
-static u32 test_delay_bit(u32 delay, u32 bit)
+static u64 test_delay_bit(u64 delay, u32 bit)
{
- bit %= PAD_DELAY_MAX;
- return delay & BIT(bit);
+ bit %= PAD_DELAY_FULL;
+ return delay & BIT_ULL(bit);
}
-static int get_delay_len(u32 delay, u32 start_bit)
+static int get_delay_len(u64 delay, u32 start_bit)
{
int i;
- for (i = 0; i < (PAD_DELAY_MAX - start_bit); i++) {
+ for (i = 0; i < (PAD_DELAY_FULL - start_bit); i++) {
if (test_delay_bit(delay, start_bit + i) == 0)
return i;
}
- return PAD_DELAY_MAX - start_bit;
+ return PAD_DELAY_FULL - start_bit;
}
-static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
+static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u64 delay)
{
int start = 0, len = 0;
int start_final = 0, len_final = 0;
@@ -1950,28 +1969,28 @@ static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
struct msdc_delay_phase delay_phase = { 0, };
if (delay == 0) {
- dev_err(host->dev, "phase error: [map:%x]\n", delay);
+ dev_err(host->dev, "phase error: [map:%016llx]\n", delay);
delay_phase.final_phase = final_phase;
return delay_phase;
}
- while (start < PAD_DELAY_MAX) {
+ while (start < PAD_DELAY_FULL) {
len = get_delay_len(delay, start);
if (len_final < len) {
start_final = start;
len_final = len;
}
start += len ? len : 1;
- if (len >= 12 && start_final < 4)
+ if (!upper_32_bits(delay) && len >= 12 && start_final < 4)
break;
}
/* The rule is that to find the smallest delay cell */
if (start_final == 0)
- final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX;
+ final_phase = (start_final + len_final / 3) % PAD_DELAY_FULL;
else
- final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX;
- dev_dbg(host->dev, "phase: [map:%x] [maxlen:%d] [final:%d]\n",
+ final_phase = (start_final + len_final / 2) % PAD_DELAY_FULL;
+ dev_dbg(host->dev, "phase: [map:%016llx] [maxlen:%d] [final:%d]\n",
delay, len_final, final_phase);
delay_phase.maxlen = len_final;
@@ -1984,30 +2003,64 @@ static inline void msdc_set_cmd_delay(struct msdc_host *host, u32 value)
{
u32 tune_reg = host->dev_comp->pad_tune_reg;
- if (host->top_base)
- sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY,
- value);
- else
- sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY,
- value);
+ if (host->top_base) {
+ if (value < PAD_DELAY_HALF) {
+ sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY, value);
+ sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY2, 0);
+ } else {
+ sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY,
+ PAD_DELAY_HALF - 1);
+ sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY2,
+ value - PAD_DELAY_HALF);
+ }
+ } else {
+ if (value < PAD_DELAY_HALF) {
+ sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY, value);
+ sdr_set_field(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST,
+ MSDC_PAD_TUNE_CMDRDLY2, 0);
+ } else {
+ sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY,
+ PAD_DELAY_HALF - 1);
+ sdr_set_field(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST,
+ MSDC_PAD_TUNE_CMDRDLY2, value - PAD_DELAY_HALF);
+ }
+ }
}
static inline void msdc_set_data_delay(struct msdc_host *host, u32 value)
{
u32 tune_reg = host->dev_comp->pad_tune_reg;
- if (host->top_base)
- sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
- PAD_DAT_RD_RXDLY, value);
- else
- sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY,
- value);
+ if (host->top_base) {
+ if (value < PAD_DELAY_HALF) {
+ sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
+ PAD_DAT_RD_RXDLY, value);
+ sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
+ PAD_DAT_RD_RXDLY2, 0);
+ } else {
+ sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
+ PAD_DAT_RD_RXDLY, PAD_DELAY_HALF - 1);
+ sdr_set_field(host->top_base + EMMC_TOP_CONTROL,
+ PAD_DAT_RD_RXDLY2, value - PAD_DELAY_HALF);
+ }
+ } else {
+ if (value < PAD_DELAY_HALF) {
+ sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY, value);
+ sdr_set_field(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST,
+ MSDC_PAD_TUNE_DATRRDLY2, 0);
+ } else {
+ sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY,
+ PAD_DELAY_HALF - 1);
+ sdr_set_field(host->base + tune_reg + TUNING_REG2_FIXED_OFFEST,
+ MSDC_PAD_TUNE_DATRRDLY2, value - PAD_DELAY_HALF);
+ }
+ }
}
static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
{
struct msdc_host *host = mmc_priv(mmc);
- u32 rise_delay = 0, fall_delay = 0;
+ u64 rise_delay = 0, fall_delay = 0;
struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
struct msdc_delay_phase internal_delay_phase;
u8 final_delay, final_maxlen;
@@ -2023,7 +2076,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
host->hs200_cmd_int_delay);
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
- for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+ for (i = 0; i < host->tuning_step; i++) {
msdc_set_cmd_delay(host, i);
/*
* Using the same parameters, it may sometimes pass the test,
@@ -2033,9 +2086,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
for (j = 0; j < 3; j++) {
mmc_send_tuning(mmc, opcode, &cmd_err);
if (!cmd_err) {
- rise_delay |= BIT(i);
+ rise_delay |= BIT_ULL(i);
} else {
- rise_delay &= ~BIT(i);
+ rise_delay &= ~BIT_ULL(i);
break;
}
}
@@ -2047,7 +2100,7 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
goto skip_fall;
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
- for (i = 0; i < PAD_DELAY_MAX; i++) {
+ for (i = 0; i < host->tuning_step; i++) {
msdc_set_cmd_delay(host, i);
/*
* Using the same parameters, it may sometimes pass the test,
@@ -2057,9 +2110,9 @@ static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
for (j = 0; j < 3; j++) {
mmc_send_tuning(mmc, opcode, &cmd_err);
if (!cmd_err) {
- fall_delay |= BIT(i);
+ fall_delay |= BIT_ULL(i);
} else {
- fall_delay &= ~BIT(i);
+ fall_delay &= ~BIT_ULL(i);
break;
}
}
@@ -2082,12 +2135,12 @@ skip_fall:
if (host->dev_comp->async_fifo || host->hs200_cmd_int_delay)
goto skip_internal;
- for (i = 0; i < PAD_DELAY_MAX; i++) {
+ for (i = 0; i < host->tuning_step; i++) {
sdr_set_field(host->base + tune_reg,
MSDC_PAD_TUNE_CMDRRDLY, i);
mmc_send_tuning(mmc, opcode, &cmd_err);
if (!cmd_err)
- internal_delay |= BIT(i);
+ internal_delay |= BIT_ULL(i);
}
dev_dbg(host->dev, "Final internal delay: 0x%x\n", internal_delay);
internal_delay_phase = get_best_delay(host, internal_delay);
@@ -2121,7 +2174,8 @@ static int hs400_tune_response(struct mmc_host *mmc, u32 opcode)
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
else
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
- for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+
+ for (i = 0; i < PAD_DELAY_HALF; i++) {
sdr_set_field(host->base + PAD_CMD_TUNE,
PAD_CMD_TUNE_RX_DLY3, i);
/*
@@ -2151,7 +2205,7 @@ static int hs400_tune_response(struct mmc_host *mmc, u32 opcode)
static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
{
struct msdc_host *host = mmc_priv(mmc);
- u32 rise_delay = 0, fall_delay = 0;
+ u64 rise_delay = 0, fall_delay = 0;
struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
u8 final_delay, final_maxlen;
int i, ret;
@@ -2160,11 +2214,11 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
host->latch_ck);
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
- for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+ for (i = 0; i < host->tuning_step; i++) {
msdc_set_data_delay(host, i);
ret = mmc_send_tuning(mmc, opcode, NULL);
if (!ret)
- rise_delay |= BIT(i);
+ rise_delay |= BIT_ULL(i);
}
final_rise_delay = get_best_delay(host, rise_delay);
/* if rising edge has enough margin, then do not scan falling edge */
@@ -2174,11 +2228,11 @@ static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
- for (i = 0; i < PAD_DELAY_MAX; i++) {
+ for (i = 0; i < host->tuning_step; i++) {
msdc_set_data_delay(host, i);
ret = mmc_send_tuning(mmc, opcode, NULL);
if (!ret)
- fall_delay |= BIT(i);
+ fall_delay |= BIT_ULL(i);
}
final_fall_delay = get_best_delay(host, fall_delay);
@@ -2206,7 +2260,7 @@ skip_fall:
static int msdc_tune_together(struct mmc_host *mmc, u32 opcode)
{
struct msdc_host *host = mmc_priv(mmc);
- u32 rise_delay = 0, fall_delay = 0;
+ u64 rise_delay = 0, fall_delay = 0;
struct msdc_delay_phase final_rise_delay, final_fall_delay = { 0,};
u8 final_delay, final_maxlen;
int i, ret;
@@ -2217,12 +2271,12 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode)
sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
sdr_clr_bits(host->base + MSDC_IOCON,
MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
- for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+ for (i = 0; i < host->tuning_step; i++) {
msdc_set_cmd_delay(host, i);
msdc_set_data_delay(host, i);
ret = mmc_send_tuning(mmc, opcode, NULL);
if (!ret)
- rise_delay |= BIT(i);
+ rise_delay |= BIT_ULL(i);
}
final_rise_delay = get_best_delay(host, rise_delay);
/* if rising edge has enough margin, then do not scan falling edge */
@@ -2233,12 +2287,12 @@ static int msdc_tune_together(struct mmc_host *mmc, u32 opcode)
sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
sdr_set_bits(host->base + MSDC_IOCON,
MSDC_IOCON_DSPL | MSDC_IOCON_W_DSPL);
- for (i = 0; i < PAD_DELAY_MAX; i++) {
+ for (i = 0; i < host->tuning_step; i++) {
msdc_set_cmd_delay(host, i);
msdc_set_data_delay(host, i);
ret = mmc_send_tuning(mmc, opcode, NULL);
if (!ret)
- fall_delay |= BIT(i);
+ fall_delay |= BIT_ULL(i);
}
final_fall_delay = get_best_delay(host, fall_delay);
@@ -2346,7 +2400,7 @@ static int msdc_execute_hs400_tuning(struct mmc_host *mmc, struct mmc_card *card
}
host->hs400_tuning = true;
- for (i = 0; i < PAD_DELAY_MAX; i++) {
+ for (i = 0; i < PAD_DELAY_HALF; i++) {
if (host->top_base)
sdr_set_field(host->top_base + EMMC50_PAD_DS_TUNE,
PAD_DS_DLY1, i);
@@ -2580,6 +2634,8 @@ static const struct cqhci_host_ops msdc_cmdq_ops = {
static void msdc_of_property_parse(struct platform_device *pdev,
struct msdc_host *host)
{
+ struct mmc_host *mmc = mmc_from_priv(host);
+
of_property_read_u32(pdev->dev.of_node, "mediatek,latch-ck",
&host->latch_ck);
@@ -2601,6 +2657,14 @@ static void msdc_of_property_parse(struct platform_device *pdev,
else
host->hs400_cmd_resp_sel_rising = false;
+ if (of_property_read_u32(pdev->dev.of_node, "mediatek,tuning-step",
+ &host->tuning_step)) {
+ if (mmc->caps2 & MMC_CAP2_NO_MMC)
+ host->tuning_step = PAD_DELAY_FULL;
+ else
+ host->tuning_step = PAD_DELAY_HALF;
+ }
+
if (of_property_read_bool(pdev->dev.of_node,
"supports-cqe"))
host->cqhci = true;
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index 87d78432a1e0..7dfe7c4e0077 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -7,6 +7,7 @@
* Wei WANG <[email protected]>
*/
+#include <linux/pci.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/highmem.h>
@@ -947,7 +948,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host, unsigned char power_mode)
/* send at least 74 clocks */
rtsx_pci_write_register(pcr, SD_BUS_STAT, SD_CLK_TOGGLE_EN, SD_CLK_TOGGLE_EN);
- if (PCI_PID(pcr) == PID_5261) {
+ if ((PCI_PID(pcr) == PID_5261) || (PCI_PID(pcr) == PID_5264)) {
/*
* If test mode is set switch to SD Express mandatorily,
* this is only for factory testing.
@@ -1364,6 +1365,14 @@ static int sdmmc_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
struct realtek_pci_sdmmc *host = mmc_priv(mmc);
struct rtsx_pcr *pcr = host->pcr;
+ if (PCI_PID(pcr) == PID_5264) {
+ pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL2,
+ PCI_EXP_LNKCTL2_TLS, PCI_EXP_LNKCTL2_TLS_2_5GT);
+ pci_write_config_byte(pcr->pci, 0x80e, 0x02);
+ pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL2,
+ PCI_EXP_LNKCTL2_TLS, PCI_EXP_LNKCTL2_TLS_5_0GT);
+ }
+
/* Set relink_time for changing to PCIe card */
relink_time = 0x8FFF;
@@ -1379,6 +1388,12 @@ static int sdmmc_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
if (pcr->ops->disable_auto_blink)
pcr->ops->disable_auto_blink(pcr);
+ if (PCI_PID(pcr) == PID_5264) {
+ rtsx_pci_write_register(pcr, RTS5264_AUTOLOAD_CFG2,
+ RTS5264_CHIP_RST_N_SEL, RTS5264_CHIP_RST_N_SEL);
+ rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00);
+ }
+
/* For PCIe/NVMe mode can't enter delink issue */
pcr->hw_param.interrupt_en &= ~(SD_INT_EN);
rtsx_pci_writel(pcr, RTSX_BIER, pcr->hw_param.interrupt_en);
diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c
index c23251bb95f3..9053526fa212 100644
--- a/drivers/mmc/host/sdhci-brcmstb.c
+++ b/drivers/mmc/host/sdhci-brcmstb.c
@@ -6,6 +6,7 @@
*/
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -44,8 +45,13 @@ struct brcmstb_match_priv {
static inline void enable_clock_gating(struct sdhci_host *host)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
u32 reg;
+ if (!(priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK))
+ return;
+
reg = sdhci_readl(host, SDHCI_VENDOR);
reg |= SDHCI_VENDOR_GATE_SDCLK_EN;
sdhci_writel(host, reg, SDHCI_VENDOR);
@@ -53,14 +59,53 @@ static inline void enable_clock_gating(struct sdhci_host *host)
static void brcmstb_reset(struct sdhci_host *host, u8 mask)
{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_brcmstb_priv *priv = sdhci_pltfm_priv(pltfm_host);
-
sdhci_and_cqhci_reset(host, mask);
/* Reset will clear this, so re-enable it */
- if (priv->flags & BRCMSTB_PRIV_FLAGS_GATE_CLOCK)
- enable_clock_gating(host);
+ enable_clock_gating(host);
+}
+
+static void brcmstb_sdhci_reset_cmd_data(struct sdhci_host *host, u8 mask)
+{
+ u32 new_mask = (mask & (SDHCI_RESET_CMD | SDHCI_RESET_DATA)) << 24;
+ int ret;
+ u32 reg;
+
+ /*
+ * SDHCI_CLOCK_CONTROL register CARD_EN and CLOCK_INT_EN bits shall
+ * be set along with SOFTWARE_RESET register RESET_CMD or RESET_DATA
+ * bits, hence access SDHCI_CLOCK_CONTROL register as 32-bit register
+ */
+ new_mask |= SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN;
+ reg = sdhci_readl(host, SDHCI_CLOCK_CONTROL);
+ sdhci_writel(host, reg | new_mask, SDHCI_CLOCK_CONTROL);
+
+ reg = sdhci_readb(host, SDHCI_SOFTWARE_RESET);
+
+ ret = read_poll_timeout_atomic(sdhci_readb, reg, !(reg & mask),
+ 10, 10000, false,
+ host, SDHCI_SOFTWARE_RESET);
+
+ if (ret) {
+ pr_err("%s: Reset 0x%x never completed.\n",
+ mmc_hostname(host->mmc), (int)mask);
+ sdhci_err_stats_inc(host, CTRL_TIMEOUT);
+ sdhci_dumpregs(host);
+ }
+}
+
+static void brcmstb_reset_74165b0(struct sdhci_host *host, u8 mask)
+{
+ /* take care of RESET_ALL as usual */
+ if (mask & SDHCI_RESET_ALL)
+ sdhci_and_cqhci_reset(host, SDHCI_RESET_ALL);
+
+ /* cmd and/or data treated differently on this core */
+ if (mask & (SDHCI_RESET_CMD | SDHCI_RESET_DATA))
+ brcmstb_sdhci_reset_cmd_data(host, mask);
+
+ /* Reset will clear this, so re-enable it */
+ enable_clock_gating(host);
}
static void sdhci_brcmstb_hs400es(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -162,6 +207,13 @@ static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
.set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling,
};
+static struct sdhci_ops sdhci_brcmstb_ops_74165b0 = {
+ .set_clock = sdhci_brcmstb_set_clock,
+ .set_bus_width = sdhci_set_bus_width,
+ .reset = brcmstb_reset_74165b0,
+ .set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling,
+};
+
static struct brcmstb_match_priv match_priv_7425 = {
.flags = BRCMSTB_MATCH_FLAGS_NO_64BIT |
BRCMSTB_MATCH_FLAGS_BROKEN_TIMEOUT,
@@ -179,10 +231,17 @@ static const struct brcmstb_match_priv match_priv_7216 = {
.ops = &sdhci_brcmstb_ops_7216,
};
+static struct brcmstb_match_priv match_priv_74165b0 = {
+ .flags = BRCMSTB_MATCH_FLAGS_HAS_CLOCK_GATE,
+ .hs400es = sdhci_brcmstb_hs400es,
+ .ops = &sdhci_brcmstb_ops_74165b0,
+};
+
static const struct of_device_id __maybe_unused sdhci_brcm_of_match[] = {
{ .compatible = "brcm,bcm7425-sdhci", .data = &match_priv_7425 },
{ .compatible = "brcm,bcm7445-sdhci", .data = &match_priv_7445 },
{ .compatible = "brcm,bcm7216-sdhci", .data = &match_priv_7216 },
+ { .compatible = "brcm,bcm74165b0-sdhci", .data = &match_priv_74165b0 },
{},
};
diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c
index 3a3bae6948a8..a1f57af6acfb 100644
--- a/drivers/mmc/host/sdhci-of-dwcmshc.c
+++ b/drivers/mmc/host/sdhci-of-dwcmshc.c
@@ -8,6 +8,7 @@
*/
#include <linux/acpi.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
@@ -35,6 +36,21 @@
#define DWCMSHC_CARD_IS_EMMC BIT(0)
#define DWCMSHC_ENHANCED_STROBE BIT(8)
#define DWCMSHC_EMMC_ATCTRL 0x40
+/* Tuning and auto-tuning fields in AT_CTRL_R control register */
+#define AT_CTRL_AT_EN BIT(0) /* autotuning is enabled */
+#define AT_CTRL_CI_SEL BIT(1) /* interval to drive center phase select */
+#define AT_CTRL_SWIN_TH_EN BIT(2) /* sampling window threshold enable */
+#define AT_CTRL_RPT_TUNE_ERR BIT(3) /* enable reporting framing errors */
+#define AT_CTRL_SW_TUNE_EN BIT(4) /* enable software managed tuning */
+#define AT_CTRL_WIN_EDGE_SEL_MASK GENMASK(11, 8) /* bits [11:8] */
+#define AT_CTRL_WIN_EDGE_SEL 0xf /* sampling window edge select */
+#define AT_CTRL_TUNE_CLK_STOP_EN BIT(16) /* clocks stopped during phase code change */
+#define AT_CTRL_PRE_CHANGE_DLY_MASK GENMASK(18, 17) /* bits [18:17] */
+#define AT_CTRL_PRE_CHANGE_DLY 0x1 /* 2-cycle latency */
+#define AT_CTRL_POST_CHANGE_DLY_MASK GENMASK(20, 19) /* bits [20:19] */
+#define AT_CTRL_POST_CHANGE_DLY 0x3 /* 4-cycle latency */
+#define AT_CTRL_SWIN_TH_VAL_MASK GENMASK(31, 24) /* bits [31:24] */
+#define AT_CTRL_SWIN_TH_VAL 0x9 /* sampling window threshold */
/* Rockchip specific Registers */
#define DWCMSHC_EMMC_DLL_CTRL 0x800
@@ -72,6 +88,82 @@
(((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
#define RK35xx_MAX_CLKS 3
+/* PHY register area pointer */
+#define DWC_MSHC_PTR_PHY_R 0x300
+
+/* PHY general configuration */
+#define PHY_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x00)
+#define PHY_CNFG_RSTN_DEASSERT 0x1 /* Deassert PHY reset */
+#define PHY_CNFG_PAD_SP_MASK GENMASK(19, 16) /* bits [19:16] */
+#define PHY_CNFG_PAD_SP 0x0c /* PMOS TX drive strength */
+#define PHY_CNFG_PAD_SN_MASK GENMASK(23, 20) /* bits [23:20] */
+#define PHY_CNFG_PAD_SN 0x0c /* NMOS TX drive strength */
+
+/* PHY command/response pad settings */
+#define PHY_CMDPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x04)
+
+/* PHY data pad settings */
+#define PHY_DATAPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x06)
+
+/* PHY clock pad settings */
+#define PHY_CLKPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x08)
+
+/* PHY strobe pad settings */
+#define PHY_STBPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x0a)
+
+/* PHY reset pad settings */
+#define PHY_RSTNPAD_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x0c)
+
+/* Bitfields are common for all pad settings */
+#define PHY_PAD_RXSEL_1V8 0x1 /* Receiver type select for 1.8V */
+#define PHY_PAD_RXSEL_3V3 0x2 /* Receiver type select for 3.3V */
+
+#define PHY_PAD_WEAKPULL_MASK GENMASK(4, 3) /* bits [4:3] */
+#define PHY_PAD_WEAKPULL_PULLUP 0x1 /* Weak pull up enabled */
+#define PHY_PAD_WEAKPULL_PULLDOWN 0x2 /* Weak pull down enabled */
+
+#define PHY_PAD_TXSLEW_CTRL_P_MASK GENMASK(8, 5) /* bits [8:5] */
+#define PHY_PAD_TXSLEW_CTRL_P 0x3 /* Slew control for P-Type pad TX */
+#define PHY_PAD_TXSLEW_CTRL_N_MASK GENMASK(12, 9) /* bits [12:9] */
+#define PHY_PAD_TXSLEW_CTRL_N 0x3 /* Slew control for N-Type pad TX */
+
+/* PHY CLK delay line settings */
+#define PHY_SDCLKDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x1d)
+#define PHY_SDCLKDL_CNFG_UPDATE BIT(4) /* set before writing to SDCLKDL_DC */
+
+/* PHY CLK delay line delay code */
+#define PHY_SDCLKDL_DC_R (DWC_MSHC_PTR_PHY_R + 0x1e)
+#define PHY_SDCLKDL_DC_INITIAL 0x40 /* initial delay code */
+#define PHY_SDCLKDL_DC_DEFAULT 0x32 /* default delay code */
+#define PHY_SDCLKDL_DC_HS400 0x18 /* delay code for HS400 mode */
+
+/* PHY drift_cclk_rx delay line configuration setting */
+#define PHY_ATDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x21)
+#define PHY_ATDL_CNFG_INPSEL_MASK GENMASK(3, 2) /* bits [3:2] */
+#define PHY_ATDL_CNFG_INPSEL 0x3 /* delay line input source */
+
+/* PHY DLL control settings */
+#define PHY_DLL_CTRL_R (DWC_MSHC_PTR_PHY_R + 0x24)
+#define PHY_DLL_CTRL_DISABLE 0x0 /* PHY DLL is enabled */
+#define PHY_DLL_CTRL_ENABLE 0x1 /* PHY DLL is disabled */
+
+/* PHY DLL configuration register 1 */
+#define PHY_DLL_CNFG1_R (DWC_MSHC_PTR_PHY_R + 0x25)
+#define PHY_DLL_CNFG1_SLVDLY_MASK GENMASK(5, 4) /* bits [5:4] */
+#define PHY_DLL_CNFG1_SLVDLY 0x2 /* DLL slave update delay input */
+#define PHY_DLL_CNFG1_WAITCYCLE 0x5 /* DLL wait cycle input */
+
+/* PHY DLL configuration register 2 */
+#define PHY_DLL_CNFG2_R (DWC_MSHC_PTR_PHY_R + 0x26)
+#define PHY_DLL_CNFG2_JUMPSTEP 0xa /* DLL jump step input */
+
+/* PHY DLL master and slave delay line configuration settings */
+#define PHY_DLLDL_CNFG_R (DWC_MSHC_PTR_PHY_R + 0x28)
+#define PHY_DLLDL_CNFG_SLV_INPSEL_MASK GENMASK(6, 5) /* bits [6:5] */
+#define PHY_DLLDL_CNFG_SLV_INPSEL 0x3 /* clock source select for slave DL */
+
+#define FLAG_IO_FIXED_1V8 BIT(0)
+
#define BOUNDARY_OK(addr, len) \
((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
@@ -92,6 +184,8 @@ struct dwcmshc_priv {
struct clk *bus_clk;
int vendor_specific_area1; /* P_VENDOR_SPECIFIC_AREA reg */
void *priv; /* pointer to SoC private stuff */
+ u16 delay_line;
+ u16 flags;
};
/*
@@ -157,6 +251,127 @@ static void dwcmshc_request(struct mmc_host *mmc, struct mmc_request *mrq)
sdhci_request(mmc, mrq);
}
+static void dwcmshc_phy_1_8v_init(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ u32 val;
+
+ /* deassert phy reset & set tx drive strength */
+ val = PHY_CNFG_RSTN_DEASSERT;
+ val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP);
+ val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN);
+ sdhci_writel(host, val, PHY_CNFG_R);
+
+ /* disable delay line */
+ sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R);
+
+ /* set delay line */
+ sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R);
+ sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R);
+
+ /* enable delay lane */
+ val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R);
+ val &= ~(PHY_SDCLKDL_CNFG_UPDATE);
+ sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R);
+
+ /* configure phy pads */
+ val = PHY_PAD_RXSEL_1V8;
+ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP);
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
+ sdhci_writew(host, val, PHY_CMDPAD_CNFG_R);
+ sdhci_writew(host, val, PHY_DATAPAD_CNFG_R);
+ sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R);
+
+ val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
+ sdhci_writew(host, val, PHY_CLKPAD_CNFG_R);
+
+ val = PHY_PAD_RXSEL_1V8;
+ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN);
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
+ sdhci_writew(host, val, PHY_STBPAD_CNFG_R);
+
+ /* enable data strobe mode */
+ sdhci_writeb(host, FIELD_PREP(PHY_DLLDL_CNFG_SLV_INPSEL_MASK, PHY_DLLDL_CNFG_SLV_INPSEL),
+ PHY_DLLDL_CNFG_R);
+
+ /* enable phy dll */
+ sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R);
+}
+
+static void dwcmshc_phy_3_3v_init(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ u32 val;
+
+ /* deassert phy reset & set tx drive strength */
+ val = PHY_CNFG_RSTN_DEASSERT;
+ val |= FIELD_PREP(PHY_CNFG_PAD_SP_MASK, PHY_CNFG_PAD_SP);
+ val |= FIELD_PREP(PHY_CNFG_PAD_SN_MASK, PHY_CNFG_PAD_SN);
+ sdhci_writel(host, val, PHY_CNFG_R);
+
+ /* disable delay line */
+ sdhci_writeb(host, PHY_SDCLKDL_CNFG_UPDATE, PHY_SDCLKDL_CNFG_R);
+
+ /* set delay line */
+ sdhci_writeb(host, priv->delay_line, PHY_SDCLKDL_DC_R);
+ sdhci_writeb(host, PHY_DLL_CNFG2_JUMPSTEP, PHY_DLL_CNFG2_R);
+
+ /* enable delay lane */
+ val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R);
+ val &= ~(PHY_SDCLKDL_CNFG_UPDATE);
+ sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R);
+
+ /* configure phy pads */
+ val = PHY_PAD_RXSEL_3V3;
+ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLUP);
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
+ sdhci_writew(host, val, PHY_CMDPAD_CNFG_R);
+ sdhci_writew(host, val, PHY_DATAPAD_CNFG_R);
+ sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R);
+
+ val = FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
+ sdhci_writew(host, val, PHY_CLKPAD_CNFG_R);
+
+ val = PHY_PAD_RXSEL_3V3;
+ val |= FIELD_PREP(PHY_PAD_WEAKPULL_MASK, PHY_PAD_WEAKPULL_PULLDOWN);
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_P_MASK, PHY_PAD_TXSLEW_CTRL_P);
+ val |= FIELD_PREP(PHY_PAD_TXSLEW_CTRL_N_MASK, PHY_PAD_TXSLEW_CTRL_N);
+ sdhci_writew(host, val, PHY_STBPAD_CNFG_R);
+
+ /* enable phy dll */
+ sdhci_writeb(host, PHY_DLL_CTRL_ENABLE, PHY_DLL_CTRL_R);
+}
+
+static void th1520_sdhci_set_phy(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ u32 emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO;
+ u16 emmc_ctrl;
+
+ /* Before power on, set PHY configs */
+ if (priv->flags & FLAG_IO_FIXED_1V8)
+ dwcmshc_phy_1_8v_init(host);
+ else
+ dwcmshc_phy_3_3v_init(host);
+
+ if ((host->mmc->caps2 & emmc_caps) == emmc_caps) {
+ emmc_ctrl = sdhci_readw(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);
+ emmc_ctrl |= DWCMSHC_CARD_IS_EMMC;
+ sdhci_writew(host, emmc_ctrl, priv->vendor_specific_area1 + DWCMSHC_EMMC_CONTROL);
+ }
+
+ sdhci_writeb(host, FIELD_PREP(PHY_DLL_CNFG1_SLVDLY_MASK, PHY_DLL_CNFG1_SLVDLY) |
+ PHY_DLL_CNFG1_WAITCYCLE, PHY_DLL_CNFG1_R);
+}
+
static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
unsigned int timing)
{
@@ -189,9 +404,25 @@ static void dwcmshc_set_uhs_signaling(struct sdhci_host *host,
ctrl_2 |= DWCMSHC_CTRL_HS400;
}
+ if (priv->flags & FLAG_IO_FIXED_1V8)
+ ctrl_2 |= SDHCI_CTRL_VDD_180;
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
}
+static void th1520_set_uhs_signaling(struct sdhci_host *host,
+ unsigned int timing)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
+
+ dwcmshc_set_uhs_signaling(host, timing);
+ if (timing == MMC_TIMING_MMC_HS400)
+ priv->delay_line = PHY_SDCLKDL_DC_HS400;
+ else
+ sdhci_writeb(host, 0, PHY_DLLDL_CNFG_R);
+ th1520_sdhci_set_phy(host);
+}
+
static void dwcmshc_hs400_enhanced_strobe(struct mmc_host *mmc,
struct mmc_ios *ios)
{
@@ -338,6 +569,79 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask)
sdhci_reset(host, mask);
}
+static int th1520_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ u32 val = 0;
+
+ if (host->flags & SDHCI_HS400_TUNING)
+ return 0;
+
+ sdhci_writeb(host, FIELD_PREP(PHY_ATDL_CNFG_INPSEL_MASK, PHY_ATDL_CNFG_INPSEL),
+ PHY_ATDL_CNFG_R);
+ val = sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
+
+ /*
+ * configure tuning settings:
+ * - center phase select code driven in block gap interval
+ * - disable reporting of framing errors
+ * - disable software managed tuning
+ * - disable user selection of sampling window edges,
+ * instead tuning calculated edges are used
+ */
+ val &= ~(AT_CTRL_CI_SEL | AT_CTRL_RPT_TUNE_ERR | AT_CTRL_SW_TUNE_EN |
+ FIELD_PREP(AT_CTRL_WIN_EDGE_SEL_MASK, AT_CTRL_WIN_EDGE_SEL));
+
+ /*
+ * configure tuning settings:
+ * - enable auto-tuning
+ * - enable sampling window threshold
+ * - stop clocks during phase code change
+ * - set max latency in cycles between tx and rx clocks
+ * - set max latency in cycles to switch output phase
+ * - set max sampling window threshold value
+ */
+ val |= AT_CTRL_AT_EN | AT_CTRL_SWIN_TH_EN | AT_CTRL_TUNE_CLK_STOP_EN;
+ val |= FIELD_PREP(AT_CTRL_PRE_CHANGE_DLY_MASK, AT_CTRL_PRE_CHANGE_DLY);
+ val |= FIELD_PREP(AT_CTRL_POST_CHANGE_DLY_MASK, AT_CTRL_POST_CHANGE_DLY);
+ val |= FIELD_PREP(AT_CTRL_SWIN_TH_VAL_MASK, AT_CTRL_SWIN_TH_VAL);
+
+ sdhci_writel(host, val, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
+ val = sdhci_readl(host, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
+
+ /* perform tuning */
+ sdhci_start_tuning(host);
+ host->tuning_err = __sdhci_execute_tuning(host, opcode);
+ if (host->tuning_err) {
+ /* disable auto-tuning upon tuning error */
+ val &= ~AT_CTRL_AT_EN;
+ sdhci_writel(host, val, priv->vendor_specific_area1 + DWCMSHC_EMMC_ATCTRL);
+ dev_err(mmc_dev(host->mmc), "tuning failed: %d\n", host->tuning_err);
+ return -EIO;
+ }
+ sdhci_end_tuning(host);
+
+ return 0;
+}
+
+static void th1520_sdhci_reset(struct sdhci_host *host, u8 mask)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host);
+ u16 ctrl_2;
+
+ sdhci_reset(host, mask);
+
+ if (priv->flags & FLAG_IO_FIXED_1V8) {
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (!(ctrl_2 & SDHCI_CTRL_VDD_180)) {
+ ctrl_2 |= SDHCI_CTRL_VDD_180;
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+ }
+ }
+}
+
static const struct sdhci_ops sdhci_dwcmshc_ops = {
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
@@ -356,6 +660,17 @@ static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = {
.adma_write_desc = dwcmshc_adma_write_desc,
};
+static const struct sdhci_ops sdhci_dwcmshc_th1520_ops = {
+ .set_clock = sdhci_set_clock,
+ .set_bus_width = sdhci_set_bus_width,
+ .set_uhs_signaling = th1520_set_uhs_signaling,
+ .get_max_clock = dwcmshc_get_max_clock,
+ .reset = th1520_sdhci_reset,
+ .adma_write_desc = dwcmshc_adma_write_desc,
+ .voltage_switch = dwcmshc_phy_1_8v_init,
+ .platform_execute_tuning = &th1520_execute_tuning,
+};
+
static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = {
.ops = &sdhci_dwcmshc_ops,
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
@@ -379,6 +694,12 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = {
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN,
};
+static const struct sdhci_pltfm_data sdhci_dwcmshc_th1520_pdata = {
+ .ops = &sdhci_dwcmshc_th1520_ops,
+ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv)
{
int err;
@@ -447,6 +768,10 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = {
.compatible = "snps,dwcmshc-sdhci",
.data = &sdhci_dwcmshc_pdata,
},
+ {
+ .compatible = "thead,th1520-dwcmshc",
+ .data = &sdhci_dwcmshc_th1520_pdata,
+ },
{},
};
MODULE_DEVICE_TABLE(of, sdhci_dwcmshc_dt_ids);
@@ -542,6 +867,30 @@ static int dwcmshc_probe(struct platform_device *pdev)
goto err_clk;
}
+ if (pltfm_data == &sdhci_dwcmshc_th1520_pdata) {
+ priv->delay_line = PHY_SDCLKDL_DC_DEFAULT;
+
+ if (device_property_read_bool(dev, "mmc-ddr-1_8v") ||
+ device_property_read_bool(dev, "mmc-hs200-1_8v") ||
+ device_property_read_bool(dev, "mmc-hs400-1_8v"))
+ priv->flags |= FLAG_IO_FIXED_1V8;
+ else
+ priv->flags &= ~FLAG_IO_FIXED_1V8;
+
+ /*
+ * start_signal_voltage_switch() will try 3.3V first
+ * then 1.8V. Use SDHCI_SIGNALING_180 rather than
+ * SDHCI_SIGNALING_330 to avoid setting voltage to 3.3V
+ * in sdhci_start_signal_voltage_switch().
+ */
+ if (priv->flags & FLAG_IO_FIXED_1V8) {
+ host->flags &= ~SDHCI_SIGNALING_330;
+ host->flags |= SDHCI_SIGNALING_180;
+ }
+
+ sdhci_enable_v4_mode(host);
+ }
+
#ifdef CONFIG_ACPI
if (pltfm_data == &sdhci_dwcmshc_bf3_pdata)
sdhci_enable_v4_mode(host);
diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c
index 1e0bc7bace1b..e78faef67d7a 100644
--- a/drivers/mmc/host/sdhci-omap.c
+++ b/drivers/mmc/host/sdhci-omap.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* SDHCI Controller driver for TI's OMAP SoCs
*
* Copyright (C) 2017 Texas Instruments
diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c
index 25ba7aecc3be..0e52867f6e91 100644
--- a/drivers/mmc/host/sdhci-xenon.c
+++ b/drivers/mmc/host/sdhci-xenon.c
@@ -18,6 +18,8 @@
#include <linux/of.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
#include "sdhci-pltfm.h"
#include "sdhci-xenon.h"
@@ -422,6 +424,7 @@ static int xenon_probe_params(struct platform_device *pdev)
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
u32 sdhc_id, nr_sdhc;
u32 tuning_count;
+ struct sysinfo si;
/* Disable HS200 on Armada AP806 */
if (priv->hw_version == XENON_AP806)
@@ -450,6 +453,23 @@ static int xenon_probe_params(struct platform_device *pdev)
}
priv->tuning_count = tuning_count;
+ /*
+ * AC5/X/IM HW has only 31-bits passed in the crossbar switch.
+ * If we have more than 2GB of memory, this means we might pass
+ * memory pointers which are above 2GB and which cannot be properly
+ * represented. In this case, disable ADMA, 64-bit DMA and allow only SDMA.
+ * This effectively will enable bounce buffer quirk in the
+ * generic SDHCI driver, which will make sure DMA is only done
+ * from supported memory regions:
+ */
+ if (priv->hw_version == XENON_AC5) {
+ si_meminfo(&si);
+ if (si.totalram * si.mem_unit > SZ_2G) {
+ host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
+ host->quirks2 |= SDHCI_QUIRK2_BROKEN_64_BIT_DMA;
+ }
+ }
+
return xenon_phy_parse_params(dev, host);
}
@@ -562,6 +582,16 @@ static int xenon_probe(struct platform_device *pdev)
goto remove_sdhc;
pm_runtime_put_autosuspend(&pdev->dev);
+ /*
+ * If we previously detected AC5 with over 2GB of memory,
+ * then we disable ADMA and 64-bit DMA.
+ * This means generic SDHCI driver has set the DMA mask to
+ * 32-bit. Since DDR starts at 0x2_0000_0000, we must use
+ * 34-bit DMA mask to access this DDR memory:
+ */
+ if (priv->hw_version == XENON_AC5 &&
+ host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA)
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
return 0;
@@ -680,6 +710,7 @@ static const struct of_device_id sdhci_xenon_dt_ids[] = {
{ .compatible = "marvell,armada-ap807-sdhci", .data = (void *)XENON_AP807},
{ .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110},
{ .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700},
+ { .compatible = "marvell,ac5-sdhci", .data = (void *)XENON_AC5},
{}
};
MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids);
diff --git a/drivers/mmc/host/sdhci-xenon.h b/drivers/mmc/host/sdhci-xenon.h
index 3e9c6c908a79..0460d97aad26 100644
--- a/drivers/mmc/host/sdhci-xenon.h
+++ b/drivers/mmc/host/sdhci-xenon.h
@@ -57,7 +57,8 @@ enum xenon_variant {
XENON_A3700,
XENON_AP806,
XENON_AP807,
- XENON_CP110
+ XENON_CP110,
+ XENON_AC5
};
struct xenon_priv {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ff41aa56564e..c79f73459915 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2841,7 +2841,7 @@ void sdhci_send_tuning(struct sdhci_host *host, u32 opcode)
}
EXPORT_SYMBOL_GPL(sdhci_send_tuning);
-static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
+int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
{
int i;
@@ -2879,6 +2879,7 @@ static int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
sdhci_reset_tuning(host);
return -EAGAIN;
}
+EXPORT_SYMBOL_GPL(__sdhci_execute_tuning);
int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index f219bdea8f28..a20864fc0641 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -793,6 +793,7 @@ void sdhci_set_bus_width(struct sdhci_host *host, int width);
void sdhci_reset(struct sdhci_host *host, u8 mask);
void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
+int __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode);
void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
struct mmc_ios *ios);
diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c
index 967bd2dfcda1..d659c59422e1 100644
--- a/drivers/mmc/host/sdhci_am654.c
+++ b/drivers/mmc/host/sdhci_am654.c
@@ -141,7 +141,6 @@ static const struct timing_data td[] = {
struct sdhci_am654_data {
struct regmap *base;
- bool legacy_otapdly;
int otap_del_sel[ARRAY_SIZE(td)];
int itap_del_sel[ARRAY_SIZE(td)];
int clkbuf_sel;
@@ -272,11 +271,7 @@ static void sdhci_am654_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_set_clock(host, clock);
/* Setup DLL Output TAP delay */
- if (sdhci_am654->legacy_otapdly)
- otap_del_sel = sdhci_am654->otap_del_sel[0];
- else
- otap_del_sel = sdhci_am654->otap_del_sel[timing];
-
+ otap_del_sel = sdhci_am654->otap_del_sel[timing];
otap_del_ena = (timing > MMC_TIMING_UHS_SDR25) ? 1 : 0;
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
@@ -314,10 +309,7 @@ static void sdhci_j721e_4bit_set_clock(struct sdhci_host *host,
u32 mask, val;
/* Setup DLL Output TAP delay */
- if (sdhci_am654->legacy_otapdly)
- otap_del_sel = sdhci_am654->otap_del_sel[0];
- else
- otap_del_sel = sdhci_am654->otap_del_sel[timing];
+ otap_del_sel = sdhci_am654->otap_del_sel[timing];
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
val = (0x1 << OTAPDLYENA_SHIFT) |
@@ -577,32 +569,15 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host,
int i;
int ret;
- ret = device_property_read_u32(dev, td[MMC_TIMING_LEGACY].otap_binding,
- &sdhci_am654->otap_del_sel[MMC_TIMING_LEGACY]);
- if (ret) {
- /*
- * ti,otap-del-sel-legacy is mandatory, look for old binding
- * if not found.
- */
- ret = device_property_read_u32(dev, "ti,otap-del-sel",
- &sdhci_am654->otap_del_sel[0]);
- if (ret) {
- dev_err(dev, "Couldn't find otap-del-sel\n");
-
- return ret;
- }
-
- dev_info(dev, "Using legacy binding ti,otap-del-sel\n");
- sdhci_am654->legacy_otapdly = true;
-
- return 0;
- }
-
for (i = MMC_TIMING_LEGACY; i <= MMC_TIMING_MMC_HS400; i++) {
ret = device_property_read_u32(dev, td[i].otap_binding,
&sdhci_am654->otap_del_sel[i]);
if (ret) {
+ if (i == MMC_TIMING_LEGACY) {
+ dev_err(dev, "Couldn't find mandatory ti,otap-del-sel-legacy\n");
+ return ret;
+ }
dev_dbg(dev, "Couldn't find %s\n",
td[i].otap_binding);
/*
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index bb0759ca12f1..e451b28840d5 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -30,6 +30,7 @@
#include <linux/debugfs.h>
#include <linux/nvmem-provider.h>
#include <linux/root_dev.h>
+#include <linux/error-injection.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -1412,6 +1413,7 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
return ret;
}
EXPORT_SYMBOL_GPL(mtd_erase);
+ALLOW_ERROR_INJECTION(mtd_erase, ERRNO);
/*
* This stuff for eXecute-In-Place. phys is optional and may be set to NULL.
@@ -1511,6 +1513,7 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
return ret;
}
EXPORT_SYMBOL_GPL(mtd_read);
+ALLOW_ERROR_INJECTION(mtd_read, ERRNO);
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
const u_char *buf)
@@ -1527,6 +1530,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
return ret;
}
EXPORT_SYMBOL_GPL(mtd_write);
+ALLOW_ERROR_INJECTION(mtd_write, ERRNO);
/*
* In blackbox flight recorder like scenarios we want to make successful writes
@@ -2347,6 +2351,7 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
return 0;
}
EXPORT_SYMBOL_GPL(mtd_block_markbad);
+ALLOW_ERROR_INJECTION(mtd_block_markbad, ERRNO);
/*
* default_mtd_writev - the default writev method
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index 2ed77b7b3fcb..7499a540121e 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -104,4 +104,13 @@ config MTD_UBI_BLOCK
If in doubt, say "N".
+config MTD_UBI_FAULT_INJECTION
+ bool "Fault injection capability of UBI device"
+ default n
+ depends on FAULT_INJECTION_DEBUG_FS
+ help
+ This option enables fault-injection support for UBI devices for
+ testing purposes.
+
+ If in doubt, say "N".
endif # MTD_UBI
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index 309a42aeaa4c..654bd7372cd8 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -434,7 +434,7 @@ out_remove_minor:
list_del(&dev->list);
idr_remove(&ubiblock_minor_idr, gd->first_minor);
out_cleanup_disk:
- put_disk(dev->gd);
+ put_disk(gd);
out_free_tags:
blk_mq_free_tag_set(&dev->tag_set);
out_free_dev:
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 27168f511d6d..d57f52bd2ff3 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -10,7 +10,37 @@
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/seq_file.h>
+#include <linux/fault-inject.h>
+
+#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
+static DECLARE_FAULT_ATTR(fault_eccerr_attr);
+static DECLARE_FAULT_ATTR(fault_bitflips_attr);
+static DECLARE_FAULT_ATTR(fault_read_failure_attr);
+static DECLARE_FAULT_ATTR(fault_write_failure_attr);
+static DECLARE_FAULT_ATTR(fault_erase_failure_attr);
+static DECLARE_FAULT_ATTR(fault_power_cut_attr);
+static DECLARE_FAULT_ATTR(fault_io_ff_attr);
+static DECLARE_FAULT_ATTR(fault_io_ff_bitflips_attr);
+static DECLARE_FAULT_ATTR(fault_bad_hdr_attr);
+static DECLARE_FAULT_ATTR(fault_bad_hdr_ebadmsg_attr);
+
+#define FAIL_ACTION(name, fault_attr) \
+bool should_fail_##name(void) \
+{ \
+ return should_fail(&fault_attr, 1); \
+}
+FAIL_ACTION(eccerr, fault_eccerr_attr)
+FAIL_ACTION(bitflips, fault_bitflips_attr)
+FAIL_ACTION(read_failure, fault_read_failure_attr)
+FAIL_ACTION(write_failure, fault_write_failure_attr)
+FAIL_ACTION(erase_failure, fault_erase_failure_attr)
+FAIL_ACTION(power_cut, fault_power_cut_attr)
+FAIL_ACTION(io_ff, fault_io_ff_attr)
+FAIL_ACTION(io_ff_bitflips, fault_io_ff_bitflips_attr)
+FAIL_ACTION(bad_hdr, fault_bad_hdr_attr)
+FAIL_ACTION(bad_hdr_ebadmsg, fault_bad_hdr_ebadmsg_attr)
+#endif
/**
* ubi_dump_flash - dump a region of flash.
@@ -212,6 +242,52 @@ void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req)
*/
static struct dentry *dfs_rootdir;
+#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
+static void dfs_create_fault_entry(struct dentry *parent)
+{
+ struct dentry *dir;
+
+ dir = debugfs_create_dir("fault_inject", parent);
+ if (IS_ERR_OR_NULL(dir)) {
+ int err = dir ? PTR_ERR(dir) : -ENODEV;
+
+ pr_warn("UBI error: cannot create \"fault_inject\" debugfs directory, error %d\n",
+ err);
+ return;
+ }
+
+ fault_create_debugfs_attr("emulate_eccerr", dir,
+ &fault_eccerr_attr);
+
+ fault_create_debugfs_attr("emulate_read_failure", dir,
+ &fault_read_failure_attr);
+
+ fault_create_debugfs_attr("emulate_bitflips", dir,
+ &fault_bitflips_attr);
+
+ fault_create_debugfs_attr("emulate_write_failure", dir,
+ &fault_write_failure_attr);
+
+ fault_create_debugfs_attr("emulate_erase_failure", dir,
+ &fault_erase_failure_attr);
+
+ fault_create_debugfs_attr("emulate_power_cut", dir,
+ &fault_power_cut_attr);
+
+ fault_create_debugfs_attr("emulate_io_ff", dir,
+ &fault_io_ff_attr);
+
+ fault_create_debugfs_attr("emulate_io_ff_bitflips", dir,
+ &fault_io_ff_bitflips_attr);
+
+ fault_create_debugfs_attr("emulate_bad_hdr", dir,
+ &fault_bad_hdr_attr);
+
+ fault_create_debugfs_attr("emulate_bad_hdr_ebadmsg", dir,
+ &fault_bad_hdr_ebadmsg_attr);
+}
+#endif
+
/**
* ubi_debugfs_init - create UBI debugfs directory.
*
@@ -232,6 +308,10 @@ int ubi_debugfs_init(void)
return err;
}
+#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
+ dfs_create_fault_entry(dfs_rootdir);
+#endif
+
return 0;
}
@@ -252,7 +332,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
struct dentry *dent = file->f_path.dentry;
struct ubi_device *ubi;
struct ubi_debug_info *d;
- char buf[8];
+ char buf[16];
int val;
ubi = ubi_get_device(ubi_num);
@@ -272,7 +352,12 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
val = d->emulate_bitflips;
else if (dent == d->dfs_emulate_io_failures)
val = d->emulate_io_failures;
- else if (dent == d->dfs_emulate_power_cut) {
+ else if (dent == d->dfs_emulate_failures) {
+ snprintf(buf, sizeof(buf), "0x%04x\n", d->emulate_failures);
+ count = simple_read_from_buffer(user_buf, count, ppos,
+ buf, strlen(buf));
+ goto out;
+ } else if (dent == d->dfs_emulate_power_cut) {
snprintf(buf, sizeof(buf), "%u\n", d->emulate_power_cut);
count = simple_read_from_buffer(user_buf, count, ppos,
buf, strlen(buf));
@@ -287,8 +372,7 @@ static ssize_t dfs_file_read(struct file *file, char __user *user_buf,
count = simple_read_from_buffer(user_buf, count, ppos,
buf, strlen(buf));
goto out;
- }
- else {
+ } else {
count = -EINVAL;
goto out;
}
@@ -316,7 +400,7 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
struct ubi_device *ubi;
struct ubi_debug_info *d;
size_t buf_size;
- char buf[8] = {0};
+ char buf[16] = {0};
int val;
ubi = ubi_get_device(ubi_num);
@@ -330,7 +414,11 @@ static ssize_t dfs_file_write(struct file *file, const char __user *user_buf,
goto out;
}
- if (dent == d->dfs_power_cut_min) {
+ if (dent == d->dfs_emulate_failures) {
+ if (kstrtouint(buf, 0, &d->emulate_failures) != 0)
+ count = -EINVAL;
+ goto out;
+ } else if (dent == d->dfs_power_cut_min) {
if (kstrtouint(buf, 0, &d->power_cut_min) != 0)
count = -EINVAL;
goto out;
@@ -559,6 +647,12 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi)
debugfs_create_file("detailed_erase_block_info", S_IRUSR, d->dfs_dir,
(void *)ubi_num, &eraseblk_count_fops);
+#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
+ d->dfs_emulate_failures = debugfs_create_file("emulate_failures",
+ mode, d->dfs_dir,
+ (void *)ubi_num,
+ &dfs_fops);
+#endif
return 0;
}
@@ -600,7 +694,5 @@ int ubi_dbg_power_cut(struct ubi_device *ubi, int caller)
if (ubi->dbg.power_cut_counter)
return 0;
- ubi_msg(ubi, "XXXXXXXXXXXXXXX emulating a power cut XXXXXXXXXXXXXXXX");
- ubi_ro_mode(ubi);
return 1;
}
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index 23676f32b681..b2fd97548808 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -53,56 +53,315 @@ int ubi_debugfs_init_dev(struct ubi_device *ubi);
void ubi_debugfs_exit_dev(struct ubi_device *ubi);
/**
- * ubi_dbg_is_bgt_disabled - if the background thread is disabled.
+ * The following function is a legacy implementation of UBI fault-injection
+ * hook. When using more powerful fault injection capabilities, the legacy
+ * fault injection interface should be retained.
+ */
+int ubi_dbg_power_cut(struct ubi_device *ubi, int caller);
+
+static inline int ubi_dbg_bitflip(const struct ubi_device *ubi)
+{
+ if (ubi->dbg.emulate_bitflips)
+ return !get_random_u32_below(200);
+ return 0;
+}
+
+static inline int ubi_dbg_write_failure(const struct ubi_device *ubi)
+{
+ if (ubi->dbg.emulate_io_failures)
+ return !get_random_u32_below(500);
+ return 0;
+}
+
+static inline int ubi_dbg_erase_failure(const struct ubi_device *ubi)
+{
+ if (ubi->dbg.emulate_io_failures)
+ return !get_random_u32_below(400);
+ return 0;
+}
+
+/**
+ * MASK_XXX: Mask for emulate_failures in ubi_debug_info.The mask is used to
+ * precisely control the type and process of fault injection.
+ */
+/* Emulate a power cut when writing EC/VID header */
+#define MASK_POWER_CUT_EC (1 << 0)
+#define MASK_POWER_CUT_VID (1 << 1)
+/* Emulate a power cut when writing data*/
+#define MASK_POWER_CUT_DATA (1 << 2)
+/* Emulate bit-flips */
+#define MASK_BITFLIPS (1 << 3)
+/* Emulate ecc error */
+#define MASK_ECCERR (1 << 4)
+/* Emulates -EIO during data read */
+#define MASK_READ_FAILURE (1 << 5)
+#define MASK_READ_FAILURE_EC (1 << 6)
+#define MASK_READ_FAILURE_VID (1 << 7)
+/* Emulates -EIO during data write */
+#define MASK_WRITE_FAILURE (1 << 8)
+/* Emulates -EIO during erase a PEB*/
+#define MASK_ERASE_FAILURE (1 << 9)
+/* Return UBI_IO_FF when reading EC/VID header */
+#define MASK_IO_FF_EC (1 << 10)
+#define MASK_IO_FF_VID (1 << 11)
+/* Return UBI_IO_FF_BITFLIPS when reading EC/VID header */
+#define MASK_IO_FF_BITFLIPS_EC (1 << 12)
+#define MASK_IO_FF_BITFLIPS_VID (1 << 13)
+/* Return UBI_IO_BAD_HDR when reading EC/VID header */
+#define MASK_BAD_HDR_EC (1 << 14)
+#define MASK_BAD_HDR_VID (1 << 15)
+/* Return UBI_IO_BAD_HDR_EBADMSG when reading EC/VID header */
+#define MASK_BAD_HDR_EBADMSG_EC (1 << 16)
+#define MASK_BAD_HDR_EBADMSG_VID (1 << 17)
+
+#ifdef CONFIG_MTD_UBI_FAULT_INJECTION
+
+extern bool should_fail_eccerr(void);
+extern bool should_fail_bitflips(void);
+extern bool should_fail_read_failure(void);
+extern bool should_fail_write_failure(void);
+extern bool should_fail_erase_failure(void);
+extern bool should_fail_power_cut(void);
+extern bool should_fail_io_ff(void);
+extern bool should_fail_io_ff_bitflips(void);
+extern bool should_fail_bad_hdr(void);
+extern bool should_fail_bad_hdr_ebadmsg(void);
+
+static inline bool ubi_dbg_fail_bitflip(const struct ubi_device *ubi)
+{
+ if (ubi->dbg.emulate_failures & MASK_BITFLIPS)
+ return should_fail_bitflips();
+ return false;
+}
+
+static inline bool ubi_dbg_fail_write(const struct ubi_device *ubi)
+{
+ if (ubi->dbg.emulate_failures & MASK_WRITE_FAILURE)
+ return should_fail_write_failure();
+ return false;
+}
+
+static inline bool ubi_dbg_fail_erase(const struct ubi_device *ubi)
+{
+ if (ubi->dbg.emulate_failures & MASK_ERASE_FAILURE)
+ return should_fail_erase_failure();
+ return false;
+}
+
+static inline bool ubi_dbg_fail_power_cut(const struct ubi_device *ubi,
+ unsigned int caller)
+{
+ if (ubi->dbg.emulate_failures & caller)
+ return should_fail_power_cut();
+ return false;
+}
+
+static inline bool ubi_dbg_fail_read(const struct ubi_device *ubi,
+ unsigned int caller)
+{
+ if (ubi->dbg.emulate_failures & caller)
+ return should_fail_read_failure();
+ return false;
+}
+
+static inline bool ubi_dbg_fail_eccerr(const struct ubi_device *ubi)
+{
+ if (ubi->dbg.emulate_failures & MASK_ECCERR)
+ return should_fail_eccerr();
+ return false;
+}
+
+static inline bool ubi_dbg_fail_ff(const struct ubi_device *ubi,
+ unsigned int caller)
+{
+ if (ubi->dbg.emulate_failures & caller)
+ return should_fail_io_ff();
+ return false;
+}
+
+static inline bool ubi_dbg_fail_ff_bitflips(const struct ubi_device *ubi,
+ unsigned int caller)
+{
+ if (ubi->dbg.emulate_failures & caller)
+ return should_fail_io_ff_bitflips();
+ return false;
+}
+
+static inline bool ubi_dbg_fail_bad_hdr(const struct ubi_device *ubi,
+ unsigned int caller)
+{
+ if (ubi->dbg.emulate_failures & caller)
+ return should_fail_bad_hdr();
+ return false;
+}
+
+static inline bool ubi_dbg_fail_bad_hdr_ebadmsg(const struct ubi_device *ubi,
+ unsigned int caller)
+{
+ if (ubi->dbg.emulate_failures & caller)
+ return should_fail_bad_hdr_ebadmsg();
+ return false;
+}
+#else /* CONFIG_MTD_UBI_FAULT_INJECTION */
+
+#define ubi_dbg_fail_bitflip(u) false
+#define ubi_dbg_fail_write(u) false
+#define ubi_dbg_fail_erase(u) false
+#define ubi_dbg_fail_power_cut(u, c) false
+#define ubi_dbg_fail_read(u, c) false
+#define ubi_dbg_fail_eccerr(u) false
+#define ubi_dbg_fail_ff(u, c) false
+#define ubi_dbg_fail_ff_bitflips(u, v) false
+#define ubi_dbg_fail_bad_hdr(u, c) false
+#define ubi_dbg_fail_bad_hdr_ebadmsg(u, c) false
+
+#endif
+
+/**
+ * ubi_dbg_is_power_cut - if it is time to emulate power cut.
* @ubi: UBI device description object
*
- * Returns non-zero if the UBI background thread is disabled for testing
- * purposes.
+ * Returns true if power cut should be emulated, otherwise returns false.
*/
-static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
+static inline bool ubi_dbg_is_power_cut(struct ubi_device *ubi,
+ unsigned int caller)
{
- return ubi->dbg.disable_bgt;
+ if (ubi_dbg_power_cut(ubi, caller))
+ return true;
+ return ubi_dbg_fail_power_cut(ubi, caller);
}
/**
* ubi_dbg_is_bitflip - if it is time to emulate a bit-flip.
* @ubi: UBI device description object
*
- * Returns non-zero if a bit-flip should be emulated, otherwise returns zero.
+ * Returns true if a bit-flip should be emulated, otherwise returns false.
*/
-static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi)
+static inline bool ubi_dbg_is_bitflip(const struct ubi_device *ubi)
{
- if (ubi->dbg.emulate_bitflips)
- return !get_random_u32_below(200);
- return 0;
+ if (ubi_dbg_bitflip(ubi))
+ return true;
+ return ubi_dbg_fail_bitflip(ubi);
}
/**
* ubi_dbg_is_write_failure - if it is time to emulate a write failure.
* @ubi: UBI device description object
*
- * Returns non-zero if a write failure should be emulated, otherwise returns
- * zero.
+ * Returns true if a write failure should be emulated, otherwise returns
+ * false.
*/
-static inline int ubi_dbg_is_write_failure(const struct ubi_device *ubi)
+static inline bool ubi_dbg_is_write_failure(const struct ubi_device *ubi)
{
- if (ubi->dbg.emulate_io_failures)
- return !get_random_u32_below(500);
- return 0;
+ if (ubi_dbg_write_failure(ubi))
+ return true;
+ return ubi_dbg_fail_write(ubi);
}
/**
* ubi_dbg_is_erase_failure - if its time to emulate an erase failure.
* @ubi: UBI device description object
*
- * Returns non-zero if an erase failure should be emulated, otherwise returns
- * zero.
+ * Returns true if an erase failure should be emulated, otherwise returns
+ * false.
*/
-static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
+static inline bool ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
{
- if (ubi->dbg.emulate_io_failures)
- return !get_random_u32_below(400);
- return 0;
+ if (ubi_dbg_erase_failure(ubi))
+ return true;
+ return ubi_dbg_fail_erase(ubi);
+}
+
+/**
+ * ubi_dbg_is_eccerr - if it is time to emulate ECC error.
+ * @ubi: UBI device description object
+ *
+ * Returns true if a ECC error should be emulated, otherwise returns false.
+ */
+static inline bool ubi_dbg_is_eccerr(const struct ubi_device *ubi)
+{
+ return ubi_dbg_fail_eccerr(ubi);
+}
+
+/**
+ * ubi_dbg_is_read_failure - if it is time to emulate a read failure.
+ * @ubi: UBI device description object
+ *
+ * Returns true if a read failure should be emulated, otherwise returns
+ * false.
+ */
+static inline bool ubi_dbg_is_read_failure(const struct ubi_device *ubi,
+ unsigned int caller)
+{
+ return ubi_dbg_fail_read(ubi, caller);
+}
+
+/**
+ * ubi_dbg_is_ff - if it is time to emulate that read region is only 0xFF.
+ * @ubi: UBI device description object
+ *
+ * Returns true if read region should be emulated 0xFF, otherwise
+ * returns false.
+ */
+static inline bool ubi_dbg_is_ff(const struct ubi_device *ubi,
+ unsigned int caller)
+{
+ return ubi_dbg_fail_ff(ubi, caller);
+}
+
+/**
+ * ubi_dbg_is_ff_bitflips - if it is time to emulate that read region is only 0xFF
+ * with error reported by the MTD driver
+ *
+ * @ubi: UBI device description object
+ *
+ * Returns true if read region should be emulated 0xFF and error
+ * reported by the MTD driver, otherwise returns false.
+ */
+static inline bool ubi_dbg_is_ff_bitflips(const struct ubi_device *ubi,
+ unsigned int caller)
+{
+ return ubi_dbg_fail_ff_bitflips(ubi, caller);
+}
+
+/**
+ * ubi_dbg_is_bad_hdr - if it is time to emulate a bad header
+ * @ubi: UBI device description object
+ *
+ * Returns true if a bad header error should be emulated, otherwise
+ * returns false.
+ */
+static inline bool ubi_dbg_is_bad_hdr(const struct ubi_device *ubi,
+ unsigned int caller)
+{
+ return ubi_dbg_fail_bad_hdr(ubi, caller);
+}
+
+/**
+ * ubi_dbg_is_bad_hdr_ebadmsg - if it is time to emulate a bad header with
+ * ECC error.
+ *
+ * @ubi: UBI device description object
+ *
+ * Returns true if a bad header with ECC error should be emulated, otherwise
+ * returns false.
+ */
+static inline bool ubi_dbg_is_bad_hdr_ebadmsg(const struct ubi_device *ubi,
+ unsigned int caller)
+{
+ return ubi_dbg_fail_bad_hdr_ebadmsg(ubi, caller);
+}
+
+/**
+ * ubi_dbg_is_bgt_disabled - if the background thread is disabled.
+ * @ubi: UBI device description object
+ *
+ * Returns non-zero if the UBI background thread is disabled for testing
+ * purposes.
+ */
+static inline int ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi)
+{
+ return ubi->dbg.disable_bgt;
}
static inline int ubi_dbg_chk_io(const struct ubi_device *ubi)
@@ -125,5 +384,4 @@ static inline void ubi_enable_dbg_chk_fastmap(struct ubi_device *ubi)
ubi->dbg.chk_fastmap = 1;
}
-int ubi_dbg_power_cut(struct ubi_device *ubi, int caller);
#endif /* !__UBI_DEBUG_H__ */
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 01b644861253..a4999bce435f 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -195,7 +195,19 @@ retry:
if (ubi_dbg_is_bitflip(ubi)) {
dbg_gen("bit-flip (emulated)");
- err = UBI_IO_BITFLIPS;
+ return UBI_IO_BITFLIPS;
+ }
+
+ if (ubi_dbg_is_read_failure(ubi, MASK_READ_FAILURE)) {
+ ubi_warn(ubi, "cannot read %d bytes from PEB %d:%d (emulated)",
+ len, pnum, offset);
+ return -EIO;
+ }
+
+ if (ubi_dbg_is_eccerr(ubi)) {
+ ubi_warn(ubi, "ECC error (emulated) while reading %d bytes from PEB %d:%d, read %zd bytes",
+ len, pnum, offset, read);
+ return -EBADMSG;
}
}
@@ -782,7 +794,36 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
* If there was %-EBADMSG, but the header CRC is still OK, report about
* a bit-flip to force scrubbing on this PEB.
*/
- return read_err ? UBI_IO_BITFLIPS : 0;
+ if (read_err)
+ return UBI_IO_BITFLIPS;
+
+ if (ubi_dbg_is_read_failure(ubi, MASK_READ_FAILURE_EC)) {
+ ubi_warn(ubi, "cannot read EC header from PEB %d (emulated)",
+ pnum);
+ return -EIO;
+ }
+
+ if (ubi_dbg_is_ff(ubi, MASK_IO_FF_EC)) {
+ ubi_warn(ubi, "bit-all-ff (emulated)");
+ return UBI_IO_FF;
+ }
+
+ if (ubi_dbg_is_ff_bitflips(ubi, MASK_IO_FF_BITFLIPS_EC)) {
+ ubi_warn(ubi, "bit-all-ff with error reported by MTD driver (emulated)");
+ return UBI_IO_FF_BITFLIPS;
+ }
+
+ if (ubi_dbg_is_bad_hdr(ubi, MASK_BAD_HDR_EC)) {
+ ubi_warn(ubi, "bad_hdr (emulated)");
+ return UBI_IO_BAD_HDR;
+ }
+
+ if (ubi_dbg_is_bad_hdr_ebadmsg(ubi, MASK_BAD_HDR_EBADMSG_EC)) {
+ ubi_warn(ubi, "bad_hdr with ECC error (emulated)");
+ return UBI_IO_BAD_HDR_EBADMSG;
+ }
+
+ return 0;
}
/**
@@ -821,8 +862,11 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
if (err)
return err;
- if (ubi_dbg_power_cut(ubi, POWER_CUT_EC_WRITE))
+ if (ubi_dbg_is_power_cut(ubi, MASK_POWER_CUT_EC)) {
+ ubi_warn(ubi, "emulating a power cut when writing EC header");
+ ubi_ro_mode(ubi);
return -EROFS;
+ }
err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize);
return err;
@@ -1029,7 +1073,36 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
return -EINVAL;
}
- return read_err ? UBI_IO_BITFLIPS : 0;
+ if (read_err)
+ return UBI_IO_BITFLIPS;
+
+ if (ubi_dbg_is_read_failure(ubi, MASK_READ_FAILURE_VID)) {
+ ubi_warn(ubi, "cannot read VID header from PEB %d (emulated)",
+ pnum);
+ return -EIO;
+ }
+
+ if (ubi_dbg_is_ff(ubi, MASK_IO_FF_VID)) {
+ ubi_warn(ubi, "bit-all-ff (emulated)");
+ return UBI_IO_FF;
+ }
+
+ if (ubi_dbg_is_ff_bitflips(ubi, MASK_IO_FF_BITFLIPS_VID)) {
+ ubi_warn(ubi, "bit-all-ff with error reported by MTD driver (emulated)");
+ return UBI_IO_FF_BITFLIPS;
+ }
+
+ if (ubi_dbg_is_bad_hdr(ubi, MASK_BAD_HDR_VID)) {
+ ubi_warn(ubi, "bad_hdr (emulated)");
+ return UBI_IO_BAD_HDR;
+ }
+
+ if (ubi_dbg_is_bad_hdr_ebadmsg(ubi, MASK_BAD_HDR_EBADMSG_VID)) {
+ ubi_warn(ubi, "bad_hdr with ECC error (emulated)");
+ return UBI_IO_BAD_HDR_EBADMSG;
+ }
+
+ return 0;
}
/**
@@ -1071,8 +1144,11 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
if (err)
return err;
- if (ubi_dbg_power_cut(ubi, POWER_CUT_VID_WRITE))
+ if (ubi_dbg_is_power_cut(ubi, MASK_POWER_CUT_VID)) {
+ ubi_warn(ubi, "emulating a power cut when writing VID header");
+ ubi_ro_mode(ubi);
return -EROFS;
+ }
err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset,
ubi->vid_hdr_alsize);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index a5ec566df0d7..0b42bb45dd84 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -145,17 +145,6 @@ enum {
UBI_BAD_FASTMAP,
};
-/*
- * Flags for emulate_power_cut in ubi_debug_info
- *
- * POWER_CUT_EC_WRITE: Emulate a power cut when writing an EC header
- * POWER_CUT_VID_WRITE: Emulate a power cut when writing a VID header
- */
-enum {
- POWER_CUT_EC_WRITE = 0x01,
- POWER_CUT_VID_WRITE = 0x02,
-};
-
/**
* struct ubi_vid_io_buf - VID buffer used to read/write VID info to/from the
* flash.
@@ -404,6 +393,7 @@ struct ubi_volume_desc {
* @power_cut_counter: count down for writes left until emulated power cut
* @power_cut_min: minimum number of writes before emulating a power cut
* @power_cut_max: maximum number of writes until emulating a power cut
+ * @emulate_failures: emulate failures for testing purposes
* @dfs_dir_name: name of debugfs directory containing files of this UBI device
* @dfs_dir: direntry object of the UBI device debugfs directory
* @dfs_chk_gen: debugfs knob to enable UBI general extra checks
@@ -415,6 +405,7 @@ struct ubi_volume_desc {
* @dfs_emulate_power_cut: debugfs knob to emulate power cuts
* @dfs_power_cut_min: debugfs knob for minimum writes before power cut
* @dfs_power_cut_max: debugfs knob for maximum writes until power cut
+ * @dfs_emulate_failures: debugfs entry to control the fault injection type
*/
struct ubi_debug_info {
unsigned int chk_gen:1;
@@ -427,6 +418,7 @@ struct ubi_debug_info {
unsigned int power_cut_counter;
unsigned int power_cut_min;
unsigned int power_cut_max;
+ unsigned int emulate_failures;
char dfs_dir_name[UBI_DFS_DIR_LEN + 1];
struct dentry *dfs_dir;
struct dentry *dfs_chk_gen;
@@ -438,6 +430,7 @@ struct ubi_debug_info {
struct dentry *dfs_emulate_power_cut;
struct dentry *dfs_power_cut_min;
struct dentry *dfs_power_cut_max;
+ struct dentry *dfs_emulate_failures;
};
/**
@@ -1130,6 +1123,19 @@ static inline struct ubi_vid_hdr *ubi_get_vid_hdr(struct ubi_vid_io_buf *vidb)
return vidb->hdr;
}
+/**
+ * ubi_ro_mode - switch to read-only mode.
+ * @ubi: UBI device description object
+ */
+static inline void ubi_ro_mode(struct ubi_device *ubi)
+{
+ if (!ubi->ro_mode) {
+ ubi->ro_mode = 1;
+ ubi_warn(ubi, "switch to read-only mode");
+ dump_stack();
+ }
+}
+
/*
* This function is equivalent to 'ubi_io_read()', but @offset is relative to
* the beginning of the logical eraseblock, not to the beginning of the
@@ -1151,20 +1157,13 @@ static inline int ubi_io_write_data(struct ubi_device *ubi, const void *buf,
int pnum, int offset, int len)
{
ubi_assert(offset >= 0);
- return ubi_io_write(ubi, buf, pnum, offset + ubi->leb_start, len);
-}
-/**
- * ubi_ro_mode - switch to read-only mode.
- * @ubi: UBI device description object
- */
-static inline void ubi_ro_mode(struct ubi_device *ubi)
-{
- if (!ubi->ro_mode) {
- ubi->ro_mode = 1;
- ubi_warn(ubi, "switch to read-only mode");
- dump_stack();
+ if (ubi_dbg_power_cut(ubi, MASK_POWER_CUT_DATA)) {
+ ubi_warn(ubi, "XXXXX emulating a power cut when writing data XXXXX");
+ ubi_ro_mode(ubi);
+ return -EROFS;
}
+ return ubi_io_write(ubi, buf, pnum, offset + ubi->leb_start, len);
}
/**
diff --git a/drivers/mux/mmio.c b/drivers/mux/mmio.c
index fd1d121a584b..30a952c34365 100644
--- a/drivers/mux/mmio.c
+++ b/drivers/mux/mmio.c
@@ -44,15 +44,20 @@ static int mux_mmio_probe(struct platform_device *pdev)
int ret;
int i;
- if (of_device_is_compatible(np, "mmio-mux"))
+ if (of_device_is_compatible(np, "mmio-mux")) {
regmap = syscon_node_to_regmap(np->parent);
- else
- regmap = dev_get_regmap(dev->parent, NULL) ?: ERR_PTR(-ENODEV);
- if (IS_ERR(regmap)) {
- ret = PTR_ERR(regmap);
- dev_err(dev, "failed to get regmap: %d\n", ret);
- return ret;
+ } else {
+ regmap = device_node_to_regmap(np);
+ /* Fallback to checking the parent node on "real" errors. */
+ if (IS_ERR(regmap) && regmap != ERR_PTR(-EPROBE_DEFER)) {
+ regmap = dev_get_regmap(dev->parent, NULL);
+ if (!regmap)
+ regmap = ERR_PTR(-ENODEV);
+ }
}
+ if (IS_ERR(regmap))
+ return dev_err_probe(dev, PTR_ERR(regmap),
+ "failed to get regmap\n");
ret = of_property_count_u32_elems(np, "mux-reg-masks");
if (ret == 0 || ret % 2)
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index 24ad9f593a77..1efa39e134f4 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -1143,7 +1143,7 @@ static void __exit peak_usb_exit(void)
int err;
/* last chance do send any synchronous commands here */
- err = driver_for_each_device(&peak_usb_driver.drvwrap.driver, NULL,
+ err = driver_for_each_device(&peak_usb_driver.driver, NULL,
NULL, peak_usb_do_device_exit);
if (err)
pr_err("%s: failed to stop all can devices (err %d)\n",
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
index b4eb17141edf..349e28a6dd8d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h
@@ -618,13 +618,6 @@ static inline bool mlx5_esw_allowed(const struct mlx5_eswitch *esw)
return esw && MLX5_ESWITCH_MANAGER(esw->dev);
}
-/* The returned number is valid only when the dev is eswitch manager. */
-static inline u16 mlx5_eswitch_manager_vport(struct mlx5_core_dev *dev)
-{
- return mlx5_core_is_ecpf_esw_manager(dev) ?
- MLX5_VPORT_ECPF : MLX5_VPORT_PF;
-}
-
static inline bool
mlx5_esw_is_manager_vport(const struct mlx5_eswitch *esw, u16 vport_num)
{
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c b/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c
index 9482e51ac82a..7c5516b0a844 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/dm.c
@@ -13,11 +13,13 @@ struct mlx5_dm {
unsigned long *steering_sw_icm_alloc_blocks;
unsigned long *header_modify_sw_icm_alloc_blocks;
unsigned long *header_modify_pattern_sw_icm_alloc_blocks;
+ unsigned long *header_encap_sw_icm_alloc_blocks;
};
struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
{
u64 header_modify_pattern_icm_blocks = 0;
+ u64 header_sw_encap_icm_blocks = 0;
u64 header_modify_icm_blocks = 0;
u64 steering_icm_blocks = 0;
struct mlx5_dm *dm;
@@ -54,6 +56,17 @@ struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
goto err_modify_hdr;
}
+ if (MLX5_CAP_DEV_MEM(dev, log_indirect_encap_sw_icm_size)) {
+ header_sw_encap_icm_blocks =
+ BIT(MLX5_CAP_DEV_MEM(dev, log_indirect_encap_sw_icm_size) -
+ MLX5_LOG_SW_ICM_BLOCK_SIZE(dev));
+
+ dm->header_encap_sw_icm_alloc_blocks =
+ bitmap_zalloc(header_sw_encap_icm_blocks, GFP_KERNEL);
+ if (!dm->header_encap_sw_icm_alloc_blocks)
+ goto err_pattern;
+ }
+
support_v2 = MLX5_CAP_FLOWTABLE_NIC_RX(dev, sw_owner_v2) &&
MLX5_CAP_FLOWTABLE_NIC_TX(dev, sw_owner_v2) &&
MLX5_CAP64_DEV_MEM(dev, header_modify_pattern_sw_icm_start_address);
@@ -66,11 +79,14 @@ struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev)
dm->header_modify_pattern_sw_icm_alloc_blocks =
bitmap_zalloc(header_modify_pattern_icm_blocks, GFP_KERNEL);
if (!dm->header_modify_pattern_sw_icm_alloc_blocks)
- goto err_pattern;
+ goto err_sw_encap;
}
return dm;
+err_sw_encap:
+ bitmap_free(dm->header_encap_sw_icm_alloc_blocks);
+
err_pattern:
bitmap_free(dm->header_modify_sw_icm_alloc_blocks);
@@ -105,6 +121,14 @@ void mlx5_dm_cleanup(struct mlx5_core_dev *dev)
bitmap_free(dm->header_modify_sw_icm_alloc_blocks);
}
+ if (dm->header_encap_sw_icm_alloc_blocks) {
+ WARN_ON(!bitmap_empty(dm->header_encap_sw_icm_alloc_blocks,
+ BIT(MLX5_CAP_DEV_MEM(dev,
+ log_indirect_encap_sw_icm_size) -
+ MLX5_LOG_SW_ICM_BLOCK_SIZE(dev))));
+ bitmap_free(dm->header_encap_sw_icm_alloc_blocks);
+ }
+
if (dm->header_modify_pattern_sw_icm_alloc_blocks) {
WARN_ON(!bitmap_empty(dm->header_modify_pattern_sw_icm_alloc_blocks,
BIT(MLX5_CAP_DEV_MEM(dev,
@@ -164,6 +188,13 @@ int mlx5_dm_sw_icm_alloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type,
log_header_modify_pattern_sw_icm_size);
block_map = dm->header_modify_pattern_sw_icm_alloc_blocks;
break;
+ case MLX5_SW_ICM_TYPE_SW_ENCAP:
+ icm_start_addr = MLX5_CAP64_DEV_MEM(dev,
+ indirect_encap_sw_icm_start_address);
+ log_icm_size = MLX5_CAP_DEV_MEM(dev,
+ log_indirect_encap_sw_icm_size);
+ block_map = dm->header_encap_sw_icm_alloc_blocks;
+ break;
default:
return -EINVAL;
}
@@ -242,6 +273,11 @@ int mlx5_dm_sw_icm_dealloc(struct mlx5_core_dev *dev, enum mlx5_sw_icm_type type
header_modify_pattern_sw_icm_start_address);
block_map = dm->header_modify_pattern_sw_icm_alloc_blocks;
break;
+ case MLX5_SW_ICM_TYPE_SW_ENCAP:
+ icm_start_addr = MLX5_CAP64_DEV_MEM(dev,
+ indirect_encap_sw_icm_start_address);
+ block_map = dm->header_encap_sw_icm_alloc_blocks;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index a6863011d682..d33b27214539 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -158,6 +158,9 @@ static int mana_gd_detect_devices(struct pci_dev *pdev)
if (dev_type == GDMA_DEVICE_MANA) {
gc->mana.gdma_context = gc;
gc->mana.dev_id = dev;
+ } else if (dev_type == GDMA_DEVICE_MANA_IB) {
+ gc->mana_ib.dev_id = dev;
+ gc->mana_ib.gdma_context = gc;
}
}
@@ -967,6 +970,7 @@ int mana_gd_register_device(struct gdma_dev *gd)
return 0;
}
+EXPORT_SYMBOL_NS(mana_gd_register_device, NET_MANA);
int mana_gd_deregister_device(struct gdma_dev *gd)
{
@@ -997,6 +1001,7 @@ int mana_gd_deregister_device(struct gdma_dev *gd)
return err;
}
+EXPORT_SYMBOL_NS(mana_gd_deregister_device, NET_MANA);
u32 mana_gd_wq_avail_space(struct gdma_queue *wq)
{
diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c
index 9adec91f35e9..223321897b96 100644
--- a/drivers/net/ethernet/qualcomm/qca_uart.c
+++ b/drivers/net/ethernet/qualcomm/qca_uart.c
@@ -58,9 +58,8 @@ struct qcauart {
unsigned char *tx_buffer;
};
-static int
-qca_tty_receive(struct serdev_device *serdev, const unsigned char *data,
- size_t count)
+static ssize_t
+qca_tty_receive(struct serdev_device *serdev, const u8 *data, size_t count)
{
struct qcauart *qca = serdev_device_get_drvdata(serdev);
struct net_device *netdev = qca->net_dev;
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 83b8452220ec..f088ea2ba6f3 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -363,7 +363,6 @@ static int disable_net;
/* driver info */
static const char driver_name[] = "hso";
static const char tty_filename[] = "ttyHS";
-static const char *version = __FILE__ ": " MOD_AUTHOR;
/* the usb driver itself (registered in hso_init) */
static struct usb_driver hso_driver;
/* serial structures */
@@ -3228,16 +3227,8 @@ static struct usb_driver hso_driver = {
static int __init hso_init(void)
{
- int i;
int result;
- /* put it in the log */
- pr_info("%s\n", version);
-
- /* Initialise the serial table semaphore and table */
- for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++)
- serial_table[i] = NULL;
-
/* allocate our driver using the proper amount of supported minors */
tty_drv = tty_alloc_driver(HSO_SERIAL_TTY_MINORS, TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV);
@@ -3285,8 +3276,6 @@ err_free_tty:
static void __exit hso_exit(void)
{
- pr_info("unloaded\n");
-
tty_unregister_driver(tty_drv);
/* deregister the usb driver */
usb_deregister(&hso_driver);
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 9bf2140fd0a1..0d0672d2a654 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -10069,7 +10069,7 @@ static struct usb_driver rtl8152_driver = {
.disable_hub_initiated_lpm = 1,
};
-static int rtl8152_cfgselector_probe(struct usb_device *udev)
+static int rtl8152_cfgselector_choose_configuration(struct usb_device *udev)
{
struct usb_host_config *c;
int i, num_configs;
@@ -10096,19 +10096,13 @@ static int rtl8152_cfgselector_probe(struct usb_device *udev)
if (i == num_configs)
return -ENODEV;
- if (usb_set_configuration(udev, c->desc.bConfigurationValue)) {
- dev_err(&udev->dev, "Failed to set configuration %d\n",
- c->desc.bConfigurationValue);
- return -ENODEV;
- }
-
- return 0;
+ return c->desc.bConfigurationValue;
}
static struct usb_device_driver rtl8152_cfgselector_driver = {
- .name = MODULENAME "-cfgselector",
- .probe = rtl8152_cfgselector_probe,
- .id_table = rtl8152_table,
+ .name = MODULENAME "-cfgselector",
+ .choose_configuration = rtl8152_cfgselector_choose_configuration,
+ .id_table = rtl8152_table,
.generic_subclass = 1,
.supports_autosuspend = 1,
};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 80220685f5e4..d7fb88bb6ae1 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -2707,7 +2707,6 @@ MODULE_DEVICE_TABLE(pci, brcmf_pcie_devid_table);
static struct pci_driver brcmf_pciedrvr = {
- .node = {},
.name = KBUILD_MODNAME,
.id_table = brcmf_pcie_devid_table,
.probe = brcmf_pcie_probe,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index 2178675ae1a4..0ccf735316c2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -1581,7 +1581,7 @@ static int brcmf_usb_reset_device(struct device *dev, void *notused)
void brcmf_usb_exit(void)
{
- struct device_driver *drv = &brcmf_usbdrvr.drvwrap.driver;
+ struct device_driver *drv = &brcmf_usbdrvr.driver;
int ret;
brcmf_dbg(USB, "Enter\n");
diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c
index d3ab9572e711..515e6db410f2 100644
--- a/drivers/net/wireless/marvell/mwifiex/usb.c
+++ b/drivers/net/wireless/marvell/mwifiex/usb.c
@@ -687,7 +687,7 @@ static struct usb_driver mwifiex_usb_driver = {
.suspend = mwifiex_usb_suspend,
.resume = mwifiex_usb_resume,
.soft_unbind = 1,
- .drvwrap.driver = {
+ .driver = {
.coredump = mwifiex_usb_coredump,
},
};
diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c
index a556acdb947b..2eb5978bd79e 100644
--- a/drivers/nfc/pn533/uart.c
+++ b/drivers/nfc/pn533/uart.c
@@ -203,8 +203,8 @@ static int pn532_uart_rx_is_frame(struct sk_buff *skb)
return 0;
}
-static int pn532_receive_buf(struct serdev_device *serdev,
- const unsigned char *data, size_t count)
+static ssize_t pn532_receive_buf(struct serdev_device *serdev,
+ const u8 *data, size_t count)
{
struct pn532_uart_phy *dev = serdev_device_get_drvdata(serdev);
size_t i;
diff --git a/drivers/nfc/s3fwrn5/uart.c b/drivers/nfc/s3fwrn5/uart.c
index 82ea35d748a5..456d3947116c 100644
--- a/drivers/nfc/s3fwrn5/uart.c
+++ b/drivers/nfc/s3fwrn5/uart.c
@@ -51,9 +51,8 @@ static const struct s3fwrn5_phy_ops uart_phy_ops = {
.write = s3fwrn82_uart_write,
};
-static int s3fwrn82_uart_read(struct serdev_device *serdev,
- const unsigned char *data,
- size_t count)
+static ssize_t s3fwrn82_uart_read(struct serdev_device *serdev,
+ const u8 *data, size_t count)
{
struct s3fwrn82_uart_phy *phy = serdev_device_get_drvdata(serdev);
size_t i;
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 9372c36e8f76..bb3726b622ad 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -16,6 +16,7 @@
#include <linux/fs.h>
#include <linux/nd.h>
#include <linux/backing-dev.h>
+#include <linux/cleanup.h>
#include "btt.h"
#include "nd.h"
@@ -847,23 +848,20 @@ static int discover_arenas(struct btt *btt)
{
int ret = 0;
struct arena_info *arena;
- struct btt_sb *super;
size_t remaining = btt->rawsize;
u64 cur_nlba = 0;
size_t cur_off = 0;
int num_arenas = 0;
- super = kzalloc(sizeof(*super), GFP_KERNEL);
+ struct btt_sb *super __free(kfree) = kzalloc(sizeof(*super), GFP_KERNEL);
if (!super)
return -ENOMEM;
while (remaining) {
/* Alloc memory for arena */
arena = alloc_arena(btt, 0, 0, 0);
- if (!arena) {
- ret = -ENOMEM;
- goto out_super;
- }
+ if (!arena)
+ return -ENOMEM;
arena->infooff = cur_off;
ret = btt_info_read(arena, super);
@@ -919,14 +917,11 @@ static int discover_arenas(struct btt *btt)
btt->nlba = cur_nlba;
btt->init_state = INIT_READY;
- kfree(super);
return ret;
out:
kfree(arena);
free_arenas(btt);
- out_super:
- kfree(super);
return ret;
}
@@ -1550,7 +1545,7 @@ static void btt_blk_cleanup(struct btt *btt)
* @rawsize: raw size in bytes of the backing device
* @lbasize: lba size of the backing device
* @uuid: A uuid for the backing device - this is stored on media
- * @maxlane: maximum number of parallel requests the device can handle
+ * @nd_region: &struct nd_region for the REGION device
*
* Initialize a Block Translation Table on a backing device to provide
* single sector power fail atomicity.
diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c
index fabbb31f2c35..497fd434a6a1 100644
--- a/drivers/nvdimm/btt_devs.c
+++ b/drivers/nvdimm/btt_devs.c
@@ -19,7 +19,7 @@ static void nd_btt_release(struct device *dev)
dev_dbg(dev, "trace\n");
nd_detach_ndns(&nd_btt->dev, &nd_btt->ndns);
- ida_simple_remove(&nd_region->btt_ida, nd_btt->id);
+ ida_free(&nd_region->btt_ida, nd_btt->id);
kfree(nd_btt->uuid);
kfree(nd_btt);
}
@@ -191,7 +191,7 @@ static struct device *__nd_btt_create(struct nd_region *nd_region,
if (!nd_btt)
return NULL;
- nd_btt->id = ida_simple_get(&nd_region->btt_ida, 0, 0, GFP_KERNEL);
+ nd_btt->id = ida_alloc(&nd_region->btt_ida, GFP_KERNEL);
if (nd_btt->id < 0)
goto out_nd_btt;
@@ -217,7 +217,7 @@ static struct device *__nd_btt_create(struct nd_region *nd_region,
return dev;
out_put_id:
- ida_simple_remove(&nd_region->btt_ida, nd_btt->id);
+ ida_free(&nd_region->btt_ida, nd_btt->id);
out_nd_btt:
kfree(nd_btt);
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 5852fe290523..ef3d0f83318b 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -285,7 +285,7 @@ static void nvdimm_bus_release(struct device *dev)
struct nvdimm_bus *nvdimm_bus;
nvdimm_bus = container_of(dev, struct nvdimm_bus, dev);
- ida_simple_remove(&nd_ida, nvdimm_bus->id);
+ ida_free(&nd_ida, nvdimm_bus->id);
kfree(nvdimm_bus);
}
@@ -342,7 +342,7 @@ struct nvdimm_bus *nvdimm_bus_register(struct device *parent,
INIT_LIST_HEAD(&nvdimm_bus->list);
INIT_LIST_HEAD(&nvdimm_bus->mapping_list);
init_waitqueue_head(&nvdimm_bus->wait);
- nvdimm_bus->id = ida_simple_get(&nd_ida, 0, 0, GFP_KERNEL);
+ nvdimm_bus->id = ida_alloc(&nd_ida, GFP_KERNEL);
if (nvdimm_bus->id < 0) {
kfree(nvdimm_bus);
return NULL;
diff --git a/drivers/nvdimm/dax_devs.c b/drivers/nvdimm/dax_devs.c
index 3bd61f245788..6b4922de3047 100644
--- a/drivers/nvdimm/dax_devs.c
+++ b/drivers/nvdimm/dax_devs.c
@@ -18,7 +18,7 @@ static void nd_dax_release(struct device *dev)
dev_dbg(dev, "trace\n");
nd_detach_ndns(dev, &nd_pfn->ndns);
- ida_simple_remove(&nd_region->dax_ida, nd_pfn->id);
+ ida_free(&nd_region->dax_ida, nd_pfn->id);
kfree(nd_pfn->uuid);
kfree(nd_dax);
}
@@ -55,7 +55,7 @@ static struct nd_dax *nd_dax_alloc(struct nd_region *nd_region)
return NULL;
nd_pfn = &nd_dax->nd_pfn;
- nd_pfn->id = ida_simple_get(&nd_region->dax_ida, 0, 0, GFP_KERNEL);
+ nd_pfn->id = ida_alloc(&nd_region->dax_ida, GFP_KERNEL);
if (nd_pfn->id < 0) {
kfree(nd_dax);
return NULL;
diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c
index 1273873582be..21498d461fde 100644
--- a/drivers/nvdimm/dimm_devs.c
+++ b/drivers/nvdimm/dimm_devs.c
@@ -53,7 +53,9 @@ static int validate_dimm(struct nvdimm_drvdata *ndd)
/**
* nvdimm_init_nsarea - determine the geometry of a dimm's namespace area
- * @nvdimm: dimm to initialize
+ * @ndd: dimm to initialize
+ *
+ * Returns: %0 if the area is already valid, -errno on error
*/
int nvdimm_init_nsarea(struct nvdimm_drvdata *ndd)
{
@@ -194,7 +196,7 @@ static void nvdimm_release(struct device *dev)
{
struct nvdimm *nvdimm = to_nvdimm(dev);
- ida_simple_remove(&dimm_ida, nvdimm->id);
+ ida_free(&dimm_ida, nvdimm->id);
kfree(nvdimm);
}
@@ -592,7 +594,7 @@ struct nvdimm *__nvdimm_create(struct nvdimm_bus *nvdimm_bus,
if (!nvdimm)
return NULL;
- nvdimm->id = ida_simple_get(&dimm_ida, 0, 0, GFP_KERNEL);
+ nvdimm->id = ida_alloc(&dimm_ida, GFP_KERNEL);
if (nvdimm->id < 0) {
kfree(nvdimm);
return NULL;
@@ -722,6 +724,9 @@ static unsigned long dpa_align(struct nd_region *nd_region)
* contiguous unallocated dpa range.
* @nd_region: constrain available space check to this reference region
* @nd_mapping: container of dpa-resource-root + labels
+ *
+ * Returns: %0 if there is an alignment error, otherwise the max
+ * unallocated dpa range
*/
resource_size_t nd_pmem_max_contiguous_dpa(struct nd_region *nd_region,
struct nd_mapping *nd_mapping)
@@ -767,6 +772,8 @@ resource_size_t nd_pmem_max_contiguous_dpa(struct nd_region *nd_region,
*
* Validate that a PMEM label, if present, aligns with the start of an
* interleave set.
+ *
+ * Returns: %0 if there is an alignment error, otherwise the unallocated dpa
*/
resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region,
struct nd_mapping *nd_mapping)
@@ -836,8 +843,10 @@ struct resource *nvdimm_allocate_dpa(struct nvdimm_drvdata *ndd,
/**
* nvdimm_allocated_dpa - sum up the dpa currently allocated to this label_id
- * @nvdimm: container of dpa-resource-root + labels
+ * @ndd: container of dpa-resource-root + labels
* @label_id: dpa resource name of the form pmem-<human readable uuid>
+ *
+ * Returns: sum of the dpa allocated to the label_id
*/
resource_size_t nvdimm_allocated_dpa(struct nvdimm_drvdata *ndd,
struct nd_label_id *label_id)
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index 07177eadc56e..d6d558f94d6b 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -27,7 +27,7 @@ static void namespace_pmem_release(struct device *dev)
struct nd_region *nd_region = to_nd_region(dev->parent);
if (nspm->id >= 0)
- ida_simple_remove(&nd_region->ns_ida, nspm->id);
+ ida_free(&nd_region->ns_ida, nspm->id);
kfree(nspm->alt_name);
kfree(nspm->uuid);
kfree(nspm);
@@ -71,6 +71,8 @@ static int is_namespace_uuid_busy(struct device *dev, void *data)
* nd_is_uuid_unique - verify that no other namespace has @uuid
* @dev: any device on a nvdimm_bus
* @uuid: uuid to check
+ *
+ * Returns: %true if the uuid is unique, %false if not
*/
bool nd_is_uuid_unique(struct device *dev, uuid_t *uuid)
{
@@ -337,6 +339,8 @@ static int scan_free(struct nd_region *nd_region,
* adjust_resource() the allocation to @n, but if @n is larger than the
* allocation delete it and find the 'new' last allocation in the label
* set.
+ *
+ * Returns: %0 on success on -errno on error
*/
static int shrink_dpa_allocation(struct nd_region *nd_region,
struct nd_label_id *label_id, resource_size_t n)
@@ -662,6 +666,8 @@ void release_free_pmem(struct nvdimm_bus *nvdimm_bus,
* allocations from the start of an interleave set and end at the first
* BLK allocation or the end of the interleave set, whichever comes
* first.
+ *
+ * Returns: %0 on success on -errno on error
*/
static int grow_dpa_allocation(struct nd_region *nd_region,
struct nd_label_id *label_id, resource_size_t n)
@@ -951,6 +957,8 @@ static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
* @dev: namespace type for generating label_id
* @new_uuid: incoming uuid
* @old_uuid: reference to the uuid storage location in the namespace object
+ *
+ * Returns: %0 on success on -errno on error
*/
static int namespace_update_uuid(struct nd_region *nd_region,
struct device *dev, uuid_t *new_uuid,
@@ -1656,8 +1664,10 @@ static int select_pmem_id(struct nd_region *nd_region, const uuid_t *pmem_id)
/**
* create_namespace_pmem - validate interleave set labelling, retrieve label0
* @nd_region: region with mappings to validate
- * @nspm: target namespace to create
+ * @nd_mapping: container of dpa-resource-root + labels
* @nd_label: target pmem namespace label to evaluate
+ *
+ * Returns: the created &struct device on success or ERR_PTR(-errno) on error
*/
static struct device *create_namespace_pmem(struct nd_region *nd_region,
struct nd_mapping *nd_mapping,
@@ -1810,7 +1820,7 @@ static struct device *nd_namespace_pmem_create(struct nd_region *nd_region)
res->name = dev_name(&nd_region->dev);
res->flags = IORESOURCE_MEM;
- nspm->id = ida_simple_get(&nd_region->ns_ida, 0, 0, GFP_KERNEL);
+ nspm->id = ida_alloc(&nd_region->ns_ida, GFP_KERNEL);
if (nspm->id < 0) {
kfree(nspm);
return NULL;
@@ -2188,8 +2198,7 @@ int nd_region_register_namespaces(struct nd_region *nd_region, int *err)
struct nd_namespace_pmem *nspm;
nspm = to_nd_namespace_pmem(dev);
- id = ida_simple_get(&nd_region->ns_ida, 0, 0,
- GFP_KERNEL);
+ id = ida_alloc(&nd_region->ns_ida, GFP_KERNEL);
nspm->id = id;
} else
id = i;
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 0d08e21a1cea..586348125b61 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -22,7 +22,7 @@ static void nd_pfn_release(struct device *dev)
dev_dbg(dev, "trace\n");
nd_detach_ndns(&nd_pfn->dev, &nd_pfn->ndns);
- ida_simple_remove(&nd_region->pfn_ida, nd_pfn->id);
+ ida_free(&nd_region->pfn_ida, nd_pfn->id);
kfree(nd_pfn->uuid);
kfree(nd_pfn);
}
@@ -326,7 +326,7 @@ static struct nd_pfn *nd_pfn_alloc(struct nd_region *nd_region)
if (!nd_pfn)
return NULL;
- nd_pfn->id = ida_simple_get(&nd_region->pfn_ida, 0, 0, GFP_KERNEL);
+ nd_pfn->id = ida_alloc(&nd_region->pfn_ida, GFP_KERNEL);
if (nd_pfn->id < 0) {
kfree(nd_pfn);
return NULL;
diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c
index a92eb172f0e7..4ceced5cefcf 100644
--- a/drivers/nvdimm/virtio_pmem.c
+++ b/drivers/nvdimm/virtio_pmem.c
@@ -29,12 +29,27 @@ static int init_vq(struct virtio_pmem *vpmem)
return 0;
};
+static int virtio_pmem_validate(struct virtio_device *vdev)
+{
+ struct virtio_shm_region shm_reg;
+
+ if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION) &&
+ !virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID)
+ ) {
+ dev_notice(&vdev->dev, "failed to get shared memory region %d\n",
+ VIRTIO_PMEM_SHMEM_REGION_ID);
+ __virtio_clear_bit(vdev, VIRTIO_PMEM_F_SHMEM_REGION);
+ }
+ return 0;
+}
+
static int virtio_pmem_probe(struct virtio_device *vdev)
{
struct nd_region_desc ndr_desc = {};
struct nd_region *nd_region;
struct virtio_pmem *vpmem;
struct resource res;
+ struct virtio_shm_region shm_reg;
int err = 0;
if (!vdev->config->get) {
@@ -57,10 +72,16 @@ static int virtio_pmem_probe(struct virtio_device *vdev)
goto out_err;
}
- virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
- start, &vpmem->start);
- virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
- size, &vpmem->size);
+ if (virtio_has_feature(vdev, VIRTIO_PMEM_F_SHMEM_REGION)) {
+ virtio_get_shm_region(vdev, &shm_reg, (u8)VIRTIO_PMEM_SHMEM_REGION_ID);
+ vpmem->start = shm_reg.addr;
+ vpmem->size = shm_reg.len;
+ } else {
+ virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
+ start, &vpmem->start);
+ virtio_cread_le(vpmem->vdev, struct virtio_pmem_config,
+ size, &vpmem->size);
+ }
res.start = vpmem->start;
res.end = vpmem->start + vpmem->size - 1;
@@ -122,10 +143,17 @@ static void virtio_pmem_remove(struct virtio_device *vdev)
virtio_reset_device(vdev);
}
+static unsigned int features[] = {
+ VIRTIO_PMEM_F_SHMEM_REGION,
+};
+
static struct virtio_driver virtio_pmem_driver = {
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
+ .validate = virtio_pmem_validate,
.probe = virtio_pmem_probe,
.remove = virtio_pmem_remove,
};
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 5bc9c4874fe3..283134498fbc 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig NVMEM
bool "NVMEM Support"
+ imply NVMEM_LAYOUTS
help
Support for NVMEM(Non Volatile Memory) devices like EEPROM, EFUSES...
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 423baf089515..cdd01fbf1313 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -5,6 +5,8 @@
obj-$(CONFIG_NVMEM) += nvmem_core.o
nvmem_core-y := core.o
+obj-$(CONFIG_NVMEM_LAYOUTS) += nvmem_layouts.o
+nvmem_layouts-y := layouts.o
obj-y += layouts/
# Devices
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 608b352a7d91..980123fb4dde 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -19,29 +19,7 @@
#include <linux/of.h>
#include <linux/slab.h>
-struct nvmem_device {
- struct module *owner;
- struct device dev;
- int stride;
- int word_size;
- int id;
- struct kref refcnt;
- size_t size;
- bool read_only;
- bool root_only;
- int flags;
- enum nvmem_type type;
- struct bin_attribute eeprom;
- struct device *base_dev;
- struct list_head cells;
- const struct nvmem_keepout *keepout;
- unsigned int nkeepout;
- nvmem_reg_read_t reg_read;
- nvmem_reg_write_t reg_write;
- struct gpio_desc *wp_gpio;
- struct nvmem_layout *layout;
- void *priv;
-};
+#include "internals.h"
#define to_nvmem_device(d) container_of(d, struct nvmem_device, dev)
@@ -77,9 +55,6 @@ static LIST_HEAD(nvmem_lookup_list);
static BLOCKING_NOTIFIER_HEAD(nvmem_notifier);
-static DEFINE_SPINLOCK(nvmem_layout_lock);
-static LIST_HEAD(nvmem_layouts);
-
static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset,
void *val, size_t bytes)
{
@@ -324,6 +299,43 @@ static umode_t nvmem_bin_attr_is_visible(struct kobject *kobj,
return nvmem_bin_attr_get_umode(nvmem);
}
+static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry,
+ const char *id, int index);
+
+static ssize_t nvmem_cell_attr_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t pos, size_t count)
+{
+ struct nvmem_cell_entry *entry;
+ struct nvmem_cell *cell = NULL;
+ size_t cell_sz, read_len;
+ void *content;
+
+ entry = attr->private;
+ cell = nvmem_create_cell(entry, entry->name, 0);
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ if (!cell)
+ return -EINVAL;
+
+ content = nvmem_cell_read(cell, &cell_sz);
+ if (IS_ERR(content)) {
+ read_len = PTR_ERR(content);
+ goto destroy_cell;
+ }
+
+ read_len = min_t(unsigned int, cell_sz - pos, count);
+ memcpy(buf, content + pos, read_len);
+ kfree(content);
+
+destroy_cell:
+ kfree_const(cell->id);
+ kfree(cell);
+
+ return read_len;
+}
+
/* default read/write permissions */
static struct bin_attribute bin_attr_rw_nvmem = {
.attr = {
@@ -345,11 +357,21 @@ static const struct attribute_group nvmem_bin_group = {
.is_bin_visible = nvmem_bin_attr_is_visible,
};
+/* Cell attributes will be dynamically allocated */
+static struct attribute_group nvmem_cells_group = {
+ .name = "cells",
+};
+
static const struct attribute_group *nvmem_dev_groups[] = {
&nvmem_bin_group,
NULL,
};
+static const struct attribute_group *nvmem_cells_groups[] = {
+ &nvmem_cells_group,
+ NULL,
+};
+
static struct bin_attribute bin_attr_nvmem_eeprom_compat = {
.attr = {
.name = "eeprom",
@@ -405,6 +427,68 @@ static void nvmem_sysfs_remove_compat(struct nvmem_device *nvmem,
device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
}
+static int nvmem_populate_sysfs_cells(struct nvmem_device *nvmem)
+{
+ struct bin_attribute **cells_attrs, *attrs;
+ struct nvmem_cell_entry *entry;
+ unsigned int ncells = 0, i = 0;
+ int ret = 0;
+
+ mutex_lock(&nvmem_mutex);
+
+ if (list_empty(&nvmem->cells) || nvmem->sysfs_cells_populated) {
+ nvmem_cells_group.bin_attrs = NULL;
+ goto unlock_mutex;
+ }
+
+ /* Allocate an array of attributes with a sentinel */
+ ncells = list_count_nodes(&nvmem->cells);
+ cells_attrs = devm_kcalloc(&nvmem->dev, ncells + 1,
+ sizeof(struct bin_attribute *), GFP_KERNEL);
+ if (!cells_attrs) {
+ ret = -ENOMEM;
+ goto unlock_mutex;
+ }
+
+ attrs = devm_kcalloc(&nvmem->dev, ncells, sizeof(struct bin_attribute), GFP_KERNEL);
+ if (!attrs) {
+ ret = -ENOMEM;
+ goto unlock_mutex;
+ }
+
+ /* Initialize each attribute to take the name and size of the cell */
+ list_for_each_entry(entry, &nvmem->cells, node) {
+ sysfs_bin_attr_init(&attrs[i]);
+ attrs[i].attr.name = devm_kasprintf(&nvmem->dev, GFP_KERNEL,
+ "%s@%x", entry->name,
+ entry->offset);
+ attrs[i].attr.mode = 0444;
+ attrs[i].size = entry->bytes;
+ attrs[i].read = &nvmem_cell_attr_read;
+ attrs[i].private = entry;
+ if (!attrs[i].attr.name) {
+ ret = -ENOMEM;
+ goto unlock_mutex;
+ }
+
+ cells_attrs[i] = &attrs[i];
+ i++;
+ }
+
+ nvmem_cells_group.bin_attrs = cells_attrs;
+
+ ret = devm_device_add_groups(&nvmem->dev, nvmem_cells_groups);
+ if (ret)
+ goto unlock_mutex;
+
+ nvmem->sysfs_cells_populated = true;
+
+unlock_mutex:
+ mutex_unlock(&nvmem_mutex);
+
+ return ret;
+}
+
#else /* CONFIG_NVMEM_SYSFS */
static int nvmem_sysfs_setup_compat(struct nvmem_device *nvmem,
@@ -697,7 +781,6 @@ static int nvmem_validate_keepouts(struct nvmem_device *nvmem)
static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
{
- struct nvmem_layout *layout = nvmem->layout;
struct device *dev = &nvmem->dev;
struct device_node *child;
const __be32 *addr;
@@ -727,8 +810,8 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod
info.np = of_node_get(child);
- if (layout && layout->fixup_cell_info)
- layout->fixup_cell_info(nvmem, layout, &info);
+ if (nvmem->fixup_dt_cell_info)
+ nvmem->fixup_dt_cell_info(nvmem, &info);
ret = nvmem_add_one_cell(nvmem, &info);
kfree(info.name);
@@ -763,117 +846,35 @@ static int nvmem_add_cells_from_fixed_layout(struct nvmem_device *nvmem)
return err;
}
-int __nvmem_layout_register(struct nvmem_layout *layout, struct module *owner)
-{
- layout->owner = owner;
-
- spin_lock(&nvmem_layout_lock);
- list_add(&layout->node, &nvmem_layouts);
- spin_unlock(&nvmem_layout_lock);
-
- blocking_notifier_call_chain(&nvmem_notifier, NVMEM_LAYOUT_ADD, layout);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(__nvmem_layout_register);
-
-void nvmem_layout_unregister(struct nvmem_layout *layout)
-{
- blocking_notifier_call_chain(&nvmem_notifier, NVMEM_LAYOUT_REMOVE, layout);
-
- spin_lock(&nvmem_layout_lock);
- list_del(&layout->node);
- spin_unlock(&nvmem_layout_lock);
-}
-EXPORT_SYMBOL_GPL(nvmem_layout_unregister);
-
-static struct nvmem_layout *nvmem_layout_get(struct nvmem_device *nvmem)
+int nvmem_layout_register(struct nvmem_layout *layout)
{
- struct device_node *layout_np;
- struct nvmem_layout *l, *layout = ERR_PTR(-EPROBE_DEFER);
-
- layout_np = of_nvmem_layout_get_container(nvmem);
- if (!layout_np)
- return NULL;
-
- /* Fixed layouts don't have a matching driver */
- if (of_device_is_compatible(layout_np, "fixed-layout")) {
- of_node_put(layout_np);
- return NULL;
- }
-
- /*
- * In case the nvmem device was built-in while the layout was built as a
- * module, we shall manually request the layout driver loading otherwise
- * we'll never have any match.
- */
- of_request_module(layout_np);
-
- spin_lock(&nvmem_layout_lock);
-
- list_for_each_entry(l, &nvmem_layouts, node) {
- if (of_match_node(l->of_match_table, layout_np)) {
- if (try_module_get(l->owner))
- layout = l;
-
- break;
- }
- }
-
- spin_unlock(&nvmem_layout_lock);
- of_node_put(layout_np);
-
- return layout;
-}
+ int ret;
-static void nvmem_layout_put(struct nvmem_layout *layout)
-{
- if (layout)
- module_put(layout->owner);
-}
+ if (!layout->add_cells)
+ return -EINVAL;
-static int nvmem_add_cells_from_layout(struct nvmem_device *nvmem)
-{
- struct nvmem_layout *layout = nvmem->layout;
- int ret;
+ /* Populate the cells */
+ ret = layout->add_cells(layout);
+ if (ret)
+ return ret;
- if (layout && layout->add_cells) {
- ret = layout->add_cells(&nvmem->dev, nvmem, layout);
- if (ret)
- return ret;
+#ifdef CONFIG_NVMEM_SYSFS
+ ret = nvmem_populate_sysfs_cells(layout->nvmem);
+ if (ret) {
+ nvmem_device_remove_all_cells(layout->nvmem);
+ return ret;
}
+#endif
return 0;
}
+EXPORT_SYMBOL_GPL(nvmem_layout_register);
-#if IS_ENABLED(CONFIG_OF)
-/**
- * of_nvmem_layout_get_container() - Get OF node to layout container.
- *
- * @nvmem: nvmem device.
- *
- * Return: a node pointer with refcount incremented or NULL if no
- * container exists. Use of_node_put() on it when done.
- */
-struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
-{
- return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
-}
-EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
-#endif
-
-const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem,
- struct nvmem_layout *layout)
+void nvmem_layout_unregister(struct nvmem_layout *layout)
{
- struct device_node __maybe_unused *layout_np;
- const struct of_device_id *match;
-
- layout_np = of_nvmem_layout_get_container(nvmem);
- match = of_match_node(layout->of_match_table, layout_np);
-
- return match ? match->data : NULL;
+ /* Keep the API even with an empty stub in case we need it later */
}
-EXPORT_SYMBOL_GPL(nvmem_layout_get_match_data);
+EXPORT_SYMBOL_GPL(nvmem_layout_unregister);
/**
* nvmem_register() - Register a nvmem device for given nvmem_config.
@@ -925,6 +926,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
kref_init(&nvmem->refcnt);
INIT_LIST_HEAD(&nvmem->cells);
+ nvmem->fixup_dt_cell_info = config->fixup_dt_cell_info;
nvmem->owner = config->owner;
if (!nvmem->owner && config->dev->driver)
@@ -980,19 +982,6 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
goto err_put_device;
}
- /*
- * If the driver supplied a layout by config->layout, the module
- * pointer will be NULL and nvmem_layout_put() will be a noop.
- */
- nvmem->layout = config->layout ?: nvmem_layout_get(nvmem);
- if (IS_ERR(nvmem->layout)) {
- rval = PTR_ERR(nvmem->layout);
- nvmem->layout = NULL;
-
- if (rval == -EPROBE_DEFER)
- goto err_teardown_compat;
- }
-
if (config->cells) {
rval = nvmem_add_cells(nvmem, config->cells, config->ncells);
if (rval)
@@ -1013,24 +1002,34 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
if (rval)
goto err_remove_cells;
- rval = nvmem_add_cells_from_layout(nvmem);
- if (rval)
- goto err_remove_cells;
-
dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name);
rval = device_add(&nvmem->dev);
if (rval)
goto err_remove_cells;
+ rval = nvmem_populate_layout(nvmem);
+ if (rval)
+ goto err_remove_dev;
+
+#ifdef CONFIG_NVMEM_SYSFS
+ rval = nvmem_populate_sysfs_cells(nvmem);
+ if (rval)
+ goto err_destroy_layout;
+#endif
+
blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem);
return nvmem;
+#ifdef CONFIG_NVMEM_SYSFS
+err_destroy_layout:
+ nvmem_destroy_layout(nvmem);
+#endif
+err_remove_dev:
+ device_del(&nvmem->dev);
err_remove_cells:
nvmem_device_remove_all_cells(nvmem);
- nvmem_layout_put(nvmem->layout);
-err_teardown_compat:
if (config->compat)
nvmem_sysfs_remove_compat(nvmem, config);
err_put_device:
@@ -1052,7 +1051,7 @@ static void nvmem_device_release(struct kref *kref)
device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom);
nvmem_device_remove_all_cells(nvmem);
- nvmem_layout_put(nvmem->layout);
+ nvmem_destroy_layout(nvmem);
device_unregister(&nvmem->dev);
}
@@ -1354,6 +1353,12 @@ nvmem_cell_get_from_lookup(struct device *dev, const char *con_id)
return cell;
}
+static void nvmem_layout_module_put(struct nvmem_device *nvmem)
+{
+ if (nvmem->layout && nvmem->layout->dev.driver)
+ module_put(nvmem->layout->dev.driver->owner);
+}
+
#if IS_ENABLED(CONFIG_OF)
static struct nvmem_cell_entry *
nvmem_find_cell_entry_by_node(struct nvmem_device *nvmem, struct device_node *np)
@@ -1372,6 +1377,18 @@ nvmem_find_cell_entry_by_node(struct nvmem_device *nvmem, struct device_node *np
return cell;
}
+static int nvmem_layout_module_get_optional(struct nvmem_device *nvmem)
+{
+ if (!nvmem->layout)
+ return 0;
+
+ if (!nvmem->layout->dev.driver ||
+ !try_module_get(nvmem->layout->dev.driver->owner))
+ return -EPROBE_DEFER;
+
+ return 0;
+}
+
/**
* of_nvmem_cell_get() - Get a nvmem cell from given device node and cell id
*
@@ -1434,16 +1451,29 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, const char *id)
return ERR_CAST(nvmem);
}
+ ret = nvmem_layout_module_get_optional(nvmem);
+ if (ret) {
+ of_node_put(cell_np);
+ __nvmem_device_put(nvmem);
+ return ERR_PTR(ret);
+ }
+
cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np);
of_node_put(cell_np);
if (!cell_entry) {
__nvmem_device_put(nvmem);
- return ERR_PTR(-ENOENT);
+ nvmem_layout_module_put(nvmem);
+ if (nvmem->layout)
+ return ERR_PTR(-EPROBE_DEFER);
+ else
+ return ERR_PTR(-ENOENT);
}
cell = nvmem_create_cell(cell_entry, id, cell_index);
- if (IS_ERR(cell))
+ if (IS_ERR(cell)) {
__nvmem_device_put(nvmem);
+ nvmem_layout_module_put(nvmem);
+ }
return cell;
}
@@ -1557,6 +1587,7 @@ void nvmem_cell_put(struct nvmem_cell *cell)
kfree(cell);
__nvmem_device_put(nvmem);
+ nvmem_layout_module_put(nvmem);
}
EXPORT_SYMBOL_GPL(nvmem_cell_put);
@@ -2132,13 +2163,37 @@ const char *nvmem_dev_name(struct nvmem_device *nvmem)
}
EXPORT_SYMBOL_GPL(nvmem_dev_name);
+/**
+ * nvmem_dev_size() - Get the size of a given nvmem device.
+ *
+ * @nvmem: nvmem device.
+ *
+ * Return: size of the nvmem device.
+ */
+size_t nvmem_dev_size(struct nvmem_device *nvmem)
+{
+ return nvmem->size;
+}
+EXPORT_SYMBOL_GPL(nvmem_dev_size);
+
static int __init nvmem_init(void)
{
- return bus_register(&nvmem_bus_type);
+ int ret;
+
+ ret = bus_register(&nvmem_bus_type);
+ if (ret)
+ return ret;
+
+ ret = nvmem_layout_bus_register();
+ if (ret)
+ bus_unregister(&nvmem_bus_type);
+
+ return ret;
}
static void __exit nvmem_exit(void)
{
+ nvmem_layout_bus_unregister();
bus_unregister(&nvmem_bus_type);
}
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
index f1e202efaa49..79dd4fda0329 100644
--- a/drivers/nvmem/imx-ocotp.c
+++ b/drivers/nvmem/imx-ocotp.c
@@ -583,17 +583,12 @@ static const struct of_device_id imx_ocotp_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids);
-static void imx_ocotp_fixup_cell_info(struct nvmem_device *nvmem,
- struct nvmem_layout *layout,
- struct nvmem_cell_info *cell)
+static void imx_ocotp_fixup_dt_cell_info(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *cell)
{
cell->read_post_process = imx_ocotp_cell_pp;
}
-static struct nvmem_layout imx_ocotp_layout = {
- .fixup_cell_info = imx_ocotp_fixup_cell_info,
-};
-
static int imx_ocotp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -619,7 +614,7 @@ static int imx_ocotp_probe(struct platform_device *pdev)
imx_ocotp_nvmem_config.size = 4 * priv->params->nregs;
imx_ocotp_nvmem_config.dev = dev;
imx_ocotp_nvmem_config.priv = priv;
- imx_ocotp_nvmem_config.layout = &imx_ocotp_layout;
+ imx_ocotp_nvmem_config.fixup_dt_cell_info = &imx_ocotp_fixup_dt_cell_info;
priv->config = &imx_ocotp_nvmem_config;
diff --git a/drivers/nvmem/internals.h b/drivers/nvmem/internals.h
new file mode 100644
index 000000000000..18fed57270e5
--- /dev/null
+++ b/drivers/nvmem/internals.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_NVMEM_INTERNALS_H
+#define _LINUX_NVMEM_INTERNALS_H
+
+#include <linux/device.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/nvmem-provider.h>
+
+struct nvmem_device {
+ struct module *owner;
+ struct device dev;
+ struct list_head node;
+ int stride;
+ int word_size;
+ int id;
+ struct kref refcnt;
+ size_t size;
+ bool read_only;
+ bool root_only;
+ int flags;
+ enum nvmem_type type;
+ struct bin_attribute eeprom;
+ struct device *base_dev;
+ struct list_head cells;
+ void (*fixup_dt_cell_info)(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *cell);
+ const struct nvmem_keepout *keepout;
+ unsigned int nkeepout;
+ nvmem_reg_read_t reg_read;
+ nvmem_reg_write_t reg_write;
+ struct gpio_desc *wp_gpio;
+ struct nvmem_layout *layout;
+ void *priv;
+ bool sysfs_cells_populated;
+};
+
+#if IS_ENABLED(CONFIG_OF)
+int nvmem_layout_bus_register(void);
+void nvmem_layout_bus_unregister(void);
+int nvmem_populate_layout(struct nvmem_device *nvmem);
+void nvmem_destroy_layout(struct nvmem_device *nvmem);
+#else /* CONFIG_OF */
+static inline int nvmem_layout_bus_register(void)
+{
+ return 0;
+}
+
+static inline void nvmem_layout_bus_unregister(void) {}
+
+static inline int nvmem_populate_layout(struct nvmem_device *nvmem)
+{
+ return 0;
+}
+
+static inline void nvmem_destroy_layout(struct nvmem_device *nvmem) { }
+#endif /* CONFIG_OF */
+
+#endif /* ifndef _LINUX_NVMEM_INTERNALS_H */
diff --git a/drivers/nvmem/layouts.c b/drivers/nvmem/layouts.c
new file mode 100644
index 000000000000..6a6aa58369ff
--- /dev/null
+++ b/drivers/nvmem/layouts.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * NVMEM layout bus handling
+ *
+ * Copyright (C) 2023 Bootlin
+ * Author: Miquel Raynal <[email protected]
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+
+#include "internals.h"
+
+#define to_nvmem_layout_driver(drv) \
+ (container_of((drv), struct nvmem_layout_driver, driver))
+#define to_nvmem_layout_device(_dev) \
+ container_of((_dev), struct nvmem_layout, dev)
+
+static int nvmem_layout_bus_match(struct device *dev, struct device_driver *drv)
+{
+ return of_driver_match_device(dev, drv);
+}
+
+static int nvmem_layout_bus_probe(struct device *dev)
+{
+ struct nvmem_layout_driver *drv = to_nvmem_layout_driver(dev->driver);
+ struct nvmem_layout *layout = to_nvmem_layout_device(dev);
+
+ if (!drv->probe || !drv->remove)
+ return -EINVAL;
+
+ return drv->probe(layout);
+}
+
+static void nvmem_layout_bus_remove(struct device *dev)
+{
+ struct nvmem_layout_driver *drv = to_nvmem_layout_driver(dev->driver);
+ struct nvmem_layout *layout = to_nvmem_layout_device(dev);
+
+ return drv->remove(layout);
+}
+
+static struct bus_type nvmem_layout_bus_type = {
+ .name = "nvmem-layout",
+ .match = nvmem_layout_bus_match,
+ .probe = nvmem_layout_bus_probe,
+ .remove = nvmem_layout_bus_remove,
+};
+
+int nvmem_layout_driver_register(struct nvmem_layout_driver *drv)
+{
+ drv->driver.bus = &nvmem_layout_bus_type;
+
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(nvmem_layout_driver_register);
+
+void nvmem_layout_driver_unregister(struct nvmem_layout_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(nvmem_layout_driver_unregister);
+
+static void nvmem_layout_release_device(struct device *dev)
+{
+ struct nvmem_layout *layout = to_nvmem_layout_device(dev);
+
+ of_node_put(layout->dev.of_node);
+ kfree(layout);
+}
+
+static int nvmem_layout_create_device(struct nvmem_device *nvmem,
+ struct device_node *np)
+{
+ struct nvmem_layout *layout;
+ struct device *dev;
+ int ret;
+
+ layout = kzalloc(sizeof(*layout), GFP_KERNEL);
+ if (!layout)
+ return -ENOMEM;
+
+ /* Create a bidirectional link */
+ layout->nvmem = nvmem;
+ nvmem->layout = layout;
+
+ /* Device model registration */
+ dev = &layout->dev;
+ device_initialize(dev);
+ dev->parent = &nvmem->dev;
+ dev->bus = &nvmem_layout_bus_type;
+ dev->release = nvmem_layout_release_device;
+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ dev->dma_mask = &dev->coherent_dma_mask;
+ device_set_node(dev, of_fwnode_handle(of_node_get(np)));
+ of_device_make_bus_id(dev);
+ of_msi_configure(dev, dev->of_node);
+
+ ret = device_add(dev);
+ if (ret) {
+ put_device(dev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id of_nvmem_layout_skip_table[] = {
+ { .compatible = "fixed-layout", },
+ {}
+};
+
+static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,
+ struct device_node *layout_dn)
+{
+ int ret;
+
+ /* Make sure it has a compatible property */
+ if (!of_get_property(layout_dn, "compatible", NULL)) {
+ pr_debug("%s() - skipping %pOF, no compatible prop\n",
+ __func__, layout_dn);
+ return 0;
+ }
+
+ /* Fixed layouts are parsed manually somewhere else for now */
+ if (of_match_node(of_nvmem_layout_skip_table, layout_dn)) {
+ pr_debug("%s() - skipping %pOF node\n", __func__, layout_dn);
+ return 0;
+ }
+
+ if (of_node_check_flag(layout_dn, OF_POPULATED_BUS)) {
+ pr_debug("%s() - skipping %pOF, already populated\n",
+ __func__, layout_dn);
+
+ return 0;
+ }
+
+ /* NVMEM layout buses expect only a single device representing the layout */
+ ret = nvmem_layout_create_device(nvmem, layout_dn);
+ if (ret)
+ return ret;
+
+ of_node_set_flag(layout_dn, OF_POPULATED_BUS);
+
+ return 0;
+}
+
+struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
+{
+ return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
+}
+EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
+
+/*
+ * Returns the number of devices populated, 0 if the operation was not relevant
+ * for this nvmem device, an error code otherwise.
+ */
+int nvmem_populate_layout(struct nvmem_device *nvmem)
+{
+ struct device_node *layout_dn;
+ int ret;
+
+ layout_dn = of_nvmem_layout_get_container(nvmem);
+ if (!layout_dn)
+ return 0;
+
+ /* Populate the layout device */
+ device_links_supplier_sync_state_pause();
+ ret = nvmem_layout_bus_populate(nvmem, layout_dn);
+ device_links_supplier_sync_state_resume();
+
+ of_node_put(layout_dn);
+ return ret;
+}
+
+void nvmem_destroy_layout(struct nvmem_device *nvmem)
+{
+ struct device *dev;
+
+ if (!nvmem->layout)
+ return;
+
+ dev = &nvmem->layout->dev;
+ of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
+ device_unregister(dev);
+}
+
+int nvmem_layout_bus_register(void)
+{
+ return bus_register(&nvmem_layout_bus_type);
+}
+
+void nvmem_layout_bus_unregister(void)
+{
+ bus_unregister(&nvmem_layout_bus_type);
+}
diff --git a/drivers/nvmem/layouts/Kconfig b/drivers/nvmem/layouts/Kconfig
index 7ff1ee1c1f05..9c6e672fc350 100644
--- a/drivers/nvmem/layouts/Kconfig
+++ b/drivers/nvmem/layouts/Kconfig
@@ -1,5 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
+config NVMEM_LAYOUTS
+ bool
+ depends on OF
+
+if NVMEM_LAYOUTS
+
menu "Layout Types"
config NVMEM_LAYOUT_SL28_VPD
@@ -21,3 +27,5 @@ config NVMEM_LAYOUT_ONIE_TLV
If unsure, say N.
endmenu
+
+endif
diff --git a/drivers/nvmem/layouts/onie-tlv.c b/drivers/nvmem/layouts/onie-tlv.c
index 59fc87ccfcff..9d2ad5f2dc10 100644
--- a/drivers/nvmem/layouts/onie-tlv.c
+++ b/drivers/nvmem/layouts/onie-tlv.c
@@ -182,9 +182,10 @@ static bool onie_tlv_crc_is_valid(struct device *dev, size_t table_len, u8 *tabl
return true;
}
-static int onie_tlv_parse_table(struct device *dev, struct nvmem_device *nvmem,
- struct nvmem_layout *layout)
+static int onie_tlv_parse_table(struct nvmem_layout *layout)
{
+ struct nvmem_device *nvmem = layout->nvmem;
+ struct device *dev = &layout->dev;
struct onie_tlv_hdr hdr;
size_t table_len, data_len, hdr_len;
u8 *table, *data;
@@ -226,16 +227,32 @@ static int onie_tlv_parse_table(struct device *dev, struct nvmem_device *nvmem,
return 0;
}
+static int onie_tlv_probe(struct nvmem_layout *layout)
+{
+ layout->add_cells = onie_tlv_parse_table;
+
+ return nvmem_layout_register(layout);
+}
+
+static void onie_tlv_remove(struct nvmem_layout *layout)
+{
+ nvmem_layout_unregister(layout);
+}
+
static const struct of_device_id onie_tlv_of_match_table[] = {
{ .compatible = "onie,tlv-layout", },
{},
};
MODULE_DEVICE_TABLE(of, onie_tlv_of_match_table);
-static struct nvmem_layout onie_tlv_layout = {
- .name = "ONIE tlv layout",
- .of_match_table = onie_tlv_of_match_table,
- .add_cells = onie_tlv_parse_table,
+static struct nvmem_layout_driver onie_tlv_layout = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "onie-tlv-layout",
+ .of_match_table = onie_tlv_of_match_table,
+ },
+ .probe = onie_tlv_probe,
+ .remove = onie_tlv_remove,
};
module_nvmem_layout_driver(onie_tlv_layout);
diff --git a/drivers/nvmem/layouts/sl28vpd.c b/drivers/nvmem/layouts/sl28vpd.c
index 05671371f631..53fa50f17dca 100644
--- a/drivers/nvmem/layouts/sl28vpd.c
+++ b/drivers/nvmem/layouts/sl28vpd.c
@@ -80,9 +80,10 @@ static int sl28vpd_v1_check_crc(struct device *dev, struct nvmem_device *nvmem)
return 0;
}
-static int sl28vpd_add_cells(struct device *dev, struct nvmem_device *nvmem,
- struct nvmem_layout *layout)
+static int sl28vpd_add_cells(struct nvmem_layout *layout)
{
+ struct nvmem_device *nvmem = layout->nvmem;
+ struct device *dev = &layout->dev;
const struct nvmem_cell_info *pinfo;
struct nvmem_cell_info info = {0};
struct device_node *layout_np;
@@ -135,16 +136,32 @@ static int sl28vpd_add_cells(struct device *dev, struct nvmem_device *nvmem,
return 0;
}
+static int sl28vpd_probe(struct nvmem_layout *layout)
+{
+ layout->add_cells = sl28vpd_add_cells;
+
+ return nvmem_layout_register(layout);
+}
+
+static void sl28vpd_remove(struct nvmem_layout *layout)
+{
+ nvmem_layout_unregister(layout);
+}
+
static const struct of_device_id sl28vpd_of_match_table[] = {
{ .compatible = "kontron,sl28-vpd" },
{},
};
MODULE_DEVICE_TABLE(of, sl28vpd_of_match_table);
-static struct nvmem_layout sl28vpd_layout = {
- .name = "sl28-vpd",
- .of_match_table = sl28vpd_of_match_table,
- .add_cells = sl28vpd_add_cells,
+static struct nvmem_layout_driver sl28vpd_layout = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "kontron-sl28vpd-layout",
+ .of_match_table = sl28vpd_of_match_table,
+ },
+ .probe = sl28vpd_probe,
+ .remove = sl28vpd_remove,
};
module_nvmem_layout_driver(sl28vpd_layout);
diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c
index 87c94686cfd2..84f05b40a411 100644
--- a/drivers/nvmem/mtk-efuse.c
+++ b/drivers/nvmem/mtk-efuse.c
@@ -45,9 +45,8 @@ static int mtk_efuse_gpu_speedbin_pp(void *context, const char *id, int index,
return 0;
}
-static void mtk_efuse_fixup_cell_info(struct nvmem_device *nvmem,
- struct nvmem_layout *layout,
- struct nvmem_cell_info *cell)
+static void mtk_efuse_fixup_dt_cell_info(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *cell)
{
size_t sz = strlen(cell->name);
@@ -61,10 +60,6 @@ static void mtk_efuse_fixup_cell_info(struct nvmem_device *nvmem,
cell->read_post_process = mtk_efuse_gpu_speedbin_pp;
}
-static struct nvmem_layout mtk_efuse_layout = {
- .fixup_cell_info = mtk_efuse_fixup_cell_info,
-};
-
static int mtk_efuse_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -91,7 +86,7 @@ static int mtk_efuse_probe(struct platform_device *pdev)
econfig.priv = priv;
econfig.dev = dev;
if (pdata->uses_post_processing)
- econfig.layout = &mtk_efuse_layout;
+ econfig.fixup_dt_cell_info = &mtk_efuse_fixup_dt_cell_info;
nvmem = devm_nvmem_register(dev, &econfig);
return PTR_ERR_OR_ZERO(nvmem);
diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c
index 8a553b1799a8..82879b1c9eb9 100644
--- a/drivers/nvmem/stm32-romem.c
+++ b/drivers/nvmem/stm32-romem.c
@@ -269,6 +269,19 @@ static const struct stm32_romem_cfg stm32mp13_bsec_cfg = {
.ta = true,
};
+/*
+ * STM32MP25 BSEC OTP: 3 regions of 32-bits data words
+ * lower OTP (OTP0 to OTP127), bitwise (1-bit) programmable
+ * mid OTP (OTP128 to OTP255), bulk (32-bit) programmable
+ * upper OTP (OTP256 to OTP383), bulk (32-bit) programmable
+ * but no access to HWKEY and ECIES key: limited at OTP367
+ */
+static const struct stm32_romem_cfg stm32mp25_bsec_cfg = {
+ .size = 368 * 4,
+ .lower = 127,
+ .ta = true,
+};
+
static const struct of_device_id stm32_romem_of_match[] __maybe_unused = {
{ .compatible = "st,stm32f4-otp", }, {
.compatible = "st,stm32mp15-bsec",
@@ -276,6 +289,9 @@ static const struct of_device_id stm32_romem_of_match[] __maybe_unused = {
}, {
.compatible = "st,stm32mp13-bsec",
.data = (void *)&stm32mp13_bsec_cfg,
+ }, {
+ .compatible = "st,stm32mp25-bsec",
+ .data = (void *)&stm32mp25_bsec_cfg,
},
{ /* sentinel */ },
};
diff --git a/drivers/nvmem/u-boot-env.c b/drivers/nvmem/u-boot-env.c
index c4ae94af4af7..befbab156cda 100644
--- a/drivers/nvmem/u-boot-env.c
+++ b/drivers/nvmem/u-boot-env.c
@@ -23,13 +23,10 @@ enum u_boot_env_format {
struct u_boot_env {
struct device *dev;
+ struct nvmem_device *nvmem;
enum u_boot_env_format format;
struct mtd_info *mtd;
-
- /* Cells */
- struct nvmem_cell_info *cells;
- int ncells;
};
struct u_boot_env_image_single {
@@ -94,70 +91,71 @@ static int u_boot_env_read_post_process_ethaddr(void *context, const char *id, i
static int u_boot_env_add_cells(struct u_boot_env *priv, uint8_t *buf,
size_t data_offset, size_t data_len)
{
+ struct nvmem_device *nvmem = priv->nvmem;
struct device *dev = priv->dev;
char *data = buf + data_offset;
char *var, *value, *eq;
- int idx;
-
- priv->ncells = 0;
- for (var = data; var < data + data_len && *var; var += strlen(var) + 1)
- priv->ncells++;
-
- priv->cells = devm_kcalloc(dev, priv->ncells, sizeof(*priv->cells), GFP_KERNEL);
- if (!priv->cells)
- return -ENOMEM;
- for (var = data, idx = 0;
+ for (var = data;
var < data + data_len && *var;
- var = value + strlen(value) + 1, idx++) {
+ var = value + strlen(value) + 1) {
+ struct nvmem_cell_info info = {};
+
eq = strchr(var, '=');
if (!eq)
break;
*eq = '\0';
value = eq + 1;
- priv->cells[idx].name = devm_kstrdup(dev, var, GFP_KERNEL);
- if (!priv->cells[idx].name)
+ info.name = devm_kstrdup(dev, var, GFP_KERNEL);
+ if (!info.name)
return -ENOMEM;
- priv->cells[idx].offset = data_offset + value - data;
- priv->cells[idx].bytes = strlen(value);
- priv->cells[idx].np = of_get_child_by_name(dev->of_node, priv->cells[idx].name);
+ info.offset = data_offset + value - data;
+ info.bytes = strlen(value);
+ info.np = of_get_child_by_name(dev->of_node, info.name);
if (!strcmp(var, "ethaddr")) {
- priv->cells[idx].raw_len = strlen(value);
- priv->cells[idx].bytes = ETH_ALEN;
- priv->cells[idx].read_post_process = u_boot_env_read_post_process_ethaddr;
+ info.raw_len = strlen(value);
+ info.bytes = ETH_ALEN;
+ info.read_post_process = u_boot_env_read_post_process_ethaddr;
}
- }
- if (WARN_ON(idx != priv->ncells))
- priv->ncells = idx;
+ nvmem_add_one_cell(nvmem, &info);
+ }
return 0;
}
static int u_boot_env_parse(struct u_boot_env *priv)
{
+ struct nvmem_device *nvmem = priv->nvmem;
struct device *dev = priv->dev;
size_t crc32_data_offset;
size_t crc32_data_len;
size_t crc32_offset;
+ __le32 *crc32_addr;
size_t data_offset;
size_t data_len;
+ size_t dev_size;
uint32_t crc32;
uint32_t calc;
- size_t bytes;
uint8_t *buf;
+ int bytes;
int err;
- buf = kcalloc(1, priv->mtd->size, GFP_KERNEL);
+ dev_size = nvmem_dev_size(nvmem);
+
+ buf = kzalloc(dev_size, GFP_KERNEL);
if (!buf) {
err = -ENOMEM;
goto err_out;
}
- err = mtd_read(priv->mtd, 0, priv->mtd->size, &bytes, buf);
- if ((err && !mtd_is_bitflip(err)) || bytes != priv->mtd->size) {
- dev_err(dev, "Failed to read from mtd: %d\n", err);
+ bytes = nvmem_device_read(nvmem, 0, dev_size, buf);
+ if (bytes < 0) {
+ err = bytes;
+ goto err_kfree;
+ } else if (bytes != dev_size) {
+ err = -EIO;
goto err_kfree;
}
@@ -178,9 +176,10 @@ static int u_boot_env_parse(struct u_boot_env *priv)
data_offset = offsetof(struct u_boot_env_image_broadcom, data);
break;
}
- crc32 = le32_to_cpu(*(__le32 *)(buf + crc32_offset));
- crc32_data_len = priv->mtd->size - crc32_data_offset;
- data_len = priv->mtd->size - data_offset;
+ crc32_addr = (__le32 *)(buf + crc32_offset);
+ crc32 = le32_to_cpu(*crc32_addr);
+ crc32_data_len = dev_size - crc32_data_offset;
+ data_len = dev_size - data_offset;
calc = crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L;
if (calc != crc32) {
@@ -189,10 +188,8 @@ static int u_boot_env_parse(struct u_boot_env *priv)
goto err_kfree;
}
- buf[priv->mtd->size - 1] = '\0';
+ buf[dev_size - 1] = '\0';
err = u_boot_env_add_cells(priv, buf, data_offset, data_len);
- if (err)
- dev_err(dev, "Failed to add cells: %d\n", err);
err_kfree:
kfree(buf);
@@ -209,7 +206,6 @@ static int u_boot_env_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct u_boot_env *priv;
- int err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -224,17 +220,15 @@ static int u_boot_env_probe(struct platform_device *pdev)
return PTR_ERR(priv->mtd);
}
- err = u_boot_env_parse(priv);
- if (err)
- return err;
-
config.dev = dev;
- config.cells = priv->cells;
- config.ncells = priv->ncells;
config.priv = priv;
config.size = priv->mtd->size;
- return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config));
+ priv->nvmem = devm_nvmem_register(dev, &config);
+ if (IS_ERR(priv->nvmem))
+ return PTR_ERR(priv->nvmem);
+
+ return u_boot_env_parse(priv);
}
static const struct of_device_id u_boot_env_of_match_table[] = {
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 8d93cb6ea9cd..b0ad8fc06e80 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1464,6 +1464,7 @@ int of_parse_phandle_with_args_map(const struct device_node *np,
out_args->np = new;
of_node_put(cur);
cur = new;
+ new = NULL;
}
put:
of_node_put(cur);
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 1ca42ad9dd15..de89f9906375 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -93,12 +93,12 @@ of_dma_set_restricted_buffer(struct device *dev, struct device_node *np)
int of_dma_configure_id(struct device *dev, struct device_node *np,
bool force_dma, const u32 *id)
{
- const struct iommu_ops *iommu;
const struct bus_dma_region *map = NULL;
struct device_node *bus_np;
u64 dma_start = 0;
u64 mask, end, size = 0;
bool coherent;
+ int iommu_ret;
int ret;
if (np == dev->of_node)
@@ -181,21 +181,29 @@ int of_dma_configure_id(struct device *dev, struct device_node *np,
dev_dbg(dev, "device is%sdma coherent\n",
coherent ? " " : " not ");
- iommu = of_iommu_configure(dev, np, id);
- if (PTR_ERR(iommu) == -EPROBE_DEFER) {
+ iommu_ret = of_iommu_configure(dev, np, id);
+ if (iommu_ret == -EPROBE_DEFER) {
/* Don't touch range map if it wasn't set from a valid dma-ranges */
if (!ret)
dev->dma_range_map = NULL;
kfree(map);
return -EPROBE_DEFER;
- }
+ } else if (iommu_ret == -ENODEV) {
+ dev_dbg(dev, "device is not behind an iommu\n");
+ } else if (iommu_ret) {
+ dev_err(dev, "iommu configuration for device failed with %pe\n",
+ ERR_PTR(iommu_ret));
- dev_dbg(dev, "device is%sbehind an iommu\n",
- iommu ? " " : " not ");
+ /*
+ * Historically this routine doesn't fail driver probing
+ * due to errors in of_iommu_configure()
+ */
+ } else
+ dev_dbg(dev, "device is behind an iommu\n");
- arch_setup_dma_ops(dev, dma_start, size, iommu, coherent);
+ arch_setup_dma_ops(dev, dma_start, size, coherent);
- if (!iommu)
+ if (iommu_ret)
of_dma_set_restricted_buffer(dev, np);
return 0;
@@ -304,3 +312,44 @@ int of_device_uevent_modalias(const struct device *dev, struct kobj_uevent_env *
return 0;
}
EXPORT_SYMBOL_GPL(of_device_uevent_modalias);
+
+/**
+ * of_device_make_bus_id - Use the device node data to assign a unique name
+ * @dev: pointer to device structure that is linked to a device tree node
+ *
+ * This routine will first try using the translated bus address to
+ * derive a unique name. If it cannot, then it will prepend names from
+ * parent nodes until a unique name can be derived.
+ */
+void of_device_make_bus_id(struct device *dev)
+{
+ struct device_node *node = dev->of_node;
+ const __be32 *reg;
+ u64 addr;
+ u32 mask;
+
+ /* Construct the name, using parent nodes if necessary to ensure uniqueness */
+ while (node->parent) {
+ /*
+ * If the address can be translated, then that is as much
+ * uniqueness as we need. Make it the first component and return
+ */
+ reg = of_get_property(node, "reg", NULL);
+ if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
+ if (!of_property_read_u32(node, "mask", &mask))
+ dev_set_name(dev, dev_name(dev) ? "%llx.%x.%pOFn:%s" : "%llx.%x.%pOFn",
+ addr, ffs(mask) - 1, node, dev_name(dev));
+
+ else
+ dev_set_name(dev, dev_name(dev) ? "%llx.%pOFn:%s" : "%llx.%pOFn",
+ addr, node, dev_name(dev));
+ return;
+ }
+
+ /* format arguments only used if dev_name() resolves to NULL */
+ dev_set_name(dev, dev_name(dev) ? "%s:%s" : "%s",
+ kbasename(node->full_name), dev_name(dev));
+ node = node->parent;
+ }
+}
+EXPORT_SYMBOL_GPL(of_device_make_bus_id);
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index a9a292d6d59b..2ae7e9d24a64 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -964,7 +964,7 @@ out:
return ret;
}
-/*
+/**
* of_overlay_fdt_apply() - Create and apply an overlay changeset
* @overlay_fdt: pointer to overlay FDT
* @overlay_fdt_size: number of bytes in @overlay_fdt
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 126d265aa7d8..b7708a06dc78 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -20,6 +20,7 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/sysfb.h>
#include "of_private.h"
@@ -98,46 +99,6 @@ static const struct of_device_id of_skipped_node_table[] = {
*/
/**
- * of_device_make_bus_id - Use the device node data to assign a unique name
- * @dev: pointer to device structure that is linked to a device tree node
- *
- * This routine will first try using the translated bus address to
- * derive a unique name. If it cannot, then it will prepend names from
- * parent nodes until a unique name can be derived.
- */
-static void of_device_make_bus_id(struct device *dev)
-{
- struct device_node *node = dev->of_node;
- const __be32 *reg;
- u64 addr;
- u32 mask;
-
- /* Construct the name, using parent nodes if necessary to ensure uniqueness */
- while (node->parent) {
- /*
- * If the address can be translated, then that is as much
- * uniqueness as we need. Make it the first component and return
- */
- reg = of_get_property(node, "reg", NULL);
- if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
- if (!of_property_read_u32(node, "mask", &mask))
- dev_set_name(dev, dev_name(dev) ? "%llx.%x.%pOFn:%s" : "%llx.%x.%pOFn",
- addr, ffs(mask) - 1, node, dev_name(dev));
-
- else
- dev_set_name(dev, dev_name(dev) ? "%llx.%pOFn:%s" : "%llx.%pOFn",
- addr, node, dev_name(dev));
- return;
- }
-
- /* format arguments only used if dev_name() resolves to NULL */
- dev_set_name(dev, dev_name(dev) ? "%s:%s" : "%s",
- kbasename(node->full_name), dev_name(dev));
- node = node->parent;
- }
-}
-
-/**
* of_device_alloc - Allocate and initialize an of_device
* @np: device node to assign to device
* @bus_id: Name to assign to the device. May be null to use default name.
@@ -621,8 +582,21 @@ static int __init of_platform_default_populate_init(void)
}
node = of_get_compatible_child(of_chosen, "simple-framebuffer");
- of_platform_device_create(node, NULL, NULL);
- of_node_put(node);
+ if (node) {
+ /*
+ * Since a "simple-framebuffer" device is already added
+ * here, disable the Generic System Framebuffers (sysfb)
+ * to prevent it from registering another device for the
+ * system framebuffer later (e.g: using the screen_info
+ * data that may had been filled as well).
+ *
+ * This can happen for example on DT systems that do EFI
+ * booting and may provide a GOP handle to the EFI stub.
+ */
+ sysfb_disable();
+ of_platform_device_create(node, NULL, NULL);
+ of_node_put(node);
+ }
/* Populate everything else. */
of_platform_default_populate(NULL, NULL, NULL);
@@ -668,7 +642,7 @@ EXPORT_SYMBOL_GPL(of_platform_device_destroy);
* @parent: device which children will be removed
*
* Complementary to of_platform_populate(), this function removes children
- * of the given device (and, recurrently, their children) that have been
+ * of the given device (and, recursively, their children) that have been
* created from their respective device tree nodes (and only those,
* leaving others - eg. manually created - unharmed).
*/
@@ -737,7 +711,7 @@ static int devm_of_platform_match(struct device *dev, void *res, void *data)
* @dev: device that requested to depopulate from device tree data
*
* Complementary to devm_of_platform_populate(), this function removes children
- * of the given device (and, recurrently, their children) that have been
+ * of the given device (and, recursively, their children) that have been
* created from their respective device tree nodes (and only those,
* leaving others - eg. manually created - unharmed).
*/
diff --git a/drivers/of/property.c b/drivers/of/property.c
index afdaefbd03f6..641a40cf5cf3 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -441,6 +441,7 @@ int of_property_read_string(const struct device_node *np, const char *propname,
const char **out_string)
{
const struct property *prop = of_find_property(np, propname, NULL);
+
if (!prop)
return -EINVAL;
if (!prop->length)
@@ -1217,9 +1218,9 @@ static struct device_node *parse_##fname(struct device_node *np, \
*
* @parse_prop: function name
* parse_prop() finds the node corresponding to a supplier phandle
- * @parse_prop.np: Pointer to device node holding supplier phandle property
- * @parse_prop.prop_name: Name of property holding a phandle value
- * @parse_prop.index: For properties holding a list of phandles, this is the
+ * parse_prop.np: Pointer to device node holding supplier phandle property
+ * parse_prop.prop_name: Name of property holding a phandle value
+ * parse_prop.index: For properties holding a list of phandles, this is the
* index into the list
* @optional: Describes whether a supplier is mandatory or not
* @node_not_dev: The consumer node containing the property is never converted
diff --git a/drivers/of/unittest-data/tests-phandle.dtsi b/drivers/of/unittest-data/tests-phandle.dtsi
index d01f92f0f0db..554a996b2ef1 100644
--- a/drivers/of/unittest-data/tests-phandle.dtsi
+++ b/drivers/of/unittest-data/tests-phandle.dtsi
@@ -40,6 +40,13 @@
phandle-map-pass-thru = <0x0 0xf0>;
};
+ provider5: provider5 {
+ #phandle-cells = <2>;
+ phandle-map = <2 7 &provider4 2 3>;
+ phandle-map-mask = <0xff 0xf>;
+ phandle-map-pass-thru = <0x0 0xf0>;
+ };
+
consumer-a {
phandle-list = <&provider1 1>,
<&provider2 2 0>,
@@ -66,7 +73,8 @@
<&provider4 4 0x100>,
<&provider4 0 0x61>,
<&provider0>,
- <&provider4 19 0x20>;
+ <&provider4 19 0x20>,
+ <&provider5 2 7>;
phandle-list-bad-phandle = <12345678 0 0>;
phandle-list-bad-args = <&provider2 1 0>,
<&provider4 0>;
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index e9e90e96600e..cfd60e35a899 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -456,6 +456,9 @@ static void __init of_unittest_parse_phandle_with_args(void)
unittest(passed, "index %i - data error on node %pOF rc=%i\n",
i, args.np, rc);
+
+ if (rc == 0)
+ of_node_put(args.np);
}
/* Check for missing list property */
@@ -545,8 +548,9 @@ static void __init of_unittest_parse_phandle_with_args(void)
static void __init of_unittest_parse_phandle_with_args_map(void)
{
- struct device_node *np, *p0, *p1, *p2, *p3;
+ struct device_node *np, *p[6] = {};
struct of_phandle_args args;
+ unsigned int prefs[6];
int i, rc;
np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-b");
@@ -555,34 +559,24 @@ static void __init of_unittest_parse_phandle_with_args_map(void)
return;
}
- p0 = of_find_node_by_path("/testcase-data/phandle-tests/provider0");
- if (!p0) {
- pr_err("missing testcase data\n");
- return;
- }
-
- p1 = of_find_node_by_path("/testcase-data/phandle-tests/provider1");
- if (!p1) {
- pr_err("missing testcase data\n");
- return;
- }
-
- p2 = of_find_node_by_path("/testcase-data/phandle-tests/provider2");
- if (!p2) {
- pr_err("missing testcase data\n");
- return;
- }
-
- p3 = of_find_node_by_path("/testcase-data/phandle-tests/provider3");
- if (!p3) {
- pr_err("missing testcase data\n");
- return;
+ p[0] = of_find_node_by_path("/testcase-data/phandle-tests/provider0");
+ p[1] = of_find_node_by_path("/testcase-data/phandle-tests/provider1");
+ p[2] = of_find_node_by_path("/testcase-data/phandle-tests/provider2");
+ p[3] = of_find_node_by_path("/testcase-data/phandle-tests/provider3");
+ p[4] = of_find_node_by_path("/testcase-data/phandle-tests/provider4");
+ p[5] = of_find_node_by_path("/testcase-data/phandle-tests/provider5");
+ for (i = 0; i < ARRAY_SIZE(p); ++i) {
+ if (!p[i]) {
+ pr_err("missing testcase data\n");
+ return;
+ }
+ prefs[i] = kref_read(&p[i]->kobj.kref);
}
rc = of_count_phandle_with_args(np, "phandle-list", "#phandle-cells");
- unittest(rc == 7, "of_count_phandle_with_args() returned %i, expected 7\n", rc);
+ unittest(rc == 8, "of_count_phandle_with_args() returned %i, expected 8\n", rc);
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < 9; i++) {
bool passed = true;
memset(&args, 0, sizeof(args));
@@ -593,13 +587,13 @@ static void __init of_unittest_parse_phandle_with_args_map(void)
switch (i) {
case 0:
passed &= !rc;
- passed &= (args.np == p1);
+ passed &= (args.np == p[1]);
passed &= (args.args_count == 1);
passed &= (args.args[0] == 1);
break;
case 1:
passed &= !rc;
- passed &= (args.np == p3);
+ passed &= (args.np == p[3]);
passed &= (args.args_count == 3);
passed &= (args.args[0] == 2);
passed &= (args.args[1] == 5);
@@ -610,28 +604,36 @@ static void __init of_unittest_parse_phandle_with_args_map(void)
break;
case 3:
passed &= !rc;
- passed &= (args.np == p0);
+ passed &= (args.np == p[0]);
passed &= (args.args_count == 0);
break;
case 4:
passed &= !rc;
- passed &= (args.np == p1);
+ passed &= (args.np == p[1]);
passed &= (args.args_count == 1);
passed &= (args.args[0] == 3);
break;
case 5:
passed &= !rc;
- passed &= (args.np == p0);
+ passed &= (args.np == p[0]);
passed &= (args.args_count == 0);
break;
case 6:
passed &= !rc;
- passed &= (args.np == p2);
+ passed &= (args.np == p[2]);
passed &= (args.args_count == 2);
passed &= (args.args[0] == 15);
passed &= (args.args[1] == 0x20);
break;
case 7:
+ passed &= !rc;
+ passed &= (args.np == p[3]);
+ passed &= (args.args_count == 3);
+ passed &= (args.args[0] == 2);
+ passed &= (args.args[1] == 5);
+ passed &= (args.args[2] == 3);
+ break;
+ case 8:
passed &= (rc == -ENOENT);
break;
default:
@@ -640,6 +642,9 @@ static void __init of_unittest_parse_phandle_with_args_map(void)
unittest(passed, "index %i - data error on node %s rc=%i\n",
i, args.np->full_name, rc);
+
+ if (rc == 0)
+ of_node_put(args.np);
}
/* Check for missing list property */
@@ -686,6 +691,13 @@ static void __init of_unittest_parse_phandle_with_args_map(void)
"OF: /testcase-data/phandle-tests/consumer-b: #phandle-cells = 2 found 1");
unittest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc);
+
+ for (i = 0; i < ARRAY_SIZE(p); ++i) {
+ unittest(prefs[i] == kref_read(&p[i]->kobj.kref),
+ "provider%d: expected:%d got:%d\n",
+ i, prefs[i], kref_read(&p[i]->kobj.kref));
+ of_node_put(p[i]);
+ }
}
static void __init of_unittest_property_string(void)
diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c
index bb0d92461b08..7a6a3e7f2825 100644
--- a/drivers/parisc/power.c
+++ b/drivers/parisc/power.c
@@ -213,7 +213,7 @@ static int __init power_init(void)
if (running_on_qemu && soft_power_reg)
register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_DEFAULT,
qemu_power_off, (void *)soft_power_reg);
- else
+ if (!running_on_qemu || soft_power_reg)
power_task = kthread_run(kpowerswd, (void*)soft_power_reg,
KTHREAD_NAME);
if (IS_ERR(power_task)) {
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index 9f5d784cd95d..3644997a8342 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -65,6 +65,10 @@ enum parport_pc_pci_cards {
sunix_5069a,
sunix_5079a,
sunix_5099a,
+ brainboxes_uc257,
+ brainboxes_is300,
+ brainboxes_uc414,
+ brainboxes_px263,
};
/* each element directly indexed from enum list, above */
@@ -158,6 +162,10 @@ static struct parport_pc_pci cards[] = {
/* sunix_5069a */ { 1, { { 1, 2 }, } },
/* sunix_5079a */ { 1, { { 1, 2 }, } },
/* sunix_5099a */ { 1, { { 1, 2 }, } },
+ /* brainboxes_uc257 */ { 1, { { 3, -1 }, } },
+ /* brainboxes_is300 */ { 1, { { 3, -1 }, } },
+ /* brainboxes_uc414 */ { 1, { { 3, -1 }, } },
+ /* brainboxes_px263 */ { 1, { { 3, -1 }, } },
};
static struct pci_device_id parport_serial_pci_tbl[] = {
@@ -277,6 +285,38 @@ static struct pci_device_id parport_serial_pci_tbl[] = {
{ PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999, PCI_VENDOR_ID_SUNIX,
0x0104, 0, 0, sunix_5099a },
+ /* Brainboxes UC-203 */
+ { PCI_VENDOR_ID_INTASHIELD, 0x0bc1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0bc2,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
+
+ /* Brainboxes UC-257 */
+ { PCI_VENDOR_ID_INTASHIELD, 0x0861,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0862,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0863,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
+
+ /* Brainboxes UC-414 */
+ { PCI_VENDOR_ID_INTASHIELD, 0x0e61,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc414 },
+
+ /* Brainboxes UC-475 */
+ { PCI_VENDOR_ID_INTASHIELD, 0x0981,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0982,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc257 },
+
+ /* Brainboxes IS-300/IS-500 */
+ { PCI_VENDOR_ID_INTASHIELD, 0x0da0,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_is300 },
+
+ /* Brainboxes PX-263/PX-295 */
+ { PCI_VENDOR_ID_INTASHIELD, 0x402c,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_px263 },
+
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
@@ -542,6 +582,30 @@ static struct pciserial_board pci_parport_serial_boards[] = {
.base_baud = 921600,
.uart_offset = 0x8,
},
+ [brainboxes_uc257] = {
+ .flags = FL_BASE2,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [brainboxes_is300] = {
+ .flags = FL_BASE2,
+ .num_ports = 1,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [brainboxes_uc414] = {
+ .flags = FL_BASE2,
+ .num_ports = 4,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
+ [brainboxes_px263] = {
+ .flags = FL_BASE2,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
};
struct parport_serial_private {
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index e21831d93305..49c74ded8a53 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -611,7 +611,7 @@ static void free_pardevice(struct device *dev)
{
struct pardevice *par_dev = to_pardevice(dev);
- kfree(par_dev->name);
+ kfree_const(par_dev->name);
kfree(par_dev);
}
@@ -682,8 +682,8 @@ parport_register_dev_model(struct parport *port, const char *name,
const struct pardev_cb *par_dev_cb, int id)
{
struct pardevice *par_dev;
+ const char *devname;
int ret;
- char *devname;
if (port->physport->flags & PARPORT_FLAG_EXCL) {
/* An exclusive device is registered. */
@@ -726,7 +726,7 @@ parport_register_dev_model(struct parport *port, const char *name,
if (!par_dev->state)
goto err_put_par_dev;
- devname = kstrdup(name, GFP_KERNEL);
+ devname = kstrdup_const(name, GFP_KERNEL);
if (!devname)
goto err_free_par_dev;
@@ -804,7 +804,7 @@ parport_register_dev_model(struct parport *port, const char *name,
return par_dev;
err_free_devname:
- kfree(devname);
+ kfree_const(devname);
err_free_par_dev:
kfree(par_dev->state);
err_put_par_dev:
diff --git a/drivers/pci/controller/cadence/Kconfig b/drivers/pci/controller/cadence/Kconfig
index 291d12711363..1d5a70c9055e 100644
--- a/drivers/pci/controller/cadence/Kconfig
+++ b/drivers/pci/controller/cadence/Kconfig
@@ -47,6 +47,7 @@ config PCI_J721E
config PCI_J721E_HOST
bool "TI J721E PCIe controller (host mode)"
+ depends on ARCH_K3 || COMPILE_TEST
depends on OF
select PCIE_CADENCE_HOST
select PCI_J721E
@@ -57,6 +58,7 @@ config PCI_J721E_HOST
config PCI_J721E_EP
bool "TI J721E PCIe controller (endpoint mode)"
+ depends on ARCH_K3 || COMPILE_TEST
depends on OF
depends on PCI_ENDPOINT
select PCIE_CADENCE_EP
diff --git a/drivers/pci/controller/cadence/pci-j721e.c b/drivers/pci/controller/cadence/pci-j721e.c
index 2c87e7728a65..85718246016b 100644
--- a/drivers/pci/controller/cadence/pci-j721e.c
+++ b/drivers/pci/controller/cadence/pci-j721e.c
@@ -42,18 +42,16 @@ enum link_status {
};
#define J721E_MODE_RC BIT(7)
-#define LANE_COUNT_MASK BIT(8)
#define LANE_COUNT(n) ((n) << 8)
#define GENERATION_SEL_MASK GENMASK(1, 0)
-#define MAX_LANES 2
-
struct j721e_pcie {
struct cdns_pcie *cdns_pcie;
struct clk *refclk;
u32 mode;
u32 num_lanes;
+ u32 max_lanes;
void __iomem *user_cfg_base;
void __iomem *intd_cfg_base;
u32 linkdown_irq_regfield;
@@ -71,6 +69,7 @@ struct j721e_pcie_data {
unsigned int quirk_disable_flr:1;
u32 linkdown_irq_regfield;
unsigned int byte_access_allowed:1;
+ unsigned int max_lanes;
};
static inline u32 j721e_pcie_user_readl(struct j721e_pcie *pcie, u32 offset)
@@ -206,11 +205,15 @@ static int j721e_pcie_set_lane_count(struct j721e_pcie *pcie,
{
struct device *dev = pcie->cdns_pcie->dev;
u32 lanes = pcie->num_lanes;
+ u32 mask = BIT(8);
u32 val = 0;
int ret;
+ if (pcie->max_lanes == 4)
+ mask = GENMASK(9, 8);
+
val = LANE_COUNT(lanes - 1);
- ret = regmap_update_bits(syscon, offset, LANE_COUNT_MASK, val);
+ ret = regmap_update_bits(syscon, offset, mask, val);
if (ret)
dev_err(dev, "failed to set link count\n");
@@ -290,11 +293,13 @@ static const struct j721e_pcie_data j721e_pcie_rc_data = {
.quirk_retrain_flag = true,
.byte_access_allowed = false,
.linkdown_irq_regfield = LINK_DOWN,
+ .max_lanes = 2,
};
static const struct j721e_pcie_data j721e_pcie_ep_data = {
.mode = PCI_MODE_EP,
.linkdown_irq_regfield = LINK_DOWN,
+ .max_lanes = 2,
};
static const struct j721e_pcie_data j7200_pcie_rc_data = {
@@ -302,23 +307,41 @@ static const struct j721e_pcie_data j7200_pcie_rc_data = {
.quirk_detect_quiet_flag = true,
.linkdown_irq_regfield = J7200_LINK_DOWN,
.byte_access_allowed = true,
+ .max_lanes = 2,
};
static const struct j721e_pcie_data j7200_pcie_ep_data = {
.mode = PCI_MODE_EP,
.quirk_detect_quiet_flag = true,
.quirk_disable_flr = true,
+ .max_lanes = 2,
};
static const struct j721e_pcie_data am64_pcie_rc_data = {
.mode = PCI_MODE_RC,
.linkdown_irq_regfield = J7200_LINK_DOWN,
.byte_access_allowed = true,
+ .max_lanes = 1,
};
static const struct j721e_pcie_data am64_pcie_ep_data = {
.mode = PCI_MODE_EP,
.linkdown_irq_regfield = J7200_LINK_DOWN,
+ .max_lanes = 1,
+};
+
+static const struct j721e_pcie_data j784s4_pcie_rc_data = {
+ .mode = PCI_MODE_RC,
+ .quirk_retrain_flag = true,
+ .byte_access_allowed = false,
+ .linkdown_irq_regfield = LINK_DOWN,
+ .max_lanes = 4,
+};
+
+static const struct j721e_pcie_data j784s4_pcie_ep_data = {
+ .mode = PCI_MODE_EP,
+ .linkdown_irq_regfield = LINK_DOWN,
+ .max_lanes = 4,
};
static const struct of_device_id of_j721e_pcie_match[] = {
@@ -346,6 +369,14 @@ static const struct of_device_id of_j721e_pcie_match[] = {
.compatible = "ti,am64-pcie-ep",
.data = &am64_pcie_ep_data,
},
+ {
+ .compatible = "ti,j784s4-pcie-host",
+ .data = &j784s4_pcie_rc_data,
+ },
+ {
+ .compatible = "ti,j784s4-pcie-ep",
+ .data = &j784s4_pcie_ep_data,
+ },
{},
};
@@ -432,9 +463,13 @@ static int j721e_pcie_probe(struct platform_device *pdev)
pcie->user_cfg_base = base;
ret = of_property_read_u32(node, "num-lanes", &num_lanes);
- if (ret || num_lanes > MAX_LANES)
+ if (ret || num_lanes > data->max_lanes) {
+ dev_warn(dev, "num-lanes property not provided or invalid, setting num-lanes to 1\n");
num_lanes = 1;
+ }
+
pcie->num_lanes = num_lanes;
+ pcie->max_lanes = data->max_lanes;
if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48)))
return -EINVAL;
diff --git a/drivers/pci/controller/cadence/pcie-cadence-ep.c b/drivers/pci/controller/cadence/pcie-cadence-ep.c
index 3142feb8ac19..2d0a8d78bffb 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-ep.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-ep.c
@@ -360,8 +360,8 @@ static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn, u8 intx,
writel(0, ep->irq_cpu_addr + offset);
}
-static int cdns_pcie_ep_send_legacy_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
- u8 intx)
+static int cdns_pcie_ep_send_intx_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
+ u8 intx)
{
u16 cmd;
@@ -371,7 +371,7 @@ static int cdns_pcie_ep_send_legacy_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
cdns_pcie_ep_assert_intx(ep, fn, intx, true);
/*
- * The mdelay() value was taken from dra7xx_pcie_raise_legacy_irq()
+ * The mdelay() value was taken from dra7xx_pcie_raise_intx_irq()
*/
mdelay(1);
cdns_pcie_ep_assert_intx(ep, fn, intx, false);
@@ -532,25 +532,24 @@ static int cdns_pcie_ep_send_msix_irq(struct cdns_pcie_ep *ep, u8 fn, u8 vfn,
}
static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, u8 vfn,
- enum pci_epc_irq_type type,
- u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
struct cdns_pcie *pcie = &ep->pcie;
struct device *dev = pcie->dev;
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
+ case PCI_IRQ_INTX:
if (vfn > 0) {
- dev_err(dev, "Cannot raise legacy interrupts for VF\n");
+ dev_err(dev, "Cannot raise INTX interrupts for VF\n");
return -EINVAL;
}
- return cdns_pcie_ep_send_legacy_irq(ep, fn, vfn, 0);
+ return cdns_pcie_ep_send_intx_irq(ep, fn, vfn, 0);
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_MSI:
return cdns_pcie_ep_send_msi_irq(ep, fn, vfn, interrupt_num);
- case PCI_EPC_IRQ_MSIX:
+ case PCI_IRQ_MSIX:
return cdns_pcie_ep_send_msix_irq(ep, fn, vfn, interrupt_num);
default:
diff --git a/drivers/pci/controller/cadence/pcie-cadence.h b/drivers/pci/controller/cadence/pcie-cadence.h
index 373cb50fcd15..03b96798f858 100644
--- a/drivers/pci/controller/cadence/pcie-cadence.h
+++ b/drivers/pci/controller/cadence/pcie-cadence.h
@@ -347,16 +347,16 @@ struct cdns_pcie_epf {
* @max_regions: maximum number of regions supported by hardware
* @ob_region_map: bitmask of mapped outbound regions
* @ob_addr: base addresses in the AXI bus where the outbound regions start
- * @irq_phys_addr: base address on the AXI bus where the MSI/legacy IRQ
+ * @irq_phys_addr: base address on the AXI bus where the MSI/INTX IRQ
* dedicated outbound regions is mapped.
* @irq_cpu_addr: base address in the CPU space where a write access triggers
- * the sending of a memory write (MSI) / normal message (legacy
+ * the sending of a memory write (MSI) / normal message (INTX
* IRQ) TLP through the PCIe bus.
- * @irq_pci_addr: used to save the current mapping of the MSI/legacy IRQ
+ * @irq_pci_addr: used to save the current mapping of the MSI/INTX IRQ
* dedicated outbound region.
* @irq_pci_fn: the latest PCI function that has updated the mapping of
- * the MSI/legacy IRQ dedicated outbound region.
- * @irq_pending: bitmask of asserted legacy IRQs.
+ * the MSI/INTX IRQ dedicated outbound region.
+ * @irq_pending: bitmask of asserted INTX IRQs.
* @lock: spin lock to disable interrupts while modifying PCIe controller
* registers fields (RMW) accessible by both remote RC and EP to
* minimize time between read and write
@@ -374,7 +374,7 @@ struct cdns_pcie_ep {
u64 irq_pci_addr;
u8 irq_pci_fn;
u8 irq_pending;
- /* protect writing to PCI_STATUS while raising legacy interrupts */
+ /* protect writing to PCI_STATUS while raising INTX interrupts */
spinlock_t lock;
struct cdns_pcie_epf *epf;
unsigned int quirk_detect_quiet_flag:1;
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
index 5ac021dbd46a..8afacc90c63b 100644
--- a/drivers/pci/controller/dwc/Kconfig
+++ b/drivers/pci/controller/dwc/Kconfig
@@ -336,7 +336,7 @@ config PCI_EXYNOS
config PCIE_FU740
bool "SiFive FU740 PCIe controller"
depends on PCI_MSI
- depends on SOC_SIFIVE || COMPILE_TEST
+ depends on ARCH_SIFIVE || COMPILE_TEST
select PCIE_DW_HOST
help
Say Y here if you want PCIe controller support for the SiFive
diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
index b445ffe95e3f..0e406677060d 100644
--- a/drivers/pci/controller/dwc/pci-dra7xx.c
+++ b/drivers/pci/controller/dwc/pci-dra7xx.c
@@ -371,7 +371,7 @@ static int dra7xx_pcie_init_irq_domain(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
- .host_init = dra7xx_pcie_host_init,
+ .init = dra7xx_pcie_host_init,
};
static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep)
@@ -386,7 +386,7 @@ static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep)
dra7xx_pcie_enable_wrapper_interrupts(dra7xx);
}
-static void dra7xx_pcie_raise_legacy_irq(struct dra7xx_pcie *dra7xx)
+static void dra7xx_pcie_raise_intx_irq(struct dra7xx_pcie *dra7xx)
{
dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_INTX_ASSERT, 0x1);
mdelay(1);
@@ -404,16 +404,16 @@ static void dra7xx_pcie_raise_msi_irq(struct dra7xx_pcie *dra7xx,
}
static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type, u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
- dra7xx_pcie_raise_legacy_irq(dra7xx);
+ case PCI_IRQ_INTX:
+ dra7xx_pcie_raise_intx_irq(dra7xx);
break;
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_MSI:
dra7xx_pcie_raise_msi_irq(dra7xx, interrupt_num);
break;
default:
@@ -436,7 +436,7 @@ dra7xx_pcie_get_features(struct dw_pcie_ep *ep)
}
static const struct dw_pcie_ep_ops pcie_ep_ops = {
- .ep_init = dra7xx_pcie_ep_init,
+ .init = dra7xx_pcie_ep_init,
.raise_irq = dra7xx_pcie_raise_irq,
.get_features = dra7xx_pcie_get_features,
};
diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c
index c6bede346932..a33fa98a252e 100644
--- a/drivers/pci/controller/dwc/pci-exynos.c
+++ b/drivers/pci/controller/dwc/pci-exynos.c
@@ -268,7 +268,7 @@ static int exynos_pcie_host_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops exynos_pcie_host_ops = {
- .host_init = exynos_pcie_host_init,
+ .init = exynos_pcie_host_init,
};
static int exynos_add_pcie_port(struct exynos_pcie *ep,
@@ -375,7 +375,7 @@ fail_probe:
return ret;
}
-static int exynos_pcie_remove(struct platform_device *pdev)
+static void exynos_pcie_remove(struct platform_device *pdev)
{
struct exynos_pcie *ep = platform_get_drvdata(pdev);
@@ -385,8 +385,6 @@ static int exynos_pcie_remove(struct platform_device *pdev)
phy_exit(ep->phy);
exynos_pcie_deinit_clk_resources(ep);
regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
-
- return 0;
}
static int exynos_pcie_suspend_noirq(struct device *dev)
@@ -431,7 +429,7 @@ static const struct of_device_id exynos_pcie_of_match[] = {
static struct platform_driver exynos_pcie_driver = {
.probe = exynos_pcie_probe,
- .remove = exynos_pcie_remove,
+ .remove_new = exynos_pcie_remove,
.driver = {
.name = "exynos-pcie",
.of_match_table = exynos_pcie_of_match,
diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index 74703362aeec..dc2c036ab28c 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -1039,8 +1039,8 @@ static void imx6_pcie_host_exit(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops imx6_pcie_host_ops = {
- .host_init = imx6_pcie_host_init,
- .host_deinit = imx6_pcie_host_exit,
+ .init = imx6_pcie_host_init,
+ .deinit = imx6_pcie_host_exit,
};
static const struct dw_pcie_ops dw_pcie_ops = {
@@ -1058,17 +1058,16 @@ static void imx6_pcie_ep_init(struct dw_pcie_ep *ep)
}
static int imx6_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type,
- u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
- return dw_pcie_ep_raise_legacy_irq(ep, func_no);
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_INTX:
+ return dw_pcie_ep_raise_intx_irq(ep, func_no);
+ case PCI_IRQ_MSI:
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
- case PCI_EPC_IRQ_MSIX:
+ case PCI_IRQ_MSIX:
return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
default:
dev_err(pci->dev, "UNKNOWN IRQ type\n");
@@ -1093,7 +1092,7 @@ imx6_pcie_ep_get_features(struct dw_pcie_ep *ep)
}
static const struct dw_pcie_ep_ops pcie_ep_ops = {
- .ep_init = imx6_pcie_ep_init,
+ .init = imx6_pcie_ep_init,
.raise_irq = imx6_pcie_ep_raise_irq,
.get_features = imx6_pcie_ep_get_features,
};
diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
index 0def919f89fa..c0c62533a3f1 100644
--- a/drivers/pci/controller/dwc/pci-keystone.c
+++ b/drivers/pci/controller/dwc/pci-keystone.c
@@ -115,8 +115,7 @@ struct keystone_pcie {
struct dw_pcie *pci;
/* PCI Device ID */
u32 device_id;
- int legacy_host_irqs[PCI_NUM_INTX];
- struct device_node *legacy_intc_np;
+ int intx_host_irqs[PCI_NUM_INTX];
int msi_host_irq;
int num_lanes;
@@ -124,7 +123,7 @@ struct keystone_pcie {
struct phy **phy;
struct device_link **link;
struct device_node *msi_intc_np;
- struct irq_domain *legacy_irq_domain;
+ struct irq_domain *intx_irq_domain;
struct device_node *np;
/* Application register space */
@@ -252,8 +251,8 @@ static int ks_pcie_msi_host_init(struct dw_pcie_rp *pp)
return dw_pcie_allocate_domains(pp);
}
-static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
- int offset)
+static void ks_pcie_handle_intx_irq(struct keystone_pcie *ks_pcie,
+ int offset)
{
struct dw_pcie *pci = ks_pcie->pci;
struct device *dev = pci->dev;
@@ -263,7 +262,7 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
if (BIT(0) & pending) {
dev_dbg(dev, ": irq: irq_offset %d", offset);
- generic_handle_domain_irq(ks_pcie->legacy_irq_domain, offset);
+ generic_handle_domain_irq(ks_pcie->intx_irq_domain, offset);
}
/* EOI the INTx interrupt */
@@ -307,38 +306,37 @@ static irqreturn_t ks_pcie_handle_error_irq(struct keystone_pcie *ks_pcie)
return IRQ_HANDLED;
}
-static void ks_pcie_ack_legacy_irq(struct irq_data *d)
+static void ks_pcie_ack_intx_irq(struct irq_data *d)
{
}
-static void ks_pcie_mask_legacy_irq(struct irq_data *d)
+static void ks_pcie_mask_intx_irq(struct irq_data *d)
{
}
-static void ks_pcie_unmask_legacy_irq(struct irq_data *d)
+static void ks_pcie_unmask_intx_irq(struct irq_data *d)
{
}
-static struct irq_chip ks_pcie_legacy_irq_chip = {
- .name = "Keystone-PCI-Legacy-IRQ",
- .irq_ack = ks_pcie_ack_legacy_irq,
- .irq_mask = ks_pcie_mask_legacy_irq,
- .irq_unmask = ks_pcie_unmask_legacy_irq,
+static struct irq_chip ks_pcie_intx_irq_chip = {
+ .name = "Keystone-PCI-INTX-IRQ",
+ .irq_ack = ks_pcie_ack_intx_irq,
+ .irq_mask = ks_pcie_mask_intx_irq,
+ .irq_unmask = ks_pcie_unmask_intx_irq,
};
-static int ks_pcie_init_legacy_irq_map(struct irq_domain *d,
- unsigned int irq,
- irq_hw_number_t hw_irq)
+static int ks_pcie_init_intx_irq_map(struct irq_domain *d,
+ unsigned int irq, irq_hw_number_t hw_irq)
{
- irq_set_chip_and_handler(irq, &ks_pcie_legacy_irq_chip,
+ irq_set_chip_and_handler(irq, &ks_pcie_intx_irq_chip,
handle_level_irq);
irq_set_chip_data(irq, d->host_data);
return 0;
}
-static const struct irq_domain_ops ks_pcie_legacy_irq_domain_ops = {
- .map = ks_pcie_init_legacy_irq_map,
+static const struct irq_domain_ops ks_pcie_intx_irq_domain_ops = {
+ .map = ks_pcie_init_intx_irq_map,
.xlate = irq_domain_xlate_onetwocell,
};
@@ -605,22 +603,22 @@ static void ks_pcie_msi_irq_handler(struct irq_desc *desc)
}
/**
- * ks_pcie_legacy_irq_handler() - Handle legacy interrupt
+ * ks_pcie_intx_irq_handler() - Handle INTX interrupt
* @desc: Pointer to irq descriptor
*
- * Traverse through pending legacy interrupts and invoke handler for each. Also
+ * Traverse through pending INTX interrupts and invoke handler for each. Also
* takes care of interrupt controller level mask/ack operation.
*/
-static void ks_pcie_legacy_irq_handler(struct irq_desc *desc)
+static void ks_pcie_intx_irq_handler(struct irq_desc *desc)
{
unsigned int irq = irq_desc_get_irq(desc);
struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
struct dw_pcie *pci = ks_pcie->pci;
struct device *dev = pci->dev;
- u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
+ u32 irq_offset = irq - ks_pcie->intx_host_irqs[0];
struct irq_chip *chip = irq_desc_get_chip(desc);
- dev_dbg(dev, ": Handling legacy irq %d\n", irq);
+ dev_dbg(dev, ": Handling INTX irq %d\n", irq);
/*
* The chained irq handler installation would have replaced normal
@@ -628,7 +626,7 @@ static void ks_pcie_legacy_irq_handler(struct irq_desc *desc)
* ack operation.
*/
chained_irq_enter(chip, desc);
- ks_pcie_handle_legacy_irq(ks_pcie, irq_offset);
+ ks_pcie_handle_intx_irq(ks_pcie, irq_offset);
chained_irq_exit(chip, desc);
}
@@ -686,10 +684,10 @@ err:
return ret;
}
-static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie)
+static int ks_pcie_config_intx_irq(struct keystone_pcie *ks_pcie)
{
struct device *dev = ks_pcie->pci->dev;
- struct irq_domain *legacy_irq_domain;
+ struct irq_domain *intx_irq_domain;
struct device_node *np = ks_pcie->np;
struct device_node *intc_np;
int irq_count, irq, ret = 0, i;
@@ -697,7 +695,7 @@ static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie)
intc_np = of_get_child_by_name(np, "legacy-interrupt-controller");
if (!intc_np) {
/*
- * Since legacy interrupts are modeled as edge-interrupts in
+ * Since INTX interrupts are modeled as edge-interrupts in
* AM6, keep it disabled for now.
*/
if (ks_pcie->is_am6)
@@ -719,22 +717,21 @@ static int ks_pcie_config_legacy_irq(struct keystone_pcie *ks_pcie)
ret = -EINVAL;
goto err;
}
- ks_pcie->legacy_host_irqs[i] = irq;
+ ks_pcie->intx_host_irqs[i] = irq;
irq_set_chained_handler_and_data(irq,
- ks_pcie_legacy_irq_handler,
+ ks_pcie_intx_irq_handler,
ks_pcie);
}
- legacy_irq_domain =
- irq_domain_add_linear(intc_np, PCI_NUM_INTX,
- &ks_pcie_legacy_irq_domain_ops, NULL);
- if (!legacy_irq_domain) {
- dev_err(dev, "Failed to add irq domain for legacy irqs\n");
+ intx_irq_domain = irq_domain_add_linear(intc_np, PCI_NUM_INTX,
+ &ks_pcie_intx_irq_domain_ops, NULL);
+ if (!intx_irq_domain) {
+ dev_err(dev, "Failed to add irq domain for INTX irqs\n");
ret = -EINVAL;
goto err;
}
- ks_pcie->legacy_irq_domain = legacy_irq_domain;
+ ks_pcie->intx_irq_domain = intx_irq_domain;
for (i = 0; i < PCI_NUM_INTX; i++)
ks_pcie_app_writel(ks_pcie, IRQ_ENABLE_SET(i), INTx_EN);
@@ -808,7 +805,7 @@ static int __init ks_pcie_host_init(struct dw_pcie_rp *pp)
if (!ks_pcie->is_am6)
pp->bridge->child_ops = &ks_child_pcie_ops;
- ret = ks_pcie_config_legacy_irq(ks_pcie);
+ ret = ks_pcie_config_intx_irq(ks_pcie);
if (ret)
return ret;
@@ -838,12 +835,12 @@ static int __init ks_pcie_host_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops ks_pcie_host_ops = {
- .host_init = ks_pcie_host_init,
- .msi_host_init = ks_pcie_msi_host_init,
+ .init = ks_pcie_host_init,
+ .msi_init = ks_pcie_msi_host_init,
};
static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = {
- .host_init = ks_pcie_host_init,
+ .init = ks_pcie_host_init,
};
static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv)
@@ -881,7 +878,7 @@ static void ks_pcie_am654_ep_init(struct dw_pcie_ep *ep)
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, flags);
}
-static void ks_pcie_am654_raise_legacy_irq(struct keystone_pcie *ks_pcie)
+static void ks_pcie_am654_raise_intx_irq(struct keystone_pcie *ks_pcie)
{
struct dw_pcie *pci = ks_pcie->pci;
u8 int_pin;
@@ -900,20 +897,19 @@ static void ks_pcie_am654_raise_legacy_irq(struct keystone_pcie *ks_pcie)
}
static int ks_pcie_am654_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type,
- u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
- ks_pcie_am654_raise_legacy_irq(ks_pcie);
+ case PCI_IRQ_INTX:
+ ks_pcie_am654_raise_intx_irq(ks_pcie);
break;
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_MSI:
dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
break;
- case PCI_EPC_IRQ_MSIX:
+ case PCI_IRQ_MSIX:
dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
break;
default:
@@ -944,7 +940,7 @@ ks_pcie_am654_get_features(struct dw_pcie_ep *ep)
}
static const struct dw_pcie_ep_ops ks_pcie_am654_ep_ops = {
- .ep_init = ks_pcie_am654_ep_init,
+ .init = ks_pcie_am654_ep_init,
.raise_irq = ks_pcie_am654_raise_irq,
.get_features = &ks_pcie_am654_get_features,
};
@@ -1218,7 +1214,16 @@ static int ks_pcie_probe(struct platform_device *pdev)
goto err_link;
}
+ /* Obtain references to the PHYs */
+ for (i = 0; i < num_lanes; i++)
+ phy_pm_runtime_get_sync(ks_pcie->phy[i]);
+
ret = ks_pcie_enable_phy(ks_pcie);
+
+ /* Release references to the PHYs */
+ for (i = 0; i < num_lanes; i++)
+ phy_pm_runtime_put_sync(ks_pcie->phy[i]);
+
if (ret) {
dev_err(dev, "failed to enable phy\n");
goto err_link;
@@ -1302,7 +1307,7 @@ err_link:
return ret;
}
-static int ks_pcie_remove(struct platform_device *pdev)
+static void ks_pcie_remove(struct platform_device *pdev)
{
struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
struct device_link **link = ks_pcie->link;
@@ -1314,13 +1319,11 @@ static int ks_pcie_remove(struct platform_device *pdev)
ks_pcie_disable_phy(ks_pcie);
while (num_lanes--)
device_link_del(link[num_lanes]);
-
- return 0;
}
static struct platform_driver ks_pcie_driver = {
.probe = ks_pcie_probe,
- .remove = ks_pcie_remove,
+ .remove_new = ks_pcie_remove,
.driver = {
.name = "keystone-pcie",
.of_match_table = ks_pcie_of_match,
diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
index 3d3c50ef4b6f..2e398494e7c0 100644
--- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
+++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
@@ -49,7 +49,7 @@ struct ls_pcie_ep {
bool big_endian;
};
-static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
+static u32 ls_pcie_pf_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
{
struct dw_pcie *pci = pcie->pci;
@@ -59,7 +59,7 @@ static u32 ls_lut_readl(struct ls_pcie_ep *pcie, u32 offset)
return ioread32(pci->dbi_base + offset);
}
-static void ls_lut_writel(struct ls_pcie_ep *pcie, u32 offset, u32 value)
+static void ls_pcie_pf_lut_writel(struct ls_pcie_ep *pcie, u32 offset, u32 value)
{
struct dw_pcie *pci = pcie->pci;
@@ -76,8 +76,8 @@ static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
u32 val, cfg;
u8 offset;
- val = ls_lut_readl(pcie, PEX_PF0_PME_MES_DR);
- ls_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
+ val = ls_pcie_pf_lut_readl(pcie, PEX_PF0_PME_MES_DR);
+ ls_pcie_pf_lut_writel(pcie, PEX_PF0_PME_MES_DR, val);
if (!val)
return IRQ_NONE;
@@ -96,9 +96,9 @@ static irqreturn_t ls_pcie_ep_event_handler(int irq, void *dev_id)
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, pcie->lnkcap);
dw_pcie_dbi_ro_wr_dis(pci);
- cfg = ls_lut_readl(pcie, PEX_PF0_CONFIG);
+ cfg = ls_pcie_pf_lut_readl(pcie, PEX_PF0_CONFIG);
cfg |= PEX_PF0_CFG_READY;
- ls_lut_writel(pcie, PEX_PF0_CONFIG, cfg);
+ ls_pcie_pf_lut_writel(pcie, PEX_PF0_CONFIG, cfg);
dw_pcie_ep_linkup(&pci->ep);
dev_dbg(pci->dev, "Link up\n");
@@ -130,10 +130,10 @@ static int ls_pcie_ep_interrupt_init(struct ls_pcie_ep *pcie,
}
/* Enable interrupts */
- val = ls_lut_readl(pcie, PEX_PF0_PME_MES_IER);
+ val = ls_pcie_pf_lut_readl(pcie, PEX_PF0_PME_MES_IER);
val |= PEX_PF0_PME_MES_IER_LDDIE | PEX_PF0_PME_MES_IER_HRDIE |
PEX_PF0_PME_MES_IER_LUDIE;
- ls_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
+ ls_pcie_pf_lut_writel(pcie, PEX_PF0_PME_MES_IER, val);
return 0;
}
@@ -166,16 +166,16 @@ static void ls_pcie_ep_init(struct dw_pcie_ep *ep)
}
static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type, u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
- return dw_pcie_ep_raise_legacy_irq(ep, func_no);
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_INTX:
+ return dw_pcie_ep_raise_intx_irq(ep, func_no);
+ case PCI_IRQ_MSI:
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
- case PCI_EPC_IRQ_MSIX:
+ case PCI_IRQ_MSIX:
return dw_pcie_ep_raise_msix_irq_doorbell(ep, func_no,
interrupt_num);
default:
@@ -184,8 +184,7 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
}
}
-static unsigned int ls_pcie_ep_func_conf_select(struct dw_pcie_ep *ep,
- u8 func_no)
+static unsigned int ls_pcie_ep_get_dbi_offset(struct dw_pcie_ep *ep, u8 func_no)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
@@ -195,10 +194,10 @@ static unsigned int ls_pcie_ep_func_conf_select(struct dw_pcie_ep *ep,
}
static const struct dw_pcie_ep_ops ls_pcie_ep_ops = {
- .ep_init = ls_pcie_ep_init,
+ .init = ls_pcie_ep_init,
.raise_irq = ls_pcie_ep_raise_irq,
.get_features = ls_pcie_ep_get_features,
- .func_conf_select = ls_pcie_ep_func_conf_select,
+ .get_dbi_offset = ls_pcie_ep_get_dbi_offset,
};
static const struct ls_pcie_ep_drvdata ls1_ep_drvdata = {
diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
index 37956e09c65b..ee6f52568133 100644
--- a/drivers/pci/controller/dwc/pci-layerscape.c
+++ b/drivers/pci/controller/dwc/pci-layerscape.c
@@ -35,21 +35,41 @@
#define PF_MCR_PTOMR BIT(0)
#define PF_MCR_EXL2S BIT(1)
+/* LS1021A PEXn PM Write Control Register */
+#define SCFG_PEXPMWRCR(idx) (0x5c + (idx) * 0x64)
+#define PMXMTTURNOFF BIT(31)
+#define SCFG_PEXSFTRSTCR 0x190
+#define PEXSR(idx) BIT(idx)
+
+/* LS1043A PEX PME control register */
+#define SCFG_PEXPMECR 0x144
+#define PEXPME(idx) BIT(31 - (idx) * 4)
+
+/* LS1043A PEX LUT debug register */
+#define LS_PCIE_LDBG 0x7fc
+#define LDBG_SR BIT(30)
+#define LDBG_WE BIT(31)
+
#define PCIE_IATU_NUM 6
struct ls_pcie_drvdata {
- const u32 pf_off;
+ const u32 pf_lut_off;
+ const struct dw_pcie_host_ops *ops;
+ int (*exit_from_l2)(struct dw_pcie_rp *pp);
+ bool scfg_support;
bool pm_support;
};
struct ls_pcie {
struct dw_pcie *pci;
const struct ls_pcie_drvdata *drvdata;
- void __iomem *pf_base;
+ void __iomem *pf_lut_base;
+ struct regmap *scfg;
+ int index;
bool big_endian;
};
-#define ls_pcie_pf_readl_addr(addr) ls_pcie_pf_readl(pcie, addr)
+#define ls_pcie_pf_lut_readl_addr(addr) ls_pcie_pf_lut_readl(pcie, addr)
#define to_ls_pcie(x) dev_get_drvdata((x)->dev)
static bool ls_pcie_is_bridge(struct ls_pcie *pcie)
@@ -90,20 +110,20 @@ static void ls_pcie_fix_error_response(struct ls_pcie *pcie)
iowrite32(PCIE_ABSERR_SETTING, pci->dbi_base + PCIE_ABSERR);
}
-static u32 ls_pcie_pf_readl(struct ls_pcie *pcie, u32 off)
+static u32 ls_pcie_pf_lut_readl(struct ls_pcie *pcie, u32 off)
{
if (pcie->big_endian)
- return ioread32be(pcie->pf_base + off);
+ return ioread32be(pcie->pf_lut_base + off);
- return ioread32(pcie->pf_base + off);
+ return ioread32(pcie->pf_lut_base + off);
}
-static void ls_pcie_pf_writel(struct ls_pcie *pcie, u32 off, u32 val)
+static void ls_pcie_pf_lut_writel(struct ls_pcie *pcie, u32 off, u32 val)
{
if (pcie->big_endian)
- iowrite32be(val, pcie->pf_base + off);
+ iowrite32be(val, pcie->pf_lut_base + off);
else
- iowrite32(val, pcie->pf_base + off);
+ iowrite32(val, pcie->pf_lut_base + off);
}
static void ls_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
@@ -113,11 +133,11 @@ static void ls_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
u32 val;
int ret;
- val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR);
+ val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_PF_MCR);
val |= PF_MCR_PTOMR;
- ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val);
+ ls_pcie_pf_lut_writel(pcie, LS_PCIE_PF_MCR, val);
- ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR,
+ ret = readx_poll_timeout(ls_pcie_pf_lut_readl_addr, LS_PCIE_PF_MCR,
val, !(val & PF_MCR_PTOMR),
PCIE_PME_TO_L2_TIMEOUT_US/10,
PCIE_PME_TO_L2_TIMEOUT_US);
@@ -125,7 +145,7 @@ static void ls_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
dev_err(pcie->pci->dev, "PME_Turn_off timeout\n");
}
-static void ls_pcie_exit_from_l2(struct dw_pcie_rp *pp)
+static int ls_pcie_exit_from_l2(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct ls_pcie *pcie = to_ls_pcie(pci);
@@ -136,20 +156,22 @@ static void ls_pcie_exit_from_l2(struct dw_pcie_rp *pp)
* Set PF_MCR_EXL2S bit in LS_PCIE_PF_MCR register for the link
* to exit L2 state.
*/
- val = ls_pcie_pf_readl(pcie, LS_PCIE_PF_MCR);
+ val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_PF_MCR);
val |= PF_MCR_EXL2S;
- ls_pcie_pf_writel(pcie, LS_PCIE_PF_MCR, val);
+ ls_pcie_pf_lut_writel(pcie, LS_PCIE_PF_MCR, val);
/*
* L2 exit timeout of 10ms is not defined in the specifications,
* it was chosen based on empirical observations.
*/
- ret = readx_poll_timeout(ls_pcie_pf_readl_addr, LS_PCIE_PF_MCR,
+ ret = readx_poll_timeout(ls_pcie_pf_lut_readl_addr, LS_PCIE_PF_MCR,
val, !(val & PF_MCR_EXL2S),
1000,
10000);
if (ret)
dev_err(pcie->pci->dev, "L2 exit timeout\n");
+
+ return ret;
}
static int ls_pcie_host_init(struct dw_pcie_rp *pp)
@@ -168,25 +190,130 @@ static int ls_pcie_host_init(struct dw_pcie_rp *pp)
return 0;
}
+static void scfg_pcie_send_turnoff_msg(struct regmap *scfg, u32 reg, u32 mask)
+{
+ /* Send PME_Turn_Off message */
+ regmap_write_bits(scfg, reg, mask, mask);
+
+ /*
+ * There is no specific register to check for PME_To_Ack from endpoint.
+ * So on the safe side, wait for PCIE_PME_TO_L2_TIMEOUT_US.
+ */
+ mdelay(PCIE_PME_TO_L2_TIMEOUT_US/1000);
+
+ /*
+ * Layerscape hardware reference manual recommends clearing the PMXMTTURNOFF bit
+ * to complete the PME_Turn_Off handshake.
+ */
+ regmap_write_bits(scfg, reg, mask, 0);
+}
+
+static void ls1021a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct ls_pcie *pcie = to_ls_pcie(pci);
+
+ scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMWRCR(pcie->index), PMXMTTURNOFF);
+}
+
+static int scfg_pcie_exit_from_l2(struct regmap *scfg, u32 reg, u32 mask)
+{
+ /* Reset the PEX wrapper to bring the link out of L2 */
+ regmap_write_bits(scfg, reg, mask, mask);
+ regmap_write_bits(scfg, reg, mask, 0);
+
+ return 0;
+}
+
+static int ls1021a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct ls_pcie *pcie = to_ls_pcie(pci);
+
+ return scfg_pcie_exit_from_l2(pcie->scfg, SCFG_PEXSFTRSTCR, PEXSR(pcie->index));
+}
+
+static void ls1043a_pcie_send_turnoff_msg(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct ls_pcie *pcie = to_ls_pcie(pci);
+
+ scfg_pcie_send_turnoff_msg(pcie->scfg, SCFG_PEXPMECR, PEXPME(pcie->index));
+}
+
+static int ls1043a_pcie_exit_from_l2(struct dw_pcie_rp *pp)
+{
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct ls_pcie *pcie = to_ls_pcie(pci);
+ u32 val;
+
+ /*
+ * Reset the PEX wrapper to bring the link out of L2.
+ * LDBG_WE: allows the user to have write access to the PEXDBG[SR] for both setting and
+ * clearing the soft reset on the PEX module.
+ * LDBG_SR: When SR is set to 1, the PEX module enters soft reset.
+ */
+ val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
+ val |= LDBG_WE;
+ ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
+
+ val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
+ val |= LDBG_SR;
+ ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
+
+ val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
+ val &= ~LDBG_SR;
+ ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
+
+ val = ls_pcie_pf_lut_readl(pcie, LS_PCIE_LDBG);
+ val &= ~LDBG_WE;
+ ls_pcie_pf_lut_writel(pcie, LS_PCIE_LDBG, val);
+
+ return 0;
+}
+
static const struct dw_pcie_host_ops ls_pcie_host_ops = {
- .host_init = ls_pcie_host_init,
+ .init = ls_pcie_host_init,
.pme_turn_off = ls_pcie_send_turnoff_msg,
};
+static const struct dw_pcie_host_ops ls1021a_pcie_host_ops = {
+ .init = ls_pcie_host_init,
+ .pme_turn_off = ls1021a_pcie_send_turnoff_msg,
+};
+
static const struct ls_pcie_drvdata ls1021a_drvdata = {
- .pm_support = false,
+ .pm_support = true,
+ .scfg_support = true,
+ .ops = &ls1021a_pcie_host_ops,
+ .exit_from_l2 = ls1021a_pcie_exit_from_l2,
+};
+
+static const struct dw_pcie_host_ops ls1043a_pcie_host_ops = {
+ .init = ls_pcie_host_init,
+ .pme_turn_off = ls1043a_pcie_send_turnoff_msg,
+};
+
+static const struct ls_pcie_drvdata ls1043a_drvdata = {
+ .pf_lut_off = 0x10000,
+ .pm_support = true,
+ .scfg_support = true,
+ .ops = &ls1043a_pcie_host_ops,
+ .exit_from_l2 = ls1043a_pcie_exit_from_l2,
};
static const struct ls_pcie_drvdata layerscape_drvdata = {
- .pf_off = 0xc0000,
+ .pf_lut_off = 0xc0000,
.pm_support = true,
+ .ops = &ls_pcie_host_ops,
+ .exit_from_l2 = ls_pcie_exit_from_l2,
};
static const struct of_device_id ls_pcie_of_match[] = {
{ .compatible = "fsl,ls1012a-pcie", .data = &layerscape_drvdata },
{ .compatible = "fsl,ls1021a-pcie", .data = &ls1021a_drvdata },
{ .compatible = "fsl,ls1028a-pcie", .data = &layerscape_drvdata },
- { .compatible = "fsl,ls1043a-pcie", .data = &ls1021a_drvdata },
+ { .compatible = "fsl,ls1043a-pcie", .data = &ls1043a_drvdata },
{ .compatible = "fsl,ls1046a-pcie", .data = &layerscape_drvdata },
{ .compatible = "fsl,ls2080a-pcie", .data = &layerscape_drvdata },
{ .compatible = "fsl,ls2085a-pcie", .data = &layerscape_drvdata },
@@ -201,6 +328,8 @@ static int ls_pcie_probe(struct platform_device *pdev)
struct dw_pcie *pci;
struct ls_pcie *pcie;
struct resource *dbi_base;
+ u32 index[2];
+ int ret;
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
@@ -213,9 +342,8 @@ static int ls_pcie_probe(struct platform_device *pdev)
pcie->drvdata = of_device_get_match_data(dev);
pci->dev = dev;
- pci->pp.ops = &ls_pcie_host_ops;
-
pcie->pci = pci;
+ pci->pp.ops = pcie->drvdata->ops;
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
@@ -224,7 +352,21 @@ static int ls_pcie_probe(struct platform_device *pdev)
pcie->big_endian = of_property_read_bool(dev->of_node, "big-endian");
- pcie->pf_base = pci->dbi_base + pcie->drvdata->pf_off;
+ pcie->pf_lut_base = pci->dbi_base + pcie->drvdata->pf_lut_off;
+
+ if (pcie->drvdata->scfg_support) {
+ pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node, "fsl,pcie-scfg");
+ if (IS_ERR(pcie->scfg)) {
+ dev_err(dev, "No syscfg phandle specified\n");
+ return PTR_ERR(pcie->scfg);
+ }
+
+ ret = of_property_read_u32_array(dev->of_node, "fsl,pcie-scfg", index, 2);
+ if (ret)
+ return ret;
+
+ pcie->index = index[1];
+ }
if (!ls_pcie_is_bridge(pcie))
return -ENODEV;
@@ -247,11 +389,14 @@ static int ls_pcie_suspend_noirq(struct device *dev)
static int ls_pcie_resume_noirq(struct device *dev)
{
struct ls_pcie *pcie = dev_get_drvdata(dev);
+ int ret;
if (!pcie->drvdata->pm_support)
return 0;
- ls_pcie_exit_from_l2(&pcie->pci->pp);
+ ret = pcie->drvdata->exit_from_l2(&pcie->pci->pp);
+ if (ret)
+ return ret;
return dw_pcie_resume_noirq(pcie->pci);
}
diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
index 407558f5d74a..6477c83262c2 100644
--- a/drivers/pci/controller/dwc/pci-meson.c
+++ b/drivers/pci/controller/dwc/pci-meson.c
@@ -389,7 +389,7 @@ static int meson_pcie_host_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops meson_pcie_host_ops = {
- .host_init = meson_pcie_host_init,
+ .init = meson_pcie_host_init,
};
static const struct dw_pcie_ops dw_pcie_ops = {
diff --git a/drivers/pci/controller/dwc/pcie-al.c b/drivers/pci/controller/dwc/pcie-al.c
index b8cb77c9c4bd..6dfdda59f328 100644
--- a/drivers/pci/controller/dwc/pcie-al.c
+++ b/drivers/pci/controller/dwc/pcie-al.c
@@ -311,7 +311,7 @@ static int al_pcie_host_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops al_pcie_host_ops = {
- .host_init = al_pcie_host_init,
+ .init = al_pcie_host_init,
};
static int al_pcie_probe(struct platform_device *pdev)
diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c
index 5c999e15c357..b5c599ccaacf 100644
--- a/drivers/pci/controller/dwc/pcie-armada8k.c
+++ b/drivers/pci/controller/dwc/pcie-armada8k.c
@@ -225,7 +225,7 @@ static irqreturn_t armada8k_pcie_irq_handler(int irq, void *arg)
}
static const struct dw_pcie_host_ops armada8k_pcie_host_ops = {
- .host_init = armada8k_pcie_host_init,
+ .init = armada8k_pcie_host_init,
};
static int armada8k_add_pcie_port(struct armada8k_pcie *pcie,
diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c
index 9b572a2b2c9a..9ed0a9ba7619 100644
--- a/drivers/pci/controller/dwc/pcie-artpec6.c
+++ b/drivers/pci/controller/dwc/pcie-artpec6.c
@@ -333,7 +333,7 @@ static int artpec6_pcie_host_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops artpec6_pcie_host_ops = {
- .host_init = artpec6_pcie_host_init,
+ .init = artpec6_pcie_host_init,
};
static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
@@ -352,15 +352,15 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
}
static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type, u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
- dev_err(pci->dev, "EP cannot trigger legacy IRQs\n");
+ case PCI_IRQ_INTX:
+ dev_err(pci->dev, "EP cannot trigger INTx IRQs\n");
return -EINVAL;
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_MSI:
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
default:
dev_err(pci->dev, "UNKNOWN IRQ type\n");
@@ -370,7 +370,7 @@ static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
}
static const struct dw_pcie_ep_ops pcie_ep_ops = {
- .ep_init = artpec6_pcie_ep_init,
+ .init = artpec6_pcie_ep_init,
.raise_irq = artpec6_pcie_raise_irq,
};
diff --git a/drivers/pci/controller/dwc/pcie-bt1.c b/drivers/pci/controller/dwc/pcie-bt1.c
index 17e696797ff5..76d0ddea8007 100644
--- a/drivers/pci/controller/dwc/pcie-bt1.c
+++ b/drivers/pci/controller/dwc/pcie-bt1.c
@@ -559,8 +559,8 @@ static void bt1_pcie_host_deinit(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops bt1_pcie_host_ops = {
- .host_init = bt1_pcie_host_init,
- .host_deinit = bt1_pcie_host_deinit,
+ .init = bt1_pcie_host_init,
+ .deinit = bt1_pcie_host_deinit,
};
static struct bt1_pcie *bt1_pcie_create_data(struct platform_device *pdev)
diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index f6207989fc6a..5befed2dc02b 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -43,46 +43,19 @@ dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
return NULL;
}
-static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no)
-{
- unsigned int func_offset = 0;
-
- if (ep->ops->func_conf_select)
- func_offset = ep->ops->func_conf_select(ep, func_no);
-
- return func_offset;
-}
-
-static unsigned int dw_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep, u8 func_no)
-{
- unsigned int dbi2_offset = 0;
-
- if (ep->ops->get_dbi2_offset)
- dbi2_offset = ep->ops->get_dbi2_offset(ep, func_no);
- else if (ep->ops->func_conf_select) /* for backward compatibility */
- dbi2_offset = ep->ops->func_conf_select(ep, func_no);
-
- return dbi2_offset;
-}
-
static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no,
enum pci_barno bar, int flags)
{
- unsigned int func_offset, dbi2_offset;
struct dw_pcie_ep *ep = &pci->ep;
- u32 reg, reg_dbi2;
-
- func_offset = dw_pcie_ep_func_select(ep, func_no);
- dbi2_offset = dw_pcie_ep_get_dbi2_offset(ep, func_no);
+ u32 reg;
- reg = func_offset + PCI_BASE_ADDRESS_0 + (4 * bar);
- reg_dbi2 = dbi2_offset + PCI_BASE_ADDRESS_0 + (4 * bar);
+ reg = PCI_BASE_ADDRESS_0 + (4 * bar);
dw_pcie_dbi_ro_wr_en(pci);
- dw_pcie_writel_dbi2(pci, reg_dbi2, 0x0);
- dw_pcie_writel_dbi(pci, reg, 0x0);
+ dw_pcie_ep_writel_dbi2(ep, func_no, reg, 0x0);
+ dw_pcie_ep_writel_dbi(ep, func_no, reg, 0x0);
if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- dw_pcie_writel_dbi2(pci, reg_dbi2 + 4, 0x0);
- dw_pcie_writel_dbi(pci, reg + 4, 0x0);
+ dw_pcie_ep_writel_dbi2(ep, func_no, reg + 4, 0x0);
+ dw_pcie_ep_writel_dbi(ep, func_no, reg + 4, 0x0);
}
dw_pcie_dbi_ro_wr_dis(pci);
}
@@ -99,19 +72,15 @@ void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
EXPORT_SYMBOL_GPL(dw_pcie_ep_reset_bar);
static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no,
- u8 cap_ptr, u8 cap)
+ u8 cap_ptr, u8 cap)
{
- struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
- unsigned int func_offset = 0;
u8 cap_id, next_cap_ptr;
u16 reg;
if (!cap_ptr)
return 0;
- func_offset = dw_pcie_ep_func_select(ep, func_no);
-
- reg = dw_pcie_readw_dbi(pci, func_offset + cap_ptr);
+ reg = dw_pcie_ep_readw_dbi(ep, func_no, cap_ptr);
cap_id = (reg & 0x00ff);
if (cap_id > PCI_CAP_ID_MAX)
@@ -126,14 +95,10 @@ static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no,
static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap)
{
- struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
- unsigned int func_offset = 0;
u8 next_cap_ptr;
u16 reg;
- func_offset = dw_pcie_ep_func_select(ep, func_no);
-
- reg = dw_pcie_readw_dbi(pci, func_offset + PCI_CAPABILITY_LIST);
+ reg = dw_pcie_ep_readw_dbi(ep, func_no, PCI_CAPABILITY_LIST);
next_cap_ptr = (reg & 0x00ff);
return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap);
@@ -144,24 +109,21 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
{
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
- unsigned int func_offset = 0;
-
- func_offset = dw_pcie_ep_func_select(ep, func_no);
dw_pcie_dbi_ro_wr_en(pci);
- dw_pcie_writew_dbi(pci, func_offset + PCI_VENDOR_ID, hdr->vendorid);
- dw_pcie_writew_dbi(pci, func_offset + PCI_DEVICE_ID, hdr->deviceid);
- dw_pcie_writeb_dbi(pci, func_offset + PCI_REVISION_ID, hdr->revid);
- dw_pcie_writeb_dbi(pci, func_offset + PCI_CLASS_PROG, hdr->progif_code);
- dw_pcie_writew_dbi(pci, func_offset + PCI_CLASS_DEVICE,
- hdr->subclass_code | hdr->baseclass_code << 8);
- dw_pcie_writeb_dbi(pci, func_offset + PCI_CACHE_LINE_SIZE,
- hdr->cache_line_size);
- dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_VENDOR_ID,
- hdr->subsys_vendor_id);
- dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_ID, hdr->subsys_id);
- dw_pcie_writeb_dbi(pci, func_offset + PCI_INTERRUPT_PIN,
- hdr->interrupt_pin);
+ dw_pcie_ep_writew_dbi(ep, func_no, PCI_VENDOR_ID, hdr->vendorid);
+ dw_pcie_ep_writew_dbi(ep, func_no, PCI_DEVICE_ID, hdr->deviceid);
+ dw_pcie_ep_writeb_dbi(ep, func_no, PCI_REVISION_ID, hdr->revid);
+ dw_pcie_ep_writeb_dbi(ep, func_no, PCI_CLASS_PROG, hdr->progif_code);
+ dw_pcie_ep_writew_dbi(ep, func_no, PCI_CLASS_DEVICE,
+ hdr->subclass_code | hdr->baseclass_code << 8);
+ dw_pcie_ep_writeb_dbi(ep, func_no, PCI_CACHE_LINE_SIZE,
+ hdr->cache_line_size);
+ dw_pcie_ep_writew_dbi(ep, func_no, PCI_SUBSYSTEM_VENDOR_ID,
+ hdr->subsys_vendor_id);
+ dw_pcie_ep_writew_dbi(ep, func_no, PCI_SUBSYSTEM_ID, hdr->subsys_id);
+ dw_pcie_ep_writeb_dbi(ep, func_no, PCI_INTERRUPT_PIN,
+ hdr->interrupt_pin);
dw_pcie_dbi_ro_wr_dis(pci);
return 0;
@@ -243,18 +205,13 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
{
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
- unsigned int func_offset, dbi2_offset;
enum pci_barno bar = epf_bar->barno;
size_t size = epf_bar->size;
int flags = epf_bar->flags;
- u32 reg, reg_dbi2;
int ret, type;
+ u32 reg;
- func_offset = dw_pcie_ep_func_select(ep, func_no);
- dbi2_offset = dw_pcie_ep_get_dbi2_offset(ep, func_no);
-
- reg = PCI_BASE_ADDRESS_0 + (4 * bar) + func_offset;
- reg_dbi2 = PCI_BASE_ADDRESS_0 + (4 * bar) + dbi2_offset;
+ reg = PCI_BASE_ADDRESS_0 + (4 * bar);
if (!(flags & PCI_BASE_ADDRESS_SPACE))
type = PCIE_ATU_TYPE_MEM;
@@ -270,12 +227,12 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
dw_pcie_dbi_ro_wr_en(pci);
- dw_pcie_writel_dbi2(pci, reg_dbi2, lower_32_bits(size - 1));
- dw_pcie_writel_dbi(pci, reg, flags);
+ dw_pcie_ep_writel_dbi2(ep, func_no, reg, lower_32_bits(size - 1));
+ dw_pcie_ep_writel_dbi(ep, func_no, reg, flags);
if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- dw_pcie_writel_dbi2(pci, reg_dbi2 + 4, upper_32_bits(size - 1));
- dw_pcie_writel_dbi(pci, reg + 4, 0);
+ dw_pcie_ep_writel_dbi2(ep, func_no, reg + 4, upper_32_bits(size - 1));
+ dw_pcie_ep_writel_dbi(ep, func_no, reg + 4, 0);
}
ep->epf_bar[bar] = epf_bar;
@@ -335,19 +292,15 @@ static int dw_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
{
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
- struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
- u32 val, reg;
- unsigned int func_offset = 0;
struct dw_pcie_ep_func *ep_func;
+ u32 val, reg;
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
if (!ep_func || !ep_func->msi_cap)
return -EINVAL;
- func_offset = dw_pcie_ep_func_select(ep, func_no);
-
- reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
- val = dw_pcie_readw_dbi(pci, reg);
+ reg = ep_func->msi_cap + PCI_MSI_FLAGS;
+ val = dw_pcie_ep_readw_dbi(ep, func_no, reg);
if (!(val & PCI_MSI_FLAGS_ENABLE))
return -EINVAL;
@@ -361,22 +314,19 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
{
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
- u32 val, reg;
- unsigned int func_offset = 0;
struct dw_pcie_ep_func *ep_func;
+ u32 val, reg;
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
if (!ep_func || !ep_func->msi_cap)
return -EINVAL;
- func_offset = dw_pcie_ep_func_select(ep, func_no);
-
- reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
- val = dw_pcie_readw_dbi(pci, reg);
+ reg = ep_func->msi_cap + PCI_MSI_FLAGS;
+ val = dw_pcie_ep_readw_dbi(ep, func_no, reg);
val &= ~PCI_MSI_FLAGS_QMASK;
val |= FIELD_PREP(PCI_MSI_FLAGS_QMASK, interrupts);
dw_pcie_dbi_ro_wr_en(pci);
- dw_pcie_writew_dbi(pci, reg, val);
+ dw_pcie_ep_writew_dbi(ep, func_no, reg, val);
dw_pcie_dbi_ro_wr_dis(pci);
return 0;
@@ -385,19 +335,15 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
{
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
- struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
- u32 val, reg;
- unsigned int func_offset = 0;
struct dw_pcie_ep_func *ep_func;
+ u32 val, reg;
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
if (!ep_func || !ep_func->msix_cap)
return -EINVAL;
- func_offset = dw_pcie_ep_func_select(ep, func_no);
-
- reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS;
- val = dw_pcie_readw_dbi(pci, reg);
+ reg = ep_func->msix_cap + PCI_MSIX_FLAGS;
+ val = dw_pcie_ep_readw_dbi(ep, func_no, reg);
if (!(val & PCI_MSIX_FLAGS_ENABLE))
return -EINVAL;
@@ -411,9 +357,8 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
{
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
- u32 val, reg;
- unsigned int func_offset = 0;
struct dw_pcie_ep_func *ep_func;
+ u32 val, reg;
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
if (!ep_func || !ep_func->msix_cap)
@@ -421,21 +366,19 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
dw_pcie_dbi_ro_wr_en(pci);
- func_offset = dw_pcie_ep_func_select(ep, func_no);
-
- reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS;
- val = dw_pcie_readw_dbi(pci, reg);
+ reg = ep_func->msix_cap + PCI_MSIX_FLAGS;
+ val = dw_pcie_ep_readw_dbi(ep, func_no, reg);
val &= ~PCI_MSIX_FLAGS_QSIZE;
val |= interrupts;
dw_pcie_writew_dbi(pci, reg, val);
- reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE;
+ reg = ep_func->msix_cap + PCI_MSIX_TABLE;
val = offset | bir;
- dw_pcie_writel_dbi(pci, reg, val);
+ dw_pcie_ep_writel_dbi(ep, func_no, reg, val);
- reg = ep_func->msix_cap + func_offset + PCI_MSIX_PBA;
+ reg = ep_func->msix_cap + PCI_MSIX_PBA;
val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
- dw_pcie_writel_dbi(pci, reg, val);
+ dw_pcie_ep_writel_dbi(ep, func_no, reg, val);
dw_pcie_dbi_ro_wr_dis(pci);
@@ -443,7 +386,7 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
}
static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
- enum pci_epc_irq_type type, u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
@@ -496,52 +439,48 @@ static const struct pci_epc_ops epc_ops = {
.get_features = dw_pcie_ep_get_features,
};
-int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no)
+int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct device *dev = pci->dev;
- dev_err(dev, "EP cannot trigger legacy IRQs\n");
+ dev_err(dev, "EP cannot raise INTX IRQs\n");
return -EINVAL;
}
-EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_legacy_irq);
+EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_intx_irq);
int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
u8 interrupt_num)
{
- struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ u32 msg_addr_lower, msg_addr_upper, reg;
struct dw_pcie_ep_func *ep_func;
struct pci_epc *epc = ep->epc;
unsigned int aligned_offset;
- unsigned int func_offset = 0;
u16 msg_ctrl, msg_data;
- u32 msg_addr_lower, msg_addr_upper, reg;
- u64 msg_addr;
bool has_upper;
+ u64 msg_addr;
int ret;
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
if (!ep_func || !ep_func->msi_cap)
return -EINVAL;
- func_offset = dw_pcie_ep_func_select(ep, func_no);
-
/* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */
- reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
- msg_ctrl = dw_pcie_readw_dbi(pci, reg);
+ reg = ep_func->msi_cap + PCI_MSI_FLAGS;
+ msg_ctrl = dw_pcie_ep_readw_dbi(ep, func_no, reg);
has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT);
- reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_LO;
- msg_addr_lower = dw_pcie_readl_dbi(pci, reg);
+ reg = ep_func->msi_cap + PCI_MSI_ADDRESS_LO;
+ msg_addr_lower = dw_pcie_ep_readl_dbi(ep, func_no, reg);
if (has_upper) {
- reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_HI;
- msg_addr_upper = dw_pcie_readl_dbi(pci, reg);
- reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_64;
- msg_data = dw_pcie_readw_dbi(pci, reg);
+ reg = ep_func->msi_cap + PCI_MSI_ADDRESS_HI;
+ msg_addr_upper = dw_pcie_ep_readl_dbi(ep, func_no, reg);
+ reg = ep_func->msi_cap + PCI_MSI_DATA_64;
+ msg_data = dw_pcie_ep_readw_dbi(ep, func_no, reg);
} else {
msg_addr_upper = 0;
- reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_32;
- msg_data = dw_pcie_readw_dbi(pci, reg);
+ reg = ep_func->msi_cap + PCI_MSI_DATA_32;
+ msg_data = dw_pcie_ep_readw_dbi(ep, func_no, reg);
}
aligned_offset = msg_addr_lower & (epc->mem->window.page_size - 1);
msg_addr = ((u64)msg_addr_upper) << 32 |
@@ -582,10 +521,9 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
- struct dw_pcie_ep_func *ep_func;
struct pci_epf_msix_tbl *msix_tbl;
+ struct dw_pcie_ep_func *ep_func;
struct pci_epc *epc = ep->epc;
- unsigned int func_offset = 0;
u32 reg, msg_data, vec_ctrl;
unsigned int aligned_offset;
u32 tbl_offset;
@@ -597,10 +535,8 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
if (!ep_func || !ep_func->msix_cap)
return -EINVAL;
- func_offset = dw_pcie_ep_func_select(ep, func_no);
-
- reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE;
- tbl_offset = dw_pcie_readl_dbi(pci, reg);
+ reg = ep_func->msix_cap + PCI_MSIX_TABLE;
+ tbl_offset = dw_pcie_ep_readl_dbi(ep, func_no, reg);
bir = FIELD_GET(PCI_MSIX_TABLE_BIR, tbl_offset);
tbl_offset &= PCI_MSIX_TABLE_OFFSET;
@@ -615,6 +551,7 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
}
aligned_offset = msg_addr & (epc->mem->window.page_size - 1);
+ msg_addr &= ~aligned_offset;
ret = dw_pcie_ep_map_addr(epc, func_no, 0, ep->msi_mem_phys, msg_addr,
epc->mem->window.page_size);
if (ret)
@@ -794,8 +731,8 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
list_add_tail(&ep_func->list, &ep->func_list);
}
- if (ep->ops->ep_init)
- ep->ops->ep_init(ep);
+ if (ep->ops->init)
+ ep->ops->init(ep);
ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
ep->page_size);
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 7991f0e179b2..d5fc31f8345f 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -441,14 +441,14 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
bridge->ops = &dw_pcie_ops;
bridge->child_ops = &dw_child_pcie_ops;
- if (pp->ops->host_init) {
- ret = pp->ops->host_init(pp);
+ if (pp->ops->init) {
+ ret = pp->ops->init(pp);
if (ret)
return ret;
}
if (pci_msi_enabled()) {
- pp->has_msi_ctrl = !(pp->ops->msi_host_init ||
+ pp->has_msi_ctrl = !(pp->ops->msi_init ||
of_property_read_bool(np, "msi-parent") ||
of_property_read_bool(np, "msi-map"));
@@ -464,8 +464,8 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
goto err_deinit_host;
}
- if (pp->ops->msi_host_init) {
- ret = pp->ops->msi_host_init(pp);
+ if (pp->ops->msi_init) {
+ ret = pp->ops->msi_init(pp);
if (ret < 0)
goto err_deinit_host;
} else if (pp->has_msi_ctrl) {
@@ -502,8 +502,8 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
if (ret)
goto err_stop_link;
- if (pp->ops->host_post_init)
- pp->ops->host_post_init(pp);
+ if (pp->ops->post_init)
+ pp->ops->post_init(pp);
return 0;
@@ -518,8 +518,8 @@ err_free_msi:
dw_pcie_free_msi(pp);
err_deinit_host:
- if (pp->ops->host_deinit)
- pp->ops->host_deinit(pp);
+ if (pp->ops->deinit)
+ pp->ops->deinit(pp);
return ret;
}
@@ -539,8 +539,8 @@ void dw_pcie_host_deinit(struct dw_pcie_rp *pp)
if (pp->has_msi_ctrl)
dw_pcie_free_msi(pp);
- if (pp->ops->host_deinit)
- pp->ops->host_deinit(pp);
+ if (pp->ops->deinit)
+ pp->ops->deinit(pp);
}
EXPORT_SYMBOL_GPL(dw_pcie_host_deinit);
@@ -842,8 +842,8 @@ int dw_pcie_suspend_noirq(struct dw_pcie *pci)
return ret;
}
- if (pci->pp.ops->host_deinit)
- pci->pp.ops->host_deinit(&pci->pp);
+ if (pci->pp.ops->deinit)
+ pci->pp.ops->deinit(&pci->pp);
pci->suspended = true;
@@ -860,8 +860,8 @@ int dw_pcie_resume_noirq(struct dw_pcie *pci)
pci->suspended = false;
- if (pci->pp.ops->host_init) {
- ret = pci->pp.ops->host_init(&pci->pp);
+ if (pci->pp.ops->init) {
+ ret = pci->pp.ops->init(&pci->pp);
if (ret) {
dev_err(pci->dev, "Host init failed: %d\n", ret);
return ret;
diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
index b625841e98aa..778588b4be70 100644
--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
+++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
@@ -42,17 +42,16 @@ static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
}
static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type,
- u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
- return dw_pcie_ep_raise_legacy_irq(ep, func_no);
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_INTX:
+ return dw_pcie_ep_raise_intx_irq(ep, func_no);
+ case PCI_IRQ_MSI:
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
- case PCI_EPC_IRQ_MSIX:
+ case PCI_IRQ_MSIX:
return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
default:
dev_err(pci->dev, "UNKNOWN IRQ type\n");
@@ -74,7 +73,7 @@ dw_plat_pcie_get_features(struct dw_pcie_ep *ep)
}
static const struct dw_pcie_ep_ops pcie_ep_ops = {
- .ep_init = dw_plat_pcie_ep_init,
+ .init = dw_plat_pcie_ep_init,
.raise_irq = dw_plat_pcie_ep_raise_irq,
.get_features = dw_plat_pcie_get_features,
};
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 55ff76e3d384..26dae4837462 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -300,10 +300,10 @@ enum dw_pcie_ltssm {
};
struct dw_pcie_host_ops {
- int (*host_init)(struct dw_pcie_rp *pp);
- void (*host_deinit)(struct dw_pcie_rp *pp);
- void (*host_post_init)(struct dw_pcie_rp *pp);
- int (*msi_host_init)(struct dw_pcie_rp *pp);
+ int (*init)(struct dw_pcie_rp *pp);
+ void (*deinit)(struct dw_pcie_rp *pp);
+ void (*post_init)(struct dw_pcie_rp *pp);
+ int (*msi_init)(struct dw_pcie_rp *pp);
void (*pme_turn_off)(struct dw_pcie_rp *pp);
};
@@ -332,10 +332,10 @@ struct dw_pcie_rp {
struct dw_pcie_ep_ops {
void (*pre_init)(struct dw_pcie_ep *ep);
- void (*ep_init)(struct dw_pcie_ep *ep);
+ void (*init)(struct dw_pcie_ep *ep);
void (*deinit)(struct dw_pcie_ep *ep);
int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type, u16 interrupt_num);
+ unsigned int type, u16 interrupt_num);
const struct pci_epc_features* (*get_features)(struct dw_pcie_ep *ep);
/*
* Provide a method to implement the different func config space
@@ -344,7 +344,7 @@ struct dw_pcie_ep_ops {
* return a 0, and implement code in callback function of platform
* driver.
*/
- unsigned int (*func_conf_select)(struct dw_pcie_ep *ep, u8 func_no);
+ unsigned int (*get_dbi_offset)(struct dw_pcie_ep *ep, u8 func_no);
unsigned int (*get_dbi2_offset)(struct dw_pcie_ep *ep, u8 func_no);
};
@@ -486,6 +486,99 @@ static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val)
dw_pcie_write_dbi2(pci, reg, 0x4, val);
}
+static inline unsigned int dw_pcie_ep_get_dbi_offset(struct dw_pcie_ep *ep,
+ u8 func_no)
+{
+ unsigned int dbi_offset = 0;
+
+ if (ep->ops->get_dbi_offset)
+ dbi_offset = ep->ops->get_dbi_offset(ep, func_no);
+
+ return dbi_offset;
+}
+
+static inline u32 dw_pcie_ep_read_dbi(struct dw_pcie_ep *ep, u8 func_no,
+ u32 reg, size_t size)
+{
+ unsigned int offset = dw_pcie_ep_get_dbi_offset(ep, func_no);
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+
+ return dw_pcie_read_dbi(pci, offset + reg, size);
+}
+
+static inline void dw_pcie_ep_write_dbi(struct dw_pcie_ep *ep, u8 func_no,
+ u32 reg, size_t size, u32 val)
+{
+ unsigned int offset = dw_pcie_ep_get_dbi_offset(ep, func_no);
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+
+ dw_pcie_write_dbi(pci, offset + reg, size, val);
+}
+
+static inline void dw_pcie_ep_writel_dbi(struct dw_pcie_ep *ep, u8 func_no,
+ u32 reg, u32 val)
+{
+ dw_pcie_ep_write_dbi(ep, func_no, reg, 0x4, val);
+}
+
+static inline u32 dw_pcie_ep_readl_dbi(struct dw_pcie_ep *ep, u8 func_no,
+ u32 reg)
+{
+ return dw_pcie_ep_read_dbi(ep, func_no, reg, 0x4);
+}
+
+static inline void dw_pcie_ep_writew_dbi(struct dw_pcie_ep *ep, u8 func_no,
+ u32 reg, u16 val)
+{
+ dw_pcie_ep_write_dbi(ep, func_no, reg, 0x2, val);
+}
+
+static inline u16 dw_pcie_ep_readw_dbi(struct dw_pcie_ep *ep, u8 func_no,
+ u32 reg)
+{
+ return dw_pcie_ep_read_dbi(ep, func_no, reg, 0x2);
+}
+
+static inline void dw_pcie_ep_writeb_dbi(struct dw_pcie_ep *ep, u8 func_no,
+ u32 reg, u8 val)
+{
+ dw_pcie_ep_write_dbi(ep, func_no, reg, 0x1, val);
+}
+
+static inline u8 dw_pcie_ep_readb_dbi(struct dw_pcie_ep *ep, u8 func_no,
+ u32 reg)
+{
+ return dw_pcie_ep_read_dbi(ep, func_no, reg, 0x1);
+}
+
+static inline unsigned int dw_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep,
+ u8 func_no)
+{
+ unsigned int dbi2_offset = 0;
+
+ if (ep->ops->get_dbi2_offset)
+ dbi2_offset = ep->ops->get_dbi2_offset(ep, func_no);
+ else if (ep->ops->get_dbi_offset) /* for backward compatibility */
+ dbi2_offset = ep->ops->get_dbi_offset(ep, func_no);
+
+ return dbi2_offset;
+}
+
+static inline void dw_pcie_ep_write_dbi2(struct dw_pcie_ep *ep, u8 func_no,
+ u32 reg, size_t size, u32 val)
+{
+ unsigned int offset = dw_pcie_ep_get_dbi2_offset(ep, func_no);
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+
+ dw_pcie_write_dbi2(pci, offset + reg, size, val);
+}
+
+static inline void dw_pcie_ep_writel_dbi2(struct dw_pcie_ep *ep, u8 func_no,
+ u32 reg, u32 val)
+{
+ dw_pcie_ep_write_dbi2(ep, func_no, reg, 0x4, val);
+}
+
static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
{
u32 reg;
@@ -580,7 +673,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep);
int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep);
void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep);
void dw_pcie_ep_exit(struct dw_pcie_ep *ep);
-int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no);
+int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no);
int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
u8 interrupt_num);
int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
@@ -613,7 +706,7 @@ static inline void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
{
}
-static inline int dw_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep, u8 func_no)
+static inline int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no)
{
return 0;
}
diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
index 2fe42c70097f..d6842141d384 100644
--- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c
+++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c
@@ -72,7 +72,7 @@ static void rockchip_pcie_writel_apb(struct rockchip_pcie *rockchip,
writel_relaxed(val, rockchip->apb_base + reg);
}
-static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc)
+static void rockchip_pcie_intx_handler(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct rockchip_pcie *rockchip = irq_desc_get_handler_data(desc);
@@ -202,7 +202,7 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
if (ret < 0)
dev_err(dev, "failed to init irq domain\n");
- irq_set_chained_handler_and_data(irq, rockchip_pcie_legacy_int_handler,
+ irq_set_chained_handler_and_data(irq, rockchip_pcie_intx_handler,
rockchip);
/* LTSSM enable control mode */
@@ -215,7 +215,7 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops rockchip_pcie_host_ops = {
- .host_init = rockchip_pcie_host_init,
+ .init = rockchip_pcie_host_init,
};
static int rockchip_pcie_clk_init(struct rockchip_pcie *rockchip)
diff --git a/drivers/pci/controller/dwc/pcie-fu740.c b/drivers/pci/controller/dwc/pcie-fu740.c
index 1e9b44b8bba4..66367252032b 100644
--- a/drivers/pci/controller/dwc/pcie-fu740.c
+++ b/drivers/pci/controller/dwc/pcie-fu740.c
@@ -279,7 +279,7 @@ static int fu740_pcie_host_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops fu740_pcie_host_ops = {
- .host_init = fu740_pcie_host_init,
+ .init = fu740_pcie_host_init,
};
static const struct dw_pcie_ops dw_pcie_ops = {
diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c
index fd484cc7c481..7a11c618b9d9 100644
--- a/drivers/pci/controller/dwc/pcie-histb.c
+++ b/drivers/pci/controller/dwc/pcie-histb.c
@@ -198,7 +198,7 @@ static int histb_pcie_host_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops histb_pcie_host_ops = {
- .host_init = histb_pcie_host_init,
+ .init = histb_pcie_host_init,
};
static void histb_pcie_host_disable(struct histb_pcie *hipcie)
diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
index c9c93524e01d..acbe4f6d3291 100644
--- a/drivers/pci/controller/dwc/pcie-intel-gw.c
+++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
@@ -391,7 +391,7 @@ static const struct dw_pcie_ops intel_pcie_ops = {
};
static const struct dw_pcie_host_ops intel_pcie_dw_ops = {
- .host_init = intel_pcie_rc_init,
+ .init = intel_pcie_rc_init,
};
static int intel_pcie_probe(struct platform_device *pdev)
diff --git a/drivers/pci/controller/dwc/pcie-keembay.c b/drivers/pci/controller/dwc/pcie-keembay.c
index 289bff99d762..208d3b0ba196 100644
--- a/drivers/pci/controller/dwc/pcie-keembay.c
+++ b/drivers/pci/controller/dwc/pcie-keembay.c
@@ -289,19 +289,18 @@ static void keembay_pcie_ep_init(struct dw_pcie_ep *ep)
}
static int keembay_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type,
- u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
- /* Legacy interrupts are not supported in Keem Bay */
- dev_err(pci->dev, "Legacy IRQ is not supported\n");
+ case PCI_IRQ_INTX:
+ /* INTx interrupts are not supported in Keem Bay */
+ dev_err(pci->dev, "INTx IRQ is not supported\n");
return -EINVAL;
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_MSI:
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
- case PCI_EPC_IRQ_MSIX:
+ case PCI_IRQ_MSIX:
return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
default:
dev_err(pci->dev, "Unknown IRQ type %d\n", type);
@@ -325,7 +324,7 @@ keembay_pcie_get_features(struct dw_pcie_ep *ep)
}
static const struct dw_pcie_ep_ops keembay_pcie_ep_ops = {
- .ep_init = keembay_pcie_ep_init,
+ .init = keembay_pcie_ep_init,
.raise_irq = keembay_pcie_ep_raise_irq,
.get_features = keembay_pcie_get_features,
};
diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
index 2ee146767971..d5523f302102 100644
--- a/drivers/pci/controller/dwc/pcie-kirin.c
+++ b/drivers/pci/controller/dwc/pcie-kirin.c
@@ -366,7 +366,6 @@ static int kirin_pcie_get_gpio_enable(struct kirin_pcie *pcie,
struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- char name[32];
int ret, i;
/* This is an optional property */
@@ -387,9 +386,8 @@ static int kirin_pcie_get_gpio_enable(struct kirin_pcie *pcie,
if (pcie->gpio_id_clkreq[i] < 0)
return pcie->gpio_id_clkreq[i];
- sprintf(name, "pcie_clkreq_%d", i);
- pcie->clkreq_names[i] = devm_kstrdup_const(dev, name,
- GFP_KERNEL);
+ pcie->clkreq_names[i] = devm_kasprintf(dev, GFP_KERNEL,
+ "pcie_clkreq_%d", i);
if (!pcie->clkreq_names[i])
return -ENOMEM;
}
@@ -404,7 +402,6 @@ static int kirin_pcie_parse_port(struct kirin_pcie *pcie,
struct device *dev = &pdev->dev;
struct device_node *parent, *child;
int ret, slot, i;
- char name[32];
for_each_available_child_of_node(node, parent) {
for_each_available_child_of_node(parent, child) {
@@ -430,9 +427,9 @@ static int kirin_pcie_parse_port(struct kirin_pcie *pcie,
slot = PCI_SLOT(ret);
- sprintf(name, "pcie_perst_%d", slot);
- pcie->reset_names[i] = devm_kstrdup_const(dev, name,
- GFP_KERNEL);
+ pcie->reset_names[i] = devm_kasprintf(dev, GFP_KERNEL,
+ "pcie_perst_%d",
+ slot);
if (!pcie->reset_names[i]) {
ret = -ENOMEM;
goto put_node;
@@ -672,7 +669,7 @@ static const struct dw_pcie_ops kirin_dw_pcie_ops = {
};
static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
- .host_init = kirin_pcie_host_init,
+ .init = kirin_pcie_host_init,
};
static int kirin_pcie_power_off(struct kirin_pcie *kirin_pcie)
@@ -741,15 +738,13 @@ err:
return ret;
}
-static int kirin_pcie_remove(struct platform_device *pdev)
+static void kirin_pcie_remove(struct platform_device *pdev)
{
struct kirin_pcie *kirin_pcie = platform_get_drvdata(pdev);
dw_pcie_host_deinit(&kirin_pcie->pci->pp);
kirin_pcie_power_off(kirin_pcie);
-
- return 0;
}
struct kirin_pcie_data {
@@ -818,7 +813,7 @@ static int kirin_pcie_probe(struct platform_device *pdev)
static struct platform_driver kirin_pcie_driver = {
.probe = kirin_pcie_probe,
- .remove = kirin_pcie_remove,
+ .remove_new = kirin_pcie_remove,
.driver = {
.name = "kirin-pcie",
.of_match_table = kirin_pcie_match,
diff --git a/drivers/pci/controller/dwc/pcie-qcom-ep.c b/drivers/pci/controller/dwc/pcie-qcom-ep.c
index 9e58f055199a..36e5e80cd22f 100644
--- a/drivers/pci/controller/dwc/pcie-qcom-ep.c
+++ b/drivers/pci/controller/dwc/pcie-qcom-ep.c
@@ -726,14 +726,14 @@ static int qcom_pcie_ep_enable_irq_resources(struct platform_device *pdev,
}
static int qcom_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type, u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
- return dw_pcie_ep_raise_legacy_irq(ep, func_no);
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_INTX:
+ return dw_pcie_ep_raise_intx_irq(ep, func_no);
+ case PCI_IRQ_MSI:
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
default:
dev_err(pci->dev, "Unknown IRQ type\n");
@@ -796,7 +796,7 @@ static void qcom_pcie_ep_init(struct dw_pcie_ep *ep)
}
static const struct dw_pcie_ep_ops pci_ep_ops = {
- .ep_init = qcom_pcie_ep_init,
+ .init = qcom_pcie_ep_init,
.raise_irq = qcom_pcie_ep_raise_irq,
.get_features = qcom_pcie_epc_get_features,
};
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 11c80555d975..10f2d0bb86be 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -1247,9 +1247,9 @@ static void qcom_pcie_host_post_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops qcom_pcie_dw_ops = {
- .host_init = qcom_pcie_host_init,
- .host_deinit = qcom_pcie_host_deinit,
- .host_post_init = qcom_pcie_host_post_init,
+ .init = qcom_pcie_host_init,
+ .deinit = qcom_pcie_host_deinit,
+ .post_init = qcom_pcie_host_post_init,
};
/* Qcom IP rev.: 2.1.0 Synopsys IP rev.: 4.01a */
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 3bc45e513b3d..e9166619b1f9 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -8,7 +8,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -307,8 +307,8 @@ static void rcar_gen4_pcie_host_deinit(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops rcar_gen4_pcie_host_ops = {
- .host_init = rcar_gen4_pcie_host_init,
- .host_deinit = rcar_gen4_pcie_host_deinit,
+ .init = rcar_gen4_pcie_host_init,
+ .deinit = rcar_gen4_pcie_host_deinit,
};
static int rcar_gen4_add_dw_pcie_rp(struct rcar_gen4_pcie *rcar)
@@ -362,15 +362,14 @@ static void rcar_gen4_pcie_ep_deinit(struct dw_pcie_ep *ep)
}
static int rcar_gen4_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type,
- u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct dw_pcie *dw = to_dw_pcie_from_ep(ep);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
- return dw_pcie_ep_raise_legacy_irq(ep, func_no);
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_INTX:
+ return dw_pcie_ep_raise_intx_irq(ep, func_no);
+ case PCI_IRQ_MSI:
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
default:
dev_err(dw->dev, "Unknown IRQ type\n");
@@ -394,7 +393,7 @@ rcar_gen4_pcie_ep_get_features(struct dw_pcie_ep *ep)
return &rcar_gen4_pcie_epc_features;
}
-static unsigned int rcar_gen4_pcie_ep_func_conf_select(struct dw_pcie_ep *ep,
+static unsigned int rcar_gen4_pcie_ep_get_dbi_offset(struct dw_pcie_ep *ep,
u8 func_no)
{
return func_no * RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET;
@@ -408,11 +407,11 @@ static unsigned int rcar_gen4_pcie_ep_get_dbi2_offset(struct dw_pcie_ep *ep,
static const struct dw_pcie_ep_ops pcie_ep_ops = {
.pre_init = rcar_gen4_pcie_ep_pre_init,
- .ep_init = rcar_gen4_pcie_ep_init,
+ .init = rcar_gen4_pcie_ep_init,
.deinit = rcar_gen4_pcie_ep_deinit,
.raise_irq = rcar_gen4_pcie_ep_raise_irq,
.get_features = rcar_gen4_pcie_ep_get_features,
- .func_conf_select = rcar_gen4_pcie_ep_func_conf_select,
+ .get_dbi_offset = rcar_gen4_pcie_ep_get_dbi_offset,
.get_dbi2_offset = rcar_gen4_pcie_ep_get_dbi2_offset,
};
@@ -436,7 +435,7 @@ static void rcar_gen4_remove_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
/* Common */
static int rcar_gen4_add_dw_pcie(struct rcar_gen4_pcie *rcar)
{
- rcar->mode = (enum dw_pcie_device_mode)of_device_get_match_data(&rcar->pdev->dev);
+ rcar->mode = (uintptr_t)of_device_get_match_data(&rcar->pdev->dev);
switch (rcar->mode) {
case DW_PCIE_RC_TYPE:
diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c
index 99d47ae80331..201dced209f0 100644
--- a/drivers/pci/controller/dwc/pcie-spear13xx.c
+++ b/drivers/pci/controller/dwc/pcie-spear13xx.c
@@ -148,7 +148,7 @@ static int spear13xx_pcie_host_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops spear13xx_pcie_host_ops = {
- .host_init = spear13xx_pcie_host_init,
+ .init = spear13xx_pcie_host_init,
};
static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie,
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
index 0fe113598ebb..7afa9e9aabe2 100644
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
@@ -773,13 +773,13 @@ static void tegra_pcie_enable_system_interrupts(struct dw_pcie_rp *pp)
val_w);
}
-static void tegra_pcie_enable_legacy_interrupts(struct dw_pcie_rp *pp)
+static void tegra_pcie_enable_intx_interrupts(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
u32 val;
- /* Enable legacy interrupt generation */
+ /* Enable INTX interrupt generation */
val = appl_readl(pcie, APPL_INTR_EN_L0_0);
val |= APPL_INTR_EN_L0_0_SYS_INTR_EN;
val |= APPL_INTR_EN_L0_0_INT_INT_EN;
@@ -830,7 +830,7 @@ static void tegra_pcie_enable_interrupts(struct dw_pcie_rp *pp)
appl_writel(pcie, 0xFFFFFFFF, APPL_INTR_STATUS_L1_17);
tegra_pcie_enable_system_interrupts(pp);
- tegra_pcie_enable_legacy_interrupts(pp);
+ tegra_pcie_enable_intx_interrupts(pp);
if (IS_ENABLED(CONFIG_PCI_MSI))
tegra_pcie_enable_msi_interrupts(pp);
}
@@ -1060,7 +1060,7 @@ static const struct dw_pcie_ops tegra_dw_pcie_ops = {
};
static const struct dw_pcie_host_ops tegra_pcie_dw_host_ops = {
- .host_init = tegra_pcie_dw_host_init,
+ .init = tegra_pcie_dw_host_init,
};
static void tegra_pcie_disable_phy(struct tegra_pcie_dw *pcie)
@@ -1947,7 +1947,7 @@ static irqreturn_t tegra_pcie_ep_pex_rst_irq(int irq, void *arg)
return IRQ_HANDLED;
}
-static int tegra_pcie_ep_raise_legacy_irq(struct tegra_pcie_dw *pcie, u16 irq)
+static int tegra_pcie_ep_raise_intx_irq(struct tegra_pcie_dw *pcie, u16 irq)
{
/* Tegra194 supports only INTA */
if (irq > 1)
@@ -1979,20 +1979,19 @@ static int tegra_pcie_ep_raise_msix_irq(struct tegra_pcie_dw *pcie, u16 irq)
}
static int tegra_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type,
- u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
- return tegra_pcie_ep_raise_legacy_irq(pcie, interrupt_num);
+ case PCI_IRQ_INTX:
+ return tegra_pcie_ep_raise_intx_irq(pcie, interrupt_num);
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_MSI:
return tegra_pcie_ep_raise_msi_irq(pcie, interrupt_num);
- case PCI_EPC_IRQ_MSIX:
+ case PCI_IRQ_MSIX:
return tegra_pcie_ep_raise_msix_irq(pcie, interrupt_num);
default:
diff --git a/drivers/pci/controller/dwc/pcie-uniphier-ep.c b/drivers/pci/controller/dwc/pcie-uniphier-ep.c
index cba3c88fcf39..3fced0d3e851 100644
--- a/drivers/pci/controller/dwc/pcie-uniphier-ep.c
+++ b/drivers/pci/controller/dwc/pcie-uniphier-ep.c
@@ -212,7 +212,7 @@ static void uniphier_pcie_ep_init(struct dw_pcie_ep *ep)
dw_pcie_ep_reset_bar(pci, bar);
}
-static int uniphier_pcie_ep_raise_legacy_irq(struct dw_pcie_ep *ep)
+static int uniphier_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
struct uniphier_pcie_ep_priv *priv = to_uniphier_pcie(pci);
@@ -256,15 +256,14 @@ static int uniphier_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep,
}
static int uniphier_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
- enum pci_epc_irq_type type,
- u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
- return uniphier_pcie_ep_raise_legacy_irq(ep);
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_INTX:
+ return uniphier_pcie_ep_raise_intx_irq(ep);
+ case PCI_IRQ_MSI:
return uniphier_pcie_ep_raise_msi_irq(ep, func_no,
interrupt_num);
default:
@@ -284,7 +283,7 @@ uniphier_pcie_get_features(struct dw_pcie_ep *ep)
}
static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = {
- .ep_init = uniphier_pcie_ep_init,
+ .init = uniphier_pcie_ep_init,
.raise_irq = uniphier_pcie_ep_raise_irq,
.get_features = uniphier_pcie_get_features,
};
diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c
index 48c3eba817b4..5757ca3803c9 100644
--- a/drivers/pci/controller/dwc/pcie-uniphier.c
+++ b/drivers/pci/controller/dwc/pcie-uniphier.c
@@ -67,7 +67,7 @@ struct uniphier_pcie {
struct clk *clk;
struct reset_control *rst;
struct phy *phy;
- struct irq_domain *legacy_irq_domain;
+ struct irq_domain *intx_irq_domain;
};
#define to_uniphier_pcie(x) dev_get_drvdata((x)->dev)
@@ -253,12 +253,12 @@ static void uniphier_pcie_irq_handler(struct irq_desc *desc)
reg = FIELD_GET(PCL_RCV_INTX_ALL_STATUS, val);
for_each_set_bit(bit, &reg, PCI_NUM_INTX)
- generic_handle_domain_irq(pcie->legacy_irq_domain, bit);
+ generic_handle_domain_irq(pcie->intx_irq_domain, bit);
chained_irq_exit(chip, desc);
}
-static int uniphier_pcie_config_legacy_irq(struct dw_pcie_rp *pp)
+static int uniphier_pcie_config_intx_irq(struct dw_pcie_rp *pp)
{
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct uniphier_pcie *pcie = to_uniphier_pcie(pci);
@@ -279,9 +279,9 @@ static int uniphier_pcie_config_legacy_irq(struct dw_pcie_rp *pp)
goto out_put_node;
}
- pcie->legacy_irq_domain = irq_domain_add_linear(np_intc, PCI_NUM_INTX,
+ pcie->intx_irq_domain = irq_domain_add_linear(np_intc, PCI_NUM_INTX,
&uniphier_intx_domain_ops, pp);
- if (!pcie->legacy_irq_domain) {
+ if (!pcie->intx_irq_domain) {
dev_err(pci->dev, "Failed to get INTx domain\n");
ret = -ENODEV;
goto out_put_node;
@@ -301,7 +301,7 @@ static int uniphier_pcie_host_init(struct dw_pcie_rp *pp)
struct uniphier_pcie *pcie = to_uniphier_pcie(pci);
int ret;
- ret = uniphier_pcie_config_legacy_irq(pp);
+ ret = uniphier_pcie_config_intx_irq(pp);
if (ret)
return ret;
@@ -311,7 +311,7 @@ static int uniphier_pcie_host_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops uniphier_pcie_host_ops = {
- .host_init = uniphier_pcie_host_init,
+ .init = uniphier_pcie_host_init,
};
static int uniphier_pcie_host_enable(struct uniphier_pcie *pcie)
diff --git a/drivers/pci/controller/dwc/pcie-visconti.c b/drivers/pci/controller/dwc/pcie-visconti.c
index 71026fefa366..318c278e65c8 100644
--- a/drivers/pci/controller/dwc/pcie-visconti.c
+++ b/drivers/pci/controller/dwc/pcie-visconti.c
@@ -236,7 +236,7 @@ static int visconti_pcie_host_init(struct dw_pcie_rp *pp)
}
static const struct dw_pcie_host_ops visconti_pcie_host_ops = {
- .host_init = visconti_pcie_host_init,
+ .init = visconti_pcie_host_init,
};
static int visconti_get_resources(struct platform_device *pdev,
diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c
index 6be3266cd7b5..45b71806182d 100644
--- a/drivers/pci/controller/pci-host-common.c
+++ b/drivers/pci/controller/pci-host-common.c
@@ -85,7 +85,7 @@ int pci_host_common_probe(struct platform_device *pdev)
}
EXPORT_SYMBOL_GPL(pci_host_common_probe);
-int pci_host_common_remove(struct platform_device *pdev)
+void pci_host_common_remove(struct platform_device *pdev)
{
struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
@@ -93,8 +93,6 @@ int pci_host_common_remove(struct platform_device *pdev)
pci_stop_root_bus(bridge->bus);
pci_remove_root_bus(bridge->bus);
pci_unlock_rescan_remove();
-
- return 0;
}
EXPORT_SYMBOL_GPL(pci_host_common_remove);
diff --git a/drivers/pci/controller/pci-host-generic.c b/drivers/pci/controller/pci-host-generic.c
index 63865aeb636b..41cb6a057f6e 100644
--- a/drivers/pci/controller/pci-host-generic.c
+++ b/drivers/pci/controller/pci-host-generic.c
@@ -82,7 +82,7 @@ static struct platform_driver gen_pci_driver = {
.of_match_table = gen_pci_of_match,
},
.probe = pci_host_common_probe,
- .remove = pci_host_common_remove,
+ .remove_new = pci_host_common_remove,
};
module_platform_driver(gen_pci_driver);
diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
index f9dd6622fe10..5b0730c3891b 100644
--- a/drivers/pci/controller/pcie-brcmstb.c
+++ b/drivers/pci/controller/pcie-brcmstb.c
@@ -48,6 +48,9 @@
#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY 0x04dc
#define PCIE_RC_CFG_PRIV1_LINK_CAPABILITY_ASPM_SUPPORT_MASK 0xc00
+#define PCIE_RC_CFG_PRIV1_ROOT_CAP 0x4f8
+#define PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK 0xf8
+
#define PCIE_RC_DL_MDIO_ADDR 0x1100
#define PCIE_RC_DL_MDIO_WR_DATA 0x1104
#define PCIE_RC_DL_MDIO_RD_DATA 0x1108
@@ -121,9 +124,12 @@
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2
+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK 0x200000
#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000
#define PCIE_BMIPS_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x00800000
-
+#define PCIE_CLKREQ_MASK \
+ (PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK | \
+ PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK)
#define PCIE_INTR2_CPU_BASE 0x4300
#define PCIE_MSI_INTR2_BASE 0x4500
@@ -1028,13 +1034,89 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
return 0;
}
+/*
+ * This extends the timeout period for an access to an internal bus. This
+ * access timeout may occur during L1SS sleep periods, even without the
+ * presence of a PCIe access.
+ */
+static void brcm_extend_rbus_timeout(struct brcm_pcie *pcie)
+{
+ /* TIMEOUT register is two registers before RGR1_SW_INIT_1 */
+ const unsigned int REG_OFFSET = PCIE_RGR1_SW_INIT_1(pcie) - 8;
+ u32 timeout_us = 4000000; /* 4 seconds, our setting for L1SS */
+
+ /* Each unit in timeout register is 1/216,000,000 seconds */
+ writel(216 * timeout_us, pcie->base + REG_OFFSET);
+}
+
+static void brcm_config_clkreq(struct brcm_pcie *pcie)
+{
+ static const char err_msg[] = "invalid 'brcm,clkreq-mode' DT string\n";
+ const char *mode = "default";
+ u32 clkreq_cntl;
+ int ret, tmp;
+
+ ret = of_property_read_string(pcie->np, "brcm,clkreq-mode", &mode);
+ if (ret && ret != -EINVAL) {
+ dev_err(pcie->dev, err_msg);
+ mode = "safe";
+ }
+
+ /* Start out assuming safe mode (both mode bits cleared) */
+ clkreq_cntl = readl(pcie->base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
+ clkreq_cntl &= ~PCIE_CLKREQ_MASK;
+
+ if (strcmp(mode, "no-l1ss") == 0) {
+ /*
+ * "no-l1ss" -- Provides Clock Power Management, L0s, and
+ * L1, but cannot provide L1 substate (L1SS) power
+ * savings. If the downstream device connected to the RC is
+ * L1SS capable AND the OS enables L1SS, all PCIe traffic
+ * may abruptly halt, potentially hanging the system.
+ */
+ clkreq_cntl |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
+ /*
+ * We want to un-advertise L1 substates because if the OS
+ * tries to configure the controller into using L1 substate
+ * power savings it may fail or hang when the RC HW is in
+ * "no-l1ss" mode.
+ */
+ tmp = readl(pcie->base + PCIE_RC_CFG_PRIV1_ROOT_CAP);
+ u32p_replace_bits(&tmp, 2, PCIE_RC_CFG_PRIV1_ROOT_CAP_L1SS_MODE_MASK);
+ writel(tmp, pcie->base + PCIE_RC_CFG_PRIV1_ROOT_CAP);
+
+ } else if (strcmp(mode, "default") == 0) {
+ /*
+ * "default" -- Provides L0s, L1, and L1SS, but not
+ * compliant to provide Clock Power Management;
+ * specifically, may not be able to meet the Tclron max
+ * timing of 400ns as specified in "Dynamic Clock Control",
+ * section 3.2.5.2.2 of the PCIe spec. This situation is
+ * atypical and should happen only with older devices.
+ */
+ clkreq_cntl |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_L1SS_ENABLE_MASK;
+ brcm_extend_rbus_timeout(pcie);
+
+ } else {
+ /*
+ * "safe" -- No power savings; refclk is driven by RC
+ * unconditionally.
+ */
+ if (strcmp(mode, "safe") != 0)
+ dev_err(pcie->dev, err_msg);
+ mode = "safe";
+ }
+ writel(clkreq_cntl, pcie->base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
+
+ dev_info(pcie->dev, "clkreq-mode set to %s\n", mode);
+}
+
static int brcm_pcie_start_link(struct brcm_pcie *pcie)
{
struct device *dev = pcie->dev;
void __iomem *base = pcie->base;
u16 nlw, cls, lnksta;
bool ssc_good = false;
- u32 tmp;
int ret, i;
/* Unassert the fundamental reset */
@@ -1059,6 +1141,8 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie)
return -ENODEV;
}
+ brcm_config_clkreq(pcie);
+
if (pcie->gen)
brcm_pcie_set_gen(pcie, pcie->gen);
@@ -1077,14 +1161,6 @@ static int brcm_pcie_start_link(struct brcm_pcie *pcie)
pci_speed_string(pcie_link_speed[cls]), nlw,
ssc_good ? "(SSC)" : "(!SSC)");
- /*
- * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1
- * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1.
- */
- tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
- tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK;
- writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG);
-
return 0;
}
diff --git a/drivers/pci/controller/pcie-iproc-platform.c b/drivers/pci/controller/pcie-iproc-platform.c
index acdc583d2980..4e6aa882a567 100644
--- a/drivers/pci/controller/pcie-iproc-platform.c
+++ b/drivers/pci/controller/pcie-iproc-platform.c
@@ -52,7 +52,7 @@ static int iproc_pltfm_pcie_probe(struct platform_device *pdev)
pcie = pci_host_bridge_priv(bridge);
pcie->dev = dev;
- pcie->type = (enum iproc_pcie_type) of_device_get_match_data(dev);
+ pcie->type = (uintptr_t)of_device_get_match_data(dev);
ret = of_address_to_resource(np, 0, &reg);
if (ret < 0) {
diff --git a/drivers/pci/controller/pcie-mediatek-gen3.c b/drivers/pci/controller/pcie-mediatek-gen3.c
index e0e27645fdf4..975b3024fb08 100644
--- a/drivers/pci/controller/pcie-mediatek-gen3.c
+++ b/drivers/pci/controller/pcie-mediatek-gen3.c
@@ -245,35 +245,60 @@ static int mtk_pcie_set_trans_table(struct mtk_gen3_pcie *pcie,
resource_size_t cpu_addr,
resource_size_t pci_addr,
resource_size_t size,
- unsigned long type, int num)
+ unsigned long type, int *num)
{
+ resource_size_t remaining = size;
+ resource_size_t table_size;
+ resource_size_t addr_align;
+ const char *range_type;
void __iomem *table;
u32 val;
- if (num >= PCIE_MAX_TRANS_TABLES) {
- dev_err(pcie->dev, "not enough translate table for addr: %#llx, limited to [%d]\n",
- (unsigned long long)cpu_addr, PCIE_MAX_TRANS_TABLES);
- return -ENODEV;
- }
+ while (remaining && (*num < PCIE_MAX_TRANS_TABLES)) {
+ /* Table size needs to be a power of 2 */
+ table_size = BIT(fls(remaining) - 1);
+
+ if (cpu_addr > 0) {
+ addr_align = BIT(ffs(cpu_addr) - 1);
+ table_size = min(table_size, addr_align);
+ }
+
+ /* Minimum size of translate table is 4KiB */
+ if (table_size < 0x1000) {
+ dev_err(pcie->dev, "illegal table size %#llx\n",
+ (unsigned long long)table_size);
+ return -EINVAL;
+ }
- table = pcie->base + PCIE_TRANS_TABLE_BASE_REG +
- num * PCIE_ATR_TLB_SET_OFFSET;
+ table = pcie->base + PCIE_TRANS_TABLE_BASE_REG + *num * PCIE_ATR_TLB_SET_OFFSET;
+ writel_relaxed(lower_32_bits(cpu_addr) | PCIE_ATR_SIZE(fls(table_size) - 1), table);
+ writel_relaxed(upper_32_bits(cpu_addr), table + PCIE_ATR_SRC_ADDR_MSB_OFFSET);
+ writel_relaxed(lower_32_bits(pci_addr), table + PCIE_ATR_TRSL_ADDR_LSB_OFFSET);
+ writel_relaxed(upper_32_bits(pci_addr), table + PCIE_ATR_TRSL_ADDR_MSB_OFFSET);
- writel_relaxed(lower_32_bits(cpu_addr) | PCIE_ATR_SIZE(fls(size) - 1),
- table);
- writel_relaxed(upper_32_bits(cpu_addr),
- table + PCIE_ATR_SRC_ADDR_MSB_OFFSET);
- writel_relaxed(lower_32_bits(pci_addr),
- table + PCIE_ATR_TRSL_ADDR_LSB_OFFSET);
- writel_relaxed(upper_32_bits(pci_addr),
- table + PCIE_ATR_TRSL_ADDR_MSB_OFFSET);
+ if (type == IORESOURCE_IO) {
+ val = PCIE_ATR_TYPE_IO | PCIE_ATR_TLP_TYPE_IO;
+ range_type = "IO";
+ } else {
+ val = PCIE_ATR_TYPE_MEM | PCIE_ATR_TLP_TYPE_MEM;
+ range_type = "MEM";
+ }
- if (type == IORESOURCE_IO)
- val = PCIE_ATR_TYPE_IO | PCIE_ATR_TLP_TYPE_IO;
- else
- val = PCIE_ATR_TYPE_MEM | PCIE_ATR_TLP_TYPE_MEM;
+ writel_relaxed(val, table + PCIE_ATR_TRSL_PARAM_OFFSET);
- writel_relaxed(val, table + PCIE_ATR_TRSL_PARAM_OFFSET);
+ dev_dbg(pcie->dev, "set %s trans window[%d]: cpu_addr = %#llx, pci_addr = %#llx, size = %#llx\n",
+ range_type, *num, (unsigned long long)cpu_addr,
+ (unsigned long long)pci_addr, (unsigned long long)table_size);
+
+ cpu_addr += table_size;
+ pci_addr += table_size;
+ remaining -= table_size;
+ (*num)++;
+ }
+
+ if (remaining)
+ dev_warn(pcie->dev, "not enough translate table for addr: %#llx, limited to [%d]\n",
+ (unsigned long long)cpu_addr, PCIE_MAX_TRANS_TABLES);
return 0;
}
@@ -380,30 +405,20 @@ static int mtk_pcie_startup_port(struct mtk_gen3_pcie *pcie)
resource_size_t cpu_addr;
resource_size_t pci_addr;
resource_size_t size;
- const char *range_type;
- if (type == IORESOURCE_IO) {
+ if (type == IORESOURCE_IO)
cpu_addr = pci_pio_to_address(res->start);
- range_type = "IO";
- } else if (type == IORESOURCE_MEM) {
+ else if (type == IORESOURCE_MEM)
cpu_addr = res->start;
- range_type = "MEM";
- } else {
+ else
continue;
- }
pci_addr = res->start - entry->offset;
size = resource_size(res);
err = mtk_pcie_set_trans_table(pcie, cpu_addr, pci_addr, size,
- type, table_index);
+ type, &table_index);
if (err)
return err;
-
- dev_dbg(pcie->dev, "set %s trans window[%d]: cpu_addr = %#llx, pci_addr = %#llx, size = %#llx\n",
- range_type, table_index, (unsigned long long)cpu_addr,
- (unsigned long long)pci_addr, (unsigned long long)size);
-
- table_index++;
}
return 0;
diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c
index 66a8f73296fc..48372013f26d 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -617,12 +617,18 @@ static void mtk_pcie_intr_handler(struct irq_desc *desc)
if (status & MSI_STATUS){
unsigned long imsi_status;
+ /*
+ * The interrupt status can be cleared even if the
+ * MSI status remains pending. As such, given the
+ * edge-triggered interrupt type, its status should
+ * be cleared before being dispatched to the
+ * handler of the underlying device.
+ */
+ writel(MSI_STATUS, port->base + PCIE_INT_STATUS);
while ((imsi_status = readl(port->base + PCIE_IMSI_STATUS))) {
for_each_set_bit(bit, &imsi_status, MTK_MSI_IRQS_NUM)
generic_handle_domain_irq(port->inner_domain, bit);
}
- /* Clear MSI interrupt status */
- writel(MSI_STATUS, port->base + PCIE_INT_STATUS);
}
}
diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c
index 7034c0ff23d0..e6909271def7 100644
--- a/drivers/pci/controller/pcie-rcar-ep.c
+++ b/drivers/pci/controller/pcie-rcar-ep.c
@@ -402,16 +402,15 @@ static int rcar_pcie_ep_assert_msi(struct rcar_pcie *pcie,
}
static int rcar_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, u8 vfn,
- enum pci_epc_irq_type type,
- u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
+ case PCI_IRQ_INTX:
return rcar_pcie_ep_assert_intx(ep, fn, 0);
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_MSI:
return rcar_pcie_ep_assert_msi(&ep->pcie, fn, interrupt_num);
default:
diff --git a/drivers/pci/controller/pcie-rcar-host.c b/drivers/pci/controller/pcie-rcar-host.c
index bf7cc0b6a695..996077ab7cfd 100644
--- a/drivers/pci/controller/pcie-rcar-host.c
+++ b/drivers/pci/controller/pcie-rcar-host.c
@@ -29,6 +29,7 @@
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include "pcie-rcar.h"
@@ -953,14 +954,22 @@ static const struct of_device_id rcar_pcie_of_match[] = {
{},
};
+/* Design note 346 from Linear Technology says order is not important. */
+static const char * const rcar_pcie_supplies[] = {
+ "vpcie1v5",
+ "vpcie3v3",
+ "vpcie12v",
+};
+
static int rcar_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct pci_host_bridge *bridge;
struct rcar_pcie_host *host;
struct rcar_pcie *pcie;
+ unsigned int i;
u32 data;
int err;
- struct pci_host_bridge *bridge;
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*host));
if (!bridge)
@@ -971,6 +980,13 @@ static int rcar_pcie_probe(struct platform_device *pdev)
pcie->dev = dev;
platform_set_drvdata(pdev, host);
+ for (i = 0; i < ARRAY_SIZE(rcar_pcie_supplies); i++) {
+ err = devm_regulator_get_enable_optional(dev, rcar_pcie_supplies[i]);
+ if (err < 0 && err != -ENODEV)
+ return dev_err_probe(dev, err, "failed to enable regulator: %s\n",
+ rcar_pcie_supplies[i]);
+ }
+
pm_runtime_enable(pcie->dev);
err = pm_runtime_get_sync(pcie->dev);
if (err < 0) {
diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
index 0af0e965fb57..c9046e97a1d2 100644
--- a/drivers/pci/controller/pcie-rockchip-ep.c
+++ b/drivers/pci/controller/pcie-rockchip-ep.c
@@ -26,16 +26,16 @@
* @max_regions: maximum number of regions supported by hardware
* @ob_region_map: bitmask of mapped outbound regions
* @ob_addr: base addresses in the AXI bus where the outbound regions start
- * @irq_phys_addr: base address on the AXI bus where the MSI/legacy IRQ
+ * @irq_phys_addr: base address on the AXI bus where the MSI/INTX IRQ
* dedicated outbound regions is mapped.
* @irq_cpu_addr: base address in the CPU space where a write access triggers
- * the sending of a memory write (MSI) / normal message (legacy
+ * the sending of a memory write (MSI) / normal message (INTX
* IRQ) TLP through the PCIe bus.
- * @irq_pci_addr: used to save the current mapping of the MSI/legacy IRQ
+ * @irq_pci_addr: used to save the current mapping of the MSI/INTX IRQ
* dedicated outbound region.
* @irq_pci_fn: the latest PCI function that has updated the mapping of
- * the MSI/legacy IRQ dedicated outbound region.
- * @irq_pending: bitmask of asserted legacy IRQs.
+ * the MSI/INTX IRQ dedicated outbound region.
+ * @irq_pending: bitmask of asserted INTX IRQs.
*/
struct rockchip_pcie_ep {
struct rockchip_pcie rockchip;
@@ -325,8 +325,8 @@ static void rockchip_pcie_ep_assert_intx(struct rockchip_pcie_ep *ep, u8 fn,
}
}
-static int rockchip_pcie_ep_send_legacy_irq(struct rockchip_pcie_ep *ep, u8 fn,
- u8 intx)
+static int rockchip_pcie_ep_send_intx_irq(struct rockchip_pcie_ep *ep, u8 fn,
+ u8 intx)
{
u16 cmd;
@@ -407,15 +407,14 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn,
}
static int rockchip_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, u8 vfn,
- enum pci_epc_irq_type type,
- u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
switch (type) {
- case PCI_EPC_IRQ_LEGACY:
- return rockchip_pcie_ep_send_legacy_irq(ep, fn, 0);
- case PCI_EPC_IRQ_MSI:
+ case PCI_IRQ_INTX:
+ return rockchip_pcie_ep_send_intx_irq(ep, fn, 0);
+ case PCI_IRQ_MSI:
return rockchip_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
default:
return -EINVAL;
diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c
index afbbdccd195d..300b9dc85ecc 100644
--- a/drivers/pci/controller/pcie-rockchip-host.c
+++ b/drivers/pci/controller/pcie-rockchip-host.c
@@ -505,7 +505,7 @@ static irqreturn_t rockchip_pcie_client_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
-static void rockchip_pcie_legacy_int_handler(struct irq_desc *desc)
+static void rockchip_pcie_intx_handler(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct rockchip_pcie *rockchip = irq_desc_get_handler_data(desc);
@@ -553,7 +553,7 @@ static int rockchip_pcie_setup_irq(struct rockchip_pcie *rockchip)
return irq;
irq_set_chained_handler_and_data(irq,
- rockchip_pcie_legacy_int_handler,
+ rockchip_pcie_intx_handler,
rockchip);
irq = platform_get_irq_byname(pdev, "client");
diff --git a/drivers/pci/controller/pcie-xilinx-dma-pl.c b/drivers/pci/controller/pcie-xilinx-dma-pl.c
index 2f7d676c683c..5be5dfd8398f 100644
--- a/drivers/pci/controller/pcie-xilinx-dma-pl.c
+++ b/drivers/pci/controller/pcie-xilinx-dma-pl.c
@@ -576,7 +576,7 @@ static int xilinx_pl_dma_pcie_init_irq_domain(struct pl_dma_pcie *port)
&intx_domain_ops, port);
if (!port->intx_domain) {
dev_err(dev, "Failed to get a INTx IRQ domain\n");
- return PTR_ERR(port->intx_domain);
+ return -ENOMEM;
}
irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED);
@@ -635,14 +635,14 @@ static int xilinx_pl_dma_pcie_setup_irq(struct pl_dma_pcie *port)
err = devm_request_irq(dev, port->intx_irq, xilinx_pl_dma_pcie_intx_flow,
IRQF_SHARED | IRQF_NO_THREAD, NULL, port);
if (err) {
- dev_err(dev, "Failed to request INTx IRQ %d\n", irq);
+ dev_err(dev, "Failed to request INTx IRQ %d\n", port->intx_irq);
return err;
}
err = devm_request_irq(dev, port->irq, xilinx_pl_dma_pcie_event_flow,
IRQF_SHARED | IRQF_NO_THREAD, NULL, port);
if (err) {
- dev_err(dev, "Failed to request event IRQ %d\n", irq);
+ dev_err(dev, "Failed to request event IRQ %d\n", port->irq);
return err;
}
@@ -684,10 +684,8 @@ static int xilinx_request_msi_irq(struct pl_dma_pcie *port)
int ret;
port->msi.irq_msi0 = platform_get_irq_byname(pdev, "msi0");
- if (port->msi.irq_msi0 <= 0) {
- dev_err(dev, "Unable to find msi0 IRQ line\n");
+ if (port->msi.irq_msi0 <= 0)
return port->msi.irq_msi0;
- }
ret = devm_request_irq(dev, port->msi.irq_msi0, xilinx_pl_dma_pcie_msi_handler_low,
IRQF_SHARED | IRQF_NO_THREAD, "xlnx-pcie-dma-pl",
@@ -698,10 +696,8 @@ static int xilinx_request_msi_irq(struct pl_dma_pcie *port)
}
port->msi.irq_msi1 = platform_get_irq_byname(pdev, "msi1");
- if (port->msi.irq_msi1 <= 0) {
- dev_err(dev, "Unable to find msi1 IRQ line\n");
+ if (port->msi.irq_msi1 <= 0)
return port->msi.irq_msi1;
- }
ret = devm_request_irq(dev, port->msi.irq_msi1, xilinx_pl_dma_pcie_msi_handler_high,
IRQF_SHARED | IRQF_NO_THREAD, "xlnx-pcie-dma-pl",
diff --git a/drivers/pci/controller/pcie-xilinx-nwl.c b/drivers/pci/controller/pcie-xilinx-nwl.c
index e307aceba5c9..0408f4d612b5 100644
--- a/drivers/pci/controller/pcie-xilinx-nwl.c
+++ b/drivers/pci/controller/pcie-xilinx-nwl.c
@@ -166,7 +166,7 @@ struct nwl_pcie {
int irq_intx;
int irq_misc;
struct nwl_msi msi;
- struct irq_domain *legacy_irq_domain;
+ struct irq_domain *intx_irq_domain;
struct clk *clk;
raw_spinlock_t leg_mask_lock;
};
@@ -324,7 +324,7 @@ static void nwl_pcie_leg_handler(struct irq_desc *desc)
while ((status = nwl_bridge_readl(pcie, MSGF_LEG_STATUS) &
MSGF_LEG_SR_MASKALL) != 0) {
for_each_set_bit(bit, &status, PCI_NUM_INTX)
- generic_handle_domain_irq(pcie->legacy_irq_domain, bit);
+ generic_handle_domain_irq(pcie->intx_irq_domain, bit);
}
chained_irq_exit(chip, desc);
@@ -364,7 +364,7 @@ static void nwl_pcie_msi_handler_low(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
-static void nwl_mask_leg_irq(struct irq_data *data)
+static void nwl_mask_intx_irq(struct irq_data *data)
{
struct nwl_pcie *pcie = irq_data_get_irq_chip_data(data);
unsigned long flags;
@@ -378,7 +378,7 @@ static void nwl_mask_leg_irq(struct irq_data *data)
raw_spin_unlock_irqrestore(&pcie->leg_mask_lock, flags);
}
-static void nwl_unmask_leg_irq(struct irq_data *data)
+static void nwl_unmask_intx_irq(struct irq_data *data)
{
struct nwl_pcie *pcie = irq_data_get_irq_chip_data(data);
unsigned long flags;
@@ -392,26 +392,26 @@ static void nwl_unmask_leg_irq(struct irq_data *data)
raw_spin_unlock_irqrestore(&pcie->leg_mask_lock, flags);
}
-static struct irq_chip nwl_leg_irq_chip = {
+static struct irq_chip nwl_intx_irq_chip = {
.name = "nwl_pcie:legacy",
- .irq_enable = nwl_unmask_leg_irq,
- .irq_disable = nwl_mask_leg_irq,
- .irq_mask = nwl_mask_leg_irq,
- .irq_unmask = nwl_unmask_leg_irq,
+ .irq_enable = nwl_unmask_intx_irq,
+ .irq_disable = nwl_mask_intx_irq,
+ .irq_mask = nwl_mask_intx_irq,
+ .irq_unmask = nwl_unmask_intx_irq,
};
-static int nwl_legacy_map(struct irq_domain *domain, unsigned int irq,
- irq_hw_number_t hwirq)
+static int nwl_intx_map(struct irq_domain *domain, unsigned int irq,
+ irq_hw_number_t hwirq)
{
- irq_set_chip_and_handler(irq, &nwl_leg_irq_chip, handle_level_irq);
+ irq_set_chip_and_handler(irq, &nwl_intx_irq_chip, handle_level_irq);
irq_set_chip_data(irq, domain->host_data);
irq_set_status_flags(irq, IRQ_LEVEL);
return 0;
}
-static const struct irq_domain_ops legacy_domain_ops = {
- .map = nwl_legacy_map,
+static const struct irq_domain_ops intx_domain_ops = {
+ .map = nwl_intx_map,
.xlate = pci_irqd_intx_xlate,
};
@@ -525,20 +525,20 @@ static int nwl_pcie_init_irq_domain(struct nwl_pcie *pcie)
{
struct device *dev = pcie->dev;
struct device_node *node = dev->of_node;
- struct device_node *legacy_intc_node;
+ struct device_node *intc_node;
- legacy_intc_node = of_get_next_child(node, NULL);
- if (!legacy_intc_node) {
+ intc_node = of_get_next_child(node, NULL);
+ if (!intc_node) {
dev_err(dev, "No legacy intc node found\n");
return -EINVAL;
}
- pcie->legacy_irq_domain = irq_domain_add_linear(legacy_intc_node,
- PCI_NUM_INTX,
- &legacy_domain_ops,
- pcie);
- of_node_put(legacy_intc_node);
- if (!pcie->legacy_irq_domain) {
+ pcie->intx_irq_domain = irq_domain_add_linear(intc_node,
+ PCI_NUM_INTX,
+ &intx_domain_ops,
+ pcie);
+ of_node_put(intc_node);
+ if (!pcie->intx_irq_domain) {
dev_err(dev, "failed to create IRQ domain\n");
return -ENOMEM;
}
@@ -710,14 +710,14 @@ static int nwl_pcie_bridge_init(struct nwl_pcie *pcie)
/* Enable all misc interrupts */
nwl_bridge_writel(pcie, MSGF_MISC_SR_MASKALL, MSGF_MISC_MASK);
- /* Disable all legacy interrupts */
+ /* Disable all INTX interrupts */
nwl_bridge_writel(pcie, (u32)~MSGF_LEG_SR_MASKALL, MSGF_LEG_MASK);
- /* Clear pending legacy interrupts */
+ /* Clear pending INTX interrupts */
nwl_bridge_writel(pcie, nwl_bridge_readl(pcie, MSGF_LEG_STATUS) &
MSGF_LEG_SR_MASKALL, MSGF_LEG_STATUS);
- /* Enable all legacy interrupts */
+ /* Enable all INTX interrupts */
nwl_bridge_writel(pcie, MSGF_LEG_SR_MASKALL, MSGF_LEG_MASK);
/* Enable the bridge config interrupt */
diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
index 0452cbc362ee..87b7856f375a 100644
--- a/drivers/pci/controller/vmd.c
+++ b/drivers/pci/controller/vmd.c
@@ -984,7 +984,7 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
return -ENOMEM;
vmd->dev = dev;
- vmd->instance = ida_simple_get(&vmd_instance_ida, 0, 0, GFP_KERNEL);
+ vmd->instance = ida_alloc(&vmd_instance_ida, GFP_KERNEL);
if (vmd->instance < 0)
return vmd->instance;
@@ -1026,7 +1026,7 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id)
return 0;
out_release_instance:
- ida_simple_remove(&vmd_instance_ida, vmd->instance);
+ ida_free(&vmd_instance_ida, vmd->instance);
return err;
}
@@ -1048,7 +1048,7 @@ static void vmd_remove(struct pci_dev *dev)
vmd_cleanup_srcu(vmd);
vmd_detach_resources(vmd);
vmd_remove_irq_domain(vmd);
- ida_simple_remove(&vmd_instance_ida, vmd->instance);
+ ida_free(&vmd_instance_ida, vmd->instance);
}
static void vmd_shutdown(struct pci_dev *dev)
diff --git a/drivers/pci/endpoint/functions/pci-epf-mhi.c b/drivers/pci/endpoint/functions/pci-epf-mhi.c
index b7b9d3e21f97..1c3e4ea76bd2 100644
--- a/drivers/pci/endpoint/functions/pci-epf-mhi.c
+++ b/drivers/pci/endpoint/functions/pci-epf-mhi.c
@@ -21,6 +21,15 @@
/* Platform specific flags */
#define MHI_EPF_USE_DMA BIT(0)
+struct pci_epf_mhi_dma_transfer {
+ struct pci_epf_mhi *epf_mhi;
+ struct mhi_ep_buf_info buf_info;
+ struct list_head node;
+ dma_addr_t paddr;
+ enum dma_data_direction dir;
+ size_t size;
+};
+
struct pci_epf_mhi_ep_info {
const struct mhi_ep_cntrl_config *config;
struct pci_epf_header *epf_header;
@@ -124,6 +133,10 @@ struct pci_epf_mhi {
resource_size_t mmio_phys;
struct dma_chan *dma_chan_tx;
struct dma_chan *dma_chan_rx;
+ struct workqueue_struct *dma_wq;
+ struct work_struct dma_work;
+ struct list_head dma_list;
+ spinlock_t list_lock;
u32 mmio_size;
int irq;
};
@@ -205,63 +218,69 @@ static void pci_epf_mhi_raise_irq(struct mhi_ep_cntrl *mhi_cntrl, u32 vector)
* MHI supplies 0 based MSI vectors but the API expects the vector
* number to start from 1, so we need to increment the vector by 1.
*/
- pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no, PCI_EPC_IRQ_MSI,
+ pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no, PCI_IRQ_MSI,
vector + 1);
}
-static int pci_epf_mhi_iatu_read(struct mhi_ep_cntrl *mhi_cntrl, u64 from,
- void *to, size_t size)
+static int pci_epf_mhi_iatu_read(struct mhi_ep_cntrl *mhi_cntrl,
+ struct mhi_ep_buf_info *buf_info)
{
struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl);
- size_t offset = get_align_offset(epf_mhi, from);
+ size_t offset = get_align_offset(epf_mhi, buf_info->host_addr);
void __iomem *tre_buf;
phys_addr_t tre_phys;
int ret;
mutex_lock(&epf_mhi->lock);
- ret = __pci_epf_mhi_alloc_map(mhi_cntrl, from, &tre_phys, &tre_buf,
- offset, size);
+ ret = __pci_epf_mhi_alloc_map(mhi_cntrl, buf_info->host_addr, &tre_phys,
+ &tre_buf, offset, buf_info->size);
if (ret) {
mutex_unlock(&epf_mhi->lock);
return ret;
}
- memcpy_fromio(to, tre_buf, size);
+ memcpy_fromio(buf_info->dev_addr, tre_buf, buf_info->size);
- __pci_epf_mhi_unmap_free(mhi_cntrl, from, tre_phys, tre_buf, offset,
- size);
+ __pci_epf_mhi_unmap_free(mhi_cntrl, buf_info->host_addr, tre_phys,
+ tre_buf, offset, buf_info->size);
mutex_unlock(&epf_mhi->lock);
+ if (buf_info->cb)
+ buf_info->cb(buf_info);
+
return 0;
}
static int pci_epf_mhi_iatu_write(struct mhi_ep_cntrl *mhi_cntrl,
- void *from, u64 to, size_t size)
+ struct mhi_ep_buf_info *buf_info)
{
struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl);
- size_t offset = get_align_offset(epf_mhi, to);
+ size_t offset = get_align_offset(epf_mhi, buf_info->host_addr);
void __iomem *tre_buf;
phys_addr_t tre_phys;
int ret;
mutex_lock(&epf_mhi->lock);
- ret = __pci_epf_mhi_alloc_map(mhi_cntrl, to, &tre_phys, &tre_buf,
- offset, size);
+ ret = __pci_epf_mhi_alloc_map(mhi_cntrl, buf_info->host_addr, &tre_phys,
+ &tre_buf, offset, buf_info->size);
if (ret) {
mutex_unlock(&epf_mhi->lock);
return ret;
}
- memcpy_toio(tre_buf, from, size);
+ memcpy_toio(tre_buf, buf_info->dev_addr, buf_info->size);
- __pci_epf_mhi_unmap_free(mhi_cntrl, to, tre_phys, tre_buf, offset,
- size);
+ __pci_epf_mhi_unmap_free(mhi_cntrl, buf_info->host_addr, tre_phys,
+ tre_buf, offset, buf_info->size);
mutex_unlock(&epf_mhi->lock);
+ if (buf_info->cb)
+ buf_info->cb(buf_info);
+
return 0;
}
@@ -270,8 +289,8 @@ static void pci_epf_mhi_dma_callback(void *param)
complete(param);
}
-static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl, u64 from,
- void *to, size_t size)
+static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl,
+ struct mhi_ep_buf_info *buf_info)
{
struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl);
struct device *dma_dev = epf_mhi->epf->epc->dev.parent;
@@ -284,13 +303,13 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl, u64 from,
dma_addr_t dst_addr;
int ret;
- if (size < SZ_4K)
- return pci_epf_mhi_iatu_read(mhi_cntrl, from, to, size);
+ if (buf_info->size < SZ_4K)
+ return pci_epf_mhi_iatu_read(mhi_cntrl, buf_info);
mutex_lock(&epf_mhi->lock);
config.direction = DMA_DEV_TO_MEM;
- config.src_addr = from;
+ config.src_addr = buf_info->host_addr;
ret = dmaengine_slave_config(chan, &config);
if (ret) {
@@ -298,14 +317,16 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl, u64 from,
goto err_unlock;
}
- dst_addr = dma_map_single(dma_dev, to, size, DMA_FROM_DEVICE);
+ dst_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
+ DMA_FROM_DEVICE);
ret = dma_mapping_error(dma_dev, dst_addr);
if (ret) {
dev_err(dev, "Failed to map remote memory\n");
goto err_unlock;
}
- desc = dmaengine_prep_slave_single(chan, dst_addr, size, DMA_DEV_TO_MEM,
+ desc = dmaengine_prep_slave_single(chan, dst_addr, buf_info->size,
+ DMA_DEV_TO_MEM,
DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
if (!desc) {
dev_err(dev, "Failed to prepare DMA\n");
@@ -332,15 +353,15 @@ static int pci_epf_mhi_edma_read(struct mhi_ep_cntrl *mhi_cntrl, u64 from,
}
err_unmap:
- dma_unmap_single(dma_dev, dst_addr, size, DMA_FROM_DEVICE);
+ dma_unmap_single(dma_dev, dst_addr, buf_info->size, DMA_FROM_DEVICE);
err_unlock:
mutex_unlock(&epf_mhi->lock);
return ret;
}
-static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl, void *from,
- u64 to, size_t size)
+static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl,
+ struct mhi_ep_buf_info *buf_info)
{
struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl);
struct device *dma_dev = epf_mhi->epf->epc->dev.parent;
@@ -353,13 +374,13 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl, void *from,
dma_addr_t src_addr;
int ret;
- if (size < SZ_4K)
- return pci_epf_mhi_iatu_write(mhi_cntrl, from, to, size);
+ if (buf_info->size < SZ_4K)
+ return pci_epf_mhi_iatu_write(mhi_cntrl, buf_info);
mutex_lock(&epf_mhi->lock);
config.direction = DMA_MEM_TO_DEV;
- config.dst_addr = to;
+ config.dst_addr = buf_info->host_addr;
ret = dmaengine_slave_config(chan, &config);
if (ret) {
@@ -367,14 +388,16 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl, void *from,
goto err_unlock;
}
- src_addr = dma_map_single(dma_dev, from, size, DMA_TO_DEVICE);
+ src_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
+ DMA_TO_DEVICE);
ret = dma_mapping_error(dma_dev, src_addr);
if (ret) {
dev_err(dev, "Failed to map remote memory\n");
goto err_unlock;
}
- desc = dmaengine_prep_slave_single(chan, src_addr, size, DMA_MEM_TO_DEV,
+ desc = dmaengine_prep_slave_single(chan, src_addr, buf_info->size,
+ DMA_MEM_TO_DEV,
DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
if (!desc) {
dev_err(dev, "Failed to prepare DMA\n");
@@ -401,7 +424,199 @@ static int pci_epf_mhi_edma_write(struct mhi_ep_cntrl *mhi_cntrl, void *from,
}
err_unmap:
- dma_unmap_single(dma_dev, src_addr, size, DMA_FROM_DEVICE);
+ dma_unmap_single(dma_dev, src_addr, buf_info->size, DMA_TO_DEVICE);
+err_unlock:
+ mutex_unlock(&epf_mhi->lock);
+
+ return ret;
+}
+
+static void pci_epf_mhi_dma_worker(struct work_struct *work)
+{
+ struct pci_epf_mhi *epf_mhi = container_of(work, struct pci_epf_mhi, dma_work);
+ struct device *dma_dev = epf_mhi->epf->epc->dev.parent;
+ struct pci_epf_mhi_dma_transfer *itr, *tmp;
+ struct mhi_ep_buf_info *buf_info;
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&epf_mhi->list_lock, flags);
+ list_splice_tail_init(&epf_mhi->dma_list, &head);
+ spin_unlock_irqrestore(&epf_mhi->list_lock, flags);
+
+ list_for_each_entry_safe(itr, tmp, &head, node) {
+ list_del(&itr->node);
+ dma_unmap_single(dma_dev, itr->paddr, itr->size, itr->dir);
+ buf_info = &itr->buf_info;
+ buf_info->cb(buf_info);
+ kfree(itr);
+ }
+}
+
+static void pci_epf_mhi_dma_async_callback(void *param)
+{
+ struct pci_epf_mhi_dma_transfer *transfer = param;
+ struct pci_epf_mhi *epf_mhi = transfer->epf_mhi;
+
+ spin_lock(&epf_mhi->list_lock);
+ list_add_tail(&transfer->node, &epf_mhi->dma_list);
+ spin_unlock(&epf_mhi->list_lock);
+
+ queue_work(epf_mhi->dma_wq, &epf_mhi->dma_work);
+}
+
+static int pci_epf_mhi_edma_read_async(struct mhi_ep_cntrl *mhi_cntrl,
+ struct mhi_ep_buf_info *buf_info)
+{
+ struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl);
+ struct device *dma_dev = epf_mhi->epf->epc->dev.parent;
+ struct pci_epf_mhi_dma_transfer *transfer = NULL;
+ struct dma_chan *chan = epf_mhi->dma_chan_rx;
+ struct device *dev = &epf_mhi->epf->dev;
+ DECLARE_COMPLETION_ONSTACK(complete);
+ struct dma_async_tx_descriptor *desc;
+ struct dma_slave_config config = {};
+ dma_cookie_t cookie;
+ dma_addr_t dst_addr;
+ int ret;
+
+ mutex_lock(&epf_mhi->lock);
+
+ config.direction = DMA_DEV_TO_MEM;
+ config.src_addr = buf_info->host_addr;
+
+ ret = dmaengine_slave_config(chan, &config);
+ if (ret) {
+ dev_err(dev, "Failed to configure DMA channel\n");
+ goto err_unlock;
+ }
+
+ dst_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
+ DMA_FROM_DEVICE);
+ ret = dma_mapping_error(dma_dev, dst_addr);
+ if (ret) {
+ dev_err(dev, "Failed to map remote memory\n");
+ goto err_unlock;
+ }
+
+ desc = dmaengine_prep_slave_single(chan, dst_addr, buf_info->size,
+ DMA_DEV_TO_MEM,
+ DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+ if (!desc) {
+ dev_err(dev, "Failed to prepare DMA\n");
+ ret = -EIO;
+ goto err_unmap;
+ }
+
+ transfer = kzalloc(sizeof(*transfer), GFP_KERNEL);
+ if (!transfer) {
+ ret = -ENOMEM;
+ goto err_unmap;
+ }
+
+ transfer->epf_mhi = epf_mhi;
+ transfer->paddr = dst_addr;
+ transfer->size = buf_info->size;
+ transfer->dir = DMA_FROM_DEVICE;
+ memcpy(&transfer->buf_info, buf_info, sizeof(*buf_info));
+
+ desc->callback = pci_epf_mhi_dma_async_callback;
+ desc->callback_param = transfer;
+
+ cookie = dmaengine_submit(desc);
+ ret = dma_submit_error(cookie);
+ if (ret) {
+ dev_err(dev, "Failed to do DMA submit\n");
+ goto err_free_transfer;
+ }
+
+ dma_async_issue_pending(chan);
+
+ goto err_unlock;
+
+err_free_transfer:
+ kfree(transfer);
+err_unmap:
+ dma_unmap_single(dma_dev, dst_addr, buf_info->size, DMA_FROM_DEVICE);
+err_unlock:
+ mutex_unlock(&epf_mhi->lock);
+
+ return ret;
+}
+
+static int pci_epf_mhi_edma_write_async(struct mhi_ep_cntrl *mhi_cntrl,
+ struct mhi_ep_buf_info *buf_info)
+{
+ struct pci_epf_mhi *epf_mhi = to_epf_mhi(mhi_cntrl);
+ struct device *dma_dev = epf_mhi->epf->epc->dev.parent;
+ struct pci_epf_mhi_dma_transfer *transfer = NULL;
+ struct dma_chan *chan = epf_mhi->dma_chan_tx;
+ struct device *dev = &epf_mhi->epf->dev;
+ DECLARE_COMPLETION_ONSTACK(complete);
+ struct dma_async_tx_descriptor *desc;
+ struct dma_slave_config config = {};
+ dma_cookie_t cookie;
+ dma_addr_t src_addr;
+ int ret;
+
+ mutex_lock(&epf_mhi->lock);
+
+ config.direction = DMA_MEM_TO_DEV;
+ config.dst_addr = buf_info->host_addr;
+
+ ret = dmaengine_slave_config(chan, &config);
+ if (ret) {
+ dev_err(dev, "Failed to configure DMA channel\n");
+ goto err_unlock;
+ }
+
+ src_addr = dma_map_single(dma_dev, buf_info->dev_addr, buf_info->size,
+ DMA_TO_DEVICE);
+ ret = dma_mapping_error(dma_dev, src_addr);
+ if (ret) {
+ dev_err(dev, "Failed to map remote memory\n");
+ goto err_unlock;
+ }
+
+ desc = dmaengine_prep_slave_single(chan, src_addr, buf_info->size,
+ DMA_MEM_TO_DEV,
+ DMA_CTRL_ACK | DMA_PREP_INTERRUPT);
+ if (!desc) {
+ dev_err(dev, "Failed to prepare DMA\n");
+ ret = -EIO;
+ goto err_unmap;
+ }
+
+ transfer = kzalloc(sizeof(*transfer), GFP_KERNEL);
+ if (!transfer) {
+ ret = -ENOMEM;
+ goto err_unmap;
+ }
+
+ transfer->epf_mhi = epf_mhi;
+ transfer->paddr = src_addr;
+ transfer->size = buf_info->size;
+ transfer->dir = DMA_TO_DEVICE;
+ memcpy(&transfer->buf_info, buf_info, sizeof(*buf_info));
+
+ desc->callback = pci_epf_mhi_dma_async_callback;
+ desc->callback_param = transfer;
+
+ cookie = dmaengine_submit(desc);
+ ret = dma_submit_error(cookie);
+ if (ret) {
+ dev_err(dev, "Failed to do DMA submit\n");
+ goto err_free_transfer;
+ }
+
+ dma_async_issue_pending(chan);
+
+ goto err_unlock;
+
+err_free_transfer:
+ kfree(transfer);
+err_unmap:
+ dma_unmap_single(dma_dev, src_addr, buf_info->size, DMA_TO_DEVICE);
err_unlock:
mutex_unlock(&epf_mhi->lock);
@@ -431,6 +646,7 @@ static int pci_epf_mhi_dma_init(struct pci_epf_mhi *epf_mhi)
struct device *dev = &epf_mhi->epf->dev;
struct epf_dma_filter filter;
dma_cap_mask_t mask;
+ int ret;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
@@ -449,16 +665,35 @@ static int pci_epf_mhi_dma_init(struct pci_epf_mhi *epf_mhi)
&filter);
if (IS_ERR_OR_NULL(epf_mhi->dma_chan_rx)) {
dev_err(dev, "Failed to request rx channel\n");
- dma_release_channel(epf_mhi->dma_chan_tx);
- epf_mhi->dma_chan_tx = NULL;
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_release_tx;
+ }
+
+ epf_mhi->dma_wq = alloc_workqueue("pci_epf_mhi_dma_wq", 0, 0);
+ if (!epf_mhi->dma_wq) {
+ ret = -ENOMEM;
+ goto err_release_rx;
}
+ INIT_LIST_HEAD(&epf_mhi->dma_list);
+ INIT_WORK(&epf_mhi->dma_work, pci_epf_mhi_dma_worker);
+ spin_lock_init(&epf_mhi->list_lock);
+
return 0;
+
+err_release_rx:
+ dma_release_channel(epf_mhi->dma_chan_rx);
+ epf_mhi->dma_chan_rx = NULL;
+err_release_tx:
+ dma_release_channel(epf_mhi->dma_chan_tx);
+ epf_mhi->dma_chan_tx = NULL;
+
+ return ret;
}
static void pci_epf_mhi_dma_deinit(struct pci_epf_mhi *epf_mhi)
{
+ destroy_workqueue(epf_mhi->dma_wq);
dma_release_channel(epf_mhi->dma_chan_tx);
dma_release_channel(epf_mhi->dma_chan_rx);
epf_mhi->dma_chan_tx = NULL;
@@ -531,12 +766,13 @@ static int pci_epf_mhi_link_up(struct pci_epf *epf)
mhi_cntrl->raise_irq = pci_epf_mhi_raise_irq;
mhi_cntrl->alloc_map = pci_epf_mhi_alloc_map;
mhi_cntrl->unmap_free = pci_epf_mhi_unmap_free;
+ mhi_cntrl->read_sync = mhi_cntrl->read_async = pci_epf_mhi_iatu_read;
+ mhi_cntrl->write_sync = mhi_cntrl->write_async = pci_epf_mhi_iatu_write;
if (info->flags & MHI_EPF_USE_DMA) {
- mhi_cntrl->read_from_host = pci_epf_mhi_edma_read;
- mhi_cntrl->write_to_host = pci_epf_mhi_edma_write;
- } else {
- mhi_cntrl->read_from_host = pci_epf_mhi_iatu_read;
- mhi_cntrl->write_to_host = pci_epf_mhi_iatu_write;
+ mhi_cntrl->read_sync = pci_epf_mhi_edma_read;
+ mhi_cntrl->write_sync = pci_epf_mhi_edma_write;
+ mhi_cntrl->read_async = pci_epf_mhi_edma_read_async;
+ mhi_cntrl->write_async = pci_epf_mhi_edma_write_async;
}
/* Register the MHI EP controller */
@@ -644,7 +880,7 @@ static void pci_epf_mhi_unbind(struct pci_epf *epf)
pci_epc_clear_bar(epc, epf->func_no, epf->vfunc_no, epf_bar);
}
-static struct pci_epc_event_ops pci_epf_mhi_event_ops = {
+static const struct pci_epc_event_ops pci_epf_mhi_event_ops = {
.core_init = pci_epf_mhi_core_init,
.link_up = pci_epf_mhi_link_up,
.link_down = pci_epf_mhi_link_down,
@@ -682,7 +918,7 @@ static const struct pci_epf_device_id pci_epf_mhi_ids[] = {
{},
};
-static struct pci_epf_ops pci_epf_mhi_ops = {
+static const struct pci_epf_ops pci_epf_mhi_ops = {
.unbind = pci_epf_mhi_unbind,
.bind = pci_epf_mhi_bind,
};
diff --git a/drivers/pci/endpoint/functions/pci-epf-ntb.c b/drivers/pci/endpoint/functions/pci-epf-ntb.c
index 9aac2c6f3bb9..0553946005c4 100644
--- a/drivers/pci/endpoint/functions/pci-epf-ntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-ntb.c
@@ -140,9 +140,9 @@ static struct pci_epf_header epf_ntb_header = {
static int epf_ntb_link_up(struct epf_ntb *ntb, bool link_up)
{
enum pci_epc_interface_type type;
- enum pci_epc_irq_type irq_type;
struct epf_ntb_epc *ntb_epc;
struct epf_ntb_ctrl *ctrl;
+ unsigned int irq_type;
struct pci_epc *epc;
u8 func_no, vfunc_no;
bool is_msix;
@@ -159,7 +159,7 @@ static int epf_ntb_link_up(struct epf_ntb *ntb, bool link_up)
ctrl->link_status |= LINK_STATUS_UP;
else
ctrl->link_status &= ~LINK_STATUS_UP;
- irq_type = is_msix ? PCI_EPC_IRQ_MSIX : PCI_EPC_IRQ_MSI;
+ irq_type = is_msix ? PCI_IRQ_MSIX : PCI_IRQ_MSI;
ret = pci_epc_raise_irq(epc, func_no, vfunc_no, irq_type, 1);
if (ret) {
dev_err(&epc->dev,
@@ -2099,7 +2099,7 @@ static int epf_ntb_probe(struct pci_epf *epf,
return 0;
}
-static struct pci_epf_ops epf_ntb_ops = {
+static const struct pci_epf_ops epf_ntb_ops = {
.bind = epf_ntb_bind,
.unbind = epf_ntb_unbind,
.add_cfs = epf_ntb_add_cfs,
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 1f0d2b84296a..18c80002d3bd 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -19,11 +19,11 @@
#include <linux/pci-epf.h>
#include <linux/pci_regs.h>
-#define IRQ_TYPE_LEGACY 0
+#define IRQ_TYPE_INTX 0
#define IRQ_TYPE_MSI 1
#define IRQ_TYPE_MSIX 2
-#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
+#define COMMAND_RAISE_INTX_IRQ BIT(0)
#define COMMAND_RAISE_MSI_IRQ BIT(1)
#define COMMAND_RAISE_MSIX_IRQ BIT(2)
#define COMMAND_READ BIT(3)
@@ -600,9 +600,9 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
WRITE_ONCE(reg->status, status);
switch (reg->irq_type) {
- case IRQ_TYPE_LEGACY:
+ case IRQ_TYPE_INTX:
pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
- PCI_EPC_IRQ_LEGACY, 0);
+ PCI_IRQ_INTX, 0);
break;
case IRQ_TYPE_MSI:
count = pci_epc_get_msi(epc, epf->func_no, epf->vfunc_no);
@@ -612,7 +612,7 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
return;
}
pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
- PCI_EPC_IRQ_MSI, reg->irq_number);
+ PCI_IRQ_MSI, reg->irq_number);
break;
case IRQ_TYPE_MSIX:
count = pci_epc_get_msix(epc, epf->func_no, epf->vfunc_no);
@@ -622,7 +622,7 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test,
return;
}
pci_epc_raise_irq(epc, epf->func_no, epf->vfunc_no,
- PCI_EPC_IRQ_MSIX, reg->irq_number);
+ PCI_IRQ_MSIX, reg->irq_number);
break;
default:
dev_err(dev, "Failed to raise IRQ, unknown type\n");
@@ -659,7 +659,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
}
switch (command) {
- case COMMAND_RAISE_LEGACY_IRQ:
+ case COMMAND_RAISE_INTX_IRQ:
case COMMAND_RAISE_MSI_IRQ:
case COMMAND_RAISE_MSIX_IRQ:
pci_epf_test_raise_irq(epf_test, reg);
@@ -973,7 +973,7 @@ static int pci_epf_test_probe(struct pci_epf *epf,
return 0;
}
-static struct pci_epf_ops ops = {
+static const struct pci_epf_ops ops = {
.unbind = pci_epf_test_unbind,
.bind = pci_epf_test_bind,
};
diff --git a/drivers/pci/endpoint/functions/pci-epf-vntb.c b/drivers/pci/endpoint/functions/pci-epf-vntb.c
index 3f60128560ed..e75a2af77328 100644
--- a/drivers/pci/endpoint/functions/pci-epf-vntb.c
+++ b/drivers/pci/endpoint/functions/pci-epf-vntb.c
@@ -1172,11 +1172,8 @@ static int vntb_epf_peer_db_set(struct ntb_dev *ndev, u64 db_bits)
func_no = ntb->epf->func_no;
vfunc_no = ntb->epf->vfunc_no;
- ret = pci_epc_raise_irq(ntb->epf->epc,
- func_no,
- vfunc_no,
- PCI_EPC_IRQ_MSI,
- interrupt_num + 1);
+ ret = pci_epc_raise_irq(ntb->epf->epc, func_no, vfunc_no,
+ PCI_IRQ_MSI, interrupt_num + 1);
if (ret)
dev_err(&ntb->ntb.dev, "Failed to raise IRQ\n");
@@ -1387,7 +1384,7 @@ static void epf_ntb_unbind(struct pci_epf *epf)
}
// EPF driver probe
-static struct pci_epf_ops epf_ntb_ops = {
+static const struct pci_epf_ops epf_ntb_ops = {
.bind = epf_ntb_bind,
.unbind = epf_ntb_unbind,
.add_cfs = epf_ntb_add_cfs,
diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 56e1184bc6c2..dcd4e66430c1 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -211,13 +211,13 @@ EXPORT_SYMBOL_GPL(pci_epc_start);
* @epc: the EPC device which has to interrupt the host
* @func_no: the physical endpoint function number in the EPC device
* @vfunc_no: the virtual endpoint function number in the physical function
- * @type: specify the type of interrupt; legacy, MSI or MSI-X
+ * @type: specify the type of interrupt; INTX, MSI or MSI-X
* @interrupt_num: the MSI or MSI-X interrupt number with range (1-N)
*
- * Invoke to raise an legacy, MSI or MSI-X interrupt
+ * Invoke to raise an INTX, MSI or MSI-X interrupt
*/
int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
- enum pci_epc_irq_type type, u16 interrupt_num)
+ unsigned int type, u16 interrupt_num)
{
int ret;
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 25dbe85c4217..aaa33e8dc4c9 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -745,6 +745,7 @@ static int sriov_init(struct pci_dev *dev, int pos)
u16 ctrl, total;
struct pci_sriov *iov;
struct resource *res;
+ const char *res_name;
struct pci_dev *pdev;
pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl);
@@ -785,6 +786,8 @@ found:
nres = 0;
for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
res = &dev->resource[i + PCI_IOV_RESOURCES];
+ res_name = pci_resource_name(dev, i + PCI_IOV_RESOURCES);
+
/*
* If it is already FIXED, don't change it, something
* (perhaps EA or header fixups) wants it this way.
@@ -802,8 +805,8 @@ found:
}
iov->barsz[i] = resource_size(res);
res->end = res->start + resource_size(res) * total - 1;
- pci_info(dev, "VF(n) BAR%d space: %pR (contains BAR%d for %d VFs)\n",
- i, res, i, total);
+ pci_info(dev, "%s %pR: contains BAR %d for %d VFs\n",
+ res_name, res, i, total);
i += bar64;
nres++;
}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index ae550d71b815..d8f11a078924 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -851,6 +851,66 @@ struct resource *pci_find_resource(struct pci_dev *dev, struct resource *res)
EXPORT_SYMBOL(pci_find_resource);
/**
+ * pci_resource_name - Return the name of the PCI resource
+ * @dev: PCI device to query
+ * @i: index of the resource
+ *
+ * Return the standard PCI resource (BAR) name according to their index.
+ */
+const char *pci_resource_name(struct pci_dev *dev, unsigned int i)
+{
+ static const char * const bar_name[] = {
+ "BAR 0",
+ "BAR 1",
+ "BAR 2",
+ "BAR 3",
+ "BAR 4",
+ "BAR 5",
+ "ROM",
+#ifdef CONFIG_PCI_IOV
+ "VF BAR 0",
+ "VF BAR 1",
+ "VF BAR 2",
+ "VF BAR 3",
+ "VF BAR 4",
+ "VF BAR 5",
+#endif
+ "bridge window", /* "io" included in %pR */
+ "bridge window", /* "mem" included in %pR */
+ "bridge window", /* "mem pref" included in %pR */
+ };
+ static const char * const cardbus_name[] = {
+ "BAR 1",
+ "unknown",
+ "unknown",
+ "unknown",
+ "unknown",
+ "unknown",
+#ifdef CONFIG_PCI_IOV
+ "unknown",
+ "unknown",
+ "unknown",
+ "unknown",
+ "unknown",
+ "unknown",
+#endif
+ "CardBus bridge window 0", /* I/O */
+ "CardBus bridge window 1", /* I/O */
+ "CardBus bridge window 0", /* mem */
+ "CardBus bridge window 1", /* mem */
+ };
+
+ if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS &&
+ i < ARRAY_SIZE(cardbus_name))
+ return cardbus_name[i];
+
+ if (i < ARRAY_SIZE(bar_name))
+ return bar_name[i];
+
+ return "unknown";
+}
+
+/**
* pci_wait_for_pending - wait for @mask bit(s) to clear in status word @pos
* @dev: the PCI device to operate on
* @pos: config space offset of status word
@@ -3299,6 +3359,7 @@ static struct resource *pci_ea_get_resource(struct pci_dev *dev, u8 bei,
static int pci_ea_read(struct pci_dev *dev, int offset)
{
struct resource *res;
+ const char *res_name;
int ent_size, ent_offset = offset;
resource_size_t start, end;
unsigned long flags;
@@ -3328,6 +3389,7 @@ static int pci_ea_read(struct pci_dev *dev, int offset)
goto out;
res = pci_ea_get_resource(dev, bei, prop);
+ res_name = pci_resource_name(dev, bei);
if (!res) {
pci_err(dev, "Unsupported EA entry BEI: %u\n", bei);
goto out;
@@ -3401,16 +3463,16 @@ static int pci_ea_read(struct pci_dev *dev, int offset)
res->flags = flags;
if (bei <= PCI_EA_BEI_BAR5)
- pci_info(dev, "BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
- bei, res, prop);
+ pci_info(dev, "%s %pR: from Enhanced Allocation, properties %#02x\n",
+ res_name, res, prop);
else if (bei == PCI_EA_BEI_ROM)
- pci_info(dev, "ROM: %pR (from Enhanced Allocation, properties %#02x)\n",
- res, prop);
+ pci_info(dev, "%s %pR: from Enhanced Allocation, properties %#02x\n",
+ res_name, res, prop);
else if (bei >= PCI_EA_BEI_VF_BAR0 && bei <= PCI_EA_BEI_VF_BAR5)
- pci_info(dev, "VF BAR %d: %pR (from Enhanced Allocation, properties %#02x)\n",
- bei - PCI_EA_BEI_VF_BAR0, res, prop);
+ pci_info(dev, "%s %pR: from Enhanced Allocation, properties %#02x\n",
+ res_name, res, prop);
else
- pci_info(dev, "BEI %d res: %pR (from Enhanced Allocation, properties %#02x)\n",
+ pci_info(dev, "BEI %d %pR: from Enhanced Allocation, properties %#02x\n",
bei, res, prop);
out:
@@ -6233,6 +6295,41 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
}
EXPORT_SYMBOL(pcie_set_mps);
+static enum pci_bus_speed to_pcie_link_speed(u16 lnksta)
+{
+ return pcie_link_speed[FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta)];
+}
+
+int pcie_link_speed_mbps(struct pci_dev *pdev)
+{
+ u16 lnksta;
+ int err;
+
+ err = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnksta);
+ if (err)
+ return err;
+
+ switch (to_pcie_link_speed(lnksta)) {
+ case PCIE_SPEED_2_5GT:
+ return 2500;
+ case PCIE_SPEED_5_0GT:
+ return 5000;
+ case PCIE_SPEED_8_0GT:
+ return 8000;
+ case PCIE_SPEED_16_0GT:
+ return 16000;
+ case PCIE_SPEED_32_0GT:
+ return 32000;
+ case PCIE_SPEED_64_0GT:
+ return 64000;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(pcie_link_speed_mbps);
+
/**
* pcie_bandwidth_available - determine minimum link settings of a PCIe
* device and its bandwidth limitation
@@ -6266,8 +6363,7 @@ u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
while (dev) {
pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
- next_speed = pcie_link_speed[FIELD_GET(PCI_EXP_LNKSTA_CLS,
- lnksta)];
+ next_speed = to_pcie_link_speed(lnksta);
next_width = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta);
next_bw = next_width * PCIE_SPEED2MBS_ENC(next_speed);
@@ -6698,14 +6794,15 @@ static void pci_request_resource_alignment(struct pci_dev *dev, int bar,
resource_size_t align, bool resize)
{
struct resource *r = &dev->resource[bar];
+ const char *r_name = pci_resource_name(dev, bar);
resource_size_t size;
if (!(r->flags & IORESOURCE_MEM))
return;
if (r->flags & IORESOURCE_PCI_FIXED) {
- pci_info(dev, "BAR%d %pR: ignoring requested alignment %#llx\n",
- bar, r, (unsigned long long)align);
+ pci_info(dev, "%s %pR: ignoring requested alignment %#llx\n",
+ r_name, r, (unsigned long long)align);
return;
}
@@ -6741,8 +6838,8 @@ static void pci_request_resource_alignment(struct pci_dev *dev, int bar,
* devices and we use the second.
*/
- pci_info(dev, "BAR%d %pR: requesting alignment to %#llx\n",
- bar, r, (unsigned long long)align);
+ pci_info(dev, "%s %pR: requesting alignment to %#llx\n",
+ r_name, r, (unsigned long long)align);
if (resize) {
r->start = 0;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index f43873049d52..2336a8d1edab 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -255,6 +255,8 @@ void __pci_bus_assign_resources(const struct pci_bus *bus,
struct list_head *fail_head);
bool pci_bus_clip_resource(struct pci_dev *dev, int idx);
+const char *pci_resource_name(struct pci_dev *dev, unsigned int i);
+
void pci_reassigndev_resource_alignment(struct pci_dev *dev);
void pci_disable_bridge_window(struct pci_dev *dev);
struct pci_bus *pci_bus_get(struct pci_bus *bus);
@@ -272,7 +274,7 @@ void pci_bus_put(struct pci_bus *bus);
/* PCIe speed to Mb/s reduced by encoding overhead */
#define PCIE_SPEED2MBS_ENC(speed) \
- ((speed) == PCIE_SPEED_64_0GT ? 64000*128/130 : \
+ ((speed) == PCIE_SPEED_64_0GT ? 64000*1/1 : \
(speed) == PCIE_SPEED_32_0GT ? 32000*128/130 : \
(speed) == PCIE_SPEED_16_0GT ? 16000*128/130 : \
(speed) == PCIE_SPEED_8_0GT ? 8000*128/130 : \
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index 42a3bd35a3e1..05fc30bb5134 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -41,8 +41,8 @@
#define AER_MAX_TYPEOF_UNCOR_ERRS 27 /* as per PCI_ERR_UNCOR_STATUS*/
struct aer_err_source {
- unsigned int status;
- unsigned int id;
+ u32 status; /* PCI_ERR_ROOT_STATUS */
+ u32 id; /* PCI_ERR_ROOT_ERR_SRC */
};
struct aer_rpc {
@@ -435,10 +435,10 @@ void pci_aer_exit(struct pci_dev *dev)
/*
* AER error strings
*/
-static const char *aer_error_severity_string[] = {
- "Uncorrected (Non-Fatal)",
- "Uncorrected (Fatal)",
- "Corrected"
+static const char * const aer_error_severity_string[] = {
+ "Uncorrectable (Non-Fatal)",
+ "Uncorrectable (Fatal)",
+ "Correctable"
};
static const char *aer_error_layer[] = {
@@ -740,7 +740,7 @@ static void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)
u8 bus = info->id >> 8;
u8 devfn = info->id & 0xff;
- pci_info(dev, "%s%s error received: %04x:%02x:%02x.%d\n",
+ pci_info(dev, "%s%s error message received from %04x:%02x:%02x.%d\n",
info->multi_error_valid ? "Multiple " : "",
aer_error_severity_string[info->severity],
pci_domain_nr(dev->bus), bus, PCI_SLOT(devfn),
@@ -929,7 +929,12 @@ static bool find_source_device(struct pci_dev *parent,
pci_walk_bus(parent->subordinate, find_device_iter, e_info);
if (!e_info->error_dev_num) {
- pci_info(parent, "can't find device of ID%04x\n", e_info->id);
+ u8 bus = e_info->id >> 8;
+ u8 devfn = e_info->id & 0xff;
+
+ pci_info(parent, "found no error details for %04x:%02x:%02x.%d\n",
+ pci_domain_nr(parent->bus), bus, PCI_SLOT(devfn),
+ PCI_FUNC(devfn));
return false;
}
return true;
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ed6b7f48736a..b7335be56008 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -180,6 +180,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
u64 l64, sz64, mask64;
u16 orig_cmd;
struct pci_bus_region region, inverted_region;
+ const char *res_name = pci_resource_name(dev, res - dev->resource);
mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
@@ -254,8 +255,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
sz64 = pci_size(l64, sz64, mask64);
if (!sz64) {
- pci_info(dev, FW_BUG "reg 0x%x: invalid BAR (can't size)\n",
- pos);
+ pci_info(dev, FW_BUG "%s: invalid; can't size\n", res_name);
goto fail;
}
@@ -265,8 +265,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
res->start = 0;
res->end = 0;
- pci_err(dev, "reg 0x%x: can't handle BAR larger than 4GB (size %#010llx)\n",
- pos, (unsigned long long)sz64);
+ pci_err(dev, "%s: can't handle BAR larger than 4GB (size %#010llx)\n",
+ res_name, (unsigned long long)sz64);
goto out;
}
@@ -275,8 +275,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
res->flags |= IORESOURCE_UNSET;
res->start = 0;
res->end = sz64 - 1;
- pci_info(dev, "reg 0x%x: can't handle BAR above 4GB (bus address %#010llx)\n",
- pos, (unsigned long long)l64);
+ pci_info(dev, "%s: can't handle BAR above 4GB (bus address %#010llx)\n",
+ res_name, (unsigned long long)l64);
goto out;
}
}
@@ -302,8 +302,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
res->flags |= IORESOURCE_UNSET;
res->start = 0;
res->end = region.end - region.start;
- pci_info(dev, "reg 0x%x: initial BAR value %#010llx invalid\n",
- pos, (unsigned long long)region.start);
+ pci_info(dev, "%s: initial BAR value %#010llx invalid\n",
+ res_name, (unsigned long long)region.start);
}
goto out;
@@ -313,7 +313,7 @@ fail:
res->flags = 0;
out:
if (res->flags)
- pci_info(dev, "reg 0x%x: %pR\n", pos, res);
+ pci_info(dev, "%s %pR\n", res_name, res);
return (res->flags & IORESOURCE_MEM_64) ? 1 : 0;
}
@@ -344,64 +344,12 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
}
}
-static void pci_read_bridge_windows(struct pci_dev *bridge)
+static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res,
+ bool log)
{
- u16 io;
- u32 pmem, tmp;
-
- pci_read_config_word(bridge, PCI_IO_BASE, &io);
- if (!io) {
- pci_write_config_word(bridge, PCI_IO_BASE, 0xe0f0);
- pci_read_config_word(bridge, PCI_IO_BASE, &io);
- pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
- }
- if (io)
- bridge->io_window = 1;
-
- /*
- * DECchip 21050 pass 2 errata: the bridge may miss an address
- * disconnect boundary by one PCI data phase. Workaround: do not
- * use prefetching on this device.
- */
- if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001)
- return;
-
- pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
- if (!pmem) {
- pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE,
- 0xffe0fff0);
- pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
- pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
- }
- if (!pmem)
- return;
-
- bridge->pref_window = 1;
-
- if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
-
- /*
- * Bridge claims to have a 64-bit prefetchable memory
- * window; verify that the upper bits are actually
- * writable.
- */
- pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &pmem);
- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
- 0xffffffff);
- pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp);
- pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, pmem);
- if (tmp)
- bridge->pref_64_window = 1;
- }
-}
-
-static void pci_read_bridge_io(struct pci_bus *child)
-{
- struct pci_dev *dev = child->self;
u8 io_base_lo, io_limit_lo;
unsigned long io_mask, io_granularity, base, limit;
struct pci_bus_region region;
- struct resource *res;
io_mask = PCI_IO_RANGE_MASK;
io_granularity = 0x1000;
@@ -411,7 +359,6 @@ static void pci_read_bridge_io(struct pci_bus *child)
io_granularity = 0x400;
}
- res = child->resource[0];
pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
base = (io_base_lo & io_mask) << 8;
@@ -431,19 +378,18 @@ static void pci_read_bridge_io(struct pci_bus *child)
region.start = base;
region.end = limit + io_granularity - 1;
pcibios_bus_to_resource(dev->bus, res, &region);
- pci_info(dev, " bridge window %pR\n", res);
+ if (log)
+ pci_info(dev, " bridge window %pR\n", res);
}
}
-static void pci_read_bridge_mmio(struct pci_bus *child)
+static void pci_read_bridge_mmio(struct pci_dev *dev, struct resource *res,
+ bool log)
{
- struct pci_dev *dev = child->self;
u16 mem_base_lo, mem_limit_lo;
unsigned long base, limit;
struct pci_bus_region region;
- struct resource *res;
- res = child->resource[1];
pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
base = ((unsigned long) mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
@@ -453,20 +399,19 @@ static void pci_read_bridge_mmio(struct pci_bus *child)
region.start = base;
region.end = limit + 0xfffff;
pcibios_bus_to_resource(dev->bus, res, &region);
- pci_info(dev, " bridge window %pR\n", res);
+ if (log)
+ pci_info(dev, " bridge window %pR\n", res);
}
}
-static void pci_read_bridge_mmio_pref(struct pci_bus *child)
+static void pci_read_bridge_mmio_pref(struct pci_dev *dev, struct resource *res,
+ bool log)
{
- struct pci_dev *dev = child->self;
u16 mem_base_lo, mem_limit_lo;
u64 base64, limit64;
pci_bus_addr_t base, limit;
struct pci_bus_region region;
- struct resource *res;
- res = child->resource[2];
pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
base64 = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
@@ -506,10 +451,77 @@ static void pci_read_bridge_mmio_pref(struct pci_bus *child)
region.start = base;
region.end = limit + 0xfffff;
pcibios_bus_to_resource(dev->bus, res, &region);
- pci_info(dev, " bridge window %pR\n", res);
+ if (log)
+ pci_info(dev, " bridge window %pR\n", res);
}
}
+static void pci_read_bridge_windows(struct pci_dev *bridge)
+{
+ u32 buses;
+ u16 io;
+ u32 pmem, tmp;
+ struct resource res;
+
+ pci_read_config_dword(bridge, PCI_PRIMARY_BUS, &buses);
+ res.flags = IORESOURCE_BUS;
+ res.start = (buses >> 8) & 0xff;
+ res.end = (buses >> 16) & 0xff;
+ pci_info(bridge, "PCI bridge to %pR%s\n", &res,
+ bridge->transparent ? " (subtractive decode)" : "");
+
+ pci_read_config_word(bridge, PCI_IO_BASE, &io);
+ if (!io) {
+ pci_write_config_word(bridge, PCI_IO_BASE, 0xe0f0);
+ pci_read_config_word(bridge, PCI_IO_BASE, &io);
+ pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
+ }
+ if (io) {
+ bridge->io_window = 1;
+ pci_read_bridge_io(bridge, &res, true);
+ }
+
+ pci_read_bridge_mmio(bridge, &res, true);
+
+ /*
+ * DECchip 21050 pass 2 errata: the bridge may miss an address
+ * disconnect boundary by one PCI data phase. Workaround: do not
+ * use prefetching on this device.
+ */
+ if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001)
+ return;
+
+ pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
+ if (!pmem) {
+ pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE,
+ 0xffe0fff0);
+ pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);
+ pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);
+ }
+ if (!pmem)
+ return;
+
+ bridge->pref_window = 1;
+
+ if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
+
+ /*
+ * Bridge claims to have a 64-bit prefetchable memory
+ * window; verify that the upper bits are actually
+ * writable.
+ */
+ pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &pmem);
+ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
+ 0xffffffff);
+ pci_read_config_dword(bridge, PCI_PREF_BASE_UPPER32, &tmp);
+ pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, pmem);
+ if (tmp)
+ bridge->pref_64_window = 1;
+ }
+
+ pci_read_bridge_mmio_pref(bridge, &res, true);
+}
+
void pci_read_bridge_bases(struct pci_bus *child)
{
struct pci_dev *dev = child->self;
@@ -527,9 +539,9 @@ void pci_read_bridge_bases(struct pci_bus *child)
for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
- pci_read_bridge_io(child);
- pci_read_bridge_mmio(child);
- pci_read_bridge_mmio_pref(child);
+ pci_read_bridge_io(child->self, child->resource[0], false);
+ pci_read_bridge_mmio(child->self, child->resource[1], false);
+ pci_read_bridge_mmio_pref(child->self, child->resource[2], false);
if (dev->transparent) {
pci_bus_for_each_resource(child->parent, res) {
@@ -1817,6 +1829,43 @@ static void early_dump_pci_device(struct pci_dev *pdev)
value, 256, false);
}
+static const char *pci_type_str(struct pci_dev *dev)
+{
+ static const char * const str[] = {
+ "PCIe Endpoint",
+ "PCIe Legacy Endpoint",
+ "PCIe unknown",
+ "PCIe unknown",
+ "PCIe Root Port",
+ "PCIe Switch Upstream Port",
+ "PCIe Switch Downstream Port",
+ "PCIe to PCI/PCI-X bridge",
+ "PCI/PCI-X to PCIe bridge",
+ "PCIe Root Complex Integrated Endpoint",
+ "PCIe Root Complex Event Collector",
+ };
+ int type;
+
+ if (pci_is_pcie(dev)) {
+ type = pci_pcie_type(dev);
+ if (type < ARRAY_SIZE(str))
+ return str[type];
+
+ return "PCIe unknown";
+ }
+
+ switch (dev->hdr_type) {
+ case PCI_HEADER_TYPE_NORMAL:
+ return "conventional PCI endpoint";
+ case PCI_HEADER_TYPE_BRIDGE:
+ return "conventional PCI bridge";
+ case PCI_HEADER_TYPE_CARDBUS:
+ return "CardBus bridge";
+ default:
+ return "conventional PCI";
+ }
+}
+
/**
* pci_setup_device - Fill in class and map information of a device
* @dev: the device structure to fill
@@ -1887,8 +1936,9 @@ int pci_setup_device(struct pci_dev *dev)
pci_set_removable(dev);
- pci_info(dev, "[%04x:%04x] type %02x class %#08x\n",
- dev->vendor, dev->device, dev->hdr_type, dev->class);
+ pci_info(dev, "[%04x:%04x] type %02x class %#08x %s\n",
+ dev->vendor, dev->device, dev->hdr_type, dev->class,
+ pci_type_str(dev));
/* Device class may be changed after fixup */
class = dev->class >> 8;
@@ -1929,14 +1979,14 @@ int pci_setup_device(struct pci_dev *dev)
res = &dev->resource[0];
res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev->bus, res, &region);
- pci_info(dev, "legacy IDE quirk: reg 0x10: %pR\n",
+ pci_info(dev, "BAR 0 %pR: legacy IDE quirk\n",
res);
region.start = 0x3F6;
region.end = 0x3F6;
res = &dev->resource[1];
res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev->bus, res, &region);
- pci_info(dev, "legacy IDE quirk: reg 0x14: %pR\n",
+ pci_info(dev, "BAR 1 %pR: legacy IDE quirk\n",
res);
}
if ((progif & 4) == 0) {
@@ -1945,14 +1995,14 @@ int pci_setup_device(struct pci_dev *dev)
res = &dev->resource[2];
res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev->bus, res, &region);
- pci_info(dev, "legacy IDE quirk: reg 0x18: %pR\n",
+ pci_info(dev, "BAR 2 %pR: legacy IDE quirk\n",
res);
region.start = 0x376;
region.end = 0x376;
res = &dev->resource[3];
res->flags = LEGACY_IO_RESOURCE;
pcibios_bus_to_resource(dev->bus, res, &region);
- pci_info(dev, "legacy IDE quirk: reg 0x1c: %pR\n",
+ pci_info(dev, "BAR 3 %pR: legacy IDE quirk\n",
res);
}
}
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index d208047d1b8f..d797df6e5f3e 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -570,13 +570,14 @@ static void quirk_extend_bar_to_page(struct pci_dev *dev)
for (i = 0; i < PCI_STD_NUM_BARS; i++) {
struct resource *r = &dev->resource[i];
+ const char *r_name = pci_resource_name(dev, i);
if (r->flags & IORESOURCE_MEM && resource_size(r) < PAGE_SIZE) {
r->end = PAGE_SIZE - 1;
r->start = 0;
r->flags |= IORESOURCE_UNSET;
- pci_info(dev, "expanded BAR %d to page size: %pR\n",
- i, r);
+ pci_info(dev, "%s %pR: expanded to page size\n",
+ r_name, r);
}
}
}
@@ -605,6 +606,7 @@ static void quirk_io(struct pci_dev *dev, int pos, unsigned int size,
u32 region;
struct pci_bus_region bus_region;
struct resource *res = dev->resource + pos;
+ const char *res_name = pci_resource_name(dev, pos);
pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (pos << 2), &region);
@@ -622,8 +624,7 @@ static void quirk_io(struct pci_dev *dev, int pos, unsigned int size,
bus_region.end = region + size - 1;
pcibios_bus_to_resource(dev->bus, res, &bus_region);
- pci_info(dev, FW_BUG "%s quirk: reg 0x%x: %pR\n",
- name, PCI_BASE_ADDRESS_0 + (pos << 2), res);
+ pci_info(dev, FW_BUG "%s %pR: %s quirk\n", res_name, res, name);
}
/*
@@ -670,6 +671,12 @@ static void quirk_io_region(struct pci_dev *dev, int port,
bus_region.end = region + size - 1;
pcibios_bus_to_resource(dev->bus, res, &bus_region);
+ /*
+ * "res" is typically a bridge window resource that's not being
+ * used for a bridge window, so it's just a place to stash this
+ * non-standard resource. Printing "nr" or pci_resource_name() of
+ * it doesn't really make sense.
+ */
if (!pci_claim_resource(dev, nr))
pci_info(dev, "quirk: %pR claimed by %s\n", res, name);
}
@@ -702,10 +709,13 @@ static void quirk_amd_dwc_class(struct pci_dev *pdev)
{
u32 class = pdev->class;
- /* Use "USB Device (not host controller)" class */
- pdev->class = PCI_CLASS_SERIAL_USB_DEVICE;
- pci_info(pdev, "PCI class overridden (%#08x -> %#08x) so dwc3 driver can claim this instead of xhci\n",
- class, pdev->class);
+ if (class != PCI_CLASS_SERIAL_USB_DEVICE) {
+ /* Use "USB Device (not host controller)" class */
+ pdev->class = PCI_CLASS_SERIAL_USB_DEVICE;
+ pci_info(pdev,
+ "PCI class overridden (%#08x -> %#08x) so dwc3 driver can claim this instead of xhci\n",
+ class, pdev->class);
+ }
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB,
quirk_amd_dwc_class);
@@ -4712,17 +4722,21 @@ static int pci_quirk_xgene_acs(struct pci_dev *dev, u16 acs_flags)
* But the implementation could block peer-to-peer transactions between them
* and provide ACS-like functionality.
*/
-static int pci_quirk_zhaoxin_pcie_ports_acs(struct pci_dev *dev, u16 acs_flags)
+static int pci_quirk_zhaoxin_pcie_ports_acs(struct pci_dev *dev, u16 acs_flags)
{
if (!pci_is_pcie(dev) ||
((pci_pcie_type(dev) != PCI_EXP_TYPE_ROOT_PORT) &&
(pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM)))
return -ENOTTY;
+ /*
+ * Future Zhaoxin Root Ports and Switch Downstream Ports will
+ * implement ACS capability in accordance with the PCIe Spec.
+ */
switch (dev->device) {
case 0x0710 ... 0x071e:
case 0x0721:
- case 0x0723 ... 0x0732:
+ case 0x0723 ... 0x0752:
return pci_acs_ctrl_enabled(acs_flags,
PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
}
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index fd74f1c99dba..909e6a7c3cc3 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -213,6 +213,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
struct list_head *head)
{
struct resource *res;
+ const char *res_name;
struct pci_dev_resource *add_res, *tmp;
struct pci_dev_resource *dev_res;
resource_size_t add_size, align;
@@ -222,6 +223,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
bool found_match = false;
res = add_res->res;
+
/* Skip resource that has been reset */
if (!res->flags)
goto out;
@@ -237,6 +239,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
continue;
idx = res - &add_res->dev->resource[0];
+ res_name = pci_resource_name(add_res->dev, idx);
add_size = add_res->add_size;
align = add_res->min_align;
if (!resource_size(res)) {
@@ -249,9 +252,9 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
(IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
if (pci_reassign_resource(add_res->dev, idx,
add_size, align))
- pci_info(add_res->dev, "failed to add %llx res[%d]=%pR\n",
- (unsigned long long) add_size, idx,
- res);
+ pci_info(add_res->dev, "%s %pR: failed to add %llx\n",
+ res_name, res,
+ (unsigned long long) add_size);
}
out:
list_del(&add_res->list);
@@ -571,6 +574,7 @@ EXPORT_SYMBOL(pci_setup_cardbus);
static void pci_setup_bridge_io(struct pci_dev *bridge)
{
struct resource *res;
+ const char *res_name;
struct pci_bus_region region;
unsigned long io_mask;
u8 io_base_lo, io_limit_lo;
@@ -583,6 +587,7 @@ static void pci_setup_bridge_io(struct pci_dev *bridge)
/* Set up the top and bottom of the PCI I/O segment for this bus */
res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
+ res_name = pci_resource_name(bridge, PCI_BRIDGE_IO_WINDOW);
pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_IO) {
pci_read_config_word(bridge, PCI_IO_BASE, &l);
@@ -591,7 +596,7 @@ static void pci_setup_bridge_io(struct pci_dev *bridge)
l = ((u16) io_limit_lo << 8) | io_base_lo;
/* Set up upper 16 bits of I/O base/limit */
io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
- pci_info(bridge, " bridge window %pR\n", res);
+ pci_info(bridge, " %s %pR\n", res_name, res);
} else {
/* Clear upper 16 bits of I/O base/limit */
io_upper16 = 0;
@@ -608,16 +613,18 @@ static void pci_setup_bridge_io(struct pci_dev *bridge)
static void pci_setup_bridge_mmio(struct pci_dev *bridge)
{
struct resource *res;
+ const char *res_name;
struct pci_bus_region region;
u32 l;
/* Set up the top and bottom of the PCI Memory segment for this bus */
res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW];
+ res_name = pci_resource_name(bridge, PCI_BRIDGE_MEM_WINDOW);
pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_MEM) {
l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000;
- pci_info(bridge, " bridge window %pR\n", res);
+ pci_info(bridge, " %s %pR\n", res_name, res);
} else {
l = 0x0000fff0;
}
@@ -627,6 +634,7 @@ static void pci_setup_bridge_mmio(struct pci_dev *bridge)
static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
{
struct resource *res;
+ const char *res_name;
struct pci_bus_region region;
u32 l, bu, lu;
@@ -640,6 +648,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
/* Set up PREF base/limit */
bu = lu = 0;
res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
+ res_name = pci_resource_name(bridge, PCI_BRIDGE_PREF_MEM_WINDOW);
pcibios_resource_to_bus(bridge->bus, &region, res);
if (res->flags & IORESOURCE_PREFETCH) {
l = (region.start >> 16) & 0xfff0;
@@ -648,7 +657,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
bu = upper_32_bits(region.start);
lu = upper_32_bits(region.end);
}
- pci_info(bridge, " bridge window %pR\n", res);
+ pci_info(bridge, " %s %pR\n", res_name, res);
} else {
l = 0x0000fff0;
}
@@ -1013,6 +1022,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
int i;
pci_dev_for_each_resource(dev, r, i) {
+ const char *r_name = pci_resource_name(dev, i);
resource_size_t r_size;
if (r->parent || (r->flags & IORESOURCE_PCI_FIXED) ||
@@ -1043,8 +1053,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
if (order < 0)
order = 0;
if (order >= ARRAY_SIZE(aligns)) {
- pci_warn(dev, "disabling BAR %d: %pR (bad alignment %#llx)\n",
- i, r, (unsigned long long) align);
+ pci_warn(dev, "%s %pR: disabling; bad alignment %#llx\n",
+ r_name, r, (unsigned long long) align);
r->flags = 0;
continue;
}
@@ -2235,6 +2245,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
for (i = PCI_BRIDGE_RESOURCES; i < PCI_BRIDGE_RESOURCE_END;
i++) {
struct resource *res = &bridge->resource[i];
+ const char *res_name = pci_resource_name(bridge, i);
if ((res->flags ^ type) & PCI_RES_TYPE_MASK)
continue;
@@ -2247,8 +2258,7 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
if (ret)
goto cleanup;
- pci_info(bridge, "BAR %d: releasing %pR\n",
- i, res);
+ pci_info(bridge, "%s %pR: releasing\n", res_name, res);
if (res->parent)
release_resource(res);
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index ceaa69491f5e..c6d933ddfd46 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -30,6 +30,7 @@ static void pci_std_update_resource(struct pci_dev *dev, int resno)
u32 new, check, mask;
int reg;
struct resource *res = dev->resource + resno;
+ const char *res_name = pci_resource_name(dev, resno);
/* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */
if (dev->is_virtfn)
@@ -104,8 +105,8 @@ static void pci_std_update_resource(struct pci_dev *dev, int resno)
pci_read_config_dword(dev, reg, &check);
if ((new ^ check) & mask) {
- pci_err(dev, "BAR %d: error updating (%#010x != %#010x)\n",
- resno, new, check);
+ pci_err(dev, "%s: error updating (%#010x != %#010x)\n",
+ res_name, new, check);
}
if (res->flags & IORESOURCE_MEM_64) {
@@ -113,8 +114,8 @@ static void pci_std_update_resource(struct pci_dev *dev, int resno)
pci_write_config_dword(dev, reg + 4, new);
pci_read_config_dword(dev, reg + 4, &check);
if (check != new) {
- pci_err(dev, "BAR %d: error updating (high %#010x != %#010x)\n",
- resno, new, check);
+ pci_err(dev, "%s: error updating (high %#010x != %#010x)\n",
+ res_name, new, check);
}
}
@@ -135,11 +136,12 @@ void pci_update_resource(struct pci_dev *dev, int resno)
int pci_claim_resource(struct pci_dev *dev, int resource)
{
struct resource *res = &dev->resource[resource];
+ const char *res_name = pci_resource_name(dev, resource);
struct resource *root, *conflict;
if (res->flags & IORESOURCE_UNSET) {
- pci_info(dev, "can't claim BAR %d %pR: no address assigned\n",
- resource, res);
+ pci_info(dev, "%s %pR: can't claim; no address assigned\n",
+ res_name, res);
return -EINVAL;
}
@@ -153,16 +155,16 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
root = pci_find_parent_resource(dev, res);
if (!root) {
- pci_info(dev, "can't claim BAR %d %pR: no compatible bridge window\n",
- resource, res);
+ pci_info(dev, "%s %pR: can't claim; no compatible bridge window\n",
+ res_name, res);
res->flags |= IORESOURCE_UNSET;
return -EINVAL;
}
conflict = request_resource_conflict(root, res);
if (conflict) {
- pci_info(dev, "can't claim BAR %d %pR: address conflict with %s %pR\n",
- resource, res, conflict->name, conflict);
+ pci_info(dev, "%s %pR: can't claim; address conflict with %s %pR\n",
+ res_name, res, conflict->name, conflict);
res->flags |= IORESOURCE_UNSET;
return -EBUSY;
}
@@ -201,6 +203,7 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
{
struct resource *root, *conflict;
resource_size_t fw_addr, start, end;
+ const char *res_name = pci_resource_name(dev, resno);
fw_addr = pcibios_retrieve_fw_addr(dev, resno);
if (!fw_addr)
@@ -231,12 +234,11 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
root = &iomem_resource;
}
- pci_info(dev, "BAR %d: trying firmware assignment %pR\n",
- resno, res);
+ pci_info(dev, "%s: trying firmware assignment %pR\n", res_name, res);
conflict = request_resource_conflict(root, res);
if (conflict) {
- pci_info(dev, "BAR %d: %pR conflicts with %s %pR\n",
- resno, res, conflict->name, conflict);
+ pci_info(dev, "%s %pR: conflicts with %s %pR\n", res_name, res,
+ conflict->name, conflict);
res->start = start;
res->end = end;
res->flags |= IORESOURCE_UNSET;
@@ -325,6 +327,7 @@ static int _pci_assign_resource(struct pci_dev *dev, int resno,
int pci_assign_resource(struct pci_dev *dev, int resno)
{
struct resource *res = dev->resource + resno;
+ const char *res_name = pci_resource_name(dev, resno);
resource_size_t align, size;
int ret;
@@ -334,8 +337,8 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
res->flags |= IORESOURCE_UNSET;
align = pci_resource_alignment(dev, res);
if (!align) {
- pci_info(dev, "BAR %d: can't assign %pR (bogus alignment)\n",
- resno, res);
+ pci_info(dev, "%s %pR: can't assign; bogus alignment\n",
+ res_name, res);
return -EINVAL;
}
@@ -348,18 +351,18 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
* working, which is better than just leaving it disabled.
*/
if (ret < 0) {
- pci_info(dev, "BAR %d: no space for %pR\n", resno, res);
+ pci_info(dev, "%s %pR: can't assign; no space\n", res_name, res);
ret = pci_revert_fw_address(res, dev, resno, size);
}
if (ret < 0) {
- pci_info(dev, "BAR %d: failed to assign %pR\n", resno, res);
+ pci_info(dev, "%s %pR: failed to assign\n", res_name, res);
return ret;
}
res->flags &= ~IORESOURCE_UNSET;
res->flags &= ~IORESOURCE_STARTALIGN;
- pci_info(dev, "BAR %d: assigned %pR\n", resno, res);
+ pci_info(dev, "%s %pR: assigned\n", res_name, res);
if (resno < PCI_BRIDGE_RESOURCES)
pci_update_resource(dev, resno);
@@ -367,10 +370,11 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
}
EXPORT_SYMBOL(pci_assign_resource);
-int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsize,
- resource_size_t min_align)
+int pci_reassign_resource(struct pci_dev *dev, int resno,
+ resource_size_t addsize, resource_size_t min_align)
{
struct resource *res = dev->resource + resno;
+ const char *res_name = pci_resource_name(dev, resno);
unsigned long flags;
resource_size_t new_size;
int ret;
@@ -381,8 +385,8 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
flags = res->flags;
res->flags |= IORESOURCE_UNSET;
if (!res->parent) {
- pci_info(dev, "BAR %d: can't reassign an unassigned resource %pR\n",
- resno, res);
+ pci_info(dev, "%s %pR: can't reassign; unassigned resource\n",
+ res_name, res);
return -EINVAL;
}
@@ -391,15 +395,15 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
ret = _pci_assign_resource(dev, resno, new_size, min_align);
if (ret) {
res->flags = flags;
- pci_info(dev, "BAR %d: %pR (failed to expand by %#llx)\n",
- resno, res, (unsigned long long) addsize);
+ pci_info(dev, "%s %pR: failed to expand by %#llx\n",
+ res_name, res, (unsigned long long) addsize);
return ret;
}
res->flags &= ~IORESOURCE_UNSET;
res->flags &= ~IORESOURCE_STARTALIGN;
- pci_info(dev, "BAR %d: reassigned %pR (expanded by %#llx)\n",
- resno, res, (unsigned long long) addsize);
+ pci_info(dev, "%s %pR: reassigned; expanded by %#llx\n",
+ res_name, res, (unsigned long long) addsize);
if (resno < PCI_BRIDGE_RESOURCES)
pci_update_resource(dev, resno);
@@ -409,8 +413,9 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
void pci_release_resource(struct pci_dev *dev, int resno)
{
struct resource *res = dev->resource + resno;
+ const char *res_name = pci_resource_name(dev, resno);
- pci_info(dev, "BAR %d: releasing %pR\n", resno, res);
+ pci_info(dev, "%s %pR: releasing\n", res_name, res);
if (!res->parent)
return;
@@ -480,6 +485,7 @@ int pci_enable_resources(struct pci_dev *dev, int mask)
u16 cmd, old_cmd;
int i;
struct resource *r;
+ const char *r_name;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
@@ -488,6 +494,8 @@ int pci_enable_resources(struct pci_dev *dev, int mask)
if (!(mask & (1 << i)))
continue;
+ r_name = pci_resource_name(dev, i);
+
if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
continue;
if ((i == PCI_ROM_RESOURCE) &&
@@ -495,14 +503,14 @@ int pci_enable_resources(struct pci_dev *dev, int mask)
continue;
if (r->flags & IORESOURCE_UNSET) {
- pci_err(dev, "can't enable device: BAR %d %pR not assigned\n",
- i, r);
+ pci_err(dev, "%s %pR: not assigned; can't enable device\n",
+ r_name, r);
return -EINVAL;
}
if (!r->parent) {
- pci_err(dev, "can't enable device: BAR %d %pR not claimed\n",
- i, r);
+ pci_err(dev, "%s %pR: not claimed; can't enable device\n",
+ r_name, r);
return -EINVAL;
}
diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c
index 5b921387eca6..1804794d0e68 100644
--- a/drivers/pci/switch/switchtec.c
+++ b/drivers/pci/switch/switchtec.c
@@ -1308,13 +1308,6 @@ static void stdev_release(struct device *dev)
{
struct switchtec_dev *stdev = to_stdev(dev);
- if (stdev->dma_mrpc) {
- iowrite32(0, &stdev->mmio_mrpc->dma_en);
- flush_wc_buf(stdev);
- writeq(0, &stdev->mmio_mrpc->dma_addr);
- dma_free_coherent(&stdev->pdev->dev, sizeof(*stdev->dma_mrpc),
- stdev->dma_mrpc, stdev->dma_mrpc_dma_addr);
- }
kfree(stdev);
}
@@ -1358,7 +1351,7 @@ static struct switchtec_dev *stdev_create(struct pci_dev *pdev)
return ERR_PTR(-ENOMEM);
stdev->alive = true;
- stdev->pdev = pdev;
+ stdev->pdev = pci_dev_get(pdev);
INIT_LIST_HEAD(&stdev->mrpc_queue);
mutex_init(&stdev->mrpc_mutex);
stdev->mrpc_busy = 0;
@@ -1391,6 +1384,7 @@ static struct switchtec_dev *stdev_create(struct pci_dev *pdev)
return stdev;
err_put:
+ pci_dev_put(stdev->pdev);
put_device(&stdev->dev);
return ERR_PTR(rc);
}
@@ -1644,6 +1638,18 @@ static int switchtec_init_pci(struct switchtec_dev *stdev,
return 0;
}
+static void switchtec_exit_pci(struct switchtec_dev *stdev)
+{
+ if (stdev->dma_mrpc) {
+ iowrite32(0, &stdev->mmio_mrpc->dma_en);
+ flush_wc_buf(stdev);
+ writeq(0, &stdev->mmio_mrpc->dma_addr);
+ dma_free_coherent(&stdev->pdev->dev, sizeof(*stdev->dma_mrpc),
+ stdev->dma_mrpc, stdev->dma_mrpc_dma_addr);
+ stdev->dma_mrpc = NULL;
+ }
+}
+
static int switchtec_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -1703,6 +1709,9 @@ static void switchtec_pci_remove(struct pci_dev *pdev)
ida_free(&switchtec_minor_ida, MINOR(stdev->dev.devt));
dev_info(&stdev->dev, "unregistered.\n");
stdev_kill(stdev);
+ switchtec_exit_pci(stdev);
+ pci_dev_put(stdev->pdev);
+ stdev->pdev = NULL;
put_device(&stdev->dev);
}
diff --git a/drivers/pcmcia/bcm63xx_pcmcia.c b/drivers/pcmcia/bcm63xx_pcmcia.c
index dd3c26099048..a5414441834a 100644
--- a/drivers/pcmcia/bcm63xx_pcmcia.c
+++ b/drivers/pcmcia/bcm63xx_pcmcia.c
@@ -437,7 +437,7 @@ err:
return ret;
}
-static int bcm63xx_drv_pcmcia_remove(struct platform_device *pdev)
+static void bcm63xx_drv_pcmcia_remove(struct platform_device *pdev)
{
struct bcm63xx_pcmcia_socket *skt;
struct resource *res;
@@ -449,12 +449,11 @@ static int bcm63xx_drv_pcmcia_remove(struct platform_device *pdev)
res = skt->reg_res;
release_mem_region(res->start, resource_size(res));
kfree(skt);
- return 0;
}
struct platform_driver bcm63xx_pcmcia_driver = {
.probe = bcm63xx_drv_pcmcia_probe,
- .remove = bcm63xx_drv_pcmcia_remove,
+ .remove_new = bcm63xx_drv_pcmcia_remove,
.driver = {
.name = "bcm63xx_pcmcia",
.owner = THIS_MODULE,
diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c
index 87a33ecc2cf1..509713b9a502 100644
--- a/drivers/pcmcia/db1xxx_ss.c
+++ b/drivers/pcmcia/db1xxx_ss.c
@@ -577,7 +577,7 @@ out0:
return ret;
}
-static int db1x_pcmcia_socket_remove(struct platform_device *pdev)
+static void db1x_pcmcia_socket_remove(struct platform_device *pdev)
{
struct db1x_pcmcia_sock *sock = platform_get_drvdata(pdev);
@@ -585,8 +585,6 @@ static int db1x_pcmcia_socket_remove(struct platform_device *pdev)
pcmcia_unregister_socket(&sock->socket);
iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
kfree(sock);
-
- return 0;
}
static struct platform_driver db1x_pcmcia_socket_driver = {
@@ -594,7 +592,7 @@ static struct platform_driver db1x_pcmcia_socket_driver = {
.name = "db1xxx_pcmcia",
},
.probe = db1x_pcmcia_socket_probe,
- .remove = db1x_pcmcia_socket_remove,
+ .remove_new = db1x_pcmcia_socket_remove,
};
module_platform_driver(db1x_pcmcia_socket_driver);
diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c
index efc27bc15152..5ae826e54811 100644
--- a/drivers/pcmcia/electra_cf.c
+++ b/drivers/pcmcia/electra_cf.c
@@ -307,7 +307,7 @@ out_free_cf:
}
-static int electra_cf_remove(struct platform_device *ofdev)
+static void electra_cf_remove(struct platform_device *ofdev)
{
struct device *device = &ofdev->dev;
struct electra_cf_socket *cf;
@@ -326,8 +326,6 @@ static int electra_cf_remove(struct platform_device *ofdev)
release_region(cf->io_base, cf->io_size);
kfree(cf);
-
- return 0;
}
static const struct of_device_id electra_cf_match[] = {
@@ -344,7 +342,7 @@ static struct platform_driver electra_cf_driver = {
.of_match_table = electra_cf_match,
},
.probe = electra_cf_probe,
- .remove = electra_cf_remove,
+ .remove_new = electra_cf_remove,
};
module_platform_driver(electra_cf_driver);
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index e613818dc0bc..80137c7afe0d 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -290,7 +290,7 @@ fail0:
return status;
}
-static int __exit omap_cf_remove(struct platform_device *pdev)
+static void __exit omap_cf_remove(struct platform_device *pdev)
{
struct omap_cf_socket *cf = platform_get_drvdata(pdev);
@@ -300,14 +300,13 @@ static int __exit omap_cf_remove(struct platform_device *pdev)
release_mem_region(cf->phys_cf, SZ_8K);
free_irq(cf->irq, cf);
kfree(cf);
- return 0;
}
static struct platform_driver omap_cf_driver = {
.driver = {
.name = driver_name,
},
- .remove = __exit_p(omap_cf_remove),
+ .remove_new = __exit_p(omap_cf_remove),
};
static int __init omap_cf_init(void)
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index 5254028354f4..457fb81b497a 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -313,15 +313,13 @@ err0:
return ret;
}
-static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev)
+static void pxa2xx_drv_pcmcia_remove(struct platform_device *dev)
{
struct skt_dev_info *sinfo = platform_get_drvdata(dev);
int i;
for (i = 0; i < sinfo->nskt; i++)
soc_pcmcia_remove_one(&sinfo->skt[i]);
-
- return 0;
}
static int pxa2xx_drv_pcmcia_resume(struct device *dev)
@@ -338,7 +336,7 @@ static const struct dev_pm_ops pxa2xx_drv_pcmcia_pm_ops = {
static struct platform_driver pxa2xx_pcmcia_driver = {
.probe = pxa2xx_drv_pcmcia_probe,
- .remove = pxa2xx_drv_pcmcia_remove,
+ .remove_new = pxa2xx_drv_pcmcia_remove,
.driver = {
.name = "pxa2xx-pcmcia",
.pm = &pxa2xx_drv_pcmcia_pm_ops,
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
index 89d4ba58c891..ccb219c38761 100644
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -158,20 +158,18 @@ static int sa11x0_drv_pcmcia_probe(struct platform_device *pdev)
return sa11xx_drv_pcmcia_add_one(skt);
}
-static int sa11x0_drv_pcmcia_remove(struct platform_device *dev)
+static void sa11x0_drv_pcmcia_remove(struct platform_device *dev)
{
struct soc_pcmcia_socket *skt;
if (dev->id == -1) {
sa11x0_drv_pcmcia_legacy_remove(dev);
- return 0;
+ return;
}
skt = platform_get_drvdata(dev);
soc_pcmcia_remove_one(skt);
-
- return 0;
}
static struct platform_driver sa11x0_pcmcia_driver = {
@@ -179,7 +177,7 @@ static struct platform_driver sa11x0_pcmcia_driver = {
.name = "sa11x0-pcmcia",
},
.probe = sa11x0_drv_pcmcia_probe,
- .remove = sa11x0_drv_pcmcia_remove,
+ .remove_new = sa11x0_drv_pcmcia_remove,
};
/* sa11x0_pcmcia_init()
diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c
index b11c7abb1dc0..2a93fbbd128d 100644
--- a/drivers/pcmcia/xxs1500_ss.c
+++ b/drivers/pcmcia/xxs1500_ss.c
@@ -301,7 +301,7 @@ out0:
return ret;
}
-static int xxs1500_pcmcia_remove(struct platform_device *pdev)
+static void xxs1500_pcmcia_remove(struct platform_device *pdev)
{
struct xxs1500_pcmcia_sock *sock = platform_get_drvdata(pdev);
@@ -309,8 +309,6 @@ static int xxs1500_pcmcia_remove(struct platform_device *pdev)
free_irq(gpio_to_irq(GPIO_CDA), sock);
iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
kfree(sock);
-
- return 0;
}
static struct platform_driver xxs1500_pcmcia_socket_driver = {
@@ -318,7 +316,7 @@ static struct platform_driver xxs1500_pcmcia_socket_driver = {
.name = "xxs1500_pcmcia",
},
.probe = xxs1500_pcmcia_probe,
- .remove = xxs1500_pcmcia_remove,
+ .remove_new = xxs1500_pcmcia_remove,
};
module_platform_driver(xxs1500_pcmcia_socket_driver);
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index b11144bb448c..8163a5983166 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -484,6 +484,22 @@ config PINCTRL_TB10X
depends on OF && ARC_PLAT_TB10X
select GPIOLIB
+config PINCTRL_TPS6594
+ tristate "Pinctrl and GPIO driver for TI TPS6594 PMIC"
+ depends on OF && MFD_TPS6594
+ default MFD_TPS6594
+ select PINMUX
+ select GPIOLIB
+ select REGMAP
+ select GPIO_REGMAP
+ select GENERIC_PINCONF
+ help
+ Say Y to select the pinmuxing and GPIOs driver for the TPS6594
+ PMICs chip family.
+
+ This driver can also be built as a module
+ called tps6594-pinctrl.
+
config PINCTRL_ZYNQ
bool "Pinctrl driver for Xilinx Zynq"
depends on ARCH_ZYNQ
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 7ac5d59c83e7..1071f301cc70 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o
obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o
obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o
+obj-$(CONFIG_PINCTRL_TPS6594) += pinctrl-tps6594.o
obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o
obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o
diff --git a/drivers/pinctrl/bcm/pinctrl-ns.c b/drivers/pinctrl/bcm/pinctrl-ns.c
index d099a7f25f64..6bb2b461950b 100644
--- a/drivers/pinctrl/bcm/pinctrl-ns.c
+++ b/drivers/pinctrl/bcm/pinctrl-ns.c
@@ -171,8 +171,8 @@ static int ns_pinctrl_set_mux(struct pinctrl_dev *pctrl_dev,
if (!group)
return -EINVAL;
- for (i = 0; i < group->num_pins; i++)
- unset |= BIT(group->pins[i]);
+ for (i = 0; i < group->grp.npins; i++)
+ unset |= BIT(group->grp.pins[i]);
tmp = readl(ns_pinctrl->base);
tmp &= ~unset;
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index f2977eb65522..ee56856cb80c 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -13,6 +13,7 @@
#define pr_fmt(fmt) "pinctrl core: " fmt
#include <linux/array_size.h>
+#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -23,6 +24,7 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
+#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/pinctrl/consumer.h>
@@ -30,10 +32,6 @@
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinctrl.h>
-#ifdef CONFIG_GPIOLIB
-#include "../gpio/gpiolib.h"
-#endif
-
#include "core.h"
#include "devicetree.h"
#include "pinconf.h"
@@ -145,7 +143,7 @@ struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np)
*/
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name)
{
- unsigned i, pin;
+ unsigned int i, pin;
/* The pin number can be retrived from the pin controller descriptor */
for (i = 0; i < pctldev->desc->npins; i++) {
@@ -166,7 +164,7 @@ int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name)
* @pctldev: the pin control device to lookup the pin on
* @pin: pin number/id to look up
*/
-const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin)
+const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned int pin)
{
const struct pin_desc *desc;
@@ -184,7 +182,7 @@ EXPORT_SYMBOL_GPL(pin_get_name);
/* Deletes a range of pin descriptors */
static void pinctrl_free_pindescs(struct pinctrl_dev *pctldev,
const struct pinctrl_pin_desc *pins,
- unsigned num_pins)
+ unsigned int num_pins)
{
int i;
@@ -252,9 +250,9 @@ failed:
static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
const struct pinctrl_pin_desc *pins,
- unsigned num_descs)
+ unsigned int num_descs)
{
- unsigned i;
+ unsigned int i;
int ret = 0;
for (i = 0; i < num_descs; i++) {
@@ -428,7 +426,7 @@ EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *ranges,
- unsigned nranges)
+ unsigned int nranges)
{
int i;
@@ -459,7 +457,7 @@ struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range);
int pinctrl_get_group_pins(struct pinctrl_dev *pctldev, const char *pin_group,
- const unsigned **pins, unsigned *num_pins)
+ const unsigned int **pins, unsigned int *num_pins)
{
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
int gs;
@@ -559,7 +557,7 @@ const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev,
if (!group)
return NULL;
- return group->name;
+ return group->grp.name;
}
EXPORT_SYMBOL_GPL(pinctrl_generic_get_group_name);
@@ -585,8 +583,8 @@ int pinctrl_generic_get_group_pins(struct pinctrl_dev *pctldev,
return -EINVAL;
}
- *pins = group->pins;
- *num_pins = group->num_pins;
+ *pins = group->grp.pins;
+ *num_pins = group->grp.npins;
return 0;
}
@@ -642,7 +640,7 @@ static int pinctrl_generic_group_name_to_selector(struct pinctrl_dev *pctldev,
* Note that the caller must take care of locking.
*/
int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name,
- int *pins, int num_pins, void *data)
+ const unsigned int *pins, int num_pins, void *data)
{
struct group_desc *group;
int selector, error;
@@ -660,10 +658,7 @@ int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name,
if (!group)
return -ENOMEM;
- group->name = name;
- group->pins = pins;
- group->num_pins = num_pins;
- group->data = data;
+ *group = PINCTRL_GROUP_DESC(name, pins, num_pins, data);
error = radix_tree_insert(&pctldev->pin_group_tree, selector, group);
if (error)
@@ -734,8 +729,8 @@ int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
const char *pin_group)
{
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
- unsigned ngroups = pctlops->get_groups_count(pctldev);
- unsigned group_selector = 0;
+ unsigned int ngroups = pctlops->get_groups_count(pctldev);
+ unsigned int group_selector = 0;
while (group_selector < ngroups) {
const char *gname = pctlops->get_group_name(pctldev,
@@ -1432,7 +1427,7 @@ EXPORT_SYMBOL_GPL(devm_pinctrl_put);
* @num_maps: the number of maps in the mapping table
*/
int pinctrl_register_mappings(const struct pinctrl_map *maps,
- unsigned num_maps)
+ unsigned int num_maps)
{
int i, ret;
struct pinctrl_maps *maps_node;
@@ -1647,10 +1642,10 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
{
struct pinctrl_dev *pctldev = s->private;
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
- unsigned i, pin;
+ unsigned int i, pin;
#ifdef CONFIG_GPIOLIB
+ struct gpio_device *gdev __free(gpio_device_put) = NULL;
struct pinctrl_gpio_range *range;
- struct gpio_chip *chip;
int gpio_num;
#endif
@@ -1685,11 +1680,11 @@ static int pinctrl_pins_show(struct seq_file *s, void *what)
* we need to get rid of the range->base eventually and
* get the descriptor directly from the gpio_chip.
*/
- chip = gpiod_to_chip(gpio_to_desc(gpio_num));
- else
- chip = NULL;
- if (chip)
- seq_printf(s, "%u:%s ", gpio_num - chip->gpiodev->base, chip->label);
+ gdev = gpiod_to_gpio_device(gpio_to_desc(gpio_num));
+ if (gdev)
+ seq_printf(s, "%u:%s ",
+ gpio_num - gpio_device_get_base(gdev),
+ gpio_device_get_label(gdev));
else
seq_puts(s, "0:? ");
#endif
@@ -1711,7 +1706,7 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
{
struct pinctrl_dev *pctldev = s->private;
const struct pinctrl_ops *ops = pctldev->desc->pctlops;
- unsigned ngroups, selector = 0;
+ unsigned int ngroups, selector = 0;
mutex_lock(&pctldev->mutex);
@@ -1719,8 +1714,8 @@ static int pinctrl_groups_show(struct seq_file *s, void *what)
seq_puts(s, "registered pin groups:\n");
while (selector < ngroups) {
- const unsigned *pins = NULL;
- unsigned num_pins = 0;
+ const unsigned int *pins = NULL;
+ unsigned int num_pins = 0;
const char *gname = ops->get_group_name(pctldev, selector);
const char *pname;
int ret = 0;
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index 530370443c19..837fd5bd903d 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -111,8 +111,8 @@ struct pinctrl_state {
* @func: the function selector to program
*/
struct pinctrl_setting_mux {
- unsigned group;
- unsigned func;
+ unsigned int group;
+ unsigned int func;
};
/**
@@ -124,9 +124,9 @@ struct pinctrl_setting_mux {
* @num_configs: the number of entries in array @configs
*/
struct pinctrl_setting_configs {
- unsigned group_or_pin;
+ unsigned int group_or_pin;
unsigned long *configs;
- unsigned num_configs;
+ unsigned int num_configs;
};
/**
@@ -173,7 +173,7 @@ struct pin_desc {
void *drv_data;
/* These fields only added when supporting pinmux drivers */
#ifdef CONFIG_PINMUX
- unsigned mux_usecount;
+ unsigned int mux_usecount;
const char *mux_owner;
const struct pinctrl_setting_mux *mux_setting;
const char *gpio_owner;
@@ -189,25 +189,30 @@ struct pin_desc {
struct pinctrl_maps {
struct list_head node;
const struct pinctrl_map *maps;
- unsigned num_maps;
+ unsigned int num_maps;
};
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
+#include <linux/pinctrl/pinctrl.h>
+
/**
* struct group_desc - generic pin group descriptor
- * @name: name of the pin group
- * @pins: array of pins that belong to the group
- * @num_pins: number of pins in the group
+ * @grp: generic data of the pin group (name and pins)
* @data: pin controller driver specific data
*/
struct group_desc {
- const char *name;
- int *pins;
- int num_pins;
+ struct pingroup grp;
void *data;
};
+/* Convenience macro to define a generic pin group descriptor */
+#define PINCTRL_GROUP_DESC(_name, _pins, _num_pins, _data) \
+(struct group_desc) { \
+ .grp = PINCTRL_PINGROUP(_name, _pins, _num_pins), \
+ .data = _data, \
+}
+
int pinctrl_generic_get_group_count(struct pinctrl_dev *pctldev);
const char *pinctrl_generic_get_group_name(struct pinctrl_dev *pctldev,
@@ -222,7 +227,7 @@ struct group_desc *pinctrl_generic_get_group(struct pinctrl_dev *pctldev,
unsigned int group_selector);
int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name,
- int *gpins, int ngpins, void *data);
+ const unsigned int *pins, int num_pins, void *data);
int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev,
unsigned int group_selector);
@@ -232,7 +237,7 @@ int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev,
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np);
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
-const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin);
+const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned int pin);
int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
const char *pin_group);
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index 6e0a40962f38..df1efc2e5202 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -24,11 +24,11 @@ struct pinctrl_dt_map {
struct list_head node;
struct pinctrl_dev *pctldev;
struct pinctrl_map *map;
- unsigned num_maps;
+ unsigned int num_maps;
};
static void dt_free_map(struct pinctrl_dev *pctldev,
- struct pinctrl_map *map, unsigned num_maps)
+ struct pinctrl_map *map, unsigned int num_maps)
{
int i;
@@ -64,7 +64,7 @@ void pinctrl_dt_free_maps(struct pinctrl *p)
static int dt_remember_or_free_map(struct pinctrl *p, const char *statename,
struct pinctrl_dev *pctldev,
- struct pinctrl_map *map, unsigned num_maps)
+ struct pinctrl_map *map, unsigned int num_maps)
{
int i;
struct pinctrl_dt_map *dt_map;
@@ -116,7 +116,7 @@ static int dt_to_map_one_config(struct pinctrl *p,
const struct pinctrl_ops *ops;
int ret;
struct pinctrl_map *map;
- unsigned num_maps;
+ unsigned int num_maps;
bool allow_default = false;
/* Find the pin controller containing np_config */
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c
index 9bc16943014f..2d3d80921c0d 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx.c
@@ -42,7 +42,7 @@ static inline const struct group_desc *imx_pinctrl_find_group_by_name(
for (i = 0; i < pctldev->num_groups; i++) {
grp = pinctrl_generic_get_group(pctldev, i);
- if (grp && !strcmp(grp->name, name))
+ if (grp && !strcmp(grp->grp.name, name))
break;
}
@@ -79,9 +79,9 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
}
if (info->flags & IMX_USE_SCU) {
- map_num += grp->num_pins;
+ map_num += grp->grp.npins;
} else {
- for (i = 0; i < grp->num_pins; i++) {
+ for (i = 0; i < grp->grp.npins; i++) {
pin = &((struct imx_pin *)(grp->data))[i];
if (!(pin->conf.mmio.config & IMX_NO_PAD_CTL))
map_num++;
@@ -109,7 +109,7 @@ static int imx_dt_node_to_map(struct pinctrl_dev *pctldev,
/* create config map */
new_map++;
- for (i = j = 0; i < grp->num_pins; i++) {
+ for (i = j = 0; i < grp->grp.npins; i++) {
pin = &((struct imx_pin *)(grp->data))[i];
/*
@@ -263,10 +263,10 @@ static int imx_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
if (!func)
return -EINVAL;
- npins = grp->num_pins;
+ npins = grp->grp.npins;
dev_dbg(ipctl->dev, "enable function %s group %s\n",
- func->name, grp->name);
+ func->name, grp->grp.name);
for (i = 0; i < npins; i++) {
/*
@@ -423,7 +423,7 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
if (!grp)
return;
- for (i = 0; i < grp->num_pins; i++) {
+ for (i = 0; i < grp->grp.npins; i++) {
struct imx_pin *pin = &((struct imx_pin *)(grp->data))[i];
name = pin_get_name(pctldev, pin->pin);
@@ -511,6 +511,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
{
const struct imx_pinctrl_soc_info *info = ipctl->info;
struct imx_pin *pin;
+ unsigned int *pins;
int size, pin_size;
const __be32 *list;
int i;
@@ -525,7 +526,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
pin_size = FSL_PIN_SIZE;
/* Initialise group */
- grp->name = np->name;
+ grp->grp.name = np->name;
/*
* the binding format is fsl,pins = <PIN_FUNC_ID CONFIG ...>,
@@ -553,24 +554,22 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
return -EINVAL;
}
- grp->num_pins = size / pin_size;
- grp->data = devm_kcalloc(ipctl->dev,
- grp->num_pins, sizeof(struct imx_pin),
- GFP_KERNEL);
- grp->pins = devm_kcalloc(ipctl->dev,
- grp->num_pins, sizeof(unsigned int),
- GFP_KERNEL);
- if (!grp->pins || !grp->data)
+ grp->grp.npins = size / pin_size;
+ grp->data = devm_kcalloc(ipctl->dev, grp->grp.npins, sizeof(*pin), GFP_KERNEL);
+ if (!grp->data)
return -ENOMEM;
- for (i = 0; i < grp->num_pins; i++) {
+ pins = devm_kcalloc(ipctl->dev, grp->grp.npins, sizeof(*pins), GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+ grp->grp.pins = pins;
+
+ for (i = 0; i < grp->grp.npins; i++) {
pin = &((struct imx_pin *)(grp->data))[i];
if (info->flags & IMX_USE_SCU)
- info->imx_pinctrl_parse_pin(ipctl, &grp->pins[i],
- pin, &list);
+ info->imx_pinctrl_parse_pin(ipctl, &pins[i], pin, &list);
else
- imx_pinctrl_parse_pin_mmio(ipctl, &grp->pins[i],
- pin, &list, np);
+ imx_pinctrl_parse_pin_mmio(ipctl, &pins[i], pin, &list, np);
}
return 0;
@@ -612,8 +611,7 @@ static int imx_pinctrl_parse_functions(struct device_node *np,
i = 0;
for_each_child_of_node(np, child) {
- grp = devm_kzalloc(ipctl->dev, sizeof(struct group_desc),
- GFP_KERNEL);
+ grp = devm_kzalloc(ipctl->dev, sizeof(*grp), GFP_KERNEL);
if (!grp) {
of_node_put(child);
return -ENOMEM;
diff --git a/drivers/pinctrl/intel/Kconfig b/drivers/pinctrl/intel/Kconfig
index d66f4f6932d8..2101d30bd66c 100644
--- a/drivers/pinctrl/intel/Kconfig
+++ b/drivers/pinctrl/intel/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
# Intel pin control drivers
menu "Intel pinctrl drivers"
- depends on ACPI && (X86 || COMPILE_TEST)
+ depends on (ACPI && X86) || COMPILE_TEST
config PINCTRL_BAYTRAIL
bool "Intel Baytrail GPIO pin control"
@@ -37,6 +37,16 @@ config PINCTRL_INTEL
select GPIOLIB
select GPIOLIB_IRQCHIP
+config PINCTRL_INTEL_PLATFORM
+ tristate "Intel pinctrl and GPIO platform driver"
+ depends on ACPI
+ select PINCTRL_INTEL
+ help
+ This pinctrl driver provides an interface that allows configuring
+ of Intel PCH pins and using them as GPIOs. Currently the following
+ Intel SoCs / platforms require this to be functional:
+ - Lunar Lake
+
config PINCTRL_ALDERLAKE
tristate "Intel Alder Lake pinctrl and GPIO driver"
select PINCTRL_INTEL
@@ -128,6 +138,15 @@ config PINCTRL_METEORLAKE
This pinctrl driver provides an interface that allows configuring
of Intel Meteor Lake pins and using them as GPIOs.
+config PINCTRL_METEORPOINT
+ tristate "Intel Meteor Point pinctrl and GPIO driver"
+ depends on ACPI
+ select PINCTRL_INTEL
+ help
+ Meteor Point is the PCH of Intel Meteor Lake. This pinctrl driver
+ provides an interface that allows configuring of PCH pins and
+ using them as GPIOs.
+
config PINCTRL_SUNRISEPOINT
tristate "Intel Sunrisepoint pinctrl and GPIO driver"
select PINCTRL_INTEL
diff --git a/drivers/pinctrl/intel/Makefile b/drivers/pinctrl/intel/Makefile
index f6d30f2d973a..d0d868c9a622 100644
--- a/drivers/pinctrl/intel/Makefile
+++ b/drivers/pinctrl/intel/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PINCTRL_TANGIER) += pinctrl-tangier.o
obj-$(CONFIG_PINCTRL_MERRIFIELD) += pinctrl-merrifield.o
obj-$(CONFIG_PINCTRL_MOOREFIELD) += pinctrl-moorefield.o
obj-$(CONFIG_PINCTRL_INTEL) += pinctrl-intel.o
+obj-$(CONFIG_PINCTRL_INTEL_PLATFORM) += pinctrl-intel-platform.o
obj-$(CONFIG_PINCTRL_ALDERLAKE) += pinctrl-alderlake.o
obj-$(CONFIG_PINCTRL_BROXTON) += pinctrl-broxton.o
obj-$(CONFIG_PINCTRL_CANNONLAKE) += pinctrl-cannonlake.o
@@ -21,5 +22,6 @@ obj-$(CONFIG_PINCTRL_JASPERLAKE) += pinctrl-jasperlake.o
obj-$(CONFIG_PINCTRL_LAKEFIELD) += pinctrl-lakefield.o
obj-$(CONFIG_PINCTRL_LEWISBURG) += pinctrl-lewisburg.o
obj-$(CONFIG_PINCTRL_METEORLAKE) += pinctrl-meteorlake.o
+obj-$(CONFIG_PINCTRL_METEORPOINT) += pinctrl-meteorpoint.o
obj-$(CONFIG_PINCTRL_SUNRISEPOINT) += pinctrl-sunrisepoint.o
obj-$(CONFIG_PINCTRL_TIGERLAKE) += pinctrl-tigerlake.o
diff --git a/drivers/pinctrl/intel/pinctrl-alderlake.c b/drivers/pinctrl/intel/pinctrl-alderlake.c
index 4a37dc273d63..7d9948e5f422 100644
--- a/drivers/pinctrl/intel/pinctrl-alderlake.c
+++ b/drivers/pinctrl/intel/pinctrl-alderlake.c
@@ -9,6 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -733,14 +734,12 @@ static const struct acpi_device_id adl_pinctrl_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, adl_pinctrl_acpi_match);
-static INTEL_PINCTRL_PM_OPS(adl_pinctrl_pm_ops);
-
static struct platform_driver adl_pinctrl_driver = {
.probe = intel_pinctrl_probe_by_hid,
.driver = {
.name = "alderlake-pinctrl",
.acpi_match_table = adl_pinctrl_acpi_match,
- .pm = &adl_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
module_platform_driver(adl_pinctrl_driver);
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index 3c8c02043481..ac97724c59ba 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -588,10 +588,9 @@ static void byt_set_group_simple_mux(struct intel_pinctrl *vg,
const struct intel_pingroup group,
unsigned int func)
{
- unsigned long flags;
int i;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
for (i = 0; i < group.grp.npins; i++) {
void __iomem *padcfg0;
@@ -609,18 +608,15 @@ static void byt_set_group_simple_mux(struct intel_pinctrl *vg,
value |= func;
writel(value, padcfg0);
}
-
- raw_spin_unlock_irqrestore(&byt_lock, flags);
}
static void byt_set_group_mixed_mux(struct intel_pinctrl *vg,
const struct intel_pingroup group,
const unsigned int *func)
{
- unsigned long flags;
int i;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
for (i = 0; i < group.grp.npins; i++) {
void __iomem *padcfg0;
@@ -638,8 +634,6 @@ static void byt_set_group_mixed_mux(struct intel_pinctrl *vg,
value |= func[i];
writel(value, padcfg0);
}
-
- raw_spin_unlock_irqrestore(&byt_lock, flags);
}
static int byt_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
@@ -677,10 +671,10 @@ static u32 byt_get_gpio_mux(struct intel_pinctrl *vg, unsigned int offset)
static void byt_gpio_clear_triggering(struct intel_pinctrl *vg, unsigned int offset)
{
void __iomem *reg = byt_gpio_reg(vg, offset, BYT_CONF0_REG);
- unsigned long flags;
u32 value;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
+
value = readl(reg);
/* Do not clear direct-irq enabled IRQs (from gpio_disable_free) */
@@ -688,7 +682,6 @@ static void byt_gpio_clear_triggering(struct intel_pinctrl *vg, unsigned int off
value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
writel(value, reg);
- raw_spin_unlock_irqrestore(&byt_lock, flags);
}
static int byt_gpio_request_enable(struct pinctrl_dev *pctl_dev,
@@ -698,9 +691,8 @@ static int byt_gpio_request_enable(struct pinctrl_dev *pctl_dev,
struct intel_pinctrl *vg = pinctrl_dev_get_drvdata(pctl_dev);
void __iomem *reg = byt_gpio_reg(vg, offset, BYT_CONF0_REG);
u32 value, gpio_mux;
- unsigned long flags;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
/*
* In most cases, func pin mux 000 means GPIO function.
@@ -713,15 +705,14 @@ static int byt_gpio_request_enable(struct pinctrl_dev *pctl_dev,
*/
value = readl(reg) & BYT_PIN_MUX;
gpio_mux = byt_get_gpio_mux(vg, offset);
- if (gpio_mux != value) {
- value = readl(reg) & ~BYT_PIN_MUX;
- value |= gpio_mux;
- writel(value, reg);
+ if (gpio_mux == value)
+ return 0;
- dev_warn(vg->dev, FW_BUG "Pin %i: forcibly re-configured as GPIO\n", offset);
- }
+ value = readl(reg) & ~BYT_PIN_MUX;
+ value |= gpio_mux;
+ writel(value, reg);
- raw_spin_unlock_irqrestore(&byt_lock, flags);
+ dev_warn(vg->dev, FW_BUG "Pin %i: forcibly re-configured as GPIO\n", offset);
return 0;
}
@@ -759,10 +750,9 @@ static int byt_gpio_set_direction(struct pinctrl_dev *pctl_dev,
{
struct intel_pinctrl *vg = pinctrl_dev_get_drvdata(pctl_dev);
void __iomem *val_reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
- unsigned long flags;
u32 value;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
value = readl(val_reg);
value &= ~BYT_DIR_MASK;
@@ -773,8 +763,6 @@ static int byt_gpio_set_direction(struct pinctrl_dev *pctl_dev,
writel(value, val_reg);
- raw_spin_unlock_irqrestore(&byt_lock, flags);
-
return 0;
}
@@ -811,6 +799,7 @@ static int byt_set_pull_strength(u32 *reg, u16 strength)
*reg &= ~BYT_PULL_STR_MASK;
switch (strength) {
+ case 1: /* Set default strength value in case none is given */
case 2000:
*reg |= BYT_PULL_STR_2K;
break;
@@ -830,6 +819,24 @@ static int byt_set_pull_strength(u32 *reg, u16 strength)
return 0;
}
+static void byt_gpio_force_input_mode(struct intel_pinctrl *vg, unsigned int offset)
+{
+ void __iomem *reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
+ u32 value;
+
+ value = readl(reg);
+ if (!(value & BYT_INPUT_EN))
+ return;
+
+ /*
+ * Pull assignment is only applicable in input mode. If
+ * chip is not in input mode, set it and warn about it.
+ */
+ value &= ~BYT_INPUT_EN;
+ writel(value, reg);
+ dev_warn(vg->dev, "Pin %i: forcibly set to input mode\n", offset);
+}
+
static int byt_pin_config_get(struct pinctrl_dev *pctl_dev, unsigned int offset,
unsigned long *config)
{
@@ -838,15 +845,15 @@ static int byt_pin_config_get(struct pinctrl_dev *pctl_dev, unsigned int offset,
void __iomem *conf_reg = byt_gpio_reg(vg, offset, BYT_CONF0_REG);
void __iomem *val_reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
void __iomem *db_reg = byt_gpio_reg(vg, offset, BYT_DEBOUNCE_REG);
- unsigned long flags;
u32 conf, pull, val, debounce;
u16 arg = 0;
- raw_spin_lock_irqsave(&byt_lock, flags);
- conf = readl(conf_reg);
+ scoped_guard(raw_spinlock_irqsave, &byt_lock) {
+ conf = readl(conf_reg);
+ val = readl(val_reg);
+ }
+
pull = conf & BYT_PULL_ASSIGN_MASK;
- val = readl(val_reg);
- raw_spin_unlock_irqrestore(&byt_lock, flags);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
@@ -873,9 +880,8 @@ static int byt_pin_config_get(struct pinctrl_dev *pctl_dev, unsigned int offset,
if (!(conf & BYT_DEBOUNCE_EN))
return -EINVAL;
- raw_spin_lock_irqsave(&byt_lock, flags);
- debounce = readl(db_reg);
- raw_spin_unlock_irqrestore(&byt_lock, flags);
+ scoped_guard(raw_spinlock_irqsave, &byt_lock)
+ debounce = readl(db_reg);
switch (debounce & BYT_DEBOUNCE_PULSE_MASK) {
case BYT_DEBOUNCE_PULSE_375US:
@@ -919,18 +925,16 @@ static int byt_pin_config_set(struct pinctrl_dev *pctl_dev,
unsigned int num_configs)
{
struct intel_pinctrl *vg = pinctrl_dev_get_drvdata(pctl_dev);
- unsigned int param, arg;
void __iomem *conf_reg = byt_gpio_reg(vg, offset, BYT_CONF0_REG);
- void __iomem *val_reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
void __iomem *db_reg = byt_gpio_reg(vg, offset, BYT_DEBOUNCE_REG);
- u32 conf, val, db_pulse, debounce;
- unsigned long flags;
- int i, ret = 0;
+ u32 conf, db_pulse, debounce;
+ enum pin_config_param param;
+ int i, ret;
+ u32 arg;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
conf = readl(conf_reg);
- val = readl(val_reg);
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(configs[i]);
@@ -941,59 +945,30 @@ static int byt_pin_config_set(struct pinctrl_dev *pctl_dev,
conf &= ~BYT_PULL_ASSIGN_MASK;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- /* Set default strength value in case none is given */
- if (arg == 1)
- arg = 2000;
-
- /*
- * Pull assignment is only applicable in input mode. If
- * chip is not in input mode, set it and warn about it.
- */
- if (val & BYT_INPUT_EN) {
- val &= ~BYT_INPUT_EN;
- writel(val, val_reg);
- dev_warn(vg->dev, "Pin %i: forcibly set to input mode\n", offset);
- }
+ byt_gpio_force_input_mode(vg, offset);
conf &= ~BYT_PULL_ASSIGN_MASK;
conf |= BYT_PULL_ASSIGN_DOWN;
ret = byt_set_pull_strength(&conf, arg);
+ if (ret)
+ return ret;
break;
case PIN_CONFIG_BIAS_PULL_UP:
- /* Set default strength value in case none is given */
- if (arg == 1)
- arg = 2000;
-
- /*
- * Pull assignment is only applicable in input mode. If
- * chip is not in input mode, set it and warn about it.
- */
- if (val & BYT_INPUT_EN) {
- val &= ~BYT_INPUT_EN;
- writel(val, val_reg);
- dev_warn(vg->dev, "Pin %i: forcibly set to input mode\n", offset);
- }
+ byt_gpio_force_input_mode(vg, offset);
conf &= ~BYT_PULL_ASSIGN_MASK;
conf |= BYT_PULL_ASSIGN_UP;
ret = byt_set_pull_strength(&conf, arg);
+ if (ret)
+ return ret;
break;
case PIN_CONFIG_INPUT_DEBOUNCE:
- if (arg) {
- conf |= BYT_DEBOUNCE_EN;
- } else {
- conf &= ~BYT_DEBOUNCE_EN;
-
- /*
- * No need to update the pulse value.
- * Debounce is going to be disabled.
- */
- break;
- }
-
switch (arg) {
+ case 0:
+ db_pulse = 0;
+ break;
case 375:
db_pulse = BYT_DEBOUNCE_PULSE_375US;
break;
@@ -1016,33 +991,28 @@ static int byt_pin_config_set(struct pinctrl_dev *pctl_dev,
db_pulse = BYT_DEBOUNCE_PULSE_24MS;
break;
default:
- if (arg)
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
- if (ret)
- break;
+ if (db_pulse) {
+ debounce = readl(db_reg);
+ debounce = (debounce & ~BYT_DEBOUNCE_PULSE_MASK) | db_pulse;
+ writel(debounce, db_reg);
- debounce = readl(db_reg);
- debounce = (debounce & ~BYT_DEBOUNCE_PULSE_MASK) | db_pulse;
- writel(debounce, db_reg);
+ conf |= BYT_DEBOUNCE_EN;
+ } else {
+ conf &= ~BYT_DEBOUNCE_EN;
+ }
break;
default:
- ret = -ENOTSUPP;
+ return -ENOTSUPP;
}
-
- if (ret)
- break;
}
- if (!ret)
- writel(conf, conf_reg);
-
- raw_spin_unlock_irqrestore(&byt_lock, flags);
+ writel(conf, conf_reg);
- return ret;
+ return 0;
}
static const struct pinconf_ops byt_pinconf_ops = {
@@ -1062,12 +1032,10 @@ static int byt_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct intel_pinctrl *vg = gpiochip_get_data(chip);
void __iomem *reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
- unsigned long flags;
u32 val;
- raw_spin_lock_irqsave(&byt_lock, flags);
- val = readl(reg);
- raw_spin_unlock_irqrestore(&byt_lock, flags);
+ scoped_guard(raw_spinlock_irqsave, &byt_lock)
+ val = readl(reg);
return !!(val & BYT_LEVEL);
}
@@ -1075,35 +1043,34 @@ static int byt_gpio_get(struct gpio_chip *chip, unsigned int offset)
static void byt_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct intel_pinctrl *vg = gpiochip_get_data(chip);
- void __iomem *reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
- unsigned long flags;
+ void __iomem *reg;
u32 old_val;
+ reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
if (!reg)
return;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
+
old_val = readl(reg);
if (value)
writel(old_val | BYT_LEVEL, reg);
else
writel(old_val & ~BYT_LEVEL, reg);
- raw_spin_unlock_irqrestore(&byt_lock, flags);
}
static int byt_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{
struct intel_pinctrl *vg = gpiochip_get_data(chip);
- void __iomem *reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
- unsigned long flags;
+ void __iomem *reg;
u32 value;
+ reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
if (!reg)
return -EINVAL;
- raw_spin_lock_irqsave(&byt_lock, flags);
- value = readl(reg);
- raw_spin_unlock_irqrestore(&byt_lock, flags);
+ scoped_guard(raw_spinlock_irqsave, &byt_lock)
+ value = readl(reg);
if (!(value & BYT_OUTPUT_EN))
return GPIO_LINE_DIRECTION_OUT;
@@ -1117,17 +1084,15 @@ static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
struct intel_pinctrl *vg = gpiochip_get_data(chip);
void __iomem *val_reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
- unsigned long flags;
u32 reg;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
reg = readl(val_reg);
reg &= ~BYT_DIR_MASK;
reg |= BYT_OUTPUT_EN;
writel(reg, val_reg);
- raw_spin_unlock_irqrestore(&byt_lock, flags);
return 0;
}
@@ -1142,10 +1107,9 @@ static int byt_gpio_direction_output(struct gpio_chip *chip,
{
struct intel_pinctrl *vg = gpiochip_get_data(chip);
void __iomem *val_reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
- unsigned long flags;
u32 reg;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
byt_gpio_direct_irq_check(vg, offset);
@@ -1158,7 +1122,6 @@ static int byt_gpio_direction_output(struct gpio_chip *chip,
writel(reg, val_reg);
- raw_spin_unlock_irqrestore(&byt_lock, flags);
return 0;
}
@@ -1173,7 +1136,6 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
void __iomem *conf_reg, *val_reg;
const char *pull_str = NULL;
const char *pull = NULL;
- unsigned long flags;
unsigned int pin;
pin = vg->soc->pins[i].number;
@@ -1190,10 +1152,10 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
continue;
}
- raw_spin_lock_irqsave(&byt_lock, flags);
- conf0 = readl(conf_reg);
- val = readl(val_reg);
- raw_spin_unlock_irqrestore(&byt_lock, flags);
+ scoped_guard(raw_spinlock_irqsave, &byt_lock) {
+ conf0 = readl(conf_reg);
+ val = readl(val_reg);
+ }
comm = intel_get_community(vg, pin);
if (!comm) {
@@ -1278,9 +1240,9 @@ static void byt_irq_ack(struct irq_data *d)
if (!reg)
return;
- raw_spin_lock(&byt_lock);
+ guard(raw_spinlock)(&byt_lock);
+
writel(BIT(hwirq % 32), reg);
- raw_spin_unlock(&byt_lock);
}
static void byt_irq_mask(struct irq_data *d)
@@ -1298,7 +1260,6 @@ static void byt_irq_unmask(struct irq_data *d)
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct intel_pinctrl *vg = gpiochip_get_data(gc);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
- unsigned long flags;
void __iomem *reg;
u32 value;
@@ -1308,7 +1269,8 @@ static void byt_irq_unmask(struct irq_data *d)
if (!reg)
return;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
+
value = readl(reg);
switch (irqd_get_trigger_type(d)) {
@@ -1330,23 +1292,21 @@ static void byt_irq_unmask(struct irq_data *d)
}
writel(value, reg);
-
- raw_spin_unlock_irqrestore(&byt_lock, flags);
}
static int byt_irq_type(struct irq_data *d, unsigned int type)
{
struct intel_pinctrl *vg = gpiochip_get_data(irq_data_get_irq_chip_data(d));
irq_hw_number_t hwirq = irqd_to_hwirq(d);
- u32 value;
- unsigned long flags;
void __iomem *reg;
+ u32 value;
reg = byt_gpio_reg(vg, hwirq, BYT_CONF0_REG);
if (!reg)
return -EINVAL;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
+
value = readl(reg);
WARN(value & BYT_DIRECT_IRQ_EN,
@@ -1368,8 +1328,6 @@ static int byt_irq_type(struct irq_data *d, unsigned int type)
else if (type & IRQ_TYPE_LEVEL_MASK)
irq_set_handler_locked(d, handle_level_irq);
- raw_spin_unlock_irqrestore(&byt_lock, flags);
-
return 0;
}
@@ -1401,9 +1359,8 @@ static void byt_gpio_irq_handler(struct irq_desc *desc)
continue;
}
- raw_spin_lock(&byt_lock);
- pending = readl(reg);
- raw_spin_unlock(&byt_lock);
+ scoped_guard(raw_spinlock, &byt_lock)
+ pending = readl(reg);
for_each_set_bit(pin, &pending, 32)
generic_handle_domain_irq(vg->chip.irq.domain, base + pin);
}
@@ -1666,10 +1623,9 @@ static int byt_pinctrl_probe(struct platform_device *pdev)
static int byt_gpio_suspend(struct device *dev)
{
struct intel_pinctrl *vg = dev_get_drvdata(dev);
- unsigned long flags;
int i;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
for (i = 0; i < vg->soc->npins; i++) {
void __iomem *reg;
@@ -1693,17 +1649,15 @@ static int byt_gpio_suspend(struct device *dev)
vg->context.pads[i].val = value;
}
- raw_spin_unlock_irqrestore(&byt_lock, flags);
return 0;
}
static int byt_gpio_resume(struct device *dev)
{
struct intel_pinctrl *vg = dev_get_drvdata(dev);
- unsigned long flags;
int i;
- raw_spin_lock_irqsave(&byt_lock, flags);
+ guard(raw_spinlock_irqsave)(&byt_lock);
for (i = 0; i < vg->soc->npins; i++) {
void __iomem *reg;
@@ -1743,7 +1697,6 @@ static int byt_gpio_resume(struct device *dev)
}
}
- raw_spin_unlock_irqrestore(&byt_lock, flags);
return 0;
}
diff --git a/drivers/pinctrl/intel/pinctrl-broxton.c b/drivers/pinctrl/intel/pinctrl-broxton.c
index 3118c7c8842f..d99541676630 100644
--- a/drivers/pinctrl/intel/pinctrl-broxton.c
+++ b/drivers/pinctrl/intel/pinctrl-broxton.c
@@ -9,6 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -1000,14 +1001,12 @@ static const struct platform_device_id bxt_pinctrl_platform_ids[] = {
};
MODULE_DEVICE_TABLE(platform, bxt_pinctrl_platform_ids);
-static INTEL_PINCTRL_PM_OPS(bxt_pinctrl_pm_ops);
-
static struct platform_driver bxt_pinctrl_driver = {
.probe = intel_pinctrl_probe_by_uid,
.driver = {
.name = "broxton-pinctrl",
.acpi_match_table = bxt_pinctrl_acpi_match,
- .pm = &bxt_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
.id_table = bxt_pinctrl_platform_ids,
};
diff --git a/drivers/pinctrl/intel/pinctrl-cannonlake.c b/drivers/pinctrl/intel/pinctrl-cannonlake.c
index 95976abfb785..1aa09f950be1 100644
--- a/drivers/pinctrl/intel/pinctrl-cannonlake.c
+++ b/drivers/pinctrl/intel/pinctrl-cannonlake.c
@@ -10,6 +10,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -824,14 +825,12 @@ static const struct acpi_device_id cnl_pinctrl_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, cnl_pinctrl_acpi_match);
-static INTEL_PINCTRL_PM_OPS(cnl_pinctrl_pm_ops);
-
static struct platform_driver cnl_pinctrl_driver = {
.probe = intel_pinctrl_probe_by_hid,
.driver = {
.name = "cannonlake-pinctrl",
.acpi_match_table = cnl_pinctrl_acpi_match,
- .pm = &cnl_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
module_platform_driver(cnl_pinctrl_driver);
diff --git a/drivers/pinctrl/intel/pinctrl-cedarfork.c b/drivers/pinctrl/intel/pinctrl-cedarfork.c
index a20465eb2dc6..48af8930dd1f 100644
--- a/drivers/pinctrl/intel/pinctrl-cedarfork.c
+++ b/drivers/pinctrl/intel/pinctrl-cedarfork.c
@@ -9,6 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -319,8 +320,6 @@ static const struct intel_pinctrl_soc_data cdf_soc_data = {
.ncommunities = ARRAY_SIZE(cdf_communities),
};
-static INTEL_PINCTRL_PM_OPS(cdf_pinctrl_pm_ops);
-
static const struct acpi_device_id cdf_pinctrl_acpi_match[] = {
{ "INTC3001", (kernel_ulong_t)&cdf_soc_data },
{ }
@@ -332,7 +331,7 @@ static struct platform_driver cdf_pinctrl_driver = {
.driver = {
.name = "cedarfork-pinctrl",
.acpi_match_table = cdf_pinctrl_acpi_match,
- .pm = &cdf_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
diff --git a/drivers/pinctrl/intel/pinctrl-denverton.c b/drivers/pinctrl/intel/pinctrl-denverton.c
index 562a4f9188e4..666507f54f27 100644
--- a/drivers/pinctrl/intel/pinctrl-denverton.c
+++ b/drivers/pinctrl/intel/pinctrl-denverton.c
@@ -9,6 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -249,8 +250,6 @@ static const struct intel_pinctrl_soc_data dnv_soc_data = {
.ncommunities = ARRAY_SIZE(dnv_communities),
};
-static INTEL_PINCTRL_PM_OPS(dnv_pinctrl_pm_ops);
-
static const struct acpi_device_id dnv_pinctrl_acpi_match[] = {
{ "INTC3000", (kernel_ulong_t)&dnv_soc_data },
{ }
@@ -268,7 +267,7 @@ static struct platform_driver dnv_pinctrl_driver = {
.driver = {
.name = "denverton-pinctrl",
.acpi_match_table = dnv_pinctrl_acpi_match,
- .pm = &dnv_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
.id_table = dnv_pinctrl_platform_ids,
};
diff --git a/drivers/pinctrl/intel/pinctrl-elkhartlake.c b/drivers/pinctrl/intel/pinctrl-elkhartlake.c
index 81581ab85316..1678634ebc06 100644
--- a/drivers/pinctrl/intel/pinctrl-elkhartlake.c
+++ b/drivers/pinctrl/intel/pinctrl-elkhartlake.c
@@ -9,6 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -485,14 +486,12 @@ static const struct acpi_device_id ehl_pinctrl_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, ehl_pinctrl_acpi_match);
-static INTEL_PINCTRL_PM_OPS(ehl_pinctrl_pm_ops);
-
static struct platform_driver ehl_pinctrl_driver = {
.probe = intel_pinctrl_probe_by_uid,
.driver = {
.name = "elkhartlake-pinctrl",
.acpi_match_table = ehl_pinctrl_acpi_match,
- .pm = &ehl_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
module_platform_driver(ehl_pinctrl_driver);
diff --git a/drivers/pinctrl/intel/pinctrl-emmitsburg.c b/drivers/pinctrl/intel/pinctrl-emmitsburg.c
index 099ec8351d5f..e4798d32492c 100644
--- a/drivers/pinctrl/intel/pinctrl-emmitsburg.c
+++ b/drivers/pinctrl/intel/pinctrl-emmitsburg.c
@@ -9,6 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -358,14 +359,12 @@ static const struct acpi_device_id ebg_pinctrl_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, ebg_pinctrl_acpi_match);
-static INTEL_PINCTRL_PM_OPS(ebg_pinctrl_pm_ops);
-
static struct platform_driver ebg_pinctrl_driver = {
.probe = intel_pinctrl_probe_by_hid,
.driver = {
.name = "emmitsburg-pinctrl",
.acpi_match_table = ebg_pinctrl_acpi_match,
- .pm = &ebg_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
module_platform_driver(ebg_pinctrl_driver);
diff --git a/drivers/pinctrl/intel/pinctrl-geminilake.c b/drivers/pinctrl/intel/pinctrl-geminilake.c
index 9effa06b61e9..6dcf0ac2059f 100644
--- a/drivers/pinctrl/intel/pinctrl-geminilake.c
+++ b/drivers/pinctrl/intel/pinctrl-geminilake.c
@@ -9,6 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -447,14 +448,12 @@ static const struct acpi_device_id glk_pinctrl_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, glk_pinctrl_acpi_match);
-static INTEL_PINCTRL_PM_OPS(glk_pinctrl_pm_ops);
-
static struct platform_driver glk_pinctrl_driver = {
.probe = intel_pinctrl_probe_by_uid,
.driver = {
.name = "geminilake-pinctrl",
.acpi_match_table = glk_pinctrl_acpi_match,
- .pm = &glk_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
diff --git a/drivers/pinctrl/intel/pinctrl-icelake.c b/drivers/pinctrl/intel/pinctrl-icelake.c
index 300e1538c8d0..fe3042de891a 100644
--- a/drivers/pinctrl/intel/pinctrl-icelake.c
+++ b/drivers/pinctrl/intel/pinctrl-icelake.c
@@ -10,6 +10,7 @@
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -668,8 +669,6 @@ static const struct intel_pinctrl_soc_data icln_soc_data = {
.ncommunities = ARRAY_SIZE(icln_communities),
};
-static INTEL_PINCTRL_PM_OPS(icl_pinctrl_pm_ops);
-
static const struct acpi_device_id icl_pinctrl_acpi_match[] = {
{ "INT3455", (kernel_ulong_t)&icllp_soc_data },
{ "INT34C3", (kernel_ulong_t)&icln_soc_data },
@@ -682,7 +681,7 @@ static struct platform_driver icl_pinctrl_driver = {
.driver = {
.name = "icelake-pinctrl",
.acpi_match_table = icl_pinctrl_acpi_match,
- .pm = &icl_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
module_platform_driver(icl_pinctrl_driver);
diff --git a/drivers/pinctrl/intel/pinctrl-intel-platform.c b/drivers/pinctrl/intel/pinctrl-intel-platform.c
new file mode 100644
index 000000000000..4a19ab3b4ba7
--- /dev/null
+++ b/drivers/pinctrl/intel/pinctrl-intel-platform.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel PCH pinctrl/GPIO driver
+ *
+ * Copyright (C) 2021-2023, Intel Corporation
+ * Author: Andy Shevchenko <[email protected]>
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/property.h>
+#include <linux/string_helpers.h>
+
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-intel.h"
+
+struct intel_platform_pins {
+ struct pinctrl_pin_desc *pins;
+ size_t npins;
+};
+
+static int intel_platform_pinctrl_prepare_pins(struct device *dev, size_t base,
+ const char *name, u32 size,
+ struct intel_platform_pins *pins)
+{
+ struct pinctrl_pin_desc *descs;
+ char **pin_names;
+ unsigned int i;
+
+ pin_names = devm_kasprintf_strarray(dev, name, size);
+ if (IS_ERR(pin_names))
+ return PTR_ERR(pin_names);
+
+ descs = devm_krealloc_array(dev, pins->pins, base + size, sizeof(*descs), GFP_KERNEL);
+ if (!descs)
+ return -ENOMEM;
+
+ for (i = 0; i < size; i++) {
+ unsigned int pin_number = base + i;
+ char *pin_name = pin_names[i];
+ struct pinctrl_pin_desc *desc;
+
+ /* Unify delimiter for pin name */
+ strreplace(pin_name, '-', '_');
+
+ desc = &descs[pin_number];
+ desc->number = pin_number;
+ desc->name = pin_name;
+ }
+
+ pins->pins = descs;
+ pins->npins = base + size;
+
+ return 0;
+}
+
+static int intel_platform_pinctrl_prepare_group(struct device *dev,
+ struct fwnode_handle *child,
+ struct intel_padgroup *gpp,
+ struct intel_platform_pins *pins)
+{
+ size_t base = pins->npins;
+ const char *name;
+ u32 size;
+ int ret;
+
+ ret = fwnode_property_read_string(child, "intc-gpio-group-name", &name);
+ if (ret)
+ return ret;
+
+ ret = fwnode_property_read_u32(child, "intc-gpio-pad-count", &size);
+ if (ret)
+ return ret;
+
+ ret = intel_platform_pinctrl_prepare_pins(dev, base, name, size, pins);
+ if (ret)
+ return ret;
+
+ gpp->base = base;
+ gpp->size = size;
+ gpp->gpio_base = INTEL_GPIO_BASE_MATCH;
+
+ return 0;
+}
+
+static int intel_platform_pinctrl_prepare_community(struct device *dev,
+ struct intel_community *community,
+ struct intel_platform_pins *pins)
+{
+ struct fwnode_handle *child;
+ struct intel_padgroup *gpps;
+ unsigned int group;
+ size_t ngpps;
+ u32 offset;
+ int ret;
+
+ ret = device_property_read_u32(dev, "intc-gpio-pad-ownership-offset", &offset);
+ if (ret)
+ return ret;
+ community->padown_offset = offset;
+
+ ret = device_property_read_u32(dev, "intc-gpio-pad-configuration-lock-offset", &offset);
+ if (ret)
+ return ret;
+ community->padcfglock_offset = offset;
+
+ ret = device_property_read_u32(dev, "intc-gpio-host-software-pad-ownership-offset", &offset);
+ if (ret)
+ return ret;
+ community->hostown_offset = offset;
+
+ ret = device_property_read_u32(dev, "intc-gpio-gpi-interrupt-status-offset", &offset);
+ if (ret)
+ return ret;
+ community->is_offset = offset;
+
+ ret = device_property_read_u32(dev, "intc-gpio-gpi-interrupt-enable-offset", &offset);
+ if (ret)
+ return ret;
+ community->ie_offset = offset;
+
+ ngpps = device_get_child_node_count(dev);
+ if (!ngpps)
+ return -ENODEV;
+
+ gpps = devm_kcalloc(dev, ngpps, sizeof(*gpps), GFP_KERNEL);
+ if (!gpps)
+ return -ENOMEM;
+
+ group = 0;
+ device_for_each_child_node(dev, child) {
+ struct intel_padgroup *gpp = &gpps[group];
+
+ gpp->reg_num = group;
+
+ ret = intel_platform_pinctrl_prepare_group(dev, child, gpp, pins);
+ if (ret)
+ return ret;
+
+ group++;
+ }
+
+ community->ngpps = ngpps;
+ community->gpps = gpps;
+
+ return 0;
+}
+
+static int intel_platform_pinctrl_prepare_soc_data(struct device *dev,
+ struct intel_pinctrl_soc_data *data)
+{
+ struct intel_platform_pins pins = {};
+ struct intel_community *communities;
+ size_t ncommunities;
+ unsigned int i;
+ int ret;
+
+ /* Version 1.0 of the specification assumes only a single community per device node */
+ ncommunities = 1,
+ communities = devm_kcalloc(dev, ncommunities, sizeof(*communities), GFP_KERNEL);
+ if (!communities)
+ return -ENOMEM;
+
+ for (i = 0; i < ncommunities; i++) {
+ struct intel_community *community = &communities[i];
+
+ community->barno = i;
+ community->pin_base = pins.npins;
+
+ ret = intel_platform_pinctrl_prepare_community(dev, community, &pins);
+ if (ret)
+ return ret;
+
+ community->npins = pins.npins - community->pin_base;
+ }
+
+ data->ncommunities = ncommunities;
+ data->communities = communities;
+
+ data->npins = pins.npins;
+ data->pins = pins.pins;
+
+ return 0;
+}
+
+static int intel_platform_pinctrl_probe(struct platform_device *pdev)
+{
+ struct intel_pinctrl_soc_data *data;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ ret = intel_platform_pinctrl_prepare_soc_data(dev, data);
+ if (ret)
+ return ret;
+
+ return intel_pinctrl_probe(pdev, data);
+}
+
+static const struct acpi_device_id intel_platform_pinctrl_acpi_match[] = {
+ { "INTC105F" },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, intel_platform_pinctrl_acpi_match);
+
+static struct platform_driver intel_platform_pinctrl_driver = {
+ .probe = intel_platform_pinctrl_probe,
+ .driver = {
+ .name = "intel-pinctrl",
+ .acpi_match_table = intel_platform_pinctrl_acpi_match,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
+ },
+};
+module_platform_driver(intel_platform_pinctrl_driver);
+
+MODULE_AUTHOR("Andy Shevchenko <[email protected]>");
+MODULE_DESCRIPTION("Intel PCH pinctrl/GPIO driver");
+MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(PINCTRL_INTEL);
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 652ba451f885..d6f29e6faab7 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -677,10 +677,6 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin,
u32 term = 0, up = 0, value;
void __iomem *padcfg1;
- /* Set default strength value in case none is given */
- if (arg == 1)
- arg = 5000;
-
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
break;
@@ -690,6 +686,7 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin,
case 20000:
term = PADCFG1_TERM_20K;
break;
+ case 1: /* Set default strength value in case none is given */
case 5000:
term = PADCFG1_TERM_5K;
break;
@@ -716,6 +713,7 @@ static int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin,
case 20000:
term = PADCFG1_TERM_20K;
break;
+ case 1: /* Set default strength value in case none is given */
case 5000:
term = PADCFG1_TERM_5K;
break;
@@ -899,7 +897,7 @@ static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned int offset,
*
* Return: a GPIO offset, or negative error code if translation can't be done.
*/
-static __maybe_unused int intel_pin_to_gpio(struct intel_pinctrl *pctrl, int pin)
+static int intel_pin_to_gpio(struct intel_pinctrl *pctrl, int pin)
{
const struct intel_community *community;
const struct intel_padgroup *padgrp;
@@ -1506,8 +1504,8 @@ static int intel_pinctrl_probe_pwm(struct intel_pinctrl *pctrl,
return PTR_ERR_OR_ZERO(pwm);
}
-static int intel_pinctrl_probe(struct platform_device *pdev,
- const struct intel_pinctrl_soc_data *soc_data)
+int intel_pinctrl_probe(struct platform_device *pdev,
+ const struct intel_pinctrl_soc_data *soc_data)
{
struct device *dev = &pdev->dev;
struct intel_pinctrl *pctrl;
@@ -1625,6 +1623,7 @@ static int intel_pinctrl_probe(struct platform_device *pdev,
return 0;
}
+EXPORT_SYMBOL_NS_GPL(intel_pinctrl_probe, PINCTRL_INTEL);
int intel_pinctrl_probe_by_hid(struct platform_device *pdev)
{
@@ -1653,7 +1652,7 @@ EXPORT_SYMBOL_NS_GPL(intel_pinctrl_probe_by_uid, PINCTRL_INTEL);
const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev)
{
const struct intel_pinctrl_soc_data * const *table;
- const struct intel_pinctrl_soc_data *data = NULL;
+ const struct intel_pinctrl_soc_data *data;
struct device *dev = &pdev->dev;
table = device_get_match_data(dev);
@@ -1662,11 +1661,10 @@ const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_
unsigned int i;
for (i = 0; table[i]; i++) {
- if (acpi_dev_uid_match(adev, table[i]->uid)) {
- data = table[i];
+ if (acpi_dev_uid_match(adev, table[i]->uid))
break;
- }
}
+ data = table[i];
} else {
const struct platform_device_id *id;
@@ -1682,7 +1680,6 @@ const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_
}
EXPORT_SYMBOL_NS_GPL(intel_pinctrl_get_soc_data, PINCTRL_INTEL);
-#ifdef CONFIG_PM_SLEEP
static bool __intel_gpio_is_direct_irq(u32 value)
{
return (value & PADCFG0_GPIROUTIOXAPIC) && (value & PADCFG0_GPIOTXDIS) &&
@@ -1728,7 +1725,7 @@ static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int
return false;
}
-int intel_pinctrl_suspend_noirq(struct device *dev)
+static int intel_pinctrl_suspend_noirq(struct device *dev)
{
struct intel_pinctrl *pctrl = dev_get_drvdata(dev);
struct intel_community_context *communities;
@@ -1771,7 +1768,6 @@ int intel_pinctrl_suspend_noirq(struct device *dev)
return 0;
}
-EXPORT_SYMBOL_GPL(intel_pinctrl_suspend_noirq);
static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value)
{
@@ -1838,7 +1834,7 @@ static void intel_restore_padcfg(struct intel_pinctrl *pctrl, unsigned int pin,
dev_dbg(dev, "restored pin %u padcfg%u %#08x\n", pin, n, readl(padcfg));
}
-int intel_pinctrl_resume_noirq(struct device *dev)
+static int intel_pinctrl_resume_noirq(struct device *dev)
{
struct intel_pinctrl *pctrl = dev_get_drvdata(dev);
const struct intel_community_context *communities;
@@ -1882,8 +1878,10 @@ int intel_pinctrl_resume_noirq(struct device *dev)
return 0;
}
-EXPORT_SYMBOL_GPL(intel_pinctrl_resume_noirq);
-#endif
+
+EXPORT_NS_GPL_DEV_SLEEP_PM_OPS(intel_pinctrl_pm_ops, PINCTRL_INTEL) = {
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend_noirq, intel_pinctrl_resume_noirq)
+};
MODULE_AUTHOR("Mathias Nyman <[email protected]>");
MODULE_AUTHOR("Mika Westerberg <[email protected]>");
diff --git a/drivers/pinctrl/intel/pinctrl-intel.h b/drivers/pinctrl/intel/pinctrl-intel.h
index 2bb553598e8b..fde65e18cd14 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.h
+++ b/drivers/pinctrl/intel/pinctrl-intel.h
@@ -252,19 +252,13 @@ struct intel_pinctrl {
int irq;
};
+int intel_pinctrl_probe(struct platform_device *pdev,
+ const struct intel_pinctrl_soc_data *soc_data);
+
int intel_pinctrl_probe_by_hid(struct platform_device *pdev);
int intel_pinctrl_probe_by_uid(struct platform_device *pdev);
-#ifdef CONFIG_PM_SLEEP
-int intel_pinctrl_suspend_noirq(struct device *dev);
-int intel_pinctrl_resume_noirq(struct device *dev);
-#endif
-
-#define INTEL_PINCTRL_PM_OPS(_name) \
-const struct dev_pm_ops _name = { \
- SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(intel_pinctrl_suspend_noirq, \
- intel_pinctrl_resume_noirq) \
-}
+extern const struct dev_pm_ops intel_pinctrl_pm_ops;
struct intel_community *intel_get_community(struct intel_pinctrl *pctrl, unsigned int pin);
diff --git a/drivers/pinctrl/intel/pinctrl-jasperlake.c b/drivers/pinctrl/intel/pinctrl-jasperlake.c
index 50f137deed9c..3525480428ea 100644
--- a/drivers/pinctrl/intel/pinctrl-jasperlake.c
+++ b/drivers/pinctrl/intel/pinctrl-jasperlake.c
@@ -9,6 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -326,14 +327,12 @@ static const struct acpi_device_id jsl_pinctrl_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, jsl_pinctrl_acpi_match);
-static INTEL_PINCTRL_PM_OPS(jsl_pinctrl_pm_ops);
-
static struct platform_driver jsl_pinctrl_driver = {
.probe = intel_pinctrl_probe_by_hid,
.driver = {
.name = "jasperlake-pinctrl",
.acpi_match_table = jsl_pinctrl_acpi_match,
- .pm = &jsl_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
module_platform_driver(jsl_pinctrl_driver);
diff --git a/drivers/pinctrl/intel/pinctrl-lakefield.c b/drivers/pinctrl/intel/pinctrl-lakefield.c
index 0b94e11b78ac..adef85db82ca 100644
--- a/drivers/pinctrl/intel/pinctrl-lakefield.c
+++ b/drivers/pinctrl/intel/pinctrl-lakefield.c
@@ -9,6 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -347,14 +348,12 @@ static const struct acpi_device_id lkf_pinctrl_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, lkf_pinctrl_acpi_match);
-static INTEL_PINCTRL_PM_OPS(lkf_pinctrl_pm_ops);
-
static struct platform_driver lkf_pinctrl_driver = {
.probe = intel_pinctrl_probe_by_hid,
.driver = {
.name = "lakefield-pinctrl",
.acpi_match_table = lkf_pinctrl_acpi_match,
- .pm = &lkf_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
module_platform_driver(lkf_pinctrl_driver);
diff --git a/drivers/pinctrl/intel/pinctrl-lewisburg.c b/drivers/pinctrl/intel/pinctrl-lewisburg.c
index aa725a5d62b9..a304d30ea9ed 100644
--- a/drivers/pinctrl/intel/pinctrl-lewisburg.c
+++ b/drivers/pinctrl/intel/pinctrl-lewisburg.c
@@ -9,6 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -301,8 +302,6 @@ static const struct intel_pinctrl_soc_data lbg_soc_data = {
.ncommunities = ARRAY_SIZE(lbg_communities),
};
-static INTEL_PINCTRL_PM_OPS(lbg_pinctrl_pm_ops);
-
static const struct acpi_device_id lbg_pinctrl_acpi_match[] = {
{ "INT3536", (kernel_ulong_t)&lbg_soc_data },
{ }
@@ -314,7 +313,7 @@ static struct platform_driver lbg_pinctrl_driver = {
.driver = {
.name = "lewisburg-pinctrl",
.acpi_match_table = lbg_pinctrl_acpi_match,
- .pm = &lbg_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
module_platform_driver(lbg_pinctrl_driver);
diff --git a/drivers/pinctrl/intel/pinctrl-lynxpoint.c b/drivers/pinctrl/intel/pinctrl-lynxpoint.c
index e6878e4cf20c..1fb0bba8b386 100644
--- a/drivers/pinctrl/intel/pinctrl-lynxpoint.c
+++ b/drivers/pinctrl/intel/pinctrl-lynxpoint.c
@@ -10,6 +10,7 @@
#include <linux/acpi.h>
#include <linux/array_size.h>
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -291,10 +292,9 @@ static int lp_pinmux_set_mux(struct pinctrl_dev *pctldev,
{
struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev);
const struct intel_pingroup *grp = &lg->soc->groups[group];
- unsigned long flags;
int i;
- raw_spin_lock_irqsave(&lg->lock, flags);
+ guard(raw_spinlock_irqsave)(&lg->lock);
/* Now enable the mux setting for each pin in the group */
for (i = 0; i < grp->grp.npins; i++) {
@@ -312,8 +312,6 @@ static int lp_pinmux_set_mux(struct pinctrl_dev *pctldev,
iowrite32(value, reg);
}
- raw_spin_unlock_irqrestore(&lg->lock, flags);
-
return 0;
}
@@ -334,10 +332,9 @@ static int lp_gpio_request_enable(struct pinctrl_dev *pctldev,
struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev);
void __iomem *reg = lp_gpio_reg(&lg->chip, pin, LP_CONFIG1);
void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2);
- unsigned long flags;
u32 value;
- raw_spin_lock_irqsave(&lg->lock, flags);
+ guard(raw_spinlock_irqsave)(&lg->lock);
/*
* Reconfigure pin to GPIO mode if needed and issue a warning,
@@ -352,8 +349,6 @@ static int lp_gpio_request_enable(struct pinctrl_dev *pctldev,
/* Enable input sensing */
lp_gpio_enable_input(conf2);
- raw_spin_unlock_irqrestore(&lg->lock, flags);
-
return 0;
}
@@ -363,14 +358,11 @@ static void lp_gpio_disable_free(struct pinctrl_dev *pctldev,
{
struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev);
void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2);
- unsigned long flags;
- raw_spin_lock_irqsave(&lg->lock, flags);
+ guard(raw_spinlock_irqsave)(&lg->lock);
/* Disable input sensing */
lp_gpio_disable_input(conf2);
-
- raw_spin_unlock_irqrestore(&lg->lock, flags);
}
static int lp_gpio_set_direction(struct pinctrl_dev *pctldev,
@@ -379,10 +371,9 @@ static int lp_gpio_set_direction(struct pinctrl_dev *pctldev,
{
struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev);
void __iomem *reg = lp_gpio_reg(&lg->chip, pin, LP_CONFIG1);
- unsigned long flags;
u32 value;
- raw_spin_lock_irqsave(&lg->lock, flags);
+ guard(raw_spinlock_irqsave)(&lg->lock);
value = ioread32(reg);
value &= ~DIR_BIT;
@@ -400,8 +391,6 @@ static int lp_gpio_set_direction(struct pinctrl_dev *pctldev,
}
iowrite32(value, reg);
- raw_spin_unlock_irqrestore(&lg->lock, flags);
-
return 0;
}
@@ -421,13 +410,11 @@ static int lp_pin_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev);
void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2);
enum pin_config_param param = pinconf_to_config_param(*config);
- unsigned long flags;
u32 value, pull;
u16 arg;
- raw_spin_lock_irqsave(&lg->lock, flags);
- value = ioread32(conf2);
- raw_spin_unlock_irqrestore(&lg->lock, flags);
+ scoped_guard(raw_spinlock_irqsave, &lg->lock)
+ value = ioread32(conf2);
pull = value & GPIWP_MASK;
@@ -464,11 +451,10 @@ static int lp_pin_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
struct intel_pinctrl *lg = pinctrl_dev_get_drvdata(pctldev);
void __iomem *conf2 = lp_gpio_reg(&lg->chip, pin, LP_CONFIG2);
enum pin_config_param param;
- unsigned long flags;
- int i, ret = 0;
+ unsigned int i;
u32 value;
- raw_spin_lock_irqsave(&lg->lock, flags);
+ guard(raw_spinlock_irqsave)(&lg->lock);
value = ioread32(conf2);
@@ -489,19 +475,13 @@ static int lp_pin_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
value |= GPIWP_UP;
break;
default:
- ret = -ENOTSUPP;
+ return -ENOTSUPP;
}
-
- if (ret)
- break;
}
- if (!ret)
- iowrite32(value, conf2);
+ iowrite32(value, conf2);
- raw_spin_unlock_irqrestore(&lg->lock, flags);
-
- return ret;
+ return 0;
}
static const struct pinconf_ops lptlp_pinconf_ops = {
@@ -527,16 +507,13 @@ static void lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct intel_pinctrl *lg = gpiochip_get_data(chip);
void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
- unsigned long flags;
- raw_spin_lock_irqsave(&lg->lock, flags);
+ guard(raw_spinlock_irqsave)(&lg->lock);
if (value)
iowrite32(ioread32(reg) | OUT_LVL_BIT, reg);
else
iowrite32(ioread32(reg) & ~OUT_LVL_BIT, reg);
-
- raw_spin_unlock_irqrestore(&lg->lock, flags);
}
static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
@@ -592,11 +569,10 @@ static void lp_irq_ack(struct irq_data *d)
struct intel_pinctrl *lg = gpiochip_get_data(gc);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_STAT);
- unsigned long flags;
- raw_spin_lock_irqsave(&lg->lock, flags);
+ guard(raw_spinlock_irqsave)(&lg->lock);
+
iowrite32(BIT(hwirq % 32), reg);
- raw_spin_unlock_irqrestore(&lg->lock, flags);
}
static void lp_irq_unmask(struct irq_data *d)
@@ -613,13 +589,11 @@ static void lp_irq_enable(struct irq_data *d)
struct intel_pinctrl *lg = gpiochip_get_data(gc);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
- unsigned long flags;
gpiochip_enable_irq(gc, hwirq);
- raw_spin_lock_irqsave(&lg->lock, flags);
- iowrite32(ioread32(reg) | BIT(hwirq % 32), reg);
- raw_spin_unlock_irqrestore(&lg->lock, flags);
+ scoped_guard(raw_spinlock_irqsave, &lg->lock)
+ iowrite32(ioread32(reg) | BIT(hwirq % 32), reg);
}
static void lp_irq_disable(struct irq_data *d)
@@ -628,11 +602,9 @@ static void lp_irq_disable(struct irq_data *d)
struct intel_pinctrl *lg = gpiochip_get_data(gc);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
void __iomem *reg = lp_gpio_reg(&lg->chip, hwirq, LP_INT_ENABLE);
- unsigned long flags;
- raw_spin_lock_irqsave(&lg->lock, flags);
- iowrite32(ioread32(reg) & ~BIT(hwirq % 32), reg);
- raw_spin_unlock_irqrestore(&lg->lock, flags);
+ scoped_guard(raw_spinlock_irqsave, &lg->lock)
+ iowrite32(ioread32(reg) & ~BIT(hwirq % 32), reg);
gpiochip_disable_irq(gc, hwirq);
}
@@ -642,7 +614,6 @@ static int lp_irq_set_type(struct irq_data *d, unsigned int type)
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct intel_pinctrl *lg = gpiochip_get_data(gc);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
- unsigned long flags;
void __iomem *reg;
u32 value;
@@ -656,7 +627,8 @@ static int lp_irq_set_type(struct irq_data *d, unsigned int type)
return -EBUSY;
}
- raw_spin_lock_irqsave(&lg->lock, flags);
+ guard(raw_spinlock_irqsave)(&lg->lock);
+
value = ioread32(reg);
/* set both TRIG_SEL and INV bits to 0 for rising edge */
@@ -682,8 +654,6 @@ static int lp_irq_set_type(struct irq_data *d, unsigned int type)
else if (type & IRQ_TYPE_LEVEL_MASK)
irq_set_handler_locked(d, handle_level_irq);
- raw_spin_unlock_irqrestore(&lg->lock, flags);
-
return 0;
}
diff --git a/drivers/pinctrl/intel/pinctrl-meteorlake.c b/drivers/pinctrl/intel/pinctrl-meteorlake.c
index 7ced2b402dce..cc44890c6699 100644
--- a/drivers/pinctrl/intel/pinctrl-meteorlake.c
+++ b/drivers/pinctrl/intel/pinctrl-meteorlake.c
@@ -9,6 +9,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -589,14 +590,12 @@ static const struct acpi_device_id mtl_pinctrl_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, mtl_pinctrl_acpi_match);
-static INTEL_PINCTRL_PM_OPS(mtl_pinctrl_pm_ops);
-
static struct platform_driver mtl_pinctrl_driver = {
.probe = intel_pinctrl_probe_by_hid,
.driver = {
.name = "meteorlake-pinctrl",
.acpi_match_table = mtl_pinctrl_acpi_match,
- .pm = &mtl_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
module_platform_driver(mtl_pinctrl_driver);
diff --git a/drivers/pinctrl/intel/pinctrl-meteorpoint.c b/drivers/pinctrl/intel/pinctrl-meteorpoint.c
new file mode 100644
index 000000000000..77e97775a60b
--- /dev/null
+++ b/drivers/pinctrl/intel/pinctrl-meteorpoint.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Meteor Point PCH pinctrl/GPIO driver
+ *
+ * Copyright (C) 2022-2023, Intel Corporation
+ * Author: Andy Shevchenko <[email protected]>
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-intel.h"
+
+#define MTP_PAD_OWN 0x0b0
+#define MTP_PADCFGLOCK 0x110
+#define MTP_HOSTSW_OWN 0x150
+#define MTP_GPI_IS 0x200
+#define MTP_GPI_IE 0x220
+
+#define MTP_GPP(r, s, e, g) \
+ { \
+ .reg_num = (r), \
+ .base = (s), \
+ .size = ((e) - (s) + 1), \
+ .gpio_base = (g), \
+ }
+
+#define MTP_COMMUNITY(b, s, e, g) \
+ INTEL_COMMUNITY_GPPS(b, s, e, g, MTP)
+
+/* Meteor Point-S */
+static const struct pinctrl_pin_desc mtps_pins[] = {
+ /* GPP_D */
+ PINCTRL_PIN(0, "GPP_D_0"),
+ PINCTRL_PIN(1, "GPP_D_1"),
+ PINCTRL_PIN(2, "GPP_D_2"),
+ PINCTRL_PIN(3, "GPP_D_3"),
+ PINCTRL_PIN(4, "GPP_D_4"),
+ PINCTRL_PIN(5, "CNV_RF_RESET_B"),
+ PINCTRL_PIN(6, "CRF_CLKREQ"),
+ PINCTRL_PIN(7, "GPP_D_7"),
+ PINCTRL_PIN(8, "GPP_D_8"),
+ PINCTRL_PIN(9, "SML0CLK"),
+ PINCTRL_PIN(10, "SML0DATA"),
+ PINCTRL_PIN(11, "GPP_D_11"),
+ PINCTRL_PIN(12, "GPP_D_12"),
+ PINCTRL_PIN(13, "GPP_D_13"),
+ PINCTRL_PIN(14, "GPP_D_14"),
+ PINCTRL_PIN(15, "GPP_D_15"),
+ PINCTRL_PIN(16, "GPP_D_16"),
+ PINCTRL_PIN(17, "GPP_D_17"),
+ PINCTRL_PIN(18, "GPP_D_18"),
+ PINCTRL_PIN(19, "GPP_D_19"),
+ PINCTRL_PIN(20, "GPP_D_20"),
+ PINCTRL_PIN(21, "GPP_D_21"),
+ PINCTRL_PIN(22, "GPP_D_22"),
+ PINCTRL_PIN(23, "GPP_D_23"),
+ PINCTRL_PIN(24, "GSPI3_CLK_LOOPBK"),
+ /* GPP_R */
+ PINCTRL_PIN(25, "HDA_BCLK"),
+ PINCTRL_PIN(26, "HDA_SYNC"),
+ PINCTRL_PIN(27, "HDA_SDO"),
+ PINCTRL_PIN(28, "HDA_SDI_0"),
+ PINCTRL_PIN(29, "HDA_RSTB"),
+ PINCTRL_PIN(30, "GPP_R_5"),
+ PINCTRL_PIN(31, "GPP_R_6"),
+ PINCTRL_PIN(32, "GPP_R_7"),
+ PINCTRL_PIN(33, "GPP_R_8"),
+ PINCTRL_PIN(34, "GPP_R_9"),
+ PINCTRL_PIN(35, "GPP_R_10"),
+ PINCTRL_PIN(36, "GPP_R_11"),
+ PINCTRL_PIN(37, "GPP_R_12"),
+ PINCTRL_PIN(38, "GSPI2_CLK_LOOPBK"),
+ /* GPP_J */
+ PINCTRL_PIN(39, "GPP_J_0"),
+ PINCTRL_PIN(40, "CNV_BRI_DT"),
+ PINCTRL_PIN(41, "CNV_BRI_RSP"),
+ PINCTRL_PIN(42, "CNV_RGI_DT"),
+ PINCTRL_PIN(43, "CNV_RGI_RSP"),
+ PINCTRL_PIN(44, "GPP_J_5"),
+ PINCTRL_PIN(45, "GPP_J_6"),
+ PINCTRL_PIN(46, "BOOTHALT_B"),
+ PINCTRL_PIN(47, "RTCCLKOUT"),
+ PINCTRL_PIN(48, "BPKI3C_SDA"),
+ PINCTRL_PIN(49, "BPKI3C_SCL"),
+ PINCTRL_PIN(50, "DAM"),
+ PINCTRL_PIN(51, "HDACPU_SDI"),
+ PINCTRL_PIN(52, "HDACPU_SDO"),
+ PINCTRL_PIN(53, "HDACPU_BCLK"),
+ PINCTRL_PIN(54, "AUX_PWRGD"),
+ PINCTRL_PIN(55, "GLB_RST_WARN_B"),
+ PINCTRL_PIN(56, "RESET_SYNCB"),
+ /* vGPIO */
+ PINCTRL_PIN(57, "CNV_BTEN"),
+ PINCTRL_PIN(58, "CNV_BT_HOST_WAKEB"),
+ PINCTRL_PIN(59, "CNV_BT_IF_SELECT"),
+ PINCTRL_PIN(60, "vCNV_BT_UART_TXD"),
+ PINCTRL_PIN(61, "vCNV_BT_UART_RXD"),
+ PINCTRL_PIN(62, "vCNV_BT_UART_CTS_B"),
+ PINCTRL_PIN(63, "vCNV_BT_UART_RTS_B"),
+ PINCTRL_PIN(64, "vCNV_MFUART1_TXD"),
+ PINCTRL_PIN(65, "vCNV_MFUART1_RXD"),
+ PINCTRL_PIN(66, "vCNV_MFUART1_CTS_B"),
+ PINCTRL_PIN(67, "vCNV_MFUART1_RTS_B"),
+ PINCTRL_PIN(68, "vUART0_TXD"),
+ PINCTRL_PIN(69, "vUART0_RXD"),
+ PINCTRL_PIN(70, "vUART0_CTS_B"),
+ PINCTRL_PIN(71, "vUART0_RTS_B"),
+ PINCTRL_PIN(72, "vISH_UART0_TXD"),
+ PINCTRL_PIN(73, "vISH_UART0_RXD"),
+ PINCTRL_PIN(74, "vISH_UART0_CTS_B"),
+ PINCTRL_PIN(75, "vISH_UART0_RTS_B"),
+ PINCTRL_PIN(76, "vCNV_BT_I2S_BCLK"),
+ PINCTRL_PIN(77, "vCNV_BT_I2S_WS_SYNC"),
+ PINCTRL_PIN(78, "vCNV_BT_I2S_SDO"),
+ PINCTRL_PIN(79, "vCNV_BT_I2S_SDI"),
+ PINCTRL_PIN(80, "vI2S2_SCLK"),
+ PINCTRL_PIN(81, "vI2S2_SFRM"),
+ PINCTRL_PIN(82, "vI2S2_TXD"),
+ PINCTRL_PIN(83, "vI2S2_RXD"),
+ PINCTRL_PIN(84, "THC0_WOT_INT"),
+ PINCTRL_PIN(85, "THC1_WOT_INT"),
+ PINCTRL_PIN(86, "THC0_WHC_INT"),
+ PINCTRL_PIN(87, "THC1_WHC_INT"),
+ /* GPP_A */
+ PINCTRL_PIN(88, "ESPI_IO_0"),
+ PINCTRL_PIN(89, "ESPI_IO_1"),
+ PINCTRL_PIN(90, "ESPI_IO_2"),
+ PINCTRL_PIN(91, "ESPI_IO_3"),
+ PINCTRL_PIN(92, "ESPI_CS0B"),
+ PINCTRL_PIN(93, "ESPI_CLK"),
+ PINCTRL_PIN(94, "ESPI_RESETB"),
+ PINCTRL_PIN(95, "ESPI_CS1B"),
+ PINCTRL_PIN(96, "ESPI_CS2B"),
+ PINCTRL_PIN(97, "ESPI_CS3B"),
+ PINCTRL_PIN(98, "ESPI_ALERT0B"),
+ PINCTRL_PIN(99, "ESPI_ALERT1B"),
+ PINCTRL_PIN(100, "ESPI_ALERT2B"),
+ PINCTRL_PIN(101, "ESPI_ALERT3B"),
+ PINCTRL_PIN(102, "ESPI_CLK_LOOPBK"),
+ /* DIR_ESPI */
+ PINCTRL_PIN(103, "PWRBTNB_OUT"),
+ PINCTRL_PIN(104, "DMI_PERSTB"),
+ PINCTRL_PIN(105, "DMI_CLKREQB"),
+ PINCTRL_PIN(106, "DIR_ESPI_IO_0"),
+ PINCTRL_PIN(107, "DIR_ESPI_IO_1"),
+ PINCTRL_PIN(108, "DIR_ESPI_IO_2"),
+ PINCTRL_PIN(109, "DIR_ESPI_IO_3"),
+ PINCTRL_PIN(110, "DIR_ESPI_CSB"),
+ PINCTRL_PIN(111, "DIR_ESPI_RESETB"),
+ PINCTRL_PIN(112, "DIR_ESPI_CLK"),
+ PINCTRL_PIN(113, "DIR_ESPI_RCLK"),
+ PINCTRL_PIN(114, "DIR_ESPI_ALERTB"),
+ /* GPP_B */
+ PINCTRL_PIN(115, "GPP_B_0"),
+ PINCTRL_PIN(116, "GPP_B_1"),
+ PINCTRL_PIN(117, "GPP_B_2"),
+ PINCTRL_PIN(118, "GPP_B_3"),
+ PINCTRL_PIN(119, "GPP_B_4"),
+ PINCTRL_PIN(120, "GPP_B_5"),
+ PINCTRL_PIN(121, "CLKOUT_48"),
+ PINCTRL_PIN(122, "GPP_B_7"),
+ PINCTRL_PIN(123, "GPP_B_8"),
+ PINCTRL_PIN(124, "GPP_B_9"),
+ PINCTRL_PIN(125, "GPP_B_10"),
+ PINCTRL_PIN(126, "GPP_B_11"),
+ PINCTRL_PIN(127, "SLP_S0B"),
+ PINCTRL_PIN(128, "PLTRSTB"),
+ PINCTRL_PIN(129, "GPP_B_14"),
+ PINCTRL_PIN(130, "GPP_B_15"),
+ PINCTRL_PIN(131, "GPP_B_16"),
+ PINCTRL_PIN(132, "GPP_B_17"),
+ PINCTRL_PIN(133, "GPP_B_18"),
+ PINCTRL_PIN(134, "FUSA_DIAGTEST_EN"),
+ PINCTRL_PIN(135, "FUSA_DIAGTEST_MODE"),
+ PINCTRL_PIN(136, "GPP_B_21"),
+ /* SPI0 */
+ PINCTRL_PIN(137, "SPI0_IO_2"),
+ PINCTRL_PIN(138, "SPI0_IO_3"),
+ PINCTRL_PIN(139, "SPI0_MOSI_IO_0"),
+ PINCTRL_PIN(140, "SPI0_MISO_IO_1"),
+ PINCTRL_PIN(141, "SPI0_TPM_CSB"),
+ PINCTRL_PIN(142, "SPI0_FLASH_0_CSB"),
+ PINCTRL_PIN(143, "SPI0_FLASH_1_CSB"),
+ PINCTRL_PIN(144, "SPI0_CLK"),
+ PINCTRL_PIN(145, "SPI0_CLK_LOOPBK"),
+ /* GPP_C */
+ PINCTRL_PIN(146, "SMBCLK"),
+ PINCTRL_PIN(147, "SMBDATA"),
+ PINCTRL_PIN(148, "SMBALERTB"),
+ PINCTRL_PIN(149, "GPP_C_3"),
+ PINCTRL_PIN(150, "GPP_C_4"),
+ PINCTRL_PIN(151, "GPP_C_5"),
+ PINCTRL_PIN(152, "GPP_C_6"),
+ PINCTRL_PIN(153, "GPP_C_7"),
+ PINCTRL_PIN(154, "GPP_C_8"),
+ PINCTRL_PIN(155, "GPP_C_9"),
+ PINCTRL_PIN(156, "GPP_C_10"),
+ PINCTRL_PIN(157, "GPP_C_11"),
+ PINCTRL_PIN(158, "GPP_C_12"),
+ PINCTRL_PIN(159, "GPP_C_13"),
+ PINCTRL_PIN(160, "GPP_C_14"),
+ PINCTRL_PIN(161, "GPP_C_15"),
+ PINCTRL_PIN(162, "GPP_C_16"),
+ PINCTRL_PIN(163, "GPP_C_17"),
+ PINCTRL_PIN(164, "GPP_C_18"),
+ PINCTRL_PIN(165, "GPP_C_19"),
+ PINCTRL_PIN(166, "GPP_C_20"),
+ PINCTRL_PIN(167, "GPP_C_21"),
+ PINCTRL_PIN(168, "GPP_C_22"),
+ PINCTRL_PIN(169, "GPP_C_23"),
+ /* GPP_H */
+ PINCTRL_PIN(170, "GPP_H_0"),
+ PINCTRL_PIN(171, "GPP_H_1"),
+ PINCTRL_PIN(172, "GPP_H_2"),
+ PINCTRL_PIN(173, "GPP_H_3"),
+ PINCTRL_PIN(174, "GPP_H_4"),
+ PINCTRL_PIN(175, "GPP_H_5"),
+ PINCTRL_PIN(176, "GPP_H_6"),
+ PINCTRL_PIN(177, "GPP_H_7"),
+ PINCTRL_PIN(178, "GPP_H_8"),
+ PINCTRL_PIN(179, "GPP_H_9"),
+ PINCTRL_PIN(180, "GPP_H_10"),
+ PINCTRL_PIN(181, "GPP_H_11"),
+ PINCTRL_PIN(182, "GPP_H_12"),
+ PINCTRL_PIN(183, "GPP_H_13"),
+ PINCTRL_PIN(184, "GPP_H_14"),
+ PINCTRL_PIN(185, "GPP_H_15"),
+ PINCTRL_PIN(186, "GPP_H_16"),
+ PINCTRL_PIN(187, "GPP_H_17"),
+ PINCTRL_PIN(188, "GPP_H_18"),
+ PINCTRL_PIN(189, "GPP_H_19"),
+ /* vGPIO_3 */
+ PINCTRL_PIN(190, "CPU_PCIE_LNK_DN_0"),
+ PINCTRL_PIN(191, "CPU_PCIE_LNK_DN_1"),
+ PINCTRL_PIN(192, "CPU_PCIE_LNK_DN_2"),
+ PINCTRL_PIN(193, "CPU_PCIE_LNK_DN_3"),
+ /* vGPIO_0 */
+ PINCTRL_PIN(194, "ESPI_USB_OCB_0"),
+ PINCTRL_PIN(195, "ESPI_USB_OCB_1"),
+ PINCTRL_PIN(196, "ESPI_USB_OCB_2"),
+ PINCTRL_PIN(197, "ESPI_USB_OCB_3"),
+ PINCTRL_PIN(198, "USB_CPU_OCB_0"),
+ PINCTRL_PIN(199, "USB_CPU_OCB_1"),
+ PINCTRL_PIN(200, "USB_CPU_OCB_2"),
+ PINCTRL_PIN(201, "USB_CPU_OCB_3"),
+ /* vGPIO_4 */
+ PINCTRL_PIN(202, "ESPI_ISCLK_XTAL_CLKREQ"),
+ PINCTRL_PIN(203, "ISCLK_ESPI_XTAL_CLKACK"),
+ PINCTRL_PIN(204, "ME_SLPC_FTPM_ENABLE"),
+ PINCTRL_PIN(205, "GP_SLPC_DTFUS_CORE_SPITPM_DIS"),
+ PINCTRL_PIN(206, "GP_SLPC_SPI_STRAP_TOS"),
+ PINCTRL_PIN(207, "GP_SLPC_DTFUS_CORE_SPITPM_DIS_L01"),
+ PINCTRL_PIN(208, "GP_SLPC_SPI_STRAP_TOS_L01"),
+ PINCTRL_PIN(209, "LPC_PRR_TS_OVR"),
+ PINCTRL_PIN(210, "ITSS_KU1_SHTDWN"),
+ PINCTRL_PIN(211, "vGPIO_SPARE_0"),
+ PINCTRL_PIN(212, "vGPIO_SPARE_1"),
+ PINCTRL_PIN(213, "vGPIO_SPARE_2"),
+ PINCTRL_PIN(214, "vGPIO_SPARE_3"),
+ PINCTRL_PIN(215, "vGPIO_SPARE_4"),
+ PINCTRL_PIN(216, "vGPIO_SPARE_5"),
+ PINCTRL_PIN(217, "vGPIO_SPARE_6"),
+ PINCTRL_PIN(218, "vGPIO_SPARE_7"),
+ PINCTRL_PIN(219, "vGPIO_SPARE_8"),
+ PINCTRL_PIN(220, "vGPIO_SPARE_9"),
+ PINCTRL_PIN(221, "vGPIO_SPARE_10"),
+ PINCTRL_PIN(222, "vGPIO_SPARE_11"),
+ PINCTRL_PIN(223, "vGPIO_SPARE_12"),
+ PINCTRL_PIN(224, "vGPIO_SPARE_13"),
+ PINCTRL_PIN(225, "vGPIO_SPARE_14"),
+ PINCTRL_PIN(226, "vGPIO_SPARE_15"),
+ PINCTRL_PIN(227, "vGPIO_SPARE_16"),
+ PINCTRL_PIN(228, "vGPIO_SPARE_17"),
+ PINCTRL_PIN(229, "vGPIO_SPARE_18"),
+ PINCTRL_PIN(230, "vGPIO_SPARE_19"),
+ PINCTRL_PIN(231, "vGPIO_SPARE_20"),
+ PINCTRL_PIN(232, "vGPIO_SPARE_21"),
+ /* GPP_S */
+ PINCTRL_PIN(233, "GPP_S_0"),
+ PINCTRL_PIN(234, "GPP_S_1"),
+ PINCTRL_PIN(235, "GPP_S_2"),
+ PINCTRL_PIN(236, "GPP_S_3"),
+ PINCTRL_PIN(237, "GPP_S_4"),
+ PINCTRL_PIN(238, "GPP_S_5"),
+ PINCTRL_PIN(239, "GPP_S_6"),
+ PINCTRL_PIN(240, "GPP_S_7"),
+ /* GPP_E */
+ PINCTRL_PIN(241, "GPP_E_0"),
+ PINCTRL_PIN(242, "GPP_E_1"),
+ PINCTRL_PIN(243, "GPP_E_2"),
+ PINCTRL_PIN(244, "GPP_E_3"),
+ PINCTRL_PIN(245, "GPP_E_4"),
+ PINCTRL_PIN(246, "GPP_E_5"),
+ PINCTRL_PIN(247, "GPP_E_6"),
+ PINCTRL_PIN(248, "GPP_E_7"),
+ PINCTRL_PIN(249, "GPP_E_8"),
+ PINCTRL_PIN(250, "GPP_E_9"),
+ PINCTRL_PIN(251, "GPP_E_10"),
+ PINCTRL_PIN(252, "GPP_E_11"),
+ PINCTRL_PIN(253, "GPP_E_12"),
+ PINCTRL_PIN(254, "GPP_E_13"),
+ PINCTRL_PIN(255, "GPP_E_14"),
+ PINCTRL_PIN(256, "GPP_E_15"),
+ PINCTRL_PIN(257, "GPP_E_16"),
+ PINCTRL_PIN(258, "GPP_E_17"),
+ PINCTRL_PIN(259, "GPP_E_18"),
+ PINCTRL_PIN(260, "GPP_E_19"),
+ PINCTRL_PIN(261, "GPP_E_20"),
+ PINCTRL_PIN(262, "GPP_E_21"),
+ PINCTRL_PIN(263, "SPI1_CLK_LOOPBK"),
+ /* GPP_K */
+ PINCTRL_PIN(264, "GPP_K_0"),
+ PINCTRL_PIN(265, "GPP_K_1"),
+ PINCTRL_PIN(266, "GPP_K_2"),
+ PINCTRL_PIN(267, "GPP_K_3"),
+ PINCTRL_PIN(268, "GPP_K_4"),
+ PINCTRL_PIN(269, "GPP_K_5"),
+ PINCTRL_PIN(270, "FUSE_SORT_BUMP_0"),
+ PINCTRL_PIN(271, "FUSE_SORT_BUMP_1"),
+ PINCTRL_PIN(272, "CORE_VID_0"),
+ PINCTRL_PIN(273, "CORE_VID_1"),
+ PINCTRL_PIN(274, "FUSE_SORT_BUMP_2"),
+ PINCTRL_PIN(275, "MISC_SPARE"),
+ PINCTRL_PIN(276, "SYS_RESETB"),
+ PINCTRL_PIN(277, "MLK_RSTB"),
+ /* GPP_F */
+ PINCTRL_PIN(278, "SATAXPCIE_3"),
+ PINCTRL_PIN(279, "SATAXPCIE_4"),
+ PINCTRL_PIN(280, "SATAXPCIE_5"),
+ PINCTRL_PIN(281, "SATAXPCIE_6"),
+ PINCTRL_PIN(282, "SATAXPCIE_7"),
+ PINCTRL_PIN(283, "SATA_DEVSLP_3"),
+ PINCTRL_PIN(284, "SATA_DEVSLP_4"),
+ PINCTRL_PIN(285, "SATA_DEVSLP_5"),
+ PINCTRL_PIN(286, "SATA_DEVSLP_6"),
+ PINCTRL_PIN(287, "GPP_F_9"),
+ PINCTRL_PIN(288, "GPP_F_10"),
+ PINCTRL_PIN(289, "GPP_F_11"),
+ PINCTRL_PIN(290, "GPP_F_12"),
+ PINCTRL_PIN(291, "GPP_F_13"),
+ PINCTRL_PIN(292, "GPP_F_14"),
+ PINCTRL_PIN(293, "GPP_F_15"),
+ PINCTRL_PIN(294, "GPP_F_16"),
+ PINCTRL_PIN(295, "GPP_F_17"),
+ PINCTRL_PIN(296, "GPP_F_18"),
+ PINCTRL_PIN(297, "DNX_FORCE_RELOAD"),
+ PINCTRL_PIN(298, "GPP_F_20"),
+ PINCTRL_PIN(299, "GPP_F_21"),
+ PINCTRL_PIN(300, "GPP_F_22"),
+ PINCTRL_PIN(301, "GPP_F_23"),
+ /* GPP_I */
+ PINCTRL_PIN(302, "GPP_I_0"),
+ PINCTRL_PIN(303, "GPP_I_1"),
+ PINCTRL_PIN(304, "GPP_I_2"),
+ PINCTRL_PIN(305, "GPP_I_3"),
+ PINCTRL_PIN(306, "GPP_I_4"),
+ PINCTRL_PIN(307, "GPP_I_5"),
+ PINCTRL_PIN(308, "GPP_I_6"),
+ PINCTRL_PIN(309, "GPP_I_7"),
+ PINCTRL_PIN(310, "GPP_I_8"),
+ PINCTRL_PIN(311, "GPP_I_9"),
+ PINCTRL_PIN(312, "GPP_I_10"),
+ PINCTRL_PIN(313, "GPP_I_11"),
+ PINCTRL_PIN(314, "GPP_I_12"),
+ PINCTRL_PIN(315, "GPP_I_13"),
+ PINCTRL_PIN(316, "GPP_I_14"),
+ PINCTRL_PIN(317, "GPP_I_15"),
+ PINCTRL_PIN(318, "GPP_I_16"),
+ PINCTRL_PIN(319, "GSPI0_CLK_LOOPBK"),
+ PINCTRL_PIN(320, "GSPI1_CLK_LOOPBK"),
+ PINCTRL_PIN(321, "ISH_I3C0_CLK_LOOPBK"),
+ PINCTRL_PIN(322, "I3C0_CLK_LOOPBK"),
+ /* JTAG_CPU */
+ PINCTRL_PIN(323, "JTAG_TDO"),
+ PINCTRL_PIN(324, "JTAGX"),
+ PINCTRL_PIN(325, "PRDYB"),
+ PINCTRL_PIN(326, "PREQB"),
+ PINCTRL_PIN(327, "JTAG_TDI"),
+ PINCTRL_PIN(328, "JTAG_TMS"),
+ PINCTRL_PIN(329, "JTAG_TCK"),
+ PINCTRL_PIN(330, "DBG_PMODE"),
+ PINCTRL_PIN(331, "CPU_TRSTB"),
+ PINCTRL_PIN(332, "CPUPWRGD"),
+ PINCTRL_PIN(333, "PM_SPARE0"),
+ PINCTRL_PIN(334, "PM_SPARE1"),
+ PINCTRL_PIN(335, "CRASHLOG_TRIG_N"),
+ PINCTRL_PIN(336, "TRIGGER_IN"),
+ PINCTRL_PIN(337, "TRIGGER_OUT"),
+ PINCTRL_PIN(338, "FBRK_OUT_N"),
+};
+
+static const struct intel_padgroup mtps_community0_gpps[] = {
+ MTP_GPP(0, 0, 24, 0), /* GPP_D */
+ MTP_GPP(1, 25, 38, 32), /* GPP_R */
+ MTP_GPP(2, 39, 56, 64), /* GPP_J */
+ MTP_GPP(3, 57, 87, 96), /* vGPIO */
+};
+
+static const struct intel_padgroup mtps_community1_gpps[] = {
+ MTP_GPP(0, 88, 102, 128), /* GPP_A */
+ MTP_GPP(1, 103, 114, 160), /* DIR_ESPI */
+ MTP_GPP(2, 115, 136, 192), /* GPP_B */
+};
+
+static const struct intel_padgroup mtps_community3_gpps[] = {
+ MTP_GPP(0, 137, 145, 224), /* SPI0 */
+ MTP_GPP(1, 146, 169, 256), /* GPP_C */
+ MTP_GPP(2, 170, 189, 288), /* GPP_H */
+ MTP_GPP(3, 190, 193, 320), /* vGPIO_3 */
+ MTP_GPP(4, 194, 201, 352), /* vGPIO_0 */
+ MTP_GPP(5, 202, 232, 384), /* vGPIO_4 */
+};
+
+static const struct intel_padgroup mtps_community4_gpps[] = {
+ MTP_GPP(0, 233, 240, 416), /* GPP_S */
+ MTP_GPP(1, 241, 263, 448), /* GPP_E */
+ MTP_GPP(2, 264, 277, 480), /* GPP_K */
+ MTP_GPP(3, 278, 301, 512), /* GPP_F */
+};
+
+static const struct intel_padgroup mtps_community5_gpps[] = {
+ MTP_GPP(0, 302, 322, 544), /* GPP_I */
+ MTP_GPP(1, 323, 338, 576), /* JTAG_CPU */
+};
+
+static const struct intel_community mtps_communities[] = {
+ MTP_COMMUNITY(0, 0, 87, mtps_community0_gpps),
+ MTP_COMMUNITY(1, 88, 136, mtps_community1_gpps),
+ MTP_COMMUNITY(2, 137, 232, mtps_community3_gpps),
+ MTP_COMMUNITY(3, 233, 301, mtps_community4_gpps),
+ MTP_COMMUNITY(4, 302, 338, mtps_community5_gpps),
+};
+
+static const struct intel_pinctrl_soc_data mtps_soc_data = {
+ .pins = mtps_pins,
+ .npins = ARRAY_SIZE(mtps_pins),
+ .communities = mtps_communities,
+ .ncommunities = ARRAY_SIZE(mtps_communities),
+};
+
+static const struct acpi_device_id mtp_pinctrl_acpi_match[] = {
+ { "INTC1084", (kernel_ulong_t)&mtps_soc_data },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, mtp_pinctrl_acpi_match);
+
+static struct platform_driver mtp_pinctrl_driver = {
+ .probe = intel_pinctrl_probe_by_hid,
+ .driver = {
+ .name = "meteorpoint-pinctrl",
+ .acpi_match_table = mtp_pinctrl_acpi_match,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
+ },
+};
+module_platform_driver(mtp_pinctrl_driver);
+
+MODULE_AUTHOR("Andy Shevchenko <[email protected]>");
+MODULE_DESCRIPTION("Intel Meteor Point PCH pinctrl/GPIO driver");
+MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(PINCTRL_INTEL);
diff --git a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
index b7a40ab0bca8..55df9d2cfb1b 100644
--- a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
+++ b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
@@ -10,6 +10,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -579,14 +580,12 @@ static const struct acpi_device_id spt_pinctrl_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, spt_pinctrl_acpi_match);
-static INTEL_PINCTRL_PM_OPS(spt_pinctrl_pm_ops);
-
static struct platform_driver spt_pinctrl_driver = {
.probe = intel_pinctrl_probe_by_hid,
.driver = {
.name = "sunrisepoint-pinctrl",
.acpi_match_table = spt_pinctrl_acpi_match,
- .pm = &spt_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
diff --git a/drivers/pinctrl/intel/pinctrl-tangier.c b/drivers/pinctrl/intel/pinctrl-tangier.c
index 40dd60c9e526..2cb0b4758269 100644
--- a/drivers/pinctrl/intel/pinctrl-tangier.c
+++ b/drivers/pinctrl/intel/pinctrl-tangier.c
@@ -9,6 +9,7 @@
*/
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
@@ -220,7 +221,6 @@ static int tng_pinmux_set_mux(struct pinctrl_dev *pctldev,
const struct intel_pingroup *grp = &tp->groups[group];
u32 bits = grp->mode << BUFCFG_PINMODE_SHIFT;
u32 mask = BUFCFG_PINMODE_MASK;
- unsigned long flags;
unsigned int i;
/*
@@ -232,11 +232,11 @@ static int tng_pinmux_set_mux(struct pinctrl_dev *pctldev,
return -EBUSY;
}
+ guard(raw_spinlock_irqsave)(&tp->lock);
+
/* Now enable the mux setting for each pin in the group */
- raw_spin_lock_irqsave(&tp->lock, flags);
for (i = 0; i < grp->grp.npins; i++)
tng_update_bufcfg(tp, grp->grp.pins[i], bits, mask);
- raw_spin_unlock_irqrestore(&tp->lock, flags);
return 0;
}
@@ -248,14 +248,13 @@ static int tng_gpio_request_enable(struct pinctrl_dev *pctldev,
struct tng_pinctrl *tp = pinctrl_dev_get_drvdata(pctldev);
u32 bits = BUFCFG_PINMODE_GPIO << BUFCFG_PINMODE_SHIFT;
u32 mask = BUFCFG_PINMODE_MASK;
- unsigned long flags;
if (!tng_buf_available(tp, pin))
return -EBUSY;
- raw_spin_lock_irqsave(&tp->lock, flags);
+ guard(raw_spinlock_irqsave)(&tp->lock);
+
tng_update_bufcfg(tp, pin, bits, mask);
- raw_spin_unlock_irqrestore(&tp->lock, flags);
return 0;
}
@@ -360,7 +359,6 @@ static int tng_config_set_pin(struct tng_pinctrl *tp, unsigned int pin,
unsigned int param = pinconf_to_config_param(config);
unsigned int arg = pinconf_to_config_argument(config);
u32 mask, term, value = 0;
- unsigned long flags;
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
@@ -368,20 +366,20 @@ static int tng_config_set_pin(struct tng_pinctrl *tp, unsigned int pin,
break;
case PIN_CONFIG_BIAS_PULL_UP:
- /* Set default strength value in case none is given */
- if (arg == 1)
- arg = 20000;
-
switch (arg) {
case 50000:
term = BUFCFG_PUPD_VAL_50K;
break;
+ case 1: /* Set default strength value in case none is given */
case 20000:
term = BUFCFG_PUPD_VAL_20K;
break;
case 2000:
term = BUFCFG_PUPD_VAL_2K;
break;
+ case 910:
+ term = BUFCFG_PUPD_VAL_910;
+ break;
default:
return -EINVAL;
}
@@ -391,20 +389,20 @@ static int tng_config_set_pin(struct tng_pinctrl *tp, unsigned int pin,
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- /* Set default strength value in case none is given */
- if (arg == 1)
- arg = 20000;
-
switch (arg) {
case 50000:
term = BUFCFG_PUPD_VAL_50K;
break;
+ case 1: /* Set default strength value in case none is given */
case 20000:
term = BUFCFG_PUPD_VAL_20K;
break;
case 2000:
term = BUFCFG_PUPD_VAL_2K;
break;
+ case 910:
+ term = BUFCFG_PUPD_VAL_910;
+ break;
default:
return -EINVAL;
}
@@ -432,9 +430,9 @@ static int tng_config_set_pin(struct tng_pinctrl *tp, unsigned int pin,
return -EINVAL;
}
- raw_spin_lock_irqsave(&tp->lock, flags);
+ guard(raw_spinlock_irqsave)(&tp->lock);
+
tng_update_bufcfg(tp, pin, value, mask);
- raw_spin_unlock_irqrestore(&tp->lock, flags);
return 0;
}
diff --git a/drivers/pinctrl/intel/pinctrl-tigerlake.c b/drivers/pinctrl/intel/pinctrl-tigerlake.c
index 4768a69a9258..80cd7a06fe5a 100644
--- a/drivers/pinctrl/intel/pinctrl-tigerlake.c
+++ b/drivers/pinctrl/intel/pinctrl-tigerlake.c
@@ -10,6 +10,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm.h>
#include <linux/pinctrl/pinctrl.h>
@@ -743,14 +744,12 @@ static const struct acpi_device_id tgl_pinctrl_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, tgl_pinctrl_acpi_match);
-static INTEL_PINCTRL_PM_OPS(tgl_pinctrl_pm_ops);
-
static struct platform_driver tgl_pinctrl_driver = {
.probe = intel_pinctrl_probe_by_hid,
.driver = {
.name = "tigerlake-pinctrl",
.acpi_match_table = tgl_pinctrl_acpi_match,
- .pm = &tgl_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&intel_pinctrl_pm_ops),
},
};
module_platform_driver(tgl_pinctrl_driver);
diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.c b/drivers/pinctrl/mediatek/pinctrl-moore.c
index c3d59eddd994..d972584c0519 100644
--- a/drivers/pinctrl/mediatek/pinctrl-moore.c
+++ b/drivers/pinctrl/mediatek/pinctrl-moore.c
@@ -56,12 +56,12 @@ static int mtk_pinmux_set_mux(struct pinctrl_dev *pctldev,
return -EINVAL;
dev_dbg(pctldev->dev, "enable function %s group %s\n",
- func->name, grp->name);
+ func->name, grp->grp.name);
- for (i = 0; i < grp->num_pins; i++) {
+ for (i = 0; i < grp->grp.npins; i++) {
const struct mtk_pin_desc *desc;
int *pin_modes = grp->data;
- int pin = grp->pins[i];
+ int pin = grp->grp.pins[i];
desc = (const struct mtk_pin_desc *)&hw->soc->pins[pin];
if (!desc->name)
@@ -602,13 +602,12 @@ static int mtk_build_groups(struct mtk_pinctrl *hw)
for (i = 0; i < hw->soc->ngrps; i++) {
const struct group_desc *group = hw->soc->grps + i;
+ const struct pingroup *grp = &group->grp;
- err = pinctrl_generic_add_group(hw->pctrl, group->name,
- group->pins, group->num_pins,
+ err = pinctrl_generic_add_group(hw->pctrl, grp->name, grp->pins, grp->npins,
group->data);
if (err < 0) {
- dev_err(hw->dev, "Failed to register group %s\n",
- group->name);
+ dev_err(hw->dev, "Failed to register group %s\n", grp->name);
return err;
}
}
diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.h b/drivers/pinctrl/mediatek/pinctrl-moore.h
index e1b4b82b9d3d..e0313e7a1fe0 100644
--- a/drivers/pinctrl/mediatek/pinctrl-moore.h
+++ b/drivers/pinctrl/mediatek/pinctrl-moore.h
@@ -37,12 +37,10 @@
.funcs = NULL, \
}
-#define PINCTRL_PIN_GROUP(name, id) \
- { \
- name, \
- id##_pins, \
- ARRAY_SIZE(id##_pins), \
- id##_funcs, \
+#define PINCTRL_PIN_GROUP(_name_, id) \
+ { \
+ .grp = PINCTRL_PINGROUP(_name_, id##_pins, ARRAY_SIZE(id##_pins)), \
+ .data = id##_funcs, \
}
int mtk_moore_pinctrl_probe(struct platform_device *pdev,
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2701.c b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
index 5fb377c1668b..6b1c7122b0fb 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2701.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2701.c
@@ -533,7 +533,7 @@ static struct platform_driver mtk_pinctrl_driver = {
.driver = {
.name = "mediatek-mt2701-pinctrl",
.of_match_table = mt2701_pctrl_match,
- .pm = &mtk_eint_pm_ops,
+ .pm = pm_sleep_ptr(&mtk_eint_pm_ops),
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt2712.c b/drivers/pinctrl/mediatek/pinctrl-mt2712.c
index 8a6daa0db54b..bb7394ae252b 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt2712.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt2712.c
@@ -581,7 +581,7 @@ static struct platform_driver mtk_pinctrl_driver = {
.driver = {
.name = "mediatek-mt2712-pinctrl",
.of_match_table = mt2712_pctrl_match,
- .pm = &mtk_eint_pm_ops,
+ .pm = pm_sleep_ptr(&mtk_eint_pm_ops),
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt6795.c b/drivers/pinctrl/mediatek/pinctrl-mt6795.c
index 01e855ccd4dd..ee3ae3d2fa7e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt6795.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt6795.c
@@ -612,7 +612,7 @@ static struct platform_driver mt6795_pinctrl_driver = {
.driver = {
.name = "mt6795-pinctrl",
.of_match_table = mt6795_pctrl_match,
- .pm = &mtk_paris_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&mtk_paris_pinctrl_pm_ops),
},
.probe = mtk_paris_pinctrl_probe,
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8167.c b/drivers/pinctrl/mediatek/pinctrl-mt8167.c
index ba7f30c3296f..143c26622272 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8167.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8167.c
@@ -334,7 +334,7 @@ static struct platform_driver mtk_pinctrl_driver = {
.driver = {
.name = "mediatek-mt8167-pinctrl",
.of_match_table = mt8167_pctrl_match,
- .pm = &mtk_eint_pm_ops,
+ .pm = pm_sleep_ptr(&mtk_eint_pm_ops),
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8173.c b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
index 455eec018f93..b214deeafbf1 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8173.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
@@ -347,7 +347,7 @@ static struct platform_driver mtk_pinctrl_driver = {
.driver = {
.name = "mediatek-mt8173-pinctrl",
.of_match_table = mt8173_pctrl_match,
- .pm = &mtk_eint_pm_ops,
+ .pm = pm_sleep_ptr(&mtk_eint_pm_ops),
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8183.c b/drivers/pinctrl/mediatek/pinctrl-mt8183.c
index ddc48b725c22..93e482c6b5fd 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8183.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8183.c
@@ -576,7 +576,7 @@ static struct platform_driver mt8183_pinctrl_driver = {
.driver = {
.name = "mt8183-pinctrl",
.of_match_table = mt8183_pinctrl_of_match,
- .pm = &mtk_paris_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&mtk_paris_pinctrl_pm_ops),
},
.probe = mtk_paris_pinctrl_probe,
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8186.c b/drivers/pinctrl/mediatek/pinctrl-mt8186.c
index a02f7c326970..7be591591cce 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8186.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8186.c
@@ -1255,7 +1255,7 @@ static struct platform_driver mt8186_pinctrl_driver = {
.driver = {
.name = "mt8186-pinctrl",
.of_match_table = mt8186_pinctrl_of_match,
- .pm = &mtk_paris_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&mtk_paris_pinctrl_pm_ops),
},
.probe = mtk_paris_pinctrl_probe,
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8188.c b/drivers/pinctrl/mediatek/pinctrl-mt8188.c
index c067e043e619..3975e99d9cf4 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8188.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8188.c
@@ -1658,7 +1658,7 @@ static struct platform_driver mt8188_pinctrl_driver = {
.driver = {
.name = "mt8188-pinctrl",
.of_match_table = mt8188_pinctrl_of_match,
- .pm = &mtk_paris_pinctrl_pm_ops
+ .pm = pm_sleep_ptr(&mtk_paris_pinctrl_pm_ops)
},
.probe = mtk_paris_pinctrl_probe,
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8192.c b/drivers/pinctrl/mediatek/pinctrl-mt8192.c
index dee1b3aefd36..e3a76381f7f4 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8192.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8192.c
@@ -1420,7 +1420,7 @@ static struct platform_driver mt8192_pinctrl_driver = {
.driver = {
.name = "mt8192-pinctrl",
.of_match_table = mt8192_pinctrl_of_match,
- .pm = &mtk_paris_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&mtk_paris_pinctrl_pm_ops),
},
.probe = mtk_paris_pinctrl_probe,
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8195.c b/drivers/pinctrl/mediatek/pinctrl-mt8195.c
index 09c4dcef9338..83345c52b2fa 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8195.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8195.c
@@ -968,7 +968,7 @@ static struct platform_driver mt8195_pinctrl_driver = {
.driver = {
.name = "mt8195-pinctrl",
.of_match_table = mt8195_pinctrl_of_match,
- .pm = &mtk_paris_pinctrl_pm_ops,
+ .pm = pm_sleep_ptr(&mtk_paris_pinctrl_pm_ops),
},
.probe = mtk_paris_pinctrl_probe,
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8365.c b/drivers/pinctrl/mediatek/pinctrl-mt8365.c
index 1db04bbdb423..e3e0d66cfbbf 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8365.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8365.c
@@ -484,7 +484,7 @@ static struct platform_driver mtk_pinctrl_driver = {
.driver = {
.name = "mediatek-mt8365-pinctrl",
.of_match_table = mt8365_pctrl_match,
- .pm = &mtk_eint_pm_ops,
+ .pm = pm_sleep_ptr(&mtk_eint_pm_ops),
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8516.c b/drivers/pinctrl/mediatek/pinctrl-mt8516.c
index 950275c47122..abda75d4354e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8516.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8516.c
@@ -334,7 +334,7 @@ static struct platform_driver mtk_pinctrl_driver = {
.driver = {
.name = "mediatek-mt8516-pinctrl",
.of_match_table = mt8516_pctrl_match,
- .pm = &mtk_eint_pm_ops,
+ .pm = pm_sleep_ptr(&mtk_eint_pm_ops),
},
};
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index e79d66a04194..d39afc122516 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -914,9 +914,8 @@ static int mtk_eint_resume(struct device *device)
return mtk_eint_do_resume(pctl->eint);
}
-const struct dev_pm_ops mtk_eint_pm_ops = {
- .suspend_noirq = mtk_eint_suspend,
- .resume_noirq = mtk_eint_resume,
+EXPORT_GPL_DEV_SLEEP_PM_OPS(mtk_eint_pm_ops) = {
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_eint_suspend, mtk_eint_resume)
};
static int mtk_pctrl_build_state(struct platform_device *pdev)
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c
index 6392f1e05d02..b6bc31abd2b0 100644
--- a/drivers/pinctrl/mediatek/pinctrl-paris.c
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.c
@@ -1131,9 +1131,8 @@ static int mtk_paris_pinctrl_resume(struct device *device)
return mtk_eint_do_resume(pctl->eint);
}
-const struct dev_pm_ops mtk_paris_pinctrl_pm_ops = {
- .suspend_noirq = mtk_paris_pinctrl_suspend,
- .resume_noirq = mtk_paris_pinctrl_resume,
+EXPORT_GPL_DEV_SLEEP_PM_OPS(mtk_paris_pinctrl_pm_ops) = {
+ NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_paris_pinctrl_suspend, mtk_paris_pinctrl_resume)
};
MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.h b/drivers/pinctrl/mediatek/pinctrl-paris.h
index 8762ac599329..948ce126aa0c 100644
--- a/drivers/pinctrl/mediatek/pinctrl-paris.h
+++ b/drivers/pinctrl/mediatek/pinctrl-paris.h
@@ -49,12 +49,10 @@
__VA_ARGS__, { } }, \
}
-#define PINCTRL_PIN_GROUP(name, id) \
- { \
- name, \
- id##_pins, \
- ARRAY_SIZE(id##_pins), \
- id##_funcs, \
+#define PINCTRL_PIN_GROUP(_name_, id) \
+ { \
+ .grp = PINCTRL_PINGROUP(_name_,id##_pins, ARRAY_SIZE(id##_pins)), \
+ .data = id##_funcs, \
}
int mtk_paris_pinctrl_probe(struct platform_device *pdev);
diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
index 1e658721aaba..62a46d824b46 100644
--- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
+++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
@@ -1790,8 +1790,8 @@ static int npcm7xx_config_set_one(struct npcm7xx_pinctrl *npcm,
bank->direction_input(&bank->gc, pin % bank->gc.ngpio);
break;
case PIN_CONFIG_OUTPUT:
- iowrite32(gpio, bank->base + NPCM7XX_GP_N_OES);
bank->direction_output(&bank->gc, pin % bank->gc.ngpio, arg);
+ iowrite32(gpio, bank->base + NPCM7XX_GP_N_OES);
break;
case PIN_CONFIG_DRIVE_PUSH_PULL:
npcm_gpio_clr(&bank->gc, bank->base + NPCM7XX_GP_N_OTYP, gpio);
diff --git a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c
index 0cff44b07b29..4589900244c7 100644
--- a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c
+++ b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c
@@ -474,9 +474,8 @@ enum {
#undef WPCM450_GRP
};
-static struct group_desc wpcm450_groups[] = {
-#define WPCM450_GRP(x) { .name = #x, .pins = x ## _pins, \
- .num_pins = ARRAY_SIZE(x ## _pins) }
+static struct pingroup wpcm450_groups[] = {
+#define WPCM450_GRP(x) PINCTRL_PINGROUP(#x, x ## _pins, ARRAY_SIZE(x ## _pins))
WPCM450_GRPS
#undef WPCM450_GRP
};
@@ -852,7 +851,7 @@ static int wpcm450_get_group_pins(struct pinctrl_dev *pctldev,
const unsigned int **pins,
unsigned int *npins)
{
- *npins = wpcm450_groups[selector].num_pins;
+ *npins = wpcm450_groups[selector].npins;
*pins = wpcm450_groups[selector].pins;
return 0;
@@ -901,7 +900,7 @@ static int wpcm450_pinmux_set_mux(struct pinctrl_dev *pctldev,
struct wpcm450_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
wpcm450_setfunc(pctrl->gcr_regmap, wpcm450_groups[group].pins,
- wpcm450_groups[group].num_pins, function);
+ wpcm450_groups[group].npins, function);
return 0;
}
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 8313cb5f3b3c..cada5d18ffae 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -57,7 +57,7 @@ static const struct pin_config_item conf_items[] = {
static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
struct seq_file *s, const char *gname,
- unsigned pin,
+ unsigned int pin,
const struct pin_config_item *items,
int nitems, int *print_sep)
{
@@ -110,7 +110,7 @@ static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
* to be specified the other can be NULL/0.
*/
void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, struct seq_file *s,
- const char *gname, unsigned pin)
+ const char *gname, unsigned int pin)
{
const struct pinconf_ops *ops = pctldev->desc->confops;
int print_sep = 0;
@@ -295,15 +295,15 @@ EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_config);
int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
struct device_node *np, struct pinctrl_map **map,
- unsigned *reserved_maps, unsigned *num_maps,
+ unsigned int *reserved_maps, unsigned int *num_maps,
enum pinctrl_map_type type)
{
int ret;
const char *function;
struct device *dev = pctldev->dev;
unsigned long *configs = NULL;
- unsigned num_configs = 0;
- unsigned reserve, strings_count;
+ unsigned int num_configs = 0;
+ unsigned int reserve, strings_count;
struct property *prop;
const char *group;
const char *subnode_target_type = "pins";
@@ -379,9 +379,9 @@ EXPORT_SYMBOL_GPL(pinconf_generic_dt_subnode_to_map);
int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np_config, struct pinctrl_map **map,
- unsigned *num_maps, enum pinctrl_map_type type)
+ unsigned int *num_maps, enum pinctrl_map_type type)
{
- unsigned reserved_maps;
+ unsigned int reserved_maps;
struct device_node *np;
int ret;
@@ -412,7 +412,7 @@ EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map);
void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev,
struct pinctrl_map *map,
- unsigned num_maps)
+ unsigned int num_maps)
{
pinctrl_utils_free_map(pctldev, map, num_maps);
}
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index 96d853a8f339..dca963633b5d 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -55,7 +55,7 @@ int pinconf_validate_map(const struct pinctrl_map *map, int i)
return 0;
}
-int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
+int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *config)
{
const struct pinconf_ops *ops = pctldev->desc->confops;
@@ -199,7 +199,7 @@ int pinconf_apply_setting(const struct pinctrl_setting *setting)
return 0;
}
-int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned pin,
+int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *configs, size_t nconfigs)
{
const struct pinconf_ops *ops;
@@ -214,7 +214,7 @@ int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned pin,
#ifdef CONFIG_DEBUG_FS
static void pinconf_show_config(struct seq_file *s, struct pinctrl_dev *pctldev,
- unsigned long *configs, unsigned num_configs)
+ unsigned long *configs, unsigned int num_configs)
{
const struct pinconf_ops *confops;
int i;
@@ -304,7 +304,7 @@ static void pinconf_dump_pin(struct pinctrl_dev *pctldev,
static int pinconf_pins_show(struct seq_file *s, void *what)
{
struct pinctrl_dev *pctldev = s->private;
- unsigned i, pin;
+ unsigned int i, pin;
seq_puts(s, "Pin config settings per pin\n");
seq_puts(s, "Format: pin (name): configs\n");
@@ -333,7 +333,7 @@ static int pinconf_pins_show(struct seq_file *s, void *what)
}
static void pinconf_dump_group(struct pinctrl_dev *pctldev,
- struct seq_file *s, unsigned selector,
+ struct seq_file *s, unsigned int selector,
const char *gname)
{
const struct pinconf_ops *ops = pctldev->desc->confops;
@@ -348,8 +348,8 @@ static int pinconf_groups_show(struct seq_file *s, void *what)
{
struct pinctrl_dev *pctldev = s->private;
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
- unsigned ngroups = pctlops->get_groups_count(pctldev);
- unsigned selector = 0;
+ unsigned int ngroups = pctlops->get_groups_count(pctldev);
+ unsigned int selector = 0;
seq_puts(s, "Pin config settings per pin group\n");
seq_puts(s, "Format: group (name): configs\n");
diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h
index 694bfc9961fa..a14c950bc700 100644
--- a/drivers/pinctrl/pinconf.h
+++ b/drivers/pinctrl/pinconf.h
@@ -29,14 +29,14 @@ int pinconf_map_to_setting(const struct pinctrl_map *map,
void pinconf_free_setting(const struct pinctrl_setting *setting);
int pinconf_apply_setting(const struct pinctrl_setting *setting);
-int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned pin,
+int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *configs, size_t nconfigs);
/*
* You will only be interested in these if you're using PINCONF
* so don't supply any stubs for these.
*/
-int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
+int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *config);
int pin_config_group_get(const char *dev_name, const char *pin_group,
unsigned long *config);
@@ -68,7 +68,7 @@ static inline int pinconf_apply_setting(const struct pinctrl_setting *setting)
return 0;
}
-static inline int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned pin,
+static inline int pinconf_set_config(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *configs, size_t nconfigs)
{
return -ENOTSUPP;
@@ -112,7 +112,7 @@ static inline void pinconf_init_device_debugfs(struct dentry *devroot,
void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev,
struct seq_file *s, const char *gname,
- unsigned pin);
+ unsigned int pin);
void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
struct seq_file *s, unsigned long config);
@@ -120,7 +120,7 @@ void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
static inline void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev,
struct seq_file *s,
- const char *gname, unsigned pin)
+ const char *gname, unsigned int pin)
{
return;
}
diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c
index 6a5f23cf7a2a..0d8c75ce20ed 100644
--- a/drivers/pinctrl/pinctrl-as3722.c
+++ b/drivers/pinctrl/pinctrl-as3722.c
@@ -542,7 +542,6 @@ static int as3722_pinctrl_probe(struct platform_device *pdev)
as_pci->dev = &pdev->dev;
as_pci->as3722 = dev_get_drvdata(pdev->dev.parent);
- platform_set_drvdata(pdev, as_pci);
as_pci->pins = as3722_pins_desc;
as_pci->num_pins = ARRAY_SIZE(as3722_pins_desc);
@@ -562,7 +561,7 @@ static int as3722_pinctrl_probe(struct platform_device *pdev)
as_pci->gpio_chip = as3722_gpio_chip;
as_pci->gpio_chip.parent = &pdev->dev;
- ret = gpiochip_add_data(&as_pci->gpio_chip, as_pci);
+ ret = devm_gpiochip_add_data(&pdev->dev, &as_pci->gpio_chip, as_pci);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't register gpiochip, %d\n", ret);
return ret;
@@ -572,21 +571,10 @@ static int as3722_pinctrl_probe(struct platform_device *pdev)
0, 0, AS3722_PIN_NUM);
if (ret < 0) {
dev_err(&pdev->dev, "Couldn't add pin range, %d\n", ret);
- goto fail_range_add;
+ return ret;
}
return 0;
-
-fail_range_add:
- gpiochip_remove(&as_pci->gpio_chip);
- return ret;
-}
-
-static void as3722_pinctrl_remove(struct platform_device *pdev)
-{
- struct as3722_pctrl_info *as_pci = platform_get_drvdata(pdev);
-
- gpiochip_remove(&as_pci->gpio_chip);
}
static const struct of_device_id as3722_pinctrl_of_match[] = {
@@ -601,7 +589,6 @@ static struct platform_driver as3722_pinctrl_driver = {
.of_match_table = as3722_pinctrl_of_match,
},
.probe = as3722_pinctrl_probe,
- .remove_new = as3722_pinctrl_remove,
};
module_platform_driver(as3722_pinctrl_driver);
diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c
index fe9545c630a2..67b5d160c027 100644
--- a/drivers/pinctrl/pinctrl-cy8c95x0.c
+++ b/drivers/pinctrl/pinctrl-cy8c95x0.c
@@ -58,6 +58,10 @@
#define CY8C95X0_PIN_TO_OFFSET(x) (((x) >= 20) ? ((x) + 4) : (x))
+#define CY8C95X0_MUX_REGMAP_TO_PORT(x) ((x) / MUXED_STRIDE)
+#define CY8C95X0_MUX_REGMAP_TO_REG(x) (((x) % MUXED_STRIDE) + CY8C95X0_INTMASK)
+#define CY8C95X0_MUX_REGMAP_TO_OFFSET(x, p) ((x) - CY8C95X0_INTMASK + (p) * MUXED_STRIDE)
+
static const struct i2c_device_id cy8c95x0_id[] = {
{ "cy8c9520", 20, },
{ "cy8c9540", 40, },
@@ -119,12 +123,13 @@ static const struct dmi_system_id cy8c95x0_dmi_acpi_irq_info[] = {
#define MAX_BANK 8
#define BANK_SZ 8
#define MAX_LINE (MAX_BANK * BANK_SZ)
-
+#define MUXED_STRIDE 16
#define CY8C95X0_GPIO_MASK GENMASK(7, 0)
/**
* struct cy8c95x0_pinctrl - driver data
- * @regmap: Device's regmap
+ * @regmap: Device's regmap. Only direct access registers.
+ * @muxed_regmap: Regmap for all muxed registers.
* @irq_lock: IRQ bus lock
* @i2c_lock: Mutex for the device internal mux register
* @irq_mask: I/O bits affected by interrupts
@@ -147,6 +152,7 @@ static const struct dmi_system_id cy8c95x0_dmi_acpi_irq_info[] = {
*/
struct cy8c95x0_pinctrl {
struct regmap *regmap;
+ struct regmap *muxed_regmap;
struct mutex irq_lock;
struct mutex i2c_lock;
DECLARE_BITMAP(irq_mask, MAX_LINE);
@@ -379,6 +385,54 @@ static bool cy8c95x0_precious_register(struct device *dev, unsigned int reg)
}
}
+static bool cy8c95x0_muxed_register(unsigned int reg)
+{
+ switch (reg) {
+ case CY8C95X0_INTMASK:
+ case CY8C95X0_PWMSEL:
+ case CY8C95X0_INVERT:
+ case CY8C95X0_DIRECTION:
+ case CY8C95X0_DRV_PU:
+ case CY8C95X0_DRV_PD:
+ case CY8C95X0_DRV_ODH:
+ case CY8C95X0_DRV_ODL:
+ case CY8C95X0_DRV_PP_FAST:
+ case CY8C95X0_DRV_PP_SLOW:
+ case CY8C95X0_DRV_HIZ:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cy8c95x0_wc_register(unsigned int reg)
+{
+ switch (reg) {
+ case CY8C95X0_DRV_PU:
+ case CY8C95X0_DRV_PD:
+ case CY8C95X0_DRV_ODH:
+ case CY8C95X0_DRV_ODL:
+ case CY8C95X0_DRV_PP_FAST:
+ case CY8C95X0_DRV_PP_SLOW:
+ case CY8C95X0_DRV_HIZ:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cy8c95x0_quick_path_register(unsigned int reg)
+{
+ switch (reg) {
+ case CY8C95X0_INPUT_(0) ... CY8C95X0_INPUT_(7):
+ case CY8C95X0_INTSTATUS_(0) ... CY8C95X0_INTSTATUS_(7):
+ case CY8C95X0_OUTPUT_(0) ... CY8C95X0_OUTPUT_(7):
+ return true;
+ default:
+ return false;
+ }
+}
+
static const struct reg_default cy8c95x0_reg_defaults[] = {
{ CY8C95X0_OUTPUT_(0), GENMASK(7, 0) },
{ CY8C95X0_OUTPUT_(1), GENMASK(7, 0) },
@@ -392,7 +446,89 @@ static const struct reg_default cy8c95x0_reg_defaults[] = {
{ CY8C95X0_PWMSEL, 0 },
};
+static int
+cy8c95x0_mux_reg_read(void *context, unsigned int off, unsigned int *val)
+{
+ struct cy8c95x0_pinctrl *chip = context;
+ u8 port = CY8C95X0_MUX_REGMAP_TO_PORT(off);
+ int ret, reg = CY8C95X0_MUX_REGMAP_TO_REG(off);
+
+ mutex_lock(&chip->i2c_lock);
+ /* Select the correct bank */
+ ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
+ if (ret < 0)
+ goto out;
+
+ /*
+ * Read the register through direct access regmap. The target range
+ * is marked volatile.
+ */
+ ret = regmap_read(chip->regmap, reg, val);
+out:
+ mutex_unlock(&chip->i2c_lock);
+
+ return ret;
+}
+
+static int
+cy8c95x0_mux_reg_write(void *context, unsigned int off, unsigned int val)
+{
+ struct cy8c95x0_pinctrl *chip = context;
+ u8 port = CY8C95X0_MUX_REGMAP_TO_PORT(off);
+ int ret, reg = CY8C95X0_MUX_REGMAP_TO_REG(off);
+
+ mutex_lock(&chip->i2c_lock);
+ /* Select the correct bank */
+ ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
+ if (ret < 0)
+ goto out;
+
+ /*
+ * Write the register through direct access regmap. The target range
+ * is marked volatile.
+ */
+ ret = regmap_write(chip->regmap, reg, val);
+out:
+ mutex_unlock(&chip->i2c_lock);
+
+ return ret;
+}
+
+static bool cy8c95x0_mux_accessible_register(struct device *dev, unsigned int off)
+{
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct cy8c95x0_pinctrl *chip = i2c_get_clientdata(i2c);
+ u8 port = CY8C95X0_MUX_REGMAP_TO_PORT(off);
+ u8 reg = CY8C95X0_MUX_REGMAP_TO_REG(off);
+
+ if (port >= chip->nport)
+ return false;
+
+ return cy8c95x0_muxed_register(reg);
+}
+
+static struct regmap_bus cy8c95x0_regmap_bus = {
+ .reg_read = cy8c95x0_mux_reg_read,
+ .reg_write = cy8c95x0_mux_reg_write,
+};
+
+/* Regmap for muxed registers CY8C95X0_INTMASK - CY8C95X0_DRV_HIZ */
+static const struct regmap_config cy8c95x0_muxed_regmap = {
+ .name = "muxed",
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_FLAT,
+ .use_single_read = true,
+ .use_single_write = true,
+ .max_register = MUXED_STRIDE * BANK_SZ,
+ .num_reg_defaults_raw = MUXED_STRIDE * BANK_SZ,
+ .readable_reg = cy8c95x0_mux_accessible_register,
+ .writeable_reg = cy8c95x0_mux_accessible_register,
+};
+
+/* Direct access regmap */
static const struct regmap_config cy8c95x0_i2c_regmap = {
+ .name = "direct",
.reg_bits = 8,
.val_bits = 8,
@@ -408,6 +544,147 @@ static const struct regmap_config cy8c95x0_i2c_regmap = {
.max_register = CY8C95X0_COMMAND,
};
+static inline int cy8c95x0_regmap_update_bits_base(struct cy8c95x0_pinctrl *chip,
+ unsigned int reg,
+ unsigned int port,
+ unsigned int mask,
+ unsigned int val,
+ bool *change, bool async,
+ bool force)
+{
+ struct regmap *regmap;
+ int ret, off, i, read_val;
+
+ /* Caller should never modify PORTSEL directly */
+ if (reg == CY8C95X0_PORTSEL)
+ return -EINVAL;
+
+ /* Registers behind the PORTSEL mux have their own regmap */
+ if (cy8c95x0_muxed_register(reg)) {
+ regmap = chip->muxed_regmap;
+ off = CY8C95X0_MUX_REGMAP_TO_OFFSET(reg, port);
+ } else {
+ regmap = chip->regmap;
+ /* Quick path direct access registers honor the port argument */
+ if (cy8c95x0_quick_path_register(reg))
+ off = reg + port;
+ else
+ off = reg;
+ }
+
+ ret = regmap_update_bits_base(regmap, off, mask, val, change, async, force);
+ if (ret < 0)
+ return ret;
+
+ /* Update the cache when a WC bit is written */
+ if (cy8c95x0_wc_register(reg) && (mask & val)) {
+ for (i = CY8C95X0_DRV_PU; i <= CY8C95X0_DRV_HIZ; i++) {
+ if (i == reg)
+ continue;
+ off = CY8C95X0_MUX_REGMAP_TO_OFFSET(i, port);
+
+ ret = regmap_read(regmap, off, &read_val);
+ if (ret < 0)
+ continue;
+
+ if (!(read_val & mask & val))
+ continue;
+
+ regcache_cache_only(regmap, true);
+ regmap_update_bits(regmap, off, mask & val, 0);
+ regcache_cache_only(regmap, false);
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * cy8c95x0_regmap_write_bits() - writes a register using the regmap cache
+ * @chip: The pinctrl to work on
+ * @reg: The register to write to. Can be direct access or muxed register.
+ * MUST NOT be the PORTSEL register.
+ * @port: The port to be used for muxed registers or quick path direct access
+ * registers. Otherwise unused.
+ * @mask: Bitmask to change
+ * @val: New value for bitmask
+ *
+ * This function handles the register writes to the direct access registers and
+ * the muxed registers while caching all register accesses, internally handling
+ * the correct state of the PORTSEL register and protecting the access to muxed
+ * registers.
+ * The caller must only use this function to change registers behind the PORTSEL mux.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int cy8c95x0_regmap_write_bits(struct cy8c95x0_pinctrl *chip, unsigned int reg,
+ unsigned int port, unsigned int mask, unsigned int val)
+{
+ return cy8c95x0_regmap_update_bits_base(chip, reg, port, mask, val, NULL, false, true);
+}
+
+/**
+ * cy8c95x0_regmap_update_bits() - updates a register using the regmap cache
+ * @chip: The pinctrl to work on
+ * @reg: The register to write to. Can be direct access or muxed register.
+ * MUST NOT be the PORTSEL register.
+ * @port: The port to be used for muxed registers or quick path direct access
+ * registers. Otherwise unused.
+ * @mask: Bitmask to change
+ * @val: New value for bitmask
+ *
+ * This function handles the register updates to the direct access registers and
+ * the muxed registers while caching all register accesses, internally handling
+ * the correct state of the PORTSEL register and protecting the access to muxed
+ * registers.
+ * The caller must only use this function to change registers behind the PORTSEL mux.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int cy8c95x0_regmap_update_bits(struct cy8c95x0_pinctrl *chip, unsigned int reg,
+ unsigned int port, unsigned int mask, unsigned int val)
+{
+ return cy8c95x0_regmap_update_bits_base(chip, reg, port, mask, val, NULL, false, false);
+}
+
+/**
+ * cy8c95x0_regmap_read() - reads a register using the regmap cache
+ * @chip: The pinctrl to work on
+ * @reg: The register to read from. Can be direct access or muxed register.
+ * @port: The port to be used for muxed registers or quick path direct access
+ * registers. Otherwise unused.
+ * @read_val: Value read from hardware or cache
+ *
+ * This function handles the register reads from the direct access registers and
+ * the muxed registers while caching all register accesses, internally handling
+ * the correct state of the PORTSEL register and protecting the access to muxed
+ * registers.
+ * The caller must only use this function to read registers behind the PORTSEL mux.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int cy8c95x0_regmap_read(struct cy8c95x0_pinctrl *chip, unsigned int reg,
+ unsigned int port, unsigned int *read_val)
+{
+ struct regmap *regmap;
+ int off;
+
+ /* Registers behind the PORTSEL mux have their own regmap */
+ if (cy8c95x0_muxed_register(reg)) {
+ regmap = chip->muxed_regmap;
+ off = CY8C95X0_MUX_REGMAP_TO_OFFSET(reg, port);
+ } else {
+ regmap = chip->regmap;
+ /* Quick path direct access registers honor the port argument */
+ if (cy8c95x0_quick_path_register(reg))
+ off = reg + port;
+ else
+ off = reg;
+ }
+
+ return regmap_read(regmap, off, read_val);
+}
+
static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
unsigned long *val, unsigned long *mask)
{
@@ -415,7 +692,7 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
DECLARE_BITMAP(tval, MAX_LINE);
int write_val;
int ret = 0;
- int i, off = 0;
+ int i;
u8 bits;
/* Add the 4 bit gap of Gport2 */
@@ -427,53 +704,22 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
bitmap_shift_left(tval, tval, 4, MAX_LINE);
bitmap_replace(tval, tval, val, chip->shiftmask, BANK_SZ * 3);
- mutex_lock(&chip->i2c_lock);
for (i = 0; i < chip->nport; i++) {
/* Skip over unused banks */
bits = bitmap_get_value8(tmask, i * BANK_SZ);
if (!bits)
continue;
- switch (reg) {
- /* Muxed registers */
- case CY8C95X0_INTMASK:
- case CY8C95X0_PWMSEL:
- case CY8C95X0_INVERT:
- case CY8C95X0_DIRECTION:
- case CY8C95X0_DRV_PU:
- case CY8C95X0_DRV_PD:
- case CY8C95X0_DRV_ODH:
- case CY8C95X0_DRV_ODL:
- case CY8C95X0_DRV_PP_FAST:
- case CY8C95X0_DRV_PP_SLOW:
- case CY8C95X0_DRV_HIZ:
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, i);
- if (ret < 0)
- goto out;
- off = reg;
- break;
- /* Direct access registers */
- case CY8C95X0_INPUT:
- case CY8C95X0_OUTPUT:
- case CY8C95X0_INTSTATUS:
- off = reg + i;
- break;
- default:
- ret = -EINVAL;
- goto out;
- }
-
write_val = bitmap_get_value8(tval, i * BANK_SZ);
- ret = regmap_update_bits(chip->regmap, off, bits, write_val);
+ ret = cy8c95x0_regmap_update_bits(chip, reg, i, bits, write_val);
if (ret < 0)
goto out;
}
out:
- mutex_unlock(&chip->i2c_lock);
if (ret < 0)
- dev_err(chip->dev, "failed writing register %d: err %d\n", off, ret);
+ dev_err(chip->dev, "failed writing register %d, port %d: err %d\n", reg, i, ret);
return ret;
}
@@ -486,7 +732,7 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
DECLARE_BITMAP(tmp, MAX_LINE);
int read_val;
int ret = 0;
- int i, off = 0;
+ int i;
u8 bits;
/* Add the 4 bit gap of Gport2 */
@@ -498,43 +744,13 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
bitmap_shift_left(tval, tval, 4, MAX_LINE);
bitmap_replace(tval, tval, val, chip->shiftmask, BANK_SZ * 3);
- mutex_lock(&chip->i2c_lock);
for (i = 0; i < chip->nport; i++) {
/* Skip over unused banks */
bits = bitmap_get_value8(tmask, i * BANK_SZ);
if (!bits)
continue;
- switch (reg) {
- /* Muxed registers */
- case CY8C95X0_INTMASK:
- case CY8C95X0_PWMSEL:
- case CY8C95X0_INVERT:
- case CY8C95X0_DIRECTION:
- case CY8C95X0_DRV_PU:
- case CY8C95X0_DRV_PD:
- case CY8C95X0_DRV_ODH:
- case CY8C95X0_DRV_ODL:
- case CY8C95X0_DRV_PP_FAST:
- case CY8C95X0_DRV_PP_SLOW:
- case CY8C95X0_DRV_HIZ:
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, i);
- if (ret < 0)
- goto out;
- off = reg;
- break;
- /* Direct access registers */
- case CY8C95X0_INPUT:
- case CY8C95X0_OUTPUT:
- case CY8C95X0_INTSTATUS:
- off = reg + i;
- break;
- default:
- ret = -EINVAL;
- goto out;
- }
-
- ret = regmap_read(chip->regmap, off, &read_val);
+ ret = cy8c95x0_regmap_read(chip, reg, i, &read_val);
if (ret < 0)
goto out;
@@ -548,10 +764,8 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
bitmap_replace(val, tmp, tval, chip->shiftmask, MAX_LINE);
out:
- mutex_unlock(&chip->i2c_lock);
-
if (ret < 0)
- dev_err(chip->dev, "failed reading register %d: err %d\n", off, ret);
+ dev_err(chip->dev, "failed reading register %d, port %d: err %d\n", reg, i, ret);
return ret;
}
@@ -566,12 +780,11 @@ static int cy8c95x0_gpio_direction_output(struct gpio_chip *gc,
{
struct cy8c95x0_pinctrl *chip = gpiochip_get_data(gc);
u8 port = cypress_get_port(chip, off);
- u8 outreg = CY8C95X0_OUTPUT_(port);
u8 bit = cypress_get_pin_mask(chip, off);
int ret;
/* Set output level */
- ret = regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0);
+ ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_OUTPUT, port, bit, val ? bit : 0);
if (ret)
return ret;
@@ -581,12 +794,12 @@ static int cy8c95x0_gpio_direction_output(struct gpio_chip *gc,
static int cy8c95x0_gpio_get_value(struct gpio_chip *gc, unsigned int off)
{
struct cy8c95x0_pinctrl *chip = gpiochip_get_data(gc);
- u8 inreg = CY8C95X0_INPUT_(cypress_get_port(chip, off));
+ u8 port = cypress_get_port(chip, off);
u8 bit = cypress_get_pin_mask(chip, off);
u32 reg_val;
int ret;
- ret = regmap_read(chip->regmap, inreg, &reg_val);
+ ret = cy8c95x0_regmap_read(chip, CY8C95X0_INPUT, port, &reg_val);
if (ret < 0) {
/*
* NOTE:
@@ -604,10 +817,10 @@ static void cy8c95x0_gpio_set_value(struct gpio_chip *gc, unsigned int off,
int val)
{
struct cy8c95x0_pinctrl *chip = gpiochip_get_data(gc);
- u8 outreg = CY8C95X0_OUTPUT_(cypress_get_port(chip, off));
+ u8 port = cypress_get_port(chip, off);
u8 bit = cypress_get_pin_mask(chip, off);
- regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0);
+ cy8c95x0_regmap_write_bits(chip, CY8C95X0_OUTPUT, port, bit, val ? bit : 0);
}
static int cy8c95x0_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
@@ -618,24 +831,15 @@ static int cy8c95x0_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
u32 reg_val;
int ret;
- mutex_lock(&chip->i2c_lock);
-
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
- if (ret < 0)
- goto out;
-
- ret = regmap_read(chip->regmap, CY8C95X0_DIRECTION, &reg_val);
+ ret = cy8c95x0_regmap_read(chip, CY8C95X0_DIRECTION, port, &reg_val);
if (ret < 0)
goto out;
- mutex_unlock(&chip->i2c_lock);
-
if (reg_val & bit)
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
out:
- mutex_unlock(&chip->i2c_lock);
return ret;
}
@@ -651,13 +855,6 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip,
u16 arg = 0;
int ret;
- mutex_lock(&chip->i2c_lock);
-
- /* Select port */
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
- if (ret < 0)
- goto out;
-
switch (param) {
case PIN_CONFIG_BIAS_PULL_UP:
reg = CY8C95X0_DRV_PU;
@@ -684,7 +881,7 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip,
reg = CY8C95X0_PWMSEL;
break;
case PIN_CONFIG_OUTPUT:
- reg = CY8C95X0_OUTPUT_(port);
+ reg = CY8C95X0_OUTPUT;
break;
case PIN_CONFIG_OUTPUT_ENABLE:
reg = CY8C95X0_DIRECTION;
@@ -712,7 +909,10 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip,
* Writing 1 to one of the drive mode registers will automatically
* clear conflicting set bits in the other drive mode registers.
*/
- ret = regmap_read(chip->regmap, reg, &reg_val);
+ ret = cy8c95x0_regmap_read(chip, reg, port, &reg_val);
+ if (ret < 0)
+ goto out;
+
if (reg_val & bit)
arg = 1;
if (param == PIN_CONFIG_OUTPUT_ENABLE)
@@ -720,8 +920,6 @@ static int cy8c95x0_gpio_get_pincfg(struct cy8c95x0_pinctrl *chip,
*config = pinconf_to_config_packed(param, (u16)arg);
out:
- mutex_unlock(&chip->i2c_lock);
-
return ret;
}
@@ -736,13 +934,6 @@ static int cy8c95x0_gpio_set_pincfg(struct cy8c95x0_pinctrl *chip,
unsigned int reg;
int ret;
- mutex_lock(&chip->i2c_lock);
-
- /* Select port */
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
- if (ret < 0)
- goto out;
-
switch (param) {
case PIN_CONFIG_BIAS_PULL_UP:
__clear_bit(off, chip->push_pull);
@@ -785,10 +976,8 @@ static int cy8c95x0_gpio_set_pincfg(struct cy8c95x0_pinctrl *chip,
* Writing 1 to one of the drive mode registers will automatically
* clear conflicting set bits in the other drive mode registers.
*/
- ret = regmap_write_bits(chip->regmap, reg, bit, bit);
-
+ ret = cy8c95x0_regmap_write_bits(chip, reg, port, bit, bit);
out:
- mutex_unlock(&chip->i2c_lock);
return ret;
}
@@ -1105,14 +1294,8 @@ static int cy8c95x0_set_mode(struct cy8c95x0_pinctrl *chip, unsigned int off, bo
{
u8 port = cypress_get_port(chip, off);
u8 bit = cypress_get_pin_mask(chip, off);
- int ret;
- /* Select port */
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
- if (ret < 0)
- return ret;
-
- return regmap_write_bits(chip->regmap, CY8C95X0_PWMSEL, bit, mode ? bit : 0);
+ return cy8c95x0_regmap_write_bits(chip, CY8C95X0_PWMSEL, port, bit, mode ? bit : 0);
}
static int cy8c95x0_pinmux_mode(struct cy8c95x0_pinctrl *chip,
@@ -1130,24 +1313,19 @@ static int cy8c95x0_pinmux_mode(struct cy8c95x0_pinctrl *chip,
return 0;
/* Set direction to output & set output to 1 so that PWM can work */
- ret = regmap_write_bits(chip->regmap, CY8C95X0_DIRECTION, bit, bit);
+ ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DIRECTION, port, bit, bit);
if (ret < 0)
return ret;
- return regmap_write_bits(chip->regmap, CY8C95X0_OUTPUT_(port), bit, bit);
+ return cy8c95x0_regmap_write_bits(chip, CY8C95X0_OUTPUT, port, bit, bit);
}
static int cy8c95x0_set_mux(struct pinctrl_dev *pctldev, unsigned int selector,
unsigned int group)
{
struct cy8c95x0_pinctrl *chip = pinctrl_dev_get_drvdata(pctldev);
- int ret;
- mutex_lock(&chip->i2c_lock);
- ret = cy8c95x0_pinmux_mode(chip, selector, group);
- mutex_unlock(&chip->i2c_lock);
-
- return ret;
+ return cy8c95x0_pinmux_mode(chip, selector, group);
}
static int cy8c95x0_gpio_request_enable(struct pinctrl_dev *pctldev,
@@ -1155,13 +1333,8 @@ static int cy8c95x0_gpio_request_enable(struct pinctrl_dev *pctldev,
unsigned int pin)
{
struct cy8c95x0_pinctrl *chip = pinctrl_dev_get_drvdata(pctldev);
- int ret;
-
- mutex_lock(&chip->i2c_lock);
- ret = cy8c95x0_set_mode(chip, pin, false);
- mutex_unlock(&chip->i2c_lock);
- return ret;
+ return cy8c95x0_set_mode(chip, pin, false);
}
static int cy8c95x0_pinmux_direction(struct cy8c95x0_pinctrl *chip,
@@ -1171,13 +1344,7 @@ static int cy8c95x0_pinmux_direction(struct cy8c95x0_pinctrl *chip,
u8 bit = cypress_get_pin_mask(chip, pin);
int ret;
- /* Select port... */
- ret = regmap_write(chip->regmap, CY8C95X0_PORTSEL, port);
- if (ret)
- return ret;
-
- /* ...then direction */
- ret = regmap_write_bits(chip->regmap, CY8C95X0_DIRECTION, bit, input ? bit : 0);
+ ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DIRECTION, port, bit, input ? bit : 0);
if (ret)
return ret;
@@ -1186,7 +1353,7 @@ static int cy8c95x0_pinmux_direction(struct cy8c95x0_pinctrl *chip,
* the direction register isn't sufficient in Push-Pull mode.
*/
if (input && test_bit(pin, chip->push_pull)) {
- ret = regmap_write_bits(chip->regmap, CY8C95X0_DRV_HIZ, bit, bit);
+ ret = cy8c95x0_regmap_write_bits(chip, CY8C95X0_DRV_HIZ, port, bit, bit);
if (ret)
return ret;
@@ -1201,13 +1368,8 @@ static int cy8c95x0_gpio_set_direction(struct pinctrl_dev *pctldev,
unsigned int pin, bool input)
{
struct cy8c95x0_pinctrl *chip = pinctrl_dev_get_drvdata(pctldev);
- int ret;
- mutex_lock(&chip->i2c_lock);
- ret = cy8c95x0_pinmux_direction(chip, pin, input);
- mutex_unlock(&chip->i2c_lock);
-
- return ret;
+ return cy8c95x0_pinmux_direction(chip, pin, input);
}
static const struct pinmux_ops cy8c95x0_pmxops = {
@@ -1409,12 +1571,22 @@ static int cy8c95x0_probe(struct i2c_client *client)
gpiod_set_consumer_name(chip->gpio_reset, "CY8C95X0 RESET");
}
+ /* Generic regmap for direct access registers */
chip->regmap = devm_regmap_init_i2c(client, &cy8c95x0_i2c_regmap);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
goto err_exit;
}
+ /* Port specific regmap behind PORTSEL mux */
+ chip->muxed_regmap = devm_regmap_init(&client->dev, &cy8c95x0_regmap_bus,
+ chip, &cy8c95x0_muxed_regmap);
+ if (IS_ERR(chip->muxed_regmap)) {
+ ret = dev_err_probe(&client->dev, PTR_ERR(chip->muxed_regmap),
+ "Failed to register muxed regmap\n");
+ goto err_exit;
+ }
+
bitmap_zero(chip->push_pull, MAX_LINE);
bitmap_zero(chip->shiftmask, MAX_LINE);
bitmap_set(chip->shiftmask, 0, 20);
diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c
index 5b5ddf7e5d0e..6e1be38865c3 100644
--- a/drivers/pinctrl/pinctrl-equilibrium.c
+++ b/drivers/pinctrl/pinctrl-equilibrium.c
@@ -331,8 +331,8 @@ static int eqbr_pinmux_set_mux(struct pinctrl_dev *pctldev,
return -EINVAL;
pinmux = grp->data;
- for (i = 0; i < grp->num_pins; i++)
- eqbr_set_pin_mux(pctl, pinmux[i], grp->pins[i]);
+ for (i = 0; i < grp->grp.npins; i++)
+ eqbr_set_pin_mux(pctl, pinmux[i], grp->grp.pins[i]);
return 0;
}
@@ -704,8 +704,8 @@ static int eqbr_build_groups(struct eqbr_pinctrl_drv_data *drvdata)
{
struct device *dev = drvdata->dev;
struct device_node *node = dev->of_node;
- unsigned int *pinmux, pin_id, pinmux_id;
- struct group_desc group;
+ unsigned int *pins, *pinmux, pin_id, pinmux_id;
+ struct pingroup group, *grp = &group;
struct device_node *np;
struct property *prop;
int j, err;
@@ -715,55 +715,55 @@ static int eqbr_build_groups(struct eqbr_pinctrl_drv_data *drvdata)
if (!prop)
continue;
- group.num_pins = of_property_count_u32_elems(np, "pins");
- if (group.num_pins < 0) {
+ err = of_property_count_u32_elems(np, "pins");
+ if (err < 0) {
dev_err(dev, "No pins in the group: %s\n", prop->name);
of_node_put(np);
- return -EINVAL;
+ return err;
}
- group.name = prop->value;
- group.pins = devm_kcalloc(dev, group.num_pins,
- sizeof(*(group.pins)), GFP_KERNEL);
- if (!group.pins) {
+ grp->npins = err;
+ grp->name = prop->value;
+ pins = devm_kcalloc(dev, grp->npins, sizeof(*pins), GFP_KERNEL);
+ if (!pins) {
of_node_put(np);
return -ENOMEM;
}
+ grp->pins = pins;
- pinmux = devm_kcalloc(dev, group.num_pins, sizeof(*pinmux),
- GFP_KERNEL);
+ pinmux = devm_kcalloc(dev, grp->npins, sizeof(*pinmux), GFP_KERNEL);
if (!pinmux) {
of_node_put(np);
return -ENOMEM;
}
- for (j = 0; j < group.num_pins; j++) {
+ for (j = 0; j < grp->npins; j++) {
if (of_property_read_u32_index(np, "pins", j, &pin_id)) {
dev_err(dev, "Group %s: Read intel pins id failed\n",
- group.name);
+ grp->name);
of_node_put(np);
return -EINVAL;
}
if (pin_id >= drvdata->pctl_desc.npins) {
dev_err(dev, "Group %s: Invalid pin ID, idx: %d, pin %u\n",
- group.name, j, pin_id);
+ grp->name, j, pin_id);
of_node_put(np);
return -EINVAL;
}
- group.pins[j] = pin_id;
+ pins[j] = pin_id;
if (of_property_read_u32_index(np, "pinmux", j, &pinmux_id)) {
dev_err(dev, "Group %s: Read intel pinmux id failed\n",
- group.name);
+ grp->name);
of_node_put(np);
return -EINVAL;
}
pinmux[j] = pinmux_id;
}
- err = pinctrl_generic_add_group(drvdata->pctl_dev, group.name,
- group.pins, group.num_pins,
+ err = pinctrl_generic_add_group(drvdata->pctl_dev,
+ grp->name, grp->pins, grp->npins,
pinmux);
if (err < 0) {
- dev_err(dev, "Failed to register group %s\n", group.name);
+ dev_err(dev, "Failed to register group %s\n", grp->name);
of_node_put(np);
return err;
}
diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c
index ee718f6e2556..bc6358a686fc 100644
--- a/drivers/pinctrl/pinctrl-ingenic.c
+++ b/drivers/pinctrl/pinctrl-ingenic.c
@@ -82,16 +82,17 @@
#define PINS_PER_GPIO_CHIP 32
#define JZ4730_PINS_PER_PAIRED_REG 16
-#define INGENIC_PIN_GROUP_FUNCS(name, id, funcs) \
- { \
- name, \
- id##_pins, \
- ARRAY_SIZE(id##_pins), \
- funcs, \
+#define INGENIC_PIN_GROUP_FUNCS(_name_, id, funcs) \
+ { \
+ .grp = PINCTRL_PINGROUP(_name_, id##_pins, ARRAY_SIZE(id##_pins)), \
+ .data = funcs, \
}
-#define INGENIC_PIN_GROUP(name, id, func) \
- INGENIC_PIN_GROUP_FUNCS(name, id, (void *)(func))
+#define INGENIC_PIN_GROUP(_name_, id, func) \
+ { \
+ .grp = PINCTRL_PINGROUP(_name_, id##_pins, ARRAY_SIZE(id##_pins)), \
+ .data = (void *)func, \
+ }
enum jz_version {
ID_JZ4730,
@@ -3761,17 +3762,17 @@ static int ingenic_pinmux_set_mux(struct pinctrl_dev *pctldev,
return -EINVAL;
dev_dbg(pctldev->dev, "enable function %s group %s\n",
- func->name, grp->name);
+ func->name, grp->grp.name);
mode = (uintptr_t)grp->data;
if (mode <= 3) {
- for (i = 0; i < grp->num_pins; i++)
- ingenic_pinmux_set_pin_fn(jzpc, grp->pins[i], mode);
+ for (i = 0; i < grp->grp.npins; i++)
+ ingenic_pinmux_set_pin_fn(jzpc, grp->grp.pins[i], mode);
} else {
pin_modes = grp->data;
- for (i = 0; i < grp->num_pins; i++)
- ingenic_pinmux_set_pin_fn(jzpc, grp->pins[i], pin_modes[i]);
+ for (i = 0; i < grp->grp.npins; i++)
+ ingenic_pinmux_set_pin_fn(jzpc, grp->grp.pins[i], pin_modes[i]);
}
return 0;
@@ -4298,12 +4299,12 @@ static int __init ingenic_pinctrl_probe(struct platform_device *pdev)
for (i = 0; i < chip_info->num_groups; i++) {
const struct group_desc *group = &chip_info->groups[i];
+ const struct pingroup *grp = &group->grp;
- err = pinctrl_generic_add_group(jzpc->pctl, group->name,
- group->pins, group->num_pins, group->data);
+ err = pinctrl_generic_add_group(jzpc->pctl, grp->name, grp->pins, grp->npins,
+ group->data);
if (err < 0) {
- dev_err(dev, "Failed to register group %s\n",
- group->name);
+ dev_err(dev, "Failed to register group %s\n", grp->name);
return err;
}
}
diff --git a/drivers/pinctrl/pinctrl-keembay.c b/drivers/pinctrl/pinctrl-keembay.c
index 152c35bce8ec..b1349ee22799 100644
--- a/drivers/pinctrl/pinctrl-keembay.c
+++ b/drivers/pinctrl/pinctrl-keembay.c
@@ -945,7 +945,7 @@ static int keembay_set_mux(struct pinctrl_dev *pctldev, unsigned int fun_sel,
return -EINVAL;
/* Change modes for pins in the selected group */
- pin = *grp->pins;
+ pin = *grp->grp.pins;
pin_mode = *(u8 *)(func->data);
val = keembay_read_reg(kpc->base1 + KEEMBAY_GPIO_MODE, pin);
@@ -1517,7 +1517,7 @@ static int keembay_gpiochip_probe(struct keembay_pinctrl *kpc,
static int keembay_build_groups(struct keembay_pinctrl *kpc)
{
- struct group_desc *grp;
+ struct pingroup *grp;
unsigned int i;
kpc->ngroups = kpc->npins;
@@ -1528,7 +1528,7 @@ static int keembay_build_groups(struct keembay_pinctrl *kpc)
/* Each pin is categorised as one group */
for (i = 0; i < kpc->ngroups; i++) {
const struct pinctrl_pin_desc *pdesc = keembay_pins + i;
- struct group_desc *kmb_grp = grp + i;
+ struct pingroup *kmb_grp = grp + i;
kmb_grp->name = pdesc->name;
kmb_grp->pins = (int *)&pdesc->number;
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 8267be769635..19cc0db771a5 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -1955,6 +1955,10 @@ static const struct pcs_soc_data pinctrl_single_am654 = {
.irq_status_mask = (1 << 30), /* WKUP_EVT */
};
+static const struct pcs_soc_data pinctrl_single_j7200 = {
+ .flags = PCS_CONTEXT_LOSS_OFF,
+};
+
static const struct pcs_soc_data pinctrl_single = {
};
@@ -1969,6 +1973,7 @@ static const struct of_device_id pcs_of_match[] = {
{ .compatible = "ti,omap3-padconf", .data = &pinctrl_single_omap_wkup },
{ .compatible = "ti,omap4-padconf", .data = &pinctrl_single_omap_wkup },
{ .compatible = "ti,omap5-padconf", .data = &pinctrl_single_omap_wkup },
+ { .compatible = "ti,j7200-padconf", .data = &pinctrl_single_j7200 },
{ .compatible = "pinctrl-single", .data = &pinctrl_single },
{ .compatible = "pinconf-single", .data = &pinconf_single },
{ },
diff --git a/drivers/pinctrl/pinctrl-tps6594.c b/drivers/pinctrl/pinctrl-tps6594.c
new file mode 100644
index 000000000000..66985e54b74a
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-tps6594.c
@@ -0,0 +1,373 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Pinmux and GPIO driver for tps6594 PMIC
+ *
+ * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/gpio/regmap.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
+
+#include <linux/mfd/tps6594.h>
+
+#define TPS6594_PINCTRL_PINS_NB 11
+
+#define TPS6594_PINCTRL_GPIO_FUNCTION 0
+#define TPS6594_PINCTRL_SCL_I2C2_CS_SPI_FUNCTION 1
+#define TPS6594_PINCTRL_TRIG_WDOG_FUNCTION 1
+#define TPS6594_PINCTRL_CLK32KOUT_FUNCTION 1
+#define TPS6594_PINCTRL_SCLK_SPMI_FUNCTION 1
+#define TPS6594_PINCTRL_SDATA_SPMI_FUNCTION 1
+#define TPS6594_PINCTRL_NERR_MCU_FUNCTION 1
+#define TPS6594_PINCTRL_PDOG_FUNCTION 1
+#define TPS6594_PINCTRL_SYNCCLKIN_FUNCTION 1
+#define TPS6594_PINCTRL_NRSTOUT_SOC_FUNCTION 2
+#define TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION 2
+#define TPS6594_PINCTRL_SDA_I2C2_SDO_SPI_FUNCTION 2
+#define TPS6594_PINCTRL_NERR_SOC_FUNCTION 2
+#define TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION 3
+#define TPS6594_PINCTRL_NSLEEP1_FUNCTION 4
+#define TPS6594_PINCTRL_NSLEEP2_FUNCTION 5
+#define TPS6594_PINCTRL_WKUP1_FUNCTION 6
+#define TPS6594_PINCTRL_WKUP2_FUNCTION 7
+
+/* Special muxval for recalcitrant pins */
+#define TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION_GPIO8 2
+#define TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION_GPIO8 3
+#define TPS6594_PINCTRL_CLK32KOUT_FUNCTION_GPIO9 3
+
+#define TPS6594_OFFSET_GPIO_SEL 5
+
+#define FUNCTION(fname, v) \
+{ \
+ .pinfunction = PINCTRL_PINFUNCTION(#fname, \
+ tps6594_##fname##_func_group_names, \
+ ARRAY_SIZE(tps6594_##fname##_func_group_names)),\
+ .muxval = v, \
+}
+
+static const struct pinctrl_pin_desc tps6594_pins[TPS6594_PINCTRL_PINS_NB] = {
+ PINCTRL_PIN(0, "GPIO0"), PINCTRL_PIN(1, "GPIO1"),
+ PINCTRL_PIN(2, "GPIO2"), PINCTRL_PIN(3, "GPIO3"),
+ PINCTRL_PIN(4, "GPIO4"), PINCTRL_PIN(5, "GPIO5"),
+ PINCTRL_PIN(6, "GPIO6"), PINCTRL_PIN(7, "GPIO7"),
+ PINCTRL_PIN(8, "GPIO8"), PINCTRL_PIN(9, "GPIO9"),
+ PINCTRL_PIN(10, "GPIO10"),
+};
+
+static const char *const tps6594_gpio_func_group_names[] = {
+ "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5",
+ "GPIO6", "GPIO7", "GPIO8", "GPIO9", "GPIO10",
+};
+
+static const char *const tps6594_nsleep1_func_group_names[] = {
+ "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5",
+ "GPIO6", "GPIO7", "GPIO8", "GPIO9", "GPIO10",
+};
+
+static const char *const tps6594_nsleep2_func_group_names[] = {
+ "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5",
+ "GPIO6", "GPIO7", "GPIO8", "GPIO9", "GPIO10",
+};
+
+static const char *const tps6594_wkup1_func_group_names[] = {
+ "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5",
+ "GPIO6", "GPIO7", "GPIO8", "GPIO9", "GPIO10",
+};
+
+static const char *const tps6594_wkup2_func_group_names[] = {
+ "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", "GPIO5",
+ "GPIO6", "GPIO7", "GPIO8", "GPIO9", "GPIO10",
+};
+
+static const char *const tps6594_scl_i2c2_cs_spi_func_group_names[] = {
+ "GPIO0",
+ "GPIO1",
+};
+
+static const char *const tps6594_nrstout_soc_func_group_names[] = {
+ "GPIO0",
+ "GPIO10",
+};
+
+static const char *const tps6594_trig_wdog_func_group_names[] = {
+ "GPIO1",
+ "GPIO10",
+};
+
+static const char *const tps6594_sda_i2c2_sdo_spi_func_group_names[] = {
+ "GPIO1",
+};
+
+static const char *const tps6594_clk32kout_func_group_names[] = {
+ "GPIO2",
+ "GPIO3",
+ "GPIO7",
+};
+
+static const char *const tps6594_nerr_soc_func_group_names[] = {
+ "GPIO2",
+};
+
+static const char *const tps6594_sclk_spmi_func_group_names[] = {
+ "GPIO4",
+};
+
+static const char *const tps6594_sdata_spmi_func_group_names[] = {
+ "GPIO5",
+};
+
+static const char *const tps6594_nerr_mcu_func_group_names[] = {
+ "GPIO6",
+};
+
+static const char *const tps6594_syncclkout_func_group_names[] = {
+ "GPIO7",
+ "GPIO9",
+};
+
+static const char *const tps6594_disable_wdog_func_group_names[] = {
+ "GPIO7",
+ "GPIO8",
+};
+
+static const char *const tps6594_pdog_func_group_names[] = {
+ "GPIO8",
+};
+
+static const char *const tps6594_syncclkin_func_group_names[] = {
+ "GPIO9",
+};
+
+struct tps6594_pinctrl_function {
+ struct pinfunction pinfunction;
+ u8 muxval;
+};
+
+static const struct tps6594_pinctrl_function pinctrl_functions[] = {
+ FUNCTION(gpio, TPS6594_PINCTRL_GPIO_FUNCTION),
+ FUNCTION(nsleep1, TPS6594_PINCTRL_NSLEEP1_FUNCTION),
+ FUNCTION(nsleep2, TPS6594_PINCTRL_NSLEEP2_FUNCTION),
+ FUNCTION(wkup1, TPS6594_PINCTRL_WKUP1_FUNCTION),
+ FUNCTION(wkup2, TPS6594_PINCTRL_WKUP2_FUNCTION),
+ FUNCTION(scl_i2c2_cs_spi, TPS6594_PINCTRL_SCL_I2C2_CS_SPI_FUNCTION),
+ FUNCTION(nrstout_soc, TPS6594_PINCTRL_NRSTOUT_SOC_FUNCTION),
+ FUNCTION(trig_wdog, TPS6594_PINCTRL_TRIG_WDOG_FUNCTION),
+ FUNCTION(sda_i2c2_sdo_spi, TPS6594_PINCTRL_SDA_I2C2_SDO_SPI_FUNCTION),
+ FUNCTION(clk32kout, TPS6594_PINCTRL_CLK32KOUT_FUNCTION),
+ FUNCTION(nerr_soc, TPS6594_PINCTRL_NERR_SOC_FUNCTION),
+ FUNCTION(sclk_spmi, TPS6594_PINCTRL_SCLK_SPMI_FUNCTION),
+ FUNCTION(sdata_spmi, TPS6594_PINCTRL_SDATA_SPMI_FUNCTION),
+ FUNCTION(nerr_mcu, TPS6594_PINCTRL_NERR_MCU_FUNCTION),
+ FUNCTION(syncclkout, TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION),
+ FUNCTION(disable_wdog, TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION),
+ FUNCTION(pdog, TPS6594_PINCTRL_PDOG_FUNCTION),
+ FUNCTION(syncclkin, TPS6594_PINCTRL_SYNCCLKIN_FUNCTION),
+};
+
+struct tps6594_pinctrl {
+ struct tps6594 *tps;
+ struct gpio_regmap *gpio_regmap;
+ struct pinctrl_dev *pctl_dev;
+ const struct tps6594_pinctrl_function *funcs;
+ const struct pinctrl_pin_desc *pins;
+};
+
+static int tps6594_gpio_regmap_xlate(struct gpio_regmap *gpio,
+ unsigned int base, unsigned int offset,
+ unsigned int *reg, unsigned int *mask)
+{
+ unsigned int line = offset % 8;
+ unsigned int stride = offset / 8;
+
+ switch (base) {
+ case TPS6594_REG_GPIOX_CONF(0):
+ *reg = TPS6594_REG_GPIOX_CONF(offset);
+ *mask = TPS6594_BIT_GPIO_DIR;
+ return 0;
+ case TPS6594_REG_GPIO_IN_1:
+ case TPS6594_REG_GPIO_OUT_1:
+ *reg = base + stride;
+ *mask = BIT(line);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tps6594_pmx_func_cnt(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(pinctrl_functions);
+}
+
+static const char *tps6594_pmx_func_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pinctrl->funcs[selector].pinfunction.name;
+}
+
+static int tps6594_pmx_func_groups(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const char *const **groups,
+ unsigned int *num_groups)
+{
+ struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pinctrl->funcs[selector].pinfunction.groups;
+ *num_groups = pinctrl->funcs[selector].pinfunction.ngroups;
+
+ return 0;
+}
+
+static int tps6594_pmx_set(struct tps6594_pinctrl *pinctrl, unsigned int pin,
+ u8 muxval)
+{
+ u8 mux_sel_val = muxval << TPS6594_OFFSET_GPIO_SEL;
+
+ return regmap_update_bits(pinctrl->tps->regmap,
+ TPS6594_REG_GPIOX_CONF(pin),
+ TPS6594_MASK_GPIO_SEL, mux_sel_val);
+}
+
+static int tps6594_pmx_set_mux(struct pinctrl_dev *pctldev,
+ unsigned int function, unsigned int group)
+{
+ struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
+ u8 muxval = pinctrl->funcs[function].muxval;
+
+ /* Some pins don't have the same muxval for the same function... */
+ if (group == 8) {
+ if (muxval == TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION)
+ muxval = TPS6594_PINCTRL_DISABLE_WDOG_FUNCTION_GPIO8;
+ else if (muxval == TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION)
+ muxval = TPS6594_PINCTRL_SYNCCLKOUT_FUNCTION_GPIO8;
+ } else if (group == 9) {
+ if (muxval == TPS6594_PINCTRL_CLK32KOUT_FUNCTION)
+ muxval = TPS6594_PINCTRL_CLK32KOUT_FUNCTION_GPIO9;
+ }
+
+ return tps6594_pmx_set(pinctrl, group, muxval);
+}
+
+static int tps6594_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned int offset, bool input)
+{
+ struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
+ u8 muxval = pinctrl->funcs[TPS6594_PINCTRL_GPIO_FUNCTION].muxval;
+
+ return tps6594_pmx_set(pinctrl, offset, muxval);
+}
+
+static const struct pinmux_ops tps6594_pmx_ops = {
+ .get_functions_count = tps6594_pmx_func_cnt,
+ .get_function_name = tps6594_pmx_func_name,
+ .get_function_groups = tps6594_pmx_func_groups,
+ .set_mux = tps6594_pmx_set_mux,
+ .gpio_set_direction = tps6594_pmx_gpio_set_direction,
+ .strict = true,
+};
+
+static int tps6594_groups_cnt(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(tps6594_pins);
+}
+
+static int tps6594_group_pins(struct pinctrl_dev *pctldev,
+ unsigned int selector, const unsigned int **pins,
+ unsigned int *num_pins)
+{
+ struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = &pinctrl->pins[selector].number;
+ *num_pins = 1;
+
+ return 0;
+}
+
+static const char *tps6594_group_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct tps6594_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pinctrl->pins[selector].name;
+}
+
+static const struct pinctrl_ops tps6594_pctrl_ops = {
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
+ .dt_free_map = pinconf_generic_dt_free_map,
+ .get_groups_count = tps6594_groups_cnt,
+ .get_group_name = tps6594_group_name,
+ .get_group_pins = tps6594_group_pins,
+};
+
+static int tps6594_pinctrl_probe(struct platform_device *pdev)
+{
+ struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct tps6594_pinctrl *pinctrl;
+ struct pinctrl_desc *pctrl_desc;
+ struct gpio_regmap_config config = {};
+
+ pctrl_desc = devm_kzalloc(dev, sizeof(*pctrl_desc), GFP_KERNEL);
+ if (!pctrl_desc)
+ return -ENOMEM;
+ pctrl_desc->name = dev_name(dev);
+ pctrl_desc->owner = THIS_MODULE;
+ pctrl_desc->pins = tps6594_pins;
+ pctrl_desc->npins = ARRAY_SIZE(tps6594_pins);
+ pctrl_desc->pctlops = &tps6594_pctrl_ops;
+ pctrl_desc->pmxops = &tps6594_pmx_ops;
+
+ pinctrl = devm_kzalloc(dev, sizeof(*pinctrl), GFP_KERNEL);
+ if (!pinctrl)
+ return -ENOMEM;
+ pinctrl->tps = dev_get_drvdata(dev->parent);
+ pinctrl->funcs = pinctrl_functions;
+ pinctrl->pins = tps6594_pins;
+ pinctrl->pctl_dev = devm_pinctrl_register(dev, pctrl_desc, pinctrl);
+ if (IS_ERR(pinctrl->pctl_dev))
+ return dev_err_probe(dev, PTR_ERR(pinctrl->pctl_dev),
+ "Couldn't register pinctrl driver\n");
+
+ config.parent = tps->dev;
+ config.regmap = tps->regmap;
+ config.ngpio = TPS6594_PINCTRL_PINS_NB;
+ config.ngpio_per_reg = 8;
+ config.reg_dat_base = TPS6594_REG_GPIO_IN_1;
+ config.reg_set_base = TPS6594_REG_GPIO_OUT_1;
+ config.reg_dir_out_base = TPS6594_REG_GPIOX_CONF(0);
+ config.reg_mask_xlate = tps6594_gpio_regmap_xlate;
+
+ pinctrl->gpio_regmap = devm_gpio_regmap_register(dev, &config);
+ if (IS_ERR(pinctrl->gpio_regmap))
+ return dev_err_probe(dev, PTR_ERR(pinctrl->gpio_regmap),
+ "Couldn't register gpio_regmap driver\n");
+
+ return 0;
+}
+
+static const struct platform_device_id tps6594_pinctrl_id_table[] = {
+ { "tps6594-pinctrl", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, tps6594_pinctrl_id_table);
+
+static struct platform_driver tps6594_pinctrl_driver = {
+ .probe = tps6594_pinctrl_probe,
+ .driver = {
+ .name = "tps6594-pinctrl",
+ },
+ .id_table = tps6594_pinctrl_id_table,
+};
+module_platform_driver(tps6594_pinctrl_driver);
+
+MODULE_AUTHOR("Esteban Blanc <[email protected]>");
+MODULE_DESCRIPTION("TPS6594 pinctrl and GPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/pinctrl-utils.c b/drivers/pinctrl/pinctrl-utils.c
index 40862f7bd6ca..d81d7b46116c 100644
--- a/drivers/pinctrl/pinctrl-utils.c
+++ b/drivers/pinctrl/pinctrl-utils.c
@@ -18,11 +18,11 @@
#include "pinctrl-utils.h"
int pinctrl_utils_reserve_map(struct pinctrl_dev *pctldev,
- struct pinctrl_map **map, unsigned *reserved_maps,
- unsigned *num_maps, unsigned reserve)
+ struct pinctrl_map **map, unsigned int *reserved_maps,
+ unsigned int *num_maps, unsigned int reserve)
{
- unsigned old_num = *reserved_maps;
- unsigned new_num = *num_maps + reserve;
+ unsigned int old_num = *reserved_maps;
+ unsigned int new_num = *num_maps + reserve;
struct pinctrl_map *new_map;
if (old_num >= new_num)
@@ -43,8 +43,8 @@ int pinctrl_utils_reserve_map(struct pinctrl_dev *pctldev,
EXPORT_SYMBOL_GPL(pinctrl_utils_reserve_map);
int pinctrl_utils_add_map_mux(struct pinctrl_dev *pctldev,
- struct pinctrl_map **map, unsigned *reserved_maps,
- unsigned *num_maps, const char *group,
+ struct pinctrl_map **map, unsigned int *reserved_maps,
+ unsigned int *num_maps, const char *group,
const char *function)
{
if (WARN_ON(*num_maps == *reserved_maps))
@@ -60,9 +60,9 @@ int pinctrl_utils_add_map_mux(struct pinctrl_dev *pctldev,
EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_mux);
int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev,
- struct pinctrl_map **map, unsigned *reserved_maps,
- unsigned *num_maps, const char *group,
- unsigned long *configs, unsigned num_configs,
+ struct pinctrl_map **map, unsigned int *reserved_maps,
+ unsigned int *num_maps, const char *group,
+ unsigned long *configs, unsigned int num_configs,
enum pinctrl_map_type type)
{
unsigned long *dup_configs;
@@ -86,11 +86,11 @@ int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev,
EXPORT_SYMBOL_GPL(pinctrl_utils_add_map_configs);
int pinctrl_utils_add_config(struct pinctrl_dev *pctldev,
- unsigned long **configs, unsigned *num_configs,
+ unsigned long **configs, unsigned int *num_configs,
unsigned long config)
{
- unsigned old_num = *num_configs;
- unsigned new_num = old_num + 1;
+ unsigned int old_num = *num_configs;
+ unsigned int new_num = old_num + 1;
unsigned long *new_configs;
new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
@@ -110,7 +110,7 @@ int pinctrl_utils_add_config(struct pinctrl_dev *pctldev,
EXPORT_SYMBOL_GPL(pinctrl_utils_add_config);
void pinctrl_utils_free_map(struct pinctrl_dev *pctldev,
- struct pinctrl_map *map, unsigned num_maps)
+ struct pinctrl_map *map, unsigned int num_maps)
{
int i;
diff --git a/drivers/pinctrl/pinctrl-utils.h b/drivers/pinctrl/pinctrl-utils.h
index 4108ee2dd6d0..203fba257d71 100644
--- a/drivers/pinctrl/pinctrl-utils.h
+++ b/drivers/pinctrl/pinctrl-utils.h
@@ -15,21 +15,21 @@ struct pinctrl_dev;
struct pinctrl_map;
int pinctrl_utils_reserve_map(struct pinctrl_dev *pctldev,
- struct pinctrl_map **map, unsigned *reserved_maps,
- unsigned *num_maps, unsigned reserve);
+ struct pinctrl_map **map, unsigned int *reserved_maps,
+ unsigned int *num_maps, unsigned int reserve);
int pinctrl_utils_add_map_mux(struct pinctrl_dev *pctldev,
- struct pinctrl_map **map, unsigned *reserved_maps,
- unsigned *num_maps, const char *group,
+ struct pinctrl_map **map, unsigned int *reserved_maps,
+ unsigned int *num_maps, const char *group,
const char *function);
int pinctrl_utils_add_map_configs(struct pinctrl_dev *pctldev,
- struct pinctrl_map **map, unsigned *reserved_maps,
- unsigned *num_maps, const char *group,
- unsigned long *configs, unsigned num_configs,
+ struct pinctrl_map **map, unsigned int *reserved_maps,
+ unsigned int *num_maps, const char *group,
+ unsigned long *configs, unsigned int num_configs,
enum pinctrl_map_type type);
int pinctrl_utils_add_config(struct pinctrl_dev *pctldev,
- unsigned long **configs, unsigned *num_configs,
+ unsigned long **configs, unsigned int *num_configs,
unsigned long config);
void pinctrl_utils_free_map(struct pinctrl_dev *pctldev,
- struct pinctrl_map *map, unsigned num_maps);
+ struct pinctrl_map *map, unsigned int num_maps);
#endif /* __PINCTRL_UTILS_H__ */
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index 23d2da0b99b9..abbb044d6ace 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -35,8 +35,8 @@
int pinmux_check_ops(struct pinctrl_dev *pctldev)
{
const struct pinmux_ops *ops = pctldev->desc->pmxops;
- unsigned nfuncs;
- unsigned selector = 0;
+ unsigned int nfuncs;
+ unsigned int selector = 0;
/* Check that we implement required operations */
if (!ops ||
@@ -84,7 +84,7 @@ int pinmux_validate_map(const struct pinctrl_map *map, int i)
* Controllers not defined as strict will always return true,
* menaning that the gpio can be used.
*/
-bool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev, unsigned pin)
+bool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev, unsigned int pin)
{
struct pin_desc *desc = pin_desc_get(pctldev, pin);
const struct pinmux_ops *ops = pctldev->desc->pmxops;
@@ -262,7 +262,7 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
*/
int pinmux_request_gpio(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned pin, unsigned gpio)
+ unsigned int pin, unsigned int gpio)
{
const char *owner;
int ret;
@@ -285,7 +285,7 @@ int pinmux_request_gpio(struct pinctrl_dev *pctldev,
* @pin: the affected currently GPIO-muxed in pin
* @range: applicable GPIO range
*/
-void pinmux_free_gpio(struct pinctrl_dev *pctldev, unsigned pin,
+void pinmux_free_gpio(struct pinctrl_dev *pctldev, unsigned int pin,
struct pinctrl_gpio_range *range)
{
const char *owner;
@@ -303,7 +303,7 @@ void pinmux_free_gpio(struct pinctrl_dev *pctldev, unsigned pin,
*/
int pinmux_gpio_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned pin, bool input)
+ unsigned int pin, bool input)
{
const struct pinmux_ops *ops;
int ret;
@@ -322,8 +322,8 @@ static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev,
const char *function)
{
const struct pinmux_ops *ops = pctldev->desc->pmxops;
- unsigned nfuncs = ops->get_functions_count(pctldev);
- unsigned selector = 0;
+ unsigned int nfuncs = ops->get_functions_count(pctldev);
+ unsigned int selector = 0;
/* See if this pctldev has this function */
while (selector < nfuncs) {
@@ -344,7 +344,7 @@ int pinmux_map_to_setting(const struct pinctrl_map *map,
struct pinctrl_dev *pctldev = setting->pctldev;
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
char const * const *groups;
- unsigned num_groups;
+ unsigned int num_groups;
int ret;
const char *group;
@@ -409,8 +409,8 @@ int pinmux_enable_setting(const struct pinctrl_setting *setting)
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
const struct pinmux_ops *ops = pctldev->desc->pmxops;
int ret = 0;
- const unsigned *pins = NULL;
- unsigned num_pins = 0;
+ const unsigned int *pins = NULL;
+ unsigned int num_pins = 0;
int i;
struct pin_desc *desc;
@@ -489,8 +489,8 @@ void pinmux_disable_setting(const struct pinctrl_setting *setting)
struct pinctrl_dev *pctldev = setting->pctldev;
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
int ret = 0;
- const unsigned *pins = NULL;
- unsigned num_pins = 0;
+ const unsigned int *pins = NULL;
+ unsigned int num_pins = 0;
int i;
struct pin_desc *desc;
@@ -541,8 +541,8 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
{
struct pinctrl_dev *pctldev = s->private;
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
- unsigned nfuncs;
- unsigned func_selector = 0;
+ unsigned int nfuncs;
+ unsigned int func_selector = 0;
if (!pmxops)
return 0;
@@ -553,7 +553,7 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
const char *func = pmxops->get_function_name(pctldev,
func_selector);
const char * const *groups;
- unsigned num_groups;
+ unsigned int num_groups;
int ret;
int i;
@@ -584,7 +584,7 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
struct pinctrl_dev *pctldev = s->private;
const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
- unsigned i, pin;
+ unsigned int i, pin;
if (!pmxops)
return 0;
@@ -818,7 +818,7 @@ EXPORT_SYMBOL_GPL(pinmux_generic_get_function_name);
int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev,
unsigned int selector,
const char * const **groups,
- unsigned * const num_groups)
+ unsigned int * const num_groups)
{
struct function_desc *function;
diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h
index ea6f99c24aa5..7c8aa25ccc80 100644
--- a/drivers/pinctrl/pinmux.h
+++ b/drivers/pinctrl/pinmux.h
@@ -26,16 +26,16 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev);
int pinmux_validate_map(const struct pinctrl_map *map, int i);
-bool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev, unsigned pin);
+bool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev, unsigned int pin);
int pinmux_request_gpio(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned pin, unsigned gpio);
-void pinmux_free_gpio(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned int pin, unsigned int gpio);
+void pinmux_free_gpio(struct pinctrl_dev *pctldev, unsigned int pin,
struct pinctrl_gpio_range *range);
int pinmux_gpio_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned pin, bool input);
+ unsigned int pin, bool input);
int pinmux_map_to_setting(const struct pinctrl_map *map,
struct pinctrl_setting *setting);
@@ -56,27 +56,27 @@ static inline int pinmux_validate_map(const struct pinctrl_map *map, int i)
}
static inline bool pinmux_can_be_used_for_gpio(struct pinctrl_dev *pctldev,
- unsigned pin)
+ unsigned int pin)
{
return true;
}
static inline int pinmux_request_gpio(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned pin, unsigned gpio)
+ unsigned int pin, unsigned int gpio)
{
return 0;
}
static inline void pinmux_free_gpio(struct pinctrl_dev *pctldev,
- unsigned pin,
+ unsigned int pin,
struct pinctrl_gpio_range *range)
{
}
static inline int pinmux_gpio_direction(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned pin, bool input)
+ unsigned int pin, bool input)
{
return 0;
}
@@ -154,7 +154,7 @@ pinmux_generic_get_function_name(struct pinctrl_dev *pctldev,
int pinmux_generic_get_function_groups(struct pinctrl_dev *pctldev,
unsigned int selector,
const char * const **groups,
- unsigned * const num_groups);
+ unsigned int * const num_groups);
struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev,
unsigned int selector);
@@ -162,7 +162,7 @@ struct function_desc *pinmux_generic_get_function(struct pinctrl_dev *pctldev,
int pinmux_generic_add_function(struct pinctrl_dev *pctldev,
const char *name,
const char * const *groups,
- unsigned const num_groups,
+ unsigned int const num_groups,
void *data);
int pinmux_generic_remove_function(struct pinctrl_dev *pctldev,
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index f84c0d3b7951..e0f2829c15d6 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -124,4 +124,14 @@ config PINCTRL_SM8550_LPASS_LPI
(Low Power Island) found on the Qualcomm Technologies Inc SM8550
platform.
+config PINCTRL_SM8650_LPASS_LPI
+ tristate "Qualcomm Technologies Inc SM8550 LPASS LPI pin controller driver"
+ depends on ARM64 || COMPILE_TEST
+ depends on PINCTRL_LPASS_LPI
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc LPASS (Low Power Audio SubSystem) LPI
+ (Low Power Island) found on the Qualcomm Technologies Inc SM8650
+ platform.
+
endif
diff --git a/drivers/pinctrl/qcom/Kconfig.msm b/drivers/pinctrl/qcom/Kconfig.msm
index 01dd7b134354..8fe459d082ed 100644
--- a/drivers/pinctrl/qcom/Kconfig.msm
+++ b/drivers/pinctrl/qcom/Kconfig.msm
@@ -286,6 +286,14 @@ config PINCTRL_SDX75
Qualcomm Technologies Inc TLMM block found on the Qualcomm
Technologies Inc SDX75 platform.
+config PINCTRL_SM4450
+ tristate "Qualcomm Technologies Inc SM4450 pin controller driver"
+ depends on ARM64 || COMPILE_TEST
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Qualcomm
+ Technologies Inc SM4450 platform.
+
config PINCTRL_SM6115
tristate "Qualcomm Technologies Inc SM6115,SM4250 pin controller driver"
depends on ARM64 || COMPILE_TEST
@@ -366,4 +374,22 @@ config PINCTRL_SM8550
Qualcomm Technologies Inc TLMM block found on the Qualcomm
Technologies Inc SM8550 platform.
+config PINCTRL_SM8650
+ tristate "Qualcomm Technologies Inc SM8650 pin controller driver"
+ depends on ARM64 || COMPILE_TEST
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Qualcomm
+ Technologies Inc SM8650 platform.
+
+config PINCTRL_X1E80100
+ tristate "Qualcomm Technologies Inc X1E80100 pin controller driver"
+ depends on ARM64 || COMPILE_TEST
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc Top Level Mode Multiplexer block (TLMM)
+ block found on the Qualcomm Technologies Inc X1E80100 platform.
+ Say Y here to compile statically, or M here to compile it as a module.
+ If unsure, say N.
+
endif
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 5910e08c84ce..e2e76071d268 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o
obj-$(CONFIG_PINCTRL_SDX55) += pinctrl-sdx55.o
obj-$(CONFIG_PINCTRL_SDX65) += pinctrl-sdx65.o
obj-$(CONFIG_PINCTRL_SDX75) += pinctrl-sdx75.o
+obj-$(CONFIG_PINCTRL_SM4450) += pinctrl-sm4450.o
obj-$(CONFIG_PINCTRL_SM6115) += pinctrl-sm6115.o
obj-$(CONFIG_PINCTRL_SM6115_LPASS_LPI) += pinctrl-sm6115-lpass-lpi.o
obj-$(CONFIG_PINCTRL_SM6125) += pinctrl-sm6125.o
@@ -58,5 +59,8 @@ obj-$(CONFIG_PINCTRL_SM8450) += pinctrl-sm8450.o
obj-$(CONFIG_PINCTRL_SM8450_LPASS_LPI) += pinctrl-sm8450-lpass-lpi.o
obj-$(CONFIG_PINCTRL_SM8550) += pinctrl-sm8550.o
obj-$(CONFIG_PINCTRL_SM8550_LPASS_LPI) += pinctrl-sm8550-lpass-lpi.o
+obj-$(CONFIG_PINCTRL_SM8650) += pinctrl-sm8650.o
+obj-$(CONFIG_PINCTRL_SM8650_LPASS_LPI) += pinctrl-sm8650-lpass-lpi.o
obj-$(CONFIG_PINCTRL_SC8280XP_LPASS_LPI) += pinctrl-sc8280xp-lpass-lpi.o
obj-$(CONFIG_PINCTRL_LPASS_LPI) += pinctrl-lpass-lpi.o
+obj-$(CONFIG_PINCTRL_X1E80100) += pinctrl-x1e80100.o
diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
index 9651aed048cf..0d98008e33ee 100644
--- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c
@@ -186,6 +186,41 @@ static int lpi_config_get(struct pinctrl_dev *pctldev,
return 0;
}
+static int lpi_config_set_slew_rate(struct lpi_pinctrl *pctrl,
+ const struct lpi_pingroup *g,
+ unsigned int group, unsigned int slew)
+{
+ unsigned long sval;
+ void __iomem *reg;
+ int slew_offset;
+
+ if (slew > LPI_SLEW_RATE_MAX) {
+ dev_err(pctrl->dev, "invalid slew rate %u for pin: %d\n",
+ slew, group);
+ return -EINVAL;
+ }
+
+ slew_offset = g->slew_offset;
+ if (slew_offset == LPI_NO_SLEW)
+ return 0;
+
+ if (pctrl->data->flags & LPI_FLAG_SLEW_RATE_SAME_REG)
+ reg = pctrl->tlmm_base + LPI_TLMM_REG_OFFSET * group + LPI_GPIO_CFG_REG;
+ else
+ reg = pctrl->slew_base + LPI_SLEW_RATE_CTL_REG;
+
+ mutex_lock(&pctrl->lock);
+
+ sval = ioread32(reg);
+ sval &= ~(LPI_SLEW_RATE_MASK << slew_offset);
+ sval |= slew << slew_offset;
+ iowrite32(sval, reg);
+
+ mutex_unlock(&pctrl->lock);
+
+ return 0;
+}
+
static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
unsigned long *configs, unsigned int nconfs)
{
@@ -193,8 +228,7 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
unsigned int param, arg, pullup = LPI_GPIO_BIAS_DISABLE, strength = 2;
bool value, output_enabled = false;
const struct lpi_pingroup *g;
- unsigned long sval;
- int i, slew_offset;
+ int i, ret;
u32 val;
g = &pctrl->data->groups[group];
@@ -226,24 +260,9 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
strength = arg;
break;
case PIN_CONFIG_SLEW_RATE:
- if (arg > LPI_SLEW_RATE_MAX) {
- dev_err(pctldev->dev, "invalid slew rate %u for pin: %d\n",
- arg, group);
- return -EINVAL;
- }
-
- slew_offset = g->slew_offset;
- if (slew_offset == LPI_NO_SLEW)
- break;
-
- mutex_lock(&pctrl->lock);
-
- sval = ioread32(pctrl->slew_base + LPI_SLEW_RATE_CTL_REG);
- sval &= ~(LPI_SLEW_RATE_MASK << slew_offset);
- sval |= arg << slew_offset;
- iowrite32(sval, pctrl->slew_base + LPI_SLEW_RATE_CTL_REG);
-
- mutex_unlock(&pctrl->lock);
+ ret = lpi_config_set_slew_rate(pctrl, g, group, arg);
+ if (ret)
+ return ret;
break;
default:
return -EINVAL;
@@ -319,7 +338,6 @@ static void lpi_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
}
#ifdef CONFIG_DEBUG_FS
-#include <linux/seq_file.h>
static unsigned int lpi_regval_to_drive(u32 val)
{
@@ -439,10 +457,12 @@ int lpi_pinctrl_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(pctrl->tlmm_base),
"TLMM resource not provided\n");
- pctrl->slew_base = devm_platform_ioremap_resource(pdev, 1);
- if (IS_ERR(pctrl->slew_base))
- return dev_err_probe(dev, PTR_ERR(pctrl->slew_base),
- "Slew resource not provided\n");
+ if (!(data->flags & LPI_FLAG_SLEW_RATE_SAME_REG)) {
+ pctrl->slew_base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(pctrl->slew_base))
+ return dev_err_probe(dev, PTR_ERR(pctrl->slew_base),
+ "Slew resource not provided\n");
+ }
ret = devm_clk_bulk_get_optional(dev, MAX_LPI_NUM_CLKS, pctrl->clks);
if (ret)
diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.h b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.h
index 387d83ee95b5..a9b2f65c1ebe 100644
--- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.h
+++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.h
@@ -6,8 +6,8 @@
#ifndef __PINCTRL_LPASS_LPI_H__
#define __PINCTRL_LPASS_LPI_H__
+#include <linux/array_size.h>
#include <linux/bits.h>
-#include <linux/kernel.h>
#include "../core.h"
@@ -45,11 +45,8 @@ struct pinctrl_pin_desc;
#define LPI_PINGROUP(id, soff, f1, f2, f3, f4) \
{ \
- .group.name = "gpio" #id, \
- .group.pins = gpio##id##_pins, \
.pin = id, \
.slew_offset = soff, \
- .group.num_pins = ARRAY_SIZE(gpio##id##_pins), \
.funcs = (int[]){ \
LPI_MUX_gpio, \
LPI_MUX_##f1, \
@@ -60,8 +57,13 @@ struct pinctrl_pin_desc;
.nfuncs = 5, \
}
+/*
+ * Slew rate control is done in the same register as rest of the
+ * pin configuration.
+ */
+#define LPI_FLAG_SLEW_RATE_SAME_REG BIT(0)
+
struct lpi_pingroup {
- struct group_desc group;
unsigned int pin;
/* Bit offset in slew register for SoundWire pins only */
int slew_offset;
@@ -82,6 +84,7 @@ struct lpi_pinctrl_variant_data {
int ngroups;
const struct lpi_function *functions;
int nfunctions;
+ unsigned int flags;
};
int lpi_pinctrl_probe(struct platform_device *pdev);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index 395040346d0f..aeaf0d1958f5 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -358,6 +358,10 @@ static int msm_config_group_get(struct pinctrl_dev *pctldev,
int ret;
u32 val;
+ /* Pin information can only be requested from valid pin groups */
+ if (!gpiochip_line_is_valid(&pctrl->chip, group))
+ return -EINVAL;
+
g = &pctrl->soc->groups[group];
ret = msm_config_reg(pctrl, g, param, &mask, &bit);
@@ -1196,6 +1200,8 @@ static int msm_gpio_irq_reqres(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
+ const struct msm_pingroup *g = &pctrl->soc->groups[d->hwirq];
+ unsigned long flags;
int ret;
if (!try_module_get(gc->owner))
@@ -1221,6 +1227,28 @@ static int msm_gpio_irq_reqres(struct irq_data *d)
*/
irq_set_status_flags(d->irq, IRQ_DISABLE_UNLAZY);
+ /*
+ * If the wakeup_enable bit is present and marked as available for the
+ * requested GPIO, it should be enabled when the GPIO is marked as
+ * wake irq in order to allow the interrupt event to be transfered to
+ * the PDC HW.
+ * While the name implies only the wakeup event, it's also required for
+ * the interrupt event.
+ */
+ if (test_bit(d->hwirq, pctrl->skip_wake_irqs) && g->intr_wakeup_present_bit) {
+ u32 intr_cfg;
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+
+ intr_cfg = msm_readl_intr_cfg(pctrl, g);
+ if (intr_cfg & BIT(g->intr_wakeup_present_bit)) {
+ intr_cfg |= BIT(g->intr_wakeup_enable_bit);
+ msm_writel_intr_cfg(intr_cfg, pctrl, g);
+ }
+
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ }
+
return 0;
out:
module_put(gc->owner);
@@ -1230,6 +1258,24 @@ out:
static void msm_gpio_irq_relres(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
+ const struct msm_pingroup *g = &pctrl->soc->groups[d->hwirq];
+ unsigned long flags;
+
+ /* Disable the wakeup_enable bit if it has been set in msm_gpio_irq_reqres() */
+ if (test_bit(d->hwirq, pctrl->skip_wake_irqs) && g->intr_wakeup_present_bit) {
+ u32 intr_cfg;
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+
+ intr_cfg = msm_readl_intr_cfg(pctrl, g);
+ if (intr_cfg & BIT(g->intr_wakeup_present_bit)) {
+ intr_cfg &= ~BIT(g->intr_wakeup_enable_bit);
+ msm_writel_intr_cfg(intr_cfg, pctrl, g);
+ }
+
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ }
gpiochip_unlock_as_irq(gc, d->hwirq);
module_put(gc->owner);
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index 4968d08a384d..63852ed70295 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -58,6 +58,9 @@ struct pinctrl_pin_desc;
* @intr_enable_bit: Offset in @intr_cfg_reg for enabling the interrupt for this group.
* @intr_status_bit: Offset in @intr_status_reg for reading and acking the interrupt
* status.
+ * @intr_wakeup_present_bit: Offset in @intr_target_reg specifying the GPIO can generate
+ * wakeup events.
+ * @intr_wakeup_enable_bit: Offset in @intr_target_reg to enable wakeup events for the GPIO.
* @intr_target_bit: Offset in @intr_target_reg for configuring the interrupt routing.
* @intr_target_width: Number of bits used for specifying interrupt routing target.
* @intr_target_kpss_val: Value in @intr_target_bit for specifying that the interrupt from
@@ -100,6 +103,8 @@ struct msm_pingroup {
unsigned intr_status_bit:5;
unsigned intr_ack_high:1;
+ unsigned intr_wakeup_present_bit:5;
+ unsigned intr_wakeup_enable_bit:5;
unsigned intr_target_bit:5;
unsigned intr_target_width:5;
unsigned intr_target_kpss_val:5;
diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c
index 99156217c6a5..6bb39812e1d8 100644
--- a/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-sc7280-lpass-lpi.c
@@ -36,22 +36,6 @@ enum lpass_lpi_functions {
LPI_MUX__,
};
-static int gpio0_pins[] = { 0 };
-static int gpio1_pins[] = { 1 };
-static int gpio2_pins[] = { 2 };
-static int gpio3_pins[] = { 3 };
-static int gpio4_pins[] = { 4 };
-static int gpio5_pins[] = { 5 };
-static int gpio6_pins[] = { 6 };
-static int gpio7_pins[] = { 7 };
-static int gpio8_pins[] = { 8 };
-static int gpio9_pins[] = { 9 };
-static int gpio10_pins[] = { 10 };
-static int gpio11_pins[] = { 11 };
-static int gpio12_pins[] = { 12 };
-static int gpio13_pins[] = { 13 };
-static int gpio14_pins[] = { 14 };
-
static const struct pinctrl_pin_desc sc7280_lpi_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
diff --git a/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c
index b33483056f42..c0369baf3398 100644
--- a/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-sc8280xp-lpass-lpi.c
@@ -45,26 +45,6 @@ enum lpass_lpi_functions {
LPI_MUX__,
};
-static int gpio0_pins[] = { 0 };
-static int gpio1_pins[] = { 1 };
-static int gpio2_pins[] = { 2 };
-static int gpio3_pins[] = { 3 };
-static int gpio4_pins[] = { 4 };
-static int gpio5_pins[] = { 5 };
-static int gpio6_pins[] = { 6 };
-static int gpio7_pins[] = { 7 };
-static int gpio8_pins[] = { 8 };
-static int gpio9_pins[] = { 9 };
-static int gpio10_pins[] = { 10 };
-static int gpio11_pins[] = { 11 };
-static int gpio12_pins[] = { 12 };
-static int gpio13_pins[] = { 13 };
-static int gpio14_pins[] = { 14 };
-static int gpio15_pins[] = { 15 };
-static int gpio16_pins[] = { 16 };
-static int gpio17_pins[] = { 17 };
-static int gpio18_pins[] = { 18 };
-
static const struct pinctrl_pin_desc sc8280xp_lpi_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
diff --git a/drivers/pinctrl/qcom/pinctrl-sm4450.c b/drivers/pinctrl/qcom/pinctrl-sm4450.c
new file mode 100644
index 000000000000..27317b86d835
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sm4450.c
@@ -0,0 +1,1014 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-msm.h"
+
+#define REG_SIZE 0x1000
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .grp = PINCTRL_PINGROUP("gpio" #id, \
+ gpio##id##_pins, \
+ ARRAY_SIZE(gpio##id##_pins)), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .intr_target_reg = 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .egpio_enable = 12, \
+ .egpio_present = 11, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .grp = PINCTRL_PINGROUP(#pg_name, \
+ pg_name##_pins, \
+ ARRAY_SIZE(pg_name##_pins)), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define UFS_RESET(pg_name, offset) \
+ { \
+ .grp = PINCTRL_PINGROUP(#pg_name, \
+ pg_name##_pins, \
+ ARRAY_SIZE(pg_name##_pins)), \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define QUP_I3C(qup_mode, qup_offset) \
+ { \
+ .mode = qup_mode, \
+ .offset = qup_offset, \
+ }
+
+
+static const struct pinctrl_pin_desc sm4450_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "UFS_RESET"),
+ PINCTRL_PIN(137, "SDC1_RCLK"),
+ PINCTRL_PIN(138, "SDC1_CLK"),
+ PINCTRL_PIN(139, "SDC1_CMD"),
+ PINCTRL_PIN(140, "SDC1_DATA"),
+ PINCTRL_PIN(141, "SDC2_CLK"),
+ PINCTRL_PIN(142, "SDC2_CMD"),
+ PINCTRL_PIN(143, "SDC2_DATA"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+
+static const unsigned int ufs_reset_pins[] = { 136 };
+static const unsigned int sdc1_rclk_pins[] = { 137 };
+static const unsigned int sdc1_clk_pins[] = { 138 };
+static const unsigned int sdc1_cmd_pins[] = { 139 };
+static const unsigned int sdc1_data_pins[] = { 140 };
+static const unsigned int sdc2_clk_pins[] = { 141 };
+static const unsigned int sdc2_cmd_pins[] = { 142 };
+static const unsigned int sdc2_data_pins[] = { 143 };
+
+enum sm4450_functions {
+ msm_mux_gpio,
+ msm_mux_atest_char,
+ msm_mux_atest_usb0,
+ msm_mux_audio_ref_clk,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async_in0,
+ msm_mux_cci_i2c,
+ msm_mux_cci,
+ msm_mux_cmu_rng,
+ msm_mux_coex_uart1_rx,
+ msm_mux_coex_uart1_tx,
+ msm_mux_cri_trng,
+ msm_mux_dbg_out_clk,
+ msm_mux_ddr_bist,
+ msm_mux_ddr_pxi0_test,
+ msm_mux_ddr_pxi1_test,
+ msm_mux_gcc_gp1_clk,
+ msm_mux_gcc_gp2_clk,
+ msm_mux_gcc_gp3_clk,
+ msm_mux_host2wlan_sol,
+ msm_mux_ibi_i3c_qup0,
+ msm_mux_ibi_i3c_qup1,
+ msm_mux_jitter_bist_ref,
+ msm_mux_mdp_vsync0_out,
+ msm_mux_mdp_vsync1_out,
+ msm_mux_mdp_vsync2_out,
+ msm_mux_mdp_vsync3_out,
+ msm_mux_mdp_vsync,
+ msm_mux_nav,
+ msm_mux_pcie0_clk_req,
+ msm_mux_phase_flag,
+ msm_mux_pll_bist_sync,
+ msm_mux_pll_clk_aux,
+ msm_mux_prng_rosc,
+ msm_mux_qdss_cti_trig0,
+ msm_mux_qdss_cti_trig1,
+ msm_mux_qdss_gpio,
+ msm_mux_qlink0_enable,
+ msm_mux_qlink0_request,
+ msm_mux_qlink0_wmss_reset,
+ msm_mux_qup0_se0,
+ msm_mux_qup0_se1,
+ msm_mux_qup0_se2,
+ msm_mux_qup0_se3,
+ msm_mux_qup0_se4,
+ msm_mux_qup1_se0,
+ msm_mux_qup1_se1,
+ msm_mux_qup1_se2,
+ msm_mux_qup1_se3,
+ msm_mux_qup1_se4,
+ msm_mux_sd_write_protect,
+ msm_mux_tb_trig_sdc1,
+ msm_mux_tb_trig_sdc2,
+ msm_mux_tgu_ch0_trigout,
+ msm_mux_tgu_ch1_trigout,
+ msm_mux_tgu_ch2_trigout,
+ msm_mux_tgu_ch3_trigout,
+ msm_mux_tmess_prng,
+ msm_mux_tsense_pwm1_out,
+ msm_mux_tsense_pwm2_out,
+ msm_mux_uim0,
+ msm_mux_uim1,
+ msm_mux_usb0_hs_ac,
+ msm_mux_usb0_phy_ps,
+ msm_mux_vfr_0_mira,
+ msm_mux_vfr_0_mirb,
+ msm_mux_vfr_1,
+ msm_mux_vsense_trigger_mirnat,
+ msm_mux_wlan1_adc_dtest0,
+ msm_mux_wlan1_adc_dtest1,
+ msm_mux__,
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+ "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+ "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+ "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+ "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+ "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+ "gpio135",
+};
+static const char * const atest_char_groups[] = {
+ "gpio95", "gpio97", "gpio98", "gpio99", "gpio100",
+};
+static const char * const atest_usb0_groups[] = {
+ "gpio75", "gpio10", "gpio78", "gpio79", "gpio80",
+};
+static const char * const audio_ref_clk_groups[] = {
+ "gpio71",
+};
+static const char * const cam_mclk_groups[] = {
+ "gpio36", "gpio37", "gpio38", "gpio39",
+};
+static const char * const cci_async_in0_groups[] = {
+ "gpio40",
+};
+static const char * const cci_i2c_groups[] = {
+ "gpio45", "gpio47", "gpio49", "gpio44",
+ "gpio46", "gpio48",
+};
+static const char * const cci_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio43",
+};
+static const char * const cmu_rng_groups[] = {
+ "gpio28", "gpio3", "gpio1", "gpio0",
+};
+static const char * const coex_uart1_rx_groups[] = {
+ "gpio54",
+};
+static const char * const coex_uart1_tx_groups[] = {
+ "gpio55",
+};
+static const char * const cri_trng_groups[] = {
+ "gpio42", "gpio40", "gpio41",
+};
+static const char * const dbg_out_clk_groups[] = {
+ "gpio80",
+};
+static const char * const ddr_bist_groups[] = {
+ "gpio32", "gpio29", "gpio30", "gpio31",
+};
+static const char * const ddr_pxi0_test_groups[] = {
+ "gpio90", "gpio127",
+};
+static const char * const ddr_pxi1_test_groups[] = {
+ "gpio118", "gpio122",
+};
+static const char * const gcc_gp1_clk_groups[] = {
+ "gpio37", "gpio48",
+};
+static const char * const gcc_gp2_clk_groups[] = {
+ "gpio30", "gpio49",
+};
+static const char * const gcc_gp3_clk_groups[] = {
+ "gpio3", "gpio50",
+};
+static const char * const host2wlan_sol_groups[] = {
+ "gpio106",
+};
+static const char * const ibi_i3c_qup0_groups[] = {
+ "gpio4", "gpio5",
+};
+static const char * const ibi_i3c_qup1_groups[] = {
+ "gpio0", "gpio1",
+};
+static const char * const jitter_bist_ref_groups[] = {
+ "gpio90",
+};
+static const char * const mdp_vsync0_out_groups[] = {
+ "gpio93",
+};
+static const char * const mdp_vsync1_out_groups[] = {
+ "gpio93",
+};
+static const char * const mdp_vsync2_out_groups[] = {
+ "gpio22",
+};
+static const char * const mdp_vsync3_out_groups[] = {
+ "gpio22",
+};
+static const char * const mdp_vsync_groups[] = {
+ "gpio26", "gpio22", "gpio30", "gpio34", "gpio93", "gpio97",
+};
+static const char * const nav_groups[] = {
+ "gpio81", "gpio83", "gpio84",
+};
+static const char * const pcie0_clk_req_groups[] = {
+ "gpio107",
+};
+static const char * const phase_flag_groups[] = {
+ "gpio7", "gpio8", "gpio9", "gpio11", "gpio13", "gpio14", "gpio15",
+ "gpio17", "gpio18", "gpio19", "gpio21", "gpio24", "gpio25", "gpio31",
+ "gpio32", "gpio33", "gpio35", "gpio61", "gpio72", "gpio82", "gpio91",
+ "gpio95", "gpio97", "gpio98", "gpio99", "gpio100", "gpio105", "gpio115",
+ "gpio116", "gpio117", "gpio133", "gpio135",
+};
+static const char * const pll_bist_sync_groups[] = {
+ "gpio73",
+};
+static const char * const pll_clk_aux_groups[] = {
+ "gpio108",
+};
+static const char * const prng_rosc_groups[] = {
+ "gpio36", "gpio37", "gpio38", "gpio39",
+};
+static const char * const qdss_cti_trig0_groups[] = {
+ "gpio26", "gpio60", "gpio113", "gpio114",
+};
+static const char * const qdss_cti_trig1_groups[] = {
+ "gpio6", "gpio27", "gpio57", "gpio58",
+};
+static const char * const qdss_gpio_groups[] = {
+ "gpio0", "gpio1", "gpio3", "gpio4", "gpio5", "gpio7", "gpio8",
+ "gpio9", "gpio14", "gpio15", "gpio17", "gpio23", "gpio31", "gpio32",
+ "gpio33", "gpio35", "gpio36", "gpio37", "gpio38", "gpio39", "gpio40",
+ "gpio41", "gpio42", "gpio43", "gpio44", "gpio45", "gpio46", "gpio47",
+ "gpio49", "gpio59", "gpio62", "gpio118", "gpio121", "gpio122", "gpio126",
+ "gpio127",
+};
+static const char * const qlink0_enable_groups[] = {
+ "gpio88",
+};
+static const char * const qlink0_request_groups[] = {
+ "gpio87",
+};
+static const char * const qlink0_wmss_reset_groups[] = {
+ "gpio89",
+};
+static const char * const qup0_se0_groups[] = {
+ "gpio4", "gpio5", "gpio34", "gpio35",
+};
+static const char * const qup0_se1_groups[] = {
+ "gpio10", "gpio11", "gpio12", "gpio13",
+};
+static const char * const qup0_se2_groups[] = {
+ "gpio14", "gpio15", "gpio16", "gpio17",
+};
+static const char * const qup0_se3_groups[] = {
+ "gpio18", "gpio19", "gpio20", "gpio21",
+};
+static const char * const qup0_se4_groups[] = {
+ "gpio6", "gpio7", "gpio8", "gpio9",
+ "gpio26", "gpio27", "gpio34",
+};
+static const char * const qup1_se0_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const qup1_se1_groups[] = {
+ "gpio26", "gpio27", "gpio50", "gpio51",
+};
+static const char * const qup1_se2_groups[] = {
+ "gpio22", "gpio23", "gpio31", "gpio32",
+};
+static const char * const qup1_se3_groups[] = {
+ "gpio24", "gpio25", "gpio51", "gpio50",
+};
+static const char * const qup1_se4_groups[] = {
+ "gpio43", "gpio48", "gpio49", "gpio90",
+ "gpio91",
+};
+static const char * const sd_write_protect_groups[] = {
+ "gpio102",
+};
+static const char * const tb_trig_sdc1_groups[] = {
+ "gpio128",
+};
+static const char * const tb_trig_sdc2_groups[] = {
+ "gpio51",
+};
+static const char * const tgu_ch0_trigout_groups[] = {
+ "gpio20",
+};
+static const char * const tgu_ch1_trigout_groups[] = {
+ "gpio21",
+};
+static const char * const tgu_ch2_trigout_groups[] = {
+ "gpio22",
+};
+static const char * const tgu_ch3_trigout_groups[] = {
+ "gpio23",
+};
+static const char * const tmess_prng_groups[] = {
+ "gpio57", "gpio58", "gpio59", "gpio60",
+};
+static const char * const tsense_pwm1_out_groups[] = {
+ "gpio134",
+};
+static const char * const tsense_pwm2_out_groups[] = {
+ "gpio134",
+};
+static const char * const uim0_groups[] = {
+ "gpio64", "gpio63", "gpio66", "gpio65",
+};
+static const char * const uim1_groups[] = {
+ "gpio68", "gpio67", "gpio69", "gpio70",
+};
+static const char * const usb0_hs_ac_groups[] = {
+ "gpio99",
+};
+static const char * const usb0_phy_ps_groups[] = {
+ "gpio94",
+};
+static const char * const vfr_0_mira_groups[] = {
+ "gpio19",
+};
+static const char * const vfr_0_mirb_groups[] = {
+ "gpio100",
+};
+static const char * const vfr_1_groups[] = {
+ "gpio84",
+};
+static const char * const vsense_trigger_mirnat_groups[] = {
+ "gpio75",
+};
+static const char * const wlan1_adc_dtest0_groups[] = {
+ "gpio79",
+};
+static const char * const wlan1_adc_dtest1_groups[] = {
+ "gpio80",
+};
+
+static const struct pinfunction sm4450_functions[] = {
+ MSM_PIN_FUNCTION(gpio),
+ MSM_PIN_FUNCTION(atest_char),
+ MSM_PIN_FUNCTION(atest_usb0),
+ MSM_PIN_FUNCTION(audio_ref_clk),
+ MSM_PIN_FUNCTION(cam_mclk),
+ MSM_PIN_FUNCTION(cci_async_in0),
+ MSM_PIN_FUNCTION(cci_i2c),
+ MSM_PIN_FUNCTION(cci),
+ MSM_PIN_FUNCTION(cmu_rng),
+ MSM_PIN_FUNCTION(coex_uart1_rx),
+ MSM_PIN_FUNCTION(coex_uart1_tx),
+ MSM_PIN_FUNCTION(cri_trng),
+ MSM_PIN_FUNCTION(dbg_out_clk),
+ MSM_PIN_FUNCTION(ddr_bist),
+ MSM_PIN_FUNCTION(ddr_pxi0_test),
+ MSM_PIN_FUNCTION(ddr_pxi1_test),
+ MSM_PIN_FUNCTION(gcc_gp1_clk),
+ MSM_PIN_FUNCTION(gcc_gp2_clk),
+ MSM_PIN_FUNCTION(gcc_gp3_clk),
+ MSM_PIN_FUNCTION(host2wlan_sol),
+ MSM_PIN_FUNCTION(ibi_i3c_qup0),
+ MSM_PIN_FUNCTION(ibi_i3c_qup1),
+ MSM_PIN_FUNCTION(jitter_bist_ref),
+ MSM_PIN_FUNCTION(mdp_vsync0_out),
+ MSM_PIN_FUNCTION(mdp_vsync1_out),
+ MSM_PIN_FUNCTION(mdp_vsync2_out),
+ MSM_PIN_FUNCTION(mdp_vsync3_out),
+ MSM_PIN_FUNCTION(mdp_vsync),
+ MSM_PIN_FUNCTION(nav),
+ MSM_PIN_FUNCTION(pcie0_clk_req),
+ MSM_PIN_FUNCTION(phase_flag),
+ MSM_PIN_FUNCTION(pll_bist_sync),
+ MSM_PIN_FUNCTION(pll_clk_aux),
+ MSM_PIN_FUNCTION(prng_rosc),
+ MSM_PIN_FUNCTION(qdss_cti_trig0),
+ MSM_PIN_FUNCTION(qdss_cti_trig1),
+ MSM_PIN_FUNCTION(qdss_gpio),
+ MSM_PIN_FUNCTION(qlink0_enable),
+ MSM_PIN_FUNCTION(qlink0_request),
+ MSM_PIN_FUNCTION(qlink0_wmss_reset),
+ MSM_PIN_FUNCTION(qup0_se0),
+ MSM_PIN_FUNCTION(qup0_se1),
+ MSM_PIN_FUNCTION(qup0_se2),
+ MSM_PIN_FUNCTION(qup0_se3),
+ MSM_PIN_FUNCTION(qup0_se4),
+ MSM_PIN_FUNCTION(qup1_se0),
+ MSM_PIN_FUNCTION(qup1_se1),
+ MSM_PIN_FUNCTION(qup1_se2),
+ MSM_PIN_FUNCTION(qup1_se3),
+ MSM_PIN_FUNCTION(qup1_se4),
+ MSM_PIN_FUNCTION(sd_write_protect),
+ MSM_PIN_FUNCTION(tb_trig_sdc1),
+ MSM_PIN_FUNCTION(tb_trig_sdc2),
+ MSM_PIN_FUNCTION(tgu_ch0_trigout),
+ MSM_PIN_FUNCTION(tgu_ch1_trigout),
+ MSM_PIN_FUNCTION(tgu_ch2_trigout),
+ MSM_PIN_FUNCTION(tgu_ch3_trigout),
+ MSM_PIN_FUNCTION(tmess_prng),
+ MSM_PIN_FUNCTION(tsense_pwm1_out),
+ MSM_PIN_FUNCTION(tsense_pwm2_out),
+ MSM_PIN_FUNCTION(uim0),
+ MSM_PIN_FUNCTION(uim1),
+ MSM_PIN_FUNCTION(usb0_hs_ac),
+ MSM_PIN_FUNCTION(usb0_phy_ps),
+ MSM_PIN_FUNCTION(vfr_0_mira),
+ MSM_PIN_FUNCTION(vfr_0_mirb),
+ MSM_PIN_FUNCTION(vfr_1),
+ MSM_PIN_FUNCTION(vsense_trigger_mirnat),
+ MSM_PIN_FUNCTION(wlan1_adc_dtest0),
+ MSM_PIN_FUNCTION(wlan1_adc_dtest1),
+};
+
+/*
+ * Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup sm4450_groups[] = {
+ [0] = PINGROUP(0, qup1_se0, ibi_i3c_qup1, cmu_rng, qdss_gpio, _, _, _, _, _),
+ [1] = PINGROUP(1, qup1_se0, ibi_i3c_qup1, cmu_rng, qdss_gpio, _, _, _, _, _),
+ [2] = PINGROUP(2, qup1_se0, _, _, _, _, _, _, _, _),
+ [3] = PINGROUP(3, qup1_se0, gcc_gp3_clk, cmu_rng, qdss_gpio, _, _, _, _, _),
+ [4] = PINGROUP(4, qup0_se0, ibi_i3c_qup0, qdss_gpio, _, _, _, _, _, _),
+ [5] = PINGROUP(5, qup0_se0, ibi_i3c_qup0, qdss_gpio, _, _, _, _, _, _),
+ [6] = PINGROUP(6, qup0_se4, qdss_cti_trig1, _, _, _, _, _, _, _),
+ [7] = PINGROUP(7, qup0_se4, _, phase_flag, qdss_gpio, _, _, _, _, _),
+ [8] = PINGROUP(8, qup0_se4, _, phase_flag, qdss_gpio, _, _, _, _, _),
+ [9] = PINGROUP(9, qup0_se4, _, phase_flag, qdss_gpio, _, _, _, _, _),
+ [10] = PINGROUP(10, qup0_se1, _, atest_usb0, _, _, _, _, _, _),
+ [11] = PINGROUP(11, qup0_se1, _, phase_flag, _, _, _, _, _, _),
+ [12] = PINGROUP(12, qup0_se1, _, _, _, _, _, _, _, _),
+ [13] = PINGROUP(13, qup0_se1, _, phase_flag, _, _, _, _, _, _),
+ [14] = PINGROUP(14, qup0_se2, _, phase_flag, _, qdss_gpio, _, _, _, _),
+ [15] = PINGROUP(15, qup0_se2, _, phase_flag, _, qdss_gpio, _, _, _, _),
+ [16] = PINGROUP(16, qup0_se2, _, _, _, _, _, _, _, _),
+ [17] = PINGROUP(17, qup0_se2, _, phase_flag, _, qdss_gpio, _, _, _, _),
+ [18] = PINGROUP(18, qup0_se3, _, phase_flag, _, _, _, _, _, _),
+ [19] = PINGROUP(19, qup0_se3, vfr_0_mira, _, phase_flag, _, _, _, _, _),
+ [20] = PINGROUP(20, qup0_se3, tgu_ch0_trigout, _, _, _, _, _, _, _),
+ [21] = PINGROUP(21, qup0_se3, _, phase_flag, tgu_ch1_trigout, _, _, _, _, _),
+ [22] = PINGROUP(22, qup1_se2, mdp_vsync, mdp_vsync2_out, mdp_vsync3_out, tgu_ch2_trigout, _, _, _, _),
+ [23] = PINGROUP(23, qup1_se2, tgu_ch3_trigout, qdss_gpio, _, _, _, _, _, _),
+ [24] = PINGROUP(24, qup1_se3, _, phase_flag, _, _, _, _, _, _),
+ [25] = PINGROUP(25, qup1_se3, _, phase_flag, _, _, _, _, _, _),
+ [26] = PINGROUP(26, qup1_se1, mdp_vsync, qup0_se4, qdss_cti_trig0, _, _, _, _, _),
+ [27] = PINGROUP(27, qup1_se1, qup0_se4, qdss_cti_trig1, _, _, _, _, _, _),
+ [28] = PINGROUP(28, cmu_rng, _, _, _, _, _, _, _, _),
+ [29] = PINGROUP(29, ddr_bist, _, _, _, _, _, _, _, _),
+ [30] = PINGROUP(30, mdp_vsync, gcc_gp2_clk, ddr_bist, _, _, _, _, _, _),
+ [31] = PINGROUP(31, qup1_se2, _, phase_flag, ddr_bist, qdss_gpio, _, _, _, _),
+ [32] = PINGROUP(32, qup1_se2, _, phase_flag, ddr_bist, qdss_gpio, _, _, _, _),
+ [33] = PINGROUP(33, _, phase_flag, qdss_gpio, _, _, _, _, _, _),
+ [34] = PINGROUP(34, qup0_se0, qup0_se4, mdp_vsync, _, _, _, _, _, _),
+ [35] = PINGROUP(35, qup0_se0, _, phase_flag, qdss_gpio, _, _, _, _, _),
+ [36] = PINGROUP(36, cam_mclk, prng_rosc, qdss_gpio, _, _, _, _, _, _),
+ [37] = PINGROUP(37, cam_mclk, gcc_gp1_clk, prng_rosc, qdss_gpio, _, _, _, _, _),
+ [38] = PINGROUP(38, cam_mclk, prng_rosc, qdss_gpio, _, _, _, _, _, _),
+ [39] = PINGROUP(39, cam_mclk, prng_rosc, qdss_gpio, _, _, _, _, _, _),
+ [40] = PINGROUP(40, cci, cci_async_in0, cri_trng, qdss_gpio, _, _, _, _, _),
+ [41] = PINGROUP(41, cci, cri_trng, qdss_gpio, _, _, _, _, _, _),
+ [42] = PINGROUP(42, cci, cri_trng, qdss_gpio, _, _, _, _, _, _),
+ [43] = PINGROUP(43, cci, qup1_se4, qdss_gpio, _, _, _, _, _, _),
+ [44] = PINGROUP(44, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [45] = PINGROUP(45, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [46] = PINGROUP(46, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [47] = PINGROUP(47, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [48] = PINGROUP(48, cci_i2c, qup1_se4, gcc_gp1_clk, _, _, _, _, _, _),
+ [49] = PINGROUP(49, cci_i2c, qup1_se4, gcc_gp2_clk, qdss_gpio, _, _, _, _, _),
+ [50] = PINGROUP(50, qup1_se1, qup1_se3, _, gcc_gp3_clk, _, _, _, _, _),
+ [51] = PINGROUP(51, qup1_se1, qup1_se3, _, tb_trig_sdc2, _, _, _, _, _),
+ [52] = PINGROUP(52, _, _, _, _, _, _, _, _, _),
+ [53] = PINGROUP(53, _, _, _, _, _, _, _, _, _),
+ [54] = PINGROUP(54, coex_uart1_rx, _, _, _, _, _, _, _, _),
+ [55] = PINGROUP(55, coex_uart1_tx, _, _, _, _, _, _, _, _),
+ [56] = PINGROUP(56, _, _, _, _, _, _, _, _, _),
+ [57] = PINGROUP(57, tmess_prng, qdss_cti_trig1, _, _, _, _, _, _, _),
+ [58] = PINGROUP(58, tmess_prng, qdss_cti_trig1, _, _, _, _, _, _, _),
+ [59] = PINGROUP(59, tmess_prng, qdss_gpio, _, _, _, _, _, _, _),
+ [60] = PINGROUP(60, tmess_prng, qdss_cti_trig0, _, _, _, _, _, _, _),
+ [61] = PINGROUP(61, _, phase_flag, _, _, _, _, _, _, _),
+ [62] = PINGROUP(62, qdss_gpio, _, _, _, _, _, _, _, _),
+ [63] = PINGROUP(63, uim0, _, _, _, _, _, _, _, _),
+ [64] = PINGROUP(64, uim0, _, _, _, _, _, _, _, _),
+ [65] = PINGROUP(65, uim0, _, _, _, _, _, _, _, _),
+ [66] = PINGROUP(66, uim0, _, _, _, _, _, _, _, _),
+ [67] = PINGROUP(67, uim1, _, _, _, _, _, _, _, _),
+ [68] = PINGROUP(68, uim1, _, _, _, _, _, _, _, _),
+ [69] = PINGROUP(69, uim1, _, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, uim1, _, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, _, _, _, audio_ref_clk, _, _, _, _, _),
+ [72] = PINGROUP(72, _, _, _, phase_flag, _, _, _, _, _),
+ [73] = PINGROUP(73, _, _, _, pll_bist_sync, _, _, _, _, _),
+ [74] = PINGROUP(74, _, _, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, _, _, _, vsense_trigger_mirnat, atest_usb0, _, _, _, _),
+ [76] = PINGROUP(76, _, _, _, _, _, _, _, _, _),
+ [77] = PINGROUP(77, _, _, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, _, _, _, atest_usb0, _, _, _, _, _),
+ [79] = PINGROUP(79, _, _, _, wlan1_adc_dtest0, atest_usb0, _, _, _, _),
+ [80] = PINGROUP(80, _, _, dbg_out_clk, wlan1_adc_dtest1, atest_usb0, _, _, _, _),
+ [81] = PINGROUP(81, _, nav, _, _, _, _, _, _, _),
+ [82] = PINGROUP(82, _, _, phase_flag, _, _, _, _, _, _),
+ [83] = PINGROUP(83, nav, _, _, _, _, _, _, _, _),
+ [84] = PINGROUP(84, nav, vfr_1, _, _, _, _, _, _, _),
+ [85] = PINGROUP(85, _, _, _, _, _, _, _, _, _),
+ [86] = PINGROUP(86, _, _, _, _, _, _, _, _, _),
+ [87] = PINGROUP(87, qlink0_request, _, _, _, _, _, _, _, _),
+ [88] = PINGROUP(88, qlink0_enable, _, _, _, _, _, _, _, _),
+ [89] = PINGROUP(89, qlink0_wmss_reset, _, _, _, _, _, _, _, _),
+ [90] = PINGROUP(90, qup1_se4, jitter_bist_ref, ddr_pxi0_test, _, _, _, _, _, _),
+ [91] = PINGROUP(91, qup1_se4, _, phase_flag, _, _, _, _, _, _),
+ [92] = PINGROUP(92, _, _, _, _, _, _, _, _, _),
+ [93] = PINGROUP(93, mdp_vsync, mdp_vsync0_out, mdp_vsync1_out, _, _, _, _, _, _),
+ [94] = PINGROUP(94, usb0_phy_ps, _, _, _, _, _, _, _, _),
+ [95] = PINGROUP(95, _, phase_flag, atest_char, _, _, _, _, _, _),
+ [96] = PINGROUP(96, _, _, _, _, _, _, _, _, _),
+ [97] = PINGROUP(97, mdp_vsync, _, phase_flag, atest_char, _, _, _, _, _),
+ [98] = PINGROUP(98, _, phase_flag, atest_char, _, _, _, _, _, _),
+ [99] = PINGROUP(99, usb0_hs_ac, _, phase_flag, atest_char, _, _, _, _, _),
+ [100] = PINGROUP(100, vfr_0_mirb, _, phase_flag, atest_char, _, _, _, _, _),
+ [101] = PINGROUP(101, _, _, _, _, _, _, _, _, _),
+ [102] = PINGROUP(102, sd_write_protect, _, _, _, _, _, _, _, _),
+ [103] = PINGROUP(103, _, _, _, _, _, _, _, _, _),
+ [104] = PINGROUP(104, _, _, _, _, _, _, _, _, _),
+ [105] = PINGROUP(105, _, phase_flag, _, _, _, _, _, _, _),
+ [106] = PINGROUP(106, host2wlan_sol, _, _, _, _, _, _, _, _),
+ [107] = PINGROUP(107, pcie0_clk_req, _, _, _, _, _, _, _, _),
+ [108] = PINGROUP(108, pll_clk_aux, _, _, _, _, _, _, _, _),
+ [109] = PINGROUP(109, _, _, _, _, _, _, _, _, _),
+ [110] = PINGROUP(110, _, _, _, _, _, _, _, _, _),
+ [111] = PINGROUP(111, _, _, _, _, _, _, _, _, _),
+ [112] = PINGROUP(112, _, _, _, _, _, _, _, _, _),
+ [113] = PINGROUP(113, qdss_cti_trig0, _, _, _, _, _, _, _, _),
+ [114] = PINGROUP(114, qdss_cti_trig0, _, _, _, _, _, _, _, _),
+ [115] = PINGROUP(115, _, phase_flag, _, _, _, _, _, _, _),
+ [116] = PINGROUP(116, _, phase_flag, _, _, _, _, _, _, _),
+ [117] = PINGROUP(117, _, phase_flag, _, _, _, _, _, _, _),
+ [118] = PINGROUP(118, qdss_gpio, _, ddr_pxi1_test, _, _, _, _, _, _),
+ [119] = PINGROUP(119, _, _, _, _, _, _, _, _, _),
+ [120] = PINGROUP(120, _, _, _, _, _, _, _, _, _),
+ [121] = PINGROUP(121, qdss_gpio, _, _, _, _, _, _, _, _),
+ [122] = PINGROUP(122, qdss_gpio, _, ddr_pxi1_test, _, _, _, _, _, _),
+ [123] = PINGROUP(123, _, _, _, _, _, _, _, _, _),
+ [124] = PINGROUP(124, _, _, _, _, _, _, _, _, _),
+ [125] = PINGROUP(125, _, _, _, _, _, _, _, _, _),
+ [126] = PINGROUP(126, qdss_gpio, _, _, _, _, _, _, _, _),
+ [127] = PINGROUP(127, qdss_gpio, ddr_pxi0_test, _, _, _, _, _, _, _),
+ [128] = PINGROUP(128, tb_trig_sdc1, _, _, _, _, _, _, _, _),
+ [129] = PINGROUP(129, _, _, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, _, _, _, _, _, _, _, _, _),
+ [131] = PINGROUP(131, _, _, _, _, _, _, _, _, _),
+ [132] = PINGROUP(132, _, _, _, _, _, _, _, _, _),
+ [133] = PINGROUP(133, _, phase_flag, _, _, _, _, _, _, _),
+ [134] = PINGROUP(134, tsense_pwm1_out, tsense_pwm2_out, _, _, _, _, _, _, _),
+ [135] = PINGROUP(135, _, phase_flag, _, _, _, _, _, _, _),
+ [136] = UFS_RESET(ufs_reset, 0x97000),
+ [137] = SDC_QDSD_PINGROUP(sdc1_rclk, 0x8c004, 0, 0),
+ [138] = SDC_QDSD_PINGROUP(sdc1_clk, 0x8c000, 13, 6),
+ [139] = SDC_QDSD_PINGROUP(sdc1_cmd, 0x8c000, 11, 3),
+ [140] = SDC_QDSD_PINGROUP(sdc1_data, 0x8c000, 9, 0),
+ [141] = SDC_QDSD_PINGROUP(sdc2_clk, 0x8f000, 14, 6),
+ [142] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x8f000, 11, 3),
+ [143] = SDC_QDSD_PINGROUP(sdc2_data, 0x8f000, 9, 0),
+};
+
+static const struct msm_gpio_wakeirq_map sm4450_pdc_map[] = {
+ { 0, 67 }, { 3, 82 }, { 4, 69 }, { 5, 70 }, { 6, 44 }, { 7, 43 },
+ { 8, 71 }, { 9, 86 }, { 10, 48 }, { 11, 77 }, { 12, 90 },
+ { 13, 54 }, { 14, 91 }, { 17, 97 }, { 18, 102 }, { 21, 103 },
+ { 22, 104 }, { 23, 105 }, { 24, 53 }, { 25, 106 }, { 26, 65 },
+ { 27, 55 }, { 28, 89 }, { 30, 80 }, { 31, 109 }, { 33, 87 },
+ { 34, 81 }, { 35, 75 }, { 40, 88 }, { 41, 98 }, { 42, 110 },
+ { 43, 95 }, { 47, 118 }, { 50, 111 }, { 52, 52 }, { 53, 114 },
+ { 54, 115 }, { 55, 99 }, { 56, 45 }, { 57, 85 }, { 58, 56 },
+ { 59, 84 }, { 60, 83 }, { 61, 96 }, { 62, 93 }, { 66, 116 },
+ { 67, 113 }, { 70, 42 }, { 71, 122 }, { 73, 119 }, { 75, 121 },
+ { 77, 120 }, { 79, 123 }, { 81, 124 }, { 83, 64 }, { 84, 128 },
+ { 86, 129 }, { 87, 63 }, { 91, 92 }, { 92, 66 }, { 93, 125 },
+ { 94, 76 }, { 95, 62 }, { 96, 132 }, { 97, 135 }, { 98, 73 },
+ { 99, 133 }, { 101, 46 }, { 102, 134 }, { 103, 49 }, { 105, 58 },
+ { 107, 94 }, { 110, 59 }, { 113, 57 }, { 114, 60 }, { 118, 107 },
+ { 120, 61 }, { 121, 108 }, { 123, 68 }, { 125, 72 }, { 128, 112 },
+};
+
+static const struct msm_pinctrl_soc_data sm4450_tlmm = {
+ .pins = sm4450_pins,
+ .npins = ARRAY_SIZE(sm4450_pins),
+ .functions = sm4450_functions,
+ .nfunctions = ARRAY_SIZE(sm4450_functions),
+ .groups = sm4450_groups,
+ .ngroups = ARRAY_SIZE(sm4450_groups),
+ .ngpios = 137,
+ .wakeirq_map = sm4450_pdc_map,
+ .nwakeirq_map = ARRAY_SIZE(sm4450_pdc_map),
+};
+
+static int sm4450_tlmm_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &sm4450_tlmm);
+}
+
+static const struct of_device_id sm4450_tlmm_of_match[] = {
+ { .compatible = "qcom,sm4450-tlmm", },
+ { }
+};
+
+static struct platform_driver sm4450_tlmm_driver = {
+ .driver = {
+ .name = "sm4450-tlmm",
+ .of_match_table = sm4450_tlmm_of_match,
+ },
+ .probe = sm4450_tlmm_probe,
+ .remove_new = msm_pinctrl_remove,
+};
+MODULE_DEVICE_TABLE(of, sm4450_tlmm_of_match);
+
+static int __init sm4450_tlmm_init(void)
+{
+ return platform_driver_register(&sm4450_tlmm_driver);
+}
+arch_initcall(sm4450_tlmm_init);
+
+static void __exit sm4450_tlmm_exit(void)
+{
+ platform_driver_unregister(&sm4450_tlmm_driver);
+}
+module_exit(sm4450_tlmm_exit);
+
+MODULE_DESCRIPTION("QTI SM4450 TLMM driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c
index e8a6f6f6af54..316d6fc69131 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm6115-lpass-lpi.c
@@ -36,26 +36,6 @@ enum lpass_lpi_functions {
LPI_MUX__,
};
-static int gpio0_pins[] = { 0 };
-static int gpio1_pins[] = { 1 };
-static int gpio2_pins[] = { 2 };
-static int gpio3_pins[] = { 3 };
-static int gpio4_pins[] = { 4 };
-static int gpio5_pins[] = { 5 };
-static int gpio6_pins[] = { 6 };
-static int gpio7_pins[] = { 7 };
-static int gpio8_pins[] = { 8 };
-static int gpio9_pins[] = { 9 };
-static int gpio10_pins[] = { 10 };
-static int gpio11_pins[] = { 11 };
-static int gpio12_pins[] = { 12 };
-static int gpio13_pins[] = { 13 };
-static int gpio14_pins[] = { 14 };
-static int gpio15_pins[] = { 15 };
-static int gpio16_pins[] = { 16 };
-static int gpio17_pins[] = { 17 };
-static int gpio18_pins[] = { 18 };
-
static const struct pinctrl_pin_desc sm6115_lpi_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c
index cb10ce8d5d28..9791d9ba5087 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm8250-lpass-lpi.c
@@ -36,21 +36,6 @@ enum lpass_lpi_functions {
LPI_MUX__,
};
-static int gpio0_pins[] = { 0 };
-static int gpio1_pins[] = { 1 };
-static int gpio2_pins[] = { 2 };
-static int gpio3_pins[] = { 3 };
-static int gpio4_pins[] = { 4 };
-static int gpio5_pins[] = { 5 };
-static int gpio6_pins[] = { 6 };
-static int gpio7_pins[] = { 7 };
-static int gpio8_pins[] = { 8 };
-static int gpio9_pins[] = { 9 };
-static int gpio10_pins[] = { 10 };
-static int gpio11_pins[] = { 11 };
-static int gpio12_pins[] = { 12 };
-static int gpio13_pins[] = { 13 };
-
static const struct pinctrl_pin_desc sm8250_lpi_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8350-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8350-lpass-lpi.c
index 297cc95ac3c0..5b9a2cb216bd 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm8350-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm8350-lpass-lpi.c
@@ -36,22 +36,6 @@ enum lpass_lpi_functions {
LPI_MUX__,
};
-static int gpio0_pins[] = { 0 };
-static int gpio1_pins[] = { 1 };
-static int gpio2_pins[] = { 2 };
-static int gpio3_pins[] = { 3 };
-static int gpio4_pins[] = { 4 };
-static int gpio5_pins[] = { 5 };
-static int gpio6_pins[] = { 6 };
-static int gpio7_pins[] = { 7 };
-static int gpio8_pins[] = { 8 };
-static int gpio9_pins[] = { 9 };
-static int gpio10_pins[] = { 10 };
-static int gpio11_pins[] = { 11 };
-static int gpio12_pins[] = { 12 };
-static int gpio13_pins[] = { 13 };
-static int gpio14_pins[] = { 14 };
-
static const struct pinctrl_pin_desc sm8350_lpi_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c
index 2e7896791fc0..a028cbb49947 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm8450-lpass-lpi.c
@@ -52,30 +52,6 @@ enum lpass_lpi_functions {
LPI_MUX__,
};
-static int gpio0_pins[] = { 0 };
-static int gpio1_pins[] = { 1 };
-static int gpio2_pins[] = { 2 };
-static int gpio3_pins[] = { 3 };
-static int gpio4_pins[] = { 4 };
-static int gpio5_pins[] = { 5 };
-static int gpio6_pins[] = { 6 };
-static int gpio7_pins[] = { 7 };
-static int gpio8_pins[] = { 8 };
-static int gpio9_pins[] = { 9 };
-static int gpio10_pins[] = { 10 };
-static int gpio11_pins[] = { 11 };
-static int gpio12_pins[] = { 12 };
-static int gpio13_pins[] = { 13 };
-static int gpio14_pins[] = { 14 };
-static int gpio15_pins[] = { 15 };
-static int gpio16_pins[] = { 16 };
-static int gpio17_pins[] = { 17 };
-static int gpio18_pins[] = { 18 };
-static int gpio19_pins[] = { 19 };
-static int gpio20_pins[] = { 20 };
-static int gpio21_pins[] = { 21 };
-static int gpio22_pins[] = { 22 };
-
static const struct pinctrl_pin_desc sm8450_lpi_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c
index 64458c3fbe5e..852192b044e1 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm8550-lpass-lpi.c
@@ -52,30 +52,6 @@ enum lpass_lpi_functions {
LPI_MUX__,
};
-static int gpio0_pins[] = { 0 };
-static int gpio1_pins[] = { 1 };
-static int gpio2_pins[] = { 2 };
-static int gpio3_pins[] = { 3 };
-static int gpio4_pins[] = { 4 };
-static int gpio5_pins[] = { 5 };
-static int gpio6_pins[] = { 6 };
-static int gpio7_pins[] = { 7 };
-static int gpio8_pins[] = { 8 };
-static int gpio9_pins[] = { 9 };
-static int gpio10_pins[] = { 10 };
-static int gpio11_pins[] = { 11 };
-static int gpio12_pins[] = { 12 };
-static int gpio13_pins[] = { 13 };
-static int gpio14_pins[] = { 14 };
-static int gpio15_pins[] = { 15 };
-static int gpio16_pins[] = { 16 };
-static int gpio17_pins[] = { 17 };
-static int gpio18_pins[] = { 18 };
-static int gpio19_pins[] = { 19 };
-static int gpio20_pins[] = { 20 };
-static int gpio21_pins[] = { 21 };
-static int gpio22_pins[] = { 22 };
-
static const struct pinctrl_pin_desc sm8550_lpi_pins[] = {
PINCTRL_PIN(0, "gpio0"),
PINCTRL_PIN(1, "gpio1"),
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c
new file mode 100644
index 000000000000..04400c832327
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sm8650-lpass-lpi.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022-2023 Linaro Ltd.
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-lpass-lpi.h"
+
+enum lpass_lpi_functions {
+ LPI_MUX_dmic1_clk,
+ LPI_MUX_dmic1_data,
+ LPI_MUX_dmic2_clk,
+ LPI_MUX_dmic2_data,
+ LPI_MUX_dmic3_clk,
+ LPI_MUX_dmic3_data,
+ LPI_MUX_dmic4_clk,
+ LPI_MUX_dmic4_data,
+ LPI_MUX_i2s0_clk,
+ LPI_MUX_i2s0_data,
+ LPI_MUX_i2s0_ws,
+ LPI_MUX_i2s1_clk,
+ LPI_MUX_i2s1_data,
+ LPI_MUX_i2s1_ws,
+ LPI_MUX_i2s2_clk,
+ LPI_MUX_i2s2_data,
+ LPI_MUX_i2s2_ws,
+ LPI_MUX_i2s3_clk,
+ LPI_MUX_i2s3_data,
+ LPI_MUX_i2s3_ws,
+ LPI_MUX_i2s4_clk,
+ LPI_MUX_i2s4_data,
+ LPI_MUX_i2s4_ws,
+ LPI_MUX_qca_swr_clk,
+ LPI_MUX_qca_swr_data,
+ LPI_MUX_slimbus_clk,
+ LPI_MUX_slimbus_data,
+ LPI_MUX_swr_rx_clk,
+ LPI_MUX_swr_rx_data,
+ LPI_MUX_swr_tx_clk,
+ LPI_MUX_swr_tx_data,
+ LPI_MUX_wsa_swr_clk,
+ LPI_MUX_wsa_swr_data,
+ LPI_MUX_wsa2_swr_clk,
+ LPI_MUX_wsa2_swr_data,
+ LPI_MUX_ext_mclk1_a,
+ LPI_MUX_ext_mclk1_b,
+ LPI_MUX_ext_mclk1_c,
+ LPI_MUX_ext_mclk1_d,
+ LPI_MUX_ext_mclk1_e,
+ LPI_MUX_gpio,
+ LPI_MUX__,
+};
+
+static const struct pinctrl_pin_desc sm8650_lpi_pins[] = {
+ PINCTRL_PIN(0, "gpio0"),
+ PINCTRL_PIN(1, "gpio1"),
+ PINCTRL_PIN(2, "gpio2"),
+ PINCTRL_PIN(3, "gpio3"),
+ PINCTRL_PIN(4, "gpio4"),
+ PINCTRL_PIN(5, "gpio5"),
+ PINCTRL_PIN(6, "gpio6"),
+ PINCTRL_PIN(7, "gpio7"),
+ PINCTRL_PIN(8, "gpio8"),
+ PINCTRL_PIN(9, "gpio9"),
+ PINCTRL_PIN(10, "gpio10"),
+ PINCTRL_PIN(11, "gpio11"),
+ PINCTRL_PIN(12, "gpio12"),
+ PINCTRL_PIN(13, "gpio13"),
+ PINCTRL_PIN(14, "gpio14"),
+ PINCTRL_PIN(15, "gpio15"),
+ PINCTRL_PIN(16, "gpio16"),
+ PINCTRL_PIN(17, "gpio17"),
+ PINCTRL_PIN(18, "gpio18"),
+ PINCTRL_PIN(19, "gpio19"),
+ PINCTRL_PIN(20, "gpio20"),
+ PINCTRL_PIN(21, "gpio21"),
+ PINCTRL_PIN(22, "gpio22"),
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22",
+};
+
+static const char * const dmic1_clk_groups[] = { "gpio6" };
+static const char * const dmic1_data_groups[] = { "gpio7" };
+static const char * const dmic2_clk_groups[] = { "gpio8" };
+static const char * const dmic2_data_groups[] = { "gpio9" };
+static const char * const dmic3_clk_groups[] = { "gpio12" };
+static const char * const dmic3_data_groups[] = { "gpio13" };
+static const char * const dmic4_clk_groups[] = { "gpio17" };
+static const char * const dmic4_data_groups[] = { "gpio18" };
+static const char * const i2s0_clk_groups[] = { "gpio0" };
+static const char * const i2s0_ws_groups[] = { "gpio1" };
+static const char * const i2s0_data_groups[] = { "gpio2", "gpio3", "gpio4", "gpio5" };
+static const char * const i2s1_clk_groups[] = { "gpio6" };
+static const char * const i2s1_ws_groups[] = { "gpio7" };
+static const char * const i2s1_data_groups[] = { "gpio8", "gpio9" };
+static const char * const i2s2_clk_groups[] = { "gpio10" };
+static const char * const i2s2_ws_groups[] = { "gpio11" };
+static const char * const i2s2_data_groups[] = { "gpio15", "gpio16" };
+static const char * const i2s3_clk_groups[] = { "gpio12" };
+static const char * const i2s3_ws_groups[] = { "gpio13" };
+static const char * const i2s3_data_groups[] = { "gpio17", "gpio18" };
+static const char * const i2s4_clk_groups[] = { "gpio19"};
+static const char * const i2s4_ws_groups[] = { "gpio20"};
+static const char * const i2s4_data_groups[] = { "gpio21", "gpio22"};
+static const char * const qca_swr_clk_groups[] = { "gpio19" };
+static const char * const qca_swr_data_groups[] = { "gpio20" };
+static const char * const slimbus_clk_groups[] = { "gpio19"};
+static const char * const slimbus_data_groups[] = { "gpio20"};
+static const char * const swr_tx_clk_groups[] = { "gpio0" };
+static const char * const swr_tx_data_groups[] = { "gpio1", "gpio2", "gpio14" };
+static const char * const swr_rx_clk_groups[] = { "gpio3" };
+static const char * const swr_rx_data_groups[] = { "gpio4", "gpio5", "gpio15" };
+static const char * const wsa_swr_clk_groups[] = { "gpio10" };
+static const char * const wsa_swr_data_groups[] = { "gpio11" };
+static const char * const wsa2_swr_clk_groups[] = { "gpio15" };
+static const char * const wsa2_swr_data_groups[] = { "gpio16" };
+static const char * const ext_mclk1_c_groups[] = { "gpio5" };
+static const char * const ext_mclk1_b_groups[] = { "gpio9" };
+static const char * const ext_mclk1_a_groups[] = { "gpio13" };
+static const char * const ext_mclk1_d_groups[] = { "gpio14" };
+static const char * const ext_mclk1_e_groups[] = { "gpio22" };
+
+static const struct lpi_pingroup sm8650_groups[] = {
+ LPI_PINGROUP(0, 11, swr_tx_clk, i2s0_clk, _, _),
+ LPI_PINGROUP(1, 11, swr_tx_data, i2s0_ws, _, _),
+ LPI_PINGROUP(2, 11, swr_tx_data, i2s0_data, _, _),
+ LPI_PINGROUP(3, 11, swr_rx_clk, i2s0_data, _, _),
+ LPI_PINGROUP(4, 11, swr_rx_data, i2s0_data, _, _),
+ LPI_PINGROUP(5, 11, swr_rx_data, ext_mclk1_c, i2s0_data, _),
+ LPI_PINGROUP(6, LPI_NO_SLEW, dmic1_clk, i2s1_clk, _, _),
+ LPI_PINGROUP(7, LPI_NO_SLEW, dmic1_data, i2s1_ws, _, _),
+ LPI_PINGROUP(8, LPI_NO_SLEW, dmic2_clk, i2s1_data, _, _),
+ LPI_PINGROUP(9, LPI_NO_SLEW, dmic2_data, i2s1_data, ext_mclk1_b, _),
+ LPI_PINGROUP(10, 11, i2s2_clk, wsa_swr_clk, _, _),
+ LPI_PINGROUP(11, 11, i2s2_ws, wsa_swr_data, _, _),
+ LPI_PINGROUP(12, LPI_NO_SLEW, dmic3_clk, i2s3_clk, _, _),
+ LPI_PINGROUP(13, LPI_NO_SLEW, dmic3_data, i2s3_ws, ext_mclk1_a, _),
+ LPI_PINGROUP(14, 11, swr_tx_data, ext_mclk1_d, _, _),
+ LPI_PINGROUP(15, 11, i2s2_data, wsa2_swr_clk, _, _),
+ LPI_PINGROUP(16, 11, i2s2_data, wsa2_swr_data, _, _),
+ LPI_PINGROUP(17, LPI_NO_SLEW, dmic4_clk, i2s3_data, _, _),
+ LPI_PINGROUP(18, LPI_NO_SLEW, dmic4_data, i2s3_data, _, _),
+ LPI_PINGROUP(19, 11, i2s4_clk, slimbus_clk, qca_swr_clk, _),
+ LPI_PINGROUP(20, 11, i2s4_ws, slimbus_data, qca_swr_data, _),
+ LPI_PINGROUP(21, LPI_NO_SLEW, i2s4_data, _, _, _),
+ LPI_PINGROUP(22, LPI_NO_SLEW, i2s4_data, ext_mclk1_e, _, _),
+};
+
+static const struct lpi_function sm8650_functions[] = {
+ LPI_FUNCTION(gpio),
+ LPI_FUNCTION(dmic1_clk),
+ LPI_FUNCTION(dmic1_data),
+ LPI_FUNCTION(dmic2_clk),
+ LPI_FUNCTION(dmic2_data),
+ LPI_FUNCTION(dmic3_clk),
+ LPI_FUNCTION(dmic3_data),
+ LPI_FUNCTION(dmic4_clk),
+ LPI_FUNCTION(dmic4_data),
+ LPI_FUNCTION(i2s0_clk),
+ LPI_FUNCTION(i2s0_data),
+ LPI_FUNCTION(i2s0_ws),
+ LPI_FUNCTION(i2s1_clk),
+ LPI_FUNCTION(i2s1_data),
+ LPI_FUNCTION(i2s1_ws),
+ LPI_FUNCTION(i2s2_clk),
+ LPI_FUNCTION(i2s2_data),
+ LPI_FUNCTION(i2s2_ws),
+ LPI_FUNCTION(i2s3_clk),
+ LPI_FUNCTION(i2s3_data),
+ LPI_FUNCTION(i2s3_ws),
+ LPI_FUNCTION(i2s4_clk),
+ LPI_FUNCTION(i2s4_data),
+ LPI_FUNCTION(i2s4_ws),
+ LPI_FUNCTION(qca_swr_clk),
+ LPI_FUNCTION(qca_swr_data),
+ LPI_FUNCTION(slimbus_clk),
+ LPI_FUNCTION(slimbus_data),
+ LPI_FUNCTION(swr_rx_clk),
+ LPI_FUNCTION(swr_rx_data),
+ LPI_FUNCTION(swr_tx_clk),
+ LPI_FUNCTION(swr_tx_data),
+ LPI_FUNCTION(wsa_swr_clk),
+ LPI_FUNCTION(wsa_swr_data),
+ LPI_FUNCTION(wsa2_swr_clk),
+ LPI_FUNCTION(wsa2_swr_data),
+ LPI_FUNCTION(ext_mclk1_a),
+ LPI_FUNCTION(ext_mclk1_b),
+ LPI_FUNCTION(ext_mclk1_c),
+ LPI_FUNCTION(ext_mclk1_d),
+ LPI_FUNCTION(ext_mclk1_e),
+};
+
+static const struct lpi_pinctrl_variant_data sm8650_lpi_data = {
+ .pins = sm8650_lpi_pins,
+ .npins = ARRAY_SIZE(sm8650_lpi_pins),
+ .groups = sm8650_groups,
+ .ngroups = ARRAY_SIZE(sm8650_groups),
+ .functions = sm8650_functions,
+ .nfunctions = ARRAY_SIZE(sm8650_functions),
+ .flags = LPI_FLAG_SLEW_RATE_SAME_REG,
+};
+
+static const struct of_device_id lpi_pinctrl_of_match[] = {
+ {
+ .compatible = "qcom,sm8650-lpass-lpi-pinctrl",
+ .data = &sm8650_lpi_data,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lpi_pinctrl_of_match);
+
+static struct platform_driver lpi_pinctrl_driver = {
+ .driver = {
+ .name = "qcom-sm8650-lpass-lpi-pinctrl",
+ .of_match_table = lpi_pinctrl_of_match,
+ },
+ .probe = lpi_pinctrl_probe,
+ .remove_new = lpi_pinctrl_remove,
+};
+
+module_platform_driver(lpi_pinctrl_driver);
+MODULE_DESCRIPTION("Qualcomm SM8650 LPI GPIO pin control driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8650.c b/drivers/pinctrl/qcom/pinctrl-sm8650.c
new file mode 100644
index 000000000000..adaddd728662
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-sm8650.c
@@ -0,0 +1,1762 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-msm.h"
+
+#define REG_SIZE 0x1000
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10) \
+ { \
+ .grp = PINCTRL_PINGROUP("gpio" #id, \
+ gpio##id##_pins, \
+ ARRAY_SIZE(gpio##id##_pins)), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9, \
+ msm_mux_##f10 \
+ }, \
+ .nfuncs = 11, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .intr_target_reg = 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .i2c_pull_bit = 13, \
+ .egpio_enable = 12, \
+ .egpio_present = 11, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_wakeup_present_bit = 6, \
+ .intr_wakeup_enable_bit = 7, \
+ .intr_target_bit = 8, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .grp = PINCTRL_PINGROUP(#pg_name, \
+ pg_name##_pins, \
+ ARRAY_SIZE(pg_name##_pins)), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define UFS_RESET(pg_name, ctl, io) \
+ { \
+ .grp = PINCTRL_PINGROUP(#pg_name, \
+ pg_name##_pins, \
+ ARRAY_SIZE(pg_name##_pins)), \
+ .ctl_reg = ctl, \
+ .io_reg = io, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+static const struct pinctrl_pin_desc sm8650_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "GPIO_136"),
+ PINCTRL_PIN(137, "GPIO_137"),
+ PINCTRL_PIN(138, "GPIO_138"),
+ PINCTRL_PIN(139, "GPIO_139"),
+ PINCTRL_PIN(140, "GPIO_140"),
+ PINCTRL_PIN(141, "GPIO_141"),
+ PINCTRL_PIN(142, "GPIO_142"),
+ PINCTRL_PIN(143, "GPIO_143"),
+ PINCTRL_PIN(144, "GPIO_144"),
+ PINCTRL_PIN(145, "GPIO_145"),
+ PINCTRL_PIN(146, "GPIO_146"),
+ PINCTRL_PIN(147, "GPIO_147"),
+ PINCTRL_PIN(148, "GPIO_148"),
+ PINCTRL_PIN(149, "GPIO_149"),
+ PINCTRL_PIN(150, "GPIO_150"),
+ PINCTRL_PIN(151, "GPIO_151"),
+ PINCTRL_PIN(152, "GPIO_152"),
+ PINCTRL_PIN(153, "GPIO_153"),
+ PINCTRL_PIN(154, "GPIO_154"),
+ PINCTRL_PIN(155, "GPIO_155"),
+ PINCTRL_PIN(156, "GPIO_156"),
+ PINCTRL_PIN(157, "GPIO_157"),
+ PINCTRL_PIN(158, "GPIO_158"),
+ PINCTRL_PIN(159, "GPIO_159"),
+ PINCTRL_PIN(160, "GPIO_160"),
+ PINCTRL_PIN(161, "GPIO_161"),
+ PINCTRL_PIN(162, "GPIO_162"),
+ PINCTRL_PIN(163, "GPIO_163"),
+ PINCTRL_PIN(164, "GPIO_164"),
+ PINCTRL_PIN(165, "GPIO_165"),
+ PINCTRL_PIN(166, "GPIO_166"),
+ PINCTRL_PIN(167, "GPIO_167"),
+ PINCTRL_PIN(168, "GPIO_168"),
+ PINCTRL_PIN(169, "GPIO_169"),
+ PINCTRL_PIN(170, "GPIO_170"),
+ PINCTRL_PIN(171, "GPIO_171"),
+ PINCTRL_PIN(172, "GPIO_172"),
+ PINCTRL_PIN(173, "GPIO_173"),
+ PINCTRL_PIN(174, "GPIO_174"),
+ PINCTRL_PIN(175, "GPIO_175"),
+ PINCTRL_PIN(176, "GPIO_176"),
+ PINCTRL_PIN(177, "GPIO_177"),
+ PINCTRL_PIN(178, "GPIO_178"),
+ PINCTRL_PIN(179, "GPIO_179"),
+ PINCTRL_PIN(180, "GPIO_180"),
+ PINCTRL_PIN(181, "GPIO_181"),
+ PINCTRL_PIN(182, "GPIO_182"),
+ PINCTRL_PIN(183, "GPIO_183"),
+ PINCTRL_PIN(184, "GPIO_184"),
+ PINCTRL_PIN(185, "GPIO_185"),
+ PINCTRL_PIN(186, "GPIO_186"),
+ PINCTRL_PIN(187, "GPIO_187"),
+ PINCTRL_PIN(188, "GPIO_188"),
+ PINCTRL_PIN(189, "GPIO_189"),
+ PINCTRL_PIN(190, "GPIO_190"),
+ PINCTRL_PIN(191, "GPIO_191"),
+ PINCTRL_PIN(192, "GPIO_192"),
+ PINCTRL_PIN(193, "GPIO_193"),
+ PINCTRL_PIN(194, "GPIO_194"),
+ PINCTRL_PIN(195, "GPIO_195"),
+ PINCTRL_PIN(196, "GPIO_196"),
+ PINCTRL_PIN(197, "GPIO_197"),
+ PINCTRL_PIN(198, "GPIO_198"),
+ PINCTRL_PIN(199, "GPIO_199"),
+ PINCTRL_PIN(200, "GPIO_200"),
+ PINCTRL_PIN(201, "GPIO_201"),
+ PINCTRL_PIN(202, "GPIO_202"),
+ PINCTRL_PIN(203, "GPIO_203"),
+ PINCTRL_PIN(204, "GPIO_204"),
+ PINCTRL_PIN(205, "GPIO_205"),
+ PINCTRL_PIN(206, "GPIO_206"),
+ PINCTRL_PIN(207, "GPIO_207"),
+ PINCTRL_PIN(208, "GPIO_208"),
+ PINCTRL_PIN(209, "GPIO_209"),
+ PINCTRL_PIN(210, "UFS_RESET"),
+ PINCTRL_PIN(211, "SDC2_CLK"),
+ PINCTRL_PIN(212, "SDC2_CMD"),
+ PINCTRL_PIN(213, "SDC2_DATA"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+DECLARE_MSM_GPIO_PINS(150);
+DECLARE_MSM_GPIO_PINS(151);
+DECLARE_MSM_GPIO_PINS(152);
+DECLARE_MSM_GPIO_PINS(153);
+DECLARE_MSM_GPIO_PINS(154);
+DECLARE_MSM_GPIO_PINS(155);
+DECLARE_MSM_GPIO_PINS(156);
+DECLARE_MSM_GPIO_PINS(157);
+DECLARE_MSM_GPIO_PINS(158);
+DECLARE_MSM_GPIO_PINS(159);
+DECLARE_MSM_GPIO_PINS(160);
+DECLARE_MSM_GPIO_PINS(161);
+DECLARE_MSM_GPIO_PINS(162);
+DECLARE_MSM_GPIO_PINS(163);
+DECLARE_MSM_GPIO_PINS(164);
+DECLARE_MSM_GPIO_PINS(165);
+DECLARE_MSM_GPIO_PINS(166);
+DECLARE_MSM_GPIO_PINS(167);
+DECLARE_MSM_GPIO_PINS(168);
+DECLARE_MSM_GPIO_PINS(169);
+DECLARE_MSM_GPIO_PINS(170);
+DECLARE_MSM_GPIO_PINS(171);
+DECLARE_MSM_GPIO_PINS(172);
+DECLARE_MSM_GPIO_PINS(173);
+DECLARE_MSM_GPIO_PINS(174);
+DECLARE_MSM_GPIO_PINS(175);
+DECLARE_MSM_GPIO_PINS(176);
+DECLARE_MSM_GPIO_PINS(177);
+DECLARE_MSM_GPIO_PINS(178);
+DECLARE_MSM_GPIO_PINS(179);
+DECLARE_MSM_GPIO_PINS(180);
+DECLARE_MSM_GPIO_PINS(181);
+DECLARE_MSM_GPIO_PINS(182);
+DECLARE_MSM_GPIO_PINS(183);
+DECLARE_MSM_GPIO_PINS(184);
+DECLARE_MSM_GPIO_PINS(185);
+DECLARE_MSM_GPIO_PINS(186);
+DECLARE_MSM_GPIO_PINS(187);
+DECLARE_MSM_GPIO_PINS(188);
+DECLARE_MSM_GPIO_PINS(189);
+DECLARE_MSM_GPIO_PINS(190);
+DECLARE_MSM_GPIO_PINS(191);
+DECLARE_MSM_GPIO_PINS(192);
+DECLARE_MSM_GPIO_PINS(193);
+DECLARE_MSM_GPIO_PINS(194);
+DECLARE_MSM_GPIO_PINS(195);
+DECLARE_MSM_GPIO_PINS(196);
+DECLARE_MSM_GPIO_PINS(197);
+DECLARE_MSM_GPIO_PINS(198);
+DECLARE_MSM_GPIO_PINS(199);
+DECLARE_MSM_GPIO_PINS(200);
+DECLARE_MSM_GPIO_PINS(201);
+DECLARE_MSM_GPIO_PINS(202);
+DECLARE_MSM_GPIO_PINS(203);
+DECLARE_MSM_GPIO_PINS(204);
+DECLARE_MSM_GPIO_PINS(205);
+DECLARE_MSM_GPIO_PINS(206);
+DECLARE_MSM_GPIO_PINS(207);
+DECLARE_MSM_GPIO_PINS(208);
+DECLARE_MSM_GPIO_PINS(209);
+
+static const unsigned int ufs_reset_pins[] = { 210 };
+static const unsigned int sdc2_clk_pins[] = { 211 };
+static const unsigned int sdc2_cmd_pins[] = { 212 };
+static const unsigned int sdc2_data_pins[] = { 213 };
+
+enum sm8650_functions {
+ msm_mux_gpio,
+ msm_mux_aoss_cti,
+ msm_mux_atest_char,
+ msm_mux_atest_usb,
+ msm_mux_audio_ext_mclk0,
+ msm_mux_audio_ext_mclk1,
+ msm_mux_audio_ref_clk,
+ msm_mux_cam_aon_mclk2,
+ msm_mux_cam_aon_mclk4,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async_in,
+ msm_mux_cci_i2c_scl,
+ msm_mux_cci_i2c_sda,
+ msm_mux_cci_timer,
+ msm_mux_cmu_rng,
+ msm_mux_coex_uart1_rx,
+ msm_mux_coex_uart1_tx,
+ msm_mux_coex_uart2_rx,
+ msm_mux_coex_uart2_tx,
+ msm_mux_cri_trng,
+ msm_mux_dbg_out_clk,
+ msm_mux_ddr_bist_complete,
+ msm_mux_ddr_bist_fail,
+ msm_mux_ddr_bist_start,
+ msm_mux_ddr_bist_stop,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_pxi1,
+ msm_mux_ddr_pxi2,
+ msm_mux_ddr_pxi3,
+ msm_mux_do_not,
+ msm_mux_dp_hot,
+ msm_mux_egpio,
+ msm_mux_gcc_gp1,
+ msm_mux_gcc_gp2,
+ msm_mux_gcc_gp3,
+ msm_mux_gnss_adc0,
+ msm_mux_gnss_adc1,
+ msm_mux_i2chub0_se0,
+ msm_mux_i2chub0_se1,
+ msm_mux_i2chub0_se2,
+ msm_mux_i2chub0_se3,
+ msm_mux_i2chub0_se4,
+ msm_mux_i2chub0_se5,
+ msm_mux_i2chub0_se6,
+ msm_mux_i2chub0_se7,
+ msm_mux_i2chub0_se8,
+ msm_mux_i2chub0_se9,
+ msm_mux_i2s0_data0,
+ msm_mux_i2s0_data1,
+ msm_mux_i2s0_sck,
+ msm_mux_i2s0_ws,
+ msm_mux_i2s1_data0,
+ msm_mux_i2s1_data1,
+ msm_mux_i2s1_sck,
+ msm_mux_i2s1_ws,
+ msm_mux_ibi_i3c,
+ msm_mux_jitter_bist,
+ msm_mux_mdp_vsync,
+ msm_mux_mdp_vsync0_out,
+ msm_mux_mdp_vsync1_out,
+ msm_mux_mdp_vsync2_out,
+ msm_mux_mdp_vsync3_out,
+ msm_mux_mdp_vsync_e,
+ msm_mux_nav_gpio0,
+ msm_mux_nav_gpio1,
+ msm_mux_nav_gpio2,
+ msm_mux_nav_gpio3,
+ msm_mux_pcie0_clk_req_n,
+ msm_mux_pcie1_clk_req_n,
+ msm_mux_phase_flag,
+ msm_mux_pll_bist_sync,
+ msm_mux_pll_clk_aux,
+ msm_mux_prng_rosc0,
+ msm_mux_prng_rosc1,
+ msm_mux_prng_rosc2,
+ msm_mux_prng_rosc3,
+ msm_mux_qdss_cti,
+ msm_mux_qdss_gpio,
+ msm_mux_qlink_big_enable,
+ msm_mux_qlink_big_request,
+ msm_mux_qlink_little_enable,
+ msm_mux_qlink_little_request,
+ msm_mux_qlink_wmss,
+ msm_mux_qspi0,
+ msm_mux_qspi1,
+ msm_mux_qspi2,
+ msm_mux_qspi3,
+ msm_mux_qspi_clk,
+ msm_mux_qspi_cs,
+ msm_mux_qup1_se0,
+ msm_mux_qup1_se1,
+ msm_mux_qup1_se2,
+ msm_mux_qup1_se3,
+ msm_mux_qup1_se4,
+ msm_mux_qup1_se5,
+ msm_mux_qup1_se6,
+ msm_mux_qup1_se7,
+ msm_mux_qup2_se0,
+ msm_mux_qup2_se1,
+ msm_mux_qup2_se2,
+ msm_mux_qup2_se3,
+ msm_mux_qup2_se4,
+ msm_mux_qup2_se5,
+ msm_mux_qup2_se6,
+ msm_mux_qup2_se7,
+ msm_mux_sd_write_protect,
+ msm_mux_sdc40,
+ msm_mux_sdc41,
+ msm_mux_sdc42,
+ msm_mux_sdc43,
+ msm_mux_sdc4_clk,
+ msm_mux_sdc4_cmd,
+ msm_mux_tb_trig_sdc2,
+ msm_mux_tb_trig_sdc4,
+ msm_mux_tgu_ch0_trigout,
+ msm_mux_tgu_ch1_trigout,
+ msm_mux_tgu_ch2_trigout,
+ msm_mux_tgu_ch3_trigout,
+ msm_mux_tmess_prng0,
+ msm_mux_tmess_prng1,
+ msm_mux_tmess_prng2,
+ msm_mux_tmess_prng3,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_tsense_pwm3,
+ msm_mux_uim0_clk,
+ msm_mux_uim0_data,
+ msm_mux_uim0_present,
+ msm_mux_uim0_reset,
+ msm_mux_uim1_clk,
+ msm_mux_uim1_data,
+ msm_mux_uim1_present,
+ msm_mux_uim1_reset,
+ msm_mux_usb1_hs,
+ msm_mux_usb_phy,
+ msm_mux_vfr_0,
+ msm_mux_vfr_1,
+ msm_mux_vsense_trigger_mirnat,
+ msm_mux__,
+};
+
+static const char *const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+ "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11",
+ "gpio12", "gpio13", "gpio14", "gpio15",
+ "gpio16", "gpio17", "gpio18", "gpio19",
+ "gpio20", "gpio21", "gpio22", "gpio23",
+ "gpio24", "gpio25", "gpio26", "gpio27",
+ "gpio28", "gpio29", "gpio30", "gpio31",
+ "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39",
+ "gpio40", "gpio41", "gpio42", "gpio43",
+ "gpio44", "gpio45", "gpio46", "gpio47",
+ "gpio48", "gpio49", "gpio50", "gpio51",
+ "gpio52", "gpio53", "gpio54", "gpio55",
+ "gpio56", "gpio57", "gpio58", "gpio59",
+ "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67",
+ "gpio68", "gpio69", "gpio70", "gpio71",
+ "gpio72", "gpio73", "gpio74", "gpio75",
+ "gpio76", "gpio77", "gpio78", "gpio79",
+ "gpio80", "gpio81", "gpio82", "gpio83",
+ "gpio84", "gpio85", "gpio86", "gpio87",
+ "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95",
+ "gpio96", "gpio97", "gpio98", "gpio99",
+ "gpio100", "gpio101", "gpio102", "gpio103",
+ "gpio104", "gpio105", "gpio106", "gpio107",
+ "gpio108", "gpio109", "gpio110", "gpio111",
+ "gpio112", "gpio113", "gpio114", "gpio115",
+ "gpio116", "gpio117", "gpio118", "gpio119",
+ "gpio120", "gpio121", "gpio122", "gpio123",
+ "gpio124", "gpio125", "gpio126", "gpio127",
+ "gpio128", "gpio129", "gpio130", "gpio131",
+ "gpio132", "gpio133", "gpio134", "gpio135",
+ "gpio136", "gpio137", "gpio138", "gpio139",
+ "gpio140", "gpio141", "gpio142", "gpio143",
+ "gpio144", "gpio145", "gpio146", "gpio147",
+ "gpio148", "gpio149", "gpio150", "gpio151",
+ "gpio152", "gpio153", "gpio154", "gpio155",
+ "gpio156", "gpio157", "gpio158", "gpio159",
+ "gpio160", "gpio161", "gpio162", "gpio163",
+ "gpio164", "gpio165", "gpio166", "gpio167",
+ "gpio168", "gpio169", "gpio170", "gpio171",
+ "gpio172", "gpio173", "gpio174", "gpio175",
+ "gpio176", "gpio177", "gpio178", "gpio179",
+ "gpio180", "gpio181", "gpio182", "gpio183",
+ "gpio184", "gpio185", "gpio186", "gpio187",
+ "gpio188", "gpio189", "gpio190", "gpio191",
+ "gpio192", "gpio193", "gpio194", "gpio195",
+ "gpio196", "gpio197", "gpio198", "gpio199",
+ "gpio200", "gpio201", "gpio202", "gpio203",
+ "gpio204", "gpio205", "gpio206", "gpio207",
+ "gpio208", "gpio209",
+};
+
+static const char * const egpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5",
+ "gpio6", "gpio7", "gpio165", "gpio166", "gpio167", "gpio168",
+ "gpio169", "gpio170", "gpio171", "gpio172", "gpio173", "gpio174",
+ "gpio175", "gpio176", "gpio177", "gpio178", "gpio179", "gpio180",
+ "gpio181", "gpio182", "gpio183", "gpio184", "gpio185", "gpio186",
+ "gpio187", "gpio188", "gpio189", "gpio190", "gpio191", "gpio192",
+ "gpio193", "gpio194", "gpio195", "gpio196", "gpio197", "gpio198",
+ "gpio199", "gpio200", "gpio201", "gpio202", "gpio203", "gpio204",
+ "gpio205", "gpio206", "gpio207", "gpio208", "gpio209",
+};
+
+static const char * const aoss_cti_groups[] = {
+ "gpio50", "gpio51", "gpio60", "gpio61",
+};
+
+static const char *const atest_char_groups[] = {
+ "gpio130", "gpio131", "gpio132", "gpio133",
+ "gpio137",
+};
+
+static const char *const atest_usb_groups[] = {
+ "gpio71", "gpio72", "gpio74", "gpio130",
+ "gpio131",
+};
+
+static const char *const audio_ext_mclk0_groups[] = {
+ "gpio125",
+};
+
+static const char *const audio_ext_mclk1_groups[] = {
+ "gpio124",
+};
+
+static const char *const audio_ref_clk_groups[] = {
+ "gpio124",
+};
+
+static const char *const cam_aon_mclk2_groups[] = {
+ "gpio102",
+};
+
+static const char *const cam_aon_mclk4_groups[] = {
+ "gpio104",
+};
+
+static const char *const cam_mclk_groups[] = {
+ "gpio100", "gpio101", "gpio103", "gpio105",
+ "gpio106", "gpio108",
+};
+
+static const char *const cci_async_in_groups[] = {
+ "gpio15", "gpio163", "gpio164",
+};
+
+static const char *const cci_i2c_scl_groups[] = {
+ "gpio13", "gpio114", "gpio116", "gpio118",
+ "gpio120", "gpio153",
+};
+
+static const char *const cci_i2c_sda_groups[] = {
+ "gpio12", "gpio112", "gpio113", "gpio115",
+ "gpio117", "gpio119",
+};
+
+static const char *const cci_timer_groups[] = {
+ "gpio10", "gpio11", "gpio109", "gpio110",
+ "gpio111",
+};
+
+static const char *const cmu_rng_groups[] = {
+ "gpio95", "gpio96", "gpio112", "gpio127",
+ "gpio122", "gpio128",
+};
+
+static const char *const coex_uart1_rx_groups[] = {
+ "gpio148",
+};
+
+static const char *const coex_uart1_tx_groups[] = {
+ "gpio149",
+};
+
+static const char *const coex_uart2_rx_groups[] = {
+ "gpio150",
+};
+
+static const char *const coex_uart2_tx_groups[] = {
+ "gpio151",
+};
+
+static const char *const cri_trng_groups[] = {
+ "gpio187",
+};
+
+static const char *const dbg_out_clk_groups[] = {
+ "gpio92",
+};
+
+static const char *const ddr_bist_complete_groups[] = {
+ "gpio44",
+};
+
+static const char *const ddr_bist_fail_groups[] = {
+ "gpio40",
+};
+
+static const char *const ddr_bist_start_groups[] = {
+ "gpio41",
+};
+
+static const char *const ddr_bist_stop_groups[] = {
+ "gpio45",
+};
+
+static const char *const ddr_pxi0_groups[] = {
+ "gpio75", "gpio76",
+};
+
+static const char *const ddr_pxi1_groups[] = {
+ "gpio44", "gpio45",
+};
+
+static const char *const ddr_pxi2_groups[] = {
+ "gpio51", "gpio62",
+};
+
+static const char *const ddr_pxi3_groups[] = {
+ "gpio46", "gpio47",
+};
+
+static const char *const do_not_groups[] = {
+ "gpio36", "gpio37", "gpio38", "gpio39",
+ "gpio134", "gpio135", "gpio136",
+};
+
+static const char *const dp_hot_groups[] = {
+ "gpio47",
+};
+
+static const char *const gcc_gp1_groups[] = {
+ "gpio86", "gpio134",
+};
+
+static const char *const gcc_gp2_groups[] = {
+ "gpio87", "gpio135",
+};
+
+static const char *const gcc_gp3_groups[] = {
+ "gpio88", "gpio136",
+};
+
+static const char *const gnss_adc0_groups[] = {
+ "gpio89", "gpio91",
+};
+
+static const char *const gnss_adc1_groups[] = {
+ "gpio90", "gpio92",
+};
+
+static const char *const i2chub0_se0_groups[] = {
+ "gpio64", "gpio65",
+};
+
+static const char *const i2chub0_se1_groups[] = {
+ "gpio66", "gpio67",
+};
+
+static const char *const i2chub0_se2_groups[] = {
+ "gpio68", "gpio69",
+};
+
+static const char *const i2chub0_se3_groups[] = {
+ "gpio70", "gpio71",
+};
+
+static const char *const i2chub0_se4_groups[] = {
+ "gpio72", "gpio73",
+};
+
+static const char *const i2chub0_se5_groups[] = {
+ "gpio74", "gpio75",
+};
+
+static const char *const i2chub0_se6_groups[] = {
+ "gpio76", "gpio77",
+};
+
+static const char *const i2chub0_se7_groups[] = {
+ "gpio78", "gpio79",
+};
+
+static const char *const i2chub0_se8_groups[] = {
+ "gpio206", "gpio207",
+};
+
+static const char *const i2chub0_se9_groups[] = {
+ "gpio80", "gpio81",
+};
+
+static const char *const i2s0_data0_groups[] = {
+ "gpio127",
+};
+
+static const char *const i2s0_data1_groups[] = {
+ "gpio128",
+};
+
+static const char *const i2s0_sck_groups[] = {
+ "gpio126",
+};
+
+static const char *const i2s0_ws_groups[] = {
+ "gpio129",
+};
+
+static const char *const i2s1_data0_groups[] = {
+ "gpio122",
+};
+
+static const char *const i2s1_data1_groups[] = {
+ "gpio124",
+};
+
+static const char *const i2s1_sck_groups[] = {
+ "gpio121",
+};
+
+static const char *const i2s1_ws_groups[] = {
+ "gpio123",
+};
+
+static const char *const ibi_i3c_groups[] = {
+ "gpio0", "gpio1", "gpio4", "gpio5",
+ "gpio8", "gpio9", "gpio12", "gpio13",
+ "gpio32", "gpio33", "gpio36", "gpio37",
+ "gpio48", "gpio49", "gpio56", "gpio57",
+};
+
+static const char *const jitter_bist_groups[] = {
+ "gpio73",
+};
+
+static const char *const mdp_vsync_groups[] = {
+ "gpio86", "gpio87", "gpio133", "gpio137",
+};
+
+static const char *const mdp_vsync0_out_groups[] = {
+ "gpio86",
+};
+
+static const char *const mdp_vsync1_out_groups[] = {
+ "gpio86",
+};
+
+static const char *const mdp_vsync2_out_groups[] = {
+ "gpio87",
+};
+
+static const char *const mdp_vsync3_out_groups[] = {
+ "gpio87",
+};
+
+static const char *const mdp_vsync_e_groups[] = {
+ "gpio88",
+};
+
+static const char *const nav_gpio0_groups[] = {
+ "gpio154",
+};
+
+static const char *const nav_gpio1_groups[] = {
+ "gpio155",
+};
+
+static const char *const nav_gpio2_groups[] = {
+ "gpio152",
+};
+
+static const char *const nav_gpio3_groups[] = {
+ "gpio154",
+};
+
+static const char *const pcie0_clk_req_n_groups[] = {
+ "gpio95",
+};
+
+static const char *const pcie1_clk_req_n_groups[] = {
+ "gpio98",
+};
+
+static const char *const phase_flag_groups[] = {
+ "gpio0", "gpio1", "gpio3", "gpio4",
+ "gpio5", "gpio7", "gpio8", "gpio9",
+ "gpio11", "gpio12", "gpio13", "gpio15",
+ "gpio16", "gpio17", "gpio19", "gpio94",
+ "gpio95", "gpio96", "gpio109", "gpio111",
+ "gpio112", "gpio113", "gpio114", "gpio115",
+ "gpio116", "gpio117", "gpio118", "gpio119",
+ "gpio120", "gpio153", "gpio163", "gpio164",
+};
+
+static const char *const pll_bist_sync_groups[] = {
+ "gpio68",
+};
+
+static const char *const pll_clk_aux_groups[] = {
+ "gpio106",
+};
+
+static const char *const prng_rosc0_groups[] = {
+ "gpio186",
+};
+
+static const char *const prng_rosc1_groups[] = {
+ "gpio183",
+};
+
+static const char *const prng_rosc2_groups[] = {
+ "gpio182",
+};
+
+static const char *const prng_rosc3_groups[] = {
+ "gpio181",
+};
+
+static const char *const qdss_cti_groups[] = {
+ "gpio27", "gpio31", "gpio78", "gpio79",
+ "gpio82", "gpio83", "gpio159", "gpio162",
+};
+
+static const char *const qdss_gpio_groups[] = {
+ "gpio3", "gpio7", "gpio8", "gpio13",
+ "gpio15", "gpio100", "gpio101", "gpio102",
+ "gpio103", "gpio104", "gpio105", "gpio113",
+ "gpio114", "gpio115", "gpio116", "gpio117",
+ "gpio118", "gpio140", "gpio141", "gpio142",
+ "gpio143", "gpio144", "gpio145", "gpio146",
+ "gpio147", "gpio148", "gpio149", "gpio150",
+ "gpio151", "gpio152", "gpio153", "gpio154",
+ "gpio155", "gpio156", "gpio157", "gpio158",
+};
+
+static const char *const qlink_big_enable_groups[] = {
+ "gpio160",
+};
+
+static const char *const qlink_big_request_groups[] = {
+ "gpio159",
+};
+
+static const char *const qlink_little_enable_groups[] = {
+ "gpio157",
+};
+
+static const char *const qlink_little_request_groups[] = {
+ "gpio156",
+};
+
+static const char *const qlink_wmss_groups[] = {
+ "gpio158",
+};
+
+static const char *const qspi0_groups[] = {
+ "gpio134",
+};
+
+static const char *const qspi1_groups[] = {
+ "gpio136",
+};
+
+static const char *const qspi2_groups[] = {
+ "gpio56",
+};
+
+static const char *const qspi3_groups[] = {
+ "gpio57",
+};
+
+static const char *const qspi_clk_groups[] = {
+ "gpio135",
+};
+
+static const char *const qspi_cs_groups[] = {
+ "gpio58", "gpio59",
+};
+
+static const char *const qup1_se0_groups[] = {
+ "gpio32", "gpio33", "gpio34", "gpio35",
+};
+
+static const char *const qup1_se1_groups[] = {
+ "gpio36", "gpio37", "gpio38", "gpio39",
+};
+
+static const char *const qup1_se2_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio43",
+ "gpio44", "gpio45", "gpio46",
+};
+
+static const char *const qup1_se3_groups[] = {
+ "gpio44", "gpio45", "gpio46", "gpio47",
+};
+
+static const char *const qup1_se4_groups[] = {
+ "gpio48", "gpio49", "gpio50", "gpio51",
+};
+
+static const char *const qup1_se5_groups[] = {
+ "gpio52", "gpio53", "gpio54", "gpio55",
+};
+
+static const char *const qup1_se6_groups[] = {
+ "gpio56", "gpio57", "gpio58", "gpio59",
+};
+
+static const char *const qup1_se7_groups[] = {
+ "gpio60", "gpio61", "gpio62", "gpio63",
+};
+
+static const char *const qup2_se0_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+
+static const char *const qup2_se1_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+
+static const char *const qup2_se2_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+ "gpio13", "gpio15", "gpio12",
+};
+
+static const char *const qup2_se3_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15",
+};
+
+static const char *const qup2_se4_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19",
+};
+
+static const char *const qup2_se5_groups[] = {
+ "gpio20", "gpio21", "gpio22", "gpio23",
+ "gpio23",
+};
+
+static const char *const qup2_se6_groups[] = {
+ "gpio24", "gpio25", "gpio26", "gpio27",
+};
+
+static const char *const qup2_se7_groups[] = {
+ "gpio28", "gpio29", "gpio30", "gpio31",
+};
+
+static const char *const sd_write_protect_groups[] = {
+ "gpio93",
+};
+
+static const char *const sdc40_groups[] = {
+ "gpio134",
+};
+
+static const char *const sdc41_groups[] = {
+ "gpio136",
+};
+
+static const char *const sdc42_groups[] = {
+ "gpio56",
+};
+
+static const char *const sdc43_groups[] = {
+ "gpio57",
+};
+
+static const char *const sdc4_clk_groups[] = {
+ "gpio135",
+};
+
+static const char *const sdc4_cmd_groups[] = {
+ "gpio59",
+};
+
+static const char *const tb_trig_sdc2_groups[] = {
+ "gpio8",
+};
+
+static const char *const tb_trig_sdc4_groups[] = {
+ "gpio58",
+};
+
+static const char *const tgu_ch0_trigout_groups[] = {
+ "gpio8",
+};
+
+static const char *const tgu_ch1_trigout_groups[] = {
+ "gpio9",
+};
+
+static const char *const tgu_ch2_trigout_groups[] = {
+ "gpio10",
+};
+
+static const char *const tgu_ch3_trigout_groups[] = {
+ "gpio11",
+};
+
+static const char *const tmess_prng0_groups[] = {
+ "gpio94",
+};
+
+static const char *const tmess_prng1_groups[] = {
+ "gpio95",
+};
+
+static const char *const tmess_prng2_groups[] = {
+ "gpio96",
+};
+
+static const char *const tmess_prng3_groups[] = {
+ "gpio109",
+};
+
+static const char *const tsense_pwm1_groups[] = {
+ "gpio58",
+};
+
+static const char *const tsense_pwm2_groups[] = {
+ "gpio58",
+};
+
+static const char *const tsense_pwm3_groups[] = {
+ "gpio58",
+};
+
+static const char *const uim0_clk_groups[] = {
+ "gpio131",
+};
+
+static const char *const uim0_data_groups[] = {
+ "gpio130",
+};
+
+static const char *const uim0_present_groups[] = {
+ "gpio47",
+};
+
+static const char *const uim0_reset_groups[] = {
+ "gpio132",
+};
+
+static const char *const uim1_clk_groups[] = {
+ "gpio135",
+};
+
+static const char *const uim1_data_groups[] = {
+ "gpio134",
+};
+
+static const char *const uim1_present_groups[] = {
+ "gpio76",
+};
+
+static const char *const uim1_reset_groups[] = {
+ "gpio136",
+};
+
+static const char *const usb1_hs_groups[] = {
+ "gpio89",
+};
+
+static const char *const usb_phy_groups[] = {
+ "gpio29", "gpio54",
+};
+
+static const char *const vfr_0_groups[] = {
+ "gpio150",
+};
+
+static const char *const vfr_1_groups[] = {
+ "gpio155",
+};
+
+static const char *const vsense_trigger_mirnat_groups[] = {
+ "gpio60",
+};
+
+static const struct pinfunction sm8650_functions[] = {
+ MSM_PIN_FUNCTION(gpio),
+ MSM_PIN_FUNCTION(aoss_cti),
+ MSM_PIN_FUNCTION(atest_char),
+ MSM_PIN_FUNCTION(atest_usb),
+ MSM_PIN_FUNCTION(audio_ext_mclk0),
+ MSM_PIN_FUNCTION(audio_ext_mclk1),
+ MSM_PIN_FUNCTION(audio_ref_clk),
+ MSM_PIN_FUNCTION(cam_aon_mclk2),
+ MSM_PIN_FUNCTION(cam_aon_mclk4),
+ MSM_PIN_FUNCTION(cam_mclk),
+ MSM_PIN_FUNCTION(cci_async_in),
+ MSM_PIN_FUNCTION(cci_i2c_scl),
+ MSM_PIN_FUNCTION(cci_i2c_sda),
+ MSM_PIN_FUNCTION(cci_timer),
+ MSM_PIN_FUNCTION(cmu_rng),
+ MSM_PIN_FUNCTION(coex_uart1_rx),
+ MSM_PIN_FUNCTION(coex_uart1_tx),
+ MSM_PIN_FUNCTION(coex_uart2_rx),
+ MSM_PIN_FUNCTION(coex_uart2_tx),
+ MSM_PIN_FUNCTION(cri_trng),
+ MSM_PIN_FUNCTION(dbg_out_clk),
+ MSM_PIN_FUNCTION(ddr_bist_complete),
+ MSM_PIN_FUNCTION(ddr_bist_fail),
+ MSM_PIN_FUNCTION(ddr_bist_start),
+ MSM_PIN_FUNCTION(ddr_bist_stop),
+ MSM_PIN_FUNCTION(ddr_pxi0),
+ MSM_PIN_FUNCTION(ddr_pxi1),
+ MSM_PIN_FUNCTION(ddr_pxi2),
+ MSM_PIN_FUNCTION(ddr_pxi3),
+ MSM_PIN_FUNCTION(do_not),
+ MSM_PIN_FUNCTION(dp_hot),
+ MSM_PIN_FUNCTION(egpio),
+ MSM_PIN_FUNCTION(gcc_gp1),
+ MSM_PIN_FUNCTION(gcc_gp2),
+ MSM_PIN_FUNCTION(gcc_gp3),
+ MSM_PIN_FUNCTION(gnss_adc0),
+ MSM_PIN_FUNCTION(gnss_adc1),
+ MSM_PIN_FUNCTION(i2chub0_se0),
+ MSM_PIN_FUNCTION(i2chub0_se1),
+ MSM_PIN_FUNCTION(i2chub0_se2),
+ MSM_PIN_FUNCTION(i2chub0_se3),
+ MSM_PIN_FUNCTION(i2chub0_se4),
+ MSM_PIN_FUNCTION(i2chub0_se5),
+ MSM_PIN_FUNCTION(i2chub0_se6),
+ MSM_PIN_FUNCTION(i2chub0_se7),
+ MSM_PIN_FUNCTION(i2chub0_se8),
+ MSM_PIN_FUNCTION(i2chub0_se9),
+ MSM_PIN_FUNCTION(i2s0_data0),
+ MSM_PIN_FUNCTION(i2s0_data1),
+ MSM_PIN_FUNCTION(i2s0_sck),
+ MSM_PIN_FUNCTION(i2s0_ws),
+ MSM_PIN_FUNCTION(i2s1_data0),
+ MSM_PIN_FUNCTION(i2s1_data1),
+ MSM_PIN_FUNCTION(i2s1_sck),
+ MSM_PIN_FUNCTION(i2s1_ws),
+ MSM_PIN_FUNCTION(ibi_i3c),
+ MSM_PIN_FUNCTION(jitter_bist),
+ MSM_PIN_FUNCTION(mdp_vsync),
+ MSM_PIN_FUNCTION(mdp_vsync0_out),
+ MSM_PIN_FUNCTION(mdp_vsync1_out),
+ MSM_PIN_FUNCTION(mdp_vsync2_out),
+ MSM_PIN_FUNCTION(mdp_vsync3_out),
+ MSM_PIN_FUNCTION(mdp_vsync_e),
+ MSM_PIN_FUNCTION(nav_gpio0),
+ MSM_PIN_FUNCTION(nav_gpio1),
+ MSM_PIN_FUNCTION(nav_gpio2),
+ MSM_PIN_FUNCTION(nav_gpio3),
+ MSM_PIN_FUNCTION(pcie0_clk_req_n),
+ MSM_PIN_FUNCTION(pcie1_clk_req_n),
+ MSM_PIN_FUNCTION(phase_flag),
+ MSM_PIN_FUNCTION(pll_bist_sync),
+ MSM_PIN_FUNCTION(pll_clk_aux),
+ MSM_PIN_FUNCTION(prng_rosc0),
+ MSM_PIN_FUNCTION(prng_rosc1),
+ MSM_PIN_FUNCTION(prng_rosc2),
+ MSM_PIN_FUNCTION(prng_rosc3),
+ MSM_PIN_FUNCTION(qdss_cti),
+ MSM_PIN_FUNCTION(qdss_gpio),
+ MSM_PIN_FUNCTION(qlink_big_enable),
+ MSM_PIN_FUNCTION(qlink_big_request),
+ MSM_PIN_FUNCTION(qlink_little_enable),
+ MSM_PIN_FUNCTION(qlink_little_request),
+ MSM_PIN_FUNCTION(qlink_wmss),
+ MSM_PIN_FUNCTION(qspi0),
+ MSM_PIN_FUNCTION(qspi1),
+ MSM_PIN_FUNCTION(qspi2),
+ MSM_PIN_FUNCTION(qspi3),
+ MSM_PIN_FUNCTION(qspi_clk),
+ MSM_PIN_FUNCTION(qspi_cs),
+ MSM_PIN_FUNCTION(qup1_se0),
+ MSM_PIN_FUNCTION(qup1_se1),
+ MSM_PIN_FUNCTION(qup1_se2),
+ MSM_PIN_FUNCTION(qup1_se3),
+ MSM_PIN_FUNCTION(qup1_se4),
+ MSM_PIN_FUNCTION(qup1_se5),
+ MSM_PIN_FUNCTION(qup1_se6),
+ MSM_PIN_FUNCTION(qup1_se7),
+ MSM_PIN_FUNCTION(qup2_se0),
+ MSM_PIN_FUNCTION(qup2_se1),
+ MSM_PIN_FUNCTION(qup2_se2),
+ MSM_PIN_FUNCTION(qup2_se3),
+ MSM_PIN_FUNCTION(qup2_se4),
+ MSM_PIN_FUNCTION(qup2_se5),
+ MSM_PIN_FUNCTION(qup2_se6),
+ MSM_PIN_FUNCTION(qup2_se7),
+ MSM_PIN_FUNCTION(sd_write_protect),
+ MSM_PIN_FUNCTION(sdc40),
+ MSM_PIN_FUNCTION(sdc41),
+ MSM_PIN_FUNCTION(sdc42),
+ MSM_PIN_FUNCTION(sdc43),
+ MSM_PIN_FUNCTION(sdc4_clk),
+ MSM_PIN_FUNCTION(sdc4_cmd),
+ MSM_PIN_FUNCTION(tb_trig_sdc2),
+ MSM_PIN_FUNCTION(tb_trig_sdc4),
+ MSM_PIN_FUNCTION(tgu_ch0_trigout),
+ MSM_PIN_FUNCTION(tgu_ch1_trigout),
+ MSM_PIN_FUNCTION(tgu_ch2_trigout),
+ MSM_PIN_FUNCTION(tgu_ch3_trigout),
+ MSM_PIN_FUNCTION(tmess_prng0),
+ MSM_PIN_FUNCTION(tmess_prng1),
+ MSM_PIN_FUNCTION(tmess_prng2),
+ MSM_PIN_FUNCTION(tmess_prng3),
+ MSM_PIN_FUNCTION(tsense_pwm1),
+ MSM_PIN_FUNCTION(tsense_pwm2),
+ MSM_PIN_FUNCTION(tsense_pwm3),
+ MSM_PIN_FUNCTION(uim0_clk),
+ MSM_PIN_FUNCTION(uim0_data),
+ MSM_PIN_FUNCTION(uim0_present),
+ MSM_PIN_FUNCTION(uim0_reset),
+ MSM_PIN_FUNCTION(uim1_clk),
+ MSM_PIN_FUNCTION(uim1_data),
+ MSM_PIN_FUNCTION(uim1_present),
+ MSM_PIN_FUNCTION(uim1_reset),
+ MSM_PIN_FUNCTION(usb1_hs),
+ MSM_PIN_FUNCTION(usb_phy),
+ MSM_PIN_FUNCTION(vfr_0),
+ MSM_PIN_FUNCTION(vfr_1),
+ MSM_PIN_FUNCTION(vsense_trigger_mirnat),
+};
+
+/*
+ * Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup sm8650_groups[] = {
+ [0] = PINGROUP(0, qup2_se0, ibi_i3c, phase_flag, _, _, _, _, _, _, egpio),
+ [1] = PINGROUP(1, qup2_se0, ibi_i3c, phase_flag, _, _, _, _, _, _, egpio),
+ [2] = PINGROUP(2, qup2_se0, _, _, _, _, _, _, _, _, egpio),
+ [3] = PINGROUP(3, qup2_se0, phase_flag, _, qdss_gpio, _, _, _, _, _, egpio),
+ [4] = PINGROUP(4, qup2_se1, ibi_i3c, phase_flag, _, _, _, _, _, _, egpio),
+ [5] = PINGROUP(5, qup2_se1, ibi_i3c, phase_flag, _, _, _, _, _, _, egpio),
+ [6] = PINGROUP(6, qup2_se1, _, _, _, _, _, _, _, _, egpio),
+ [7] = PINGROUP(7, qup2_se1, phase_flag, _, qdss_gpio, _, _, _, _, _, egpio),
+ [8] = PINGROUP(8, qup2_se2, ibi_i3c, tb_trig_sdc2, phase_flag, tgu_ch0_trigout, _, qdss_gpio, _, _, _),
+ [9] = PINGROUP(9, qup2_se2, ibi_i3c, phase_flag, tgu_ch1_trigout, _, _, _, _, _, _),
+ [10] = PINGROUP(10, qup2_se2, cci_timer, tgu_ch2_trigout, _, _, _, _, _, _, _),
+ [11] = PINGROUP(11, qup2_se2, cci_timer, phase_flag, tgu_ch3_trigout, _, _, _, _, _, _),
+ [12] = PINGROUP(12, qup2_se3, cci_i2c_sda, ibi_i3c, qup2_se2, phase_flag, _, _, _, _, _),
+ [13] = PINGROUP(13, qup2_se3, cci_i2c_scl, ibi_i3c, qup2_se2, phase_flag, _, qdss_gpio, _, _, _),
+ [14] = PINGROUP(14, qup2_se3, _, _, _, _, _, _, _, _, _),
+ [15] = PINGROUP(15, qup2_se3, cci_async_in, qup2_se2, phase_flag, _, qdss_gpio, _, _, _, _),
+ [16] = PINGROUP(16, qup2_se4, phase_flag, _, _, _, _, _, _, _, _),
+ [17] = PINGROUP(17, qup2_se4, phase_flag, _, _, _, _, _, _, _, _),
+ [18] = PINGROUP(18, qup2_se4, _, _, _, _, _, _, _, _, _),
+ [19] = PINGROUP(19, qup2_se4, phase_flag, _, _, _, _, _, _, _, _),
+ [20] = PINGROUP(20, qup2_se5, _, _, _, _, _, _, _, _, _),
+ [21] = PINGROUP(21, qup2_se5, _, _, _, _, _, _, _, _, _),
+ [22] = PINGROUP(22, qup2_se5, _, _, _, _, _, _, _, _, _),
+ [23] = PINGROUP(23, qup2_se5, qup2_se5, _, _, _, _, _, _, _, _),
+ [24] = PINGROUP(24, qup2_se6, _, _, _, _, _, _, _, _, _),
+ [25] = PINGROUP(25, qup2_se6, _, _, _, _, _, _, _, _, _),
+ [26] = PINGROUP(26, qup2_se6, _, _, _, _, _, _, _, _, _),
+ [27] = PINGROUP(27, qup2_se6, qdss_cti, _, _, _, _, _, _, _, _),
+ [28] = PINGROUP(28, qup2_se7, _, _, _, _, _, _, _, _, _),
+ [29] = PINGROUP(29, qup2_se7, usb_phy, _, _, _, _, _, _, _, _),
+ [30] = PINGROUP(30, qup2_se7, _, _, _, _, _, _, _, _, _),
+ [31] = PINGROUP(31, qup2_se7, qdss_cti, _, _, _, _, _, _, _, _),
+ [32] = PINGROUP(32, qup1_se0, ibi_i3c, _, _, _, _, _, _, _, _),
+ [33] = PINGROUP(33, qup1_se0, ibi_i3c, _, _, _, _, _, _, _, _),
+ [34] = PINGROUP(34, qup1_se0, _, _, _, _, _, _, _, _, _),
+ [35] = PINGROUP(35, qup1_se0, _, _, _, _, _, _, _, _, _),
+ [36] = PINGROUP(36, qup1_se1, do_not, ibi_i3c, _, _, _, _, _, _, _),
+ [37] = PINGROUP(37, qup1_se1, do_not, ibi_i3c, _, _, _, _, _, _, _),
+ [38] = PINGROUP(38, qup1_se1, do_not, _, _, _, _, _, _, _, _),
+ [39] = PINGROUP(39, qup1_se1, do_not, _, _, _, _, _, _, _, _),
+ [40] = PINGROUP(40, qup1_se2, ddr_bist_fail, _, _, _, _, _, _, _, _),
+ [41] = PINGROUP(41, qup1_se2, ddr_bist_start, _, _, _, _, _, _, _, _),
+ [42] = PINGROUP(42, qup1_se2, _, _, _, _, _, _, _, _, _),
+ [43] = PINGROUP(43, qup1_se2, _, _, _, _, _, _, _, _, _),
+ [44] = PINGROUP(44, qup1_se3, qup1_se2, ddr_bist_complete, ddr_pxi1, _, _, _, _, _, _),
+ [45] = PINGROUP(45, qup1_se3, qup1_se2, ddr_bist_stop, ddr_pxi1, _, _, _, _, _, _),
+ [46] = PINGROUP(46, qup1_se3, qup1_se2, ddr_pxi3, _, _, _, _, _, _, _),
+ [47] = PINGROUP(47, qup1_se3, uim0_present, dp_hot, ddr_pxi3, _, _, _, _, _, _),
+ [48] = PINGROUP(48, qup1_se4, ibi_i3c, _, _, _, _, _, _, _, _),
+ [49] = PINGROUP(49, qup1_se4, ibi_i3c, _, _, _, _, _, _, _, _),
+ [50] = PINGROUP(50, qup1_se4, aoss_cti, _, _, _, _, _, _, _, _),
+ [51] = PINGROUP(51, qup1_se4, aoss_cti, ddr_pxi2, _, _, _, _, _, _, _),
+ [52] = PINGROUP(52, qup1_se5, _, _, _, _, _, _, _, _, _),
+ [53] = PINGROUP(53, qup1_se5, _, _, _, _, _, _, _, _, _),
+ [54] = PINGROUP(54, qup1_se5, usb_phy, _, _, _, _, _, _, _, _),
+ [55] = PINGROUP(55, qup1_se5, _, _, _, _, _, _, _, _, _),
+ [56] = PINGROUP(56, qup1_se6, ibi_i3c, qspi2, sdc42, _, _, _, _, _, _),
+ [57] = PINGROUP(57, qup1_se6, ibi_i3c, qspi3, sdc43, _, _, _, _, _, _),
+ [58] = PINGROUP(58, qup1_se6, qspi_cs, tb_trig_sdc4, tsense_pwm1, tsense_pwm2, tsense_pwm3, _, _, _, _),
+ [59] = PINGROUP(59, qup1_se6, _, qspi_cs, sdc4_cmd, _, _, _, _, _, _),
+ [60] = PINGROUP(60, qup1_se7, aoss_cti, vsense_trigger_mirnat, _, _, _, _, _, _, _),
+ [61] = PINGROUP(61, qup1_se7, aoss_cti, _, _, _, _, _, _, _, _),
+ [62] = PINGROUP(62, qup1_se7, ddr_pxi2, _, _, _, _, _, _, _, _),
+ [63] = PINGROUP(63, qup1_se7, _, _, _, _, _, _, _, _, _),
+ [64] = PINGROUP(64, i2chub0_se0, _, _, _, _, _, _, _, _, _),
+ [65] = PINGROUP(65, i2chub0_se0, _, _, _, _, _, _, _, _, _),
+ [66] = PINGROUP(66, i2chub0_se1, _, _, _, _, _, _, _, _, _),
+ [67] = PINGROUP(67, i2chub0_se1, _, _, _, _, _, _, _, _, _),
+ [68] = PINGROUP(68, i2chub0_se2, pll_bist_sync, _, _, _, _, _, _, _, _),
+ [69] = PINGROUP(69, i2chub0_se2, _, _, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, i2chub0_se3, _, _, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, i2chub0_se3, _, atest_usb, _, _, _, _, _, _, _),
+ [72] = PINGROUP(72, i2chub0_se4, _, atest_usb, _, _, _, _, _, _, _),
+ [73] = PINGROUP(73, i2chub0_se4, jitter_bist, _, _, _, _, _, _, _, _),
+ [74] = PINGROUP(74, i2chub0_se5, atest_usb, _, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, i2chub0_se5, ddr_pxi0, _, _, _, _, _, _, _, _),
+ [76] = PINGROUP(76, i2chub0_se6, ddr_pxi0, uim1_present, _, _, _, _, _, _, _),
+ [77] = PINGROUP(77, i2chub0_se6, _, _, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, i2chub0_se7, qdss_cti, _, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, i2chub0_se7, qdss_cti, _, _, _, _, _, _, _, _),
+ [80] = PINGROUP(80, i2chub0_se9, _, _, _, _, _, _, _, _, _),
+ [81] = PINGROUP(81, i2chub0_se9, _, _, _, _, _, _, _, _, _),
+ [82] = PINGROUP(82, qdss_cti, _, _, _, _, _, _, _, _, _),
+ [83] = PINGROUP(83, qdss_cti, _, _, _, _, _, _, _, _, _),
+ [84] = PINGROUP(84, _, _, _, _, _, _, _, _, _, _),
+ [85] = PINGROUP(85, _, _, _, _, _, _, _, _, _, _),
+ [86] = PINGROUP(86, mdp_vsync, mdp_vsync0_out, mdp_vsync1_out, gcc_gp1, _, _, _, _, _, _),
+ [87] = PINGROUP(87, mdp_vsync, mdp_vsync2_out, mdp_vsync3_out, gcc_gp2, _, _, _, _, _, _),
+ [88] = PINGROUP(88, mdp_vsync_e, gcc_gp3, _, _, _, _, _, _, _, _),
+ [89] = PINGROUP(89, usb1_hs, gnss_adc0, _, _, _, _, _, _, _, _),
+ [90] = PINGROUP(90, gnss_adc1, _, _, _, _, _, _, _, _, _),
+ [91] = PINGROUP(91, _, gnss_adc0, _, _, _, _, _, _, _, _),
+ [92] = PINGROUP(92, dbg_out_clk, gnss_adc1, _, _, _, _, _, _, _, _),
+ [93] = PINGROUP(93, sd_write_protect, _, _, _, _, _, _, _, _, _),
+ [94] = PINGROUP(94, cmu_rng, phase_flag, tmess_prng0, _, _, _, _, _, _, _),
+ [95] = PINGROUP(95, pcie0_clk_req_n, cmu_rng, phase_flag, tmess_prng1, _, _, _, _, _, _),
+ [96] = PINGROUP(96, cmu_rng, phase_flag, tmess_prng2, _, _, _, _, _, _, _),
+ [97] = PINGROUP(97, _, _, _, _, _, _, _, _, _, _),
+ [98] = PINGROUP(98, pcie1_clk_req_n, _, _, _, _, _, _, _, _, _),
+ [99] = PINGROUP(99, _, _, _, _, _, _, _, _, _, _),
+ [100] = PINGROUP(100, cam_mclk, qdss_gpio, _, _, _, _, _, _, _, _),
+ [101] = PINGROUP(101, cam_mclk, qdss_gpio, _, _, _, _, _, _, _, _),
+ [102] = PINGROUP(102, cam_aon_mclk2, qdss_gpio, _, _, _, _, _, _, _, _),
+ [103] = PINGROUP(103, cam_mclk, qdss_gpio, _, _, _, _, _, _, _, _),
+ [104] = PINGROUP(104, cam_aon_mclk4, qdss_gpio, _, _, _, _, _, _, _, _),
+ [105] = PINGROUP(105, cam_mclk, qdss_gpio, _, _, _, _, _, _, _, _),
+ [106] = PINGROUP(106, cam_mclk, pll_clk_aux, _, _, _, _, _, _, _, _),
+ [107] = PINGROUP(107, _, _, _, _, _, _, _, _, _, _),
+ [108] = PINGROUP(108, cam_mclk, _, _, _, _, _, _, _, _, _),
+ [109] = PINGROUP(109, cci_timer, phase_flag, tmess_prng3, _, _, _, _, _, _, _),
+ [110] = PINGROUP(110, cci_timer, _, _, _, _, _, _, _, _, _),
+ [111] = PINGROUP(111, cci_timer, phase_flag, _, _, _, _, _, _, _, _),
+ [112] = PINGROUP(112, cci_i2c_sda, cmu_rng, phase_flag, _, _, _, _, _, _, _),
+ [113] = PINGROUP(113, cci_i2c_sda, phase_flag, _, qdss_gpio, _, _, _, _, _, _),
+ [114] = PINGROUP(114, cci_i2c_scl, phase_flag, _, qdss_gpio, _, _, _, _, _, _),
+ [115] = PINGROUP(115, cci_i2c_sda, phase_flag, _, qdss_gpio, _, _, _, _, _, _),
+ [116] = PINGROUP(116, cci_i2c_scl, phase_flag, _, qdss_gpio, _, _, _, _, _, _),
+ [117] = PINGROUP(117, cci_i2c_sda, phase_flag, _, qdss_gpio, _, _, _, _, _, _),
+ [118] = PINGROUP(118, cci_i2c_scl, phase_flag, _, qdss_gpio, _, _, _, _, _, _),
+ [119] = PINGROUP(119, cci_i2c_sda, phase_flag, _, _, _, _, _, _, _, _),
+ [120] = PINGROUP(120, cci_i2c_scl, phase_flag, _, _, _, _, _, _, _, _),
+ [121] = PINGROUP(121, i2s1_sck, _, _, _, _, _, _, _, _, _),
+ [122] = PINGROUP(122, i2s1_data0, cmu_rng, _, _, _, _, _, _, _, _),
+ [123] = PINGROUP(123, i2s1_ws, _, _, _, _, _, _, _, _, _),
+ [124] = PINGROUP(124, i2s1_data1, audio_ext_mclk1, audio_ref_clk, _, _, _, _, _, _, _),
+ [125] = PINGROUP(125, audio_ext_mclk0, _, _, _, _, _, _, _, _, _),
+ [126] = PINGROUP(126, i2s0_sck, _, _, _, _, _, _, _, _, _),
+ [127] = PINGROUP(127, i2s0_data0, cmu_rng, _, _, _, _, _, _, _, _),
+ [128] = PINGROUP(128, i2s0_data1, cmu_rng, _, _, _, _, _, _, _, _),
+ [129] = PINGROUP(129, i2s0_ws, cmu_rng, _, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, uim0_data, atest_usb, atest_char, _, _, _, _, _, _, _),
+ [131] = PINGROUP(131, uim0_clk, atest_usb, atest_char, _, _, _, _, _, _, _),
+ [132] = PINGROUP(132, uim0_reset, atest_char, _, _, _, _, _, _, _, _),
+ [133] = PINGROUP(133, mdp_vsync, atest_char, _, _, _, _, _, _, _, _),
+ [134] = PINGROUP(134, uim1_data, do_not, qspi0, sdc40, gcc_gp1, _, _, _, _, _),
+ [135] = PINGROUP(135, uim1_clk, do_not, qspi_clk, sdc4_clk, gcc_gp2, _, _, _, _, _),
+ [136] = PINGROUP(136, uim1_reset, do_not, qspi1, sdc41, gcc_gp3, _, _, _, _, _),
+ [137] = PINGROUP(137, mdp_vsync, atest_char, _, _, _, _, _, _, _, _),
+ [138] = PINGROUP(138, _, _, _, _, _, _, _, _, _, _),
+ [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _, _),
+ [140] = PINGROUP(140, _, _, qdss_gpio, _, _, _, _, _, _, _),
+ [141] = PINGROUP(141, _, _, qdss_gpio, _, _, _, _, _, _, _),
+ [142] = PINGROUP(142, _, _, qdss_gpio, _, _, _, _, _, _, _),
+ [143] = PINGROUP(143, _, _, qdss_gpio, _, _, _, _, _, _, _),
+ [144] = PINGROUP(144, _, qdss_gpio, _, _, _, _, _, _, _, _),
+ [145] = PINGROUP(145, _, qdss_gpio, _, _, _, _, _, _, _, _),
+ [146] = PINGROUP(146, _, qdss_gpio, _, _, _, _, _, _, _, _),
+ [147] = PINGROUP(147, _, qdss_gpio, _, _, _, _, _, _, _, _),
+ [148] = PINGROUP(148, coex_uart1_rx, qdss_gpio, _, _, _, _, _, _, _, _),
+ [149] = PINGROUP(149, coex_uart1_tx, qdss_gpio, _, _, _, _, _, _, _, _),
+ [150] = PINGROUP(150, _, vfr_0, coex_uart2_rx, qdss_gpio, _, _, _, _, _, _),
+ [151] = PINGROUP(151, _, coex_uart2_tx, qdss_gpio, _, _, _, _, _, _, _),
+ [152] = PINGROUP(152, nav_gpio2, _, qdss_gpio, _, _, _, _, _, _, _),
+ [153] = PINGROUP(153, cci_i2c_scl, phase_flag, _, qdss_gpio, _, _, _, _, _, _),
+ [154] = PINGROUP(154, nav_gpio0, nav_gpio3, qdss_gpio, _, _, _, _, _, _, _),
+ [155] = PINGROUP(155, nav_gpio1, vfr_1, qdss_gpio, _, _, _, _, _, _, _),
+ [156] = PINGROUP(156, qlink_little_request, qdss_gpio, _, _, _, _, _, _, _, _),
+ [157] = PINGROUP(157, qlink_little_enable, qdss_gpio, _, _, _, _, _, _, _, _),
+ [158] = PINGROUP(158, qlink_wmss, qdss_gpio, _, _, _, _, _, _, _, _),
+ [159] = PINGROUP(159, qlink_big_request, qdss_cti, _, _, _, _, _, _, _, _),
+ [160] = PINGROUP(160, qlink_big_enable, _, _, _, _, _, _, _, _, _),
+ [161] = PINGROUP(161, _, _, _, _, _, _, _, _, _, _),
+ [162] = PINGROUP(162, qdss_cti, _, _, _, _, _, _, _, _, _),
+ [163] = PINGROUP(163, cci_async_in, phase_flag, _, _, _, _, _, _, _, _),
+ [164] = PINGROUP(164, cci_async_in, phase_flag, _, _, _, _, _, _, _, _),
+ [165] = PINGROUP(165, _, _, _, _, _, _, _, _, _, egpio),
+ [166] = PINGROUP(166, _, _, _, _, _, _, _, _, _, egpio),
+ [167] = PINGROUP(167, _, _, _, _, _, _, _, _, _, egpio),
+ [168] = PINGROUP(168, _, _, _, _, _, _, _, _, _, egpio),
+ [169] = PINGROUP(169, _, _, _, _, _, _, _, _, _, egpio),
+ [170] = PINGROUP(170, _, _, _, _, _, _, _, _, _, egpio),
+ [171] = PINGROUP(171, _, _, _, _, _, _, _, _, _, egpio),
+ [172] = PINGROUP(172, _, _, _, _, _, _, _, _, _, egpio),
+ [173] = PINGROUP(173, _, _, _, _, _, _, _, _, _, egpio),
+ [174] = PINGROUP(174, _, _, _, _, _, _, _, _, _, egpio),
+ [175] = PINGROUP(175, _, _, _, _, _, _, _, _, _, egpio),
+ [176] = PINGROUP(176, _, _, _, _, _, _, _, _, _, egpio),
+ [177] = PINGROUP(177, _, _, _, _, _, _, _, _, _, egpio),
+ [178] = PINGROUP(178, _, _, _, _, _, _, _, _, _, egpio),
+ [179] = PINGROUP(179, _, _, _, _, _, _, _, _, _, egpio),
+ [180] = PINGROUP(180, _, _, _, _, _, _, _, _, _, egpio),
+ [181] = PINGROUP(181, prng_rosc3, _, _, _, _, _, _, _, _, egpio),
+ [182] = PINGROUP(182, prng_rosc2, _, _, _, _, _, _, _, _, egpio),
+ [183] = PINGROUP(183, prng_rosc1, _, _, _, _, _, _, _, _, egpio),
+ [184] = PINGROUP(184, _, _, _, _, _, _, _, _, _, egpio),
+ [185] = PINGROUP(185, _, _, _, _, _, _, _, _, _, egpio),
+ [186] = PINGROUP(186, prng_rosc0, _, _, _, _, _, _, _, _, egpio),
+ [187] = PINGROUP(187, cri_trng, _, _, _, _, _, _, _, _, egpio),
+ [188] = PINGROUP(188, _, _, _, _, _, _, _, _, _, egpio),
+ [189] = PINGROUP(189, _, _, _, _, _, _, _, _, _, egpio),
+ [190] = PINGROUP(190, _, _, _, _, _, _, _, _, _, egpio),
+ [191] = PINGROUP(191, _, _, _, _, _, _, _, _, _, egpio),
+ [192] = PINGROUP(192, _, _, _, _, _, _, _, _, _, egpio),
+ [193] = PINGROUP(193, _, _, _, _, _, _, _, _, _, egpio),
+ [194] = PINGROUP(194, _, _, _, _, _, _, _, _, _, egpio),
+ [195] = PINGROUP(195, _, _, _, _, _, _, _, _, _, egpio),
+ [196] = PINGROUP(196, _, _, _, _, _, _, _, _, _, egpio),
+ [197] = PINGROUP(197, _, _, _, _, _, _, _, _, _, egpio),
+ [198] = PINGROUP(198, _, _, _, _, _, _, _, _, _, egpio),
+ [199] = PINGROUP(199, _, _, _, _, _, _, _, _, _, egpio),
+ [200] = PINGROUP(200, _, _, _, _, _, _, _, _, _, egpio),
+ [201] = PINGROUP(201, _, _, _, _, _, _, _, _, _, egpio),
+ [202] = PINGROUP(202, _, _, _, _, _, _, _, _, _, egpio),
+ [203] = PINGROUP(203, _, _, _, _, _, _, _, _, _, egpio),
+ [204] = PINGROUP(204, _, _, _, _, _, _, _, _, _, egpio),
+ [205] = PINGROUP(205, _, _, _, _, _, _, _, _, _, egpio),
+ [206] = PINGROUP(206, i2chub0_se8, _, _, _, _, _, _, _, _, egpio),
+ [207] = PINGROUP(207, i2chub0_se8, _, _, _, _, _, _, _, _, egpio),
+ [208] = PINGROUP(208, _, _, _, _, _, _, _, _, _, egpio),
+ [209] = PINGROUP(209, _, _, _, _, _, _, _, _, _, egpio),
+ [210] = UFS_RESET(ufs_reset, 0xde004, 0xdf000),
+ [211] = SDC_QDSD_PINGROUP(sdc2_clk, 0xd6000, 14, 6),
+ [212] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xd6000, 11, 3),
+ [213] = SDC_QDSD_PINGROUP(sdc2_data, 0xd6000, 9, 0),
+};
+
+static const struct msm_gpio_wakeirq_map sm8650_pdc_map[] = {
+ { 0, 94 }, { 3, 105 }, { 4, 78 }, { 7, 67 }, { 8, 64 },
+ { 11, 121 }, { 12, 71 }, { 15, 82 }, { 18, 75 }, { 19, 63 },
+ { 20, 114 }, { 23, 84 }, { 27, 61 }, { 29, 112 }, { 31, 113 },
+ { 32, 66 }, { 35, 52 }, { 36, 123 }, { 39, 56 }, { 43, 59 },
+ { 46, 79 }, { 47, 124 }, { 48, 125 }, { 51, 93 }, { 54, 60 },
+ { 55, 104 }, { 56, 72 }, { 57, 77 }, { 59, 51 }, { 63, 85 },
+ { 64, 107 }, { 65, 108 }, { 66, 109 }, { 67, 83 }, { 68, 110 },
+ { 69, 111 }, { 75, 96 }, { 76, 97 }, { 77, 98 }, { 80, 89 },
+ { 81, 90 }, { 84, 106 }, { 85, 100 }, { 86, 87 }, { 87, 88 },
+ { 88, 65 }, { 90, 92 }, { 92, 99 }, { 95, 118 }, { 96, 119 },
+ { 98, 101 }, { 99, 62 }, { 112, 120 }, { 133, 80 }, { 136, 69 },
+ { 137, 81 }, { 148, 57 }, { 150, 58 }, { 152, 127 }, { 153, 74 },
+ { 154, 126 }, { 155, 73 }, { 156, 128 }, { 159, 129 }, { 162, 86 },
+ { 163, 122 }, { 166, 139 }, { 169, 140 }, { 171, 141 }, { 172, 142 },
+ { 174, 102 }, { 176, 143 }, { 177, 55 }, { 181, 144 }, { 182, 145 },
+ { 185, 146 }, { 187, 95 }, { 188, 130 }, { 190, 131 }, { 191, 132 },
+ { 192, 133 }, { 193, 134 }, { 195, 68 }, { 196, 135 }, { 197, 136 },
+ { 198, 54 }, { 199, 103 }, { 200, 53 }, { 201, 137 }, { 202, 70 },
+ { 203, 138 }, { 204, 76 }, { 205, 91 },
+};
+
+static const struct msm_pinctrl_soc_data sm8650_tlmm = {
+ .pins = sm8650_pins,
+ .npins = ARRAY_SIZE(sm8650_pins),
+ .functions = sm8650_functions,
+ .nfunctions = ARRAY_SIZE(sm8650_functions),
+ .groups = sm8650_groups,
+ .ngroups = ARRAY_SIZE(sm8650_groups),
+ .ngpios = 211,
+ .wakeirq_map = sm8650_pdc_map,
+ .nwakeirq_map = ARRAY_SIZE(sm8650_pdc_map),
+ .egpio_func = 10,
+};
+
+static int sm8650_tlmm_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &sm8650_tlmm);
+}
+
+static const struct of_device_id sm8650_tlmm_of_match[] = {
+ { .compatible = "qcom,sm8650-tlmm", },
+ {},
+};
+
+static struct platform_driver sm8650_tlmm_driver = {
+ .driver = {
+ .name = "sm8650-tlmm",
+ .of_match_table = sm8650_tlmm_of_match,
+ },
+ .probe = sm8650_tlmm_probe,
+ .remove_new = msm_pinctrl_remove,
+};
+
+static int __init sm8650_tlmm_init(void)
+{
+ return platform_driver_register(&sm8650_tlmm_driver);
+}
+arch_initcall(sm8650_tlmm_init);
+
+static void __exit sm8650_tlmm_exit(void)
+{
+ platform_driver_unregister(&sm8650_tlmm_driver);
+}
+module_exit(sm8650_tlmm_exit);
+
+MODULE_DESCRIPTION("QTI SM8650 TLMM driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, sm8650_tlmm_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-x1e80100.c b/drivers/pinctrl/qcom/pinctrl-x1e80100.c
new file mode 100644
index 000000000000..e30e93840357
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-x1e80100.c
@@ -0,0 +1,1876 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-msm.h"
+
+#define REG_SIZE 0x1000
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .grp = PINCTRL_PINGROUP("gpio" #id, \
+ gpio##id##_pins, \
+ ARRAY_SIZE(gpio##id##_pins)), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .intr_target_reg = 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .i2c_pull_bit = 13, \
+ .egpio_enable = 12, \
+ .egpio_present = 11, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .grp = PINCTRL_PINGROUP(#pg_name, \
+ pg_name##_pins, \
+ ARRAY_SIZE(pg_name##_pins)), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define UFS_RESET(pg_name, offset) \
+ { \
+ .grp = PINCTRL_PINGROUP(#pg_name, \
+ pg_name##_pins, \
+ ARRAY_SIZE(pg_name##_pins)), \
+ .ctl_reg = offset, \
+ .io_reg = offset + 0x4, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+static const struct pinctrl_pin_desc x1e80100_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "GPIO_136"),
+ PINCTRL_PIN(137, "GPIO_137"),
+ PINCTRL_PIN(138, "GPIO_138"),
+ PINCTRL_PIN(139, "GPIO_139"),
+ PINCTRL_PIN(140, "GPIO_140"),
+ PINCTRL_PIN(141, "GPIO_141"),
+ PINCTRL_PIN(142, "GPIO_142"),
+ PINCTRL_PIN(143, "GPIO_143"),
+ PINCTRL_PIN(144, "GPIO_144"),
+ PINCTRL_PIN(145, "GPIO_145"),
+ PINCTRL_PIN(146, "GPIO_146"),
+ PINCTRL_PIN(147, "GPIO_147"),
+ PINCTRL_PIN(148, "GPIO_148"),
+ PINCTRL_PIN(149, "GPIO_149"),
+ PINCTRL_PIN(150, "GPIO_150"),
+ PINCTRL_PIN(151, "GPIO_151"),
+ PINCTRL_PIN(152, "GPIO_152"),
+ PINCTRL_PIN(153, "GPIO_153"),
+ PINCTRL_PIN(154, "GPIO_154"),
+ PINCTRL_PIN(155, "GPIO_155"),
+ PINCTRL_PIN(156, "GPIO_156"),
+ PINCTRL_PIN(157, "GPIO_157"),
+ PINCTRL_PIN(158, "GPIO_158"),
+ PINCTRL_PIN(159, "GPIO_159"),
+ PINCTRL_PIN(160, "GPIO_160"),
+ PINCTRL_PIN(161, "GPIO_161"),
+ PINCTRL_PIN(162, "GPIO_162"),
+ PINCTRL_PIN(163, "GPIO_163"),
+ PINCTRL_PIN(164, "GPIO_164"),
+ PINCTRL_PIN(165, "GPIO_165"),
+ PINCTRL_PIN(166, "GPIO_166"),
+ PINCTRL_PIN(167, "GPIO_167"),
+ PINCTRL_PIN(168, "GPIO_168"),
+ PINCTRL_PIN(169, "GPIO_169"),
+ PINCTRL_PIN(170, "GPIO_170"),
+ PINCTRL_PIN(171, "GPIO_171"),
+ PINCTRL_PIN(172, "GPIO_172"),
+ PINCTRL_PIN(173, "GPIO_173"),
+ PINCTRL_PIN(174, "GPIO_174"),
+ PINCTRL_PIN(175, "GPIO_175"),
+ PINCTRL_PIN(176, "GPIO_176"),
+ PINCTRL_PIN(177, "GPIO_177"),
+ PINCTRL_PIN(178, "GPIO_178"),
+ PINCTRL_PIN(179, "GPIO_179"),
+ PINCTRL_PIN(180, "GPIO_180"),
+ PINCTRL_PIN(181, "GPIO_181"),
+ PINCTRL_PIN(182, "GPIO_182"),
+ PINCTRL_PIN(183, "GPIO_183"),
+ PINCTRL_PIN(184, "GPIO_184"),
+ PINCTRL_PIN(185, "GPIO_185"),
+ PINCTRL_PIN(186, "GPIO_186"),
+ PINCTRL_PIN(187, "GPIO_187"),
+ PINCTRL_PIN(188, "GPIO_188"),
+ PINCTRL_PIN(189, "GPIO_189"),
+ PINCTRL_PIN(190, "GPIO_190"),
+ PINCTRL_PIN(191, "GPIO_191"),
+ PINCTRL_PIN(192, "GPIO_192"),
+ PINCTRL_PIN(193, "GPIO_193"),
+ PINCTRL_PIN(194, "GPIO_194"),
+ PINCTRL_PIN(195, "GPIO_195"),
+ PINCTRL_PIN(196, "GPIO_196"),
+ PINCTRL_PIN(197, "GPIO_197"),
+ PINCTRL_PIN(198, "GPIO_198"),
+ PINCTRL_PIN(199, "GPIO_199"),
+ PINCTRL_PIN(200, "GPIO_200"),
+ PINCTRL_PIN(201, "GPIO_201"),
+ PINCTRL_PIN(202, "GPIO_202"),
+ PINCTRL_PIN(203, "GPIO_203"),
+ PINCTRL_PIN(204, "GPIO_204"),
+ PINCTRL_PIN(205, "GPIO_205"),
+ PINCTRL_PIN(206, "GPIO_206"),
+ PINCTRL_PIN(207, "GPIO_207"),
+ PINCTRL_PIN(208, "GPIO_208"),
+ PINCTRL_PIN(209, "GPIO_209"),
+ PINCTRL_PIN(210, "GPIO_210"),
+ PINCTRL_PIN(211, "GPIO_211"),
+ PINCTRL_PIN(212, "GPIO_212"),
+ PINCTRL_PIN(213, "GPIO_213"),
+ PINCTRL_PIN(214, "GPIO_214"),
+ PINCTRL_PIN(215, "GPIO_215"),
+ PINCTRL_PIN(216, "GPIO_216"),
+ PINCTRL_PIN(217, "GPIO_217"),
+ PINCTRL_PIN(218, "GPIO_218"),
+ PINCTRL_PIN(219, "GPIO_219"),
+ PINCTRL_PIN(220, "GPIO_220"),
+ PINCTRL_PIN(221, "GPIO_221"),
+ PINCTRL_PIN(222, "GPIO_222"),
+ PINCTRL_PIN(223, "GPIO_223"),
+ PINCTRL_PIN(224, "GPIO_224"),
+ PINCTRL_PIN(225, "GPIO_225"),
+ PINCTRL_PIN(226, "GPIO_226"),
+ PINCTRL_PIN(227, "GPIO_227"),
+ PINCTRL_PIN(228, "GPIO_228"),
+ PINCTRL_PIN(229, "GPIO_229"),
+ PINCTRL_PIN(230, "GPIO_230"),
+ PINCTRL_PIN(231, "GPIO_231"),
+ PINCTRL_PIN(232, "GPIO_232"),
+ PINCTRL_PIN(233, "GPIO_233"),
+ PINCTRL_PIN(234, "GPIO_234"),
+ PINCTRL_PIN(235, "GPIO_235"),
+ PINCTRL_PIN(236, "GPIO_236"),
+ PINCTRL_PIN(237, "GPIO_237"),
+ PINCTRL_PIN(238, "UFS_RESET"),
+ PINCTRL_PIN(239, "SDC2_CLK"),
+ PINCTRL_PIN(240, "SDC2_CMD"),
+ PINCTRL_PIN(241, "SDC2_DATA"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+DECLARE_MSM_GPIO_PINS(150);
+DECLARE_MSM_GPIO_PINS(151);
+DECLARE_MSM_GPIO_PINS(152);
+DECLARE_MSM_GPIO_PINS(153);
+DECLARE_MSM_GPIO_PINS(154);
+DECLARE_MSM_GPIO_PINS(155);
+DECLARE_MSM_GPIO_PINS(156);
+DECLARE_MSM_GPIO_PINS(157);
+DECLARE_MSM_GPIO_PINS(158);
+DECLARE_MSM_GPIO_PINS(159);
+DECLARE_MSM_GPIO_PINS(160);
+DECLARE_MSM_GPIO_PINS(161);
+DECLARE_MSM_GPIO_PINS(162);
+DECLARE_MSM_GPIO_PINS(163);
+DECLARE_MSM_GPIO_PINS(164);
+DECLARE_MSM_GPIO_PINS(165);
+DECLARE_MSM_GPIO_PINS(166);
+DECLARE_MSM_GPIO_PINS(167);
+DECLARE_MSM_GPIO_PINS(168);
+DECLARE_MSM_GPIO_PINS(169);
+DECLARE_MSM_GPIO_PINS(170);
+DECLARE_MSM_GPIO_PINS(171);
+DECLARE_MSM_GPIO_PINS(172);
+DECLARE_MSM_GPIO_PINS(173);
+DECLARE_MSM_GPIO_PINS(174);
+DECLARE_MSM_GPIO_PINS(175);
+DECLARE_MSM_GPIO_PINS(176);
+DECLARE_MSM_GPIO_PINS(177);
+DECLARE_MSM_GPIO_PINS(178);
+DECLARE_MSM_GPIO_PINS(179);
+DECLARE_MSM_GPIO_PINS(180);
+DECLARE_MSM_GPIO_PINS(181);
+DECLARE_MSM_GPIO_PINS(182);
+DECLARE_MSM_GPIO_PINS(183);
+DECLARE_MSM_GPIO_PINS(184);
+DECLARE_MSM_GPIO_PINS(185);
+DECLARE_MSM_GPIO_PINS(186);
+DECLARE_MSM_GPIO_PINS(187);
+DECLARE_MSM_GPIO_PINS(188);
+DECLARE_MSM_GPIO_PINS(189);
+DECLARE_MSM_GPIO_PINS(190);
+DECLARE_MSM_GPIO_PINS(191);
+DECLARE_MSM_GPIO_PINS(192);
+DECLARE_MSM_GPIO_PINS(193);
+DECLARE_MSM_GPIO_PINS(194);
+DECLARE_MSM_GPIO_PINS(195);
+DECLARE_MSM_GPIO_PINS(196);
+DECLARE_MSM_GPIO_PINS(197);
+DECLARE_MSM_GPIO_PINS(198);
+DECLARE_MSM_GPIO_PINS(199);
+DECLARE_MSM_GPIO_PINS(200);
+DECLARE_MSM_GPIO_PINS(201);
+DECLARE_MSM_GPIO_PINS(202);
+DECLARE_MSM_GPIO_PINS(203);
+DECLARE_MSM_GPIO_PINS(204);
+DECLARE_MSM_GPIO_PINS(205);
+DECLARE_MSM_GPIO_PINS(206);
+DECLARE_MSM_GPIO_PINS(207);
+DECLARE_MSM_GPIO_PINS(208);
+DECLARE_MSM_GPIO_PINS(209);
+DECLARE_MSM_GPIO_PINS(210);
+DECLARE_MSM_GPIO_PINS(211);
+DECLARE_MSM_GPIO_PINS(212);
+DECLARE_MSM_GPIO_PINS(213);
+DECLARE_MSM_GPIO_PINS(214);
+DECLARE_MSM_GPIO_PINS(215);
+DECLARE_MSM_GPIO_PINS(216);
+DECLARE_MSM_GPIO_PINS(217);
+DECLARE_MSM_GPIO_PINS(218);
+DECLARE_MSM_GPIO_PINS(219);
+DECLARE_MSM_GPIO_PINS(220);
+DECLARE_MSM_GPIO_PINS(221);
+DECLARE_MSM_GPIO_PINS(222);
+DECLARE_MSM_GPIO_PINS(223);
+DECLARE_MSM_GPIO_PINS(224);
+DECLARE_MSM_GPIO_PINS(225);
+DECLARE_MSM_GPIO_PINS(226);
+DECLARE_MSM_GPIO_PINS(227);
+DECLARE_MSM_GPIO_PINS(228);
+DECLARE_MSM_GPIO_PINS(229);
+DECLARE_MSM_GPIO_PINS(230);
+DECLARE_MSM_GPIO_PINS(231);
+DECLARE_MSM_GPIO_PINS(232);
+DECLARE_MSM_GPIO_PINS(233);
+DECLARE_MSM_GPIO_PINS(234);
+DECLARE_MSM_GPIO_PINS(235);
+DECLARE_MSM_GPIO_PINS(236);
+DECLARE_MSM_GPIO_PINS(237);
+
+static const unsigned int ufs_reset_pins[] = { 238 };
+static const unsigned int sdc2_clk_pins[] = { 239 };
+static const unsigned int sdc2_cmd_pins[] = { 240 };
+static const unsigned int sdc2_data_pins[] = { 241 };
+
+enum x1e80100_functions {
+ msm_mux_gpio,
+ msm_mux_RESOUT_GPIO,
+ msm_mux_aon_cci,
+ msm_mux_aoss_cti,
+ msm_mux_atest_char,
+ msm_mux_atest_char0,
+ msm_mux_atest_char1,
+ msm_mux_atest_char2,
+ msm_mux_atest_char3,
+ msm_mux_atest_usb,
+ msm_mux_audio_ext,
+ msm_mux_audio_ref,
+ msm_mux_cam_aon,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async,
+ msm_mux_cci_i2c,
+ msm_mux_cci_timer0,
+ msm_mux_cci_timer1,
+ msm_mux_cci_timer2,
+ msm_mux_cci_timer3,
+ msm_mux_cci_timer4,
+ msm_mux_cmu_rng0,
+ msm_mux_cmu_rng1,
+ msm_mux_cmu_rng2,
+ msm_mux_cmu_rng3,
+ msm_mux_cri_trng,
+ msm_mux_dbg_out,
+ msm_mux_ddr_bist,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_pxi1,
+ msm_mux_ddr_pxi2,
+ msm_mux_ddr_pxi3,
+ msm_mux_ddr_pxi4,
+ msm_mux_ddr_pxi5,
+ msm_mux_ddr_pxi6,
+ msm_mux_ddr_pxi7,
+ msm_mux_edp0_hot,
+ msm_mux_edp0_lcd,
+ msm_mux_edp1_hot,
+ msm_mux_edp1_lcd,
+ msm_mux_eusb0_ac,
+ msm_mux_eusb1_ac,
+ msm_mux_eusb2_ac,
+ msm_mux_eusb3_ac,
+ msm_mux_eusb5_ac,
+ msm_mux_eusb6_ac,
+ msm_mux_gcc_gp1,
+ msm_mux_gcc_gp2,
+ msm_mux_gcc_gp3,
+ msm_mux_i2s0_data0,
+ msm_mux_i2s0_data1,
+ msm_mux_i2s0_sck,
+ msm_mux_i2s0_ws,
+ msm_mux_i2s1_data0,
+ msm_mux_i2s1_data1,
+ msm_mux_i2s1_sck,
+ msm_mux_i2s1_ws,
+ msm_mux_ibi_i3c,
+ msm_mux_jitter_bist,
+ msm_mux_mdp_vsync0,
+ msm_mux_mdp_vsync1,
+ msm_mux_mdp_vsync2,
+ msm_mux_mdp_vsync3,
+ msm_mux_mdp_vsync4,
+ msm_mux_mdp_vsync5,
+ msm_mux_mdp_vsync6,
+ msm_mux_mdp_vsync7,
+ msm_mux_mdp_vsync8,
+ msm_mux_pcie3_clk,
+ msm_mux_pcie4_clk,
+ msm_mux_pcie5_clk,
+ msm_mux_pcie6a_clk,
+ msm_mux_pcie6b_clk,
+ msm_mux_phase_flag,
+ msm_mux_pll_bist,
+ msm_mux_pll_clk,
+ msm_mux_prng_rosc0,
+ msm_mux_prng_rosc1,
+ msm_mux_prng_rosc2,
+ msm_mux_prng_rosc3,
+ msm_mux_qdss_cti,
+ msm_mux_qdss_gpio,
+ msm_mux_qspi00,
+ msm_mux_qspi01,
+ msm_mux_qspi02,
+ msm_mux_qspi03,
+ msm_mux_qspi0_clk,
+ msm_mux_qspi0_cs0,
+ msm_mux_qspi0_cs1,
+ msm_mux_qup0_se0,
+ msm_mux_qup0_se1,
+ msm_mux_qup0_se2,
+ msm_mux_qup0_se3,
+ msm_mux_qup0_se4,
+ msm_mux_qup0_se5,
+ msm_mux_qup0_se6,
+ msm_mux_qup0_se7,
+ msm_mux_qup1_se0,
+ msm_mux_qup1_se1,
+ msm_mux_qup1_se2,
+ msm_mux_qup1_se3,
+ msm_mux_qup1_se4,
+ msm_mux_qup1_se5,
+ msm_mux_qup1_se6,
+ msm_mux_qup1_se7,
+ msm_mux_qup2_se0,
+ msm_mux_qup2_se1,
+ msm_mux_qup2_se2,
+ msm_mux_qup2_se3,
+ msm_mux_qup2_se4,
+ msm_mux_qup2_se5,
+ msm_mux_qup2_se6,
+ msm_mux_qup2_se7,
+ msm_mux_sd_write,
+ msm_mux_sdc4_clk,
+ msm_mux_sdc4_cmd,
+ msm_mux_sdc4_data0,
+ msm_mux_sdc4_data1,
+ msm_mux_sdc4_data2,
+ msm_mux_sdc4_data3,
+ msm_mux_sys_throttle,
+ msm_mux_tb_trig,
+ msm_mux_tgu_ch0,
+ msm_mux_tgu_ch1,
+ msm_mux_tgu_ch2,
+ msm_mux_tgu_ch3,
+ msm_mux_tgu_ch4,
+ msm_mux_tgu_ch5,
+ msm_mux_tgu_ch6,
+ msm_mux_tgu_ch7,
+ msm_mux_tmess_prng0,
+ msm_mux_tmess_prng1,
+ msm_mux_tmess_prng2,
+ msm_mux_tmess_prng3,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_tsense_pwm3,
+ msm_mux_tsense_pwm4,
+ msm_mux_usb0_dp,
+ msm_mux_usb0_phy,
+ msm_mux_usb0_sbrx,
+ msm_mux_usb0_sbtx,
+ msm_mux_usb1_dp,
+ msm_mux_usb1_phy,
+ msm_mux_usb1_sbrx,
+ msm_mux_usb1_sbtx,
+ msm_mux_usb2_dp,
+ msm_mux_usb2_phy,
+ msm_mux_usb2_sbrx,
+ msm_mux_usb2_sbtx,
+ msm_mux_vsense_trigger,
+ msm_mux__,
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+ "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+ "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+ "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+ "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+ "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+ "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
+ "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
+ "gpio147", "gpio148", "gpio149", "gpio150", "gpio151", "gpio152",
+ "gpio153", "gpio154", "gpio155", "gpio156", "gpio157", "gpio158",
+ "gpio159", "gpio160", "gpio161", "gpio162", "gpio163", "gpio164",
+ "gpio165", "gpio166", "gpio167", "gpio168", "gpio169", "gpio170",
+ "gpio171", "gpio172", "gpio173", "gpio174", "gpio175", "gpio176",
+ "gpio177", "gpio178", "gpio179", "gpio180", "gpio181", "gpio182",
+ "gpio183", "gpio184", "gpio185", "gpio186", "gpio187", "gpio188",
+ "gpio189", "gpio190", "gpio191", "gpio192", "gpio193", "gpio194",
+ "gpio195", "gpio196", "gpio197", "gpio198", "gpio199", "gpio200",
+ "gpio201", "gpio202", "gpio203", "gpio204", "gpio205", "gpio206",
+ "gpio207", "gpio208", "gpio209", "gpio210", "gpio211", "gpio212",
+ "gpio213", "gpio214", "gpio215", "gpio216", "gpio217", "gpio218",
+ "gpio219", "gpio220", "gpio221", "gpio222", "gpio223", "gpio224",
+ "gpio225", "gpio226", "gpio227", "gpio228", "gpio229", "gpio230",
+ "gpio231", "gpio232", "gpio233", "gpio234", "gpio235", "gpio236",
+ "gpio237",
+};
+
+static const char * const RESOUT_GPIO_groups[] = {
+ "gpio160",
+};
+
+static const char * const aon_cci_groups[] = {
+ "gpio235", "gpio236",
+};
+
+static const char * const aoss_cti_groups[] = {
+ "gpio60", "gpio61", "gpio62", "gpio63",
+};
+
+static const char * const atest_char_groups[] = {
+ "gpio181",
+};
+
+static const char * const atest_char0_groups[] = {
+ "gpio185",
+};
+
+static const char * const atest_char1_groups[] = {
+ "gpio184",
+};
+
+static const char * const atest_char2_groups[] = {
+ "gpio188",
+};
+
+static const char * const atest_char3_groups[] = {
+ "gpio182",
+};
+
+static const char * const atest_usb_groups[] = {
+ "gpio9", "gpio10", "gpio35", "gpio38", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48",
+ "gpio49", "gpio50", "gpio51", "gpio52", "gpio53", "gpio54",
+ "gpio58", "gpio59", "gpio65", "gpio66", "gpio67", "gpio72",
+ "gpio73", "gpio74", "gpio75", "gpio80", "gpio81", "gpio83",
+};
+
+static const char * const audio_ext_groups[] = {
+ "gpio134", "gpio142",
+};
+
+static const char * const audio_ref_groups[] = {
+ "gpio142",
+};
+
+static const char * const cam_aon_groups[] = {
+ "gpio100",
+};
+
+static const char * const cam_mclk_groups[] = {
+ "gpio96", "gpio97", "gpio98", "gpio99",
+};
+
+static const char * const cci_async_groups[] = {
+ "gpio111", "gpio112", "gpio113",
+};
+
+static const char * const cci_i2c_groups[] = {
+ "gpio101", "gpio102", "gpio103", "gpio104", "gpio105", "gpio106",
+};
+
+static const char * const cci_timer0_groups[] = {
+ "gpio109",
+};
+
+static const char * const cci_timer1_groups[] = {
+ "gpio110",
+};
+
+static const char * const cci_timer2_groups[] = {
+ "gpio111",
+};
+
+static const char * const cci_timer3_groups[] = {
+ "gpio112",
+};
+
+static const char * const cci_timer4_groups[] = {
+ "gpio113",
+};
+
+static const char * const cmu_rng0_groups[] = {
+ "gpio48",
+};
+
+static const char * const cmu_rng1_groups[] = {
+ "gpio47",
+};
+
+static const char * const cmu_rng2_groups[] = {
+ "gpio46",
+};
+
+static const char * const cmu_rng3_groups[] = {
+ "gpio45",
+};
+
+static const char * const cri_trng_groups[] = {
+ "gpio187",
+};
+
+static const char * const dbg_out_groups[] = {
+ "gpio51",
+};
+
+static const char * const ddr_bist_groups[] = {
+ "gpio54", "gpio55", "gpio56", "gpio57",
+};
+
+static const char * const ddr_pxi0_groups[] = {
+ "gpio9", "gpio38",
+};
+
+static const char * const ddr_pxi1_groups[] = {
+ "gpio10", "gpio41",
+};
+
+static const char * const ddr_pxi2_groups[] = {
+ "gpio42", "gpio43",
+};
+
+static const char * const ddr_pxi3_groups[] = {
+ "gpio44", "gpio45",
+};
+
+static const char * const ddr_pxi4_groups[] = {
+ "gpio46", "gpio47",
+};
+
+static const char * const ddr_pxi5_groups[] = {
+ "gpio48", "gpio49",
+};
+
+static const char * const ddr_pxi6_groups[] = {
+ "gpio50", "gpio51",
+};
+
+static const char * const ddr_pxi7_groups[] = {
+ "gpio52", "gpio53",
+};
+
+static const char * const edp0_hot_groups[] = {
+ "gpio119",
+};
+
+static const char * const edp0_lcd_groups[] = {
+ "gpio120",
+};
+
+static const char * const edp1_hot_groups[] = {
+ "gpio120",
+};
+
+static const char * const edp1_lcd_groups[] = {
+ "gpio115", "gpio119",
+};
+
+static const char * const eusb0_ac_groups[] = {
+ "gpio168",
+};
+
+static const char * const eusb1_ac_groups[] = {
+ "gpio177",
+};
+
+static const char * const eusb2_ac_groups[] = {
+ "gpio186",
+};
+
+static const char * const eusb3_ac_groups[] = {
+ "gpio169",
+};
+
+static const char * const eusb5_ac_groups[] = {
+ "gpio187",
+};
+
+static const char * const eusb6_ac_groups[] = {
+ "gpio178",
+};
+
+static const char * const gcc_gp1_groups[] = {
+ "gpio71", "gpio72",
+};
+
+static const char * const gcc_gp2_groups[] = {
+ "gpio64", "gpio73",
+};
+
+static const char * const gcc_gp3_groups[] = {
+ "gpio74", "gpio82",
+};
+
+static const char * const i2s0_data0_groups[] = {
+ "gpio136",
+};
+
+static const char * const i2s0_data1_groups[] = {
+ "gpio137",
+};
+
+static const char * const i2s0_sck_groups[] = {
+ "gpio135",
+};
+
+static const char * const i2s0_ws_groups[] = {
+ "gpio138",
+};
+
+static const char * const i2s1_data0_groups[] = {
+ "gpio140",
+};
+
+static const char * const i2s1_data1_groups[] = {
+ "gpio142",
+};
+
+static const char * const i2s1_sck_groups[] = {
+ "gpio139",
+};
+
+static const char * const i2s1_ws_groups[] = {
+ "gpio141",
+};
+
+static const char * const ibi_i3c_groups[] = {
+ "gpio0", "gpio1", "gpio32", "gpio33", "gpio36", "gpio37", "gpio68",
+ "gpio69",
+};
+
+static const char * const jitter_bist_groups[] = {
+ "gpio42",
+};
+
+static const char * const mdp_vsync0_groups[] = {
+ "gpio114",
+};
+
+static const char * const mdp_vsync1_groups[] = {
+ "gpio114",
+};
+
+static const char * const mdp_vsync2_groups[] = {
+ "gpio115",
+};
+
+static const char * const mdp_vsync3_groups[] = {
+ "gpio115",
+};
+
+static const char * const mdp_vsync4_groups[] = {
+ "gpio109",
+};
+
+static const char * const mdp_vsync5_groups[] = {
+ "gpio110",
+};
+
+static const char * const mdp_vsync6_groups[] = {
+ "gpio111",
+};
+
+static const char * const mdp_vsync7_groups[] = {
+ "gpio112",
+};
+
+static const char * const mdp_vsync8_groups[] = {
+ "gpio113",
+};
+
+static const char * const pcie3_clk_groups[] = {
+ "gpio144",
+};
+
+static const char * const pcie4_clk_groups[] = {
+ "gpio147",
+};
+
+static const char * const pcie5_clk_groups[] = {
+ "gpio150",
+};
+
+static const char * const pcie6a_clk_groups[] = {
+ "gpio153",
+};
+
+static const char * const pcie6b_clk_groups[] = {
+ "gpio156",
+};
+
+static const char * const phase_flag_groups[] = {
+ "gpio6", "gpio7", "gpio8", "gpio11", "gpio12", "gpio13",
+ "gpio14", "gpio15", "gpio16", "gpio17", "gpio18", "gpio19",
+ "gpio20", "gpio21", "gpio22", "gpio23", "gpio24", "gpio25",
+ "gpio26", "gpio27", "gpio39", "gpio40", "gpio76", "gpio77",
+ "gpio78", "gpio181", "gpio182", "gpio184", "gpio185",
+ "gpio186", "gpio187", "gpio188",
+};
+
+static const char * const pll_bist_groups[] = {
+ "gpio28",
+};
+
+static const char * const pll_clk_groups[] = {
+ "gpio35",
+};
+
+static const char * const prng_rosc0_groups[] = {
+ "gpio186",
+};
+
+static const char * const prng_rosc1_groups[] = {
+ "gpio188",
+};
+
+static const char * const prng_rosc2_groups[] = {
+ "gpio182",
+};
+
+static const char * const prng_rosc3_groups[] = {
+ "gpio181",
+};
+
+static const char * const qdss_cti_groups[] = {
+ "gpio18", "gpio19", "gpio23", "gpio27", "gpio161", "gpio162",
+ "gpio215", "gpio217",
+};
+
+static const char * const qdss_gpio_groups[] = {
+ "gpio96", "gpio97", "gpio98", "gpio99", "gpio100", "gpio101",
+ "gpio102", "gpio103", "gpio104", "gpio105", "gpio106", "gpio107",
+ "gpio108", "gpio109", "gpio110", "gpio111", "gpio112", "gpio113",
+ "gpio219", "gpio220", "gpio221", "gpio222", "gpio223", "gpio224",
+ "gpio225", "gpio226", "gpio227", "gpio228", "gpio229", "gpio230",
+ "gpio231", "gpio232", "gpio233", "gpio234", "gpio235", "gpio236",
+};
+
+static const char * const qspi00_groups[] = {
+ "gpio128",
+};
+
+static const char * const qspi01_groups[] = {
+ "gpio129",
+};
+
+static const char * const qspi02_groups[] = {
+ "gpio130",
+};
+
+static const char * const qspi03_groups[] = {
+ "gpio131",
+};
+
+static const char * const qspi0_clk_groups[] = {
+ "gpio127",
+};
+
+static const char * const qspi0_cs0_groups[] = {
+ "gpio132",
+};
+
+static const char * const qspi0_cs1_groups[] = {
+ "gpio133",
+};
+
+static const char * const qup0_se0_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+
+static const char * const qup0_se1_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+
+static const char * const qup0_se2_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio17", "gpio18", "gpio19",
+};
+
+static const char * const qup0_se3_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15", "gpio21", "gpio22", "gpio23",
+};
+
+static const char * const qup0_se4_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19",
+};
+
+static const char * const qup0_se5_groups[] = {
+ "gpio20", "gpio21", "gpio22", "gpio23",
+};
+
+static const char * const qup0_se6_groups[] = {
+ "gpio24", "gpio25", "gpio26", "gpio27",
+};
+
+static const char * const qup0_se7_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15",
+};
+
+static const char * const qup1_se0_groups[] = {
+ "gpio32", "gpio33", "gpio34", "gpio35",
+};
+
+static const char * const qup1_se1_groups[] = {
+ "gpio36", "gpio37", "gpio38", "gpio39",
+};
+
+static const char * const qup1_se2_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio43", "gpio49", "gpio50", "gpio51",
+};
+
+static const char * const qup1_se3_groups[] = {
+ "gpio33", "gpio34", "gpio35", "gpio44", "gpio45", "gpio46", "gpio47",
+};
+
+static const char * const qup1_se4_groups[] = {
+ "gpio48", "gpio49", "gpio50", "gpio51",
+};
+
+static const char * const qup1_se5_groups[] = {
+ "gpio52", "gpio53", "gpio54", "gpio55",
+};
+
+static const char * const qup1_se6_groups[] = {
+ "gpio56", "gpio57", "gpio58", "gpio59",
+};
+
+static const char * const qup1_se7_groups[] = {
+ "gpio52", "gpio53", "gpio54", "gpio55",
+};
+
+static const char * const qup2_se0_groups[] = {
+ "gpio64", "gpio65", "gpio66", "gpio67",
+};
+
+static const char * const qup2_se1_groups[] = {
+ "gpio68", "gpio69", "gpio70", "gpio71",
+};
+
+static const char * const qup2_se2_groups[] = {
+ "gpio72", "gpio73", "gpio74", "gpio75", "gpio81", "gpio82", "gpio83",
+};
+
+static const char * const qup2_se3_groups[] = {
+ "gpio65", "gpio66", "gpio67", "gpio76", "gpio77", "gpio78", "gpio79",
+};
+
+static const char * const qup2_se4_groups[] = {
+ "gpio80", "gpio81", "gpio82", "gpio83",
+};
+
+static const char * const qup2_se5_groups[] = {
+ "gpio84", "gpio85", "gpio86", "gpio87",
+};
+
+static const char * const qup2_se6_groups[] = {
+ "gpio88", "gpio89", "gpio90", "gpio91",
+};
+
+static const char * const qup2_se7_groups[] = {
+ "gpio84", "gpio85", "gpio86", "gpio87",
+};
+
+static const char * const sd_write_groups[] = {
+ "gpio162",
+};
+
+static const char * const sdc4_clk_groups[] = {
+ "gpio127",
+};
+
+static const char * const sdc4_cmd_groups[] = {
+ "gpio132",
+};
+
+static const char * const sdc4_data0_groups[] = {
+ "gpio128",
+};
+
+static const char * const sdc4_data1_groups[] = {
+ "gpio129",
+};
+
+static const char * const sdc4_data2_groups[] = {
+ "gpio130",
+};
+
+static const char * const sdc4_data3_groups[] = {
+ "gpio131",
+};
+
+static const char * const sys_throttle_groups[] = {
+ "gpio39", "gpio94",
+};
+
+static const char * const tb_trig_groups[] = {
+ "gpio133", "gpio137",
+};
+
+static const char * const tgu_ch0_groups[] = {
+ "gpio81",
+};
+
+static const char * const tgu_ch1_groups[] = {
+ "gpio65",
+};
+
+static const char * const tgu_ch2_groups[] = {
+ "gpio66",
+};
+
+static const char * const tgu_ch3_groups[] = {
+ "gpio67",
+};
+
+static const char * const tgu_ch4_groups[] = {
+ "gpio68",
+};
+
+static const char * const tgu_ch5_groups[] = {
+ "gpio69",
+};
+
+static const char * const tgu_ch6_groups[] = {
+ "gpio83",
+};
+
+static const char * const tgu_ch7_groups[] = {
+ "gpio80",
+};
+
+static const char * const tmess_prng0_groups[] = {
+ "gpio92",
+};
+
+static const char * const tmess_prng1_groups[] = {
+ "gpio93",
+};
+
+static const char * const tmess_prng2_groups[] = {
+ "gpio94",
+};
+
+static const char * const tmess_prng3_groups[] = {
+ "gpio95",
+};
+
+static const char * const tsense_pwm1_groups[] = {
+ "gpio34",
+};
+
+static const char * const tsense_pwm2_groups[] = {
+ "gpio34",
+};
+
+static const char * const tsense_pwm3_groups[] = {
+ "gpio34",
+};
+
+static const char * const tsense_pwm4_groups[] = {
+ "gpio34",
+};
+
+static const char * const usb0_dp_groups[] = {
+ "gpio122",
+};
+
+static const char * const usb0_phy_groups[] = {
+ "gpio121",
+};
+
+static const char * const usb0_sbrx_groups[] = {
+ "gpio163",
+};
+
+static const char * const usb0_sbtx_groups[] = {
+ "gpio164", "gpio165",
+};
+
+static const char * const usb1_dp_groups[] = {
+ "gpio124",
+};
+
+static const char * const usb1_phy_groups[] = {
+ "gpio123",
+};
+
+static const char * const usb1_sbrx_groups[] = {
+ "gpio172",
+};
+
+static const char * const usb1_sbtx_groups[] = {
+ "gpio173", "gpio174",
+};
+
+static const char * const usb2_dp_groups[] = {
+ "gpio126",
+};
+
+static const char * const usb2_phy_groups[] = {
+ "gpio125",
+};
+
+static const char * const usb2_sbrx_groups[] = {
+ "gpio181",
+};
+
+static const char * const usb2_sbtx_groups[] = {
+ "gpio182", "gpio183",
+};
+
+static const char * const vsense_trigger_groups[] = {
+ "gpio38",
+};
+
+static const struct pinfunction x1e80100_functions[] = {
+ MSM_PIN_FUNCTION(gpio),
+ MSM_PIN_FUNCTION(RESOUT_GPIO),
+ MSM_PIN_FUNCTION(aon_cci),
+ MSM_PIN_FUNCTION(aoss_cti),
+ MSM_PIN_FUNCTION(atest_char),
+ MSM_PIN_FUNCTION(atest_char0),
+ MSM_PIN_FUNCTION(atest_char1),
+ MSM_PIN_FUNCTION(atest_char2),
+ MSM_PIN_FUNCTION(atest_char3),
+ MSM_PIN_FUNCTION(atest_usb),
+ MSM_PIN_FUNCTION(audio_ext),
+ MSM_PIN_FUNCTION(audio_ref),
+ MSM_PIN_FUNCTION(cam_aon),
+ MSM_PIN_FUNCTION(cam_mclk),
+ MSM_PIN_FUNCTION(cci_async),
+ MSM_PIN_FUNCTION(cci_i2c),
+ MSM_PIN_FUNCTION(cci_timer0),
+ MSM_PIN_FUNCTION(cci_timer1),
+ MSM_PIN_FUNCTION(cci_timer2),
+ MSM_PIN_FUNCTION(cci_timer3),
+ MSM_PIN_FUNCTION(cci_timer4),
+ MSM_PIN_FUNCTION(cmu_rng0),
+ MSM_PIN_FUNCTION(cmu_rng1),
+ MSM_PIN_FUNCTION(cmu_rng2),
+ MSM_PIN_FUNCTION(cmu_rng3),
+ MSM_PIN_FUNCTION(cri_trng),
+ MSM_PIN_FUNCTION(dbg_out),
+ MSM_PIN_FUNCTION(ddr_bist),
+ MSM_PIN_FUNCTION(ddr_pxi0),
+ MSM_PIN_FUNCTION(ddr_pxi1),
+ MSM_PIN_FUNCTION(ddr_pxi2),
+ MSM_PIN_FUNCTION(ddr_pxi3),
+ MSM_PIN_FUNCTION(ddr_pxi4),
+ MSM_PIN_FUNCTION(ddr_pxi5),
+ MSM_PIN_FUNCTION(ddr_pxi6),
+ MSM_PIN_FUNCTION(ddr_pxi7),
+ MSM_PIN_FUNCTION(edp0_hot),
+ MSM_PIN_FUNCTION(edp0_lcd),
+ MSM_PIN_FUNCTION(edp1_hot),
+ MSM_PIN_FUNCTION(edp1_lcd),
+ MSM_PIN_FUNCTION(eusb0_ac),
+ MSM_PIN_FUNCTION(eusb1_ac),
+ MSM_PIN_FUNCTION(eusb2_ac),
+ MSM_PIN_FUNCTION(eusb3_ac),
+ MSM_PIN_FUNCTION(eusb5_ac),
+ MSM_PIN_FUNCTION(eusb6_ac),
+ MSM_PIN_FUNCTION(gcc_gp1),
+ MSM_PIN_FUNCTION(gcc_gp2),
+ MSM_PIN_FUNCTION(gcc_gp3),
+ MSM_PIN_FUNCTION(i2s0_data0),
+ MSM_PIN_FUNCTION(i2s0_data1),
+ MSM_PIN_FUNCTION(i2s0_sck),
+ MSM_PIN_FUNCTION(i2s0_ws),
+ MSM_PIN_FUNCTION(i2s1_data0),
+ MSM_PIN_FUNCTION(i2s1_data1),
+ MSM_PIN_FUNCTION(i2s1_sck),
+ MSM_PIN_FUNCTION(i2s1_ws),
+ MSM_PIN_FUNCTION(ibi_i3c),
+ MSM_PIN_FUNCTION(jitter_bist),
+ MSM_PIN_FUNCTION(mdp_vsync0),
+ MSM_PIN_FUNCTION(mdp_vsync1),
+ MSM_PIN_FUNCTION(mdp_vsync2),
+ MSM_PIN_FUNCTION(mdp_vsync3),
+ MSM_PIN_FUNCTION(mdp_vsync4),
+ MSM_PIN_FUNCTION(mdp_vsync5),
+ MSM_PIN_FUNCTION(mdp_vsync6),
+ MSM_PIN_FUNCTION(mdp_vsync7),
+ MSM_PIN_FUNCTION(mdp_vsync8),
+ MSM_PIN_FUNCTION(pcie3_clk),
+ MSM_PIN_FUNCTION(pcie4_clk),
+ MSM_PIN_FUNCTION(pcie5_clk),
+ MSM_PIN_FUNCTION(pcie6a_clk),
+ MSM_PIN_FUNCTION(pcie6b_clk),
+ MSM_PIN_FUNCTION(phase_flag),
+ MSM_PIN_FUNCTION(pll_bist),
+ MSM_PIN_FUNCTION(pll_clk),
+ MSM_PIN_FUNCTION(prng_rosc0),
+ MSM_PIN_FUNCTION(prng_rosc1),
+ MSM_PIN_FUNCTION(prng_rosc2),
+ MSM_PIN_FUNCTION(prng_rosc3),
+ MSM_PIN_FUNCTION(qdss_cti),
+ MSM_PIN_FUNCTION(qdss_gpio),
+ MSM_PIN_FUNCTION(qspi00),
+ MSM_PIN_FUNCTION(qspi01),
+ MSM_PIN_FUNCTION(qspi02),
+ MSM_PIN_FUNCTION(qspi03),
+ MSM_PIN_FUNCTION(qspi0_clk),
+ MSM_PIN_FUNCTION(qspi0_cs0),
+ MSM_PIN_FUNCTION(qspi0_cs1),
+ MSM_PIN_FUNCTION(qup0_se0),
+ MSM_PIN_FUNCTION(qup0_se1),
+ MSM_PIN_FUNCTION(qup0_se2),
+ MSM_PIN_FUNCTION(qup0_se3),
+ MSM_PIN_FUNCTION(qup0_se4),
+ MSM_PIN_FUNCTION(qup0_se5),
+ MSM_PIN_FUNCTION(qup0_se6),
+ MSM_PIN_FUNCTION(qup0_se7),
+ MSM_PIN_FUNCTION(qup1_se0),
+ MSM_PIN_FUNCTION(qup1_se1),
+ MSM_PIN_FUNCTION(qup1_se2),
+ MSM_PIN_FUNCTION(qup1_se3),
+ MSM_PIN_FUNCTION(qup1_se4),
+ MSM_PIN_FUNCTION(qup1_se5),
+ MSM_PIN_FUNCTION(qup1_se6),
+ MSM_PIN_FUNCTION(qup1_se7),
+ MSM_PIN_FUNCTION(qup2_se0),
+ MSM_PIN_FUNCTION(qup2_se1),
+ MSM_PIN_FUNCTION(qup2_se2),
+ MSM_PIN_FUNCTION(qup2_se3),
+ MSM_PIN_FUNCTION(qup2_se4),
+ MSM_PIN_FUNCTION(qup2_se5),
+ MSM_PIN_FUNCTION(qup2_se6),
+ MSM_PIN_FUNCTION(qup2_se7),
+ MSM_PIN_FUNCTION(sd_write),
+ MSM_PIN_FUNCTION(sdc4_clk),
+ MSM_PIN_FUNCTION(sdc4_cmd),
+ MSM_PIN_FUNCTION(sdc4_data0),
+ MSM_PIN_FUNCTION(sdc4_data1),
+ MSM_PIN_FUNCTION(sdc4_data2),
+ MSM_PIN_FUNCTION(sdc4_data3),
+ MSM_PIN_FUNCTION(sys_throttle),
+ MSM_PIN_FUNCTION(tb_trig),
+ MSM_PIN_FUNCTION(tgu_ch0),
+ MSM_PIN_FUNCTION(tgu_ch1),
+ MSM_PIN_FUNCTION(tgu_ch2),
+ MSM_PIN_FUNCTION(tgu_ch3),
+ MSM_PIN_FUNCTION(tgu_ch4),
+ MSM_PIN_FUNCTION(tgu_ch5),
+ MSM_PIN_FUNCTION(tgu_ch6),
+ MSM_PIN_FUNCTION(tgu_ch7),
+ MSM_PIN_FUNCTION(tmess_prng0),
+ MSM_PIN_FUNCTION(tmess_prng1),
+ MSM_PIN_FUNCTION(tmess_prng2),
+ MSM_PIN_FUNCTION(tmess_prng3),
+ MSM_PIN_FUNCTION(tsense_pwm1),
+ MSM_PIN_FUNCTION(tsense_pwm2),
+ MSM_PIN_FUNCTION(tsense_pwm3),
+ MSM_PIN_FUNCTION(tsense_pwm4),
+ MSM_PIN_FUNCTION(usb0_dp),
+ MSM_PIN_FUNCTION(usb0_phy),
+ MSM_PIN_FUNCTION(usb0_sbrx),
+ MSM_PIN_FUNCTION(usb0_sbtx),
+ MSM_PIN_FUNCTION(usb1_dp),
+ MSM_PIN_FUNCTION(usb1_phy),
+ MSM_PIN_FUNCTION(usb1_sbrx),
+ MSM_PIN_FUNCTION(usb1_sbtx),
+ MSM_PIN_FUNCTION(usb2_dp),
+ MSM_PIN_FUNCTION(usb2_phy),
+ MSM_PIN_FUNCTION(usb2_sbrx),
+ MSM_PIN_FUNCTION(usb2_sbtx),
+ MSM_PIN_FUNCTION(vsense_trigger),
+};
+
+/*
+ * Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup x1e80100_groups[] = {
+ [0] = PINGROUP(0, qup0_se0, ibi_i3c, _, _, _, _, _, _, _),
+ [1] = PINGROUP(1, qup0_se0, ibi_i3c, _, _, _, _, _, _, _),
+ [2] = PINGROUP(2, qup0_se0, _, _, _, _, _, _, _, _),
+ [3] = PINGROUP(3, qup0_se0, _, _, _, _, _, _, _, _),
+ [4] = PINGROUP(4, qup0_se1, _, _, _, _, _, _, _, _),
+ [5] = PINGROUP(5, qup0_se1, _, _, _, _, _, _, _, _),
+ [6] = PINGROUP(6, qup0_se1, phase_flag, _, _, _, _, _, _, _),
+ [7] = PINGROUP(7, qup0_se1, phase_flag, _, _, _, _, _, _, _),
+ [8] = PINGROUP(8, qup0_se2, phase_flag, _, _, _, _, _, _, _),
+ [9] = PINGROUP(9, qup0_se2, _, atest_usb, ddr_pxi0, _, _, _, _, _),
+ [10] = PINGROUP(10, qup0_se2, _, atest_usb, ddr_pxi1, _, _, _, _, _),
+ [11] = PINGROUP(11, qup0_se2, phase_flag, _, _, _, _, _, _, _),
+ [12] = PINGROUP(12, qup0_se3, qup0_se7, phase_flag, _, _, _, _, _, _),
+ [13] = PINGROUP(13, qup0_se3, qup0_se7, phase_flag, _, _, _, _, _, _),
+ [14] = PINGROUP(14, qup0_se3, qup0_se7, phase_flag, _, _, _, _, _, _),
+ [15] = PINGROUP(15, qup0_se3, qup0_se7, phase_flag, _, _, _, _, _, _),
+ [16] = PINGROUP(16, qup0_se4, phase_flag, _, _, _, _, _, _, _),
+ [17] = PINGROUP(17, qup0_se4, qup0_se2, phase_flag, _, _, _, _, _, _),
+ [18] = PINGROUP(18, qup0_se4, qup0_se2, phase_flag, _, qdss_cti, _, _, _, _),
+ [19] = PINGROUP(19, qup0_se4, qup0_se2, phase_flag, _, qdss_cti, _, _, _, _),
+ [20] = PINGROUP(20, qup0_se5, _, phase_flag, _, _, _, _, _, _),
+ [21] = PINGROUP(21, qup0_se5, qup0_se3, _, phase_flag, _, _, _, _, _),
+ [22] = PINGROUP(22, qup0_se5, qup0_se3, _, phase_flag, _, _, _, _, _),
+ [23] = PINGROUP(23, qup0_se5, qup0_se3, phase_flag, _, qdss_cti, _, _, _, _),
+ [24] = PINGROUP(24, qup0_se6, phase_flag, _, _, _, _, _, _, _),
+ [25] = PINGROUP(25, qup0_se6, phase_flag, _, _, _, _, _, _, _),
+ [26] = PINGROUP(26, qup0_se6, phase_flag, _, _, _, _, _, _, _),
+ [27] = PINGROUP(27, qup0_se6, phase_flag, _, qdss_cti, _, _, _, _, _),
+ [28] = PINGROUP(28, pll_bist, _, _, _, _, _, _, _, _),
+ [29] = PINGROUP(29, _, _, _, _, _, _, _, _, _),
+ [30] = PINGROUP(30, _, _, _, _, _, _, _, _, _),
+ [31] = PINGROUP(31, _, _, _, _, _, _, _, _, _),
+ [32] = PINGROUP(32, qup1_se0, ibi_i3c, _, _, _, _, _, _, _),
+ [33] = PINGROUP(33, qup1_se0, ibi_i3c, qup1_se3, _, _, _, _, _, _),
+ [34] = PINGROUP(34, qup1_se0, qup1_se3, tsense_pwm1, tsense_pwm2, tsense_pwm3, tsense_pwm4, _, _, _),
+ [35] = PINGROUP(35, qup1_se0, qup1_se3, pll_clk, atest_usb, _, _, _, _, _),
+ [36] = PINGROUP(36, qup1_se1, ibi_i3c, _, _, _, _, _, _, _),
+ [37] = PINGROUP(37, qup1_se1, ibi_i3c, _, _, _, _, _, _, _),
+ [38] = PINGROUP(38, qup1_se1, vsense_trigger, atest_usb, ddr_pxi0, _, _, _, _, _),
+ [39] = PINGROUP(39, qup1_se1, sys_throttle, phase_flag, _, _, _, _, _, _),
+ [40] = PINGROUP(40, qup1_se2, phase_flag, _, _, _, _, _, _, _),
+ [41] = PINGROUP(41, qup1_se2, atest_usb, ddr_pxi1, _, _, _, _, _, _),
+ [42] = PINGROUP(42, qup1_se2, jitter_bist, atest_usb, ddr_pxi2, _, _, _, _, _),
+ [43] = PINGROUP(43, qup1_se2, _, atest_usb, ddr_pxi2, _, _, _, _, _),
+ [44] = PINGROUP(44, qup1_se3, _, atest_usb, ddr_pxi3, _, _, _, _, _),
+ [45] = PINGROUP(45, qup1_se3, cmu_rng3, _, atest_usb, ddr_pxi3, _, _, _, _),
+ [46] = PINGROUP(46, qup1_se3, cmu_rng2, _, atest_usb, ddr_pxi4, _, _, _, _),
+ [47] = PINGROUP(47, qup1_se3, cmu_rng1, _, atest_usb, ddr_pxi4, _, _, _, _),
+ [48] = PINGROUP(48, qup1_se4, cmu_rng0, _, atest_usb, ddr_pxi5, _, _, _, _),
+ [49] = PINGROUP(49, qup1_se4, qup1_se2, _, atest_usb, ddr_pxi5, _, _, _, _),
+ [50] = PINGROUP(50, qup1_se4, qup1_se2, _, atest_usb, ddr_pxi6, _, _, _, _),
+ [51] = PINGROUP(51, qup1_se4, qup1_se2, dbg_out, atest_usb, ddr_pxi6, _, _, _, _),
+ [52] = PINGROUP(52, qup1_se5, qup1_se7, atest_usb, ddr_pxi7, _, _, _, _, _),
+ [53] = PINGROUP(53, qup1_se5, qup1_se7, _, atest_usb, ddr_pxi7, _, _, _, _),
+ [54] = PINGROUP(54, qup1_se5, qup1_se7, ddr_bist, atest_usb, _, _, _, _, _),
+ [55] = PINGROUP(55, qup1_se5, qup1_se7, ddr_bist, _, _, _, _, _, _),
+ [56] = PINGROUP(56, qup1_se6, ddr_bist, _, _, _, _, _, _, _),
+ [57] = PINGROUP(57, qup1_se6, ddr_bist, _, _, _, _, _, _, _),
+ [58] = PINGROUP(58, qup1_se6, atest_usb, _, _, _, _, _, _, _),
+ [59] = PINGROUP(59, qup1_se6, atest_usb, _, _, _, _, _, _, _),
+ [60] = PINGROUP(60, aoss_cti, _, _, _, _, _, _, _, _),
+ [61] = PINGROUP(61, aoss_cti, _, _, _, _, _, _, _, _),
+ [62] = PINGROUP(62, aoss_cti, _, _, _, _, _, _, _, _),
+ [63] = PINGROUP(63, aoss_cti, _, _, _, _, _, _, _, _),
+ [64] = PINGROUP(64, qup2_se0, gcc_gp2, _, _, _, _, _, _, _),
+ [65] = PINGROUP(65, qup2_se0, qup2_se3, tgu_ch1, atest_usb, _, _, _, _, _),
+ [66] = PINGROUP(66, qup2_se0, qup2_se3, tgu_ch2, atest_usb, _, _, _, _, _),
+ [67] = PINGROUP(67, qup2_se0, qup2_se3, tgu_ch3, atest_usb, _, _, _, _, _),
+ [68] = PINGROUP(68, qup2_se1, ibi_i3c, tgu_ch4, _, _, _, _, _, _),
+ [69] = PINGROUP(69, qup2_se1, ibi_i3c, tgu_ch5, _, _, _, _, _, _),
+ [70] = PINGROUP(70, qup2_se1, _, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, qup2_se1, gcc_gp1, _, _, _, _, _, _, _),
+ [72] = PINGROUP(72, qup2_se2, gcc_gp1, atest_usb, _, _, _, _, _, _),
+ [73] = PINGROUP(73, qup2_se2, gcc_gp2, atest_usb, _, _, _, _, _, _),
+ [74] = PINGROUP(74, qup2_se2, gcc_gp3, atest_usb, _, _, _, _, _, _),
+ [75] = PINGROUP(75, qup2_se2, atest_usb, _, _, _, _, _, _, _),
+ [76] = PINGROUP(76, qup2_se3, phase_flag, _, _, _, _, _, _, _),
+ [77] = PINGROUP(77, qup2_se3, phase_flag, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, qup2_se3, phase_flag, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, qup2_se3, _, _, _, _, _, _, _, _),
+ [80] = PINGROUP(80, qup2_se4, tgu_ch7, atest_usb, _, _, _, _, _, _),
+ [81] = PINGROUP(81, qup2_se4, qup2_se2, tgu_ch0, atest_usb, _, _, _, _, _),
+ [82] = PINGROUP(82, qup2_se4, qup2_se2, gcc_gp3, _, _, _, _, _, _),
+ [83] = PINGROUP(83, qup2_se4, qup2_se2, tgu_ch6, atest_usb, _, _, _, _, _),
+ [84] = PINGROUP(84, qup2_se5, qup2_se7, _, _, _, _, _, _, _),
+ [85] = PINGROUP(85, qup2_se5, qup2_se7, _, _, _, _, _, _, _),
+ [86] = PINGROUP(86, qup2_se5, qup2_se7, _, _, _, _, _, _, _),
+ [87] = PINGROUP(87, qup2_se5, qup2_se7, _, _, _, _, _, _, _),
+ [88] = PINGROUP(88, qup2_se6, _, _, _, _, _, _, _, _),
+ [89] = PINGROUP(89, qup2_se6, _, _, _, _, _, _, _, _),
+ [90] = PINGROUP(90, qup2_se6, _, _, _, _, _, _, _, _),
+ [91] = PINGROUP(91, qup2_se6, _, _, _, _, _, _, _, _),
+ [92] = PINGROUP(92, tmess_prng0, _, _, _, _, _, _, _, _),
+ [93] = PINGROUP(93, tmess_prng1, _, _, _, _, _, _, _, _),
+ [94] = PINGROUP(94, sys_throttle, tmess_prng2, _, _, _, _, _, _, _),
+ [95] = PINGROUP(95, tmess_prng3, _, _, _, _, _, _, _, _),
+ [96] = PINGROUP(96, cam_mclk, qdss_gpio, _, _, _, _, _, _, _),
+ [97] = PINGROUP(97, cam_mclk, qdss_gpio, _, _, _, _, _, _, _),
+ [98] = PINGROUP(98, cam_mclk, qdss_gpio, _, _, _, _, _, _, _),
+ [99] = PINGROUP(99, cam_mclk, qdss_gpio, _, _, _, _, _, _, _),
+ [100] = PINGROUP(100, cam_aon, qdss_gpio, _, _, _, _, _, _, _),
+ [101] = PINGROUP(101, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [102] = PINGROUP(102, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [103] = PINGROUP(103, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [104] = PINGROUP(104, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [105] = PINGROUP(105, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [106] = PINGROUP(106, cci_i2c, qdss_gpio, _, _, _, _, _, _, _),
+ [107] = PINGROUP(107, qdss_gpio, _, _, _, _, _, _, _, _),
+ [108] = PINGROUP(108, qdss_gpio, _, _, _, _, _, _, _, _),
+ [109] = PINGROUP(109, cci_timer0, mdp_vsync4, qdss_gpio, _, _, _, _, _, _),
+ [110] = PINGROUP(110, cci_timer1, mdp_vsync5, qdss_gpio, _, _, _, _, _, _),
+ [111] = PINGROUP(111, cci_timer2, cci_async, mdp_vsync6, qdss_gpio, _, _, _, _, _),
+ [112] = PINGROUP(112, cci_timer3, cci_async, mdp_vsync7, qdss_gpio, _, _, _, _, _),
+ [113] = PINGROUP(113, cci_timer4, cci_async, mdp_vsync8, qdss_gpio, _, _, _, _, _),
+ [114] = PINGROUP(114, mdp_vsync0, mdp_vsync1, _, _, _, _, _, _, _),
+ [115] = PINGROUP(115, mdp_vsync3, mdp_vsync2, edp1_lcd, _, _, _, _, _, _),
+ [116] = PINGROUP(116, _, _, _, _, _, _, _, _, _),
+ [117] = PINGROUP(117, _, _, _, _, _, _, _, _, _),
+ [118] = PINGROUP(118, _, _, _, _, _, _, _, _, _),
+ [119] = PINGROUP(119, edp0_hot, edp1_lcd, _, _, _, _, _, _, _),
+ [120] = PINGROUP(120, edp1_hot, edp0_lcd, _, _, _, _, _, _, _),
+ [121] = PINGROUP(121, usb0_phy, _, _, _, _, _, _, _, _),
+ [122] = PINGROUP(122, usb0_dp, _, _, _, _, _, _, _, _),
+ [123] = PINGROUP(123, usb1_phy, _, _, _, _, _, _, _, _),
+ [124] = PINGROUP(124, usb1_dp, _, _, _, _, _, _, _, _),
+ [125] = PINGROUP(125, usb2_phy, _, _, _, _, _, _, _, _),
+ [126] = PINGROUP(126, usb2_dp, _, _, _, _, _, _, _, _),
+ [127] = PINGROUP(127, qspi0_clk, sdc4_clk, _, _, _, _, _, _, _),
+ [128] = PINGROUP(128, qspi00, sdc4_data0, _, _, _, _, _, _, _),
+ [129] = PINGROUP(129, qspi01, sdc4_data1, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, qspi02, sdc4_data2, _, _, _, _, _, _, _),
+ [131] = PINGROUP(131, qspi03, sdc4_data3, _, _, _, _, _, _, _),
+ [132] = PINGROUP(132, qspi0_cs0, sdc4_cmd, _, _, _, _, _, _, _),
+ [133] = PINGROUP(133, qspi0_cs1, tb_trig, _, _, _, _, _, _, _),
+ [134] = PINGROUP(134, audio_ext, _, _, _, _, _, _, _, _),
+ [135] = PINGROUP(135, i2s0_sck, _, _, _, _, _, _, _, _),
+ [136] = PINGROUP(136, i2s0_data0, _, _, _, _, _, _, _, _),
+ [137] = PINGROUP(137, i2s0_data1, tb_trig, _, _, _, _, _, _, _),
+ [138] = PINGROUP(138, i2s0_ws, _, _, _, _, _, _, _, _),
+ [139] = PINGROUP(139, i2s1_sck, _, _, _, _, _, _, _, _),
+ [140] = PINGROUP(140, i2s1_data0, _, _, _, _, _, _, _, _),
+ [141] = PINGROUP(141, i2s1_ws, _, _, _, _, _, _, _, _),
+ [142] = PINGROUP(142, i2s1_data1, audio_ext, audio_ref, _, _, _, _, _, _),
+ [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _),
+ [144] = PINGROUP(144, pcie3_clk, _, _, _, _, _, _, _, _),
+ [145] = PINGROUP(145, _, _, _, _, _, _, _, _, _),
+ [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _),
+ [147] = PINGROUP(147, pcie4_clk, _, _, _, _, _, _, _, _),
+ [148] = PINGROUP(148, _, _, _, _, _, _, _, _, _),
+ [149] = PINGROUP(149, _, _, _, _, _, _, _, _, _),
+ [150] = PINGROUP(150, pcie5_clk, _, _, _, _, _, _, _, _),
+ [151] = PINGROUP(151, _, _, _, _, _, _, _, _, _),
+ [152] = PINGROUP(152, _, _, _, _, _, _, _, _, _),
+ [153] = PINGROUP(153, pcie6a_clk, _, _, _, _, _, _, _, _),
+ [154] = PINGROUP(154, _, _, _, _, _, _, _, _, _),
+ [155] = PINGROUP(155, _, _, _, _, _, _, _, _, _),
+ [156] = PINGROUP(156, pcie6b_clk, _, _, _, _, _, _, _, _),
+ [157] = PINGROUP(157, _, _, _, _, _, _, _, _, _),
+ [158] = PINGROUP(158, _, _, _, _, _, _, _, _, _),
+ [159] = PINGROUP(159, _, _, _, _, _, _, _, _, _),
+ [160] = PINGROUP(160, RESOUT_GPIO, _, _, _, _, _, _, _, _),
+ [161] = PINGROUP(161, qdss_cti, _, _, _, _, _, _, _, _),
+ [162] = PINGROUP(162, sd_write, qdss_cti, _, _, _, _, _, _, _),
+ [163] = PINGROUP(163, usb0_sbrx, _, _, _, _, _, _, _, _),
+ [164] = PINGROUP(164, usb0_sbtx, _, _, _, _, _, _, _, _),
+ [165] = PINGROUP(165, usb0_sbtx, _, _, _, _, _, _, _, _),
+ [166] = PINGROUP(166, _, _, _, _, _, _, _, _, _),
+ [167] = PINGROUP(167, _, _, _, _, _, _, _, _, _),
+ [168] = PINGROUP(168, eusb0_ac, _, _, _, _, _, _, _, _),
+ [169] = PINGROUP(169, eusb3_ac, _, _, _, _, _, _, _, _),
+ [170] = PINGROUP(170, _, _, _, _, _, _, _, _, _),
+ [171] = PINGROUP(171, _, _, _, _, _, _, _, _, _),
+ [172] = PINGROUP(172, usb1_sbrx, _, _, _, _, _, _, _, _),
+ [173] = PINGROUP(173, usb1_sbtx, _, _, _, _, _, _, _, _),
+ [174] = PINGROUP(174, usb1_sbtx, _, _, _, _, _, _, _, _),
+ [175] = PINGROUP(175, _, _, _, _, _, _, _, _, _),
+ [176] = PINGROUP(176, _, _, _, _, _, _, _, _, _),
+ [177] = PINGROUP(177, eusb1_ac, _, _, _, _, _, _, _, _),
+ [178] = PINGROUP(178, eusb6_ac, _, _, _, _, _, _, _, _),
+ [179] = PINGROUP(179, _, _, _, _, _, _, _, _, _),
+ [180] = PINGROUP(180, _, _, _, _, _, _, _, _, _),
+ [181] = PINGROUP(181, usb2_sbrx, prng_rosc3, phase_flag, _, atest_char, _, _, _, _),
+ [182] = PINGROUP(182, usb2_sbtx, prng_rosc2, phase_flag, _, atest_char3, _, _, _, _),
+ [183] = PINGROUP(183, usb2_sbtx, _, _, _, _, _, _, _, _),
+ [184] = PINGROUP(184, phase_flag, _, atest_char1, _, _, _, _, _, _),
+ [185] = PINGROUP(185, phase_flag, _, atest_char0, _, _, _, _, _, _),
+ [186] = PINGROUP(186, eusb2_ac, prng_rosc0, phase_flag, _, _, _, _, _, _),
+ [187] = PINGROUP(187, eusb5_ac, cri_trng, phase_flag, _, _, _, _, _, _),
+ [188] = PINGROUP(188, prng_rosc1, phase_flag, _, atest_char2, _, _, _, _, _),
+ [189] = PINGROUP(189, _, _, _, _, _, _, _, _, _),
+ [190] = PINGROUP(190, _, _, _, _, _, _, _, _, _),
+ [191] = PINGROUP(191, _, _, _, _, _, _, _, _, _),
+ [192] = PINGROUP(192, _, _, _, _, _, _, _, _, _),
+ [193] = PINGROUP(193, _, _, _, _, _, _, _, _, _),
+ [194] = PINGROUP(194, _, _, _, _, _, _, _, _, _),
+ [195] = PINGROUP(195, _, _, _, _, _, _, _, _, _),
+ [196] = PINGROUP(196, _, _, _, _, _, _, _, _, _),
+ [197] = PINGROUP(197, _, _, _, _, _, _, _, _, _),
+ [198] = PINGROUP(198, _, _, _, _, _, _, _, _, _),
+ [199] = PINGROUP(199, _, _, _, _, _, _, _, _, _),
+ [200] = PINGROUP(200, _, _, _, _, _, _, _, _, _),
+ [201] = PINGROUP(201, _, _, _, _, _, _, _, _, _),
+ [202] = PINGROUP(202, _, _, _, _, _, _, _, _, _),
+ [203] = PINGROUP(203, _, _, _, _, _, _, _, _, _),
+ [204] = PINGROUP(204, _, _, _, _, _, _, _, _, _),
+ [205] = PINGROUP(205, _, _, _, _, _, _, _, _, _),
+ [206] = PINGROUP(206, _, _, _, _, _, _, _, _, _),
+ [207] = PINGROUP(207, _, _, _, _, _, _, _, _, _),
+ [208] = PINGROUP(208, _, _, _, _, _, _, _, _, _),
+ [209] = PINGROUP(209, _, _, _, _, _, _, _, _, _),
+ [210] = PINGROUP(210, _, _, _, _, _, _, _, _, _),
+ [211] = PINGROUP(211, _, _, _, _, _, _, _, _, _),
+ [212] = PINGROUP(212, _, _, _, _, _, _, _, _, _),
+ [213] = PINGROUP(213, _, _, _, _, _, _, _, _, _),
+ [214] = PINGROUP(214, _, _, _, _, _, _, _, _, _),
+ [215] = PINGROUP(215, _, qdss_cti, _, _, _, _, _, _, _),
+ [216] = PINGROUP(216, _, _, _, _, _, _, _, _, _),
+ [217] = PINGROUP(217, _, qdss_cti, _, _, _, _, _, _, _),
+ [218] = PINGROUP(218, _, _, _, _, _, _, _, _, _),
+ [219] = PINGROUP(219, _, qdss_gpio, _, _, _, _, _, _, _),
+ [220] = PINGROUP(220, _, qdss_gpio, _, _, _, _, _, _, _),
+ [221] = PINGROUP(221, _, qdss_gpio, _, _, _, _, _, _, _),
+ [222] = PINGROUP(222, _, qdss_gpio, _, _, _, _, _, _, _),
+ [223] = PINGROUP(223, _, qdss_gpio, _, _, _, _, _, _, _),
+ [224] = PINGROUP(224, _, qdss_gpio, _, _, _, _, _, _, _),
+ [225] = PINGROUP(225, _, qdss_gpio, _, _, _, _, _, _, _),
+ [226] = PINGROUP(226, _, qdss_gpio, _, _, _, _, _, _, _),
+ [227] = PINGROUP(227, _, qdss_gpio, _, _, _, _, _, _, _),
+ [228] = PINGROUP(228, _, qdss_gpio, _, _, _, _, _, _, _),
+ [229] = PINGROUP(229, qdss_gpio, _, _, _, _, _, _, _, _),
+ [230] = PINGROUP(230, qdss_gpio, _, _, _, _, _, _, _, _),
+ [231] = PINGROUP(231, qdss_gpio, _, _, _, _, _, _, _, _),
+ [232] = PINGROUP(232, qdss_gpio, _, _, _, _, _, _, _, _),
+ [233] = PINGROUP(233, qdss_gpio, _, _, _, _, _, _, _, _),
+ [234] = PINGROUP(234, qdss_gpio, _, _, _, _, _, _, _, _),
+ [235] = PINGROUP(235, aon_cci, qdss_gpio, _, _, _, _, _, _, _),
+ [236] = PINGROUP(236, aon_cci, qdss_gpio, _, _, _, _, _, _, _),
+ [237] = PINGROUP(237, _, _, _, _, _, _, _, _, _),
+ [238] = UFS_RESET(ufs_reset, 0x1f9000),
+ [239] = SDC_QDSD_PINGROUP(sdc2_clk, 0x1f2000, 14, 6),
+ [240] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x1f2000, 11, 3),
+ [241] = SDC_QDSD_PINGROUP(sdc2_data, 0x1f2000, 9, 0),
+};
+
+static const struct msm_gpio_wakeirq_map x1e80100_pdc_map[] = {
+ { 0, 72 }, { 2, 70 }, { 3, 71 }, { 6, 123 }, { 7, 67 }, { 11, 85 },
+ { 15, 68 }, { 18, 122 }, { 19, 69 }, { 21, 158 }, { 23, 143 }, { 26, 129 },
+ { 27, 144 }, { 28, 77 }, { 29, 78 }, { 30, 92 }, { 32, 145 }, { 33, 115 },
+ { 34, 130 }, { 35, 146 }, { 36, 147 }, { 39, 80 }, { 43, 148 }, { 47, 149 },
+ { 51, 79 }, { 53, 89 }, { 59, 87 }, { 64, 90 }, { 65, 106 }, { 66, 142 },
+ { 67, 88 }, { 71, 91 }, { 75, 152 }, { 79, 153 }, { 80, 125 }, { 81, 128 },
+ { 84, 137 }, { 85, 155 }, { 87, 156 }, { 91, 157 }, { 92, 138 }, { 94, 140 },
+ { 95, 141 }, { 113, 84 }, { 121, 73 }, { 123, 74 }, { 129, 76 }, { 131, 82 },
+ { 134, 83 }, { 141, 93 }, { 144, 94 }, { 147, 96 }, { 148, 97 }, { 150, 102 },
+ { 151, 103 }, { 153, 104 }, { 156, 105 }, { 157, 107 }, { 163, 98 }, { 166, 112 },
+ { 172, 99 }, { 181, 101 }, { 184, 116 }, { 193, 40 }, { 193, 117 }, { 196, 108 },
+ { 203, 133 }, { 212, 120 }, { 213, 150 }, { 214, 121 }, { 215, 118 }, { 217, 109 },
+ { 220, 110 }, { 221, 111 }, { 222, 124 }, { 224, 131 }, { 225, 132 },
+};
+
+static const struct msm_pinctrl_soc_data x1e80100_pinctrl = {
+ .pins = x1e80100_pins,
+ .npins = ARRAY_SIZE(x1e80100_pins),
+ .functions = x1e80100_functions,
+ .nfunctions = ARRAY_SIZE(x1e80100_functions),
+ .groups = x1e80100_groups,
+ .ngroups = ARRAY_SIZE(x1e80100_groups),
+ .ngpios = 239,
+ .wakeirq_map = x1e80100_pdc_map,
+ .nwakeirq_map = ARRAY_SIZE(x1e80100_pdc_map),
+ .egpio_func = 9,
+};
+
+static int x1e80100_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &x1e80100_pinctrl);
+}
+
+static const struct of_device_id x1e80100_pinctrl_of_match[] = {
+ { .compatible = "qcom,x1e80100-tlmm", },
+ { },
+};
+
+static struct platform_driver x1e80100_pinctrl_driver = {
+ .driver = {
+ .name = "x1e80100-tlmm",
+ .of_match_table = x1e80100_pinctrl_of_match,
+ },
+ .probe = x1e80100_pinctrl_probe,
+ .remove_new = msm_pinctrl_remove,
+};
+
+static int __init x1e80100_pinctrl_init(void)
+{
+ return platform_driver_register(&x1e80100_pinctrl_driver);
+}
+arch_initcall(x1e80100_pinctrl_init);
+
+static void __exit x1e80100_pinctrl_exit(void)
+{
+ platform_driver_unregister(&x1e80100_pinctrl_driver);
+}
+module_exit(x1e80100_pinctrl_exit);
+
+MODULE_DESCRIPTION("QTI X1E80100 TLMM pinctrl driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, x1e80100_pinctrl_of_match);
diff --git a/drivers/pinctrl/renesas/pinctrl-rza1.c b/drivers/pinctrl/renesas/pinctrl-rza1.c
index f43f1196fea8..edcbe7c9ad56 100644
--- a/drivers/pinctrl/renesas/pinctrl-rza1.c
+++ b/drivers/pinctrl/renesas/pinctrl-rza1.c
@@ -1131,7 +1131,7 @@ static int rza1_set_mux(struct pinctrl_dev *pctldev, unsigned int selector,
return -EINVAL;
mux_confs = (struct rza1_mux_conf *)func->data;
- for (i = 0; i < grp->num_pins; ++i) {
+ for (i = 0; i < grp->grp.npins; ++i) {
int ret;
ret = rza1_pin_mux_single(rza1_pctl, &mux_confs[i]);
diff --git a/drivers/pinctrl/renesas/pinctrl-rza2.c b/drivers/pinctrl/renesas/pinctrl-rza2.c
index 990b96d45967..af689d7c117f 100644
--- a/drivers/pinctrl/renesas/pinctrl-rza2.c
+++ b/drivers/pinctrl/renesas/pinctrl-rza2.c
@@ -447,15 +447,15 @@ static int rza2_set_mux(struct pinctrl_dev *pctldev, unsigned int selector,
psel_val = func->data;
- for (i = 0; i < grp->num_pins; ++i) {
+ for (i = 0; i < grp->grp.npins; ++i) {
dev_dbg(priv->dev, "Setting P%c_%d to PSEL=%d\n",
- port_names[RZA2_PIN_ID_TO_PORT(grp->pins[i])],
- RZA2_PIN_ID_TO_PIN(grp->pins[i]),
+ port_names[RZA2_PIN_ID_TO_PORT(grp->grp.pins[i])],
+ RZA2_PIN_ID_TO_PIN(grp->grp.pins[i]),
psel_val[i]);
rza2_set_pin_function(
priv->base,
- RZA2_PIN_ID_TO_PORT(grp->pins[i]),
- RZA2_PIN_ID_TO_PIN(grp->pins[i]),
+ RZA2_PIN_ID_TO_PORT(grp->grp.pins[i]),
+ RZA2_PIN_ID_TO_PIN(grp->grp.pins[i]),
psel_val[i]);
}
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index 9de350ad7e7d..80fb5011c7bb 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -57,6 +57,7 @@
#define PIN_CFG_FILCLKSEL BIT(12)
#define PIN_CFG_IOLH_C BIT(13)
#define PIN_CFG_SOFT_PS BIT(14)
+#define PIN_CFG_OEN BIT(15)
#define RZG2L_MPXED_COMMON_PIN_FUNCS(group) \
(PIN_CFG_IOLH_##group | \
@@ -107,8 +108,11 @@
#define IEN(off) (0x1800 + (off) * 8)
#define ISEL(off) (0x2C00 + (off) * 8)
#define SD_CH(off, ch) ((off) + (ch) * 4)
+#define ETH_POC(off, ch) ((off) + (ch) * 4)
#define QSPI (0x3008)
+#define ETH_MODE (0x3018)
+#define PVDD_2500 2 /* I/O domain voltage 2.5V */
#define PVDD_1800 1 /* I/O domain voltage <= 1.8V */
#define PVDD_3300 0 /* I/O domain voltage >= 3.3V */
@@ -116,7 +120,6 @@
#define PWPR_PFCWE BIT(6) /* PFC Register Write Enable */
#define PM_MASK 0x03
-#define PVDD_MASK 0x01
#define PFC_MASK 0x07
#define IEN_MASK 0x01
#define IOLH_MASK 0x03
@@ -135,10 +138,12 @@
* struct rzg2l_register_offsets - specific register offsets
* @pwpr: PWPR register offset
* @sd_ch: SD_CH register offset
+ * @eth_poc: ETH_POC register offset
*/
struct rzg2l_register_offsets {
u16 pwpr;
u16 sd_ch;
+ u16 eth_poc;
};
/**
@@ -167,6 +172,8 @@ enum rzg2l_iolh_index {
* @iolh_groupb_oi: IOLH group B output impedance specific values
* @drive_strength_ua: drive strength in uA is supported (otherwise mA is supported)
* @func_base: base number for port function (see register PFC)
+ * @oen_max_pin: the maximum pin number supporting output enable
+ * @oen_max_port: the maximum port number supporting output enable
*/
struct rzg2l_hwcfg {
const struct rzg2l_register_offsets regs;
@@ -176,6 +183,8 @@ struct rzg2l_hwcfg {
u16 iolh_groupb_oi[4];
bool drive_strength_ua;
u8 func_base;
+ u8 oen_max_pin;
+ u8 oen_max_port;
};
struct rzg2l_dedicated_configs {
@@ -273,7 +282,7 @@ static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev,
struct function_desc *func;
unsigned int i, *psel_val;
struct group_desc *group;
- int *pins;
+ const unsigned int *pins;
func = pinmux_generic_get_function(pctldev, func_selector);
if (!func)
@@ -283,9 +292,9 @@ static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev,
return -EINVAL;
psel_val = func->data;
- pins = group->pins;
+ pins = group->grp.pins;
- for (i = 0; i < group->num_pins; i++) {
+ for (i = 0; i < group->grp.npins; i++) {
unsigned int *pin_data = pctrl->desc.pins[pins[i]].drv_data;
u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
u32 pin = RZG2L_PIN_ID_TO_PIN(pins[i]);
@@ -376,8 +385,11 @@ static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev,
goto done;
}
- if (num_pinmux)
+ if (num_pinmux) {
nmaps += 1;
+ if (num_configs)
+ nmaps += 1;
+ }
if (num_pins)
nmaps += num_pins;
@@ -462,6 +474,16 @@ static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev,
maps[idx].data.mux.function = name;
idx++;
+ if (num_configs) {
+ ret = rzg2l_map_add_config(&maps[idx], name,
+ PIN_MAP_TYPE_CONFIGS_GROUP,
+ configs, num_configs);
+ if (ret < 0)
+ goto remove_group;
+
+ idx++;
+ }
+
dev_dbg(pctrl->dev, "Parsed %pOF with %d pins\n", np, num_pinmux);
ret = 0;
goto done;
@@ -591,6 +613,10 @@ static int rzg2l_caps_to_pwr_reg(const struct rzg2l_register_offsets *regs, u32
return SD_CH(regs->sd_ch, 0);
if (caps & PIN_CFG_IO_VMC_SD1)
return SD_CH(regs->sd_ch, 1);
+ if (caps & PIN_CFG_IO_VMC_ETH0)
+ return ETH_POC(regs->eth_poc, 0);
+ if (caps & PIN_CFG_IO_VMC_ETH1)
+ return ETH_POC(regs->eth_poc, 1);
if (caps & PIN_CFG_IO_VMC_QSPI)
return QSPI;
@@ -602,6 +628,7 @@ static int rzg2l_get_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps
const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
const struct rzg2l_register_offsets *regs = &hwcfg->regs;
int pwr_reg;
+ u8 val;
if (caps & PIN_CFG_SOFT_PS)
return pctrl->settings[pin].power_source;
@@ -610,7 +637,18 @@ static int rzg2l_get_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps
if (pwr_reg < 0)
return pwr_reg;
- return (readl(pctrl->base + pwr_reg) & PVDD_MASK) ? 1800 : 3300;
+ val = readb(pctrl->base + pwr_reg);
+ switch (val) {
+ case PVDD_1800:
+ return 1800;
+ case PVDD_2500:
+ return 2500;
+ case PVDD_3300:
+ return 3300;
+ default:
+ /* Should not happen. */
+ return -EINVAL;
+ }
}
static int rzg2l_set_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps, u32 ps)
@@ -618,17 +656,32 @@ static int rzg2l_set_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps
const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
const struct rzg2l_register_offsets *regs = &hwcfg->regs;
int pwr_reg;
+ u8 val;
if (caps & PIN_CFG_SOFT_PS) {
pctrl->settings[pin].power_source = ps;
return 0;
}
+ switch (ps) {
+ case 1800:
+ val = PVDD_1800;
+ break;
+ case 2500:
+ val = PVDD_2500;
+ break;
+ case 3300:
+ val = PVDD_3300;
+ break;
+ default:
+ return -EINVAL;
+ }
+
pwr_reg = rzg2l_caps_to_pwr_reg(regs, caps);
if (pwr_reg < 0)
return pwr_reg;
- writel((ps == 1800) ? PVDD_1800 : PVDD_3300, pctrl->base + pwr_reg);
+ writeb(val, pctrl->base + pwr_reg);
pctrl->settings[pin].power_source = ps;
return 0;
@@ -735,6 +788,66 @@ static bool rzg2l_ds_is_supported(struct rzg2l_pinctrl *pctrl, u32 caps,
return false;
}
+static bool rzg2l_oen_is_supported(u32 caps, u8 pin, u8 max_pin)
+{
+ if (!(caps & PIN_CFG_OEN))
+ return false;
+
+ if (pin > max_pin)
+ return false;
+
+ return true;
+}
+
+static u8 rzg2l_pin_to_oen_bit(u32 offset, u8 pin, u8 max_port)
+{
+ if (pin)
+ pin *= 2;
+
+ if (offset / RZG2L_PINS_PER_PORT == max_port)
+ pin += 1;
+
+ return pin;
+}
+
+static u32 rzg2l_read_oen(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin)
+{
+ u8 max_port = pctrl->data->hwcfg->oen_max_port;
+ u8 max_pin = pctrl->data->hwcfg->oen_max_pin;
+ u8 bit;
+
+ if (!rzg2l_oen_is_supported(caps, pin, max_pin))
+ return 0;
+
+ bit = rzg2l_pin_to_oen_bit(offset, pin, max_port);
+
+ return !(readb(pctrl->base + ETH_MODE) & BIT(bit));
+}
+
+static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin, u8 oen)
+{
+ u8 max_port = pctrl->data->hwcfg->oen_max_port;
+ u8 max_pin = pctrl->data->hwcfg->oen_max_pin;
+ unsigned long flags;
+ u8 val, bit;
+
+ if (!rzg2l_oen_is_supported(caps, pin, max_pin))
+ return -EINVAL;
+
+ bit = rzg2l_pin_to_oen_bit(offset, pin, max_port);
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+ val = readb(pctrl->base + ETH_MODE);
+ if (oen)
+ val &= ~BIT(bit);
+ else
+ val |= BIT(bit);
+ writeb(val, pctrl->base + ETH_MODE);
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+}
+
static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
unsigned int _pin,
unsigned long *config)
@@ -772,6 +885,12 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
return -EINVAL;
break;
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ arg = rzg2l_read_oen(pctrl, cfg, _pin, bit);
+ if (!arg)
+ return -EINVAL;
+ break;
+
case PIN_CONFIG_POWER_SOURCE:
ret = rzg2l_get_power_source(pctrl, _pin, cfg);
if (ret < 0)
@@ -842,7 +961,7 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
struct rzg2l_pinctrl_pin_settings settings = pctrl->settings[_pin];
unsigned int *pin_data = pin->drv_data;
enum pin_config_param param;
- unsigned int i;
+ unsigned int i, arg, index;
u32 cfg, off;
int ret;
u8 bit;
@@ -864,24 +983,28 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
for (i = 0; i < num_configs; i++) {
param = pinconf_to_config_param(_configs[i]);
switch (param) {
- case PIN_CONFIG_INPUT_ENABLE: {
- unsigned int arg =
- pinconf_to_config_argument(_configs[i]);
+ case PIN_CONFIG_INPUT_ENABLE:
+ arg = pinconf_to_config_argument(_configs[i]);
if (!(cfg & PIN_CFG_IEN))
return -EINVAL;
rzg2l_rmw_pin_config(pctrl, IEN(off), bit, IEN_MASK, !!arg);
break;
- }
+
+ case PIN_CONFIG_OUTPUT_ENABLE:
+ arg = pinconf_to_config_argument(_configs[i]);
+ ret = rzg2l_write_oen(pctrl, cfg, _pin, bit, !!arg);
+ if (ret)
+ return ret;
+ break;
case PIN_CONFIG_POWER_SOURCE:
settings.power_source = pinconf_to_config_argument(_configs[i]);
break;
- case PIN_CONFIG_DRIVE_STRENGTH: {
- unsigned int arg = pinconf_to_config_argument(_configs[i]);
- unsigned int index;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ arg = pinconf_to_config_argument(_configs[i]);
if (!(cfg & PIN_CFG_IOLH_A) || hwcfg->drive_strength_ua)
return -EINVAL;
@@ -896,7 +1019,6 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
rzg2l_rmw_pin_config(pctrl, IOLH(off), bit, IOLH_MASK, index);
break;
- }
case PIN_CONFIG_DRIVE_STRENGTH_UA:
if (!(cfg & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C)) ||
@@ -906,9 +1028,8 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
settings.drive_strength_ua = pinconf_to_config_argument(_configs[i]);
break;
- case PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS: {
- unsigned int arg = pinconf_to_config_argument(_configs[i]);
- unsigned int index;
+ case PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS:
+ arg = pinconf_to_config_argument(_configs[i]);
if (!(cfg & PIN_CFG_IOLH_B) || !hwcfg->iolh_groupb_oi[0])
return -EINVAL;
@@ -922,7 +1043,6 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
rzg2l_rmw_pin_config(pctrl, IOLH(off), bit, IOLH_MASK, index);
break;
- }
default:
return -EOPNOTSUPP;
@@ -1323,7 +1443,8 @@ static const u32 r9a07g043_gpio_configs[] = {
static const u32 r9a08g045_gpio_configs[] = {
RZG2L_GPIO_PORT_PACK(4, 0x20, RZG3S_MPXED_PIN_FUNCS(A)), /* P0 */
RZG2L_GPIO_PORT_PACK(5, 0x30, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
- PIN_CFG_IO_VMC_ETH0)), /* P1 */
+ PIN_CFG_IO_VMC_ETH0)) |
+ PIN_CFG_OEN | PIN_CFG_IEN, /* P1 */
RZG2L_GPIO_PORT_PACK(4, 0x31, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
PIN_CFG_IO_VMC_ETH0)), /* P2 */
RZG2L_GPIO_PORT_PACK(4, 0x32, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
@@ -1333,7 +1454,8 @@ static const u32 r9a08g045_gpio_configs[] = {
RZG2L_GPIO_PORT_PACK(5, 0x21, RZG3S_MPXED_PIN_FUNCS(A)), /* P5 */
RZG2L_GPIO_PORT_PACK(5, 0x22, RZG3S_MPXED_PIN_FUNCS(A)), /* P6 */
RZG2L_GPIO_PORT_PACK(5, 0x34, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
- PIN_CFG_IO_VMC_ETH1)), /* P7 */
+ PIN_CFG_IO_VMC_ETH1)) |
+ PIN_CFG_OEN | PIN_CFG_IEN, /* P7 */
RZG2L_GPIO_PORT_PACK(5, 0x35, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
PIN_CFG_IO_VMC_ETH1)), /* P8 */
RZG2L_GPIO_PORT_PACK(4, 0x36, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
@@ -1576,6 +1698,7 @@ static const struct irq_chip rzg2l_gpio_irqchip = {
.irq_set_type = rzg2l_gpio_irq_set_type,
.irq_eoi = rzg2l_gpio_irqc_eoi,
.irq_print_chip = rzg2l_gpio_irq_print_chip,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
.flags = IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
@@ -1877,6 +2000,7 @@ static const struct rzg2l_hwcfg rzg2l_hwcfg = {
.regs = {
.pwpr = 0x3014,
.sd_ch = 0x3000,
+ .eth_poc = 0x300c,
},
.iolh_groupa_ua = {
/* 3v3 power source */
@@ -1889,6 +2013,7 @@ static const struct rzg2l_hwcfg rzg3s_hwcfg = {
.regs = {
.pwpr = 0x3000,
.sd_ch = 0x3004,
+ .eth_poc = 0x3010,
},
.iolh_groupa_ua = {
/* 1v8 power source */
@@ -1912,6 +2037,8 @@ static const struct rzg2l_hwcfg rzg3s_hwcfg = {
},
.drive_strength_ua = true,
.func_base = 1,
+ .oen_max_pin = 1, /* Pin 1 of P0 and P7 is the maximum OEN pin. */
+ .oen_max_port = 7, /* P7_1 is the maximum OEN port. */
};
static struct rzg2l_pinctrl_data r9a07g043_data = {
diff --git a/drivers/pinctrl/renesas/pinctrl-rzv2m.c b/drivers/pinctrl/renesas/pinctrl-rzv2m.c
index 21d7d5ac8c4a..0767a5ac23e0 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzv2m.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzv2m.c
@@ -165,7 +165,7 @@ static int rzv2m_pinctrl_set_mux(struct pinctrl_dev *pctldev,
struct function_desc *func;
unsigned int i, *psel_val;
struct group_desc *group;
- int *pins;
+ const unsigned int *pins;
func = pinmux_generic_get_function(pctldev, func_selector);
if (!func)
@@ -175,9 +175,9 @@ static int rzv2m_pinctrl_set_mux(struct pinctrl_dev *pctldev,
return -EINVAL;
psel_val = func->data;
- pins = group->pins;
+ pins = group->grp.pins;
- for (i = 0; i < group->num_pins; i++) {
+ for (i = 0; i < group->grp.npins; i++) {
dev_dbg(pctrl->dev, "port:%u pin: %u PSEL:%u\n",
RZV2M_PIN_ID_TO_PORT(pins[i]), RZV2M_PIN_ID_TO_PIN(pins[i]),
psel_val[i]);
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
index cb965cf93705..5480e0884abe 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
@@ -726,6 +726,146 @@ const struct samsung_pinctrl_of_match_data exynosautov9_of_data __initconst = {
.num_ctrl = ARRAY_SIZE(exynosautov9_pin_ctrl),
};
+/* pin banks of exynosautov920 pin-controller 0 (ALIVE) */
+static const struct samsung_pin_bank_data exynosautov920_pin_banks0[] = {
+ EXYNOSV920_PIN_BANK_EINTW(8, 0x0000, "gpa0", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTW(2, 0x1000, "gpa1", 0x18, 0x20, 0x24),
+ EXYNOS850_PIN_BANK_EINTN(2, 0x2000, "gpq0"),
+};
+
+/* pin banks of exynosautov920 pin-controller 1 (AUD) */
+static const struct samsung_pin_bank_data exynosautov920_pin_banks1[] = {
+ EXYNOSV920_PIN_BANK_EINTG(7, 0x0000, "gpb0", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(6, 0x1000, "gpb1", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(8, 0x2000, "gpb2", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(8, 0x3000, "gpb3", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(8, 0x4000, "gpb4", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(5, 0x5000, "gpb5", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(5, 0x6000, "gpb6", 0x18, 0x24, 0x28),
+};
+
+/* pin banks of exynosautov920 pin-controller 2 (HSI0) */
+static const struct samsung_pin_bank_data exynosautov920_pin_banks2[] = {
+ EXYNOSV920_PIN_BANK_EINTG(6, 0x0000, "gph0", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(2, 0x1000, "gph1", 0x18, 0x20, 0x24),
+};
+
+/* pin banks of exynosautov920 pin-controller 3 (HSI1) */
+static const struct samsung_pin_bank_data exynosautov920_pin_banks3[] = {
+ EXYNOSV920_PIN_BANK_EINTG(7, 0x000, "gph8", 0x18, 0x24, 0x28),
+};
+
+/* pin banks of exynosautov920 pin-controller 4 (HSI2) */
+static const struct samsung_pin_bank_data exynosautov920_pin_banks4[] = {
+ EXYNOSV920_PIN_BANK_EINTG(8, 0x0000, "gph3", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(7, 0x1000, "gph4", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(8, 0x2000, "gph5", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(7, 0x3000, "gph6", 0x18, 0x24, 0x28),
+};
+
+/* pin banks of exynosautov920 pin-controller 5 (HSI2UFS) */
+static const struct samsung_pin_bank_data exynosautov920_pin_banks5[] = {
+ EXYNOSV920_PIN_BANK_EINTG(4, 0x000, "gph2", 0x18, 0x20, 0x24),
+};
+
+/* pin banks of exynosautov920 pin-controller 6 (PERIC0) */
+static const struct samsung_pin_bank_data exynosautov920_pin_banks6[] = {
+ EXYNOSV920_PIN_BANK_EINTG(8, 0x0000, "gpp0", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(8, 0x1000, "gpp1", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(8, 0x2000, "gpp2", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(5, 0x3000, "gpg0", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(8, 0x4000, "gpp3", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(4, 0x5000, "gpp4", 0x18, 0x20, 0x24),
+ EXYNOSV920_PIN_BANK_EINTG(4, 0x6000, "gpg2", 0x18, 0x20, 0x24),
+ EXYNOSV920_PIN_BANK_EINTG(4, 0x7000, "gpg5", 0x18, 0x20, 0x24),
+ EXYNOSV920_PIN_BANK_EINTG(3, 0x8000, "gpg3", 0x18, 0x20, 0x24),
+ EXYNOSV920_PIN_BANK_EINTG(5, 0x9000, "gpg4", 0x18, 0x24, 0x28),
+};
+
+/* pin banks of exynosautov920 pin-controller 7 (PERIC1) */
+static const struct samsung_pin_bank_data exynosautov920_pin_banks7[] = {
+ EXYNOSV920_PIN_BANK_EINTG(8, 0x0000, "gpp5", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(5, 0x1000, "gpp6", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(4, 0x2000, "gpp10", 0x18, 0x20, 0x24),
+ EXYNOSV920_PIN_BANK_EINTG(8, 0x3000, "gpp7", 0x18, 0x24, 0x28),
+ EXYNOSV920_PIN_BANK_EINTG(4, 0x4000, "gpp8", 0x18, 0x20, 0x24),
+ EXYNOSV920_PIN_BANK_EINTG(4, 0x5000, "gpp11", 0x18, 0x20, 0x24),
+ EXYNOSV920_PIN_BANK_EINTG(4, 0x6000, "gpp9", 0x18, 0x20, 0x24),
+ EXYNOSV920_PIN_BANK_EINTG(4, 0x7000, "gpp12", 0x18, 0x20, 0x24),
+ EXYNOSV920_PIN_BANK_EINTG(8, 0x8000, "gpg1", 0x18, 0x24, 0x28),
+};
+
+static const struct samsung_retention_data exynosautov920_retention_data __initconst = {
+ .regs = NULL,
+ .nr_regs = 0,
+ .value = 0,
+ .refcnt = &exynos_shared_retention_refcnt,
+ .init = exynos_retention_init,
+};
+
+static const struct samsung_pin_ctrl exynosautov920_pin_ctrl[] = {
+ {
+ /* pin-controller instance 0 ALIVE data */
+ .pin_banks = exynosautov920_pin_banks0,
+ .nr_banks = ARRAY_SIZE(exynosautov920_pin_banks0),
+ .eint_wkup_init = exynos_eint_wkup_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ .retention_data = &exynosautov920_retention_data,
+ }, {
+ /* pin-controller instance 1 AUD data */
+ .pin_banks = exynosautov920_pin_banks1,
+ .nr_banks = ARRAY_SIZE(exynosautov920_pin_banks1),
+ }, {
+ /* pin-controller instance 2 HSI0 data */
+ .pin_banks = exynosautov920_pin_banks2,
+ .nr_banks = ARRAY_SIZE(exynosautov920_pin_banks2),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin-controller instance 3 HSI1 data */
+ .pin_banks = exynosautov920_pin_banks3,
+ .nr_banks = ARRAY_SIZE(exynosautov920_pin_banks3),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin-controller instance 4 HSI2 data */
+ .pin_banks = exynosautov920_pin_banks4,
+ .nr_banks = ARRAY_SIZE(exynosautov920_pin_banks4),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin-controller instance 5 HSI2UFS data */
+ .pin_banks = exynosautov920_pin_banks5,
+ .nr_banks = ARRAY_SIZE(exynosautov920_pin_banks5),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin-controller instance 6 PERIC0 data */
+ .pin_banks = exynosautov920_pin_banks6,
+ .nr_banks = ARRAY_SIZE(exynosautov920_pin_banks6),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin-controller instance 7 PERIC1 data */
+ .pin_banks = exynosautov920_pin_banks7,
+ .nr_banks = ARRAY_SIZE(exynosautov920_pin_banks7),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ },
+};
+
+const struct samsung_pinctrl_of_match_data exynosautov920_of_data __initconst = {
+ .ctrl = exynosautov920_pin_ctrl,
+ .num_ctrl = ARRAY_SIZE(exynosautov920_pin_ctrl),
+};
+
/*
* Pinctrl driver data for Tesla FSD SoC. FSD SoC includes three
* gpio/pin-mux/pinconfig controllers.
@@ -796,3 +936,143 @@ const struct samsung_pinctrl_of_match_data fsd_of_data __initconst = {
.ctrl = fsd_pin_ctrl,
.num_ctrl = ARRAY_SIZE(fsd_pin_ctrl),
};
+
+/* pin banks of gs101 pin-controller (ALIVE) */
+static const struct samsung_pin_bank_data gs101_pin_alive[] = {
+ EXYNOS850_PIN_BANK_EINTW(8, 0x0, "gpa0", 0x00),
+ EXYNOS850_PIN_BANK_EINTW(7, 0x20, "gpa1", 0x04),
+ EXYNOS850_PIN_BANK_EINTW(5, 0x40, "gpa2", 0x08),
+ EXYNOS850_PIN_BANK_EINTW(4, 0x60, "gpa3", 0x0c),
+ EXYNOS850_PIN_BANK_EINTW(4, 0x80, "gpa4", 0x10),
+ EXYNOS850_PIN_BANK_EINTW(7, 0xa0, "gpa5", 0x14),
+ EXYNOS850_PIN_BANK_EINTW(8, 0xc0, "gpa9", 0x18),
+ EXYNOS850_PIN_BANK_EINTW(2, 0xe0, "gpa10", 0x1c),
+};
+
+/* pin banks of gs101 pin-controller (FAR_ALIVE) */
+static const struct samsung_pin_bank_data gs101_pin_far_alive[] = {
+ EXYNOS850_PIN_BANK_EINTW(8, 0x0, "gpa6", 0x00),
+ EXYNOS850_PIN_BANK_EINTW(4, 0x20, "gpa7", 0x04),
+ EXYNOS850_PIN_BANK_EINTW(8, 0x40, "gpa8", 0x08),
+ EXYNOS850_PIN_BANK_EINTW(2, 0x60, "gpa11", 0x0c),
+};
+
+/* pin banks of gs101 pin-controller (GSACORE) */
+static const struct samsung_pin_bank_data gs101_pin_gsacore[] = {
+ EXYNOS850_PIN_BANK_EINTG(2, 0x0, "gps0", 0x00),
+ EXYNOS850_PIN_BANK_EINTG(8, 0x20, "gps1", 0x04),
+ EXYNOS850_PIN_BANK_EINTG(3, 0x40, "gps2", 0x08),
+};
+
+/* pin banks of gs101 pin-controller (GSACTRL) */
+static const struct samsung_pin_bank_data gs101_pin_gsactrl[] = {
+ EXYNOS850_PIN_BANK_EINTW(6, 0x0, "gps3", 0x00),
+};
+
+/* pin banks of gs101 pin-controller (PERIC0) */
+static const struct samsung_pin_bank_data gs101_pin_peric0[] = {
+ EXYNOS850_PIN_BANK_EINTG(5, 0x0, "gpp0", 0x00),
+ EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpp1", 0x04),
+ EXYNOS850_PIN_BANK_EINTG(4, 0x40, "gpp2", 0x08),
+ EXYNOS850_PIN_BANK_EINTG(2, 0x60, "gpp3", 0x0c),
+ EXYNOS850_PIN_BANK_EINTG(4, 0x80, "gpp4", 0x10),
+ EXYNOS850_PIN_BANK_EINTG(2, 0xa0, "gpp5", 0x14),
+ EXYNOS850_PIN_BANK_EINTG(4, 0xc0, "gpp6", 0x18),
+ EXYNOS850_PIN_BANK_EINTG(2, 0xe0, "gpp7", 0x1c),
+ EXYNOS850_PIN_BANK_EINTG(4, 0x100, "gpp8", 0x20),
+ EXYNOS850_PIN_BANK_EINTG(2, 0x120, "gpp9", 0x24),
+ EXYNOS850_PIN_BANK_EINTG(4, 0x140, "gpp10", 0x28),
+ EXYNOS850_PIN_BANK_EINTG(2, 0x160, "gpp11", 0x2c),
+ EXYNOS850_PIN_BANK_EINTG(4, 0x180, "gpp12", 0x30),
+ EXYNOS850_PIN_BANK_EINTG(2, 0x1a0, "gpp13", 0x34),
+ EXYNOS850_PIN_BANK_EINTG(4, 0x1c0, "gpp14", 0x38),
+ EXYNOS850_PIN_BANK_EINTG(2, 0x1e0, "gpp15", 0x3c),
+ EXYNOS850_PIN_BANK_EINTG(4, 0x200, "gpp16", 0x40),
+ EXYNOS850_PIN_BANK_EINTG(2, 0x220, "gpp17", 0x44),
+ EXYNOS850_PIN_BANK_EINTG(4, 0x240, "gpp18", 0x48),
+ EXYNOS850_PIN_BANK_EINTG(4, 0x260, "gpp19", 0x4c),
+};
+
+/* pin banks of gs101 pin-controller (PERIC1) */
+static const struct samsung_pin_bank_data gs101_pin_peric1[] = {
+ EXYNOS850_PIN_BANK_EINTG(8, 0x0, "gpp20", 0x00),
+ EXYNOS850_PIN_BANK_EINTG(4, 0x20, "gpp21", 0x04),
+ EXYNOS850_PIN_BANK_EINTG(2, 0x40, "gpp22", 0x08),
+ EXYNOS850_PIN_BANK_EINTG(8, 0x60, "gpp23", 0x0c),
+ EXYNOS850_PIN_BANK_EINTG(4, 0x80, "gpp24", 0x10),
+ EXYNOS850_PIN_BANK_EINTG(4, 0xa0, "gpp25", 0x14),
+ EXYNOS850_PIN_BANK_EINTG(5, 0xc0, "gpp26", 0x18),
+ EXYNOS850_PIN_BANK_EINTG(4, 0xe0, "gpp27", 0x1c),
+};
+
+/* pin banks of gs101 pin-controller (HSI1) */
+static const struct samsung_pin_bank_data gs101_pin_hsi1[] = {
+ EXYNOS850_PIN_BANK_EINTG(6, 0x0, "gph0", 0x00),
+ EXYNOS850_PIN_BANK_EINTG(7, 0x20, "gph1", 0x04),
+};
+
+/* pin banks of gs101 pin-controller (HSI2) */
+static const struct samsung_pin_bank_data gs101_pin_hsi2[] = {
+ EXYNOS850_PIN_BANK_EINTG(6, 0x0, "gph2", 0x00),
+ EXYNOS850_PIN_BANK_EINTG(2, 0x20, "gph3", 0x04),
+ EXYNOS850_PIN_BANK_EINTG(6, 0x40, "gph4", 0x08),
+};
+
+static const struct samsung_pin_ctrl gs101_pin_ctrl[] __initconst = {
+ {
+ /* pin banks of gs101 pin-controller (ALIVE) */
+ .pin_banks = gs101_pin_alive,
+ .nr_banks = ARRAY_SIZE(gs101_pin_alive),
+ .eint_wkup_init = exynos_eint_wkup_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin banks of gs101 pin-controller (FAR_ALIVE) */
+ .pin_banks = gs101_pin_far_alive,
+ .nr_banks = ARRAY_SIZE(gs101_pin_far_alive),
+ .eint_wkup_init = exynos_eint_wkup_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin banks of gs101 pin-controller (GSACORE) */
+ .pin_banks = gs101_pin_gsacore,
+ .nr_banks = ARRAY_SIZE(gs101_pin_gsacore),
+ }, {
+ /* pin banks of gs101 pin-controller (GSACTRL) */
+ .pin_banks = gs101_pin_gsactrl,
+ .nr_banks = ARRAY_SIZE(gs101_pin_gsactrl),
+ }, {
+ /* pin banks of gs101 pin-controller (PERIC0) */
+ .pin_banks = gs101_pin_peric0,
+ .nr_banks = ARRAY_SIZE(gs101_pin_peric0),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin banks of gs101 pin-controller (PERIC1) */
+ .pin_banks = gs101_pin_peric1,
+ .nr_banks = ARRAY_SIZE(gs101_pin_peric1),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin banks of gs101 pin-controller (HSI1) */
+ .pin_banks = gs101_pin_hsi1,
+ .nr_banks = ARRAY_SIZE(gs101_pin_hsi1),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin banks of gs101 pin-controller (HSI2) */
+ .pin_banks = gs101_pin_hsi2,
+ .nr_banks = ARRAY_SIZE(gs101_pin_hsi2),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ },
+};
+
+const struct samsung_pinctrl_of_match_data gs101_of_data __initconst = {
+ .ctrl = gs101_pin_ctrl,
+ .num_ctrl = ARRAY_SIZE(gs101_pin_ctrl),
+};
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index 6b58ec84e34b..871c1eb46ddf 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -52,10 +52,15 @@ static void exynos_irq_mask(struct irq_data *irqd)
struct irq_chip *chip = irq_data_get_irq_chip(irqd);
struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
- unsigned long reg_mask = our_chip->eint_mask + bank->eint_offset;
+ unsigned long reg_mask;
unsigned int mask;
unsigned long flags;
+ if (bank->eint_mask_offset)
+ reg_mask = bank->pctl_offset + bank->eint_mask_offset;
+ else
+ reg_mask = our_chip->eint_mask + bank->eint_offset;
+
raw_spin_lock_irqsave(&bank->slock, flags);
mask = readl(bank->eint_base + reg_mask);
@@ -70,7 +75,12 @@ static void exynos_irq_ack(struct irq_data *irqd)
struct irq_chip *chip = irq_data_get_irq_chip(irqd);
struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
- unsigned long reg_pend = our_chip->eint_pend + bank->eint_offset;
+ unsigned long reg_pend;
+
+ if (bank->eint_pend_offset)
+ reg_pend = bank->pctl_offset + bank->eint_pend_offset;
+ else
+ reg_pend = our_chip->eint_pend + bank->eint_offset;
writel(1 << irqd->hwirq, bank->eint_base + reg_pend);
}
@@ -80,7 +90,7 @@ static void exynos_irq_unmask(struct irq_data *irqd)
struct irq_chip *chip = irq_data_get_irq_chip(irqd);
struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
- unsigned long reg_mask = our_chip->eint_mask + bank->eint_offset;
+ unsigned long reg_mask;
unsigned int mask;
unsigned long flags;
@@ -95,6 +105,11 @@ static void exynos_irq_unmask(struct irq_data *irqd)
if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK)
exynos_irq_ack(irqd);
+ if (bank->eint_mask_offset)
+ reg_mask = bank->pctl_offset + bank->eint_mask_offset;
+ else
+ reg_mask = our_chip->eint_mask + bank->eint_offset;
+
raw_spin_lock_irqsave(&bank->slock, flags);
mask = readl(bank->eint_base + reg_mask);
@@ -111,7 +126,7 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
unsigned int con, trig_type;
- unsigned long reg_con = our_chip->eint_con + bank->eint_offset;
+ unsigned long reg_con;
switch (type) {
case IRQ_TYPE_EDGE_RISING:
@@ -139,6 +154,11 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
else
irq_set_handler_locked(irqd, handle_level_irq);
+ if (bank->eint_con_offset)
+ reg_con = bank->pctl_offset + bank->eint_con_offset;
+ else
+ reg_con = our_chip->eint_con + bank->eint_offset;
+
con = readl(bank->eint_base + reg_con);
con &= ~(EXYNOS_EINT_CON_MASK << shift);
con |= trig_type << shift;
@@ -147,6 +167,19 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type)
return 0;
}
+static int exynos_irq_set_affinity(struct irq_data *irqd,
+ const struct cpumask *dest, bool force)
+{
+ struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = bank->drvdata;
+ struct irq_data *parent = irq_get_irq_data(d->irq);
+
+ if (parent)
+ return parent->chip->irq_set_affinity(parent, dest, force);
+
+ return -EINVAL;
+}
+
static int exynos_irq_request_resources(struct irq_data *irqd)
{
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
@@ -212,6 +245,7 @@ static const struct exynos_irq_chip exynos_gpio_irq_chip __initconst = {
.irq_mask = exynos_irq_mask,
.irq_ack = exynos_irq_ack,
.irq_set_type = exynos_irq_set_type,
+ .irq_set_affinity = exynos_irq_set_affinity,
.irq_request_resources = exynos_irq_request_resources,
.irq_release_resources = exynos_irq_release_resources,
},
@@ -247,7 +281,10 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
unsigned int svc, group, pin;
int ret;
- svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET);
+ if (bank->eint_con_offset)
+ svc = readl(bank->eint_base + EXYNOSAUTO_SVC_OFFSET);
+ else
+ svc = readl(bank->eint_base + EXYNOS_SVC_OFFSET);
group = EXYNOS_SVC_GROUP(svc);
pin = svc & EXYNOS_SVC_NUM_MASK;
@@ -456,6 +493,22 @@ static const struct exynos_irq_chip exynos7_wkup_irq_chip __initconst = {
.set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
};
+static const struct exynos_irq_chip exynosautov920_wkup_irq_chip __initconst = {
+ .chip = {
+ .name = "exynosautov920_wkup_irq_chip",
+ .irq_unmask = exynos_irq_unmask,
+ .irq_mask = exynos_irq_mask,
+ .irq_ack = exynos_irq_ack,
+ .irq_set_type = exynos_irq_set_type,
+ .irq_set_wake = exynos_wkup_irq_set_wake,
+ .irq_request_resources = exynos_irq_request_resources,
+ .irq_release_resources = exynos_irq_release_resources,
+ },
+ .eint_wake_mask_value = &eint_wake_mask_value,
+ .eint_wake_mask_reg = EXYNOS5433_EINT_WAKEUP_MASK,
+ .set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
+};
+
/* list of external wakeup controllers supported */
static const struct of_device_id exynos_wkup_irq_ids[] = {
{ .compatible = "samsung,s5pv210-wakeup-eint",
@@ -468,6 +521,8 @@ static const struct of_device_id exynos_wkup_irq_ids[] = {
.data = &exynos7_wkup_irq_chip },
{ .compatible = "samsung,exynosautov9-wakeup-eint",
.data = &exynos7_wkup_irq_chip },
+ { .compatible = "samsung,exynosautov920-wakeup-eint",
+ .data = &exynosautov920_wkup_irq_chip },
{ }
};
@@ -638,7 +693,7 @@ static void exynos_pinctrl_suspend_bank(
struct samsung_pin_bank *bank)
{
struct exynos_eint_gpio_save *save = bank->soc_priv;
- void __iomem *regs = bank->eint_base;
+ const void __iomem *regs = bank->eint_base;
save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET
+ bank->eint_offset);
@@ -655,6 +710,19 @@ static void exynos_pinctrl_suspend_bank(
pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask);
}
+static void exynosauto_pinctrl_suspend_bank(struct samsung_pinctrl_drv_data *drvdata,
+ struct samsung_pin_bank *bank)
+{
+ struct exynos_eint_gpio_save *save = bank->soc_priv;
+ const void __iomem *regs = bank->eint_base;
+
+ save->eint_con = readl(regs + bank->pctl_offset + bank->eint_con_offset);
+ save->eint_mask = readl(regs + bank->pctl_offset + bank->eint_mask_offset);
+
+ pr_debug("%s: save con %#010x\n", bank->name, save->eint_con);
+ pr_debug("%s: save mask %#010x\n", bank->name, save->eint_mask);
+}
+
void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
{
struct samsung_pin_bank *bank = drvdata->pin_banks;
@@ -662,8 +730,12 @@ void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
int i;
for (i = 0; i < drvdata->nr_banks; ++i, ++bank) {
- if (bank->eint_type == EINT_TYPE_GPIO)
- exynos_pinctrl_suspend_bank(drvdata, bank);
+ if (bank->eint_type == EINT_TYPE_GPIO) {
+ if (bank->eint_con_offset)
+ exynosauto_pinctrl_suspend_bank(drvdata, bank);
+ else
+ exynos_pinctrl_suspend_bank(drvdata, bank);
+ }
else if (bank->eint_type == EINT_TYPE_WKUP) {
if (!irq_chip) {
irq_chip = bank->irq_chip;
@@ -704,14 +776,33 @@ static void exynos_pinctrl_resume_bank(
+ bank->eint_offset);
}
+static void exynosauto_pinctrl_resume_bank(struct samsung_pinctrl_drv_data *drvdata,
+ struct samsung_pin_bank *bank)
+{
+ struct exynos_eint_gpio_save *save = bank->soc_priv;
+ void __iomem *regs = bank->eint_base;
+
+ pr_debug("%s: con %#010x => %#010x\n", bank->name,
+ readl(regs + bank->pctl_offset + bank->eint_con_offset), save->eint_con);
+ pr_debug("%s: mask %#010x => %#010x\n", bank->name,
+ readl(regs + bank->pctl_offset + bank->eint_mask_offset), save->eint_mask);
+
+ writel(save->eint_con, regs + bank->pctl_offset + bank->eint_con_offset);
+ writel(save->eint_mask, regs + bank->pctl_offset + bank->eint_mask_offset);
+}
+
void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
{
struct samsung_pin_bank *bank = drvdata->pin_banks;
int i;
for (i = 0; i < drvdata->nr_banks; ++i, ++bank)
- if (bank->eint_type == EINT_TYPE_GPIO)
- exynos_pinctrl_resume_bank(drvdata, bank);
+ if (bank->eint_type == EINT_TYPE_GPIO) {
+ if (bank->eint_con_offset)
+ exynosauto_pinctrl_resume_bank(drvdata, bank);
+ else
+ exynos_pinctrl_resume_bank(drvdata, bank);
+ }
}
static void exynos_retention_enable(struct samsung_pinctrl_drv_data *drvdata)
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h
index 3ac52c2cf998..305cb1d31de4 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.h
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.h
@@ -31,6 +31,7 @@
#define EXYNOS7_WKUP_EMASK_OFFSET 0x900
#define EXYNOS7_WKUP_EPEND_OFFSET 0xA00
#define EXYNOS_SVC_OFFSET 0xB08
+#define EXYNOSAUTO_SVC_OFFSET 0xF008
/* helpers to access interrupt service register */
#define EXYNOS_SVC_GROUP_SHIFT 3
@@ -140,6 +141,30 @@
.name = id \
}
+#define EXYNOSV920_PIN_BANK_EINTG(pins, reg, id, con_offs, mask_offs, pend_offs) \
+ { \
+ .type = &exynos850_bank_type_off, \
+ .pctl_offset = reg, \
+ .nr_pins = pins, \
+ .eint_type = EINT_TYPE_GPIO, \
+ .eint_con_offset = con_offs, \
+ .eint_mask_offset = mask_offs, \
+ .eint_pend_offset = pend_offs, \
+ .name = id \
+ }
+
+#define EXYNOSV920_PIN_BANK_EINTW(pins, reg, id, con_offs, mask_offs, pend_offs) \
+ { \
+ .type = &exynos850_bank_type_alive, \
+ .pctl_offset = reg, \
+ .nr_pins = pins, \
+ .eint_type = EINT_TYPE_WKUP, \
+ .eint_con_offset = con_offs, \
+ .eint_mask_offset = mask_offs, \
+ .eint_pend_offset = pend_offs, \
+ .name = id \
+ }
+
/**
* struct exynos_weint_data: irq specific data for all the wakeup interrupts
* generated by the external wakeup interrupt controller.
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index 79babbb39ced..ed07e23e0912 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -565,7 +565,7 @@ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
/* gpiolib gpio_get callback function */
static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
{
- void __iomem *reg;
+ const void __iomem *reg;
u32 data;
struct samsung_pin_bank *bank = gpiochip_get_data(gc);
const struct samsung_pin_bank_type *type = bank->type;
@@ -1106,6 +1106,9 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
bank->eint_type = bdata->eint_type;
bank->eint_mask = bdata->eint_mask;
bank->eint_offset = bdata->eint_offset;
+ bank->eint_con_offset = bdata->eint_con_offset;
+ bank->eint_mask_offset = bdata->eint_mask_offset;
+ bank->eint_pend_offset = bdata->eint_pend_offset;
bank->name = bdata->name;
raw_spin_lock_init(&bank->slock);
@@ -1201,7 +1204,7 @@ static int __maybe_unused samsung_pinctrl_suspend(struct device *dev)
for (i = 0; i < drvdata->nr_banks; i++) {
struct samsung_pin_bank *bank = &drvdata->pin_banks[i];
- void __iomem *reg = bank->pctl_base + bank->pctl_offset;
+ const void __iomem *reg = bank->pctl_base + bank->pctl_offset;
const u8 *offs = bank->type->reg_offset;
const u8 *widths = bank->type->fld_width;
enum pincfg_type type;
@@ -1309,6 +1312,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
.data = &s5pv210_of_data },
#endif
#ifdef CONFIG_PINCTRL_EXYNOS_ARM64
+ { .compatible = "google,gs101-pinctrl",
+ .data = &gs101_of_data },
{ .compatible = "samsung,exynos5433-pinctrl",
.data = &exynos5433_of_data },
{ .compatible = "samsung,exynos7-pinctrl",
@@ -1319,6 +1324,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
.data = &exynos850_of_data },
{ .compatible = "samsung,exynosautov9-pinctrl",
.data = &exynosautov9_of_data },
+ { .compatible = "samsung,exynosautov920-pinctrl",
+ .data = &exynosautov920_of_data },
{ .compatible = "tesla,fsd-pinctrl",
.data = &fsd_of_data },
#endif
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h
index 9b3db50adef3..ab791afaabf5 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.h
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.h
@@ -122,6 +122,9 @@ struct samsung_pin_bank_type {
* @eint_type: type of the external interrupt supported by the bank.
* @eint_mask: bit mask of pins which support EINT function.
* @eint_offset: SoC-specific EINT register or interrupt offset of bank.
+ * @eint_con_offset: ExynosAuto SoC-specific EINT control register offset of bank.
+ * @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank.
+ * @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank.
* @name: name to be prefixed for each pin in this pin bank.
*/
struct samsung_pin_bank_data {
@@ -133,6 +136,9 @@ struct samsung_pin_bank_data {
enum eint_type eint_type;
u32 eint_mask;
u32 eint_offset;
+ u32 eint_con_offset;
+ u32 eint_mask_offset;
+ u32 eint_pend_offset;
const char *name;
};
@@ -147,6 +153,9 @@ struct samsung_pin_bank_data {
* @eint_type: type of the external interrupt supported by the bank.
* @eint_mask: bit mask of pins which support EINT function.
* @eint_offset: SoC-specific EINT register or interrupt offset of bank.
+ * @eint_con_offset: ExynosAuto SoC-specific EINT register or interrupt offset of bank.
+ * @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank.
+ * @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank.
* @name: name to be prefixed for each pin in this pin bank.
* @id: id of the bank, propagated to the pin range.
* @pin_base: starting pin number of the bank.
@@ -170,6 +179,9 @@ struct samsung_pin_bank {
enum eint_type eint_type;
u32 eint_mask;
u32 eint_offset;
+ u32 eint_con_offset;
+ u32 eint_mask_offset;
+ u32 eint_pend_offset;
const char *name;
u32 id;
@@ -350,7 +362,9 @@ extern const struct samsung_pinctrl_of_match_data exynos7_of_data;
extern const struct samsung_pinctrl_of_match_data exynos7885_of_data;
extern const struct samsung_pinctrl_of_match_data exynos850_of_data;
extern const struct samsung_pinctrl_of_match_data exynosautov9_of_data;
+extern const struct samsung_pinctrl_of_match_data exynosautov920_of_data;
extern const struct samsung_pinctrl_of_match_data fsd_of_data;
+extern const struct samsung_pinctrl_of_match_data gs101_of_data;
extern const struct samsung_pinctrl_of_match_data s3c64xx_of_data;
extern const struct samsung_pinctrl_of_match_data s3c2412_of_data;
extern const struct samsung_pinctrl_of_match_data s3c2416_of_data;
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c
index b29b0ab9892b..6df7a310c7ed 100644
--- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c
@@ -654,7 +654,7 @@ static int starfive_set_mux(struct pinctrl_dev *pctldev,
return -EINVAL;
pinmux = group->data;
- for (i = 0; i < group->num_pins; i++) {
+ for (i = 0; i < group->grp.npins; i++) {
u32 v = pinmux[i];
unsigned int gpio = starfive_pinmux_to_gpio(v);
u32 dout = starfive_pinmux_to_dout(v);
@@ -797,7 +797,7 @@ static int starfive_pinconf_group_get(struct pinctrl_dev *pctldev,
if (!group)
return -EINVAL;
- return starfive_pinconf_get(pctldev, group->pins[0], config);
+ return starfive_pinconf_get(pctldev, group->grp.pins[0], config);
}
static int starfive_pinconf_group_set(struct pinctrl_dev *pctldev,
@@ -876,8 +876,8 @@ static int starfive_pinconf_group_set(struct pinctrl_dev *pctldev,
}
}
- for (i = 0; i < group->num_pins; i++)
- starfive_padctl_rmw(sfp, group->pins[i], mask, value);
+ for (i = 0; i < group->grp.npins; i++)
+ starfive_padctl_rmw(sfp, group->grp.pins[i], mask, value);
return 0;
}
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c
index 6de11a405734..9609eb1ecc3d 100644
--- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c
@@ -307,7 +307,7 @@ static int jh7110_set_mux(struct pinctrl_dev *pctldev,
return -EINVAL;
pinmux = group->data;
- for (i = 0; i < group->num_pins; i++) {
+ for (i = 0; i < group->grp.npins; i++) {
u32 v = pinmux[i];
if (info->jh7110_set_one_pin_mux)
@@ -437,7 +437,7 @@ static int jh7110_pinconf_group_get(struct pinctrl_dev *pctldev,
if (!group)
return -EINVAL;
- return jh7110_pinconf_get(pctldev, group->pins[0], config);
+ return jh7110_pinconf_get(pctldev, group->grp.pins[0], config);
}
static int jh7110_pinconf_group_set(struct pinctrl_dev *pctldev,
@@ -508,8 +508,8 @@ static int jh7110_pinconf_group_set(struct pinctrl_dev *pctldev,
}
}
- for (i = 0; i < group->num_pins; i++)
- jh7110_padcfg_rmw(sfp, group->pins[i], mask, value);
+ for (i = 0; i < group->grp.npins; i++)
+ jh7110_padcfg_rmw(sfp, group->grp.pins[i], mask, value);
return 0;
}
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
index 603f900e88c1..978ccdbaf3d3 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
@@ -240,9 +240,8 @@ static int stm32_gpio_direction_output(struct gpio_chip *chip,
struct stm32_gpio_bank *bank = gpiochip_get_data(chip);
__stm32_gpio_set(bank, offset, value);
- pinctrl_gpio_direction_output(chip, offset);
- return 0;
+ return pinctrl_gpio_direction_output(chip, offset);
}
diff --git a/drivers/pinctrl/tegra/pinctrl-tegra.c b/drivers/pinctrl/tegra/pinctrl-tegra.c
index 6bf8db424bec..ccfa3870a67d 100644
--- a/drivers/pinctrl/tegra/pinctrl-tegra.c
+++ b/drivers/pinctrl/tegra/pinctrl-tegra.c
@@ -636,6 +636,14 @@ static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
seq_printf(s, "\n\t%s=%u",
strip_prefix(cfg_params[i].property), val);
}
+
+ if (g->mux_reg >= 0) {
+ /* read pinmux function and dump to seq_file */
+ val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
+ val = g->funcs[(val >> g->mux_bit) & 0x3];
+
+ seq_printf(s, "\n\tfunction=%s", pmx->functions[val].name);
+ }
}
static void tegra_pinconf_config_dbg_show(struct pinctrl_dev *pctldev,
diff --git a/drivers/platform/chrome/cros_ec_ishtp.c b/drivers/platform/chrome/cros_ec_ishtp.c
index cb2031cf7106..5ac37bd024c8 100644
--- a/drivers/platform/chrome/cros_ec_ishtp.c
+++ b/drivers/platform/chrome/cros_ec_ishtp.c
@@ -367,55 +367,33 @@ static void ish_event_cb(struct ishtp_cl_device *cl_device)
/**
* cros_ish_init() - Init function for ISHTP client
* @cros_ish_cl: ISHTP client instance
+ * @reset: true if called from reset handler
*
* This function complete the initializtion of the client.
*
* Return: 0 for success, negative error code for failure.
*/
-static int cros_ish_init(struct ishtp_cl *cros_ish_cl)
+static int cros_ish_init(struct ishtp_cl *cros_ish_cl, bool reset)
{
int rv;
- struct ishtp_device *dev;
- struct ishtp_fw_client *fw_client;
struct ishtp_cl_data *client_data = ishtp_get_client_data(cros_ish_cl);
- rv = ishtp_cl_link(cros_ish_cl);
- if (rv) {
- dev_err(cl_data_to_dev(client_data),
- "ishtp_cl_link failed\n");
- return rv;
- }
-
- dev = ishtp_get_ishtp_device(cros_ish_cl);
-
- /* Connect to firmware client */
- ishtp_set_tx_ring_size(cros_ish_cl, CROS_ISH_CL_TX_RING_SIZE);
- ishtp_set_rx_ring_size(cros_ish_cl, CROS_ISH_CL_RX_RING_SIZE);
-
- fw_client = ishtp_fw_cl_get_client(dev, &cros_ec_ishtp_id_table[0].guid);
- if (!fw_client) {
- dev_err(cl_data_to_dev(client_data),
- "ish client uuid not found\n");
- rv = -ENOENT;
- goto err_cl_unlink;
- }
-
- ishtp_cl_set_fw_client_id(cros_ish_cl,
- ishtp_get_fw_client_id(fw_client));
- ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_CONNECTING);
-
- rv = ishtp_cl_connect(cros_ish_cl);
+ rv = ishtp_cl_establish_connection(cros_ish_cl,
+ &cros_ec_ishtp_id_table[0].guid,
+ CROS_ISH_CL_TX_RING_SIZE,
+ CROS_ISH_CL_RX_RING_SIZE,
+ reset);
if (rv) {
dev_err(cl_data_to_dev(client_data),
"client connect fail\n");
- goto err_cl_unlink;
+ goto err_cl_disconnect;
}
ishtp_register_event_cb(client_data->cl_device, ish_event_cb);
return 0;
-err_cl_unlink:
- ishtp_cl_unlink(cros_ish_cl);
+err_cl_disconnect:
+ ishtp_cl_destroy_connection(cros_ish_cl, reset);
return rv;
}
@@ -427,10 +405,7 @@ err_cl_unlink:
*/
static void cros_ish_deinit(struct ishtp_cl *cros_ish_cl)
{
- ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_DISCONNECTING);
- ishtp_cl_disconnect(cros_ish_cl);
- ishtp_cl_unlink(cros_ish_cl);
- ishtp_cl_flush_queues(cros_ish_cl);
+ ishtp_cl_destroy_connection(cros_ish_cl, false);
/* Disband and free all Tx and Rx client-level rings */
ishtp_cl_free(cros_ish_cl);
@@ -592,7 +567,6 @@ static void reset_handler(struct work_struct *work)
int rv;
struct device *dev;
struct ishtp_cl *cros_ish_cl;
- struct ishtp_cl_device *cl_device;
struct ishtp_cl_data *client_data =
container_of(work, struct ishtp_cl_data, work_ishtp_reset);
@@ -600,26 +574,11 @@ static void reset_handler(struct work_struct *work)
down_write(&init_lock);
cros_ish_cl = client_data->cros_ish_cl;
- cl_device = client_data->cl_device;
- /* Unlink, flush queues & start again */
- ishtp_cl_unlink(cros_ish_cl);
- ishtp_cl_flush_queues(cros_ish_cl);
- ishtp_cl_free(cros_ish_cl);
-
- cros_ish_cl = ishtp_cl_allocate(cl_device);
- if (!cros_ish_cl) {
- up_write(&init_lock);
- return;
- }
-
- ishtp_set_drvdata(cl_device, cros_ish_cl);
- ishtp_set_client_data(cros_ish_cl, client_data);
- client_data->cros_ish_cl = cros_ish_cl;
+ ishtp_cl_destroy_connection(cros_ish_cl, true);
- rv = cros_ish_init(cros_ish_cl);
+ rv = cros_ish_init(cros_ish_cl, true);
if (rv) {
- ishtp_cl_free(cros_ish_cl);
dev_err(cl_data_to_dev(client_data), "Reset Failed\n");
up_write(&init_lock);
return;
@@ -672,7 +631,7 @@ static int cros_ec_ishtp_probe(struct ishtp_cl_device *cl_device)
INIT_WORK(&client_data->work_ec_evt,
ish_evt_handler);
- rv = cros_ish_init(cros_ish_cl);
+ rv = cros_ish_init(cros_ish_cl, false);
if (rv)
goto end_ishtp_cl_init_error;
@@ -690,10 +649,7 @@ static int cros_ec_ishtp_probe(struct ishtp_cl_device *cl_device)
return 0;
end_cros_ec_dev_init_error:
- ishtp_set_connection_state(cros_ish_cl, ISHTP_CL_DISCONNECTING);
- ishtp_cl_disconnect(cros_ish_cl);
- ishtp_cl_unlink(cros_ish_cl);
- ishtp_cl_flush_queues(cros_ish_cl);
+ ishtp_cl_destroy_connection(cros_ish_cl, false);
ishtp_put_device(cl_device);
end_ishtp_cl_init_error:
ishtp_cl_free(cros_ish_cl);
diff --git a/drivers/platform/chrome/cros_ec_uart.c b/drivers/platform/chrome/cros_ec_uart.c
index 788246559bbb..68d80559fddc 100644
--- a/drivers/platform/chrome/cros_ec_uart.c
+++ b/drivers/platform/chrome/cros_ec_uart.c
@@ -81,9 +81,8 @@ struct cros_ec_uart {
struct response_info response;
};
-static int cros_ec_uart_rx_bytes(struct serdev_device *serdev,
- const u8 *data,
- size_t count)
+static ssize_t cros_ec_uart_rx_bytes(struct serdev_device *serdev,
+ const u8 *data, size_t count)
{
struct ec_host_response *host_response;
struct cros_ec_device *ec_dev = serdev_device_get_drvdata(serdev);
diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
index 7737d56191d7..061aa9647c19 100644
--- a/drivers/platform/goldfish/goldfish_pipe.c
+++ b/drivers/platform/goldfish/goldfish_pipe.c
@@ -915,12 +915,11 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
return goldfish_pipe_device_init(pdev, dev);
}
-static int goldfish_pipe_remove(struct platform_device *pdev)
+static void goldfish_pipe_remove(struct platform_device *pdev)
{
struct goldfish_pipe_dev *dev = platform_get_drvdata(pdev);
goldfish_pipe_device_deinit(pdev, dev);
- return 0;
}
static const struct acpi_device_id goldfish_pipe_acpi_match[] = {
@@ -937,7 +936,7 @@ MODULE_DEVICE_TABLE(of, goldfish_pipe_of_match);
static struct platform_driver goldfish_pipe_driver = {
.probe = goldfish_pipe_probe,
- .remove = goldfish_pipe_remove,
+ .remove_new = goldfish_pipe_remove,
.driver = {
.name = "goldfish_pipe",
.of_match_table = goldfish_pipe_of_match,
diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
index 42ccd7f1c9b9..118caa651bec 100644
--- a/drivers/platform/surface/aggregator/bus.c
+++ b/drivers/platform/surface/aggregator/bus.c
@@ -35,6 +35,8 @@ static struct attribute *ssam_device_attrs[] = {
};
ATTRIBUTE_GROUPS(ssam_device);
+static const struct bus_type ssam_bus_type;
+
static int ssam_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
const struct ssam_device *sdev = to_ssam_device(dev);
@@ -329,13 +331,12 @@ static void ssam_bus_remove(struct device *dev)
sdrv->remove(to_ssam_device(dev));
}
-struct bus_type ssam_bus_type = {
+static const struct bus_type ssam_bus_type = {
.name = "surface_aggregator",
.match = ssam_bus_match,
.probe = ssam_bus_probe,
.remove = ssam_bus_remove,
};
-EXPORT_SYMBOL_GPL(ssam_bus_type);
/**
* __ssam_device_driver_register() - Register a SSAM client device driver.
diff --git a/drivers/platform/surface/aggregator/controller.h b/drivers/platform/surface/aggregator/controller.h
index f0d987abc51e..f1638c2081e8 100644
--- a/drivers/platform/surface/aggregator/controller.h
+++ b/drivers/platform/surface/aggregator/controller.h
@@ -238,8 +238,8 @@ struct ssam_controller {
* layer of the controller has been shut down, %-ESHUTDOWN.
*/
static inline
-int ssam_controller_receive_buf(struct ssam_controller *ctrl,
- const unsigned char *buf, size_t n)
+ssize_t ssam_controller_receive_buf(struct ssam_controller *ctrl, const u8 *buf,
+ size_t n)
{
return ssh_ptl_rx_rcvbuf(&ctrl->rtl.ptl, buf, n);
}
diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
index 6152be38398c..9591a28bc38a 100644
--- a/drivers/platform/surface/aggregator/core.c
+++ b/drivers/platform/surface/aggregator/core.c
@@ -227,8 +227,8 @@ EXPORT_SYMBOL_GPL(ssam_client_bind);
/* -- Glue layer (serdev_device -> ssam_controller). ------------------------ */
-static int ssam_receive_buf(struct serdev_device *dev, const unsigned char *buf,
- size_t n)
+static ssize_t ssam_receive_buf(struct serdev_device *dev, const u8 *buf,
+ size_t n)
{
struct ssam_controller *ctrl;
int ret;
diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c
index def8d7ac541f..d726b1a86319 100644
--- a/drivers/platform/surface/aggregator/ssh_packet_layer.c
+++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c
@@ -1887,9 +1887,9 @@ int ssh_ptl_rx_stop(struct ssh_ptl *ptl)
* Return: Returns the number of bytes transferred (positive or zero) on
* success. Returns %-ESHUTDOWN if the packet layer has been shut down.
*/
-int ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n)
+ssize_t ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n)
{
- int used;
+ size_t used;
if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state))
return -ESHUTDOWN;
diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.h b/drivers/platform/surface/aggregator/ssh_packet_layer.h
index 64633522f971..c80e822070df 100644
--- a/drivers/platform/surface/aggregator/ssh_packet_layer.h
+++ b/drivers/platform/surface/aggregator/ssh_packet_layer.h
@@ -162,7 +162,7 @@ void ssh_ptl_shutdown(struct ssh_ptl *ptl);
int ssh_ptl_submit(struct ssh_ptl *ptl, struct ssh_packet *p);
void ssh_ptl_cancel(struct ssh_packet *p);
-int ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n);
+ssize_t ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n);
/**
* ssh_ptl_tx_wakeup_transfer() - Wake up packet transmitter thread for
diff --git a/drivers/platform/x86/intel/chtwc_int33fe.c b/drivers/platform/x86/intel/chtwc_int33fe.c
index 848baecc1bb0..93f75ba1dafd 100644
--- a/drivers/platform/x86/intel/chtwc_int33fe.c
+++ b/drivers/platform/x86/intel/chtwc_int33fe.c
@@ -136,7 +136,7 @@ static const struct software_node altmodes_node = {
};
static const struct property_entry dp_altmode_properties[] = {
- PROPERTY_ENTRY_U32("svid", 0xff01),
+ PROPERTY_ENTRY_U16("svid", 0xff01),
PROPERTY_ENTRY_U32("vdo", 0x0c0086),
{ }
};
diff --git a/drivers/platform/x86/lenovo-yogabook.c b/drivers/platform/x86/lenovo-yogabook.c
index b8d0239192cb..fd62bf746ebd 100644
--- a/drivers/platform/x86/lenovo-yogabook.c
+++ b/drivers/platform/x86/lenovo-yogabook.c
@@ -435,7 +435,7 @@ static int yogabook_pdev_set_kbd_backlight(struct yogabook_data *data, u8 level)
.enabled = level,
};
- pwm_apply_state(data->kbd_bl_pwm, &state);
+ pwm_apply_might_sleep(data->kbd_bl_pwm, &state);
gpiod_set_value(data->kbd_bl_led_enable, level ? 1 : 0);
return 0;
}
diff --git a/drivers/pmdomain/Kconfig b/drivers/pmdomain/Kconfig
index c98c5bf75a14..23c64851a5b0 100644
--- a/drivers/pmdomain/Kconfig
+++ b/drivers/pmdomain/Kconfig
@@ -4,6 +4,7 @@ menu "PM Domains"
source "drivers/pmdomain/actions/Kconfig"
source "drivers/pmdomain/amlogic/Kconfig"
source "drivers/pmdomain/apple/Kconfig"
+source "drivers/pmdomain/arm/Kconfig"
source "drivers/pmdomain/bcm/Kconfig"
source "drivers/pmdomain/imx/Kconfig"
source "drivers/pmdomain/mediatek/Kconfig"
diff --git a/drivers/pmdomain/Makefile b/drivers/pmdomain/Makefile
index f0326b27b30b..a68ece2f4c68 100644
--- a/drivers/pmdomain/Makefile
+++ b/drivers/pmdomain/Makefile
@@ -16,3 +16,4 @@ obj-y += sunxi/
obj-y += tegra/
obj-y += ti/
obj-y += xilinx/
+obj-y += core.o governor.o
diff --git a/drivers/pmdomain/amlogic/meson-ee-pwrc.c b/drivers/pmdomain/amlogic/meson-ee-pwrc.c
index 0dd71cd814c5..fcec6eb610e4 100644
--- a/drivers/pmdomain/amlogic/meson-ee-pwrc.c
+++ b/drivers/pmdomain/amlogic/meson-ee-pwrc.c
@@ -47,6 +47,8 @@
#define G12A_HHI_NANOQ_MEM_PD_REG0 (0x43 << 2)
#define G12A_HHI_NANOQ_MEM_PD_REG1 (0x44 << 2)
+#define G12A_HHI_ISP_MEM_PD_REG0 (0x45 << 2)
+#define G12A_HHI_ISP_MEM_PD_REG1 (0x46 << 2)
struct meson_ee_pwrc;
struct meson_ee_pwrc_domain;
@@ -115,6 +117,13 @@ static struct meson_ee_pwrc_top_domain g12a_pwrc_nna = {
.iso_mask = BIT(16) | BIT(17),
};
+static struct meson_ee_pwrc_top_domain g12a_pwrc_isp = {
+ .sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0,
+ .sleep_mask = BIT(18) | BIT(19),
+ .iso_reg = GX_AO_RTI_GEN_PWR_ISO0,
+ .iso_mask = BIT(18) | BIT(19),
+};
+
/* Memory PD Domains */
#define VPU_MEMPD(__reg) \
@@ -231,6 +240,11 @@ static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_nna[] = {
{ G12A_HHI_NANOQ_MEM_PD_REG1, GENMASK(31, 0) },
};
+static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_isp[] = {
+ { G12A_HHI_ISP_MEM_PD_REG0, GENMASK(31, 0) },
+ { G12A_HHI_ISP_MEM_PD_REG1, GENMASK(31, 0) },
+};
+
#define VPU_PD(__name, __top_pd, __mem, __is_pwr_off, __resets, __clks) \
{ \
.name = __name, \
@@ -269,6 +283,8 @@ static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
[PWRC_G12A_ETH_ID] = MEM_PD("ETH", meson_pwrc_mem_eth),
[PWRC_G12A_NNA_ID] = TOP_PD("NNA", &g12a_pwrc_nna, g12a_pwrc_mem_nna,
pwrc_ee_is_powered_off),
+ [PWRC_G12A_ISP_ID] = TOP_PD("ISP", &g12a_pwrc_isp, g12a_pwrc_mem_isp,
+ pwrc_ee_is_powered_off),
};
static struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains[] = {
diff --git a/drivers/pmdomain/arm/Kconfig b/drivers/pmdomain/arm/Kconfig
new file mode 100644
index 000000000000..efa139c34e08
--- /dev/null
+++ b/drivers/pmdomain/arm/Kconfig
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config ARM_SCMI_PERF_DOMAIN
+ tristate "SCMI performance domain driver"
+ depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
+ default y
+ select PM_GENERIC_DOMAINS if PM
+ help
+ This enables support for the SCMI performance domains which can be
+ enabled or disabled via the SCP firmware.
+
+ This driver can also be built as a module. If so, the module will be
+ called scmi_perf_domain.
+
+config ARM_SCMI_POWER_DOMAIN
+ tristate "SCMI power domain driver"
+ depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
+ default y
+ select PM_GENERIC_DOMAINS if PM
+ help
+ This enables support for the SCMI power domains which can be
+ enabled or disabled via the SCP firmware
+
+ This driver can also be built as a module. If so, the module
+ will be called scmi_pm_domain. Note this may needed early in boot
+ before rootfs may be available.
+
+config ARM_SCPI_POWER_DOMAIN
+ tristate "SCPI power domain driver"
+ depends on ARM_SCPI_PROTOCOL || (COMPILE_TEST && OF)
+ default y
+ select PM_GENERIC_DOMAINS if PM
+ help
+ This enables support for the SCPI power domains which can be
+ enabled or disabled via the SCP firmware
+
+ This driver can also be built as a module. If so, the module will be
+ called scpi_pm_domain.
diff --git a/drivers/pmdomain/arm/Makefile b/drivers/pmdomain/arm/Makefile
index cfcb1f6cdd90..502fe4d0a83e 100644
--- a/drivers/pmdomain/arm/Makefile
+++ b/drivers/pmdomain/arm/Makefile
@@ -2,3 +2,4 @@
obj-$(CONFIG_ARM_SCMI_PERF_DOMAIN) += scmi_perf_domain.o
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
+obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o
diff --git a/drivers/firmware/scpi_pm_domain.c b/drivers/pmdomain/arm/scpi_pm_domain.c
index 2231e6dd2070..2231e6dd2070 100644
--- a/drivers/firmware/scpi_pm_domain.c
+++ b/drivers/pmdomain/arm/scpi_pm_domain.c
diff --git a/drivers/base/power/domain.c b/drivers/pmdomain/core.c
index da1777e39eaa..a1f6cba3ae6c 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/pmdomain/core.c
@@ -23,8 +23,6 @@
#include <linux/cpu.h>
#include <linux/debugfs.h>
-#include "power.h"
-
#define GENPD_RETRY_MAX_MS 250 /* Approximate */
#define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \
@@ -2670,7 +2668,7 @@ static void genpd_release_dev(struct device *dev)
kfree(dev);
}
-static struct bus_type genpd_bus_type = {
+static const struct bus_type genpd_bus_type = {
.name = "genpd",
};
@@ -3042,38 +3040,6 @@ int of_genpd_parse_idle_states(struct device_node *dn,
}
EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states);
-/**
- * pm_genpd_opp_to_performance_state - Gets performance state of the genpd from its OPP node.
- *
- * @genpd_dev: Genpd's device for which the performance-state needs to be found.
- * @opp: struct dev_pm_opp of the OPP for which we need to find performance
- * state.
- *
- * Returns performance state encoded in the OPP of the genpd. This calls
- * platform specific genpd->opp_to_performance_state() callback to translate
- * power domain OPP to performance state.
- *
- * Returns performance state on success and 0 on failure.
- */
-unsigned int pm_genpd_opp_to_performance_state(struct device *genpd_dev,
- struct dev_pm_opp *opp)
-{
- struct generic_pm_domain *genpd = NULL;
- int state;
-
- genpd = container_of(genpd_dev, struct generic_pm_domain, dev);
-
- if (unlikely(!genpd->opp_to_performance_state))
- return 0;
-
- genpd_lock(genpd);
- state = genpd->opp_to_performance_state(genpd, opp);
- genpd_unlock(genpd);
-
- return state;
-}
-EXPORT_SYMBOL_GPL(pm_genpd_opp_to_performance_state);
-
static int __init genpd_bus_init(void)
{
return bus_register(&genpd_bus_type);
diff --git a/drivers/base/power/domain_governor.c b/drivers/pmdomain/governor.c
index cc2c3a5a6d35..d1a10eeebd16 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/pmdomain/governor.c
@@ -49,6 +49,8 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
/**
* default_suspend_ok - Default PM domain governor routine to suspend devices.
* @dev: Device to check.
+ *
+ * Returns: true if OK to suspend, false if not OK to suspend
*/
static bool default_suspend_ok(struct device *dev)
{
@@ -261,6 +263,8 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
* @now: current ktime.
*
* This routine must be executed under the PM domain's lock.
+ *
+ * Returns: true if OK to power down, false if not OK to power down
*/
static bool _default_power_down_ok(struct dev_pm_domain *pd, ktime_t now)
{
@@ -406,8 +410,8 @@ struct dev_power_governor simple_qos_governor = {
.power_down_ok = default_power_down_ok,
};
-/**
- * pm_genpd_gov_always_on - A governor implementing an always-on policy
+/*
+ * pm_domain_always_on_gov - A governor implementing an always-on policy
*/
struct dev_power_governor pm_domain_always_on_gov = {
.suspend_ok = default_suspend_ok,
diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c
index 7d81e3171d39..9517cce93d8a 100644
--- a/drivers/pmdomain/imx/gpc.c
+++ b/drivers/pmdomain/imx/gpc.c
@@ -212,7 +212,7 @@ genpd_err:
return ret;
}
-static int imx_pgc_power_domain_remove(struct platform_device *pdev)
+static void imx_pgc_power_domain_remove(struct platform_device *pdev)
{
struct imx_pm_domain *domain = pdev->dev.platform_data;
@@ -221,8 +221,6 @@ static int imx_pgc_power_domain_remove(struct platform_device *pdev)
pm_genpd_remove(&domain->base);
imx_pgc_put_clocks(domain);
}
-
- return 0;
}
static const struct platform_device_id imx_pgc_power_domain_id[] = {
@@ -235,7 +233,7 @@ static struct platform_driver imx_pgc_power_domain_driver = {
.name = "imx-pgc-pd",
},
.probe = imx_pgc_power_domain_probe,
- .remove = imx_pgc_power_domain_remove,
+ .remove_new = imx_pgc_power_domain_remove,
.id_table = imx_pgc_power_domain_id,
};
builtin_platform_driver(imx_pgc_power_domain_driver)
@@ -511,7 +509,7 @@ static int imx_gpc_probe(struct platform_device *pdev)
return 0;
}
-static int imx_gpc_remove(struct platform_device *pdev)
+static void imx_gpc_remove(struct platform_device *pdev)
{
struct device_node *pgc_node;
int ret;
@@ -521,7 +519,7 @@ static int imx_gpc_remove(struct platform_device *pdev)
/* bail out if DT too old and doesn't provide the necessary info */
if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") &&
!pgc_node)
- return 0;
+ return;
/*
* If the old DT binding is used the toplevel driver needs to
@@ -531,16 +529,20 @@ static int imx_gpc_remove(struct platform_device *pdev)
of_genpd_del_provider(pdev->dev.of_node);
ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base);
- if (ret)
- return ret;
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to remove PU power domain (%pe)\n",
+ ERR_PTR(ret));
+ return;
+ }
imx_pgc_put_clocks(&imx_gpc_domains[GPC_PGC_DOMAIN_PU]);
ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base);
- if (ret)
- return ret;
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to remove ARM power domain (%pe)\n",
+ ERR_PTR(ret));
+ return;
+ }
}
-
- return 0;
}
static struct platform_driver imx_gpc_driver = {
@@ -549,6 +551,6 @@ static struct platform_driver imx_gpc_driver = {
.of_match_table = imx_gpc_dt_ids,
},
.probe = imx_gpc_probe,
- .remove = imx_gpc_remove,
+ .remove_new = imx_gpc_remove,
};
builtin_platform_driver(imx_gpc_driver)
diff --git a/drivers/pmdomain/imx/gpcv2.c b/drivers/pmdomain/imx/gpcv2.c
index fbd3d92f8cd8..4b828d74a606 100644
--- a/drivers/pmdomain/imx/gpcv2.c
+++ b/drivers/pmdomain/imx/gpcv2.c
@@ -1373,7 +1373,7 @@ out_domain_unmap:
return ret;
}
-static int imx_pgc_domain_remove(struct platform_device *pdev)
+static void imx_pgc_domain_remove(struct platform_device *pdev)
{
struct imx_pgc_domain *domain = pdev->dev.platform_data;
@@ -1385,8 +1385,6 @@ static int imx_pgc_domain_remove(struct platform_device *pdev)
domain->bits.map, 0);
pm_runtime_disable(domain->dev);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -1430,7 +1428,7 @@ static struct platform_driver imx_pgc_domain_driver = {
.pm = &imx_pgc_domain_pm_ops,
},
.probe = imx_pgc_domain_probe,
- .remove = imx_pgc_domain_remove,
+ .remove_new = imx_pgc_domain_remove,
.id_table = imx_pgc_domain_id,
};
builtin_platform_driver(imx_pgc_domain_driver)
diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
index cc5ef6e2f0a8..1341a707f61b 100644
--- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
@@ -330,7 +330,7 @@ cleanup_pds:
return ret;
}
-static int imx8m_blk_ctrl_remove(struct platform_device *pdev)
+static void imx8m_blk_ctrl_remove(struct platform_device *pdev)
{
struct imx8m_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
int i;
@@ -347,8 +347,6 @@ static int imx8m_blk_ctrl_remove(struct platform_device *pdev)
dev_pm_genpd_remove_notifier(bc->bus_power_dev);
dev_pm_domain_detach(bc->bus_power_dev, true);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -888,7 +886,7 @@ MODULE_DEVICE_TABLE(of, imx8m_blk_ctrl_of_match);
static struct platform_driver imx8m_blk_ctrl_driver = {
.probe = imx8m_blk_ctrl_probe,
- .remove = imx8m_blk_ctrl_remove,
+ .remove_new = imx8m_blk_ctrl_remove,
.driver = {
.name = "imx8m-blk-ctrl",
.pm = &imx8m_blk_ctrl_pm_ops,
diff --git a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
index c6ac32c1a8c1..e3203eb6a022 100644
--- a/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c
@@ -760,7 +760,7 @@ cleanup_pds:
return ret;
}
-static int imx8mp_blk_ctrl_remove(struct platform_device *pdev)
+static void imx8mp_blk_ctrl_remove(struct platform_device *pdev)
{
struct imx8mp_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
int i;
@@ -777,8 +777,6 @@ static int imx8mp_blk_ctrl_remove(struct platform_device *pdev)
dev_pm_genpd_remove_notifier(bc->bus_power_dev);
dev_pm_domain_detach(bc->bus_power_dev, true);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -856,7 +854,7 @@ MODULE_DEVICE_TABLE(of, imx8mp_blk_ctrl_of_match);
static struct platform_driver imx8mp_blk_ctrl_driver = {
.probe = imx8mp_blk_ctrl_probe,
- .remove = imx8mp_blk_ctrl_remove,
+ .remove_new = imx8mp_blk_ctrl_remove,
.driver = {
.name = "imx8mp-blk-ctrl",
.pm = &imx8mp_blk_ctrl_pm_ops,
diff --git a/drivers/pmdomain/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c
index 40bd90f8b977..904ffa55b8f4 100644
--- a/drivers/pmdomain/imx/imx93-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c
@@ -306,7 +306,7 @@ cleanup_pds:
return ret;
}
-static int imx93_blk_ctrl_remove(struct platform_device *pdev)
+static void imx93_blk_ctrl_remove(struct platform_device *pdev)
{
struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
int i;
@@ -318,8 +318,6 @@ static int imx93_blk_ctrl_remove(struct platform_device *pdev)
pm_genpd_remove(&domain->genpd);
}
-
- return 0;
}
static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = {
@@ -438,7 +436,7 @@ MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match);
static struct platform_driver imx93_blk_ctrl_driver = {
.probe = imx93_blk_ctrl_probe,
- .remove = imx93_blk_ctrl_remove,
+ .remove_new = imx93_blk_ctrl_remove,
.driver = {
.name = "imx93-blk-ctrl",
.of_match_table = imx93_blk_ctrl_of_match,
diff --git a/drivers/pmdomain/imx/imx93-pd.c b/drivers/pmdomain/imx/imx93-pd.c
index b9e60d136875..1e94b499c19b 100644
--- a/drivers/pmdomain/imx/imx93-pd.c
+++ b/drivers/pmdomain/imx/imx93-pd.c
@@ -83,7 +83,7 @@ static int imx93_pd_off(struct generic_pm_domain *genpd)
return 0;
};
-static int imx93_pd_remove(struct platform_device *pdev)
+static void imx93_pd_remove(struct platform_device *pdev)
{
struct imx93_power_domain *domain = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
@@ -94,8 +94,6 @@ static int imx93_pd_remove(struct platform_device *pdev)
of_genpd_del_provider(np);
pm_genpd_remove(&domain->genpd);
-
- return 0;
}
static int imx93_pd_probe(struct platform_device *pdev)
@@ -167,7 +165,7 @@ static struct platform_driver imx93_power_domain_driver = {
.of_match_table = imx93_pd_ids,
},
.probe = imx93_pd_probe,
- .remove = imx93_pd_remove,
+ .remove_new = imx93_pd_remove,
};
module_platform_driver(imx93_power_domain_driver);
diff --git a/drivers/pmdomain/qcom/cpr.c b/drivers/pmdomain/qcom/cpr.c
index e9dd42bded6f..c64e84a27cc7 100644
--- a/drivers/pmdomain/qcom/cpr.c
+++ b/drivers/pmdomain/qcom/cpr.c
@@ -1712,7 +1712,7 @@ err_remove_genpd:
return ret;
}
-static int cpr_remove(struct platform_device *pdev)
+static void cpr_remove(struct platform_device *pdev)
{
struct cpr_drv *drv = platform_get_drvdata(pdev);
@@ -1725,8 +1725,6 @@ static int cpr_remove(struct platform_device *pdev)
pm_genpd_remove(&drv->pd);
debugfs_remove_recursive(drv->debugfs);
-
- return 0;
}
static const struct of_device_id cpr_match_table[] = {
@@ -1737,7 +1735,7 @@ MODULE_DEVICE_TABLE(of, cpr_match_table);
static struct platform_driver cpr_driver = {
.probe = cpr_probe,
- .remove = cpr_remove,
+ .remove_new = cpr_remove,
.driver = {
.name = "qcom-cpr",
.of_match_table = cpr_match_table,
diff --git a/drivers/pmdomain/qcom/rpmhpd.c b/drivers/pmdomain/qcom/rpmhpd.c
index f2e64324deb8..3078896b1300 100644
--- a/drivers/pmdomain/qcom/rpmhpd.c
+++ b/drivers/pmdomain/qcom/rpmhpd.c
@@ -598,8 +598,8 @@ static const struct rpmhpd_desc sc8280xp_desc = {
.num_pds = ARRAY_SIZE(sc8280xp_rpmhpds),
};
-/* SC8380xp RPMH powerdomains */
-static struct rpmhpd *sc8380xp_rpmhpds[] = {
+/* X1E80100 RPMH powerdomains */
+static struct rpmhpd *x1e80100_rpmhpds[] = {
[RPMHPD_CX] = &cx,
[RPMHPD_CX_AO] = &cx_ao,
[RPMHPD_EBI] = &ebi,
@@ -615,9 +615,9 @@ static struct rpmhpd *sc8380xp_rpmhpds[] = {
[RPMHPD_GMXC] = &gmxc,
};
-static const struct rpmhpd_desc sc8380xp_desc = {
- .rpmhpds = sc8380xp_rpmhpds,
- .num_pds = ARRAY_SIZE(sc8380xp_rpmhpds),
+static const struct rpmhpd_desc x1e80100_desc = {
+ .rpmhpds = x1e80100_rpmhpds,
+ .num_pds = ARRAY_SIZE(x1e80100_rpmhpds),
};
static const struct of_device_id rpmhpd_match_table[] = {
@@ -629,7 +629,6 @@ static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,sc7280-rpmhpd", .data = &sc7280_desc },
{ .compatible = "qcom,sc8180x-rpmhpd", .data = &sc8180x_desc },
{ .compatible = "qcom,sc8280xp-rpmhpd", .data = &sc8280xp_desc },
- { .compatible = "qcom,sc8380xp-rpmhpd", .data = &sc8380xp_desc },
{ .compatible = "qcom,sdm670-rpmhpd", .data = &sdm670_desc },
{ .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc },
{ .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc},
@@ -643,6 +642,7 @@ static const struct of_device_id rpmhpd_match_table[] = {
{ .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc },
{ .compatible = "qcom,sm8550-rpmhpd", .data = &sm8550_desc },
{ .compatible = "qcom,sm8650-rpmhpd", .data = &sm8650_desc },
+ { .compatible = "qcom,x1e80100-rpmhpd", .data = &x1e80100_desc },
{ }
};
MODULE_DEVICE_TABLE(of, rpmhpd_match_table);
diff --git a/drivers/pmdomain/xilinx/zynqmp-pm-domains.c b/drivers/pmdomain/xilinx/zynqmp-pm-domains.c
index 69d03ad4cf1e..6fd514286d82 100644
--- a/drivers/pmdomain/xilinx/zynqmp-pm-domains.c
+++ b/drivers/pmdomain/xilinx/zynqmp-pm-domains.c
@@ -293,11 +293,9 @@ static int zynqmp_gpd_probe(struct platform_device *pdev)
return 0;
}
-static int zynqmp_gpd_remove(struct platform_device *pdev)
+static void zynqmp_gpd_remove(struct platform_device *pdev)
{
of_genpd_del_provider(pdev->dev.parent->of_node);
-
- return 0;
}
static void zynqmp_gpd_sync_state(struct device *dev)
@@ -315,7 +313,7 @@ static struct platform_driver zynqmp_power_domain_driver = {
.sync_state = zynqmp_gpd_sync_state,
},
.probe = zynqmp_gpd_probe,
- .remove = zynqmp_gpd_remove,
+ .remove_new = zynqmp_gpd_remove,
};
module_platform_driver(zynqmp_power_domain_driver);
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index 46c534f6b1c9..0a5d0d8befa8 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -256,7 +256,7 @@ static const struct dev_pm_ops pnp_bus_dev_pm_ops = {
.restore = pnp_bus_resume,
};
-struct bus_type pnp_bus_type = {
+const struct bus_type pnp_bus_type = {
.name = "pnp",
.match = pnp_bus_match,
.probe = pnp_device_probe,
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 29078486534d..f2728ee787d7 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -8,6 +8,7 @@
#include <linux/acpi.h>
#include <linux/module.h>
+#include <linux/idr.h>
#include <linux/of.h>
#include <linux/pwm.h>
#include <linux/list.h>
@@ -23,52 +24,25 @@
#define CREATE_TRACE_POINTS
#include <trace/events/pwm.h>
-#define MAX_PWMS 1024
-
static DEFINE_MUTEX(pwm_lookup_lock);
static LIST_HEAD(pwm_lookup_list);
-/* protects access to pwm_chips and allocated_pwms */
+/* protects access to pwm_chips */
static DEFINE_MUTEX(pwm_lock);
-static LIST_HEAD(pwm_chips);
-static DECLARE_BITMAP(allocated_pwms, MAX_PWMS);
-
-/* Called with pwm_lock held */
-static int alloc_pwms(unsigned int count)
-{
- unsigned int start;
-
- start = bitmap_find_next_zero_area(allocated_pwms, MAX_PWMS, 0,
- count, 0);
-
- if (start + count > MAX_PWMS)
- return -ENOSPC;
-
- bitmap_set(allocated_pwms, start, count);
-
- return start;
-}
-
-/* Called with pwm_lock held */
-static void free_pwms(struct pwm_chip *chip)
-{
- bitmap_clear(allocated_pwms, chip->base, chip->npwm);
-
- kfree(chip->pwms);
- chip->pwms = NULL;
-}
+static DEFINE_IDR(pwm_chips);
static struct pwm_chip *pwmchip_find_by_name(const char *name)
{
struct pwm_chip *chip;
+ unsigned long id, tmp;
if (!name)
return NULL;
mutex_lock(&pwm_lock);
- list_for_each_entry(chip, &pwm_chips, list) {
+ idr_for_each_entry_ul(&pwm_chips, chip, tmp, id) {
const char *chip_name = dev_name(chip->dev);
if (chip_name && strcmp(chip_name, name) == 0) {
@@ -85,22 +59,24 @@ static struct pwm_chip *pwmchip_find_by_name(const char *name)
static int pwm_device_request(struct pwm_device *pwm, const char *label)
{
int err;
+ struct pwm_chip *chip = pwm->chip;
+ const struct pwm_ops *ops = chip->ops;
if (test_bit(PWMF_REQUESTED, &pwm->flags))
return -EBUSY;
- if (!try_module_get(pwm->chip->owner))
+ if (!try_module_get(chip->owner))
return -ENODEV;
- if (pwm->chip->ops->request) {
- err = pwm->chip->ops->request(pwm->chip, pwm);
+ if (ops->request) {
+ err = ops->request(chip, pwm);
if (err) {
- module_put(pwm->chip->owner);
+ module_put(chip->owner);
return err;
}
}
- if (pwm->chip->ops->get_state) {
+ if (ops->get_state) {
/*
* Zero-initialize state because most drivers are unaware of
* .usage_power. The other members of state are supposed to be
@@ -110,7 +86,7 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
*/
struct pwm_state state = { 0, };
- err = pwm->chip->ops->get_state(pwm->chip, pwm, &state);
+ err = ops->get_state(chip, pwm, &state);
trace_pwm_get(pwm, &state, err);
if (!err)
@@ -176,7 +152,7 @@ of_pwm_single_xlate(struct pwm_chip *chip, const struct of_phandle_args *args)
pwm->args.period = args->args[0];
pwm->args.polarity = PWM_POLARITY_NORMAL;
- if (args->args_count == 2 && args->args[2] & PWM_POLARITY_INVERTED)
+ if (args->args_count == 2 && args->args[1] & PWM_POLARITY_INVERTED)
pwm->args.polarity = PWM_POLARITY_INVERSED;
return pwm;
@@ -234,7 +210,6 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
*/
int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
{
- struct pwm_device *pwm;
unsigned int i;
int ret;
@@ -246,31 +221,28 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
chip->owner = owner;
- chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL);
+ chip->pwms = kcalloc(chip->npwm, sizeof(*chip->pwms), GFP_KERNEL);
if (!chip->pwms)
return -ENOMEM;
mutex_lock(&pwm_lock);
- ret = alloc_pwms(chip->npwm);
+ ret = idr_alloc(&pwm_chips, chip, 0, 0, GFP_KERNEL);
if (ret < 0) {
mutex_unlock(&pwm_lock);
kfree(chip->pwms);
return ret;
}
- chip->base = ret;
+ chip->id = ret;
for (i = 0; i < chip->npwm; i++) {
- pwm = &chip->pwms[i];
+ struct pwm_device *pwm = &chip->pwms[i];
pwm->chip = chip;
- pwm->pwm = chip->base + i;
pwm->hwpwm = i;
}
- list_add(&chip->list, &pwm_chips);
-
mutex_unlock(&pwm_lock);
if (IS_ENABLED(CONFIG_OF))
@@ -297,11 +269,11 @@ void pwmchip_remove(struct pwm_chip *chip)
mutex_lock(&pwm_lock);
- list_del_init(&chip->list);
-
- free_pwms(chip);
+ idr_remove(&pwm_chips, chip->id);
mutex_unlock(&pwm_lock);
+
+ kfree(chip->pwms);
}
EXPORT_SYMBOL_GPL(pwmchip_remove);
@@ -356,8 +328,8 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
}
EXPORT_SYMBOL_GPL(pwm_request_from_chip);
-static void pwm_apply_state_debug(struct pwm_device *pwm,
- const struct pwm_state *state)
+static void pwm_apply_debug(struct pwm_device *pwm,
+ const struct pwm_state *state)
{
struct pwm_state *last = &pwm->last;
struct pwm_chip *chip = pwm->chip;
@@ -463,24 +435,15 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
}
/**
- * pwm_apply_state() - atomically apply a new state to a PWM device
+ * __pwm_apply() - atomically apply a new state to a PWM device
* @pwm: PWM device
* @state: new state to apply
*/
-int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
+static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state)
{
struct pwm_chip *chip;
int err;
- /*
- * Some lowlevel driver's implementations of .apply() make use of
- * mutexes, also with some drivers only returning when the new
- * configuration is active calling pwm_apply_state() from atomic context
- * is a bad idea. So make it explicit that calling this function might
- * sleep.
- */
- might_sleep();
-
if (!pwm || !state || !state->period ||
state->duty_cycle > state->period)
return -EINVAL;
@@ -505,11 +468,60 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
* only do this after pwm->state was applied as some
* implementations of .get_state depend on this
*/
- pwm_apply_state_debug(pwm, state);
+ pwm_apply_debug(pwm, state);
return 0;
}
-EXPORT_SYMBOL_GPL(pwm_apply_state);
+
+/**
+ * pwm_apply_might_sleep() - atomically apply a new state to a PWM device
+ * Cannot be used in atomic context.
+ * @pwm: PWM device
+ * @state: new state to apply
+ */
+int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state)
+{
+ int err;
+
+ /*
+ * Some lowlevel driver's implementations of .apply() make use of
+ * mutexes, also with some drivers only returning when the new
+ * configuration is active calling pwm_apply_might_sleep() from atomic context
+ * is a bad idea. So make it explicit that calling this function might
+ * sleep.
+ */
+ might_sleep();
+
+ if (IS_ENABLED(CONFIG_PWM_DEBUG) && pwm->chip->atomic) {
+ /*
+ * Catch any drivers that have been marked as atomic but
+ * that will sleep anyway.
+ */
+ non_block_start();
+ err = __pwm_apply(pwm, state);
+ non_block_end();
+ } else {
+ err = __pwm_apply(pwm, state);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(pwm_apply_might_sleep);
+
+/**
+ * pwm_apply_atomic() - apply a new state to a PWM device from atomic context
+ * Not all PWM devices support this function, check with pwm_might_sleep().
+ * @pwm: PWM device
+ * @state: new state to apply
+ */
+int pwm_apply_atomic(struct pwm_device *pwm, const struct pwm_state *state)
+{
+ WARN_ONCE(!pwm->chip->atomic,
+ "sleeping PWM driver used in atomic context\n");
+
+ return __pwm_apply(pwm, state);
+}
+EXPORT_SYMBOL_GPL(pwm_apply_atomic);
/**
* pwm_capture() - capture and report a PWM signal
@@ -567,7 +579,7 @@ int pwm_adjust_config(struct pwm_device *pwm)
state.period = pargs.period;
state.polarity = pargs.polarity;
- return pwm_apply_state(pwm, &state);
+ return pwm_apply_might_sleep(pwm, &state);
}
/*
@@ -590,17 +602,18 @@ int pwm_adjust_config(struct pwm_device *pwm)
state.duty_cycle = state.period - state.duty_cycle;
}
- return pwm_apply_state(pwm, &state);
+ return pwm_apply_might_sleep(pwm, &state);
}
EXPORT_SYMBOL_GPL(pwm_adjust_config);
static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode)
{
struct pwm_chip *chip;
+ unsigned long id, tmp;
mutex_lock(&pwm_lock);
- list_for_each_entry(chip, &pwm_chips, list)
+ idr_for_each_entry_ul(&pwm_chips, chip, tmp, id)
if (chip->dev && device_match_fwnode(chip->dev, fwnode)) {
mutex_unlock(&pwm_lock);
return chip;
@@ -1058,17 +1071,27 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
static void *pwm_seq_start(struct seq_file *s, loff_t *pos)
{
+ unsigned long id = *pos;
+ void *ret;
+
mutex_lock(&pwm_lock);
s->private = "";
- return seq_list_start(&pwm_chips, *pos);
+ ret = idr_get_next_ul(&pwm_chips, &id);
+ *pos = id;
+ return ret;
}
static void *pwm_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
+ unsigned long id = *pos + 1;
+ void *ret;
+
s->private = "\n";
- return seq_list_next(v, &pwm_chips, pos);
+ ret = idr_get_next_ul(&pwm_chips, &id);
+ *pos = id;
+ return ret;
}
static void pwm_seq_stop(struct seq_file *s, void *v)
@@ -1078,9 +1101,10 @@ static void pwm_seq_stop(struct seq_file *s, void *v)
static int pwm_seq_show(struct seq_file *s, void *v)
{
- struct pwm_chip *chip = list_entry(v, struct pwm_chip, list);
+ struct pwm_chip *chip = v;
- seq_printf(s, "%s%s/%s, %d PWM device%s\n", (char *)s->private,
+ seq_printf(s, "%s%d: %s/%s, %d PWM device%s\n",
+ (char *)s->private, chip->id,
chip->dev->bus ? chip->dev->bus->name : "no-bus",
dev_name(chip->dev), chip->npwm,
(chip->npwm != 1) ? "s" : "");
diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
index 07920e034757..3f2c5031a3ba 100644
--- a/drivers/pwm/pwm-atmel-hlcdc.c
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -180,7 +180,6 @@ static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = {
.div1_clk_erratum = true,
};
-#ifdef CONFIG_PM_SLEEP
static int atmel_hlcdc_pwm_suspend(struct device *dev)
{
struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev);
@@ -210,10 +209,9 @@ static int atmel_hlcdc_pwm_resume(struct device *dev)
return atmel_hlcdc_pwm_apply(&atmel->chip, &atmel->chip.pwms[0],
&state);
}
-#endif
-static SIMPLE_DEV_PM_OPS(atmel_hlcdc_pwm_pm_ops,
- atmel_hlcdc_pwm_suspend, atmel_hlcdc_pwm_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(atmel_hlcdc_pwm_pm_ops,
+ atmel_hlcdc_pwm_suspend, atmel_hlcdc_pwm_resume);
static const struct of_device_id atmel_hlcdc_dt_ids[] = {
{
@@ -297,7 +295,7 @@ static struct platform_driver atmel_hlcdc_pwm_driver = {
.driver = {
.name = "atmel-hlcdc-pwm",
.of_match_table = atmel_hlcdc_pwm_dt_ids,
- .pm = &atmel_hlcdc_pwm_pm_ops,
+ .pm = pm_ptr(&atmel_hlcdc_pwm_pm_ops),
},
.probe = atmel_hlcdc_pwm_probe,
.remove_new = atmel_hlcdc_pwm_remove,
diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
index 98b33c016c3c..d42c897cb85e 100644
--- a/drivers/pwm/pwm-atmel-tcb.c
+++ b/drivers/pwm/pwm-atmel-tcb.c
@@ -489,7 +489,6 @@ static const struct of_device_id atmel_tcb_pwm_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, atmel_tcb_pwm_dt_ids);
-#ifdef CONFIG_PM_SLEEP
static int atmel_tcb_pwm_suspend(struct device *dev)
{
struct atmel_tcb_pwm_chip *tcbpwm = dev_get_drvdata(dev);
@@ -522,16 +521,15 @@ static int atmel_tcb_pwm_resume(struct device *dev)
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(atmel_tcb_pwm_pm_ops, atmel_tcb_pwm_suspend,
- atmel_tcb_pwm_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(atmel_tcb_pwm_pm_ops, atmel_tcb_pwm_suspend,
+ atmel_tcb_pwm_resume);
static struct platform_driver atmel_tcb_pwm_driver = {
.driver = {
.name = "atmel-tcb-pwm",
.of_match_table = atmel_tcb_pwm_dt_ids,
- .pm = &atmel_tcb_pwm_pm_ops,
+ .pm = pm_ptr(&atmel_tcb_pwm_pm_ops),
},
.probe = atmel_tcb_pwm_probe,
.remove_new = atmel_tcb_pwm_remove,
diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index 15d6ed03c3ce..45046a5c20a5 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -260,7 +260,7 @@ static int kona_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return err;
}
- err = kona_pwmc_config(pwm->chip, pwm, state->duty_cycle, state->period);
+ err = kona_pwmc_config(chip, pwm, state->duty_cycle, state->period);
if (err && !pwm->state.enabled)
clk_disable_unprepare(kp->clk);
diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c
index ab30667f4f95..283cf27f25ba 100644
--- a/drivers/pwm/pwm-bcm2835.c
+++ b/drivers/pwm/pwm-bcm2835.c
@@ -28,6 +28,7 @@ struct bcm2835_pwm {
struct device *dev;
void __iomem *base;
struct clk *clk;
+ unsigned long rate;
};
static inline struct bcm2835_pwm *to_bcm2835_pwm(struct pwm_chip *chip)
@@ -63,17 +64,11 @@ static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
{
struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
- unsigned long rate = clk_get_rate(pc->clk);
unsigned long long period_cycles;
u64 max_period;
u32 val;
- if (!rate) {
- dev_err(pc->dev, "failed to get clock rate\n");
- return -EINVAL;
- }
-
/*
* period_cycles must be a 32 bit value, so period * rate / NSEC_PER_SEC
* must be <= U32_MAX. As U32_MAX * NSEC_PER_SEC < U64_MAX the
@@ -88,13 +83,13 @@ static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
* <=> period < ((U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC/2) / rate
* <=> period <= ceil((U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC/2) / rate) - 1
*/
- max_period = DIV_ROUND_UP_ULL((u64)U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC / 2, rate) - 1;
+ max_period = DIV_ROUND_UP_ULL((u64)U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC / 2, pc->rate) - 1;
if (state->period > max_period)
return -EINVAL;
/* set period */
- period_cycles = DIV_ROUND_CLOSEST_ULL(state->period * rate, NSEC_PER_SEC);
+ period_cycles = DIV_ROUND_CLOSEST_ULL(state->period * pc->rate, NSEC_PER_SEC);
/* don't accept a period that is too small */
if (period_cycles < PERIOD_MIN)
@@ -103,7 +98,7 @@ static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
writel(period_cycles, pc->base + PERIOD(pwm->hwpwm));
/* set duty cycle */
- val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * rate, NSEC_PER_SEC);
+ val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * pc->rate, NSEC_PER_SEC);
writel(val, pc->base + DUTY(pwm->hwpwm));
/* set polarity */
@@ -131,6 +126,13 @@ static const struct pwm_ops bcm2835_pwm_ops = {
.apply = bcm2835_pwm_apply,
};
+static void devm_clk_rate_exclusive_put(void *data)
+{
+ struct clk *clk = data;
+
+ clk_rate_exclusive_put(clk);
+}
+
static int bcm2835_pwm_probe(struct platform_device *pdev)
{
struct bcm2835_pwm *pc;
@@ -151,8 +153,24 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
"clock not found\n");
+ ret = clk_rate_exclusive_get(pc->clk);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "fail to get exclusive rate\n");
+
+ ret = devm_add_action_or_reset(&pdev->dev, devm_clk_rate_exclusive_put,
+ pc->clk);
+ if (ret)
+ return ret;
+
+ pc->rate = clk_get_rate(pc->clk);
+ if (!pc->rate)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "failed to get clock rate\n");
+
pc->chip.dev = &pdev->dev;
pc->chip.ops = &bcm2835_pwm_ops;
+ pc->chip.atomic = true;
pc->chip.npwm = 2;
platform_set_drvdata(pdev, pc);
diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c
index ba2d79991769..442913232dc0 100644
--- a/drivers/pwm/pwm-berlin.c
+++ b/drivers/pwm/pwm-berlin.c
@@ -226,7 +226,6 @@ static int berlin_pwm_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int berlin_pwm_suspend(struct device *dev)
{
struct berlin_pwm_chip *bpc = dev_get_drvdata(dev);
@@ -267,17 +266,16 @@ static int berlin_pwm_resume(struct device *dev)
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(berlin_pwm_pm_ops, berlin_pwm_suspend,
- berlin_pwm_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(berlin_pwm_pm_ops, berlin_pwm_suspend,
+ berlin_pwm_resume);
static struct platform_driver berlin_pwm_driver = {
.probe = berlin_pwm_probe,
.driver = {
.name = "berlin-pwm",
.of_match_table = berlin_pwm_match,
- .pm = &berlin_pwm_pm_ops,
+ .pm = pm_ptr(&berlin_pwm_pm_ops),
},
};
module_platform_driver(berlin_pwm_driver);
diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c
index b723c2d4f485..0fdeb0b2dbf3 100644
--- a/drivers/pwm/pwm-brcmstb.c
+++ b/drivers/pwm/pwm-brcmstb.c
@@ -259,7 +259,6 @@ static int brcmstb_pwm_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
static int brcmstb_pwm_suspend(struct device *dev)
{
struct brcmstb_pwm *p = dev_get_drvdata(dev);
@@ -275,17 +274,16 @@ static int brcmstb_pwm_resume(struct device *dev)
return clk_prepare_enable(p->clk);
}
-#endif
-static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend,
- brcmstb_pwm_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend,
+ brcmstb_pwm_resume);
static struct platform_driver brcmstb_pwm_driver = {
.probe = brcmstb_pwm_probe,
.driver = {
.name = "pwm-brcmstb",
.of_match_table = brcmstb_pwm_of_match,
- .pm = &brcmstb_pwm_pm_ops,
+ .pm = pm_ptr(&brcmstb_pwm_pm_ops),
},
};
module_platform_driver(brcmstb_pwm_driver);
diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
index 2b0b659eee97..e09358901ab5 100644
--- a/drivers/pwm/pwm-crc.c
+++ b/drivers/pwm/pwm-crc.c
@@ -160,22 +160,22 @@ static const struct pwm_ops crc_pwm_ops = {
static int crystalcove_pwm_probe(struct platform_device *pdev)
{
- struct crystalcove_pwm *pwm;
+ struct crystalcove_pwm *crc_pwm;
struct device *dev = pdev->dev.parent;
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
- pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
- if (!pwm)
+ crc_pwm = devm_kzalloc(&pdev->dev, sizeof(*crc_pwm), GFP_KERNEL);
+ if (!crc_pwm)
return -ENOMEM;
- pwm->chip.dev = &pdev->dev;
- pwm->chip.ops = &crc_pwm_ops;
- pwm->chip.npwm = 1;
+ crc_pwm->chip.dev = &pdev->dev;
+ crc_pwm->chip.ops = &crc_pwm_ops;
+ crc_pwm->chip.npwm = 1;
/* get the PMIC regmap */
- pwm->regmap = pmic->regmap;
+ crc_pwm->regmap = pmic->regmap;
- return devm_pwmchip_add(&pdev->dev, &pwm->chip);
+ return devm_pwmchip_add(&pdev->dev, &crc_pwm->chip);
}
static struct platform_driver crystalcove_pwm_driver = {
diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c
index 4fbd23e4ef69..5fe303b8656d 100644
--- a/drivers/pwm/pwm-cros-ec.c
+++ b/drivers/pwm/pwm-cros-ec.c
@@ -18,14 +18,12 @@
/**
* struct cros_ec_pwm_device - Driver data for EC PWM
*
- * @dev: Device node
* @ec: Pointer to EC device
* @chip: PWM controller chip
* @use_pwm_type: Use PWM types instead of generic channels
* @channel: array with per-channel data
*/
struct cros_ec_pwm_device {
- struct device *dev;
struct cros_ec_device *ec;
struct pwm_chip chip;
bool use_pwm_type;
diff --git a/drivers/pwm/pwm-dwc.c b/drivers/pwm/pwm-dwc.c
index bd9cadb497d7..4929354f8cd9 100644
--- a/drivers/pwm/pwm-dwc.c
+++ b/drivers/pwm/pwm-dwc.c
@@ -71,7 +71,6 @@ static void dwc_pwm_remove(struct pci_dev *pci)
pm_runtime_get_noresume(&pci->dev);
}
-#ifdef CONFIG_PM_SLEEP
static int dwc_pwm_suspend(struct device *dev)
{
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
@@ -106,9 +105,8 @@ static int dwc_pwm_resume(struct device *dev)
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(dwc_pwm_pm_ops, dwc_pwm_suspend, dwc_pwm_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(dwc_pwm_pm_ops, dwc_pwm_suspend, dwc_pwm_resume);
static const struct pci_device_id dwc_pwm_id_table[] = {
{ PCI_VDEVICE(INTEL, 0x4bb7) }, /* Elkhart Lake */
@@ -122,7 +120,7 @@ static struct pci_driver dwc_pwm_driver = {
.remove = dwc_pwm_remove,
.id_table = dwc_pwm_id_table,
.driver = {
- .pm = &dwc_pwm_pm_ops,
+ .pm = pm_ptr(&dwc_pwm_pm_ops),
},
};
diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c
index 116fa060e302..5965ac35b32e 100644
--- a/drivers/pwm/pwm-img.c
+++ b/drivers/pwm/pwm-img.c
@@ -13,9 +13,9 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -196,7 +196,7 @@ static int img_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- err = img_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
+ err = img_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;
@@ -260,7 +260,6 @@ static int img_pwm_probe(struct platform_device *pdev)
u64 val;
unsigned long clk_rate;
struct img_pwm_chip *imgchip;
- const struct of_device_id *of_dev_id;
imgchip = devm_kzalloc(&pdev->dev, sizeof(*imgchip), GFP_KERNEL);
if (!imgchip)
@@ -272,10 +271,7 @@ static int img_pwm_probe(struct platform_device *pdev)
if (IS_ERR(imgchip->base))
return PTR_ERR(imgchip->base);
- of_dev_id = of_match_device(img_pwm_of_match, &pdev->dev);
- if (!of_dev_id)
- return -ENODEV;
- imgchip->data = of_dev_id->data;
+ imgchip->data = device_get_match_data(&pdev->dev);
imgchip->periph_regs = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"img,cr-periph");
diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c
index dc6aafeb9f7b..9fc290e647e1 100644
--- a/drivers/pwm/pwm-imx-tpm.c
+++ b/drivers/pwm/pwm-imx-tpm.c
@@ -371,7 +371,7 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev)
+static int pwm_imx_tpm_suspend(struct device *dev)
{
struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev);
@@ -390,7 +390,7 @@ static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused pwm_imx_tpm_resume(struct device *dev)
+static int pwm_imx_tpm_resume(struct device *dev)
{
struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev);
int ret = 0;
@@ -402,8 +402,8 @@ static int __maybe_unused pwm_imx_tpm_resume(struct device *dev)
return ret;
}
-static SIMPLE_DEV_PM_OPS(imx_tpm_pwm_pm,
- pwm_imx_tpm_suspend, pwm_imx_tpm_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(imx_tpm_pwm_pm,
+ pwm_imx_tpm_suspend, pwm_imx_tpm_resume);
static const struct of_device_id imx_tpm_pwm_dt_ids[] = {
{ .compatible = "fsl,imx7ulp-pwm", },
@@ -415,7 +415,7 @@ static struct platform_driver imx_tpm_pwm_driver = {
.driver = {
.name = "imx7ulp-tpm-pwm",
.of_match_table = imx_tpm_pwm_dt_ids,
- .pm = &imx_tpm_pwm_pm,
+ .pm = pm_ptr(&imx_tpm_pwm_pm),
},
.probe = pwm_imx_tpm_probe,
};
diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index e9375de60ad6..3933418e551b 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -61,9 +61,10 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
snprintf(name, sizeof(name), "timer%u", pwm->hwpwm);
clk = clk_get(chip->dev, name);
- if (IS_ERR(clk))
- return dev_err_probe(chip->dev, PTR_ERR(clk),
- "Failed to get clock\n");
+ if (IS_ERR(clk)) {
+ dev_err(chip->dev, "error %pe: Failed to get clock\n", clk);
+ return PTR_ERR(clk);
+ }
err = clk_prepare_enable(clk);
if (err < 0) {
@@ -123,7 +124,7 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state)
{
- struct jz4740_pwm_chip *jz = to_jz4740(pwm->chip);
+ struct jz4740_pwm_chip *jz = to_jz4740(chip);
unsigned long long tmp = 0xffffull * NSEC_PER_SEC;
struct clk *clk = jz->clk[pwm->hwpwm];
unsigned long period, duty;
@@ -149,7 +150,7 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
*/
rate = clk_round_rate(clk, tmp);
if (rate < 0) {
- dev_err(chip->dev, "Unable to round rate: %ld", rate);
+ dev_err(chip->dev, "Unable to round rate: %ld\n", rate);
return rate;
}
@@ -170,7 +171,7 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
err = clk_set_rate(clk, rate);
if (err) {
- dev_err(chip->dev, "Unable to set rate: %d", err);
+ dev_err(chip->dev, "Unable to set rate: %d\n", err);
return err;
}
diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c
index ef7d0da137ed..fe891fa71a1d 100644
--- a/drivers/pwm/pwm-lpc18xx-sct.c
+++ b/drivers/pwm/pwm-lpc18xx-sct.c
@@ -194,7 +194,7 @@ static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
{
struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
- int requested_events, i;
+ int requested_events;
if (period_ns < lpc18xx_pwm->min_period_ns ||
period_ns > lpc18xx_pwm->max_period_ns) {
@@ -223,8 +223,6 @@ static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
if ((requested_events <= 2 && lpc18xx_pwm->period_ns != period_ns) ||
!lpc18xx_pwm->period_ns) {
lpc18xx_pwm->period_ns = period_ns;
- for (i = 0; i < chip->npwm; i++)
- pwm_set_period(&chip->pwms[i], period_ns);
lpc18xx_pwm_config_period(chip, period_ns);
}
@@ -328,7 +326,7 @@ static int lpc18xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- err = lpc18xx_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
+ err = lpc18xx_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;
diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c
index 78f664e41e6e..1d9f3e7a2434 100644
--- a/drivers/pwm/pwm-lpc32xx.c
+++ b/drivers/pwm/pwm-lpc32xx.c
@@ -103,7 +103,7 @@ static int lpc32xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- err = lpc32xx_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
+ err = lpc32xx_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;
diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
index 373abfd25acb..17d290f847af 100644
--- a/drivers/pwm/pwm-mediatek.c
+++ b/drivers/pwm/pwm-mediatek.c
@@ -217,7 +217,7 @@ static int pwm_mediatek_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- err = pwm_mediatek_config(pwm->chip, pwm, state->duty_cycle, state->period);
+ err = pwm_mediatek_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index 5bea53243ed2..2971bbf3b5e7 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -468,10 +468,9 @@ static int meson_pwm_init_channels(struct meson_pwm *meson)
channel->mux.hw.init = &init;
err = devm_clk_hw_register(dev, &channel->mux.hw);
- if (err) {
- dev_err(dev, "failed to register %s: %d\n", name, err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "failed to register %s\n", name);
snprintf(name, sizeof(name), "%s#div%u", dev_name(dev), i);
@@ -491,10 +490,9 @@ static int meson_pwm_init_channels(struct meson_pwm *meson)
channel->div.lock = &meson->lock;
err = devm_clk_hw_register(dev, &channel->div.hw);
- if (err) {
- dev_err(dev, "failed to register %s: %d\n", name, err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err,
+ "failed to register %s\n", name);
snprintf(name, sizeof(name), "%s#gate%u", dev_name(dev), i);
@@ -513,17 +511,13 @@ static int meson_pwm_init_channels(struct meson_pwm *meson)
channel->gate.lock = &meson->lock;
err = devm_clk_hw_register(dev, &channel->gate.hw);
- if (err) {
- dev_err(dev, "failed to register %s: %d\n", name, err);
- return err;
- }
+ if (err)
+ return dev_err_probe(dev, err, "failed to register %s\n", name);
channel->clk = devm_clk_hw_get_clk(dev, &channel->gate.hw, NULL);
- if (IS_ERR(channel->clk)) {
- err = PTR_ERR(channel->clk);
- dev_err(dev, "failed to register %s: %d\n", name, err);
- return err;
- }
+ if (IS_ERR(channel->clk))
+ return dev_err_probe(dev, PTR_ERR(channel->clk),
+ "failed to register %s\n", name);
}
return 0;
@@ -554,10 +548,9 @@ static int meson_pwm_probe(struct platform_device *pdev)
return err;
err = devm_pwmchip_add(&pdev->dev, &meson->chip);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to register PWM chip: %d\n", err);
- return err;
- }
+ if (err < 0)
+ return dev_err_probe(&pdev->dev, err,
+ "failed to register PWM chip\n");
return 0;
}
diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c
index 13161e08dd6e..496bd73d29fe 100644
--- a/drivers/pwm/pwm-omap-dmtimer.c
+++ b/drivers/pwm/pwm-omap-dmtimer.c
@@ -37,7 +37,6 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <clocksource/timer-ti-dm.h>
@@ -55,7 +54,6 @@
* struct pwm_omap_dmtimer_chip - Structure representing a pwm chip
* corresponding to omap dmtimer.
* @chip: PWM chip structure representing PWM controller
- * @mutex: Mutex to protect pwm apply state
* @dm_timer: Pointer to omap dm timer.
* @pdata: Pointer to omap dm timer ops.
* @dm_timer_pdev: Pointer to omap dm timer platform device
@@ -63,7 +61,6 @@
struct pwm_omap_dmtimer_chip {
struct pwm_chip chip;
/* Mutex to protect pwm apply state */
- struct mutex mutex;
struct omap_dm_timer *dm_timer;
const struct omap_dm_timer_ops *pdata;
struct platform_device *dm_timer_pdev;
@@ -277,13 +274,11 @@ static int pwm_omap_dmtimer_apply(struct pwm_chip *chip,
const struct pwm_state *state)
{
struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
- int ret = 0;
-
- mutex_lock(&omap->mutex);
+ int ret;
if (pwm_omap_dmtimer_is_enabled(omap) && !state->enabled) {
omap->pdata->stop(omap->dm_timer);
- goto unlock_mutex;
+ return 0;
}
if (pwm_omap_dmtimer_polarity(omap) != state->polarity)
@@ -292,7 +287,7 @@ static int pwm_omap_dmtimer_apply(struct pwm_chip *chip,
ret = pwm_omap_dmtimer_config(chip, pwm, state->duty_cycle,
state->period);
if (ret)
- goto unlock_mutex;
+ return ret;
if (!pwm_omap_dmtimer_is_enabled(omap) && state->enabled) {
omap->pdata->set_pwm(omap->dm_timer,
@@ -303,10 +298,7 @@ static int pwm_omap_dmtimer_apply(struct pwm_chip *chip,
pwm_omap_dmtimer_start(omap);
}
-unlock_mutex:
- mutex_unlock(&omap->mutex);
-
- return ret;
+ return 0;
}
static const struct pwm_ops pwm_omap_dmtimer_ops = {
@@ -404,8 +396,6 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
omap->chip.ops = &pwm_omap_dmtimer_ops;
omap->chip.npwm = 1;
- mutex_init(&omap->mutex);
-
ret = pwmchip_add(&omap->chip);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register PWM\n");
@@ -452,8 +442,6 @@ static void pwm_omap_dmtimer_remove(struct platform_device *pdev)
omap->pdata->free(omap->dm_timer);
put_device(&omap->dm_timer_pdev->dev);
-
- mutex_destroy(&omap->mutex);
}
static const struct of_device_id pwm_omap_dmtimer_of_match[] = {
diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c
index 4239f2c3e8b2..28265fdfc92a 100644
--- a/drivers/pwm/pwm-renesas-tpu.c
+++ b/drivers/pwm/pwm-renesas-tpu.c
@@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/module.h>
-#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -416,7 +415,7 @@ static int tpu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- err = tpu_pwm_config(pwm->chip, pwm,
+ err = tpu_pwm_config(chip, pwm,
state->duty_cycle, state->period, enabled);
if (err)
return err;
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index cce4381e188a..a7c647e37837 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -10,8 +10,8 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/time.h>
@@ -296,16 +296,11 @@ MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
static int rockchip_pwm_probe(struct platform_device *pdev)
{
- const struct of_device_id *id;
struct rockchip_pwm_chip *pc;
u32 enable_conf, ctrl;
bool enabled;
int ret, count;
- id = of_match_device(rockchip_pwm_dt_ids, &pdev->dev);
- if (!id)
- return -EINVAL;
-
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
if (!pc)
return -ENOMEM;
@@ -344,7 +339,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pc);
- pc->data = id->data;
+ pc->data = device_get_match_data(&pdev->dev);
pc->chip.dev = &pdev->dev;
pc->chip.ops = &rockchip_pwm_ops;
pc->chip.npwm = 1;
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index 69d9f4577b34..6e77302f7368 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -620,7 +620,6 @@ static void pwm_samsung_remove(struct platform_device *pdev)
clk_disable_unprepare(our_chip->base_clk);
}
-#ifdef CONFIG_PM_SLEEP
static int pwm_samsung_resume(struct device *dev)
{
struct samsung_pwm_chip *our_chip = dev_get_drvdata(dev);
@@ -653,14 +652,13 @@ static int pwm_samsung_resume(struct device *dev)
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(pwm_samsung_pm_ops, NULL, pwm_samsung_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(pwm_samsung_pm_ops, NULL, pwm_samsung_resume);
static struct platform_driver pwm_samsung_driver = {
.driver = {
.name = "samsung-pwm",
- .pm = &pwm_samsung_pm_ops,
+ .pm = pm_ptr(&pwm_samsung_pm_ops),
.of_match_table = of_match_ptr(samsung_pwm_matches),
},
.probe = pwm_samsung_probe,
diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c
index dc92cea31cd0..6cf55cf34d39 100644
--- a/drivers/pwm/pwm-sti.c
+++ b/drivers/pwm/pwm-sti.c
@@ -407,7 +407,7 @@ static int sti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- err = sti_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
+ err = sti_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;
diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c
index b67974cc1872..439068f3eca1 100644
--- a/drivers/pwm/pwm-stm32-lp.c
+++ b/drivers/pwm/pwm-stm32-lp.c
@@ -218,7 +218,7 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused stm32_pwm_lp_suspend(struct device *dev)
+static int stm32_pwm_lp_suspend(struct device *dev)
{
struct stm32_pwm_lp *priv = dev_get_drvdata(dev);
struct pwm_state state;
@@ -233,13 +233,13 @@ static int __maybe_unused stm32_pwm_lp_suspend(struct device *dev)
return pinctrl_pm_select_sleep_state(dev);
}
-static int __maybe_unused stm32_pwm_lp_resume(struct device *dev)
+static int stm32_pwm_lp_resume(struct device *dev)
{
return pinctrl_pm_select_default_state(dev);
}
-static SIMPLE_DEV_PM_OPS(stm32_pwm_lp_pm_ops, stm32_pwm_lp_suspend,
- stm32_pwm_lp_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(stm32_pwm_lp_pm_ops, stm32_pwm_lp_suspend,
+ stm32_pwm_lp_resume);
static const struct of_device_id stm32_pwm_lp_of_match[] = {
{ .compatible = "st,stm32-pwm-lp", },
@@ -252,7 +252,7 @@ static struct platform_driver stm32_pwm_lp_driver = {
.driver = {
.name = "stm32-pwm-lp",
.of_match_table = stm32_pwm_lp_of_match,
- .pm = &stm32_pwm_lp_pm_ops,
+ .pm = pm_ptr(&stm32_pwm_lp_pm_ops),
},
};
module_platform_driver(stm32_pwm_lp_driver);
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 3303a754ea02..5f10cba492ec 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -52,21 +52,6 @@ static u32 active_channels(struct stm32_pwm *dev)
return ccer & TIM_CCER_CCXE;
}
-static int write_ccrx(struct stm32_pwm *dev, int ch, u32 value)
-{
- switch (ch) {
- case 0:
- return regmap_write(dev->regmap, TIM_CCR1, value);
- case 1:
- return regmap_write(dev->regmap, TIM_CCR2, value);
- case 2:
- return regmap_write(dev->regmap, TIM_CCR3, value);
- case 3:
- return regmap_write(dev->regmap, TIM_CCR4, value);
- }
- return -EINVAL;
-}
-
#define TIM_CCER_CC12P (TIM_CCER_CC1P | TIM_CCER_CC2P)
#define TIM_CCER_CC12E (TIM_CCER_CC1E | TIM_CCER_CC2E)
#define TIM_CCER_CC34P (TIM_CCER_CC3P | TIM_CCER_CC4P)
@@ -323,7 +308,7 @@ unlock:
return ret;
}
-static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
+static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch,
int duty_ns, int period_ns)
{
unsigned long long prd, div, dty;
@@ -369,7 +354,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
dty = prd * duty_ns;
do_div(dty, period_ns);
- write_ccrx(priv, ch, dty);
+ regmap_write(priv->regmap, TIM_CCR1 + 4 * ch, dty);
/* Configure output mode */
shift = (ch & 0x1) * CCMR_CHANNEL_SHIFT;
@@ -386,7 +371,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
return 0;
}
-static int stm32_pwm_set_polarity(struct stm32_pwm *priv, int ch,
+static int stm32_pwm_set_polarity(struct stm32_pwm *priv, unsigned int ch,
enum pwm_polarity polarity)
{
u32 mask;
@@ -401,7 +386,7 @@ static int stm32_pwm_set_polarity(struct stm32_pwm *priv, int ch,
return 0;
}
-static int stm32_pwm_enable(struct stm32_pwm *priv, int ch)
+static int stm32_pwm_enable(struct stm32_pwm *priv, unsigned int ch)
{
u32 mask;
int ret;
@@ -426,7 +411,7 @@ static int stm32_pwm_enable(struct stm32_pwm *priv, int ch)
return 0;
}
-static void stm32_pwm_disable(struct stm32_pwm *priv, int ch)
+static void stm32_pwm_disable(struct stm32_pwm *priv, unsigned int ch)
{
u32 mask;
@@ -486,8 +471,50 @@ static int stm32_pwm_apply_locked(struct pwm_chip *chip, struct pwm_device *pwm,
return ret;
}
+static int stm32_pwm_get_state(struct pwm_chip *chip,
+ struct pwm_device *pwm, struct pwm_state *state)
+{
+ struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
+ int ch = pwm->hwpwm;
+ unsigned long rate;
+ u32 ccer, psc, arr, ccr;
+ u64 dty, prd;
+ int ret;
+
+ mutex_lock(&priv->lock);
+
+ ret = regmap_read(priv->regmap, TIM_CCER, &ccer);
+ if (ret)
+ goto out;
+
+ state->enabled = ccer & (TIM_CCER_CC1E << (ch * 4));
+ state->polarity = (ccer & (TIM_CCER_CC1P << (ch * 4))) ?
+ PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL;
+ ret = regmap_read(priv->regmap, TIM_PSC, &psc);
+ if (ret)
+ goto out;
+ ret = regmap_read(priv->regmap, TIM_ARR, &arr);
+ if (ret)
+ goto out;
+ ret = regmap_read(priv->regmap, TIM_CCR1 + 4 * ch, &ccr);
+ if (ret)
+ goto out;
+
+ rate = clk_get_rate(priv->clk);
+
+ prd = (u64)NSEC_PER_SEC * (psc + 1) * (arr + 1);
+ state->period = DIV_ROUND_UP_ULL(prd, rate);
+ dty = (u64)NSEC_PER_SEC * (psc + 1) * ccr;
+ state->duty_cycle = DIV_ROUND_UP_ULL(dty, rate);
+
+out:
+ mutex_unlock(&priv->lock);
+ return ret;
+}
+
static const struct pwm_ops stm32pwm_ops = {
.apply = stm32_pwm_apply_locked,
+ .get_state = stm32_pwm_get_state,
.capture = IS_ENABLED(CONFIG_DMA_ENGINE) ? stm32_pwm_capture : NULL,
};
@@ -578,32 +605,23 @@ static void stm32_pwm_detect_complementary(struct stm32_pwm *priv)
priv->have_complementary_output = (ccer != 0);
}
-static int stm32_pwm_detect_channels(struct stm32_pwm *priv)
+static unsigned int stm32_pwm_detect_channels(struct stm32_pwm *priv,
+ unsigned int *num_enabled)
{
- u32 ccer;
- int npwm = 0;
+ u32 ccer, ccer_backup;
/*
* If channels enable bits don't exist writing 1 will have no
* effect so we can detect and count them.
*/
+ regmap_read(priv->regmap, TIM_CCER, &ccer_backup);
regmap_set_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE);
regmap_read(priv->regmap, TIM_CCER, &ccer);
- regmap_clear_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE);
-
- if (ccer & TIM_CCER_CC1E)
- npwm++;
-
- if (ccer & TIM_CCER_CC2E)
- npwm++;
+ regmap_write(priv->regmap, TIM_CCER, ccer_backup);
- if (ccer & TIM_CCER_CC3E)
- npwm++;
+ *num_enabled = hweight32(ccer_backup & TIM_CCER_CCXE);
- if (ccer & TIM_CCER_CC4E)
- npwm++;
-
- return npwm;
+ return hweight32(ccer & TIM_CCER_CCXE);
}
static int stm32_pwm_probe(struct platform_device *pdev)
@@ -612,6 +630,8 @@ static int stm32_pwm_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
struct stm32_pwm *priv;
+ unsigned int num_enabled;
+ unsigned int i;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -634,7 +654,11 @@ static int stm32_pwm_probe(struct platform_device *pdev)
priv->chip.dev = dev;
priv->chip.ops = &stm32pwm_ops;
- priv->chip.npwm = stm32_pwm_detect_channels(priv);
+ priv->chip.npwm = stm32_pwm_detect_channels(priv, &num_enabled);
+
+ /* Initialize clock refcount to number of enabled PWM channels. */
+ for (i = 0; i < num_enabled; i++)
+ clk_enable(priv->clk);
ret = devm_pwmchip_add(dev, &priv->chip);
if (ret < 0)
@@ -645,7 +669,7 @@ static int stm32_pwm_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused stm32_pwm_suspend(struct device *dev)
+static int stm32_pwm_suspend(struct device *dev)
{
struct stm32_pwm *priv = dev_get_drvdata(dev);
unsigned int i;
@@ -666,7 +690,7 @@ static int __maybe_unused stm32_pwm_suspend(struct device *dev)
return pinctrl_pm_select_sleep_state(dev);
}
-static int __maybe_unused stm32_pwm_resume(struct device *dev)
+static int stm32_pwm_resume(struct device *dev)
{
struct stm32_pwm *priv = dev_get_drvdata(dev);
int ret;
@@ -679,7 +703,7 @@ static int __maybe_unused stm32_pwm_resume(struct device *dev)
return stm32_pwm_apply_breakinputs(priv);
}
-static SIMPLE_DEV_PM_OPS(stm32_pwm_pm_ops, stm32_pwm_suspend, stm32_pwm_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(stm32_pwm_pm_ops, stm32_pwm_suspend, stm32_pwm_resume);
static const struct of_device_id stm32_pwm_of_match[] = {
{ .compatible = "st,stm32-pwm", },
@@ -692,7 +716,7 @@ static struct platform_driver stm32_pwm_driver = {
.driver = {
.name = "stm32-pwm",
.of_match_table = stm32_pwm_of_match,
- .pm = &stm32_pwm_pm_ops,
+ .pm = pm_ptr(&stm32_pwm_pm_ops),
},
};
module_platform_driver(stm32_pwm_driver);
diff --git a/drivers/pwm/pwm-stmpe.c b/drivers/pwm/pwm-stmpe.c
index a46f5b4dd816..19c0c0f39675 100644
--- a/drivers/pwm/pwm-stmpe.c
+++ b/drivers/pwm/pwm-stmpe.c
@@ -44,7 +44,7 @@ static int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
ret = stmpe_reg_read(stmpe_pwm->stmpe, STMPE24XX_PWMCS);
if (ret < 0) {
- dev_err(chip->dev, "error reading PWM#%u control\n",
+ dev_dbg(chip->dev, "error reading PWM#%u control\n",
pwm->hwpwm);
return ret;
}
@@ -53,7 +53,7 @@ static int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value);
if (ret) {
- dev_err(chip->dev, "error writing PWM#%u control\n",
+ dev_dbg(chip->dev, "error writing PWM#%u control\n",
pwm->hwpwm);
return ret;
}
@@ -70,7 +70,7 @@ static int stmpe_24xx_pwm_disable(struct pwm_chip *chip,
ret = stmpe_reg_read(stmpe_pwm->stmpe, STMPE24XX_PWMCS);
if (ret < 0) {
- dev_err(chip->dev, "error reading PWM#%u control\n",
+ dev_dbg(chip->dev, "error reading PWM#%u control\n",
pwm->hwpwm);
return ret;
}
@@ -79,7 +79,7 @@ static int stmpe_24xx_pwm_disable(struct pwm_chip *chip,
ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value);
if (ret)
- dev_err(chip->dev, "error writing PWM#%u control\n",
+ dev_dbg(chip->dev, "error writing PWM#%u control\n",
pwm->hwpwm);
return ret;
}
@@ -233,7 +233,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
ret = stmpe_reg_write(stmpe_pwm->stmpe, offset, value);
if (ret) {
- dev_err(chip->dev, "error writing register %02x: %d\n",
+ dev_dbg(chip->dev, "error writing register %02x: %d\n",
offset, ret);
return ret;
}
@@ -242,7 +242,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
ret = stmpe_reg_write(stmpe_pwm->stmpe, offset, value);
if (ret) {
- dev_err(chip->dev, "error writing register %02x: %d\n",
+ dev_dbg(chip->dev, "error writing register %02x: %d\n",
offset, ret);
return ret;
}
@@ -275,7 +275,7 @@ static int stmpe_24xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- err = stmpe_24xx_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
+ err = stmpe_24xx_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
index 39ea51e08c94..82ee2f0754f9 100644
--- a/drivers/pwm/pwm-tegra.c
+++ b/drivers/pwm/pwm-tegra.c
@@ -256,7 +256,7 @@ static int tegra_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- err = tegra_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
+ err = tegra_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 11e3549cf103..d974f4414ac9 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -269,7 +269,6 @@ static void ecap_pwm_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-#ifdef CONFIG_PM_SLEEP
static void ecap_pwm_save_context(struct ecap_pwm_chip *pc)
{
pm_runtime_get_sync(pc->chip.dev);
@@ -312,15 +311,14 @@ static int ecap_pwm_resume(struct device *dev)
ecap_pwm_restore_context(pc);
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(ecap_pwm_pm_ops, ecap_pwm_suspend, ecap_pwm_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ecap_pwm_pm_ops, ecap_pwm_suspend, ecap_pwm_resume);
static struct platform_driver ecap_pwm_driver = {
.driver = {
.name = "ecap",
.of_match_table = ecap_of_match,
- .pm = &ecap_pwm_pm_ops,
+ .pm = pm_ptr(&ecap_pwm_pm_ops),
},
.probe = ecap_pwm_probe,
.remove_new = ecap_pwm_remove,
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index 66ac2655845f..af231fa74fa9 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -521,7 +521,6 @@ static void ehrpwm_pwm_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-#ifdef CONFIG_PM_SLEEP
static void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc)
{
pm_runtime_get_sync(pc->chip.dev);
@@ -589,16 +588,15 @@ static int ehrpwm_pwm_resume(struct device *dev)
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(ehrpwm_pwm_pm_ops, ehrpwm_pwm_suspend,
- ehrpwm_pwm_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ehrpwm_pwm_pm_ops, ehrpwm_pwm_suspend,
+ ehrpwm_pwm_resume);
static struct platform_driver ehrpwm_pwm_driver = {
.driver = {
.name = "ehrpwm",
.of_match_table = ehrpwm_of_match,
- .pm = &ehrpwm_pwm_pm_ops,
+ .pm = pm_ptr(&ehrpwm_pwm_pm_ops),
},
.probe = ehrpwm_pwm_probe,
.remove_new = ehrpwm_pwm_remove,
diff --git a/drivers/pwm/pwm-twl-led.c b/drivers/pwm/pwm-twl-led.c
index 625233f4703a..c670ccb81653 100644
--- a/drivers/pwm/pwm-twl-led.c
+++ b/drivers/pwm/pwm-twl-led.c
@@ -172,10 +172,10 @@ static int twl4030_pwmled_apply(struct pwm_chip *chip, struct pwm_device *pwm,
* We cannot skip calling ->config even if state->period ==
* pwm->state.period && state->duty_cycle == pwm->state.duty_cycle
* because we might have exited early in the last call to
- * pwm_apply_state because of !state->enabled and so the two values in
+ * pwm_apply_might_sleep because of !state->enabled and so the two values in
* pwm->state might not be configured in hardware.
*/
- ret = twl4030_pwmled_config(pwm->chip, pwm,
+ ret = twl4030_pwmled_config(chip, pwm,
state->duty_cycle, state->period);
if (ret)
return ret;
@@ -275,7 +275,7 @@ static int twl6030_pwmled_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- err = twl6030_pwmled_config(pwm->chip, pwm,
+ err = twl6030_pwmled_config(chip, pwm,
state->duty_cycle, state->period);
if (err)
return err;
diff --git a/drivers/pwm/pwm-twl.c b/drivers/pwm/pwm-twl.c
index 603d31f27470..68e02c9a6bf9 100644
--- a/drivers/pwm/pwm-twl.c
+++ b/drivers/pwm/pwm-twl.c
@@ -294,7 +294,7 @@ static int twl4030_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- err = twl_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
+ err = twl_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;
@@ -319,7 +319,7 @@ static int twl6030_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
- err = twl_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
+ err = twl_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;
diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c
index 5568d5312d3c..7bfeacee05d0 100644
--- a/drivers/pwm/pwm-vt8500.c
+++ b/drivers/pwm/pwm-vt8500.c
@@ -206,10 +206,10 @@ static int vt8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
* We cannot skip calling ->config even if state->period ==
* pwm->state.period && state->duty_cycle == pwm->state.duty_cycle
* because we might have exited early in the last call to
- * pwm_apply_state because of !state->enabled and so the two values in
+ * pwm_apply_might_sleep because of !state->enabled and so the two values in
* pwm->state might not be configured in hardware.
*/
- err = vt8500_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
+ err = vt8500_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index 8d1254761e4d..1698609d91c8 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -62,7 +62,7 @@ static ssize_t period_store(struct device *child,
mutex_lock(&export->lock);
pwm_get_state(pwm, &state);
state.period = val;
- ret = pwm_apply_state(pwm, &state);
+ ret = pwm_apply_might_sleep(pwm, &state);
mutex_unlock(&export->lock);
return ret ? : size;
@@ -97,7 +97,7 @@ static ssize_t duty_cycle_store(struct device *child,
mutex_lock(&export->lock);
pwm_get_state(pwm, &state);
state.duty_cycle = val;
- ret = pwm_apply_state(pwm, &state);
+ ret = pwm_apply_might_sleep(pwm, &state);
mutex_unlock(&export->lock);
return ret ? : size;
@@ -144,7 +144,7 @@ static ssize_t enable_store(struct device *child,
goto unlock;
}
- ret = pwm_apply_state(pwm, &state);
+ ret = pwm_apply_might_sleep(pwm, &state);
unlock:
mutex_unlock(&export->lock);
@@ -194,7 +194,7 @@ static ssize_t polarity_store(struct device *child,
mutex_lock(&export->lock);
pwm_get_state(pwm, &state);
state.polarity = polarity;
- ret = pwm_apply_state(pwm, &state);
+ ret = pwm_apply_might_sleep(pwm, &state);
mutex_unlock(&export->lock);
return ret ? : size;
@@ -401,7 +401,7 @@ static int pwm_class_apply_state(struct pwm_export *export,
struct pwm_device *pwm,
struct pwm_state *state)
{
- int ret = pwm_apply_state(pwm, state);
+ int ret = pwm_apply_might_sleep(pwm, state);
/* release lock taken in pwm_class_get_state */
mutex_unlock(&export->lock);
@@ -510,7 +510,7 @@ void pwmchip_sysfs_export(struct pwm_chip *chip)
* the kernel it's just not exported.
*/
parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
- "pwmchip%d", chip->base);
+ "pwmchip%d", chip->id);
if (IS_ERR(parent)) {
dev_warn(chip->dev,
"device_create failed for pwm_chip sysfs export\n");
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c
index 2aff6db748e2..698c420e0869 100644
--- a/drivers/regulator/pwm-regulator.c
+++ b/drivers/regulator/pwm-regulator.c
@@ -90,7 +90,7 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
pwm_set_relative_duty_cycle(&pstate,
drvdata->duty_cycle_table[selector].dutycycle, 100);
- ret = pwm_apply_state(drvdata->pwm, &pstate);
+ ret = pwm_apply_might_sleep(drvdata->pwm, &pstate);
if (ret) {
dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
return ret;
@@ -216,7 +216,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit);
- ret = pwm_apply_state(drvdata->pwm, &pstate);
+ ret = pwm_apply_might_sleep(drvdata->pwm, &pstate);
if (ret) {
dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
return ret;
diff --git a/drivers/remoteproc/imx_dsp_rproc.c b/drivers/remoteproc/imx_dsp_rproc.c
index 8fcda9b74545..a1c62d15f16c 100644
--- a/drivers/remoteproc/imx_dsp_rproc.c
+++ b/drivers/remoteproc/imx_dsp_rproc.c
@@ -940,6 +940,7 @@ static const struct rproc_ops imx_dsp_rproc_ops = {
.kick = imx_dsp_rproc_kick,
.load = imx_dsp_rproc_elf_load_segments,
.parse_fw = imx_dsp_rproc_parse_fw,
+ .find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
.sanity_check = rproc_elf_sanity_check,
.get_boot_addr = rproc_elf_get_boot_addr,
};
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index 913a5d2068e8..a9dd58608052 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -1165,6 +1165,22 @@ static const struct adsp_data sm8550_mpss_resource = {
.region_assign_idx = 2,
};
+static const struct adsp_data sc7280_wpss_resource = {
+ .crash_reason_smem = 626,
+ .firmware_name = "wpss.mdt",
+ .pas_id = 6,
+ .auto_boot = true,
+ .proxy_pd_names = (char*[]){
+ "cx",
+ "mx",
+ NULL
+ },
+ .load_state = "wpss",
+ .ssr_name = "wpss",
+ .sysmon_name = "wpss",
+ .ssctl_id = 0x19,
+};
+
static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,msm8226-adsp-pil", .data = &adsp_resource_init},
{ .compatible = "qcom,msm8953-adsp-pil", .data = &msm8996_adsp_resource},
@@ -1178,7 +1194,10 @@ static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,qcs404-wcss-pas", .data = &wcss_resource_init },
{ .compatible = "qcom,sc7180-adsp-pas", .data = &sm8250_adsp_resource},
{ .compatible = "qcom,sc7180-mpss-pas", .data = &mpss_resource_init},
+ { .compatible = "qcom,sc7280-adsp-pas", .data = &sm8350_adsp_resource},
+ { .compatible = "qcom,sc7280-cdsp-pas", .data = &sm6350_cdsp_resource},
{ .compatible = "qcom,sc7280-mpss-pas", .data = &mpss_resource_init},
+ { .compatible = "qcom,sc7280-wpss-pas", .data = &sc7280_wpss_resource},
{ .compatible = "qcom,sc8180x-adsp-pas", .data = &sm8150_adsp_resource},
{ .compatible = "qcom,sc8180x-cdsp-pas", .data = &sm8150_cdsp_resource},
{ .compatible = "qcom,sc8180x-mpss-pas", .data = &sc8180x_mpss_resource},
diff --git a/drivers/remoteproc/ti_k3_dsp_remoteproc.c b/drivers/remoteproc/ti_k3_dsp_remoteproc.c
index ef8415a7cd54..ab882e3b7130 100644
--- a/drivers/remoteproc/ti_k3_dsp_remoteproc.c
+++ b/drivers/remoteproc/ti_k3_dsp_remoteproc.c
@@ -158,8 +158,8 @@ static void k3_dsp_rproc_kick(struct rproc *rproc, int vqid)
/* send the index of the triggered virtqueue in the mailbox payload */
ret = mbox_send_message(kproc->mbox, (void *)msg);
if (ret < 0)
- dev_err(dev, "failed to send mailbox message, status = %d\n",
- ret);
+ dev_err(dev, "failed to send mailbox message (%pe)\n",
+ ERR_PTR(ret));
}
/* Put the DSP processor into reset */
@@ -170,7 +170,7 @@ static int k3_dsp_rproc_reset(struct k3_dsp_rproc *kproc)
ret = reset_control_assert(kproc->reset);
if (ret) {
- dev_err(dev, "local-reset assert failed, ret = %d\n", ret);
+ dev_err(dev, "local-reset assert failed (%pe)\n", ERR_PTR(ret));
return ret;
}
@@ -180,7 +180,7 @@ static int k3_dsp_rproc_reset(struct k3_dsp_rproc *kproc)
ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci,
kproc->ti_sci_id);
if (ret) {
- dev_err(dev, "module-reset assert failed, ret = %d\n", ret);
+ dev_err(dev, "module-reset assert failed (%pe)\n", ERR_PTR(ret));
if (reset_control_deassert(kproc->reset))
dev_warn(dev, "local-reset deassert back failed\n");
}
@@ -200,14 +200,14 @@ static int k3_dsp_rproc_release(struct k3_dsp_rproc *kproc)
ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci,
kproc->ti_sci_id);
if (ret) {
- dev_err(dev, "module-reset deassert failed, ret = %d\n", ret);
+ dev_err(dev, "module-reset deassert failed (%pe)\n", ERR_PTR(ret));
return ret;
}
lreset:
ret = reset_control_deassert(kproc->reset);
if (ret) {
- dev_err(dev, "local-reset deassert failed, ret = %d\n", ret);
+ dev_err(dev, "local-reset deassert failed, (%pe)\n", ERR_PTR(ret));
if (kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci,
kproc->ti_sci_id))
dev_warn(dev, "module-reset assert back failed\n");
@@ -246,7 +246,7 @@ static int k3_dsp_rproc_request_mbox(struct rproc *rproc)
*/
ret = mbox_send_message(kproc->mbox, (void *)RP_MBOX_ECHO_REQUEST);
if (ret < 0) {
- dev_err(dev, "mbox_send_message failed: %d\n", ret);
+ dev_err(dev, "mbox_send_message failed (%pe)\n", ERR_PTR(ret));
mbox_free_channel(kproc->mbox);
return ret;
}
@@ -272,8 +272,8 @@ static int k3_dsp_rproc_prepare(struct rproc *rproc)
ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci,
kproc->ti_sci_id);
if (ret)
- dev_err(dev, "module-reset deassert failed, cannot enable internal RAM loading, ret = %d\n",
- ret);
+ dev_err(dev, "module-reset deassert failed, cannot enable internal RAM loading (%pe)\n",
+ ERR_PTR(ret));
return ret;
}
@@ -296,7 +296,7 @@ static int k3_dsp_rproc_unprepare(struct rproc *rproc)
ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci,
kproc->ti_sci_id);
if (ret)
- dev_err(dev, "module-reset assert failed, ret = %d\n", ret);
+ dev_err(dev, "module-reset assert failed (%pe)\n", ERR_PTR(ret));
return ret;
}
@@ -561,9 +561,9 @@ static int k3_dsp_reserved_mem_init(struct k3_dsp_rproc *kproc)
num_rmems = of_property_count_elems_of_size(np, "memory-region",
sizeof(phandle));
- if (num_rmems <= 0) {
- dev_err(dev, "device does not reserved memory regions, ret = %d\n",
- num_rmems);
+ if (num_rmems < 0) {
+ dev_err(dev, "device does not reserved memory regions (%pe)\n",
+ ERR_PTR(num_rmems));
return -EINVAL;
}
if (num_rmems < 2) {
@@ -575,8 +575,8 @@ static int k3_dsp_reserved_mem_init(struct k3_dsp_rproc *kproc)
/* use reserved memory region 0 for vring DMA allocations */
ret = of_reserved_mem_device_init_by_idx(dev, np, 0);
if (ret) {
- dev_err(dev, "device cannot initialize DMA pool, ret = %d\n",
- ret);
+ dev_err(dev, "device cannot initialize DMA pool (%pe)\n",
+ ERR_PTR(ret));
return ret;
}
@@ -687,11 +687,8 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev)
return -ENODEV;
ret = rproc_of_parse_firmware(dev, 0, &fw_name);
- if (ret) {
- dev_err(dev, "failed to parse firmware-name property, ret = %d\n",
- ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to parse firmware-name property\n");
rproc = rproc_alloc(dev, dev_name(dev), &k3_dsp_rproc_ops, fw_name,
sizeof(*kproc));
@@ -711,39 +708,35 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev)
kproc->ti_sci = ti_sci_get_by_phandle(np, "ti,sci");
if (IS_ERR(kproc->ti_sci)) {
- ret = PTR_ERR(kproc->ti_sci);
- if (ret != -EPROBE_DEFER) {
- dev_err(dev, "failed to get ti-sci handle, ret = %d\n",
- ret);
- }
+ ret = dev_err_probe(dev, PTR_ERR(kproc->ti_sci),
+ "failed to get ti-sci handle\n");
kproc->ti_sci = NULL;
goto free_rproc;
}
ret = of_property_read_u32(np, "ti,sci-dev-id", &kproc->ti_sci_id);
if (ret) {
- dev_err(dev, "missing 'ti,sci-dev-id' property\n");
+ dev_err_probe(dev, ret, "missing 'ti,sci-dev-id' property\n");
goto put_sci;
}
kproc->reset = devm_reset_control_get_exclusive(dev, NULL);
if (IS_ERR(kproc->reset)) {
- ret = PTR_ERR(kproc->reset);
- dev_err(dev, "failed to get reset, status = %d\n", ret);
+ ret = dev_err_probe(dev, PTR_ERR(kproc->reset),
+ "failed to get reset\n");
goto put_sci;
}
kproc->tsp = k3_dsp_rproc_of_get_tsp(dev, kproc->ti_sci);
if (IS_ERR(kproc->tsp)) {
- dev_err(dev, "failed to construct ti-sci proc control, ret = %d\n",
- ret);
- ret = PTR_ERR(kproc->tsp);
+ ret = dev_err_probe(dev, PTR_ERR(kproc->tsp),
+ "failed to construct ti-sci proc control\n");
goto put_sci;
}
ret = ti_sci_proc_request(kproc->tsp);
if (ret < 0) {
- dev_err(dev, "ti_sci_proc_request failed, ret = %d\n", ret);
+ dev_err_probe(dev, ret, "ti_sci_proc_request failed\n");
goto free_tsp;
}
@@ -753,15 +746,14 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev)
ret = k3_dsp_reserved_mem_init(kproc);
if (ret) {
- dev_err(dev, "reserved memory init failed, ret = %d\n", ret);
+ dev_err_probe(dev, ret, "reserved memory init failed\n");
goto release_tsp;
}
ret = kproc->ti_sci->ops.dev_ops.is_on(kproc->ti_sci, kproc->ti_sci_id,
NULL, &p_state);
if (ret) {
- dev_err(dev, "failed to get initial state, mode cannot be determined, ret = %d\n",
- ret);
+ dev_err_probe(dev, ret, "failed to get initial state, mode cannot be determined\n");
goto release_mem;
}
@@ -787,8 +779,7 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev)
if (data->uses_lreset) {
ret = reset_control_status(kproc->reset);
if (ret < 0) {
- dev_err(dev, "failed to get reset status, status = %d\n",
- ret);
+ dev_err_probe(dev, ret, "failed to get reset status\n");
goto release_mem;
} else if (ret == 0) {
dev_warn(dev, "local reset is deasserted for device\n");
@@ -799,8 +790,7 @@ static int k3_dsp_rproc_probe(struct platform_device *pdev)
ret = rproc_add(rproc);
if (ret) {
- dev_err(dev, "failed to add register device with remoteproc core, status = %d\n",
- ret);
+ dev_err_probe(dev, ret, "failed to add register device with remoteproc core\n");
goto release_mem;
}
@@ -813,19 +803,19 @@ release_mem:
release_tsp:
ret1 = ti_sci_proc_release(kproc->tsp);
if (ret1)
- dev_err(dev, "failed to release proc, ret = %d\n", ret1);
+ dev_err(dev, "failed to release proc (%pe)\n", ERR_PTR(ret1));
free_tsp:
kfree(kproc->tsp);
put_sci:
ret1 = ti_sci_put_handle(kproc->ti_sci);
if (ret1)
- dev_err(dev, "failed to put ti_sci handle, ret = %d\n", ret1);
+ dev_err(dev, "failed to put ti_sci handle (%pe)\n", ERR_PTR(ret1));
free_rproc:
rproc_free(rproc);
return ret;
}
-static int k3_dsp_rproc_remove(struct platform_device *pdev)
+static void k3_dsp_rproc_remove(struct platform_device *pdev)
{
struct k3_dsp_rproc *kproc = platform_get_drvdata(pdev);
struct rproc *rproc = kproc->rproc;
@@ -835,8 +825,9 @@ static int k3_dsp_rproc_remove(struct platform_device *pdev)
if (rproc->state == RPROC_ATTACHED) {
ret = rproc_detach(rproc);
if (ret) {
- dev_err(dev, "failed to detach proc, ret = %d\n", ret);
- return ret;
+ /* Note this error path leaks resources */
+ dev_err(dev, "failed to detach proc (%pe)\n", ERR_PTR(ret));
+ return;
}
}
@@ -844,18 +835,16 @@ static int k3_dsp_rproc_remove(struct platform_device *pdev)
ret = ti_sci_proc_release(kproc->tsp);
if (ret)
- dev_err(dev, "failed to release proc, ret = %d\n", ret);
+ dev_err(dev, "failed to release proc (%pe)\n", ERR_PTR(ret));
kfree(kproc->tsp);
ret = ti_sci_put_handle(kproc->ti_sci);
if (ret)
- dev_err(dev, "failed to put ti_sci handle, ret = %d\n", ret);
+ dev_err(dev, "failed to put ti_sci handle (%pe)\n", ERR_PTR(ret));
k3_dsp_reserved_mem_exit(kproc);
rproc_free(kproc->rproc);
-
- return 0;
}
static const struct k3_dsp_mem_data c66_mems[] = {
@@ -906,7 +895,7 @@ MODULE_DEVICE_TABLE(of, k3_dsp_of_match);
static struct platform_driver k3_dsp_rproc_driver = {
.probe = k3_dsp_rproc_probe,
- .remove = k3_dsp_rproc_remove,
+ .remove_new = k3_dsp_rproc_remove,
.driver = {
.name = "k3-dsp-rproc",
.of_match_table = k3_dsp_of_match,
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index dc87965f8164..1062939c3264 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -378,6 +378,7 @@ static void virtio_rpmsg_release_device(struct device *dev)
struct rpmsg_device *rpdev = to_rpmsg_device(dev);
struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
+ kfree(rpdev->driver_override);
kfree(vch);
}
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 99361618c31f..0b0324fe4aff 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -79,8 +79,8 @@ struct raw3215_info {
struct ccw_device *cdev; /* device for tty driver */
spinlock_t *lock; /* pointer to irq lock */
int flags; /* state flags */
- char *buffer; /* pointer to output buffer */
- char *inbuf; /* pointer to input buffer */
+ u8 *buffer; /* pointer to output buffer */
+ u8 *inbuf; /* pointer to input buffer */
int head; /* first free byte in output buffer */
int count; /* number of bytes in output buffer */
int written; /* number of bytes in write requests */
@@ -89,7 +89,6 @@ struct raw3215_info {
wait_queue_head_t empty_wait; /* wait queue for flushing */
struct timer_list timer; /* timer for delayed output */
int line_pos; /* position on the line (for tabs) */
- char ubuffer[80]; /* copy_from_user buffer */
};
/* array of 3215 devices structures */
@@ -523,12 +522,14 @@ static unsigned int raw3215_make_room(struct raw3215_info *raw,
* string without blocking.
* Return value is the number of bytes copied.
*/
-static unsigned int raw3215_addtext(const char *str, unsigned int length,
+static unsigned int raw3215_addtext(const u8 *str, size_t length,
struct raw3215_info *raw, int opmode,
unsigned int todrop)
{
- unsigned int c, ch, i, blanks, expanded_size = 0;
+ unsigned int i, blanks, expanded_size = 0;
unsigned int column = raw->line_pos;
+ size_t c;
+ u8 ch;
if (opmode == RAW3215_COUNT)
todrop = 0;
@@ -559,7 +560,7 @@ static unsigned int raw3215_addtext(const char *str, unsigned int length,
if (todrop && expanded_size < todrop) /* Drop head data */
continue;
for (i = 0; i < blanks; i++) {
- raw->buffer[raw->head] = (char)_ascebc[(int)ch];
+ raw->buffer[raw->head] = _ascebc[ch];
raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1);
raw->count++;
}
@@ -571,8 +572,8 @@ static unsigned int raw3215_addtext(const char *str, unsigned int length,
/*
* String write routine for 3215 devices
*/
-static void raw3215_write(struct raw3215_info *raw, const char *str,
- unsigned int length)
+static void raw3215_write(struct raw3215_info *raw, const u8 *str,
+ size_t length)
{
unsigned int count, avail;
unsigned long flags;
@@ -597,7 +598,7 @@ static void raw3215_write(struct raw3215_info *raw, const char *str,
/*
* Put character routine for 3215 devices
*/
-static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch)
+static void raw3215_putchar(struct raw3215_info *raw, u8 ch)
{
raw3215_write(raw, &ch, 1);
}
@@ -824,12 +825,10 @@ static struct ccw_driver raw3215_ccw_driver = {
.int_class = IRQIO_C15,
};
-static void handle_write(struct raw3215_info *raw, const char *str, int count)
+static void handle_write(struct raw3215_info *raw, const u8 *str, size_t count)
{
- int i;
-
while (count > 0) {
- i = min_t(int, count, RAW3215_BUFFER_SIZE - 1);
+ size_t i = min_t(size_t, count, RAW3215_BUFFER_SIZE - 1);
raw3215_write(raw, str, i);
count -= i;
str += i;
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index 363315fa1666..251d2a1c3eef 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -54,7 +54,7 @@ struct tty3270_attribute {
};
struct tty3270_cell {
- unsigned char character;
+ u8 character;
struct tty3270_attribute attributes;
};
@@ -123,7 +123,7 @@ struct tty3270 {
/* Character array for put_char/flush_chars. */
unsigned int char_count;
- char char_buf[TTY3270_CHAR_BUF_SIZE];
+ u8 char_buf[TTY3270_CHAR_BUF_SIZE];
};
/* tty3270->update_flags. See tty3270_update for details. */
@@ -1255,7 +1255,7 @@ static unsigned int tty3270_write_room(struct tty_struct *tty)
* Insert character into the screen at the current position with the
* current color and highlight. This function does NOT do cursor movement.
*/
-static void tty3270_put_character(struct tty3270 *tp, char ch)
+static void tty3270_put_character(struct tty3270 *tp, u8 ch)
{
struct tty3270_line *line;
struct tty3270_cell *cell;
@@ -1561,7 +1561,7 @@ static void tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
* Pn is a numeric parameter, a string of zero or more decimal digits.
* Ps is a selective parameter.
*/
-static void tty3270_escape_sequence(struct tty3270 *tp, char ch)
+static void tty3270_escape_sequence(struct tty3270 *tp, u8 ch)
{
enum { ES_NORMAL, ES_ESC, ES_SQUARE, ES_PAREN, ES_GETPARS };
@@ -1726,7 +1726,7 @@ static void tty3270_escape_sequence(struct tty3270 *tp, char ch)
* String write routine for 3270 ttys
*/
static void tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
- const unsigned char *buf, int count)
+ const u8 *buf, size_t count)
{
int i_msg, i;
@@ -2052,7 +2052,7 @@ con3270_write(struct console *co, const char *str, unsigned int count)
{
struct tty3270 *tp = co->data;
unsigned long flags;
- char c;
+ u8 c;
spin_lock_irqsave(&tp->view.lock, flags);
while (count--) {
diff --git a/drivers/s390/char/uvdevice.c b/drivers/s390/char/uvdevice.c
index 144cd2e03590..42c9f77f8da0 100644
--- a/drivers/s390/char/uvdevice.c
+++ b/drivers/s390/char/uvdevice.c
@@ -109,6 +109,7 @@ static int uvio_copy_attest_result_to_user(struct uv_cb_attest *uvcb_attest,
struct uvio_attest *uvio_attest)
{
struct uvio_attest __user *user_uvio_attest = (void __user *)uv_ioctl->argument_addr;
+ u32 __user *user_buf_add_len = (u32 __user *)&user_uvio_attest->add_data_len;
void __user *user_buf_add = (void __user *)uvio_attest->add_data_addr;
void __user *user_buf_meas = (void __user *)uvio_attest->meas_addr;
void __user *user_buf_uid = &user_uvio_attest->config_uid;
@@ -117,6 +118,8 @@ static int uvio_copy_attest_result_to_user(struct uv_cb_attest *uvcb_attest,
return -EFAULT;
if (add_data && copy_to_user(user_buf_add, add_data, uvio_attest->add_data_len))
return -EFAULT;
+ if (put_user(uvio_attest->add_data_len, user_buf_add_len))
+ return -EFAULT;
if (copy_to_user(user_buf_uid, uvcb_attest->config_uid, sizeof(uvcb_attest->config_uid)))
return -EFAULT;
return 0;
diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index acb710d3d7bc..983b3b16196c 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -32,7 +32,8 @@
#define AP_RESET_INTERVAL 20 /* Reset sleep interval (20ms) */
-static int vfio_ap_mdev_reset_queues(struct ap_queue_table *qtable);
+static int vfio_ap_mdev_reset_queues(struct ap_matrix_mdev *matrix_mdev);
+static int vfio_ap_mdev_reset_qlist(struct list_head *qlist);
static struct vfio_ap_queue *vfio_ap_find_queue(int apqn);
static const struct vfio_device_ops vfio_ap_matrix_dev_ops;
static void vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q);
@@ -665,17 +666,23 @@ static bool vfio_ap_mdev_filter_cdoms(struct ap_matrix_mdev *matrix_mdev)
* device driver.
*
* @matrix_mdev: the matrix mdev whose matrix is to be filtered.
+ * @apm_filtered: a 256-bit bitmap for storing the APIDs filtered from the
+ * guest's AP configuration that are still in the host's AP
+ * configuration.
*
* Note: If an APQN referencing a queue device that is not bound to the vfio_ap
* driver, its APID will be filtered from the guest's APCB. The matrix
* structure precludes filtering an individual APQN, so its APID will be
- * filtered.
+ * filtered. Consequently, all queues associated with the adapter that
+ * are in the host's AP configuration must be reset. If queues are
+ * subsequently made available again to the guest, they should re-appear
+ * in a reset state
*
* Return: a boolean value indicating whether the KVM guest's APCB was changed
* by the filtering or not.
*/
-static bool vfio_ap_mdev_filter_matrix(unsigned long *apm, unsigned long *aqm,
- struct ap_matrix_mdev *matrix_mdev)
+static bool vfio_ap_mdev_filter_matrix(struct ap_matrix_mdev *matrix_mdev,
+ unsigned long *apm_filtered)
{
unsigned long apid, apqi, apqn;
DECLARE_BITMAP(prev_shadow_apm, AP_DEVICES);
@@ -685,6 +692,7 @@ static bool vfio_ap_mdev_filter_matrix(unsigned long *apm, unsigned long *aqm,
bitmap_copy(prev_shadow_apm, matrix_mdev->shadow_apcb.apm, AP_DEVICES);
bitmap_copy(prev_shadow_aqm, matrix_mdev->shadow_apcb.aqm, AP_DOMAINS);
vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->shadow_apcb);
+ bitmap_clear(apm_filtered, 0, AP_DEVICES);
/*
* Copy the adapters, domains and control domains to the shadow_apcb
@@ -696,8 +704,9 @@ static bool vfio_ap_mdev_filter_matrix(unsigned long *apm, unsigned long *aqm,
bitmap_and(matrix_mdev->shadow_apcb.aqm, matrix_mdev->matrix.aqm,
(unsigned long *)matrix_dev->info.aqm, AP_DOMAINS);
- for_each_set_bit_inv(apid, apm, AP_DEVICES) {
- for_each_set_bit_inv(apqi, aqm, AP_DOMAINS) {
+ for_each_set_bit_inv(apid, matrix_mdev->shadow_apcb.apm, AP_DEVICES) {
+ for_each_set_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm,
+ AP_DOMAINS) {
/*
* If the APQN is not bound to the vfio_ap device
* driver, then we can't assign it to the guest's
@@ -709,8 +718,16 @@ static bool vfio_ap_mdev_filter_matrix(unsigned long *apm, unsigned long *aqm,
apqn = AP_MKQID(apid, apqi);
q = vfio_ap_mdev_get_queue(matrix_mdev, apqn);
if (!q || q->reset_status.response_code) {
- clear_bit_inv(apid,
- matrix_mdev->shadow_apcb.apm);
+ clear_bit_inv(apid, matrix_mdev->shadow_apcb.apm);
+
+ /*
+ * If the adapter was previously plugged into
+ * the guest, let's let the caller know that
+ * the APID was filtered.
+ */
+ if (test_bit_inv(apid, prev_shadow_apm))
+ set_bit_inv(apid, apm_filtered);
+
break;
}
}
@@ -812,7 +829,7 @@ static void vfio_ap_mdev_remove(struct mdev_device *mdev)
mutex_lock(&matrix_dev->guests_lock);
mutex_lock(&matrix_dev->mdevs_lock);
- vfio_ap_mdev_reset_queues(&matrix_mdev->qtable);
+ vfio_ap_mdev_reset_queues(matrix_mdev);
vfio_ap_mdev_unlink_fr_queues(matrix_mdev);
list_del(&matrix_mdev->node);
mutex_unlock(&matrix_dev->mdevs_lock);
@@ -922,6 +939,47 @@ static void vfio_ap_mdev_link_adapter(struct ap_matrix_mdev *matrix_mdev,
AP_MKQID(apid, apqi));
}
+static void collect_queues_to_reset(struct ap_matrix_mdev *matrix_mdev,
+ unsigned long apid,
+ struct list_head *qlist)
+{
+ struct vfio_ap_queue *q;
+ unsigned long apqi;
+
+ for_each_set_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm, AP_DOMAINS) {
+ q = vfio_ap_mdev_get_queue(matrix_mdev, AP_MKQID(apid, apqi));
+ if (q)
+ list_add_tail(&q->reset_qnode, qlist);
+ }
+}
+
+static void reset_queues_for_apid(struct ap_matrix_mdev *matrix_mdev,
+ unsigned long apid)
+{
+ struct list_head qlist;
+
+ INIT_LIST_HEAD(&qlist);
+ collect_queues_to_reset(matrix_mdev, apid, &qlist);
+ vfio_ap_mdev_reset_qlist(&qlist);
+}
+
+static int reset_queues_for_apids(struct ap_matrix_mdev *matrix_mdev,
+ unsigned long *apm_reset)
+{
+ struct list_head qlist;
+ unsigned long apid;
+
+ if (bitmap_empty(apm_reset, AP_DEVICES))
+ return 0;
+
+ INIT_LIST_HEAD(&qlist);
+
+ for_each_set_bit_inv(apid, apm_reset, AP_DEVICES)
+ collect_queues_to_reset(matrix_mdev, apid, &qlist);
+
+ return vfio_ap_mdev_reset_qlist(&qlist);
+}
+
/**
* assign_adapter_store - parses the APID from @buf and sets the
* corresponding bit in the mediated matrix device's APM
@@ -962,7 +1020,7 @@ static ssize_t assign_adapter_store(struct device *dev,
{
int ret;
unsigned long apid;
- DECLARE_BITMAP(apm_delta, AP_DEVICES);
+ DECLARE_BITMAP(apm_filtered, AP_DEVICES);
struct ap_matrix_mdev *matrix_mdev = dev_get_drvdata(dev);
mutex_lock(&ap_perms_mutex);
@@ -991,12 +1049,11 @@ static ssize_t assign_adapter_store(struct device *dev,
}
vfio_ap_mdev_link_adapter(matrix_mdev, apid);
- memset(apm_delta, 0, sizeof(apm_delta));
- set_bit_inv(apid, apm_delta);
- if (vfio_ap_mdev_filter_matrix(apm_delta,
- matrix_mdev->matrix.aqm, matrix_mdev))
+ if (vfio_ap_mdev_filter_matrix(matrix_mdev, apm_filtered)) {
vfio_ap_mdev_update_guest_apcb(matrix_mdev);
+ reset_queues_for_apids(matrix_mdev, apm_filtered);
+ }
ret = count;
done:
@@ -1027,11 +1084,12 @@ static struct vfio_ap_queue
* adapter was assigned.
* @matrix_mdev: the matrix mediated device to which the adapter was assigned.
* @apid: the APID of the unassigned adapter.
- * @qtable: table for storing queues associated with unassigned adapter.
+ * @qlist: list for storing queues associated with unassigned adapter that
+ * need to be reset.
*/
static void vfio_ap_mdev_unlink_adapter(struct ap_matrix_mdev *matrix_mdev,
unsigned long apid,
- struct ap_queue_table *qtable)
+ struct list_head *qlist)
{
unsigned long apqi;
struct vfio_ap_queue *q;
@@ -1039,11 +1097,10 @@ static void vfio_ap_mdev_unlink_adapter(struct ap_matrix_mdev *matrix_mdev,
for_each_set_bit_inv(apqi, matrix_mdev->matrix.aqm, AP_DOMAINS) {
q = vfio_ap_unlink_apqn_fr_mdev(matrix_mdev, apid, apqi);
- if (q && qtable) {
+ if (q && qlist) {
if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) &&
test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm))
- hash_add(qtable->queues, &q->mdev_qnode,
- q->apqn);
+ list_add_tail(&q->reset_qnode, qlist);
}
}
}
@@ -1051,26 +1108,23 @@ static void vfio_ap_mdev_unlink_adapter(struct ap_matrix_mdev *matrix_mdev,
static void vfio_ap_mdev_hot_unplug_adapter(struct ap_matrix_mdev *matrix_mdev,
unsigned long apid)
{
- int loop_cursor;
- struct vfio_ap_queue *q;
- struct ap_queue_table *qtable = kzalloc(sizeof(*qtable), GFP_KERNEL);
+ struct vfio_ap_queue *q, *tmpq;
+ struct list_head qlist;
- hash_init(qtable->queues);
- vfio_ap_mdev_unlink_adapter(matrix_mdev, apid, qtable);
+ INIT_LIST_HEAD(&qlist);
+ vfio_ap_mdev_unlink_adapter(matrix_mdev, apid, &qlist);
if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm)) {
clear_bit_inv(apid, matrix_mdev->shadow_apcb.apm);
vfio_ap_mdev_update_guest_apcb(matrix_mdev);
}
- vfio_ap_mdev_reset_queues(qtable);
+ vfio_ap_mdev_reset_qlist(&qlist);
- hash_for_each(qtable->queues, loop_cursor, q, mdev_qnode) {
+ list_for_each_entry_safe(q, tmpq, &qlist, reset_qnode) {
vfio_ap_unlink_mdev_fr_queue(q);
- hash_del(&q->mdev_qnode);
+ list_del(&q->reset_qnode);
}
-
- kfree(qtable);
}
/**
@@ -1171,7 +1225,7 @@ static ssize_t assign_domain_store(struct device *dev,
{
int ret;
unsigned long apqi;
- DECLARE_BITMAP(aqm_delta, AP_DOMAINS);
+ DECLARE_BITMAP(apm_filtered, AP_DEVICES);
struct ap_matrix_mdev *matrix_mdev = dev_get_drvdata(dev);
mutex_lock(&ap_perms_mutex);
@@ -1200,12 +1254,11 @@ static ssize_t assign_domain_store(struct device *dev,
}
vfio_ap_mdev_link_domain(matrix_mdev, apqi);
- memset(aqm_delta, 0, sizeof(aqm_delta));
- set_bit_inv(apqi, aqm_delta);
- if (vfio_ap_mdev_filter_matrix(matrix_mdev->matrix.apm, aqm_delta,
- matrix_mdev))
+ if (vfio_ap_mdev_filter_matrix(matrix_mdev, apm_filtered)) {
vfio_ap_mdev_update_guest_apcb(matrix_mdev);
+ reset_queues_for_apids(matrix_mdev, apm_filtered);
+ }
ret = count;
done:
@@ -1218,7 +1271,7 @@ static DEVICE_ATTR_WO(assign_domain);
static void vfio_ap_mdev_unlink_domain(struct ap_matrix_mdev *matrix_mdev,
unsigned long apqi,
- struct ap_queue_table *qtable)
+ struct list_head *qlist)
{
unsigned long apid;
struct vfio_ap_queue *q;
@@ -1226,11 +1279,10 @@ static void vfio_ap_mdev_unlink_domain(struct ap_matrix_mdev *matrix_mdev,
for_each_set_bit_inv(apid, matrix_mdev->matrix.apm, AP_DEVICES) {
q = vfio_ap_unlink_apqn_fr_mdev(matrix_mdev, apid, apqi);
- if (q && qtable) {
+ if (q && qlist) {
if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) &&
test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm))
- hash_add(qtable->queues, &q->mdev_qnode,
- q->apqn);
+ list_add_tail(&q->reset_qnode, qlist);
}
}
}
@@ -1238,26 +1290,23 @@ static void vfio_ap_mdev_unlink_domain(struct ap_matrix_mdev *matrix_mdev,
static void vfio_ap_mdev_hot_unplug_domain(struct ap_matrix_mdev *matrix_mdev,
unsigned long apqi)
{
- int loop_cursor;
- struct vfio_ap_queue *q;
- struct ap_queue_table *qtable = kzalloc(sizeof(*qtable), GFP_KERNEL);
+ struct vfio_ap_queue *q, *tmpq;
+ struct list_head qlist;
- hash_init(qtable->queues);
- vfio_ap_mdev_unlink_domain(matrix_mdev, apqi, qtable);
+ INIT_LIST_HEAD(&qlist);
+ vfio_ap_mdev_unlink_domain(matrix_mdev, apqi, &qlist);
if (test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm)) {
clear_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm);
vfio_ap_mdev_update_guest_apcb(matrix_mdev);
}
- vfio_ap_mdev_reset_queues(qtable);
+ vfio_ap_mdev_reset_qlist(&qlist);
- hash_for_each(qtable->queues, loop_cursor, q, mdev_qnode) {
+ list_for_each_entry_safe(q, tmpq, &qlist, reset_qnode) {
vfio_ap_unlink_mdev_fr_queue(q);
- hash_del(&q->mdev_qnode);
+ list_del(&q->reset_qnode);
}
-
- kfree(qtable);
}
/**
@@ -1612,7 +1661,7 @@ static void vfio_ap_mdev_unset_kvm(struct ap_matrix_mdev *matrix_mdev)
get_update_locks_for_kvm(kvm);
kvm_arch_crypto_clear_masks(kvm);
- vfio_ap_mdev_reset_queues(&matrix_mdev->qtable);
+ vfio_ap_mdev_reset_queues(matrix_mdev);
kvm_put_kvm(kvm);
matrix_mdev->kvm = NULL;
@@ -1748,15 +1797,33 @@ static void vfio_ap_mdev_reset_queue(struct vfio_ap_queue *q)
}
}
-static int vfio_ap_mdev_reset_queues(struct ap_queue_table *qtable)
+static int vfio_ap_mdev_reset_queues(struct ap_matrix_mdev *matrix_mdev)
{
int ret = 0, loop_cursor;
struct vfio_ap_queue *q;
- hash_for_each(qtable->queues, loop_cursor, q, mdev_qnode)
+ hash_for_each(matrix_mdev->qtable.queues, loop_cursor, q, mdev_qnode)
vfio_ap_mdev_reset_queue(q);
- hash_for_each(qtable->queues, loop_cursor, q, mdev_qnode) {
+ hash_for_each(matrix_mdev->qtable.queues, loop_cursor, q, mdev_qnode) {
+ flush_work(&q->reset_work);
+
+ if (q->reset_status.response_code)
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int vfio_ap_mdev_reset_qlist(struct list_head *qlist)
+{
+ int ret = 0;
+ struct vfio_ap_queue *q;
+
+ list_for_each_entry(q, qlist, reset_qnode)
+ vfio_ap_mdev_reset_queue(q);
+
+ list_for_each_entry(q, qlist, reset_qnode) {
flush_work(&q->reset_work);
if (q->reset_status.response_code)
@@ -1942,7 +2009,7 @@ static ssize_t vfio_ap_mdev_ioctl(struct vfio_device *vdev,
ret = vfio_ap_mdev_get_device_info(arg);
break;
case VFIO_DEVICE_RESET:
- ret = vfio_ap_mdev_reset_queues(&matrix_mdev->qtable);
+ ret = vfio_ap_mdev_reset_queues(matrix_mdev);
break;
case VFIO_DEVICE_GET_IRQ_INFO:
ret = vfio_ap_get_irq_info(arg);
@@ -2088,6 +2155,7 @@ int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
{
int ret;
struct vfio_ap_queue *q;
+ DECLARE_BITMAP(apm_filtered, AP_DEVICES);
struct ap_matrix_mdev *matrix_mdev;
ret = sysfs_create_group(&apdev->device.kobj, &vfio_queue_attr_group);
@@ -2109,15 +2177,28 @@ int vfio_ap_mdev_probe_queue(struct ap_device *apdev)
if (matrix_mdev) {
vfio_ap_mdev_link_queue(matrix_mdev, q);
- if (vfio_ap_mdev_filter_matrix(matrix_mdev->matrix.apm,
- matrix_mdev->matrix.aqm,
- matrix_mdev))
+ /*
+ * If we're in the process of handling the adding of adapters or
+ * domains to the host's AP configuration, then let the
+ * vfio_ap device driver's on_scan_complete callback filter the
+ * matrix and update the guest's AP configuration after all of
+ * the new queue devices are probed.
+ */
+ if (!bitmap_empty(matrix_mdev->apm_add, AP_DEVICES) ||
+ !bitmap_empty(matrix_mdev->aqm_add, AP_DOMAINS))
+ goto done;
+
+ if (vfio_ap_mdev_filter_matrix(matrix_mdev, apm_filtered)) {
vfio_ap_mdev_update_guest_apcb(matrix_mdev);
+ reset_queues_for_apids(matrix_mdev, apm_filtered);
+ }
}
+
+done:
dev_set_drvdata(&apdev->device, q);
release_update_locks_for_mdev(matrix_mdev);
- return 0;
+ return ret;
err_remove_group:
sysfs_remove_group(&apdev->device.kobj, &vfio_queue_attr_group);
@@ -2134,26 +2215,40 @@ void vfio_ap_mdev_remove_queue(struct ap_device *apdev)
q = dev_get_drvdata(&apdev->device);
get_update_locks_for_queue(q);
matrix_mdev = q->matrix_mdev;
+ apid = AP_QID_CARD(q->apqn);
+ apqi = AP_QID_QUEUE(q->apqn);
if (matrix_mdev) {
- vfio_ap_unlink_queue_fr_mdev(q);
-
- apid = AP_QID_CARD(q->apqn);
- apqi = AP_QID_QUEUE(q->apqn);
-
- /*
- * If the queue is assigned to the guest's APCB, then remove
- * the adapter's APID from the APCB and hot it into the guest.
- */
+ /* If the queue is assigned to the guest's AP configuration */
if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm) &&
test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm)) {
+ /*
+ * Since the queues are defined via a matrix of adapters
+ * and domains, it is not possible to hot unplug a
+ * single queue; so, let's unplug the adapter.
+ */
clear_bit_inv(apid, matrix_mdev->shadow_apcb.apm);
vfio_ap_mdev_update_guest_apcb(matrix_mdev);
+ reset_queues_for_apid(matrix_mdev, apid);
+ goto done;
}
}
- vfio_ap_mdev_reset_queue(q);
- flush_work(&q->reset_work);
+ /*
+ * If the queue is not in the host's AP configuration, then resetting
+ * it will fail with response code 01, (APQN not valid); so, let's make
+ * sure it is in the host's config.
+ */
+ if (test_bit_inv(apid, (unsigned long *)matrix_dev->info.apm) &&
+ test_bit_inv(apqi, (unsigned long *)matrix_dev->info.aqm)) {
+ vfio_ap_mdev_reset_queue(q);
+ flush_work(&q->reset_work);
+ }
+
+done:
+ if (matrix_mdev)
+ vfio_ap_unlink_queue_fr_mdev(q);
+
dev_set_drvdata(&apdev->device, NULL);
kfree(q);
release_update_locks_for_mdev(matrix_mdev);
@@ -2461,39 +2556,30 @@ void vfio_ap_on_cfg_changed(struct ap_config_info *cur_cfg_info,
static void vfio_ap_mdev_hot_plug_cfg(struct ap_matrix_mdev *matrix_mdev)
{
- bool do_hotplug = false;
- int filter_domains = 0;
- int filter_adapters = 0;
- DECLARE_BITMAP(apm, AP_DEVICES);
- DECLARE_BITMAP(aqm, AP_DOMAINS);
+ DECLARE_BITMAP(apm_filtered, AP_DEVICES);
+ bool filter_domains, filter_adapters, filter_cdoms, do_hotplug = false;
mutex_lock(&matrix_mdev->kvm->lock);
mutex_lock(&matrix_dev->mdevs_lock);
- filter_adapters = bitmap_and(apm, matrix_mdev->matrix.apm,
- matrix_mdev->apm_add, AP_DEVICES);
- filter_domains = bitmap_and(aqm, matrix_mdev->matrix.aqm,
- matrix_mdev->aqm_add, AP_DOMAINS);
-
- if (filter_adapters && filter_domains)
- do_hotplug |= vfio_ap_mdev_filter_matrix(apm, aqm, matrix_mdev);
- else if (filter_adapters)
- do_hotplug |=
- vfio_ap_mdev_filter_matrix(apm,
- matrix_mdev->shadow_apcb.aqm,
- matrix_mdev);
- else
- do_hotplug |=
- vfio_ap_mdev_filter_matrix(matrix_mdev->shadow_apcb.apm,
- aqm, matrix_mdev);
+ filter_adapters = bitmap_intersects(matrix_mdev->matrix.apm,
+ matrix_mdev->apm_add, AP_DEVICES);
+ filter_domains = bitmap_intersects(matrix_mdev->matrix.aqm,
+ matrix_mdev->aqm_add, AP_DOMAINS);
+ filter_cdoms = bitmap_intersects(matrix_mdev->matrix.adm,
+ matrix_mdev->adm_add, AP_DOMAINS);
- if (bitmap_intersects(matrix_mdev->matrix.adm, matrix_mdev->adm_add,
- AP_DOMAINS))
+ if (filter_adapters || filter_domains)
+ do_hotplug = vfio_ap_mdev_filter_matrix(matrix_mdev, apm_filtered);
+
+ if (filter_cdoms)
do_hotplug |= vfio_ap_mdev_filter_cdoms(matrix_mdev);
if (do_hotplug)
vfio_ap_mdev_update_guest_apcb(matrix_mdev);
+ reset_queues_for_apids(matrix_mdev, apm_filtered);
+
mutex_unlock(&matrix_dev->mdevs_lock);
mutex_unlock(&matrix_mdev->kvm->lock);
}
diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h
index 88aff8b81f2f..98d37aa27044 100644
--- a/drivers/s390/crypto/vfio_ap_private.h
+++ b/drivers/s390/crypto/vfio_ap_private.h
@@ -133,6 +133,8 @@ struct ap_matrix_mdev {
* @apqn: the APQN of the AP queue device
* @saved_isc: the guest ISC registered with the GIB interface
* @mdev_qnode: allows the vfio_ap_queue struct to be added to a hashtable
+ * @reset_qnode: allows the vfio_ap_queue struct to be added to a list of queues
+ * that need to be reset
* @reset_status: the status from the last reset of the queue
* @reset_work: work to wait for queue reset to complete
*/
@@ -143,6 +145,7 @@ struct vfio_ap_queue {
#define VFIO_AP_ISC_INVALID 0xff
unsigned char saved_isc;
struct hlist_node mdev_qnode;
+ struct list_head reset_qnode;
struct ap_queue_status reset_status;
struct work_struct reset_work;
};
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 46e6f807d1ca..706985358c6a 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -4880,7 +4880,7 @@ void lpfc_reset_barrier(struct lpfc_hba *phba)
lockdep_assert_held(&phba->hbalock);
pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype);
- if (hdrtype != 0x80 ||
+ if (hdrtype != PCI_HEADER_TYPE_MFD ||
(FC_JEDEC_ID(phba->vpd.rev.biuRev) != HELIOS_JEDEC_ID &&
FC_JEDEC_ID(phba->vpd.rev.biuRev) != THOR_JEDEC_ID))
return;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 03348f605c2e..dd674378f2f3 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -2889,7 +2889,7 @@ static void qla2x00_iocb_work_fn(struct work_struct *work)
static void
qla_trace_init(void)
{
- qla_trc_array = trace_array_get_by_name("qla2xxx");
+ qla_trc_array = trace_array_get_by_name("qla2xxx", NULL);
if (!qla_trc_array) {
ql_log(ql_log_fatal, NULL, 0x0001,
"Unable to create qla2xxx trace instance, instance logging will be disabled.\n");
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index 9d1bdcdc1331..4cf20be668a6 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -37,6 +37,11 @@
#define VIRTIO_SCSI_EVENT_LEN 8
#define VIRTIO_SCSI_VQ_BASE 2
+static unsigned int virtscsi_poll_queues;
+module_param(virtscsi_poll_queues, uint, 0644);
+MODULE_PARM_DESC(virtscsi_poll_queues,
+ "The number of dedicated virtqueues for polling I/O");
+
/* Command queue element */
struct virtio_scsi_cmd {
struct scsi_cmnd *sc;
@@ -76,6 +81,7 @@ struct virtio_scsi {
struct virtio_scsi_event_node event_list[VIRTIO_SCSI_EVENT_LEN];
u32 num_queues;
+ int io_queues[HCTX_MAX_TYPES];
struct hlist_node node;
@@ -722,9 +728,49 @@ static int virtscsi_abort(struct scsi_cmnd *sc)
static void virtscsi_map_queues(struct Scsi_Host *shost)
{
struct virtio_scsi *vscsi = shost_priv(shost);
- struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
+ int i, qoff;
+
+ for (i = 0, qoff = 0; i < shost->nr_maps; i++) {
+ struct blk_mq_queue_map *map = &shost->tag_set.map[i];
+
+ map->nr_queues = vscsi->io_queues[i];
+ map->queue_offset = qoff;
+ qoff += map->nr_queues;
+
+ if (map->nr_queues == 0)
+ continue;
+
+ /*
+ * Regular queues have interrupts and hence CPU affinity is
+ * defined by the core virtio code, but polling queues have
+ * no interrupts so we let the block layer assign CPU affinity.
+ */
+ if (i == HCTX_TYPE_POLL)
+ blk_mq_map_queues(map);
+ else
+ blk_mq_virtio_map_queues(map, vscsi->vdev, 2);
+ }
+}
+
+static int virtscsi_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
+{
+ struct virtio_scsi *vscsi = shost_priv(shost);
+ struct virtio_scsi_vq *virtscsi_vq = &vscsi->req_vqs[queue_num];
+ unsigned long flags;
+ unsigned int len;
+ int found = 0;
+ void *buf;
+
+ spin_lock_irqsave(&virtscsi_vq->vq_lock, flags);
+
+ while ((buf = virtqueue_get_buf(virtscsi_vq->vq, &len)) != NULL) {
+ virtscsi_complete_cmd(vscsi, buf);
+ found++;
+ }
+
+ spin_unlock_irqrestore(&virtscsi_vq->vq_lock, flags);
- blk_mq_virtio_map_queues(qmap, vscsi->vdev, 2);
+ return found;
}
static void virtscsi_commit_rqs(struct Scsi_Host *shost, u16 hwq)
@@ -751,6 +797,7 @@ static const struct scsi_host_template virtscsi_host_template = {
.this_id = -1,
.cmd_size = sizeof(struct virtio_scsi_cmd),
.queuecommand = virtscsi_queuecommand,
+ .mq_poll = virtscsi_mq_poll,
.commit_rqs = virtscsi_commit_rqs,
.change_queue_depth = virtscsi_change_queue_depth,
.eh_abort_handler = virtscsi_abort,
@@ -795,13 +842,14 @@ static int virtscsi_init(struct virtio_device *vdev,
{
int err;
u32 i;
- u32 num_vqs;
+ u32 num_vqs, num_poll_vqs, num_req_vqs;
vq_callback_t **callbacks;
const char **names;
struct virtqueue **vqs;
struct irq_affinity desc = { .pre_vectors = 2 };
- num_vqs = vscsi->num_queues + VIRTIO_SCSI_VQ_BASE;
+ num_req_vqs = vscsi->num_queues;
+ num_vqs = num_req_vqs + VIRTIO_SCSI_VQ_BASE;
vqs = kmalloc_array(num_vqs, sizeof(struct virtqueue *), GFP_KERNEL);
callbacks = kmalloc_array(num_vqs, sizeof(vq_callback_t *),
GFP_KERNEL);
@@ -812,15 +860,31 @@ static int virtscsi_init(struct virtio_device *vdev,
goto out;
}
+ num_poll_vqs = min_t(unsigned int, virtscsi_poll_queues,
+ num_req_vqs - 1);
+ vscsi->io_queues[HCTX_TYPE_DEFAULT] = num_req_vqs - num_poll_vqs;
+ vscsi->io_queues[HCTX_TYPE_READ] = 0;
+ vscsi->io_queues[HCTX_TYPE_POLL] = num_poll_vqs;
+
+ dev_info(&vdev->dev, "%d/%d/%d default/read/poll queues\n",
+ vscsi->io_queues[HCTX_TYPE_DEFAULT],
+ vscsi->io_queues[HCTX_TYPE_READ],
+ vscsi->io_queues[HCTX_TYPE_POLL]);
+
callbacks[0] = virtscsi_ctrl_done;
callbacks[1] = virtscsi_event_done;
names[0] = "control";
names[1] = "event";
- for (i = VIRTIO_SCSI_VQ_BASE; i < num_vqs; i++) {
+ for (i = VIRTIO_SCSI_VQ_BASE; i < num_vqs - num_poll_vqs; i++) {
callbacks[i] = virtscsi_req_done;
names[i] = "request";
}
+ for (; i < num_vqs; i++) {
+ callbacks[i] = NULL;
+ names[i] = "request_poll";
+ }
+
/* Discover virtqueues and write information to configuration. */
err = virtio_find_vqs(vdev, num_vqs, vqs, callbacks, names, &desc);
if (err)
@@ -874,6 +938,7 @@ static int virtscsi_probe(struct virtio_device *vdev)
sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1;
shost->sg_tablesize = sg_elems;
+ shost->nr_maps = 1;
vscsi = shost_priv(shost);
vscsi->vdev = vdev;
vscsi->num_queues = num_queues;
@@ -883,6 +948,9 @@ static int virtscsi_probe(struct virtio_device *vdev)
if (err)
goto virtscsi_init_failed;
+ if (vscsi->io_queues[HCTX_TYPE_POLL])
+ shost->nr_maps = HCTX_TYPE_POLL + 1;
+
shost->can_queue = virtqueue_get_vring_size(vscsi->req_vqs[0].vq);
cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1;
diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c
index e05473c5c267..16018009a5a6 100644
--- a/drivers/sh/maple/maple.c
+++ b/drivers/sh/maple/maple.c
@@ -59,6 +59,7 @@ struct maple_device_specify {
static bool checked[MAPLE_PORTS];
static bool empty[MAPLE_PORTS];
static struct maple_device *baseunits[MAPLE_PORTS];
+static const struct bus_type maple_bus_type;
/**
* maple_driver_register - register a maple driver
@@ -773,11 +774,10 @@ static struct maple_driver maple_unsupported_device = {
/*
* maple_bus_type - core maple bus structure
*/
-struct bus_type maple_bus_type = {
+static const struct bus_type maple_bus_type = {
.name = "maple",
.match = maple_match_bus_driver,
};
-EXPORT_SYMBOL_GPL(maple_bus_type);
static struct device maple_bus = {
.init_name = "maple",
diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c
index 042553abe1bf..253299e4214d 100644
--- a/drivers/soc/xilinx/xlnx_event_manager.c
+++ b/drivers/soc/xilinx/xlnx_event_manager.c
@@ -77,11 +77,26 @@ struct registered_event_data {
static bool xlnx_is_error_event(const u32 node_id)
{
- if (node_id == EVENT_ERROR_PMC_ERR1 ||
- node_id == EVENT_ERROR_PMC_ERR2 ||
- node_id == EVENT_ERROR_PSM_ERR1 ||
- node_id == EVENT_ERROR_PSM_ERR2)
- return true;
+ u32 pm_family_code, pm_sub_family_code;
+
+ zynqmp_pm_get_family_info(&pm_family_code, &pm_sub_family_code);
+
+ if (pm_sub_family_code == VERSAL_SUB_FAMILY_CODE) {
+ if (node_id == VERSAL_EVENT_ERROR_PMC_ERR1 ||
+ node_id == VERSAL_EVENT_ERROR_PMC_ERR2 ||
+ node_id == VERSAL_EVENT_ERROR_PSM_ERR1 ||
+ node_id == VERSAL_EVENT_ERROR_PSM_ERR2)
+ return true;
+ } else {
+ if (node_id == VERSAL_NET_EVENT_ERROR_PMC_ERR1 ||
+ node_id == VERSAL_NET_EVENT_ERROR_PMC_ERR2 ||
+ node_id == VERSAL_NET_EVENT_ERROR_PMC_ERR3 ||
+ node_id == VERSAL_NET_EVENT_ERROR_PSM_ERR1 ||
+ node_id == VERSAL_NET_EVENT_ERROR_PSM_ERR2 ||
+ node_id == VERSAL_NET_EVENT_ERROR_PSM_ERR3 ||
+ node_id == VERSAL_NET_EVENT_ERROR_PSM_ERR4)
+ return true;
+ }
return false;
}
@@ -483,7 +498,7 @@ static void xlnx_call_notify_cb_handler(const u32 *payload)
static void xlnx_get_event_callback_data(u32 *buf)
{
- zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, 0, 0, 0, 0, buf);
+ zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, buf, 0);
}
static irqreturn_t xlnx_event_handler(int irq, void *dev_id)
@@ -656,7 +671,11 @@ static int xlnx_event_manager_probe(struct platform_device *pdev)
ret = zynqmp_pm_register_sgi(sgi_num, 0);
if (ret) {
- dev_err(&pdev->dev, "SGI %d Registration over TF-A failed with %d\n", sgi_num, ret);
+ if (ret == -EOPNOTSUPP)
+ dev_err(&pdev->dev, "SGI registration not supported by TF-A or Xen\n");
+ else
+ dev_err(&pdev->dev, "SGI %d registration failed, err %d\n", sgi_num, ret);
+
xlnx_event_cleanup_sgi(pdev);
return ret;
}
diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c
index 07d735b38b49..965b1143936a 100644
--- a/drivers/soc/xilinx/zynqmp_power.c
+++ b/drivers/soc/xilinx/zynqmp_power.c
@@ -51,7 +51,7 @@ static enum pm_suspend_mode suspend_mode = PM_SUSPEND_MODE_STD;
static void zynqmp_pm_get_callback_data(u32 *buf)
{
- zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, 0, 0, 0, 0, buf);
+ zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, buf, 0);
}
static void suspend_event_callback(const u32 *payload, void *data)
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 9d974424c8c1..7f152167bb05 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -2,7 +2,7 @@
#
# Makefile for kernel SPMI framework.
#
-obj-$(CONFIG_SPMI) += spmi.o
+obj-$(CONFIG_SPMI) += spmi.o spmi-devres.o
obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o
obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o
diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c
index 9cbd473487cb..674a350cc676 100644
--- a/drivers/spmi/hisi-spmi-controller.c
+++ b/drivers/spmi/hisi-spmi-controller.c
@@ -267,10 +267,10 @@ static int spmi_controller_probe(struct platform_device *pdev)
struct resource *iores;
int ret;
- ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
- if (!ctrl) {
+ ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller));
+ if (IS_ERR(ctrl)) {
dev_err(&pdev->dev, "can not allocate spmi_controller data\n");
- return -ENOMEM;
+ return PTR_ERR(ctrl);
}
spmi_controller = spmi_controller_get_drvdata(ctrl);
spmi_controller->controller = ctrl;
@@ -278,24 +278,21 @@ static int spmi_controller_probe(struct platform_device *pdev)
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iores) {
dev_err(&pdev->dev, "can not get resource!\n");
- ret = -EINVAL;
- goto err_put_controller;
+ return -EINVAL;
}
spmi_controller->base = devm_ioremap(&pdev->dev, iores->start,
resource_size(iores));
if (!spmi_controller->base) {
dev_err(&pdev->dev, "can not remap base addr!\n");
- ret = -EADDRNOTAVAIL;
- goto err_put_controller;
+ return -EADDRNOTAVAIL;
}
ret = of_property_read_u32(pdev->dev.of_node, "hisilicon,spmi-channel",
&spmi_controller->channel);
if (ret) {
dev_err(&pdev->dev, "can not get channel\n");
- ret = -ENODEV;
- goto err_put_controller;
+ return -ENODEV;
}
platform_set_drvdata(pdev, spmi_controller);
@@ -311,25 +308,13 @@ static int spmi_controller_probe(struct platform_device *pdev)
ctrl->read_cmd = spmi_read_cmd;
ctrl->write_cmd = spmi_write_cmd;
- ret = spmi_controller_add(ctrl);
+ ret = devm_spmi_controller_add(&pdev->dev, ctrl);
if (ret) {
dev_err(&pdev->dev, "spmi_controller_add failed with error %d!\n", ret);
- goto err_put_controller;
+ return ret;
}
return 0;
-
-err_put_controller:
- spmi_controller_put(ctrl);
- return ret;
-}
-
-static void spmi_del_controller(struct platform_device *pdev)
-{
- struct spmi_controller *ctrl = platform_get_drvdata(pdev);
-
- spmi_controller_remove(ctrl);
- spmi_controller_put(ctrl);
}
static const struct of_device_id spmi_controller_match_table[] = {
@@ -342,7 +327,6 @@ MODULE_DEVICE_TABLE(of, spmi_controller_match_table);
static struct platform_driver spmi_controller_driver = {
.probe = spmi_controller_probe,
- .remove_new = spmi_del_controller,
.driver = {
.name = "hisi_spmi_controller",
.of_match_table = spmi_controller_match_table,
diff --git a/drivers/spmi/spmi-devres.c b/drivers/spmi/spmi-devres.c
new file mode 100644
index 000000000000..62c4b3f24d06
--- /dev/null
+++ b/drivers/spmi/spmi-devres.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2023 Google LLC.
+ */
+
+#include <linux/device.h>
+#include <linux/spmi.h>
+
+static void devm_spmi_controller_release(struct device *parent, void *res)
+{
+ spmi_controller_put(*(struct spmi_controller **)res);
+}
+
+struct spmi_controller *devm_spmi_controller_alloc(struct device *parent, size_t size)
+{
+ struct spmi_controller **ptr, *ctrl;
+
+ ptr = devres_alloc(devm_spmi_controller_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ ctrl = spmi_controller_alloc(parent, size);
+ if (IS_ERR(ctrl)) {
+ devres_free(ptr);
+ return ctrl;
+ }
+
+ *ptr = ctrl;
+ devres_add(parent, ptr);
+
+ return ctrl;
+}
+EXPORT_SYMBOL_GPL(devm_spmi_controller_alloc);
+
+static void devm_spmi_controller_remove(struct device *parent, void *res)
+{
+ spmi_controller_remove(*(struct spmi_controller **)res);
+}
+
+int devm_spmi_controller_add(struct device *parent, struct spmi_controller *ctrl)
+{
+ struct spmi_controller **ptr;
+ int ret;
+
+ ptr = devres_alloc(devm_spmi_controller_remove, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = spmi_controller_add(ctrl);
+ if (ret) {
+ devres_free(ptr);
+ return ret;
+ }
+
+ *ptr = ctrl;
+ devres_add(parent, ptr);
+
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(devm_spmi_controller_add);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SPMI devres helpers");
diff --git a/drivers/spmi/spmi-mtk-pmif.c b/drivers/spmi/spmi-mtk-pmif.c
index b3c991e1ea40..5079442f8ea1 100644
--- a/drivers/spmi/spmi-mtk-pmif.c
+++ b/drivers/spmi/spmi-mtk-pmif.c
@@ -50,6 +50,7 @@ struct pmif {
struct clk_bulk_data clks[PMIF_MAX_CLKS];
size_t nclks;
const struct pmif_data *data;
+ raw_spinlock_t lock;
};
static const char * const pmif_clock_names[] = {
@@ -314,6 +315,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
struct ch_reg *inf_reg;
int ret;
u32 data, cmd;
+ unsigned long flags;
/* Check for argument validation. */
if (sid & ~0xf) {
@@ -334,6 +336,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
else
return -EINVAL;
+ raw_spin_lock_irqsave(&arb->lock, flags);
/* Wait for Software Interface FSM state to be IDLE. */
inf_reg = &arb->chan;
ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
@@ -343,6 +346,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
/* set channel ready if the data has transferred */
if (pmif_is_fsm_vldclr(arb))
pmif_writel(arb, 1, inf_reg->ch_rdy);
+ raw_spin_unlock_irqrestore(&arb->lock, flags);
dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
return ret;
}
@@ -350,6 +354,7 @@ static int pmif_spmi_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
/* Send the command. */
cmd = (opc << 30) | (sid << 24) | ((len - 1) << 16) | addr;
pmif_writel(arb, cmd, inf_reg->ch_send);
+ raw_spin_unlock_irqrestore(&arb->lock, flags);
/*
* Wait for Software Interface FSM state to be WFVLDCLR,
@@ -376,7 +381,14 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
struct pmif *arb = spmi_controller_get_drvdata(ctrl);
struct ch_reg *inf_reg;
int ret;
- u32 data, cmd;
+ u32 data, wdata, cmd;
+ unsigned long flags;
+
+ /* Check for argument validation. */
+ if (unlikely(sid & ~0xf)) {
+ dev_err(&ctrl->dev, "exceed the max slv id\n");
+ return -EINVAL;
+ }
if (len > 4) {
dev_err(&ctrl->dev, "pmif supports 1..4 bytes per trans, but:%zu requested", len);
@@ -394,6 +406,10 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
else
return -EINVAL;
+ /* Set the write data. */
+ memcpy(&wdata, buf, len);
+
+ raw_spin_lock_irqsave(&arb->lock, flags);
/* Wait for Software Interface FSM state to be IDLE. */
inf_reg = &arb->chan;
ret = readl_poll_timeout_atomic(arb->base + arb->data->regs[inf_reg->ch_sta],
@@ -403,17 +419,17 @@ static int pmif_spmi_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
/* set channel ready if the data has transferred */
if (pmif_is_fsm_vldclr(arb))
pmif_writel(arb, 1, inf_reg->ch_rdy);
+ raw_spin_unlock_irqrestore(&arb->lock, flags);
dev_err(&ctrl->dev, "failed to wait for SWINF_IDLE\n");
return ret;
}
- /* Set the write data. */
- memcpy(&data, buf, len);
- pmif_writel(arb, data, inf_reg->wdata);
+ pmif_writel(arb, wdata, inf_reg->wdata);
/* Send the command. */
cmd = (opc << 30) | BIT(29) | (sid << 24) | ((len - 1) << 16) | addr;
pmif_writel(arb, cmd, inf_reg->ch_send);
+ raw_spin_unlock_irqrestore(&arb->lock, flags);
return 0;
}
@@ -437,44 +453,39 @@ static int mtk_spmi_probe(struct platform_device *pdev)
int err, i;
u32 chan_offset;
- ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*arb));
- if (!ctrl)
- return -ENOMEM;
+ ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*arb));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
arb = spmi_controller_get_drvdata(ctrl);
arb->data = device_get_match_data(&pdev->dev);
if (!arb->data) {
- err = -EINVAL;
dev_err(&pdev->dev, "Cannot get drv_data\n");
- goto err_put_ctrl;
+ return -EINVAL;
}
arb->base = devm_platform_ioremap_resource_byname(pdev, "pmif");
- if (IS_ERR(arb->base)) {
- err = PTR_ERR(arb->base);
- goto err_put_ctrl;
- }
+ if (IS_ERR(arb->base))
+ return PTR_ERR(arb->base);
arb->spmimst_base = devm_platform_ioremap_resource_byname(pdev, "spmimst");
- if (IS_ERR(arb->spmimst_base)) {
- err = PTR_ERR(arb->spmimst_base);
- goto err_put_ctrl;
- }
+ if (IS_ERR(arb->spmimst_base))
+ return PTR_ERR(arb->spmimst_base);
arb->nclks = ARRAY_SIZE(pmif_clock_names);
for (i = 0; i < arb->nclks; i++)
arb->clks[i].id = pmif_clock_names[i];
- err = devm_clk_bulk_get(&pdev->dev, arb->nclks, arb->clks);
+ err = clk_bulk_get(&pdev->dev, arb->nclks, arb->clks);
if (err) {
dev_err(&pdev->dev, "Failed to get clocks: %d\n", err);
- goto err_put_ctrl;
+ return err;
}
err = clk_bulk_prepare_enable(arb->nclks, arb->clks);
if (err) {
dev_err(&pdev->dev, "Failed to enable clocks: %d\n", err);
- goto err_put_ctrl;
+ goto err_put_clks;
}
ctrl->cmd = pmif_arb_cmd;
@@ -488,6 +499,8 @@ static int mtk_spmi_probe(struct platform_device *pdev)
arb->chan.ch_send = PMIF_SWINF_0_ACC + chan_offset;
arb->chan.ch_rdy = PMIF_SWINF_0_VLD_CLR + chan_offset;
+ raw_spin_lock_init(&arb->lock);
+
platform_set_drvdata(pdev, ctrl);
err = spmi_controller_add(ctrl);
@@ -498,8 +511,8 @@ static int mtk_spmi_probe(struct platform_device *pdev)
err_domain_remove:
clk_bulk_disable_unprepare(arb->nclks, arb->clks);
-err_put_ctrl:
- spmi_controller_put(ctrl);
+err_put_clks:
+ clk_bulk_put(arb->nclks, arb->clks);
return err;
}
@@ -508,9 +521,9 @@ static void mtk_spmi_remove(struct platform_device *pdev)
struct spmi_controller *ctrl = platform_get_drvdata(pdev);
struct pmif *arb = spmi_controller_get_drvdata(ctrl);
- clk_bulk_disable_unprepare(arb->nclks, arb->clks);
spmi_controller_remove(ctrl);
- spmi_controller_put(ctrl);
+ clk_bulk_disable_unprepare(arb->nclks, arb->clks);
+ clk_bulk_put(arb->nclks, arb->clks);
}
static const struct of_device_id mtk_spmi_match_table[] = {
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index dcb675d980d4..9ed1180fe31f 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -1443,9 +1443,9 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
u32 channel, ee, hw_ver;
int err;
- ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pmic_arb));
- if (!ctrl)
- return -ENOMEM;
+ ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*pmic_arb));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
pmic_arb = spmi_controller_get_drvdata(ctrl);
pmic_arb->spmic = ctrl;
@@ -1462,20 +1462,16 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
*/
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
core = devm_ioremap(&ctrl->dev, res->start, resource_size(res));
- if (IS_ERR(core)) {
- err = PTR_ERR(core);
- goto err_put_ctrl;
- }
+ if (IS_ERR(core))
+ return PTR_ERR(core);
pmic_arb->core_size = resource_size(res);
pmic_arb->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID,
sizeof(*pmic_arb->ppid_to_apid),
GFP_KERNEL);
- if (!pmic_arb->ppid_to_apid) {
- err = -ENOMEM;
- goto err_put_ctrl;
- }
+ if (!pmic_arb->ppid_to_apid)
+ return -ENOMEM;
hw_ver = readl_relaxed(core + PMIC_ARB_VERSION);
@@ -1499,19 +1495,15 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
"obsrvr");
pmic_arb->rd_base = devm_ioremap(&ctrl->dev, res->start,
resource_size(res));
- if (IS_ERR(pmic_arb->rd_base)) {
- err = PTR_ERR(pmic_arb->rd_base);
- goto err_put_ctrl;
- }
+ if (IS_ERR(pmic_arb->rd_base))
+ return PTR_ERR(pmic_arb->rd_base);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"chnls");
pmic_arb->wr_base = devm_ioremap(&ctrl->dev, res->start,
resource_size(res));
- if (IS_ERR(pmic_arb->wr_base)) {
- err = PTR_ERR(pmic_arb->wr_base);
- goto err_put_ctrl;
- }
+ if (IS_ERR(pmic_arb->wr_base))
+ return PTR_ERR(pmic_arb->wr_base);
}
pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS;
@@ -1522,10 +1514,9 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
of_property_read_u32(pdev->dev.of_node, "qcom,bus-id",
&pmic_arb->bus_instance);
if (pmic_arb->bus_instance > 1) {
- err = -EINVAL;
dev_err(&pdev->dev, "invalid bus instance (%u) specified\n",
pmic_arb->bus_instance);
- goto err_put_ctrl;
+ return -EINVAL;
}
if (pmic_arb->bus_instance == 0) {
@@ -1543,10 +1534,9 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
}
if (pmic_arb->base_apid + pmic_arb->apid_count > pmic_arb->max_periphs) {
- err = -EINVAL;
dev_err(&pdev->dev, "Unsupported APID count %d detected\n",
pmic_arb->base_apid + pmic_arb->apid_count);
- goto err_put_ctrl;
+ return -EINVAL;
}
} else if (hw_ver >= PMIC_ARB_VERSION_V5_MIN) {
pmic_arb->base_apid = 0;
@@ -1554,55 +1544,45 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
PMIC_ARB_FEATURES_PERIPH_MASK;
if (pmic_arb->apid_count > pmic_arb->max_periphs) {
- err = -EINVAL;
dev_err(&pdev->dev, "Unsupported APID count %d detected\n",
pmic_arb->apid_count);
- goto err_put_ctrl;
+ return -EINVAL;
}
}
pmic_arb->apid_data = devm_kcalloc(&ctrl->dev, pmic_arb->max_periphs,
sizeof(*pmic_arb->apid_data),
GFP_KERNEL);
- if (!pmic_arb->apid_data) {
- err = -ENOMEM;
- goto err_put_ctrl;
- }
+ if (!pmic_arb->apid_data)
+ return -ENOMEM;
dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
pmic_arb->ver_ops->ver_str, hw_ver);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
pmic_arb->intr = devm_ioremap_resource(&ctrl->dev, res);
- if (IS_ERR(pmic_arb->intr)) {
- err = PTR_ERR(pmic_arb->intr);
- goto err_put_ctrl;
- }
+ if (IS_ERR(pmic_arb->intr))
+ return PTR_ERR(pmic_arb->intr);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg");
pmic_arb->cnfg = devm_ioremap_resource(&ctrl->dev, res);
- if (IS_ERR(pmic_arb->cnfg)) {
- err = PTR_ERR(pmic_arb->cnfg);
- goto err_put_ctrl;
- }
+ if (IS_ERR(pmic_arb->cnfg))
+ return PTR_ERR(pmic_arb->cnfg);
pmic_arb->irq = platform_get_irq_byname(pdev, "periph_irq");
- if (pmic_arb->irq < 0) {
- err = pmic_arb->irq;
- goto err_put_ctrl;
- }
+ if (pmic_arb->irq < 0)
+ return pmic_arb->irq;
err = of_property_read_u32(pdev->dev.of_node, "qcom,channel", &channel);
if (err) {
dev_err(&pdev->dev, "channel unspecified.\n");
- goto err_put_ctrl;
+ return err;
}
if (channel > 5) {
dev_err(&pdev->dev, "invalid channel (%u) specified.\n",
channel);
- err = -EINVAL;
- goto err_put_ctrl;
+ return -EINVAL;
}
pmic_arb->channel = channel;
@@ -1610,22 +1590,19 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
err = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &ee);
if (err) {
dev_err(&pdev->dev, "EE unspecified.\n");
- goto err_put_ctrl;
+ return err;
}
if (ee > 5) {
dev_err(&pdev->dev, "invalid EE (%u) specified\n", ee);
- err = -EINVAL;
- goto err_put_ctrl;
+ return -EINVAL;
}
pmic_arb->ee = ee;
mapping_table = devm_kcalloc(&ctrl->dev, pmic_arb->max_periphs,
sizeof(*mapping_table), GFP_KERNEL);
- if (!mapping_table) {
- err = -ENOMEM;
- goto err_put_ctrl;
- }
+ if (!mapping_table)
+ return -ENOMEM;
pmic_arb->mapping_table = mapping_table;
/* Initialize max_apid/min_apid to the opposite bounds, during
@@ -1645,7 +1622,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
if (err) {
dev_err(&pdev->dev, "could not read APID->PPID mapping table, rc= %d\n",
err);
- goto err_put_ctrl;
+ return err;
}
}
@@ -1654,8 +1631,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
&pmic_arb_irq_domain_ops, pmic_arb);
if (!pmic_arb->domain) {
dev_err(&pdev->dev, "unable to create irq_domain\n");
- err = -ENOMEM;
- goto err_put_ctrl;
+ return -ENOMEM;
}
irq_set_chained_handler_and_data(pmic_arb->irq, pmic_arb_chained_irq,
@@ -1669,8 +1645,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
err_domain_remove:
irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL);
irq_domain_remove(pmic_arb->domain);
-err_put_ctrl:
- spmi_controller_put(ctrl);
return err;
}
@@ -1681,7 +1655,6 @@ static void spmi_pmic_arb_remove(struct platform_device *pdev)
spmi_controller_remove(ctrl);
irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL);
irq_domain_remove(pmic_arb->domain);
- spmi_controller_put(ctrl);
}
static const struct of_device_id spmi_pmic_arb_match_table[] = {
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 93cd4a34debc..3a60fd2e09e1 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -448,11 +448,11 @@ struct spmi_controller *spmi_controller_alloc(struct device *parent,
int id;
if (WARN_ON(!parent))
- return NULL;
+ return ERR_PTR(-EINVAL);
ctrl = kzalloc(sizeof(*ctrl) + size, GFP_KERNEL);
if (!ctrl)
- return NULL;
+ return ERR_PTR(-ENOMEM);
device_initialize(&ctrl->dev);
ctrl->dev.type = &spmi_ctrl_type;
@@ -466,7 +466,7 @@ struct spmi_controller *spmi_controller_alloc(struct device *parent,
dev_err(parent,
"unable to allocate SPMI controller identifier.\n");
spmi_controller_put(ctrl);
- return NULL;
+ return ERR_PTR(id);
}
ctrl->nr = id;
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index bc6c7b248f86..554c2e475ce3 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -36,6 +36,8 @@ source "drivers/staging/media/omap4iss/Kconfig"
source "drivers/staging/media/rkvdec/Kconfig"
+source "drivers/staging/media/starfive/Kconfig"
+
source "drivers/staging/media/sunxi/Kconfig"
source "drivers/staging/media/tegra-video/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 1a4c3a062e3d..dcaeeca0ee6d 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_VIDEO_MAX96712) += max96712/
obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/
obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/
obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/
+obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive/
obj-$(CONFIG_VIDEO_SUNXI) += sunxi/
obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/
obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
index 58cddf11c9ab..5bcd634a2a44 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
@@ -361,7 +361,7 @@ gc0310_get_pad_format(struct gc0310_device *dev,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&dev->sd, state, pad);
+ return v4l2_subdev_state_get_format(state, pad);
return &dev->mode.fmt;
}
@@ -496,9 +496,17 @@ error_power_down:
return ret;
}
-static int gc0310_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval)
+static int gc0310_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *interval)
{
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
interval->interval.numerator = 1;
interval->interval.denominator = GC0310_FPS;
@@ -545,7 +553,6 @@ static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = {
static const struct v4l2_subdev_video_ops gc0310_video_ops = {
.s_stream = gc0310_s_stream,
- .g_frame_interval = gc0310_g_frame_interval,
};
static const struct v4l2_subdev_pad_ops gc0310_pad_ops = {
@@ -553,6 +560,7 @@ static const struct v4l2_subdev_pad_ops gc0310_pad_ops = {
.enum_frame_size = gc0310_enum_frame_size,
.get_fmt = gc0310_get_fmt,
.set_fmt = gc0310_set_fmt,
+ .get_frame_interval = gc0310_get_frame_interval,
};
static const struct v4l2_subdev_ops gc0310_ops = {
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
index 9fa390fbc5f3..bec4c5615864 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
@@ -561,7 +561,7 @@ static int gc2235_set_fmt(struct v4l2_subdev *sd,
fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sd_state->pads->try_fmt = *fmt;
+ *v4l2_subdev_state_get_format(sd_state, 0) = *fmt;
mutex_unlock(&dev->input_lock);
return 0;
}
@@ -698,11 +698,19 @@ fail_power_off:
return ret;
}
-static int gc2235_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval)
+static int gc2235_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *interval)
{
struct gc2235_device *dev = to_gc2235_sensor(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
interval->interval.numerator = 1;
interval->interval.denominator = dev->res->fps;
@@ -754,7 +762,6 @@ static const struct v4l2_subdev_sensor_ops gc2235_sensor_ops = {
static const struct v4l2_subdev_video_ops gc2235_video_ops = {
.s_stream = gc2235_s_stream,
- .g_frame_interval = gc2235_g_frame_interval,
};
static const struct v4l2_subdev_core_ops gc2235_core_ops = {
@@ -767,6 +774,7 @@ static const struct v4l2_subdev_pad_ops gc2235_pad_ops = {
.enum_frame_size = gc2235_enum_frame_size,
.get_fmt = gc2235_get_fmt,
.set_fmt = gc2235_set_fmt,
+ .get_frame_interval = gc2235_get_frame_interval,
};
static const struct v4l2_subdev_ops gc2235_ops = {
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
index 1c6643c442ef..20f02d18a8de 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
@@ -666,7 +666,7 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
fmt->height = res->height;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sd_state->pads->try_fmt = *fmt;
+ *v4l2_subdev_state_get_format(sd_state, 0) = *fmt;
return 0;
}
@@ -1388,11 +1388,19 @@ static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value)
return !!err;
}
-static int mt9m114_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval)
+static int mt9m114_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *interval)
{
struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
interval->interval.numerator = 1;
interval->interval.denominator = mt9m114_res[dev->res].fps;
@@ -1479,7 +1487,6 @@ static int mt9m114_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
static const struct v4l2_subdev_video_ops mt9m114_video_ops = {
.s_stream = mt9m114_s_stream,
- .g_frame_interval = mt9m114_g_frame_interval,
};
static const struct v4l2_subdev_sensor_ops mt9m114_sensor_ops = {
@@ -1498,6 +1505,7 @@ static const struct v4l2_subdev_pad_ops mt9m114_pad_ops = {
.get_fmt = mt9m114_get_fmt,
.set_fmt = mt9m114_set_fmt,
.set_selection = mt9m114_s_exposure_selection,
+ .get_frame_interval = mt9m114_get_frame_interval,
};
static const struct v4l2_subdev_ops mt9m114_ops = {
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
index 6a72691ed5b7..133e346ae51b 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
@@ -671,7 +671,7 @@ static int ov2722_set_fmt(struct v4l2_subdev *sd,
fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sd_state->pads->try_fmt = *fmt;
+ *v4l2_subdev_state_get_format(sd_state, 0) = *fmt;
return 0;
}
@@ -845,11 +845,19 @@ fail_power_off:
return ret;
}
-static int ov2722_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval)
+static int ov2722_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *interval)
{
struct ov2722_device *dev = to_ov2722_sensor(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
interval->interval.numerator = 1;
interval->interval.denominator = dev->res->fps;
@@ -901,7 +909,6 @@ static const struct v4l2_subdev_sensor_ops ov2722_sensor_ops = {
static const struct v4l2_subdev_video_ops ov2722_video_ops = {
.s_stream = ov2722_s_stream,
- .g_frame_interval = ov2722_g_frame_interval,
};
static const struct v4l2_subdev_core_ops ov2722_core_ops = {
@@ -914,6 +921,7 @@ static const struct v4l2_subdev_pad_ops ov2722_pad_ops = {
.enum_frame_size = ov2722_enum_frame_size,
.get_fmt = ov2722_get_fmt,
.set_fmt = ov2722_set_fmt,
+ .get_frame_interval = ov2722_get_frame_interval,
};
static const struct v4l2_subdev_ops ov2722_ops = {
diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
index 759233a7ba50..f44e6412f4e3 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c
@@ -105,8 +105,8 @@ static unsigned short atomisp_get_sensor_fps(struct atomisp_sub_device *asd)
unsigned short fps = 0;
int ret;
- ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
- video, g_frame_interval, &fi);
+ ret = v4l2_subdev_call_state_active(isp->inputs[asd->input_curr].camera,
+ pad, get_frame_interval, &fi);
if (!ret && fi.interval.numerator)
fps = fi.interval.denominator / fi.interval.numerator;
diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c
index abf55a86f795..89118438a3b6 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c
@@ -29,8 +29,7 @@ v4l2_mbus_framefmt *__csi2_get_format(struct atomisp_mipi_csi2_device *csi2,
unsigned int pad)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csi2->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
else
return &csi2->formats[pad];
}
diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
index a8e4779d007f..01b7fa9b56a2 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
@@ -1028,7 +1028,7 @@ static int atomisp_qbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer
struct atomisp_device *isp = video_get_drvdata(vdev);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
- if (buf->index >= vdev->queue->num_buffers)
+ if (buf->index >= vb2_get_num_buffers(vdev->queue))
return -EINVAL;
if (buf->reserved2 & ATOMISP_BUFFER_HAS_PER_FRAME_SETTING) {
@@ -1059,7 +1059,7 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer
if (ret)
return ret;
- vb = pipe->vb_queue.bufs[buf->index];
+ vb = vb2_get_buffer(&pipe->vb_queue, buf->index);
frame = vb_to_frame(vb);
buf->reserved = asd->frame_status[buf->index];
@@ -1739,8 +1739,8 @@ static int atomisp_s_parm(struct file *file, void *fh,
fi.interval = parm->parm.capture.timeperframe;
- rval = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
- video, s_frame_interval, &fi);
+ rval = v4l2_subdev_call_state_active(isp->inputs[asd->input_curr].camera,
+ pad, set_frame_interval, &fi);
if (!rval)
parm->parm.capture.timeperframe = fi.interval;
diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c
index 471912dea5cd..a87fc74159e2 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c
@@ -240,9 +240,9 @@ struct v4l2_rect *atomisp_subdev_get_rect(struct v4l2_subdev *sd,
if (which == V4L2_SUBDEV_FORMAT_TRY) {
switch (target) {
case V4L2_SEL_TGT_CROP:
- return v4l2_subdev_get_try_crop(sd, sd_state, pad);
+ return v4l2_subdev_state_get_crop(sd_state, pad);
case V4L2_SEL_TGT_COMPOSE:
- return v4l2_subdev_get_try_compose(sd, sd_state, pad);
+ return v4l2_subdev_state_get_compose(sd_state, pad);
}
}
@@ -264,7 +264,7 @@ struct v4l2_mbus_framefmt
struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd);
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
return &isp_sd->fmt[pad].fmt;
}
diff --git a/drivers/staging/media/atomisp/pci/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp_tpg.c
index 074826a5b706..92e61ee90993 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_tpg.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_tpg.c
@@ -47,7 +47,7 @@ static int tpg_set_fmt(struct v4l2_subdev *sd,
/* only raw8 grbg is supported by TPG */
fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- sd_state->pads->try_fmt = *fmt;
+ *v4l2_subdev_state_get_format(sd_state, 0) = *fmt;
return 0;
}
return 0;
diff --git a/drivers/staging/media/deprecated/atmel/atmel-isc-base.c b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c
index 8e26663cecb6..305b103153d7 100644
--- a/drivers/staging/media/deprecated/atmel/atmel-isc-base.c
+++ b/drivers/staging/media/deprecated/atmel/atmel-isc-base.c
@@ -820,6 +820,8 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
static void isc_try_fse(struct isc_device *isc,
struct v4l2_subdev_state *sd_state)
{
+ struct v4l2_rect *try_crop =
+ v4l2_subdev_state_get_crop(sd_state, 0);
struct v4l2_subdev_frame_size_enum fse = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -841,11 +843,11 @@ static void isc_try_fse(struct isc_device *isc,
* just use the maximum ISC can receive.
*/
if (ret) {
- sd_state->pads->try_crop.width = isc->max_width;
- sd_state->pads->try_crop.height = isc->max_height;
+ try_crop->width = isc->max_width;
+ try_crop->height = isc->max_height;
} else {
- sd_state->pads->try_crop.width = fse.max_width;
- sd_state->pads->try_crop.height = fse.max_height;
+ try_crop->width = fse.max_width;
+ try_crop->height = fse.max_height;
}
}
@@ -1869,7 +1871,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->lock = &isc->lock;
- q->min_buffers_needed = 1;
+ q->min_queued_buffers = 1;
q->dev = isc->dev;
ret = vb2_queue_init(q);
diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c
index ac5fb332088e..2b80d54006b3 100644
--- a/drivers/staging/media/imx/imx-ic-prp.c
+++ b/drivers/staging/media/imx/imx-ic-prp.c
@@ -82,10 +82,8 @@ static struct v4l2_mbus_framefmt *
__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
- struct imx_ic_priv *ic_priv = priv->ic_priv;
-
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ic_priv->sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
else
return &priv->format_mbus;
}
@@ -395,11 +393,19 @@ out:
return ret;
}
-static int prp_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int prp_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct prp_priv *priv = sd_to_priv(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (fi->pad >= PRP_NUM_PADS)
return -EINVAL;
@@ -410,11 +416,19 @@ static int prp_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int prp_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int prp_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct prp_priv *priv = sd_to_priv(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (fi->pad >= PRP_NUM_PADS)
return -EINVAL;
@@ -450,16 +464,15 @@ static int prp_registered(struct v4l2_subdev *sd)
}
static const struct v4l2_subdev_pad_ops prp_pad_ops = {
- .init_cfg = imx_media_init_cfg,
.enum_mbus_code = prp_enum_mbus_code,
.get_fmt = prp_get_fmt,
.set_fmt = prp_set_fmt,
+ .get_frame_interval = prp_get_frame_interval,
+ .set_frame_interval = prp_set_frame_interval,
.link_validate = prp_link_validate,
};
static const struct v4l2_subdev_video_ops prp_video_ops = {
- .g_frame_interval = prp_g_frame_interval,
- .s_frame_interval = prp_s_frame_interval,
.s_stream = prp_s_stream,
};
@@ -474,6 +487,7 @@ static const struct v4l2_subdev_ops prp_subdev_ops = {
};
static const struct v4l2_subdev_internal_ops prp_internal_ops = {
+ .init_state = imx_media_init_state,
.registered = prp_registered,
};
diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c
index 9b81cfbcd777..17fd980c9d3c 100644
--- a/drivers/staging/media/imx/imx-ic-prpencvf.c
+++ b/drivers/staging/media/imx/imx-ic-prpencvf.c
@@ -790,10 +790,8 @@ static struct v4l2_mbus_framefmt *
__prp_get_fmt(struct prp_priv *priv, struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
- struct imx_ic_priv *ic_priv = priv->ic_priv;
-
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ic_priv->sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
else
return &priv->format_mbus[pad];
}
@@ -1205,11 +1203,19 @@ out:
return ret;
}
-static int prp_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int prp_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct prp_priv *priv = sd_to_priv(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (fi->pad >= PRPENCVF_NUM_PADS)
return -EINVAL;
@@ -1220,11 +1226,19 @@ static int prp_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int prp_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int prp_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct prp_priv *priv = sd_to_priv(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (fi->pad >= PRPENCVF_NUM_PADS)
return -EINVAL;
@@ -1298,16 +1312,15 @@ static void prp_unregistered(struct v4l2_subdev *sd)
}
static const struct v4l2_subdev_pad_ops prp_pad_ops = {
- .init_cfg = imx_media_init_cfg,
.enum_mbus_code = prp_enum_mbus_code,
.enum_frame_size = prp_enum_frame_size,
.get_fmt = prp_get_fmt,
.set_fmt = prp_set_fmt,
+ .get_frame_interval = prp_get_frame_interval,
+ .set_frame_interval = prp_set_frame_interval,
};
static const struct v4l2_subdev_video_ops prp_video_ops = {
- .g_frame_interval = prp_g_frame_interval,
- .s_frame_interval = prp_s_frame_interval,
.s_stream = prp_s_stream,
};
@@ -1322,6 +1335,7 @@ static const struct v4l2_subdev_ops prp_subdev_ops = {
};
static const struct v4l2_subdev_internal_ops prp_internal_ops = {
+ .init_state = imx_media_init_state,
.registered = prp_registered,
.unregistered = prp_unregistered,
};
diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c
index 4846078315ff..efa7623b5cee 100644
--- a/drivers/staging/media/imx/imx-media-capture.c
+++ b/drivers/staging/media/imx/imx-media-capture.c
@@ -511,7 +511,8 @@ static int capture_legacy_g_parm(struct file *file, void *fh,
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- ret = v4l2_subdev_call(priv->src_sd, video, g_frame_interval, &fi);
+ ret = v4l2_subdev_call_state_active(priv->src_sd, pad,
+ get_frame_interval, &fi);
if (ret < 0)
return ret;
@@ -534,7 +535,8 @@ static int capture_legacy_s_parm(struct file *file, void *fh,
return -EINVAL;
fi.interval = a->parm.capture.timeperframe;
- ret = v4l2_subdev_call(priv->src_sd, video, s_frame_interval, &fi);
+ ret = v4l2_subdev_call_state_active(priv->src_sd, pad,
+ set_frame_interval, &fi);
if (ret < 0)
return ret;
@@ -605,6 +607,7 @@ static int capture_queue_setup(struct vb2_queue *vq,
{
struct capture_priv *priv = vb2_get_drv_priv(vq);
struct v4l2_pix_format *pix = &priv->vdev.fmt;
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
unsigned int count = *nbuffers;
if (vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -613,14 +616,14 @@ static int capture_queue_setup(struct vb2_queue *vq,
if (*nplanes) {
if (*nplanes != 1 || sizes[0] < pix->sizeimage)
return -EINVAL;
- count += vq->num_buffers;
+ count += q_num_bufs;
}
count = min_t(__u32, VID_MEM_LIMIT / pix->sizeimage, count);
if (*nplanes)
- *nbuffers = (count < vq->num_buffers) ? 0 :
- count - vq->num_buffers;
+ *nbuffers = (count < q_num_bufs) ? 0 :
+ count - q_num_bufs;
else
*nbuffers = count;
@@ -1021,7 +1024,7 @@ imx_media_capture_device_init(struct device *dev, struct v4l2_subdev *src_sd,
vq->mem_ops = &vb2_dma_contig_memops;
vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
vq->lock = &priv->mutex;
- vq->min_buffers_needed = 2;
+ vq->min_queued_buffers = 2;
vq->dev = priv->dev;
ret = vb2_queue_init(vq);
diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c
index dda1ebc34692..785aac881922 100644
--- a/drivers/staging/media/imx/imx-media-csi.c
+++ b/drivers/staging/media/imx/imx-media-csi.c
@@ -902,11 +902,19 @@ static const struct csi_skip_desc *csi_find_best_skip(struct v4l2_fract *in,
* V4L2 subdev operations.
*/
-static int csi_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int csi_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (fi->pad >= CSI_NUM_PADS)
return -EINVAL;
@@ -919,13 +927,21 @@ static int csi_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int csi_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int csi_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct csi_priv *priv = v4l2_get_subdevdata(sd);
struct v4l2_fract *input_fi;
int ret = 0;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(&priv->lock);
input_fi = &priv->frame_interval[CSI_SINK_PAD];
@@ -1148,7 +1164,7 @@ __csi_get_fmt(struct csi_priv *priv, struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
else
return &priv->format_mbus[pad];
}
@@ -1158,8 +1174,7 @@ __csi_get_crop(struct csi_priv *priv, struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&priv->sd, sd_state,
- CSI_SINK_PAD);
+ return v4l2_subdev_state_get_crop(sd_state, CSI_SINK_PAD);
else
return &priv->crop;
}
@@ -1169,8 +1184,7 @@ __csi_get_compose(struct csi_priv *priv, struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_compose(&priv->sd, sd_state,
- CSI_SINK_PAD);
+ return v4l2_subdev_state_get_compose(sd_state, CSI_SINK_PAD);
else
return &priv->compose;
}
@@ -1862,13 +1876,10 @@ static const struct v4l2_subdev_core_ops csi_core_ops = {
};
static const struct v4l2_subdev_video_ops csi_video_ops = {
- .g_frame_interval = csi_g_frame_interval,
- .s_frame_interval = csi_s_frame_interval,
.s_stream = csi_s_stream,
};
static const struct v4l2_subdev_pad_ops csi_pad_ops = {
- .init_cfg = imx_media_init_cfg,
.enum_mbus_code = csi_enum_mbus_code,
.enum_frame_size = csi_enum_frame_size,
.enum_frame_interval = csi_enum_frame_interval,
@@ -1876,6 +1887,8 @@ static const struct v4l2_subdev_pad_ops csi_pad_ops = {
.set_fmt = csi_set_fmt,
.get_selection = csi_get_selection,
.set_selection = csi_set_selection,
+ .get_frame_interval = csi_get_frame_interval,
+ .set_frame_interval = csi_set_frame_interval,
.link_validate = csi_link_validate,
};
@@ -1886,6 +1899,7 @@ static const struct v4l2_subdev_ops csi_subdev_ops = {
};
static const struct v4l2_subdev_internal_ops csi_internal_ops = {
+ .init_state = imx_media_init_state,
.registered = csi_registered,
.unregistered = csi_unregistered,
};
diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c
index 064dc562bc96..1b5af8945e6b 100644
--- a/drivers/staging/media/imx/imx-media-utils.c
+++ b/drivers/staging/media/imx/imx-media-utils.c
@@ -426,10 +426,10 @@ EXPORT_SYMBOL_GPL(imx_media_init_mbus_fmt);
/*
* Initializes the TRY format to the ACTIVE format on all pads
- * of a subdev. Can be used as the .init_cfg pad operation.
+ * of a subdev. Can be used as the .init_state internal operation.
*/
-int imx_media_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+int imx_media_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *mf_try;
unsigned int pad;
@@ -445,13 +445,13 @@ int imx_media_init_cfg(struct v4l2_subdev *sd,
if (ret)
continue;
- mf_try = v4l2_subdev_get_try_format(sd, sd_state, pad);
+ mf_try = v4l2_subdev_state_get_format(sd_state, pad);
*mf_try = format.format;
}
return 0;
}
-EXPORT_SYMBOL_GPL(imx_media_init_cfg);
+EXPORT_SYMBOL_GPL(imx_media_init_state);
/*
* Default the colorspace in tryfmt to SRGB if set to an unsupported
diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c
index 3c2093c520ba..09da4103a8db 100644
--- a/drivers/staging/media/imx/imx-media-vdic.c
+++ b/drivers/staging/media/imx/imx-media-vdic.c
@@ -536,7 +536,7 @@ __vdic_get_fmt(struct vdic_priv *priv, struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
else
return &priv->format_mbus[pad];
}
@@ -780,11 +780,19 @@ static int vdic_link_validate(struct v4l2_subdev *sd,
return ret;
}
-static int vdic_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int vdic_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct vdic_priv *priv = v4l2_get_subdevdata(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (fi->pad >= VDIC_NUM_PADS)
return -EINVAL;
@@ -797,13 +805,21 @@ static int vdic_g_frame_interval(struct v4l2_subdev *sd,
return 0;
}
-static int vdic_s_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int vdic_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct vdic_priv *priv = v4l2_get_subdevdata(sd);
struct v4l2_fract *input_fi, *output_fi;
int ret = 0;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
mutex_lock(&priv->lock);
input_fi = &priv->frame_interval[priv->active_input_pad];
@@ -882,16 +898,15 @@ static void vdic_unregistered(struct v4l2_subdev *sd)
}
static const struct v4l2_subdev_pad_ops vdic_pad_ops = {
- .init_cfg = imx_media_init_cfg,
.enum_mbus_code = vdic_enum_mbus_code,
.get_fmt = vdic_get_fmt,
.set_fmt = vdic_set_fmt,
+ .get_frame_interval = vdic_get_frame_interval,
+ .set_frame_interval = vdic_set_frame_interval,
.link_validate = vdic_link_validate,
};
static const struct v4l2_subdev_video_ops vdic_video_ops = {
- .g_frame_interval = vdic_g_frame_interval,
- .s_frame_interval = vdic_s_frame_interval,
.s_stream = vdic_s_stream,
};
@@ -906,6 +921,7 @@ static const struct v4l2_subdev_ops vdic_subdev_ops = {
};
static const struct v4l2_subdev_internal_ops vdic_internal_ops = {
+ .init_state = imx_media_init_state,
.registered = vdic_registered,
.unregistered = vdic_unregistered,
};
diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h
index 2640cd34dce2..f095d9134fee 100644
--- a/drivers/staging/media/imx/imx-media.h
+++ b/drivers/staging/media/imx/imx-media.h
@@ -192,8 +192,8 @@ static inline int imx_media_enum_ipu_formats(u32 *code, u32 index,
int imx_media_init_mbus_fmt(struct v4l2_mbus_framefmt *mbus,
u32 width, u32 height, u32 code, u32 field,
const struct imx_media_pixfmt **cc);
-int imx_media_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state);
+int imx_media_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state);
void imx_media_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt,
bool ic_route);
int imx_media_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c
index b2d8476d83a0..0d8b42061623 100644
--- a/drivers/staging/media/imx/imx6-mipi-csi2.c
+++ b/drivers/staging/media/imx/imx6-mipi-csi2.c
@@ -501,7 +501,7 @@ __csi2_get_fmt(struct csi2_dev *csi2, struct v4l2_subdev_state *sd_state,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csi2->sd, sd_state, pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
else
return &csi2->format_mbus;
}
@@ -619,7 +619,6 @@ static const struct v4l2_subdev_video_ops csi2_video_ops = {
};
static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
- .init_cfg = imx_media_init_cfg,
.get_fmt = csi2_get_fmt,
.set_fmt = csi2_set_fmt,
};
@@ -631,6 +630,7 @@ static const struct v4l2_subdev_ops csi2_subdev_ops = {
};
static const struct v4l2_subdev_internal_ops csi2_internal_ops = {
+ .init_state = imx_media_init_state,
.registered = csi2_registered,
};
diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c
index e530767e80a5..a66f034380c0 100644
--- a/drivers/staging/media/ipu3/ipu3-v4l2.c
+++ b/drivers/staging/media/ipu3/ipu3-v4l2.c
@@ -36,7 +36,7 @@ static int imgu_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
/* Initialize try_fmt */
for (i = 0; i < IMGU_NODE_NUM; i++) {
struct v4l2_mbus_framefmt *try_fmt =
- v4l2_subdev_get_try_format(sd, fh->state, i);
+ v4l2_subdev_state_get_format(fh->state, i);
try_fmt->width = try_crop.width;
try_fmt->height = try_crop.height;
@@ -44,8 +44,8 @@ static int imgu_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
try_fmt->field = V4L2_FIELD_NONE;
}
- *v4l2_subdev_get_try_crop(sd, fh->state, IMGU_NODE_IN) = try_crop;
- *v4l2_subdev_get_try_compose(sd, fh->state, IMGU_NODE_IN) = try_crop;
+ *v4l2_subdev_state_get_crop(fh->state, IMGU_NODE_IN) = try_crop;
+ *v4l2_subdev_state_get_compose(fh->state, IMGU_NODE_IN) = try_crop;
return 0;
}
@@ -136,7 +136,7 @@ static int imgu_subdev_get_fmt(struct v4l2_subdev *sd,
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
fmt->format = imgu_pipe->nodes[pad].pad_fmt;
} else {
- mf = v4l2_subdev_get_try_format(sd, sd_state, pad);
+ mf = v4l2_subdev_state_get_format(sd_state, pad);
fmt->format = *mf;
}
@@ -161,7 +161,7 @@ static int imgu_subdev_set_fmt(struct v4l2_subdev *sd,
imgu_pipe = &imgu->imgu_pipe[pipe];
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
- mf = v4l2_subdev_get_try_format(sd, sd_state, pad);
+ mf = v4l2_subdev_state_get_format(sd_state, pad);
else
mf = &imgu_pipe->nodes[pad].pad_fmt;
@@ -194,7 +194,7 @@ imgu_subdev_get_crop(struct imgu_v4l2_subdev *sd,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&sd->subdev, sd_state, pad);
+ return v4l2_subdev_state_get_crop(sd_state, pad);
else
return &sd->rect.eff;
}
@@ -205,7 +205,7 @@ imgu_subdev_get_compose(struct imgu_v4l2_subdev *sd,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_compose(&sd->subdev, sd_state, pad);
+ return v4l2_subdev_state_get_compose(sd_state, pad);
else
return &sd->rect.bds;
}
@@ -1198,7 +1198,7 @@ static int imgu_v4l2_node_setup(struct imgu_device *imgu, unsigned int pipe,
vbq->buf_struct_size = imgu->buf_struct_size;
vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
/* can streamon w/o buffers */
- vbq->min_buffers_needed = 0;
+ vbq->min_queued_buffers = 0;
vbq->drv_priv = imgu;
vbq->lock = &node->lock;
r = vb2_queue_init(vbq);
diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
index 219185aaa588..de3e0345ab7c 100644
--- a/drivers/staging/media/meson/vdec/vdec.c
+++ b/drivers/staging/media/meson/vdec/vdec.c
@@ -167,23 +167,24 @@ static void process_num_buffers(struct vb2_queue *q,
bool is_reqbufs)
{
const struct amvdec_format *fmt_out = sess->fmt_out;
- unsigned int buffers_total = q->num_buffers + *num_buffers;
+ unsigned int q_num_bufs = vb2_get_num_buffers(q);
+ unsigned int buffers_total = q_num_bufs + *num_buffers;
u32 min_buf_capture = v4l2_ctrl_g_ctrl(sess->ctrl_min_buf_capture);
- if (q->num_buffers + *num_buffers < min_buf_capture)
- *num_buffers = min_buf_capture - q->num_buffers;
+ if (q_num_bufs + *num_buffers < min_buf_capture)
+ *num_buffers = min_buf_capture - q_num_bufs;
if (is_reqbufs && buffers_total < fmt_out->min_buffers)
- *num_buffers = fmt_out->min_buffers - q->num_buffers;
+ *num_buffers = fmt_out->min_buffers - q_num_bufs;
if (buffers_total > fmt_out->max_buffers)
- *num_buffers = fmt_out->max_buffers - q->num_buffers;
+ *num_buffers = fmt_out->max_buffers - q_num_bufs;
/* We need to program the complete CAPTURE buffer list
* in registers during start_streaming, and the firmwares
* are free to choose any of them to write frames to. As such,
* we need all of them to be queued into the driver
*/
- sess->num_dst_bufs = q->num_buffers + *num_buffers;
- q->min_buffers_needed = max(fmt_out->min_buffers, sess->num_dst_bufs);
+ sess->num_dst_bufs = q_num_bufs + *num_buffers;
+ q->min_queued_buffers = max(fmt_out->min_buffers, sess->num_dst_bufs);
}
static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
@@ -824,7 +825,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->drv_priv = sess;
src_vq->buf_struct_size = sizeof(struct dummy_buf);
- src_vq->min_buffers_needed = 1;
+ src_vq->min_queued_buffers = 1;
src_vq->dev = sess->core->dev;
src_vq->lock = &sess->lock;
ret = vb2_queue_init(src_vq);
@@ -838,7 +839,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->drv_priv = sess;
dst_vq->buf_struct_size = sizeof(struct dummy_buf);
- dst_vq->min_buffers_needed = 1;
+ dst_vq->min_queued_buffers = 1;
dst_vq->dev = sess->core->dev;
dst_vq->lock = &sess->lock;
return vb2_queue_init(dst_vq);
diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c
index d2844414de4f..0e6c5bd81930 100644
--- a/drivers/staging/media/omap4iss/iss_csi2.c
+++ b/drivers/staging/media/omap4iss/iss_csi2.c
@@ -830,8 +830,7 @@ __csi2_get_format(struct iss_csi2_device *csi2,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&csi2->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
return &csi2->formats[pad];
}
@@ -891,7 +890,7 @@ csi2_try_format(struct iss_csi2_device *csi2,
/*
* csi2_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @cfg : V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
@@ -965,7 +964,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd,
/*
* csi2_get_format - Handle get format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
@@ -987,7 +986,7 @@ static int csi2_get_format(struct v4l2_subdev *sd,
/*
* csi2_set_format - Handle set format by pads subdev method
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @fmt: pointer to v4l2 subdev format structure
* return -EINVAL or zero on success
*/
diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c
index 23f707cb336f..4a4eae290d65 100644
--- a/drivers/staging/media/omap4iss/iss_ipipe.c
+++ b/drivers/staging/media/omap4iss/iss_ipipe.c
@@ -180,8 +180,7 @@ __ipipe_get_format(struct iss_ipipe_device *ipipe,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ipipe->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
return &ipipe->formats[pad];
}
@@ -189,7 +188,7 @@ __ipipe_get_format(struct iss_ipipe_device *ipipe,
/*
* ipipe_try_format - Try video format on a pad
* @ipipe: ISS IPIPE device
- * @cfg: V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @pad: Pad number
* @fmt: Format
*/
@@ -240,7 +239,7 @@ ipipe_try_format(struct iss_ipipe_device *ipipe,
/*
* ipipe_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @cfg : V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
@@ -304,7 +303,7 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
/*
* ipipe_get_format - Retrieve the video format on a pad
* @sd : ISP IPIPE V4L2 subdevice
- * @cfg: V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @fmt: Format
*
* Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
@@ -328,7 +327,7 @@ static int ipipe_get_format(struct v4l2_subdev *sd,
/*
* ipipe_set_format - Set the video format on a pad
* @sd : ISP IPIPE V4L2 subdevice
- * @cfg: V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @fmt: Format
*
* Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c
index 5e7f25cd53ac..8fa99532d9d4 100644
--- a/drivers/staging/media/omap4iss/iss_ipipeif.c
+++ b/drivers/staging/media/omap4iss/iss_ipipeif.c
@@ -361,15 +361,14 @@ __ipipeif_get_format(struct iss_ipipeif_device *ipipeif,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&ipipeif->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
return &ipipeif->formats[pad];
}
/*
* ipipeif_try_format - Try video format on a pad
* @ipipeif: ISS IPIPEIF device
- * @cfg: V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @pad: Pad number
* @fmt: Format
*/
@@ -440,7 +439,7 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif,
/*
* ipipeif_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @cfg : V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
@@ -512,7 +511,7 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd,
/*
* ipipeif_get_format - Retrieve the video format on a pad
* @sd : ISP IPIPEIF V4L2 subdevice
- * @cfg: V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @fmt: Format
*
* Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
@@ -536,7 +535,7 @@ static int ipipeif_get_format(struct v4l2_subdev *sd,
/*
* ipipeif_set_format - Set the video format on a pad
* @sd : ISP IPIPEIF V4L2 subdevice
- * @cfg: V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @fmt: Format
*
* Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c
index a5f8f9f1ab16..58e698ef9108 100644
--- a/drivers/staging/media/omap4iss/iss_resizer.c
+++ b/drivers/staging/media/omap4iss/iss_resizer.c
@@ -420,15 +420,14 @@ __resizer_get_format(struct iss_resizer_device *resizer,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&resizer->subdev, sd_state,
- pad);
+ return v4l2_subdev_state_get_format(sd_state, pad);
return &resizer->formats[pad];
}
/*
* resizer_try_format - Try video format on a pad
* @resizer: ISS RESIZER device
- * @cfg: V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @pad: Pad number
* @fmt: Format
*/
@@ -489,7 +488,7 @@ resizer_try_format(struct iss_resizer_device *resizer,
/*
* resizer_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
- * @cfg: V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @code : pointer to v4l2_subdev_mbus_code_enum structure
* return -EINVAL or zero on success
*/
@@ -572,7 +571,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd,
/*
* resizer_get_format - Retrieve the video format on a pad
* @sd : ISP RESIZER V4L2 subdevice
- * @cfg: V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @fmt: Format
*
* Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
@@ -596,7 +595,7 @@ static int resizer_get_format(struct v4l2_subdev *sd,
/*
* resizer_set_format - Set the video format on a pad
* @sd : ISP RESIZER V4L2 subdevice
- * @cfg: V4L2 subdev pad config
+ * @sd_state: V4L2 subdev state
* @fmt: Format
*
* Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
diff --git a/drivers/staging/media/rkvdec/Kconfig b/drivers/staging/media/rkvdec/Kconfig
index e963d60cc6ad..5f3bdd848a2c 100644
--- a/drivers/staging/media/rkvdec/Kconfig
+++ b/drivers/staging/media/rkvdec/Kconfig
@@ -4,7 +4,6 @@ config VIDEO_ROCKCHIP_VDEC
depends on ARCH_ROCKCHIP || COMPILE_TEST
depends on VIDEO_DEV
select MEDIA_CONTROLLER
- select MEDIA_CONTROLLER_REQUEST_API
select VIDEOBUF2_DMA_CONTIG
select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c
index 84a41792cb4b..ac398b5a9736 100644
--- a/drivers/staging/media/rkvdec/rkvdec.c
+++ b/drivers/staging/media/rkvdec/rkvdec.c
@@ -461,6 +461,9 @@ static const struct v4l2_ioctl_ops rkvdec_ioctl_ops = {
.vidioc_streamon = v4l2_m2m_ioctl_streamon,
.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd,
+ .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd,
};
static int rkvdec_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers,
diff --git a/drivers/staging/media/starfive/Kconfig b/drivers/staging/media/starfive/Kconfig
new file mode 100644
index 000000000000..34727cf56072
--- /dev/null
+++ b/drivers/staging/media/starfive/Kconfig
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+comment "StarFive media platform drivers"
+
+source "drivers/staging/media/starfive/camss/Kconfig"
diff --git a/drivers/staging/media/starfive/Makefile b/drivers/staging/media/starfive/Makefile
new file mode 100644
index 000000000000..4639fa1bca32
--- /dev/null
+++ b/drivers/staging/media/starfive/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-y += camss/
diff --git a/drivers/staging/media/starfive/camss/Kconfig b/drivers/staging/media/starfive/camss/Kconfig
new file mode 100644
index 000000000000..9ea5708fe409
--- /dev/null
+++ b/drivers/staging/media/starfive/camss/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VIDEO_STARFIVE_CAMSS
+ tristate "Starfive Camera Subsystem driver"
+ depends on V4L_PLATFORM_DRIVERS
+ depends on VIDEO_DEV && OF
+ depends on HAS_DMA
+ depends on PM
+ depends on ARCH_STARFIVE || COMPILE_TEST
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_FWNODE
+ help
+ Enable this to support for the Starfive Camera subsystem
+ found on Starfive JH7110 SoC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called starfive-camss.
diff --git a/drivers/staging/media/starfive/camss/Makefile b/drivers/staging/media/starfive/camss/Makefile
new file mode 100644
index 000000000000..005790202e7b
--- /dev/null
+++ b/drivers/staging/media/starfive/camss/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for StarFive Camera Subsystem driver
+#
+
+starfive-camss-objs += \
+ stf-camss.o \
+ stf-capture.o \
+ stf-isp.o \
+ stf-isp-hw-ops.o \
+ stf-video.o
+
+obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive-camss.o
diff --git a/drivers/staging/media/starfive/camss/TODO.txt b/drivers/staging/media/starfive/camss/TODO.txt
new file mode 100644
index 000000000000..7d459f4f09d0
--- /dev/null
+++ b/drivers/staging/media/starfive/camss/TODO.txt
@@ -0,0 +1,4 @@
+Unstaging requirements:
+- Add userspace support which demonstrates the ability to receive statistics and
+ adapt hardware modules configuration accordingly;
+- Add documentation for description of the statistics data structures;
diff --git a/drivers/staging/media/starfive/camss/stf-camss.c b/drivers/staging/media/starfive/camss/stf-camss.c
new file mode 100644
index 000000000000..a587f860101a
--- /dev/null
+++ b/drivers/staging/media/starfive/camss/stf-camss.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * stf_camss.c
+ *
+ * Starfive Camera Subsystem driver
+ *
+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
+ *
+ * Author: Jack Zhu <[email protected]>
+ * Author: Changhuang Liang <[email protected]>
+ *
+ */
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
+
+#include "stf-camss.h"
+
+static const char * const stfcamss_clocks[] = {
+ "wrapper_clk_c",
+ "ispcore_2x",
+ "isp_axi",
+};
+
+static const char * const stfcamss_resets[] = {
+ "wrapper_p",
+ "wrapper_c",
+ "axiwr",
+ "isp_top_n",
+ "isp_top_axi",
+};
+
+static const struct stf_isr_data stf_isrs[] = {
+ {"wr_irq", stf_wr_irq_handler},
+ {"isp_irq", stf_isp_irq_handler},
+ {"line_irq", stf_line_irq_handler},
+};
+
+static int stfcamss_get_mem_res(struct stfcamss *stfcamss)
+{
+ struct platform_device *pdev = to_platform_device(stfcamss->dev);
+
+ stfcamss->syscon_base =
+ devm_platform_ioremap_resource_byname(pdev, "syscon");
+ if (IS_ERR(stfcamss->syscon_base))
+ return PTR_ERR(stfcamss->syscon_base);
+
+ stfcamss->isp_base = devm_platform_ioremap_resource_byname(pdev, "isp");
+ if (IS_ERR(stfcamss->isp_base))
+ return PTR_ERR(stfcamss->isp_base);
+
+ return 0;
+}
+
+/*
+ * stfcamss_of_parse_endpoint_node - Parse port endpoint node
+ * @dev: Device
+ * @node: Device node to be parsed
+ * @csd: Parsed data from port endpoint node
+ *
+ * Return 0 on success or a negative error code on failure
+ */
+static int stfcamss_of_parse_endpoint_node(struct stfcamss *stfcamss,
+ struct device_node *node,
+ struct stfcamss_async_subdev *csd)
+{
+ struct v4l2_fwnode_endpoint vep = { { 0 } };
+ int ret;
+
+ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep);
+ if (ret) {
+ dev_err(stfcamss->dev, "endpoint not defined at %pOF\n", node);
+ return ret;
+ }
+
+ csd->port = vep.base.port;
+
+ return 0;
+}
+
+/*
+ * stfcamss_of_parse_ports - Parse ports node
+ * @stfcamss: STFCAMSS device
+ *
+ * Return number of "port" nodes found in "ports" node
+ */
+static int stfcamss_of_parse_ports(struct stfcamss *stfcamss)
+{
+ struct device_node *node = NULL;
+ int ret, num_subdevs = 0;
+
+ for_each_endpoint_of_node(stfcamss->dev->of_node, node) {
+ struct stfcamss_async_subdev *csd;
+
+ if (!of_device_is_available(node))
+ continue;
+
+ csd = v4l2_async_nf_add_fwnode_remote(&stfcamss->notifier,
+ of_fwnode_handle(node),
+ struct stfcamss_async_subdev);
+ if (IS_ERR(csd)) {
+ ret = PTR_ERR(csd);
+ dev_err(stfcamss->dev, "failed to add async notifier\n");
+ goto err_cleanup;
+ }
+
+ ret = stfcamss_of_parse_endpoint_node(stfcamss, node, csd);
+ if (ret)
+ goto err_cleanup;
+
+ num_subdevs++;
+ }
+
+ return num_subdevs;
+
+err_cleanup:
+ of_node_put(node);
+ return ret;
+}
+
+static int stfcamss_register_devs(struct stfcamss *stfcamss)
+{
+ struct stf_capture *cap_yuv = &stfcamss->captures[STF_CAPTURE_YUV];
+ struct stf_isp_dev *isp_dev = &stfcamss->isp_dev;
+ int ret;
+
+ ret = stf_isp_register(isp_dev, &stfcamss->v4l2_dev);
+ if (ret < 0) {
+ dev_err(stfcamss->dev,
+ "failed to register stf isp%d entity: %d\n", 0, ret);
+ return ret;
+ }
+
+ ret = stf_capture_register(stfcamss, &stfcamss->v4l2_dev);
+ if (ret < 0) {
+ dev_err(stfcamss->dev,
+ "failed to register capture: %d\n", ret);
+ goto err_isp_unregister;
+ }
+
+ ret = media_create_pad_link(&isp_dev->subdev.entity, STF_ISP_PAD_SRC,
+ &cap_yuv->video.vdev.entity, 0, 0);
+ if (ret)
+ goto err_cap_unregister;
+
+ cap_yuv->video.source_subdev = &isp_dev->subdev;
+
+ return ret;
+
+err_cap_unregister:
+ stf_capture_unregister(stfcamss);
+err_isp_unregister:
+ stf_isp_unregister(&stfcamss->isp_dev);
+
+ return ret;
+}
+
+static void stfcamss_unregister_devs(struct stfcamss *stfcamss)
+{
+ stf_isp_unregister(&stfcamss->isp_dev);
+ stf_capture_unregister(stfcamss);
+}
+
+static int stfcamss_subdev_notifier_bound(struct v4l2_async_notifier *async,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_connection *asc)
+{
+ struct stfcamss *stfcamss =
+ container_of(async, struct stfcamss, notifier);
+ struct stfcamss_async_subdev *csd =
+ container_of(asc, struct stfcamss_async_subdev, asd);
+ enum stf_port_num port = csd->port;
+ struct stf_isp_dev *isp_dev = &stfcamss->isp_dev;
+ struct stf_capture *cap_raw = &stfcamss->captures[STF_CAPTURE_RAW];
+ struct media_pad *pad;
+ int ret;
+
+ if (port == STF_PORT_CSI2RX) {
+ pad = &isp_dev->pads[STF_ISP_PAD_SINK];
+ } else {
+ dev_err(stfcamss->dev, "not support port %d\n", port);
+ return -EPERM;
+ }
+
+ ret = v4l2_create_fwnode_links_to_pad(subdev, pad, 0);
+ if (ret)
+ return ret;
+
+ ret = media_create_pad_link(&subdev->entity, 1,
+ &cap_raw->video.vdev.entity, 0, 0);
+ if (ret)
+ return ret;
+
+ isp_dev->source_subdev = subdev;
+ cap_raw->video.source_subdev = subdev;
+
+ return 0;
+}
+
+static int stfcamss_subdev_notifier_complete(struct v4l2_async_notifier *ntf)
+{
+ struct stfcamss *stfcamss =
+ container_of(ntf, struct stfcamss, notifier);
+
+ return v4l2_device_register_subdev_nodes(&stfcamss->v4l2_dev);
+}
+
+static const struct v4l2_async_notifier_operations
+stfcamss_subdev_notifier_ops = {
+ .bound = stfcamss_subdev_notifier_bound,
+ .complete = stfcamss_subdev_notifier_complete,
+};
+
+static void stfcamss_mc_init(struct platform_device *pdev,
+ struct stfcamss *stfcamss)
+{
+ stfcamss->media_dev.dev = stfcamss->dev;
+ strscpy(stfcamss->media_dev.model, "Starfive Camera Subsystem",
+ sizeof(stfcamss->media_dev.model));
+ media_device_init(&stfcamss->media_dev);
+
+ stfcamss->v4l2_dev.mdev = &stfcamss->media_dev;
+}
+
+/*
+ * stfcamss_probe - Probe STFCAMSS platform device
+ * @pdev: Pointer to STFCAMSS platform device
+ *
+ * Return 0 on success or a negative error code on failure
+ */
+static int stfcamss_probe(struct platform_device *pdev)
+{
+ struct stfcamss *stfcamss;
+ struct device *dev = &pdev->dev;
+ int ret, num_subdevs;
+ unsigned int i;
+
+ stfcamss = devm_kzalloc(dev, sizeof(*stfcamss), GFP_KERNEL);
+ if (!stfcamss)
+ return -ENOMEM;
+
+ stfcamss->dev = dev;
+
+ for (i = 0; i < ARRAY_SIZE(stf_isrs); ++i) {
+ int irq;
+
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(stfcamss->dev, irq, stf_isrs[i].isr, 0,
+ stf_isrs[i].name, stfcamss);
+ if (ret) {
+ dev_err(dev, "request irq failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ stfcamss->nclks = ARRAY_SIZE(stfcamss->sys_clk);
+ for (i = 0; i < stfcamss->nclks; ++i)
+ stfcamss->sys_clk[i].id = stfcamss_clocks[i];
+ ret = devm_clk_bulk_get(dev, stfcamss->nclks, stfcamss->sys_clk);
+ if (ret) {
+ dev_err(dev, "Failed to get clk controls\n");
+ return ret;
+ }
+
+ stfcamss->nrsts = ARRAY_SIZE(stfcamss->sys_rst);
+ for (i = 0; i < stfcamss->nrsts; ++i)
+ stfcamss->sys_rst[i].id = stfcamss_resets[i];
+ ret = devm_reset_control_bulk_get_shared(dev, stfcamss->nrsts,
+ stfcamss->sys_rst);
+ if (ret) {
+ dev_err(dev, "Failed to get reset controls\n");
+ return ret;
+ }
+
+ ret = stfcamss_get_mem_res(stfcamss);
+ if (ret) {
+ dev_err(dev, "Could not map registers\n");
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, stfcamss);
+
+ v4l2_async_nf_init(&stfcamss->notifier, &stfcamss->v4l2_dev);
+
+ num_subdevs = stfcamss_of_parse_ports(stfcamss);
+ if (num_subdevs < 0) {
+ ret = -ENODEV;
+ dev_err(dev, "Failed to get sub devices: %d\n", ret);
+ goto err_cleanup_notifier;
+ }
+
+ ret = stf_isp_init(stfcamss);
+ if (ret < 0) {
+ dev_err(dev, "Failed to init isp: %d\n", ret);
+ goto err_cleanup_notifier;
+ }
+
+ stfcamss_mc_init(pdev, stfcamss);
+
+ ret = v4l2_device_register(stfcamss->dev, &stfcamss->v4l2_dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register V4L2 device: %d\n", ret);
+ goto err_cleanup_media_device;
+ }
+
+ ret = media_device_register(&stfcamss->media_dev);
+ if (ret) {
+ dev_err(dev, "Failed to register media device: %d\n", ret);
+ goto err_unregister_device;
+ }
+
+ ret = stfcamss_register_devs(stfcamss);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register subdevice: %d\n", ret);
+ goto err_unregister_media_dev;
+ }
+
+ pm_runtime_enable(dev);
+
+ stfcamss->notifier.ops = &stfcamss_subdev_notifier_ops;
+ ret = v4l2_async_nf_register(&stfcamss->notifier);
+ if (ret) {
+ dev_err(dev, "Failed to register async subdev nodes: %d\n",
+ ret);
+ pm_runtime_disable(dev);
+ goto err_unregister_subdevs;
+ }
+
+ return 0;
+
+err_unregister_subdevs:
+ stfcamss_unregister_devs(stfcamss);
+err_unregister_media_dev:
+ media_device_unregister(&stfcamss->media_dev);
+err_unregister_device:
+ v4l2_device_unregister(&stfcamss->v4l2_dev);
+err_cleanup_media_device:
+ media_device_cleanup(&stfcamss->media_dev);
+err_cleanup_notifier:
+ v4l2_async_nf_cleanup(&stfcamss->notifier);
+ return ret;
+}
+
+/*
+ * stfcamss_remove - Remove STFCAMSS platform device
+ * @pdev: Pointer to STFCAMSS platform device
+ *
+ * Always returns 0.
+ */
+static int stfcamss_remove(struct platform_device *pdev)
+{
+ struct stfcamss *stfcamss = platform_get_drvdata(pdev);
+
+ stfcamss_unregister_devs(stfcamss);
+ v4l2_device_unregister(&stfcamss->v4l2_dev);
+ media_device_cleanup(&stfcamss->media_dev);
+ v4l2_async_nf_cleanup(&stfcamss->notifier);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id stfcamss_of_match[] = {
+ { .compatible = "starfive,jh7110-camss" },
+ { /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, stfcamss_of_match);
+
+static int __maybe_unused stfcamss_runtime_suspend(struct device *dev)
+{
+ struct stfcamss *stfcamss = dev_get_drvdata(dev);
+ int ret;
+
+ ret = reset_control_bulk_assert(stfcamss->nrsts, stfcamss->sys_rst);
+ if (ret) {
+ dev_err(dev, "reset assert failed\n");
+ return ret;
+ }
+
+ clk_bulk_disable_unprepare(stfcamss->nclks, stfcamss->sys_clk);
+
+ return 0;
+}
+
+static int __maybe_unused stfcamss_runtime_resume(struct device *dev)
+{
+ struct stfcamss *stfcamss = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_bulk_prepare_enable(stfcamss->nclks, stfcamss->sys_clk);
+ if (ret) {
+ dev_err(dev, "clock prepare enable failed\n");
+ return ret;
+ }
+
+ ret = reset_control_bulk_deassert(stfcamss->nrsts, stfcamss->sys_rst);
+ if (ret < 0) {
+ dev_err(dev, "cannot deassert resets\n");
+ clk_bulk_disable_unprepare(stfcamss->nclks, stfcamss->sys_clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops stfcamss_pm_ops = {
+ SET_RUNTIME_PM_OPS(stfcamss_runtime_suspend,
+ stfcamss_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver stfcamss_driver = {
+ .probe = stfcamss_probe,
+ .remove = stfcamss_remove,
+ .driver = {
+ .name = "starfive-camss",
+ .pm = &stfcamss_pm_ops,
+ .of_match_table = stfcamss_of_match,
+ },
+};
+
+module_platform_driver(stfcamss_driver);
+
+MODULE_AUTHOR("Jack Zhu <[email protected]>");
+MODULE_AUTHOR("Changhuang Liang <[email protected]>");
+MODULE_DESCRIPTION("StarFive Camera Subsystem driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/starfive/camss/stf-camss.h b/drivers/staging/media/starfive/camss/stf-camss.h
new file mode 100644
index 000000000000..e2b0cfb437bd
--- /dev/null
+++ b/drivers/staging/media/starfive/camss/stf-camss.h
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * stf_camss.h
+ *
+ * Starfive Camera Subsystem driver
+ *
+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
+ */
+
+#ifndef STF_CAMSS_H
+#define STF_CAMSS_H
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/reset.h>
+#include <media/media-device.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-device.h>
+
+#include "stf-isp.h"
+#include "stf-capture.h"
+
+enum stf_port_num {
+ STF_PORT_DVP = 0,
+ STF_PORT_CSI2RX
+};
+
+enum stf_clk {
+ STF_CLK_WRAPPER_CLK_C = 0,
+ STF_CLK_ISPCORE_2X,
+ STF_CLK_ISP_AXI,
+ STF_CLK_NUM
+};
+
+enum stf_rst {
+ STF_RST_WRAPPER_P = 0,
+ STF_RST_WRAPPER_C,
+ STF_RST_AXIWR,
+ STF_RST_ISP_TOP_N,
+ STF_RST_ISP_TOP_AXI,
+ STF_RST_NUM
+};
+
+struct stf_isr_data {
+ const char *name;
+ irqreturn_t (*isr)(int irq, void *priv);
+};
+
+struct stfcamss {
+ struct v4l2_device v4l2_dev;
+ struct media_device media_dev;
+ struct media_pipeline pipe;
+ struct device *dev;
+ struct stf_isp_dev isp_dev;
+ struct stf_capture captures[STF_CAPTURE_NUM];
+ struct v4l2_async_notifier notifier;
+ void __iomem *syscon_base;
+ void __iomem *isp_base;
+ struct clk_bulk_data sys_clk[STF_CLK_NUM];
+ int nclks;
+ struct reset_control_bulk_data sys_rst[STF_RST_NUM];
+ int nrsts;
+};
+
+struct stfcamss_async_subdev {
+ struct v4l2_async_connection asd; /* must be first */
+ enum stf_port_num port;
+};
+
+static inline u32 stf_isp_reg_read(struct stfcamss *stfcamss, u32 reg)
+{
+ return ioread32(stfcamss->isp_base + reg);
+}
+
+static inline void stf_isp_reg_write(struct stfcamss *stfcamss,
+ u32 reg, u32 val)
+{
+ iowrite32(val, stfcamss->isp_base + reg);
+}
+
+static inline void stf_isp_reg_write_delay(struct stfcamss *stfcamss,
+ u32 reg, u32 val, u32 delay)
+{
+ iowrite32(val, stfcamss->isp_base + reg);
+ usleep_range(1000 * delay, 1000 * delay + 100);
+}
+
+static inline void stf_isp_reg_set_bit(struct stfcamss *stfcamss,
+ u32 reg, u32 mask, u32 val)
+{
+ u32 value;
+
+ value = ioread32(stfcamss->isp_base + reg) & ~mask;
+ val &= mask;
+ val |= value;
+ iowrite32(val, stfcamss->isp_base + reg);
+}
+
+static inline void stf_isp_reg_set(struct stfcamss *stfcamss, u32 reg, u32 mask)
+{
+ iowrite32(ioread32(stfcamss->isp_base + reg) | mask,
+ stfcamss->isp_base + reg);
+}
+
+static inline u32 stf_syscon_reg_read(struct stfcamss *stfcamss, u32 reg)
+{
+ return ioread32(stfcamss->syscon_base + reg);
+}
+
+static inline void stf_syscon_reg_write(struct stfcamss *stfcamss,
+ u32 reg, u32 val)
+{
+ iowrite32(val, stfcamss->syscon_base + reg);
+}
+
+static inline void stf_syscon_reg_set_bit(struct stfcamss *stfcamss,
+ u32 reg, u32 bit_mask)
+{
+ u32 value;
+
+ value = ioread32(stfcamss->syscon_base + reg);
+ iowrite32(value | bit_mask, stfcamss->syscon_base + reg);
+}
+
+static inline void stf_syscon_reg_clear_bit(struct stfcamss *stfcamss,
+ u32 reg, u32 bit_mask)
+{
+ u32 value;
+
+ value = ioread32(stfcamss->syscon_base + reg);
+ iowrite32(value & ~bit_mask, stfcamss->syscon_base + reg);
+}
+#endif /* STF_CAMSS_H */
diff --git a/drivers/staging/media/starfive/camss/stf-capture.c b/drivers/staging/media/starfive/camss/stf-capture.c
new file mode 100644
index 000000000000..70c24b050a1b
--- /dev/null
+++ b/drivers/staging/media/starfive/camss/stf-capture.c
@@ -0,0 +1,603 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * stf_capture.c
+ *
+ * StarFive Camera Subsystem - capture device
+ *
+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
+ */
+
+#include "stf-camss.h"
+
+static const char * const stf_cap_names[] = {
+ "capture_raw",
+ "capture_yuv",
+};
+
+static const struct stfcamss_format_info stf_wr_fmts[] = {
+ {
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .pixelformat = V4L2_PIX_FMT_SRGGB10,
+ .planes = 1,
+ .vsub = { 1 },
+ .bpp = 10,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .pixelformat = V4L2_PIX_FMT_SGRBG10,
+ .planes = 1,
+ .vsub = { 1 },
+ .bpp = 10,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .pixelformat = V4L2_PIX_FMT_SGBRG10,
+ .planes = 1,
+ .vsub = { 1 },
+ .bpp = 10,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .pixelformat = V4L2_PIX_FMT_SBGGR10,
+ .planes = 1,
+ .vsub = { 1 },
+ .bpp = 10,
+ },
+};
+
+static const struct stfcamss_format_info stf_isp_fmts[] = {
+ {
+ .code = MEDIA_BUS_FMT_YUYV8_1_5X8,
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ .planes = 2,
+ .vsub = { 1, 2 },
+ .bpp = 8,
+ },
+};
+
+static inline struct stf_capture *to_stf_capture(struct stfcamss_video *video)
+{
+ return container_of(video, struct stf_capture, video);
+}
+
+static void stf_set_raw_addr(struct stfcamss *stfcamss, dma_addr_t addr)
+{
+ stf_syscon_reg_write(stfcamss, VIN_START_ADDR_O, (long)addr);
+ stf_syscon_reg_write(stfcamss, VIN_START_ADDR_N, (long)addr);
+}
+
+static void stf_set_yuv_addr(struct stfcamss *stfcamss,
+ dma_addr_t y_addr, dma_addr_t uv_addr)
+{
+ stf_isp_reg_write(stfcamss, ISP_REG_Y_PLANE_START_ADDR, y_addr);
+ stf_isp_reg_write(stfcamss, ISP_REG_UV_PLANE_START_ADDR, uv_addr);
+}
+
+static void stf_init_addrs(struct stfcamss_video *video)
+{
+ struct stf_capture *cap = to_stf_capture(video);
+ struct stf_v_buf *output = &cap->buffers;
+ dma_addr_t addr0, addr1;
+
+ output->active_buf = 0;
+
+ if (!output->buf[0])
+ return;
+
+ addr0 = output->buf[0]->addr[0];
+ addr1 = output->buf[0]->addr[1];
+
+ if (cap->type == STF_CAPTURE_RAW)
+ stf_set_raw_addr(video->stfcamss, addr0);
+ else if (cap->type == STF_CAPTURE_YUV)
+ stf_set_yuv_addr(video->stfcamss, addr0, addr1);
+}
+
+static struct stfcamss_buffer *stf_buf_get_pending(struct stf_v_buf *output)
+{
+ struct stfcamss_buffer *buffer = NULL;
+
+ if (!list_empty(&output->pending_bufs)) {
+ buffer = list_first_entry(&output->pending_bufs,
+ struct stfcamss_buffer,
+ queue);
+ list_del(&buffer->queue);
+ }
+
+ return buffer;
+}
+
+static void stf_cap_s_cfg(struct stfcamss_video *video)
+{
+ struct stf_capture *cap = to_stf_capture(video);
+ struct stf_v_buf *output = &cap->buffers;
+ unsigned long flags;
+
+ spin_lock_irqsave(&output->lock, flags);
+
+ output->state = STF_OUTPUT_IDLE;
+ output->buf[0] = stf_buf_get_pending(output);
+
+ if (!output->buf[0] && output->buf[1]) {
+ output->buf[0] = output->buf[1];
+ output->buf[1] = NULL;
+ }
+
+ if (output->buf[0])
+ output->state = STF_OUTPUT_SINGLE;
+
+ output->sequence = 0;
+ stf_init_addrs(video);
+
+ spin_unlock_irqrestore(&output->lock, flags);
+}
+
+static int stf_cap_s_cleanup(struct stfcamss_video *video)
+{
+ struct stf_capture *cap = to_stf_capture(video);
+ struct stf_v_buf *output = &cap->buffers;
+ unsigned long flags;
+
+ spin_lock_irqsave(&output->lock, flags);
+
+ output->state = STF_OUTPUT_OFF;
+
+ spin_unlock_irqrestore(&output->lock, flags);
+
+ return 0;
+}
+
+static void stf_wr_data_en(struct stfcamss_video *video)
+{
+ struct stf_capture *cap = to_stf_capture(video);
+ struct stfcamss *stfcamss = cap->video.stfcamss;
+
+ stf_syscon_reg_set_bit(stfcamss, VIN_CHANNEL_SEL_EN, U0_VIN_AXIWR0_EN);
+}
+
+static void stf_wr_irq_enable(struct stfcamss_video *video)
+{
+ struct stf_capture *cap = to_stf_capture(video);
+ struct stfcamss *stfcamss = cap->video.stfcamss;
+
+ stf_syscon_reg_clear_bit(stfcamss, VIN_INRT_PIX_CFG, U0_VIN_INTR_M);
+}
+
+static void stf_wr_irq_disable(struct stfcamss_video *video)
+{
+ struct stf_capture *cap = to_stf_capture(video);
+ struct stfcamss *stfcamss = cap->video.stfcamss;
+
+ stf_syscon_reg_set_bit(stfcamss, VIN_INRT_PIX_CFG, U0_VIN_INTR_CLEAN);
+ stf_syscon_reg_clear_bit(stfcamss, VIN_INRT_PIX_CFG, U0_VIN_INTR_CLEAN);
+ stf_syscon_reg_set_bit(stfcamss, VIN_INRT_PIX_CFG, U0_VIN_INTR_M);
+}
+
+static void stf_channel_set(struct stfcamss_video *video)
+{
+ struct stf_capture *cap = to_stf_capture(video);
+ struct stfcamss *stfcamss = cap->video.stfcamss;
+ u32 val;
+
+ if (cap->type == STF_CAPTURE_RAW) {
+ val = stf_syscon_reg_read(stfcamss, VIN_CHANNEL_SEL_EN);
+ val &= ~U0_VIN_CHANNEL_SEL_MASK;
+ val |= CHANNEL(0);
+ stf_syscon_reg_write(stfcamss, VIN_CHANNEL_SEL_EN, val);
+
+ val = stf_syscon_reg_read(stfcamss, VIN_INRT_PIX_CFG);
+ val &= ~U0_VIN_PIX_CT_MASK;
+ val |= PIX_CT(1);
+
+ val &= ~U0_VIN_PIXEL_HEIGH_BIT_SEL_MAKS;
+ val |= PIXEL_HEIGH_BIT_SEL(0);
+
+ val &= ~U0_VIN_PIX_CNT_END_MASK;
+ val |= PIX_CNT_END(IMAGE_MAX_WIDTH / 4 - 1);
+
+ stf_syscon_reg_write(stfcamss, VIN_INRT_PIX_CFG, val);
+ } else if (cap->type == STF_CAPTURE_YUV) {
+ val = stf_syscon_reg_read(stfcamss, VIN_CFG_REG);
+ val &= ~U0_VIN_MIPI_BYTE_EN_ISP0_MASK;
+ val |= U0_VIN_MIPI_BYTE_EN_ISP0(0);
+
+ val &= ~U0_VIN_MIPI_CHANNEL_SEL0_MASK;
+ val |= U0_VIN_MIPI_CHANNEL_SEL0(0);
+
+ val &= ~U0_VIN_PIX_NUM_MASK;
+ val |= U0_VIN_PIX_NUM(0);
+
+ val &= ~U0_VIN_P_I_MIPI_HAEDER_EN0_MASK;
+ val |= U0_VIN_P_I_MIPI_HAEDER_EN0(1);
+
+ stf_syscon_reg_write(stfcamss, VIN_CFG_REG, val);
+ }
+}
+
+static void stf_capture_start(struct stfcamss_video *video)
+{
+ struct stf_capture *cap = to_stf_capture(video);
+
+ stf_channel_set(video);
+ if (cap->type == STF_CAPTURE_RAW) {
+ stf_wr_irq_enable(video);
+ stf_wr_data_en(video);
+ }
+
+ stf_cap_s_cfg(video);
+}
+
+static void stf_capture_stop(struct stfcamss_video *video)
+{
+ struct stf_capture *cap = to_stf_capture(video);
+
+ if (cap->type == STF_CAPTURE_RAW)
+ stf_wr_irq_disable(video);
+
+ stf_cap_s_cleanup(video);
+}
+
+static void stf_capture_init(struct stfcamss *stfcamss, struct stf_capture *cap)
+{
+ cap->buffers.state = STF_OUTPUT_OFF;
+ cap->buffers.buf[0] = NULL;
+ cap->buffers.buf[1] = NULL;
+ cap->buffers.active_buf = 0;
+ atomic_set(&cap->buffers.frame_skip, 4);
+ INIT_LIST_HEAD(&cap->buffers.pending_bufs);
+ INIT_LIST_HEAD(&cap->buffers.ready_bufs);
+ spin_lock_init(&cap->buffers.lock);
+
+ cap->video.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cap->video.stfcamss = stfcamss;
+ cap->video.bpl_alignment = 16 * 8;
+
+ if (cap->type == STF_CAPTURE_RAW) {
+ cap->video.formats = stf_wr_fmts;
+ cap->video.nformats = ARRAY_SIZE(stf_wr_fmts);
+ cap->video.bpl_alignment = 8;
+ } else if (cap->type == STF_CAPTURE_YUV) {
+ cap->video.formats = stf_isp_fmts;
+ cap->video.nformats = ARRAY_SIZE(stf_isp_fmts);
+ cap->video.bpl_alignment = 1;
+ }
+}
+
+static void stf_buf_add_ready(struct stf_v_buf *output,
+ struct stfcamss_buffer *buffer)
+{
+ INIT_LIST_HEAD(&buffer->queue);
+ list_add_tail(&buffer->queue, &output->ready_bufs);
+}
+
+static struct stfcamss_buffer *stf_buf_get_ready(struct stf_v_buf *output)
+{
+ struct stfcamss_buffer *buffer = NULL;
+
+ if (!list_empty(&output->ready_bufs)) {
+ buffer = list_first_entry(&output->ready_bufs,
+ struct stfcamss_buffer,
+ queue);
+ list_del(&buffer->queue);
+ }
+
+ return buffer;
+}
+
+static void stf_buf_add_pending(struct stf_v_buf *output,
+ struct stfcamss_buffer *buffer)
+{
+ INIT_LIST_HEAD(&buffer->queue);
+ list_add_tail(&buffer->queue, &output->pending_bufs);
+}
+
+static void stf_buf_update_on_last(struct stf_v_buf *output)
+{
+ switch (output->state) {
+ case STF_OUTPUT_CONTINUOUS:
+ output->state = STF_OUTPUT_SINGLE;
+ output->active_buf = !output->active_buf;
+ break;
+ case STF_OUTPUT_SINGLE:
+ output->state = STF_OUTPUT_STOPPING;
+ break;
+ default:
+ break;
+ }
+}
+
+static void stf_buf_update_on_next(struct stf_v_buf *output)
+{
+ switch (output->state) {
+ case STF_OUTPUT_CONTINUOUS:
+ output->active_buf = !output->active_buf;
+ break;
+ case STF_OUTPUT_SINGLE:
+ default:
+ break;
+ }
+}
+
+static void stf_buf_update_on_new(struct stfcamss_video *video,
+ struct stfcamss_buffer *new_buf)
+{
+ struct stf_capture *cap = to_stf_capture(video);
+ struct stf_v_buf *output = &cap->buffers;
+
+ switch (output->state) {
+ case STF_OUTPUT_SINGLE:
+ stf_buf_add_pending(output, new_buf);
+ break;
+ case STF_OUTPUT_IDLE:
+ if (!output->buf[0]) {
+ output->buf[0] = new_buf;
+ stf_init_addrs(video);
+ output->state = STF_OUTPUT_SINGLE;
+ } else {
+ stf_buf_add_pending(output, new_buf);
+ }
+ break;
+ case STF_OUTPUT_STOPPING:
+ if (output->last_buffer) {
+ output->buf[output->active_buf] = output->last_buffer;
+ output->last_buffer = NULL;
+ }
+
+ output->state = STF_OUTPUT_SINGLE;
+ stf_buf_add_pending(output, new_buf);
+ break;
+ case STF_OUTPUT_CONTINUOUS:
+ default:
+ stf_buf_add_pending(output, new_buf);
+ break;
+ }
+}
+
+static void stf_buf_flush(struct stf_v_buf *output, enum vb2_buffer_state state)
+{
+ struct stfcamss_buffer *buf;
+ struct stfcamss_buffer *t;
+
+ list_for_each_entry_safe(buf, t, &output->pending_bufs, queue) {
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ list_del(&buf->queue);
+ }
+ list_for_each_entry_safe(buf, t, &output->ready_bufs, queue) {
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ list_del(&buf->queue);
+ }
+}
+
+static void stf_buf_done(struct stf_v_buf *output)
+{
+ struct stfcamss_buffer *ready_buf;
+ u64 ts = ktime_get_ns();
+ unsigned long flags;
+
+ if (output->state == STF_OUTPUT_OFF ||
+ output->state == STF_OUTPUT_RESERVED)
+ return;
+
+ spin_lock_irqsave(&output->lock, flags);
+
+ while ((ready_buf = stf_buf_get_ready(output))) {
+ ready_buf->vb.vb2_buf.timestamp = ts;
+ ready_buf->vb.sequence = output->sequence++;
+
+ vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ }
+
+ spin_unlock_irqrestore(&output->lock, flags);
+}
+
+static void stf_change_buffer(struct stf_v_buf *output)
+{
+ struct stf_capture *cap = container_of(output, struct stf_capture,
+ buffers);
+ struct stfcamss *stfcamss = cap->video.stfcamss;
+ struct stfcamss_buffer *ready_buf;
+ dma_addr_t *new_addr;
+ unsigned long flags;
+ u32 active_index;
+
+ if (output->state == STF_OUTPUT_OFF ||
+ output->state == STF_OUTPUT_STOPPING ||
+ output->state == STF_OUTPUT_RESERVED ||
+ output->state == STF_OUTPUT_IDLE)
+ return;
+
+ spin_lock_irqsave(&output->lock, flags);
+
+ active_index = output->active_buf;
+
+ ready_buf = output->buf[active_index];
+ if (!ready_buf) {
+ dev_dbg(stfcamss->dev, "missing ready buf %d %d.\n",
+ active_index, output->state);
+ active_index = !active_index;
+ ready_buf = output->buf[active_index];
+ if (!ready_buf) {
+ dev_dbg(stfcamss->dev,
+ "missing ready buf2 %d %d.\n",
+ active_index, output->state);
+ goto out_unlock;
+ }
+ }
+
+ /* Get next buffer */
+ output->buf[active_index] = stf_buf_get_pending(output);
+ if (!output->buf[active_index]) {
+ new_addr = ready_buf->addr;
+ stf_buf_update_on_last(output);
+ } else {
+ new_addr = output->buf[active_index]->addr;
+ stf_buf_update_on_next(output);
+ }
+
+ if (output->state == STF_OUTPUT_STOPPING) {
+ output->last_buffer = ready_buf;
+ } else {
+ if (cap->type == STF_CAPTURE_RAW)
+ stf_set_raw_addr(stfcamss, new_addr[0]);
+ else if (cap->type == STF_CAPTURE_YUV)
+ stf_set_yuv_addr(stfcamss, new_addr[0], new_addr[1]);
+
+ stf_buf_add_ready(output, ready_buf);
+ }
+
+out_unlock:
+ spin_unlock_irqrestore(&output->lock, flags);
+}
+
+irqreturn_t stf_wr_irq_handler(int irq, void *priv)
+{
+ struct stfcamss *stfcamss = priv;
+ struct stf_capture *cap = &stfcamss->captures[STF_CAPTURE_RAW];
+
+ if (atomic_dec_if_positive(&cap->buffers.frame_skip) < 0) {
+ stf_change_buffer(&cap->buffers);
+ stf_buf_done(&cap->buffers);
+ }
+
+ stf_syscon_reg_set_bit(stfcamss, VIN_INRT_PIX_CFG, U0_VIN_INTR_CLEAN);
+ stf_syscon_reg_clear_bit(stfcamss, VIN_INRT_PIX_CFG, U0_VIN_INTR_CLEAN);
+
+ return IRQ_HANDLED;
+}
+
+irqreturn_t stf_isp_irq_handler(int irq, void *priv)
+{
+ struct stfcamss *stfcamss = priv;
+ struct stf_capture *cap = &stfcamss->captures[STF_CAPTURE_YUV];
+ u32 status;
+
+ status = stf_isp_reg_read(stfcamss, ISP_REG_ISP_CTRL_0);
+ if (status & ISPC_ISP) {
+ if (status & ISPC_ENUO)
+ stf_buf_done(&cap->buffers);
+
+ stf_isp_reg_write(stfcamss, ISP_REG_ISP_CTRL_0,
+ (status & ~ISPC_INT_ALL_MASK) |
+ ISPC_ISP | ISPC_CSI | ISPC_SC);
+ }
+
+ return IRQ_HANDLED;
+}
+
+irqreturn_t stf_line_irq_handler(int irq, void *priv)
+{
+ struct stfcamss *stfcamss = priv;
+ struct stf_capture *cap = &stfcamss->captures[STF_CAPTURE_YUV];
+ u32 status;
+
+ status = stf_isp_reg_read(stfcamss, ISP_REG_ISP_CTRL_0);
+ if (status & ISPC_LINE) {
+ if (atomic_dec_if_positive(&cap->buffers.frame_skip) < 0) {
+ if ((status & ISPC_ENUO))
+ stf_change_buffer(&cap->buffers);
+ }
+
+ stf_isp_reg_set_bit(stfcamss, ISP_REG_CSIINTS,
+ CSI_INTS_MASK, CSI_INTS(0x3));
+ stf_isp_reg_set_bit(stfcamss, ISP_REG_IESHD,
+ SHAD_UP_M | SHAD_UP_EN, 0x3);
+
+ stf_isp_reg_write(stfcamss, ISP_REG_ISP_CTRL_0,
+ (status & ~ISPC_INT_ALL_MASK) | ISPC_LINE);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int stf_queue_buffer(struct stfcamss_video *video,
+ struct stfcamss_buffer *buf)
+{
+ struct stf_capture *cap = to_stf_capture(video);
+ struct stf_v_buf *v_bufs = &cap->buffers;
+ unsigned long flags;
+
+ spin_lock_irqsave(&v_bufs->lock, flags);
+ stf_buf_update_on_new(video, buf);
+ spin_unlock_irqrestore(&v_bufs->lock, flags);
+
+ return 0;
+}
+
+static int stf_flush_buffers(struct stfcamss_video *video,
+ enum vb2_buffer_state state)
+{
+ struct stf_capture *cap = to_stf_capture(video);
+ struct stf_v_buf *v_bufs = &cap->buffers;
+ unsigned long flags;
+ unsigned int i;
+
+ spin_lock_irqsave(&v_bufs->lock, flags);
+
+ stf_buf_flush(v_bufs, state);
+
+ for (i = 0; i < ARRAY_SIZE(v_bufs->buf); i++) {
+ if (v_bufs->buf[i])
+ vb2_buffer_done(&v_bufs->buf[i]->vb.vb2_buf, state);
+
+ v_bufs->buf[i] = NULL;
+ }
+
+ if (v_bufs->last_buffer) {
+ vb2_buffer_done(&v_bufs->last_buffer->vb.vb2_buf, state);
+ v_bufs->last_buffer = NULL;
+ }
+
+ spin_unlock_irqrestore(&v_bufs->lock, flags);
+ return 0;
+}
+
+static const struct stfcamss_video_ops stf_capture_ops = {
+ .queue_buffer = stf_queue_buffer,
+ .flush_buffers = stf_flush_buffers,
+ .start_streaming = stf_capture_start,
+ .stop_streaming = stf_capture_stop,
+};
+
+static void stf_capture_unregister_one(struct stf_capture *cap)
+{
+ if (!video_is_registered(&cap->video.vdev))
+ return;
+
+ media_entity_cleanup(&cap->video.vdev.entity);
+ vb2_video_unregister_device(&cap->video.vdev);
+}
+
+void stf_capture_unregister(struct stfcamss *stfcamss)
+{
+ struct stf_capture *cap_raw = &stfcamss->captures[STF_CAPTURE_RAW];
+ struct stf_capture *cap_yuv = &stfcamss->captures[STF_CAPTURE_YUV];
+
+ stf_capture_unregister_one(cap_raw);
+ stf_capture_unregister_one(cap_yuv);
+}
+
+int stf_capture_register(struct stfcamss *stfcamss,
+ struct v4l2_device *v4l2_dev)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(stfcamss->captures); i++) {
+ struct stf_capture *capture = &stfcamss->captures[i];
+
+ capture->type = i;
+ capture->video.ops = &stf_capture_ops;
+ stf_capture_init(stfcamss, capture);
+
+ ret = stf_video_register(&capture->video, v4l2_dev,
+ stf_cap_names[i]);
+ if (ret < 0) {
+ dev_err(stfcamss->dev,
+ "Failed to register video node: %d\n", ret);
+ stf_capture_unregister(stfcamss);
+ return ret;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/staging/media/starfive/camss/stf-capture.h b/drivers/staging/media/starfive/camss/stf-capture.h
new file mode 100644
index 000000000000..2f9740b7e500
--- /dev/null
+++ b/drivers/staging/media/starfive/camss/stf-capture.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * stf_capture.h
+ *
+ * Starfive Camera Subsystem driver
+ *
+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
+ */
+
+#ifndef STF_CAPTURE_H
+#define STF_CAPTURE_H
+
+#include "stf-video.h"
+
+#define VIN_CHANNEL_SEL_EN 0x14
+#define VIN_START_ADDR_N 0x18
+#define VIN_INRT_PIX_CFG 0x1c
+#define VIN_START_ADDR_O 0x20
+#define VIN_CFG_REG 0x24
+
+#define U0_VIN_CNFG_AXI_DVP_EN BIT(2)
+
+#define U0_VIN_CHANNEL_SEL_MASK GENMASK(3, 0)
+#define U0_VIN_AXIWR0_EN BIT(4)
+#define CHANNEL(x) ((x) << 0)
+
+#define U0_VIN_INTR_CLEAN BIT(0)
+#define U0_VIN_INTR_M BIT(1)
+#define U0_VIN_PIX_CNT_END_MASK GENMASK(12, 2)
+#define U0_VIN_PIX_CT_MASK GENMASK(14, 13)
+#define U0_VIN_PIXEL_HEIGH_BIT_SEL_MAKS GENMASK(16, 15)
+
+#define PIX_CNT_END(x) ((x) << 2)
+#define PIX_CT(x) ((x) << 13)
+#define PIXEL_HEIGH_BIT_SEL(x) ((x) << 15)
+
+#define U0_VIN_CNFG_DVP_HS_POS BIT(1)
+#define U0_VIN_CNFG_DVP_SWAP_EN BIT(2)
+#define U0_VIN_CNFG_DVP_VS_POS BIT(3)
+#define U0_VIN_CNFG_GEN_EN_AXIRD BIT(4)
+#define U0_VIN_CNFG_ISP_DVP_EN0 BIT(5)
+#define U0_VIN_MIPI_BYTE_EN_ISP0(n) ((n) << 6)
+#define U0_VIN_MIPI_CHANNEL_SEL0(n) ((n) << 8)
+#define U0_VIN_P_I_MIPI_HAEDER_EN0(n) ((n) << 12)
+#define U0_VIN_PIX_NUM(n) ((n) << 13)
+#define U0_VIN_MIPI_BYTE_EN_ISP0_MASK GENMASK(7, 6)
+#define U0_VIN_MIPI_CHANNEL_SEL0_MASK GENMASK(11, 8)
+#define U0_VIN_P_I_MIPI_HAEDER_EN0_MASK BIT(12)
+#define U0_VIN_PIX_NUM_MASK GENMASK(16, 13)
+
+enum stf_v_state {
+ STF_OUTPUT_OFF,
+ STF_OUTPUT_RESERVED,
+ STF_OUTPUT_SINGLE,
+ STF_OUTPUT_CONTINUOUS,
+ STF_OUTPUT_IDLE,
+ STF_OUTPUT_STOPPING
+};
+
+struct stf_v_buf {
+ int active_buf;
+ struct stfcamss_buffer *buf[2];
+ struct stfcamss_buffer *last_buffer;
+ struct list_head pending_bufs;
+ struct list_head ready_bufs;
+ enum stf_v_state state;
+ unsigned int sequence;
+ /* protects the above member variables */
+ spinlock_t lock;
+ atomic_t frame_skip;
+};
+
+struct stf_capture {
+ struct stfcamss_video video;
+ struct stf_v_buf buffers;
+ enum stf_capture_type type;
+};
+
+irqreturn_t stf_wr_irq_handler(int irq, void *priv);
+irqreturn_t stf_isp_irq_handler(int irq, void *priv);
+irqreturn_t stf_line_irq_handler(int irq, void *priv);
+int stf_capture_register(struct stfcamss *stfcamss,
+ struct v4l2_device *v4l2_dev);
+void stf_capture_unregister(struct stfcamss *stfcamss);
+
+#endif
diff --git a/drivers/staging/media/starfive/camss/stf-isp-hw-ops.c b/drivers/staging/media/starfive/camss/stf-isp-hw-ops.c
new file mode 100644
index 000000000000..c34631ff9422
--- /dev/null
+++ b/drivers/staging/media/starfive/camss/stf-isp-hw-ops.c
@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * stf_isp_hw_ops.c
+ *
+ * Register interface file for StarFive ISP driver
+ *
+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
+ *
+ */
+
+#include "stf-camss.h"
+
+static void stf_isp_config_obc(struct stfcamss *stfcamss)
+{
+ u32 reg_val, reg_add;
+
+ stf_isp_reg_write(stfcamss, ISP_REG_OBC_CFG, OBC_W_H(11) | OBC_W_W(11));
+
+ reg_val = GAIN_D_POINT(0x40) | GAIN_C_POINT(0x40) |
+ GAIN_B_POINT(0x40) | GAIN_A_POINT(0x40);
+ for (reg_add = ISP_REG_OBCG_CFG_0; reg_add <= ISP_REG_OBCG_CFG_3;) {
+ stf_isp_reg_write(stfcamss, reg_add, reg_val);
+ reg_add += 4;
+ }
+
+ reg_val = OFFSET_D_POINT(0) | OFFSET_C_POINT(0) |
+ OFFSET_B_POINT(0) | OFFSET_A_POINT(0);
+ for (reg_add = ISP_REG_OBCO_CFG_0; reg_add <= ISP_REG_OBCO_CFG_3;) {
+ stf_isp_reg_write(stfcamss, reg_add, reg_val);
+ reg_add += 4;
+ }
+}
+
+static void stf_isp_config_oecf(struct stfcamss *stfcamss)
+{
+ u32 reg_add, par_val;
+ u16 par_h, par_l;
+
+ par_h = 0x10; par_l = 0;
+ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
+ for (reg_add = ISP_REG_OECF_X0_CFG0; reg_add <= ISP_REG_OECF_Y3_CFG0;) {
+ stf_isp_reg_write(stfcamss, reg_add, par_val);
+ reg_add += 0x20;
+ }
+
+ par_h = 0x40; par_l = 0x20;
+ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
+ for (reg_add = ISP_REG_OECF_X0_CFG1; reg_add <= ISP_REG_OECF_Y3_CFG1;) {
+ stf_isp_reg_write(stfcamss, reg_add, par_val);
+ reg_add += 0x20;
+ }
+
+ par_h = 0x80; par_l = 0x60;
+ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
+ for (reg_add = ISP_REG_OECF_X0_CFG2; reg_add <= ISP_REG_OECF_Y3_CFG2;) {
+ stf_isp_reg_write(stfcamss, reg_add, par_val);
+ reg_add += 0x20;
+ }
+
+ par_h = 0xc0; par_l = 0xa0;
+ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
+ for (reg_add = ISP_REG_OECF_X0_CFG3; reg_add <= ISP_REG_OECF_Y3_CFG3;) {
+ stf_isp_reg_write(stfcamss, reg_add, par_val);
+ reg_add += 0x20;
+ }
+
+ par_h = 0x100; par_l = 0xe0;
+ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
+ for (reg_add = ISP_REG_OECF_X0_CFG4; reg_add <= ISP_REG_OECF_Y3_CFG4;) {
+ stf_isp_reg_write(stfcamss, reg_add, par_val);
+ reg_add += 0x20;
+ }
+
+ par_h = 0x200; par_l = 0x180;
+ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
+ for (reg_add = ISP_REG_OECF_X0_CFG5; reg_add <= ISP_REG_OECF_Y3_CFG5;) {
+ stf_isp_reg_write(stfcamss, reg_add, par_val);
+ reg_add += 0x20;
+ }
+
+ par_h = 0x300; par_l = 0x280;
+ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
+ for (reg_add = ISP_REG_OECF_X0_CFG6; reg_add <= ISP_REG_OECF_Y3_CFG6;) {
+ stf_isp_reg_write(stfcamss, reg_add, par_val);
+ reg_add += 0x20;
+ }
+
+ par_h = 0x3fe; par_l = 0x380;
+ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
+ for (reg_add = ISP_REG_OECF_X0_CFG7; reg_add <= ISP_REG_OECF_Y3_CFG7;) {
+ stf_isp_reg_write(stfcamss, reg_add, par_val);
+ reg_add += 0x20;
+ }
+
+ par_h = 0x80; par_l = 0x80;
+ par_val = OCEF_PAR_H(par_h) | OCEF_PAR_L(par_l);
+ for (reg_add = ISP_REG_OECF_S0_CFG0; reg_add <= ISP_REG_OECF_S3_CFG7;) {
+ stf_isp_reg_write(stfcamss, reg_add, par_val);
+ reg_add += 4;
+ }
+}
+
+static void stf_isp_config_lccf(struct stfcamss *stfcamss)
+{
+ u32 reg_add;
+
+ stf_isp_reg_write(stfcamss, ISP_REG_LCCF_CFG_0,
+ Y_DISTANCE(0x21C) | X_DISTANCE(0x3C0));
+ stf_isp_reg_write(stfcamss, ISP_REG_LCCF_CFG_1, LCCF_MAX_DIS(0xb));
+
+ for (reg_add = ISP_REG_LCCF_CFG_2; reg_add <= ISP_REG_LCCF_CFG_5;) {
+ stf_isp_reg_write(stfcamss, reg_add,
+ LCCF_F2_PAR(0x0) | LCCF_F1_PAR(0x0));
+ reg_add += 4;
+ }
+}
+
+static void stf_isp_config_awb(struct stfcamss *stfcamss)
+{
+ u32 reg_val, reg_add;
+ u16 symbol_h, symbol_l;
+
+ symbol_h = 0x0; symbol_l = 0x0;
+ reg_val = AWB_X_SYMBOL_H(symbol_h) | AWB_X_SYMBOL_L(symbol_l);
+
+ for (reg_add = ISP_REG_AWB_X0_CFG_0; reg_add <= ISP_REG_AWB_X3_CFG_1;) {
+ stf_isp_reg_write(stfcamss, reg_add, reg_val);
+ reg_add += 4;
+ }
+
+ symbol_h = 0x0, symbol_l = 0x0;
+ reg_val = AWB_Y_SYMBOL_H(symbol_h) | AWB_Y_SYMBOL_L(symbol_l);
+
+ for (reg_add = ISP_REG_AWB_Y0_CFG_0; reg_add <= ISP_REG_AWB_Y3_CFG_1;) {
+ stf_isp_reg_write(stfcamss, reg_add, reg_val);
+ reg_add += 4;
+ }
+
+ symbol_h = 0x80, symbol_l = 0x80;
+ reg_val = AWB_S_SYMBOL_H(symbol_h) | AWB_S_SYMBOL_L(symbol_l);
+
+ for (reg_add = ISP_REG_AWB_S0_CFG_0; reg_add <= ISP_REG_AWB_S3_CFG_1;) {
+ stf_isp_reg_write(stfcamss, reg_add, reg_val);
+ reg_add += 4;
+ }
+}
+
+static void stf_isp_config_grgb(struct stfcamss *stfcamss)
+{
+ stf_isp_reg_write(stfcamss, ISP_REG_ICTC,
+ GF_MODE(1) | MAXGT(0x140) | MINGT(0x40));
+ stf_isp_reg_write(stfcamss, ISP_REG_IDBC, BADGT(0x200) | BADXT(0x200));
+}
+
+static void stf_isp_config_cfa(struct stfcamss *stfcamss)
+{
+ stf_isp_reg_write(stfcamss, ISP_REG_RAW_FORMAT_CFG,
+ SMY13(0) | SMY12(1) | SMY11(0) | SMY10(1) | SMY3(2) |
+ SMY2(3) | SMY1(2) | SMY0(3));
+ stf_isp_reg_write(stfcamss, ISP_REG_ICFAM, CROSS_COV(3) | HV_W(2));
+}
+
+static void stf_isp_config_ccm(struct stfcamss *stfcamss)
+{
+ u32 reg_add;
+
+ stf_isp_reg_write(stfcamss, ISP_REG_ICAMD_0, DNRM_F(6) | CCM_M_DAT(0));
+
+ for (reg_add = ISP_REG_ICAMD_12; reg_add <= ISP_REG_ICAMD_20;) {
+ stf_isp_reg_write(stfcamss, reg_add, CCM_M_DAT(0x80));
+ reg_add += 0x10;
+ }
+
+ stf_isp_reg_write(stfcamss, ISP_REG_ICAMD_24, CCM_M_DAT(0x700));
+ stf_isp_reg_write(stfcamss, ISP_REG_ICAMD_25, CCM_M_DAT(0x200));
+}
+
+static void stf_isp_config_gamma(struct stfcamss *stfcamss)
+{
+ u32 reg_val, reg_add;
+ u16 gamma_slope_v, gamma_v;
+
+ gamma_slope_v = 0x2400; gamma_v = 0x0;
+ reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v);
+ stf_isp_reg_write(stfcamss, ISP_REG_GAMMA_VAL0, reg_val);
+
+ gamma_slope_v = 0x800; gamma_v = 0x20;
+ for (reg_add = ISP_REG_GAMMA_VAL1; reg_add <= ISP_REG_GAMMA_VAL7;) {
+ reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v);
+ stf_isp_reg_write(stfcamss, reg_add, reg_val);
+ reg_add += 4;
+ gamma_v += 0x20;
+ }
+
+ gamma_v = 0x100;
+ for (reg_add = ISP_REG_GAMMA_VAL8; reg_add <= ISP_REG_GAMMA_VAL13;) {
+ reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v);
+ stf_isp_reg_write(stfcamss, reg_add, reg_val);
+ reg_add += 4;
+ gamma_v += 0x80;
+ }
+
+ gamma_v = 0x3fe;
+ reg_val = GAMMA_S_VAL(gamma_slope_v) | GAMMA_VAL(gamma_v);
+ stf_isp_reg_write(stfcamss, ISP_REG_GAMMA_VAL14, reg_val);
+}
+
+static void stf_isp_config_r2y(struct stfcamss *stfcamss)
+{
+ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_0, 0x4C);
+ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_1, 0x97);
+ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_2, 0x1d);
+ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_3, 0x1d5);
+ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_4, 0x1ac);
+ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_5, 0x80);
+ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_6, 0x80);
+ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_7, 0x194);
+ stf_isp_reg_write(stfcamss, ISP_REG_R2Y_8, 0x1ec);
+}
+
+static void stf_isp_config_y_curve(struct stfcamss *stfcamss)
+{
+ u32 reg_add;
+ u16 y_curve;
+
+ y_curve = 0x0;
+ for (reg_add = ISP_REG_YCURVE_0; reg_add <= ISP_REG_YCURVE_63;) {
+ stf_isp_reg_write(stfcamss, reg_add, y_curve);
+ reg_add += 4;
+ y_curve += 0x10;
+ }
+}
+
+static void stf_isp_config_sharpen(struct stfcamss *sc)
+{
+ u32 reg_add;
+
+ stf_isp_reg_write(sc, ISP_REG_SHARPEN0, S_DELTA(0x7) | S_WEIGHT(0xf));
+ stf_isp_reg_write(sc, ISP_REG_SHARPEN1, S_DELTA(0x18) | S_WEIGHT(0xf));
+ stf_isp_reg_write(sc, ISP_REG_SHARPEN2, S_DELTA(0x80) | S_WEIGHT(0xf));
+ stf_isp_reg_write(sc, ISP_REG_SHARPEN3, S_DELTA(0x100) | S_WEIGHT(0xf));
+ stf_isp_reg_write(sc, ISP_REG_SHARPEN4, S_DELTA(0x10) | S_WEIGHT(0xf));
+ stf_isp_reg_write(sc, ISP_REG_SHARPEN5, S_DELTA(0x60) | S_WEIGHT(0xf));
+ stf_isp_reg_write(sc, ISP_REG_SHARPEN6, S_DELTA(0x100) | S_WEIGHT(0xf));
+ stf_isp_reg_write(sc, ISP_REG_SHARPEN7, S_DELTA(0x190) | S_WEIGHT(0xf));
+ stf_isp_reg_write(sc, ISP_REG_SHARPEN8, S_DELTA(0x0) | S_WEIGHT(0xf));
+
+ for (reg_add = ISP_REG_SHARPEN9; reg_add <= ISP_REG_SHARPEN14;) {
+ stf_isp_reg_write(sc, reg_add, S_WEIGHT(0xf));
+ reg_add += 4;
+ }
+
+ for (reg_add = ISP_REG_SHARPEN_FS0; reg_add <= ISP_REG_SHARPEN_FS5;) {
+ stf_isp_reg_write(sc, reg_add, S_FACTOR(0x10) | S_SLOPE(0x0));
+ reg_add += 4;
+ }
+
+ stf_isp_reg_write(sc, ISP_REG_SHARPEN_WN,
+ PDIRF(0x8) | NDIRF(0x8) | WSUM(0xd7c));
+ stf_isp_reg_write(sc, ISP_REG_IUVS1, UVDIFF2(0xC0) | UVDIFF1(0x40));
+ stf_isp_reg_write(sc, ISP_REG_IUVS2, UVF(0xff) | UVSLOPE(0x0));
+ stf_isp_reg_write(sc, ISP_REG_IUVCKS1,
+ UVCKDIFF2(0xa0) | UVCKDIFF1(0x40));
+}
+
+static void stf_isp_config_dnyuv(struct stfcamss *stfcamss)
+{
+ u32 reg_val;
+
+ reg_val = YUVSW5(7) | YUVSW4(7) | YUVSW3(7) | YUVSW2(7) |
+ YUVSW1(7) | YUVSW0(7);
+ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YSWR0, reg_val);
+ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CSWR0, reg_val);
+
+ reg_val = YUVSW3(7) | YUVSW2(7) | YUVSW1(7) | YUVSW0(7);
+ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YSWR1, reg_val);
+ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CSWR1, reg_val);
+
+ reg_val = CURVE_D_H(0x60) | CURVE_D_L(0x40);
+ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YDR0, reg_val);
+ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CDR0, reg_val);
+
+ reg_val = CURVE_D_H(0xd8) | CURVE_D_L(0x90);
+ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YDR1, reg_val);
+ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CDR1, reg_val);
+
+ reg_val = CURVE_D_H(0x1e6) | CURVE_D_L(0x144);
+ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_YDR2, reg_val);
+ stf_isp_reg_write(stfcamss, ISP_REG_DNYUV_CDR2, reg_val);
+}
+
+static void stf_isp_config_sat(struct stfcamss *stfcamss)
+{
+ stf_isp_reg_write(stfcamss, ISP_REG_CS_GAIN, CMAD(0x0) | CMAB(0x100));
+ stf_isp_reg_write(stfcamss, ISP_REG_CS_THRESHOLD, CMD(0x1f) | CMB(0x1));
+ stf_isp_reg_write(stfcamss, ISP_REG_CS_OFFSET, VOFF(0x0) | UOFF(0x0));
+ stf_isp_reg_write(stfcamss, ISP_REG_CS_HUE_F, SIN(0x0) | COS(0x100));
+ stf_isp_reg_write(stfcamss, ISP_REG_CS_SCALE, 0x8);
+ stf_isp_reg_write(stfcamss, ISP_REG_YADJ0, YOIR(0x401) | YIMIN(0x1));
+ stf_isp_reg_write(stfcamss, ISP_REG_YADJ1, YOMAX(0x3ff) | YOMIN(0x1));
+}
+
+int stf_isp_reset(struct stf_isp_dev *isp_dev)
+{
+ stf_isp_reg_set_bit(isp_dev->stfcamss, ISP_REG_ISP_CTRL_0,
+ ISPC_RST_MASK, ISPC_RST);
+ stf_isp_reg_set_bit(isp_dev->stfcamss, ISP_REG_ISP_CTRL_0,
+ ISPC_RST_MASK, 0);
+
+ return 0;
+}
+
+void stf_isp_init_cfg(struct stf_isp_dev *isp_dev)
+{
+ stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_DC_CFG_1, DC_AXI_ID(0x0));
+ stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_DEC_CFG,
+ DEC_V_KEEP(0x0) |
+ DEC_V_PERIOD(0x0) |
+ DEC_H_KEEP(0x0) |
+ DEC_H_PERIOD(0x0));
+
+ stf_isp_config_obc(isp_dev->stfcamss);
+ stf_isp_config_oecf(isp_dev->stfcamss);
+ stf_isp_config_lccf(isp_dev->stfcamss);
+ stf_isp_config_awb(isp_dev->stfcamss);
+ stf_isp_config_grgb(isp_dev->stfcamss);
+ stf_isp_config_cfa(isp_dev->stfcamss);
+ stf_isp_config_ccm(isp_dev->stfcamss);
+ stf_isp_config_gamma(isp_dev->stfcamss);
+ stf_isp_config_r2y(isp_dev->stfcamss);
+ stf_isp_config_y_curve(isp_dev->stfcamss);
+ stf_isp_config_sharpen(isp_dev->stfcamss);
+ stf_isp_config_dnyuv(isp_dev->stfcamss);
+ stf_isp_config_sat(isp_dev->stfcamss);
+
+ stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_CSI_MODULE_CFG,
+ CSI_DUMP_EN | CSI_SC_EN | CSI_AWB_EN |
+ CSI_LCCF_EN | CSI_OECF_EN | CSI_OBC_EN | CSI_DEC_EN);
+ stf_isp_reg_write(isp_dev->stfcamss, ISP_REG_ISP_CTRL_1,
+ CTRL_SAT(1) | CTRL_DBC | CTRL_CTC | CTRL_YHIST |
+ CTRL_YCURVE | CTRL_BIYUV | CTRL_SCE | CTRL_EE |
+ CTRL_CCE | CTRL_RGE | CTRL_CME | CTRL_AE | CTRL_CE);
+}
+
+static void stf_isp_config_crop(struct stfcamss *stfcamss,
+ struct v4l2_rect *crop)
+{
+ u32 bpp = stfcamss->isp_dev.current_fmt->bpp;
+ u32 val;
+
+ val = VSTART_CAP(crop->top) | HSTART_CAP(crop->left);
+ stf_isp_reg_write(stfcamss, ISP_REG_PIC_CAPTURE_START_CFG, val);
+
+ val = VEND_CAP(crop->height + crop->top - 1) |
+ HEND_CAP(crop->width + crop->left - 1);
+ stf_isp_reg_write(stfcamss, ISP_REG_PIC_CAPTURE_END_CFG, val);
+
+ val = H_ACT_CAP(crop->height) | W_ACT_CAP(crop->width);
+ stf_isp_reg_write(stfcamss, ISP_REG_PIPELINE_XY_SIZE, val);
+
+ val = ALIGN(crop->width * bpp / 8, STFCAMSS_FRAME_WIDTH_ALIGN_8);
+ stf_isp_reg_write(stfcamss, ISP_REG_STRIDE, val);
+}
+
+static void stf_isp_config_raw_fmt(struct stfcamss *stfcamss, u32 mcode)
+{
+ u32 val, val1;
+
+ switch (mcode) {
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
+ /* 3 2 3 2 1 0 1 0 B Gb B Gb Gr R Gr R */
+ val = SMY13(3) | SMY12(2) | SMY11(3) | SMY10(2) |
+ SMY3(1) | SMY2(0) | SMY1(1) | SMY0(0);
+ val1 = CTRL_SAT(0x0);
+ break;
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ /* 2 3 2 3 0 1 0 1, Gb B Gb B R Gr R Gr */
+ val = SMY13(2) | SMY12(3) | SMY11(2) | SMY10(3) |
+ SMY3(0) | SMY2(1) | SMY1(0) | SMY0(1);
+ val1 = CTRL_SAT(0x2);
+ break;
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ /* 1 0 1 0 3 2 3 2, Gr R Gr R B Gb B Gb */
+ val = SMY13(1) | SMY12(0) | SMY11(1) | SMY10(0) |
+ SMY3(3) | SMY2(2) | SMY1(3) | SMY0(2);
+ val1 = CTRL_SAT(0x3);
+ break;
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ /* 0 1 0 1 2 3 2 3 R Gr R Gr Gb B Gb B */
+ val = SMY13(0) | SMY12(1) | SMY11(0) | SMY10(1) |
+ SMY3(2) | SMY2(3) | SMY1(2) | SMY0(3);
+ val1 = CTRL_SAT(0x1);
+ break;
+ default:
+ val = SMY13(0) | SMY12(1) | SMY11(0) | SMY10(1) |
+ SMY3(2) | SMY2(3) | SMY1(2) | SMY0(3);
+ val1 = CTRL_SAT(0x1);
+ break;
+ }
+ stf_isp_reg_write(stfcamss, ISP_REG_RAW_FORMAT_CFG, val);
+ stf_isp_reg_set_bit(stfcamss, ISP_REG_ISP_CTRL_1, CTRL_SAT_MASK, val1);
+}
+
+void stf_isp_settings(struct stf_isp_dev *isp_dev,
+ struct v4l2_rect *crop, u32 mcode)
+{
+ struct stfcamss *stfcamss = isp_dev->stfcamss;
+
+ stf_isp_config_crop(stfcamss, crop);
+ stf_isp_config_raw_fmt(stfcamss, mcode);
+
+ stf_isp_reg_set_bit(stfcamss, ISP_REG_DUMP_CFG_1,
+ DUMP_BURST_LEN_MASK | DUMP_SD_MASK,
+ DUMP_BURST_LEN(3));
+
+ stf_isp_reg_write(stfcamss, ISP_REG_ITIIWSR,
+ ITI_HSIZE(IMAGE_MAX_HEIGH) |
+ ITI_WSIZE(IMAGE_MAX_WIDTH));
+ stf_isp_reg_write(stfcamss, ISP_REG_ITIDWLSR, 0x960);
+ stf_isp_reg_write(stfcamss, ISP_REG_ITIDRLSR, 0x960);
+ stf_isp_reg_write(stfcamss, ISP_REG_SENSOR, IMAGER_SEL(1));
+}
+
+void stf_isp_stream_set(struct stf_isp_dev *isp_dev)
+{
+ struct stfcamss *stfcamss = isp_dev->stfcamss;
+
+ stf_isp_reg_write_delay(stfcamss, ISP_REG_ISP_CTRL_0,
+ ISPC_ENUO | ISPC_ENLS | ISPC_RST, 10);
+ stf_isp_reg_write_delay(stfcamss, ISP_REG_ISP_CTRL_0,
+ ISPC_ENUO | ISPC_ENLS, 10);
+ stf_isp_reg_write(stfcamss, ISP_REG_IESHD, SHAD_UP_M);
+ stf_isp_reg_write_delay(stfcamss, ISP_REG_ISP_CTRL_0,
+ ISPC_ENUO | ISPC_ENLS | ISPC_EN, 10);
+ stf_isp_reg_write_delay(stfcamss, ISP_REG_CSIINTS,
+ CSI_INTS(1) | CSI_SHA_M(4), 10);
+ stf_isp_reg_write_delay(stfcamss, ISP_REG_CSIINTS,
+ CSI_INTS(2) | CSI_SHA_M(4), 10);
+ stf_isp_reg_write_delay(stfcamss, ISP_REG_CSI_INPUT_EN_AND_STATUS,
+ CSI_EN_S, 10);
+}
diff --git a/drivers/staging/media/starfive/camss/stf-isp.c b/drivers/staging/media/starfive/camss/stf-isp.c
new file mode 100644
index 000000000000..d50616ef351e
--- /dev/null
+++ b/drivers/staging/media/starfive/camss/stf-isp.c
@@ -0,0 +1,385 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * stf_isp.c
+ *
+ * StarFive Camera Subsystem - ISP Module
+ *
+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
+ */
+#include <media/v4l2-rect.h>
+
+#include "stf-camss.h"
+
+#define SINK_FORMATS_INDEX 0
+#define SOURCE_FORMATS_INDEX 1
+
+static int isp_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel);
+
+static const struct stf_isp_format isp_formats_sink[] = {
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
+};
+
+static const struct stf_isp_format isp_formats_source[] = {
+ { MEDIA_BUS_FMT_YUYV8_1_5X8, 8 },
+};
+
+static const struct stf_isp_format_table isp_formats_st7110[] = {
+ { isp_formats_sink, ARRAY_SIZE(isp_formats_sink) },
+ { isp_formats_source, ARRAY_SIZE(isp_formats_source) },
+};
+
+static const struct stf_isp_format *
+stf_g_fmt_by_mcode(const struct stf_isp_format_table *fmt_table, u32 mcode)
+{
+ unsigned int i;
+
+ for (i = 0; i < fmt_table->nfmts; i++) {
+ if (fmt_table->fmts[i].code == mcode)
+ return &fmt_table->fmts[i];
+ }
+
+ return NULL;
+}
+
+int stf_isp_init(struct stfcamss *stfcamss)
+{
+ struct stf_isp_dev *isp_dev = &stfcamss->isp_dev;
+
+ isp_dev->stfcamss = stfcamss;
+ isp_dev->formats = isp_formats_st7110;
+ isp_dev->nformats = ARRAY_SIZE(isp_formats_st7110);
+ isp_dev->current_fmt = &isp_formats_source[0];
+
+ return 0;
+}
+
+static int isp_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
+ struct v4l2_subdev_state *sd_state;
+ struct v4l2_mbus_framefmt *fmt;
+ struct v4l2_rect *crop;
+
+ sd_state = v4l2_subdev_lock_and_get_active_state(sd);
+ fmt = v4l2_subdev_state_get_format(sd_state, STF_ISP_PAD_SINK);
+ crop = v4l2_subdev_state_get_crop(sd_state, STF_ISP_PAD_SRC);
+
+ if (enable) {
+ stf_isp_reset(isp_dev);
+ stf_isp_init_cfg(isp_dev);
+ stf_isp_settings(isp_dev, crop, fmt->code);
+ stf_isp_stream_set(isp_dev);
+ }
+
+ v4l2_subdev_call(isp_dev->source_subdev, video, s_stream, enable);
+
+ v4l2_subdev_unlock_state(sd_state);
+ return 0;
+}
+
+static void isp_try_format(struct stf_isp_dev *isp_dev,
+ struct v4l2_subdev_state *state,
+ unsigned int pad,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ const struct stf_isp_format_table *formats;
+
+ if (pad >= STF_ISP_PAD_MAX) {
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ return;
+ }
+
+ if (pad == STF_ISP_PAD_SINK)
+ formats = &isp_dev->formats[SINK_FORMATS_INDEX];
+ else if (pad == STF_ISP_PAD_SRC)
+ formats = &isp_dev->formats[SOURCE_FORMATS_INDEX];
+
+ fmt->width = clamp_t(u32, fmt->width, STFCAMSS_FRAME_MIN_WIDTH,
+ STFCAMSS_FRAME_MAX_WIDTH);
+ fmt->height = clamp_t(u32, fmt->height, STFCAMSS_FRAME_MIN_HEIGHT,
+ STFCAMSS_FRAME_MAX_HEIGHT);
+ fmt->height &= ~0x1;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->flags = 0;
+
+ if (!stf_g_fmt_by_mcode(formats, fmt->code))
+ fmt->code = formats->fmts[0].code;
+}
+
+static int isp_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
+ const struct stf_isp_format_table *formats;
+
+ if (code->pad == STF_ISP_PAD_SINK) {
+ if (code->index >= ARRAY_SIZE(isp_formats_sink))
+ return -EINVAL;
+
+ formats = &isp_dev->formats[SINK_FORMATS_INDEX];
+ code->code = formats->fmts[code->index].code;
+ } else {
+ struct v4l2_mbus_framefmt *sink_fmt;
+
+ if (code->index >= ARRAY_SIZE(isp_formats_source))
+ return -EINVAL;
+
+ sink_fmt = v4l2_subdev_state_get_format(state,
+ STF_ISP_PAD_SRC);
+
+ code->code = sink_fmt->code;
+ if (!code->code)
+ return -EINVAL;
+ }
+ code->flags = 0;
+
+ return 0;
+}
+
+static int isp_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
+ if (!format)
+ return -EINVAL;
+
+ isp_try_format(isp_dev, state, fmt->pad, &fmt->format);
+ *format = fmt->format;
+
+ isp_dev->current_fmt = stf_g_fmt_by_mcode(&isp_dev->formats[fmt->pad],
+ fmt->format.code);
+
+ /* Propagate to in crop */
+ if (fmt->pad == STF_ISP_PAD_SINK) {
+ struct v4l2_subdev_selection sel = { 0 };
+
+ /* Reset sink pad compose selection */
+ sel.which = fmt->which;
+ sel.pad = STF_ISP_PAD_SINK;
+ sel.target = V4L2_SEL_TGT_CROP;
+ sel.r.width = fmt->format.width;
+ sel.r.height = fmt->format.height;
+ isp_set_selection(sd, state, &sel);
+ }
+
+ return 0;
+}
+
+static const struct v4l2_rect stf_frame_min_crop = {
+ .width = STFCAMSS_FRAME_MIN_WIDTH,
+ .height = STFCAMSS_FRAME_MIN_HEIGHT,
+ .top = 0,
+ .left = 0,
+};
+
+static void isp_try_crop(struct stf_isp_dev *isp_dev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_rect *crop)
+{
+ struct v4l2_mbus_framefmt *fmt =
+ v4l2_subdev_state_get_format(state, STF_ISP_PAD_SINK);
+
+ const struct v4l2_rect bounds = {
+ .width = fmt->width,
+ .height = fmt->height,
+ .left = 0,
+ .top = 0,
+ };
+
+ v4l2_rect_set_min_size(crop, &stf_frame_min_crop);
+ v4l2_rect_map_inside(crop, &bounds);
+}
+
+static int isp_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct v4l2_subdev_format fmt = { 0 };
+ struct v4l2_rect *rect;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ if (sel->pad == STF_ISP_PAD_SINK) {
+ fmt.format = *v4l2_subdev_state_get_format(state,
+ sel->pad);
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = fmt.format.width;
+ sel->r.height = fmt.format.height;
+ } else if (sel->pad == STF_ISP_PAD_SRC) {
+ rect = v4l2_subdev_state_get_crop(state, sel->pad);
+ sel->r = *rect;
+ }
+ break;
+
+ case V4L2_SEL_TGT_CROP:
+ rect = v4l2_subdev_state_get_crop(state, sel->pad);
+ if (!rect)
+ return -EINVAL;
+
+ sel->r = *rect;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int isp_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct stf_isp_dev *isp_dev = v4l2_get_subdevdata(sd);
+ struct v4l2_rect *rect;
+
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ if (sel->target == V4L2_SEL_TGT_CROP &&
+ sel->pad == STF_ISP_PAD_SINK) {
+ struct v4l2_subdev_selection crop = { 0 };
+
+ rect = v4l2_subdev_state_get_crop(state, sel->pad);
+ if (!rect)
+ return -EINVAL;
+
+ isp_try_crop(isp_dev, state, &sel->r);
+ *rect = sel->r;
+
+ /* Reset source crop selection */
+ crop.which = sel->which;
+ crop.pad = STF_ISP_PAD_SRC;
+ crop.target = V4L2_SEL_TGT_CROP;
+ crop.r = *rect;
+ isp_set_selection(sd, state, &crop);
+ } else if (sel->target == V4L2_SEL_TGT_CROP &&
+ sel->pad == STF_ISP_PAD_SRC) {
+ struct v4l2_subdev_format fmt = { 0 };
+
+ rect = v4l2_subdev_state_get_crop(state, sel->pad);
+ if (!rect)
+ return -EINVAL;
+
+ isp_try_crop(isp_dev, state, &sel->r);
+ *rect = sel->r;
+
+ /* Reset source pad format width and height */
+ fmt.which = sel->which;
+ fmt.pad = STF_ISP_PAD_SRC;
+ fmt.format.width = rect->width;
+ fmt.format.height = rect->height;
+ isp_set_format(sd, state, &fmt);
+ }
+
+ dev_dbg(isp_dev->stfcamss->dev, "pad: %d sel(%d,%d)/%dx%d\n",
+ sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
+
+ return 0;
+}
+
+static int isp_init_formats(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct v4l2_subdev_format format = {
+ .pad = STF_ISP_PAD_SINK,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .format = {
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .width = 1920,
+ .height = 1080
+ }
+ };
+
+ return isp_set_format(sd, sd_state, &format);
+}
+
+static const struct v4l2_subdev_video_ops isp_video_ops = {
+ .s_stream = isp_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops isp_pad_ops = {
+ .enum_mbus_code = isp_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = isp_set_format,
+ .get_selection = isp_get_selection,
+ .set_selection = isp_set_selection,
+};
+
+static const struct v4l2_subdev_ops isp_v4l2_ops = {
+ .video = &isp_video_ops,
+ .pad = &isp_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops isp_internal_ops = {
+ .init_state = isp_init_formats,
+};
+
+static const struct media_entity_operations isp_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+int stf_isp_register(struct stf_isp_dev *isp_dev, struct v4l2_device *v4l2_dev)
+{
+ struct v4l2_subdev *sd = &isp_dev->subdev;
+ struct media_pad *pads = isp_dev->pads;
+ int ret;
+
+ v4l2_subdev_init(sd, &isp_v4l2_ops);
+ sd->internal_ops = &isp_internal_ops;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(sd->name, ARRAY_SIZE(sd->name), "stf_isp");
+ v4l2_set_subdevdata(sd, isp_dev);
+
+ pads[STF_ISP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ pads[STF_ISP_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE;
+
+ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_ISP;
+ sd->entity.ops = &isp_media_ops;
+ ret = media_entity_pads_init(&sd->entity, STF_ISP_PAD_MAX, pads);
+ if (ret) {
+ dev_err(isp_dev->stfcamss->dev,
+ "Failed to init media entity: %d\n", ret);
+ return ret;
+ }
+
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret)
+ goto err_entity_cleanup;
+
+ ret = v4l2_device_register_subdev(v4l2_dev, sd);
+ if (ret) {
+ dev_err(isp_dev->stfcamss->dev,
+ "Failed to register subdev: %d\n", ret);
+ goto err_subdev_cleanup;
+ }
+
+ return 0;
+
+err_subdev_cleanup:
+ v4l2_subdev_cleanup(sd);
+err_entity_cleanup:
+ media_entity_cleanup(&sd->entity);
+ return ret;
+}
+
+int stf_isp_unregister(struct stf_isp_dev *isp_dev)
+{
+ v4l2_device_unregister_subdev(&isp_dev->subdev);
+ v4l2_subdev_cleanup(&isp_dev->subdev);
+ media_entity_cleanup(&isp_dev->subdev.entity);
+
+ return 0;
+}
diff --git a/drivers/staging/media/starfive/camss/stf-isp.h b/drivers/staging/media/starfive/camss/stf-isp.h
new file mode 100644
index 000000000000..955cbb048363
--- /dev/null
+++ b/drivers/staging/media/starfive/camss/stf-isp.h
@@ -0,0 +1,428 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * stf_isp.h
+ *
+ * StarFive Camera Subsystem - ISP Module
+ *
+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
+ */
+
+#ifndef STF_ISP_H
+#define STF_ISP_H
+
+#include <media/v4l2-subdev.h>
+
+#include "stf-video.h"
+
+#define ISP_RAW_DATA_BITS 12
+#define SCALER_RATIO_MAX 1
+#define STF_ISP_REG_OFFSET_MAX 0x0fff
+#define STF_ISP_REG_DELAY_MAX 100
+
+/* isp registers */
+#define ISP_REG_CSI_INPUT_EN_AND_STATUS 0x000
+#define CSI_SCD_ERR BIT(6)
+#define CSI_ITU656_ERR BIT(4)
+#define CSI_ITU656_F BIT(3)
+#define CSI_SCD_DONE BIT(2)
+#define CSI_BUSY_S BIT(1)
+#define CSI_EN_S BIT(0)
+
+#define ISP_REG_CSIINTS 0x008
+#define CSI_INTS(n) ((n) << 16)
+#define CSI_SHA_M(n) ((n) << 0)
+#define CSI_INTS_MASK GENMASK(17, 16)
+
+#define ISP_REG_CSI_MODULE_CFG 0x010
+#define CSI_DUMP_EN BIT(19)
+#define CSI_VS_EN BIT(18)
+#define CSI_SC_EN BIT(17)
+#define CSI_OBA_EN BIT(16)
+#define CSI_AWB_EN BIT(7)
+#define CSI_LCCF_EN BIT(6)
+#define CSI_OECFHM_EN BIT(5)
+#define CSI_OECF_EN BIT(4)
+#define CSI_LCBQ_EN BIT(3)
+#define CSI_OBC_EN BIT(2)
+#define CSI_DEC_EN BIT(1)
+#define CSI_DC_EN BIT(0)
+
+#define ISP_REG_SENSOR 0x014
+#define DVP_SYNC_POL(n) ((n) << 2)
+#define ITU656_EN(n) ((n) << 1)
+#define IMAGER_SEL(n) ((n) << 0)
+
+#define ISP_REG_RAW_FORMAT_CFG 0x018
+#define SMY13(n) ((n) << 14)
+#define SMY12(n) ((n) << 12)
+#define SMY11(n) ((n) << 10)
+#define SMY10(n) ((n) << 8)
+#define SMY3(n) ((n) << 6)
+#define SMY2(n) ((n) << 4)
+#define SMY1(n) ((n) << 2)
+#define SMY0(n) ((n) << 0)
+
+#define ISP_REG_PIC_CAPTURE_START_CFG 0x01c
+#define VSTART_CAP(n) ((n) << 16)
+#define HSTART_CAP(n) ((n) << 0)
+
+#define ISP_REG_PIC_CAPTURE_END_CFG 0x020
+#define VEND_CAP(n) ((n) << 16)
+#define HEND_CAP(n) ((n) << 0)
+
+#define ISP_REG_DUMP_CFG_0 0x024
+#define ISP_REG_DUMP_CFG_1 0x028
+#define DUMP_ID(n) ((n) << 24)
+#define DUMP_SHT(n) ((n) << 20)
+#define DUMP_BURST_LEN(n) ((n) << 16)
+#define DUMP_SD(n) ((n) << 0)
+#define DUMP_BURST_LEN_MASK GENMASK(17, 16)
+#define DUMP_SD_MASK GENMASK(15, 0)
+
+#define ISP_REG_DEC_CFG 0x030
+#define DEC_V_KEEP(n) ((n) << 24)
+#define DEC_V_PERIOD(n) ((n) << 16)
+#define DEC_H_KEEP(n) ((n) << 8)
+#define DEC_H_PERIOD(n) ((n) << 0)
+
+#define ISP_REG_OBC_CFG 0x034
+#define OBC_W_H(y) ((y) << 4)
+#define OBC_W_W(x) ((x) << 0)
+
+#define ISP_REG_DC_CFG_1 0x044
+#define DC_AXI_ID(n) ((n) << 0)
+
+#define ISP_REG_LCCF_CFG_0 0x050
+#define Y_DISTANCE(y) ((y) << 16)
+#define X_DISTANCE(x) ((x) << 0)
+
+#define ISP_REG_LCCF_CFG_1 0x058
+#define LCCF_MAX_DIS(n) ((n) << 0)
+
+#define ISP_REG_LCBQ_CFG_0 0x074
+#define H_LCBQ(y) ((y) << 12)
+#define W_LCBQ(x) ((x) << 8)
+
+#define ISP_REG_LCBQ_CFG_1 0x07c
+#define Y_COOR(y) ((y) << 16)
+#define X_COOR(x) ((x) << 0)
+
+#define ISP_REG_LCCF_CFG_2 0x0e0
+#define ISP_REG_LCCF_CFG_3 0x0e4
+#define ISP_REG_LCCF_CFG_4 0x0e8
+#define ISP_REG_LCCF_CFG_5 0x0ec
+#define LCCF_F2_PAR(n) ((n) << 16)
+#define LCCF_F1_PAR(n) ((n) << 0)
+
+#define ISP_REG_OECF_X0_CFG0 0x100
+#define ISP_REG_OECF_X0_CFG1 0x104
+#define ISP_REG_OECF_X0_CFG2 0x108
+#define ISP_REG_OECF_X0_CFG3 0x10c
+#define ISP_REG_OECF_X0_CFG4 0x110
+#define ISP_REG_OECF_X0_CFG5 0x114
+#define ISP_REG_OECF_X0_CFG6 0x118
+#define ISP_REG_OECF_X0_CFG7 0x11c
+
+#define ISP_REG_OECF_Y3_CFG0 0x1e0
+#define ISP_REG_OECF_Y3_CFG1 0x1e4
+#define ISP_REG_OECF_Y3_CFG2 0x1e8
+#define ISP_REG_OECF_Y3_CFG3 0x1ec
+#define ISP_REG_OECF_Y3_CFG4 0x1f0
+#define ISP_REG_OECF_Y3_CFG5 0x1f4
+#define ISP_REG_OECF_Y3_CFG6 0x1f8
+#define ISP_REG_OECF_Y3_CFG7 0x1fc
+
+#define ISP_REG_OECF_S0_CFG0 0x200
+#define ISP_REG_OECF_S3_CFG7 0x27c
+#define OCEF_PAR_H(n) ((n) << 16)
+#define OCEF_PAR_L(n) ((n) << 0)
+
+#define ISP_REG_AWB_X0_CFG_0 0x280
+#define ISP_REG_AWB_X0_CFG_1 0x284
+#define ISP_REG_AWB_X1_CFG_0 0x288
+#define ISP_REG_AWB_X1_CFG_1 0x28c
+#define ISP_REG_AWB_X2_CFG_0 0x290
+#define ISP_REG_AWB_X2_CFG_1 0x294
+#define ISP_REG_AWB_X3_CFG_0 0x298
+#define ISP_REG_AWB_X3_CFG_1 0x29c
+#define AWB_X_SYMBOL_H(n) ((n) << 16)
+#define AWB_X_SYMBOL_L(n) ((n) << 0)
+
+#define ISP_REG_AWB_Y0_CFG_0 0x2a0
+#define ISP_REG_AWB_Y0_CFG_1 0x2a4
+#define ISP_REG_AWB_Y1_CFG_0 0x2a8
+#define ISP_REG_AWB_Y1_CFG_1 0x2ac
+#define ISP_REG_AWB_Y2_CFG_0 0x2b0
+#define ISP_REG_AWB_Y2_CFG_1 0x2b4
+#define ISP_REG_AWB_Y3_CFG_0 0x2b8
+#define ISP_REG_AWB_Y3_CFG_1 0x2bc
+#define AWB_Y_SYMBOL_H(n) ((n) << 16)
+#define AWB_Y_SYMBOL_L(n) ((n) << 0)
+
+#define ISP_REG_AWB_S0_CFG_0 0x2c0
+#define ISP_REG_AWB_S0_CFG_1 0x2c4
+#define ISP_REG_AWB_S1_CFG_0 0x2c8
+#define ISP_REG_AWB_S1_CFG_1 0x2cc
+#define ISP_REG_AWB_S2_CFG_0 0x2d0
+#define ISP_REG_AWB_S2_CFG_1 0x2d4
+#define ISP_REG_AWB_S3_CFG_0 0x2d8
+#define ISP_REG_AWB_S3_CFG_1 0x2dc
+#define AWB_S_SYMBOL_H(n) ((n) << 16)
+#define AWB_S_SYMBOL_L(n) ((n) << 0)
+
+#define ISP_REG_OBCG_CFG_0 0x2e0
+#define ISP_REG_OBCG_CFG_1 0x2e4
+#define ISP_REG_OBCG_CFG_2 0x2e8
+#define ISP_REG_OBCG_CFG_3 0x2ec
+#define ISP_REG_OBCO_CFG_0 0x2f0
+#define ISP_REG_OBCO_CFG_1 0x2f4
+#define ISP_REG_OBCO_CFG_2 0x2f8
+#define ISP_REG_OBCO_CFG_3 0x2fc
+#define GAIN_D_POINT(x) ((x) << 24)
+#define GAIN_C_POINT(x) ((x) << 16)
+#define GAIN_B_POINT(x) ((x) << 8)
+#define GAIN_A_POINT(x) ((x) << 0)
+#define OFFSET_D_POINT(x) ((x) << 24)
+#define OFFSET_C_POINT(x) ((x) << 16)
+#define OFFSET_B_POINT(x) ((x) << 8)
+#define OFFSET_A_POINT(x) ((x) << 0)
+
+#define ISP_REG_ISP_CTRL_0 0xa00
+#define ISPC_LINE BIT(27)
+#define ISPC_SC BIT(26)
+#define ISPC_CSI BIT(25)
+#define ISPC_ISP BIT(24)
+#define ISPC_ENUO BIT(20)
+#define ISPC_ENLS BIT(17)
+#define ISPC_ENSS1 BIT(12)
+#define ISPC_ENSS0 BIT(11)
+#define ISPC_RST BIT(1)
+#define ISPC_EN BIT(0)
+#define ISPC_RST_MASK BIT(1)
+#define ISPC_INT_ALL_MASK GENMASK(27, 24)
+
+#define ISP_REG_ISP_CTRL_1 0xa08
+#define CTRL_SAT(n) ((n) << 28)
+#define CTRL_DBC BIT(22)
+#define CTRL_CTC BIT(21)
+#define CTRL_YHIST BIT(20)
+#define CTRL_YCURVE BIT(19)
+#define CTRL_CTM BIT(18)
+#define CTRL_BIYUV BIT(17)
+#define CTRL_SCE BIT(8)
+#define CTRL_EE BIT(7)
+#define CTRL_CCE BIT(5)
+#define CTRL_RGE BIT(4)
+#define CTRL_CME BIT(3)
+#define CTRL_AE BIT(2)
+#define CTRL_CE BIT(1)
+#define CTRL_SAT_MASK GENMASK(31, 28)
+
+#define ISP_REG_PIPELINE_XY_SIZE 0xa0c
+#define H_ACT_CAP(n) ((n) << 16)
+#define W_ACT_CAP(n) ((n) << 0)
+
+#define ISP_REG_ICTC 0xa10
+#define GF_MODE(n) ((n) << 30)
+#define MAXGT(n) ((n) << 16)
+#define MINGT(n) ((n) << 0)
+
+#define ISP_REG_IDBC 0xa14
+#define BADGT(n) ((n) << 16)
+#define BADXT(n) ((n) << 0)
+
+#define ISP_REG_ICFAM 0xa1c
+#define CROSS_COV(n) ((n) << 4)
+#define HV_W(n) ((n) << 0)
+
+#define ISP_REG_CS_GAIN 0xa30
+#define CMAD(n) ((n) << 16)
+#define CMAB(n) ((n) << 0)
+
+#define ISP_REG_CS_THRESHOLD 0xa34
+#define CMD(n) ((n) << 16)
+#define CMB(n) ((n) << 0)
+
+#define ISP_REG_CS_OFFSET 0xa38
+#define VOFF(n) ((n) << 16)
+#define UOFF(n) ((n) << 0)
+
+#define ISP_REG_CS_HUE_F 0xa3c
+#define SIN(n) ((n) << 16)
+#define COS(n) ((n) << 0)
+
+#define ISP_REG_CS_SCALE 0xa40
+
+#define ISP_REG_IESHD 0xa50
+#define SHAD_UP_M BIT(1)
+#define SHAD_UP_EN BIT(0)
+
+#define ISP_REG_YADJ0 0xa54
+#define YOIR(n) ((n) << 16)
+#define YIMIN(n) ((n) << 0)
+
+#define ISP_REG_YADJ1 0xa58
+#define YOMAX(n) ((n) << 16)
+#define YOMIN(n) ((n) << 0)
+
+#define ISP_REG_Y_PLANE_START_ADDR 0xa80
+#define ISP_REG_UV_PLANE_START_ADDR 0xa84
+#define ISP_REG_STRIDE 0xa88
+
+#define ISP_REG_ITIIWSR 0xb20
+#define ITI_HSIZE(n) ((n) << 16)
+#define ITI_WSIZE(n) ((n) << 0)
+
+#define ISP_REG_ITIDWLSR 0xb24
+#define ISP_REG_ITIPDFR 0xb38
+#define ISP_REG_ITIDRLSR 0xb3C
+
+#define ISP_REG_DNYUV_YSWR0 0xc00
+#define ISP_REG_DNYUV_YSWR1 0xc04
+#define ISP_REG_DNYUV_CSWR0 0xc08
+#define ISP_REG_DNYUV_CSWR1 0xc0c
+#define YUVSW5(n) ((n) << 20)
+#define YUVSW4(n) ((n) << 16)
+#define YUVSW3(n) ((n) << 12)
+#define YUVSW2(n) ((n) << 8)
+#define YUVSW1(n) ((n) << 4)
+#define YUVSW0(n) ((n) << 0)
+
+#define ISP_REG_DNYUV_YDR0 0xc10
+#define ISP_REG_DNYUV_YDR1 0xc14
+#define ISP_REG_DNYUV_YDR2 0xc18
+#define ISP_REG_DNYUV_CDR0 0xc1c
+#define ISP_REG_DNYUV_CDR1 0xc20
+#define ISP_REG_DNYUV_CDR2 0xc24
+#define CURVE_D_H(n) ((n) << 16)
+#define CURVE_D_L(n) ((n) << 0)
+
+#define ISP_REG_ICAMD_0 0xc40
+#define ISP_REG_ICAMD_12 0xc70
+#define ISP_REG_ICAMD_20 0xc90
+#define ISP_REG_ICAMD_24 0xca0
+#define ISP_REG_ICAMD_25 0xca4
+#define DNRM_F(n) ((n) << 16)
+#define CCM_M_DAT(n) ((n) << 0)
+
+#define ISP_REG_GAMMA_VAL0 0xe00
+#define ISP_REG_GAMMA_VAL1 0xe04
+#define ISP_REG_GAMMA_VAL2 0xe08
+#define ISP_REG_GAMMA_VAL3 0xe0c
+#define ISP_REG_GAMMA_VAL4 0xe10
+#define ISP_REG_GAMMA_VAL5 0xe14
+#define ISP_REG_GAMMA_VAL6 0xe18
+#define ISP_REG_GAMMA_VAL7 0xe1c
+#define ISP_REG_GAMMA_VAL8 0xe20
+#define ISP_REG_GAMMA_VAL9 0xe24
+#define ISP_REG_GAMMA_VAL10 0xe28
+#define ISP_REG_GAMMA_VAL11 0xe2c
+#define ISP_REG_GAMMA_VAL12 0xe30
+#define ISP_REG_GAMMA_VAL13 0xe34
+#define ISP_REG_GAMMA_VAL14 0xe38
+#define GAMMA_S_VAL(n) ((n) << 16)
+#define GAMMA_VAL(n) ((n) << 0)
+
+#define ISP_REG_R2Y_0 0xe40
+#define ISP_REG_R2Y_1 0xe44
+#define ISP_REG_R2Y_2 0xe48
+#define ISP_REG_R2Y_3 0xe4c
+#define ISP_REG_R2Y_4 0xe50
+#define ISP_REG_R2Y_5 0xe54
+#define ISP_REG_R2Y_6 0xe58
+#define ISP_REG_R2Y_7 0xe5c
+#define ISP_REG_R2Y_8 0xe60
+
+#define ISP_REG_SHARPEN0 0xe80
+#define ISP_REG_SHARPEN1 0xe84
+#define ISP_REG_SHARPEN2 0xe88
+#define ISP_REG_SHARPEN3 0xe8c
+#define ISP_REG_SHARPEN4 0xe90
+#define ISP_REG_SHARPEN5 0xe94
+#define ISP_REG_SHARPEN6 0xe98
+#define ISP_REG_SHARPEN7 0xe9c
+#define ISP_REG_SHARPEN8 0xea0
+#define ISP_REG_SHARPEN9 0xea4
+#define ISP_REG_SHARPEN10 0xea8
+#define ISP_REG_SHARPEN11 0xeac
+#define ISP_REG_SHARPEN12 0xeb0
+#define ISP_REG_SHARPEN13 0xeb4
+#define ISP_REG_SHARPEN14 0xeb8
+#define S_DELTA(n) ((n) << 16)
+#define S_WEIGHT(n) ((n) << 8)
+
+#define ISP_REG_SHARPEN_FS0 0xebc
+#define ISP_REG_SHARPEN_FS1 0xec0
+#define ISP_REG_SHARPEN_FS2 0xec4
+#define ISP_REG_SHARPEN_FS3 0xec8
+#define ISP_REG_SHARPEN_FS4 0xecc
+#define ISP_REG_SHARPEN_FS5 0xed0
+#define S_FACTOR(n) ((n) << 24)
+#define S_SLOPE(n) ((n) << 0)
+
+#define ISP_REG_SHARPEN_WN 0xed4
+#define PDIRF(n) ((n) << 28)
+#define NDIRF(n) ((n) << 24)
+#define WSUM(n) ((n) << 0)
+
+#define ISP_REG_IUVS1 0xed8
+#define UVDIFF2(n) ((n) << 16)
+#define UVDIFF1(n) ((n) << 0)
+
+#define ISP_REG_IUVS2 0xedc
+#define UVF(n) ((n) << 24)
+#define UVSLOPE(n) ((n) << 0)
+
+#define ISP_REG_IUVCKS1 0xee0
+#define UVCKDIFF2(n) ((n) << 16)
+#define UVCKDIFF1(n) ((n) << 0)
+
+#define ISP_REG_IUVCKS2 0xee4
+
+#define ISP_REG_ISHRPET 0xee8
+#define TH(n) ((n) << 8)
+#define EN(n) ((n) << 0)
+
+#define ISP_REG_YCURVE_0 0xf00
+#define ISP_REG_YCURVE_63 0xffc
+
+#define IMAGE_MAX_WIDTH 1920
+#define IMAGE_MAX_HEIGH 1080
+
+/* pad id for media framework */
+enum stf_isp_pad_id {
+ STF_ISP_PAD_SINK = 0,
+ STF_ISP_PAD_SRC,
+ STF_ISP_PAD_MAX
+};
+
+struct stf_isp_format {
+ u32 code;
+ u8 bpp;
+};
+
+struct stf_isp_format_table {
+ const struct stf_isp_format *fmts;
+ int nfmts;
+};
+
+struct stf_isp_dev {
+ struct stfcamss *stfcamss;
+ struct v4l2_subdev subdev;
+ struct media_pad pads[STF_ISP_PAD_MAX];
+ const struct stf_isp_format_table *formats;
+ unsigned int nformats;
+ struct v4l2_subdev *source_subdev;
+ const struct stf_isp_format *current_fmt;
+};
+
+int stf_isp_reset(struct stf_isp_dev *isp_dev);
+void stf_isp_init_cfg(struct stf_isp_dev *isp_dev);
+void stf_isp_settings(struct stf_isp_dev *isp_dev,
+ struct v4l2_rect *crop, u32 mcode);
+void stf_isp_stream_set(struct stf_isp_dev *isp_dev);
+int stf_isp_init(struct stfcamss *stfcamss);
+int stf_isp_register(struct stf_isp_dev *isp_dev, struct v4l2_device *v4l2_dev);
+int stf_isp_unregister(struct stf_isp_dev *isp_dev);
+
+#endif /* STF_ISP_H */
diff --git a/drivers/staging/media/starfive/camss/stf-video.c b/drivers/staging/media/starfive/camss/stf-video.c
new file mode 100644
index 000000000000..989b5e82bae9
--- /dev/null
+++ b/drivers/staging/media/starfive/camss/stf-video.c
@@ -0,0 +1,572 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * stf_video.c
+ *
+ * StarFive Camera Subsystem - V4L2 device node
+ *
+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/pm_runtime.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mc.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "stf-camss.h"
+#include "stf-video.h"
+
+/* -----------------------------------------------------------------------------
+ * Helper functions
+ */
+
+static inline struct stfcamss_buffer *
+to_stfcamss_buffer(struct vb2_v4l2_buffer *vbuf)
+{
+ return container_of(vbuf, struct stfcamss_buffer, vb);
+}
+
+static const struct stfcamss_format_info *
+video_g_fi_by_index(struct stfcamss_video *video, int index)
+{
+ if (index >= video->nformats)
+ return NULL;
+
+ return &video->formats[index];
+}
+
+static const struct stfcamss_format_info *
+video_g_fi_by_mcode(struct stfcamss_video *video, u32 mcode)
+{
+ unsigned int i;
+
+ for (i = 0; i < video->nformats; i++) {
+ if (video->formats[i].code == mcode)
+ return &video->formats[i];
+ }
+
+ return NULL;
+}
+
+static const struct stfcamss_format_info *
+video_g_fi_by_pfmt(struct stfcamss_video *video, u32 pixelformat)
+{
+ unsigned int i;
+
+ for (i = 0; i < video->nformats; i++) {
+ if (video->formats[i].pixelformat == pixelformat)
+ return &video->formats[i];
+ }
+
+ return NULL;
+}
+
+static int __video_try_fmt(struct stfcamss_video *video, struct v4l2_format *f)
+{
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ const struct stfcamss_format_info *fi;
+ u32 width, height;
+ u32 bpl;
+ unsigned int i;
+
+ fi = video_g_fi_by_pfmt(video, pix->pixelformat);
+ if (!fi)
+ fi = &video->formats[0]; /* default format */
+
+ width = pix->width;
+ height = pix->height;
+
+ memset(pix, 0, sizeof(*pix));
+
+ pix->pixelformat = fi->pixelformat;
+ pix->width = clamp_t(u32, width, STFCAMSS_FRAME_MIN_WIDTH,
+ STFCAMSS_FRAME_MAX_WIDTH);
+ pix->height = clamp_t(u32, height, STFCAMSS_FRAME_MIN_HEIGHT,
+ STFCAMSS_FRAME_MAX_HEIGHT);
+ bpl = pix->width * fi->bpp / 8;
+ bpl = ALIGN(bpl, video->bpl_alignment);
+ pix->bytesperline = bpl;
+
+ for (i = 0; i < fi->planes; ++i)
+ pix->sizeimage += bpl * pix->height / fi->vsub[i];
+
+ pix->field = V4L2_FIELD_NONE;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ pix->flags = 0;
+ pix->ycbcr_enc =
+ V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
+ pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
+ pix->colorspace,
+ pix->ycbcr_enc);
+ pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
+
+ return 0;
+}
+
+static int stf_video_init_format(struct stfcamss_video *video)
+{
+ int ret;
+ struct v4l2_format format = {
+ .type = video->type,
+ .fmt.pix = {
+ .width = 1920,
+ .height = 1080,
+ .pixelformat = V4L2_PIX_FMT_NV12,
+ },
+ };
+
+ ret = __video_try_fmt(video, &format);
+
+ if (ret < 0)
+ return ret;
+
+ video->active_fmt = format;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Video queue operations
+ */
+
+static int video_queue_setup(struct vb2_queue *q,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct stfcamss_video *video = vb2_get_drv_priv(q);
+ const struct v4l2_pix_format *format = &video->active_fmt.fmt.pix;
+
+ if (*num_planes) {
+ if (*num_planes != 1)
+ return -EINVAL;
+
+ if (sizes[0] < format->sizeimage)
+ return -EINVAL;
+ } else {
+ *num_planes = 1;
+ sizes[0] = format->sizeimage;
+ }
+
+ if (!sizes[0]) {
+ dev_dbg(video->stfcamss->dev,
+ "%s: error size is zero.\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(video->stfcamss->dev, "planes = %d, size = %d\n",
+ *num_planes, sizes[0]);
+
+ return 0;
+}
+
+static int video_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue);
+ struct stfcamss_buffer *buffer = to_stfcamss_buffer(vbuf);
+ const struct v4l2_pix_format *fmt = &video->active_fmt.fmt.pix;
+ dma_addr_t *paddr;
+
+ paddr = vb2_plane_cookie(vb, 0);
+ buffer->addr[0] = *paddr;
+
+ if (fmt->pixelformat == V4L2_PIX_FMT_NV12)
+ buffer->addr[1] =
+ buffer->addr[0] + fmt->bytesperline * fmt->height;
+
+ return 0;
+}
+
+static int video_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue);
+ const struct v4l2_pix_format *fmt = &video->active_fmt.fmt.pix;
+
+ if (fmt->sizeimage > vb2_plane_size(vb, 0)) {
+ dev_dbg(video->stfcamss->dev,
+ "sizeimage = %u, plane size = %u\n",
+ fmt->sizeimage, (unsigned int)vb2_plane_size(vb, 0));
+ return -EINVAL;
+ }
+ vb2_set_plane_payload(vb, 0, fmt->sizeimage);
+
+ vbuf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static void video_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct stfcamss_video *video = vb2_get_drv_priv(vb->vb2_queue);
+ struct stfcamss_buffer *buffer = to_stfcamss_buffer(vbuf);
+
+ video->ops->queue_buffer(video, buffer);
+}
+
+static int video_get_subdev_format(struct stfcamss_video *video,
+ struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_subdev *subdev;
+ struct media_pad *pad;
+ struct media_entity *entity;
+ int ret;
+
+ entity = &video->vdev.entity;
+ while (1) {
+ pad = &entity->pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
+
+ pad = media_pad_remote_pad_first(pad);
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ break;
+
+ entity = pad->entity;
+ subdev = media_entity_to_v4l2_subdev(entity);
+
+ fmt->pad = pad->index;
+
+ ret = v4l2_subdev_call_state_active(subdev, pad, get_fmt, fmt);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+ else if (!ret)
+ break;
+ }
+
+ return 0;
+}
+
+static int stf_video_check_format(struct stfcamss_video *video)
+{
+ struct v4l2_pix_format *pix = &video->active_fmt.fmt.pix;
+ const struct stfcamss_format_info *fi;
+ int ret;
+ struct v4l2_subdev_format sd_fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+
+ ret = video_get_subdev_format(video, &sd_fmt);
+ if (ret < 0)
+ return ret;
+
+ fi = video_g_fi_by_mcode(video, sd_fmt.format.code);
+ if (!fi)
+ return -EINVAL;
+
+ if (pix->pixelformat != fi->pixelformat ||
+ pix->height != sd_fmt.format.height ||
+ pix->width != sd_fmt.format.width ||
+ pix->field != sd_fmt.format.field)
+ return -EPIPE;
+
+ return 0;
+}
+
+static int video_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct stfcamss_video *video = vb2_get_drv_priv(q);
+ struct video_device *vdev = &video->vdev;
+ int ret;
+
+ ret = video_device_pipeline_start(vdev, &video->stfcamss->pipe);
+ if (ret < 0) {
+ dev_err(video->stfcamss->dev,
+ "Failed to media_pipeline_start: %d\n", ret);
+ goto err_ret_buffers;
+ }
+
+ ret = pm_runtime_resume_and_get(video->stfcamss->dev);
+ if (ret < 0) {
+ dev_err(video->stfcamss->dev, "power up failed %d\n", ret);
+ goto err_pipeline_stop;
+ }
+
+ video->ops->start_streaming(video);
+
+ ret = v4l2_subdev_call(video->source_subdev, video, s_stream, true);
+ if (ret) {
+ dev_err(video->stfcamss->dev, "stream on failed\n");
+ goto err_pm_put;
+ }
+
+ return 0;
+
+err_pm_put:
+ pm_runtime_put(video->stfcamss->dev);
+err_pipeline_stop:
+ video_device_pipeline_stop(vdev);
+err_ret_buffers:
+ video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED);
+ return ret;
+}
+
+static void video_stop_streaming(struct vb2_queue *q)
+{
+ struct stfcamss_video *video = vb2_get_drv_priv(q);
+ struct video_device *vdev = &video->vdev;
+
+ video->ops->stop_streaming(video);
+
+ v4l2_subdev_call(video->source_subdev, video, s_stream, false);
+
+ pm_runtime_put(video->stfcamss->dev);
+
+ video_device_pipeline_stop(vdev);
+ video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR);
+}
+
+static const struct vb2_ops stf_video_vb2_q_ops = {
+ .queue_setup = video_queue_setup,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .buf_init = video_buf_init,
+ .buf_prepare = video_buf_prepare,
+ .buf_queue = video_buf_queue,
+ .start_streaming = video_start_streaming,
+ .stop_streaming = video_stop_streaming,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 ioctls
+ */
+
+static int video_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, "starfive-camss", sizeof(cap->driver));
+ strscpy(cap->card, "Starfive Camera Subsystem", sizeof(cap->card));
+
+ return 0;
+}
+
+static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ struct stfcamss_video *video = video_drvdata(file);
+ const struct stfcamss_format_info *fi;
+
+ if (f->index >= video->nformats)
+ return -EINVAL;
+
+ if (f->mbus_code) {
+ /* Each entry in formats[] table has unique mbus_code */
+ if (f->index > 0)
+ return -EINVAL;
+
+ fi = video_g_fi_by_mcode(video, f->mbus_code);
+ } else {
+ fi = video_g_fi_by_index(video, f->index);
+ }
+
+ if (!fi)
+ return -EINVAL;
+
+ f->pixelformat = fi->pixelformat;
+
+ return 0;
+}
+
+static int video_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct stfcamss_video *video = video_drvdata(file);
+ unsigned int i;
+
+ if (fsize->index)
+ return -EINVAL;
+
+ for (i = 0; i < video->nformats; i++) {
+ if (video->formats[i].pixelformat == fsize->pixel_format)
+ break;
+ }
+
+ if (i == video->nformats)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ fsize->stepwise.min_width = STFCAMSS_FRAME_MIN_WIDTH;
+ fsize->stepwise.max_width = STFCAMSS_FRAME_MAX_WIDTH;
+ fsize->stepwise.min_height = STFCAMSS_FRAME_MIN_HEIGHT;
+ fsize->stepwise.max_height = STFCAMSS_FRAME_MAX_HEIGHT;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
+static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct stfcamss_video *video = video_drvdata(file);
+
+ *f = video->active_fmt;
+
+ return 0;
+}
+
+static int video_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct stfcamss_video *video = video_drvdata(file);
+ int ret;
+
+ if (vb2_is_busy(&video->vb2_q))
+ return -EBUSY;
+
+ ret = __video_try_fmt(video, f);
+ if (ret < 0)
+ return ret;
+
+ video->active_fmt = *f;
+
+ return 0;
+}
+
+static int video_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct stfcamss_video *video = video_drvdata(file);
+
+ return __video_try_fmt(video, f);
+}
+
+static const struct v4l2_ioctl_ops stf_vid_ioctl_ops = {
+ .vidioc_querycap = video_querycap,
+ .vidioc_enum_fmt_vid_cap = video_enum_fmt,
+ .vidioc_enum_framesizes = video_enum_framesizes,
+ .vidioc_g_fmt_vid_cap = video_g_fmt,
+ .vidioc_s_fmt_vid_cap = video_s_fmt,
+ .vidioc_try_fmt_vid_cap = video_try_fmt,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 file operations
+ */
+
+static const struct v4l2_file_operations stf_vid_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = video_ioctl2,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .read = vb2_fop_read,
+};
+
+/* -----------------------------------------------------------------------------
+ * STFCAMSS video core
+ */
+
+static int stf_link_validate(struct media_link *link)
+{
+ struct video_device *vdev =
+ media_entity_to_video_device(link->sink->entity);
+ struct stfcamss_video *video = video_get_drvdata(vdev);
+ int ret;
+
+ ret = stf_video_check_format(video);
+
+ return ret;
+}
+
+static const struct media_entity_operations stf_media_ops = {
+ .link_validate = stf_link_validate,
+};
+
+static void stf_video_release(struct video_device *vdev)
+{
+ struct stfcamss_video *video = video_get_drvdata(vdev);
+
+ media_entity_cleanup(&vdev->entity);
+
+ mutex_destroy(&video->q_lock);
+ mutex_destroy(&video->lock);
+}
+
+int stf_video_register(struct stfcamss_video *video,
+ struct v4l2_device *v4l2_dev, const char *name)
+{
+ struct video_device *vdev = &video->vdev;
+ struct vb2_queue *q;
+ struct media_pad *pad = &video->pad;
+ int ret;
+
+ mutex_init(&video->q_lock);
+ mutex_init(&video->lock);
+
+ q = &video->vb2_q;
+ q->drv_priv = video;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->ops = &stf_video_vb2_q_ops;
+ q->type = video->type;
+ q->io_modes = VB2_DMABUF | VB2_MMAP;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->buf_struct_size = sizeof(struct stfcamss_buffer);
+ q->dev = video->stfcamss->dev;
+ q->lock = &video->q_lock;
+ q->min_queued_buffers = STFCAMSS_MIN_BUFFERS;
+ ret = vb2_queue_init(q);
+ if (ret < 0) {
+ dev_err(video->stfcamss->dev,
+ "Failed to init vb2 queue: %d\n", ret);
+ goto err_mutex_destroy;
+ }
+
+ pad->flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vdev->entity, 1, pad);
+ if (ret < 0) {
+ dev_err(video->stfcamss->dev,
+ "Failed to init video entity: %d\n", ret);
+ goto err_mutex_destroy;
+ }
+
+ ret = stf_video_init_format(video);
+ if (ret < 0) {
+ dev_err(video->stfcamss->dev,
+ "Failed to init format: %d\n", ret);
+ goto err_media_cleanup;
+ }
+
+ vdev->fops = &stf_vid_fops;
+ vdev->ioctl_ops = &stf_vid_ioctl_ops;
+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ vdev->entity.ops = &stf_media_ops;
+ vdev->vfl_dir = VFL_DIR_RX;
+ vdev->release = stf_video_release;
+ vdev->v4l2_dev = v4l2_dev;
+ vdev->queue = &video->vb2_q;
+ vdev->lock = &video->lock;
+ strscpy(vdev->name, name, sizeof(vdev->name));
+
+ video_set_drvdata(vdev, video);
+
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret < 0) {
+ dev_err(video->stfcamss->dev,
+ "Failed to register video device: %d\n", ret);
+ goto err_media_cleanup;
+ }
+
+ return 0;
+
+err_media_cleanup:
+ media_entity_cleanup(&vdev->entity);
+err_mutex_destroy:
+ mutex_destroy(&video->lock);
+ mutex_destroy(&video->q_lock);
+ return ret;
+}
+
+void stf_video_unregister(struct stfcamss_video *video)
+{
+ vb2_video_unregister_device(&video->vdev);
+}
diff --git a/drivers/staging/media/starfive/camss/stf-video.h b/drivers/staging/media/starfive/camss/stf-video.h
new file mode 100644
index 000000000000..8052b77e3ad8
--- /dev/null
+++ b/drivers/staging/media/starfive/camss/stf-video.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * stf_video.h
+ *
+ * StarFive Camera Subsystem - V4L2 device node
+ *
+ * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
+ */
+
+#ifndef STF_VIDEO_H
+#define STF_VIDEO_H
+
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-v4l2.h>
+
+#define STFCAMSS_FRAME_MIN_WIDTH 64
+#define STFCAMSS_FRAME_MAX_WIDTH 1920
+#define STFCAMSS_FRAME_MIN_HEIGHT 64
+#define STFCAMSS_FRAME_MAX_HEIGHT 1080
+#define STFCAMSS_FRAME_WIDTH_ALIGN_8 8
+#define STFCAMSS_FRAME_WIDTH_ALIGN_128 128
+#define STFCAMSS_MIN_BUFFERS 2
+
+#define STFCAMSS_MAX_ENTITY_NAME_LEN 27
+
+enum stf_v_line_id {
+ STF_V_LINE_WR = 0,
+ STF_V_LINE_ISP,
+ STF_V_LINE_MAX,
+};
+
+enum stf_capture_type {
+ STF_CAPTURE_RAW = 0,
+ STF_CAPTURE_YUV,
+ STF_CAPTURE_NUM,
+};
+
+struct stfcamss_buffer {
+ struct vb2_v4l2_buffer vb;
+ dma_addr_t addr[2];
+ struct list_head queue;
+};
+
+struct fract {
+ u8 numerator;
+ u8 denominator;
+};
+
+/*
+ * struct stfcamss_format_info - ISP media bus format information
+ * @code: V4L2 media bus format code
+ * @pixelformat: V4L2 pixel format FCC identifier
+ * @planes: Number of planes
+ * @vsub: Vertical subsampling (for each plane)
+ * @bpp: Bits per pixel when stored in memory (for each plane)
+ */
+struct stfcamss_format_info {
+ u32 code;
+ u32 pixelformat;
+ u8 planes;
+ u8 vsub[3];
+ u8 bpp;
+};
+
+struct stfcamss_video {
+ struct stfcamss *stfcamss;
+ struct vb2_queue vb2_q;
+ struct video_device vdev;
+ struct media_pad pad;
+ struct v4l2_format active_fmt;
+ enum v4l2_buf_type type;
+ const struct stfcamss_video_ops *ops;
+ struct mutex lock; /* serialize device access */
+ struct mutex q_lock; /* protects the queue */
+ unsigned int bpl_alignment;
+ const struct stfcamss_format_info *formats;
+ unsigned int nformats;
+ struct v4l2_subdev *source_subdev;
+};
+
+struct stfcamss_video_ops {
+ int (*queue_buffer)(struct stfcamss_video *video,
+ struct stfcamss_buffer *buf);
+ int (*flush_buffers)(struct stfcamss_video *video,
+ enum vb2_buffer_state state);
+ void (*start_streaming)(struct stfcamss_video *video);
+ void (*stop_streaming)(struct stfcamss_video *video);
+};
+
+int stf_video_register(struct stfcamss_video *video,
+ struct v4l2_device *v4l2_dev, const char *name);
+
+void stf_video_unregister(struct stfcamss_video *video);
+
+#endif /* STF_VIDEO_H */
diff --git a/drivers/staging/media/sunxi/cedrus/Kconfig b/drivers/staging/media/sunxi/cedrus/Kconfig
index 621944f9907a..cb07a343c9c2 100644
--- a/drivers/staging/media/sunxi/cedrus/Kconfig
+++ b/drivers/staging/media/sunxi/cedrus/Kconfig
@@ -6,7 +6,6 @@ config VIDEO_SUNXI_CEDRUS
depends on HAS_DMA
depends on OF
select MEDIA_CONTROLLER
- select MEDIA_CONTROLLER_REQUEST_API
select SUNXI_SRAM
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
diff --git a/drivers/staging/media/sunxi/cedrus/TODO b/drivers/staging/media/sunxi/cedrus/TODO
index ec277ece47af..00aa304a7e36 100644
--- a/drivers/staging/media/sunxi/cedrus/TODO
+++ b/drivers/staging/media/sunxi/cedrus/TODO
@@ -1,7 +1,16 @@
-Before this stateless decoder driver can leave the staging area:
-* The Request API needs to be stabilized;
-* The codec-specific controls need to be thoroughly reviewed to ensure they
- cover all intended uses cases;
-* Userspace support for the Request API needs to be reviewed;
-* Another stateless decoder driver should be submitted;
-* At least one stateless encoder driver should be submitted.
+This driver suffers from a bad initial design that results in various aspects
+being intricated, making it difficult to scale to new codecs and to add encoding
+support in the future.
+
+Before leaving the staging area, it should be reworked to clearly distinguish
+between different aspects:
+- platform, with resources management, interrupt handler, watchdog,
+ v4l2 and m2m devices registration;
+- proc, with video device registration and related operations;
+- context, with m2m context, queue and controls management;
+- engine, with each individual codec job execution and codec-specific
+ operation callbacks;
+
+This will make it possible to register two different procs (decoder and
+encoder) while sharing significant common infrastructure, common v4l2 and m2m
+devices but exposing distinct video devices.
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index dfb401df138a..3e2843ef6cce 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -653,8 +653,13 @@ static void cedrus_h264_stop(struct cedrus_ctx *ctx)
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- for (i = 0; i < vq->num_buffers; i++) {
- buf = vb2_to_cedrus_buffer(vb2_get_buffer(vq, i));
+ for (i = 0; i < vb2_get_num_buffers(vq); i++) {
+ struct vb2_buffer *vb = vb2_get_buffer(vq, i);
+
+ if (!vb)
+ continue;
+
+ buf = vb2_to_cedrus_buffer(vb);
if (buf->codec.h264.mv_col_buf_size > 0) {
dma_free_attrs(dev->dev,
diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
index fc9297232456..52e94c8f2f01 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c
@@ -869,8 +869,13 @@ static void cedrus_h265_stop(struct cedrus_ctx *ctx)
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- for (i = 0; i < vq->num_buffers; i++) {
- buf = vb2_to_cedrus_buffer(vb2_get_buffer(vq, i));
+ for (i = 0; i < vb2_get_num_buffers(vq); i++) {
+ struct vb2_buffer *vb = vb2_get_buffer(vq, i);
+
+ if (!vb)
+ continue;
+
+ buf = vb2_to_cedrus_buffer(vb);
if (buf->codec.h265.mv_col_buf_size > 0) {
dma_free_attrs(dev->dev,
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c
index 1595a9607775..0eea4c2c3627 100644
--- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_capture.c
@@ -660,7 +660,7 @@ int sun6i_isp_capture_setup(struct sun6i_isp_device *isp_dev)
queue->buf_struct_size = sizeof(struct sun6i_isp_buffer);
queue->ops = &sun6i_isp_capture_queue_ops;
queue->mem_ops = &vb2_dma_contig_memops;
- queue->min_buffers_needed = 2;
+ queue->min_queued_buffers = 2;
queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
queue->lock = &capture->lock;
queue->dev = isp_dev->dev;
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c
index e28be895b486..53d05e8a364b 100644
--- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_params.c
@@ -489,7 +489,7 @@ int sun6i_isp_params_setup(struct sun6i_isp_device *isp_dev)
queue->buf_struct_size = sizeof(struct sun6i_isp_buffer);
queue->ops = &sun6i_isp_params_queue_ops;
queue->mem_ops = &vb2_vmalloc_memops;
- queue->min_buffers_needed = 1;
+ queue->min_queued_buffers = 1;
queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
queue->lock = &params->lock;
queue->dev = isp_dev->dev;
diff --git a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c
index ccbb530aa2e2..46a334b602f1 100644
--- a/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c
+++ b/drivers/staging/media/sunxi/sun6i-isp/sun6i_isp_proc.c
@@ -256,13 +256,13 @@ sun6i_isp_proc_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format)
mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
}
-static int sun6i_isp_proc_init_cfg(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *state)
+static int sun6i_isp_proc_init_state(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state)
{
struct sun6i_isp_device *isp_dev = v4l2_get_subdevdata(subdev);
unsigned int pad = SUN6I_ISP_PROC_PAD_SINK_CSI;
struct v4l2_mbus_framefmt *mbus_format =
- v4l2_subdev_get_try_format(subdev, state, pad);
+ v4l2_subdev_state_get_format(state, pad);
struct mutex *lock = &isp_dev->proc.lock;
mutex_lock(lock);
@@ -302,8 +302,8 @@ static int sun6i_isp_proc_get_fmt(struct v4l2_subdev *subdev,
mutex_lock(lock);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *mbus_format = *v4l2_subdev_get_try_format(subdev, state,
- format->pad);
+ *mbus_format = *v4l2_subdev_state_get_format(state,
+ format->pad);
else
*mbus_format = isp_dev->proc.mbus_format;
@@ -325,7 +325,7 @@ static int sun6i_isp_proc_set_fmt(struct v4l2_subdev *subdev,
sun6i_isp_proc_mbus_format_prepare(mbus_format);
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
- *v4l2_subdev_get_try_format(subdev, state, format->pad) =
+ *v4l2_subdev_state_get_format(state, format->pad) =
*mbus_format;
else
isp_dev->proc.mbus_format = *mbus_format;
@@ -336,7 +336,6 @@ static int sun6i_isp_proc_set_fmt(struct v4l2_subdev *subdev,
}
static const struct v4l2_subdev_pad_ops sun6i_isp_proc_pad_ops = {
- .init_cfg = sun6i_isp_proc_init_cfg,
.enum_mbus_code = sun6i_isp_proc_enum_mbus_code,
.get_fmt = sun6i_isp_proc_get_fmt,
.set_fmt = sun6i_isp_proc_set_fmt,
@@ -347,6 +346,10 @@ static const struct v4l2_subdev_ops sun6i_isp_proc_subdev_ops = {
.pad = &sun6i_isp_proc_pad_ops,
};
+static const struct v4l2_subdev_internal_ops sun6i_isp_proc_internal_ops = {
+ .init_state = sun6i_isp_proc_init_state,
+};
+
/* Media Entity */
static const struct media_entity_operations sun6i_isp_proc_entity_ops = {
@@ -501,6 +504,7 @@ int sun6i_isp_proc_setup(struct sun6i_isp_device *isp_dev)
/* V4L2 Subdev */
v4l2_subdev_init(subdev, &sun6i_isp_proc_subdev_ops);
+ subdev->internal_ops = &sun6i_isp_proc_internal_ops;
strscpy(subdev->name, SUN6I_ISP_PROC_NAME, sizeof(subdev->name));
subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
subdev->owner = THIS_MODULE;
diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 9aa72863c213..255cccd0c5fd 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -222,14 +222,22 @@ static int csi_set_format(struct v4l2_subdev *subdev,
/*
* V4L2 Subdevice Video Operations
*/
-static int tegra_csi_g_frame_interval(struct v4l2_subdev *subdev,
- struct v4l2_subdev_frame_interval *vfi)
+static int tegra_csi_get_frame_interval(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *vfi)
{
struct tegra_csi_channel *csi_chan = to_csi_chan(subdev);
if (!IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
return -ENOIOCTLCMD;
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (vfi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
vfi->interval.numerator = 1;
vfi->interval.denominator = csi_chan->framerate;
@@ -430,8 +438,6 @@ static int tegra_csi_s_stream(struct v4l2_subdev *subdev, int enable)
*/
static const struct v4l2_subdev_video_ops tegra_csi_video_ops = {
.s_stream = tegra_csi_s_stream,
- .g_frame_interval = tegra_csi_g_frame_interval,
- .s_frame_interval = tegra_csi_g_frame_interval,
};
static const struct v4l2_subdev_pad_ops tegra_csi_pad_ops = {
@@ -440,6 +446,8 @@ static const struct v4l2_subdev_pad_ops tegra_csi_pad_ops = {
.enum_frame_interval = csi_enum_frameintervals,
.get_fmt = csi_get_format,
.set_fmt = csi_set_format,
+ .get_frame_interval = tegra_csi_get_frame_interval,
+ .set_frame_interval = tegra_csi_get_frame_interval,
};
static const struct v4l2_subdev_ops tegra_csi_ops = {
@@ -818,15 +826,13 @@ rpm_disable:
return ret;
}
-static int tegra_csi_remove(struct platform_device *pdev)
+static void tegra_csi_remove(struct platform_device *pdev)
{
struct tegra_csi *csi = platform_get_drvdata(pdev);
host1x_client_unregister(&csi->client);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
#if defined(CONFIG_ARCH_TEGRA_210_SOC)
@@ -852,5 +858,5 @@ struct platform_driver tegra_csi_driver = {
.pm = &tegra_csi_pm_ops,
},
.probe = tegra_csi_probe,
- .remove = tegra_csi_remove,
+ .remove_new = tegra_csi_remove,
};
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index 94171e62dee9..af6e3a0d8df4 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -439,6 +439,7 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
.target = V4L2_SEL_TGT_CROP_BOUNDS,
};
+ struct v4l2_rect *try_crop;
int ret;
subdev = tegra_channel_get_remote_source_subdev(chan);
@@ -473,24 +474,25 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
* Attempt to obtain the format size from subdev.
* If not available, try to get crop boundary from subdev.
*/
+ try_crop = v4l2_subdev_state_get_crop(sd_state, 0);
fse.code = fmtinfo->code;
ret = v4l2_subdev_call(subdev, pad, enum_frame_size, sd_state, &fse);
if (ret) {
if (!v4l2_subdev_has_op(subdev, pad, get_selection)) {
- sd_state->pads->try_crop.width = 0;
- sd_state->pads->try_crop.height = 0;
+ try_crop->width = 0;
+ try_crop->height = 0;
} else {
ret = v4l2_subdev_call(subdev, pad, get_selection,
NULL, &sdsel);
if (ret)
return -EINVAL;
- sd_state->pads->try_crop.width = sdsel.r.width;
- sd_state->pads->try_crop.height = sdsel.r.height;
+ try_crop->width = sdsel.r.width;
+ try_crop->height = sdsel.r.height;
}
} else {
- sd_state->pads->try_crop.width = fse.max_width;
- sd_state->pads->try_crop.height = fse.max_height;
+ try_crop->width = fse.max_width;
+ try_crop->height = fse.max_height;
}
ret = v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &fmt);
@@ -1172,7 +1174,7 @@ static int tegra_channel_init(struct tegra_vi_channel *chan)
chan->queue.ops = &tegra_channel_queue_qops;
chan->queue.mem_ops = &vb2_dma_contig_memops;
chan->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- chan->queue.min_buffers_needed = 2;
+ chan->queue.min_queued_buffers = 2;
chan->queue.dev = vi->dev;
ret = vb2_queue_init(&chan->queue);
if (ret < 0) {
@@ -1944,7 +1946,7 @@ rpm_disable:
return ret;
}
-static int tegra_vi_remove(struct platform_device *pdev)
+static void tegra_vi_remove(struct platform_device *pdev)
{
struct tegra_vi *vi = platform_get_drvdata(pdev);
@@ -1953,8 +1955,6 @@ static int tegra_vi_remove(struct platform_device *pdev)
if (vi->ops->vi_enable)
vi->ops->vi_enable(vi, false);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static const struct of_device_id tegra_vi_of_id_table[] = {
@@ -1979,5 +1979,5 @@ struct platform_driver tegra_vi_driver = {
.pm = &tegra_vi_pm_ops,
},
.probe = tegra_vi_probe,
- .remove = tegra_vi_remove,
+ .remove_new = tegra_vi_remove,
};
diff --git a/drivers/staging/media/tegra-video/vip.c b/drivers/staging/media/tegra-video/vip.c
index e95cc7bb190e..8504b9ea9cea 100644
--- a/drivers/staging/media/tegra-video/vip.c
+++ b/drivers/staging/media/tegra-video/vip.c
@@ -254,15 +254,13 @@ static int tegra_vip_probe(struct platform_device *pdev)
return 0;
}
-static int tegra_vip_remove(struct platform_device *pdev)
+static void tegra_vip_remove(struct platform_device *pdev)
{
struct tegra_vip *vip = platform_get_drvdata(pdev);
host1x_client_unregister(&vip->client);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
@@ -283,5 +281,5 @@ struct platform_driver tegra_vip_driver = {
.of_match_table = tegra_vip_of_id_table,
},
.probe = tegra_vip_probe,
- .remove = tegra_vip_remove,
+ .remove_new = tegra_vip_remove,
};
diff --git a/drivers/staging/rtl8192e/Makefile b/drivers/staging/rtl8192e/Makefile
index 6af519938868..a1492215dab1 100644
--- a/drivers/staging/rtl8192e/Makefile
+++ b/drivers/staging/rtl8192e/Makefile
@@ -1,6 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
rtllib-objs := \
- dot11d.o \
rtllib_module.o \
rtllib_rx.o \
rtllib_tx.o \
diff --git a/drivers/staging/rtl8192e/dot11d.c b/drivers/staging/rtl8192e/dot11d.c
deleted file mode 100644
index d0b7332645be..000000000000
--- a/drivers/staging/rtl8192e/dot11d.c
+++ /dev/null
@@ -1,165 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/******************************************************************************
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information:
- * wlanfae <[email protected]>
- ******************************************************************************/
-#include "dot11d.h"
-
-struct channel_list {
- u8 channel[32];
- u8 len;
-};
-
-static struct channel_list channel_array[] = {
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64,
- 149, 153, 157, 161, 165}, 24},
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11},
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56,
- 60, 64}, 21},
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52,
- 56, 60, 64}, 22},
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52,
- 56, 60, 64}, 22},
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52,
- 56, 60, 64}, 22},
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52,
- 56, 60, 64}, 22},
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14},
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},
- {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52,
- 56, 60, 64}, 21}
-};
-
-void dot11d_init(struct rtllib_device *ieee)
-{
- struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee);
-
- dot11d_info->enabled = false;
-
- dot11d_info->state = DOT11D_STATE_NONE;
- dot11d_info->country_len = 0;
- memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
- memset(dot11d_info->max_tx_power_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
- RESET_CIE_WATCHDOG(ieee);
-}
-EXPORT_SYMBOL(dot11d_init);
-
-void dot11d_channel_map(u8 channel_plan, struct rtllib_device *ieee)
-{
- int i, max_chan = 14, min_chan = 1;
-
- ieee->global_domain = false;
-
- if (channel_array[channel_plan].len != 0) {
- memset(GET_DOT11D_INFO(ieee)->channel_map, 0,
- sizeof(GET_DOT11D_INFO(ieee)->channel_map));
- for (i = 0; i < channel_array[channel_plan].len; i++) {
- if (channel_array[channel_plan].channel[i] < min_chan ||
- channel_array[channel_plan].channel[i] > max_chan)
- break;
- GET_DOT11D_INFO(ieee)->channel_map[channel_array
- [channel_plan].channel[i]] = 1;
- }
- }
-
- switch (channel_plan) {
- case COUNTRY_CODE_GLOBAL_DOMAIN:
- ieee->global_domain = true;
- for (i = 12; i <= 14; i++)
- GET_DOT11D_INFO(ieee)->channel_map[i] = 2;
- ieee->bss_start_channel = 10;
- break;
-
- case COUNTRY_CODE_WORLD_WIDE_13:
- for (i = 12; i <= 13; i++)
- GET_DOT11D_INFO(ieee)->channel_map[i] = 2;
- ieee->bss_start_channel = 10;
- break;
-
- default:
- ieee->bss_start_channel = 1;
- break;
- }
-}
-EXPORT_SYMBOL(dot11d_channel_map);
-
-void dot11d_reset(struct rtllib_device *ieee)
-{
- struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(ieee);
- u32 i;
-
- memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
- memset(dot11d_info->max_tx_power_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
- for (i = 1; i <= 11; i++)
- (dot11d_info->channel_map)[i] = 1;
- for (i = 12; i <= 14; i++)
- (dot11d_info->channel_map)[i] = 2;
- dot11d_info->state = DOT11D_STATE_NONE;
- dot11d_info->country_len = 0;
- RESET_CIE_WATCHDOG(ieee);
-}
-
-void dot11d_update_country(struct rtllib_device *dev, u8 *address,
- u16 country_len, u8 *country)
-{
- struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
- u8 i, j, number_of_triples, max_channel_number;
- struct chnl_txpow_triple *triple;
-
- memset(dot11d_info->channel_map, 0, MAX_CHANNEL_NUMBER + 1);
- memset(dot11d_info->max_tx_power_list, 0xFF, MAX_CHANNEL_NUMBER + 1);
- max_channel_number = 0;
- number_of_triples = (country_len - 3) / 3;
- triple = (struct chnl_txpow_triple *)(country + 3);
- for (i = 0; i < number_of_triples; i++) {
- if (max_channel_number >= triple->first_channel) {
- netdev_info(dev->dev,
- "%s: Invalid country IE, skip it......1\n",
- __func__);
- return;
- }
- if (MAX_CHANNEL_NUMBER < (triple->first_channel +
- triple->num_channels)) {
- netdev_info(dev->dev,
- "%s: Invalid country IE, skip it......2\n",
- __func__);
- return;
- }
-
- for (j = 0; j < triple->num_channels; j++) {
- dot11d_info->channel_map[triple->first_channel + j] = 1;
- dot11d_info->max_tx_power_list[triple->first_channel + j] =
- triple->max_tx_power;
- max_channel_number = triple->first_channel + j;
- }
-
- triple = (struct chnl_txpow_triple *)((u8 *)triple + 3);
- }
-
- UPDATE_CIE_SRC(dev, address);
-
- dot11d_info->country_len = country_len;
- memcpy(dot11d_info->country_buffer, country, country_len);
- dot11d_info->state = DOT11D_STATE_LEARNED;
-}
-
-void dot11d_scan_complete(struct rtllib_device *dev)
-{
- struct rt_dot11d_info *dot11d_info = GET_DOT11D_INFO(dev);
-
- switch (dot11d_info->state) {
- case DOT11D_STATE_LEARNED:
- dot11d_info->state = DOT11D_STATE_DONE;
- break;
- case DOT11D_STATE_DONE:
- dot11d_reset(dev);
- break;
- case DOT11D_STATE_NONE:
- break;
- }
-}
diff --git a/drivers/staging/rtl8192e/dot11d.h b/drivers/staging/rtl8192e/dot11d.h
deleted file mode 100644
index 6d2b93acfa43..000000000000
--- a/drivers/staging/rtl8192e/dot11d.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/******************************************************************************
- * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
- *
- * Contact Information:
- * wlanfae <[email protected]>
- ******************************************************************************/
-#ifndef __INC_DOT11D_H
-#define __INC_DOT11D_H
-
-#include "rtllib.h"
-
-struct chnl_txpow_triple {
- u8 first_channel;
- u8 num_channels;
- u8 max_tx_power;
-};
-
-enum dot11d_state {
- DOT11D_STATE_NONE = 0,
- DOT11D_STATE_LEARNED,
- DOT11D_STATE_DONE,
-};
-
-/**
- * struct rt_dot11d_info * @country_len: value greater than 0 if
- * @country_buffer contains valid country information element.
- * @channel_map: holds channel values
- * 0 - invalid,
- * 1 - valid (active scan),
- * 2 - valid (passive scan)
- * @country_src_addr - Source AP of the country IE
- */
-
-struct rt_dot11d_info {
- bool enabled;
-
- u16 country_len;
- u8 country_buffer[MAX_IE_LEN];
- u8 country_src_addr[6];
- u8 country_watchdog;
-
- u8 channel_map[MAX_CHANNEL_NUMBER + 1];
- u8 max_tx_power_list[MAX_CHANNEL_NUMBER + 1];
-
- enum dot11d_state state;
-};
-
-static inline void copy_mac_addr(unsigned char *des, unsigned char *src)
-{
- memcpy(des, src, 6);
-}
-
-#define GET_DOT11D_INFO(__ieee_dev) \
- ((struct rt_dot11d_info *)((__ieee_dev)->dot11d_info))
-
-#define IS_DOT11D_ENABLE(__ieee_dev) \
- (GET_DOT11D_INFO(__ieee_dev)->enabled)
-#define IS_COUNTRY_IE_VALID(__ieee_dev) \
- (GET_DOT11D_INFO(__ieee_dev)->country_len > 0)
-
-#define IS_EQUAL_CIE_SRC(__ieee_dev, __address) \
- ether_addr_equal_unaligned( \
- GET_DOT11D_INFO(__ieee_dev)->country_src_addr, __address)
-#define UPDATE_CIE_SRC(__ieee_dev, __address) \
- copy_mac_addr(GET_DOT11D_INFO(__ieee_dev)->country_src_addr, __address)
-
-#define GET_CIE_WATCHDOG(__ieee_dev) \
- (GET_DOT11D_INFO(__ieee_dev)->country_watchdog)
-static inline void RESET_CIE_WATCHDOG(struct rtllib_device *__ieee_dev)
-{
- GET_CIE_WATCHDOG(__ieee_dev) = 0;
-}
-
-#define UPDATE_CIE_WATCHDOG(__ieee_dev) (++GET_CIE_WATCHDOG(__ieee_dev))
-
-void dot11d_init(struct rtllib_device *dev);
-void dot11d_channel_map(u8 channel_plan, struct rtllib_device *ieee);
-void dot11d_reset(struct rtllib_device *dev);
-void dot11d_update_country(struct rtllib_device *dev, u8 *address,
- u16 country_len, u8 *country);
-void dot11d_scan_complete(struct rtllib_device *dev);
-
-#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
index eba8364d0ff2..7f0c160bc741 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
@@ -63,9 +63,9 @@ bool rtl92e_send_cmd_pkt(struct net_device *dev, u32 type, const void *data,
if (type == DESC_PACKET_TYPE_INIT &&
(!priv->rtllib->check_nic_enough_desc(dev, TXCMD_QUEUE) ||
- (!skb_queue_empty(&priv->rtllib->skb_waitQ[TXCMD_QUEUE])) ||
+ (!skb_queue_empty(&priv->rtllib->skb_waitq[TXCMD_QUEUE])) ||
(priv->rtllib->queue_stop))) {
- skb_queue_tail(&priv->rtllib->skb_waitQ[TXCMD_QUEUE],
+ skb_queue_tail(&priv->rtllib->skb_waitq[TXCMD_QUEUE],
skb);
} else {
priv->rtllib->softmac_hard_start_xmit(skb, dev);
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
index e93394c51264..c7a2eae2fdb9 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
@@ -51,12 +51,12 @@ void rtl92e_set_reg(struct net_device *dev, u8 variable, u8 *val)
case HW_VAR_MEDIA_STATUS:
{
- enum rt_op_mode OpMode = *((enum rt_op_mode *)(val));
+ enum rt_op_mode op_mode = *((enum rt_op_mode *)(val));
u8 btMsr = rtl92e_readb(dev, MSR);
btMsr &= 0xfc;
- switch (OpMode) {
+ switch (op_mode) {
case RT_OP_MODE_INFRASTRUCTURE:
btMsr |= MSR_INFRA;
break;
@@ -261,7 +261,6 @@ static void _rtl92e_read_eeprom_info(struct net_device *dev)
priv->eeprom_customer_id = usValue & 0xff;
usValue = rtl92e_eeprom_read(dev,
EEPROM_ICVersion_ChannelPlan >> 1);
- priv->eeprom_chnl_plan = usValue & 0xff;
IC_Version = (usValue & 0xff00) >> 8;
ICVer8192 = IC_Version & 0xf;
@@ -283,7 +282,6 @@ static void _rtl92e_read_eeprom_info(struct net_device *dev)
priv->eeprom_vid = 0;
priv->eeprom_did = 0;
priv->eeprom_customer_id = 0;
- priv->eeprom_chnl_plan = 0;
}
if (!priv->autoload_fail_flag) {
@@ -387,25 +385,15 @@ static void _rtl92e_read_eeprom_info(struct net_device *dev)
rtl92e_init_adaptive_rate(dev);
- priv->chnl_plan = priv->eeprom_chnl_plan;
-
switch (priv->eeprom_customer_id) {
case EEPROM_CID_NetCore:
priv->customer_id = RT_CID_819X_NETCORE;
break;
case EEPROM_CID_TOSHIBA:
priv->customer_id = RT_CID_TOSHIBA;
- if (priv->eeprom_chnl_plan & 0x80)
- priv->chnl_plan = priv->eeprom_chnl_plan & 0x7f;
- else
- priv->chnl_plan = 0x0;
break;
}
- if (priv->chnl_plan > CHANNEL_PLAN_LEN - 1)
- priv->chnl_plan = 0;
- priv->chnl_plan = COUNTRY_CODE_WORLD_WIDE_13;
-
if (priv->eeprom_vid == 0x1186 && priv->eeprom_did == 0x3304)
priv->rtllib->bSupportRemoteWakeUp = true;
else
@@ -891,11 +879,11 @@ void rtl92e_fill_tx_desc(struct net_device *dev, struct tx_desc *pdesc,
memset(pTxFwInfo, 0, sizeof(struct tx_fwinfo_8190pci));
pTxFwInfo->TxHT = (cb_desc->data_rate & 0x80) ? 1 : 0;
pTxFwInfo->TxRate = _rtl92e_rate_mgn_to_hw(cb_desc->data_rate);
- pTxFwInfo->EnableCPUDur = cb_desc->bTxEnableFwCalcDur;
+ pTxFwInfo->EnableCPUDur = cb_desc->tx_enable_fw_calc_dur;
pTxFwInfo->Short = _rtl92e_query_is_short(pTxFwInfo->TxHT,
pTxFwInfo->TxRate, cb_desc);
- if (cb_desc->bAMPDUEnable) {
+ if (cb_desc->ampdu_enable) {
pTxFwInfo->AllowAggregation = 1;
pTxFwInfo->RxMF = cb_desc->ampdu_factor;
pTxFwInfo->RxAMD = cb_desc->ampdu_density;
@@ -1685,8 +1673,6 @@ bool rtl92e_get_rx_stats(struct net_device *dev, struct rtllib_rx_stats *stats,
stats->TimeStampLow = pDrvInfo->TSFL;
stats->TimeStampHigh = rtl92e_readl(dev, TSFR + 4);
- rtl92e_update_rx_pkt_timestamp(dev, stats);
-
if ((stats->RxBufShift + stats->RxDrvInfoSize) > 0)
stats->bShift = 1;
@@ -1707,12 +1693,12 @@ void rtl92e_stop_adapter(struct net_device *dev, bool reset)
{
struct r8192_priv *priv = rtllib_priv(dev);
int i;
- u8 OpMode;
+ u8 op_mode;
u8 u1bTmp;
u32 ulRegRead;
- OpMode = RT_OP_MODE_NO_LINK;
- priv->rtllib->SetHwRegHandler(dev, HW_VAR_MEDIA_STATUS, &OpMode);
+ op_mode = RT_OP_MODE_NO_LINK;
+ priv->rtllib->SetHwRegHandler(dev, HW_VAR_MEDIA_STATUS, &op_mode);
if (!priv->rtllib->bSupportRemoteWakeUp) {
u1bTmp = 0x0;
@@ -1742,7 +1728,7 @@ void rtl92e_stop_adapter(struct net_device *dev, bool reset)
}
for (i = 0; i < MAX_QUEUE_SIZE; i++)
- skb_queue_purge(&priv->rtllib->skb_waitQ[i]);
+ skb_queue_purge(&priv->rtllib->skb_waitq[i]);
skb_queue_purge(&priv->skb_queue);
}
@@ -1767,20 +1753,17 @@ void rtl92e_update_ratr_table(struct net_device *dev)
ratr_value &= 0x00000FF7;
break;
case WIRELESS_MODE_N_24G:
- if (ieee->ht_info->peer_mimo_ps == 0)
- ratr_value &= 0x0007F007;
- else
- ratr_value &= 0x000FF007;
+ ratr_value &= 0x000FF007;
break;
default:
break;
}
ratr_value &= 0x0FFFFFFF;
if (ieee->ht_info->cur_tx_bw40mhz &&
- ieee->ht_info->bCurShortGI40MHz)
+ ieee->ht_info->cur_short_gi_40mhz)
ratr_value |= 0x80000000;
else if (!ieee->ht_info->cur_tx_bw40mhz &&
- ieee->ht_info->bCurShortGI20MHz)
+ ieee->ht_info->cur_short_gi_20mhz)
ratr_value |= 0x80000000;
rtl92e_writel(dev, RATR0 + rate_index * 4, ratr_value);
rtl92e_writeb(dev, UFWP, 1);
@@ -1814,7 +1797,7 @@ rtl92e_init_variables(struct net_device *dev)
IMR_MGNTDOK | IMR_COMDOK | IMR_HIGHDOK |
IMR_BDOK | IMR_RXCMDOK | IMR_TIMEOUT0 |
IMR_RDU | IMR_RXFOVW | IMR_TXFOVW |
- IMR_BcnInt | IMR_TBDOK | IMR_TBDER);
+ IMR_TBDOK | IMR_TBDER);
priv->bfirst_after_down = false;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
index 4d12d7385041..e1bd4d67e862 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
@@ -671,16 +671,16 @@ static void _rtl92e_phy_switch_channel_work_item(struct net_device *dev)
_rtl92e_phy_switch_channel(dev, priv->chan);
}
-u8 rtl92e_set_channel(struct net_device *dev, u8 channel)
+void rtl92e_set_channel(struct net_device *dev, u8 channel)
{
struct r8192_priv *priv = rtllib_priv(dev);
if (!priv->up) {
netdev_err(dev, "%s(): Driver is not initialized\n", __func__);
- return false;
+ return;
}
if (priv->sw_chnl_in_progress)
- return false;
+ return;
switch (priv->rtllib->mode) {
case WIRELESS_MODE_B:
@@ -688,7 +688,7 @@ u8 rtl92e_set_channel(struct net_device *dev, u8 channel)
netdev_warn(dev,
"Channel %d not available in 802.11b.\n",
channel);
- return false;
+ return;
}
break;
case WIRELESS_MODE_G:
@@ -697,7 +697,7 @@ u8 rtl92e_set_channel(struct net_device *dev, u8 channel)
netdev_warn(dev,
"Channel %d not available in 802.11g.\n",
channel);
- return false;
+ return;
}
break;
}
@@ -714,7 +714,7 @@ u8 rtl92e_set_channel(struct net_device *dev, u8 channel)
if (priv->up)
_rtl92e_phy_switch_channel_work_item(dev);
priv->sw_chnl_in_progress = false;
- return true;
+ return;
}
static void _rtl92e_cck_tx_power_track_bw_switch_tssi(struct net_device *dev)
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h
index 6c4c33ded6a9..ff4b4004b0d0 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.h
@@ -41,7 +41,7 @@ void rtl92e_get_tx_power(struct net_device *dev);
void rtl92e_set_tx_power(struct net_device *dev, u8 channel);
u8 rtl92e_config_rf_path(struct net_device *dev, enum rf90_radio_path eRFPath);
-u8 rtl92e_set_channel(struct net_device *dev, u8 channel);
+void rtl92e_set_channel(struct net_device *dev, u8 channel);
void rtl92e_set_bw_mode(struct net_device *dev,
enum ht_channel_width bandwidth,
enum ht_extchnl_offset Offset);
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
index 995daab906c9..6815d18a7919 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
@@ -226,16 +226,6 @@ static void _rtl92e_tx_timeout(struct net_device *dev, unsigned int txqueue)
netdev_info(dev, "TXTIMEOUT");
}
-static void _rtl92e_set_chan(struct net_device *dev, short ch)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- priv->chan = ch;
-
- if (priv->rf_set_chan)
- priv->rf_set_chan(dev, priv->chan);
-}
-
static void _rtl92e_update_cap(struct net_device *dev, u16 cap)
{
struct r8192_priv *priv = rtllib_priv(dev);
@@ -297,7 +287,6 @@ static void _rtl92e_update_beacon(void *data)
if (ieee->ht_info->current_ht_support)
HT_update_self_and_peer_setting(ieee, net);
ieee->ht_info->current_rt2rt_long_slot_time = net->bssht.bd_rt2rt_long_slot_time;
- ieee->ht_info->RT2RT_HT_Mode = net->bssht.rt2rt_ht_mode;
_rtl92e_update_cap(dev, net->capability);
}
@@ -426,38 +415,6 @@ static int _rtl92e_handle_assoc_response(struct net_device *dev,
return 0;
}
-static void _rtl92e_prepare_beacon(struct tasklet_struct *t)
-{
- struct r8192_priv *priv = from_tasklet(priv, t,
- irq_prepare_beacon_tasklet);
- struct net_device *dev = priv->rtllib->dev;
- struct sk_buff *pskb = NULL, *pnewskb = NULL;
- struct cb_desc *tcb_desc = NULL;
- struct rtl8192_tx_ring *ring = NULL;
- struct tx_desc *pdesc = NULL;
-
- ring = &priv->tx_ring[BEACON_QUEUE];
- pskb = __skb_dequeue(&ring->queue);
- kfree_skb(pskb);
-
- pnewskb = rtllib_get_beacon(priv->rtllib);
- if (!pnewskb)
- return;
-
- tcb_desc = (struct cb_desc *)(pnewskb->cb + 8);
- tcb_desc->queue_index = BEACON_QUEUE;
- tcb_desc->data_rate = 2;
- tcb_desc->ratr_index = 7;
- tcb_desc->tx_dis_rate_fallback = 1;
- tcb_desc->tx_use_drv_assinged_rate = 1;
- skb_push(pnewskb, priv->rtllib->tx_headroom);
-
- pdesc = &ring->desc[0];
- rtl92e_fill_tx_desc(dev, pdesc, tcb_desc, pnewskb);
- __skb_queue_tail(&ring->queue, pnewskb);
- pdesc->OWN = 1;
-}
-
void rtl92e_config_rate(struct net_device *dev, u16 *rate_config)
{
struct r8192_priv *priv = rtllib_priv(dev);
@@ -685,7 +642,7 @@ static void _rtl92e_init_priv_handler(struct net_device *dev)
struct r8192_priv *priv = rtllib_priv(dev);
priv->rtllib->softmac_hard_start_xmit = _rtl92e_hard_start_xmit;
- priv->rtllib->set_chan = _rtl92e_set_chan;
+ priv->rtllib->set_chan = rtl92e_set_channel;
priv->rtllib->link_change = rtl92e_link_change;
priv->rtllib->softmac_data_hard_start_xmit = _rtl92e_hard_data_xmit;
priv->rtllib->check_nic_enough_desc = _rtl92e_check_nic_enough_desc;
@@ -694,7 +651,6 @@ static void _rtl92e_init_priv_handler(struct net_device *dev)
priv->rtllib->set_wireless_mode = rtl92e_set_wireless_mode;
priv->rtllib->leisure_ps_leave = rtl92e_leisure_ps_leave;
priv->rtllib->set_bw_mode_handler = rtl92e_set_bw_mode;
- priv->rf_set_chan = rtl92e_set_channel;
priv->rtllib->sta_wake_up = rtl92e_hw_wakeup;
priv->rtllib->enter_sleep_state = rtl92e_enter_sleep;
@@ -767,7 +723,7 @@ static void _rtl92e_init_priv_variable(struct net_device *dev)
skb_queue_head_init(&priv->skb_queue);
for (i = 0; i < MAX_QUEUE_SIZE; i++)
- skb_queue_head_init(&priv->rtllib->skb_waitQ[i]);
+ skb_queue_head_init(&priv->rtllib->skb_waitq[i]);
}
static void _rtl92e_init_priv_lock(struct r8192_priv *priv)
@@ -796,8 +752,6 @@ static void _rtl92e_init_priv_task(struct net_device *dev)
INIT_DELAYED_WORK(&priv->rtllib->hw_sleep_wq, (void *)rtl92e_hw_sleep_wq);
tasklet_setup(&priv->irq_rx_tasklet, _rtl92e_irq_rx_tasklet);
tasklet_setup(&priv->irq_tx_tasklet, _rtl92e_irq_tx_tasklet);
- tasklet_setup(&priv->irq_prepare_beacon_tasklet,
- _rtl92e_prepare_beacon);
}
static short _rtl92e_get_channel_map(struct net_device *dev)
@@ -806,13 +760,6 @@ static short _rtl92e_get_channel_map(struct net_device *dev)
struct r8192_priv *priv = rtllib_priv(dev);
- if (priv->chnl_plan >= COUNTRY_CODE_MAX) {
- netdev_info(dev,
- "rtl819x_init:Error channel plan! Set to default.\n");
- priv->chnl_plan = COUNTRY_CODE_FCC;
- }
- dot11d_init(priv->rtllib);
- dot11d_channel_map(priv->chnl_plan, priv->rtllib);
for (i = 1; i <= 11; i++)
(priv->rtllib->active_channel_map)[i] = 1;
(priv->rtllib->active_channel_map)[12] = 2;
@@ -1024,21 +971,21 @@ static void _rtl92e_watchdog_wq_cb(void *data)
}
}
if ((ieee->link_state == MAC80211_LINKED) && (ieee->iw_mode == IW_MODE_INFRA)) {
- if (ieee->link_detect_info.NumRxOkInPeriod > 100 ||
- ieee->link_detect_info.NumTxOkInPeriod > 100)
+ if (ieee->link_detect_info.num_rx_ok_in_period > 100 ||
+ ieee->link_detect_info.num_tx_ok_in_period > 100)
bBusyTraffic = true;
- if (ieee->link_detect_info.NumRxOkInPeriod > 4000 ||
- ieee->link_detect_info.NumTxOkInPeriod > 4000) {
+ if (ieee->link_detect_info.num_rx_ok_in_period > 4000 ||
+ ieee->link_detect_info.num_tx_ok_in_period > 4000) {
bHigherBusyTraffic = true;
- if (ieee->link_detect_info.NumRxOkInPeriod > 5000)
+ if (ieee->link_detect_info.num_rx_ok_in_period > 5000)
bHigherBusyRxTraffic = true;
else
bHigherBusyRxTraffic = false;
}
if (((ieee->link_detect_info.NumRxUnicastOkInPeriod +
- ieee->link_detect_info.NumTxOkInPeriod) > 8) ||
+ ieee->link_detect_info.num_tx_ok_in_period) > 8) ||
(ieee->link_detect_info.NumRxUnicastOkInPeriod > 2))
bEnterPS = false;
else
@@ -1056,8 +1003,8 @@ static void _rtl92e_watchdog_wq_cb(void *data)
rtl92e_leisure_ps_leave(dev);
}
- ieee->link_detect_info.NumRxOkInPeriod = 0;
- ieee->link_detect_info.NumTxOkInPeriod = 0;
+ ieee->link_detect_info.num_rx_ok_in_period = 0;
+ ieee->link_detect_info.num_tx_ok_in_period = 0;
ieee->link_detect_info.NumRxUnicastOkInPeriod = 0;
ieee->link_detect_info.bBusyTraffic = bBusyTraffic;
@@ -1240,7 +1187,7 @@ static int _rtl92e_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
tcb_desc->ratr_index = 7;
tcb_desc->tx_dis_rate_fallback = 1;
tcb_desc->tx_use_drv_assinged_rate = 1;
- tcb_desc->bTxEnableFwCalcDur = 1;
+ tcb_desc->tx_enable_fw_calc_dur = 1;
skb_push(skb, priv->rtllib->tx_headroom);
ret = _rtl92e_tx(dev, skb);
if (ret != 0)
@@ -1484,17 +1431,6 @@ void rtl92e_reset_desc_ring(struct net_device *dev)
spin_unlock_irqrestore(&priv->irq_th_lock, flags);
}
-void rtl92e_update_rx_pkt_timestamp(struct net_device *dev,
- struct rtllib_rx_stats *stats)
-{
- struct r8192_priv *priv = rtllib_priv(dev);
-
- if (stats->bIsAMPDU && !stats->bFirstMPDU)
- stats->mac_time = priv->last_rx_desc_tsf;
- else
- priv->last_rx_desc_tsf = stats->mac_time;
-}
-
long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index)
{
long signal_power;
@@ -1638,9 +1574,9 @@ static void _rtl92e_tx_resume(struct net_device *dev)
for (queue_index = BK_QUEUE;
queue_index < MAX_QUEUE_SIZE; queue_index++) {
- while ((!skb_queue_empty(&ieee->skb_waitQ[queue_index])) &&
+ while ((!skb_queue_empty(&ieee->skb_waitq[queue_index])) &&
(priv->rtllib->check_nic_enough_desc(dev, queue_index) > 0)) {
- skb = skb_dequeue(&ieee->skb_waitQ[queue_index]);
+ skb = skb_dequeue(&ieee->skb_waitq[queue_index]);
ieee->softmac_data_hard_start_xmit(skb, dev, 0);
}
}
@@ -1827,9 +1763,6 @@ static irqreturn_t _rtl92e_irq(int irq, void *netdev)
if (inta & IMR_ROK)
tasklet_schedule(&priv->irq_rx_tasklet);
- if (inta & IMR_BcnInt)
- tasklet_schedule(&priv->irq_prepare_beacon_tasklet);
-
if (inta & IMR_RDU) {
rtl92e_writel(dev, INTA_MASK,
rtl92e_readl(dev, INTA_MASK) & ~IMR_RDU);
@@ -1840,22 +1773,22 @@ static irqreturn_t _rtl92e_irq(int irq, void *netdev)
tasklet_schedule(&priv->irq_rx_tasklet);
if (inta & IMR_BKDOK) {
- priv->rtllib->link_detect_info.NumTxOkInPeriod++;
+ priv->rtllib->link_detect_info.num_tx_ok_in_period++;
_rtl92e_tx_isr(dev, BK_QUEUE);
}
if (inta & IMR_BEDOK) {
- priv->rtllib->link_detect_info.NumTxOkInPeriod++;
+ priv->rtllib->link_detect_info.num_tx_ok_in_period++;
_rtl92e_tx_isr(dev, BE_QUEUE);
}
if (inta & IMR_VIDOK) {
- priv->rtllib->link_detect_info.NumTxOkInPeriod++;
+ priv->rtllib->link_detect_info.num_tx_ok_in_period++;
_rtl92e_tx_isr(dev, VI_QUEUE);
}
if (inta & IMR_VODOK) {
- priv->rtllib->link_detect_info.NumTxOkInPeriod++;
+ priv->rtllib->link_detect_info.num_tx_ok_in_period++;
_rtl92e_tx_isr(dev, VO_QUEUE);
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
index a4afbf3e934d..1d6d31292f41 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
@@ -34,8 +34,6 @@
#include "../rtllib.h"
-#include "../dot11d.h"
-
#include "r8192E_firmware.h"
#include "r8192E_hw.h"
@@ -219,7 +217,6 @@ struct r8192_priv {
struct tasklet_struct irq_rx_tasklet;
struct tasklet_struct irq_tx_tasklet;
- struct tasklet_struct irq_prepare_beacon_tasklet;
struct mutex wx_mutex;
struct mutex rf_mutex;
@@ -228,8 +225,6 @@ struct r8192_priv {
struct rt_stats stats;
struct iw_statistics wstats;
- u8 (*rf_set_chan)(struct net_device *dev, u8 ch);
-
struct rx_desc *rx_ring;
struct sk_buff *rx_buf[MAX_RX_COUNT];
dma_addr_t rx_ring_dma;
@@ -237,8 +232,6 @@ struct r8192_priv {
int rxringcount;
u16 rxbuffersize;
- u64 last_rx_desc_tsf;
-
u32 receive_config;
u8 retry_data;
u8 retry_rts;
@@ -286,7 +279,6 @@ struct r8192_priv {
u16 eeprom_vid;
u16 eeprom_did;
u8 eeprom_customer_id;
- u16 eeprom_chnl_plan;
u8 eeprom_tx_pwr_level_cck[14];
u8 eeprom_tx_pwr_level_ofdm24g[14];
@@ -312,7 +304,6 @@ struct r8192_priv {
bool tx_pwr_data_read_from_eeprom;
- u16 chnl_plan;
u8 hw_rf_off_action;
bool rf_change_in_progress;
@@ -396,8 +387,6 @@ void rtl92e_irq_enable(struct net_device *dev);
void rtl92e_config_rate(struct net_device *dev, u16 *rate_config);
void rtl92e_irq_disable(struct net_device *dev);
-void rtl92e_update_rx_pkt_timestamp(struct net_device *dev,
- struct rtllib_rx_stats *stats);
long rtl92e_translate_to_dbm(struct r8192_priv *priv, u8 signal_strength_index);
void rtl92e_update_rx_statistics(struct r8192_priv *priv,
struct rtllib_rx_stats *pprevious_stats);
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
index 330dafd62656..92143c50c149 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
@@ -287,9 +287,9 @@ static void _rtl92e_dm_check_rate_adaptive(struct net_device *dev)
if (priv->rtllib->link_state == MAC80211_LINKED) {
bshort_gi_enabled = (ht_info->cur_tx_bw40mhz &&
- ht_info->bCurShortGI40MHz) ||
+ ht_info->cur_short_gi_40mhz) ||
(!ht_info->cur_tx_bw40mhz &&
- ht_info->bCurShortGI20MHz);
+ ht_info->cur_short_gi_20mhz);
pra->upper_rssi_threshold_ratr =
(pra->upper_rssi_threshold_ratr & (~BIT(31))) |
@@ -1142,7 +1142,7 @@ static void _rtl92e_dm_check_edca_turbo(struct net_device *dev)
if (priv->bis_cur_rdlstate ||
!priv->bcurrent_turbo_EDCA) {
rtl92e_writel(dev, EDCAPARA_BE,
- edca_setting_UL[ht_info->IOTPeer]);
+ edca_setting_UL[ht_info->iot_peer]);
priv->bis_cur_rdlstate = false;
}
} else {
@@ -1150,10 +1150,10 @@ static void _rtl92e_dm_check_edca_turbo(struct net_device *dev)
!priv->bcurrent_turbo_EDCA) {
if (priv->rtllib->mode == WIRELESS_MODE_G)
rtl92e_writel(dev, EDCAPARA_BE,
- edca_setting_DL_GMode[ht_info->IOTPeer]);
+ edca_setting_DL_GMode[ht_info->iot_peer]);
else
rtl92e_writel(dev, EDCAPARA_BE,
- edca_setting_DL[ht_info->IOTPeer]);
+ edca_setting_DL[ht_info->iot_peer]);
priv->bis_cur_rdlstate = true;
}
}
@@ -1164,17 +1164,17 @@ static void _rtl92e_dm_check_edca_turbo(struct net_device *dev)
!priv->bcurrent_turbo_EDCA) {
if (priv->rtllib->mode == WIRELESS_MODE_G)
rtl92e_writel(dev, EDCAPARA_BE,
- edca_setting_DL_GMode[ht_info->IOTPeer]);
+ edca_setting_DL_GMode[ht_info->iot_peer]);
else
rtl92e_writel(dev, EDCAPARA_BE,
- edca_setting_DL[ht_info->IOTPeer]);
+ edca_setting_DL[ht_info->iot_peer]);
priv->bis_cur_rdlstate = true;
}
} else {
if (priv->bis_cur_rdlstate ||
!priv->bcurrent_turbo_EDCA) {
rtl92e_writel(dev, EDCAPARA_BE,
- edca_setting_UL[ht_info->IOTPeer]);
+ edca_setting_UL[ht_info->iot_peer]);
priv->bis_cur_rdlstate = false;
}
}
@@ -1217,7 +1217,7 @@ static void _rtl92e_dm_cts_to_self(struct net_device *dev)
ht_info->iot_action &= ~HT_IOT_ACT_FORCED_CTS2SELF;
return;
}
- if (ht_info->IOTPeer == HT_IOT_PEER_BROADCOM) {
+ if (ht_info->iot_peer == HT_IOT_PEER_BROADCOM) {
curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt;
curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt;
if (curRxOkCnt > 4 * curTxOkCnt)
@@ -1713,7 +1713,7 @@ static void _rtl92e_dm_check_fsync(struct net_device *dev)
static u8 reg_c38_State = RegC38_Default;
if (priv->rtllib->link_state == MAC80211_LINKED &&
- priv->rtllib->ht_info->IOTPeer == HT_IOT_PEER_BROADCOM) {
+ priv->rtllib->ht_info->iot_peer == HT_IOT_PEER_BROADCOM) {
if (priv->rtllib->bfsync_enable == 0) {
switch (priv->rtllib->fsync_state) {
case Default_Fsync:
@@ -1819,7 +1819,7 @@ static void _rtl92e_dm_dynamic_tx_power(struct net_device *dev)
priv->dynamic_tx_low_pwr = false;
return;
}
- if ((priv->rtllib->ht_info->IOTPeer == HT_IOT_PEER_ATHEROS) &&
+ if ((priv->rtllib->ht_info->iot_peer == HT_IOT_PEER_ATHEROS) &&
(priv->rtllib->mode == WIRELESS_MODE_G)) {
txhipower_threshold = TX_POWER_ATHEROAP_THRESH_HIGH;
txlowpower_threshold = TX_POWER_ATHEROAP_THRESH_LOW;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
index 4371ab1239ee..4c884c5277f9 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
@@ -158,28 +158,6 @@ static int _rtl92e_wx_set_mode(struct net_device *dev,
return ret;
}
-struct iw_range_with_scan_capa {
- /* Informative stuff (to choose between different interface) */
- __u32 throughput; /* To give an idea... */
- /* In theory this value should be the maximum benchmarked
- * TCP/IP throughput, because with most of these devices the
- * bit rate is meaningless (overhead an co) to estimate how
- * fast the connection will go and pick the fastest one.
- * I suggest people to play with Netperf or any benchmark...
- */
-
- /* NWID (or domain id) */
- __u32 min_nwid; /* Minimal NWID we are able to set */
- __u32 max_nwid; /* Maximal NWID we are able to set */
-
- /* Old Frequency (backward compat - moved lower ) */
- __u16 old_num_channels;
- __u8 old_num_frequency;
-
- /* Scan capabilities */
- __u8 scan_capa;
-};
-
static int _rtl92e_wx_get_range(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
diff --git a/drivers/staging/rtl8192e/rtl819x_BAProc.c b/drivers/staging/rtl8192e/rtl819x_BAProc.c
index 4af8055d2489..ee9ce392155c 100644
--- a/drivers/staging/rtl8192e/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192e/rtl819x_BAProc.c
@@ -23,35 +23,35 @@ static void deactivate_ba_entry(struct rtllib_device *ieee, struct ba_record *ba
del_timer_sync(&ba->timer);
}
-static u8 tx_ts_delete_ba(struct rtllib_device *ieee, struct tx_ts_record *pTxTs)
+static u8 tx_ts_delete_ba(struct rtllib_device *ieee, struct tx_ts_record *ts)
{
- struct ba_record *admitted_ba = &pTxTs->TxAdmittedBARecord;
- struct ba_record *pending_ba = &pTxTs->TxPendingBARecord;
- u8 bSendDELBA = false;
+ struct ba_record *admitted_ba = &ts->tx_admitted_ba_record;
+ struct ba_record *pending_ba = &ts->tx_pending_ba_record;
+ u8 send_del_ba = false;
if (pending_ba->b_valid) {
deactivate_ba_entry(ieee, pending_ba);
- bSendDELBA = true;
+ send_del_ba = true;
}
if (admitted_ba->b_valid) {
deactivate_ba_entry(ieee, admitted_ba);
- bSendDELBA = true;
+ send_del_ba = true;
}
- return bSendDELBA;
+ return send_del_ba;
}
static u8 rx_ts_delete_ba(struct rtllib_device *ieee, struct rx_ts_record *ts)
{
struct ba_record *ba = &ts->rx_admitted_ba_record;
- u8 bSendDELBA = false;
+ u8 send_del_ba = false;
if (ba->b_valid) {
deactivate_ba_entry(ieee, ba);
- bSendDELBA = true;
+ send_del_ba = true;
}
- return bSendDELBA;
+ return send_del_ba;
}
void rtllib_reset_ba_entry(struct ba_record *ba)
@@ -68,7 +68,7 @@ static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *dst,
u16 status_code, u8 type)
{
struct sk_buff *skb = NULL;
- struct ieee80211_hdr_3addr *BAReq = NULL;
+ struct ieee80211_hdr_3addr *ba_req = NULL;
u8 *tag = NULL;
u16 len = ieee->tx_headroom + 9;
@@ -87,13 +87,13 @@ static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *dst,
skb_reserve(skb, ieee->tx_headroom);
- BAReq = skb_put(skb, sizeof(struct ieee80211_hdr_3addr));
+ ba_req = skb_put(skb, sizeof(struct ieee80211_hdr_3addr));
- ether_addr_copy(BAReq->addr1, dst);
- ether_addr_copy(BAReq->addr2, ieee->dev->dev_addr);
+ ether_addr_copy(ba_req->addr1, dst);
+ ether_addr_copy(ba_req->addr2, ieee->dev->dev_addr);
- ether_addr_copy(BAReq->addr3, ieee->current_network.bssid);
- BAReq->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION);
+ ether_addr_copy(ba_req->addr3, ieee->current_network.bssid);
+ ba_req->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION);
tag = skb_put(skb, 9);
*tag++ = ACT_CAT_BA;
@@ -127,9 +127,9 @@ static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst,
struct ba_record *ba,
enum tr_select TxRxSelect, u16 reason_code)
{
- union delba_param_set DelbaParamSet;
+ union delba_param_set del_ba_param_set;
struct sk_buff *skb = NULL;
- struct ieee80211_hdr_3addr *Delba = NULL;
+ struct ieee80211_hdr_3addr *del_ba = NULL;
u8 *tag = NULL;
u16 len = 6 + ieee->tx_headroom;
@@ -137,10 +137,10 @@ static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst,
netdev_dbg(ieee->dev, "%s(): reason_code(%d) sentd to: %pM\n",
__func__, reason_code, dst);
- memset(&DelbaParamSet, 0, 2);
+ memset(&del_ba_param_set, 0, 2);
- DelbaParamSet.field.initiator = (TxRxSelect == TX_DIR) ? 1 : 0;
- DelbaParamSet.field.tid = ba->ba_param_set.field.tid;
+ del_ba_param_set.field.initiator = (TxRxSelect == TX_DIR) ? 1 : 0;
+ del_ba_param_set.field.tid = ba->ba_param_set.field.tid;
skb = dev_alloc_skb(len + sizeof(struct ieee80211_hdr_3addr));
if (!skb)
@@ -148,19 +148,19 @@ static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst,
skb_reserve(skb, ieee->tx_headroom);
- Delba = skb_put(skb, sizeof(struct ieee80211_hdr_3addr));
+ del_ba = skb_put(skb, sizeof(struct ieee80211_hdr_3addr));
- ether_addr_copy(Delba->addr1, dst);
- ether_addr_copy(Delba->addr2, ieee->dev->dev_addr);
- ether_addr_copy(Delba->addr3, ieee->current_network.bssid);
- Delba->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION);
+ ether_addr_copy(del_ba->addr1, dst);
+ ether_addr_copy(del_ba->addr2, ieee->dev->dev_addr);
+ ether_addr_copy(del_ba->addr3, ieee->current_network.bssid);
+ del_ba->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION);
tag = skb_put(skb, 6);
*tag++ = ACT_CAT_BA;
*tag++ = ACT_DELBA;
- put_unaligned_le16(DelbaParamSet.short_data, tag);
+ put_unaligned_le16(del_ba_param_set.short_data, tag);
tag += 2;
put_unaligned_le16(reason_code, tag);
@@ -215,11 +215,11 @@ int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb)
{
struct ieee80211_hdr_3addr *req = NULL;
u16 rc = 0;
- u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL;
+ u8 *dst = NULL, *dialog_token = NULL, *tag = NULL;
struct ba_record *ba = NULL;
- union ba_param_set *pBaParamSet = NULL;
- u16 *pBaTimeoutVal = NULL;
- union sequence_control *pBaStartSeqCtrl = NULL;
+ union ba_param_set *ba_param_set = NULL;
+ u16 *ba_timeout_value = NULL;
+ union sequence_control *ba_start_seq_ctrl = NULL;
struct rx_ts_record *ts = NULL;
if (skb->len < sizeof(struct ieee80211_hdr_3addr) + 9) {
@@ -238,10 +238,10 @@ int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb)
tag = (u8 *)req;
dst = (u8 *)(&req->addr2[0]);
tag += sizeof(struct ieee80211_hdr_3addr);
- pDialogToken = tag + 2;
- pBaParamSet = (union ba_param_set *)(tag + 3);
- pBaTimeoutVal = (u16 *)(tag + 5);
- pBaStartSeqCtrl = (union sequence_control *)(req + 7);
+ dialog_token = tag + 2;
+ ba_param_set = (union ba_param_set *)(tag + 3);
+ ba_timeout_value = (u16 *)(tag + 5);
+ ba_start_seq_ctrl = (union sequence_control *)(req + 7);
if (!ieee->current_network.qos_data.active ||
!ieee->ht_info->current_ht_support ||
@@ -254,14 +254,14 @@ int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb)
goto OnADDBAReq_Fail;
}
if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst,
- (u8)(pBaParamSet->field.tid), RX_DIR, true)) {
+ (u8)(ba_param_set->field.tid), RX_DIR, true)) {
rc = ADDBA_STATUS_REFUSED;
netdev_warn(ieee->dev, "%s(): can't get TS\n", __func__);
goto OnADDBAReq_Fail;
}
ba = &ts->rx_admitted_ba_record;
- if (pBaParamSet->field.ba_policy == BA_POLICY_DELAYED) {
+ if (ba_param_set->field.ba_policy == BA_POLICY_DELAYED) {
rc = ADDBA_STATUS_INVALID_PARAM;
netdev_warn(ieee->dev, "%s(): BA Policy is not correct\n",
__func__);
@@ -271,10 +271,10 @@ int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb)
rtllib_FlushRxTsPendingPkts(ieee, ts);
deactivate_ba_entry(ieee, ba);
- ba->dialog_token = *pDialogToken;
- ba->ba_param_set = *pBaParamSet;
- ba->ba_timeout_value = *pBaTimeoutVal;
- ba->ba_start_seq_ctrl = *pBaStartSeqCtrl;
+ ba->dialog_token = *dialog_token;
+ ba->ba_param_set = *ba_param_set;
+ ba->ba_timeout_value = *ba_timeout_value;
+ ba->ba_start_seq_ctrl = *ba_start_seq_ctrl;
if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev) ||
(ieee->ht_info->iot_action & HT_IOT_ACT_ALLOW_PEER_AGG_ONE_PKT))
@@ -291,9 +291,9 @@ OnADDBAReq_Fail:
{
struct ba_record BA;
- BA.ba_param_set = *pBaParamSet;
- BA.ba_timeout_value = *pBaTimeoutVal;
- BA.dialog_token = *pDialogToken;
+ BA.ba_param_set = *ba_param_set;
+ BA.ba_timeout_value = *ba_timeout_value;
+ BA.dialog_token = *dialog_token;
BA.ba_param_set.field.ba_policy = BA_POLICY_IMMEDIATE;
rtllib_send_ADDBARsp(ieee, dst, &BA, rc);
return 0;
@@ -303,11 +303,11 @@ OnADDBAReq_Fail:
int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb)
{
struct ieee80211_hdr_3addr *rsp = NULL;
- struct ba_record *pending_ba, *pAdmittedBA;
+ struct ba_record *pending_ba, *admitted_ba;
struct tx_ts_record *ts = NULL;
- u8 *dst = NULL, *pDialogToken = NULL, *tag = NULL;
- u16 *status_code = NULL, *pBaTimeoutVal = NULL;
- union ba_param_set *pBaParamSet = NULL;
+ u8 *dst = NULL, *dialog_token = NULL, *tag = NULL;
+ u16 *status_code = NULL, *ba_timeout_value = NULL;
+ union ba_param_set *ba_param_set = NULL;
u16 reason_code;
if (skb->len < sizeof(struct ieee80211_hdr_3addr) + 9) {
@@ -320,40 +320,40 @@ int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb)
tag = (u8 *)rsp;
dst = (u8 *)(&rsp->addr2[0]);
tag += sizeof(struct ieee80211_hdr_3addr);
- pDialogToken = tag + 2;
+ dialog_token = tag + 2;
status_code = (u16 *)(tag + 3);
- pBaParamSet = (union ba_param_set *)(tag + 5);
- pBaTimeoutVal = (u16 *)(tag + 7);
+ ba_param_set = (union ba_param_set *)(tag + 5);
+ ba_timeout_value = (u16 *)(tag + 7);
if (!ieee->current_network.qos_data.active ||
!ieee->ht_info->current_ht_support ||
- !ieee->ht_info->bCurrentAMPDUEnable) {
+ !ieee->ht_info->current_ampdu_enable) {
netdev_warn(ieee->dev,
"reject to ADDBA_RSP as some capability is not ready(%d, %d, %d)\n",
ieee->current_network.qos_data.active,
ieee->ht_info->current_ht_support,
- ieee->ht_info->bCurrentAMPDUEnable);
+ ieee->ht_info->current_ampdu_enable);
reason_code = DELBA_REASON_UNKNOWN_BA;
goto OnADDBARsp_Reject;
}
if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst,
- (u8)(pBaParamSet->field.tid), TX_DIR, false)) {
+ (u8)(ba_param_set->field.tid), TX_DIR, false)) {
netdev_warn(ieee->dev, "%s(): can't get TS\n", __func__);
reason_code = DELBA_REASON_UNKNOWN_BA;
goto OnADDBARsp_Reject;
}
- ts->bAddBaReqInProgress = false;
- pending_ba = &ts->TxPendingBARecord;
- pAdmittedBA = &ts->TxAdmittedBARecord;
+ ts->add_ba_req_in_progress = false;
+ pending_ba = &ts->tx_pending_ba_record;
+ admitted_ba = &ts->tx_admitted_ba_record;
- if (pAdmittedBA->b_valid) {
+ if (admitted_ba->b_valid) {
netdev_dbg(ieee->dev, "%s(): ADDBA response already admitted\n",
__func__);
return -1;
} else if (!pending_ba->b_valid ||
- (*pDialogToken != pending_ba->dialog_token)) {
+ (*dialog_token != pending_ba->dialog_token)) {
netdev_warn(ieee->dev,
"%s(): ADDBA Rsp. BA invalid, DELBA!\n",
__func__);
@@ -367,22 +367,22 @@ int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb)
}
if (*status_code == ADDBA_STATUS_SUCCESS) {
- if (pBaParamSet->field.ba_policy == BA_POLICY_DELAYED) {
- ts->bAddBaReqDelayed = true;
- deactivate_ba_entry(ieee, pAdmittedBA);
+ if (ba_param_set->field.ba_policy == BA_POLICY_DELAYED) {
+ ts->add_ba_req_delayed = true;
+ deactivate_ba_entry(ieee, admitted_ba);
reason_code = DELBA_REASON_END_BA;
goto OnADDBARsp_Reject;
}
- pAdmittedBA->dialog_token = *pDialogToken;
- pAdmittedBA->ba_timeout_value = *pBaTimeoutVal;
- pAdmittedBA->ba_start_seq_ctrl = pending_ba->ba_start_seq_ctrl;
- pAdmittedBA->ba_param_set = *pBaParamSet;
- deactivate_ba_entry(ieee, pAdmittedBA);
- activate_ba_entry(pAdmittedBA, *pBaTimeoutVal);
+ admitted_ba->dialog_token = *dialog_token;
+ admitted_ba->ba_timeout_value = *ba_timeout_value;
+ admitted_ba->ba_start_seq_ctrl = pending_ba->ba_start_seq_ctrl;
+ admitted_ba->ba_param_set = *ba_param_set;
+ deactivate_ba_entry(ieee, admitted_ba);
+ activate_ba_entry(admitted_ba, *ba_timeout_value);
} else {
- ts->bAddBaReqDelayed = true;
- ts->bDisable_AddBa = true;
+ ts->add_ba_req_delayed = true;
+ ts->disable_add_ba = true;
reason_code = DELBA_REASON_END_BA;
goto OnADDBARsp_Reject;
}
@@ -393,7 +393,7 @@ OnADDBARsp_Reject:
{
struct ba_record BA;
- BA.ba_param_set = *pBaParamSet;
+ BA.ba_param_set = *ba_param_set;
rtllib_send_DELBA(ieee, dst, &BA, TX_DIR, reason_code);
return 0;
}
@@ -402,7 +402,7 @@ OnADDBARsp_Reject:
int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb)
{
struct ieee80211_hdr_3addr *delba = NULL;
- union delba_param_set *pDelBaParamSet = NULL;
+ union delba_param_set *del_ba_param_set = NULL;
u8 *dst = NULL;
if (skb->len < sizeof(struct ieee80211_hdr_3addr) + 6) {
@@ -427,46 +427,46 @@ int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb)
#endif
delba = (struct ieee80211_hdr_3addr *)skb->data;
dst = (u8 *)(&delba->addr2[0]);
- pDelBaParamSet = (union delba_param_set *)&delba->seq_ctrl + 2;
+ del_ba_param_set = (union delba_param_set *)&delba->seq_ctrl + 2;
- if (pDelBaParamSet->field.initiator == 1) {
+ if (del_ba_param_set->field.initiator == 1) {
struct rx_ts_record *ts;
if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst,
- (u8)pDelBaParamSet->field.tid, RX_DIR, false)) {
+ (u8)del_ba_param_set->field.tid, RX_DIR, false)) {
netdev_warn(ieee->dev,
"%s(): can't get TS for RXTS. dst:%pM TID:%d\n",
__func__, dst,
- (u8)pDelBaParamSet->field.tid);
+ (u8)del_ba_param_set->field.tid);
return -1;
}
rx_ts_delete_ba(ieee, ts);
} else {
- struct tx_ts_record *pTxTs;
+ struct tx_ts_record *ts;
- if (!rtllib_get_ts(ieee, (struct ts_common_info **)&pTxTs, dst,
- (u8)pDelBaParamSet->field.tid, TX_DIR, false)) {
+ if (!rtllib_get_ts(ieee, (struct ts_common_info **)&ts, dst,
+ (u8)del_ba_param_set->field.tid, TX_DIR, false)) {
netdev_warn(ieee->dev, "%s(): can't get TS for TXTS\n",
__func__);
return -1;
}
- pTxTs->bUsingBa = false;
- pTxTs->bAddBaReqInProgress = false;
- pTxTs->bAddBaReqDelayed = false;
- del_timer_sync(&pTxTs->TsAddBaTimer);
- tx_ts_delete_ba(ieee, pTxTs);
+ ts->using_ba = false;
+ ts->add_ba_req_in_progress = false;
+ ts->add_ba_req_delayed = false;
+ del_timer_sync(&ts->ts_add_ba_timer);
+ tx_ts_delete_ba(ieee, ts);
}
return 0;
}
void rtllib_ts_init_add_ba(struct rtllib_device *ieee, struct tx_ts_record *ts,
- u8 policy, u8 bOverwritePending)
+ u8 policy, u8 overwrite_pending)
{
- struct ba_record *ba = &ts->TxPendingBARecord;
+ struct ba_record *ba = &ts->tx_pending_ba_record;
- if (ba->b_valid && !bOverwritePending)
+ if (ba->b_valid && !overwrite_pending)
return;
deactivate_ba_entry(ieee, ba);
@@ -474,35 +474,35 @@ void rtllib_ts_init_add_ba(struct rtllib_device *ieee, struct tx_ts_record *ts,
ba->dialog_token++;
ba->ba_param_set.field.amsdu_support = 0;
ba->ba_param_set.field.ba_policy = policy;
- ba->ba_param_set.field.tid = ts->TsCommonInfo.TSpec.ucTSID;
+ ba->ba_param_set.field.tid = ts->ts_common_info.tspec.ts_id;
ba->ba_param_set.field.buffer_size = 32;
ba->ba_timeout_value = 0;
- ba->ba_start_seq_ctrl.field.seq_num = (ts->TxCurSeq + 3) % 4096;
+ ba->ba_start_seq_ctrl.field.seq_num = (ts->tx_cur_seq + 3) % 4096;
activate_ba_entry(ba, BA_SETUP_TIMEOUT);
- rtllib_send_ADDBAReq(ieee, ts->TsCommonInfo.addr, ba);
+ rtllib_send_ADDBAReq(ieee, ts->ts_common_info.addr, ba);
}
void rtllib_ts_init_del_ba(struct rtllib_device *ieee,
- struct ts_common_info *pTsCommonInfo,
+ struct ts_common_info *ts_common_info,
enum tr_select TxRxSelect)
{
if (TxRxSelect == TX_DIR) {
- struct tx_ts_record *pTxTs =
- (struct tx_ts_record *)pTsCommonInfo;
-
- if (tx_ts_delete_ba(ieee, pTxTs))
- rtllib_send_DELBA(ieee, pTsCommonInfo->addr,
- (pTxTs->TxAdmittedBARecord.b_valid) ?
- (&pTxTs->TxAdmittedBARecord) :
- (&pTxTs->TxPendingBARecord),
+ struct tx_ts_record *ts =
+ (struct tx_ts_record *)ts_common_info;
+
+ if (tx_ts_delete_ba(ieee, ts))
+ rtllib_send_DELBA(ieee, ts_common_info->addr,
+ (ts->tx_admitted_ba_record.b_valid) ?
+ (&ts->tx_admitted_ba_record) :
+ (&ts->tx_pending_ba_record),
TxRxSelect, DELBA_REASON_END_BA);
} else if (TxRxSelect == RX_DIR) {
struct rx_ts_record *ts =
- (struct rx_ts_record *)pTsCommonInfo;
+ (struct rx_ts_record *)ts_common_info;
if (rx_ts_delete_ba(ieee, ts))
- rtllib_send_DELBA(ieee, pTsCommonInfo->addr,
+ rtllib_send_DELBA(ieee, ts_common_info->addr,
&ts->rx_admitted_ba_record,
TxRxSelect, DELBA_REASON_END_BA);
}
@@ -510,23 +510,23 @@ void rtllib_ts_init_del_ba(struct rtllib_device *ieee,
void rtllib_ba_setup_timeout(struct timer_list *t)
{
- struct tx_ts_record *pTxTs = from_timer(pTxTs, t,
- TxPendingBARecord.timer);
+ struct tx_ts_record *ts = from_timer(ts, t,
+ tx_pending_ba_record.timer);
- pTxTs->bAddBaReqInProgress = false;
- pTxTs->bAddBaReqDelayed = true;
- pTxTs->TxPendingBARecord.b_valid = false;
+ ts->add_ba_req_in_progress = false;
+ ts->add_ba_req_delayed = true;
+ ts->tx_pending_ba_record.b_valid = false;
}
void rtllib_tx_ba_inact_timeout(struct timer_list *t)
{
- struct tx_ts_record *pTxTs = from_timer(pTxTs, t,
- TxAdmittedBARecord.timer);
- struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device,
- TxTsRecord[pTxTs->num]);
- tx_ts_delete_ba(ieee, pTxTs);
- rtllib_send_DELBA(ieee, pTxTs->TsCommonInfo.addr,
- &pTxTs->TxAdmittedBARecord, TX_DIR,
+ struct tx_ts_record *ts = from_timer(ts, t,
+ tx_admitted_ba_record.timer);
+ struct rtllib_device *ieee = container_of(ts, struct rtllib_device,
+ tx_ts_records[ts->num]);
+ tx_ts_delete_ba(ieee, ts);
+ rtllib_send_DELBA(ieee, ts->ts_common_info.addr,
+ &ts->tx_admitted_ba_record, TX_DIR,
DELBA_REASON_TIMEOUT);
}
@@ -535,7 +535,7 @@ void rtllib_rx_ba_inact_timeout(struct timer_list *t)
struct rx_ts_record *ts = from_timer(ts, t,
rx_admitted_ba_record.timer);
struct rtllib_device *ieee = container_of(ts, struct rtllib_device,
- RxTsRecord[ts->num]);
+ rx_ts_records[ts->num]);
rx_ts_delete_ba(ieee, ts);
rtllib_send_DELBA(ieee, ts->ts_common_info.addr,
diff --git a/drivers/staging/rtl8192e/rtl819x_HT.h b/drivers/staging/rtl8192e/rtl819x_HT.h
index f8eb4d553fe0..68577bffb936 100644
--- a/drivers/staging/rtl8192e/rtl819x_HT.h
+++ b/drivers/staging/rtl8192e/rtl819x_HT.h
@@ -94,51 +94,32 @@ enum ht_aggre_mode {
struct rt_hi_throughput {
u8 enable_ht;
u8 current_ht_support;
- u8 bRegBW40MHz;
- u8 bCurBW40MHz;
- u8 bRegShortGI40MHz;
- u8 bCurShortGI40MHz;
- u8 bRegShortGI20MHz;
- u8 bCurShortGI20MHz;
- u8 bRegSuppCCK;
- u8 bCurSuppCCK;
- enum ht_spec_ver ePeerHTSpecVer;
+ u8 cur_bw_40mhz;
+ u8 cur_short_gi_40mhz;
+ u8 cur_short_gi_20mhz;
+ enum ht_spec_ver peer_ht_spec_ver;
struct ht_capab_ele SelfHTCap;
- struct ht_info_ele SelfHTInfo;
u8 PeerHTCapBuf[32];
u8 PeerHTInfoBuf[32];
- u8 bAMSDU_Support;
- u16 nAMSDU_MaxSize;
- u8 bCurrent_AMSDU_Support;
- u16 nCurrent_AMSDU_MaxSize;
- u8 bAMPDUEnable;
- u8 bCurrentAMPDUEnable;
- u8 AMPDU_Factor;
+ u8 ampdu_enable;
+ u8 current_ampdu_enable;
+ u8 ampdu_factor;
u8 CurrentAMPDUFactor;
- u8 MPDU_Density;
u8 current_mpdu_density;
- enum ht_aggre_mode ForcedAMPDUMode;
u8 forced_ampdu_factor;
u8 forced_mpdu_density;
- enum ht_aggre_mode ForcedAMSDUMode;
- u8 forced_short_gi;
u8 current_op_mode;
- u8 self_mimo_ps;
- u8 peer_mimo_ps;
enum ht_extchnl_offset CurSTAExtChnlOffset;
u8 cur_tx_bw40mhz;
u8 sw_bw_in_progress;
- u8 reg_rt2rt_aggregation;
- u8 RT2RT_HT_Mode;
u8 current_rt2rt_aggregation;
u8 current_rt2rt_long_slot_time;
u8 sz_rt2rt_agg_buf[10];
- u8 reg_rx_reorder_enable;
u8 cur_rx_reorder_enable;
u8 rx_reorder_win_size;
u8 rx_reorder_pending_time;
u16 rx_reorder_drop_counter;
- u8 IOTPeer;
+ u8 iot_peer;
u32 iot_action;
u8 iot_ra_func;
} __packed;
diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c
index e607bccc079a..6d0912f90198 100644
--- a/drivers/staging/rtl8192e/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192e/rtl819x_HTProc.c
@@ -71,75 +71,55 @@ void ht_update_default_setting(struct rtllib_device *ieee)
{
struct rt_hi_throughput *ht_info = ieee->ht_info;
- ht_info->bRegShortGI20MHz = 1;
- ht_info->bRegShortGI40MHz = 1;
+ ht_info->ampdu_enable = 1;
+ ht_info->ampdu_factor = 2;
- ht_info->bRegBW40MHz = 1;
-
- if (ht_info->bRegBW40MHz)
- ht_info->bRegSuppCCK = 1;
- else
- ht_info->bRegSuppCCK = true;
-
- ht_info->nAMSDU_MaxSize = 7935UL;
- ht_info->bAMSDU_Support = 0;
-
- ht_info->bAMPDUEnable = 1;
- ht_info->AMPDU_Factor = 2;
- ht_info->MPDU_Density = 0;
-
- ht_info->self_mimo_ps = 3;
- if (ht_info->self_mimo_ps == 2)
- ht_info->self_mimo_ps = 3;
ieee->tx_dis_rate_fallback = 0;
ieee->tx_use_drv_assinged_rate = 0;
- ieee->bTxEnableFwCalcDur = 1;
-
- ht_info->reg_rt2rt_aggregation = 1;
+ ieee->tx_enable_fw_calc_dur = 1;
- ht_info->reg_rx_reorder_enable = 1;
ht_info->rx_reorder_win_size = 64;
ht_info->rx_reorder_pending_time = 30;
}
-static u16 HTMcsToDataRate(struct rtllib_device *ieee, u8 nMcsRate)
+static u16 ht_mcs_to_data_rate(struct rtllib_device *ieee, u8 mcs_rate)
{
struct rt_hi_throughput *ht_info = ieee->ht_info;
- u8 is40MHz = (ht_info->bCurBW40MHz) ? 1 : 0;
- u8 isShortGI = (ht_info->bCurBW40MHz) ?
- ((ht_info->bCurShortGI40MHz) ? 1 : 0) :
- ((ht_info->bCurShortGI20MHz) ? 1 : 0);
- return MCS_DATA_RATE[is40MHz][isShortGI][(nMcsRate & 0x7f)];
+ u8 is40MHz = (ht_info->cur_bw_40mhz) ? 1 : 0;
+ u8 isShortGI = (ht_info->cur_bw_40mhz) ?
+ ((ht_info->cur_short_gi_40mhz) ? 1 : 0) :
+ ((ht_info->cur_short_gi_20mhz) ? 1 : 0);
+ return MCS_DATA_RATE[is40MHz][isShortGI][(mcs_rate & 0x7f)];
}
-u16 TxCountToDataRate(struct rtllib_device *ieee, u8 nDataRate)
+u16 tx_count_to_data_rate(struct rtllib_device *ieee, u8 data_rate)
{
- u16 CCKOFDMRate[12] = {0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18,
+ u16 cck_of_dm_rate[12] = {0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18,
0x24, 0x30, 0x48, 0x60, 0x6c};
u8 is40MHz = 0;
u8 isShortGI = 0;
- if (nDataRate < 12)
- return CCKOFDMRate[nDataRate];
- if (nDataRate >= 0x10 && nDataRate <= 0x1f) {
+ if (data_rate < 12)
+ return cck_of_dm_rate[data_rate];
+ if (data_rate >= 0x10 && data_rate <= 0x1f) {
is40MHz = 0;
isShortGI = 0;
- } else if (nDataRate >= 0x20 && nDataRate <= 0x2f) {
+ } else if (data_rate >= 0x20 && data_rate <= 0x2f) {
is40MHz = 1;
isShortGI = 0;
- } else if (nDataRate >= 0x30 && nDataRate <= 0x3f) {
+ } else if (data_rate >= 0x30 && data_rate <= 0x3f) {
is40MHz = 0;
isShortGI = 1;
- } else if (nDataRate >= 0x40 && nDataRate <= 0x4f) {
+ } else if (data_rate >= 0x40 && data_rate <= 0x4f) {
is40MHz = 1;
isShortGI = 1;
}
- return MCS_DATA_RATE[is40MHz][isShortGI][nDataRate & 0xf];
+ return MCS_DATA_RATE[is40MHz][isShortGI][data_rate & 0xf];
}
-bool IsHTHalfNmodeAPs(struct rtllib_device *ieee)
+bool is_ht_half_nmode_aps(struct rtllib_device *ieee)
{
bool retValue = false;
struct rtllib_network *net = &ieee->current_network;
@@ -164,187 +144,171 @@ bool IsHTHalfNmodeAPs(struct rtllib_device *ieee)
return retValue;
}
-static void HTIOTPeerDetermine(struct rtllib_device *ieee)
+static void ht_iot_peer_determine(struct rtllib_device *ieee)
{
struct rt_hi_throughput *ht_info = ieee->ht_info;
struct rtllib_network *net = &ieee->current_network;
if (net->bssht.bd_rt2rt_aggregation) {
- ht_info->IOTPeer = HT_IOT_PEER_REALTEK;
+ ht_info->iot_peer = HT_IOT_PEER_REALTEK;
if (net->bssht.rt2rt_ht_mode & RT_HT_CAP_USE_92SE)
- ht_info->IOTPeer = HT_IOT_PEER_REALTEK_92SE;
+ ht_info->iot_peer = HT_IOT_PEER_REALTEK_92SE;
if (net->bssht.rt2rt_ht_mode & RT_HT_CAP_USE_SOFTAP)
- ht_info->IOTPeer = HT_IOT_PEER_92U_SOFTAP;
+ ht_info->iot_peer = HT_IOT_PEER_92U_SOFTAP;
} else if (net->broadcom_cap_exist) {
- ht_info->IOTPeer = HT_IOT_PEER_BROADCOM;
+ ht_info->iot_peer = HT_IOT_PEER_BROADCOM;
} else if (!memcmp(net->bssid, UNKNOWN_BORADCOM, 3) ||
!memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3) ||
!memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)) {
- ht_info->IOTPeer = HT_IOT_PEER_BROADCOM;
+ ht_info->iot_peer = HT_IOT_PEER_BROADCOM;
} else if ((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3) == 0) ||
(memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3) == 0) ||
(memcmp(net->bssid, PCI_RALINK, 3) == 0) ||
(memcmp(net->bssid, EDIMAX_RALINK, 3) == 0) ||
(memcmp(net->bssid, AIRLINK_RALINK, 3) == 0) ||
net->ralink_cap_exist) {
- ht_info->IOTPeer = HT_IOT_PEER_RALINK;
+ ht_info->iot_peer = HT_IOT_PEER_RALINK;
} else if ((net->atheros_cap_exist) ||
(memcmp(net->bssid, DLINK_ATHEROS_1, 3) == 0) ||
(memcmp(net->bssid, DLINK_ATHEROS_2, 3) == 0)) {
- ht_info->IOTPeer = HT_IOT_PEER_ATHEROS;
+ ht_info->iot_peer = HT_IOT_PEER_ATHEROS;
} else if ((memcmp(net->bssid, CISCO_BROADCOM, 3) == 0) ||
net->cisco_cap_exist) {
- ht_info->IOTPeer = HT_IOT_PEER_CISCO;
+ ht_info->iot_peer = HT_IOT_PEER_CISCO;
} else if ((memcmp(net->bssid, LINKSYS_MARVELL_4400N, 3) == 0) ||
net->marvell_cap_exist) {
- ht_info->IOTPeer = HT_IOT_PEER_MARVELL;
+ ht_info->iot_peer = HT_IOT_PEER_MARVELL;
} else if (net->airgo_cap_exist) {
- ht_info->IOTPeer = HT_IOT_PEER_AIRGO;
+ ht_info->iot_peer = HT_IOT_PEER_AIRGO;
} else {
- ht_info->IOTPeer = HT_IOT_PEER_UNKNOWN;
+ ht_info->iot_peer = HT_IOT_PEER_UNKNOWN;
}
- netdev_dbg(ieee->dev, "IOTPEER: %x\n", ht_info->IOTPeer);
+ netdev_dbg(ieee->dev, "IOTPEER: %x\n", ht_info->iot_peer);
}
-static u8 HTIOTActIsMgntUseCCK6M(struct rtllib_device *ieee,
+static u8 ht_iot_act_is_mgnt_use_cck_6m(struct rtllib_device *ieee,
struct rtllib_network *network)
{
u8 retValue = 0;
- if (ieee->ht_info->IOTPeer == HT_IOT_PEER_BROADCOM)
+ if (ieee->ht_info->iot_peer == HT_IOT_PEER_BROADCOM)
retValue = 1;
return retValue;
}
-static u8 HTIOTActIsCCDFsync(struct rtllib_device *ieee)
+static u8 ht_iot_act_is_ccd_fsync(struct rtllib_device *ieee)
{
u8 retValue = 0;
- if (ieee->ht_info->IOTPeer == HT_IOT_PEER_BROADCOM)
+ if (ieee->ht_info->iot_peer == HT_IOT_PEER_BROADCOM)
retValue = 1;
return retValue;
}
-static void HTIOTActDetermineRaFunc(struct rtllib_device *ieee, bool bPeerRx2ss)
+static void ht_iot_act_determine_ra_func(struct rtllib_device *ieee, bool bPeerRx2ss)
{
struct rt_hi_throughput *ht_info = ieee->ht_info;
ht_info->iot_ra_func &= HT_IOT_RAFUNC_DISABLE_ALL;
- if (ht_info->IOTPeer == HT_IOT_PEER_RALINK && !bPeerRx2ss)
+ if (ht_info->iot_peer == HT_IOT_PEER_RALINK && !bPeerRx2ss)
ht_info->iot_ra_func |= HT_IOT_RAFUNC_PEER_1R;
if (ht_info->iot_action & HT_IOT_ACT_AMSDU_ENABLE)
ht_info->iot_ra_func |= HT_IOT_RAFUNC_TX_AMSDU;
}
-void HTResetIOTSetting(struct rt_hi_throughput *ht_info)
+void ht_reset_iot_setting(struct rt_hi_throughput *ht_info)
{
ht_info->iot_action = 0;
- ht_info->IOTPeer = HT_IOT_PEER_UNKNOWN;
+ ht_info->iot_peer = HT_IOT_PEER_UNKNOWN;
ht_info->iot_ra_func = 0;
}
-void HTConstructCapabilityElement(struct rtllib_device *ieee, u8 *posHTCap,
- u8 *len, u8 IsEncrypt, bool bAssoc)
+void ht_construct_capability_element(struct rtllib_device *ieee, u8 *pos_ht_cap,
+ u8 *len, u8 is_encrypt, bool assoc)
{
- struct rt_hi_throughput *pHT = ieee->ht_info;
- struct ht_capab_ele *pCapELE = NULL;
+ struct rt_hi_throughput *ht = ieee->ht_info;
+ struct ht_capab_ele *cap_ele = NULL;
- if (!posHTCap || !pHT) {
+ if (!pos_ht_cap || !ht) {
netdev_warn(ieee->dev,
"%s(): posHTCap and ht_info are null\n", __func__);
return;
}
- memset(posHTCap, 0, *len);
+ memset(pos_ht_cap, 0, *len);
- if ((bAssoc) && (pHT->ePeerHTSpecVer == HT_SPEC_VER_EWC)) {
+ if ((assoc) && (ht->peer_ht_spec_ver == HT_SPEC_VER_EWC)) {
static const u8 EWC11NHTCap[] = { 0x00, 0x90, 0x4c, 0x33 };
- memcpy(posHTCap, EWC11NHTCap, sizeof(EWC11NHTCap));
- pCapELE = (struct ht_capab_ele *)&posHTCap[4];
+ memcpy(pos_ht_cap, EWC11NHTCap, sizeof(EWC11NHTCap));
+ cap_ele = (struct ht_capab_ele *)&pos_ht_cap[4];
*len = 30 + 2;
} else {
- pCapELE = (struct ht_capab_ele *)posHTCap;
+ cap_ele = (struct ht_capab_ele *)pos_ht_cap;
*len = 26 + 2;
}
- pCapELE->AdvCoding = 0;
+ cap_ele->AdvCoding = 0;
if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev))
- pCapELE->ChlWidth = 0;
+ cap_ele->ChlWidth = 0;
else
- pCapELE->ChlWidth = (pHT->bRegBW40MHz ? 1 : 0);
+ cap_ele->ChlWidth = 1;
- pCapELE->MimoPwrSave = pHT->self_mimo_ps;
- pCapELE->GreenField = 0;
- pCapELE->ShortGI20Mhz = 1;
- pCapELE->ShortGI40Mhz = 1;
+ cap_ele->MimoPwrSave = 3;
+ cap_ele->GreenField = 0;
+ cap_ele->ShortGI20Mhz = 1;
+ cap_ele->ShortGI40Mhz = 1;
- pCapELE->TxSTBC = 1;
- pCapELE->RxSTBC = 0;
- pCapELE->DelayBA = 0;
- pCapELE->MaxAMSDUSize = (MAX_RECEIVE_BUFFER_SIZE >= 7935) ? 1 : 0;
- pCapELE->DssCCk = ((pHT->bRegBW40MHz) ? (pHT->bRegSuppCCK ? 1 : 0) : 0);
- pCapELE->PSMP = 0;
- pCapELE->LSigTxopProtect = 0;
+ cap_ele->TxSTBC = 1;
+ cap_ele->RxSTBC = 0;
+ cap_ele->DelayBA = 0;
+ cap_ele->MaxAMSDUSize = (MAX_RECEIVE_BUFFER_SIZE >= 7935) ? 1 : 0;
+ cap_ele->DssCCk = 1;
+ cap_ele->PSMP = 0;
+ cap_ele->LSigTxopProtect = 0;
netdev_dbg(ieee->dev,
"TX HT cap/info ele BW=%d MaxAMSDUSize:%d DssCCk:%d\n",
- pCapELE->ChlWidth, pCapELE->MaxAMSDUSize, pCapELE->DssCCk);
+ cap_ele->ChlWidth, cap_ele->MaxAMSDUSize, cap_ele->DssCCk);
- if (IsEncrypt) {
- pCapELE->MPDUDensity = 7;
- pCapELE->MaxRxAMPDUFactor = 2;
+ if (is_encrypt) {
+ cap_ele->MPDUDensity = 7;
+ cap_ele->MaxRxAMPDUFactor = 2;
} else {
- pCapELE->MaxRxAMPDUFactor = 3;
- pCapELE->MPDUDensity = 0;
+ cap_ele->MaxRxAMPDUFactor = 3;
+ cap_ele->MPDUDensity = 0;
}
- memcpy(pCapELE->MCS, ieee->reg_dot11ht_oper_rate_set, 16);
- memset(&pCapELE->ExtHTCapInfo, 0, 2);
- memset(pCapELE->TxBFCap, 0, 4);
+ memcpy(cap_ele->MCS, ieee->reg_dot11ht_oper_rate_set, 16);
+ memset(&cap_ele->ExtHTCapInfo, 0, 2);
+ memset(cap_ele->TxBFCap, 0, 4);
- pCapELE->ASCap = 0;
+ cap_ele->ASCap = 0;
- if (bAssoc) {
- if (pHT->iot_action & HT_IOT_ACT_DISABLE_MCS15)
- pCapELE->MCS[1] &= 0x7f;
+ if (assoc) {
+ if (ht->iot_action & HT_IOT_ACT_DISABLE_MCS15)
+ cap_ele->MCS[1] &= 0x7f;
- if (pHT->iot_action & HT_IOT_ACT_DISABLE_MCS14)
- pCapELE->MCS[1] &= 0xbf;
+ if (ht->iot_action & HT_IOT_ACT_DISABLE_MCS14)
+ cap_ele->MCS[1] &= 0xbf;
- if (pHT->iot_action & HT_IOT_ACT_DISABLE_ALL_2SS)
- pCapELE->MCS[1] &= 0x00;
+ if (ht->iot_action & HT_IOT_ACT_DISABLE_ALL_2SS)
+ cap_ele->MCS[1] &= 0x00;
- if (pHT->iot_action & HT_IOT_ACT_DISABLE_RX_40MHZ_SHORT_GI)
- pCapELE->ShortGI40Mhz = 0;
+ if (ht->iot_action & HT_IOT_ACT_DISABLE_RX_40MHZ_SHORT_GI)
+ cap_ele->ShortGI40Mhz = 0;
if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev)) {
- pCapELE->ChlWidth = 0;
- pCapELE->MCS[1] = 0;
+ cap_ele->ChlWidth = 0;
+ cap_ele->MCS[1] = 0;
}
}
}
-void HTConstructInfoElement(struct rtllib_device *ieee, u8 *posHTInfo,
- u8 *len, u8 IsEncrypt)
-{
- struct ht_info_ele *pHTInfoEle = (struct ht_info_ele *)posHTInfo;
-
- if (!posHTInfo || !pHTInfoEle) {
- netdev_warn(ieee->dev,
- "%s(): posHTInfo and pHTInfoEle are null\n",
- __func__);
- return;
- }
-
- memset(posHTInfo, 0, *len);
- *len = 0;
-}
-
-void HTConstructRT2RTAggElement(struct rtllib_device *ieee, u8 *posRT2RTAgg,
+void ht_construct_rt2rt_agg_element(struct rtllib_device *ieee, u8 *posRT2RTAgg,
u8 *len)
{
if (!posRT2RTAgg) {
@@ -366,7 +330,7 @@ void HTConstructRT2RTAggElement(struct rtllib_device *ieee, u8 *posRT2RTAgg,
*len = 6 + 2;
}
-static u8 HT_PickMCSRate(struct rtllib_device *ieee, u8 *pOperateMCS)
+static u8 ht_pick_mcs_rate(struct rtllib_device *ieee, u8 *pOperateMCS)
{
u8 i;
@@ -393,7 +357,7 @@ static u8 HT_PickMCSRate(struct rtllib_device *ieee, u8 *pOperateMCS)
return true;
}
-u8 HTGetHighestMCSRate(struct rtllib_device *ieee, u8 *pMCSRateSet,
+u8 ht_get_highest_mcs_rate(struct rtllib_device *ieee, u8 *pMCSRateSet,
u8 *pMCSFilter)
{
u8 i, j;
@@ -422,8 +386,8 @@ u8 HTGetHighestMCSRate(struct rtllib_device *ieee, u8 *pMCSRateSet,
bitMap = availableMcsRate[i];
for (j = 0; j < 8; j++) {
if ((bitMap % 2) != 0) {
- if (HTMcsToDataRate(ieee, (8 * i + j)) >
- HTMcsToDataRate(ieee, mcsRate))
+ if (ht_mcs_to_data_rate(ieee, (8 * i + j)) >
+ ht_mcs_to_data_rate(ieee, mcsRate))
mcsRate = 8 * i + j;
}
bitMap >>= 1;
@@ -433,7 +397,7 @@ u8 HTGetHighestMCSRate(struct rtllib_device *ieee, u8 *pMCSRateSet,
return mcsRate | 0x80;
}
-static u8 HTFilterMCSRate(struct rtllib_device *ieee, u8 *pSupportMCS,
+static u8 ht_filter_mcs_rate(struct rtllib_device *ieee, u8 *pSupportMCS,
u8 *pOperateMCS)
{
u8 i;
@@ -442,7 +406,7 @@ static u8 HTFilterMCSRate(struct rtllib_device *ieee, u8 *pSupportMCS,
pOperateMCS[i] = ieee->reg_dot11tx_ht_oper_rate_set[i] &
pSupportMCS[i];
- HT_PickMCSRate(ieee, pOperateMCS);
+ ht_pick_mcs_rate(ieee, pOperateMCS);
if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev))
pOperateMCS[1] = 0;
@@ -453,16 +417,15 @@ static u8 HTFilterMCSRate(struct rtllib_device *ieee, u8 *pSupportMCS,
return true;
}
-void HTSetConnectBwMode(struct rtllib_device *ieee,
+void ht_set_connect_bw_mode(struct rtllib_device *ieee,
enum ht_channel_width bandwidth,
enum ht_extchnl_offset Offset);
-void HTOnAssocRsp(struct rtllib_device *ieee)
+void ht_on_assoc_rsp(struct rtllib_device *ieee)
{
struct rt_hi_throughput *ht_info = ieee->ht_info;
struct ht_capab_ele *pPeerHTCap = NULL;
struct ht_info_ele *pPeerHTInfo = NULL;
- u16 nMaxAMSDUSize = 0;
u8 *pMcsFilter = NULL;
static const u8 EWC11NHTCap[] = { 0x00, 0x90, 0x4c, 0x33 };
@@ -489,79 +452,48 @@ void HTOnAssocRsp(struct rtllib_device *ieee)
print_hex_dump_bytes("%s: ", __func__, DUMP_PREFIX_NONE,
pPeerHTCap, sizeof(struct ht_capab_ele));
#endif
- HTSetConnectBwMode(ieee, (enum ht_channel_width)(pPeerHTCap->ChlWidth),
+ ht_set_connect_bw_mode(ieee, (enum ht_channel_width)(pPeerHTCap->ChlWidth),
(enum ht_extchnl_offset)(pPeerHTInfo->ExtChlOffset));
ht_info->cur_tx_bw40mhz = ((pPeerHTInfo->RecommemdedTxWidth == 1) ?
true : false);
- ht_info->bCurShortGI20MHz = ((ht_info->bRegShortGI20MHz) ?
- ((pPeerHTCap->ShortGI20Mhz == 1) ?
- true : false) : false);
- ht_info->bCurShortGI40MHz = ((ht_info->bRegShortGI40MHz) ?
- ((pPeerHTCap->ShortGI40Mhz == 1) ?
- true : false) : false);
+ ht_info->cur_short_gi_20mhz = ((pPeerHTCap->ShortGI20Mhz == 1) ? true : false);
+ ht_info->cur_short_gi_40mhz = ((pPeerHTCap->ShortGI40Mhz == 1) ? true : false);
- ht_info->bCurSuppCCK = ((ht_info->bRegSuppCCK) ?
- ((pPeerHTCap->DssCCk == 1) ? true :
- false) : false);
-
- ht_info->bCurrent_AMSDU_Support = ht_info->bAMSDU_Support;
-
- nMaxAMSDUSize = (pPeerHTCap->MaxAMSDUSize == 0) ? 3839 : 7935;
-
- if (ht_info->nAMSDU_MaxSize > nMaxAMSDUSize)
- ht_info->nCurrent_AMSDU_MaxSize = nMaxAMSDUSize;
- else
- ht_info->nCurrent_AMSDU_MaxSize = ht_info->nAMSDU_MaxSize;
-
- ht_info->bCurrentAMPDUEnable = ht_info->bAMPDUEnable;
+ ht_info->current_ampdu_enable = ht_info->ampdu_enable;
if (ieee->rtllib_ap_sec_type &&
(ieee->rtllib_ap_sec_type(ieee) & (SEC_ALG_WEP | SEC_ALG_TKIP))) {
- if ((ht_info->IOTPeer == HT_IOT_PEER_ATHEROS) ||
- (ht_info->IOTPeer == HT_IOT_PEER_UNKNOWN))
- ht_info->bCurrentAMPDUEnable = false;
+ if ((ht_info->iot_peer == HT_IOT_PEER_ATHEROS) ||
+ (ht_info->iot_peer == HT_IOT_PEER_UNKNOWN))
+ ht_info->current_ampdu_enable = false;
}
- if (!ht_info->reg_rt2rt_aggregation) {
- if (ht_info->AMPDU_Factor > pPeerHTCap->MaxRxAMPDUFactor)
+ if (ieee->current_network.bssht.bd_rt2rt_aggregation) {
+ if (ieee->pairwise_key_type != KEY_TYPE_NA)
ht_info->CurrentAMPDUFactor =
- pPeerHTCap->MaxRxAMPDUFactor;
+ pPeerHTCap->MaxRxAMPDUFactor;
else
- ht_info->CurrentAMPDUFactor = ht_info->AMPDU_Factor;
-
+ ht_info->CurrentAMPDUFactor = HT_AGG_SIZE_64K;
} else {
- if (ieee->current_network.bssht.bd_rt2rt_aggregation) {
- if (ieee->pairwise_key_type != KEY_TYPE_NA)
- ht_info->CurrentAMPDUFactor =
- pPeerHTCap->MaxRxAMPDUFactor;
- else
- ht_info->CurrentAMPDUFactor = HT_AGG_SIZE_64K;
- } else {
- ht_info->CurrentAMPDUFactor = min_t(u32, pPeerHTCap->MaxRxAMPDUFactor,
- HT_AGG_SIZE_32K);
- }
+ ht_info->CurrentAMPDUFactor = min_t(u32, pPeerHTCap->MaxRxAMPDUFactor,
+ HT_AGG_SIZE_32K);
}
- ht_info->current_mpdu_density = max_t(u8, ht_info->MPDU_Density,
- pPeerHTCap->MPDUDensity);
+
+ ht_info->current_mpdu_density = pPeerHTCap->MPDUDensity;
if (ht_info->iot_action & HT_IOT_ACT_TX_USE_AMSDU_8K) {
- ht_info->bCurrentAMPDUEnable = false;
- ht_info->ForcedAMSDUMode = HT_AGG_FORCE_ENABLE;
+ ht_info->current_ampdu_enable = false;
}
- ht_info->cur_rx_reorder_enable = ht_info->reg_rx_reorder_enable;
+ ht_info->cur_rx_reorder_enable = 1;
if (pPeerHTCap->MCS[0] == 0)
pPeerHTCap->MCS[0] = 0xff;
- HTIOTActDetermineRaFunc(ieee, ((pPeerHTCap->MCS[1]) != 0));
+ ht_iot_act_determine_ra_func(ieee, ((pPeerHTCap->MCS[1]) != 0));
- HTFilterMCSRate(ieee, pPeerHTCap->MCS, ieee->dot11ht_oper_rate_set);
+ ht_filter_mcs_rate(ieee, pPeerHTCap->MCS, ieee->dot11ht_oper_rate_set);
- ht_info->peer_mimo_ps = pPeerHTCap->MimoPwrSave;
- if (ht_info->peer_mimo_ps == MIMO_PS_STATIC)
- pMcsFilter = MCS_FILTER_1SS;
- else
- pMcsFilter = MCS_FILTER_ALL;
- ieee->HTHighestOperaRate = HTGetHighestMCSRate(ieee,
+ pMcsFilter = MCS_FILTER_ALL;
+ ieee->HTHighestOperaRate = ht_get_highest_mcs_rate(ieee,
ieee->dot11ht_oper_rate_set,
pMcsFilter);
ieee->HTCurrentOperaRate = ieee->HTHighestOperaRate;
@@ -569,30 +501,23 @@ void HTOnAssocRsp(struct rtllib_device *ieee)
ht_info->current_op_mode = pPeerHTInfo->OptMode;
}
-void HTInitializeHTInfo(struct rtllib_device *ieee)
+void ht_initialize_ht_info(struct rtllib_device *ieee)
{
struct rt_hi_throughput *ht_info = ieee->ht_info;
ht_info->current_ht_support = false;
- ht_info->bCurBW40MHz = false;
+ ht_info->cur_bw_40mhz = false;
ht_info->cur_tx_bw40mhz = false;
- ht_info->bCurShortGI20MHz = false;
- ht_info->bCurShortGI40MHz = false;
- ht_info->forced_short_gi = false;
+ ht_info->cur_short_gi_20mhz = false;
+ ht_info->cur_short_gi_40mhz = false;
- ht_info->bCurSuppCCK = true;
-
- ht_info->bCurrent_AMSDU_Support = false;
- ht_info->nCurrent_AMSDU_MaxSize = ht_info->nAMSDU_MaxSize;
- ht_info->current_mpdu_density = ht_info->MPDU_Density;
- ht_info->CurrentAMPDUFactor = ht_info->AMPDU_Factor;
+ ht_info->current_mpdu_density = 0;
+ ht_info->CurrentAMPDUFactor = ht_info->ampdu_factor;
memset((void *)(&ht_info->SelfHTCap), 0,
sizeof(ht_info->SelfHTCap));
- memset((void *)(&ht_info->SelfHTInfo), 0,
- sizeof(ht_info->SelfHTInfo));
memset((void *)(&ht_info->PeerHTCapBuf), 0,
sizeof(ht_info->PeerHTCapBuf));
memset((void *)(&ht_info->PeerHTInfoBuf), 0,
@@ -600,13 +525,12 @@ void HTInitializeHTInfo(struct rtllib_device *ieee)
ht_info->sw_bw_in_progress = false;
- ht_info->ePeerHTSpecVer = HT_SPEC_VER_IEEE;
+ ht_info->peer_ht_spec_ver = HT_SPEC_VER_IEEE;
ht_info->current_rt2rt_aggregation = false;
ht_info->current_rt2rt_long_slot_time = false;
- ht_info->RT2RT_HT_Mode = (enum rt_ht_capability)0;
- ht_info->IOTPeer = 0;
+ ht_info->iot_peer = 0;
ht_info->iot_action = 0;
ht_info->iot_ra_func = 0;
@@ -619,7 +543,7 @@ void HTInitializeHTInfo(struct rtllib_device *ieee)
}
}
-void HTInitializeBssDesc(struct bss_ht *pBssHT)
+void ht_initialize_bss_desc(struct bss_ht *pBssHT)
{
pBssHT->bd_support_ht = false;
memset(pBssHT->bd_ht_cap_buf, 0, sizeof(pBssHT->bd_ht_cap_buf));
@@ -634,7 +558,7 @@ void HTInitializeBssDesc(struct bss_ht *pBssHT)
pBssHT->rt2rt_ht_mode = (enum rt_ht_capability)0;
}
-void HTResetSelfAndSavePeerSetting(struct rtllib_device *ieee,
+void ht_reset_self_and_save_peer_setting(struct rtllib_device *ieee,
struct rtllib_network *pNetwork)
{
struct rt_hi_throughput *ht_info = ieee->ht_info;
@@ -645,7 +569,7 @@ void HTResetSelfAndSavePeerSetting(struct rtllib_device *ieee,
*/
if (pNetwork->bssht.bd_support_ht) {
ht_info->current_ht_support = true;
- ht_info->ePeerHTSpecVer = pNetwork->bssht.bd_ht_spec_ver;
+ ht_info->peer_ht_spec_ver = pNetwork->bssht.bd_ht_spec_ver;
if (pNetwork->bssht.bd_ht_cap_len > 0 &&
pNetwork->bssht.bd_ht_cap_len <= sizeof(ht_info->PeerHTCapBuf))
@@ -660,32 +584,24 @@ void HTResetSelfAndSavePeerSetting(struct rtllib_device *ieee,
pNetwork->bssht.bd_ht_info_buf,
pNetwork->bssht.bd_ht_info_len);
- if (ht_info->reg_rt2rt_aggregation) {
- ht_info->current_rt2rt_aggregation =
- pNetwork->bssht.bd_rt2rt_aggregation;
- ht_info->current_rt2rt_long_slot_time =
- pNetwork->bssht.bd_rt2rt_long_slot_time;
- ht_info->RT2RT_HT_Mode = pNetwork->bssht.rt2rt_ht_mode;
- } else {
- ht_info->current_rt2rt_aggregation = false;
- ht_info->current_rt2rt_long_slot_time = false;
- ht_info->RT2RT_HT_Mode = (enum rt_ht_capability)0;
- }
+ ht_info->current_rt2rt_aggregation =
+ pNetwork->bssht.bd_rt2rt_aggregation;
+ ht_info->current_rt2rt_long_slot_time =
+ pNetwork->bssht.bd_rt2rt_long_slot_time;
- HTIOTPeerDetermine(ieee);
+ ht_iot_peer_determine(ieee);
ht_info->iot_action = 0;
- bIOTAction = HTIOTActIsMgntUseCCK6M(ieee, pNetwork);
+ bIOTAction = ht_iot_act_is_mgnt_use_cck_6m(ieee, pNetwork);
if (bIOTAction)
ht_info->iot_action |= HT_IOT_ACT_MGNT_USE_CCK_6M;
- bIOTAction = HTIOTActIsCCDFsync(ieee);
+ bIOTAction = ht_iot_act_is_ccd_fsync(ieee);
if (bIOTAction)
ht_info->iot_action |= HT_IOT_ACT_CDD_FSYNC;
} else {
ht_info->current_ht_support = false;
ht_info->current_rt2rt_aggregation = false;
ht_info->current_rt2rt_long_slot_time = false;
- ht_info->RT2RT_HT_Mode = (enum rt_ht_capability)0;
ht_info->iot_action = 0;
ht_info->iot_ra_func = 0;
@@ -706,7 +622,7 @@ void HT_update_self_and_peer_setting(struct rtllib_device *ieee,
}
EXPORT_SYMBOL(HT_update_self_and_peer_setting);
-u8 HTCCheck(struct rtllib_device *ieee, u8 *pFrame)
+u8 ht_c_check(struct rtllib_device *ieee, u8 *pFrame)
{
if (ieee->ht_info->current_ht_support) {
if ((IsQoSDataFrame(pFrame) && Frame_Order(pFrame)) == 1) {
@@ -717,11 +633,11 @@ u8 HTCCheck(struct rtllib_device *ieee, u8 *pFrame)
return false;
}
-static void HTSetConnectBwModeCallback(struct rtllib_device *ieee)
+static void ht_set_connect_bw_mode_callback(struct rtllib_device *ieee)
{
struct rt_hi_throughput *ht_info = ieee->ht_info;
- if (ht_info->bCurBW40MHz) {
+ if (ht_info->cur_bw_40mhz) {
if (ht_info->CurSTAExtChnlOffset == HT_EXTCHNL_OFFSET_UPPER)
ieee->set_chan(ieee->dev,
ieee->current_network.channel + 2);
@@ -744,15 +660,12 @@ static void HTSetConnectBwModeCallback(struct rtllib_device *ieee)
ht_info->sw_bw_in_progress = false;
}
-void HTSetConnectBwMode(struct rtllib_device *ieee,
+void ht_set_connect_bw_mode(struct rtllib_device *ieee,
enum ht_channel_width bandwidth,
enum ht_extchnl_offset Offset)
{
struct rt_hi_throughput *ht_info = ieee->ht_info;
- if (!ht_info->bRegBW40MHz)
- return;
-
if (ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev))
bandwidth = HT_CHANNEL_WIDTH_20;
@@ -766,21 +679,21 @@ void HTSetConnectBwMode(struct rtllib_device *ieee,
Offset = HT_EXTCHNL_OFFSET_NO_EXT;
if (Offset == HT_EXTCHNL_OFFSET_UPPER ||
Offset == HT_EXTCHNL_OFFSET_LOWER) {
- ht_info->bCurBW40MHz = true;
+ ht_info->cur_bw_40mhz = true;
ht_info->CurSTAExtChnlOffset = Offset;
} else {
- ht_info->bCurBW40MHz = false;
+ ht_info->cur_bw_40mhz = false;
ht_info->CurSTAExtChnlOffset = HT_EXTCHNL_OFFSET_NO_EXT;
}
} else {
- ht_info->bCurBW40MHz = false;
+ ht_info->cur_bw_40mhz = false;
ht_info->CurSTAExtChnlOffset = HT_EXTCHNL_OFFSET_NO_EXT;
}
netdev_dbg(ieee->dev, "%s():ht_info->bCurBW40MHz:%x\n", __func__,
- ht_info->bCurBW40MHz);
+ ht_info->cur_bw_40mhz);
ht_info->sw_bw_in_progress = true;
- HTSetConnectBwModeCallback(ieee);
+ ht_set_connect_bw_mode_callback(ieee);
}
diff --git a/drivers/staging/rtl8192e/rtl819x_Qos.h b/drivers/staging/rtl8192e/rtl819x_Qos.h
index 1c00092ea3a5..50e01ca49a4c 100644
--- a/drivers/staging/rtl8192e/rtl819x_Qos.h
+++ b/drivers/staging/rtl8192e/rtl819x_Qos.h
@@ -8,7 +8,7 @@
#define __INC_QOS_TYPE_H
struct qos_tsinfo {
- u8 ucTSID:4;
+ u8 ts_id:4;
u8 ucDirection:2;
};
diff --git a/drivers/staging/rtl8192e/rtl819x_TS.h b/drivers/staging/rtl8192e/rtl819x_TS.h
index fff36315f174..5b0e4cb572d2 100644
--- a/drivers/staging/rtl8192e/rtl819x_TS.h
+++ b/drivers/staging/rtl8192e/rtl819x_TS.h
@@ -17,21 +17,21 @@ enum tr_select {
};
struct ts_common_info {
- struct list_head List;
+ struct list_head list;
u8 addr[ETH_ALEN];
- struct qos_tsinfo TSpec;
+ struct qos_tsinfo tspec;
};
struct tx_ts_record {
- struct ts_common_info TsCommonInfo;
- u16 TxCurSeq;
- struct ba_record TxPendingBARecord;
- struct ba_record TxAdmittedBARecord;
- u8 bAddBaReqInProgress;
- u8 bAddBaReqDelayed;
- u8 bUsingBa;
- u8 bDisable_AddBa;
- struct timer_list TsAddBaTimer;
+ struct ts_common_info ts_common_info;
+ u16 tx_cur_seq;
+ struct ba_record tx_pending_ba_record;
+ struct ba_record tx_admitted_ba_record;
+ u8 add_ba_req_in_progress;
+ u8 add_ba_req_delayed;
+ u8 using_ba;
+ u8 disable_add_ba;
+ struct timer_list ts_add_ba_timer;
u8 num;
};
diff --git a/drivers/staging/rtl8192e/rtl819x_TSProc.c b/drivers/staging/rtl8192e/rtl819x_TSProc.c
index 3206fdb3e65a..7e73d31dcccf 100644
--- a/drivers/staging/rtl8192e/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192e/rtl819x_TSProc.c
@@ -12,7 +12,7 @@ static void RxPktPendingTimeout(struct timer_list *t)
{
struct rx_ts_record *ts = from_timer(ts, t, rx_pkt_pending_timer);
struct rtllib_device *ieee = container_of(ts, struct rtllib_device,
- RxTsRecord[ts->num]);
+ rx_ts_records[ts->num]);
struct rx_reorder_entry *pReorderEntry = NULL;
@@ -25,7 +25,7 @@ static void RxPktPendingTimeout(struct timer_list *t)
while (!list_empty(&ts->rx_pending_pkt_list)) {
pReorderEntry = (struct rx_reorder_entry *)
list_entry(ts->rx_pending_pkt_list.prev,
- struct rx_reorder_entry, List);
+ struct rx_reorder_entry, list);
if (index == 0)
ts->rx_indicate_seq = pReorderEntry->SeqNum;
@@ -33,7 +33,7 @@ static void RxPktPendingTimeout(struct timer_list *t)
ts->rx_indicate_seq) ||
SN_EQUAL(pReorderEntry->SeqNum,
ts->rx_indicate_seq)) {
- list_del_init(&pReorderEntry->List);
+ list_del_init(&pReorderEntry->list);
if (SN_EQUAL(pReorderEntry->SeqNum,
ts->rx_indicate_seq))
@@ -47,7 +47,7 @@ static void RxPktPendingTimeout(struct timer_list *t)
pReorderEntry->prxb;
index++;
- list_add_tail(&pReorderEntry->List,
+ list_add_tail(&pReorderEntry->list,
&ieee->RxReorder_Unused_List);
} else {
bPktInBuf = true;
@@ -82,31 +82,31 @@ static void RxPktPendingTimeout(struct timer_list *t)
static void TsAddBaProcess(struct timer_list *t)
{
- struct tx_ts_record *pTxTs = from_timer(pTxTs, t, TsAddBaTimer);
- u8 num = pTxTs->num;
- struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device,
- TxTsRecord[num]);
+ struct tx_ts_record *ts = from_timer(ts, t, ts_add_ba_timer);
+ u8 num = ts->num;
+ struct rtllib_device *ieee = container_of(ts, struct rtllib_device,
+ tx_ts_records[num]);
- rtllib_ts_init_add_ba(ieee, pTxTs, BA_POLICY_IMMEDIATE, false);
+ rtllib_ts_init_add_ba(ieee, ts, BA_POLICY_IMMEDIATE, false);
netdev_dbg(ieee->dev, "%s(): ADDBA Req is started\n", __func__);
}
-static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo)
+static void ResetTsCommonInfo(struct ts_common_info *ts_common_info)
{
- eth_zero_addr(pTsCommonInfo->addr);
- memset(&pTsCommonInfo->TSpec, 0, sizeof(struct qos_tsinfo));
+ eth_zero_addr(ts_common_info->addr);
+ memset(&ts_common_info->tspec, 0, sizeof(struct qos_tsinfo));
}
static void ResetTxTsEntry(struct tx_ts_record *ts)
{
- ResetTsCommonInfo(&ts->TsCommonInfo);
- ts->TxCurSeq = 0;
- ts->bAddBaReqInProgress = false;
- ts->bAddBaReqDelayed = false;
- ts->bUsingBa = false;
- ts->bDisable_AddBa = false;
- rtllib_reset_ba_entry(&ts->TxAdmittedBARecord);
- rtllib_reset_ba_entry(&ts->TxPendingBARecord);
+ ResetTsCommonInfo(&ts->ts_common_info);
+ ts->tx_cur_seq = 0;
+ ts->add_ba_req_in_progress = false;
+ ts->add_ba_req_delayed = false;
+ ts->using_ba = false;
+ ts->disable_add_ba = false;
+ rtllib_reset_ba_entry(&ts->tx_admitted_ba_record);
+ rtllib_reset_ba_entry(&ts->tx_pending_ba_record);
}
static void ResetRxTsEntry(struct rx_ts_record *ts)
@@ -119,8 +119,8 @@ static void ResetRxTsEntry(struct rx_ts_record *ts)
void rtllib_ts_init(struct rtllib_device *ieee)
{
- struct tx_ts_record *pTxTS = ieee->TxTsRecord;
- struct rx_ts_record *rxts = ieee->RxTsRecord;
+ struct tx_ts_record *pTxTS = ieee->tx_ts_records;
+ struct rx_ts_record *rxts = ieee->rx_ts_records;
struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry;
u8 count = 0;
@@ -130,15 +130,15 @@ void rtllib_ts_init(struct rtllib_device *ieee)
for (count = 0; count < TOTAL_TS_NUM; count++) {
pTxTS->num = count;
- timer_setup(&pTxTS->TsAddBaTimer, TsAddBaProcess, 0);
+ timer_setup(&pTxTS->ts_add_ba_timer, TsAddBaProcess, 0);
- timer_setup(&pTxTS->TxPendingBARecord.timer, rtllib_ba_setup_timeout,
+ timer_setup(&pTxTS->tx_pending_ba_record.timer, rtllib_ba_setup_timeout,
0);
- timer_setup(&pTxTS->TxAdmittedBARecord.timer,
+ timer_setup(&pTxTS->tx_admitted_ba_record.timer,
rtllib_tx_ba_inact_timeout, 0);
ResetTxTsEntry(pTxTS);
- list_add_tail(&pTxTS->TsCommonInfo.List,
+ list_add_tail(&pTxTS->ts_common_info.list,
&ieee->Tx_TS_Unused_List);
pTxTS++;
}
@@ -155,13 +155,13 @@ void rtllib_ts_init(struct rtllib_device *ieee)
timer_setup(&rxts->rx_pkt_pending_timer, RxPktPendingTimeout, 0);
ResetRxTsEntry(rxts);
- list_add_tail(&rxts->ts_common_info.List,
+ list_add_tail(&rxts->ts_common_info.list,
&ieee->Rx_TS_Unused_List);
rxts++;
}
INIT_LIST_HEAD(&ieee->RxReorder_Unused_List);
for (count = 0; count < REORDER_ENTRY_NUM; count++) {
- list_add_tail(&pRxReorderEntry->List,
+ list_add_tail(&pRxReorderEntry->list,
&ieee->RxReorder_Unused_List);
if (count == (REORDER_ENTRY_NUM - 1))
break;
@@ -196,31 +196,31 @@ static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee,
for (dir = 0; dir <= DIR_BI_DIR; dir++) {
if (!search_dir[dir])
continue;
- list_for_each_entry(pRet, psearch_list, List) {
+ list_for_each_entry(pRet, psearch_list, list) {
if (memcmp(pRet->addr, addr, 6) == 0 &&
- pRet->TSpec.ucTSID == TID &&
- pRet->TSpec.ucDirection == dir)
+ pRet->tspec.ts_id == TID &&
+ pRet->tspec.ucDirection == dir)
break;
}
- if (&pRet->List != psearch_list)
+ if (&pRet->list != psearch_list)
break;
}
- if (pRet && &pRet->List != psearch_list)
+ if (pRet && &pRet->list != psearch_list)
return pRet;
return NULL;
}
-static void MakeTSEntry(struct ts_common_info *pTsCommonInfo, u8 *addr,
+static void MakeTSEntry(struct ts_common_info *ts_common_info, u8 *addr,
struct qos_tsinfo *pTSPEC)
{
- if (!pTsCommonInfo)
+ if (!ts_common_info)
return;
- memcpy(pTsCommonInfo->addr, addr, 6);
+ memcpy(ts_common_info->addr, addr, 6);
if (pTSPEC)
- memcpy((u8 *)(&(pTsCommonInfo->TSpec)), (u8 *)pTSPEC,
+ memcpy((u8 *)(&(ts_common_info->tspec)), (u8 *)pTSPEC,
sizeof(struct qos_tsinfo));
}
@@ -228,8 +228,8 @@ bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS,
u8 *addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs)
{
u8 UP = 0;
- struct qos_tsinfo TSpec;
- struct qos_tsinfo *ts_info = &TSpec;
+ struct qos_tsinfo tspec;
+ struct qos_tsinfo *ts_info = &tspec;
struct list_head *pUnusedList;
struct list_head *pAddmitList;
enum direction_value Dir;
@@ -286,13 +286,13 @@ bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS,
if (!list_empty(pUnusedList)) {
(*ppTS) = list_entry(pUnusedList->next,
- struct ts_common_info, List);
- list_del_init(&(*ppTS)->List);
+ struct ts_common_info, list);
+ list_del_init(&(*ppTS)->list);
if (TxRxSelect == TX_DIR) {
struct tx_ts_record *tmp =
container_of(*ppTS,
struct tx_ts_record,
- TsCommonInfo);
+ ts_common_info);
ResetTxTsEntry(tmp);
} else {
struct rx_ts_record *ts =
@@ -305,11 +305,11 @@ bool rtllib_get_ts(struct rtllib_device *ieee, struct ts_common_info **ppTS,
netdev_dbg(ieee->dev,
"to init current TS, UP:%d, Dir:%d, addr: %pM ppTs=%p\n",
UP, Dir, addr, *ppTS);
- ts_info->ucTSID = UP;
+ ts_info->ts_id = UP;
ts_info->ucDirection = Dir;
- MakeTSEntry(*ppTS, addr, &TSpec);
- list_add_tail(&((*ppTS)->List), pAddmitList);
+ MakeTSEntry(*ppTS, addr, &tspec);
+ list_add_tail(&((*ppTS)->list), pAddmitList);
return true;
}
@@ -335,10 +335,10 @@ static void RemoveTsEntry(struct rtllib_device *ieee,
while (!list_empty(&ts->rx_pending_pkt_list)) {
pRxReorderEntry = (struct rx_reorder_entry *)
list_entry(ts->rx_pending_pkt_list.prev,
- struct rx_reorder_entry, List);
+ struct rx_reorder_entry, list);
netdev_dbg(ieee->dev, "%s(): Delete SeqNum %d!\n",
__func__, pRxReorderEntry->SeqNum);
- list_del_init(&pRxReorderEntry->List);
+ list_del_init(&pRxReorderEntry->list);
{
int i = 0;
struct rtllib_rxb *prxb = pRxReorderEntry->prxb;
@@ -350,13 +350,13 @@ static void RemoveTsEntry(struct rtllib_device *ieee,
kfree(prxb);
prxb = NULL;
}
- list_add_tail(&pRxReorderEntry->List,
+ list_add_tail(&pRxReorderEntry->list,
&ieee->RxReorder_Unused_List);
}
} else {
struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs;
- del_timer_sync(&pTxTS->TsAddBaTimer);
+ del_timer_sync(&pTxTS->ts_add_ba_timer);
}
}
@@ -366,37 +366,37 @@ void RemovePeerTS(struct rtllib_device *ieee, u8 *addr)
netdev_info(ieee->dev, "===========>%s, %pM\n", __func__, addr);
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Pending_List, List) {
+ list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Pending_List, list) {
if (memcmp(ts->addr, addr, 6) == 0) {
RemoveTsEntry(ieee, ts, TX_DIR);
- list_del_init(&ts->List);
- list_add_tail(&ts->List, &ieee->Tx_TS_Unused_List);
+ list_del_init(&ts->list);
+ list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List);
}
}
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Admit_List, List) {
+ list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Admit_List, list) {
if (memcmp(ts->addr, addr, 6) == 0) {
netdev_info(ieee->dev,
"====>remove Tx_TS_admin_list\n");
RemoveTsEntry(ieee, ts, TX_DIR);
- list_del_init(&ts->List);
- list_add_tail(&ts->List, &ieee->Tx_TS_Unused_List);
+ list_del_init(&ts->list);
+ list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List);
}
}
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Pending_List, List) {
+ list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Pending_List, list) {
if (memcmp(ts->addr, addr, 6) == 0) {
RemoveTsEntry(ieee, ts, RX_DIR);
- list_del_init(&ts->List);
- list_add_tail(&ts->List, &ieee->Rx_TS_Unused_List);
+ list_del_init(&ts->list);
+ list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List);
}
}
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Admit_List, List) {
+ list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Admit_List, list) {
if (memcmp(ts->addr, addr, 6) == 0) {
RemoveTsEntry(ieee, ts, RX_DIR);
- list_del_init(&ts->List);
- list_add_tail(&ts->List, &ieee->Rx_TS_Unused_List);
+ list_del_init(&ts->list);
+ list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List);
}
}
}
@@ -406,43 +406,43 @@ void RemoveAllTS(struct rtllib_device *ieee)
{
struct ts_common_info *ts, *pTmpTS;
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Pending_List, List) {
+ list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Pending_List, list) {
RemoveTsEntry(ieee, ts, TX_DIR);
- list_del_init(&ts->List);
- list_add_tail(&ts->List, &ieee->Tx_TS_Unused_List);
+ list_del_init(&ts->list);
+ list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List);
}
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Admit_List, List) {
+ list_for_each_entry_safe(ts, pTmpTS, &ieee->Tx_TS_Admit_List, list) {
RemoveTsEntry(ieee, ts, TX_DIR);
- list_del_init(&ts->List);
- list_add_tail(&ts->List, &ieee->Tx_TS_Unused_List);
+ list_del_init(&ts->list);
+ list_add_tail(&ts->list, &ieee->Tx_TS_Unused_List);
}
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Pending_List, List) {
+ list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Pending_List, list) {
RemoveTsEntry(ieee, ts, RX_DIR);
- list_del_init(&ts->List);
- list_add_tail(&ts->List, &ieee->Rx_TS_Unused_List);
+ list_del_init(&ts->list);
+ list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List);
}
- list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Admit_List, List) {
+ list_for_each_entry_safe(ts, pTmpTS, &ieee->Rx_TS_Admit_List, list) {
RemoveTsEntry(ieee, ts, RX_DIR);
- list_del_init(&ts->List);
- list_add_tail(&ts->List, &ieee->Rx_TS_Unused_List);
+ list_del_init(&ts->list);
+ list_add_tail(&ts->list, &ieee->Rx_TS_Unused_List);
}
}
void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS)
{
- if (pTxTS->bAddBaReqInProgress == false) {
- pTxTS->bAddBaReqInProgress = true;
+ if (pTxTS->add_ba_req_in_progress == false) {
+ pTxTS->add_ba_req_in_progress = true;
- if (pTxTS->bAddBaReqDelayed) {
+ if (pTxTS->add_ba_req_delayed) {
netdev_dbg(ieee->dev, "Start ADDBA after 60 sec!!\n");
- mod_timer(&pTxTS->TsAddBaTimer, jiffies +
+ mod_timer(&pTxTS->ts_add_ba_timer, jiffies +
msecs_to_jiffies(TS_ADDBA_DELAY));
} else {
netdev_dbg(ieee->dev, "Immediately Start ADDBA\n");
- mod_timer(&pTxTS->TsAddBaTimer, jiffies + 10);
+ mod_timer(&pTxTS->ts_add_ba_timer, jiffies + 10);
}
} else {
netdev_dbg(ieee->dev, "BA timer is already added\n");
diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h
index d2cf3cfaaaba..7b39a1987fdd 100644
--- a/drivers/staging/rtl8192e/rtllib.h
+++ b/drivers/staging/rtl8192e/rtllib.h
@@ -103,9 +103,6 @@ struct cb_desc {
/* Tx Desc Related flags (8-9) */
u8 bLastIniPkt:1;
u8 bCmdOrInit:1;
- u8 bFirstSeg:1;
- u8 bLastSeg:1;
- u8 bEncrypt:1;
u8 tx_dis_rate_fallback:1;
u8 tx_use_drv_assinged_rate:1;
u8 bHwSec:1;
@@ -117,8 +114,8 @@ struct cb_desc {
u8 bRTSEnable:1;
u8 bUseShortGI:1;
u8 bUseShortPreamble:1;
- u8 bTxEnableFwCalcDur:1;
- u8 bAMPDUEnable:1;
+ u8 tx_enable_fw_calc_dur:1;
+ u8 ampdu_enable:1;
u8 bRTSSTBC:1;
u8 RTSSC:1;
@@ -139,7 +136,6 @@ struct cb_desc {
u8 bAMSDU:1;
u8 bFromAggrQ:1;
u8 reserved6:6;
- u8 macId;
u8 priority;
/* Tx firmware related element(20-27) */
@@ -471,7 +467,6 @@ enum _REG_PREAMBLE_MODE {
* any adverse affects.
*/
struct rtllib_rx_stats {
- u64 mac_time;
s8 rssi;
u8 signal;
u8 noise;
@@ -1047,7 +1042,7 @@ struct bandwidth_autoswitch {
#define REORDER_WIN_SIZE 128
#define REORDER_ENTRY_NUM 128
struct rx_reorder_entry {
- struct list_head List;
+ struct list_head list;
u16 SeqNum;
struct rtllib_rxb *prxb;
};
@@ -1123,8 +1118,8 @@ struct rt_link_detect {
u16 SlotNum;
u16 SlotIndex;
- u32 NumTxOkInPeriod;
- u32 NumRxOkInPeriod;
+ u32 num_tx_ok_in_period;
+ u32 num_rx_ok_in_period;
u32 NumRxUnicastOkInPeriod;
bool bBusyTraffic;
bool bHigherBusyTraffic;
@@ -1169,7 +1164,7 @@ struct rt_pmkid_list {
u8 Bssid[ETH_ALEN];
u8 PMKID[16];
u8 SsidBuf[33];
- u8 bUsed;
+ u8 used;
};
/*************** DRIVER STATUS *****/
@@ -1192,7 +1187,7 @@ struct rtllib_device {
unsigned long status;
u8 CntAfterLink;
- enum rt_op_mode OpMode;
+ enum rt_op_mode op_mode;
/* The last AssocReq/Resp IEs */
u8 *assocreq_ies, *assocresp_ies;
@@ -1224,17 +1219,17 @@ struct rtllib_device {
u8 HTHighestOperaRate;
u8 tx_dis_rate_fallback;
u8 tx_use_drv_assinged_rate;
- u8 bTxEnableFwCalcDur;
+ u8 tx_enable_fw_calc_dur;
atomic_t atm_swbw;
struct list_head Tx_TS_Admit_List;
struct list_head Tx_TS_Pending_List;
struct list_head Tx_TS_Unused_List;
- struct tx_ts_record TxTsRecord[TOTAL_TS_NUM];
+ struct tx_ts_record tx_ts_records[TOTAL_TS_NUM];
struct list_head Rx_TS_Admit_List;
struct list_head Rx_TS_Pending_List;
struct list_head Rx_TS_Unused_List;
- struct rx_ts_record RxTsRecord[TOTAL_TS_NUM];
+ struct rx_ts_record rx_ts_records[TOTAL_TS_NUM];
struct rx_reorder_entry RxReorderEntry[128];
struct list_head RxReorder_Unused_List;
@@ -1321,12 +1316,8 @@ struct rtllib_device {
u16 scan_watch_dog;
/* map of allowed channels. 0 is dummy */
- void *dot11d_info;
- bool global_domain;
u8 active_channel_map[MAX_CHANNEL_NUMBER+1];
- u8 bss_start_channel;
-
int rate; /* current rate */
int basic_rate;
@@ -1391,7 +1382,7 @@ struct rtllib_device {
int mgmt_queue_head;
int mgmt_queue_tail;
u8 AsocRetryCount;
- struct sk_buff_head skb_waitQ[MAX_QUEUE_SIZE];
+ struct sk_buff_head skb_waitq[MAX_QUEUE_SIZE];
bool bdynamic_txpower_enable;
@@ -1411,7 +1402,7 @@ struct rtllib_device {
bool FwRWRF;
struct rt_link_detect link_detect_info;
- bool bIsAggregateFrame;
+ bool is_aggregate_frame;
struct rt_pwr_save_ctrl pwr_save_ctrl;
/* used if IEEE_SOFTMAC_TX_QUEUE is set */
@@ -1421,7 +1412,6 @@ struct rtllib_device {
struct timer_list associate_timer;
/* used if IEEE_SOFTMAC_BEACONS is set */
- struct timer_list beacon_timer;
u8 need_sw_enc;
struct work_struct associate_complete_wq;
struct work_struct ips_leave_wq;
@@ -1469,7 +1459,7 @@ struct rtllib_device {
* This function can sleep. the driver should ensure
* the radio has been switched before return.
*/
- void (*set_chan)(struct net_device *dev, short ch);
+ void (*set_chan)(struct net_device *dev, u8 ch);
/* indicate the driver that the link state is changed
* for example it may indicate the card is associated now.
@@ -1687,8 +1677,8 @@ void rtllib_sta_ps_send_pspoll_frame(struct rtllib_device *ieee);
void rtllib_start_protocol(struct rtllib_device *ieee);
void rtllib_stop_protocol(struct rtllib_device *ieee);
-void rtllib_EnableNetMonitorMode(struct net_device *dev, bool bInitState);
-void rtllib_DisableNetMonitorMode(struct net_device *dev, bool bInitState);
+void rtllib_enable_net_monitor_mode(struct net_device *dev, bool init_state);
+void rtllib_disable_net_monitor_mode(struct net_device *dev, bool init_state);
void rtllib_softmac_stop_protocol(struct rtllib_device *ieee);
void rtllib_softmac_start_protocol(struct rtllib_device *ieee);
@@ -1696,7 +1686,6 @@ void rtllib_softmac_start_protocol(struct rtllib_device *ieee);
void rtllib_reset_queue(struct rtllib_device *ieee);
void rtllib_wake_all_queues(struct rtllib_device *ieee);
void rtllib_stop_all_queues(struct rtllib_device *ieee);
-struct sk_buff *rtllib_get_beacon(struct rtllib_device *ieee);
void notify_wx_assoc_event(struct rtllib_device *ieee);
void rtllib_ps_tx_ack(struct rtllib_device *ieee, short success);
@@ -1758,39 +1747,37 @@ int rtllib_wx_get_rts(struct rtllib_device *ieee, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra);
#define MAX_RECEIVE_BUFFER_SIZE 9100
-void HTSetConnectBwMode(struct rtllib_device *ieee,
+void ht_set_connect_bw_mode(struct rtllib_device *ieee,
enum ht_channel_width bandwidth,
enum ht_extchnl_offset Offset);
void ht_update_default_setting(struct rtllib_device *ieee);
-void HTConstructCapabilityElement(struct rtllib_device *ieee,
+void ht_construct_capability_element(struct rtllib_device *ieee,
u8 *posHTCap, u8 *len,
u8 isEncrypt, bool bAssoc);
-void HTConstructInfoElement(struct rtllib_device *ieee,
- u8 *posHTInfo, u8 *len, u8 isEncrypt);
-void HTConstructRT2RTAggElement(struct rtllib_device *ieee,
+void ht_construct_rt2rt_agg_element(struct rtllib_device *ieee,
u8 *posRT2RTAgg, u8 *len);
-void HTOnAssocRsp(struct rtllib_device *ieee);
-void HTInitializeHTInfo(struct rtllib_device *ieee);
-void HTInitializeBssDesc(struct bss_ht *pBssHT);
-void HTResetSelfAndSavePeerSetting(struct rtllib_device *ieee,
+void ht_on_assoc_rsp(struct rtllib_device *ieee);
+void ht_initialize_ht_info(struct rtllib_device *ieee);
+void ht_initialize_bss_desc(struct bss_ht *pBssHT);
+void ht_reset_self_and_save_peer_setting(struct rtllib_device *ieee,
struct rtllib_network *pNetwork);
void HT_update_self_and_peer_setting(struct rtllib_device *ieee,
struct rtllib_network *pNetwork);
-u8 HTGetHighestMCSRate(struct rtllib_device *ieee, u8 *pMCSRateSet,
+u8 ht_get_highest_mcs_rate(struct rtllib_device *ieee, u8 *pMCSRateSet,
u8 *pMCSFilter);
extern u8 MCS_FILTER_ALL[];
extern u16 MCS_DATA_RATE[2][2][77];
-u8 HTCCheck(struct rtllib_device *ieee, u8 *pFrame);
-void HTResetIOTSetting(struct rt_hi_throughput *ht_info);
-bool IsHTHalfNmodeAPs(struct rtllib_device *ieee);
-u16 TxCountToDataRate(struct rtllib_device *ieee, u8 nDataRate);
+u8 ht_c_check(struct rtllib_device *ieee, u8 *pFrame);
+void ht_reset_iot_setting(struct rt_hi_throughput *ht_info);
+bool is_ht_half_nmode_aps(struct rtllib_device *ieee);
+u16 tx_count_to_data_rate(struct rtllib_device *ieee, u8 nDataRate);
int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb);
int rtllib_rx_ADDBARsp(struct rtllib_device *ieee, struct sk_buff *skb);
int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb);
void rtllib_ts_init_add_ba(struct rtllib_device *ieee, struct tx_ts_record *ts,
- u8 policy, u8 bOverwritePending);
+ u8 policy, u8 overwrite_pending);
void rtllib_ts_init_del_ba(struct rtllib_device *ieee,
- struct ts_common_info *pTsCommonInfo,
+ struct ts_common_info *ts_common_info,
enum tr_select TxRxSelect);
void rtllib_ba_setup_timeout(struct timer_list *t);
void rtllib_tx_ba_inact_timeout(struct timer_list *t);
diff --git a/drivers/staging/rtl8192e/rtllib_module.c b/drivers/staging/rtl8192e/rtllib_module.c
index 95b6d6b9429c..e7af4a25b0be 100644
--- a/drivers/staging/rtl8192e/rtllib_module.c
+++ b/drivers/staging/rtl8192e/rtllib_module.c
@@ -123,7 +123,7 @@ struct net_device *alloc_rtllib(int sizeof_priv)
goto free_softmac;
ht_update_default_setting(ieee);
- HTInitializeHTInfo(ieee);
+ ht_initialize_ht_info(ieee);
rtllib_ts_init(ieee);
for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++)
INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]);
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index ecaa4dec3f94..4df20f4d6bf9 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -34,7 +34,6 @@
#include <linux/ctype.h>
#include "rtllib.h"
-#include "dot11d.h"
static void rtllib_rx_mgt(struct rtllib_device *ieee, struct sk_buff *skb,
struct rtllib_rx_stats *stats);
@@ -412,19 +411,19 @@ static bool AddReorderEntry(struct rx_ts_record *ts,
while (pList->next != &ts->rx_pending_pkt_list) {
if (SN_LESS(pReorderEntry->SeqNum, ((struct rx_reorder_entry *)
list_entry(pList->next, struct rx_reorder_entry,
- List))->SeqNum))
+ list))->SeqNum))
pList = pList->next;
else if (SN_EQUAL(pReorderEntry->SeqNum,
((struct rx_reorder_entry *)list_entry(pList->next,
- struct rx_reorder_entry, List))->SeqNum))
+ struct rx_reorder_entry, list))->SeqNum))
return false;
else
break;
}
- pReorderEntry->List.next = pList->next;
- pReorderEntry->List.next->prev = &pReorderEntry->List;
- pReorderEntry->List.prev = pList;
- pList->next = &pReorderEntry->List;
+ pReorderEntry->list.next = pList->next;
+ pReorderEntry->list.next->prev = &pReorderEntry->list;
+ pReorderEntry->list.prev = pList;
+ pList->next = &pReorderEntry->list;
return true;
}
@@ -505,15 +504,15 @@ void rtllib_FlushRxTsPendingPkts(struct rtllib_device *ieee,
pRxReorderEntry = (struct rx_reorder_entry *)
list_entry(ts->rx_pending_pkt_list.prev,
- struct rx_reorder_entry, List);
+ struct rx_reorder_entry, list);
netdev_dbg(ieee->dev, "%s(): Indicate SeqNum %d!\n", __func__,
pRxReorderEntry->SeqNum);
- list_del_init(&pRxReorderEntry->List);
+ list_del_init(&pRxReorderEntry->list);
ieee->RfdArray[RfdCnt] = pRxReorderEntry->prxb;
RfdCnt = RfdCnt + 1;
- list_add_tail(&pRxReorderEntry->List,
+ list_add_tail(&pRxReorderEntry->list,
&ieee->RxReorder_Unused_List);
}
rtllib_indicate_packets(ieee, ieee->RfdArray, RfdCnt);
@@ -602,8 +601,8 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
if (!list_empty(&ieee->RxReorder_Unused_List)) {
pReorderEntry = (struct rx_reorder_entry *)
list_entry(ieee->RxReorder_Unused_List.next,
- struct rx_reorder_entry, List);
- list_del_init(&pReorderEntry->List);
+ struct rx_reorder_entry, list);
+ list_del_init(&pReorderEntry->list);
/* Make a reorder entry and insert
* into a the packet list.
@@ -618,7 +617,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
"%s(): Duplicate packet is dropped. IndicateSeq: %d, NewSeq: %d\n",
__func__, ts->rx_indicate_seq,
SeqNum);
- list_add_tail(&pReorderEntry->List,
+ list_add_tail(&pReorderEntry->list,
&ieee->RxReorder_Unused_List);
for (i = 0; i < prxb->nr_subframes; i++)
@@ -658,7 +657,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
pReorderEntry = (struct rx_reorder_entry *)
list_entry(ts->rx_pending_pkt_list.prev,
struct rx_reorder_entry,
- List);
+ list);
if (SN_LESS(pReorderEntry->SeqNum, ts->rx_indicate_seq) ||
SN_EQUAL(pReorderEntry->SeqNum, ts->rx_indicate_seq)) {
/* This protect struct buffer from overflow. */
@@ -670,7 +669,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
break;
}
- list_del_init(&pReorderEntry->List);
+ list_del_init(&pReorderEntry->list);
if (SN_EQUAL(pReorderEntry->SeqNum, ts->rx_indicate_seq))
ts->rx_indicate_seq = (ts->rx_indicate_seq + 1) %
@@ -681,7 +680,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
__func__, pReorderEntry->SeqNum);
index++;
- list_add_tail(&pReorderEntry->List,
+ list_add_tail(&pReorderEntry->list,
&ieee->RxReorder_Unused_List);
} else {
bPktInBuf = true;
@@ -731,7 +730,7 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb,
u16 LLCOffset = sizeof(struct ieee80211_hdr_3addr);
u16 ChkLength;
- bool bIsAggregateFrame = false;
+ bool is_aggregate_frame = false;
u16 nSubframe_Length;
u8 nPadding_Length = 0;
u16 SeqNum = 0;
@@ -740,7 +739,7 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb,
SeqNum = WLAN_GET_SEQ_SEQ(le16_to_cpu(hdr->seq_ctrl));
if ((RTLLIB_QOS_HAS_SEQ(fc)) &&
(((union frameqos *)(skb->data + RTLLIB_3ADDR_LEN))->field.reserved))
- bIsAggregateFrame = true;
+ is_aggregate_frame = true;
if (RTLLIB_QOS_HAS_SEQ(fc))
LLCOffset += 2;
@@ -753,8 +752,8 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb,
return 0;
skb_pull(skb, LLCOffset);
- ieee->bIsAggregateFrame = bIsAggregateFrame;
- if (!bIsAggregateFrame) {
+ ieee->is_aggregate_frame = is_aggregate_frame;
+ if (!is_aggregate_frame) {
rxb->nr_subframes = 1;
/* altered by clark 3/30/2010
@@ -858,7 +857,7 @@ static size_t rtllib_rx_get_hdrlen(struct rtllib_device *ieee,
size_t hdrlen;
hdrlen = rtllib_get_hdrlen(fc);
- if (HTCCheck(ieee, skb->data)) {
+ if (ht_c_check(ieee, skb->data)) {
if (net_ratelimit())
netdev_info(ieee->dev, "%s: find HTCControl!\n",
__func__);
@@ -1151,7 +1150,7 @@ static void rtllib_rx_check_leave_lps(struct rtllib_device *ieee, u8 unicast,
if (unicast) {
if (ieee->link_state == MAC80211_LINKED) {
if (((ieee->link_detect_info.NumRxUnicastOkInPeriod +
- ieee->link_detect_info.NumTxOkInPeriod) > 8) ||
+ ieee->link_detect_info.num_tx_ok_in_period) > 8) ||
(ieee->link_detect_info.NumRxUnicastOkInPeriod > 2)) {
ieee->leisure_ps_leave(ieee->dev);
}
@@ -1286,7 +1285,7 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb,
/* Update statstics for AP roaming */
ieee->link_detect_info.NumRecvDataInPeriod++;
- ieee->link_detect_info.NumRxOkInPeriod++;
+ ieee->link_detect_info.num_rx_ok_in_period++;
/* Data frame - extract src/dst addresses */
rtllib_rx_extract_addr(ieee, hdr, dst, src, bssid);
@@ -1359,7 +1358,7 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb,
/* Update WAPI PN */
/* Check if leave LPS */
- if (ieee->bIsAggregateFrame)
+ if (ieee->is_aggregate_frame)
nr_subframes = rxb->nr_subframes;
else
nr_subframes = 1;
@@ -1402,7 +1401,7 @@ static int rtllib_rx_Monitor(struct rtllib_device *ieee, struct sk_buff *skb,
return 0;
}
- if (HTCCheck(ieee, skb->data)) {
+ if (ht_c_check(ieee, skb->data)) {
if (net_ratelimit())
netdev_info(ieee->dev, "%s: Find HTCControl!\n",
__func__);
@@ -1663,35 +1662,6 @@ static const char *get_info_element_string(u16 id)
}
}
-static inline void rtllib_extract_country_ie(
- struct rtllib_device *ieee,
- struct rtllib_info_element *info_element,
- struct rtllib_network *network,
- u8 *addr2)
-{
- if (IS_DOT11D_ENABLE(ieee)) {
- if (info_element->len != 0) {
- memcpy(network->CountryIeBuf, info_element->data,
- info_element->len);
- network->CountryIeLen = info_element->len;
-
- if (!IS_COUNTRY_IE_VALID(ieee)) {
- if (rtllib_act_scanning(ieee, false) &&
- ieee->FirstIe_InScan)
- netdev_info(ieee->dev,
- "Received beacon CountryIE, SSID: <%s>\n",
- network->ssid);
- dot11d_update_country(ieee, addr2,
- info_element->len,
- info_element->data);
- }
- }
-
- if (IS_EQUAL_CIE_SRC(ieee, addr2))
- UPDATE_CIE_WATCHDOG(ieee);
- }
-}
-
static void rtllib_parse_mife_generic(struct rtllib_device *ieee,
struct rtllib_info_element *info_element,
struct rtllib_network *network,
@@ -2146,8 +2116,6 @@ int rtllib_parse_info_param(struct rtllib_device *ieee,
case MFIE_TYPE_COUNTRY:
netdev_dbg(ieee->dev, "MFIE_TYPE_COUNTRY: %d bytes\n",
info_element->len);
- rtllib_extract_country_ie(ieee, info_element, network,
- network->bssid);
break;
/* TODO */
default:
@@ -2221,7 +2189,7 @@ static inline int rtllib_network_init(
network->RSSI = stats->SignalStrength;
network->CountryIeLen = 0;
memset(network->CountryIeBuf, 0, MAX_IE_LEN);
- HTInitializeBssDesc(&network->bssht);
+ ht_initialize_bss_desc(&network->bssht);
network->flags |= NETWORK_HAS_CCK;
network->wpa_ie_len = 0;
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c
index 42d652fe8601..b9278b26accd 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac.c
@@ -18,7 +18,6 @@
#include <linux/uaccess.h>
#include <linux/etherdevice.h>
#include <linux/ieee80211.h>
-#include "dot11d.h"
static void rtllib_sta_wakeup(struct rtllib_device *ieee, short nl);
@@ -45,7 +44,7 @@ static unsigned int rtllib_MFIE_rate_len(struct rtllib_device *ieee)
* Then it updates the pointer so that
* it points after the new MFIE tag added.
*/
-static void rtllib_MFIE_Brate(struct rtllib_device *ieee, u8 **tag_p)
+static void rtllib_mfie_brate(struct rtllib_device *ieee, u8 **tag_p)
{
u8 *tag = *tag_p;
@@ -62,7 +61,7 @@ static void rtllib_MFIE_Brate(struct rtllib_device *ieee, u8 **tag_p)
*tag_p = tag;
}
-static void rtllib_MFIE_Grate(struct rtllib_device *ieee, u8 **tag_p)
+static void rtllib_mfie_grate(struct rtllib_device *ieee, u8 **tag_p)
{
u8 *tag = *tag_p;
@@ -83,7 +82,7 @@ static void rtllib_MFIE_Grate(struct rtllib_device *ieee, u8 **tag_p)
*tag_p = tag;
}
-static void rtllib_WMM_Info(struct rtllib_device *ieee, u8 **tag_p)
+static void rtllib_wmm_info(struct rtllib_device *ieee, u8 **tag_p)
{
u8 *tag = *tag_p;
@@ -99,7 +98,7 @@ static void rtllib_WMM_Info(struct rtllib_device *ieee, u8 **tag_p)
*tag_p = tag;
}
-static void rtllib_TURBO_Info(struct rtllib_device *ieee, u8 **tag_p)
+static void rtllib_turbo_info(struct rtllib_device *ieee, u8 **tag_p)
{
u8 *tag = *tag_p;
@@ -135,32 +134,33 @@ static void enqueue_mgmt(struct rtllib_device *ieee, struct sk_buff *skb)
static void init_mgmt_queue(struct rtllib_device *ieee)
{
- ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0;
+ ieee->mgmt_queue_tail = 0;
+ ieee->mgmt_queue_head = 0;
}
u8 MgntQuery_TxRateExcludeCCKRates(struct rtllib_device *ieee)
{
u16 i;
- u8 QueryRate = 0;
- u8 BasicRate;
+ u8 query_rate = 0;
+ u8 basic_rate;
for (i = 0; i < ieee->current_network.rates_len; i++) {
- BasicRate = ieee->current_network.rates[i] & 0x7F;
- if (!rtllib_is_cck_rate(BasicRate)) {
- if (QueryRate == 0) {
- QueryRate = BasicRate;
+ basic_rate = ieee->current_network.rates[i] & 0x7F;
+ if (!rtllib_is_cck_rate(basic_rate)) {
+ if (query_rate == 0) {
+ query_rate = basic_rate;
} else {
- if (BasicRate < QueryRate)
- QueryRate = BasicRate;
+ if (basic_rate < query_rate)
+ query_rate = basic_rate;
}
}
}
- if (QueryRate == 0) {
- QueryRate = 12;
- netdev_info(ieee->dev, "No BasicRate found!!\n");
+ if (query_rate == 0) {
+ query_rate = 12;
+ netdev_info(ieee->dev, "No basic_rate found!!\n");
}
- return QueryRate;
+ return query_rate;
}
static u8 MgntQuery_MgntFrameTxRate(struct rtllib_device *ieee)
@@ -173,12 +173,8 @@ static u8 MgntQuery_MgntFrameTxRate(struct rtllib_device *ieee)
else
rate = ieee->basic_rate & 0x7f;
- if (rate == 0) {
- if (ieee->mode == WIRELESS_MODE_N_24G && !ht_info->bCurSuppCCK)
- rate = 0x0c;
- else
- rate = 0x02;
- }
+ if (rate == 0)
+ rate = 0x02;
return rate;
}
@@ -240,7 +236,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct rtllib_device *ieee)
/* check whether the managed packet queued greater than 5 */
if (!ieee->check_nic_enough_desc(ieee->dev,
tcb_desc->queue_index) ||
- skb_queue_len(&ieee->skb_waitQ[tcb_desc->queue_index]) ||
+ skb_queue_len(&ieee->skb_waitq[tcb_desc->queue_index]) ||
ieee->queue_stop) {
/* insert the skb packet to the management queue
*
@@ -250,7 +246,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct rtllib_device *ieee)
netdev_info(ieee->dev,
"%s():insert to waitqueue, queue_index:%d!\n",
__func__, tcb_desc->queue_index);
- skb_queue_tail(&ieee->skb_waitQ[tcb_desc->queue_index],
+ skb_queue_tail(&ieee->skb_waitq[tcb_desc->queue_index],
skb);
} else {
ieee->softmac_hard_start_xmit(skb, ieee->dev);
@@ -345,65 +341,34 @@ static inline struct sk_buff *rtllib_probe_req(struct rtllib_device *ieee)
memcpy(tag, ieee->current_network.ssid, len);
tag += len;
- rtllib_MFIE_Brate(ieee, &tag);
- rtllib_MFIE_Grate(ieee, &tag);
+ rtllib_mfie_brate(ieee, &tag);
+ rtllib_mfie_grate(ieee, &tag);
return skb;
}
-static struct sk_buff *rtllib_get_beacon_(struct rtllib_device *ieee);
-
-static void rtllib_send_beacon(struct rtllib_device *ieee)
-{
- struct sk_buff *skb;
-
- if (!ieee->ieee_up)
- return;
- skb = rtllib_get_beacon_(ieee);
-
- if (skb) {
- softmac_mgmt_xmit(skb, ieee);
- ieee->softmac_stats.tx_beacons++;
- }
-
- if (ieee->beacon_txing && ieee->ieee_up)
- mod_timer(&ieee->beacon_timer, jiffies +
- (msecs_to_jiffies(ieee->current_network.beacon_interval - 5)));
-}
-
-static void rtllib_send_beacon_cb(struct timer_list *t)
-{
- struct rtllib_device *ieee =
- from_timer(ieee, t, beacon_timer);
- unsigned long flags;
-
- spin_lock_irqsave(&ieee->beacon_lock, flags);
- rtllib_send_beacon(ieee);
- spin_unlock_irqrestore(&ieee->beacon_lock, flags);
-}
-
/* Enables network monitor mode, all rx packets will be received. */
-void rtllib_EnableNetMonitorMode(struct net_device *dev,
- bool bInitState)
+void rtllib_enable_net_monitor_mode(struct net_device *dev,
+ bool init_state)
{
struct rtllib_device *ieee = netdev_priv_rsl(dev);
netdev_info(dev, "========>Enter Monitor Mode\n");
- ieee->AllowAllDestAddrHandler(dev, true, !bInitState);
+ ieee->AllowAllDestAddrHandler(dev, true, !init_state);
}
/* Disables network monitor mode. Only packets destinated to
* us will be received.
*/
-void rtllib_DisableNetMonitorMode(struct net_device *dev,
- bool bInitState)
+void rtllib_disable_net_monitor_mode(struct net_device *dev,
+ bool init_state)
{
struct rtllib_device *ieee = netdev_priv_rsl(dev);
netdev_info(dev, "========>Exit Monitor Mode\n");
- ieee->AllowAllDestAddrHandler(dev, false, !bInitState);
+ ieee->AllowAllDestAddrHandler(dev, false, !init_state);
}
static void rtllib_send_probe(struct rtllib_device *ieee)
@@ -425,12 +390,6 @@ static void rtllib_send_probe_requests(struct rtllib_device *ieee)
}
}
-static void rtllib_update_active_chan_map(struct rtllib_device *ieee)
-{
- memcpy(ieee->active_channel_map, GET_DOT11D_INFO(ieee)->channel_map,
- MAX_CHANNEL_NUMBER + 1);
-}
-
/* this performs syncro scan blocking the caller until all channels
* in the allowed channel map has been checked.
*/
@@ -439,8 +398,6 @@ static void rtllib_softmac_scan_syncro(struct rtllib_device *ieee)
union iwreq_data wrqu;
short ch = 0;
- rtllib_update_active_chan_map(ieee);
-
ieee->be_scan_inprogress = true;
mutex_lock(&ieee->scan_mutex);
@@ -492,10 +449,6 @@ out:
ieee->actscanning = false;
ieee->sync_scan_hurryup = 0;
- if (ieee->link_state >= MAC80211_LINKED) {
- if (IS_DOT11D_ENABLE(ieee))
- dot11d_scan_complete(ieee);
- }
mutex_unlock(&ieee->scan_mutex);
ieee->be_scan_inprogress = false;
@@ -510,8 +463,6 @@ static void rtllib_softmac_scan_wq(void *data)
struct rtllib_device, softmac_scan_wq);
u8 last_channel = ieee->current_network.channel;
- rtllib_update_active_chan_map(ieee);
-
if (!ieee->ieee_up)
return;
if (rtllib_act_scanning(ieee, true))
@@ -552,8 +503,6 @@ static void rtllib_softmac_scan_wq(void *data)
return;
out:
- if (IS_DOT11D_ENABLE(ieee))
- dot11d_scan_complete(ieee);
ieee->current_network.channel = last_channel;
out1:
@@ -609,10 +558,6 @@ static void rtllib_start_scan(struct rtllib_device *ieee)
{
ieee->rtllib_ips_leave_wq(ieee->dev);
- if (IS_DOT11D_ENABLE(ieee)) {
- if (IS_COUNTRY_IE_VALID(ieee))
- RESET_CIE_WATCHDOG(ieee);
- }
if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) {
if (ieee->scanning_continue == 0) {
ieee->actscanning = true;
@@ -625,10 +570,6 @@ static void rtllib_start_scan(struct rtllib_device *ieee)
/* called with wx_mutex held */
void rtllib_start_scan_syncro(struct rtllib_device *ieee)
{
- if (IS_DOT11D_ENABLE(ieee)) {
- if (IS_COUNTRY_IE_VALID(ieee))
- RESET_CIE_WATCHDOG(ieee);
- }
ieee->sync_scan_hurryup = 0;
if (ieee->softmac_features & IEEE_SOFTMAC_SCAN)
rtllib_softmac_scan_syncro(ieee);
@@ -677,152 +618,6 @@ rtllib_authentication_req(struct rtllib_network *beacon,
return skb;
}
-static struct sk_buff *rtllib_probe_resp(struct rtllib_device *ieee,
- const u8 *dest)
-{
- u8 *tag;
- int beacon_size;
- struct rtllib_probe_response *beacon_buf;
- struct sk_buff *skb = NULL;
- int encrypt;
- int atim_len, erp_len;
- struct lib80211_crypt_data *crypt;
-
- char *ssid = ieee->current_network.ssid;
- int ssid_len = ieee->current_network.ssid_len;
- int rate_len = ieee->current_network.rates_len + 2;
- int rate_ex_len = ieee->current_network.rates_ex_len;
- int wpa_ie_len = ieee->wpa_ie_len;
- u8 erpinfo_content = 0;
-
- u8 *tmp_ht_cap_buf = NULL;
- u8 tmp_ht_cap_len = 0;
- u8 *tmp_ht_info_buf = NULL;
- u8 tmp_ht_info_len = 0;
- struct rt_hi_throughput *ht_info = ieee->ht_info;
- u8 *tmp_generic_ie_buf = NULL;
- u8 tmp_generic_ie_len = 0;
-
- if (rate_ex_len > 0)
- rate_ex_len += 2;
-
- if (ieee->current_network.capability & WLAN_CAPABILITY_IBSS)
- atim_len = 4;
- else
- atim_len = 0;
-
- if ((ieee->current_network.mode == WIRELESS_MODE_G) ||
- (ieee->current_network.mode == WIRELESS_MODE_N_24G &&
- ieee->ht_info->bCurSuppCCK)) {
- erp_len = 3;
- erpinfo_content = 0;
- if (ieee->current_network.buseprotection)
- erpinfo_content |= ERP_UseProtection;
- } else {
- erp_len = 0;
- }
-
- crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
- encrypt = crypt && crypt->ops &&
- ((strcmp(crypt->ops->name, "R-WEP") == 0 || wpa_ie_len));
- if (ieee->ht_info->current_ht_support) {
- tmp_ht_cap_buf = (u8 *)&(ieee->ht_info->SelfHTCap);
- tmp_ht_cap_len = sizeof(ieee->ht_info->SelfHTCap);
- tmp_ht_info_buf = (u8 *)&(ieee->ht_info->SelfHTInfo);
- tmp_ht_info_len = sizeof(ieee->ht_info->SelfHTInfo);
- HTConstructCapabilityElement(ieee, tmp_ht_cap_buf,
- &tmp_ht_cap_len, encrypt, false);
- HTConstructInfoElement(ieee, tmp_ht_info_buf, &tmp_ht_info_len,
- encrypt);
-
- if (ht_info->reg_rt2rt_aggregation) {
- tmp_generic_ie_buf = ieee->ht_info->sz_rt2rt_agg_buf;
- tmp_generic_ie_len =
- sizeof(ieee->ht_info->sz_rt2rt_agg_buf);
- HTConstructRT2RTAggElement(ieee, tmp_generic_ie_buf,
- &tmp_generic_ie_len);
- }
- }
-
- beacon_size = sizeof(struct rtllib_probe_response) + 2 +
- ssid_len + 3 + rate_len + rate_ex_len + atim_len + erp_len
- + wpa_ie_len + ieee->tx_headroom;
- skb = dev_alloc_skb(beacon_size);
- if (!skb)
- return NULL;
-
- skb_reserve(skb, ieee->tx_headroom);
-
- beacon_buf = skb_put(skb, (beacon_size - ieee->tx_headroom));
- ether_addr_copy(beacon_buf->header.addr1, dest);
- ether_addr_copy(beacon_buf->header.addr2, ieee->dev->dev_addr);
- ether_addr_copy(beacon_buf->header.addr3, ieee->current_network.bssid);
-
- beacon_buf->header.duration_id = 0;
- beacon_buf->beacon_interval =
- cpu_to_le16(ieee->current_network.beacon_interval);
- beacon_buf->capability =
- cpu_to_le16(ieee->current_network.capability &
- WLAN_CAPABILITY_IBSS);
- beacon_buf->capability |=
- cpu_to_le16(ieee->current_network.capability &
- WLAN_CAPABILITY_SHORT_PREAMBLE);
-
- if (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
- beacon_buf->capability |=
- cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME);
-
- crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
- if (encrypt)
- beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY);
-
- beacon_buf->header.frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP);
- beacon_buf->info_element[0].id = MFIE_TYPE_SSID;
- beacon_buf->info_element[0].len = ssid_len;
-
- tag = (u8 *)beacon_buf->info_element[0].data;
-
- memcpy(tag, ssid, ssid_len);
-
- tag += ssid_len;
-
- *(tag++) = MFIE_TYPE_RATES;
- *(tag++) = rate_len - 2;
- memcpy(tag, ieee->current_network.rates, rate_len - 2);
- tag += rate_len - 2;
-
- *(tag++) = MFIE_TYPE_DS_SET;
- *(tag++) = 1;
- *(tag++) = ieee->current_network.channel;
-
- if (atim_len) {
- u16 val16;
- *(tag++) = MFIE_TYPE_IBSS_SET;
- *(tag++) = 2;
- val16 = ieee->current_network.atim_window;
- memcpy((u8 *)tag, (u8 *)&val16, 2);
- tag += 2;
- }
-
- if (erp_len) {
- *(tag++) = MFIE_TYPE_ERP;
- *(tag++) = 1;
- *(tag++) = erpinfo_content;
- }
- if (rate_ex_len) {
- *(tag++) = MFIE_TYPE_RATES_EX;
- *(tag++) = rate_ex_len - 2;
- memcpy(tag, ieee->current_network.rates_ex, rate_ex_len - 2);
- tag += rate_ex_len - 2;
- }
-
- if (wpa_ie_len) {
- memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len);
- tag += ieee->wpa_ie_len;
- }
- return skb;
-}
-
static struct sk_buff *rtllib_null_func(struct rtllib_device *ieee, short pwr)
{
struct sk_buff *skb;
@@ -875,7 +670,7 @@ static inline int SecIsInPMKIDList(struct rtllib_device *ieee, u8 *bssid)
int i = 0;
do {
- if ((ieee->PMKIDList[i].bUsed) &&
+ if ((ieee->PMKIDList[i].used) &&
(memcmp(ieee->PMKIDList[i].Bssid, bssid, ETH_ALEN) == 0))
break;
i++;
@@ -933,15 +728,15 @@ rtllib_association_req(struct rtllib_network *beacon,
}
if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) {
- ht_cap_buf = (u8 *)&(ieee->ht_info->SelfHTCap);
+ ht_cap_buf = (u8 *)&ieee->ht_info->SelfHTCap;
ht_cap_len = sizeof(ieee->ht_info->SelfHTCap);
- HTConstructCapabilityElement(ieee, ht_cap_buf, &ht_cap_len,
+ ht_construct_capability_element(ieee, ht_cap_buf, &ht_cap_len,
encrypt, true);
if (ieee->ht_info->current_rt2rt_aggregation) {
realtek_ie_buf = ieee->ht_info->sz_rt2rt_agg_buf;
realtek_ie_len =
sizeof(ieee->ht_info->sz_rt2rt_agg_buf);
- HTConstructRT2RTAggElement(ieee, realtek_ie_buf,
+ ht_construct_rt2rt_agg_element(ieee, realtek_ie_buf,
&realtek_ie_len);
}
}
@@ -1071,7 +866,7 @@ rtllib_association_req(struct rtllib_network *beacon,
tag += osCcxVerNum.Length;
}
if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) {
- if (ieee->ht_info->ePeerHTSpecVer != HT_SPEC_VER_EWC) {
+ if (ieee->ht_info->peer_ht_spec_ver != HT_SPEC_VER_EWC) {
tag = skb_put(skb, ht_cap_len);
*tag++ = MFIE_TYPE_HT_CAP;
*tag++ = ht_cap_len - 2;
@@ -1093,7 +888,7 @@ rtllib_association_req(struct rtllib_network *beacon,
}
if (wmm_info_len) {
tag = skb_put(skb, wmm_info_len);
- rtllib_WMM_Info(ieee, &tag);
+ rtllib_wmm_info(ieee, &tag);
}
if (wps_ie_len && ieee->wps_ie)
@@ -1101,11 +896,11 @@ rtllib_association_req(struct rtllib_network *beacon,
if (turbo_info_len) {
tag = skb_put(skb, turbo_info_len);
- rtllib_TURBO_Info(ieee, &tag);
+ rtllib_turbo_info(ieee, &tag);
}
if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) {
- if (ieee->ht_info->ePeerHTSpecVer == HT_SPEC_VER_EWC) {
+ if (ieee->ht_info->peer_ht_spec_ver == HT_SPEC_VER_EWC) {
tag = skb_put(skb, ht_cap_len);
*tag++ = MFIE_TYPE_GENERIC;
*tag++ = ht_cap_len - 2;
@@ -1123,7 +918,7 @@ rtllib_association_req(struct rtllib_network *beacon,
kfree(ieee->assocreq_ies);
ieee->assocreq_ies = NULL;
- ies = &(hdr->info_element[0].id);
+ ies = &hdr->info_element[0].id;
ieee->assocreq_ies_len = (skb->data + skb->len) - ies;
ieee->assocreq_ies = kmemdup(ies, ieee->assocreq_ies_len, GFP_ATOMIC);
if (!ieee->assocreq_ies)
@@ -1269,7 +1064,7 @@ static void rtllib_associate_complete_wq(void *data)
}
if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht) {
netdev_info(ieee->dev, "Successfully associated, ht enabled\n");
- HTOnAssocRsp(ieee);
+ ht_on_assoc_rsp(ieee);
} else {
netdev_info(ieee->dev,
"Successfully associated, ht not enabled(%d, %d)\n",
@@ -1314,7 +1109,7 @@ static void rtllib_associate_procedure_wq(void *data)
mutex_lock(&ieee->wx_mutex);
rtllib_stop_scan(ieee);
- HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
+ ht_set_connect_bw_mode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
if (ieee->rf_power_state == rf_off) {
ieee->rtllib_ips_leave_wq(ieee->dev);
mutex_unlock(&ieee->wx_mutex);
@@ -1417,21 +1212,20 @@ inline void rtllib_softmac_new_net(struct rtllib_device *ieee,
!(ieee->softmac_features & IEEE_SOFTMAC_SCAN))
rtllib_stop_scan_syncro(ieee);
- HTResetIOTSetting(ieee->ht_info);
+ ht_reset_iot_setting(ieee->ht_info);
ieee->wmm_acm = 0;
if (ieee->iw_mode == IW_MODE_INFRA) {
/* Join the network for the first time */
ieee->AsocRetryCount = 0;
if ((ieee->current_network.qos_data.supported == 1) &&
ieee->current_network.bssht.bd_support_ht)
- HTResetSelfAndSavePeerSetting(ieee,
+ ht_reset_self_and_save_peer_setting(ieee,
&(ieee->current_network));
else
ieee->ht_info->current_ht_support = false;
ieee->link_state = RTLLIB_ASSOCIATING;
- schedule_delayed_work(
- &ieee->associate_procedure_wq, 0);
+ schedule_delayed_work(&ieee->associate_procedure_wq, 0);
} else {
if (rtllib_is_54g(&ieee->current_network)) {
ieee->rate = 108;
@@ -1825,7 +1619,7 @@ rtllib_rx_assoc_resp(struct rtllib_device *ieee, struct sk_buff *skb,
kfree(ieee->assocresp_ies);
ieee->assocresp_ies = NULL;
- ies = &(assoc_resp->info_element[0].id);
+ ies = &assoc_resp->info_element[0].id;
ieee->assocresp_ies_len = (skb->data + skb->len) - ies;
ieee->assocresp_ies = kmemdup(ies,
ieee->assocresp_ies_len,
@@ -1841,8 +1635,7 @@ rtllib_rx_assoc_resp(struct rtllib_device *ieee, struct sk_buff *skb,
"Association response status code 0x%x\n",
errcode);
if (ieee->AsocRetryCount < RT_ASOC_RETRY_LIMIT)
- schedule_delayed_work(
- &ieee->associate_procedure_wq, 0);
+ schedule_delayed_work(&ieee->associate_procedure_wq, 0);
else
rtllib_associate_abort(ieee);
}
@@ -1872,7 +1665,7 @@ static void rtllib_rx_auth_resp(struct rtllib_device *ieee, struct sk_buff *skb)
ieee->softmac_stats.rx_auth_rs_ok++;
if (!(ieee->ht_info->iot_action & HT_IOT_ACT_PURE_N_MODE)) {
if (!ieee->GetNmodeSupportBySecCfg(ieee->dev)) {
- if (IsHTHalfNmodeAPs(ieee)) {
+ if (is_ht_half_nmode_aps(ieee)) {
bSupportNmode = true;
bHalfSupportNmode = true;
} else {
@@ -2030,7 +1823,7 @@ void rtllib_softmac_xmit(struct rtllib_txb *txb, struct rtllib_device *ieee)
* the wait queue
*/
for (i = 0; i < txb->nr_frags; i++) {
- queue_len = skb_queue_len(&ieee->skb_waitQ[queue_index]);
+ queue_len = skb_queue_len(&ieee->skb_waitq[queue_index]);
if ((queue_len != 0) ||
(!ieee->check_nic_enough_desc(ieee->dev, queue_index)) ||
(ieee->queue_stop)) {
@@ -2039,13 +1832,12 @@ void rtllib_softmac_xmit(struct rtllib_txb *txb, struct rtllib_device *ieee)
* to check it any more.
*/
if (queue_len < 200)
- skb_queue_tail(&ieee->skb_waitQ[queue_index],
+ skb_queue_tail(&ieee->skb_waitq[queue_index],
txb->fragments[i]);
else
kfree_skb(txb->fragments[i]);
} else {
- ieee->softmac_data_hard_start_xmit(
- txb->fragments[i],
+ ieee->softmac_data_hard_start_xmit(txb->fragments[i],
ieee->dev, ieee->rate);
}
}
@@ -2090,10 +1882,6 @@ static void rtllib_start_bss(struct rtllib_device *ieee)
{
unsigned long flags;
- if (IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee)) {
- if (!ieee->global_domain)
- return;
- }
/* check if we have already found the net we
* are interested in (if any).
* if not (we are disassociated and we are not
@@ -2121,6 +1909,7 @@ static void rtllib_link_change_wq(void *data)
struct rtllib_device, link_change_wq);
ieee->link_change(ieee->dev);
}
+
/* called only in userspace context */
void rtllib_disassociate(struct rtllib_device *ieee)
{
@@ -2128,8 +1917,6 @@ void rtllib_disassociate(struct rtllib_device *ieee)
if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)
rtllib_reset_queue(ieee);
- if (IS_DOT11D_ENABLE(ieee))
- dot11d_reset(ieee);
ieee->link_state = MAC80211_NOLINK;
ieee->is_set_key = false;
ieee->wap_set = 0;
@@ -2181,46 +1968,6 @@ exit:
mutex_unlock(&ieee->wx_mutex);
}
-static struct sk_buff *rtllib_get_beacon_(struct rtllib_device *ieee)
-{
- static const u8 broadcast_addr[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
- struct sk_buff *skb;
- struct rtllib_probe_response *b;
-
- skb = rtllib_probe_resp(ieee, broadcast_addr);
-
- if (!skb)
- return NULL;
-
- b = (struct rtllib_probe_response *)skb->data;
- b->header.frame_control = cpu_to_le16(IEEE80211_STYPE_BEACON);
-
- return skb;
-}
-
-struct sk_buff *rtllib_get_beacon(struct rtllib_device *ieee)
-{
- struct sk_buff *skb;
- struct rtllib_probe_response *b;
-
- skb = rtllib_get_beacon_(ieee);
- if (!skb)
- return NULL;
-
- b = (struct rtllib_probe_response *)skb->data;
- b->header.seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4);
-
- if (ieee->seq_ctrl[0] == 0xFFF)
- ieee->seq_ctrl[0] = 0;
- else
- ieee->seq_ctrl[0]++;
-
- return skb;
-}
-EXPORT_SYMBOL(rtllib_get_beacon);
-
void rtllib_softmac_stop_protocol(struct rtllib_device *ieee)
{
rtllib_stop_scan_syncro(ieee);
@@ -2279,8 +2026,6 @@ void rtllib_start_protocol(struct rtllib_device *ieee)
short ch = 0;
int i = 0;
- rtllib_update_active_chan_map(ieee);
-
if (ieee->proto_started)
return;
@@ -2326,18 +2071,15 @@ int rtllib_softmac_init(struct rtllib_device *ieee)
ieee->link_state = MAC80211_NOLINK;
for (i = 0; i < 5; i++)
ieee->seq_ctrl[i] = 0;
- ieee->dot11d_info = kzalloc(sizeof(struct rt_dot11d_info), GFP_ATOMIC);
- if (!ieee->dot11d_info)
- return -ENOMEM;
ieee->link_detect_info.SlotIndex = 0;
ieee->link_detect_info.SlotNum = 2;
ieee->link_detect_info.NumRecvBcnInPeriod = 0;
ieee->link_detect_info.NumRecvDataInPeriod = 0;
- ieee->link_detect_info.NumTxOkInPeriod = 0;
- ieee->link_detect_info.NumRxOkInPeriod = 0;
+ ieee->link_detect_info.num_tx_ok_in_period = 0;
+ ieee->link_detect_info.num_rx_ok_in_period = 0;
ieee->link_detect_info.NumRxUnicastOkInPeriod = 0;
- ieee->bIsAggregateFrame = false;
+ ieee->is_aggregate_frame = false;
ieee->assoc_id = 0;
ieee->queue_stop = 0;
ieee->scanning_continue = 0;
@@ -2369,8 +2111,6 @@ int rtllib_softmac_init(struct rtllib_device *ieee)
timer_setup(&ieee->associate_timer, rtllib_associate_abort_cb, 0);
- timer_setup(&ieee->beacon_timer, rtllib_send_beacon_cb, 0);
-
INIT_DELAYED_WORK(&ieee->link_change_wq, (void *)rtllib_link_change_wq);
INIT_WORK(&ieee->associate_complete_wq, (void *)rtllib_associate_complete_wq);
INIT_DELAYED_WORK(&ieee->associate_procedure_wq, (void *)rtllib_associate_procedure_wq);
@@ -2404,9 +2144,6 @@ void rtllib_softmac_free(struct rtllib_device *ieee)
cancel_work_sync(&ieee->ips_leave_wq);
cancel_work_sync(&ieee->wx_sync_scan_wq);
cancel_work_sync(&ieee->ps_task);
-
- kfree(ieee->dot11d_info);
- ieee->dot11d_info = NULL;
}
static inline struct sk_buff *
@@ -2493,7 +2230,7 @@ u8 rtllib_ap_sec_type(struct rtllib_device *ieee)
return SEC_ALG_WEP;
} else if ((wpa_ie_len != 0)) {
if (((ieee->wpa_ie[0] == 0xdd) &&
- (!memcmp(&(ieee->wpa_ie[14]), ccmp_ie, 4))) ||
+ (!memcmp(&ieee->wpa_ie[14], ccmp_ie, 4))) ||
((ieee->wpa_ie[0] == 0x30) &&
(!memcmp(&ieee->wpa_ie[10], ccmp_rsn_ie, 4))))
return SEC_ALG_CCMP;
@@ -2508,7 +2245,7 @@ static void rtllib_MlmeDisassociateRequest(struct rtllib_device *rtllib,
u8 *asSta, u8 asRsn)
{
u8 i;
- u8 OpMode;
+ u8 op_mode;
RemovePeerTS(rtllib, asSta);
@@ -2517,10 +2254,10 @@ static void rtllib_MlmeDisassociateRequest(struct rtllib_device *rtllib,
for (i = 0; i < 6; i++)
rtllib->current_network.bssid[i] = 0x22;
- OpMode = RT_OP_MODE_NO_LINK;
- rtllib->OpMode = RT_OP_MODE_NO_LINK;
+ op_mode = RT_OP_MODE_NO_LINK;
+ rtllib->op_mode = RT_OP_MODE_NO_LINK;
rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_MEDIA_STATUS,
- (u8 *)(&OpMode));
+ (u8 *)(&op_mode));
rtllib_disassociate(rtllib);
rtllib->SetHwRegHandler(rtllib->dev, HW_VAR_BSSID,
@@ -2528,11 +2265,7 @@ static void rtllib_MlmeDisassociateRequest(struct rtllib_device *rtllib,
}
}
-static void
-rtllib_MgntDisconnectAP(
- struct rtllib_device *rtllib,
- u8 asRsn
-)
+static void rtllib_MgntDisconnectAP(struct rtllib_device *rtllib, u8 asRsn)
{
bool bFilterOutNonAssociatedBSSID = false;
diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
index f32584291704..2afa701e5445 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
@@ -14,7 +14,6 @@
#include <linux/etherdevice.h>
#include "rtllib.h"
-#include "dot11d.h"
int rtllib_wx_set_freq(struct rtllib_device *ieee, struct iw_request_info *a,
union iwreq_data *wrqu, char *b)
@@ -208,7 +207,7 @@ int rtllib_wx_get_rate(struct rtllib_device *ieee,
{
u32 tmp_rate;
- tmp_rate = TxCountToDataRate(ieee,
+ tmp_rate = tx_count_to_data_rate(ieee,
ieee->softmac_stats.CurrentShowTxate);
wrqu->bitrate.value = tmp_rate * 500000;
@@ -267,11 +266,11 @@ int rtllib_wx_set_mode(struct rtllib_device *ieee, struct iw_request_info *a,
if (wrqu->mode == IW_MODE_MONITOR) {
ieee->dev->type = ARPHRD_IEEE80211;
- rtllib_EnableNetMonitorMode(ieee->dev, false);
+ rtllib_enable_net_monitor_mode(ieee->dev, false);
} else {
ieee->dev->type = ARPHRD_ETHER;
if (ieee->iw_mode == IW_MODE_MONITOR)
- rtllib_DisableNetMonitorMode(ieee->dev, false);
+ rtllib_disable_net_monitor_mode(ieee->dev, false);
}
if (!ieee->proto_started) {
@@ -318,10 +317,10 @@ void rtllib_wx_sync_scan_wq(void *data)
ieee->ScanOperationBackupHandler(ieee->dev, SCAN_OPT_BACKUP);
if (ieee->ht_info->current_ht_support && ieee->ht_info->enable_ht &&
- ieee->ht_info->bCurBW40MHz) {
+ ieee->ht_info->cur_bw_40mhz) {
b40M = 1;
chan_offset = ieee->ht_info->CurSTAExtChnlOffset;
- bandwidth = (enum ht_channel_width)ieee->ht_info->bCurBW40MHz;
+ bandwidth = (enum ht_channel_width)ieee->ht_info->cur_bw_40mhz;
ieee->set_bw_mode_handler(ieee->dev, HT_CHANNEL_WIDTH_20,
HT_EXTCHNL_OFFSET_NO_EXT);
}
diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c
index 9bf679438ad1..f7098a2ba8b0 100644
--- a/drivers/staging/rtl8192e/rtllib_tx.c
+++ b/drivers/staging/rtl8192e/rtllib_tx.c
@@ -267,7 +267,7 @@ static void rtllib_tx_query_agg_cap(struct rtllib_device *ieee,
struct cb_desc *tcb_desc)
{
struct rt_hi_throughput *ht_info = ieee->ht_info;
- struct tx_ts_record *pTxTs = NULL;
+ struct tx_ts_record *ts = NULL;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
if (rtllib_act_scanning(ieee, false))
@@ -288,52 +288,35 @@ static void rtllib_tx_query_agg_cap(struct rtllib_device *ieee,
if (!ieee->GetNmodeSupportBySecCfg(ieee->dev))
return;
- if (ht_info->bCurrentAMPDUEnable) {
- if (!rtllib_get_ts(ieee, (struct ts_common_info **)(&pTxTs), hdr->addr1,
+ if (ht_info->current_ampdu_enable) {
+ if (!rtllib_get_ts(ieee, (struct ts_common_info **)(&ts), hdr->addr1,
skb->priority, TX_DIR, true)) {
netdev_info(ieee->dev, "%s: can't get TS\n", __func__);
return;
}
- if (!pTxTs->TxAdmittedBARecord.b_valid) {
+ if (!ts->tx_admitted_ba_record.b_valid) {
if (ieee->wpa_ie_len && (ieee->pairwise_key_type ==
KEY_TYPE_NA)) {
;
} else if (tcb_desc->bdhcp == 1) {
;
- } else if (!pTxTs->bDisable_AddBa) {
- TsStartAddBaProcess(ieee, pTxTs);
+ } else if (!ts->disable_add_ba) {
+ TsStartAddBaProcess(ieee, ts);
}
- goto FORCED_AGG_SETTING;
- } else if (!pTxTs->bUsingBa) {
- if (SN_LESS(pTxTs->TxAdmittedBARecord.ba_start_seq_ctrl.field.seq_num,
- (pTxTs->TxCurSeq + 1) % 4096))
- pTxTs->bUsingBa = true;
+ return;
+ } else if (!ts->using_ba) {
+ if (SN_LESS(ts->tx_admitted_ba_record.ba_start_seq_ctrl.field.seq_num,
+ (ts->tx_cur_seq + 1) % 4096))
+ ts->using_ba = true;
else
- goto FORCED_AGG_SETTING;
+ return;
}
if (ieee->iw_mode == IW_MODE_INFRA) {
- tcb_desc->bAMPDUEnable = true;
+ tcb_desc->ampdu_enable = true;
tcb_desc->ampdu_factor = ht_info->CurrentAMPDUFactor;
tcb_desc->ampdu_density = ht_info->current_mpdu_density;
}
}
-FORCED_AGG_SETTING:
- switch (ht_info->ForcedAMPDUMode) {
- case HT_AGG_AUTO:
- break;
-
- case HT_AGG_FORCE_ENABLE:
- tcb_desc->bAMPDUEnable = true;
- tcb_desc->ampdu_density = ht_info->forced_mpdu_density;
- tcb_desc->ampdu_factor = ht_info->forced_ampdu_factor;
- break;
-
- case HT_AGG_FORCE_DISABLE:
- tcb_desc->bAMPDUEnable = false;
- tcb_desc->ampdu_density = 0;
- tcb_desc->ampdu_factor = 0;
- break;
- }
}
static void rtllib_query_ShortPreambleMode(struct rtllib_device *ieee,
@@ -357,14 +340,9 @@ static void rtllib_query_HTCapShortGI(struct rtllib_device *ieee,
if (!ht_info->current_ht_support || !ht_info->enable_ht)
return;
- if (ht_info->forced_short_gi) {
- tcb_desc->bUseShortGI = true;
- return;
- }
-
- if (ht_info->bCurBW40MHz && ht_info->bCurShortGI40MHz)
+ if (ht_info->cur_bw_40mhz && ht_info->cur_short_gi_40mhz)
tcb_desc->bUseShortGI = true;
- else if (!ht_info->bCurBW40MHz && ht_info->bCurShortGI20MHz)
+ else if (!ht_info->cur_bw_40mhz && ht_info->cur_short_gi_20mhz)
tcb_desc->bUseShortGI = true;
}
@@ -383,7 +361,7 @@ static void rtllib_query_BandwidthMode(struct rtllib_device *ieee,
if ((tcb_desc->data_rate & 0x80) == 0)
return;
- if (ht_info->bCurBW40MHz && ht_info->cur_tx_bw40mhz &&
+ if (ht_info->cur_bw_40mhz && ht_info->cur_tx_bw40mhz &&
!ieee->bandwidth_auto_switch.bforced_tx20Mhz)
tcb_desc->bPacketBW = true;
}
@@ -441,9 +419,9 @@ static void rtllib_query_protectionmode(struct rtllib_device *ieee,
if (ht_info->current_ht_support && ht_info->enable_ht) {
u8 HTOpMode = ht_info->current_op_mode;
- if ((ht_info->bCurBW40MHz && (HTOpMode == 2 ||
+ if ((ht_info->cur_bw_40mhz && (HTOpMode == 2 ||
HTOpMode == 3)) ||
- (!ht_info->bCurBW40MHz && HTOpMode == 3)) {
+ (!ht_info->cur_bw_40mhz && HTOpMode == 3)) {
tcb_desc->rts_rate = MGN_24M;
tcb_desc->bRTSEnable = true;
break;
@@ -454,7 +432,7 @@ static void rtllib_query_protectionmode(struct rtllib_device *ieee,
tcb_desc->bRTSEnable = true;
break;
}
- if (tcb_desc->bAMPDUEnable) {
+ if (tcb_desc->ampdu_enable) {
tcb_desc->rts_rate = MGN_24M;
tcb_desc->bRTSEnable = false;
break;
@@ -500,8 +478,8 @@ static u16 rtllib_query_seqnum(struct rtllib_device *ieee, struct sk_buff *skb,
if (!rtllib_get_ts(ieee, (struct ts_common_info **)(&ts), dst,
skb->priority, TX_DIR, true))
return 0;
- seqnum = ts->TxCurSeq;
- ts->TxCurSeq = (ts->TxCurSeq + 1) % 4096;
+ seqnum = ts->tx_cur_seq;
+ ts->tx_cur_seq = (ts->tx_cur_seq + 1) % 4096;
return seqnum;
}
return 0;
@@ -847,7 +825,7 @@ static int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
if (txb) {
tcb_desc = (struct cb_desc *)
(txb->fragments[0]->cb + MAX_DEV_ADDR_SIZE);
- tcb_desc->bTxEnableFwCalcDur = 1;
+ tcb_desc->tx_enable_fw_calc_dur = 1;
tcb_desc->priority = skb->priority;
if (ether_type == ETH_P_PAE) {
diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c
index a37250de7ba3..f92ec0faf4d5 100644
--- a/drivers/staging/rtl8192e/rtllib_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_wx.c
@@ -134,7 +134,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
((ht_cap->ShortGI40Mhz) ? 1 : 0) :
((ht_cap->ShortGI20Mhz) ? 1 : 0);
- max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS,
+ max_mcs = ht_get_highest_mcs_rate(ieee, ht_cap->MCS,
MCS_FILTER_ALL);
rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs & 0x7f];
if (rate > max_rate)
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index b18e6d9c832b..7554613fe7e1 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -221,8 +221,7 @@ struct net_device *r8712_init_netdev(void)
static u32 start_drv_threads(struct _adapter *padapter)
{
- padapter->cmd_thread = kthread_run(r8712_cmd_thread, padapter, "%s",
- padapter->pnetdev->name);
+ padapter->cmd_thread = kthread_run(r8712_cmd_thread, padapter, "%s", padapter->pnetdev->name);
if (IS_ERR(padapter->cmd_thread))
return _FAIL;
return _SUCCESS;
diff --git a/drivers/staging/rtl8712/rtl8712_efuse.c b/drivers/staging/rtl8712/rtl8712_efuse.c
index c9400e40a1d6..a39d6c06648f 100644
--- a/drivers/staging/rtl8712/rtl8712_efuse.c
+++ b/drivers/staging/rtl8712/rtl8712_efuse.c
@@ -213,8 +213,8 @@ u16 r8712_efuse_get_current_size(struct _adapter *adapter)
u8 hworden = 0;
u8 efuse_data, word_cnts = 0;
- while (bContinual && efuse_one_byte_read(adapter, efuse_addr,
- &efuse_data) && (efuse_addr < efuse_available_max_size)) {
+ while (bContinual && efuse_one_byte_read(adapter, efuse_addr, &efuse_data) &&
+ (efuse_addr < efuse_available_max_size)) {
if (efuse_data != 0xFF) {
hworden = efuse_data & 0x0F;
word_cnts = calculate_word_cnts(hworden);
@@ -252,9 +252,8 @@ u8 r8712_efuse_pg_packet_read(struct _adapter *adapter, u8 offset, u8 *data)
memset(tmpdata, 0xFF, PGPKT_DATA_SIZE);
for (tmpidx = 0; tmpidx < word_cnts * 2;
tmpidx++) {
- if (efuse_one_byte_read(adapter,
- efuse_addr + 1 + tmpidx,
- &efuse_data)) {
+ if (efuse_one_byte_read(adapter, efuse_addr + 1 + tmpidx,
+ &efuse_data)) {
tmpdata[tmpidx] = efuse_data;
} else {
ret = false;
diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c
index 7da014ab0723..a3c4713c59b3 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.c
+++ b/drivers/staging/rtl8712/rtl8712_recv.c
@@ -267,8 +267,7 @@ union recv_frame *r8712_recvframe_chk_defrag(struct _adapter *padapter,
/*the first fragment*/
if (!list_empty(&pdefrag_q->queue)) {
/*free current defrag_q */
- r8712_free_recvframe_queue(pdefrag_q,
- pfree_recv_queue);
+ r8712_free_recvframe_queue(pdefrag_q, pfree_recv_queue);
}
}
/* Then enqueue the 0~(n-1) fragment to the defrag_q */
diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c
index 4cb01f590673..d7d678b04ca8 100644
--- a/drivers/staging/rtl8712/rtl8712_xmit.c
+++ b/drivers/staging/rtl8712/rtl8712_xmit.c
@@ -147,9 +147,8 @@ static u32 get_ff_hwaddr(struct xmit_frame *pxmitframe)
}
static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv,
- struct hw_xmit *phwxmit,
- struct tx_servq *ptxservq,
- struct __queue *pframe_queue)
+ struct hw_xmit *phwxmit, struct tx_servq *ptxservq,
+ struct __queue *pframe_queue)
{
struct list_head *xmitframe_plist, *xmitframe_phead;
struct xmit_frame *pxmitframe = NULL;
@@ -167,7 +166,7 @@ static struct xmit_frame *dequeue_one_xmitframe(struct xmit_priv *pxmitpriv,
}
static struct xmit_frame *dequeue_xframe_ex(struct xmit_priv *pxmitpriv,
- struct hw_xmit *phwxmit_i, sint entry)
+ struct hw_xmit *phwxmit_i, sint entry)
{
unsigned long irqL0;
struct list_head *sta_plist, *sta_phead;
@@ -197,11 +196,10 @@ static struct xmit_frame *dequeue_xframe_ex(struct xmit_priv *pxmitpriv,
sta_phead = &phwxmit->sta_queue->queue;
sta_plist = sta_phead->next;
while (!end_of_queue_search(sta_phead, sta_plist)) {
- ptxservq = container_of(sta_plist, struct tx_servq,
- tx_pending);
+ ptxservq = container_of(sta_plist, struct tx_servq, tx_pending);
pframe_queue = &ptxservq->sta_pending;
- pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit,
- ptxservq, pframe_queue);
+ pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq,
+ pframe_queue);
if (pxmitframe) {
phwxmit->accnt--;
goto exit_dequeue_xframe_ex;
@@ -221,8 +219,7 @@ exit_dequeue_xframe_ex:
return pxmitframe;
}
-void r8712_do_queue_select(struct _adapter *padapter,
- struct pkt_attrib *pattrib)
+void r8712_do_queue_select(struct _adapter *padapter, struct pkt_attrib *pattrib)
{
unsigned int qsel = 0;
struct dvobj_priv *pdvobj = &padapter->dvobjpriv;
@@ -292,14 +289,12 @@ void r8712_append_mpdu_unit(struct xmit_buf *pxmitbuf,
r8712_xmit_complete(padapter, pxmitframe);
if (pxmitframe->attrib.ether_type != 0x0806) {
if ((pxmitframe->attrib.ether_type != 0x888e) &&
- (pxmitframe->attrib.dhcp_pkt != 1)) {
- r8712_issue_addbareq_cmd(padapter,
- pxmitframe->attrib.priority);
+ (pxmitframe->attrib.dhcp_pkt != 1)) {
+ r8712_issue_addbareq_cmd(padapter, pxmitframe->attrib.priority);
}
}
pxmitframe->last[0] = 1;
- update_txdesc(pxmitframe, (uint *)(pxmitframe->buf_addr),
- pxmitframe->attrib.last_txcmdsz);
+ update_txdesc(pxmitframe, (uint *)(pxmitframe->buf_addr), pxmitframe->attrib.last_txcmdsz);
/*padding zero */
last_txcmdsz = pxmitframe->attrib.last_txcmdsz;
padding_sz = (8 - (last_txcmdsz % 8));
@@ -333,8 +328,7 @@ void r8712_xmitframe_aggr_1st(struct xmit_buf *pxmitbuf,
pxmitbuf->aggr_nr = 1;
}
-u16 r8712_xmitframe_aggr_next(struct xmit_buf *pxmitbuf,
- struct xmit_frame *pxmitframe)
+u16 r8712_xmitframe_aggr_next(struct xmit_buf *pxmitbuf, struct xmit_frame *pxmitframe)
{
pxmitframe->pxmitbuf = pxmitbuf;
pxmitbuf->priv_data = pxmitframe;
@@ -374,9 +368,9 @@ void r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf,
pxmitframe->bpending[0] = false;
pxmitframe->mem_addr = pxmitbuf->pbuf;
- if ((pdvobj->ishighspeed && ((total_length + TXDESC_SIZE) % 0x200) ==
- 0) || ((!pdvobj->ishighspeed && ((total_length + TXDESC_SIZE) %
- 0x40) == 0))) {
+ if ((pdvobj->ishighspeed && ((total_length + TXDESC_SIZE) % 0x200) == 0) ||
+ ((!pdvobj->ishighspeed && ((total_length + TXDESC_SIZE) %
+ 0x40) == 0))) {
ptxdesc->txdw0 |= cpu_to_le32
(((TXDESC_SIZE + OFFSET_SZ + 8) << OFFSET_SHT) &
0x00ff0000);
@@ -387,8 +381,8 @@ void r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf,
0x00ff0000);
/*default = 32 bytes for TX Desc*/
}
- r8712_write_port(pxmitframe->padapter, RTL8712_DMA_H2CCMD,
- total_length + TXDESC_SIZE, (u8 *)pxmitframe);
+ r8712_write_port(pxmitframe->padapter, RTL8712_DMA_H2CCMD, total_length + TXDESC_SIZE,
+ (u8 *)pxmitframe);
}
#endif
@@ -618,14 +612,12 @@ int r8712_xmitframe_complete(struct _adapter *padapter,
pxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry);
/* need to remember the 1st frame */
if (pxmitframe) {
-
#ifdef CONFIG_R8712_TX_AGGR
/* 1. dequeue 2nd frame
* 2. aggr if 2nd xframe is dequeued, else dump directly
*/
if (AGGR_NR_HIGH_BOUND > 1)
- p2ndxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits,
- hwentry);
+ p2ndxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry);
if (pxmitframe->frame_tag != DATA_FRAMETAG) {
r8712_free_xmitbuf(pxmitpriv, pxmitbuf);
return false;
@@ -639,16 +631,12 @@ int r8712_xmitframe_complete(struct _adapter *padapter,
if (p2ndxmitframe) {
u16 total_length;
- total_length = r8712_xmitframe_aggr_next(
- pxmitbuf, p2ndxmitframe);
+ total_length = r8712_xmitframe_aggr_next(pxmitbuf, p2ndxmitframe);
do {
- p2ndxmitframe = dequeue_xframe_ex(
- pxmitpriv, phwxmits, hwentry);
+ p2ndxmitframe = dequeue_xframe_ex(pxmitpriv, phwxmits, hwentry);
if (p2ndxmitframe)
total_length =
- r8712_xmitframe_aggr_next(
- pxmitbuf,
- p2ndxmitframe);
+ r8712_xmitframe_aggr_next(pxmitbuf, p2ndxmitframe);
else
break;
} while (total_length <= 0x1800 &&
@@ -662,8 +650,8 @@ int r8712_xmitframe_complete(struct _adapter *padapter,
xmitframe_xmitbuf_attach(pxmitframe, pxmitbuf);
if (pxmitframe->frame_tag == DATA_FRAMETAG) {
if (pxmitframe->attrib.priority <= 15)
- res = r8712_xmitframe_coalesce(padapter,
- pxmitframe->pkt, pxmitframe);
+ res = r8712_xmitframe_coalesce(padapter, pxmitframe->pkt,
+ pxmitframe);
/* always return ndis_packet after
* r8712_xmitframe_coalesce
*/
@@ -714,10 +702,10 @@ static void dump_xframe(struct _adapter *padapter,
ff_hwaddr = get_ff_hwaddr(pxmitframe);
#ifdef CONFIG_R8712_TX_AGGR
r8712_write_port(padapter, RTL8712_DMA_H2CCMD, w_sz,
- (unsigned char *)pxmitframe);
+ (unsigned char *)pxmitframe);
#else
r8712_write_port(padapter, ff_hwaddr, w_sz,
- (unsigned char *)pxmitframe);
+ (unsigned char *)pxmitframe);
#endif
mem_addr += w_sz;
mem_addr = (u8 *)RND4(((addr_t)(mem_addr)));
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c
index 4be96df5a329..bbd4a13c7bb9 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.c
+++ b/drivers/staging/rtl8712/rtl871x_cmd.c
@@ -242,8 +242,7 @@ void r8712_set_chplan_cmd(struct _adapter *padapter, int chplan)
kfree(ph2c);
return;
}
- init_h2fwcmd_w_parm_no_rsp(ph2c, psetchplanpara,
- GEN_CMD_CODE(_SetChannelPlan));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetchplanpara, GEN_CMD_CODE(_SetChannelPlan));
psetchplanpara->ChannelPlan = chplan;
r8712_enqueue_cmd(pcmdpriv, ph2c);
}
@@ -302,8 +301,7 @@ void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter,
padapter->mppriv.workparam.bcompleted = true;
}
-void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter,
- struct cmd_obj *pcmd)
+void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
{
kfree(pcmd->parmbuf);
kfree(pcmd);
@@ -374,11 +372,10 @@ int r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork)
psecuritypriv->authenticator_ie[0] = (unsigned char)
psecnetwork->IELength;
if ((psecnetwork->IELength - 12) < (256 - 1))
- memcpy(&psecuritypriv->authenticator_ie[1],
- &psecnetwork->IEs[12], psecnetwork->IELength - 12);
+ memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12],
+ psecnetwork->IELength - 12);
else
- memcpy(&psecuritypriv->authenticator_ie[1],
- &psecnetwork->IEs[12], (256 - 1));
+ memcpy(&psecuritypriv->authenticator_ie[1], &psecnetwork->IEs[12], (256 - 1));
psecnetwork->IELength = 0;
/*
* If the driver wants to use the bssid to create the connection.
@@ -388,19 +385,15 @@ int r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork)
if (!pmlmepriv->assoc_by_bssid)
ether_addr_copy(&pmlmepriv->assoc_bssid[0],
&pnetwork->network.MacAddress[0]);
- psecnetwork->IELength = r8712_restruct_sec_ie(padapter,
- &pnetwork->network.IEs[0],
- &psecnetwork->IEs[0],
- pnetwork->network.IELength);
+ psecnetwork->IELength = r8712_restruct_sec_ie(padapter, &pnetwork->network.IEs[0],
+ &psecnetwork->IEs[0], pnetwork->network.IELength);
pqospriv->qos_option = 0;
if (pregistrypriv->wmm_enable) {
u32 tmp_len;
- tmp_len = r8712_restruct_wmm_ie(padapter,
- &pnetwork->network.IEs[0],
- &psecnetwork->IEs[0],
- pnetwork->network.IELength,
- psecnetwork->IELength);
+ tmp_len = r8712_restruct_wmm_ie(padapter, &pnetwork->network.IEs[0],
+ &psecnetwork->IEs[0], pnetwork->network.IELength,
+ psecnetwork->IELength);
if (psecnetwork->IELength != tmp_len) {
psecnetwork->IELength = tmp_len;
pqospriv->qos_option = 1; /* WMM IE in beacon */
@@ -427,39 +420,28 @@ int r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork)
psecuritypriv->supplicant_ie[0] = (u8)psecnetwork->IELength;
if (psecnetwork->IELength < 255)
memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0],
- psecnetwork->IELength);
+ psecnetwork->IELength);
else
memcpy(&psecuritypriv->supplicant_ie[1], &psecnetwork->IEs[0],
- 255);
+ 255);
/* get cmdsz before endian conversion */
pcmd->cmdsz = r8712_get_wlan_bssid_ex_sz(psecnetwork);
#ifdef __BIG_ENDIAN
/* wlan_network endian conversion */
psecnetwork->Length = cpu_to_le32(psecnetwork->Length);
- psecnetwork->Ssid.SsidLength = cpu_to_le32(
- psecnetwork->Ssid.SsidLength);
+ psecnetwork->Ssid.SsidLength = cpu_to_le32(psecnetwork->Ssid.SsidLength);
psecnetwork->Privacy = cpu_to_le32(psecnetwork->Privacy);
psecnetwork->Rssi = cpu_to_le32(psecnetwork->Rssi);
- psecnetwork->NetworkTypeInUse = cpu_to_le32(
- psecnetwork->NetworkTypeInUse);
- psecnetwork->Configuration.ATIMWindow = cpu_to_le32(
- psecnetwork->Configuration.ATIMWindow);
- psecnetwork->Configuration.BeaconPeriod = cpu_to_le32(
- psecnetwork->Configuration.BeaconPeriod);
- psecnetwork->Configuration.DSConfig = cpu_to_le32(
- psecnetwork->Configuration.DSConfig);
- psecnetwork->Configuration.FHConfig.DwellTime = cpu_to_le32(
- psecnetwork->Configuration.FHConfig.DwellTime);
- psecnetwork->Configuration.FHConfig.HopPattern = cpu_to_le32(
- psecnetwork->Configuration.FHConfig.HopPattern);
- psecnetwork->Configuration.FHConfig.HopSet = cpu_to_le32(
- psecnetwork->Configuration.FHConfig.HopSet);
- psecnetwork->Configuration.FHConfig.Length = cpu_to_le32(
- psecnetwork->Configuration.FHConfig.Length);
- psecnetwork->Configuration.Length = cpu_to_le32(
- psecnetwork->Configuration.Length);
- psecnetwork->InfrastructureMode = cpu_to_le32(
- psecnetwork->InfrastructureMode);
+ psecnetwork->NetworkTypeInUse = cpu_to_le32(psecnetwork->NetworkTypeInUse);
+ psecnetwork->Configuration.ATIMWindow = cpu_to_le32(psecnetwork->Configuration.ATIMWindow);
+ psecnetwork->Configuration.BeaconPeriod = cpu_to_le32(psecnetwork->Configuration.BeaconPeriod);
+ psecnetwork->Configuration.DSConfig = cpu_to_le32(psecnetwork->Configuration.DSConfig);
+ psecnetwork->Configuration.FHConfig.DwellTime = cpu_to_le32(psecnetwork->Configuration.FHConfig.DwellTime);
+ psecnetwork->Configuration.FHConfig.HopPattern = cpu_to_le32(psecnetwork->Configuration.FHConfig.HopPattern);
+ psecnetwork->Configuration.FHConfig.HopSet = cpu_to_le32(psecnetwork->Configuration.FHConfig.HopSet);
+ psecnetwork->Configuration.FHConfig.Length = cpu_to_le32(psecnetwork->Configuration.FHConfig.Length);
+ psecnetwork->Configuration.Length = cpu_to_le32(psecnetwork->Configuration.Length);
+ psecnetwork->InfrastructureMode = cpu_to_le32(psecnetwork->InfrastructureMode);
psecnetwork->IELength = cpu_to_le32(psecnetwork->IELength);
#endif
INIT_LIST_HEAD(&pcmd->list);
@@ -485,13 +467,12 @@ void r8712_disassoc_cmd(struct _adapter *padapter) /* for sta_mode */
kfree(pdisconnect_cmd);
return;
}
- init_h2fwcmd_w_parm_no_rsp(pdisconnect_cmd, pdisconnect,
- _DisConnect_CMD_);
+ init_h2fwcmd_w_parm_no_rsp(pdisconnect_cmd, pdisconnect, _DisConnect_CMD_);
r8712_enqueue_cmd(pcmdpriv, pdisconnect_cmd);
}
void r8712_setopmode_cmd(struct _adapter *padapter,
- enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype)
+ enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype)
{
struct cmd_obj *ph2c;
struct setopmode_parm *psetop;
@@ -543,14 +524,12 @@ void r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key)
psetstakey_para->algorithm = (unsigned char)
psecuritypriv->PrivacyAlgrthm;
else
- GET_ENCRY_ALGO(psecuritypriv, sta,
- psetstakey_para->algorithm, false);
+ GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm, false);
if (unicast_key)
memcpy(&psetstakey_para->key, &sta->x_UncstKey, 16);
else
- memcpy(&psetstakey_para->key,
- &psecuritypriv->XGrpKey[
- psecuritypriv->XGrpKeyid - 1]. skey, 16);
+ memcpy(&psetstakey_para->key, &psecuritypriv->XGrpKey[psecuritypriv->XGrpKeyid - 1].
+ skey, 16);
r8712_enqueue_cmd(pcmdpriv, ph2c);
}
@@ -568,8 +547,7 @@ void r8712_setMacAddr_cmd(struct _adapter *padapter, const u8 *mac_addr)
kfree(ph2c);
return;
}
- init_h2fwcmd_w_parm_no_rsp(ph2c, psetMacAddr_para,
- _SetMacAddress_CMD_);
+ init_h2fwcmd_w_parm_no_rsp(ph2c, psetMacAddr_para, _SetMacAddress_CMD_);
ether_addr_copy(psetMacAddr_para->MacAddr, mac_addr);
r8712_enqueue_cmd(pcmdpriv, ph2c);
}
@@ -589,8 +567,7 @@ void r8712_addbareq_cmd(struct _adapter *padapter, u8 tid)
return;
}
paddbareq_parm->tid = tid;
- init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm,
- GEN_CMD_CODE(_AddBAReq));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm, GEN_CMD_CODE(_AddBAReq));
r8712_enqueue_cmd_ex(pcmdpriv, ph2c);
}
@@ -644,13 +621,11 @@ void r8712_joinbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
if (pcmd->res != H2C_SUCCESS)
- mod_timer(&pmlmepriv->assoc_timer,
- jiffies + msecs_to_jiffies(1));
+ mod_timer(&pmlmepriv->assoc_timer, jiffies + msecs_to_jiffies(1));
r8712_free_cmd_obj(pcmd);
}
-void r8712_createbss_cmd_callback(struct _adapter *padapter,
- struct cmd_obj *pcmd)
+void r8712_createbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
{
unsigned long irqL;
struct sta_info *psta = NULL;
@@ -660,8 +635,7 @@ void r8712_createbss_cmd_callback(struct _adapter *padapter,
struct wlan_network *tgt_network = &(pmlmepriv->cur_network);
if (pcmd->res != H2C_SUCCESS)
- mod_timer(&pmlmepriv->assoc_timer,
- jiffies + msecs_to_jiffies(1));
+ mod_timer(&pmlmepriv->assoc_timer, jiffies + msecs_to_jiffies(1));
del_timer(&pmlmepriv->assoc_timer);
#ifdef __BIG_ENDIAN
/* endian_convert */
@@ -670,31 +644,21 @@ void r8712_createbss_cmd_callback(struct _adapter *padapter,
pnetwork->Privacy = le32_to_cpu(pnetwork->Privacy);
pnetwork->Rssi = le32_to_cpu(pnetwork->Rssi);
pnetwork->NetworkTypeInUse = le32_to_cpu(pnetwork->NetworkTypeInUse);
- pnetwork->Configuration.ATIMWindow =
- le32_to_cpu(pnetwork->Configuration.ATIMWindow);
- pnetwork->Configuration.DSConfig =
- le32_to_cpu(pnetwork->Configuration.DSConfig);
- pnetwork->Configuration.FHConfig.DwellTime =
- le32_to_cpu(pnetwork->Configuration.FHConfig.DwellTime);
- pnetwork->Configuration.FHConfig.HopPattern =
- le32_to_cpu(pnetwork->Configuration.FHConfig.HopPattern);
- pnetwork->Configuration.FHConfig.HopSet =
- le32_to_cpu(pnetwork->Configuration.FHConfig.HopSet);
- pnetwork->Configuration.FHConfig.Length =
- le32_to_cpu(pnetwork->Configuration.FHConfig.Length);
- pnetwork->Configuration.Length =
- le32_to_cpu(pnetwork->Configuration.Length);
- pnetwork->InfrastructureMode =
- le32_to_cpu(pnetwork->InfrastructureMode);
+ pnetwork->Configuration.ATIMWindow = le32_to_cpu(pnetwork->Configuration.ATIMWindow);
+ pnetwork->Configuration.DSConfig = le32_to_cpu(pnetwork->Configuration.DSConfig);
+ pnetwork->Configuration.FHConfig.DwellTime = le32_to_cpu(pnetwork->Configuration.FHConfig.DwellTime);
+ pnetwork->Configuration.FHConfig.HopPattern = le32_to_cpu(pnetwork->Configuration.FHConfig.HopPattern);
+ pnetwork->Configuration.FHConfig.HopSet = le32_to_cpu(pnetwork->Configuration.FHConfig.HopSet);
+ pnetwork->Configuration.FHConfig.Length = le32_to_cpu(pnetwork->Configuration.FHConfig.Length);
+ pnetwork->Configuration.Length = le32_to_cpu(pnetwork->Configuration.Length);
+ pnetwork->InfrastructureMode = le32_to_cpu(pnetwork->InfrastructureMode);
pnetwork->IELength = le32_to_cpu(pnetwork->IELength);
#endif
spin_lock_irqsave(&pmlmepriv->lock, irqL);
if ((pmlmepriv->fw_state) & WIFI_AP_STATE) {
- psta = r8712_get_stainfo(&padapter->stapriv,
- pnetwork->MacAddress);
+ psta = r8712_get_stainfo(&padapter->stapriv, pnetwork->MacAddress);
if (!psta) {
- psta = r8712_alloc_stainfo(&padapter->stapriv,
- pnetwork->MacAddress);
+ psta = r8712_alloc_stainfo(&padapter->stapriv, pnetwork->MacAddress);
if (!psta)
goto createbss_cmd_fail;
}
@@ -702,20 +666,17 @@ void r8712_createbss_cmd_callback(struct _adapter *padapter,
} else {
pwlan = _r8712_alloc_network(pmlmepriv);
if (!pwlan) {
- pwlan = r8712_get_oldest_wlan_network(
- &pmlmepriv->scanned_queue);
+ pwlan = r8712_get_oldest_wlan_network(&pmlmepriv->scanned_queue);
if (!pwlan)
goto createbss_cmd_fail;
pwlan->last_scanned = jiffies;
} else {
- list_add_tail(&(pwlan->list),
- &pmlmepriv->scanned_queue.queue);
+ list_add_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue);
}
pnetwork->Length = r8712_get_wlan_bssid_ex_sz(pnetwork);
memcpy(&(pwlan->network), pnetwork, pnetwork->Length);
pwlan->fixed = true;
- memcpy(&tgt_network->network, pnetwork,
- (r8712_get_wlan_bssid_ex_sz(pnetwork)));
+ memcpy(&tgt_network->network, pnetwork, (r8712_get_wlan_bssid_ex_sz(pnetwork)));
if (pmlmepriv->fw_state & _FW_UNDER_LINKING)
pmlmepriv->fw_state ^= _FW_UNDER_LINKING;
/*
@@ -728,14 +689,11 @@ createbss_cmd_fail:
r8712_free_cmd_obj(pcmd);
}
-void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter,
- struct cmd_obj *pcmd)
+void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd)
{
struct sta_priv *pstapriv = &padapter->stapriv;
- struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *)
- (pcmd->rsp);
- struct sta_info *psta = r8712_get_stainfo(pstapriv,
- psetstakey_rsp->addr);
+ struct set_stakey_rsp *psetstakey_rsp = (struct set_stakey_rsp *) (pcmd->rsp);
+ struct sta_info *psta = r8712_get_stainfo(pstapriv, psetstakey_rsp->addr);
if (!psta)
goto exit;
@@ -750,27 +708,23 @@ void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter,
unsigned long irqL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
- struct set_assocsta_parm *passocsta_parm =
- (struct set_assocsta_parm *)(pcmd->parmbuf);
- struct set_assocsta_rsp *passocsta_rsp =
- (struct set_assocsta_rsp *) (pcmd->rsp);
- struct sta_info *psta = r8712_get_stainfo(pstapriv,
- passocsta_parm->addr);
+ struct set_assocsta_parm *passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf);
+ struct set_assocsta_rsp *passocsta_rsp = (struct set_assocsta_rsp *) (pcmd->rsp);
+ struct sta_info *psta = r8712_get_stainfo(pstapriv, passocsta_parm->addr);
if (!psta)
return;
psta->aid = psta->mac_id = passocsta_rsp->cam_id;
spin_lock_irqsave(&pmlmepriv->lock, irqL);
- if ((check_fwstate(pmlmepriv, WIFI_MP_STATE)) &&
- (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)))
+ if ((check_fwstate(pmlmepriv, WIFI_MP_STATE)) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)))
pmlmepriv->fw_state ^= _FW_UNDER_LINKING;
set_fwstate(pmlmepriv, _FW_LINKED);
spin_unlock_irqrestore(&pmlmepriv->lock, irqL);
r8712_free_cmd_obj(pcmd);
}
-void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
- u32 tryPktCnt, u32 tryPktInterval, u32 firstStageTO)
+void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl, u32 tryPktCnt,
+ u32 tryPktInterval, u32 firstStageTO)
{
struct cmd_obj *ph2c;
struct DisconnectCtrlEx_param *param;
@@ -790,7 +744,6 @@ void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
param->TryPktInterval = (unsigned char)tryPktInterval;
param->FirstStageTO = (unsigned int)firstStageTO;
- init_h2fwcmd_w_parm_no_rsp(ph2c, param,
- GEN_CMD_CODE(_DisconnectCtrlEx));
+ init_h2fwcmd_w_parm_no_rsp(ph2c, param, GEN_CMD_CODE(_DisconnectCtrlEx));
r8712_enqueue_cmd(pcmdpriv, ph2c);
}
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.h b/drivers/staging/rtl8712/rtl871x_cmd.h
index 8453d8de8248..2613b3c2acfc 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.h
+++ b/drivers/staging/rtl8712/rtl871x_cmd.h
@@ -716,39 +716,28 @@ struct DisconnectCtrlEx_param {
#define H2C_RESERVED 0x07
void r8712_setMacAddr_cmd(struct _adapter *padapter, const u8 *mac_addr);
-u8 r8712_sitesurvey_cmd(struct _adapter *padapter,
- struct ndis_802_11_ssid *pssid);
+u8 r8712_sitesurvey_cmd(struct _adapter *padapter, struct ndis_802_11_ssid *pssid);
int r8712_createbss_cmd(struct _adapter *padapter);
void r8712_setstakey_cmd(struct _adapter *padapter, u8 *psta, u8 unicast_key);
-int r8712_joinbss_cmd(struct _adapter *padapter,
- struct wlan_network *pnetwork);
+int r8712_joinbss_cmd(struct _adapter *padapter, struct wlan_network *pnetwork);
void r8712_disassoc_cmd(struct _adapter *padapter);
-void r8712_setopmode_cmd(struct _adapter *padapter,
- enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype);
+void r8712_setopmode_cmd(struct _adapter *padapter, enum NDIS_802_11_NETWORK_INFRASTRUCTURE networktype);
int r8712_setdatarate_cmd(struct _adapter *padapter, u8 *rateset);
void r8712_set_chplan_cmd(struct _adapter *padapter, int chplan);
int r8712_getrfreg_cmd(struct _adapter *padapter, u8 offset, u8 *pval);
int r8712_setrfreg_cmd(struct _adapter *padapter, u8 offset, u32 val);
void r8712_addbareq_cmd(struct _adapter *padapter, u8 tid);
void r8712_wdg_wk_cmd(struct _adapter *padapter);
-void r8712_survey_cmd_callback(struct _adapter *padapter,
- struct cmd_obj *pcmd);
-void r8712_disassoc_cmd_callback(struct _adapter *padapter,
- struct cmd_obj *pcmd);
-void r8712_joinbss_cmd_callback(struct _adapter *padapter,
- struct cmd_obj *pcmd);
-void r8712_createbss_cmd_callback(struct _adapter *padapter,
- struct cmd_obj *pcmd);
-void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter,
- struct cmd_obj *pcmd);
-void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter,
- struct cmd_obj *pcmd);
-void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter,
- struct cmd_obj *pcmd);
-void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter,
- struct cmd_obj *pcmd);
-void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl,
- u32 tryPktCnt, u32 tryPktInterval, u32 firstStageTO);
+void r8712_survey_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd);
+void r8712_disassoc_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd);
+void r8712_joinbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd);
+void r8712_createbss_cmd_callback(struct _adapter *padapter, struct cmd_obj *pcmd);
+void r8712_getbbrfreg_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd);
+void r8712_readtssi_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd);
+void r8712_setstaKey_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd);
+void r8712_setassocsta_cmdrsp_callback(struct _adapter *padapter, struct cmd_obj *pcmd);
+void r8712_disconnectCtrlEx_cmd(struct _adapter *adapter, u32 enableDrvCtrl, u32 tryPktCnt,
+ u32 tryPktInterval, u32 firstStageTO);
struct _cmd_callback {
u32 cmd_code;
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index 36f6904d25ab..0653aa27b1fa 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -59,8 +59,7 @@ void r8712_indicate_wx_assoc_event(struct _adapter *padapter)
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress,
- ETH_ALEN);
+ memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress, ETH_ALEN);
wireless_send_event(padapter->pnetdev, SIOCGIWAP, &wrqu, NULL);
}
@@ -111,11 +110,9 @@ static inline void handle_group_key(struct ieee_param *param,
memcpy(grk[param->u.crypt.idx - 1].skey,
&param->u.crypt.key[24], 8);
padapter->securitypriv.binstallGrpkey = true;
- r8712_set_key(padapter, &padapter->securitypriv,
- param->u.crypt.idx);
+ r8712_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx);
if (padapter->registrypriv.power_mgnt > PS_MODE_ACTIVE) {
- if (padapter->registrypriv.power_mgnt !=
- padapter->pwrctrlpriv.pwr_mode)
+ if (padapter->registrypriv.power_mgnt != padapter->pwrctrlpriv.pwr_mode)
mod_timer(&padapter->mlmepriv.dhcp_timer,
jiffies + msecs_to_jiffies(60000));
}
@@ -148,13 +145,11 @@ static noinline_for_stack char *translate_scan_wpa(struct iw_request_info *info,
memset(iwe, 0, sizeof(*iwe));
iwe->cmd = IWEVCUSTOM;
iwe->u.data.length = (u16)strlen(buf);
- start = iwe_stream_add_point(info, start, stop,
- iwe, buf);
+ start = iwe_stream_add_point(info, start, stop, iwe, buf);
memset(iwe, 0, sizeof(*iwe));
iwe->cmd = IWEVGENIE;
iwe->u.data.length = (u16)wpa_len;
- start = iwe_stream_add_point(info, start, stop,
- iwe, wpa_ie);
+ start = iwe_stream_add_point(info, start, stop, iwe, wpa_ie);
}
if (rsn_len > 0) {
memset(buf, 0, MAX_WPA_IE_LEN);
@@ -168,13 +163,11 @@ static noinline_for_stack char *translate_scan_wpa(struct iw_request_info *info,
memset(iwe, 0, sizeof(*iwe));
iwe->cmd = IWEVCUSTOM;
iwe->u.data.length = strlen(buf);
- start = iwe_stream_add_point(info, start, stop,
- iwe, buf);
+ start = iwe_stream_add_point(info, start, stop, iwe, buf);
memset(iwe, 0, sizeof(*iwe));
iwe->cmd = IWEVGENIE;
iwe->u.data.length = rsn_len;
- start = iwe_stream_add_point(info, start, stop, iwe,
- rsn_ie);
+ start = iwe_stream_add_point(info, start, stop, iwe, rsn_ie);
}
return start;
@@ -189,14 +182,11 @@ static noinline_for_stack char *translate_scan_wps(struct iw_request_info *info,
u8 wps_ie[512];
uint wps_ielen;
- if (r8712_get_wps_ie(pnetwork->network.IEs,
- pnetwork->network.IELength,
- wps_ie, &wps_ielen)) {
+ if (r8712_get_wps_ie(pnetwork->network.IEs, pnetwork->network.IELength, wps_ie, &wps_ielen)) {
if (wps_ielen > 2) {
iwe->cmd = IWEVGENIE;
iwe->u.data.length = (u16)wps_ielen;
- start = iwe_stream_add_point(info, start, stop,
- iwe, wps_ie);
+ start = iwe_stream_add_point(info, start, stop, iwe, wps_ie);
}
}
@@ -259,16 +249,14 @@ static char *translate_scan(struct _adapter *padapter,
start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
/* Add mode */
iwe.cmd = SIOCGIWMODE;
- memcpy((u8 *)&cap, r8712_get_capability_from_ie(pnetwork->network.IEs),
- 2);
+ memcpy((u8 *)&cap, r8712_get_capability_from_ie(pnetwork->network.IEs), 2);
le16_to_cpus(&cap);
if (cap & (WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_ESS)) {
if (cap & WLAN_CAPABILITY_ESS)
iwe.u.mode = (u32)IW_MODE_MASTER;
else
iwe.u.mode = (u32)IW_MODE_ADHOC;
- start = iwe_stream_add_event(info, start, stop, &iwe,
- IW_EV_UINT_LEN);
+ start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
}
/* Add frequency/channel */
iwe.cmd = SIOCGIWFREQ;
@@ -276,28 +264,23 @@ static char *translate_scan(struct _adapter *padapter,
/* check legal index */
u8 dsconfig = pnetwork->network.Configuration.DSConfig;
- if (dsconfig >= 1 && dsconfig <= sizeof(
- ieee80211_wlan_frequencies) / sizeof(long))
- iwe.u.freq.m =
- (s32)(ieee80211_wlan_frequencies
- [dsconfig - 1] * 100000);
+ if (dsconfig >= 1 && dsconfig <= sizeof(ieee80211_wlan_frequencies) / sizeof(long))
+ iwe.u.freq.m = (s32)(ieee80211_wlan_frequencies[dsconfig - 1] * 100000);
else
iwe.u.freq.m = 0;
}
iwe.u.freq.e = (s16)1;
iwe.u.freq.i = (u8)pnetwork->network.Configuration.DSConfig;
start = iwe_stream_add_event(info, start, stop, &iwe,
- IW_EV_FREQ_LEN);
+ IW_EV_FREQ_LEN);
/* Add encryption capability */
iwe.cmd = SIOCGIWENCODE;
if (cap & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = (u16)(IW_ENCODE_ENABLED |
- IW_ENCODE_NOKEY);
+ iwe.u.data.flags = (u16)(IW_ENCODE_ENABLED | IW_ENCODE_NOKEY);
else
iwe.u.data.flags = (u16)(IW_ENCODE_DISABLED);
iwe.u.data.length = (u16)0;
- start = iwe_stream_add_point(info, start, stop, &iwe,
- pnetwork->network.Ssid.Ssid);
+ start = iwe_stream_add_point(info, start, stop, &iwe, pnetwork->network.Ssid.Ssid);
/*Add basic and extended rates */
current_val = start + iwe_stream_lcp_len(info);
iwe.cmd = SIOCGIWRATE;
@@ -307,10 +290,9 @@ static char *translate_scan(struct _adapter *padapter,
i = 0;
while (pnetwork->network.rates[i] != 0) {
/* Bit rate given in 500 kb/s units */
- iwe.u.bitrate.value = (pnetwork->network.rates[i++] &
- 0x7F) * 500000;
- current_val = iwe_stream_add_value(info, start, current_val,
- stop, &iwe, IW_EV_PARAM_LEN);
+ iwe.u.bitrate.value = (pnetwork->network.rates[i++] & 0x7F) * 500000;
+ current_val = iwe_stream_add_value(info, start, current_val, stop, &iwe,
+ IW_EV_PARAM_LEN);
}
/* Check if we added any event */
if ((current_val - start) > iwe_stream_lcp_len(info))
@@ -324,8 +306,7 @@ static char *translate_scan(struct _adapter *padapter,
iwe.cmd = IWEVQUAL;
rssi = r8712_signal_scale_mapping(pnetwork->network.Rssi);
/* we only update signal_level (signal strength) that is rssi. */
- iwe.u.qual.updated = (u8)(IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED |
- IW_QUAL_NOISE_INVALID);
+ iwe.u.qual.updated = (u8)(IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID);
iwe.u.qual.level = rssi; /* signal strength */
iwe.u.qual.qual = 0; /* signal quality */
iwe.u.qual.noise = 0; /* noise level */
@@ -490,71 +471,59 @@ static int r871x_set_wpa_ie(struct _adapter *padapter, char *pie,
goto exit;
}
if (r8712_parse_wpa_ie(buf, ielen, &group_cipher,
- &pairwise_cipher) == 0) {
+ &pairwise_cipher) == 0) {
padapter->securitypriv.AuthAlgrthm = 2;
padapter->securitypriv.ndisauthtype =
Ndis802_11AuthModeWPAPSK;
}
if (r8712_parse_wpa2_ie(buf, ielen, &group_cipher,
- &pairwise_cipher) == 0) {
+ &pairwise_cipher) == 0) {
padapter->securitypriv.AuthAlgrthm = 2;
padapter->securitypriv.ndisauthtype =
Ndis802_11AuthModeWPA2PSK;
}
switch (group_cipher) {
case WPA_CIPHER_NONE:
- padapter->securitypriv.XGrpPrivacy =
- _NO_PRIVACY_;
- padapter->securitypriv.ndisencryptstatus =
- Ndis802_11EncryptionDisabled;
+ padapter->securitypriv.XGrpPrivacy = _NO_PRIVACY_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
break;
case WPA_CIPHER_WEP40:
padapter->securitypriv.XGrpPrivacy = _WEP40_;
- padapter->securitypriv.ndisencryptstatus =
- Ndis802_11Encryption1Enabled;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
break;
case WPA_CIPHER_TKIP:
padapter->securitypriv.XGrpPrivacy = _TKIP_;
- padapter->securitypriv.ndisencryptstatus =
- Ndis802_11Encryption2Enabled;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
break;
case WPA_CIPHER_CCMP:
padapter->securitypriv.XGrpPrivacy = _AES_;
- padapter->securitypriv.ndisencryptstatus =
- Ndis802_11Encryption3Enabled;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
break;
case WPA_CIPHER_WEP104:
padapter->securitypriv.XGrpPrivacy = _WEP104_;
- padapter->securitypriv.ndisencryptstatus =
- Ndis802_11Encryption1Enabled;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
break;
}
switch (pairwise_cipher) {
case WPA_CIPHER_NONE:
- padapter->securitypriv.PrivacyAlgrthm =
- _NO_PRIVACY_;
- padapter->securitypriv.ndisencryptstatus =
- Ndis802_11EncryptionDisabled;
+ padapter->securitypriv.PrivacyAlgrthm = _NO_PRIVACY_;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
break;
case WPA_CIPHER_WEP40:
padapter->securitypriv.PrivacyAlgrthm = _WEP40_;
- padapter->securitypriv.ndisencryptstatus =
- Ndis802_11Encryption1Enabled;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
break;
case WPA_CIPHER_TKIP:
padapter->securitypriv.PrivacyAlgrthm = _TKIP_;
- padapter->securitypriv.ndisencryptstatus =
- Ndis802_11Encryption2Enabled;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
break;
case WPA_CIPHER_CCMP:
padapter->securitypriv.PrivacyAlgrthm = _AES_;
- padapter->securitypriv.ndisencryptstatus =
- Ndis802_11Encryption3Enabled;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
break;
case WPA_CIPHER_WEP104:
padapter->securitypriv.PrivacyAlgrthm = _WEP104_;
- padapter->securitypriv.ndisencryptstatus =
- Ndis802_11Encryption1Enabled;
+ padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
break;
}
padapter->securitypriv.wps_phase = false;
@@ -574,8 +543,8 @@ static int r871x_set_wpa_ie(struct _adapter *padapter, char *pie,
(buf[cnt + 1] + 2) :
(MAX_WPA_IE_LEN << 2);
memcpy(padapter->securitypriv.wps_ie,
- &buf[cnt],
- padapter->securitypriv.wps_ie_len);
+ &buf[cnt],
+ padapter->securitypriv.wps_ie_len);
padapter->securitypriv.wps_phase =
true;
netdev_info(padapter->pnetdev, "r8712u: SET WPS_IE, wps_phase==true\n");
@@ -592,8 +561,7 @@ exit:
return ret;
}
-static int r8711_wx_get_name(struct net_device *dev,
- struct iw_request_info *info,
+static int r8711_wx_get_name(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct _adapter *padapter = netdev_priv(dev);
@@ -604,8 +572,7 @@ static int r8711_wx_get_name(struct net_device *dev,
struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
u8 *prates;
- if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE) ==
- true) {
+ if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE) == true) {
/* parsing HT_CAP_IE */
p = r8712_get_ie(&pcur_bss->IEs[12], WLAN_EID_HT_CAPABILITY,
&ht_ielen, pcur_bss->IELength - 12);
@@ -658,9 +625,7 @@ static int r8711_wx_set_freq(struct net_device *dev,
int rc = 0;
/* If setting by frequency, convert to a channel */
- if ((fwrq->e == 1) &&
- (fwrq->m >= 241200000) &&
- (fwrq->m <= 248700000)) {
+ if ((fwrq->e == 1) && (fwrq->m >= 241200000) && (fwrq->m <= 248700000)) {
int f = fwrq->m / 100000;
int c = 0;
@@ -685,8 +650,7 @@ static int r8711_wx_set_freq(struct net_device *dev,
return rc;
}
-static int r8711_wx_get_freq(struct net_device *dev,
- struct iw_request_info *info,
+static int r8711_wx_get_freq(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct _adapter *padapter = netdev_priv(dev);
@@ -745,7 +709,7 @@ static int r8711_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
wrqu->mode = IW_MODE_INFRA;
else if (check_fwstate(pmlmepriv,
- WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE))
+ WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE))
wrqu->mode = IW_MODE_ADHOC;
else if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
wrqu->mode = IW_MODE_MASTER;
@@ -754,9 +718,8 @@ static int r8711_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
return 0;
}
-static int r871x_wx_set_pmkid(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *extra)
+static int r871x_wx_set_pmkid(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
{
struct _adapter *padapter = netdev_priv(dev);
struct security_priv *psecuritypriv = &padapter->securitypriv;
@@ -828,7 +791,7 @@ static int r871x_wx_set_pmkid(struct net_device *dev,
break;
case IW_PMKSA_FLUSH:
memset(psecuritypriv->PMKIDList, 0,
- sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE);
+ sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE);
psecuritypriv->PMKIDIndex = 0;
intReturn = true;
break;
@@ -850,9 +813,8 @@ static int r8711_wx_get_sens(struct net_device *dev,
return 0;
}
-static int r8711_wx_get_range(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
+static int r8711_wx_get_range(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
{
struct iw_range *range = (struct iw_range *)extra;
u16 val;
@@ -912,9 +874,9 @@ static int r8711_wx_get_rate(struct net_device *dev,
union iwreq_data *wrqu, char *extra);
static int r871x_wx_set_priv(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *awrq,
- char *extra)
+ struct iw_request_info *info,
+ union iwreq_data *awrq,
+ char *extra)
{
int ret = 0, len = 0;
char *ext;
@@ -995,12 +957,10 @@ static int r871x_wx_set_priv(struct net_device *dev,
);
sprintf(ext, "OK");
} else {
- netdev_info(dev, "r8712u: %s: unknown Command %s.\n",
- __func__, ext);
+ netdev_info(dev, "r8712u: %s: unknown Command %s.\n", __func__, ext);
goto FREE_EXT;
}
- if (copy_to_user(dwrq->pointer, ext,
- min(dwrq->length, (__u16)(strlen(ext) + 1))))
+ if (copy_to_user(dwrq->pointer, ext, min(dwrq->length, (__u16)(strlen(ext) + 1))))
ret = -EFAULT;
FREE_EXT:
@@ -1021,10 +981,8 @@ FREE_EXT:
* For this operation to succeed, there is no need for the interface to be up.
*
*/
-static int r8711_wx_set_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *awrq,
- char *extra)
+static int r8711_wx_set_wap(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *awrq, char *extra)
{
int ret = -EINPROGRESS;
struct _adapter *padapter = netdev_priv(dev);
@@ -1072,17 +1030,15 @@ static int r8711_wx_set_wap(struct net_device *dev,
return ret;
}
-static int r8711_wx_get_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
+static int r8711_wx_get_wap(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
{
struct _adapter *padapter = netdev_priv(dev);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network;
wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE |
- WIFI_AP_STATE))
+ if (check_fwstate(pmlmepriv, _FW_LINKED | WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE))
ether_addr_copy(wrqu->ap_addr.sa_data, pcur_bss->MacAddress);
else
eth_zero_addr(wrqu->ap_addr.sa_data);
@@ -1122,9 +1078,8 @@ static int r871x_wx_set_mlme(struct net_device *dev,
* For this operation to succeed, the interface is brought Up beforehand.
*
*/
-static int r8711_wx_set_scan(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *extra)
+static int r8711_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
{
struct _adapter *padapter = netdev_priv(dev);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -1150,8 +1105,7 @@ static int r8711_wx_set_scan(struct net_device *dev,
unsigned long irqL;
u32 len = min_t(u8, req->essid_len, IW_ESSID_MAX_SIZE);
- memset((unsigned char *)&ssid, 0,
- sizeof(struct ndis_802_11_ssid));
+ memset((unsigned char *)&ssid, 0, sizeof(struct ndis_802_11_ssid));
memcpy(ssid.Ssid, req->essid, len);
ssid.SsidLength = len;
spin_lock_irqsave(&pmlmepriv->lock, irqL);
@@ -1173,9 +1127,8 @@ static int r8711_wx_set_scan(struct net_device *dev,
return 0;
}
-static int r8711_wx_get_scan(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *extra)
+static int r8711_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
{
struct _adapter *padapter = netdev_priv(dev);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -1189,8 +1142,7 @@ static int r8711_wx_get_scan(struct net_device *dev,
if (padapter->driver_stopped)
return -EINVAL;
- while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY |
- _FW_UNDER_LINKING)) {
+ while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING)) {
msleep(30);
cnt++;
if (cnt > 100)
@@ -1228,9 +1180,8 @@ static int r8711_wx_get_scan(struct net_device *dev,
* For this operation to succeed, there is no need for the interface to be Up.
*
*/
-static int r8711_wx_set_essid(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *extra)
+static int r8711_wx_set_essid(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
{
struct _adapter *padapter = netdev_priv(dev);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -1268,8 +1219,7 @@ static int r8711_wx_set_essid(struct net_device *dev,
if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength))
&& (pnetwork->network.Ssid.SsidLength ==
ndis_ssid.SsidLength)) {
- if (check_fwstate(pmlmepriv,
- WIFI_ADHOC_STATE)) {
+ if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {
if (pnetwork->network.
InfrastructureMode
!=
@@ -1291,9 +1241,8 @@ static int r8711_wx_set_essid(struct net_device *dev,
return -EINPROGRESS;
}
-static int r8711_wx_get_essid(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *extra)
+static int r8711_wx_get_essid(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
{
struct _adapter *padapter = netdev_priv(dev);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
@@ -1311,9 +1260,8 @@ static int r8711_wx_get_essid(struct net_device *dev,
return ret;
}
-static int r8711_wx_set_rate(struct net_device *dev,
- struct iw_request_info *a,
- union iwreq_data *wrqu, char *extra)
+static int r8711_wx_set_rate(struct net_device *dev, struct iw_request_info *a,
+ union iwreq_data *wrqu, char *extra)
{
struct _adapter *padapter = netdev_priv(dev);
u32 target_rate = wrqu->bitrate.value;
@@ -1382,8 +1330,7 @@ set_rate:
return r8712_setdatarate_cmd(padapter, datarates);
}
-static int r8711_wx_get_rate(struct net_device *dev,
- struct iw_request_info *info,
+static int r8711_wx_get_rate(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
struct _adapter *padapter = netdev_priv(dev);
@@ -1437,9 +1384,8 @@ static int r8711_wx_get_rate(struct net_device *dev,
return 0;
}
-static int r8711_wx_get_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
+static int r8711_wx_get_rts(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
{
struct _adapter *padapter = netdev_priv(dev);
@@ -1448,9 +1394,8 @@ static int r8711_wx_get_rts(struct net_device *dev,
return 0;
}
-static int r8711_wx_set_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
+static int r8711_wx_set_frag(struct net_device *dev, struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
{
struct _adapter *padapter = netdev_priv(dev);
diff --git a/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h b/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
index a08c5d2f59e3..bb9f83d58225 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
+++ b/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
@@ -126,7 +126,7 @@
#define rFPGA0_AnalogParameter3 0x888 /* Useless now */
#define rFPGA0_AnalogParameter4 0x88c
-#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Tranceiver LSSI Readback */
+#define rFPGA0_XA_LSSIReadBack 0x8a0 /* Transceiver LSSI Readback */
#define rFPGA0_XB_LSSIReadBack 0x8a4
#define rFPGA0_XC_LSSIReadBack 0x8a8
#define rFPGA0_XD_LSSIReadBack 0x8ac
diff --git a/drivers/staging/vc04_services/interface/TODO b/drivers/staging/vc04_services/interface/TODO
index 6d9d4a800aa7..05eb5140d096 100644
--- a/drivers/staging/vc04_services/interface/TODO
+++ b/drivers/staging/vc04_services/interface/TODO
@@ -23,11 +23,6 @@ should properly handle a module unload. This also includes that all
resources must be freed (kthreads, debugfs entries, ...) and global
variables avoided.
-* Cleanup logging mechanism
-
-The driver should probably be using the standard kernel logging mechanisms
-such as dev_info, dev_dbg, and friends.
-
* Documentation
A short top-down description of this driver's architecture (function of
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
index 9fb8f657cc78..1579bd4e5263 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -255,8 +255,7 @@ create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf,
pagelist = dma_alloc_coherent(instance->state->dev, pagelist_size, &dma_addr,
GFP_KERNEL);
- vchiq_log_trace(instance->state->dev, VCHIQ_ARM,
- "%s - %pK", __func__, pagelist);
+ dev_dbg(instance->state->dev, "arm: %pK\n", pagelist);
if (!pagelist)
return NULL;
@@ -311,9 +310,8 @@ create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf,
type == PAGELIST_READ, pages);
if (actual_pages != num_pages) {
- vchiq_log_debug(instance->state->dev, VCHIQ_ARM,
- "%s - only %d/%d pages locked",
- __func__, actual_pages, num_pages);
+ dev_dbg(instance->state->dev, "arm: Only %d/%d pages locked\n",
+ actual_pages, num_pages);
/* This is probably due to the process being killed */
if (actual_pages > 0)
@@ -407,8 +405,7 @@ free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagel
struct page **pages = pagelistinfo->pages;
unsigned int num_pages = pagelistinfo->num_pages;
- vchiq_log_trace(instance->state->dev, VCHIQ_ARM,
- "%s - %pK, %d", __func__, pagelistinfo->pagelist, actual);
+ dev_dbg(instance->state->dev, "arm: %pK, %d\n", pagelistinfo->pagelist, actual);
/*
* NOTE: dma_unmap_sg must be called before the
@@ -556,8 +553,8 @@ static int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state
return -ENXIO;
}
- vchiq_log_debug(&pdev->dev, VCHIQ_ARM, "vchiq_init - done (slots %pK, phys %pad)",
- vchiq_slot_zero, &slot_phys);
+ dev_dbg(&pdev->dev, "arm: vchiq_init - done (slots %pK, phys %pad)\n",
+ vchiq_slot_zero, &slot_phys);
vchiq_call_connected_callbacks();
@@ -659,13 +656,9 @@ vchiq_complete_bulk(struct vchiq_instance *instance, struct vchiq_bulk *bulk)
bulk->actual);
}
-int vchiq_dump_platform_state(void *dump_context)
+void vchiq_dump_platform_state(struct seq_file *f)
{
- char buf[80];
- int len;
-
- len = snprintf(buf, sizeof(buf), " Platform: 2835 (VC master)");
- return vchiq_dump(dump_context, buf, len + 1);
+ seq_puts(f, " Platform: 2835 (VC master)\n");
}
#define VCHIQ_INIT_RETRIES 10
@@ -687,19 +680,17 @@ int vchiq_initialise(struct vchiq_instance **instance_out)
usleep_range(500, 600);
}
if (i == VCHIQ_INIT_RETRIES) {
- vchiq_log_error(state->dev, VCHIQ_CORE, "%s: videocore not initialized\n",
- __func__);
+ dev_err(state->dev, "core: %s: Videocore not initialized\n", __func__);
ret = -ENOTCONN;
goto failed;
} else if (i > 0) {
- vchiq_log_warning(state->dev, VCHIQ_CORE,
- "%s: videocore initialized after %d retries\n", __func__, i);
+ dev_warn(state->dev, "core: %s: videocore initialized after %d retries\n",
+ __func__, i);
}
instance = kzalloc(sizeof(*instance), GFP_KERNEL);
if (!instance) {
- vchiq_log_error(state->dev, VCHIQ_CORE,
- "%s: error allocating vchiq instance\n", __func__);
+ dev_err(state->dev, "core: %s: Cannot allocate vchiq instance\n", __func__);
ret = -ENOMEM;
goto failed;
}
@@ -714,8 +705,7 @@ int vchiq_initialise(struct vchiq_instance **instance_out)
ret = 0;
failed:
- vchiq_log_trace(state->dev, VCHIQ_CORE,
- "%s(%p): returning %d", __func__, instance, ret);
+ dev_dbg(state->dev, "core: (%p): returning %d\n", instance, ret);
return ret;
}
@@ -728,9 +718,9 @@ void free_bulk_waiter(struct vchiq_instance *instance)
list_for_each_entry_safe(waiter, next,
&instance->bulk_waiter_list, list) {
list_del(&waiter->list);
- vchiq_log_debug(instance->state->dev, VCHIQ_ARM,
- "bulk_waiter - cleaned up %pK for pid %d",
- waiter, waiter->pid);
+ dev_dbg(instance->state->dev,
+ "arm: bulk_waiter - cleaned up %pK for pid %d\n",
+ waiter, waiter->pid);
kfree(waiter);
}
}
@@ -748,8 +738,7 @@ int vchiq_shutdown(struct vchiq_instance *instance)
mutex_unlock(&state->mutex);
- vchiq_log_trace(state->dev, VCHIQ_CORE,
- "%s(%p): returning %d", __func__, instance, status);
+ dev_dbg(state->dev, "core: (%p): returning %d\n", instance, status);
free_bulk_waiter(instance);
kfree(instance);
@@ -769,8 +758,8 @@ int vchiq_connect(struct vchiq_instance *instance)
struct vchiq_state *state = instance->state;
if (mutex_lock_killable(&state->mutex)) {
- vchiq_log_trace(state->dev, VCHIQ_CORE,
- "%s: call to mutex_lock failed", __func__);
+ dev_dbg(state->dev,
+ "core: call to mutex_lock failed\n");
status = -EAGAIN;
goto failed;
}
@@ -782,8 +771,7 @@ int vchiq_connect(struct vchiq_instance *instance)
mutex_unlock(&state->mutex);
failed:
- vchiq_log_trace(state->dev, VCHIQ_CORE,
- "%s(%p): returning %d", __func__, instance, status);
+ dev_dbg(state->dev, "core: (%p): returning %d\n", instance, status);
return status;
}
@@ -814,8 +802,7 @@ vchiq_add_service(struct vchiq_instance *instance,
status = -EINVAL;
}
- vchiq_log_trace(state->dev, VCHIQ_CORE,
- "%s(%p): returning %d", __func__, instance, status);
+ dev_dbg(state->dev, "core: (%p): returning %d\n", instance, status);
return status;
}
@@ -846,8 +833,7 @@ vchiq_open_service(struct vchiq_instance *instance,
}
failed:
- vchiq_log_trace(state->dev, VCHIQ_CORE,
- "%s(%p): returning %d", __func__, instance, status);
+ dev_dbg(state->dev, "core: (%p): returning %d\n", instance, status);
return status;
}
@@ -971,8 +957,7 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl
} else {
waiter = kzalloc(sizeof(*waiter), GFP_KERNEL);
if (!waiter) {
- vchiq_log_error(service->state->dev, VCHIQ_CORE,
- "%s - out of memory", __func__);
+ dev_err(service->state->dev, "core: %s: - Out of memory\n", __func__);
return -ENOMEM;
}
}
@@ -995,9 +980,8 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl
mutex_lock(&instance->bulk_waiter_list_mutex);
list_add(&waiter->list, &instance->bulk_waiter_list);
mutex_unlock(&instance->bulk_waiter_list_mutex);
- vchiq_log_debug(instance->state->dev, VCHIQ_ARM,
- "saved bulk_waiter %pK for pid %d", waiter,
- current->pid);
+ dev_dbg(instance->state->dev, "arm: saved bulk_waiter %pK for pid %d\n",
+ waiter, current->pid);
}
return status;
@@ -1017,16 +1001,13 @@ add_completion(struct vchiq_instance *instance, enum vchiq_reason reason,
while ((insert - instance->completion_remove) >= MAX_COMPLETIONS) {
/* Out of space - wait for the client */
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
- vchiq_log_trace(instance->state->dev, VCHIQ_CORE,
- "%s - completion queue full", __func__);
+ dev_dbg(instance->state->dev, "core: completion queue full\n");
DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
if (wait_for_completion_interruptible(&instance->remove_event)) {
- vchiq_log_debug(instance->state->dev, VCHIQ_ARM,
- "service_callback interrupted");
+ dev_dbg(instance->state->dev, "arm: service_callback interrupted\n");
return -EAGAIN;
} else if (instance->closing) {
- vchiq_log_debug(instance->state->dev, VCHIQ_ARM,
- "service_callback closing");
+ dev_dbg(instance->state->dev, "arm: service_callback closing\n");
return 0;
}
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
@@ -1106,11 +1087,10 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
vchiq_service_get(service);
rcu_read_unlock();
- vchiq_log_trace(service->state->dev, VCHIQ_ARM,
- "%s - service %lx(%d,%p), reason %d, header %lx, instance %lx, bulk_userdata %lx",
- __func__, (unsigned long)user_service, service->localport,
- user_service->userdata, reason, (unsigned long)header,
- (unsigned long)instance, (unsigned long)bulk_userdata);
+ dev_dbg(service->state->dev,
+ "arm: service %p(%d,%p), reason %d, header %p, instance %p, bulk_userdata %p\n",
+ user_service, service->localport, user_service->userdata,
+ reason, header, instance, bulk_userdata);
if (header && user_service->is_vchi) {
spin_lock(&msg_queue_spinlock);
@@ -1119,8 +1099,7 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
spin_unlock(&msg_queue_spinlock);
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
DEBUG_COUNT(MSG_QUEUE_FULL_COUNT);
- vchiq_log_trace(service->state->dev, VCHIQ_ARM,
- "%s - msg queue full", __func__);
+ dev_dbg(service->state->dev, "arm: msg queue full\n");
/*
* If there is no MESSAGE_AVAILABLE in the completion
* queue, add one
@@ -1129,8 +1108,8 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
instance->completion_remove) < 0) {
int status;
- vchiq_log_debug(instance->state->dev, VCHIQ_ARM,
- "Inserting extra MESSAGE_AVAILABLE");
+ dev_dbg(instance->state->dev,
+ "arm: Inserting extra MESSAGE_AVAILABLE\n");
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
status = add_completion(instance, reason, NULL, user_service,
bulk_userdata);
@@ -1143,14 +1122,12 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
if (wait_for_completion_interruptible(&user_service->remove_event)) {
- vchiq_log_debug(instance->state->dev, VCHIQ_ARM,
- "%s interrupted", __func__);
+ dev_dbg(instance->state->dev, "arm: interrupted\n");
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
vchiq_service_put(service);
return -EAGAIN;
} else if (instance->closing) {
- vchiq_log_debug(instance->state->dev, VCHIQ_ARM,
- "%s closing", __func__);
+ dev_dbg(instance->state->dev, "arm: closing\n");
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
vchiq_service_put(service);
return -EINVAL;
@@ -1190,56 +1167,13 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason,
bulk_userdata);
}
-int vchiq_dump(void *dump_context, const char *str, int len)
-{
- struct dump_context *context = (struct dump_context *)dump_context;
- int copy_bytes;
-
- if (context->actual >= context->space)
- return 0;
-
- if (context->offset > 0) {
- int skip_bytes = min_t(int, len, context->offset);
-
- str += skip_bytes;
- len -= skip_bytes;
- context->offset -= skip_bytes;
- if (context->offset > 0)
- return 0;
- }
- copy_bytes = min_t(int, len, context->space - context->actual);
- if (copy_bytes == 0)
- return 0;
- if (copy_to_user(context->buf + context->actual, str,
- copy_bytes))
- return -EFAULT;
- context->actual += copy_bytes;
- len -= copy_bytes;
-
- /*
- * If the terminating NUL is included in the length, then it
- * marks the end of a line and should be replaced with a
- * carriage return.
- */
- if ((len == 0) && (str[copy_bytes - 1] == '\0')) {
- char cr = '\n';
-
- if (copy_to_user(context->buf + context->actual - 1,
- &cr, 1))
- return -EFAULT;
- }
- return 0;
-}
-
-int vchiq_dump_platform_instances(void *dump_context)
+void vchiq_dump_platform_instances(struct seq_file *f)
{
struct vchiq_state *state = vchiq_get_state();
- char buf[80];
- int len;
int i;
if (!state)
- return -ENOTCONN;
+ return;
/*
* There is no list of instances, so instead scan all services,
@@ -1264,7 +1198,6 @@ int vchiq_dump_platform_instances(void *dump_context)
for (i = 0; i < state->unused_service; i++) {
struct vchiq_service *service;
struct vchiq_instance *instance;
- int err;
rcu_read_lock();
service = rcu_dereference(state->services[i]);
@@ -1280,43 +1213,35 @@ int vchiq_dump_platform_instances(void *dump_context)
}
rcu_read_unlock();
- len = snprintf(buf, sizeof(buf),
- "Instance %pK: pid %d,%s completions %d/%d",
- instance, instance->pid,
- instance->connected ? " connected, " :
- "",
- instance->completion_insert -
- instance->completion_remove,
- MAX_COMPLETIONS);
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
+ seq_printf(f, "Instance %pK: pid %d,%s completions %d/%d\n",
+ instance, instance->pid,
+ instance->connected ? " connected, " :
+ "",
+ instance->completion_insert -
+ instance->completion_remove,
+ MAX_COMPLETIONS);
instance->mark = 1;
}
- return 0;
}
-int vchiq_dump_platform_service_state(void *dump_context,
- struct vchiq_service *service)
+void vchiq_dump_platform_service_state(struct seq_file *f,
+ struct vchiq_service *service)
{
struct user_service *user_service =
(struct user_service *)service->base.userdata;
- char buf[80];
- int len;
- len = scnprintf(buf, sizeof(buf), " instance %pK", service->instance);
+ seq_printf(f, " instance %pK", service->instance);
if ((service->base.callback == service_callback) && user_service->is_vchi) {
- len += scnprintf(buf + len, sizeof(buf) - len, ", %d/%d messages",
- user_service->msg_insert - user_service->msg_remove,
- MSG_QUEUE_SIZE);
+ seq_printf(f, ", %d/%d messages",
+ user_service->msg_insert - user_service->msg_remove,
+ MSG_QUEUE_SIZE);
if (user_service->dequeue_pending)
- len += scnprintf(buf + len, sizeof(buf) - len,
- " (dequeue pending)");
+ seq_puts(f, " (dequeue pending)");
}
- return vchiq_dump(dump_context, buf, len + 1);
+ seq_puts(f, "\n");
}
struct vchiq_state *
@@ -1346,8 +1271,8 @@ vchiq_keepalive_vchiq_callback(struct vchiq_instance *instance,
struct vchiq_header *header,
unsigned int service_user, void *bulk_user)
{
- vchiq_log_error(instance->state->dev, VCHIQ_SUSPEND,
- "%s callback reason %d", __func__, reason);
+ dev_err(instance->state->dev, "suspend: %s: callback reason %d\n",
+ __func__, reason);
return 0;
}
@@ -1371,22 +1296,20 @@ vchiq_keepalive_thread_func(void *v)
ret = vchiq_initialise(&instance);
if (ret) {
- vchiq_log_error(state->dev, VCHIQ_SUSPEND,
- "%s vchiq_initialise failed %d", __func__, ret);
+ dev_err(state->dev, "suspend: %s: vchiq_initialise failed %d\n", __func__, ret);
goto exit;
}
status = vchiq_connect(instance);
if (status) {
- vchiq_log_error(state->dev, VCHIQ_SUSPEND,
- "%s vchiq_connect failed %d", __func__, status);
+ dev_err(state->dev, "suspend: %s: vchiq_connect failed %d\n", __func__, status);
goto shutdown;
}
status = vchiq_add_service(instance, &params, &ka_handle);
if (status) {
- vchiq_log_error(state->dev, VCHIQ_SUSPEND,
- "%s vchiq_open_service failed %d", __func__, status);
+ dev_err(state->dev, "suspend: %s: vchiq_open_service failed %d\n",
+ __func__, status);
goto shutdown;
}
@@ -1394,8 +1317,7 @@ vchiq_keepalive_thread_func(void *v)
long rc = 0, uc = 0;
if (wait_for_completion_interruptible(&arm_state->ka_evt)) {
- vchiq_log_error(state->dev, VCHIQ_SUSPEND,
- "%s interrupted", __func__);
+ dev_err(state->dev, "suspend: %s: interrupted\n", __func__);
flush_signals(current);
continue;
}
@@ -1415,16 +1337,15 @@ vchiq_keepalive_thread_func(void *v)
atomic_inc(&arm_state->ka_use_ack_count);
status = vchiq_use_service(instance, ka_handle);
if (status) {
- vchiq_log_error(state->dev, VCHIQ_SUSPEND,
- "%s vchiq_use_service error %d", __func__, status);
+ dev_err(state->dev, "suspend: %s: vchiq_use_service error %d\n",
+ __func__, status);
}
}
while (rc--) {
status = vchiq_release_service(instance, ka_handle);
if (status) {
- vchiq_log_error(state->dev, VCHIQ_SUSPEND,
- "%s vchiq_release_service error %d", __func__,
- status);
+ dev_err(state->dev, "suspend: %s: vchiq_release_service error %d\n",
+ __func__, status);
}
}
}
@@ -1459,7 +1380,7 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
service->client_id);
entity_uc = &service->service_use_count;
} else {
- vchiq_log_error(state->dev, VCHIQ_SUSPEND, "%s null service ptr", __func__);
+ dev_err(state->dev, "suspend: %s: null service ptr\n", __func__);
ret = -EINVAL;
goto out;
}
@@ -1468,8 +1389,8 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
local_uc = ++arm_state->videocore_use_count;
++(*entity_uc);
- vchiq_log_trace(state->dev, VCHIQ_SUSPEND, "%s %s count %d, state count %d",
- __func__, entity, *entity_uc, local_uc);
+ dev_dbg(state->dev, "suspend: %s count %d, state count %d\n",
+ entity, *entity_uc, local_uc);
write_unlock_bh(&arm_state->susp_res_lock);
@@ -1488,7 +1409,7 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
}
out:
- vchiq_log_trace(state->dev, VCHIQ_SUSPEND, "%s exit %d", __func__, ret);
+ dev_dbg(state->dev, "suspend: exit %d\n", ret);
return ret;
}
@@ -1526,14 +1447,14 @@ vchiq_release_internal(struct vchiq_state *state, struct vchiq_service *service)
--arm_state->videocore_use_count;
--(*entity_uc);
- vchiq_log_trace(state->dev, VCHIQ_SUSPEND, "%s %s count %d, state count %d",
- __func__, entity, *entity_uc, arm_state->videocore_use_count);
+ dev_dbg(state->dev, "suspend: %s count %d, state count %d\n",
+ entity, *entity_uc, arm_state->videocore_use_count);
unlock:
write_unlock_bh(&arm_state->susp_res_lock);
out:
- vchiq_log_trace(state->dev, VCHIQ_SUSPEND, "%s exit %d", __func__, ret);
+ dev_dbg(state->dev, "suspend: exit %d\n", ret);
return ret;
}
@@ -1707,20 +1628,19 @@ vchiq_dump_service_use_state(struct vchiq_state *state)
read_unlock_bh(&arm_state->susp_res_lock);
if (only_nonzero)
- vchiq_log_warning(state->dev, VCHIQ_SUSPEND,
- "Too many active services (%d). Only dumping up to first %d services with non-zero use-count",
- active_services, found);
+ dev_warn(state->dev,
+ "suspend: Too many active services (%d). Only dumping up to first %d services with non-zero use-count\n",
+ active_services, found);
for (i = 0; i < found; i++) {
- vchiq_log_warning(state->dev, VCHIQ_SUSPEND,
- "%p4cc:%d service count %d %s",
- &service_data[i].fourcc,
- service_data[i].clientid, service_data[i].use_count,
- service_data[i].use_count ? nz : "");
+ dev_warn(state->dev,
+ "suspend: %p4cc:%d service count %d %s\n",
+ &service_data[i].fourcc,
+ service_data[i].clientid, service_data[i].use_count,
+ service_data[i].use_count ? nz : "");
}
- vchiq_log_warning(state->dev, VCHIQ_SUSPEND, "VCHIQ use count %d", peer_count);
- vchiq_log_warning(state->dev, VCHIQ_SUSPEND, "Overall vchiq instance use count %d",
- vc_use_count);
+ dev_warn(state->dev, "suspend: VCHIQ use count %d\n", peer_count);
+ dev_warn(state->dev, "suspend: Overall vchiq instance use count %d\n", vc_use_count);
kfree(service_data);
}
@@ -1742,10 +1662,10 @@ vchiq_check_service(struct vchiq_service *service)
read_unlock_bh(&arm_state->susp_res_lock);
if (ret) {
- vchiq_log_error(service->state->dev, VCHIQ_SUSPEND,
- "%s ERROR - %p4cc:%d service count %d, state count %d", __func__,
- &service->base.fourcc, service->client_id,
- service->service_use_count, arm_state->videocore_use_count);
+ dev_err(service->state->dev,
+ "suspend: %s: %p4cc:%d service count %d, state count %d\n",
+ __func__, &service->base.fourcc, service->client_id,
+ service->service_use_count, arm_state->videocore_use_count);
vchiq_dump_service_use_state(service->state);
}
out:
@@ -1759,8 +1679,8 @@ void vchiq_platform_conn_state_changed(struct vchiq_state *state,
struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
char threadname[16];
- vchiq_log_debug(state->dev, VCHIQ_SUSPEND, "%d: %s->%s", state->id,
- get_conn_state_name(oldstate), get_conn_state_name(newstate));
+ dev_dbg(state->dev, "suspend: %d: %s->%s\n",
+ state->id, get_conn_state_name(oldstate), get_conn_state_name(newstate));
if (state->conn_state != VCHIQ_CONNSTATE_CONNECTED)
return;
@@ -1778,9 +1698,8 @@ void vchiq_platform_conn_state_changed(struct vchiq_state *state,
(void *)state,
threadname);
if (IS_ERR(arm_state->ka_thread)) {
- vchiq_log_error(state->dev, VCHIQ_SUSPEND,
- "vchiq: FATAL: couldn't create thread %s",
- threadname);
+ dev_err(state->dev, "suspend: Couldn't create thread %s\n",
+ threadname);
} else {
wake_up_process(arm_state->ka_thread);
}
@@ -1825,9 +1744,8 @@ static int vchiq_probe(struct platform_device *pdev)
vchiq_debugfs_init();
- vchiq_log_debug(&pdev->dev, VCHIQ_ARM,
- "vchiq: platform initialised - version %d (min %d)",
- VCHIQ_VERSION, VCHIQ_VERSION_MIN);
+ dev_dbg(&pdev->dev, "arm: platform initialised - version %d (min %d)\n",
+ VCHIQ_VERSION, VCHIQ_VERSION_MIN);
/*
* Simply exit on error since the function handles cleanup in
@@ -1835,8 +1753,7 @@ static int vchiq_probe(struct platform_device *pdev)
*/
err = vchiq_register_chrdev(&pdev->dev);
if (err) {
- vchiq_log_warning(&pdev->dev, VCHIQ_ARM,
- "Failed to initialize vchiq cdev");
+ dev_warn(&pdev->dev, "arm: Failed to initialize vchiq cdev\n");
goto error_exit;
}
@@ -1846,7 +1763,7 @@ static int vchiq_probe(struct platform_device *pdev)
return 0;
failed_platform_init:
- vchiq_log_warning(&pdev->dev, VCHIQ_ARM, "could not initialize vchiq platform");
+ dev_warn(&pdev->dev, "arm: Could not initialize vchiq platform\n");
error_exit:
return err;
}
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
index 7cdc3d70bd2c..7844ef765a00 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h
@@ -69,13 +69,6 @@ struct vchiq_instance {
struct vchiq_debugfs_node debugfs_node;
};
-struct dump_context {
- char __user *buf;
- size_t actual;
- size_t space;
- loff_t offset;
-};
-
extern spinlock_t msg_queue_spinlock;
extern struct vchiq_state g_state;
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
index b3928bd8c9c6..3cad13f09e37 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.c
@@ -27,7 +27,7 @@ static void connected_init(void)
* be made immediately, otherwise it will be deferred until
* vchiq_call_connected_callbacks is called.
*/
-void vchiq_add_connected_callback(void (*callback)(void))
+void vchiq_add_connected_callback(struct vchiq_device *device, void (*callback)(void))
{
connected_init();
@@ -39,9 +39,9 @@ void vchiq_add_connected_callback(void (*callback)(void))
callback();
} else {
if (g_num_deferred_callbacks >= MAX_CALLBACKS) {
- vchiq_log_error(NULL, VCHIQ_CORE,
- "There already %d callback registered - please increase MAX_CALLBACKS",
- g_num_deferred_callbacks);
+ dev_err(&device->dev,
+ "core: There already %d callback registered - please increase MAX_CALLBACKS\n",
+ g_num_deferred_callbacks);
} else {
g_deferred_callback[g_num_deferred_callbacks] =
callback;
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h
index 4caf5e30099d..e4ed56446f8a 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_connected.h
@@ -1,10 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/* Copyright (c) 2010-2012 Broadcom. All rights reserved. */
+#include "vchiq_bus.h"
+
#ifndef VCHIQ_CONNECTED_H
#define VCHIQ_CONNECTED_H
-void vchiq_add_connected_callback(void (*callback)(void));
+void vchiq_add_connected_callback(struct vchiq_device *device, void (*callback)(void));
void vchiq_call_connected_callbacks(void);
#endif /* VCHIQ_CONNECTED_H */
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
index 39b857da2d42..76c27778154a 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -217,10 +217,10 @@ static const char *msg_type_str(unsigned int msg_type)
static inline void
set_service_state(struct vchiq_service *service, int newstate)
{
- vchiq_log_debug(service->state->dev, VCHIQ_CORE, "%d: srv:%d %s->%s",
- service->state->id, service->localport,
- srvstate_names[service->srvstate],
- srvstate_names[newstate]);
+ dev_dbg(service->state->dev, "core: %d: srv:%d %s->%s\n",
+ service->state->id, service->localport,
+ srvstate_names[service->srvstate],
+ srvstate_names[newstate]);
service->srvstate = newstate;
}
@@ -245,8 +245,7 @@ find_service_by_handle(struct vchiq_instance *instance, unsigned int handle)
return service;
}
rcu_read_unlock();
- vchiq_log_debug(service->state->dev, VCHIQ_CORE,
- "Invalid service handle 0x%x", handle);
+ dev_dbg(instance->state->dev, "core: Invalid service handle 0x%x\n", handle);
return NULL;
}
@@ -266,8 +265,7 @@ find_service_by_port(struct vchiq_state *state, unsigned int localport)
}
rcu_read_unlock();
}
- vchiq_log_debug(state->dev, VCHIQ_CORE,
- "Invalid port %u", localport);
+ dev_dbg(state->dev, "core: Invalid port %u\n", localport);
return NULL;
}
@@ -287,8 +285,7 @@ find_service_for_instance(struct vchiq_instance *instance, unsigned int handle)
return service;
}
rcu_read_unlock();
- vchiq_log_debug(service->state->dev, VCHIQ_CORE,
- "Invalid service handle 0x%x", handle);
+ dev_dbg(instance->state->dev, "core: Invalid service handle 0x%x\n", handle);
return NULL;
}
@@ -310,8 +307,7 @@ find_closed_service_for_instance(struct vchiq_instance *instance, unsigned int h
return service;
}
rcu_read_unlock();
- vchiq_log_debug(service->state->dev, VCHIQ_CORE,
- "Invalid service handle 0x%x", handle);
+ dev_dbg(instance->state->dev, "core: Invalid service handle 0x%x\n", handle);
return service;
}
@@ -459,15 +455,15 @@ make_service_callback(struct vchiq_service *service, enum vchiq_reason reason,
{
int status;
- vchiq_log_trace(service->state->dev, VCHIQ_CORE, "%d: callback:%d (%s, %pK, %pK)",
- service->state->id, service->localport, reason_names[reason],
- header, bulk_userdata);
+ dev_dbg(service->state->dev, "core: %d: callback:%d (%s, %pK, %pK)\n",
+ service->state->id, service->localport, reason_names[reason],
+ header, bulk_userdata);
status = service->base.callback(service->instance, reason, header, service->handle,
bulk_userdata);
if (status && (status != -EAGAIN)) {
- vchiq_log_warning(service->state->dev, VCHIQ_CORE,
- "%d: ignoring ERROR from callback to service %x",
- service->state->id, service->handle);
+ dev_warn(service->state->dev,
+ "core: %d: ignoring ERROR from callback to service %x\n",
+ service->state->id, service->handle);
status = 0;
}
@@ -482,8 +478,8 @@ vchiq_set_conn_state(struct vchiq_state *state, enum vchiq_connstate newstate)
{
enum vchiq_connstate oldstate = state->conn_state;
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: %s->%s", state->id, conn_state_names[oldstate],
- conn_state_names[newstate]);
+ dev_dbg(state->dev, "core: %d: %s->%s\n",
+ state->id, conn_state_names[oldstate], conn_state_names[newstate]);
state->conn_state = newstate;
vchiq_platform_conn_state_changed(state, oldstate, newstate);
}
@@ -741,10 +737,10 @@ process_free_data_message(struct vchiq_state *state, u32 *service_found,
*/
complete(&quota->quota_event);
} else if (count == 0) {
- vchiq_log_error(state->dev, VCHIQ_CORE,
- "service %d message_use_count=%d (header %pK, msgid %x, header->msgid %x, header->size %x)",
- port, quota->message_use_count, header, msgid, header->msgid,
- header->size);
+ dev_err(state->dev,
+ "core: service %d message_use_count=%d (header %pK, msgid %x, header->msgid %x, header->size %x)\n",
+ port, quota->message_use_count, header, msgid,
+ header->msgid, header->size);
WARN(1, "invalid message use count\n");
}
if (!BITSET_IS_SET(service_found, port)) {
@@ -763,12 +759,12 @@ process_free_data_message(struct vchiq_state *state, u32 *service_found,
* it has dropped below its quota
*/
complete(&quota->quota_event);
- vchiq_log_trace(state->dev, VCHIQ_CORE, "%d: pfq:%d %x@%pK - slot_use->%d",
- state->id, port, header->size, header, count - 1);
+ dev_dbg(state->dev, "core: %d: pfq:%d %x@%pK - slot_use->%d\n",
+ state->id, port, header->size, header, count - 1);
} else {
- vchiq_log_error(state->dev, VCHIQ_CORE,
- "service %d slot_use_count=%d (header %pK, msgid %x, header->msgid %x, header->size %x)",
- port, count, header, msgid, header->msgid, header->size);
+ dev_err(state->dev,
+ "core: service %d slot_use_count=%d (header %pK, msgid %x, header->msgid %x, header->size %x)\n",
+ port, count, header, msgid, header->msgid, header->size);
WARN(1, "bad slot use count\n");
}
}
@@ -809,9 +805,9 @@ process_free_queue(struct vchiq_state *state, u32 *service_found,
*/
rmb();
- vchiq_log_trace(state->dev, VCHIQ_CORE, "%d: pfq %d=%pK %x %x",
- state->id, slot_index, data, local->slot_queue_recycle,
- slot_queue_available);
+ dev_dbg(state->dev, "core: %d: pfq %d=%pK %x %x\n",
+ state->id, slot_index, data, local->slot_queue_recycle,
+ slot_queue_available);
/* Initialise the bitmask for services which have used this slot */
memset(service_found, 0, length);
@@ -831,9 +827,9 @@ process_free_queue(struct vchiq_state *state, u32 *service_found,
pos += calc_stride(header->size);
if (pos > VCHIQ_SLOT_SIZE) {
- vchiq_log_error(state->dev, VCHIQ_CORE,
- "pfq - pos %x: header %pK, msgid %x, header->msgid %x, header->size %x",
- pos, header, msgid, header->msgid, header->size);
+ dev_err(state->dev,
+ "core: pfq - pos %x: header %pK, msgid %x, header->msgid %x, header->size %x\n",
+ pos, header, msgid, header->msgid, header->size);
WARN(1, "invalid slot position\n");
}
}
@@ -980,10 +976,10 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
((tx_end_index != quota->previous_tx_index) &&
(quota->slot_use_count == quota->slot_quota))) {
spin_unlock(&quota_spinlock);
- vchiq_log_trace(state->dev, VCHIQ_CORE,
- "%d: qm:%d %s,%zx - quota stall (msg %d, slot %d)",
- state->id, service->localport, msg_type_str(type), size,
- quota->message_use_count, quota->slot_use_count);
+ dev_dbg(state->dev,
+ "core: %d: qm:%d %s,%zx - quota stall (msg %d, slot %d)\n",
+ state->id, service->localport, msg_type_str(type), size,
+ quota->message_use_count, quota->slot_use_count);
VCHIQ_SERVICE_STATS_INC(service, quota_stalls);
mutex_unlock(&state->slot_mutex);
if (wait_for_completion_interruptible(&quota->quota_event))
@@ -1023,9 +1019,9 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
int tx_end_index;
int slot_use_count;
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: qm %s@%pK,%zx (%d->%d)", state->id,
- msg_type_str(VCHIQ_MSG_TYPE(msgid)), header, size,
- VCHIQ_MSG_SRCPORT(msgid), VCHIQ_MSG_DSTPORT(msgid));
+ dev_dbg(state->dev, "core: %d: qm %s@%pK,%zx (%d->%d)\n",
+ state->id, msg_type_str(VCHIQ_MSG_TYPE(msgid)), header, size,
+ VCHIQ_MSG_SRCPORT(msgid), VCHIQ_MSG_DSTPORT(msgid));
WARN_ON(flags & (QMFLAGS_NO_MUTEX_LOCK |
QMFLAGS_NO_MUTEX_UNLOCK));
@@ -1073,17 +1069,16 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
spin_unlock(&quota_spinlock);
if (slot_use_count)
- vchiq_log_trace(state->dev, VCHIQ_CORE,
- "%d: qm:%d %s,%zx - slot_use->%d (hdr %p)", state->id,
- service->localport, msg_type_str(VCHIQ_MSG_TYPE(msgid)),
- size, slot_use_count, header);
+ dev_dbg(state->dev, "core: %d: qm:%d %s,%zx - slot_use->%d (hdr %p)\n",
+ state->id, service->localport, msg_type_str(VCHIQ_MSG_TYPE(msgid)),
+ size, slot_use_count, header);
VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
} else {
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: qm %s@%pK,%zx (%d->%d)", state->id,
- msg_type_str(VCHIQ_MSG_TYPE(msgid)), header, size,
- VCHIQ_MSG_SRCPORT(msgid), VCHIQ_MSG_DSTPORT(msgid));
+ dev_dbg(state->dev, "core: %d: qm %s@%pK,%zx (%d->%d)\n",
+ state->id, msg_type_str(VCHIQ_MSG_TYPE(msgid)), header, size,
+ VCHIQ_MSG_SRCPORT(msgid), VCHIQ_MSG_DSTPORT(msgid));
if (size != 0) {
/*
* It is assumed for now that this code path
@@ -1111,11 +1106,9 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service,
? service->base.fourcc
: VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
- vchiq_log_debug(state->dev, VCHIQ_CORE_MSG,
- "Sent Msg %s(%u) to %p4cc s:%u d:%d len:%zu",
- msg_type_str(VCHIQ_MSG_TYPE(msgid)), VCHIQ_MSG_TYPE(msgid),
- &svc_fourcc, VCHIQ_MSG_SRCPORT(msgid),
- VCHIQ_MSG_DSTPORT(msgid), size);
+ dev_dbg(state->dev, "core_msg: Sent Msg %s(%u) to %p4cc s:%u d:%d len:%zu\n",
+ msg_type_str(VCHIQ_MSG_TYPE(msgid)), VCHIQ_MSG_TYPE(msgid),
+ &svc_fourcc, VCHIQ_MSG_SRCPORT(msgid), VCHIQ_MSG_DSTPORT(msgid), size);
}
/* Make sure the new header is visible to the peer. */
@@ -1167,15 +1160,13 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
int oldmsgid = header->msgid;
if (oldmsgid != VCHIQ_MSGID_PADDING)
- vchiq_log_error(state->dev, VCHIQ_CORE, "%d: qms - msgid %x, not PADDING",
- state->id, oldmsgid);
+ dev_err(state->dev, "core: %d: qms - msgid %x, not PADDING\n",
+ state->id, oldmsgid);
}
- vchiq_log_debug(state->dev, VCHIQ_SYNC,
- "%d: qms %s@%pK,%x (%d->%d)", state->id,
- msg_type_str(VCHIQ_MSG_TYPE(msgid)),
- header, size, VCHIQ_MSG_SRCPORT(msgid),
- VCHIQ_MSG_DSTPORT(msgid));
+ dev_dbg(state->dev, "sync: %d: qms %s@%pK,%x (%d->%d)\n",
+ state->id, msg_type_str(VCHIQ_MSG_TYPE(msgid)), header, size,
+ VCHIQ_MSG_SRCPORT(msgid), VCHIQ_MSG_DSTPORT(msgid));
callback_result =
copy_message_data(copy_callback, context,
@@ -1205,11 +1196,11 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service,
svc_fourcc = service ? service->base.fourcc
: VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
- vchiq_log_trace(state->dev, VCHIQ_SYNC,
- "Sent Sync Msg %s(%u) to %p4cc s:%u d:%d len:%d",
- msg_type_str(VCHIQ_MSG_TYPE(msgid)), VCHIQ_MSG_TYPE(msgid),
- &svc_fourcc, VCHIQ_MSG_SRCPORT(msgid),
- VCHIQ_MSG_DSTPORT(msgid), size);
+ dev_dbg(state->dev,
+ "sync: Sent Sync Msg %s(%u) to %p4cc s:%u d:%d len:%d\n",
+ msg_type_str(VCHIQ_MSG_TYPE(msgid)), VCHIQ_MSG_TYPE(msgid),
+ &svc_fourcc, VCHIQ_MSG_SRCPORT(msgid),
+ VCHIQ_MSG_DSTPORT(msgid), size);
remote_event_signal(&state->remote->sync_trigger);
@@ -1261,9 +1252,9 @@ release_slot(struct vchiq_state *state, struct vchiq_slot_info *slot_info,
VCHIQ_SLOT_QUEUE_MASK] =
SLOT_INDEX_FROM_INFO(state, slot_info);
state->remote->slot_queue_recycle = slot_queue_recycle + 1;
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: %s %d - recycle->%x",
- state->id, __func__, SLOT_INDEX_FROM_INFO(state, slot_info),
- state->remote->slot_queue_recycle);
+ dev_dbg(state->dev, "core: %d: %d - recycle->%x\n",
+ state->id, SLOT_INDEX_FROM_INFO(state, slot_info),
+ state->remote->slot_queue_recycle);
/*
* A write barrier is necessary, but remote_event_signal
@@ -1298,11 +1289,11 @@ notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue,
{
int status = 0;
- vchiq_log_trace(service->state->dev, VCHIQ_CORE,
- "%d: nb:%d %cx - p=%x rn=%x r=%x",
- service->state->id, service->localport,
- (queue == &service->bulk_tx) ? 't' : 'r',
- queue->process, queue->remote_notify, queue->remove);
+ dev_dbg(service->state->dev,
+ "core: %d: nb:%d %cx - p=%x rn=%x r=%x\n",
+ service->state->id, service->localport,
+ (queue == &service->bulk_tx) ? 't' : 'r',
+ queue->process, queue->remote_notify, queue->remove);
queue->remote_notify = queue->process;
@@ -1382,8 +1373,8 @@ poll_services_of_group(struct vchiq_state *state, int group)
service_flags = atomic_xchg(&service->poll_flags, 0);
if (service_flags & BIT(VCHIQ_POLL_REMOVE)) {
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: ps - remove %d<->%d",
- state->id, service->localport, service->remoteport);
+ dev_dbg(state->dev, "core: %d: ps - remove %d<->%d\n",
+ state->id, service->localport, service->remoteport);
/*
* Make it look like a client, because
@@ -1395,8 +1386,8 @@ poll_services_of_group(struct vchiq_state *state, int group)
if (vchiq_close_service_internal(service, NO_CLOSE_RECVD))
request_poll(state, service, VCHIQ_POLL_REMOVE);
} else if (service_flags & BIT(VCHIQ_POLL_TERMINATE)) {
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: ps - terminate %d<->%d",
- state->id, service->localport, service->remoteport);
+ dev_dbg(state->dev, "core: %d: ps - terminate %d<->%d\n",
+ state->id, service->localport, service->remoteport);
if (vchiq_close_service_internal(service, NO_CLOSE_RECVD))
request_poll(state, service, VCHIQ_POLL_TERMINATE);
}
@@ -1425,11 +1416,11 @@ abort_outstanding_bulks(struct vchiq_service *service,
{
int is_tx = (queue == &service->bulk_tx);
- vchiq_log_trace(service->state->dev, VCHIQ_CORE,
- "%d: aob:%d %cx - li=%x ri=%x p=%x",
- service->state->id, service->localport,
- is_tx ? 't' : 'r', queue->local_insert,
- queue->remote_insert, queue->process);
+ dev_dbg(service->state->dev,
+ "core: %d: aob:%d %cx - li=%x ri=%x p=%x\n",
+ service->state->id, service->localport,
+ is_tx ? 't' : 'r', queue->local_insert,
+ queue->remote_insert, queue->process);
WARN_ON((int)(queue->local_insert - queue->process) < 0);
WARN_ON((int)(queue->remote_insert - queue->process) < 0);
@@ -1448,11 +1439,11 @@ abort_outstanding_bulks(struct vchiq_service *service,
if (queue->process != queue->local_insert) {
vchiq_complete_bulk(service->instance, bulk);
- vchiq_log_debug(service->state->dev, VCHIQ_CORE_MSG,
- "%s %p4cc d:%d ABORTED - tx len:%d, rx len:%d",
- is_tx ? "Send Bulk to" : "Recv Bulk from",
- &service->base.fourcc,
- service->remoteport, bulk->size, bulk->remote_size);
+ dev_dbg(service->state->dev,
+ "core_msg: %s %p4cc d:%d ABORTED - tx len:%d, rx len:%d\n",
+ is_tx ? "Send Bulk to" : "Recv Bulk from",
+ &service->base.fourcc,
+ service->remoteport, bulk->size, bulk->remote_size);
} else {
/* fabricate a matching dummy bulk */
bulk->data = 0;
@@ -1485,8 +1476,8 @@ parse_open(struct vchiq_state *state, struct vchiq_header *header)
payload = (struct vchiq_open_payload *)header->data;
fourcc = payload->fourcc;
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: prs OPEN@%pK (%d->'%p4cc')",
- state->id, header, localport, &fourcc);
+ dev_dbg(state->dev, "core: %d: prs OPEN@%pK (%d->'%p4cc')\n",
+ state->id, header, localport, &fourcc);
service = get_listening_service(state, fourcc);
if (!service)
@@ -1609,17 +1600,17 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
vchiq_service_put(service);
service = get_connected_service(state, remoteport);
if (service)
- vchiq_log_warning(state->dev, VCHIQ_CORE,
- "%d: prs %s@%pK (%d->%d) - found connected service %d",
- state->id, msg_type_str(type), header,
- remoteport, localport, service->localport);
+ dev_warn(state->dev,
+ "core: %d: prs %s@%pK (%d->%d) - found connected service %d\n",
+ state->id, msg_type_str(type), header,
+ remoteport, localport, service->localport);
}
if (!service) {
- vchiq_log_error(state->dev, VCHIQ_CORE,
- "%d: prs %s@%pK (%d->%d) - invalid/closed service %d",
- state->id, msg_type_str(type), header, remoteport,
- localport, localport);
+ dev_err(state->dev,
+ "core: %d: prs %s@%pK (%d->%d) - invalid/closed service %d\n",
+ state->id, msg_type_str(type), header, remoteport,
+ localport, localport);
goto skip_message;
}
break;
@@ -1631,18 +1622,15 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
svc_fourcc = service ? service->base.fourcc
: VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
- vchiq_log_debug(state->dev, VCHIQ_CORE_MSG,
- "Rcvd Msg %s(%u) from %p4cc s:%d d:%d len:%d",
- msg_type_str(type), type, &svc_fourcc,
- remoteport, localport, size);
+ dev_dbg(state->dev, "core_msg: Rcvd Msg %s(%u) from %p4cc s:%d d:%d len:%d\n",
+ msg_type_str(type), type, &svc_fourcc, remoteport, localport, size);
if (size > 0)
vchiq_log_dump_mem(state->dev, "Rcvd", 0, header->data, min(16, size));
if (((unsigned long)header & VCHIQ_SLOT_MASK) +
calc_stride(size) > VCHIQ_SLOT_SIZE) {
- vchiq_log_error(state->dev, VCHIQ_CORE,
- "header %pK (msgid %x) - size %x too big for slot",
- header, (unsigned int)msgid, (unsigned int)size);
+ dev_err(state->dev, "core: header %pK (msgid %x) - size %x too big for slot\n",
+ header, (unsigned int)msgid, (unsigned int)size);
WARN(1, "oversized for slot\n");
}
@@ -1659,37 +1647,36 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
header->data;
service->peer_version = payload->version;
}
- vchiq_log_debug(state->dev, VCHIQ_CORE,
- "%d: prs OPENACK@%pK,%x (%d->%d) v:%d",
- state->id, header, size, remoteport, localport,
- service->peer_version);
+ dev_dbg(state->dev,
+ "core: %d: prs OPENACK@%pK,%x (%d->%d) v:%d\n",
+ state->id, header, size, remoteport, localport,
+ service->peer_version);
if (service->srvstate == VCHIQ_SRVSTATE_OPENING) {
service->remoteport = remoteport;
set_service_state(service, VCHIQ_SRVSTATE_OPEN);
complete(&service->remove_event);
} else {
- vchiq_log_error(state->dev, VCHIQ_CORE, "OPENACK received in state %s",
- srvstate_names[service->srvstate]);
+ dev_err(state->dev, "core: OPENACK received in state %s\n",
+ srvstate_names[service->srvstate]);
}
break;
case VCHIQ_MSG_CLOSE:
WARN_ON(size); /* There should be no data */
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: prs CLOSE@%pK (%d->%d)",
- state->id, header, remoteport, localport);
+ dev_dbg(state->dev, "core: %d: prs CLOSE@%pK (%d->%d)\n",
+ state->id, header, remoteport, localport);
mark_service_closing_internal(service, 1);
if (vchiq_close_service_internal(service, CLOSE_RECVD) == -EAGAIN)
goto bail_not_ready;
- vchiq_log_debug(state->dev, VCHIQ_CORE, "Close Service %p4cc s:%u d:%d",
- &service->base.fourcc,
- service->localport, service->remoteport);
+ dev_dbg(state->dev, "core: Close Service %p4cc s:%u d:%d\n",
+ &service->base.fourcc, service->localport, service->remoteport);
break;
case VCHIQ_MSG_DATA:
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: prs DATA@%pK,%x (%d->%d)",
- state->id, header, size, remoteport, localport);
+ dev_dbg(state->dev, "core: %d: prs DATA@%pK,%x (%d->%d)\n",
+ state->id, header, size, remoteport, localport);
if ((service->remoteport == remoteport) &&
(service->srvstate == VCHIQ_SRVSTATE_OPEN)) {
@@ -1708,8 +1695,8 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
}
break;
case VCHIQ_MSG_CONNECT:
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: prs CONNECT@%pK",
- state->id, header);
+ dev_dbg(state->dev, "core: %d: prs CONNECT@%pK\n",
+ state->id, header);
state->version_common = ((struct vchiq_slot_zero *)
state->slot_data)->version;
complete(&state->connect);
@@ -1740,11 +1727,10 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
}
if ((int)(queue->remote_insert -
queue->local_insert) >= 0) {
- vchiq_log_error(state->dev, VCHIQ_CORE,
- "%d: prs %s@%pK (%d->%d) unexpected (ri=%d,li=%d)",
- state->id, msg_type_str(type), header, remoteport,
- localport, queue->remote_insert,
- queue->local_insert);
+ dev_err(state->dev,
+ "core: %d: prs %s@%pK (%d->%d) unexpected (ri=%d,li=%d)\n",
+ state->id, msg_type_str(type), header, remoteport,
+ localport, queue->remote_insert, queue->local_insert);
mutex_unlock(&service->bulk_mutex);
break;
}
@@ -1761,15 +1747,14 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
bulk->actual = *(int *)header->data;
queue->remote_insert++;
- vchiq_log_debug(state->dev, VCHIQ_CORE,
- "%d: prs %s@%pK (%d->%d) %x@%pad",
- state->id, msg_type_str(type), header, remoteport,
- localport, bulk->actual, &bulk->data);
+ dev_dbg(state->dev, "core: %d: prs %s@%pK (%d->%d) %x@%pad\n",
+ state->id, msg_type_str(type), header, remoteport,
+ localport, bulk->actual, &bulk->data);
- vchiq_log_trace(state->dev, VCHIQ_CORE, "%d: prs:%d %cx li=%x ri=%x p=%x",
- state->id, localport,
- (type == VCHIQ_MSG_BULK_RX_DONE) ? 'r' : 't',
- queue->local_insert, queue->remote_insert, queue->process);
+ dev_dbg(state->dev, "core: %d: prs:%d %cx li=%x ri=%x p=%x\n",
+ state->id, localport,
+ (type == VCHIQ_MSG_BULK_RX_DONE) ? 'r' : 't',
+ queue->local_insert, queue->remote_insert, queue->process);
DEBUG_TRACE(PARSE_LINE);
WARN_ON(queue->process == queue->local_insert);
@@ -1782,16 +1767,16 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
}
break;
case VCHIQ_MSG_PADDING:
- vchiq_log_trace(state->dev, VCHIQ_CORE, "%d: prs PADDING@%pK,%x",
- state->id, header, size);
+ dev_dbg(state->dev, "core: %d: prs PADDING@%pK,%x\n",
+ state->id, header, size);
break;
case VCHIQ_MSG_PAUSE:
/* If initiated, signal the application thread */
- vchiq_log_trace(state->dev, VCHIQ_CORE, "%d: prs PAUSE@%pK,%x",
- state->id, header, size);
+ dev_dbg(state->dev, "core: %d: prs PAUSE@%pK,%x\n",
+ state->id, header, size);
if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) {
- vchiq_log_error(state->dev, VCHIQ_CORE,
- "%d: PAUSE received in state PAUSED", state->id);
+ dev_err(state->dev, "core: %d: PAUSE received in state PAUSED\n",
+ state->id);
break;
}
if (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT) {
@@ -1804,8 +1789,8 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSED);
break;
case VCHIQ_MSG_RESUME:
- vchiq_log_trace(state->dev, VCHIQ_CORE, "%d: prs RESUME@%pK,%x",
- state->id, header, size);
+ dev_dbg(state->dev, "core: %d: prs RESUME@%pK,%x\n",
+ state->id, header, size);
/* Release the slot mutex */
mutex_unlock(&state->slot_mutex);
vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
@@ -1821,8 +1806,8 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header)
break;
default:
- vchiq_log_error(state->dev, VCHIQ_CORE, "%d: prs invalid msgid %x@%pK,%x",
- state->id, msgid, header, size);
+ dev_err(state->dev, "core: %d: prs invalid msgid %x@%pK,%x\n",
+ state->id, msgid, header, size);
WARN(1, "invalid message\n");
break;
}
@@ -1932,7 +1917,7 @@ handle_poll(struct vchiq_state *state)
* since the PAUSE should have flushed
* through outstanding messages.
*/
- vchiq_log_error(state->dev, VCHIQ_CORE, "Failed to send RESUME message");
+ dev_err(state->dev, "core: Failed to send RESUME message\n");
}
break;
default:
@@ -2032,21 +2017,18 @@ sync_func(void *v)
service = find_service_by_port(state, localport);
if (!service) {
- vchiq_log_error(state->dev, VCHIQ_SYNC,
- "%d: sf %s@%pK (%d->%d) - invalid/closed service %d",
- state->id, msg_type_str(type), header,
- remoteport, localport, localport);
+ dev_err(state->dev,
+ "sync: %d: sf %s@%pK (%d->%d) - invalid/closed service %d\n",
+ state->id, msg_type_str(type), header, remoteport,
+ localport, localport);
release_message_sync(state, header);
continue;
}
- svc_fourcc = service ? service->base.fourcc
- : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
+ svc_fourcc = service->base.fourcc;
- vchiq_log_trace(state->dev, VCHIQ_SYNC,
- "Rcvd Msg %s from %p4cc s:%d d:%d len:%d",
- msg_type_str(type), &svc_fourcc,
- remoteport, localport, size);
+ dev_dbg(state->dev, "sync: Rcvd Msg %s from %p4cc s:%d d:%d len:%d\n",
+ msg_type_str(type), &svc_fourcc, remoteport, localport, size);
if (size > 0)
vchiq_log_dump_mem(state->dev, "Rcvd", 0, header->data, min(16, size));
@@ -2058,9 +2040,9 @@ sync_func(void *v)
header->data;
service->peer_version = payload->version;
}
- vchiq_log_debug(state->dev, VCHIQ_SYNC, "%d: sf OPENACK@%pK,%x (%d->%d) v:%d",
- state->id, header, size, remoteport, localport,
- service->peer_version);
+ dev_err(state->dev, "sync: %d: sf OPENACK@%pK,%x (%d->%d) v:%d\n",
+ state->id, header, size, remoteport, localport,
+ service->peer_version);
if (service->srvstate == VCHIQ_SRVSTATE_OPENING) {
service->remoteport = remoteport;
set_service_state(service, VCHIQ_SRVSTATE_OPENSYNC);
@@ -2071,22 +2053,22 @@ sync_func(void *v)
break;
case VCHIQ_MSG_DATA:
- vchiq_log_trace(state->dev, VCHIQ_SYNC, "%d: sf DATA@%pK,%x (%d->%d)",
- state->id, header, size, remoteport, localport);
+ dev_dbg(state->dev, "sync: %d: sf DATA@%pK,%x (%d->%d)\n",
+ state->id, header, size, remoteport, localport);
if ((service->remoteport == remoteport) &&
(service->srvstate == VCHIQ_SRVSTATE_OPENSYNC)) {
if (make_service_callback(service, VCHIQ_MESSAGE_AVAILABLE, header,
NULL) == -EAGAIN)
- vchiq_log_error(state->dev, VCHIQ_SYNC,
- "synchronous callback to service %d returns -EAGAIN",
- localport);
+ dev_err(state->dev,
+ "sync: error: synchronous callback to service %d returns -EAGAIN\n",
+ localport);
}
break;
default:
- vchiq_log_error(state->dev, VCHIQ_SYNC, "%d: sf unexpected msgid %x@%pK,%x",
- state->id, msgid, header, size);
+ dev_err(state->dev, "sync: error: %d: sf unexpected msgid %x@%pK,%x\n",
+ state->id, msgid, header, size);
release_message_sync(state, header);
break;
}
@@ -2119,8 +2101,8 @@ vchiq_init_slots(struct device *dev, void *mem_base, int mem_size)
num_slots -= first_data_slot;
if (num_slots < 4) {
- vchiq_log_error(dev, VCHIQ_CORE, "%s - insufficient memory %x bytes",
- __func__, mem_size);
+ dev_err(dev, "core: %s: Insufficient memory %x bytes\n",
+ __func__, mem_size);
return NULL;
}
@@ -2462,9 +2444,9 @@ vchiq_add_service_internal(struct vchiq_state *state,
/* Bring this service online */
set_service_state(service, srvstate);
- vchiq_log_debug(state->dev, VCHIQ_CORE_MSG, "%s Service %p4cc SrcPort:%d",
- (srvstate == VCHIQ_SRVSTATE_OPENING) ? "Open" : "Add",
- &params->fourcc, service->localport);
+ dev_dbg(state->dev, "core_msg: %s Service %p4cc SrcPort:%d\n",
+ (srvstate == VCHIQ_SRVSTATE_OPENING) ? "Open" : "Add",
+ &params->fourcc, service->localport);
/* Don't unlock the service - leave it with a ref_count of 1. */
@@ -2501,11 +2483,10 @@ vchiq_open_service_internal(struct vchiq_service *service, int client_id)
} else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) &&
(service->srvstate != VCHIQ_SRVSTATE_OPENSYNC)) {
if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT)
- vchiq_log_error(service->state->dev, VCHIQ_CORE,
- "%d: osi - srvstate = %s (ref %u)",
- service->state->id,
- srvstate_names[service->srvstate],
- kref_read(&service->ref_count));
+ dev_err(service->state->dev,
+ "core: %d: osi - srvstate = %s (ref %u)\n",
+ service->state->id, srvstate_names[service->srvstate],
+ kref_read(&service->ref_count));
status = -EINVAL;
VCHIQ_SERVICE_STATS_INC(service, error_count);
vchiq_release_service_internal(service);
@@ -2560,15 +2541,14 @@ release_service_messages(struct vchiq_service *service)
int port = VCHIQ_MSG_DSTPORT(msgid);
if ((port == service->localport) && (msgid & VCHIQ_MSGID_CLAIMED)) {
- vchiq_log_debug(state->dev, VCHIQ_CORE,
- " fsi - hdr %pK", header);
+ dev_dbg(state->dev, "core: fsi - hdr %pK\n", header);
release_slot(state, slot_info, header, NULL);
}
pos += calc_stride(header->size);
if (pos > VCHIQ_SLOT_SIZE) {
- vchiq_log_error(state->dev, VCHIQ_CORE,
- "fsi - pos %x: header %pK, msgid %x, header->msgid %x, header->size %x",
- pos, header, msgid, header->msgid, header->size);
+ dev_err(state->dev,
+ "core: fsi - pos %x: header %pK, msgid %x, header->msgid %x, header->size %x\n",
+ pos, header, msgid, header->msgid, header->size);
WARN(1, "invalid slot position\n");
}
}
@@ -2622,8 +2602,8 @@ close_service_complete(struct vchiq_service *service, int failstate)
case VCHIQ_SRVSTATE_LISTENING:
break;
default:
- vchiq_log_error(service->state->dev, VCHIQ_CORE, "%s(%x) called in state %s",
- __func__, service->handle, srvstate_names[service->srvstate]);
+ dev_err(service->state->dev, "core: (%x) called in state %s\n",
+ service->handle, srvstate_names[service->srvstate]);
WARN(1, "%s in unexpected state\n", __func__);
return -EINVAL;
}
@@ -2669,8 +2649,9 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
int close_id = MAKE_CLOSE(service->localport,
VCHIQ_MSG_DSTPORT(service->remoteport));
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: csi:%d,%d (%s)", service->state->id,
- service->localport, close_recvd, srvstate_names[service->srvstate]);
+ dev_dbg(state->dev, "core: %d: csi:%d,%d (%s)\n",
+ service->state->id, service->localport, close_recvd,
+ srvstate_names[service->srvstate]);
switch (service->srvstate) {
case VCHIQ_SRVSTATE_CLOSED:
@@ -2678,8 +2659,8 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
case VCHIQ_SRVSTATE_LISTENING:
case VCHIQ_SRVSTATE_CLOSEWAIT:
if (close_recvd) {
- vchiq_log_error(state->dev, VCHIQ_CORE, "%s(1) called in state %s",
- __func__, srvstate_names[service->srvstate]);
+ dev_err(state->dev, "core: (1) called in state %s\n",
+ srvstate_names[service->srvstate]);
} else if (is_server) {
if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) {
status = -EINVAL;
@@ -2766,8 +2747,8 @@ vchiq_close_service_internal(struct vchiq_service *service, int close_recvd)
break;
default:
- vchiq_log_error(state->dev, VCHIQ_CORE, "%s(%d) called in state %s", __func__,
- close_recvd, srvstate_names[service->srvstate]);
+ dev_err(state->dev, "core: (%d) called in state %s\n",
+ close_recvd, srvstate_names[service->srvstate]);
break;
}
@@ -2780,8 +2761,8 @@ vchiq_terminate_service_internal(struct vchiq_service *service)
{
struct vchiq_state *state = service->state;
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: tsi - (%d<->%d)", state->id,
- service->localport, service->remoteport);
+ dev_dbg(state->dev, "core: %d: tsi - (%d<->%d)\n",
+ state->id, service->localport, service->remoteport);
mark_service_closing(service);
@@ -2795,8 +2776,7 @@ vchiq_free_service_internal(struct vchiq_service *service)
{
struct vchiq_state *state = service->state;
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: fsi - (%d)",
- state->id, service->localport);
+ dev_dbg(state->dev, "core: %d: fsi - (%d)\n", state->id, service->localport);
switch (service->srvstate) {
case VCHIQ_SRVSTATE_OPENING:
@@ -2806,8 +2786,8 @@ vchiq_free_service_internal(struct vchiq_service *service)
case VCHIQ_SRVSTATE_CLOSEWAIT:
break;
default:
- vchiq_log_error(state->dev, VCHIQ_CORE, "%d: fsi - (%d) in state %s", state->id,
- service->localport, srvstate_names[service->srvstate]);
+ dev_err(state->dev, "core: %d: fsi - (%d) in state %s\n",
+ state->id, service->localport, srvstate_names[service->srvstate]);
return;
}
@@ -2876,8 +2856,8 @@ vchiq_close_service(struct vchiq_instance *instance, unsigned int handle)
if (!service)
return -EINVAL;
- vchiq_log_debug(service->state->dev, VCHIQ_CORE, "%d: close_service:%d",
- service->state->id, service->localport);
+ dev_dbg(service->state->dev, "core: %d: close_service:%d\n",
+ service->state->id, service->localport);
if ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
(service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
@@ -2907,10 +2887,10 @@ vchiq_close_service(struct vchiq_instance *instance, unsigned int handle)
(service->srvstate == VCHIQ_SRVSTATE_OPEN))
break;
- vchiq_log_warning(service->state->dev, VCHIQ_CORE,
- "%d: close_service:%d - waiting in state %s",
- service->state->id, service->localport,
- srvstate_names[service->srvstate]);
+ dev_warn(service->state->dev,
+ "core: %d: close_service:%d - waiting in state %s\n",
+ service->state->id, service->localport,
+ srvstate_names[service->srvstate]);
}
if (!status &&
@@ -2934,8 +2914,8 @@ vchiq_remove_service(struct vchiq_instance *instance, unsigned int handle)
if (!service)
return -EINVAL;
- vchiq_log_debug(service->state->dev, VCHIQ_CORE, "%d: remove_service:%d",
- service->state->id, service->localport);
+ dev_dbg(service->state->dev, "core: %d: remove_service:%d\n",
+ service->state->id, service->localport);
if (service->srvstate == VCHIQ_SRVSTATE_FREE) {
vchiq_service_put(service);
@@ -2968,10 +2948,10 @@ vchiq_remove_service(struct vchiq_instance *instance, unsigned int handle)
(service->srvstate == VCHIQ_SRVSTATE_OPEN))
break;
- vchiq_log_warning(service->state->dev, VCHIQ_CORE,
- "%d: remove_service:%d - waiting in state %s",
- service->state->id, service->localport,
- srvstate_names[service->srvstate]);
+ dev_warn(service->state->dev,
+ "core: %d: remove_service:%d - waiting in state %s\n",
+ service->state->id, service->localport,
+ srvstate_names[service->srvstate]);
}
if (!status && (service->srvstate != VCHIQ_SRVSTATE_FREE))
@@ -3078,9 +3058,9 @@ int vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned int handle,
*/
wmb();
- vchiq_log_debug(state->dev, VCHIQ_CORE, "%d: bt (%d->%d) %cx %x@%pad %pK",
- state->id, service->localport, service->remoteport,
- dir_char, size, &bulk->data, userdata);
+ dev_dbg(state->dev, "core: %d: bt (%d->%d) %cx %x@%pad %pK\n",
+ state->id, service->localport, service->remoteport,
+ dir_char, size, &bulk->data, userdata);
/*
* The slot mutex must be held when the service is being closed, so
@@ -3115,9 +3095,9 @@ int vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned int handle,
mutex_unlock(&state->slot_mutex);
mutex_unlock(&service->bulk_mutex);
- vchiq_log_trace(state->dev, VCHIQ_CORE, "%d: bt:%d %cx li=%x ri=%x p=%x",
- state->id, service->localport, dir_char, queue->local_insert,
- queue->remote_insert, queue->process);
+ dev_dbg(state->dev, "core: %d: bt:%d %cx li=%x ri=%x p=%x\n",
+ state->id, service->localport, dir_char, queue->local_insert,
+ queue->remote_insert, queue->process);
waiting:
vchiq_service_put(service);
@@ -3372,8 +3352,8 @@ vchiq_set_service_option(struct vchiq_instance *instance, unsigned int handle,
return ret;
}
-static int
-vchiq_dump_shared_state(void *dump_context, struct vchiq_state *state,
+static void
+vchiq_dump_shared_state(struct seq_file *f, struct vchiq_state *state,
struct vchiq_shared_state *shared, const char *label)
{
static const char *const debug_names[] = {
@@ -3390,146 +3370,44 @@ vchiq_dump_shared_state(void *dump_context, struct vchiq_state *state,
"COMPLETION_QUEUE_FULL_COUNT"
};
int i;
- char buf[80];
- int len;
- int err;
-
- len = scnprintf(buf, sizeof(buf), " %s: slots %d-%d tx_pos=%x recycle=%x",
- label, shared->slot_first, shared->slot_last,
- shared->tx_pos, shared->slot_queue_recycle);
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
-
- len = scnprintf(buf, sizeof(buf), " Slots claimed:");
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
+
+ seq_printf(f, " %s: slots %d-%d tx_pos=%x recycle=%x\n",
+ label, shared->slot_first, shared->slot_last,
+ shared->tx_pos, shared->slot_queue_recycle);
+
+ seq_puts(f, " Slots claimed:\n");
for (i = shared->slot_first; i <= shared->slot_last; i++) {
struct vchiq_slot_info slot_info =
*SLOT_INFO_FROM_INDEX(state, i);
if (slot_info.use_count != slot_info.release_count) {
- len = scnprintf(buf, sizeof(buf), " %d: %d/%d", i, slot_info.use_count,
- slot_info.release_count);
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
+ seq_printf(f, " %d: %d/%d\n", i, slot_info.use_count,
+ slot_info.release_count);
}
}
for (i = 1; i < shared->debug[DEBUG_ENTRIES]; i++) {
- len = scnprintf(buf, sizeof(buf), " DEBUG: %s = %d(%x)",
- debug_names[i], shared->debug[i], shared->debug[i]);
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
- }
- return 0;
-}
-
-int vchiq_dump_state(void *dump_context, struct vchiq_state *state)
-{
- char buf[80];
- int len;
- int i;
- int err;
-
- len = scnprintf(buf, sizeof(buf), "State %d: %s", state->id,
- conn_state_names[state->conn_state]);
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
-
- len = scnprintf(buf, sizeof(buf), " tx_pos=%x(@%pK), rx_pos=%x(@%pK)",
- state->local->tx_pos,
- state->tx_data + (state->local_tx_pos & VCHIQ_SLOT_MASK),
- state->rx_pos,
- state->rx_data + (state->rx_pos & VCHIQ_SLOT_MASK));
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
-
- len = scnprintf(buf, sizeof(buf), " Version: %d (min %d)",
- VCHIQ_VERSION, VCHIQ_VERSION_MIN);
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
-
- if (VCHIQ_ENABLE_STATS) {
- len = scnprintf(buf, sizeof(buf),
- " Stats: ctrl_tx_count=%d, ctrl_rx_count=%d, error_count=%d",
- state->stats.ctrl_tx_count, state->stats.ctrl_rx_count,
- state->stats.error_count);
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
- }
-
- len = scnprintf(buf, sizeof(buf),
- " Slots: %d available (%d data), %d recyclable, %d stalls (%d data)",
- ((state->slot_queue_available * VCHIQ_SLOT_SIZE) -
- state->local_tx_pos) / VCHIQ_SLOT_SIZE,
- state->data_quota - state->data_use_count,
- state->local->slot_queue_recycle - state->slot_queue_available,
- state->stats.slot_stalls, state->stats.data_stalls);
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
-
- err = vchiq_dump_platform_state(dump_context);
- if (err)
- return err;
-
- err = vchiq_dump_shared_state(dump_context,
- state,
- state->local,
- "Local");
- if (err)
- return err;
- err = vchiq_dump_shared_state(dump_context,
- state,
- state->remote,
- "Remote");
- if (err)
- return err;
-
- err = vchiq_dump_platform_instances(dump_context);
- if (err)
- return err;
-
- for (i = 0; i < state->unused_service; i++) {
- struct vchiq_service *service = find_service_by_port(state, i);
-
- if (service) {
- err = vchiq_dump_service_state(dump_context, service);
- vchiq_service_put(service);
- if (err)
- return err;
- }
+ seq_printf(f, " DEBUG: %s = %d(%x)\n",
+ debug_names[i], shared->debug[i], shared->debug[i]);
}
- return 0;
}
-int vchiq_dump_service_state(void *dump_context, struct vchiq_service *service)
+static void
+vchiq_dump_service_state(struct seq_file *f, struct vchiq_service *service)
{
- char buf[80];
- int len;
- int err;
unsigned int ref_count;
/*Don't include the lock just taken*/
ref_count = kref_read(&service->ref_count) - 1;
- len = scnprintf(buf, sizeof(buf), "Service %u: %s (ref %u)",
- service->localport, srvstate_names[service->srvstate],
- ref_count);
+ seq_printf(f, "Service %u: %s (ref %u)", service->localport,
+ srvstate_names[service->srvstate], ref_count);
if (service->srvstate != VCHIQ_SRVSTATE_FREE) {
char remoteport[30];
struct vchiq_service_quota *quota =
&service->state->service_quotas[service->localport];
int fourcc = service->base.fourcc;
- int tx_pending, rx_pending;
+ int tx_pending, rx_pending, tx_size = 0, rx_size = 0;
if (service->remoteport != VCHIQ_PORT_FREE) {
int len2 = scnprintf(remoteport, sizeof(remoteport),
@@ -3542,68 +3420,100 @@ int vchiq_dump_service_state(void *dump_context, struct vchiq_service *service)
strscpy(remoteport, "n/a", sizeof(remoteport));
}
- len += scnprintf(buf + len, sizeof(buf) - len,
- " '%p4cc' remote %s (msg use %d/%d, slot use %d/%d)",
- &fourcc, remoteport,
- quota->message_use_count, quota->message_quota,
- quota->slot_use_count, quota->slot_quota);
-
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
+ seq_printf(f, " '%p4cc' remote %s (msg use %d/%d, slot use %d/%d)\n",
+ &fourcc, remoteport,
+ quota->message_use_count, quota->message_quota,
+ quota->slot_use_count, quota->slot_quota);
tx_pending = service->bulk_tx.local_insert -
service->bulk_tx.remote_insert;
+ if (tx_pending) {
+ unsigned int i = BULK_INDEX(service->bulk_tx.remove);
+
+ tx_size = service->bulk_tx.bulks[i].size;
+ }
rx_pending = service->bulk_rx.local_insert -
service->bulk_rx.remote_insert;
+ if (rx_pending) {
+ unsigned int i = BULK_INDEX(service->bulk_rx.remove);
- len = scnprintf(buf, sizeof(buf),
- " Bulk: tx_pending=%d (size %d), rx_pending=%d (size %d)",
- tx_pending,
- tx_pending ?
- service->bulk_tx.bulks[BULK_INDEX(service->bulk_tx.remove)].size :
- 0, rx_pending, rx_pending ?
- service->bulk_rx.bulks[BULK_INDEX(service->bulk_rx.remove)].size :
- 0);
+ rx_size = service->bulk_rx.bulks[i].size;
+ }
+
+ seq_printf(f, " Bulk: tx_pending=%d (size %d), rx_pending=%d (size %d)\n",
+ tx_pending, tx_size, rx_pending, rx_size);
if (VCHIQ_ENABLE_STATS) {
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
+ seq_printf(f, " Ctrl: tx_count=%d, tx_bytes=%llu, rx_count=%d, rx_bytes=%llu\n",
+ service->stats.ctrl_tx_count,
+ service->stats.ctrl_tx_bytes,
+ service->stats.ctrl_rx_count,
+ service->stats.ctrl_rx_bytes);
+
+ seq_printf(f, " Bulk: tx_count=%d, tx_bytes=%llu, rx_count=%d, rx_bytes=%llu\n",
+ service->stats.bulk_tx_count,
+ service->stats.bulk_tx_bytes,
+ service->stats.bulk_rx_count,
+ service->stats.bulk_rx_bytes);
+
+ seq_printf(f, " %d quota stalls, %d slot stalls, %d bulk stalls, %d aborted, %d errors\n",
+ service->stats.quota_stalls,
+ service->stats.slot_stalls,
+ service->stats.bulk_stalls,
+ service->stats.bulk_aborted_count,
+ service->stats.error_count);
+ }
+ }
- len = scnprintf(buf, sizeof(buf),
- " Ctrl: tx_count=%d, tx_bytes=%llu, rx_count=%d, rx_bytes=%llu",
- service->stats.ctrl_tx_count, service->stats.ctrl_tx_bytes,
- service->stats.ctrl_rx_count, service->stats.ctrl_rx_bytes);
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
+ vchiq_dump_platform_service_state(f, service);
+}
- len = scnprintf(buf, sizeof(buf),
- " Bulk: tx_count=%d, tx_bytes=%llu, rx_count=%d, rx_bytes=%llu",
- service->stats.bulk_tx_count, service->stats.bulk_tx_bytes,
- service->stats.bulk_rx_count, service->stats.bulk_rx_bytes);
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
+void vchiq_dump_state(struct seq_file *f, struct vchiq_state *state)
+{
+ int i;
- len = scnprintf(buf, sizeof(buf),
- " %d quota stalls, %d slot stalls, %d bulk stalls, %d aborted, %d errors",
- service->stats.quota_stalls, service->stats.slot_stalls,
- service->stats.bulk_stalls,
- service->stats.bulk_aborted_count,
- service->stats.error_count);
- }
+ seq_printf(f, "State %d: %s\n", state->id,
+ conn_state_names[state->conn_state]);
+
+ seq_printf(f, " tx_pos=%x(@%pK), rx_pos=%x(@%pK)\n",
+ state->local->tx_pos,
+ state->tx_data + (state->local_tx_pos & VCHIQ_SLOT_MASK),
+ state->rx_pos,
+ state->rx_data + (state->rx_pos & VCHIQ_SLOT_MASK));
+
+ seq_printf(f, " Version: %d (min %d)\n", VCHIQ_VERSION,
+ VCHIQ_VERSION_MIN);
+
+ if (VCHIQ_ENABLE_STATS) {
+ seq_printf(f, " Stats: ctrl_tx_count=%d, ctrl_rx_count=%d, error_count=%d\n",
+ state->stats.ctrl_tx_count, state->stats.ctrl_rx_count,
+ state->stats.error_count);
}
- err = vchiq_dump(dump_context, buf, len + 1);
- if (err)
- return err;
+ seq_printf(f, " Slots: %d available (%d data), %d recyclable, %d stalls (%d data)\n",
+ ((state->slot_queue_available * VCHIQ_SLOT_SIZE) -
+ state->local_tx_pos) / VCHIQ_SLOT_SIZE,
+ state->data_quota - state->data_use_count,
+ state->local->slot_queue_recycle - state->slot_queue_available,
+ state->stats.slot_stalls, state->stats.data_stalls);
+
+ vchiq_dump_platform_state(f);
+
+ vchiq_dump_shared_state(f, state, state->local, "Local");
+
+ vchiq_dump_shared_state(f, state, state->remote, "Remote");
+
+ vchiq_dump_platform_instances(f);
- if (service->srvstate != VCHIQ_SRVSTATE_FREE)
- err = vchiq_dump_platform_service_state(dump_context, service);
- return err;
+ for (i = 0; i < state->unused_service; i++) {
+ struct vchiq_service *service = find_service_by_port(state, i);
+
+ if (service) {
+ vchiq_dump_service_state(f, service);
+ vchiq_service_put(service);
+ }
+ }
}
int vchiq_send_remote_use(struct vchiq_state *state)
@@ -3653,9 +3563,9 @@ void vchiq_log_dump_mem(struct device *dev, const char *label, u32 addr,
*s++ = '\0';
if (label && (*label != '\0'))
- vchiq_log_trace(dev, VCHIQ_CORE, "%s: %08x: %s", label, addr, line_buf);
+ dev_dbg(dev, "core: %s: %08x: %s\n", label, addr, line_buf);
else
- vchiq_log_trace(dev, VCHIQ_CORE, "%s: %08x: %s", label, addr, line_buf);
+ dev_dbg(dev, "core: %s: %08x: %s\n", label, addr, line_buf);
addr += 16;
mem += 16;
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
index 161358db457c..c8527551b58c 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
@@ -6,6 +6,7 @@
#include <linux/mutex.h>
#include <linux/completion.h>
+#include <linux/debugfs.h>
#include <linux/dev_printk.h>
#include <linux/kthread.h>
#include <linux/kref.h>
@@ -31,44 +32,6 @@
#define VCHIQ_SLOT_SIZE 4096
#define VCHIQ_MAX_MSG_SIZE (VCHIQ_SLOT_SIZE - sizeof(struct vchiq_header))
-enum vchiq_log_category {
- VCHIQ_ARM,
- VCHIQ_CORE,
- VCHIQ_CORE_MSG,
- VCHIQ_SYNC,
- VCHIQ_SUSPEND,
-};
-
-static inline const char *log_category_str(enum vchiq_log_category c)
-{
- static const char * const strings[] = {
- "vchiq_arm",
- "vchiq_core",
- "vchiq_core_msg",
- "vchiq_sync",
- "vchiq_suspend",
- };
-
- return strings[c];
-};
-
-#ifndef vchiq_log_error
-#define vchiq_log_error(dev, cat, fmt, ...) \
- do { dev_dbg(dev, "%s error: " fmt, log_category_str(cat), ##__VA_ARGS__); } while (0)
-#endif
-#ifndef vchiq_log_warning
-#define vchiq_log_warning(dev, cat, fmt, ...) \
- do { dev_dbg(dev, "%s warning: " fmt, log_category_str(cat), ##__VA_ARGS__); } while (0)
-#endif
-#ifndef vchiq_log_debug
-#define vchiq_log_debug(dev, cat, fmt, ...) \
- do { dev_dbg(dev, "%s debug: " fmt, log_category_str(cat), ##__VA_ARGS__); } while (0)
-#endif
-#ifndef vchiq_log_trace
-#define vchiq_log_trace(dev, cat, fmt, ...) \
- do { dev_dbg(dev, "%s trace: " fmt, log_category_str(cat), ##__VA_ARGS__); } while (0)
-#endif
-
#define VCHIQ_SLOT_MASK (VCHIQ_SLOT_SIZE - 1)
#define VCHIQ_SLOT_QUEUE_MASK (VCHIQ_MAX_SLOTS_PER_SIDE - 1)
#define VCHIQ_SLOT_ZERO_SLOTS DIV_ROUND_UP(sizeof(struct vchiq_slot_zero), \
@@ -504,11 +467,8 @@ vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *
void __user *uoffset, int size, void *userdata, enum vchiq_bulk_mode mode,
enum vchiq_bulk_dir dir);
-extern int
-vchiq_dump_state(void *dump_context, struct vchiq_state *state);
-
-extern int
-vchiq_dump_service_state(void *dump_context, struct vchiq_service *service);
+extern void
+vchiq_dump_state(struct seq_file *f, struct vchiq_state *state);
extern void
vchiq_loud_error_header(void);
@@ -564,13 +524,11 @@ void vchiq_complete_bulk(struct vchiq_instance *instance, struct vchiq_bulk *bul
void remote_event_signal(struct remote_event *event);
-int vchiq_dump(void *dump_context, const char *str, int len);
-
-int vchiq_dump_platform_state(void *dump_context);
+void vchiq_dump_platform_state(struct seq_file *f);
-int vchiq_dump_platform_instances(void *dump_context);
+void vchiq_dump_platform_instances(struct seq_file *f);
-int vchiq_dump_platform_service_state(void *dump_context, struct vchiq_service *service);
+void vchiq_dump_platform_service_state(struct seq_file *f, struct vchiq_service *service);
int vchiq_use_service_internal(struct vchiq_service *service);
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
index 58db78a9c8d4..d833e4e2973a 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c
@@ -40,6 +40,13 @@ static int debugfs_trace_show(struct seq_file *f, void *offset)
return 0;
}
+static int vchiq_dump_show(struct seq_file *f, void *offset)
+{
+ vchiq_dump_state(f, &g_state);
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(vchiq_dump);
+
static int debugfs_trace_open(struct inode *inode, struct file *file)
{
return single_open(file, debugfs_trace_show, inode->i_private);
@@ -115,6 +122,9 @@ void vchiq_debugfs_init(void)
{
vchiq_dbg_dir = debugfs_create_dir("vchiq", NULL);
vchiq_dbg_clients = debugfs_create_dir("clients", vchiq_dbg_dir);
+
+ debugfs_create_file("state", S_IFREG | 0444, vchiq_dbg_dir, NULL,
+ &vchiq_dump_fops);
}
/* remove all the debugfs entries */
diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c
index 0bc93f48c14c..4d9deeeb637a 100644
--- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c
+++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c
@@ -47,9 +47,8 @@ user_service_free(void *userdata)
static void close_delivered(struct user_service *user_service)
{
- vchiq_log_debug(user_service->service->state->dev, VCHIQ_ARM,
- "%s(handle=%x)",
- __func__, user_service->service->handle);
+ dev_dbg(user_service->service->state->dev,
+ "arm: (handle=%x)\n", user_service->service->handle);
if (user_service->close_pending) {
/* Allow the underlying service to be culled */
@@ -235,8 +234,7 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
spin_unlock(&msg_queue_spinlock);
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
if (wait_for_completion_interruptible(&user_service->insert_event)) {
- vchiq_log_debug(service->state->dev, VCHIQ_ARM,
- "DEQUEUE_MESSAGE interrupted");
+ dev_dbg(service->state->dev, "arm: DEQUEUE_MESSAGE interrupted\n");
ret = -EINTR;
break;
}
@@ -271,9 +269,9 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance,
ret = -EFAULT;
}
} else {
- vchiq_log_error(service->state->dev, VCHIQ_ARM,
- "header %pK: bufsize %x < size %x",
- header, args->bufsize, header->size);
+ dev_err(service->state->dev,
+ "arm: header %pK: bufsize %x < size %x\n",
+ header, args->bufsize, header->size);
WARN(1, "invalid size\n");
ret = -EMSGSIZE;
}
@@ -318,13 +316,13 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance,
}
mutex_unlock(&instance->bulk_waiter_list_mutex);
if (!waiter) {
- vchiq_log_error(service->state->dev, VCHIQ_ARM,
- "no bulk_waiter found for pid %d", current->pid);
+ dev_err(service->state->dev,
+ "arm: no bulk_waiter found for pid %d\n", current->pid);
ret = -ESRCH;
goto out;
}
- vchiq_log_debug(service->state->dev, VCHIQ_ARM,
- "found bulk_waiter %pK for pid %d", waiter, current->pid);
+ dev_dbg(service->state->dev, "arm: found bulk_waiter %pK for pid %d\n",
+ waiter, current->pid);
userdata = &waiter->bulk_waiter;
} else {
userdata = args->userdata;
@@ -355,8 +353,8 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance,
mutex_lock(&instance->bulk_waiter_list_mutex);
list_add(&waiter->list, &instance->bulk_waiter_list);
mutex_unlock(&instance->bulk_waiter_list_mutex);
- vchiq_log_debug(service->state->dev, VCHIQ_ARM,
- "saved bulk_waiter %pK for pid %d", waiter, current->pid);
+ dev_dbg(service->state->dev, "arm: saved bulk_waiter %pK for pid %d\n",
+ waiter, current->pid);
ret = put_user(mode_waiting, mode);
}
@@ -455,8 +453,7 @@ static int vchiq_ioc_await_completion(struct vchiq_instance *instance,
mutex_lock(&instance->completion_mutex);
if (rc) {
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
- vchiq_log_debug(instance->state->dev, VCHIQ_ARM,
- "AWAIT_COMPLETION interrupted");
+ dev_dbg(instance->state->dev, "arm: AWAIT_COMPLETION interrupted\n");
ret = -EINTR;
goto out;
}
@@ -501,10 +498,10 @@ static int vchiq_ioc_await_completion(struct vchiq_instance *instance,
msglen = header->size + sizeof(struct vchiq_header);
/* This must be a VCHIQ-style service */
if (args->msgbufsize < msglen) {
- vchiq_log_error(service->state->dev, VCHIQ_ARM,
- "header %pK: msgbufsize %x < msglen %x",
- header, args->msgbufsize, msglen);
- WARN(1, "invalid message size\n");
+ dev_err(service->state->dev,
+ "arm: header %pK: msgbufsize %x < msglen %x\n",
+ header, args->msgbufsize, msglen);
+ WARN(1, "invalid message size\n");
if (ret == 0)
ret = -EMSGSIZE;
break;
@@ -582,10 +579,9 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
long ret = 0;
int i, rc;
- vchiq_log_trace(instance->state->dev, VCHIQ_ARM,
- "%s - instance %pK, cmd %s, arg %lx", __func__, instance,
- ((_IOC_TYPE(cmd) == VCHIQ_IOC_MAGIC) && (_IOC_NR(cmd) <= VCHIQ_IOC_MAX)) ?
- ioctl_names[_IOC_NR(cmd)] : "<invalid>", arg);
+ dev_dbg(instance->state->dev, "arm: instance %pK, cmd %s, arg %lx\n", instance,
+ ((_IOC_TYPE(cmd) == VCHIQ_IOC_MAGIC) && (_IOC_NR(cmd) <= VCHIQ_IOC_MAX)) ?
+ ioctl_names[_IOC_NR(cmd)] : "<invalid>", arg);
switch (cmd) {
case VCHIQ_IOC_SHUTDOWN:
@@ -618,9 +614,9 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
rc = mutex_lock_killable(&instance->state->mutex);
if (rc) {
- vchiq_log_error(instance->state->dev, VCHIQ_ARM,
- "vchiq: connect: could not lock mutex for state %d: %d",
- instance->state->id, rc);
+ dev_err(instance->state->dev,
+ "arm: vchiq: connect: could not lock mutex for state %d: %d\n",
+ instance->state->id, rc);
ret = -EINTR;
break;
}
@@ -630,8 +626,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (!status)
instance->connected = 1;
else
- vchiq_log_error(instance->state->dev, VCHIQ_ARM,
- "vchiq: could not connect: %d", status);
+ dev_err(instance->state->dev,
+ "arm: vchiq: could not connect: %d\n", status);
break;
case VCHIQ_IOC_CREATE_SERVICE: {
@@ -700,13 +696,13 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
vchiq_use_service_internal(service) :
vchiq_release_service_internal(service);
if (ret) {
- vchiq_log_error(instance->state->dev, VCHIQ_SUSPEND,
- "%s: cmd %s returned error %ld for service %p4cc:%03d",
- __func__, (cmd == VCHIQ_IOC_USE_SERVICE) ?
- "VCHIQ_IOC_USE_SERVICE" :
- "VCHIQ_IOC_RELEASE_SERVICE",
- ret, &service->base.fourcc,
- service->client_id);
+ dev_err(instance->state->dev,
+ "suspend: cmd %s returned error %ld for service %p4cc:%03d\n",
+ (cmd == VCHIQ_IOC_USE_SERVICE) ?
+ "VCHIQ_IOC_USE_SERVICE" :
+ "VCHIQ_IOC_RELEASE_SERVICE",
+ ret, &service->base.fourcc,
+ service->client_id);
}
} else {
ret = -EINVAL;
@@ -868,15 +864,15 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
if (!status && (ret < 0) && (ret != -EINTR) && (ret != -EWOULDBLOCK)) {
- vchiq_log_debug(instance->state->dev, VCHIQ_ARM,
- " ioctl instance %pK, cmd %s -> status %d, %ld",
- instance, (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
- ioctl_names[_IOC_NR(cmd)] : "<invalid>", status, ret);
+ dev_dbg(instance->state->dev,
+ "arm: ioctl instance %pK, cmd %s -> status %d, %ld\n",
+ instance, (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
+ ioctl_names[_IOC_NR(cmd)] : "<invalid>", status, ret);
} else {
- vchiq_log_trace(instance->state->dev, VCHIQ_ARM,
- " ioctl instance %pK, cmd %s -> status %d, %ld",
- instance, (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
- ioctl_names[_IOC_NR(cmd)] : "<invalid>", status, ret);
+ dev_dbg(instance->state->dev,
+ "arm: ioctl instance %pK, cmd %s -> status %d\n, %ld\n",
+ instance, (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ?
+ ioctl_names[_IOC_NR(cmd)] : "<invalid>", status, ret);
}
return ret;
@@ -1170,11 +1166,10 @@ static int vchiq_open(struct inode *inode, struct file *file)
struct vchiq_state *state = vchiq_get_state();
struct vchiq_instance *instance;
- vchiq_log_debug(state->dev, VCHIQ_ARM, "vchiq_open");
+ dev_dbg(state->dev, "arm: vchiq open\n");
if (!state) {
- vchiq_log_error(state->dev, VCHIQ_ARM,
- "vchiq has no connection to VideoCore");
+ dev_err(state->dev, "arm: vchiq has no connection to VideoCore\n");
return -ENOTCONN;
}
@@ -1206,8 +1201,7 @@ static int vchiq_release(struct inode *inode, struct file *file)
int ret = 0;
int i;
- vchiq_log_debug(state->dev, VCHIQ_ARM, "%s: instance=%lx", __func__,
- (unsigned long)instance);
+ dev_dbg(state->dev, "arm: instance=%p\n", instance);
if (!state) {
ret = -EPERM;
@@ -1306,26 +1300,6 @@ out:
return ret;
}
-static ssize_t
-vchiq_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
-{
- struct dump_context context;
- int err;
-
- context.buf = buf;
- context.actual = 0;
- context.space = count;
- context.offset = *ppos;
-
- err = vchiq_dump_state(&context, &g_state);
- if (err)
- return err;
-
- *ppos += context.actual;
-
- return context.actual;
-}
-
static const struct file_operations
vchiq_fops = {
.owner = THIS_MODULE,
@@ -1335,7 +1309,6 @@ vchiq_fops = {
#endif
.open = vchiq_open,
.release = vchiq_release,
- .read = vchiq_read
};
static struct miscdevice vchiq_miscdev = {
diff --git a/drivers/staging/vme_user/Kconfig b/drivers/staging/vme_user/Kconfig
index d65cc5510649..8e5df6ce36e8 100644
--- a/drivers/staging/vme_user/Kconfig
+++ b/drivers/staging/vme_user/Kconfig
@@ -3,18 +3,32 @@ menuconfig VME_BUS
bool "VME bridge support"
depends on PCI
help
- If you say Y here you get support for the VME bridge Framework.
+ Enable support for VME (VersaModular Eurocard bus) bridge modules.
+ The bridge allows connecting VME devices to systems with existing
+ interfaces (like USB or PCI) by means of translating VME protocol
+ operations.
+
+ Note that this only enables the bridge framework. You'll also
+ likely want to enable driver for specific bridge device you have
+ to actually use it. If unsure, say N.
if VME_BUS
comment "VME Bridge Drivers"
config VME_TSI148
- tristate "Tempe"
+ tristate "Tundra TSI148 VME bridge support"
depends on HAS_DMA
help
- If you say Y here you get support for the Tundra TSI148 VME bridge
- chip.
+ If you say Y here you get support for the Tundra TSI148 VME-to-PCI/X
+ bridge chip (and pin-compatible clones).
+
+ TSI148 is a high-performant, 2eSST and VME64-compliant VME-to-PCI/X
+ interconnect bridge with support for PCI and PCI-X bus interface.
+ It is primarily used in industrial and embedded systems.
+
+ To compile this driver as a module, say M - the module will be
+ called vme_tsi148. If unsure, say N.
config VME_FAKE
tristate "Fake"
diff --git a/drivers/staging/vme_user/vme.c b/drivers/staging/vme_user/vme.c
index 5c416c31ec57..e9461a7a7ab8 100644
--- a/drivers/staging/vme_user/vme.c
+++ b/drivers/staging/vme_user/vme.c
@@ -340,8 +340,8 @@ int vme_slave_set(struct vme_resource *resource, int enabled,
image = list_entry(resource->entry, struct vme_slave_resource, list);
if (!bridge->slave_set) {
- dev_err(bridge->parent, "Function not supported\n");
- return -ENOSYS;
+ dev_err(bridge->parent, "%s not supported\n", __func__);
+ return -EINVAL;
}
if (!(((image->address_attr & aspace) == aspace) &&
diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c
index 350ab8f3778a..36183f2a64c1 100644
--- a/drivers/staging/vt6655/card.c
+++ b/drivers/staging/vt6655/card.c
@@ -10,12 +10,12 @@
* CARDvUpdateBasicTopRate - Update BasicTopRate
* CARDbAddBasicRate - Add to BasicRateSet
* CARDbIsOFDMinBasicRate - Check if any OFDM rate is in BasicRateSet
- * CARDqGetTSFOffset - Calculate TSFOffset
+ * card_get_tsf_offset - Calculate TSFOffset
* vt6655_get_current_tsf - Read Current NIC TSF counter
- * CARDqGetNextTBTT - Calculate Next Beacon TSF counter
+ * card_get_next_tbtt - Calculate Next Beacon TSF counter
* CARDvSetFirstNextTBTT - Set NIC Beacon time
* CARDvUpdateNextTBTT - Sync. NIC Beacon time
- * CARDbRadioPowerOff - Turn Off NIC Radio Power
+ * card_radio_power_off - Turn Off NIC Radio Power
*
* Revision History:
* 06-10-2003 Bryan YC Fan: Re-write codes to support VT3253 spec.
@@ -280,7 +280,7 @@ bool card_set_phy_parameter(struct vnt_private *priv, u8 bb_type)
* In:
* priv - The adapter to be sync.
* rx_rate - data rate of receive beacon
- * qwBSSTimestamp - Rx BCN's TSF
+ * bss_timestamp - Rx BCN's TSF
* qwLocalTSF - Local TSF
* Out:
* none
@@ -288,20 +288,20 @@ bool card_set_phy_parameter(struct vnt_private *priv, u8 bb_type)
* Return Value: none
*/
bool card_update_tsf(struct vnt_private *priv, unsigned char rx_rate,
- u64 qwBSSTimestamp)
+ u64 bss_timestamp)
{
u64 local_tsf;
- u64 qwTSFOffset = 0;
+ u64 tsf_offset = 0;
local_tsf = vt6655_get_current_tsf(priv);
- if (qwBSSTimestamp != local_tsf) {
- qwTSFOffset = CARDqGetTSFOffset(rx_rate, qwBSSTimestamp,
+ if (bss_timestamp != local_tsf) {
+ tsf_offset = card_get_tsf_offset(rx_rate, bss_timestamp,
local_tsf);
/* adjust TSF, HW's TSF add TSF Offset reg */
- qwTSFOffset = le64_to_cpu(qwTSFOffset);
- iowrite32((u32)qwTSFOffset, priv->port_offset + MAC_REG_TSFOFST);
- iowrite32((u32)(qwTSFOffset >> 32), priv->port_offset + MAC_REG_TSFOFST + 4);
+ tsf_offset = le64_to_cpu(tsf_offset);
+ iowrite32((u32)tsf_offset, priv->port_offset + MAC_REG_TSFOFST);
+ iowrite32((u32)(tsf_offset >> 32), priv->port_offset + MAC_REG_TSFOFST + 4);
vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_TSFSYNCEN);
}
return true;
@@ -314,28 +314,28 @@ bool card_update_tsf(struct vnt_private *priv, unsigned char rx_rate,
* Parameters:
* In:
* priv - The adapter to be set.
- * wBeaconInterval - Beacon Interval
+ * beacon_interval - Beacon Interval
* Out:
* none
*
* Return Value: true if succeed; otherwise false
*/
-bool CARDbSetBeaconPeriod(struct vnt_private *priv,
- unsigned short wBeaconInterval)
+bool card_set_beacon_period(struct vnt_private *priv,
+ unsigned short beacon_interval)
{
- u64 qwNextTBTT;
+ u64 next_tbtt;
- qwNextTBTT = vt6655_get_current_tsf(priv); /* Get Local TSF counter */
+ next_tbtt = vt6655_get_current_tsf(priv); /* Get Local TSF counter */
- qwNextTBTT = CARDqGetNextTBTT(qwNextTBTT, wBeaconInterval);
+ next_tbtt = card_get_next_tbtt(next_tbtt, beacon_interval);
/* set HW beacon interval */
- iowrite16(wBeaconInterval, priv->port_offset + MAC_REG_BI);
- priv->wBeaconInterval = wBeaconInterval;
+ iowrite16(beacon_interval, priv->port_offset + MAC_REG_BI);
+ priv->beacon_interval = beacon_interval;
/* Set NextTBTT */
- qwNextTBTT = le64_to_cpu(qwNextTBTT);
- iowrite32((u32)qwNextTBTT, priv->port_offset + MAC_REG_NEXTTBTT);
- iowrite32((u32)(qwNextTBTT >> 32), priv->port_offset + MAC_REG_NEXTTBTT + 4);
+ next_tbtt = le64_to_cpu(next_tbtt);
+ iowrite32((u32)next_tbtt, priv->port_offset + MAC_REG_NEXTTBTT);
+ iowrite32((u32)(next_tbtt >> 32), priv->port_offset + MAC_REG_NEXTTBTT + 4);
vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN);
return true;
@@ -351,7 +351,7 @@ bool CARDbSetBeaconPeriod(struct vnt_private *priv,
* none
*
*/
-void CARDbRadioPowerOff(struct vnt_private *priv)
+void card_radio_power_off(struct vnt_private *priv)
{
if (priv->radio_off)
return;
@@ -382,29 +382,29 @@ void CARDbRadioPowerOff(struct vnt_private *priv)
vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_GPIOCTL0, LED_ACTSET); /* LED issue */
}
-void CARDvSafeResetTx(struct vnt_private *priv)
+void card_safe_reset_tx(struct vnt_private *priv)
{
unsigned int uu;
- struct vnt_tx_desc *pCurrTD;
+ struct vnt_tx_desc *curr_td;
/* initialize TD index */
- priv->apTailTD[0] = &priv->apTD0Rings[0];
+ priv->tail_td[0] = &priv->apTD0Rings[0];
priv->apCurrTD[0] = &priv->apTD0Rings[0];
- priv->apTailTD[1] = &priv->apTD1Rings[0];
+ priv->tail_td[1] = &priv->apTD1Rings[0];
priv->apCurrTD[1] = &priv->apTD1Rings[0];
for (uu = 0; uu < TYPE_MAXTD; uu++)
priv->iTDUsed[uu] = 0;
for (uu = 0; uu < priv->opts.tx_descs[0]; uu++) {
- pCurrTD = &priv->apTD0Rings[uu];
- pCurrTD->td0.owner = OWNED_BY_HOST;
+ curr_td = &priv->apTD0Rings[uu];
+ curr_td->td0.owner = OWNED_BY_HOST;
/* init all Tx Packet pointer to NULL */
}
for (uu = 0; uu < priv->opts.tx_descs[1]; uu++) {
- pCurrTD = &priv->apTD1Rings[uu];
- pCurrTD->td0.owner = OWNED_BY_HOST;
+ curr_td = &priv->apTD1Rings[uu];
+ curr_td->td0.owner = OWNED_BY_HOST;
/* init all Tx Packet pointer to NULL */
}
@@ -708,7 +708,7 @@ unsigned char card_get_pkt_type(struct vnt_private *priv)
*
* Return Value: TSF Offset value
*/
-u64 CARDqGetTSFOffset(unsigned char rx_rate, u64 qwTSF1, u64 qwTSF2)
+u64 card_get_tsf_offset(unsigned char rx_rate, u64 qwTSF1, u64 qwTSF2)
{
unsigned short wRxBcnTSFOffst;
@@ -764,11 +764,11 @@ u64 vt6655_get_current_tsf(struct vnt_private *priv)
*
* Return Value: TSF value of next Beacon
*/
-u64 CARDqGetNextTBTT(u64 qwTSF, unsigned short wBeaconInterval)
+u64 card_get_next_tbtt(u64 qwTSF, unsigned short beacon_interval)
{
u32 beacon_int;
- beacon_int = wBeaconInterval * 1024;
+ beacon_int = beacon_interval * 1024;
if (beacon_int) {
do_div(qwTSF, beacon_int);
qwTSF += 1;
@@ -785,25 +785,25 @@ u64 CARDqGetNextTBTT(u64 qwTSF, unsigned short wBeaconInterval)
* Parameters:
* In:
* iobase - IO Base
- * wBeaconInterval - Beacon Interval
+ * beacon_interval - Beacon Interval
* Out:
* none
*
* Return Value: none
*/
void CARDvSetFirstNextTBTT(struct vnt_private *priv,
- unsigned short wBeaconInterval)
+ unsigned short beacon_interval)
{
void __iomem *iobase = priv->port_offset;
- u64 qwNextTBTT;
+ u64 next_tbtt;
- qwNextTBTT = vt6655_get_current_tsf(priv); /* Get Local TSF counter */
+ next_tbtt = vt6655_get_current_tsf(priv); /* Get Local TSF counter */
- qwNextTBTT = CARDqGetNextTBTT(qwNextTBTT, wBeaconInterval);
+ next_tbtt = card_get_next_tbtt(next_tbtt, beacon_interval);
/* Set NextTBTT */
- qwNextTBTT = le64_to_cpu(qwNextTBTT);
- iowrite32((u32)qwNextTBTT, iobase + MAC_REG_NEXTTBTT);
- iowrite32((u32)(qwNextTBTT >> 32), iobase + MAC_REG_NEXTTBTT + 4);
+ next_tbtt = le64_to_cpu(next_tbtt);
+ iowrite32((u32)next_tbtt, iobase + MAC_REG_NEXTTBTT);
+ iowrite32((u32)(next_tbtt >> 32), iobase + MAC_REG_NEXTTBTT + 4);
vt6655_mac_reg_bits_on(iobase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN);
}
@@ -815,18 +815,18 @@ void CARDvSetFirstNextTBTT(struct vnt_private *priv,
* In:
* priv - The adapter to be set
* qwTSF - Current TSF counter
- * wBeaconInterval - Beacon Interval
+ * beacon_interval - Beacon Interval
* Out:
* none
*
* Return Value: none
*/
void CARDvUpdateNextTBTT(struct vnt_private *priv, u64 qwTSF,
- unsigned short wBeaconInterval)
+ unsigned short beacon_interval)
{
void __iomem *iobase = priv->port_offset;
- qwTSF = CARDqGetNextTBTT(qwTSF, wBeaconInterval);
+ qwTSF = card_get_next_tbtt(qwTSF, beacon_interval);
/* Set NextTBTT */
qwTSF = le64_to_cpu(qwTSF);
iowrite32((u32)qwTSF, iobase + MAC_REG_NEXTTBTT);
diff --git a/drivers/staging/vt6655/card.h b/drivers/staging/vt6655/card.h
index 19689a291f5b..f52e42564e81 100644
--- a/drivers/staging/vt6655/card.h
+++ b/drivers/staging/vt6655/card.h
@@ -43,20 +43,20 @@ void card_set_rspinf(struct vnt_private *priv, u8 bb_type);
void CARDvUpdateBasicTopRate(struct vnt_private *priv);
bool CARDbIsOFDMinBasicRate(struct vnt_private *priv);
void CARDvSetFirstNextTBTT(struct vnt_private *priv,
- unsigned short wBeaconInterval);
+ unsigned short beacon_interval);
void CARDvUpdateNextTBTT(struct vnt_private *priv, u64 qwTSF,
- unsigned short wBeaconInterval);
+ unsigned short beacon_interval);
u64 vt6655_get_current_tsf(struct vnt_private *priv);
-u64 CARDqGetNextTBTT(u64 qwTSF, unsigned short wBeaconInterval);
-u64 CARDqGetTSFOffset(unsigned char rx_rate, u64 qwTSF1, u64 qwTSF2);
+u64 card_get_next_tbtt(u64 qwTSF, unsigned short beacon_interval);
+u64 card_get_tsf_offset(unsigned char rx_rate, u64 qwTSF1, u64 qwTSF2);
unsigned char card_get_pkt_type(struct vnt_private *priv);
-void CARDvSafeResetTx(struct vnt_private *priv);
+void card_safe_reset_tx(struct vnt_private *priv);
void CARDvSafeResetRx(struct vnt_private *priv);
-void CARDbRadioPowerOff(struct vnt_private *priv);
+void card_radio_power_off(struct vnt_private *priv);
bool card_set_phy_parameter(struct vnt_private *priv, u8 bb_type);
bool card_update_tsf(struct vnt_private *priv, unsigned char rx_rate,
- u64 qwBSSTimestamp);
-bool CARDbSetBeaconPeriod(struct vnt_private *priv,
- unsigned short wBeaconInterval);
+ u64 bss_timestamp);
+bool card_set_beacon_period(struct vnt_private *priv,
+ unsigned short beacon_interval);
#endif /* __CARD_H__ */
diff --git a/drivers/staging/vt6655/device.h b/drivers/staging/vt6655/device.h
index d9ee0b7401fe..0212240ba23f 100644
--- a/drivers/staging/vt6655/device.h
+++ b/drivers/staging/vt6655/device.h
@@ -133,7 +133,7 @@ struct vnt_private {
volatile int iTDUsed[TYPE_MAXTD];
struct vnt_tx_desc *apCurrTD[TYPE_MAXTD];
- struct vnt_tx_desc *apTailTD[TYPE_MAXTD];
+ struct vnt_tx_desc *tail_td[TYPE_MAXTD];
struct vnt_tx_desc *apTD0Rings;
struct vnt_tx_desc *apTD1Rings;
@@ -281,7 +281,7 @@ struct vnt_private {
unsigned char abyEEPROM[EEP_MAX_CONTEXT_SIZE]; /* unsigned long alignment */
- unsigned short wBeaconInterval;
+ unsigned short beacon_interval;
u16 wake_up_count;
struct work_struct interrupt_work;
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index 7d297526e653..b0b262de6480 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -454,7 +454,7 @@ static void device_init_registers(struct vnt_private *priv)
}
if (priv->hw_radio_off || priv->bRadioControlOff)
- CARDbRadioPowerOff(priv);
+ card_radio_power_off(priv);
/* get Permanent network address */
SROMvReadEtherAddress(priv->port_offset, priv->abyCurrentNetAddr);
@@ -463,7 +463,7 @@ static void device_init_registers(struct vnt_private *priv)
/* reset Tx pointer */
CARDvSafeResetRx(priv);
/* reset Rx pointer */
- CARDvSafeResetTx(priv);
+ card_safe_reset_tx(priv);
if (priv->local_id <= REV_ID_VT3253_A1)
vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_RCR, RCR_WPAERR);
@@ -737,7 +737,7 @@ static int device_init_td0_ring(struct vnt_private *priv)
if (i > 0)
priv->apTD0Rings[i - 1].next_desc = cpu_to_le32(priv->td0_pool_dma);
- priv->apTailTD[0] = priv->apCurrTD[0] = &priv->apTD0Rings[0];
+ priv->tail_td[0] = priv->apCurrTD[0] = &priv->apTD0Rings[0];
return 0;
@@ -777,7 +777,7 @@ static int device_init_td1_ring(struct vnt_private *priv)
if (i > 0)
priv->apTD1Rings[i - 1].next_desc = cpu_to_le32(priv->td1_pool_dma);
- priv->apTailTD[1] = priv->apCurrTD[1] = &priv->apTD1Rings[0];
+ priv->tail_td[1] = priv->apCurrTD[1] = &priv->apTD1Rings[0];
return 0;
@@ -969,7 +969,7 @@ static int device_tx_srv(struct vnt_private *priv, unsigned int idx)
unsigned char byTsr0;
unsigned char byTsr1;
- for (desc = priv->apTailTD[idx]; priv->iTDUsed[idx] > 0; desc = desc->next) {
+ for (desc = priv->tail_td[idx]; priv->iTDUsed[idx] > 0; desc = desc->next) {
if (desc->td0.owner == OWNED_BY_NIC)
break;
if (works++ > 15)
@@ -1007,7 +1007,7 @@ static int device_tx_srv(struct vnt_private *priv, unsigned int idx)
}
}
- priv->apTailTD[idx] = desc;
+ priv->tail_td[idx] = desc;
return works;
}
@@ -1349,7 +1349,7 @@ static void vnt_stop(struct ieee80211_hw *hw)
MACbShutdown(priv);
MACbSoftwareReset(priv);
- CARDbRadioPowerOff(priv);
+ card_radio_power_off(priv);
device_free_td0_ring(priv);
device_free_td1_ring(priv);
@@ -1537,7 +1537,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw,
card_update_tsf(priv, conf->beacon_rate->hw_value,
conf->sync_tsf);
- CARDbSetBeaconPeriod(priv, conf->beacon_int);
+ card_set_beacon_period(priv, conf->beacon_int);
CARDvSetFirstNextTBTT(priv, conf->beacon_int);
} else {
@@ -1712,7 +1712,7 @@ static int vnt_init(struct vnt_private *priv)
priv->mac_hw = true;
- CARDbRadioPowerOff(priv);
+ card_radio_power_off(priv);
return 0;
}
diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c
index 522d34ca9b0f..5e5ed582c35e 100644
--- a/drivers/staging/vt6655/rxtx.c
+++ b/drivers/staging/vt6655/rxtx.c
@@ -1456,7 +1456,7 @@ int vnt_beacon_enable(struct vnt_private *priv, struct ieee80211_vif *vif,
CARDvSetFirstNextTBTT(priv, conf->beacon_int);
- CARDbSetBeaconPeriod(priv, conf->beacon_int);
+ card_set_beacon_period(priv, conf->beacon_int);
return vnt_beacon_make(priv, vif);
}
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 59883502eff4..17a8ae5e991d 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -33,6 +33,13 @@ config THERMAL_STATISTICS
If in doubt, say N.
+config THERMAL_DEBUGFS
+ bool "Thermal subsystem debug support"
+ depends on DEBUG_FS
+ help
+ Say Y to allow the thermal subsystem to collect diagnostic
+ information that can be accessed via debugfs.
+
config THERMAL_EMERGENCY_POWEROFF_DELAY_MS
int "Emergency poweroff delay in milli-seconds"
default 0
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index a8318d671036..d77d7fe99a84 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -10,6 +10,8 @@ thermal_sys-y += thermal_trip.o thermal_helpers.o
# netlink interface to manage the thermal framework
thermal_sys-$(CONFIG_THERMAL_NETLINK) += thermal_netlink.o
+thermal_sys-$(CONFIG_THERMAL_DEBUGFS) += thermal_debugfs.o
+
# interface to/from other layers providing sensors
thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o
thermal_sys-$(CONFIG_THERMAL_OF) += thermal_of.o
diff --git a/drivers/thermal/gov_power_allocator.c b/drivers/thermal/gov_power_allocator.c
index 7b6aa265ff6a..81e061f183ad 100644
--- a/drivers/thermal/gov_power_allocator.c
+++ b/drivers/thermal/gov_power_allocator.c
@@ -762,7 +762,7 @@ static int power_allocator_throttle(struct thermal_zone_device *tz,
trip = params->trip_switch_on;
if (trip && tz->temperature < trip->temperature) {
- update = tz->last_temperature >= trip->temperature;
+ update = tz->passive;
tz->passive = 0;
reset_pid_controller(params);
allow_maximum_power(tz, update);
diff --git a/drivers/thermal/intel/intel_hfi.c b/drivers/thermal/intel/intel_hfi.c
index 22445403b520..3b04c6ec4fca 100644
--- a/drivers/thermal/intel/intel_hfi.c
+++ b/drivers/thermal/intel/intel_hfi.c
@@ -35,7 +35,9 @@
#include <linux/processor.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/suspend.h>
#include <linux/string.h>
+#include <linux/syscore_ops.h>
#include <linux/topology.h>
#include <linux/workqueue.h>
@@ -571,6 +573,30 @@ static __init int hfi_parse_features(void)
return 0;
}
+static void hfi_do_enable(void)
+{
+ /* This code runs only on the boot CPU. */
+ struct hfi_cpu_info *info = &per_cpu(hfi_cpu_info, 0);
+ struct hfi_instance *hfi_instance = info->hfi_instance;
+
+ /* No locking needed. There is no concurrency with CPU online. */
+ hfi_set_hw_table(hfi_instance);
+ hfi_enable();
+}
+
+static int hfi_do_disable(void)
+{
+ /* No locking needed. There is no concurrency with CPU offline. */
+ hfi_disable();
+
+ return 0;
+}
+
+static struct syscore_ops hfi_pm_ops = {
+ .resume = hfi_do_enable,
+ .suspend = hfi_do_disable,
+};
+
void __init intel_hfi_init(void)
{
struct hfi_instance *hfi_instance;
@@ -602,6 +628,8 @@ void __init intel_hfi_init(void)
if (!hfi_updates_wq)
goto err_nomem;
+ register_syscore_ops(&hfi_pm_ops);
+
return;
err_nomem:
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index fa88d8707241..dfaa6341694a 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -211,7 +211,7 @@ exit:
mutex_unlock(&tz->lock);
mutex_unlock(&thermal_governor_lock);
- thermal_notify_tz_gov_change(tz->id, policy);
+ thermal_notify_tz_gov_change(tz, policy);
return ret;
}
@@ -381,9 +381,8 @@ static void handle_thermal_trip(struct thermal_zone_device *tz,
* the threshold and the trip temperature will be equal.
*/
if (tz->temperature >= trip->temperature) {
- thermal_notify_tz_trip_up(tz->id,
- thermal_zone_trip_id(tz, trip),
- tz->temperature);
+ thermal_notify_tz_trip_up(tz, trip);
+ thermal_debug_tz_trip_up(tz, trip);
trip->threshold = trip->temperature - trip->hysteresis;
} else {
trip->threshold = trip->temperature;
@@ -400,9 +399,8 @@ static void handle_thermal_trip(struct thermal_zone_device *tz,
* the trip.
*/
if (tz->temperature < trip->temperature - trip->hysteresis) {
- thermal_notify_tz_trip_down(tz->id,
- thermal_zone_trip_id(tz, trip),
- tz->temperature);
+ thermal_notify_tz_trip_down(tz, trip);
+ thermal_debug_tz_trip_down(tz, trip);
trip->threshold = trip->temperature;
} else {
trip->threshold = trip->temperature - trip->hysteresis;
@@ -434,6 +432,7 @@ static void update_temperature(struct thermal_zone_device *tz)
trace_thermal_temperature(tz);
thermal_genl_sampling_temp(tz->id, temp);
+ thermal_debug_update_temp(tz);
}
static void thermal_zone_device_check(struct work_struct *work)
@@ -505,9 +504,9 @@ static int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
mutex_unlock(&tz->lock);
if (mode == THERMAL_DEVICE_ENABLED)
- thermal_notify_tz_enable(tz->id);
+ thermal_notify_tz_enable(tz);
else
- thermal_notify_tz_disable(tz->id);
+ thermal_notify_tz_disable(tz);
return ret;
}
@@ -846,7 +845,7 @@ static void thermal_release(struct device *dev)
sizeof("cooling_device") - 1)) {
cdev = to_cooling_device(dev);
thermal_cooling_device_destroy_sysfs(cdev);
- kfree(cdev->type);
+ kfree_const(cdev->type);
ida_free(&thermal_cdev_ida, cdev->id);
kfree(cdev);
}
@@ -918,7 +917,7 @@ __thermal_cooling_device_register(struct device_node *np,
cdev->id = ret;
id = ret;
- cdev->type = kstrdup(type ? type : "", GFP_KERNEL);
+ cdev->type = kstrdup_const(type ? type : "", GFP_KERNEL);
if (!cdev->type) {
ret = -ENOMEM;
goto out_ida_remove;
@@ -964,12 +963,14 @@ __thermal_cooling_device_register(struct device_node *np,
mutex_unlock(&thermal_list_lock);
+ thermal_debug_cdev_add(cdev);
+
return cdev;
out_cooling_dev:
thermal_cooling_device_destroy_sysfs(cdev);
out_cdev_type:
- kfree(cdev->type);
+ kfree_const(cdev->type);
out_ida_remove:
ida_free(&thermal_cdev_ida, id);
out_kfree_cdev:
@@ -1170,6 +1171,8 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
if (!cdev)
return;
+ thermal_debug_cdev_remove(cdev);
+
mutex_lock(&thermal_list_lock);
if (!thermal_cooling_device_present(cdev)) {
@@ -1411,7 +1414,9 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
if (atomic_cmpxchg(&tz->need_update, 1, 0))
thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
- thermal_notify_tz_create(tz->id, tz->type);
+ thermal_notify_tz_create(tz);
+
+ thermal_debug_tz_add(tz);
return tz;
@@ -1470,14 +1475,13 @@ EXPORT_SYMBOL_GPL(thermal_zone_device);
*/
void thermal_zone_device_unregister(struct thermal_zone_device *tz)
{
- int tz_id;
struct thermal_cooling_device *cdev;
struct thermal_zone_device *pos = NULL;
if (!tz)
return;
- tz_id = tz->id;
+ thermal_debug_tz_remove(tz);
mutex_lock(&thermal_list_lock);
list_for_each_entry(pos, &thermal_tz_list, node)
@@ -1514,7 +1518,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
put_device(&tz->device);
- thermal_notify_tz_delete(tz_id);
+ thermal_notify_tz_delete(tz);
wait_for_completion(&tz->removal);
kfree(tz);
@@ -1636,6 +1640,8 @@ static int __init thermal_init(void)
{
int result;
+ thermal_debug_init();
+
result = thermal_netlink_init();
if (result)
goto error;
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 4e023d54fd27..e9c099ecdd0f 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -13,6 +13,7 @@
#include <linux/thermal.h>
#include "thermal_netlink.h"
+#include "thermal_debugfs.h"
/* Default Thermal Governor */
#if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE)
diff --git a/drivers/thermal/thermal_debugfs.c b/drivers/thermal/thermal_debugfs.c
new file mode 100644
index 000000000000..c617e8b9f0dd
--- /dev/null
+++ b/drivers/thermal/thermal_debugfs.c
@@ -0,0 +1,839 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2023 Linaro Limited
+ *
+ * Author: Daniel Lezcano <[email protected]>
+ *
+ * Thermal subsystem debug support
+ */
+#include <linux/debugfs.h>
+#include <linux/ktime.h>
+#include <linux/list.h>
+#include <linux/minmax.h>
+#include <linux/mutex.h>
+#include <linux/thermal.h>
+
+#include "thermal_core.h"
+
+static struct dentry *d_root;
+static struct dentry *d_cdev;
+static struct dentry *d_tz;
+
+/*
+ * Length of the string containing the thermal zone id or the cooling
+ * device id, including the ending nul character. We can reasonably
+ * assume there won't be more than 256 thermal zones as the maximum
+ * observed today is around 32.
+ */
+#define IDSLENGTH 4
+
+/*
+ * The cooling device transition list is stored in a hash table where
+ * the size is CDEVSTATS_HASH_SIZE. The majority of cooling devices
+ * have dozen of states but some can have much more, so a hash table
+ * is more adequate in this case, because the cost of browsing the entire
+ * list when storing the transitions may not be negligible.
+ */
+#define CDEVSTATS_HASH_SIZE 16
+
+/**
+ * struct cdev_debugfs - per cooling device statistics structure
+ * A cooling device can have a high number of states. Showing the
+ * transitions on a matrix based representation can be overkill given
+ * most of the transitions won't happen and we end up with a matrix
+ * filled with zero. Instead, we show the transitions which actually
+ * happened.
+ *
+ * Every transition updates the current_state and the timestamp. The
+ * transitions and the durations are stored in lists.
+ *
+ * @total: the number of transitions for this cooling device
+ * @current_state: the current cooling device state
+ * @timestamp: the state change timestamp
+ * @transitions: an array of lists containing the state transitions
+ * @durations: an array of lists containing the residencies of each state
+ */
+struct cdev_debugfs {
+ u32 total;
+ int current_state;
+ ktime_t timestamp;
+ struct list_head transitions[CDEVSTATS_HASH_SIZE];
+ struct list_head durations[CDEVSTATS_HASH_SIZE];
+};
+
+/**
+ * struct cdev_record - Common structure for cooling device entry
+ *
+ * The following common structure allows to store the information
+ * related to the transitions and to the state residencies. They are
+ * identified with a id which is associated to a value. It is used as
+ * nodes for the "transitions" and "durations" above.
+ *
+ * @node: node to insert the structure in a list
+ * @id: identifier of the value which can be a state or a transition
+ * @residency: a ktime_t representing a state residency duration
+ * @count: a number of occurrences
+ */
+struct cdev_record {
+ struct list_head node;
+ int id;
+ union {
+ ktime_t residency;
+ u64 count;
+ };
+};
+
+/**
+ * struct trip_stats - Thermal trip statistics
+ *
+ * The trip_stats structure has the relevant information to show the
+ * statistics related to temperature going above a trip point.
+ *
+ * @timestamp: the trip crossing timestamp
+ * @duration: total time when the zone temperature was above the trip point
+ * @count: the number of times the zone temperature was above the trip point
+ * @max: maximum recorded temperature above the trip point
+ * @min: minimum recorded temperature above the trip point
+ * @avg: average temperature above the trip point
+ */
+struct trip_stats {
+ ktime_t timestamp;
+ ktime_t duration;
+ int count;
+ int max;
+ int min;
+ int avg;
+};
+
+/**
+ * struct tz_episode - A mitigation episode information
+ *
+ * The tz_episode structure describes a mitigation episode. A
+ * mitigation episode begins the trip point with the lower temperature
+ * is crossed the way up and ends when it is crossed the way
+ * down. During this episode we can have multiple trip points crossed
+ * the way up and down if there are multiple trip described in the
+ * firmware after the lowest temperature trip point.
+ *
+ * @timestamp: first trip point crossed the way up
+ * @duration: total duration of the mitigation episode
+ * @node: a list element to be added to the list of tz events
+ * @trip_stats: per trip point statistics, flexible array
+ */
+struct tz_episode {
+ ktime_t timestamp;
+ ktime_t duration;
+ struct list_head node;
+ struct trip_stats trip_stats[];
+};
+
+/**
+ * struct tz_debugfs - Store all mitigation episodes for a thermal zone
+ *
+ * The tz_debugfs structure contains the list of the mitigation
+ * episodes and has to track which trip point has been crossed in
+ * order to handle correctly nested trip point mitigation episodes.
+ *
+ * We keep the history of the trip point crossed in an array and as we
+ * can go back and forth inside this history, eg. trip 0,1,2,1,2,1,0,
+ * we keep track of the current position in the history array.
+ *
+ * @tz_episodes: a list of thermal mitigation episodes
+ * @trips_crossed: an array of trip points crossed by id
+ * @nr_trips: the number of trip points currently being crossed
+ */
+struct tz_debugfs {
+ struct list_head tz_episodes;
+ int *trips_crossed;
+ int nr_trips;
+};
+
+/**
+ * struct thermal_debugfs - High level structure for a thermal object in debugfs
+ *
+ * The thermal_debugfs structure is the common structure used by the
+ * cooling device or the thermal zone to store the statistics.
+ *
+ * @d_top: top directory of the thermal object directory
+ * @lock: per object lock to protect the internals
+ *
+ * @cdev_dbg: a cooling device debug structure
+ * @tz_dbg: a thermal zone debug structure
+ */
+struct thermal_debugfs {
+ struct dentry *d_top;
+ struct mutex lock;
+ union {
+ struct cdev_debugfs cdev_dbg;
+ struct tz_debugfs tz_dbg;
+ };
+};
+
+void thermal_debug_init(void)
+{
+ d_root = debugfs_create_dir("thermal", NULL);
+ if (!d_root)
+ return;
+
+ d_cdev = debugfs_create_dir("cooling_devices", d_root);
+ if (!d_cdev)
+ return;
+
+ d_tz = debugfs_create_dir("thermal_zones", d_root);
+}
+
+static struct thermal_debugfs *thermal_debugfs_add_id(struct dentry *d, int id)
+{
+ struct thermal_debugfs *thermal_dbg;
+ char ids[IDSLENGTH];
+
+ thermal_dbg = kzalloc(sizeof(*thermal_dbg), GFP_KERNEL);
+ if (!thermal_dbg)
+ return NULL;
+
+ mutex_init(&thermal_dbg->lock);
+
+ snprintf(ids, IDSLENGTH, "%d", id);
+
+ thermal_dbg->d_top = debugfs_create_dir(ids, d);
+ if (!thermal_dbg->d_top) {
+ kfree(thermal_dbg);
+ return NULL;
+ }
+
+ return thermal_dbg;
+}
+
+static void thermal_debugfs_remove_id(struct thermal_debugfs *thermal_dbg)
+{
+ if (!thermal_dbg)
+ return;
+
+ debugfs_remove(thermal_dbg->d_top);
+
+ kfree(thermal_dbg);
+}
+
+static struct cdev_record *
+thermal_debugfs_cdev_record_alloc(struct thermal_debugfs *thermal_dbg,
+ struct list_head *lists, int id)
+{
+ struct cdev_record *cdev_record;
+
+ cdev_record = kzalloc(sizeof(*cdev_record), GFP_KERNEL);
+ if (!cdev_record)
+ return NULL;
+
+ cdev_record->id = id;
+ INIT_LIST_HEAD(&cdev_record->node);
+ list_add_tail(&cdev_record->node,
+ &lists[cdev_record->id % CDEVSTATS_HASH_SIZE]);
+
+ return cdev_record;
+}
+
+static struct cdev_record *
+thermal_debugfs_cdev_record_find(struct thermal_debugfs *thermal_dbg,
+ struct list_head *lists, int id)
+{
+ struct cdev_record *entry;
+
+ list_for_each_entry(entry, &lists[id % CDEVSTATS_HASH_SIZE], node)
+ if (entry->id == id)
+ return entry;
+
+ return NULL;
+}
+
+static struct cdev_record *
+thermal_debugfs_cdev_record_get(struct thermal_debugfs *thermal_dbg,
+ struct list_head *lists, int id)
+{
+ struct cdev_record *cdev_record;
+
+ cdev_record = thermal_debugfs_cdev_record_find(thermal_dbg, lists, id);
+ if (cdev_record)
+ return cdev_record;
+
+ return thermal_debugfs_cdev_record_alloc(thermal_dbg, lists, id);
+}
+
+static void thermal_debugfs_cdev_clear(struct cdev_debugfs *cdev_dbg)
+{
+ int i;
+ struct cdev_record *entry, *tmp;
+
+ for (i = 0; i < CDEVSTATS_HASH_SIZE; i++) {
+
+ list_for_each_entry_safe(entry, tmp,
+ &cdev_dbg->transitions[i], node) {
+ list_del(&entry->node);
+ kfree(entry);
+ }
+
+ list_for_each_entry_safe(entry, tmp,
+ &cdev_dbg->durations[i], node) {
+ list_del(&entry->node);
+ kfree(entry);
+ }
+ }
+
+ cdev_dbg->total = 0;
+}
+
+static void *cdev_seq_start(struct seq_file *s, loff_t *pos)
+{
+ struct thermal_debugfs *thermal_dbg = s->private;
+
+ mutex_lock(&thermal_dbg->lock);
+
+ return (*pos < CDEVSTATS_HASH_SIZE) ? pos : NULL;
+}
+
+static void *cdev_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ (*pos)++;
+
+ return (*pos < CDEVSTATS_HASH_SIZE) ? pos : NULL;
+}
+
+static void cdev_seq_stop(struct seq_file *s, void *v)
+{
+ struct thermal_debugfs *thermal_dbg = s->private;
+
+ mutex_unlock(&thermal_dbg->lock);
+}
+
+static int cdev_tt_seq_show(struct seq_file *s, void *v)
+{
+ struct thermal_debugfs *thermal_dbg = s->private;
+ struct cdev_debugfs *cdev_dbg = &thermal_dbg->cdev_dbg;
+ struct list_head *transitions = cdev_dbg->transitions;
+ struct cdev_record *entry;
+ int i = *(loff_t *)v;
+
+ if (!i)
+ seq_puts(s, "Transition\tOccurences\n");
+
+ list_for_each_entry(entry, &transitions[i], node) {
+ /*
+ * Assuming maximum cdev states is 1024, the longer
+ * string for a transition would be "1024->1024\0"
+ */
+ char buffer[11];
+
+ snprintf(buffer, ARRAY_SIZE(buffer), "%d->%d",
+ entry->id >> 16, entry->id & 0xFFFF);
+
+ seq_printf(s, "%-10s\t%-10llu\n", buffer, entry->count);
+ }
+
+ return 0;
+}
+
+static const struct seq_operations tt_sops = {
+ .start = cdev_seq_start,
+ .next = cdev_seq_next,
+ .stop = cdev_seq_stop,
+ .show = cdev_tt_seq_show,
+};
+
+DEFINE_SEQ_ATTRIBUTE(tt);
+
+static int cdev_dt_seq_show(struct seq_file *s, void *v)
+{
+ struct thermal_debugfs *thermal_dbg = s->private;
+ struct cdev_debugfs *cdev_dbg = &thermal_dbg->cdev_dbg;
+ struct list_head *durations = cdev_dbg->durations;
+ struct cdev_record *entry;
+ int i = *(loff_t *)v;
+
+ if (!i)
+ seq_puts(s, "State\tResidency\n");
+
+ list_for_each_entry(entry, &durations[i], node) {
+ s64 duration = ktime_to_ms(entry->residency);
+
+ if (entry->id == cdev_dbg->current_state)
+ duration += ktime_ms_delta(ktime_get(),
+ cdev_dbg->timestamp);
+
+ seq_printf(s, "%-5d\t%-10llu\n", entry->id, duration);
+ }
+
+ return 0;
+}
+
+static const struct seq_operations dt_sops = {
+ .start = cdev_seq_start,
+ .next = cdev_seq_next,
+ .stop = cdev_seq_stop,
+ .show = cdev_dt_seq_show,
+};
+
+DEFINE_SEQ_ATTRIBUTE(dt);
+
+static int cdev_clear_set(void *data, u64 val)
+{
+ struct thermal_debugfs *thermal_dbg = data;
+
+ if (!val)
+ return -EINVAL;
+
+ mutex_lock(&thermal_dbg->lock);
+
+ thermal_debugfs_cdev_clear(&thermal_dbg->cdev_dbg);
+
+ mutex_unlock(&thermal_dbg->lock);
+
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(cdev_clear_fops, NULL, cdev_clear_set, "%llu\n");
+
+/**
+ * thermal_debug_cdev_state_update - Update a cooling device state change
+ *
+ * Computes a transition and the duration of the previous state residency.
+ *
+ * @cdev : a pointer to a cooling device
+ * @new_state: an integer corresponding to the new cooling device state
+ */
+void thermal_debug_cdev_state_update(const struct thermal_cooling_device *cdev,
+ int new_state)
+{
+ struct thermal_debugfs *thermal_dbg = cdev->debugfs;
+ struct cdev_debugfs *cdev_dbg;
+ struct cdev_record *cdev_record;
+ int transition, old_state;
+
+ if (!thermal_dbg || (thermal_dbg->cdev_dbg.current_state == new_state))
+ return;
+
+ mutex_lock(&thermal_dbg->lock);
+
+ cdev_dbg = &thermal_dbg->cdev_dbg;
+
+ old_state = cdev_dbg->current_state;
+
+ /*
+ * Get the old state information in the durations list. If
+ * this one does not exist, a new allocated one will be
+ * returned. Recompute the total duration in the old state and
+ * get a new timestamp for the new state.
+ */
+ cdev_record = thermal_debugfs_cdev_record_get(thermal_dbg,
+ cdev_dbg->durations,
+ old_state);
+ if (cdev_record) {
+ ktime_t now = ktime_get();
+ ktime_t delta = ktime_sub(now, cdev_dbg->timestamp);
+ cdev_record->residency = ktime_add(cdev_record->residency, delta);
+ cdev_dbg->timestamp = now;
+ }
+
+ cdev_dbg->current_state = new_state;
+ transition = (old_state << 16) | new_state;
+
+ /*
+ * Get the transition in the transitions list. If this one
+ * does not exist, a new allocated one will be returned.
+ * Increment the occurrence of this transition which is stored
+ * in the value field.
+ */
+ cdev_record = thermal_debugfs_cdev_record_get(thermal_dbg,
+ cdev_dbg->transitions,
+ transition);
+ if (cdev_record)
+ cdev_record->count++;
+
+ cdev_dbg->total++;
+
+ mutex_unlock(&thermal_dbg->lock);
+}
+
+/**
+ * thermal_debug_cdev_add - Add a cooling device debugfs entry
+ *
+ * Allocates a cooling device object for debug, initializes the
+ * statistics and create the entries in sysfs.
+ * @cdev: a pointer to a cooling device
+ */
+void thermal_debug_cdev_add(struct thermal_cooling_device *cdev)
+{
+ struct thermal_debugfs *thermal_dbg;
+ struct cdev_debugfs *cdev_dbg;
+ int i;
+
+ thermal_dbg = thermal_debugfs_add_id(d_cdev, cdev->id);
+ if (!thermal_dbg)
+ return;
+
+ cdev_dbg = &thermal_dbg->cdev_dbg;
+
+ for (i = 0; i < CDEVSTATS_HASH_SIZE; i++) {
+ INIT_LIST_HEAD(&cdev_dbg->transitions[i]);
+ INIT_LIST_HEAD(&cdev_dbg->durations[i]);
+ }
+
+ cdev_dbg->current_state = 0;
+ cdev_dbg->timestamp = ktime_get();
+
+ debugfs_create_file("trans_table", 0400, thermal_dbg->d_top,
+ thermal_dbg, &tt_fops);
+
+ debugfs_create_file("time_in_state_ms", 0400, thermal_dbg->d_top,
+ thermal_dbg, &dt_fops);
+
+ debugfs_create_file("clear", 0200, thermal_dbg->d_top,
+ thermal_dbg, &cdev_clear_fops);
+
+ debugfs_create_u32("total_trans", 0400, thermal_dbg->d_top,
+ &cdev_dbg->total);
+
+ cdev->debugfs = thermal_dbg;
+}
+
+/**
+ * thermal_debug_cdev_remove - Remove a cooling device debugfs entry
+ *
+ * Frees the statistics memory data and remove the debugfs entry
+ *
+ * @cdev: a pointer to a cooling device
+ */
+void thermal_debug_cdev_remove(struct thermal_cooling_device *cdev)
+{
+ struct thermal_debugfs *thermal_dbg = cdev->debugfs;
+
+ if (!thermal_dbg)
+ return;
+
+ mutex_lock(&thermal_dbg->lock);
+
+ thermal_debugfs_cdev_clear(&thermal_dbg->cdev_dbg);
+ cdev->debugfs = NULL;
+
+ mutex_unlock(&thermal_dbg->lock);
+
+ thermal_debugfs_remove_id(thermal_dbg);
+}
+
+static struct tz_episode *thermal_debugfs_tz_event_alloc(struct thermal_zone_device *tz,
+ ktime_t now)
+{
+ struct tz_episode *tze;
+ int i;
+
+ tze = kzalloc(struct_size(tze, trip_stats, tz->num_trips), GFP_KERNEL);
+ if (!tze)
+ return NULL;
+
+ INIT_LIST_HEAD(&tze->node);
+ tze->timestamp = now;
+
+ for (i = 0; i < tz->num_trips; i++) {
+ tze->trip_stats[i].min = INT_MAX;
+ tze->trip_stats[i].max = INT_MIN;
+ }
+
+ return tze;
+}
+
+void thermal_debug_tz_trip_up(struct thermal_zone_device *tz,
+ const struct thermal_trip *trip)
+{
+ struct tz_episode *tze;
+ struct tz_debugfs *tz_dbg;
+ struct thermal_debugfs *thermal_dbg = tz->debugfs;
+ int temperature = tz->temperature;
+ int trip_id = thermal_zone_trip_id(tz, trip);
+ ktime_t now = ktime_get();
+
+ if (!thermal_dbg)
+ return;
+
+ mutex_lock(&thermal_dbg->lock);
+
+ tz_dbg = &thermal_dbg->tz_dbg;
+
+ /*
+ * The mitigation is starting. A mitigation can contain
+ * several episodes where each of them is related to a
+ * temperature crossing a trip point. The episodes are
+ * nested. That means when the temperature is crossing the
+ * first trip point, the duration begins to be measured. If
+ * the temperature continues to increase and reaches the
+ * second trip point, the duration of the first trip must be
+ * also accumulated.
+ *
+ * eg.
+ *
+ * temp
+ * ^
+ * | --------
+ * trip 2 / \ ------
+ * | /| |\ /| |\
+ * trip 1 / | | `---- | | \
+ * | /| | | | | |\
+ * trip 0 / | | | | | | \
+ * | /| | | | | | | |\
+ * | / | | | | | | | | `--
+ * | / | | | | | | | |
+ * |----- | | | | | | | |
+ * | | | | | | | | |
+ * --------|-|-|--------|--------|------|-|-|------------------> time
+ * | | |<--t2-->| |<-t2'>| | |
+ * | | | |
+ * | |<------------t1------------>| |
+ * | |
+ * |<-------------t0--------------->|
+ *
+ */
+ if (!tz_dbg->nr_trips) {
+ tze = thermal_debugfs_tz_event_alloc(tz, now);
+ if (!tze)
+ goto unlock;
+
+ list_add(&tze->node, &tz_dbg->tz_episodes);
+ }
+
+ /*
+ * Each time a trip point is crossed the way up, the trip_id
+ * is stored in the trip_crossed array and the nr_trips is
+ * incremented. A nr_trips equal to zero means we are entering
+ * a mitigation episode.
+ *
+ * The trip ids may not be in the ascending order but the
+ * result in the array trips_crossed will be in the ascending
+ * temperature order. The function detecting when a trip point
+ * is crossed the way down will handle the very rare case when
+ * the trip points may have been reordered during this
+ * mitigation episode.
+ */
+ tz_dbg->trips_crossed[tz_dbg->nr_trips++] = trip_id;
+
+ tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node);
+ tze->trip_stats[trip_id].timestamp = now;
+ tze->trip_stats[trip_id].max = max(tze->trip_stats[trip_id].max, temperature);
+ tze->trip_stats[trip_id].min = min(tze->trip_stats[trip_id].min, temperature);
+ tze->trip_stats[trip_id].avg = tze->trip_stats[trip_id].avg +
+ (temperature - tze->trip_stats[trip_id].avg) /
+ tze->trip_stats[trip_id].count;
+
+unlock:
+ mutex_unlock(&thermal_dbg->lock);
+}
+
+void thermal_debug_tz_trip_down(struct thermal_zone_device *tz,
+ const struct thermal_trip *trip)
+{
+ struct thermal_debugfs *thermal_dbg = tz->debugfs;
+ struct tz_episode *tze;
+ struct tz_debugfs *tz_dbg;
+ ktime_t delta, now = ktime_get();
+ int trip_id = thermal_zone_trip_id(tz, trip);
+ int i;
+
+ if (!thermal_dbg)
+ return;
+
+ mutex_lock(&thermal_dbg->lock);
+
+ tz_dbg = &thermal_dbg->tz_dbg;
+
+ /*
+ * The temperature crosses the way down but there was not
+ * mitigation detected before. That may happen when the
+ * temperature is greater than a trip point when registering a
+ * thermal zone, which is a common use case as the kernel has
+ * no mitigation mechanism yet at boot time.
+ */
+ if (!tz_dbg->nr_trips)
+ goto out;
+
+ for (i = tz_dbg->nr_trips - 1; i >= 0; i--) {
+ if (tz_dbg->trips_crossed[i] == trip_id)
+ break;
+ }
+
+ if (i < 0)
+ goto out;
+
+ tz_dbg->nr_trips--;
+
+ if (i < tz_dbg->nr_trips)
+ tz_dbg->trips_crossed[i] = tz_dbg->trips_crossed[tz_dbg->nr_trips];
+
+ tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node);
+
+ delta = ktime_sub(now, tze->trip_stats[trip_id].timestamp);
+
+ tze->trip_stats[trip_id].duration =
+ ktime_add(delta, tze->trip_stats[trip_id].duration);
+
+ /*
+ * This event closes the mitigation as we are crossing the
+ * last trip point the way down.
+ */
+ if (!tz_dbg->nr_trips)
+ tze->duration = ktime_sub(now, tze->timestamp);
+
+out:
+ mutex_unlock(&thermal_dbg->lock);
+}
+
+void thermal_debug_update_temp(struct thermal_zone_device *tz)
+{
+ struct thermal_debugfs *thermal_dbg = tz->debugfs;
+ struct tz_episode *tze;
+ struct tz_debugfs *tz_dbg;
+ int trip_id, i;
+
+ if (!thermal_dbg)
+ return;
+
+ mutex_lock(&thermal_dbg->lock);
+
+ tz_dbg = &thermal_dbg->tz_dbg;
+
+ if (!tz_dbg->nr_trips)
+ goto out;
+
+ for (i = 0; i < tz_dbg->nr_trips; i++) {
+ trip_id = tz_dbg->trips_crossed[i];
+ tze = list_first_entry(&tz_dbg->tz_episodes, struct tz_episode, node);
+ tze->trip_stats[trip_id].count++;
+ tze->trip_stats[trip_id].max = max(tze->trip_stats[trip_id].max, tz->temperature);
+ tze->trip_stats[trip_id].min = min(tze->trip_stats[trip_id].min, tz->temperature);
+ tze->trip_stats[trip_id].avg = tze->trip_stats[trip_id].avg +
+ (tz->temperature - tze->trip_stats[trip_id].avg) /
+ tze->trip_stats[trip_id].count;
+ }
+out:
+ mutex_unlock(&thermal_dbg->lock);
+}
+
+static void *tze_seq_start(struct seq_file *s, loff_t *pos)
+{
+ struct thermal_zone_device *tz = s->private;
+ struct thermal_debugfs *thermal_dbg = tz->debugfs;
+ struct tz_debugfs *tz_dbg = &thermal_dbg->tz_dbg;
+
+ mutex_lock(&thermal_dbg->lock);
+
+ return seq_list_start(&tz_dbg->tz_episodes, *pos);
+}
+
+static void *tze_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ struct thermal_zone_device *tz = s->private;
+ struct thermal_debugfs *thermal_dbg = tz->debugfs;
+ struct tz_debugfs *tz_dbg = &thermal_dbg->tz_dbg;
+
+ return seq_list_next(v, &tz_dbg->tz_episodes, pos);
+}
+
+static void tze_seq_stop(struct seq_file *s, void *v)
+{
+ struct thermal_zone_device *tz = s->private;
+ struct thermal_debugfs *thermal_dbg = tz->debugfs;
+
+ mutex_unlock(&thermal_dbg->lock);
+}
+
+static int tze_seq_show(struct seq_file *s, void *v)
+{
+ struct thermal_zone_device *tz = s->private;
+ struct thermal_trip *trip;
+ struct tz_episode *tze;
+ const char *type;
+ int trip_id;
+
+ tze = list_entry((struct list_head *)v, struct tz_episode, node);
+
+ seq_printf(s, ",-Mitigation at %lluus, duration=%llums\n",
+ ktime_to_us(tze->timestamp),
+ ktime_to_ms(tze->duration));
+
+ seq_printf(s, "| trip | type | temp(°mC) | hyst(°mC) | duration | avg(°mC) | min(°mC) | max(°mC) |\n");
+
+ for_each_trip(tz, trip) {
+ /*
+ * There is no possible mitigation happening at the
+ * critical trip point, so the stats will be always
+ * zero, skip this trip point
+ */
+ if (trip->type == THERMAL_TRIP_CRITICAL)
+ continue;
+
+ if (trip->type == THERMAL_TRIP_PASSIVE)
+ type = "passive";
+ else if (trip->type == THERMAL_TRIP_ACTIVE)
+ type = "active";
+ else
+ type = "hot";
+
+ trip_id = thermal_zone_trip_id(tz, trip);
+
+ seq_printf(s, "| %*d | %*s | %*d | %*d | %*lld | %*d | %*d | %*d |\n",
+ 4 , trip_id,
+ 8, type,
+ 9, trip->temperature,
+ 9, trip->hysteresis,
+ 10, ktime_to_ms(tze->trip_stats[trip_id].duration),
+ 9, tze->trip_stats[trip_id].avg,
+ 9, tze->trip_stats[trip_id].min,
+ 9, tze->trip_stats[trip_id].max);
+ }
+
+ return 0;
+}
+
+static const struct seq_operations tze_sops = {
+ .start = tze_seq_start,
+ .next = tze_seq_next,
+ .stop = tze_seq_stop,
+ .show = tze_seq_show,
+};
+
+DEFINE_SEQ_ATTRIBUTE(tze);
+
+void thermal_debug_tz_add(struct thermal_zone_device *tz)
+{
+ struct thermal_debugfs *thermal_dbg;
+ struct tz_debugfs *tz_dbg;
+
+ thermal_dbg = thermal_debugfs_add_id(d_tz, tz->id);
+ if (!thermal_dbg)
+ return;
+
+ tz_dbg = &thermal_dbg->tz_dbg;
+
+ tz_dbg->trips_crossed = kzalloc(sizeof(int) * tz->num_trips, GFP_KERNEL);
+ if (!tz_dbg->trips_crossed) {
+ thermal_debugfs_remove_id(thermal_dbg);
+ return;
+ }
+
+ INIT_LIST_HEAD(&tz_dbg->tz_episodes);
+
+ debugfs_create_file("mitigations", 0400, thermal_dbg->d_top, tz, &tze_fops);
+
+ tz->debugfs = thermal_dbg;
+}
+
+void thermal_debug_tz_remove(struct thermal_zone_device *tz)
+{
+ struct thermal_debugfs *thermal_dbg = tz->debugfs;
+
+ if (!thermal_dbg)
+ return;
+
+ mutex_lock(&thermal_dbg->lock);
+
+ tz->debugfs = NULL;
+
+ mutex_unlock(&thermal_dbg->lock);
+
+ thermal_debugfs_remove_id(thermal_dbg);
+}
diff --git a/drivers/thermal/thermal_debugfs.h b/drivers/thermal/thermal_debugfs.h
new file mode 100644
index 000000000000..155b9af5fe87
--- /dev/null
+++ b/drivers/thermal/thermal_debugfs.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifdef CONFIG_THERMAL_DEBUGFS
+void thermal_debug_init(void);
+void thermal_debug_cdev_add(struct thermal_cooling_device *cdev);
+void thermal_debug_cdev_remove(struct thermal_cooling_device *cdev);
+void thermal_debug_cdev_state_update(const struct thermal_cooling_device *cdev, int state);
+void thermal_debug_tz_add(struct thermal_zone_device *tz);
+void thermal_debug_tz_remove(struct thermal_zone_device *tz);
+void thermal_debug_tz_trip_up(struct thermal_zone_device *tz,
+ const struct thermal_trip *trip);
+void thermal_debug_tz_trip_down(struct thermal_zone_device *tz,
+ const struct thermal_trip *trip);
+void thermal_debug_update_temp(struct thermal_zone_device *tz);
+#else
+static inline void thermal_debug_init(void) {}
+static inline void thermal_debug_cdev_add(struct thermal_cooling_device *cdev) {}
+static inline void thermal_debug_cdev_remove(struct thermal_cooling_device *cdev) {}
+static inline void thermal_debug_cdev_state_update(const struct thermal_cooling_device *cdev,
+ int state) {}
+static inline void thermal_debug_tz_add(struct thermal_zone_device *tz) {}
+static inline void thermal_debug_tz_remove(struct thermal_zone_device *tz) {}
+static inline void thermal_debug_tz_trip_up(struct thermal_zone_device *tz,
+ const struct thermal_trip *trip) {};
+static inline void thermal_debug_tz_trip_down(struct thermal_zone_device *tz,
+ const struct thermal_trip *trip) {}
+static inline void thermal_debug_update_temp(struct thermal_zone_device *tz) {}
+#endif /* CONFIG_THERMAL_DEBUGFS */
diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c
index c3982e0f0075..0329f4a71b02 100644
--- a/drivers/thermal/thermal_helpers.c
+++ b/drivers/thermal/thermal_helpers.c
@@ -146,14 +146,23 @@ unlock:
}
EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
-static void thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev,
- int target)
+static int thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev, int state)
{
- if (cdev->ops->set_cur_state(cdev, target))
- return;
+ int ret;
+
+ /*
+ * No check is needed for the ops->set_cur_state as the
+ * registering function checked the ops are correctly set
+ */
+ ret = cdev->ops->set_cur_state(cdev, state);
+ if (ret)
+ return ret;
- thermal_notify_cdev_state_update(cdev->id, target);
- thermal_cooling_device_stats_update(cdev, target);
+ thermal_notify_cdev_state_update(cdev, state);
+ thermal_cooling_device_stats_update(cdev, state);
+ thermal_debug_cdev_state_update(cdev, state);
+
+ return 0;
}
void __thermal_cdev_update(struct thermal_cooling_device *cdev)
diff --git a/drivers/thermal/thermal_netlink.c b/drivers/thermal/thermal_netlink.c
index 332052e24a86..76a231a29654 100644
--- a/drivers/thermal/thermal_netlink.c
+++ b/drivers/thermal/thermal_netlink.c
@@ -148,7 +148,7 @@ static int thermal_genl_event_tz_trip_up(struct param *p)
return 0;
}
-static int thermal_genl_event_tz_trip_add(struct param *p)
+static int thermal_genl_event_tz_trip_change(struct param *p)
{
if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id) ||
@@ -160,15 +160,6 @@ static int thermal_genl_event_tz_trip_add(struct param *p)
return 0;
}
-static int thermal_genl_event_tz_trip_delete(struct param *p)
-{
- if (nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_ID, p->tz_id) ||
- nla_put_u32(p->msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, p->trip_id))
- return -EMSGSIZE;
-
- return 0;
-}
-
static int thermal_genl_event_cdev_add(struct param *p)
{
if (nla_put_string(p->msg, THERMAL_GENL_ATTR_CDEV_NAME,
@@ -258,9 +249,6 @@ int thermal_genl_event_tz_disable(struct param *p)
int thermal_genl_event_tz_trip_down(struct param *p)
__attribute__((alias("thermal_genl_event_tz_trip_up")));
-int thermal_genl_event_tz_trip_change(struct param *p)
- __attribute__((alias("thermal_genl_event_tz_trip_add")));
-
static cb_t event_cb[] = {
[THERMAL_GENL_EVENT_TZ_CREATE] = thermal_genl_event_tz_create,
[THERMAL_GENL_EVENT_TZ_DELETE] = thermal_genl_event_tz_delete,
@@ -269,8 +257,6 @@ static cb_t event_cb[] = {
[THERMAL_GENL_EVENT_TZ_TRIP_UP] = thermal_genl_event_tz_trip_up,
[THERMAL_GENL_EVENT_TZ_TRIP_DOWN] = thermal_genl_event_tz_trip_down,
[THERMAL_GENL_EVENT_TZ_TRIP_CHANGE] = thermal_genl_event_tz_trip_change,
- [THERMAL_GENL_EVENT_TZ_TRIP_ADD] = thermal_genl_event_tz_trip_add,
- [THERMAL_GENL_EVENT_TZ_TRIP_DELETE] = thermal_genl_event_tz_trip_delete,
[THERMAL_GENL_EVENT_CDEV_ADD] = thermal_genl_event_cdev_add,
[THERMAL_GENL_EVENT_CDEV_DELETE] = thermal_genl_event_cdev_delete,
[THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update,
@@ -318,100 +304,93 @@ out_free_msg:
return ret;
}
-int thermal_notify_tz_create(int tz_id, const char *name)
+int thermal_notify_tz_create(const struct thermal_zone_device *tz)
{
- struct param p = { .tz_id = tz_id, .name = name };
+ struct param p = { .tz_id = tz->id, .name = tz->type };
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_CREATE, &p);
}
-int thermal_notify_tz_delete(int tz_id)
+int thermal_notify_tz_delete(const struct thermal_zone_device *tz)
{
- struct param p = { .tz_id = tz_id };
+ struct param p = { .tz_id = tz->id };
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DELETE, &p);
}
-int thermal_notify_tz_enable(int tz_id)
+int thermal_notify_tz_enable(const struct thermal_zone_device *tz)
{
- struct param p = { .tz_id = tz_id };
+ struct param p = { .tz_id = tz->id };
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_ENABLE, &p);
}
-int thermal_notify_tz_disable(int tz_id)
+int thermal_notify_tz_disable(const struct thermal_zone_device *tz)
{
- struct param p = { .tz_id = tz_id };
+ struct param p = { .tz_id = tz->id };
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_DISABLE, &p);
}
-int thermal_notify_tz_trip_down(int tz_id, int trip_id, int temp)
+int thermal_notify_tz_trip_down(const struct thermal_zone_device *tz,
+ const struct thermal_trip *trip)
{
- struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp };
+ struct param p = { .tz_id = tz->id,
+ .trip_id = thermal_zone_trip_id(tz, trip),
+ .temp = tz->temperature };
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DOWN, &p);
}
-int thermal_notify_tz_trip_up(int tz_id, int trip_id, int temp)
+int thermal_notify_tz_trip_up(const struct thermal_zone_device *tz,
+ const struct thermal_trip *trip)
{
- struct param p = { .tz_id = tz_id, .trip_id = trip_id, .temp = temp };
+ struct param p = { .tz_id = tz->id,
+ .trip_id = thermal_zone_trip_id(tz, trip),
+ .temp = tz->temperature };
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_UP, &p);
}
-int thermal_notify_tz_trip_add(int tz_id, int trip_id, int trip_type,
- int trip_temp, int trip_hyst)
-{
- struct param p = { .tz_id = tz_id, .trip_id = trip_id,
- .trip_type = trip_type, .trip_temp = trip_temp,
- .trip_hyst = trip_hyst };
-
- return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_ADD, &p);
-}
-
-int thermal_notify_tz_trip_delete(int tz_id, int trip_id)
-{
- struct param p = { .tz_id = tz_id, .trip_id = trip_id };
-
- return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_DELETE, &p);
-}
-
-int thermal_notify_tz_trip_change(int tz_id, int trip_id, int trip_type,
- int trip_temp, int trip_hyst)
+int thermal_notify_tz_trip_change(const struct thermal_zone_device *tz,
+ const struct thermal_trip *trip)
{
- struct param p = { .tz_id = tz_id, .trip_id = trip_id,
- .trip_type = trip_type, .trip_temp = trip_temp,
- .trip_hyst = trip_hyst };
+ struct param p = { .tz_id = tz->id,
+ .trip_id = thermal_zone_trip_id(tz, trip),
+ .trip_type = trip->type,
+ .trip_temp = trip->temperature,
+ .trip_hyst = trip->hysteresis };
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_TRIP_CHANGE, &p);
}
-int thermal_notify_cdev_state_update(int cdev_id, int cdev_state)
+int thermal_notify_cdev_state_update(const struct thermal_cooling_device *cdev,
+ int state)
{
- struct param p = { .cdev_id = cdev_id, .cdev_state = cdev_state };
+ struct param p = { .cdev_id = cdev->id, .cdev_state = state };
return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, &p);
}
-int thermal_notify_cdev_add(int cdev_id, const char *name, int cdev_max_state)
+int thermal_notify_cdev_add(const struct thermal_cooling_device *cdev)
{
- struct param p = { .cdev_id = cdev_id, .name = name,
- .cdev_max_state = cdev_max_state };
+ struct param p = { .cdev_id = cdev->id, .name = cdev->type,
+ .cdev_max_state = cdev->max_state };
return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_ADD, &p);
}
-int thermal_notify_cdev_delete(int cdev_id)
+int thermal_notify_cdev_delete(const struct thermal_cooling_device *cdev)
{
- struct param p = { .cdev_id = cdev_id };
+ struct param p = { .cdev_id = cdev->id };
return thermal_genl_send_event(THERMAL_GENL_EVENT_CDEV_DELETE, &p);
}
-int thermal_notify_tz_gov_change(int tz_id, const char *name)
+int thermal_notify_tz_gov_change(const struct thermal_zone_device *tz,
+ const char *name)
{
- struct param p = { .tz_id = tz_id, .name = name };
+ struct param p = { .tz_id = tz->id, .name = name };
return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p);
}
diff --git a/drivers/thermal/thermal_netlink.h b/drivers/thermal/thermal_netlink.h
index 0a9987c3bc57..93a927e144d5 100644
--- a/drivers/thermal/thermal_netlink.h
+++ b/drivers/thermal/thermal_netlink.h
@@ -10,25 +10,30 @@ struct thermal_genl_cpu_caps {
int efficiency;
};
+struct thermal_zone_device;
+struct thermal_trip;
+struct thermal_cooling_device;
+
/* Netlink notification function */
#ifdef CONFIG_THERMAL_NETLINK
int __init thermal_netlink_init(void);
void __init thermal_netlink_exit(void);
-int thermal_notify_tz_create(int tz_id, const char *name);
-int thermal_notify_tz_delete(int tz_id);
-int thermal_notify_tz_enable(int tz_id);
-int thermal_notify_tz_disable(int tz_id);
-int thermal_notify_tz_trip_down(int tz_id, int id, int temp);
-int thermal_notify_tz_trip_up(int tz_id, int id, int temp);
-int thermal_notify_tz_trip_delete(int tz_id, int id);
-int thermal_notify_tz_trip_add(int tz_id, int id, int type,
- int temp, int hyst);
-int thermal_notify_tz_trip_change(int tz_id, int id, int type,
- int temp, int hyst);
-int thermal_notify_cdev_state_update(int cdev_id, int state);
-int thermal_notify_cdev_add(int cdev_id, const char *name, int max_state);
-int thermal_notify_cdev_delete(int cdev_id);
-int thermal_notify_tz_gov_change(int tz_id, const char *name);
+int thermal_notify_tz_create(const struct thermal_zone_device *tz);
+int thermal_notify_tz_delete(const struct thermal_zone_device *tz);
+int thermal_notify_tz_enable(const struct thermal_zone_device *tz);
+int thermal_notify_tz_disable(const struct thermal_zone_device *tz);
+int thermal_notify_tz_trip_down(const struct thermal_zone_device *tz,
+ const struct thermal_trip *trip);
+int thermal_notify_tz_trip_up(const struct thermal_zone_device *tz,
+ const struct thermal_trip *trip);
+int thermal_notify_tz_trip_change(const struct thermal_zone_device *tz,
+ const struct thermal_trip *trip);
+int thermal_notify_cdev_state_update(const struct thermal_cooling_device *cdev,
+ int state);
+int thermal_notify_cdev_add(const struct thermal_cooling_device *cdev);
+int thermal_notify_cdev_delete(const struct thermal_cooling_device *cdev);
+int thermal_notify_tz_gov_change(const struct thermal_zone_device *tz,
+ const char *name);
int thermal_genl_sampling_temp(int id, int temp);
int thermal_genl_cpu_capability_event(int count,
struct thermal_genl_cpu_caps *caps);
@@ -38,70 +43,62 @@ static inline int thermal_netlink_init(void)
return 0;
}
-static inline int thermal_notify_tz_create(int tz_id, const char *name)
-{
- return 0;
-}
-
-static inline int thermal_notify_tz_delete(int tz_id)
-{
- return 0;
-}
-
-static inline int thermal_notify_tz_enable(int tz_id)
+static inline int thermal_notify_tz_create(const struct thermal_zone_device *tz)
{
return 0;
}
-static inline int thermal_notify_tz_disable(int tz_id)
+static inline int thermal_notify_tz_delete(const struct thermal_zone_device *tz)
{
return 0;
}
-static inline int thermal_notify_tz_trip_down(int tz_id, int id, int temp)
+static inline int thermal_notify_tz_enable(const struct thermal_zone_device *tz)
{
return 0;
}
-static inline int thermal_notify_tz_trip_up(int tz_id, int id, int temp)
+static inline int thermal_notify_tz_disable(const struct thermal_zone_device *tz)
{
return 0;
}
-static inline int thermal_notify_tz_trip_delete(int tz_id, int id)
+static inline int thermal_notify_tz_trip_down(const struct thermal_zone_device *tz,
+ const struct thermal_trip *trip)
{
return 0;
}
-static inline int thermal_notify_tz_trip_add(int tz_id, int id, int type,
- int temp, int hyst)
+static inline int thermal_notify_tz_trip_up(const struct thermal_zone_device *tz,
+ const struct thermal_trip *trip)
{
return 0;
}
-static inline int thermal_notify_tz_trip_change(int tz_id, int id, int type,
- int temp, int hyst)
+static inline int thermal_notify_tz_trip_change(const struct thermal_zone_device *tz,
+ const struct thermal_trip *trip)
{
return 0;
}
-static inline int thermal_notify_cdev_state_update(int cdev_id, int state)
+static inline int thermal_notify_cdev_state_update(const struct thermal_cooling_device *cdev,
+ int state)
{
return 0;
}
-static inline int thermal_notify_cdev_add(int cdev_id, const char *name,
- int max_state)
+static inline int thermal_notify_cdev_add(const struct thermal_cooling_device *cdev)
{
return 0;
}
-static inline int thermal_notify_cdev_delete(int cdev_id)
+static inline int thermal_notify_cdev_delete(const struct thermal_cooling_device *cdev)
{
return 0;
}
-static inline int thermal_notify_tz_gov_change(int tz_id, const char *name)
+static inline int thermal_notify_tz_gov_change(const struct thermal_zone_device *tz,
+ const char *name)
{
return 0;
}
diff --git a/drivers/thermal/thermal_trip.c b/drivers/thermal/thermal_trip.c
index 8bffa1e5e206..c875a26d5adf 100644
--- a/drivers/thermal/thermal_trip.c
+++ b/drivers/thermal/thermal_trip.c
@@ -155,9 +155,7 @@ int thermal_zone_trip_id(const struct thermal_zone_device *tz,
void thermal_zone_trip_updated(struct thermal_zone_device *tz,
const struct thermal_trip *trip)
{
- thermal_notify_tz_trip_change(tz->id, thermal_zone_trip_id(tz, trip),
- trip->type, trip->temperature,
- trip->hysteresis);
+ thermal_notify_tz_trip_change(tz, trip);
__thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED);
}
@@ -168,8 +166,6 @@ void thermal_zone_set_trip_temp(struct thermal_zone_device *tz,
return;
trip->temperature = temp;
- thermal_notify_tz_trip_change(tz->id, thermal_zone_trip_id(tz, trip),
- trip->type, trip->temperature,
- trip->hysteresis);
+ thermal_notify_tz_trip_change(tz, trip);
}
EXPORT_SYMBOL_GPL(thermal_zone_set_trip_temp);
diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
index ec7b5f65804e..9fb1a64f3300 100644
--- a/drivers/thunderbolt/domain.c
+++ b/drivers/thunderbolt/domain.c
@@ -307,7 +307,7 @@ static const struct attribute_group *domain_attr_groups[] = {
NULL,
};
-struct bus_type tb_bus_type = {
+const struct bus_type tb_bus_type = {
.name = "thunderbolt",
.match = tb_service_match,
.probe = tb_service_probe,
diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c
index d8b9c734abd3..56790d50f9e3 100644
--- a/drivers/thunderbolt/icm.c
+++ b/drivers/thunderbolt/icm.c
@@ -1020,7 +1020,7 @@ icm_tr_driver_ready(struct tb *tb, enum tb_security_level *security_level,
memset(&reply, 0, sizeof(reply));
ret = icm_request(tb, &request, sizeof(request), &reply, sizeof(reply),
- 1, 10, 2000);
+ 1, 10, 250);
if (ret)
return ret;
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index 4b7bec74e89f..fb4f46e51753 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -1517,6 +1517,10 @@ static struct pci_device_id nhi_ids[] = {
.driver_data = (kernel_ulong_t)&icl_nhi_ops },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL_P_NHI1),
.driver_data = (kernel_ulong_t)&icl_nhi_ops },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_LNL_NHI0),
+ .driver_data = (kernel_ulong_t)&icl_nhi_ops },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_LNL_NHI1),
+ .driver_data = (kernel_ulong_t)&icl_nhi_ops },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_80G_NHI) },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HOST_40G_NHI) },
diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h
index 0f029ce75882..7a07c7c1a9c2 100644
--- a/drivers/thunderbolt/nhi.h
+++ b/drivers/thunderbolt/nhi.h
@@ -90,6 +90,8 @@ extern const struct tb_nhi_ops icl_nhi_ops;
#define PCI_DEVICE_ID_INTEL_TGL_H_NHI1 0x9a21
#define PCI_DEVICE_ID_INTEL_RPL_NHI0 0xa73e
#define PCI_DEVICE_ID_INTEL_RPL_NHI1 0xa76d
+#define PCI_DEVICE_ID_INTEL_LNL_NHI0 0xa833
+#define PCI_DEVICE_ID_INTEL_LNL_NHI1 0xa834
#define PCI_CLASS_SERIAL_USB_USB4 0x0c0340
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index 44e9b09de47a..900114ba4371 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -941,22 +941,6 @@ int tb_port_get_link_generation(struct tb_port *port)
}
}
-static const char *width_name(enum tb_link_width width)
-{
- switch (width) {
- case TB_LINK_WIDTH_SINGLE:
- return "symmetric, single lane";
- case TB_LINK_WIDTH_DUAL:
- return "symmetric, dual lanes";
- case TB_LINK_WIDTH_ASYM_TX:
- return "asymmetric, 3 transmitters, 1 receiver";
- case TB_LINK_WIDTH_ASYM_RX:
- return "asymmetric, 3 receivers, 1 transmitter";
- default:
- return "unknown";
- }
-}
-
/**
* tb_port_get_link_width() - Get current link width
* @port: Port to check (USB4 or CIO)
@@ -2769,7 +2753,7 @@ static void tb_switch_link_init(struct tb_switch *sw)
return;
tb_sw_dbg(sw, "current link speed %u.0 Gb/s\n", sw->link_speed);
- tb_sw_dbg(sw, "current link width %s\n", width_name(sw->link_width));
+ tb_sw_dbg(sw, "current link width %s\n", tb_width_name(sw->link_width));
bonded = sw->link_width >= TB_LINK_WIDTH_DUAL;
@@ -2789,6 +2773,19 @@ static void tb_switch_link_init(struct tb_switch *sw)
if (down->dual_link_port)
down->dual_link_port->bonded = bonded;
tb_port_update_credits(down);
+
+ if (tb_port_get_link_generation(up) < 4)
+ return;
+
+ /*
+ * Set the Gen 4 preferred link width. This is what the router
+ * prefers when the link is brought up. If the router does not
+ * support asymmetric link configuration, this also will be set
+ * to TB_LINK_WIDTH_DUAL.
+ */
+ sw->preferred_link_width = sw->link_width;
+ tb_sw_dbg(sw, "preferred link width %s\n",
+ tb_width_name(sw->preferred_link_width));
}
/**
@@ -3029,7 +3026,7 @@ int tb_switch_set_link_width(struct tb_switch *sw, enum tb_link_width width)
tb_switch_update_link_attributes(sw);
- tb_sw_dbg(sw, "link width set to %s\n", width_name(width));
+ tb_sw_dbg(sw, "link width set to %s\n", tb_width_name(width));
return ret;
}
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index fd49f86e0353..846d2813bb1a 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -513,8 +513,6 @@ static void tb_port_unconfigure_xdomain(struct tb_port *port)
usb4_port_unconfigure_xdomain(port);
else
tb_lc_unconfigure_xdomain(port);
-
- tb_port_enable(port->dual_link_port);
}
static void tb_scan_xdomain(struct tb_port *port)
@@ -1087,15 +1085,14 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
struct tb_port *dst_port, int requested_up,
int requested_down)
{
+ bool clx = false, clx_disabled = false, downstream;
struct tb_switch *sw;
- bool clx, downstream;
struct tb_port *up;
int ret = 0;
if (!asym_threshold)
return 0;
- /* Disable CL states before doing any transitions */
downstream = tb_port_path_direction_downstream(src_port, dst_port);
/* Pick up router deepest in the hierarchy */
if (downstream)
@@ -1103,11 +1100,10 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
else
sw = src_port->sw;
- clx = tb_disable_clx(sw);
-
tb_for_each_upstream_port_on_path(src_port, dst_port, up) {
+ struct tb_port *down = tb_switch_downstream_port(up->sw);
+ enum tb_link_width width_up, width_down;
int consumed_up, consumed_down;
- enum tb_link_width width;
ret = tb_consumed_dp_bandwidth(tb, src_port, dst_port, up,
&consumed_up, &consumed_down);
@@ -1128,7 +1124,8 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
if (consumed_down + requested_down < asym_threshold)
continue;
- width = TB_LINK_WIDTH_ASYM_RX;
+ width_up = TB_LINK_WIDTH_ASYM_RX;
+ width_down = TB_LINK_WIDTH_ASYM_TX;
} else {
/* Upstream, the opposite of above */
if (consumed_down + requested_down >= TB_ASYM_MIN) {
@@ -1138,22 +1135,34 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
if (consumed_up + requested_up < asym_threshold)
continue;
- width = TB_LINK_WIDTH_ASYM_TX;
+ width_up = TB_LINK_WIDTH_ASYM_TX;
+ width_down = TB_LINK_WIDTH_ASYM_RX;
}
- if (up->sw->link_width == width)
+ if (up->sw->link_width == width_up)
continue;
- if (!tb_port_width_supported(up, width))
+ if (!tb_port_width_supported(up, width_up) ||
+ !tb_port_width_supported(down, width_down))
continue;
+ /*
+ * Disable CL states before doing any transitions. We
+ * delayed it until now that we know there is a real
+ * transition taking place.
+ */
+ if (!clx_disabled) {
+ clx = tb_disable_clx(sw);
+ clx_disabled = true;
+ }
+
tb_sw_dbg(up->sw, "configuring asymmetric link\n");
/*
* Here requested + consumed > threshold so we need to
* transtion the link into asymmetric now.
*/
- ret = tb_switch_set_link_width(up->sw, width);
+ ret = tb_switch_set_link_width(up->sw, width_up);
if (ret) {
tb_sw_warn(up->sw, "failed to set link width\n");
break;
@@ -1174,24 +1183,24 @@ static int tb_configure_asym(struct tb *tb, struct tb_port *src_port,
* @dst_port: Destination adapter
* @requested_up: New lower bandwidth request upstream (Mb/s)
* @requested_down: New lower bandwidth request downstream (Mb/s)
+ * @keep_asym: Keep asymmetric link if preferred
*
* Goes over each link from @src_port to @dst_port and tries to
* transition the link to symmetric if the currently consumed bandwidth
- * allows.
+ * allows and link asymmetric preference is ignored (if @keep_asym is %false).
*/
static int tb_configure_sym(struct tb *tb, struct tb_port *src_port,
struct tb_port *dst_port, int requested_up,
- int requested_down)
+ int requested_down, bool keep_asym)
{
+ bool clx = false, clx_disabled = false, downstream;
struct tb_switch *sw;
- bool clx, downstream;
struct tb_port *up;
int ret = 0;
if (!asym_threshold)
return 0;
- /* Disable CL states before doing any transitions */
downstream = tb_port_path_direction_downstream(src_port, dst_port);
/* Pick up router deepest in the hierarchy */
if (downstream)
@@ -1199,8 +1208,6 @@ static int tb_configure_sym(struct tb *tb, struct tb_port *src_port,
else
sw = src_port->sw;
- clx = tb_disable_clx(sw);
-
tb_for_each_upstream_port_on_path(src_port, dst_port, up) {
int consumed_up, consumed_down;
@@ -1233,6 +1240,25 @@ static int tb_configure_sym(struct tb *tb, struct tb_port *src_port,
if (up->sw->link_width == TB_LINK_WIDTH_DUAL)
continue;
+ /*
+ * Here consumed < threshold so we can transition the
+ * link to symmetric.
+ *
+ * However, if the router prefers asymmetric link we
+ * honor that (unless @keep_asym is %false).
+ */
+ if (keep_asym &&
+ up->sw->preferred_link_width > TB_LINK_WIDTH_DUAL) {
+ tb_sw_dbg(up->sw, "keeping preferred asymmetric link\n");
+ continue;
+ }
+
+ /* Disable CL states before doing any transitions */
+ if (!clx_disabled) {
+ clx = tb_disable_clx(sw);
+ clx_disabled = true;
+ }
+
tb_sw_dbg(up->sw, "configuring symmetric link\n");
ret = tb_switch_set_link_width(up->sw, TB_LINK_WIDTH_DUAL);
@@ -1280,7 +1306,7 @@ static void tb_configure_link(struct tb_port *down, struct tb_port *up,
struct tb_port *host_port;
host_port = tb_port_at(tb_route(sw), tb->root_switch);
- tb_configure_sym(tb, host_port, up, 0, 0);
+ tb_configure_sym(tb, host_port, up, 0, 0, false);
}
/* Set the link configured */
@@ -1465,7 +1491,7 @@ static void tb_deactivate_and_free_tunnel(struct tb_tunnel *tunnel)
* If bandwidth on a link is < asym_threshold
* transition the link to symmetric.
*/
- tb_configure_sym(tb, src_port, dst_port, 0, 0);
+ tb_configure_sym(tb, src_port, dst_port, 0, 0, true);
/* Now we can allow the domain to runtime suspend again */
pm_runtime_mark_last_busy(&dst_port->sw->dev);
pm_runtime_put_autosuspend(&dst_port->sw->dev);
@@ -1901,7 +1927,7 @@ static void tb_dp_resource_available(struct tb *tb, struct tb_port *port)
return;
}
- tb_port_dbg(port, "DP %s resource available\n",
+ tb_port_dbg(port, "DP %s resource available after hotplug\n",
tb_port_is_dpin(port) ? "IN" : "OUT");
list_add_tail(&port->list, &tcm->dp_resources);
@@ -2287,7 +2313,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
* If bandwidth on a link is < asym_threshold transition
* the link to symmetric.
*/
- tb_configure_sym(tb, in, out, *requested_up, *requested_down);
+ tb_configure_sym(tb, in, out, *requested_up, *requested_down, true);
/*
* If requested bandwidth is less or equal than what is
* currently allocated to that tunnel we simply change
@@ -2330,7 +2356,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
ret = tb_configure_asym(tb, in, out, *requested_up,
*requested_down);
if (ret) {
- tb_configure_sym(tb, in, out, 0, 0);
+ tb_configure_sym(tb, in, out, 0, 0, true);
return ret;
}
@@ -2338,7 +2364,7 @@ static int tb_alloc_dp_bandwidth(struct tb_tunnel *tunnel, int *requested_up,
requested_down);
if (ret) {
tb_tunnel_warn(tunnel, "failed to allocate bandwidth\n");
- tb_configure_sym(tb, in, out, 0, 0);
+ tb_configure_sym(tb, in, out, 0, 0, true);
}
} else {
ret = -ENOBUFS;
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index e299e53473ae..997c5a536905 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -125,6 +125,7 @@ struct tb_switch_tmu {
* @device_name: Name of the device (or %NULL if not known)
* @link_speed: Speed of the link in Gb/s
* @link_width: Width of the upstream facing link
+ * @preferred_link_width: Router preferred link width (only set for Gen 4 links)
* @link_usb4: Upstream link is USB4
* @generation: Switch Thunderbolt generation
* @cap_plug_events: Offset to the plug events capability (%0 if not found)
@@ -178,6 +179,7 @@ struct tb_switch {
const char *device_name;
unsigned int link_speed;
enum tb_link_width link_width;
+ enum tb_link_width preferred_link_width;
bool link_usb4;
unsigned int generation;
int cap_plug_events;
@@ -568,6 +570,22 @@ static inline struct tb_port *tb_port_at(u64 route, struct tb_switch *sw)
return &sw->ports[port];
}
+static inline const char *tb_width_name(enum tb_link_width width)
+{
+ switch (width) {
+ case TB_LINK_WIDTH_SINGLE:
+ return "symmetric, single lane";
+ case TB_LINK_WIDTH_DUAL:
+ return "symmetric, dual lanes";
+ case TB_LINK_WIDTH_ASYM_TX:
+ return "asymmetric, 3 transmitters, 1 receiver";
+ case TB_LINK_WIDTH_ASYM_RX:
+ return "asymmetric, 3 receivers, 1 transmitter";
+ default:
+ return "unknown";
+ }
+}
+
/**
* tb_port_has_remote() - Does the port have switch connected downstream
* @port: Port to check
diff --git a/drivers/thunderbolt/tmu.c b/drivers/thunderbolt/tmu.c
index 11f2aec2a5d3..9a259c72e5a7 100644
--- a/drivers/thunderbolt/tmu.c
+++ b/drivers/thunderbolt/tmu.c
@@ -894,7 +894,7 @@ static int tb_switch_tmu_change_mode(struct tb_switch *sw)
ret = tb_switch_set_tmu_mode_params(sw, sw->tmu.mode_request);
if (ret)
- return ret;
+ goto out;
/* Program the new mode and the downstream router lane adapter */
switch (sw->tmu.mode_request) {
diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c
index 7534cd3a81f4..6fffb2c82d3d 100644
--- a/drivers/thunderbolt/tunnel.c
+++ b/drivers/thunderbolt/tunnel.c
@@ -173,16 +173,28 @@ static int tb_pci_set_ext_encapsulation(struct tb_tunnel *tunnel, bool enable)
int ret;
/* Only supported of both routers are at least USB4 v2 */
- if (tb_port_get_link_generation(port) < 4)
+ if ((usb4_switch_version(tunnel->src_port->sw) < 2) ||
+ (usb4_switch_version(tunnel->dst_port->sw) < 2))
+ return 0;
+
+ if (enable && tb_port_get_link_generation(port) < 4)
return 0;
ret = usb4_pci_port_set_ext_encapsulation(tunnel->src_port, enable);
if (ret)
return ret;
+ /*
+ * Downstream router could be unplugged so disable of encapsulation
+ * in upstream router is still possible.
+ */
ret = usb4_pci_port_set_ext_encapsulation(tunnel->dst_port, enable);
- if (ret)
- return ret;
+ if (ret) {
+ if (enable)
+ return ret;
+ if (ret != -ENODEV)
+ return ret;
+ }
tb_tunnel_dbg(tunnel, "extended encapsulation %s\n",
str_enabled_disabled(enable));
@@ -199,14 +211,21 @@ static int tb_pci_activate(struct tb_tunnel *tunnel, bool activate)
return res;
}
- res = tb_pci_port_enable(tunnel->src_port, activate);
+ if (activate)
+ res = tb_pci_port_enable(tunnel->dst_port, activate);
+ else
+ res = tb_pci_port_enable(tunnel->src_port, activate);
if (res)
return res;
- if (tb_port_is_pcie_up(tunnel->dst_port)) {
- res = tb_pci_port_enable(tunnel->dst_port, activate);
+
+ if (activate) {
+ res = tb_pci_port_enable(tunnel->src_port, activate);
if (res)
return res;
+ } else {
+ /* Downstream router could be unplugged */
+ tb_pci_port_enable(tunnel->dst_port, activate);
}
return activate ? 0 : tb_pci_set_ext_encapsulation(tunnel, activate);
@@ -1067,8 +1086,7 @@ static int tb_dp_alloc_bandwidth(struct tb_tunnel *tunnel, int *alloc_up,
return 0;
}
-static int tb_dp_read_dprx(struct tb_tunnel *tunnel, u32 *rate, u32 *lanes,
- int timeout_msec)
+static int tb_dp_wait_dprx(struct tb_tunnel *tunnel, int timeout_msec)
{
ktime_t timeout = ktime_add_ms(ktime_get(), timeout_msec);
struct tb_port *in = tunnel->src_port;
@@ -1087,15 +1105,13 @@ static int tb_dp_read_dprx(struct tb_tunnel *tunnel, u32 *rate, u32 *lanes,
return ret;
if (val & DP_COMMON_CAP_DPRX_DONE) {
- *rate = tb_dp_cap_get_rate(val);
- *lanes = tb_dp_cap_get_lanes(val);
-
tb_tunnel_dbg(tunnel, "DPRX read done\n");
return 0;
}
usleep_range(100, 150);
} while (ktime_before(ktime_get(), timeout));
+ tb_tunnel_dbg(tunnel, "DPRX read timeout\n");
return -ETIMEDOUT;
}
@@ -1110,6 +1126,7 @@ static int tb_dp_read_cap(struct tb_tunnel *tunnel, unsigned int cap, u32 *rate,
switch (cap) {
case DP_LOCAL_CAP:
case DP_REMOTE_CAP:
+ case DP_COMMON_CAP:
break;
default:
@@ -1182,7 +1199,7 @@ static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up,
* reduced one). Otherwise return the remote (possibly
* reduced) caps.
*/
- ret = tb_dp_read_dprx(tunnel, &rate, &lanes, 150);
+ ret = tb_dp_wait_dprx(tunnel, 150);
if (ret) {
if (ret == -ETIMEDOUT)
ret = tb_dp_read_cap(tunnel, DP_REMOTE_CAP,
@@ -1190,6 +1207,9 @@ static int tb_dp_consumed_bandwidth(struct tb_tunnel *tunnel, int *consumed_up,
if (ret)
return ret;
}
+ ret = tb_dp_read_cap(tunnel, DP_COMMON_CAP, &rate, &lanes);
+ if (ret)
+ return ret;
} else if (sw->generation >= 2) {
ret = tb_dp_read_cap(tunnel, DP_REMOTE_CAP, &rate, &lanes);
if (ret)
@@ -1313,8 +1333,6 @@ static void tb_dp_dump(struct tb_tunnel *tunnel)
"DP IN maximum supported bandwidth %u Mb/s x%u = %u Mb/s\n",
rate, lanes, tb_dp_bandwidth(rate, lanes));
- out = tunnel->dst_port;
-
if (tb_port_read(out, &dp_cap, TB_CFG_PORT,
out->cap_adap + DP_LOCAL_CAP, 1))
return;
diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
index 9803f0bbf20d..9495742913d5 100644
--- a/drivers/thunderbolt/xdomain.c
+++ b/drivers/thunderbolt/xdomain.c
@@ -1462,6 +1462,11 @@ static int tb_xdomain_get_properties(struct tb_xdomain *xd)
tb_port_disable(port->dual_link_port);
}
+ dev_dbg(&xd->dev, "current link speed %u.0 Gb/s\n",
+ xd->link_speed);
+ dev_dbg(&xd->dev, "current link width %s\n",
+ tb_width_name(xd->link_width));
+
if (device_add(&xd->dev)) {
dev_err(&xd->dev, "failed to add XDomain device\n");
return -ENODEV;
@@ -1895,6 +1900,50 @@ struct device_type tb_xdomain_type = {
};
EXPORT_SYMBOL_GPL(tb_xdomain_type);
+static void tb_xdomain_link_init(struct tb_xdomain *xd, struct tb_port *down)
+{
+ if (!down->dual_link_port)
+ return;
+
+ /*
+ * Gen 4 links come up already as bonded so only update the port
+ * structures here.
+ */
+ if (tb_port_get_link_generation(down) >= 4) {
+ down->bonded = true;
+ down->dual_link_port->bonded = true;
+ } else {
+ xd->bonding_possible = true;
+ }
+}
+
+static void tb_xdomain_link_exit(struct tb_xdomain *xd)
+{
+ struct tb_port *down = tb_xdomain_downstream_port(xd);
+
+ if (!down->dual_link_port)
+ return;
+
+ if (tb_port_get_link_generation(down) >= 4) {
+ down->bonded = false;
+ down->dual_link_port->bonded = false;
+ } else if (xd->link_width > TB_LINK_WIDTH_SINGLE) {
+ /*
+ * Just return port structures back to way they were and
+ * update credits. No need to update userspace because
+ * the XDomain is removed soon anyway.
+ */
+ tb_port_lane_bonding_disable(down);
+ tb_port_update_credits(down);
+ } else if (down->dual_link_port) {
+ /*
+ * Re-enable the lane 1 adapter we disabled at the end
+ * of tb_xdomain_get_properties().
+ */
+ tb_port_enable(down->dual_link_port);
+ }
+}
+
/**
* tb_xdomain_alloc() - Allocate new XDomain object
* @tb: Domain where the XDomain belongs
@@ -1945,7 +1994,8 @@ struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent,
goto err_free_local_uuid;
} else {
xd->needs_uuid = true;
- xd->bonding_possible = !!down->dual_link_port;
+
+ tb_xdomain_link_init(xd, down);
}
device_initialize(&xd->dev);
@@ -2014,6 +2064,8 @@ void tb_xdomain_remove(struct tb_xdomain *xd)
device_for_each_child_reverse(&xd->dev, xd, unregister_service);
+ tb_xdomain_link_exit(xd);
+
/*
* Undo runtime PM here explicitly because it is possible that
* the XDomain was never added to the bus and thus device_del()
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 785558c65ae8..7716ce0d35bc 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -81,7 +81,7 @@ struct serial_state {
int quot;
int IER; /* Interrupt Enable Register */
int MCR; /* Modem control register */
- int x_char; /* xon/xoff character */
+ u8 x_char; /* xon/xoff character */
};
static struct tty_driver *serial_driver;
@@ -178,9 +178,9 @@ static void receive_chars(struct serial_state *info)
{
int status;
int serdatr;
- unsigned char ch, flag;
+ u8 ch, flag;
struct async_icount *icount;
- int oe = 0;
+ bool overrun = false;
icount = &info->icount;
@@ -230,7 +230,7 @@ static void receive_chars(struct serial_state *info)
* should be ignored.
*/
if (status & info->ignore_status_mask)
- goto out;
+ return;
status &= info->read_status_mask;
@@ -251,15 +251,13 @@ static void receive_chars(struct serial_state *info)
* reported immediately, and doesn't
* affect the current character
*/
- oe = 1;
+ overrun = true;
}
}
tty_insert_flip_char(&info->tport, ch, flag);
- if (oe == 1)
+ if (overrun)
tty_insert_flip_char(&info->tport, 0, TTY_OVERRUN);
tty_flip_buffer_push(&info->tport);
-out:
- return;
}
static void transmit_chars(struct serial_state *info)
@@ -813,7 +811,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
* This function is used to send a high-priority XON/XOFF character to
* the device
*/
-static void rs_send_xchar(struct tty_struct *tty, char ch)
+static void rs_send_xchar(struct tty_struct *tty, u8 ch)
{
struct serial_state *info = tty->driver_data;
unsigned long flags;
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index a067628e01c8..69508d7a4135 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -49,7 +49,7 @@ struct ehv_bc_data {
unsigned int tx_irq;
spinlock_t lock; /* lock for transmit buffer */
- unsigned char buf[BUF_SIZE]; /* transmit circular buffer */
+ u8 buf[BUF_SIZE]; /* transmit circular buffer */
unsigned int head; /* circular buffer head */
unsigned int tail; /* circular buffer tail */
@@ -138,14 +138,17 @@ static int find_console_handle(void)
static unsigned int local_ev_byte_channel_send(unsigned int handle,
unsigned int *count,
- const char *p)
+ const u8 *p)
{
- char buffer[EV_BYTE_CHANNEL_MAX_BYTES];
+ u8 buffer[EV_BYTE_CHANNEL_MAX_BYTES];
unsigned int c = *count;
+ /*
+ * ev_byte_channel_send() expects at least EV_BYTE_CHANNEL_MAX_BYTES
+ * (16 B) in the buffer. Fake it using a local buffer if needed.
+ */
if (c < sizeof(buffer)) {
- memcpy(buffer, p, c);
- memset(&buffer[c], 0, sizeof(buffer) - c);
+ memcpy_and_pad(buffer, sizeof(buffer), p, c, 0);
p = buffer;
}
return ev_byte_channel_send(handle, count, p);
@@ -163,7 +166,7 @@ static unsigned int local_ev_byte_channel_send(unsigned int handle,
* has been sent, or if some error has occurred.
*
*/
-static void byte_channel_spin_send(const char data)
+static void byte_channel_spin_send(const u8 data)
{
int ret, count;
@@ -471,8 +474,7 @@ static ssize_t ehv_bc_tty_write(struct tty_struct *ttys, const u8 *s,
{
struct ehv_bc_data *bc = ttys->driver_data;
unsigned long flags;
- unsigned int len;
- unsigned int written = 0;
+ size_t len, written = 0;
while (1) {
spin_lock_irqsave(&bc->lock, flags);
diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c
index 4591f940b7a1..d27979eabfdf 100644
--- a/drivers/tty/goldfish.c
+++ b/drivers/tty/goldfish.c
@@ -50,10 +50,8 @@ static u32 goldfish_tty_line_count = 8;
static u32 goldfish_tty_current_line_count;
static struct goldfish_tty *goldfish_ttys;
-static void do_rw_io(struct goldfish_tty *qtty,
- unsigned long address,
- unsigned int count,
- int is_write)
+static void do_rw_io(struct goldfish_tty *qtty, unsigned long address,
+ size_t count, bool is_write)
{
unsigned long irq_flags;
void __iomem *base = qtty->base;
@@ -73,10 +71,8 @@ static void do_rw_io(struct goldfish_tty *qtty,
spin_unlock_irqrestore(&qtty->lock, irq_flags);
}
-static void goldfish_tty_rw(struct goldfish_tty *qtty,
- unsigned long addr,
- unsigned int count,
- int is_write)
+static void goldfish_tty_rw(struct goldfish_tty *qtty, unsigned long addr,
+ size_t count, bool is_write)
{
dma_addr_t dma_handle;
enum dma_data_direction dma_dir;
@@ -125,20 +121,18 @@ static void goldfish_tty_rw(struct goldfish_tty *qtty,
}
}
-static void goldfish_tty_do_write(int line, const u8 *buf, unsigned int count)
+static void goldfish_tty_do_write(int line, const u8 *buf, size_t count)
{
struct goldfish_tty *qtty = &goldfish_ttys[line];
- unsigned long address = (unsigned long)(void *)buf;
- goldfish_tty_rw(qtty, address, count, 1);
+ goldfish_tty_rw(qtty, (unsigned long)buf, count, true);
}
static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
{
struct goldfish_tty *qtty = dev_id;
void __iomem *base = qtty->base;
- unsigned long address;
- unsigned char *buf;
+ u8 *buf;
u32 count;
count = gf_ioread32(base + GOLDFISH_TTY_REG_BYTES_READY);
@@ -147,8 +141,7 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
count = tty_prepare_flip_string(&qtty->port, &buf, count);
- address = (unsigned long)(void *)buf;
- goldfish_tty_rw(qtty, address, count, 0);
+ goldfish_tty_rw(qtty, (unsigned long)buf, count, false);
tty_flip_buffer_push(&qtty->port);
return IRQ_HANDLED;
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 959fae54ca39..cd1f657f782d 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -922,8 +922,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
return ERR_PTR(err);
}
- hp = kzalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size,
- GFP_KERNEL);
+ hp = kzalloc(struct_size(hp, outbuf, outbuf_size), GFP_KERNEL);
if (!hp)
return ERR_PTR(-ENOMEM);
@@ -931,7 +930,6 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
hp->data = data;
hp->ops = ops;
hp->outbuf_size = outbuf_size;
- hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
tty_port_init(&hp->port);
hp->port.ops = &hvc_port_ops;
@@ -976,7 +974,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
}
EXPORT_SYMBOL_GPL(hvc_alloc);
-int hvc_remove(struct hvc_struct *hp)
+void hvc_remove(struct hvc_struct *hp)
{
unsigned long flags;
struct tty_struct *tty;
@@ -1010,7 +1008,6 @@ int hvc_remove(struct hvc_struct *hp)
tty_vhangup(tty);
tty_kref_put(tty);
}
- return 0;
}
EXPORT_SYMBOL_GPL(hvc_remove);
diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h
index 9668f821db01..cf4c1af08a7c 100644
--- a/drivers/tty/hvc/hvc_console.h
+++ b/drivers/tty/hvc/hvc_console.h
@@ -37,7 +37,6 @@ struct hvc_struct {
spinlock_t lock;
int index;
int do_wakeup;
- char *outbuf;
int outbuf_size;
int n_outbuf;
uint32_t vtermno;
@@ -48,12 +47,13 @@ struct hvc_struct {
struct work_struct tty_resize;
struct list_head next;
unsigned long flags;
+ u8 outbuf[] __aligned(sizeof(long));
};
/* implemented by a low level driver */
struct hv_ops {
- int (*get_chars)(uint32_t vtermno, char *buf, int count);
- int (*put_chars)(uint32_t vtermno, const char *buf, int count);
+ ssize_t (*get_chars)(uint32_t vtermno, u8 *buf, size_t count);
+ ssize_t (*put_chars)(uint32_t vtermno, const u8 *buf, size_t count);
int (*flush)(uint32_t vtermno, bool wait);
/* Callbacks for notification. Called in open, close and hangup */
@@ -77,7 +77,7 @@ extern int hvc_instantiate(uint32_t vtermno, int index,
extern struct hvc_struct * hvc_alloc(uint32_t vtermno, int data,
const struct hv_ops *ops, int outbuf_size);
/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */
-extern int hvc_remove(struct hvc_struct *hp);
+extern void hvc_remove(struct hvc_struct *hp);
/* data available */
int hvc_poll(struct hvc_struct *hp);
diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c
index 1751108cf763..dfc5c9c38f07 100644
--- a/drivers/tty/hvc/hvc_dcc.c
+++ b/drivers/tty/hvc/hvc_dcc.c
@@ -26,10 +26,10 @@
/* Lock to serialize access to DCC fifo */
static DEFINE_SPINLOCK(dcc_lock);
-static DEFINE_KFIFO(inbuf, unsigned char, DCC_INBUF_SIZE);
-static DEFINE_KFIFO(outbuf, unsigned char, DCC_OUTBUF_SIZE);
+static DEFINE_KFIFO(inbuf, u8, DCC_INBUF_SIZE);
+static DEFINE_KFIFO(outbuf, u8, DCC_OUTBUF_SIZE);
-static void dcc_uart_console_putchar(struct uart_port *port, unsigned char ch)
+static void dcc_uart_console_putchar(struct uart_port *port, u8 ch)
{
while (__dcc_getstatus() & DCC_STATUS_TX)
cpu_relax();
@@ -47,6 +47,14 @@ static void dcc_early_write(struct console *con, const char *s, unsigned n)
static int __init dcc_early_console_setup(struct earlycon_device *device,
const char *opt)
{
+ unsigned int count = 0x4000000;
+
+ while (--count && (__dcc_getstatus() & DCC_STATUS_TX))
+ cpu_relax();
+
+ if (__dcc_getstatus() & DCC_STATUS_TX)
+ return -ENODEV;
+
device->con->write = dcc_early_write;
return 0;
@@ -54,9 +62,9 @@ static int __init dcc_early_console_setup(struct earlycon_device *device,
EARLYCON_DECLARE(dcc, dcc_early_console_setup);
-static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
+static ssize_t hvc_dcc_put_chars(uint32_t vt, const u8 *buf, size_t count)
{
- int i;
+ size_t i;
for (i = 0; i < count; i++) {
while (__dcc_getstatus() & DCC_STATUS_TX)
@@ -68,9 +76,9 @@ static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
return count;
}
-static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
+static ssize_t hvc_dcc_get_chars(uint32_t vt, u8 *buf, size_t count)
{
- int i;
+ size_t i;
for (i = 0; i < count; ++i)
if (__dcc_getstatus() & DCC_STATUS_RX)
@@ -149,8 +157,8 @@ static DECLARE_WORK(dcc_pwork, dcc_put_work);
*/
static void dcc_get_work(struct work_struct *work)
{
- unsigned char ch;
unsigned long irqflags;
+ u8 ch;
/*
* Read characters from DCC and put them into the input FIFO, as
@@ -172,10 +180,10 @@ static DECLARE_WORK(dcc_gwork, dcc_get_work);
* Write characters directly to the DCC if we're on core 0 and the FIFO
* is empty, or write them to the FIFO if we're not.
*/
-static int hvc_dcc0_put_chars(u32 vt, const char *buf, int count)
+static ssize_t hvc_dcc0_put_chars(u32 vt, const u8 *buf, size_t count)
{
- int len;
unsigned long irqflags;
+ ssize_t len;
if (!IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP))
return hvc_dcc_put_chars(vt, buf, count);
@@ -211,10 +219,10 @@ static int hvc_dcc0_put_chars(u32 vt, const char *buf, int count)
* Read characters directly from the DCC if we're on core 0 and the FIFO
* is empty, or read them from the FIFO if we're not.
*/
-static int hvc_dcc0_get_chars(u32 vt, char *buf, int count)
+static ssize_t hvc_dcc0_get_chars(u32 vt, u8 *buf, size_t count)
{
- int len;
unsigned long irqflags;
+ ssize_t len;
if (!IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP))
return hvc_dcc_get_chars(vt, buf, count);
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index 543f35ddf523..fdecc0d63731 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -215,11 +215,11 @@ static void destroy_tty_buffer_list(struct list_head *list)
* If the IUCV path has been severed, then -EPIPE is returned to cause a
* hang up (that is issued by the HVC layer).
*/
-static int hvc_iucv_write(struct hvc_iucv_private *priv,
- char *buf, int count, int *has_more_data)
+static ssize_t hvc_iucv_write(struct hvc_iucv_private *priv,
+ u8 *buf, size_t count, int *has_more_data)
{
struct iucv_tty_buffer *rb;
- int written;
+ ssize_t written;
int rc;
/* immediately return if there is no IUCV connection */
@@ -312,10 +312,10 @@ out_written:
* the routine locks the struct hvc_iucv_private->lock to call
* helper functions.
*/
-static int hvc_iucv_get_chars(uint32_t vtermno, char *buf, int count)
+static ssize_t hvc_iucv_get_chars(uint32_t vtermno, u8 *buf, size_t count)
{
struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno);
- int written;
+ ssize_t written;
int has_more_data;
if (count <= 0)
@@ -352,8 +352,8 @@ static int hvc_iucv_get_chars(uint32_t vtermno, char *buf, int count)
* If an existing IUCV communicaton path has been severed, -EPIPE is returned
* (that can be passed to HVC layer to cause a tty hangup).
*/
-static int hvc_iucv_queue(struct hvc_iucv_private *priv, const char *buf,
- int count)
+static ssize_t hvc_iucv_queue(struct hvc_iucv_private *priv, const u8 *buf,
+ size_t count)
{
size_t len;
@@ -455,12 +455,12 @@ static void hvc_iucv_sndbuf_work(struct work_struct *work)
* Locking: The method gets called under an irqsave() spinlock; and
* locks struct hvc_iucv_private->lock.
*/
-static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count)
+static ssize_t hvc_iucv_put_chars(uint32_t vtermno, const u8 *buf, size_t count)
{
struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno);
int queued;
- if (count <= 0)
+ if (!count)
return 0;
if (!priv)
diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c
index 992e199e0ea8..095c33ad10f8 100644
--- a/drivers/tty/hvc/hvc_opal.c
+++ b/drivers/tty/hvc/hvc_opal.c
@@ -58,7 +58,7 @@ static const struct hv_ops hvc_opal_raw_ops = {
.notifier_hangup = notifier_hangup_irq,
};
-static int hvc_opal_hvsi_get_chars(uint32_t vtermno, char *buf, int count)
+static ssize_t hvc_opal_hvsi_get_chars(uint32_t vtermno, u8 *buf, size_t count)
{
struct hvc_opal_priv *pv = hvc_opal_privs[vtermno];
@@ -68,7 +68,8 @@ static int hvc_opal_hvsi_get_chars(uint32_t vtermno, char *buf, int count)
return hvsilib_get_chars(&pv->hvsi, buf, count);
}
-static int hvc_opal_hvsi_put_chars(uint32_t vtermno, const char *buf, int count)
+static ssize_t hvc_opal_hvsi_put_chars(uint32_t vtermno, const u8 *buf,
+ size_t count)
{
struct hvc_opal_priv *pv = hvc_opal_privs[vtermno];
@@ -232,24 +233,21 @@ static int hvc_opal_probe(struct platform_device *dev)
return 0;
}
-static int hvc_opal_remove(struct platform_device *dev)
+static void hvc_opal_remove(struct platform_device *dev)
{
struct hvc_struct *hp = dev_get_drvdata(&dev->dev);
- int rc, termno;
+ int termno;
termno = hp->vtermno;
- rc = hvc_remove(hp);
- if (rc == 0) {
- if (hvc_opal_privs[termno] != &hvc_opal_boot_priv)
- kfree(hvc_opal_privs[termno]);
- hvc_opal_privs[termno] = NULL;
- }
- return rc;
+ hvc_remove(hp);
+ if (hvc_opal_privs[termno] != &hvc_opal_boot_priv)
+ kfree(hvc_opal_privs[termno]);
+ hvc_opal_privs[termno] = NULL;
}
static struct platform_driver hvc_opal_driver = {
.probe = hvc_opal_probe,
- .remove = hvc_opal_remove,
+ .remove_new = hvc_opal_remove,
.driver = {
.name = hvc_opal_name,
.of_match_table = hvc_opal_match,
diff --git a/drivers/tty/hvc/hvc_riscv_sbi.c b/drivers/tty/hvc/hvc_riscv_sbi.c
index 31f53fa77e4a..a72591279f86 100644
--- a/drivers/tty/hvc/hvc_riscv_sbi.c
+++ b/drivers/tty/hvc/hvc_riscv_sbi.c
@@ -15,9 +15,9 @@
#include "hvc_console.h"
-static int hvc_sbi_tty_put(uint32_t vtermno, const char *buf, int count)
+static ssize_t hvc_sbi_tty_put(uint32_t vtermno, const u8 *buf, size_t count)
{
- int i;
+ size_t i;
for (i = 0; i < count; i++)
sbi_console_putchar(buf[i]);
@@ -25,9 +25,10 @@ static int hvc_sbi_tty_put(uint32_t vtermno, const char *buf, int count)
return i;
}
-static int hvc_sbi_tty_get(uint32_t vtermno, char *buf, int count)
+static ssize_t hvc_sbi_tty_get(uint32_t vtermno, u8 *buf, size_t count)
{
- int i, c;
+ size_t i;
+ int c;
for (i = 0; i < count; i++) {
c = sbi_console_getchar();
diff --git a/drivers/tty/hvc/hvc_rtas.c b/drivers/tty/hvc/hvc_rtas.c
index 184d325abeed..a0b90275b37f 100644
--- a/drivers/tty/hvc/hvc_rtas.c
+++ b/drivers/tty/hvc/hvc_rtas.c
@@ -31,10 +31,10 @@ static struct hvc_struct *hvc_rtas_dev;
static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE;
static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE;
-static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf,
- int count)
+static ssize_t hvc_rtas_write_console(uint32_t vtermno, const u8 *buf,
+ size_t count)
{
- int i;
+ size_t i;
for (i = 0; i < count; i++) {
if (rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[i]))
@@ -44,9 +44,10 @@ static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf,
return i;
}
-static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count)
+static ssize_t hvc_rtas_read_console(uint32_t vtermno, u8 *buf, size_t count)
{
- int i, c;
+ size_t i;
+ int c;
for (i = 0; i < count; i++) {
if (rtas_call(rtascons_get_char_token, 0, 2, &c))
diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c
index ff0dcc56413c..fdc2699b78dc 100644
--- a/drivers/tty/hvc/hvc_udbg.c
+++ b/drivers/tty/hvc/hvc_udbg.c
@@ -19,9 +19,9 @@
static struct hvc_struct *hvc_udbg_dev;
-static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count)
+static ssize_t hvc_udbg_put(uint32_t vtermno, const u8 *buf, size_t count)
{
- int i;
+ size_t i;
for (i = 0; i < count && udbg_putc; i++)
udbg_putc(buf[i]);
@@ -29,9 +29,10 @@ static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count)
return i;
}
-static int hvc_udbg_get(uint32_t vtermno, char *buf, int count)
+static ssize_t hvc_udbg_get(uint32_t vtermno, u8 *buf, size_t count)
{
- int i, c;
+ size_t i;
+ int c;
if (!udbg_getc_poll)
return 0;
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c
index 736b230f5ec0..47930601a26a 100644
--- a/drivers/tty/hvc/hvc_vio.c
+++ b/drivers/tty/hvc/hvc_vio.c
@@ -58,20 +58,20 @@ struct hvterm_priv {
hv_protocol_t proto; /* Raw data or HVSI packets */
struct hvsi_priv hvsi; /* HVSI specific data */
spinlock_t buf_lock;
- char buf[SIZE_VIO_GET_CHARS];
- int left;
- int offset;
+ u8 buf[SIZE_VIO_GET_CHARS];
+ size_t left;
+ size_t offset;
};
static struct hvterm_priv *hvterm_privs[MAX_NR_HVC_CONSOLES];
/* For early boot console */
static struct hvterm_priv hvterm_priv0;
-static int hvterm_raw_get_chars(uint32_t vtermno, char *buf, int count)
+static ssize_t hvterm_raw_get_chars(uint32_t vtermno, u8 *buf, size_t count)
{
struct hvterm_priv *pv = hvterm_privs[vtermno];
unsigned long i;
unsigned long flags;
- int got;
+ size_t got;
if (WARN_ON(!pv))
return 0;
@@ -115,7 +115,8 @@ static int hvterm_raw_get_chars(uint32_t vtermno, char *buf, int count)
* you are sending fewer chars.
* @count: number of chars to send.
*/
-static int hvterm_raw_put_chars(uint32_t vtermno, const char *buf, int count)
+static ssize_t hvterm_raw_put_chars(uint32_t vtermno, const u8 *buf,
+ size_t count)
{
struct hvterm_priv *pv = hvterm_privs[vtermno];
@@ -133,7 +134,7 @@ static const struct hv_ops hvterm_raw_ops = {
.notifier_hangup = notifier_hangup_irq,
};
-static int hvterm_hvsi_get_chars(uint32_t vtermno, char *buf, int count)
+static ssize_t hvterm_hvsi_get_chars(uint32_t vtermno, u8 *buf, size_t count)
{
struct hvterm_priv *pv = hvterm_privs[vtermno];
@@ -143,7 +144,8 @@ static int hvterm_hvsi_get_chars(uint32_t vtermno, char *buf, int count)
return hvsilib_get_chars(&pv->hvsi, buf, count);
}
-static int hvterm_hvsi_put_chars(uint32_t vtermno, const char *buf, int count)
+static ssize_t hvterm_hvsi_put_chars(uint32_t vtermno, const u8 *buf,
+ size_t count)
{
struct hvterm_priv *pv = hvterm_privs[vtermno];
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 34c01874f45b..0e497501f8e3 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -84,13 +84,13 @@ static inline void notify_daemon(struct xencons_info *cons)
notify_remote_via_evtchn(cons->evtchn);
}
-static int __write_console(struct xencons_info *xencons,
- const char *data, int len)
+static ssize_t __write_console(struct xencons_info *xencons,
+ const u8 *data, size_t len)
{
XENCONS_RING_IDX cons, prod;
struct xencons_interface *intf = xencons->intf;
- int sent = 0;
unsigned long flags;
+ size_t sent = 0;
spin_lock_irqsave(&xencons->ring_lock, flags);
cons = intf->out_cons;
@@ -115,10 +115,11 @@ static int __write_console(struct xencons_info *xencons,
return sent;
}
-static int domU_write_console(uint32_t vtermno, const char *data, int len)
+static ssize_t domU_write_console(uint32_t vtermno, const u8 *data, size_t len)
{
- int ret = len;
struct xencons_info *cons = vtermno_to_xencons(vtermno);
+ size_t ret = len;
+
if (cons == NULL)
return -EINVAL;
@@ -129,7 +130,7 @@ static int domU_write_console(uint32_t vtermno, const char *data, int len)
* kernel is crippled.
*/
while (len) {
- int sent = __write_console(cons, data, len);
+ ssize_t sent = __write_console(cons, data, len);
if (sent < 0)
return sent;
@@ -144,14 +145,14 @@ static int domU_write_console(uint32_t vtermno, const char *data, int len)
return ret;
}
-static int domU_read_console(uint32_t vtermno, char *buf, int len)
+static ssize_t domU_read_console(uint32_t vtermno, u8 *buf, size_t len)
{
struct xencons_interface *intf;
XENCONS_RING_IDX cons, prod;
- int recv = 0;
struct xencons_info *xencons = vtermno_to_xencons(vtermno);
unsigned int eoiflag = 0;
unsigned long flags;
+ size_t recv = 0;
if (xencons == NULL)
return -EINVAL;
@@ -209,7 +210,7 @@ static const struct hv_ops domU_hvc_ops = {
.notifier_hangup = notifier_hangup_irq,
};
-static int dom0_read_console(uint32_t vtermno, char *buf, int len)
+static ssize_t dom0_read_console(uint32_t vtermno, u8 *buf, size_t len)
{
return HYPERVISOR_console_io(CONSOLEIO_read, len, buf);
}
@@ -218,9 +219,9 @@ static int dom0_read_console(uint32_t vtermno, char *buf, int len)
* Either for a dom0 to write to the system console, or a domU with a
* debug version of Xen
*/
-static int dom0_write_console(uint32_t vtermno, const char *str, int len)
+static ssize_t dom0_write_console(uint32_t vtermno, const u8 *str, size_t len)
{
- int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (char *)str);
+ int rc = HYPERVISOR_console_io(CONSOLEIO_write, len, (u8 *)str);
if (rc < 0)
return rc;
diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c
index 09289c8154ae..22e1bc4d8a66 100644
--- a/drivers/tty/hvc/hvsi_lib.c
+++ b/drivers/tty/hvc/hvsi_lib.c
@@ -12,7 +12,7 @@ static int hvsi_send_packet(struct hvsi_priv *pv, struct hvsi_header *packet)
packet->seqno = cpu_to_be16(atomic_inc_return(&pv->seqno));
/* Assumes that always succeeds, works in practice */
- return pv->put_chars(pv->termno, (char *)packet, packet->len);
+ return pv->put_chars(pv->termno, (u8 *)packet, packet->len);
}
static void hvsi_start_handshake(struct hvsi_priv *pv)
@@ -178,9 +178,10 @@ static int hvsi_get_packet(struct hvsi_priv *pv)
return 0;
}
-int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count)
+ssize_t hvsilib_get_chars(struct hvsi_priv *pv, u8 *buf, size_t count)
{
- unsigned int tries, read = 0;
+ unsigned int tries;
+ size_t read = 0;
if (WARN_ON(!pv))
return -ENXIO;
@@ -199,7 +200,7 @@ int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count)
for (tries = 1; count && tries < 2; tries++) {
/* Consume existing data packet */
if (pv->inbuf_pktlen) {
- unsigned int l = min(count, (int)pv->inbuf_pktlen);
+ size_t l = min(count, pv->inbuf_pktlen);
memcpy(&buf[read], &pv->inbuf[pv->inbuf_cur], l);
pv->inbuf_cur += l;
pv->inbuf_pktlen -= l;
@@ -228,10 +229,11 @@ int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count)
return read;
}
-int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count)
+ssize_t hvsilib_put_chars(struct hvsi_priv *pv, const u8 *buf, size_t count)
{
struct hvsi_data dp;
- int rc, adjcount = min(count, HVSI_MAX_OUTGOING_DATA);
+ size_t adjcount = min_t(size_t, count, HVSI_MAX_OUTGOING_DATA);
+ int rc;
if (WARN_ON(!pv))
return -ENODEV;
@@ -411,9 +413,9 @@ void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp)
}
void hvsilib_init(struct hvsi_priv *pv,
- int (*get_chars)(uint32_t termno, char *buf, int count),
- int (*put_chars)(uint32_t termno, const char *buf,
- int count),
+ ssize_t (*get_chars)(uint32_t termno, u8 *buf, size_t count),
+ ssize_t (*put_chars)(uint32_t termno, const u8 *buf,
+ size_t count),
int termno, int is_console)
{
memset(pv, 0, sizeof(*pv));
diff --git a/drivers/tty/ipwireless/main.h b/drivers/tty/ipwireless/main.h
index 73818bb64416..a5728a5b3f83 100644
--- a/drivers/tty/ipwireless/main.h
+++ b/drivers/tty/ipwireless/main.h
@@ -49,9 +49,6 @@ struct ipw_dev {
void __iomem *common_memory;
- /* Reference to attribute memory, containing CIS data */
- void *attribute_memory;
-
/* Hardware context */
struct ipw_hardware *hardware;
/* Network layer context */
diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c
index 369ec71c24ef..aac80b69a069 100644
--- a/drivers/tty/mips_ejtag_fdc.c
+++ b/drivers/tty/mips_ejtag_fdc.c
@@ -213,16 +213,16 @@ struct fdc_word {
*/
/* ranges >= 1 && sizes[0] >= 1 */
-static struct fdc_word mips_ejtag_fdc_encode(const char **ptrs,
+static struct fdc_word mips_ejtag_fdc_encode(const u8 **ptrs,
unsigned int *sizes,
unsigned int ranges)
{
struct fdc_word word = { 0, 0 };
- const char **ptrs_end = ptrs + ranges;
+ const u8 **ptrs_end = ptrs + ranges;
for (; ptrs < ptrs_end; ++ptrs) {
- const char *ptr = *(ptrs++);
- const char *end = ptr + *(sizes++);
+ const u8 *ptr = *(ptrs++);
+ const u8 *end = ptr + *(sizes++);
for (; ptr < end; ++ptr) {
word.word |= (u8)*ptr << (8*word.bytes);
@@ -417,7 +417,7 @@ static unsigned int mips_ejtag_fdc_put_chan(struct mips_ejtag_fdc_tty *priv,
{
struct mips_ejtag_fdc_tty_port *dport;
struct tty_struct *tty;
- const char *ptrs[2];
+ const u8 *ptrs[2];
unsigned int sizes[2] = { 0 };
struct fdc_word word = { .bytes = 0 };
unsigned long flags;
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index bf3f87ba3a92..ebaada8db929 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -514,7 +514,7 @@ static void MoxaPortLineCtrl(struct moxa_port *, bool, bool);
static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
static int MoxaPortLineStatus(struct moxa_port *);
static void MoxaPortFlushData(struct moxa_port *, int);
-static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
+static ssize_t MoxaPortWriteData(struct tty_struct *, const u8 *, size_t);
static int MoxaPortReadData(struct moxa_port *);
static unsigned int MoxaPortTxQueue(struct moxa_port *);
static int MoxaPortRxQueue(struct moxa_port *);
@@ -1933,10 +1933,10 @@ static void MoxaPortFlushData(struct moxa_port *port, int mode)
*
* Function 20: Write data.
* Syntax:
- * int MoxaPortWriteData(int port, unsigned char * buffer, int length);
+ * ssize_t MoxaPortWriteData(int port, u8 *buffer, size_t length);
* int port : port number (0 - 127)
- * unsigned char * buffer : pointer to write data buffer.
- * int length : write data length
+ * u8 *buffer : pointer to write data buffer.
+ * size_t length : write data length
*
* return: 0 - length : real write data length
*
@@ -2163,11 +2163,12 @@ static int MoxaPortLineStatus(struct moxa_port *port)
return val;
}
-static int MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer, int len)
+static ssize_t MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer,
+ size_t len)
{
struct moxa_port *port = tty->driver_data;
void __iomem *baseAddr, *ofsAddr, *ofs;
- unsigned int c, total;
+ size_t c, total;
u16 head, tail, tx_mask, spage, epage;
u16 pageno, pageofs, bufhead;
@@ -2224,8 +2225,8 @@ static int MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer, int len)
static int MoxaPortReadData(struct moxa_port *port)
{
struct tty_struct *tty = port->port.tty;
- unsigned char *dst;
void __iomem *baseAddr, *ofsAddr, *ofs;
+ u8 *dst;
unsigned int count, len, total;
u16 tail, rx_mask, spage, epage;
u16 pageno, pageofs, bufhead, head;
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 6ce7f259968f..458bb1280ebf 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -264,7 +264,7 @@ struct mxser_port {
u8 rx_low_water;
int type; /* UART type */
- unsigned char x_char; /* xon/xoff character */
+ u8 x_char; /* xon/xoff character */
u8 IER; /* Interrupt Enable Register */
u8 MCR; /* Modem control register */
u8 FCR; /* FIFO control register */
@@ -905,7 +905,7 @@ static ssize_t mxser_write(struct tty_struct *tty, const u8 *buf, size_t count)
{
struct mxser_port *info = tty->driver_data;
unsigned long flags;
- int written;
+ size_t written;
bool is_empty;
spin_lock_irqsave(&info->slock, flags);
@@ -1521,7 +1521,7 @@ static u8 mxser_receive_chars_old(struct tty_struct *tty,
if (++ignored > 100)
break;
} else {
- char flag = 0;
+ u8 flag = 0;
if (status & UART_LSR_BRK_ERROR_BITS) {
if (status & UART_LSR_BI) {
flag = TTY_BREAK;
@@ -1585,7 +1585,7 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port
count = port->xmit_fifo_size;
do {
- unsigned char c;
+ u8 c;
if (!kfifo_get(&port->port.xmit_fifo, &c))
break;
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index a3ab3946e4ad..4036566febcb 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -124,8 +124,8 @@ struct gsm_msg {
u8 addr; /* DLCI address + flags */
u8 ctrl; /* Control byte + flags */
unsigned int len; /* Length of data block (can be zero) */
- unsigned char *data; /* Points into buffer but not at the start */
- unsigned char buffer[];
+ u8 *data; /* Points into buffer but not at the start */
+ u8 buffer[];
};
enum gsm_dlci_state {
@@ -283,7 +283,7 @@ struct gsm_mux {
/* Bits for GSM mode decoding */
/* Framing Layer */
- unsigned char *buf;
+ u8 *buf;
enum gsm_mux_state state;
unsigned int len;
unsigned int address;
@@ -2856,7 +2856,7 @@ invalid:
* Receive bytes in gsm mode 0
*/
-static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
+static void gsm0_receive(struct gsm_mux *gsm, u8 c)
{
unsigned int len;
@@ -2947,7 +2947,7 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
* Receive bytes in mode 1 (Advanced option)
*/
-static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
+static void gsm1_receive(struct gsm_mux *gsm, u8 c)
{
/* handle XON/XOFF */
if ((c & ISO_IEC_646_MASK) == XON) {
@@ -3541,7 +3541,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const u8 *cp,
const u8 *fp, size_t count)
{
struct gsm_mux *gsm = tty->disc_data;
- char flags = TTY_NORMAL;
+ u8 flags = TTY_NORMAL;
if (debug & DBG_DATA)
gsm_hex_dump_bytes(__func__, cp, count);
@@ -3711,7 +3711,7 @@ static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
{
struct gsm_mux *gsm = tty->disc_data;
unsigned long flags;
- int space;
+ size_t space;
int ret;
if (!gsm)
@@ -3909,8 +3909,7 @@ static void gsm_mux_net_tx_timeout(struct net_device *net, unsigned int txqueue)
net->stats.tx_errors++;
}
-static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
- const unsigned char *in_buf, int size)
+static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, const u8 *in_buf, int size)
{
struct net_device *net = dlci->net;
struct sk_buff *skb;
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index a670419efe79..1615f074ab86 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -109,8 +109,8 @@
struct n_hdlc_buf {
struct list_head list_item;
- int count;
- char buf[];
+ size_t count;
+ u8 buf[];
};
struct n_hdlc_buf_list {
@@ -263,9 +263,9 @@ static int n_hdlc_tty_open(struct tty_struct *tty)
*/
static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
{
- register int actual;
unsigned long flags;
struct n_hdlc_buf *tbuf;
+ ssize_t actual;
check_again:
@@ -281,7 +281,7 @@ check_again:
tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
while (tbuf) {
- pr_debug("sending frame %p, count=%d\n", tbuf, tbuf->count);
+ pr_debug("sending frame %p, count=%zu\n", tbuf, tbuf->count);
/* Send the next block of data to device */
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
@@ -521,9 +521,9 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
const u8 *data, size_t count)
{
struct n_hdlc *n_hdlc = tty->disc_data;
- int error = 0;
DECLARE_WAITQUEUE(wait, current);
struct n_hdlc_buf *tbuf;
+ ssize_t error = 0;
pr_debug("%s() called count=%zd\n", __func__, count);
diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c
index 02cd40147b3a..e28a921c1637 100644
--- a/drivers/tty/nozomi.c
+++ b/drivers/tty/nozomi.c
@@ -65,24 +65,8 @@ do { \
#define DBG3(args...) DBG_(0x04, ##args)
#define DBG4(args...) DBG_(0x08, ##args)
-/* TODO: rewrite to optimize macros... */
-
#define TMP_BUF_MAX 256
-#define DUMP(buf__, len__) \
- do { \
- char tbuf[TMP_BUF_MAX] = {0}; \
- if (len__ > 1) { \
- u32 data_len = min_t(u32, len__, TMP_BUF_MAX); \
- strscpy(tbuf, buf__, data_len); \
- if (tbuf[data_len - 2] == '\r') \
- tbuf[data_len - 2] = 'r'; \
- DBG1("SENDING: '%s' (%d+n)", tbuf, len__); \
- } else { \
- DBG1("SENDING: '%s' (%d)", tbuf, len__); \
- } \
- } while (0)
-
/* Defines */
#define NOZOMI_NAME "nozomi"
#define NOZOMI_NAME_TTY "nozomi_tty"
@@ -754,8 +738,6 @@ static int send_data(enum port_type index, struct nozomi *dc)
return 0;
}
- /* DUMP(buf, size); */
-
/* Write length + data */
write_mem32(addr, (u32 *) &size, 4);
write_mem32(addr + 4, (u32 *) dc->send_buf, size);
@@ -801,11 +783,10 @@ static int receive_data(enum port_type index, struct nozomi *dc)
tty_insert_flip_char(&port->port, buf[0], TTY_NORMAL);
size = 0;
} else if (size < RECEIVE_BUF_MAX) {
- size -= tty_insert_flip_string(&port->port,
- (char *)buf, size);
+ size -= tty_insert_flip_string(&port->port, buf, size);
} else {
- i = tty_insert_flip_string(&port->port,
- (char *)buf, RECEIVE_BUF_MAX);
+ i = tty_insert_flip_string(&port->port, buf,
+ RECEIVE_BUF_MAX);
size -= i;
offset += i;
}
@@ -1602,10 +1583,10 @@ static void ntty_hangup(struct tty_struct *tty)
static ssize_t ntty_write(struct tty_struct *tty, const u8 *buffer,
size_t count)
{
- int rval = -EINVAL;
struct nozomi *dc = get_dc_by_tty(tty);
struct port *port = tty->driver_data;
unsigned long flags;
+ size_t rval;
if (!dc || !port)
return -ENODEV;
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index a5fdaf5e148e..822a5cd05566 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -77,7 +77,7 @@ static bool is_serdev_device(const struct device *dev)
static void serdev_ctrl_release(struct device *dev)
{
struct serdev_controller *ctrl = to_serdev_controller(dev);
- ida_simple_remove(&ctrl_ida, ctrl->nr);
+ ida_free(&ctrl_ida, ctrl->nr);
kfree(ctrl);
}
@@ -225,8 +225,7 @@ EXPORT_SYMBOL_GPL(serdev_device_write_wakeup);
* Return: The number of bytes written (less than count if not enough room in
* the write buffer), or a negative errno on errors.
*/
-int serdev_device_write_buf(struct serdev_device *serdev,
- const unsigned char *buf, size_t count)
+int serdev_device_write_buf(struct serdev_device *serdev, const u8 *buf, size_t count)
{
struct serdev_controller *ctrl = serdev->ctrl;
@@ -259,13 +258,12 @@ EXPORT_SYMBOL_GPL(serdev_device_write_buf);
* -ETIMEDOUT or -ERESTARTSYS if interrupted before any bytes were written, or
* a negative errno on errors.
*/
-int serdev_device_write(struct serdev_device *serdev,
- const unsigned char *buf, size_t count,
- long timeout)
+ssize_t serdev_device_write(struct serdev_device *serdev, const u8 *buf,
+ size_t count, long timeout)
{
struct serdev_controller *ctrl = serdev->ctrl;
- int written = 0;
- int ret;
+ size_t written = 0;
+ ssize_t ret;
if (!ctrl || !ctrl->ops->write_buf || !serdev->ops->write_wakeup)
return -EINVAL;
@@ -468,6 +466,7 @@ EXPORT_SYMBOL_GPL(serdev_device_alloc);
/**
* serdev_controller_alloc() - Allocate a new serdev controller
+ * @host: serial port hardware controller device
* @parent: parent device
* @size: size of private data
*
@@ -476,8 +475,9 @@ EXPORT_SYMBOL_GPL(serdev_device_alloc);
* The allocated private data region may be accessed via
* serdev_controller_get_drvdata()
*/
-struct serdev_controller *serdev_controller_alloc(struct device *parent,
- size_t size)
+struct serdev_controller *serdev_controller_alloc(struct device *host,
+ struct device *parent,
+ size_t size)
{
struct serdev_controller *ctrl;
int id;
@@ -489,7 +489,7 @@ struct serdev_controller *serdev_controller_alloc(struct device *parent,
if (!ctrl)
return NULL;
- id = ida_simple_get(&ctrl_ida, 0, 0, GFP_KERNEL);
+ id = ida_alloc(&ctrl_ida, GFP_KERNEL);
if (id < 0) {
dev_err(parent,
"unable to allocate serdev controller identifier.\n");
@@ -502,7 +502,8 @@ struct serdev_controller *serdev_controller_alloc(struct device *parent,
ctrl->dev.type = &serdev_ctrl_type;
ctrl->dev.bus = &serdev_bus_type;
ctrl->dev.parent = parent;
- device_set_node(&ctrl->dev, dev_fwnode(parent));
+ ctrl->host = host;
+ device_set_node(&ctrl->dev, dev_fwnode(host));
serdev_controller_set_drvdata(ctrl, &ctrl[1]);
dev_set_name(&ctrl->dev, "serial%d", id);
@@ -665,7 +666,7 @@ static int acpi_serdev_check_resources(struct serdev_controller *ctrl,
acpi_get_parent(adev->handle, &lookup.controller_handle);
/* Make sure controller and ResourceSource handle match */
- if (!device_match_acpi_handle(ctrl->dev.parent, lookup.controller_handle))
+ if (!device_match_acpi_handle(ctrl->host, lookup.controller_handle))
return -ENODEV;
return 0;
@@ -730,7 +731,7 @@ static int acpi_serdev_register_devices(struct serdev_controller *ctrl)
bool skip;
int ret;
- if (!has_acpi_companion(ctrl->dev.parent))
+ if (!has_acpi_companion(ctrl->host))
return -ENODEV;
/*
@@ -739,7 +740,7 @@ static int acpi_serdev_register_devices(struct serdev_controller *ctrl)
* succeed in this case, so that the proper serdev devices can be
* added "manually" later.
*/
- ret = acpi_quirk_skip_serdev_enumeration(ctrl->dev.parent, &skip);
+ ret = acpi_quirk_skip_serdev_enumeration(ctrl->host, &skip);
if (ret)
return ret;
if (skip)
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index e3856814ce77..e94e090cf0a1 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -74,7 +74,7 @@ static const struct tty_port_client_operations client_ops = {
* Callback functions from the serdev core.
*/
-static int ttyport_write_buf(struct serdev_controller *ctrl, const unsigned char *data, size_t len)
+static ssize_t ttyport_write_buf(struct serdev_controller *ctrl, const u8 *data, size_t len)
{
struct serport *serport = serdev_controller_get_drvdata(ctrl);
struct tty_struct *tty = serport->tty;
@@ -274,6 +274,7 @@ static const struct serdev_controller_ops ctrl_ops = {
};
struct device *serdev_tty_port_register(struct tty_port *port,
+ struct device *host,
struct device *parent,
struct tty_driver *drv, int idx)
{
@@ -284,7 +285,7 @@ struct device *serdev_tty_port_register(struct tty_port *port,
if (!port || !drv || !parent)
return ERR_PTR(-ENODEV);
- ctrl = serdev_controller_alloc(parent, sizeof(struct serport));
+ ctrl = serdev_controller_alloc(host, parent, sizeof(struct serport));
if (!ctrl)
return ERR_PTR(-ENOMEM);
serport = serdev_controller_get_drvdata(ctrl);
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c
index d7482ae33a1c..8c2aaf7af7b7 100644
--- a/drivers/tty/serial/8250/8250_aspeed_vuart.c
+++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c
@@ -566,7 +566,7 @@ err_sysfs_remove:
return rc;
}
-static int aspeed_vuart_remove(struct platform_device *pdev)
+static void aspeed_vuart_remove(struct platform_device *pdev)
{
struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
@@ -574,8 +574,6 @@ static int aspeed_vuart_remove(struct platform_device *pdev)
aspeed_vuart_set_enabled(vuart, false);
serial8250_unregister_port(vuart->line);
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
-
- return 0;
}
static const struct of_device_id aspeed_vuart_table[] = {
@@ -590,7 +588,7 @@ static struct platform_driver aspeed_vuart_driver = {
.of_match_table = aspeed_vuart_table,
},
.probe = aspeed_vuart_probe,
- .remove = aspeed_vuart_remove,
+ .remove_new = aspeed_vuart_remove,
};
module_platform_driver(aspeed_vuart_driver);
diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
index 15a2387a5b25..beac6b340ace 100644
--- a/drivers/tty/serial/8250/8250_bcm2835aux.c
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
@@ -119,6 +119,8 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
/* get the clock - this also enables the HW */
data->clk = devm_clk_get_optional(&pdev->dev, NULL);
+ if (IS_ERR(data->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(data->clk), "could not get clk\n");
/* get the interrupt */
ret = platform_get_irq(pdev, 0);
@@ -195,14 +197,12 @@ dis_clk:
return ret;
}
-static int bcm2835aux_serial_remove(struct platform_device *pdev)
+static void bcm2835aux_serial_remove(struct platform_device *pdev)
{
struct bcm2835aux_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
clk_disable_unprepare(data->clk);
-
- return 0;
}
static const struct bcm2835_aux_serial_driver_data bcm2835_acpi_data = {
@@ -228,7 +228,7 @@ static struct platform_driver bcm2835aux_serial_driver = {
.acpi_match_table = bcm2835aux_serial_acpi_match,
},
.probe = bcm2835aux_serial_probe,
- .remove = bcm2835aux_serial_remove,
+ .remove_new = bcm2835aux_serial_remove,
};
module_platform_driver(bcm2835aux_serial_driver);
diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c
index 55dea2539c47..504c4c020857 100644
--- a/drivers/tty/serial/8250/8250_bcm7271.c
+++ b/drivers/tty/serial/8250/8250_bcm7271.c
@@ -1121,7 +1121,7 @@ release_dma:
return ret;
}
-static int brcmuart_remove(struct platform_device *pdev)
+static void brcmuart_remove(struct platform_device *pdev)
{
struct brcmuart_priv *priv = platform_get_drvdata(pdev);
@@ -1131,7 +1131,6 @@ static int brcmuart_remove(struct platform_device *pdev)
brcmuart_free_bufs(&pdev->dev, priv);
if (priv->dma_enabled)
brcmuart_arbitration(priv, 0);
- return 0;
}
static int __maybe_unused brcmuart_suspend(struct device *dev)
@@ -1207,7 +1206,7 @@ static struct platform_driver brcmuart_platform_driver = {
.of_match_table = brcmuart_dt_ids,
},
.probe = brcmuart_probe,
- .remove = brcmuart_remove,
+ .remove_new = brcmuart_remove,
};
static int __init brcmuart_init(void)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 912733151858..b62ad9006780 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -883,7 +883,7 @@ static int serial8250_probe(struct platform_device *dev)
/*
* Remove serial ports registered against a platform device.
*/
-static int serial8250_remove(struct platform_device *dev)
+static void serial8250_remove(struct platform_device *dev)
{
int i;
@@ -893,7 +893,6 @@ static int serial8250_remove(struct platform_device *dev)
if (up->port.dev == &dev->dev)
serial8250_unregister_port(i);
}
- return 0;
}
static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
@@ -926,7 +925,7 @@ static int serial8250_resume(struct platform_device *dev)
static struct platform_driver serial8250_isa_driver = {
.probe = serial8250_probe,
- .remove = serial8250_remove,
+ .remove_new = serial8250_remove,
.suspend = serial8250_suspend,
.resume = serial8250_resume,
.driver = {
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index e6218766d0c8..2d1f350a4bea 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -663,7 +663,7 @@ static int dw8250_probe(struct platform_device *pdev)
return 0;
}
-static int dw8250_remove(struct platform_device *pdev)
+static void dw8250_remove(struct platform_device *pdev)
{
struct dw8250_data *data = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
@@ -680,8 +680,6 @@ static int dw8250_remove(struct platform_device *pdev)
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
-
- return 0;
}
static int dw8250_suspend(struct device *dev)
@@ -790,7 +788,7 @@ static struct platform_driver dw8250_platform_driver = {
.acpi_match_table = dw8250_acpi_match,
},
.probe = dw8250_probe,
- .remove = dw8250_remove,
+ .remove_new = dw8250_remove,
};
module_platform_driver(dw8250_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c
index 84843e204a5e..3e33ddf7bc80 100644
--- a/drivers/tty/serial/8250/8250_dwlib.c
+++ b/drivers/tty/serial/8250/8250_dwlib.c
@@ -259,17 +259,6 @@ void dw8250_setup_port(struct uart_port *p)
}
up->capabilities |= UART_CAP_NOTEMT;
- /*
- * If the Component Version Register returns zero, we know that
- * ADDITIONAL_FEATURES are not enabled. No need to go any further.
- */
- reg = dw8250_readl_ext(p, DW_UART_UCV);
- if (!reg)
- return;
-
- dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
- (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
-
/* Preserve value written by firmware or bootloader */
old_dlf = dw8250_readl_ext(p, DW_UART_DLF);
dw8250_writel_ext(p, DW_UART_DLF, ~0U);
@@ -282,6 +271,11 @@ void dw8250_setup_port(struct uart_port *p)
p->set_divisor = dw8250_set_divisor;
}
+ reg = dw8250_readl_ext(p, DW_UART_UCV);
+ if (reg)
+ dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
+ (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
+
reg = dw8250_readl_ext(p, DW_UART_CPR);
if (!reg) {
reg = data->pdata->cpr_val;
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
index ef5019e944ea..a754755100ff 100644
--- a/drivers/tty/serial/8250/8250_em.c
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -200,12 +200,11 @@ static int serial8250_em_probe(struct platform_device *pdev)
return 0;
}
-static int serial8250_em_remove(struct platform_device *pdev)
+static void serial8250_em_remove(struct platform_device *pdev)
{
struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
serial8250_unregister_port(priv->line);
- return 0;
}
static const struct of_device_id serial8250_em_dt_ids[] = {
@@ -220,7 +219,7 @@ static struct platform_driver serial8250_em_platform_driver = {
.of_match_table = serial8250_em_dt_ids,
},
.probe = serial8250_em_probe,
- .remove = serial8250_em_remove,
+ .remove_new = serial8250_em_remove,
};
module_platform_driver(serial8250_em_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 6085d356ad86..23366f868ae3 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -480,7 +480,7 @@ static int sealevel_rs485_config(struct uart_port *port, struct ktermios *termio
}
static const struct serial_rs485 generic_rs485_supported = {
- .flags = SER_RS485_ENABLED,
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND,
};
static const struct exar8250_platform exar8250_default_platform = {
@@ -524,7 +524,8 @@ static int iot2040_rs485_config(struct uart_port *port, struct ktermios *termios
}
static const struct serial_rs485 iot2040_rs485_supported = {
- .flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_TERMINATE_BUS,
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RX_DURING_TX | SER_RS485_TERMINATE_BUS,
};
static const struct property_entry iot2040_gpio_properties[] = {
diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c
index f522eb5026c9..b4ed442082a8 100644
--- a/drivers/tty/serial/8250/8250_fsl.c
+++ b/drivers/tty/serial/8250/8250_fsl.c
@@ -51,7 +51,8 @@ int fsl8250_handle_irq(struct uart_port *port)
* immediately and interrupt the CPU again. The hardware clears LSR.BI
* when the next valid char is read.)
*/
- if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) {
+ if (unlikely((iir & UART_IIR_ID) == UART_IIR_RLSI &&
+ (up->lsr_saved_flags & UART_LSR_BI))) {
up->lsr_saved_flags &= ~UART_LSR_BI;
port->serial_in(port, UART_RX);
uart_port_unlock_irqrestore(&up->port, flags);
@@ -159,12 +160,11 @@ static int fsl8250_acpi_probe(struct platform_device *pdev)
return 0;
}
-static int fsl8250_acpi_remove(struct platform_device *pdev)
+static void fsl8250_acpi_remove(struct platform_device *pdev)
{
struct fsl8250_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
- return 0;
}
static const struct acpi_device_id fsl_8250_acpi_id[] = {
@@ -179,7 +179,7 @@ static struct platform_driver fsl8250_platform_driver = {
.acpi_match_table = ACPI_PTR(fsl_8250_acpi_id),
},
.probe = fsl8250_acpi_probe,
- .remove = fsl8250_acpi_remove,
+ .remove_new = fsl8250_acpi_remove,
};
module_platform_driver(fsl8250_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 4c4c4da73ad0..a12f737924c0 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -320,14 +320,13 @@ out:
return err;
}
-static int ingenic_uart_remove(struct platform_device *pdev)
+static void ingenic_uart_remove(struct platform_device *pdev)
{
struct ingenic_uart_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
clk_disable_unprepare(data->clk_module);
clk_disable_unprepare(data->clk_baud);
- return 0;
}
static const struct ingenic_uart_config jz4740_uart_config = {
@@ -368,7 +367,7 @@ static struct platform_driver ingenic_uart_platform_driver = {
.of_match_table = of_match,
},
.probe = ingenic_uart_probe,
- .remove = ingenic_uart_remove,
+ .remove_new = ingenic_uart_remove,
};
module_platform_driver(ingenic_uart_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c
index d5a39e105a76..50c77c3dacf2 100644
--- a/drivers/tty/serial/8250/8250_ioc3.c
+++ b/drivers/tty/serial/8250/8250_ioc3.c
@@ -75,17 +75,16 @@ static int serial8250_ioc3_probe(struct platform_device *pdev)
return 0;
}
-static int serial8250_ioc3_remove(struct platform_device *pdev)
+static void serial8250_ioc3_remove(struct platform_device *pdev)
{
struct ioc3_8250_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
- return 0;
}
static struct platform_driver serial8250_ioc3_driver = {
.probe = serial8250_ioc3_probe,
- .remove = serial8250_ioc3_remove,
+ .remove_new = serial8250_ioc3_remove,
.driver = {
.name = "ioc3-serial8250",
}
diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c
index 6dc85aaba5d0..8d728a6a5991 100644
--- a/drivers/tty/serial/8250/8250_lpc18xx.c
+++ b/drivers/tty/serial/8250/8250_lpc18xx.c
@@ -182,15 +182,13 @@ dis_clk_reg:
return ret;
}
-static int lpc18xx_serial_remove(struct platform_device *pdev)
+static void lpc18xx_serial_remove(struct platform_device *pdev)
{
struct lpc18xx_uart_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
clk_disable_unprepare(data->clk_uart);
clk_disable_unprepare(data->clk_reg);
-
- return 0;
}
static const struct of_device_id lpc18xx_serial_match[] = {
@@ -201,7 +199,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_serial_match);
static struct platform_driver lpc18xx_serial_driver = {
.probe = lpc18xx_serial_probe,
- .remove = lpc18xx_serial_remove,
+ .remove_new = lpc18xx_serial_remove,
.driver = {
.name = "lpc18xx-uart",
.of_match_table = lpc18xx_serial_match,
diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c
index 0e43bdfb7459..776ec1ef29d6 100644
--- a/drivers/tty/serial/8250/8250_lpss.c
+++ b/drivers/tty/serial/8250/8250_lpss.c
@@ -287,17 +287,14 @@ static int lpss8250_dma_setup(struct lpss8250 *lpss, struct uart_8250_port *port
return 0;
}
- rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
+ rx_param = devm_kmemdup(dev, &lpss->dma_param, sizeof(*rx_param), GFP_KERNEL);
if (!rx_param)
return -ENOMEM;
- tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL);
+ tx_param = devm_kmemdup(dev, &lpss->dma_param, sizeof(*tx_param), GFP_KERNEL);
if (!tx_param)
return -ENOMEM;
- *rx_param = lpss->dma_param;
- *tx_param = lpss->dma_param;
-
dma->fn = lpss8250_dma_filter;
dma->rx_param = rx_param;
dma->tx_param = tx_param;
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index 23457daae8a1..9ff6bbe9c086 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -581,7 +581,7 @@ static int mtk8250_probe(struct platform_device *pdev)
return 0;
}
-static int mtk8250_remove(struct platform_device *pdev)
+static void mtk8250_remove(struct platform_device *pdev)
{
struct mtk8250_data *data = platform_get_drvdata(pdev);
@@ -591,8 +591,6 @@ static int mtk8250_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
-
- return 0;
}
static int __maybe_unused mtk8250_suspend(struct device *dev)
@@ -652,7 +650,7 @@ static struct platform_driver mtk8250_platform_driver = {
.of_match_table = mtk8250_of_match,
},
.probe = mtk8250_probe,
- .remove = mtk8250_remove,
+ .remove_new = mtk8250_remove,
};
module_platform_driver(mtk8250_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index ef3e745bd09c..34f17a9785e7 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -251,7 +251,7 @@ err_free:
/*
* Release a line
*/
-static int of_platform_serial_remove(struct platform_device *ofdev)
+static void of_platform_serial_remove(struct platform_device *ofdev)
{
struct of_serial_info *info = platform_get_drvdata(ofdev);
@@ -261,7 +261,6 @@ static int of_platform_serial_remove(struct platform_device *ofdev)
pm_runtime_put_sync(&ofdev->dev);
pm_runtime_disable(&ofdev->dev);
kfree(info);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -337,7 +336,7 @@ static struct platform_driver of_platform_serial_driver = {
.pm = &of_serial_pm_ops,
},
.probe = of_platform_serial_probe,
- .remove = of_platform_serial_remove,
+ .remove_new = of_platform_serial_remove,
};
module_platform_driver(of_platform_serial_driver);
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 578f35895b27..6942990a333c 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -1586,7 +1586,7 @@ err:
return ret;
}
-static int omap8250_remove(struct platform_device *pdev)
+static void omap8250_remove(struct platform_device *pdev)
{
struct omap8250_priv *priv = platform_get_drvdata(pdev);
struct uart_8250_port *up;
@@ -1594,7 +1594,7 @@ static int omap8250_remove(struct platform_device *pdev)
err = pm_runtime_resume_and_get(&pdev->dev);
if (err)
- return err;
+ dev_err(&pdev->dev, "Failed to resume hardware\n");
up = serial8250_get_port(priv->line);
omap_8250_shutdown(&up->port);
@@ -1606,7 +1606,6 @@ static int omap8250_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
cpu_latency_qos_remove_request(&priv->pm_qos_request);
device_init_wakeup(&pdev->dev, false);
- return 0;
}
static int omap8250_prepare(struct device *dev)
@@ -1865,7 +1864,7 @@ static struct platform_driver omap8250_platform_driver = {
.of_match_table = omap8250_dt_ids,
},
.probe = omap8250_probe,
- .remove = omap8250_remove,
+ .remove_new = omap8250_remove,
};
module_platform_driver(omap8250_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 614be0f13a31..0d35c77fad9e 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -19,6 +19,7 @@
#include <linux/serial_core.h>
#include <linux/8250_pci.h>
#include <linux/bitops.h>
+#include <linux/bitfield.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -1970,6 +1971,20 @@ pci_sunix_setup(struct serial_private *priv,
#define MOXA_GPIO_PIN2 BIT(2)
+#define MOXA_RS232 0x00
+#define MOXA_RS422 0x01
+#define MOXA_RS485_4W 0x0B
+#define MOXA_RS485_2W 0x0F
+#define MOXA_UIR_OFFSET 0x04
+#define MOXA_EVEN_RS_MASK GENMASK(3, 0)
+#define MOXA_ODD_RS_MASK GENMASK(7, 4)
+
+enum {
+ MOXA_SUPP_RS232 = BIT(0),
+ MOXA_SUPP_RS422 = BIT(1),
+ MOXA_SUPP_RS485 = BIT(2),
+};
+
static bool pci_moxa_is_mini_pcie(unsigned short device)
{
if (device == PCI_DEVICE_ID_MOXA_CP102N ||
@@ -1983,12 +1998,54 @@ static bool pci_moxa_is_mini_pcie(unsigned short device)
return false;
}
+static unsigned int pci_moxa_supported_rs(struct pci_dev *dev)
+{
+ switch (dev->device & 0x0F00) {
+ case 0x0000:
+ case 0x0600:
+ return MOXA_SUPP_RS232;
+ case 0x0100:
+ return MOXA_SUPP_RS232 | MOXA_SUPP_RS422 | MOXA_SUPP_RS485;
+ case 0x0300:
+ return MOXA_SUPP_RS422 | MOXA_SUPP_RS485;
+ }
+ return 0;
+}
+
+static int pci_moxa_set_interface(const struct pci_dev *dev,
+ unsigned int port_idx,
+ u8 mode)
+{
+ resource_size_t iobar_addr = pci_resource_start(dev, 2);
+ resource_size_t UIR_addr = iobar_addr + MOXA_UIR_OFFSET + port_idx / 2;
+ u8 val;
+
+ val = inb(UIR_addr);
+
+ if (port_idx % 2) {
+ val &= ~MOXA_ODD_RS_MASK;
+ val |= FIELD_PREP(MOXA_ODD_RS_MASK, mode);
+ } else {
+ val &= ~MOXA_EVEN_RS_MASK;
+ val |= FIELD_PREP(MOXA_EVEN_RS_MASK, mode);
+ }
+ outb(val, UIR_addr);
+
+ return 0;
+}
+
static int pci_moxa_init(struct pci_dev *dev)
{
unsigned short device = dev->device;
resource_size_t iobar_addr = pci_resource_start(dev, 2);
- unsigned int num_ports = (device & 0x00F0) >> 4;
- u8 val;
+ unsigned int num_ports = (device & 0x00F0) >> 4, i;
+ u8 val, init_mode = MOXA_RS232;
+
+ if (!(pci_moxa_supported_rs(dev) & MOXA_SUPP_RS232)) {
+ init_mode = MOXA_RS422;
+ }
+ for (i = 0; i < num_ports; ++i)
+ pci_moxa_set_interface(dev, i, init_mode);
/*
* Enable hardware buffer to prevent break signal output when system boots up.
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c
index 9f9e21981929..558c4c7f3104 100644
--- a/drivers/tty/serial/8250/8250_pci1xxxx.c
+++ b/drivers/tty/serial/8250/8250_pci1xxxx.c
@@ -9,15 +9,21 @@
#include <linux/bitfield.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/serial_8250.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/units.h>
#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/8250_pci.h>
#include <asm/byteorder.h>
@@ -52,6 +58,17 @@
#define PCI_SUBDEVICE_ID_EFAR_PCI11400 PCI_DEVICE_ID_EFAR_PCI11400
#define PCI_SUBDEVICE_ID_EFAR_PCI11414 PCI_DEVICE_ID_EFAR_PCI11414
+#define UART_SYSTEM_ADDR_BASE 0x1000
+#define UART_DEV_REV_REG (UART_SYSTEM_ADDR_BASE + 0x00)
+#define UART_DEV_REV_MASK GENMASK(7, 0)
+#define UART_SYSLOCK_REG (UART_SYSTEM_ADDR_BASE + 0xA0)
+#define UART_SYSLOCK BIT(2)
+#define SYSLOCK_SLEEP_TIMEOUT 100
+#define SYSLOCK_RETRY_CNT 1000
+
+#define UART_RX_BYTE_FIFO 0x00
+#define UART_FIFO_CTL 0x02
+
#define UART_ACTV_REG 0x11
#define UART_BLOCK_SET_ACTIVE BIT(0)
@@ -82,8 +99,59 @@
#define UART_RESET_REG 0x94
#define UART_RESET_D3_RESET_DISABLE BIT(16)
+#define UART_BURST_STATUS_REG 0x9C
+#define UART_RX_BURST_FIFO 0xA4
+
#define MAX_PORTS 4
#define PORT_OFFSET 0x100
+#define RX_BUF_SIZE 512
+#define UART_BYTE_SIZE 1
+#define UART_BURST_SIZE 4
+
+#define UART_BST_STAT_RX_COUNT_MASK 0x00FF
+#define UART_BST_STAT_IIR_INT_PEND 0x100000
+#define UART_LSR_OVERRUN_ERR_CLR 0x43
+#define UART_BST_STAT_LSR_RX_MASK 0x9F000000
+#define UART_BST_STAT_LSR_RX_ERR_MASK 0x9E000000
+#define UART_BST_STAT_LSR_OVERRUN_ERR 0x2000000
+#define UART_BST_STAT_LSR_PARITY_ERR 0x4000000
+#define UART_BST_STAT_LSR_FRAME_ERR 0x8000000
+
+struct pci1xxxx_8250 {
+ unsigned int nr;
+ u8 dev_rev;
+ u8 pad[3];
+ void __iomem *membase;
+ int line[] __counted_by(nr);
+};
+
+static const struct serial_rs485 pci1xxxx_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RTS_AFTER_SEND,
+ .delay_rts_after_send = 1,
+ /* Delay RTS before send is not supported */
+};
+
+static int pci1xxxx_set_sys_lock(struct pci1xxxx_8250 *port)
+{
+ writel(UART_SYSLOCK, port->membase + UART_SYSLOCK_REG);
+ return readl(port->membase + UART_SYSLOCK_REG);
+}
+
+static int pci1xxxx_acquire_sys_lock(struct pci1xxxx_8250 *port)
+{
+ u32 regval;
+
+ return readx_poll_timeout(pci1xxxx_set_sys_lock, port, regval,
+ (regval & UART_SYSLOCK),
+ SYSLOCK_SLEEP_TIMEOUT,
+ SYSLOCK_RETRY_CNT * SYSLOCK_SLEEP_TIMEOUT);
+}
+
+static void pci1xxxx_release_sys_lock(struct pci1xxxx_8250 *port)
+{
+ writel(0x0, port->membase + UART_SYSLOCK_REG);
+}
static const int logical_to_physical_port_idx[][MAX_PORTS] = {
{0, 1, 2, 3}, /* PCI12000, PCI11010, PCI11101, PCI11400, PCI11414 */
@@ -104,12 +172,6 @@ static const int logical_to_physical_port_idx[][MAX_PORTS] = {
{3, -1, -1, -1}, /* PCI1p3 */
};
-struct pci1xxxx_8250 {
- unsigned int nr;
- void __iomem *membase;
- int line[] __counted_by(nr);
-};
-
static int pci1xxxx_get_num_ports(struct pci_dev *dev)
{
switch (dev->subsystem_device) {
@@ -205,12 +267,102 @@ static int pci1xxxx_rs485_config(struct uart_port *port,
return 0;
}
-static const struct serial_rs485 pci1xxxx_rs485_supported = {
- .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
- SER_RS485_RTS_AFTER_SEND,
- .delay_rts_after_send = 1,
- /* Delay RTS before send is not supported */
-};
+static u32 pci1xxxx_read_burst_status(struct uart_port *port)
+{
+ u32 status;
+
+ status = readl(port->membase + UART_BURST_STATUS_REG);
+ if (status & UART_BST_STAT_LSR_RX_ERR_MASK) {
+ if (status & UART_BST_STAT_LSR_OVERRUN_ERR) {
+ writeb(UART_LSR_OVERRUN_ERR_CLR,
+ port->membase + UART_FIFO_CTL);
+ port->icount.overrun++;
+ }
+
+ if (status & UART_BST_STAT_LSR_FRAME_ERR)
+ port->icount.frame++;
+
+ if (status & UART_BST_STAT_LSR_PARITY_ERR)
+ port->icount.parity++;
+ }
+ return status;
+}
+
+static void pci1xxxx_process_read_data(struct uart_port *port,
+ unsigned char *rx_buff, u32 *buff_index,
+ u32 *valid_byte_count)
+{
+ u32 valid_burst_count = *valid_byte_count / UART_BURST_SIZE;
+ u32 *burst_buf;
+
+ /*
+ * Depending on the RX Trigger Level the number of bytes that can be
+ * stored in RX FIFO at a time varies. Each transaction reads data
+ * in DWORDs. If there are less than four remaining valid_byte_count
+ * to read, the data is received one byte at a time.
+ */
+ while (valid_burst_count--) {
+ if (*buff_index > (RX_BUF_SIZE - UART_BURST_SIZE))
+ break;
+ burst_buf = (u32 *)&rx_buff[*buff_index];
+ *burst_buf = readl(port->membase + UART_RX_BURST_FIFO);
+ *buff_index += UART_BURST_SIZE;
+ *valid_byte_count -= UART_BURST_SIZE;
+ }
+
+ while (*valid_byte_count) {
+ if (*buff_index > RX_BUF_SIZE)
+ break;
+ rx_buff[*buff_index] = readb(port->membase +
+ UART_RX_BYTE_FIFO);
+ *buff_index += UART_BYTE_SIZE;
+ *valid_byte_count -= UART_BYTE_SIZE;
+ }
+}
+
+static void pci1xxxx_rx_burst(struct uart_port *port, u32 uart_status)
+{
+ u32 valid_byte_count = uart_status & UART_BST_STAT_RX_COUNT_MASK;
+ struct tty_port *tty_port = &port->state->port;
+ unsigned char rx_buff[RX_BUF_SIZE];
+ u32 buff_index = 0;
+ u32 copied_len;
+
+ if (valid_byte_count != 0 &&
+ valid_byte_count < RX_BUF_SIZE) {
+ pci1xxxx_process_read_data(port, rx_buff, &buff_index,
+ &valid_byte_count);
+
+ copied_len = (u32)tty_insert_flip_string(tty_port, rx_buff,
+ buff_index);
+
+ if (copied_len != buff_index)
+ port->icount.overrun += buff_index - copied_len;
+
+ port->icount.rx += buff_index;
+ tty_flip_buffer_push(tty_port);
+ }
+}
+
+static int pci1xxxx_handle_irq(struct uart_port *port)
+{
+ unsigned long flags;
+ u32 status;
+
+ status = pci1xxxx_read_burst_status(port);
+
+ if (status & UART_BST_STAT_IIR_INT_PEND)
+ return 0;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (status & UART_BST_STAT_LSR_RX_MASK)
+ pci1xxxx_rx_burst(port, status);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return 1;
+}
static bool pci1xxxx_port_suspend(int line)
{
@@ -323,7 +475,7 @@ static int pci1xxxx_resume(struct device *dev)
}
static int pci1xxxx_setup(struct pci_dev *pdev,
- struct uart_8250_port *port, int port_idx)
+ struct uart_8250_port *port, int port_idx, int rev)
{
int ret;
@@ -335,6 +487,10 @@ static int pci1xxxx_setup(struct pci_dev *pdev,
port->port.rs485_config = pci1xxxx_rs485_config;
port->port.rs485_supported = pci1xxxx_rs485_supported;
+ /* From C0 rev Burst operation is supported */
+ if (rev >= 0xC0)
+ port->port.handle_irq = pci1xxxx_handle_irq;
+
ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0);
if (ret < 0)
return ret;
@@ -370,6 +526,27 @@ static int pci1xxxx_logical_to_physical_port_translate(int subsys_dev, int port)
return logical_to_physical_port_idx[0][port];
}
+static int pci1xxxx_get_device_revision(struct pci1xxxx_8250 *priv)
+{
+ u32 regval;
+ int ret;
+
+ /*
+ * DEV REV is a system register, HW Syslock bit
+ * should be acquired before accessing the register
+ */
+ ret = pci1xxxx_acquire_sys_lock(priv);
+ if (ret)
+ return ret;
+
+ regval = readl(priv->membase + UART_DEV_REV_REG);
+ priv->dev_rev = regval & UART_DEV_REV_MASK;
+
+ pci1xxxx_release_sys_lock(priv);
+
+ return 0;
+}
+
static int pci1xxxx_serial_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -381,6 +558,7 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
int num_vectors;
int subsys_dev;
int port_idx;
+ int ret;
int rc;
rc = pcim_enable_device(pdev);
@@ -397,6 +575,10 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
if (!priv->membase)
return -ENOMEM;
+ ret = pci1xxxx_get_device_revision(priv);
+ if (ret)
+ return ret;
+
pci_set_master(pdev);
priv->nr = nr_ports;
@@ -428,7 +610,7 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
else
uart.port.irq = pci_irq_vector(pdev, 0);
- rc = pci1xxxx_setup(pdev, &uart, port_idx);
+ rc = pci1xxxx_setup(pdev, &uart, port_idx, priv->dev_rev);
if (rc) {
dev_warn(dev, "Failed to setup port %u\n", i);
continue;
diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c
index a5b3ea27fc90..77686da42ce8 100644
--- a/drivers/tty/serial/8250/8250_pxa.c
+++ b/drivers/tty/serial/8250/8250_pxa.c
@@ -146,20 +146,18 @@ static int serial_pxa_probe(struct platform_device *pdev)
return ret;
}
-static int serial_pxa_remove(struct platform_device *pdev)
+static void serial_pxa_remove(struct platform_device *pdev)
{
struct pxa8250_data *data = platform_get_drvdata(pdev);
serial8250_unregister_port(data->line);
clk_unprepare(data->clk);
-
- return 0;
}
static struct platform_driver serial_pxa_driver = {
.probe = serial_pxa_probe,
- .remove = serial_pxa_remove,
+ .remove_new = serial_pxa_remove,
.driver = {
.name = "pxa2xx-uart",
diff --git a/drivers/tty/serial/8250/8250_tegra.c b/drivers/tty/serial/8250/8250_tegra.c
index 89956bbf34d9..ba352262df75 100644
--- a/drivers/tty/serial/8250/8250_tegra.c
+++ b/drivers/tty/serial/8250/8250_tegra.c
@@ -128,15 +128,13 @@ err_clkdisable:
return ret;
}
-static int tegra_uart_remove(struct platform_device *pdev)
+static void tegra_uart_remove(struct platform_device *pdev)
{
struct tegra_uart *uart = platform_get_drvdata(pdev);
serial8250_unregister_port(uart->line);
reset_control_assert(uart->rst);
clk_disable_unprepare(uart->clk);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -192,7 +190,7 @@ static struct platform_driver tegra_uart_driver = {
.acpi_match_table = ACPI_PTR(tegra_uart_acpi_match),
},
.probe = tegra_uart_probe,
- .remove = tegra_uart_remove,
+ .remove_new = tegra_uart_remove,
};
module_platform_driver(tegra_uart_driver);
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index a405155264b1..6399a38ecce2 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -241,14 +241,12 @@ static int uniphier_uart_probe(struct platform_device *pdev)
return 0;
}
-static int uniphier_uart_remove(struct platform_device *pdev)
+static void uniphier_uart_remove(struct platform_device *pdev)
{
struct uniphier8250_priv *priv = platform_get_drvdata(pdev);
serial8250_unregister_port(priv->line);
clk_disable_unprepare(priv->clk);
-
- return 0;
}
static int __maybe_unused uniphier_uart_suspend(struct device *dev)
@@ -293,7 +291,7 @@ MODULE_DEVICE_TABLE(of, uniphier_uart_match);
static struct platform_driver uniphier_uart_platform_driver = {
.probe = uniphier_uart_probe,
- .remove = uniphier_uart_remove,
+ .remove_new = uniphier_uart_remove,
.driver = {
.name = "uniphier-uart",
.of_match_table = uniphier_uart_match,
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index dc2ef05a10eb..2056aed46688 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -90,12 +90,6 @@ struct serial_info {
const struct serial_quirk *quirk;
};
-struct serial_cfg_mem {
- tuple_t tuple;
- cisparse_t parse;
- u_char buf[256];
-};
-
/*
* vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6"
* manfid 0x0160, 0x0104
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 732c893c8d16..8b1f5756002f 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -532,6 +532,9 @@ config SERIAL_UARTLITE_NR_UARTS
help
Set this to the number of uartlites in your system, or the number
you think you might implement.
+ If maximum number of uartlite serial ports is more than 4, then the
+ driver uses dynamic allocation instead of static allocation for major
+ number.
config SERIAL_SUNCORE
bool
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index 7090b251dd4d..effcba71ea77 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -425,7 +425,7 @@ static int altera_jtaguart_probe(struct platform_device *pdev)
return 0;
}
-static int altera_jtaguart_remove(struct platform_device *pdev)
+static void altera_jtaguart_remove(struct platform_device *pdev)
{
struct uart_port *port;
int i = pdev->id;
@@ -436,8 +436,6 @@ static int altera_jtaguart_remove(struct platform_device *pdev)
port = &altera_jtaguart_ports[i];
uart_remove_one_port(&altera_jtaguart_driver, port);
iounmap(port->membase);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -451,7 +449,7 @@ MODULE_DEVICE_TABLE(of, altera_jtaguart_match);
static struct platform_driver altera_jtaguart_platform_driver = {
.probe = altera_jtaguart_probe,
- .remove = altera_jtaguart_remove,
+ .remove_new = altera_jtaguart_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(altera_jtaguart_match),
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 77835ac68df2..897f0995b2fe 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -305,7 +305,7 @@ static int altera_uart_startup(struct uart_port *port)
int ret;
ret = request_irq(port->irq, altera_uart_interrupt, 0,
- DRV_NAME, port);
+ dev_name(port->dev), port);
if (ret) {
pr_err(DRV_NAME ": unable to attach Altera UART %d "
"interrupt vector=%d\n", port->line, port->irq);
@@ -595,7 +595,7 @@ static int altera_uart_probe(struct platform_device *pdev)
return 0;
}
-static int altera_uart_remove(struct platform_device *pdev)
+static void altera_uart_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
@@ -604,8 +604,6 @@ static int altera_uart_remove(struct platform_device *pdev)
port->mapbase = 0;
iounmap(port->membase);
}
-
- return 0;
}
#ifdef CONFIG_OF
@@ -619,7 +617,7 @@ MODULE_DEVICE_TABLE(of, altera_uart_match);
static struct platform_driver altera_uart_platform_driver = {
.probe = altera_uart_probe,
- .remove = altera_uart_remove,
+ .remove_new = altera_uart_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(altera_uart_match),
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index b7635363373e..fccec1698a54 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -50,8 +50,8 @@
#define AMBA_ISR_PASS_LIMIT 256
-#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
-#define UART_DUMMY_DR_RX (1 << 16)
+#define UART_DR_ERROR (UART011_DR_OE | UART011_DR_BE | UART011_DR_PE | UART011_DR_FE)
+#define UART_DUMMY_DR_RX BIT(16)
enum {
REG_DR,
@@ -125,7 +125,7 @@ static unsigned int get_fifosize_arm(struct amba_device *dev)
static struct vendor_data vendor_arm = {
.reg_offset = pl011_std_offsets,
- .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
+ .ifls = UART011_IFLS_RX4_8 | UART011_IFLS_TX4_8,
.fr_busy = UART01x_FR_BUSY,
.fr_dsr = UART01x_FR_DSR,
.fr_cts = UART01x_FR_CTS,
@@ -203,7 +203,7 @@ static unsigned int get_fifosize_st(struct amba_device *dev)
static struct vendor_data vendor_st = {
.reg_offset = pl011_st_offsets,
- .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
+ .ifls = UART011_IFLS_RX_HALF | UART011_IFLS_TX_HALF,
.fr_busy = UART01x_FR_BUSY,
.fr_dsr = UART01x_FR_DSR,
.fr_cts = UART01x_FR_CTS,
@@ -277,13 +277,13 @@ struct uart_amba_port {
static unsigned int pl011_tx_empty(struct uart_port *port);
static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap,
- unsigned int reg)
+ unsigned int reg)
{
return uap->reg_offset[reg];
}
static unsigned int pl011_read(const struct uart_amba_port *uap,
- unsigned int reg)
+ unsigned int reg)
{
void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg);
@@ -292,7 +292,7 @@ static unsigned int pl011_read(const struct uart_amba_port *uap,
}
static void pl011_write(unsigned int val, const struct uart_amba_port *uap,
- unsigned int reg)
+ unsigned int reg)
{
void __iomem *addr = uap->port.membase + pl011_reg_to_offset(uap, reg);
@@ -330,10 +330,11 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
uap->port.icount.brk++;
if (uart_handle_break(&uap->port))
continue;
- } else if (ch & UART011_DR_PE)
+ } else if (ch & UART011_DR_PE) {
uap->port.icount.parity++;
- else if (ch & UART011_DR_FE)
+ } else if (ch & UART011_DR_FE) {
uap->port.icount.frame++;
+ }
if (ch & UART011_DR_OE)
uap->port.icount.overrun++;
@@ -358,7 +359,6 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
return fifotaken;
}
-
/*
* All the DMA operation mode stuff goes inside this ifdef.
* This assumes that you have a generic DMA device interface,
@@ -369,7 +369,7 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
#define PL011_DMA_BUFFER_SIZE PAGE_SIZE
static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db,
- enum dma_data_direction dir)
+ enum dma_data_direction dir)
{
db->buf = dma_alloc_coherent(chan->device->dev, PL011_DMA_BUFFER_SIZE,
&db->dma, GFP_KERNEL);
@@ -381,7 +381,7 @@ static int pl011_dmabuf_init(struct dma_chan *chan, struct pl011_dmabuf *db,
}
static void pl011_dmabuf_free(struct dma_chan *chan, struct pl011_dmabuf *db,
- enum dma_data_direction dir)
+ enum dma_data_direction dir)
{
if (db->buf) {
dma_free_coherent(chan->device->dev,
@@ -424,7 +424,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
dma_cap_set(DMA_SLAVE, mask);
chan = dma_request_channel(mask, plat->dma_filter,
- plat->dma_tx_param);
+ plat->dma_tx_param);
if (!chan) {
dev_err(uap->port.dev, "no TX DMA channel!\n");
return;
@@ -438,9 +438,9 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
dma_chan_name(uap->dmatx.chan));
/* Optionally make use of an RX channel as well */
- chan = dma_request_slave_channel(dev, "rx");
+ chan = dma_request_chan(dev, "rx");
- if (!chan && plat && plat->dma_rx_param) {
+ if (IS_ERR(chan) && plat && plat->dma_rx_param) {
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
if (!chan) {
@@ -449,7 +449,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
}
}
- if (chan) {
+ if (!IS_ERR(chan)) {
struct dma_slave_config rx_conf = {
.src_addr = uap->port.mapbase +
pl011_reg_to_offset(uap, REG_DR),
@@ -465,12 +465,12 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
* If the controller does, check for suitable residue processing
* otherwise assime all is well.
*/
- if (0 == dma_get_slave_caps(chan, &caps)) {
+ if (dma_get_slave_caps(chan, &caps) == 0) {
if (caps.residue_granularity ==
DMA_RESIDUE_GRANULARITY_DESCRIPTOR) {
dma_release_channel(chan);
dev_info(uap->port.dev,
- "RX DMA disabled - no residue processing\n");
+ "RX DMA disabled - no residue processing\n");
return;
}
}
@@ -499,18 +499,16 @@ static void pl011_dma_probe(struct uart_amba_port *uap)
else
uap->dmarx.poll_timeout = 3000;
} else if (!plat && dev->of_node) {
- uap->dmarx.auto_poll_rate = of_property_read_bool(
- dev->of_node, "auto-poll");
+ uap->dmarx.auto_poll_rate =
+ of_property_read_bool(dev->of_node, "auto-poll");
if (uap->dmarx.auto_poll_rate) {
u32 x;
- if (0 == of_property_read_u32(dev->of_node,
- "poll-rate-ms", &x))
+ if (of_property_read_u32(dev->of_node, "poll-rate-ms", &x) == 0)
uap->dmarx.poll_rate = x;
else
uap->dmarx.poll_rate = 100;
- if (0 == of_property_read_u32(dev->of_node,
- "poll-timeout-ms", &x))
+ if (of_property_read_u32(dev->of_node, "poll-timeout-ms", &x) == 0)
uap->dmarx.poll_timeout = x;
else
uap->dmarx.poll_timeout = 3000;
@@ -547,7 +545,7 @@ static void pl011_dma_tx_callback(void *data)
uart_port_lock_irqsave(&uap->port, &flags);
if (uap->dmatx.queued)
dma_unmap_single(dmatx->chan->device->dev, dmatx->dma,
- dmatx->len, DMA_TO_DEVICE);
+ dmatx->len, DMA_TO_DEVICE);
dmacr = uap->dmacr;
uap->dmacr = dmacr & ~UART011_TXDMAE;
@@ -618,9 +616,9 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
if (count > PL011_DMA_BUFFER_SIZE)
count = PL011_DMA_BUFFER_SIZE;
- if (xmit->tail < xmit->head)
+ if (xmit->tail < xmit->head) {
memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
- else {
+ } else {
size_t first = UART_XMIT_SIZE - xmit->tail;
size_t second;
@@ -643,7 +641,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
}
desc = dmaengine_prep_slave_single(chan, dmatx->dma, dmatx->len, DMA_MEM_TO_DEV,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
dma_unmap_single(dma_dev->dev, dmatx->dma, dmatx->len, DMA_TO_DEVICE);
uap->dmatx.queued = false;
@@ -754,8 +752,9 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap)
if (pl011_dma_tx_refill(uap) > 0) {
uap->im &= ~UART011_TXIM;
pl011_write(uap->im, uap, REG_IMSC);
- } else
+ } else {
ret = false;
+ }
} else if (!(uap->dmacr & UART011_TXDMAE)) {
uap->dmacr |= UART011_TXDMAE;
pl011_write(uap->dmacr, uap, REG_DMACR);
@@ -832,8 +831,8 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap)
dbuf = uap->dmarx.use_buf_b ?
&uap->dmarx.dbuf_b : &uap->dmarx.dbuf_a;
desc = dmaengine_prep_slave_single(rxchan, dbuf->dma, dbuf->len,
- DMA_DEV_TO_MEM,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
/*
* If the DMA engine is busy and cannot prepare a
* channel, no big deal, the driver will fall back
@@ -889,14 +888,12 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
/* Pick the remain data from the DMA */
if (pending) {
-
/*
* First take all chars in the DMA pipe, then look in the FIFO.
* Note that tty_insert_flip_buf() tries to take as many chars
* as it can.
*/
- dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken,
- pending);
+ dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken, pending);
uap->port.icount.rx += dma_count;
if (dma_count < pending)
@@ -978,8 +975,8 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap)
/* Switch buffer & re-trigger DMA job */
dmarx->use_buf_b = !dmarx->use_buf_b;
if (pl011_dma_rx_trigger_dma(uap)) {
- dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
- "fall back to interrupt mode\n");
+ dev_dbg(uap->port.dev,
+ "could not retrigger RX DMA job fall back to interrupt mode\n");
uap->im |= UART011_RXIM;
pl011_write(uap->im, uap, REG_IMSC);
}
@@ -1026,8 +1023,8 @@ static void pl011_dma_rx_callback(void *data)
* get some IRQ immediately from RX.
*/
if (ret) {
- dev_dbg(uap->port.dev, "could not retrigger RX DMA job "
- "fall back to interrupt mode\n");
+ dev_dbg(uap->port.dev,
+ "could not retrigger RX DMA job fall back to interrupt mode\n");
uap->im |= UART011_RXIM;
pl011_write(uap->im, uap, REG_IMSC);
}
@@ -1072,7 +1069,7 @@ static void pl011_dma_rx_poll(struct timer_list *t)
dmataken = dbuf->len - dmarx->last_residue;
size = dmarx->last_residue - state.residue;
dma_count = tty_insert_flip_string(port, dbuf->buf + dmataken,
- size);
+ size);
if (dma_count == size)
dmarx->last_residue = state.residue;
dmarx->last_jiffies = jiffies;
@@ -1085,7 +1082,6 @@ static void pl011_dma_rx_poll(struct timer_list *t)
*/
if (jiffies_to_msecs(jiffies - dmarx->last_jiffies)
> uap->dmarx.poll_timeout) {
-
uart_port_lock_irqsave(&uap->port, &flags);
pl011_dma_rx_stop(uap);
uap->im |= UART011_RXIM;
@@ -1097,7 +1093,7 @@ static void pl011_dma_rx_poll(struct timer_list *t)
del_timer(&uap->dmarx.timer);
} else {
mod_timer(&uap->dmarx.timer,
- jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
+ jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
}
}
@@ -1113,7 +1109,6 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
uap->dmatx.buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL | __GFP_DMA);
if (!uap->dmatx.buf) {
- dev_err(uap->port.dev, "no memory for DMA TX buffer\n");
uap->port.fifosize = uap->fifosize;
return;
}
@@ -1129,7 +1124,7 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
/* Allocate and map DMA RX buffers */
ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_a,
- DMA_FROM_DEVICE);
+ DMA_FROM_DEVICE);
if (ret) {
dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
"RX buffer A", ret);
@@ -1137,12 +1132,12 @@ static void pl011_dma_startup(struct uart_amba_port *uap)
}
ret = pl011_dmabuf_init(uap->dmarx.chan, &uap->dmarx.dbuf_b,
- DMA_FROM_DEVICE);
+ DMA_FROM_DEVICE);
if (ret) {
dev_err(uap->port.dev, "failed to init DMA %s: %d\n",
"RX buffer B", ret);
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a,
- DMA_FROM_DEVICE);
+ DMA_FROM_DEVICE);
goto skip_rx;
}
@@ -1164,13 +1159,12 @@ skip_rx:
if (uap->using_rx_dma) {
if (pl011_dma_rx_trigger_dma(uap))
- dev_dbg(uap->port.dev, "could not trigger initial "
- "RX DMA job, fall back to interrupt mode\n");
+ dev_dbg(uap->port.dev,
+ "could not trigger initial RX DMA job, fall back to interrupt mode\n");
if (uap->dmarx.poll_rate) {
timer_setup(&uap->dmarx.timer, pl011_dma_rx_poll, 0);
mod_timer(&uap->dmarx.timer,
- jiffies +
- msecs_to_jiffies(uap->dmarx.poll_rate));
+ jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
uap->dmarx.last_jiffies = jiffies;
}
@@ -1359,8 +1353,8 @@ static void pl011_stop_rx(struct uart_port *port)
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM|
- UART011_PEIM|UART011_BEIM|UART011_OEIM);
+ uap->im &= ~(UART011_RXIM | UART011_RTIM | UART011_FEIM |
+ UART011_PEIM | UART011_BEIM | UART011_OEIM);
pl011_write(uap->im, uap, REG_IMSC);
pl011_dma_rx_stop(uap);
@@ -1380,7 +1374,7 @@ static void pl011_enable_ms(struct uart_port *port)
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
- uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM;
+ uap->im |= UART011_RIMIM | UART011_CTSMIM | UART011_DCDMIM | UART011_DSRMIM;
pl011_write(uap->im, uap, REG_IMSC);
}
@@ -1398,8 +1392,8 @@ __acquires(&uap->port.lock)
*/
if (pl011_dma_rx_available(uap)) {
if (pl011_dma_rx_trigger_dma(uap)) {
- dev_dbg(uap->port.dev, "could not trigger RX DMA job "
- "fall back to interrupt mode again\n");
+ dev_dbg(uap->port.dev,
+ "could not trigger RX DMA job fall back to interrupt mode again\n");
uap->im |= UART011_RXIM;
pl011_write(uap->im, uap, REG_IMSC);
} else {
@@ -1409,8 +1403,7 @@ __acquires(&uap->port.lock)
uap->dmarx.last_jiffies = jiffies;
uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
mod_timer(&uap->dmarx.timer,
- jiffies +
- msecs_to_jiffies(uap->dmarx.poll_rate));
+ jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
}
#endif
}
@@ -1557,18 +1550,17 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
do {
check_apply_cts_event_workaround(uap);
- pl011_write(status & ~(UART011_TXIS|UART011_RTIS|
- UART011_RXIS),
+ pl011_write(status & ~(UART011_TXIS | UART011_RTIS | UART011_RXIS),
uap, REG_ICR);
- if (status & (UART011_RTIS|UART011_RXIS)) {
+ if (status & (UART011_RTIS | UART011_RXIS)) {
if (pl011_dma_rx_running(uap))
pl011_dma_rx_irq(uap);
else
pl011_rx_chars(uap);
}
- if (status & (UART011_DSRMIS|UART011_DCDMIS|
- UART011_CTSMIS|UART011_RIMIS))
+ if (status & (UART011_DSRMIS | UART011_DCDMIS |
+ UART011_CTSMIS | UART011_RIMIS))
pl011_modem_status(uap);
if (status & UART011_TXIS)
pl011_tx_chars(uap, true);
@@ -1598,6 +1590,12 @@ static unsigned int pl011_tx_empty(struct uart_port *port)
0 : TIOCSER_TEMT;
}
+static void pl011_maybe_set_bit(bool cond, unsigned int *ptr, unsigned int mask)
+{
+ if (cond)
+ *ptr |= mask;
+}
+
static unsigned int pl011_get_mctrl(struct uart_port *port)
{
struct uart_amba_port *uap =
@@ -1605,18 +1603,22 @@ static unsigned int pl011_get_mctrl(struct uart_port *port)
unsigned int result = 0;
unsigned int status = pl011_read(uap, REG_FR);
-#define TIOCMBIT(uartbit, tiocmbit) \
- if (status & uartbit) \
- result |= tiocmbit
+ pl011_maybe_set_bit(status & UART01x_FR_DCD, &result, TIOCM_CAR);
+ pl011_maybe_set_bit(status & uap->vendor->fr_dsr, &result, TIOCM_DSR);
+ pl011_maybe_set_bit(status & uap->vendor->fr_cts, &result, TIOCM_CTS);
+ pl011_maybe_set_bit(status & uap->vendor->fr_ri, &result, TIOCM_RNG);
- TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR);
- TIOCMBIT(uap->vendor->fr_dsr, TIOCM_DSR);
- TIOCMBIT(uap->vendor->fr_cts, TIOCM_CTS);
- TIOCMBIT(uap->vendor->fr_ri, TIOCM_RNG);
-#undef TIOCMBIT
return result;
}
+static void pl011_assign_bit(bool cond, unsigned int *ptr, unsigned int mask)
+{
+ if (cond)
+ *ptr |= mask;
+ else
+ *ptr &= ~mask;
+}
+
static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_amba_port *uap =
@@ -1625,23 +1627,16 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
cr = pl011_read(uap, REG_CR);
-#define TIOCMBIT(tiocmbit, uartbit) \
- if (mctrl & tiocmbit) \
- cr |= uartbit; \
- else \
- cr &= ~uartbit
-
- TIOCMBIT(TIOCM_RTS, UART011_CR_RTS);
- TIOCMBIT(TIOCM_DTR, UART011_CR_DTR);
- TIOCMBIT(TIOCM_OUT1, UART011_CR_OUT1);
- TIOCMBIT(TIOCM_OUT2, UART011_CR_OUT2);
- TIOCMBIT(TIOCM_LOOP, UART011_CR_LBE);
+ pl011_assign_bit(mctrl & TIOCM_RTS, &cr, UART011_CR_RTS);
+ pl011_assign_bit(mctrl & TIOCM_DTR, &cr, UART011_CR_DTR);
+ pl011_assign_bit(mctrl & TIOCM_OUT1, &cr, UART011_CR_OUT1);
+ pl011_assign_bit(mctrl & TIOCM_OUT2, &cr, UART011_CR_OUT2);
+ pl011_assign_bit(mctrl & TIOCM_LOOP, &cr, UART011_CR_LBE);
if (port->status & UPSTAT_AUTORTS) {
/* We need to disable auto-RTS if we want to turn RTS off */
- TIOCMBIT(TIOCM_RTS, UART011_CR_RTSEN);
+ pl011_assign_bit(mctrl & TIOCM_RTS, &cr, UART011_CR_RTSEN);
}
-#undef TIOCMBIT
pl011_write(cr, uap, REG_CR);
}
@@ -1707,8 +1702,7 @@ static int pl011_get_poll_char(struct uart_port *port)
return pl011_read(uap, REG_DR);
}
-static void pl011_put_poll_char(struct uart_port *port,
- unsigned char ch)
+static void pl011_put_poll_char(struct uart_port *port, unsigned char ch)
{
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
@@ -1909,14 +1903,13 @@ static int sbsa_uart_startup(struct uart_port *port)
return 0;
}
-static void pl011_shutdown_channel(struct uart_amba_port *uap,
- unsigned int lcrh)
+static void pl011_shutdown_channel(struct uart_amba_port *uap, unsigned int lcrh)
{
- unsigned long val;
+ unsigned long val;
- val = pl011_read(uap, lcrh);
- val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
- pl011_write(val, uap, lcrh);
+ val = pl011_read(uap, lcrh);
+ val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
+ pl011_write(val, uap, lcrh);
}
/*
@@ -2065,7 +2058,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
uap->dmarx.poll_rate = DIV_ROUND_UP(10000000, baud);
#endif
- if (baud > port->uartclk/16)
+ if (baud > port->uartclk / 16)
quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
else
quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);
@@ -2147,9 +2140,9 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
* else we see data corruption.
*/
if (uap->vendor->oversampling) {
- if ((baud >= 3000000) && (baud < 3250000) && (quot > 1))
+ if (baud >= 3000000 && baud < 3250000 && quot > 1)
quot -= 1;
- else if ((baud > 3250000) && (quot > 2))
+ else if (baud > 3250000 && quot > 2)
quot -= 2;
}
/* Set baud rate */
@@ -2218,13 +2211,14 @@ static void pl011_config_port(struct uart_port *port, int flags)
static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
{
int ret = 0;
+
if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
ret = -EINVAL;
if (ser->irq < 0 || ser->irq >= nr_irqs)
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
- if (port->mapbase != (unsigned long) ser->iomem_base)
+ if (port->mapbase != (unsigned long)ser->iomem_base)
ret = -EINVAL;
return ret;
}
@@ -2369,35 +2363,34 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
int *parity, int *bits)
{
- if (pl011_read(uap, REG_CR) & UART01x_CR_UARTEN) {
- unsigned int lcr_h, ibrd, fbrd;
+ unsigned int lcr_h, ibrd, fbrd;
- lcr_h = pl011_read(uap, REG_LCRH_TX);
+ if (!(pl011_read(uap, REG_CR) & UART01x_CR_UARTEN))
+ return;
- *parity = 'n';
- if (lcr_h & UART01x_LCRH_PEN) {
- if (lcr_h & UART01x_LCRH_EPS)
- *parity = 'e';
- else
- *parity = 'o';
- }
+ lcr_h = pl011_read(uap, REG_LCRH_TX);
- if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
- *bits = 7;
+ *parity = 'n';
+ if (lcr_h & UART01x_LCRH_PEN) {
+ if (lcr_h & UART01x_LCRH_EPS)
+ *parity = 'e';
else
- *bits = 8;
+ *parity = 'o';
+ }
+
+ if ((lcr_h & 0x60) == UART01x_LCRH_WLEN_7)
+ *bits = 7;
+ else
+ *bits = 8;
- ibrd = pl011_read(uap, REG_IBRD);
- fbrd = pl011_read(uap, REG_FBRD);
+ ibrd = pl011_read(uap, REG_IBRD);
+ fbrd = pl011_read(uap, REG_FBRD);
- *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
+ *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);
- if (uap->vendor->oversampling) {
- if (pl011_read(uap, REG_CR)
- & ST_UART011_CR_OVSFACT)
- *baud *= 2;
- }
- }
+ if (uap->vendor->oversampling &&
+ (pl011_read(uap, REG_CR) & ST_UART011_CR_OVSFACT))
+ *baud *= 2;
}
static int pl011_console_setup(struct console *co, char *options)
@@ -2533,7 +2526,7 @@ static void qdf2400_e44_putc(struct uart_port *port, unsigned char c)
cpu_relax();
}
-static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned n)
+static void qdf2400_e44_early_write(struct console *con, const char *s, unsigned int n)
{
struct earlycon_device *dev = con->data;
@@ -2552,7 +2545,7 @@ static void pl011_putc(struct uart_port *port, unsigned char c)
cpu_relax();
}
-static void pl011_early_write(struct console *con, const char *s, unsigned n)
+static void pl011_early_write(struct console *con, const char *s, unsigned int n)
{
struct earlycon_device *dev = con->data;
@@ -2613,7 +2606,9 @@ static int __init pl011_early_console_setup(struct earlycon_device *device,
return 0;
}
+
OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
+
OF_EARLYCON_DECLARE(pl011, "arm,sbsa-uart", pl011_early_console_setup);
/*
@@ -2636,6 +2631,7 @@ qdf2400_e44_early_console_setup(struct earlycon_device *device,
device->con->write = qdf2400_e44_early_write;
return 0;
}
+
EARLYCON_DECLARE(qdf2400_e44, qdf2400_e44_early_console_setup);
#else
@@ -2655,8 +2651,8 @@ static struct uart_driver amba_reg = {
static int pl011_probe_dt_alias(int index, struct device *dev)
{
struct device_node *np;
- static bool seen_dev_with_alias = false;
- static bool seen_dev_without_alias = false;
+ static bool seen_dev_with_alias;
+ static bool seen_dev_without_alias;
int ret = index;
if (!IS_ENABLED(CONFIG_OF))
@@ -2672,7 +2668,7 @@ static int pl011_probe_dt_alias(int index, struct device *dev)
ret = index;
} else {
seen_dev_with_alias = true;
- if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret] != NULL) {
+ if (ret >= ARRAY_SIZE(amba_ports) || amba_ports[ret]) {
dev_warn(dev, "requested serial port %d not available.\n", ret);
ret = index;
}
@@ -2706,7 +2702,7 @@ static int pl011_find_free_port(void)
int i;
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
- if (amba_ports[i] == NULL)
+ if (!amba_ports[i])
return i;
return -EBUSY;
@@ -2873,6 +2869,22 @@ static int pl011_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume);
+#ifdef CONFIG_ACPI_SPCR_TABLE
+static void qpdf2400_erratum44_workaround(struct device *dev,
+ struct uart_amba_port *uap)
+{
+ if (!qdf2400_e44_present)
+ return;
+
+ dev_info(dev, "working around QDF2400 SoC erratum 44\n");
+ uap->vendor = &vendor_qdt_qdf2400_e44;
+}
+#else
+static void qpdf2400_erratum44_workaround(struct device *dev,
+ struct uart_amba_port *uap)
+{ /* empty */ }
+#endif
+
static int sbsa_uart_probe(struct platform_device *pdev)
{
struct uart_amba_port *uap;
@@ -2908,13 +2920,8 @@ static int sbsa_uart_probe(struct platform_device *pdev)
return ret;
uap->port.irq = ret;
-#ifdef CONFIG_ACPI_SPCR_TABLE
- if (qdf2400_e44_present) {
- dev_info(&pdev->dev, "working around QDF2400 SoC erratum 44\n");
- uap->vendor = &vendor_qdt_qdf2400_e44;
- } else
-#endif
- uap->vendor = &vendor_sbsa;
+ uap->vendor = &vendor_sbsa;
+ qpdf2400_erratum44_workaround(&pdev->dev, uap);
uap->reg_offset = uap->vendor->reg_offset;
uap->fifosize = 32;
@@ -2935,13 +2942,12 @@ static int sbsa_uart_probe(struct platform_device *pdev)
return pl011_register_port(uap);
}
-static int sbsa_uart_remove(struct platform_device *pdev)
+static void sbsa_uart_remove(struct platform_device *pdev)
{
struct uart_amba_port *uap = platform_get_drvdata(pdev);
uart_remove_one_port(&amba_reg, &uap->port);
pl011_unregister_port(uap);
- return 0;
}
static const struct of_device_id sbsa_uart_of_match[] = {
@@ -2959,7 +2965,7 @@ MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match);
static struct platform_driver arm_sbsa_uart_platform_driver = {
.probe = sbsa_uart_probe,
- .remove = sbsa_uart_remove,
+ .remove_new = sbsa_uart_remove,
.driver = {
.name = "sbsa-uart",
.pm = &pl011_dev_pm_ops,
@@ -2998,7 +3004,7 @@ static struct amba_driver pl011_driver = {
static int __init pl011_init(void)
{
- printk(KERN_INFO "Serial: AMBA PL011 UART driver\n");
+ pr_info("Serial: AMBA PL011 UART driver\n");
if (platform_driver_register(&arm_sbsa_uart_platform_driver))
pr_warn("could not register SBSA UART platform driver\n");
diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c
index 716cb014c028..364599f256db 100644
--- a/drivers/tty/serial/apbuart.c
+++ b/drivers/tty/serial/apbuart.c
@@ -122,7 +122,7 @@ static void apbuart_tx_chars(struct uart_port *port)
{
u8 ch;
- uart_port_tx_limited(port, ch, port->fifosize >> 1,
+ uart_port_tx_limited(port, ch, port->fifosize,
true,
UART_PUT_CHAR(port, ch),
({}));
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index ffd234673177..8d09ace062e5 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -818,7 +818,7 @@ err_disable_clk:
return ret;
}
-static int ar933x_uart_remove(struct platform_device *pdev)
+static void ar933x_uart_remove(struct platform_device *pdev)
{
struct ar933x_uart_port *up;
@@ -828,8 +828,6 @@ static int ar933x_uart_remove(struct platform_device *pdev)
uart_remove_one_port(&ar933x_uart_driver, &up->port);
clk_disable_unprepare(up->clk);
}
-
- return 0;
}
#ifdef CONFIG_OF
@@ -842,7 +840,7 @@ MODULE_DEVICE_TABLE(of, ar933x_uart_of_ids);
static struct platform_driver ar933x_uart_platform_driver = {
.probe = ar933x_uart_probe,
- .remove = ar933x_uart_remove,
+ .remove_new = ar933x_uart_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(ar933x_uart_of_ids),
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 1946fafc3f3e..85667f709515 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -1013,14 +1013,18 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
struct device *mfd_dev = port->dev->parent;
dma_cap_mask_t mask;
struct dma_slave_config config;
+ struct dma_chan *chan;
int ret, nent;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- atmel_port->chan_tx = dma_request_slave_channel(mfd_dev, "tx");
- if (atmel_port->chan_tx == NULL)
+ chan = dma_request_chan(mfd_dev, "tx");
+ if (IS_ERR(chan)) {
+ atmel_port->chan_tx = NULL;
goto chan_err;
+ }
+ atmel_port->chan_tx = chan;
dev_info(port->dev, "using %s for tx DMA transfers\n",
dma_chan_name(atmel_port->chan_tx));
@@ -1188,6 +1192,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
dma_cap_mask_t mask;
struct dma_slave_config config;
struct circ_buf *ring;
+ struct dma_chan *chan;
int ret, nent;
ring = &atmel_port->rx_ring;
@@ -1195,9 +1200,12 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
dma_cap_zero(mask);
dma_cap_set(DMA_CYCLIC, mask);
- atmel_port->chan_rx = dma_request_slave_channel(mfd_dev, "rx");
- if (atmel_port->chan_rx == NULL)
+ chan = dma_request_chan(mfd_dev, "rx");
+ if (IS_ERR(chan)) {
+ atmel_port->chan_rx = NULL;
goto chan_err;
+ }
+ atmel_port->chan_rx = chan;
dev_info(port->dev, "using %s for rx DMA transfers\n",
dma_chan_name(atmel_port->chan_rx));
@@ -3001,7 +3009,7 @@ err:
* protocol that needs bitbanging on IO lines, but use the regular serial
* port in the normal case.
*/
-static int atmel_serial_remove(struct platform_device *pdev)
+static void atmel_serial_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -3020,8 +3028,6 @@ static int atmel_serial_remove(struct platform_device *pdev)
clear_bit(port->line, atmel_ports_in_use);
pdev->dev.of_node = NULL;
-
- return 0;
}
static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend,
@@ -3029,7 +3035,7 @@ static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend,
static struct platform_driver atmel_serial_driver = {
.probe = atmel_serial_probe,
- .remove = atmel_serial_remove,
+ .remove_new = atmel_serial_remove,
.driver = {
.name = "atmel_usart_serial",
.of_match_table = of_match_ptr(atmel_serial_dt_ids),
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index 4a08fd5ee61b..a3cefa153456 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -868,7 +868,7 @@ static int bcm_uart_probe(struct platform_device *pdev)
return 0;
}
-static int bcm_uart_remove(struct platform_device *pdev)
+static void bcm_uart_remove(struct platform_device *pdev)
{
struct uart_port *port;
@@ -876,7 +876,6 @@ static int bcm_uart_remove(struct platform_device *pdev)
uart_remove_one_port(&bcm_uart_driver, port);
/* mark port as free */
ports[pdev->id].membase = NULL;
- return 0;
}
static const struct of_device_id bcm63xx_of_match[] = {
@@ -890,7 +889,7 @@ MODULE_DEVICE_TABLE(of, bcm63xx_of_match);
*/
static struct platform_driver bcm_uart_platform_driver = {
.probe = bcm_uart_probe,
- .remove = bcm_uart_remove,
+ .remove_new = bcm_uart_remove,
.driver = {
.name = "bcm63xx_uart",
.of_match_table = bcm63xx_of_match,
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 55d19937efbd..7927725b8957 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -510,13 +510,11 @@ static int uart_clps711x_probe(struct platform_device *pdev)
return ret;
}
-static int uart_clps711x_remove(struct platform_device *pdev)
+static void uart_clps711x_remove(struct platform_device *pdev)
{
struct clps711x_port *s = platform_get_drvdata(pdev);
uart_remove_one_port(&clps711x_uart, &s->port);
-
- return 0;
}
static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = {
@@ -531,7 +529,7 @@ static struct platform_driver clps711x_uart_platform = {
.of_match_table = of_match_ptr(clps711x_uart_dt_ids),
},
.probe = uart_clps711x_probe,
- .remove = uart_clps711x_remove,
+ .remove_new = uart_clps711x_remove,
};
static int __init uart_clps711x_init(void)
diff --git a/drivers/tty/serial/cpm_uart.c b/drivers/tty/serial/cpm_uart.c
index be4af6eda4c2..df56c6c5afd0 100644
--- a/drivers/tty/serial/cpm_uart.c
+++ b/drivers/tty/serial/cpm_uart.c
@@ -1549,13 +1549,11 @@ static int cpm_uart_probe(struct platform_device *ofdev)
return ret;
}
-static int cpm_uart_remove(struct platform_device *ofdev)
+static void cpm_uart_remove(struct platform_device *ofdev)
{
struct uart_cpm_port *pinfo = platform_get_drvdata(ofdev);
uart_remove_one_port(&cpm_reg, &pinfo->port);
-
- return 0;
}
static const struct of_device_id cpm_uart_match[] = {
@@ -1581,7 +1579,7 @@ static struct platform_driver cpm_uart_driver = {
.of_match_table = cpm_uart_match,
},
.probe = cpm_uart_probe,
- .remove = cpm_uart_remove,
+ .remove_new = cpm_uart_remove,
};
static int __init cpm_uart_init(void)
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
index 5004125f3045..e419c4bde8b7 100644
--- a/drivers/tty/serial/digicolor-usart.c
+++ b/drivers/tty/serial/digicolor-usart.c
@@ -503,13 +503,11 @@ static int digicolor_uart_probe(struct platform_device *pdev)
return uart_add_one_port(&digicolor_uart, &dp->port);
}
-static int digicolor_uart_remove(struct platform_device *pdev)
+static void digicolor_uart_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
uart_remove_one_port(&digicolor_uart, port);
-
- return 0;
}
static const struct of_device_id digicolor_uart_dt_ids[] = {
@@ -524,7 +522,7 @@ static struct platform_driver digicolor_uart_platform = {
.of_match_table = of_match_ptr(digicolor_uart_dt_ids),
},
.probe = digicolor_uart_probe,
- .remove = digicolor_uart_remove,
+ .remove_new = digicolor_uart_remove,
};
static int __init digicolor_uart_init(void)
diff --git a/drivers/tty/serial/esp32_acm.c b/drivers/tty/serial/esp32_acm.c
index cb28a87736aa..d4e8bdb1cdef 100644
--- a/drivers/tty/serial/esp32_acm.c
+++ b/drivers/tty/serial/esp32_acm.c
@@ -8,7 +8,7 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/tty_flip.h>
@@ -413,18 +413,17 @@ static int esp32s3_acm_probe(struct platform_device *pdev)
return uart_add_one_port(&esp32s3_acm_reg, port);
}
-static int esp32s3_acm_remove(struct platform_device *pdev)
+static void esp32s3_acm_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
uart_remove_one_port(&esp32s3_acm_reg, port);
- return 0;
}
static struct platform_driver esp32s3_acm_driver = {
.probe = esp32s3_acm_probe,
- .remove = esp32s3_acm_remove,
+ .remove_new = esp32s3_acm_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = esp32s3_acm_dt_ids,
diff --git a/drivers/tty/serial/esp32_uart.c b/drivers/tty/serial/esp32_uart.c
index 85c9c5ad7cc5..6fc61f323355 100644
--- a/drivers/tty/serial/esp32_uart.c
+++ b/drivers/tty/serial/esp32_uart.c
@@ -9,7 +9,8 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/tty_flip.h>
@@ -678,16 +679,11 @@ static struct uart_driver esp32_uart_reg = {
static int esp32_uart_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- static const struct of_device_id *match;
struct uart_port *port;
struct esp32_port *sport;
struct resource *res;
int ret;
- match = of_match_device(esp32_uart_dt_ids, &pdev->dev);
- if (!match)
- return -ENODEV;
-
sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
if (!sport)
return -ENOMEM;
@@ -728,7 +724,7 @@ static int esp32_uart_probe(struct platform_device *pdev)
port->flags = UPF_BOOT_AUTOCONF;
port->has_sysrq = 1;
port->fifosize = ESP32_UART_TX_FIFO_SIZE;
- port->private_data = (void *)match->data;
+ port->private_data = (void *)device_get_match_data(&pdev->dev);
esp32_uart_ports[port->line] = sport;
@@ -737,19 +733,17 @@ static int esp32_uart_probe(struct platform_device *pdev)
return uart_add_one_port(&esp32_uart_reg, port);
}
-static int esp32_uart_remove(struct platform_device *pdev)
+static void esp32_uart_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
uart_remove_one_port(&esp32_uart_reg, port);
-
- return 0;
}
static struct platform_driver esp32_uart_driver = {
.probe = esp32_uart_probe,
- .remove = esp32_uart_remove,
+ .remove_new = esp32_uart_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = esp32_uart_dt_ids,
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index 3bdaf1ddc309..52c87876a88d 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -851,13 +851,11 @@ static int linflex_probe(struct platform_device *pdev)
return uart_add_one_port(&linflex_reg, sport);
}
-static int linflex_remove(struct platform_device *pdev)
+static void linflex_remove(struct platform_device *pdev)
{
struct uart_port *sport = platform_get_drvdata(pdev);
uart_remove_one_port(&linflex_reg, sport);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -884,7 +882,7 @@ static SIMPLE_DEV_PM_OPS(linflex_pm_ops, linflex_suspend, linflex_resume);
static struct platform_driver linflex_driver = {
.probe = linflex_probe,
- .remove = linflex_remove,
+ .remove_new = linflex_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = linflex_dt_ids,
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 6d0cfb2e86b4..5ddf110aedbe 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -2959,7 +2959,7 @@ failed_reset:
return ret;
}
-static int lpuart_remove(struct platform_device *pdev)
+static void lpuart_remove(struct platform_device *pdev)
{
struct lpuart_port *sport = platform_get_drvdata(pdev);
@@ -2976,7 +2976,6 @@ static int lpuart_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
- return 0;
}
static int lpuart_runtime_suspend(struct device *dev)
@@ -3210,7 +3209,7 @@ static const struct dev_pm_ops lpuart_pm_ops = {
static struct platform_driver lpuart_driver = {
.probe = lpuart_probe,
- .remove = lpuart_remove,
+ .remove_new = lpuart_remove,
.driver = {
.name = "fsl-lpuart",
.of_match_table = lpuart_dt_ids,
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 708b9852a575..4aa72d5aeafb 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -415,13 +415,13 @@ static void imx_uart_stop_tx(struct uart_port *port)
ucr1 = imx_uart_readl(sport, UCR1);
imx_uart_writel(sport, ucr1 & ~UCR1_TRDYEN, UCR1);
+ ucr4 = imx_uart_readl(sport, UCR4);
usr2 = imx_uart_readl(sport, USR2);
- if (!(usr2 & USR2_TXDC)) {
+ if ((!(usr2 & USR2_TXDC)) && (ucr4 & UCR4_TCEN)) {
/* The shifter is still busy, so retry once TC triggers */
return;
}
- ucr4 = imx_uart_readl(sport, UCR4);
ucr4 &= ~UCR4_TCEN;
imx_uart_writel(sport, ucr4, UCR4);
@@ -1336,15 +1336,18 @@ static int imx_uart_dma_init(struct imx_port *sport)
{
struct dma_slave_config slave_config = {};
struct device *dev = sport->port.dev;
+ struct dma_chan *chan;
int ret;
/* Prepare for RX : */
- sport->dma_chan_rx = dma_request_slave_channel(dev, "rx");
- if (!sport->dma_chan_rx) {
+ chan = dma_request_chan(dev, "rx");
+ if (IS_ERR(chan)) {
dev_dbg(dev, "cannot get the DMA channel.\n");
- ret = -EINVAL;
+ sport->dma_chan_rx = NULL;
+ ret = PTR_ERR(chan);
goto err;
}
+ sport->dma_chan_rx = chan;
slave_config.direction = DMA_DEV_TO_MEM;
slave_config.src_addr = sport->port.mapbase + URXD0;
@@ -1366,12 +1369,14 @@ static int imx_uart_dma_init(struct imx_port *sport)
sport->rx_ring.buf = sport->rx_buf;
/* Prepare for TX : */
- sport->dma_chan_tx = dma_request_slave_channel(dev, "tx");
- if (!sport->dma_chan_tx) {
+ chan = dma_request_chan(dev, "tx");
+ if (IS_ERR(chan)) {
dev_err(dev, "cannot get the TX DMA channel!\n");
- ret = -EINVAL;
+ sport->dma_chan_tx = NULL;
+ ret = PTR_ERR(chan);
goto err;
}
+ sport->dma_chan_tx = chan;
slave_config.direction = DMA_MEM_TO_DEV;
slave_config.dst_addr = sport->port.mapbase + URTX0;
@@ -1943,10 +1948,6 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
rs485conf->flags & SER_RS485_RX_DURING_TX)
imx_uart_start_rx(port);
- if (port->rs485_rx_during_tx_gpio)
- gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio,
- !!(rs485conf->flags & SER_RS485_RX_DURING_TX));
-
return 0;
}
@@ -2210,7 +2211,6 @@ static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t)
return HRTIMER_NORESTART;
}
-static const struct serial_rs485 imx_no_rs485 = {}; /* No RS485 if no RTS */
static const struct serial_rs485 imx_rs485_supported = {
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
SER_RS485_RX_DURING_TX,
@@ -2294,8 +2294,6 @@ static int imx_uart_probe(struct platform_device *pdev)
/* RTS is required to control the RS485 transmitter */
if (sport->have_rtscts || sport->have_rtsgpio)
sport->port.rs485_supported = imx_rs485_supported;
- else
- sport->port.rs485_supported = imx_no_rs485;
sport->port.flags = UPF_BOOT_AUTOCONF;
timer_setup(&sport->timer, imx_uart_timeout, 0);
@@ -2322,19 +2320,13 @@ static int imx_uart_probe(struct platform_device *pdev)
/* For register access, we only need to enable the ipg clock. */
ret = clk_prepare_enable(sport->clk_ipg);
if (ret) {
- dev_err(&pdev->dev, "failed to enable per clk: %d\n", ret);
+ dev_err(&pdev->dev, "failed to enable ipg clk: %d\n", ret);
return ret;
}
ret = uart_get_rs485_mode(&sport->port);
- if (ret) {
- clk_disable_unprepare(sport->clk_ipg);
- return ret;
- }
-
- if (sport->port.rs485.flags & SER_RS485_ENABLED &&
- (!sport->have_rtscts && !sport->have_rtsgpio))
- dev_err(&pdev->dev, "no RTS control, disabling rs485\n");
+ if (ret)
+ goto err_clk;
/*
* If using the i.MX UART RTS/CTS control then the RTS (CTS_B)
@@ -2414,8 +2406,6 @@ static int imx_uart_probe(struct platform_device *pdev)
imx_uart_writel(sport, ucr3, UCR3);
}
- clk_disable_unprepare(sport->clk_ipg);
-
hrtimer_init(&sport->trigger_start_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
hrtimer_init(&sport->trigger_stop_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
sport->trigger_start_tx.function = imx_trigger_start_tx;
@@ -2431,7 +2421,7 @@ static int imx_uart_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "failed to request rx irq: %d\n",
ret);
- return ret;
+ goto err_clk;
}
ret = devm_request_irq(&pdev->dev, txirq, imx_uart_txint, 0,
@@ -2439,7 +2429,7 @@ static int imx_uart_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "failed to request tx irq: %d\n",
ret);
- return ret;
+ goto err_clk;
}
ret = devm_request_irq(&pdev->dev, rtsirq, imx_uart_rtsint, 0,
@@ -2447,14 +2437,14 @@ static int imx_uart_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "failed to request rts irq: %d\n",
ret);
- return ret;
+ goto err_clk;
}
} else {
ret = devm_request_irq(&pdev->dev, rxirq, imx_uart_int, 0,
dev_name(&pdev->dev), sport);
if (ret) {
dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
- return ret;
+ goto err_clk;
}
}
@@ -2462,16 +2452,19 @@ static int imx_uart_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sport);
- return uart_add_one_port(&imx_uart_uart_driver, &sport->port);
+ ret = uart_add_one_port(&imx_uart_uart_driver, &sport->port);
+
+err_clk:
+ clk_disable_unprepare(sport->clk_ipg);
+
+ return ret;
}
-static int imx_uart_remove(struct platform_device *pdev)
+static void imx_uart_remove(struct platform_device *pdev)
{
struct imx_port *sport = platform_get_drvdata(pdev);
uart_remove_one_port(&imx_uart_uart_driver, &sport->port);
-
- return 0;
}
static void imx_uart_restore_context(struct imx_port *sport)
@@ -2640,7 +2633,7 @@ static const struct dev_pm_ops imx_uart_pm_ops = {
static struct platform_driver imx_uart_platform_driver = {
.probe = imx_uart_probe,
- .remove = imx_uart_remove,
+ .remove_new = imx_uart_remove,
.driver = {
.name = "imx-uart",
diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h
index 8489c07f4cd5..df55e5dc5afc 100644
--- a/drivers/tty/serial/jsm/jsm.h
+++ b/drivers/tty/serial/jsm/jsm.h
@@ -115,8 +115,6 @@ struct board_ops {
void (*send_start_character)(struct jsm_channel *ch);
void (*send_stop_character)(struct jsm_channel *ch);
void (*copy_data_from_queue_to_uart)(struct jsm_channel *ch);
- u32 (*get_uart_bytes_left)(struct jsm_channel *ch);
- void (*send_immediate_char)(struct jsm_channel *ch, unsigned char);
};
@@ -127,7 +125,6 @@ struct jsm_board
{
int boardnum; /* Board number: 0-32 */
- int type; /* Type of board */
u8 rev; /* PCI revision ID */
struct pci_dev *pci_dev;
u32 maxports; /* MAX ports this board can handle */
@@ -155,8 +152,6 @@ struct jsm_board
u32 bd_dividend; /* Board/UARTs specific dividend */
struct board_ops *bd_ops;
-
- struct list_head jsm_board_entry;
};
/************************************************************************
diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c
index 3fd57ac3ad81..1eda48964c0b 100644
--- a/drivers/tty/serial/jsm/jsm_cls.c
+++ b/drivers/tty/serial/jsm/jsm_cls.c
@@ -878,28 +878,6 @@ static void cls_uart_off(struct jsm_channel *ch)
}
/*
- * cls_get_uarts_bytes_left.
- * Returns 0 is nothing left in the FIFO, returns 1 otherwise.
- *
- * The channel lock MUST be held by the calling function.
- */
-static u32 cls_get_uart_bytes_left(struct jsm_channel *ch)
-{
- u8 left = 0;
- u8 lsr = readb(&ch->ch_cls_uart->lsr);
-
- /* Determine whether the Transmitter is empty or not */
- if (!(lsr & UART_LSR_TEMT))
- left = 1;
- else {
- ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
- left = 0;
- }
-
- return left;
-}
-
-/*
* cls_send_break.
* Starts sending a break thru the UART.
*
@@ -916,18 +894,6 @@ static void cls_send_break(struct jsm_channel *ch)
}
}
-/*
- * cls_send_immediate_char.
- * Sends a specific character as soon as possible to the UART,
- * jumping over any bytes that might be in the write queue.
- *
- * The channel lock MUST be held by the calling function.
- */
-static void cls_send_immediate_char(struct jsm_channel *ch, unsigned char c)
-{
- writeb(c, &ch->ch_cls_uart->txrx);
-}
-
struct board_ops jsm_cls_ops = {
.intr = cls_intr,
.uart_init = cls_uart_init,
@@ -943,7 +909,5 @@ struct board_ops jsm_cls_ops = {
.send_start_character = cls_send_start_character,
.send_stop_character = cls_send_stop_character,
.copy_data_from_queue_to_uart = cls_copy_data_from_queue_to_uart,
- .get_uart_bytes_left = cls_get_uart_bytes_left,
- .send_immediate_char = cls_send_immediate_char
};
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
index 2bd640428970..1fa10f19368f 100644
--- a/drivers/tty/serial/jsm/jsm_neo.c
+++ b/drivers/tty/serial/jsm/jsm_neo.c
@@ -1309,25 +1309,6 @@ static void neo_uart_off(struct jsm_channel *ch)
writeb(0, &ch->ch_neo_uart->ier);
}
-static u32 neo_get_uart_bytes_left(struct jsm_channel *ch)
-{
- u8 left = 0;
- u8 lsr = readb(&ch->ch_neo_uart->lsr);
-
- /* We must cache the LSR as some of the bits get reset once read... */
- ch->ch_cached_lsr |= lsr;
-
- /* Determine whether the Transmitter is empty or not */
- if (!(lsr & UART_LSR_TEMT))
- left = 1;
- else {
- ch->ch_flags |= (CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
- left = 0;
- }
-
- return left;
-}
-
/* Channel lock MUST be held by the calling function! */
static void neo_send_break(struct jsm_channel *ch)
{
@@ -1348,25 +1329,6 @@ static void neo_send_break(struct jsm_channel *ch)
}
}
-/*
- * neo_send_immediate_char.
- *
- * Sends a specific character as soon as possible to the UART,
- * jumping over any bytes that might be in the write queue.
- *
- * The channel lock MUST be held by the calling function.
- */
-static void neo_send_immediate_char(struct jsm_channel *ch, unsigned char c)
-{
- if (!ch)
- return;
-
- writeb(c, &ch->ch_neo_uart->txrx);
-
- /* flush write operation */
- neo_pci_posting_flush(ch->ch_bd);
-}
-
struct board_ops jsm_neo_ops = {
.intr = neo_intr,
.uart_init = neo_uart_init,
@@ -1382,6 +1344,4 @@ struct board_ops jsm_neo_ops = {
.send_start_character = neo_send_start_character,
.send_stop_character = neo_send_stop_character,
.copy_data_from_queue_to_uart = neo_copy_data_from_queue_to_uart,
- .get_uart_bytes_left = neo_get_uart_bytes_left,
- .send_immediate_char = neo_send_immediate_char
};
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 3adb60c683f7..a0731773ce75 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -887,13 +887,11 @@ static int lqasc_probe(struct platform_device *pdev)
return ret;
}
-static int lqasc_remove(struct platform_device *pdev)
+static void lqasc_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
uart_remove_one_port(&lqasc_reg, port);
-
- return 0;
}
static const struct ltq_soc_data soc_data_lantiq = {
@@ -917,7 +915,7 @@ MODULE_DEVICE_TABLE(of, ltq_asc_match);
static struct platform_driver lqasc_driver = {
.probe = lqasc_probe,
- .remove = lqasc_remove,
+ .remove_new = lqasc_remove,
.driver = {
.name = DRVNAME,
.of_match_table = ltq_asc_match,
diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c
index a25ab1efe38f..3ce369f76349 100644
--- a/drivers/tty/serial/liteuart.c
+++ b/drivers/tty/serial/liteuart.c
@@ -336,15 +336,13 @@ err_erase_id:
return ret;
}
-static int liteuart_remove(struct platform_device *pdev)
+static void liteuart_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
unsigned int line = port->line;
uart_remove_one_port(&liteuart_driver, port);
xa_erase(&liteuart_array, line);
-
- return 0;
}
static const struct of_device_id liteuart_of_match[] = {
@@ -355,7 +353,7 @@ MODULE_DEVICE_TABLE(of, liteuart_of_match);
static struct platform_driver liteuart_platform_driver = {
.probe = liteuart_probe,
- .remove = liteuart_remove,
+ .remove_new = liteuart_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = liteuart_of_match,
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
index 5149a947b7fe..ec20329f0603 100644
--- a/drivers/tty/serial/lpc32xx_hs.c
+++ b/drivers/tty/serial/lpc32xx_hs.c
@@ -659,13 +659,11 @@ static int serial_hs_lpc32xx_probe(struct platform_device *pdev)
/*
* Remove serial ports registered against a platform device.
*/
-static int serial_hs_lpc32xx_remove(struct platform_device *pdev)
+static void serial_hs_lpc32xx_remove(struct platform_device *pdev)
{
struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
uart_remove_one_port(&lpc32xx_hs_reg, &p->port);
-
- return 0;
}
@@ -702,7 +700,7 @@ MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids);
static struct platform_driver serial_hs_lpc32xx_driver = {
.probe = serial_hs_lpc32xx_probe,
- .remove = serial_hs_lpc32xx_remove,
+ .remove_new = serial_hs_lpc32xx_remove,
.suspend = serial_hs_lpc32xx_suspend,
.resume = serial_hs_lpc32xx_resume,
.driver = {
diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c
index 21b574f78b86..19f0a305cc43 100644
--- a/drivers/tty/serial/ma35d1_serial.c
+++ b/drivers/tty/serial/ma35d1_serial.c
@@ -558,7 +558,7 @@ static void ma35d1serial_console_write(struct console *co, const char *s, u32 co
u32 ier;
if ((co->index < 0) || (co->index >= MA35_UART_NR)) {
- pr_warn("Failed to write on ononsole port %x, out of range\n",
+ pr_warn("Failed to write on console port %x, out of range\n",
co->index);
return;
}
@@ -754,14 +754,13 @@ err_iounmap:
/*
* Remove serial ports registered against a platform device.
*/
-static int ma35d1serial_remove(struct platform_device *dev)
+static void ma35d1serial_remove(struct platform_device *dev)
{
struct uart_port *port = platform_get_drvdata(dev);
struct uart_ma35d1_port *up = to_ma35d1_uart_port(port);
uart_remove_one_port(&ma35d1serial_reg, port);
clk_disable_unprepare(up->clk);
- return 0;
}
static int ma35d1serial_suspend(struct platform_device *dev, pm_message_t state)
@@ -794,7 +793,7 @@ static int ma35d1serial_resume(struct platform_device *dev)
static struct platform_driver ma35d1serial_driver = {
.probe = ma35d1serial_probe,
- .remove = ma35d1serial_remove,
+ .remove_new = ma35d1serial_remove,
.suspend = ma35d1serial_suspend,
.resume = ma35d1serial_resume,
.driver = {
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 97e4965b73d4..f3a99daebdaa 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -780,7 +780,7 @@ static void max310x_handle_tx(struct uart_port *port)
to_send = uart_circ_chars_pending(xmit);
until_end = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
if (likely(to_send)) {
- /* Limit to size of TX FIFO */
+ /* Limit to space available in TX FIFO */
txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
txlen = port->fifosize - txlen;
to_send = (to_send > txlen) ? txlen : to_send;
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index 91b15243f6c6..8690a45239e0 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -627,7 +627,7 @@ static int mcf_probe(struct platform_device *pdev)
/****************************************************************************/
-static int mcf_remove(struct platform_device *pdev)
+static void mcf_remove(struct platform_device *pdev)
{
struct uart_port *port;
int i;
@@ -637,15 +637,13 @@ static int mcf_remove(struct platform_device *pdev)
if (port)
uart_remove_one_port(&mcf_driver, port);
}
-
- return 0;
}
/****************************************************************************/
static struct platform_driver mcf_platform_driver = {
.probe = mcf_probe,
- .remove = mcf_remove,
+ .remove_new = mcf_remove,
.driver = {
.name = "mcfuart",
},
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
index 8dd84617e715..8395688f5ee9 100644
--- a/drivers/tty/serial/meson_uart.c
+++ b/drivers/tty/serial/meson_uart.c
@@ -795,7 +795,7 @@ static int meson_uart_probe(struct platform_device *pdev)
return ret;
}
-static int meson_uart_remove(struct platform_device *pdev)
+static void meson_uart_remove(struct platform_device *pdev)
{
struct uart_driver *uart_driver;
struct uart_port *port;
@@ -807,12 +807,10 @@ static int meson_uart_remove(struct platform_device *pdev)
for (int id = 0; id < AML_UART_PORT_NUM; id++)
if (meson_ports[id])
- return 0;
+ return;
/* No more available uart ports, unregister uart driver */
uart_unregister_driver(uart_driver);
-
- return 0;
}
static struct meson_uart_data meson_g12a_uart_data = {
@@ -852,7 +850,7 @@ MODULE_DEVICE_TABLE(of, meson_uart_dt_match);
static struct platform_driver meson_uart_platform_driver = {
.probe = meson_uart_probe,
- .remove = meson_uart_remove,
+ .remove_new = meson_uart_remove,
.driver = {
.name = "meson_uart",
.of_match_table = meson_uart_dt_match,
diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c
index db3b81f2aa57..da4c6f7e2a30 100644
--- a/drivers/tty/serial/milbeaut_usio.c
+++ b/drivers/tty/serial/milbeaut_usio.c
@@ -552,15 +552,13 @@ failed:
return ret;
}
-static int mlb_usio_remove(struct platform_device *pdev)
+static void mlb_usio_remove(struct platform_device *pdev)
{
struct uart_port *port = &mlb_usio_ports[pdev->id];
struct clk *clk = port->private_data;
uart_remove_one_port(&mlb_usio_uart_driver, port);
clk_disable_unprepare(clk);
-
- return 0;
}
static const struct of_device_id mlb_usio_dt_ids[] = {
@@ -571,7 +569,7 @@ MODULE_DEVICE_TABLE(of, mlb_usio_dt_ids);
static struct platform_driver mlb_usio_driver = {
.probe = mlb_usio_probe,
- .remove = mlb_usio_remove,
+ .remove_new = mlb_usio_remove,
.driver = {
.name = USIO_NAME,
.of_match_table = mlb_usio_dt_ids,
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index a252465e745f..95dae5e27b28 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -1765,15 +1765,12 @@ static int mpc52xx_uart_of_probe(struct platform_device *op)
return 0;
}
-static int
-mpc52xx_uart_of_remove(struct platform_device *op)
+static void mpc52xx_uart_of_remove(struct platform_device *op)
{
struct uart_port *port = platform_get_drvdata(op);
if (port)
uart_remove_one_port(&mpc52xx_uart_driver, port);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -1846,7 +1843,7 @@ MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match);
static struct platform_driver mpc52xx_uart_of_driver = {
.probe = mpc52xx_uart_of_probe,
- .remove = mpc52xx_uart_of_remove,
+ .remove_new = mpc52xx_uart_of_remove,
#ifdef CONFIG_PM
.suspend = mpc52xx_uart_of_suspend,
.resume = mpc52xx_uart_of_resume,
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 597264b546fd..e24204ad35de 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -1131,7 +1132,7 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
uart_port_unlock_irqrestore(port, flags);
entry = msm_find_best_baud(port, baud, &rate);
- clk_set_rate(msm_port->clk, rate);
+ dev_pm_opp_set_rate(port->dev, rate);
baud = rate / 16 / entry->divisor;
uart_port_lock_irqsave(port, &flags);
@@ -1186,6 +1187,7 @@ static void msm_init_clock(struct uart_port *port)
{
struct msm_port *msm_port = to_msm_port(port);
+ dev_pm_opp_set_rate(port->dev, port->uartclk);
clk_prepare_enable(msm_port->clk);
clk_prepare_enable(msm_port->pclk);
msm_serial_set_mnd_regs(port);
@@ -1239,6 +1241,7 @@ err_irq:
clk_disable_unprepare(msm_port->pclk);
clk_disable_unprepare(msm_port->clk);
+ dev_pm_opp_set_rate(port->dev, 0);
return ret;
}
@@ -1254,6 +1257,7 @@ static void msm_shutdown(struct uart_port *port)
msm_release_dma(msm_port);
clk_disable_unprepare(msm_port->clk);
+ dev_pm_opp_set_rate(port->dev, 0);
free_irq(port->irq, port);
}
@@ -1419,11 +1423,13 @@ static void msm_power(struct uart_port *port, unsigned int state,
switch (state) {
case 0:
+ dev_pm_opp_set_rate(port->dev, port->uartclk);
clk_prepare_enable(msm_port->clk);
clk_prepare_enable(msm_port->pclk);
break;
case 3:
clk_disable_unprepare(msm_port->clk);
+ dev_pm_opp_set_rate(port->dev, 0);
clk_disable_unprepare(msm_port->pclk);
break;
default:
@@ -1789,7 +1795,7 @@ static int msm_serial_probe(struct platform_device *pdev)
struct resource *resource;
struct uart_port *port;
const struct of_device_id *id;
- int irq, line;
+ int irq, line, ret;
if (pdev->dev.of_node)
line = of_alias_get_id(pdev->dev.of_node, "serial");
@@ -1824,6 +1830,15 @@ static int msm_serial_probe(struct platform_device *pdev)
return PTR_ERR(msm_port->pclk);
}
+ ret = devm_pm_opp_set_clkname(&pdev->dev, "core");
+ if (ret)
+ return ret;
+
+ /* OPP table is optional */
+ ret = devm_pm_opp_of_add_table(&pdev->dev);
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(&pdev->dev, ret, "invalid OPP table\n");
+
port->uartclk = clk_get_rate(msm_port->clk);
dev_info(&pdev->dev, "uartclk = %d\n", port->uartclk);
@@ -1843,13 +1858,11 @@ static int msm_serial_probe(struct platform_device *pdev)
return uart_add_one_port(&msm_uart_driver, port);
}
-static int msm_serial_remove(struct platform_device *pdev)
+static void msm_serial_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
uart_remove_one_port(&msm_uart_driver, port);
-
- return 0;
}
static const struct of_device_id msm_match_table[] = {
@@ -1882,7 +1895,7 @@ static const struct dev_pm_ops msm_serial_dev_pm_ops = {
};
static struct platform_driver msm_platform_driver = {
- .remove = msm_serial_remove,
+ .remove_new = msm_serial_remove,
.probe = msm_serial_probe,
.driver = {
.name = "msm_serial",
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 8eeecf8ad359..3ec725555bcc 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -904,21 +904,27 @@ static void mxs_auart_dma_exit(struct mxs_auart_port *s)
static int mxs_auart_dma_init(struct mxs_auart_port *s)
{
+ struct dma_chan *chan;
+
if (auart_dma_enabled(s))
return 0;
/* init for RX */
- s->rx_dma_chan = dma_request_slave_channel(s->dev, "rx");
- if (!s->rx_dma_chan)
+ chan = dma_request_chan(s->dev, "rx");
+ if (IS_ERR(chan))
goto err_out;
+ s->rx_dma_chan = chan;
+
s->rx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA);
if (!s->rx_dma_buf)
goto err_out;
/* init for TX */
- s->tx_dma_chan = dma_request_slave_channel(s->dev, "tx");
- if (!s->tx_dma_chan)
+ chan = dma_request_chan(s->dev, "tx");
+ if (IS_ERR(chan))
goto err_out;
+ s->tx_dma_chan = chan;
+
s->tx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA);
if (!s->tx_dma_buf)
goto err_out;
@@ -1686,7 +1692,7 @@ out_disable_clks:
return ret;
}
-static int mxs_auart_remove(struct platform_device *pdev)
+static void mxs_auart_remove(struct platform_device *pdev)
{
struct mxs_auart_port *s = platform_get_drvdata(pdev);
@@ -1698,13 +1704,11 @@ static int mxs_auart_remove(struct platform_device *pdev)
clk_disable_unprepare(s->clk);
clk_disable_unprepare(s->clk_ahb);
}
-
- return 0;
}
static struct platform_driver mxs_auart_driver = {
.probe = mxs_auart_probe,
- .remove = mxs_auart_remove,
+ .remove_new = mxs_auart_remove,
.driver = {
.name = "mxs-auart",
.of_match_table = mxs_auart_dt_ids,
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index ad4c1c5d0a7f..f5a0b401af63 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1483,6 +1483,13 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
return omap_up_info;
}
+static const struct serial_rs485 serial_omap_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
+ SER_RS485_RX_DURING_TX,
+ .delay_rts_before_send = 1,
+ .delay_rts_after_send = 1,
+};
+
static int serial_omap_probe_rs485(struct uart_omap_port *up,
struct device *dev)
{
@@ -1497,6 +1504,9 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
if (!np)
return 0;
+ up->port.rs485_config = serial_omap_config_rs485;
+ up->port.rs485_supported = serial_omap_rs485_supported;
+
ret = uart_get_rs485_mode(&up->port);
if (ret)
return ret;
@@ -1531,13 +1541,6 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
return 0;
}
-static const struct serial_rs485 serial_omap_rs485_supported = {
- .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
- SER_RS485_RX_DURING_TX,
- .delay_rts_before_send = 1,
- .delay_rts_after_send = 1,
-};
-
static int serial_omap_probe(struct platform_device *pdev)
{
struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
@@ -1604,17 +1607,11 @@ static int serial_omap_probe(struct platform_device *pdev)
dev_info(up->port.dev, "no wakeirq for uart%d\n",
up->port.line);
- ret = serial_omap_probe_rs485(up, &pdev->dev);
- if (ret < 0)
- goto err_rs485;
-
sprintf(up->name, "OMAP UART%d", up->port.line);
up->port.mapbase = mem->start;
up->port.membase = base;
up->port.flags = omap_up_info->flags;
up->port.uartclk = omap_up_info->uartclk;
- up->port.rs485_config = serial_omap_config_rs485;
- up->port.rs485_supported = serial_omap_rs485_supported;
if (!up->port.uartclk) {
up->port.uartclk = DEFAULT_CLK_SPEED;
dev_warn(&pdev->dev,
@@ -1622,6 +1619,10 @@ static int serial_omap_probe(struct platform_device *pdev)
DEFAULT_CLK_SPEED);
}
+ ret = serial_omap_probe_rs485(up, &pdev->dev);
+ if (ret < 0)
+ goto err_rs485;
+
up->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
up->calc_latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
cpu_latency_qos_add_request(&up->pm_qos_request, up->latency);
@@ -1658,7 +1659,7 @@ err_port_line:
return ret;
}
-static int serial_omap_remove(struct platform_device *dev)
+static void serial_omap_remove(struct platform_device *dev)
{
struct uart_omap_port *up = platform_get_drvdata(dev);
@@ -1670,8 +1671,6 @@ static int serial_omap_remove(struct platform_device *dev)
pm_runtime_disable(up->dev);
cpu_latency_qos_remove_request(&up->pm_qos_request);
device_init_wakeup(&dev->dev, false);
-
- return 0;
}
/*
@@ -1808,7 +1807,7 @@ MODULE_DEVICE_TABLE(of, omap_serial_of_match);
static struct platform_driver serial_omap_driver = {
.probe = serial_omap_probe,
- .remove = serial_omap_remove,
+ .remove_new = serial_omap_remove,
.driver = {
.name = OMAP_SERIAL_DRIVER_NAME,
.pm = &serial_omap_dev_pm_ops,
diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c
index 919f5e5aa0f1..d9fe85397741 100644
--- a/drivers/tty/serial/owl-uart.c
+++ b/drivers/tty/serial/owl-uart.c
@@ -725,20 +725,18 @@ static int owl_uart_probe(struct platform_device *pdev)
return ret;
}
-static int owl_uart_remove(struct platform_device *pdev)
+static void owl_uart_remove(struct platform_device *pdev)
{
struct owl_uart_port *owl_port = platform_get_drvdata(pdev);
uart_remove_one_port(&owl_uart_driver, &owl_port->port);
owl_uart_ports[pdev->id] = NULL;
clk_disable_unprepare(owl_port->clk);
-
- return 0;
}
static struct platform_driver owl_uart_platform_driver = {
.probe = owl_uart_probe,
- .remove = owl_uart_remove,
+ .remove_new = owl_uart_remove,
.driver = {
.name = "owl-uart",
.of_match_table = owl_uart_dt_matches,
diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c
index 3a95bf5d55d3..bbb46e6e98a2 100644
--- a/drivers/tty/serial/pic32_uart.c
+++ b/drivers/tty/serial/pic32_uart.c
@@ -938,7 +938,7 @@ err:
return ret;
}
-static int pic32_uart_remove(struct platform_device *pdev)
+static void pic32_uart_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
struct pic32_sport *sport = to_pic32_sport(port);
@@ -947,9 +947,6 @@ static int pic32_uart_remove(struct platform_device *pdev)
clk_disable_unprepare(sport->clk);
platform_set_drvdata(pdev, NULL);
pic32_sports[sport->idx] = NULL;
-
- /* automatic unroll of sport and gpios */
- return 0;
}
static const struct of_device_id pic32_serial_dt_ids[] = {
@@ -960,7 +957,7 @@ MODULE_DEVICE_TABLE(of, pic32_serial_dt_ids);
static struct platform_driver pic32_uart_platform_driver = {
.probe = pic32_uart_probe,
- .remove = pic32_uart_remove,
+ .remove_new = pic32_uart_remove,
.driver = {
.name = PIC32_DEV_NAME,
.of_match_table = of_match_ptr(pic32_serial_dt_ids),
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index 7e78f97e8f43..e63a8fbe63bd 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -1696,7 +1696,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
return 0;
}
-static int qcom_geni_serial_remove(struct platform_device *pdev)
+static void qcom_geni_serial_remove(struct platform_device *pdev)
{
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
struct uart_driver *drv = port->private_data.drv;
@@ -1704,8 +1704,6 @@ static int qcom_geni_serial_remove(struct platform_device *pdev)
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
uart_remove_one_port(drv, &port->uport);
-
- return 0;
}
static int qcom_geni_serial_sys_suspend(struct device *dev)
@@ -1805,7 +1803,7 @@ static const struct of_device_id qcom_geni_serial_match_table[] = {
MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table);
static struct platform_driver qcom_geni_serial_platform_driver = {
- .remove = qcom_geni_serial_remove,
+ .remove_new = qcom_geni_serial_remove,
.probe = qcom_geni_serial_probe,
.driver = {
.name = "qcom_geni_serial",
diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c
index d824c8318f33..13deb355cf1b 100644
--- a/drivers/tty/serial/rda-uart.c
+++ b/drivers/tty/serial/rda-uart.c
@@ -780,19 +780,17 @@ static int rda_uart_probe(struct platform_device *pdev)
return ret;
}
-static int rda_uart_remove(struct platform_device *pdev)
+static void rda_uart_remove(struct platform_device *pdev)
{
struct rda_uart_port *rda_port = platform_get_drvdata(pdev);
uart_remove_one_port(&rda_uart_driver, &rda_port->port);
rda_uart_ports[pdev->id] = NULL;
-
- return 0;
}
static struct platform_driver rda_uart_platform_driver = {
.probe = rda_uart_probe,
- .remove = rda_uart_remove,
+ .remove_new = rda_uart_remove,
.driver = {
.name = "rda-uart",
.of_match_table = rda_uart_dt_matches,
diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c
index d46a81cddfcd..4132fcff7d4e 100644
--- a/drivers/tty/serial/rp2.c
+++ b/drivers/tty/serial/rp2.c
@@ -178,7 +178,6 @@ struct rp2_card;
struct rp2_uart_port {
struct uart_port port;
int idx;
- int ignore_rx;
struct rp2_card *card;
void __iomem *asic_base;
void __iomem *base;
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index be7bcd75d9f4..79c794fa6545 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -870,19 +870,17 @@ static int sa1100_serial_probe(struct platform_device *dev)
return 0;
}
-static int sa1100_serial_remove(struct platform_device *pdev)
+static void sa1100_serial_remove(struct platform_device *pdev)
{
struct sa1100_port *sport = platform_get_drvdata(pdev);
if (sport)
uart_remove_one_port(&sa1100_reg, &sport->port);
-
- return 0;
}
static struct platform_driver sa11x0_serial_driver = {
.probe = sa1100_serial_probe,
- .remove = sa1100_serial_remove,
+ .remove_new = sa1100_serial_remove,
.suspend = sa1100_serial_suspend,
.resume = sa1100_serial_resume,
.driver = {
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 66bd6c090ace..71d17d804fda 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -2054,7 +2054,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
return 0;
}
-static int s3c24xx_serial_remove(struct platform_device *dev)
+static void s3c24xx_serial_remove(struct platform_device *dev)
{
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
@@ -2063,8 +2063,6 @@ static int s3c24xx_serial_remove(struct platform_device *dev)
}
uart_unregister_driver(&s3c24xx_uart_drv);
-
- return 0;
}
/* UART power management code */
@@ -2627,7 +2625,7 @@ MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
static struct platform_driver samsung_serial_driver = {
.probe = s3c24xx_serial_probe,
- .remove = s3c24xx_serial_remove,
+ .remove_new = s3c24xx_serial_remove,
.id_table = s3c24xx_serial_driver_ids,
.driver = {
.name = "samsung-uart",
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index cf0c6120d30e..929206a9a6e1 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -24,10 +24,12 @@
#include <linux/tty_flip.h>
#include <linux/spi/spi.h>
#include <linux/uaccess.h>
+#include <linux/units.h>
#include <uapi/linux/sched/types.h>
#define SC16IS7XX_NAME "sc16is7xx"
#define SC16IS7XX_MAX_DEVS 8
+#define SC16IS7XX_MAX_PORTS 2 /* Maximum number of UART ports per IC. */
/* SC16IS7XX register definitions */
#define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */
@@ -300,8 +302,8 @@
/* Misc definitions */
+#define SC16IS7XX_SPI_READ_BIT BIT(7)
#define SC16IS7XX_FIFO_SIZE (64)
-#define SC16IS7XX_REG_SHIFT 2
#define SC16IS7XX_GPIOS_PER_BANK 4
struct sc16is7xx_devtype {
@@ -322,18 +324,19 @@ struct sc16is7xx_one_config {
struct sc16is7xx_one {
struct uart_port port;
- u8 line;
+ struct regmap *regmap;
+ struct mutex efr_lock; /* EFR registers access */
struct kthread_work tx_work;
struct kthread_work reg_work;
struct kthread_delayed_work ms_work;
struct sc16is7xx_one_config config;
- bool irda_mode;
unsigned int old_mctrl;
+ u8 old_lcr; /* Value before EFR access. */
+ bool irda_mode;
};
struct sc16is7xx_port {
const struct sc16is7xx_devtype *devtype;
- struct regmap *regmap;
struct clk *clk;
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio;
@@ -343,65 +346,47 @@ struct sc16is7xx_port {
unsigned char buf[SC16IS7XX_FIFO_SIZE];
struct kthread_worker kworker;
struct task_struct *kworker_task;
- struct mutex efr_lock;
struct sc16is7xx_one p[];
};
-static unsigned long sc16is7xx_lines;
+static DECLARE_BITMAP(sc16is7xx_lines, SC16IS7XX_MAX_DEVS);
static struct uart_driver sc16is7xx_uart = {
.owner = THIS_MODULE,
+ .driver_name = SC16IS7XX_NAME,
.dev_name = "ttySC",
.nr = SC16IS7XX_MAX_DEVS,
};
-static void sc16is7xx_ier_set(struct uart_port *port, u8 bit);
-static void sc16is7xx_stop_tx(struct uart_port *port);
-
#define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e)))
-static int sc16is7xx_line(struct uart_port *port)
-{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
-
- return one->line;
-}
-
static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg)
{
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
unsigned int val = 0;
- const u8 line = sc16is7xx_line(port);
- regmap_read(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, &val);
+ regmap_read(one->regmap, reg, &val);
return val;
}
static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val)
{
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- const u8 line = sc16is7xx_line(port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- regmap_write(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, val);
+ regmap_write(one->regmap, reg, val);
}
-static void sc16is7xx_fifo_read(struct uart_port *port, unsigned int rxlen)
+static void sc16is7xx_fifo_read(struct uart_port *port, u8 *rxbuf, unsigned int rxlen)
{
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- const u8 line = sc16is7xx_line(port);
- u8 addr = (SC16IS7XX_RHR_REG << SC16IS7XX_REG_SHIFT) | line;
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- regcache_cache_bypass(s->regmap, true);
- regmap_raw_read(s->regmap, addr, s->buf, rxlen);
- regcache_cache_bypass(s->regmap, false);
+ regmap_noinc_read(one->regmap, SC16IS7XX_RHR_REG, rxbuf, rxlen);
}
-static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send)
+static void sc16is7xx_fifo_write(struct uart_port *port, u8 *txbuf, u8 to_send)
{
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- const u8 line = sc16is7xx_line(port);
- u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | line;
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
/*
* Don't send zero-length data, at least on SPI it confuses the chip
@@ -410,39 +395,101 @@ static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send)
if (unlikely(!to_send))
return;
- regcache_cache_bypass(s->regmap, true);
- regmap_raw_write(s->regmap, addr, s->buf, to_send);
- regcache_cache_bypass(s->regmap, false);
+ regmap_noinc_write(one->regmap, SC16IS7XX_THR_REG, txbuf, to_send);
}
static void sc16is7xx_port_update(struct uart_port *port, u8 reg,
u8 mask, u8 val)
{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+
+ regmap_update_bits(one->regmap, reg, mask, val);
+}
+
+static void sc16is7xx_power(struct uart_port *port, int on)
+{
+ sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
+ SC16IS7XX_IER_SLEEP_BIT,
+ on ? 0 : SC16IS7XX_IER_SLEEP_BIT);
+}
+
+/*
+ * In an amazing feat of design, the Enhanced Features Register (EFR)
+ * shares the address of the Interrupt Identification Register (IIR).
+ * Access to EFR is switched on by writing a magic value (0xbf) to the
+ * Line Control Register (LCR). Any interrupt firing during this time will
+ * see the EFR where it expects the IIR to be, leading to
+ * "Unexpected interrupt" messages.
+ *
+ * Prevent this possibility by claiming a mutex while accessing the EFR,
+ * and claiming the same mutex from within the interrupt handler. This is
+ * similar to disabling the interrupt, but that doesn't work because the
+ * bulk of the interrupt processing is run as a workqueue job in thread
+ * context.
+ */
+static void sc16is7xx_efr_lock(struct uart_port *port)
+{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+
+ mutex_lock(&one->efr_lock);
+
+ /* Backup content of LCR. */
+ one->old_lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
+
+ /* Enable access to Enhanced register set */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_B);
+
+ /* Disable cache updates when writing to EFR registers */
+ regcache_cache_bypass(one->regmap, true);
+}
+
+static void sc16is7xx_efr_unlock(struct uart_port *port)
+{
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+
+ /* Re-enable cache updates when writing to normal registers */
+ regcache_cache_bypass(one->regmap, false);
+
+ /* Restore original content of LCR */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, one->old_lcr);
+
+ mutex_unlock(&one->efr_lock);
+}
+
+static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit)
+{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- const u8 line = sc16is7xx_line(port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+
+ lockdep_assert_held_once(&port->lock);
- regmap_update_bits(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line,
- mask, val);
+ one->config.flags |= SC16IS7XX_RECONF_IER;
+ one->config.ier_mask |= bit;
+ one->config.ier_val &= ~bit;
+ kthread_queue_work(&s->kworker, &one->reg_work);
}
-static int sc16is7xx_alloc_line(void)
+static void sc16is7xx_ier_set(struct uart_port *port, u8 bit)
{
- int i;
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- BUILD_BUG_ON(SC16IS7XX_MAX_DEVS > BITS_PER_LONG);
+ lockdep_assert_held_once(&port->lock);
- for (i = 0; i < SC16IS7XX_MAX_DEVS; i++)
- if (!test_and_set_bit(i, &sc16is7xx_lines))
- break;
+ one->config.flags |= SC16IS7XX_RECONF_IER;
+ one->config.ier_mask |= bit;
+ one->config.ier_val |= bit;
+ kthread_queue_work(&s->kworker, &one->reg_work);
+}
- return i;
+static void sc16is7xx_stop_tx(struct uart_port *port)
+{
+ sc16is7xx_ier_clear(port, SC16IS7XX_IER_THRI_BIT);
}
-static void sc16is7xx_power(struct uart_port *port, int on)
+static void sc16is7xx_stop_rx(struct uart_port *port)
{
- sc16is7xx_port_update(port, SC16IS7XX_IER_REG,
- SC16IS7XX_IER_SLEEP_BIT,
- on ? 0 : SC16IS7XX_IER_SLEEP_BIT);
+ sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT);
}
static const struct sc16is7xx_devtype sc16is74x_devtype = {
@@ -477,7 +524,7 @@ static const struct sc16is7xx_devtype sc16is762_devtype = {
static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg)
{
- switch (reg >> SC16IS7XX_REG_SHIFT) {
+ switch (reg) {
case SC16IS7XX_RHR_REG:
case SC16IS7XX_IIR_REG:
case SC16IS7XX_LSR_REG:
@@ -488,85 +535,60 @@ static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg)
case SC16IS7XX_IOCONTROL_REG:
return true;
default:
- break;
+ return false;
}
-
- return false;
}
static bool sc16is7xx_regmap_precious(struct device *dev, unsigned int reg)
{
- switch (reg >> SC16IS7XX_REG_SHIFT) {
+ switch (reg) {
case SC16IS7XX_RHR_REG:
return true;
default:
- break;
+ return false;
}
+}
- return false;
+static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg)
+{
+ return reg == SC16IS7XX_RHR_REG;
}
static int sc16is7xx_set_baud(struct uart_port *port, int baud)
{
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
u8 lcr;
u8 prescaler = 0;
unsigned long clk = port->uartclk, div = clk / 16 / baud;
- if (div > 0xffff) {
+ if (div >= BIT(16)) {
prescaler = SC16IS7XX_MCR_CLKSEL_BIT;
div /= 4;
}
- /* In an amazing feat of design, the Enhanced Features Register shares
- * the address of the Interrupt Identification Register, and is
- * switched in by writing a magic value (0xbf) to the Line Control
- * Register. Any interrupt firing during this time will see the EFR
- * where it expects the IIR to be, leading to "Unexpected interrupt"
- * messages.
- *
- * Prevent this possibility by claiming a mutex while accessing the
- * EFR, and claiming the same mutex from within the interrupt handler.
- * This is similar to disabling the interrupt, but that doesn't work
- * because the bulk of the interrupt processing is run as a workqueue
- * job in thread context.
- */
- mutex_lock(&s->efr_lock);
-
- lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
-
- /* Open the LCR divisors for configuration */
- sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
- SC16IS7XX_LCR_CONF_MODE_B);
-
/* Enable enhanced features */
- regcache_cache_bypass(s->regmap, true);
+ sc16is7xx_efr_lock(port);
sc16is7xx_port_update(port, SC16IS7XX_EFR_REG,
SC16IS7XX_EFR_ENABLE_BIT,
SC16IS7XX_EFR_ENABLE_BIT);
-
- regcache_cache_bypass(s->regmap, false);
-
- /* Put LCR back to the normal mode */
- sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
-
- mutex_unlock(&s->efr_lock);
+ sc16is7xx_efr_unlock(port);
sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_CLKSEL_BIT,
prescaler);
- /* Open the LCR divisors for configuration */
+ /* Backup LCR and access special register set (DLL/DLH) */
+ lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
SC16IS7XX_LCR_CONF_MODE_A);
/* Write the new divisor */
- regcache_cache_bypass(s->regmap, true);
+ regcache_cache_bypass(one->regmap, true);
sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256);
sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256);
- regcache_cache_bypass(s->regmap, false);
+ regcache_cache_bypass(one->regmap, false);
- /* Put LCR back to the normal mode */
+ /* Restore LCR and access to general register set */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
return DIV_ROUND_CLOSEST(clk / 16, div);
@@ -602,7 +624,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG);
bytes_read = 1;
} else {
- sc16is7xx_fifo_read(port, rxlen);
+ sc16is7xx_fifo_read(port, s->buf, rxlen);
bytes_read = rxlen;
}
@@ -675,7 +697,7 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
/* Get length of data pending in circular buffer */
to_send = uart_circ_chars_pending(xmit);
if (likely(to_send)) {
- /* Limit to size of TX FIFO */
+ /* Limit to space available in TX FIFO */
txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG);
if (txlen > SC16IS7XX_FIFO_SIZE) {
dev_err_ratelimited(port->dev,
@@ -691,7 +713,7 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
uart_xmit_advance(port, 1);
}
- sc16is7xx_fifo_write(port, to_send);
+ sc16is7xx_fifo_write(port, s->buf, to_send);
}
uart_port_lock_irqsave(port, &flags);
@@ -700,6 +722,8 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
if (uart_circ_empty(xmit))
sc16is7xx_stop_tx(port);
+ else
+ sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT);
uart_port_unlock_irqrestore(port, flags);
}
@@ -718,11 +742,10 @@ static unsigned int sc16is7xx_get_hwmctrl(struct uart_port *port)
static void sc16is7xx_update_mlines(struct sc16is7xx_one *one)
{
struct uart_port *port = &one->port;
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
unsigned long flags;
unsigned int status, changed;
- lockdep_assert_held_once(&s->efr_lock);
+ lockdep_assert_held_once(&one->efr_lock);
status = sc16is7xx_get_hwmctrl(port);
changed = status ^ one->old_mctrl;
@@ -748,74 +771,77 @@ static void sc16is7xx_update_mlines(struct sc16is7xx_one *one)
static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
{
+ bool rc = true;
+ unsigned int iir, rxlen;
struct uart_port *port = &s->p[portno].port;
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- do {
- unsigned int iir, rxlen;
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
-
- iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
- if (iir & SC16IS7XX_IIR_NO_INT_BIT)
- return false;
-
- iir &= SC16IS7XX_IIR_ID_MASK;
-
- switch (iir) {
- case SC16IS7XX_IIR_RDI_SRC:
- case SC16IS7XX_IIR_RLSE_SRC:
- case SC16IS7XX_IIR_RTOI_SRC:
- case SC16IS7XX_IIR_XOFFI_SRC:
- rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG);
-
- /*
- * There is a silicon bug that makes the chip report a
- * time-out interrupt but no data in the FIFO. This is
- * described in errata section 18.1.4.
- *
- * When this happens, read one byte from the FIFO to
- * clear the interrupt.
- */
- if (iir == SC16IS7XX_IIR_RTOI_SRC && !rxlen)
- rxlen = 1;
-
- if (rxlen)
- sc16is7xx_handle_rx(port, rxlen, iir);
- break;
+ mutex_lock(&one->efr_lock);
+
+ iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
+ if (iir & SC16IS7XX_IIR_NO_INT_BIT) {
+ rc = false;
+ goto out_port_irq;
+ }
+
+ iir &= SC16IS7XX_IIR_ID_MASK;
+
+ switch (iir) {
+ case SC16IS7XX_IIR_RDI_SRC:
+ case SC16IS7XX_IIR_RLSE_SRC:
+ case SC16IS7XX_IIR_RTOI_SRC:
+ case SC16IS7XX_IIR_XOFFI_SRC:
+ rxlen = sc16is7xx_port_read(port, SC16IS7XX_RXLVL_REG);
+
+ /*
+ * There is a silicon bug that makes the chip report a
+ * time-out interrupt but no data in the FIFO. This is
+ * described in errata section 18.1.4.
+ *
+ * When this happens, read one byte from the FIFO to
+ * clear the interrupt.
+ */
+ if (iir == SC16IS7XX_IIR_RTOI_SRC && !rxlen)
+ rxlen = 1;
+
+ if (rxlen)
+ sc16is7xx_handle_rx(port, rxlen, iir);
+ break;
/* CTSRTS interrupt comes only when CTS goes inactive */
- case SC16IS7XX_IIR_CTSRTS_SRC:
- case SC16IS7XX_IIR_MSI_SRC:
- sc16is7xx_update_mlines(one);
- break;
- case SC16IS7XX_IIR_THRI_SRC:
- sc16is7xx_handle_tx(port);
- break;
- default:
- dev_err_ratelimited(port->dev,
- "ttySC%i: Unexpected interrupt: %x",
- port->line, iir);
- break;
- }
- } while (0);
- return true;
+ case SC16IS7XX_IIR_CTSRTS_SRC:
+ case SC16IS7XX_IIR_MSI_SRC:
+ sc16is7xx_update_mlines(one);
+ break;
+ case SC16IS7XX_IIR_THRI_SRC:
+ sc16is7xx_handle_tx(port);
+ break;
+ default:
+ dev_err_ratelimited(port->dev,
+ "ttySC%i: Unexpected interrupt: %x",
+ port->line, iir);
+ break;
+ }
+
+out_port_irq:
+ mutex_unlock(&one->efr_lock);
+
+ return rc;
}
static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
{
- struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
+ bool keep_polling;
- mutex_lock(&s->efr_lock);
+ struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
- while (1) {
- bool keep_polling = false;
+ do {
int i;
+ keep_polling = false;
+
for (i = 0; i < s->devtype->nr_uart; ++i)
keep_polling |= sc16is7xx_port_irq(s, i);
- if (!keep_polling)
- break;
- }
-
- mutex_unlock(&s->efr_lock);
+ } while (keep_polling);
return IRQ_HANDLED;
}
@@ -823,20 +849,15 @@ static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
static void sc16is7xx_tx_proc(struct kthread_work *ws)
{
struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- unsigned long flags;
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
if ((port->rs485.flags & SER_RS485_ENABLED) &&
(port->rs485.delay_rts_before_send > 0))
msleep(port->rs485.delay_rts_before_send);
- mutex_lock(&s->efr_lock);
+ mutex_lock(&one->efr_lock);
sc16is7xx_handle_tx(port);
- mutex_unlock(&s->efr_lock);
-
- uart_port_lock_irqsave(port, &flags);
- sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT);
- uart_port_unlock_irqrestore(port, flags);
+ mutex_unlock(&one->efr_lock);
}
static void sc16is7xx_reconf_rs485(struct uart_port *port)
@@ -897,51 +918,15 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws)
sc16is7xx_reconf_rs485(&one->port);
}
-static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit)
-{
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
-
- lockdep_assert_held_once(&port->lock);
-
- one->config.flags |= SC16IS7XX_RECONF_IER;
- one->config.ier_mask |= bit;
- one->config.ier_val &= ~bit;
- kthread_queue_work(&s->kworker, &one->reg_work);
-}
-
-static void sc16is7xx_ier_set(struct uart_port *port, u8 bit)
-{
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
-
- lockdep_assert_held_once(&port->lock);
-
- one->config.flags |= SC16IS7XX_RECONF_IER;
- one->config.ier_mask |= bit;
- one->config.ier_val |= bit;
- kthread_queue_work(&s->kworker, &one->reg_work);
-}
-
-static void sc16is7xx_stop_tx(struct uart_port *port)
-{
- sc16is7xx_ier_clear(port, SC16IS7XX_IER_THRI_BIT);
-}
-
-static void sc16is7xx_stop_rx(struct uart_port *port)
-{
- sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT);
-}
-
static void sc16is7xx_ms_proc(struct kthread_work *ws)
{
struct sc16is7xx_one *one = to_sc16is7xx_one(ws, ms_work.work);
struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev);
if (one->port.state) {
- mutex_lock(&s->efr_lock);
+ mutex_lock(&one->efr_lock);
sc16is7xx_update_mlines(one);
- mutex_unlock(&s->efr_lock);
+ mutex_unlock(&one->efr_lock);
kthread_queue_delayed_work(&s->kworker, &one->ms_work, HZ);
}
@@ -1025,7 +1010,6 @@ static void sc16is7xx_set_termios(struct uart_port *port,
struct ktermios *termios,
const struct ktermios *old)
{
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
unsigned int lcr, flow = 0;
int baud;
@@ -1083,17 +1067,7 @@ static void sc16is7xx_set_termios(struct uart_port *port,
if (!(termios->c_cflag & CREAD))
port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK;
- /* As above, claim the mutex while accessing the EFR. */
- mutex_lock(&s->efr_lock);
-
- sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
- SC16IS7XX_LCR_CONF_MODE_B);
-
/* Configure flow control */
- regcache_cache_bypass(s->regmap, true);
- sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]);
- sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]);
-
port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
if (termios->c_cflag & CRTSCTS) {
flow |= SC16IS7XX_EFR_AUTOCTS_BIT |
@@ -1105,16 +1079,16 @@ static void sc16is7xx_set_termios(struct uart_port *port,
if (termios->c_iflag & IXOFF)
flow |= SC16IS7XX_EFR_SWFLOW1_BIT;
- sc16is7xx_port_update(port,
- SC16IS7XX_EFR_REG,
- SC16IS7XX_EFR_FLOWCTRL_BITS,
- flow);
- regcache_cache_bypass(s->regmap, false);
-
/* Update LCR register */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
- mutex_unlock(&s->efr_lock);
+ /* Update EFR registers */
+ sc16is7xx_efr_lock(port);
+ sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]);
+ sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]);
+ sc16is7xx_port_update(port, SC16IS7XX_EFR_REG,
+ SC16IS7XX_EFR_FLOWCTRL_BITS, flow);
+ sc16is7xx_efr_unlock(port);
/* Get baud rate generator configuration */
baud = uart_get_baud_rate(port, termios, old,
@@ -1160,7 +1134,6 @@ static int sc16is7xx_config_rs485(struct uart_port *port, struct ktermios *termi
static int sc16is7xx_startup(struct uart_port *port)
{
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
unsigned int val;
unsigned long flags;
@@ -1177,7 +1150,7 @@ static int sc16is7xx_startup(struct uart_port *port)
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
SC16IS7XX_LCR_CONF_MODE_B);
- regcache_cache_bypass(s->regmap, true);
+ regcache_cache_bypass(one->regmap, true);
/* Enable write access to enhanced features and internal clock div */
sc16is7xx_port_update(port, SC16IS7XX_EFR_REG,
@@ -1195,7 +1168,7 @@ static int sc16is7xx_startup(struct uart_port *port)
SC16IS7XX_TCR_RX_RESUME(24) |
SC16IS7XX_TCR_RX_HALT(48));
- regcache_cache_bypass(s->regmap, false);
+ regcache_cache_bypass(one->regmap, false);
/* Now, initialize the UART */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8);
@@ -1425,7 +1398,7 @@ static void sc16is7xx_setup_irda_ports(struct sc16is7xx_port *s)
int i;
int ret;
int count;
- u32 irda_port[2];
+ u32 irda_port[SC16IS7XX_MAX_PORTS];
struct device *dev = s->p[0].port.dev;
count = device_property_count_u32(dev, "irda-mode-ports");
@@ -1446,12 +1419,13 @@ static void sc16is7xx_setup_irda_ports(struct sc16is7xx_port *s)
/*
* Configure ports designated to operate as modem control lines.
*/
-static int sc16is7xx_setup_mctrl_ports(struct sc16is7xx_port *s)
+static int sc16is7xx_setup_mctrl_ports(struct sc16is7xx_port *s,
+ struct regmap *regmap)
{
int i;
int ret;
int count;
- u32 mctrl_port[2];
+ u32 mctrl_port[SC16IS7XX_MAX_PORTS];
struct device *dev = s->p[0].port.dev;
count = device_property_count_u32(dev, "nxp,modem-control-line-ports");
@@ -1475,8 +1449,8 @@ static int sc16is7xx_setup_mctrl_ports(struct sc16is7xx_port *s)
if (s->mctrl_mask)
regmap_update_bits(
- s->regmap,
- SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT,
+ regmap,
+ SC16IS7XX_IOCONTROL_REG,
SC16IS7XX_IOCONTROL_MODEM_A_BIT |
SC16IS7XX_IOCONTROL_MODEM_B_BIT, s->mctrl_mask);
@@ -1491,7 +1465,7 @@ static const struct serial_rs485 sc16is7xx_rs485_supported = {
static int sc16is7xx_probe(struct device *dev,
const struct sc16is7xx_devtype *devtype,
- struct regmap *regmap, int irq)
+ struct regmap *regmaps[], int irq)
{
unsigned long freq = 0, *pfreq = dev_get_platdata(dev);
unsigned int val;
@@ -1499,16 +1473,20 @@ static int sc16is7xx_probe(struct device *dev,
int i, ret;
struct sc16is7xx_port *s;
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
+ for (i = 0; i < devtype->nr_uart; i++)
+ if (IS_ERR(regmaps[i]))
+ return PTR_ERR(regmaps[i]);
/*
* This device does not have an identification register that would
* tell us if we are really connected to the correct device.
* The best we can do is to check if communication is at all possible.
+ *
+ * Note: regmap[0] is used in the probe function to access registers
+ * common to all channels/ports, as it is guaranteed to be present on
+ * all variants.
*/
- ret = regmap_read(regmap,
- SC16IS7XX_LSR_REG << SC16IS7XX_REG_SHIFT, &val);
+ ret = regmap_read(regmaps[0], SC16IS7XX_LSR_REG, &val);
if (ret < 0)
return -EPROBE_DEFER;
@@ -1542,10 +1520,8 @@ static int sc16is7xx_probe(struct device *dev,
return -EINVAL;
}
- s->regmap = regmap;
s->devtype = devtype;
dev_set_drvdata(dev, s);
- mutex_init(&s->efr_lock);
kthread_init_worker(&s->kworker);
s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker,
@@ -1557,11 +1533,17 @@ static int sc16is7xx_probe(struct device *dev,
sched_set_fifo(s->kworker_task);
/* reset device, purging any pending irq / data */
- regmap_write(s->regmap, SC16IS7XX_IOCONTROL_REG << SC16IS7XX_REG_SHIFT,
- SC16IS7XX_IOCONTROL_SRESET_BIT);
+ regmap_write(regmaps[0], SC16IS7XX_IOCONTROL_REG,
+ SC16IS7XX_IOCONTROL_SRESET_BIT);
for (i = 0; i < devtype->nr_uart; ++i) {
- s->p[i].line = i;
+ s->p[i].port.line = find_first_zero_bit(sc16is7xx_lines,
+ SC16IS7XX_MAX_DEVS);
+ if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) {
+ ret = -ERANGE;
+ goto out_ports;
+ }
+
/* Initialize port data */
s->p[i].port.dev = dev;
s->p[i].port.irq = irq;
@@ -1581,12 +1563,9 @@ static int sc16is7xx_probe(struct device *dev,
s->p[i].port.rs485_supported = sc16is7xx_rs485_supported;
s->p[i].port.ops = &sc16is7xx_ops;
s->p[i].old_mctrl = 0;
- s->p[i].port.line = sc16is7xx_alloc_line();
+ s->p[i].regmap = regmaps[i];
- if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) {
- ret = -ENOMEM;
- goto out_ports;
- }
+ mutex_init(&s->p[i].efr_lock);
ret = uart_get_rs485_mode(&s->p[i].port);
if (ret)
@@ -1603,20 +1582,25 @@ static int sc16is7xx_probe(struct device *dev,
kthread_init_work(&s->p[i].tx_work, sc16is7xx_tx_proc);
kthread_init_work(&s->p[i].reg_work, sc16is7xx_reg_proc);
kthread_init_delayed_work(&s->p[i].ms_work, sc16is7xx_ms_proc);
+
/* Register port */
- uart_add_one_port(&sc16is7xx_uart, &s->p[i].port);
+ ret = uart_add_one_port(&sc16is7xx_uart, &s->p[i].port);
+ if (ret)
+ goto out_ports;
+
+ set_bit(s->p[i].port.line, sc16is7xx_lines);
/* Enable EFR */
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG,
SC16IS7XX_LCR_CONF_MODE_B);
- regcache_cache_bypass(s->regmap, true);
+ regcache_cache_bypass(regmaps[i], true);
/* Enable write access to enhanced features */
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFR_REG,
SC16IS7XX_EFR_ENABLE_BIT);
- regcache_cache_bypass(s->regmap, false);
+ regcache_cache_bypass(regmaps[i], false);
/* Restore access to general registers */
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 0x00);
@@ -1627,7 +1611,7 @@ static int sc16is7xx_probe(struct device *dev,
sc16is7xx_setup_irda_ports(s);
- ret = sc16is7xx_setup_mctrl_ports(s);
+ ret = sc16is7xx_setup_mctrl_ports(s, regmaps[0]);
if (ret)
goto out_ports;
@@ -1662,10 +1646,9 @@ static int sc16is7xx_probe(struct device *dev,
#endif
out_ports:
- for (i--; i >= 0; i--) {
- uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
- clear_bit(s->p[i].port.line, &sc16is7xx_lines);
- }
+ for (i = 0; i < devtype->nr_uart; i++)
+ if (test_and_clear_bit(s->p[i].port.line, sc16is7xx_lines))
+ uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
kthread_stop(s->kworker_task);
@@ -1687,8 +1670,8 @@ static void sc16is7xx_remove(struct device *dev)
for (i = 0; i < s->devtype->nr_uart; i++) {
kthread_cancel_delayed_work_sync(&s->p[i].ms_work);
- uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
- clear_bit(s->p[i].port.line, &sc16is7xx_lines);
+ if (test_and_clear_bit(s->p[i].port.line, sc16is7xx_lines))
+ uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
sc16is7xx_power(&s->p[i].port, 0);
}
@@ -1710,45 +1693,74 @@ static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
MODULE_DEVICE_TABLE(of, sc16is7xx_dt_ids);
static struct regmap_config regcfg = {
- .reg_bits = 7,
- .pad_bits = 1,
+ .reg_bits = 5,
+ .pad_bits = 3,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
.volatile_reg = sc16is7xx_regmap_volatile,
.precious_reg = sc16is7xx_regmap_precious,
+ .writeable_noinc_reg = sc16is7xx_regmap_noinc,
+ .readable_noinc_reg = sc16is7xx_regmap_noinc,
+ .max_raw_read = SC16IS7XX_FIFO_SIZE,
+ .max_raw_write = SC16IS7XX_FIFO_SIZE,
+ .max_register = SC16IS7XX_EFCR_REG,
};
+static const char *sc16is7xx_regmap_name(u8 port_id)
+{
+ switch (port_id) {
+ case 0: return "port0";
+ case 1: return "port1";
+ default:
+ WARN_ON(true);
+ return NULL;
+ }
+}
+
+static unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id)
+{
+ /* CH1,CH0 are at bits 2:1. */
+ return port_id << 1;
+}
+
#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
static int sc16is7xx_spi_probe(struct spi_device *spi)
{
const struct sc16is7xx_devtype *devtype;
- struct regmap *regmap;
+ struct regmap *regmaps[SC16IS7XX_MAX_PORTS];
+ unsigned int i;
int ret;
/* Setup SPI bus */
spi->bits_per_word = 8;
- /* only supports mode 0 on SC16IS762 */
+ /* For all variants, only mode 0 is supported */
+ if ((spi->mode & SPI_MODE_X_MASK) != SPI_MODE_0)
+ return dev_err_probe(&spi->dev, -EINVAL, "Unsupported SPI mode\n");
+
spi->mode = spi->mode ? : SPI_MODE_0;
- spi->max_speed_hz = spi->max_speed_hz ? : 15000000;
+ spi->max_speed_hz = spi->max_speed_hz ? : 4 * HZ_PER_MHZ;
ret = spi_setup(spi);
if (ret)
return ret;
- if (spi->dev.of_node) {
- devtype = device_get_match_data(&spi->dev);
- if (!devtype)
- return -ENODEV;
- } else {
- const struct spi_device_id *id_entry = spi_get_device_id(spi);
+ devtype = spi_get_device_match_data(spi);
+ if (!devtype)
+ return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n");
- devtype = (struct sc16is7xx_devtype *)id_entry->driver_data;
+ for (i = 0; i < devtype->nr_uart; i++) {
+ regcfg.name = sc16is7xx_regmap_name(i);
+ /*
+ * If read_flag_mask is 0, the regmap code sets it to a default
+ * of 0x80. Since we specify our own mask, we must add the READ
+ * bit ourselves:
+ */
+ regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i) |
+ SC16IS7XX_SPI_READ_BIT;
+ regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i);
+ regmaps[i] = devm_regmap_init_spi(spi, &regcfg);
}
- regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) |
- (devtype->nr_uart - 1);
- regmap = devm_regmap_init_spi(spi, &regcfg);
-
- return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq);
+ return sc16is7xx_probe(&spi->dev, devtype, regmaps, spi->irq);
}
static void sc16is7xx_spi_remove(struct spi_device *spi)
@@ -1778,30 +1790,27 @@ static struct spi_driver sc16is7xx_spi_uart_driver = {
.remove = sc16is7xx_spi_remove,
.id_table = sc16is7xx_spi_id_table,
};
-
-MODULE_ALIAS("spi:sc16is7xx");
#endif
#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
static int sc16is7xx_i2c_probe(struct i2c_client *i2c)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(i2c);
const struct sc16is7xx_devtype *devtype;
- struct regmap *regmap;
-
- if (i2c->dev.of_node) {
- devtype = device_get_match_data(&i2c->dev);
- if (!devtype)
- return -ENODEV;
- } else {
- devtype = (struct sc16is7xx_devtype *)id->driver_data;
+ struct regmap *regmaps[SC16IS7XX_MAX_PORTS];
+ unsigned int i;
+
+ devtype = i2c_get_match_data(i2c);
+ if (!devtype)
+ return dev_err_probe(&i2c->dev, -ENODEV, "Failed to match device\n");
+
+ for (i = 0; i < devtype->nr_uart; i++) {
+ regcfg.name = sc16is7xx_regmap_name(i);
+ regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i);
+ regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i);
+ regmaps[i] = devm_regmap_init_i2c(i2c, &regcfg);
}
- regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) |
- (devtype->nr_uart - 1);
- regmap = devm_regmap_init_i2c(i2c, &regcfg);
-
- return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq);
+ return sc16is7xx_probe(&i2c->dev, devtype, regmaps, i2c->irq);
}
static void sc16is7xx_i2c_remove(struct i2c_client *client)
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index 2be2c1098025..f24217a560d7 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -1021,7 +1021,7 @@ err_out:
return ret;
}
-static int sccnxp_remove(struct platform_device *pdev)
+static void sccnxp_remove(struct platform_device *pdev)
{
int i;
struct sccnxp_port *s = platform_get_drvdata(pdev);
@@ -1036,10 +1036,11 @@ static int sccnxp_remove(struct platform_device *pdev)
uart_unregister_driver(&s->uart);
- if (!IS_ERR(s->regulator))
- return regulator_disable(s->regulator);
-
- return 0;
+ if (!IS_ERR(s->regulator)) {
+ int ret = regulator_disable(s->regulator);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to disable regulator\n");
+ }
}
static struct platform_driver sccnxp_uart_driver = {
@@ -1047,7 +1048,7 @@ static struct platform_driver sccnxp_uart_driver = {
.name = SCCNXP_NAME,
},
.probe = sccnxp_probe,
- .remove = sccnxp_remove,
+ .remove_new = sccnxp_remove,
.id_table = sccnxp_id_table,
};
module_platform_driver(sccnxp_uart_driver);
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index 6d4006b41975..525f3a2f7bd4 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -1611,13 +1611,12 @@ static int tegra_uart_probe(struct platform_device *pdev)
return ret;
}
-static int tegra_uart_remove(struct platform_device *pdev)
+static void tegra_uart_remove(struct platform_device *pdev)
{
struct tegra_uart_port *tup = platform_get_drvdata(pdev);
struct uart_port *u = &tup->uport;
uart_remove_one_port(&tegra_uart_driver, u);
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -1644,7 +1643,7 @@ static const struct dev_pm_ops tegra_uart_pm_ops = {
static struct platform_driver tegra_uart_platform_driver = {
.probe = tegra_uart_probe,
- .remove = tegra_uart_remove,
+ .remove_new = tegra_uart_remove,
.driver = {
.name = "serial-tegra",
.of_match_table = tegra_uart_of_match,
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index f1348a509552..b56ed8c376b2 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -156,7 +156,7 @@ static void __uart_start(struct uart_state *state)
* enabled, serial_port_runtime_resume() calls start_tx() again
* after enabling the device.
*/
- if (!pm_runtime_enabled(port->dev) || pm_runtime_active(port->dev))
+ if (pm_runtime_active(&port_dev->dev))
port->ops->start_tx(port);
pm_runtime_mark_last_busy(&port_dev->dev);
pm_runtime_put_autosuspend(&port_dev->dev);
@@ -410,11 +410,10 @@ void
uart_update_timeout(struct uart_port *port, unsigned int cflag,
unsigned int baud)
{
- unsigned int size = tty_get_frame_size(cflag);
- u64 frame_time;
+ u64 temp = tty_get_frame_size(cflag);
- frame_time = (u64)size * NSEC_PER_SEC;
- port->frame_time = DIV64_U64_ROUND_UP(frame_time, baud);
+ temp *= NSEC_PER_SEC;
+ port->frame_time = (unsigned int)DIV64_U64_ROUND_UP(temp, baud);
}
EXPORT_SYMBOL(uart_update_timeout);
@@ -687,7 +686,7 @@ EXPORT_SYMBOL_GPL(uart_xchar_out);
* This function is used to send a high-priority XON/XOFF character to
* the device
*/
-static void uart_send_xchar(struct tty_struct *tty, char ch)
+static void uart_send_xchar(struct tty_struct *tty, u8 ch)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port;
@@ -1371,20 +1370,34 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4
return;
}
- /* Pick sane settings if the user hasn't */
- if ((supported_flags & (SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND)) &&
- !(rs485->flags & SER_RS485_RTS_ON_SEND) ==
- !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
- dev_warn_ratelimited(port->dev,
- "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n",
- port->name, port->line);
- rs485->flags |= SER_RS485_RTS_ON_SEND;
- rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
- supported_flags |= SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND;
+ /* Clear other RS485 flags but SER_RS485_TERMINATE_BUS and return if enabling RS422 */
+ if (rs485->flags & SER_RS485_MODE_RS422) {
+ rs485->flags &= (SER_RS485_ENABLED | SER_RS485_MODE_RS422 | SER_RS485_TERMINATE_BUS);
+ return;
}
rs485->flags &= supported_flags;
+ /* Pick sane settings if the user hasn't */
+ if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
+ !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
+ if (supported_flags & SER_RS485_RTS_ON_SEND) {
+ rs485->flags |= SER_RS485_RTS_ON_SEND;
+ rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
+
+ dev_warn_ratelimited(port->dev,
+ "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n",
+ port->name, port->line);
+ } else {
+ rs485->flags |= SER_RS485_RTS_AFTER_SEND;
+ rs485->flags &= ~SER_RS485_RTS_ON_SEND;
+
+ dev_warn_ratelimited(port->dev,
+ "%s (%d): invalid RTS setting, using RTS_AFTER_SEND instead\n",
+ port->name, port->line);
+ }
+ }
+
uart_sanitize_serial_rs485_delays(port, rs485);
/* Return clean padding area to userspace */
@@ -1402,6 +1415,16 @@ static void uart_set_rs485_termination(struct uart_port *port,
!!(rs485->flags & SER_RS485_TERMINATE_BUS));
}
+static void uart_set_rs485_rx_during_tx(struct uart_port *port,
+ const struct serial_rs485 *rs485)
+{
+ if (!(rs485->flags & SER_RS485_ENABLED))
+ return;
+
+ gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio,
+ !!(rs485->flags & SER_RS485_RX_DURING_TX));
+}
+
static int uart_rs485_config(struct uart_port *port)
{
struct serial_rs485 *rs485 = &port->rs485;
@@ -1413,12 +1436,17 @@ static int uart_rs485_config(struct uart_port *port)
uart_sanitize_serial_rs485(port, rs485);
uart_set_rs485_termination(port, rs485);
+ uart_set_rs485_rx_during_tx(port, rs485);
uart_port_lock_irqsave(port, &flags);
ret = port->rs485_config(port, NULL, rs485);
uart_port_unlock_irqrestore(port, flags);
- if (ret)
+ if (ret) {
memset(rs485, 0, sizeof(*rs485));
+ /* unset GPIOs */
+ gpiod_set_value_cansleep(port->rs485_term_gpio, 0);
+ gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, 0);
+ }
return ret;
}
@@ -1446,7 +1474,7 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port,
int ret;
unsigned long flags;
- if (!port->rs485_config)
+ if (!(port->rs485_supported.flags & SER_RS485_ENABLED))
return -ENOTTY;
if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user)))
@@ -1457,6 +1485,7 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port,
return ret;
uart_sanitize_serial_rs485(port, &rs485);
uart_set_rs485_termination(port, &rs485);
+ uart_set_rs485_rx_during_tx(port, &rs485);
uart_port_lock_irqsave(port, &flags);
ret = port->rs485_config(port, &tty->termios, &rs485);
@@ -1468,8 +1497,14 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port,
port->ops->set_mctrl(port, port->mctrl);
}
uart_port_unlock_irqrestore(port, flags);
- if (ret)
+ if (ret) {
+ /* restore old GPIO settings */
+ gpiod_set_value_cansleep(port->rs485_term_gpio,
+ !!(port->rs485.flags & SER_RS485_TERMINATE_BUS));
+ gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio,
+ !!(port->rs485.flags & SER_RS485_RX_DURING_TX));
return ret;
+ }
if (copy_to_user(rs485_user, &port->rs485, sizeof(port->rs485)))
return -EFAULT;
@@ -2342,7 +2377,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
mutex_lock(&port->mutex);
- tty_dev = device_find_child(uport->dev, &match, serial_match_port);
+ tty_dev = device_find_child(&uport->port_dev->dev, &match, serial_match_port);
if (tty_dev && device_may_wakeup(tty_dev)) {
enable_irq_wake(uport->irq);
put_device(tty_dev);
@@ -2423,7 +2458,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
mutex_lock(&port->mutex);
- tty_dev = device_find_child(uport->dev, &match, serial_match_port);
+ tty_dev = device_find_child(&uport->port_dev->dev, &match, serial_match_port);
if (!uport->suspended && device_may_wakeup(tty_dev)) {
if (irqd_is_wakeup_set(irq_get_irq_data((uport->irq))))
disable_irq_wake(uport->irq);
@@ -2633,7 +2668,8 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options)
mutex_lock(&tport->mutex);
port = uart_port_check(state);
- if (!port || !(port->ops->poll_get_char && port->ops->poll_put_char)) {
+ if (!port || port->type == PORT_UNKNOWN ||
+ !(port->ops->poll_get_char && port->ops->poll_put_char)) {
ret = -1;
goto out;
}
@@ -3153,7 +3189,8 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
* setserial to be used to alter this port's parameters.
*/
tty_dev = tty_port_register_device_attr_serdev(port, drv->tty_driver,
- uport->line, uport->dev, port, uport->tty_groups);
+ uport->line, uport->dev, &uport->port_dev->dev, port,
+ uport->tty_groups);
if (!IS_ERR(tty_dev)) {
device_set_wakeup_capable(tty_dev, 1);
} else {
@@ -3570,6 +3607,9 @@ int uart_get_rs485_mode(struct uart_port *port)
u32 rs485_delay[2];
int ret;
+ if (!(port->rs485_supported.flags & SER_RS485_ENABLED))
+ return 0;
+
ret = device_property_read_u32_array(dev, "rs485-rts-delay",
rs485_delay, 2);
if (!ret) {
@@ -3620,6 +3660,8 @@ int uart_get_rs485_mode(struct uart_port *port)
if (IS_ERR(desc))
return dev_err_probe(dev, PTR_ERR(desc), "Cannot get rs485-rx-during-tx-gpios\n");
port->rs485_rx_during_tx_gpio = desc;
+ if (port->rs485_rx_during_tx_gpio)
+ port->rs485_supported.flags |= SER_RS485_RX_DURING_TX;
return 0;
}
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
index eaa980722455..e1897894a4ef 100644
--- a/drivers/tty/serial/serial_txx9.c
+++ b/drivers/tty/serial/serial_txx9.c
@@ -1052,7 +1052,7 @@ static int serial_txx9_probe(struct platform_device *dev)
/*
* Remove serial ports registered against a platform device.
*/
-static int serial_txx9_remove(struct platform_device *dev)
+static void serial_txx9_remove(struct platform_device *dev)
{
int i;
@@ -1062,7 +1062,6 @@ static int serial_txx9_remove(struct platform_device *dev)
if (up->dev == &dev->dev)
serial_txx9_unregister_port(i);
}
- return 0;
}
#ifdef CONFIG_PM
@@ -1097,7 +1096,7 @@ static int serial_txx9_resume(struct platform_device *dev)
static struct platform_driver serial_txx9_plat_driver = {
.probe = serial_txx9_probe,
- .remove = serial_txx9_remove,
+ .remove_new = serial_txx9_remove,
#ifdef CONFIG_PM
.suspend = serial_txx9_suspend,
.resume = serial_txx9_resume,
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 84ab434c94ba..a85e7b9a2e49 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1558,10 +1558,9 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
struct dma_slave_config cfg;
int ret;
- chan = dma_request_slave_channel(port->dev,
- dir == DMA_MEM_TO_DEV ? "tx" : "rx");
- if (!chan) {
- dev_dbg(port->dev, "dma_request_slave_channel failed\n");
+ chan = dma_request_chan(port->dev, dir == DMA_MEM_TO_DEV ? "tx" : "rx");
+ if (IS_ERR(chan)) {
+ dev_dbg(port->dev, "dma_request_chan failed\n");
return NULL;
}
@@ -3190,7 +3189,7 @@ static struct uart_driver sci_uart_driver = {
.cons = SCI_CONSOLE,
};
-static int sci_remove(struct platform_device *dev)
+static void sci_remove(struct platform_device *dev)
{
struct sci_port *port = platform_get_drvdata(dev);
unsigned int type = port->port.type; /* uart_remove_... clears it */
@@ -3204,8 +3203,6 @@ static int sci_remove(struct platform_device *dev)
device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger);
if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF)
device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout);
-
- return 0;
}
@@ -3470,7 +3467,7 @@ static SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume);
static struct platform_driver sci_driver = {
.probe = sci_probe,
- .remove = sci_remove,
+ .remove_new = sci_remove,
.driver = {
.name = "sh-sci",
.pm = &sci_dev_pm_ops,
diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index b296e57a9dee..a4cc569a78a2 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -1007,7 +1007,7 @@ probe_out1:
return r;
}
-static int sifive_serial_remove(struct platform_device *dev)
+static void sifive_serial_remove(struct platform_device *dev)
{
struct sifive_serial_port *ssp = platform_get_drvdata(dev);
@@ -1015,8 +1015,6 @@ static int sifive_serial_remove(struct platform_device *dev)
uart_remove_one_port(&sifive_serial_uart_driver, &ssp->port);
free_irq(ssp->port.irq, ssp);
clk_notifier_unregister(ssp->clk, &ssp->clk_notifier);
-
- return 0;
}
static int sifive_serial_suspend(struct device *dev)
@@ -1033,8 +1031,8 @@ static int sifive_serial_resume(struct device *dev)
return uart_resume_port(&sifive_serial_uart_driver, &ssp->port);
}
-DEFINE_SIMPLE_DEV_PM_OPS(sifive_uart_pm_ops, sifive_serial_suspend,
- sifive_serial_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(sifive_uart_pm_ops, sifive_serial_suspend,
+ sifive_serial_resume);
static const struct of_device_id sifive_serial_of_match[] = {
{ .compatible = "sifive,fu540-c000-uart0" },
@@ -1045,7 +1043,7 @@ MODULE_DEVICE_TABLE(of, sifive_serial_of_match);
static struct platform_driver sifive_serial_platform_driver = {
.probe = sifive_serial_probe,
- .remove = sifive_serial_remove,
+ .remove_new = sifive_serial_remove,
.driver = {
.name = SIFIVE_SERIAL_NAME,
.pm = pm_sleep_ptr(&sifive_uart_pm_ops),
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index f257525f9299..15f14fa593da 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -1076,7 +1076,7 @@ static struct uart_driver sprd_uart_driver = {
.cons = SPRD_CONSOLE,
};
-static int sprd_remove(struct platform_device *dev)
+static void sprd_remove(struct platform_device *dev)
{
struct sprd_uart_port *sup = platform_get_drvdata(dev);
@@ -1089,8 +1089,6 @@ static int sprd_remove(struct platform_device *dev)
if (!sprd_ports_num)
uart_unregister_driver(&sprd_uart_driver);
-
- return 0;
}
static bool sprd_uart_is_console(struct uart_port *uport)
@@ -1257,7 +1255,7 @@ MODULE_DEVICE_TABLE(of, serial_ids);
static struct platform_driver sprd_platform_driver = {
.probe = sprd_probe,
- .remove = sprd_remove,
+ .remove_new = sprd_remove,
.driver = {
.name = "sprd_serial",
.of_match_table = serial_ids,
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index a821f5d76a26..bbb5595d7e24 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -793,13 +793,11 @@ static int asc_serial_probe(struct platform_device *pdev)
return 0;
}
-static int asc_serial_remove(struct platform_device *pdev)
+static void asc_serial_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
uart_remove_one_port(&asc_uart_driver, port);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -932,7 +930,7 @@ static const struct dev_pm_ops asc_serial_pm_ops = {
static struct platform_driver asc_serial_driver = {
.probe = asc_serial_probe,
- .remove = asc_serial_remove,
+ .remove_new = asc_serial_remove,
.driver = {
.name = DRIVER_NAME,
.pm = &asc_serial_pm_ops,
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 3048620315d6..794b77512740 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -226,12 +226,6 @@ static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *ter
stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
- if (port->rs485_rx_during_tx_gpio)
- gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio,
- !!(rs485conf->flags & SER_RS485_RX_DURING_TX));
- else
- rs485conf->flags |= SER_RS485_RX_DURING_TX;
-
if (rs485conf->flags & SER_RS485_ENABLED) {
cr1 = readl_relaxed(port->membase + ofs->cr1);
cr3 = readl_relaxed(port->membase + ofs->cr3);
@@ -256,6 +250,8 @@ static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *ter
writel_relaxed(cr3, port->membase + ofs->cr3);
writel_relaxed(cr1, port->membase + ofs->cr1);
+
+ rs485conf->flags |= SER_RS485_RX_DURING_TX;
} else {
stm32_usart_clr_bits(port, ofs->cr3,
USART_CR3_DEM | USART_CR3_DEP);
@@ -1822,7 +1818,7 @@ err_dma_rx:
return ret;
}
-static int stm32_usart_serial_remove(struct platform_device *pdev)
+static void stm32_usart_serial_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
struct stm32_port *stm32_port = to_stm32_port(port);
@@ -1861,8 +1857,6 @@ static int stm32_usart_serial_remove(struct platform_device *pdev)
}
stm32_usart_deinit_port(stm32_port);
-
- return 0;
}
static void __maybe_unused stm32_usart_console_putchar(struct uart_port *port, unsigned char ch)
@@ -2146,7 +2140,7 @@ static const struct dev_pm_ops stm32_serial_pm_ops = {
static struct platform_driver stm32_serial_driver = {
.probe = stm32_usart_serial_probe,
- .remove = stm32_usart_serial_remove,
+ .remove_new = stm32_usart_serial_remove,
.driver = {
.name = DRIVER_NAME,
.pm = &stm32_serial_pm_ops,
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index 5bfc0040f17b..8d612ab80680 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -595,7 +595,7 @@ out_free_port:
return err;
}
-static int hv_remove(struct platform_device *dev)
+static void hv_remove(struct platform_device *dev)
{
struct uart_port *port = platform_get_drvdata(dev);
@@ -608,8 +608,6 @@ static int hv_remove(struct platform_device *dev)
kfree(con_write_page);
kfree(port);
sunhv_port = NULL;
-
- return 0;
}
static const struct of_device_id hv_match[] = {
@@ -630,7 +628,7 @@ static struct platform_driver hv_driver = {
.of_match_table = hv_match,
},
.probe = hv_probe,
- .remove = hv_remove,
+ .remove_new = hv_remove,
};
static int __init sunhv_init(void)
diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c
index 4251f4e1ba99..99f5285819d4 100644
--- a/drivers/tty/serial/sunplus-uart.c
+++ b/drivers/tty/serial/sunplus-uart.c
@@ -662,13 +662,11 @@ static int sunplus_uart_probe(struct platform_device *pdev)
return ret;
}
-static int sunplus_uart_remove(struct platform_device *pdev)
+static void sunplus_uart_remove(struct platform_device *pdev)
{
struct sunplus_uart_port *sup = platform_get_drvdata(pdev);
uart_remove_one_port(&sunplus_uart_driver, &sup->port);
-
- return 0;
}
static int __maybe_unused sunplus_uart_suspend(struct device *dev)
@@ -703,7 +701,7 @@ MODULE_DEVICE_TABLE(of, sp_uart_of_match);
static struct platform_driver sunplus_uart_platform_driver = {
.probe = sunplus_uart_probe,
- .remove = sunplus_uart_remove,
+ .remove_new = sunplus_uart_remove,
.driver = {
.name = "sunplus_uart",
.of_match_table = sp_uart_of_match,
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index 6aa51a6f8063..1ea2f33a07a7 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -443,7 +443,7 @@ static void sunsab_start_tx(struct uart_port *port)
up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
writeb(up->interrupt_mask1, &up->regs->w.imr1);
-
+
if (!test_bit(SAB82532_XPR, &up->irqflags))
return;
@@ -549,7 +549,7 @@ static int sunsab_startup(struct uart_port *port)
(void) readb(&up->regs->r.isr1);
/*
- * Now, initialize the UART
+ * Now, initialize the UART
*/
writeb(0, &up->regs->w.ccr0); /* power-down */
writeb(SAB82532_CCR0_MCE | SAB82532_CCR0_SC_NRZ |
@@ -563,7 +563,7 @@ static int sunsab_startup(struct uart_port *port)
SAB82532_MODE_RAC);
writeb(up->cached_mode, &up->regs->w.mode);
writeb(SAB82532_RFC_DPS|SAB82532_RFC_RFTH_32, &up->regs->w.rfc);
-
+
tmp = readb(&up->regs->rw.ccr0);
tmp |= SAB82532_CCR0_PU; /* power-up */
writeb(tmp, &up->regs->rw.ccr0);
@@ -607,7 +607,7 @@ static void sunsab_shutdown(struct uart_port *port)
up->cached_dafo &= ~SAB82532_DAFO_XBRK;
writeb(up->cached_dafo, &up->regs->rw.dafo);
- /* Disable Receiver */
+ /* Disable Receiver */
up->cached_mode &= ~SAB82532_MODE_RAC;
writeb(up->cached_mode, &up->regs->rw.mode);
@@ -622,7 +622,7 @@ static void sunsab_shutdown(struct uart_port *port)
* speed the chip was configured for when the port was open).
*/
#if 0
- /* Power Down */
+ /* Power Down */
tmp = readb(&up->regs->rw.ccr0);
tmp &= ~SAB82532_CCR0_PU;
writeb(tmp, &up->regs->rw.ccr0);
@@ -649,7 +649,7 @@ static void calc_ebrg(int baud, int *n_ret, int *m_ret)
*m_ret = 0;
return;
}
-
+
/*
* We scale numbers by 10 so that we get better accuracy
* without having to use floating point. Here we increment m
@@ -788,7 +788,7 @@ static const char *sunsab_type(struct uart_port *port)
{
struct uart_sunsab_port *up = (void *)port;
static char buf[36];
-
+
sprintf(buf, "SAB82532 %s", sab82532_version[up->type]);
return buf;
}
@@ -933,7 +933,7 @@ static int sunsab_console_setup(struct console *con, char *options)
sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
uart_port_unlock_irqrestore(&up->port, flags);
-
+
return 0;
}
@@ -1066,7 +1066,7 @@ out:
return err;
}
-static int sab_remove(struct platform_device *op)
+static void sab_remove(struct platform_device *op)
{
struct uart_sunsab_port *up = platform_get_drvdata(op);
@@ -1078,8 +1078,6 @@ static int sab_remove(struct platform_device *op)
of_iounmap(&op->resource[0],
up[0].port.membase,
sizeof(union sab82532_async_regs));
-
- return 0;
}
static const struct of_device_id sab_match[] = {
@@ -1100,7 +1098,7 @@ static struct platform_driver sab_driver = {
.of_match_table = sab_match,
},
.probe = sab_probe,
- .remove = sab_remove,
+ .remove_new = sab_remove,
};
static int __init sunsab_init(void)
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index 1e051cc2591c..c8b65f4b2710 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -1515,7 +1515,7 @@ out_unmap:
return err;
}
-static int su_remove(struct platform_device *op)
+static void su_remove(struct platform_device *op)
{
struct uart_sunsu_port *up = platform_get_drvdata(op);
bool kbdms = false;
@@ -1536,8 +1536,6 @@ static int su_remove(struct platform_device *op)
if (kbdms)
kfree(up);
-
- return 0;
}
static const struct of_device_id su_match[] = {
@@ -1565,7 +1563,7 @@ static struct platform_driver su_driver = {
.of_match_table = su_match,
},
.probe = su_probe,
- .remove = su_remove,
+ .remove_new = su_remove,
};
static int __init sunsu_init(void)
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index d3b5e864b727..c99289c6c8f8 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -1513,7 +1513,7 @@ static void zs_remove_one(struct uart_sunzilog_port *up)
uart_remove_one_port(&sunzilog_reg, &up->port);
}
-static int zs_remove(struct platform_device *op)
+static void zs_remove(struct platform_device *op)
{
struct uart_sunzilog_port *up = platform_get_drvdata(op);
struct zilog_layout __iomem *regs;
@@ -1523,8 +1523,6 @@ static int zs_remove(struct platform_device *op)
regs = sunzilog_chip_regs[up[0].port.line / 2];
of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout));
-
- return 0;
}
static const struct of_device_id zs_match[] = {
@@ -1541,7 +1539,7 @@ static struct platform_driver zs_driver = {
.of_match_table = zs_match,
},
.probe = zs_probe,
- .remove = zs_remove,
+ .remove_new = zs_remove,
};
static int __init sunzilog_init(void)
diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c
index 65069daf36ec..d9c78320eb02 100644
--- a/drivers/tty/serial/tegra-tcu.c
+++ b/drivers/tty/serial/tegra-tcu.c
@@ -266,7 +266,7 @@ free_tx:
return err;
}
-static int tegra_tcu_remove(struct platform_device *pdev)
+static void tegra_tcu_remove(struct platform_device *pdev)
{
struct tegra_tcu *tcu = platform_get_drvdata(pdev);
@@ -277,8 +277,6 @@ static int tegra_tcu_remove(struct platform_device *pdev)
uart_remove_one_port(&tcu->driver, &tcu->port);
uart_unregister_driver(&tcu->driver);
mbox_free_channel(tcu->tx);
-
- return 0;
}
static const struct of_device_id tegra_tcu_match[] = {
@@ -293,7 +291,7 @@ static struct platform_driver tegra_tcu_driver = {
.of_match_table = tegra_tcu_match,
},
.probe = tegra_tcu_probe,
- .remove = tegra_tcu_remove,
+ .remove_new = tegra_tcu_remove,
};
module_platform_driver(tegra_tcu_driver);
diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c
index 0cc6524f5e8b..4bc89a9b380a 100644
--- a/drivers/tty/serial/timbuart.c
+++ b/drivers/tty/serial/timbuart.c
@@ -473,7 +473,7 @@ err_mem:
return err;
}
-static int timbuart_remove(struct platform_device *dev)
+static void timbuart_remove(struct platform_device *dev)
{
struct timbuart_port *uart = platform_get_drvdata(dev);
@@ -481,8 +481,6 @@ static int timbuart_remove(struct platform_device *dev)
uart_remove_one_port(&timbuart_driver, &uart->port);
uart_unregister_driver(&timbuart_driver);
kfree(uart);
-
- return 0;
}
static struct platform_driver timbuart_platform_driver = {
@@ -490,7 +488,7 @@ static struct platform_driver timbuart_platform_driver = {
.name = "timb-uart",
},
.probe = timbuart_probe,
- .remove = timbuart_remove,
+ .remove_new = timbuart_remove,
};
module_platform_driver(timbuart_platform_driver);
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index 404c14acafa5..10ba41b7be99 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -24,8 +24,13 @@
#include <linux/pm_runtime.h>
#define ULITE_NAME "ttyUL"
+#if CONFIG_SERIAL_UARTLITE_NR_UARTS > 4
+#define ULITE_MAJOR 0 /* use dynamic node allocation */
+#define ULITE_MINOR 0
+#else
#define ULITE_MAJOR 204
#define ULITE_MINOR 187
+#endif
#define ULITE_NR_UARTS CONFIG_SERIAL_UARTLITE_NR_UARTS
/* ---------------------------------------------------------------------
@@ -62,11 +67,11 @@ static struct uart_port *console_port;
#endif
/**
- * struct uartlite_data: Driver private data
- * reg_ops: Functions to read/write registers
- * clk: Our parent clock, if present
- * baud: The baud rate configured when this device was synthesized
- * cflags: The cflags for parity and data bits
+ * struct uartlite_data - Driver private data
+ * @reg_ops: Functions to read/write registers
+ * @clk: Our parent clock, if present
+ * @baud: The baud rate configured when this device was synthesized
+ * @cflags: The cflags for parity and data bits
*/
struct uartlite_data {
const struct uartlite_reg_ops *reg_ops;
@@ -890,7 +895,7 @@ of_err:
return ret;
}
-static int ulite_remove(struct platform_device *pdev)
+static void ulite_remove(struct platform_device *pdev)
{
struct uart_port *port = dev_get_drvdata(&pdev->dev);
struct uartlite_data *pdata = port->private_data;
@@ -900,7 +905,6 @@ static int ulite_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
- return 0;
}
/* work with hotplug and coldplug */
@@ -908,7 +912,7 @@ MODULE_ALIAS("platform:uartlite");
static struct platform_driver ulite_platform_driver = {
.probe = ulite_probe,
- .remove = ulite_remove,
+ .remove_new = ulite_remove,
.driver = {
.name = "uartlite",
.of_match_table = of_match_ptr(ulite_of_match),
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index ed7a6bb5596a..397b95dff7ed 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -189,10 +189,10 @@ struct uart_qe_port {
u16 tx_fifosize;
int wait_closing;
u32 flags;
- struct qe_bd *rx_bd_base;
- struct qe_bd *rx_cur;
- struct qe_bd *tx_bd_base;
- struct qe_bd *tx_cur;
+ struct qe_bd __iomem *rx_bd_base;
+ struct qe_bd __iomem *rx_cur;
+ struct qe_bd __iomem *tx_bd_base;
+ struct qe_bd __iomem *tx_cur;
unsigned char *tx_buf;
unsigned char *rx_buf;
void *bd_virt; /* virtual address of the BD buffers */
@@ -258,7 +258,7 @@ static unsigned int qe_uart_tx_empty(struct uart_port *port)
{
struct uart_qe_port *qe_port =
container_of(port, struct uart_qe_port, port);
- struct qe_bd *bdp = qe_port->tx_bd_base;
+ struct qe_bd __iomem *bdp = qe_port->tx_bd_base;
while (1) {
if (ioread16be(&bdp->status) & BD_SC_READY)
@@ -330,7 +330,7 @@ static void qe_uart_stop_tx(struct uart_port *port)
*/
static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
{
- struct qe_bd *bdp;
+ struct qe_bd __iomem *bdp;
unsigned char *p;
unsigned int count;
struct uart_port *port = &qe_port->port;
@@ -341,7 +341,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
/* Pick next descriptor and fill from buffer */
bdp = qe_port->tx_cur;
- p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port);
+ p = qe2cpu_addr(ioread32be(&bdp->buf), qe_port);
*p++ = port->x_char;
iowrite16be(1, &bdp->length);
@@ -368,7 +368,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
while (!(ioread16be(&bdp->status) & BD_SC_READY) && !uart_circ_empty(xmit)) {
count = 0;
- p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port);
+ p = qe2cpu_addr(ioread32be(&bdp->buf), qe_port);
while (count < qe_port->tx_fifosize) {
*p++ = xmit->buf[xmit->tail];
uart_xmit_advance(port, 1);
@@ -460,7 +460,7 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port)
unsigned char ch, *cp;
struct uart_port *port = &qe_port->port;
struct tty_port *tport = &port->state->port;
- struct qe_bd *bdp;
+ struct qe_bd __iomem *bdp;
u16 status;
unsigned int flg;
@@ -487,7 +487,7 @@ static void qe_uart_int_rx(struct uart_qe_port *qe_port)
}
/* get pointer */
- cp = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port);
+ cp = qe2cpu_addr(ioread32be(&bdp->buf), qe_port);
/* loop through the buffer */
while (i-- > 0) {
@@ -590,7 +590,7 @@ static void qe_uart_initbd(struct uart_qe_port *qe_port)
{
int i;
void *bd_virt;
- struct qe_bd *bdp;
+ struct qe_bd __iomem *bdp;
/* Set the physical address of the host memory buffers in the buffer
* descriptors, and the virtual address for us to work with.
@@ -648,7 +648,7 @@ static void qe_uart_init_ucc(struct uart_qe_port *qe_port)
{
u32 cecr_subblock;
struct ucc_slow __iomem *uccp = qe_port->uccp;
- struct ucc_uart_pram *uccup = qe_port->uccup;
+ struct ucc_uart_pram __iomem *uccup = qe_port->uccup;
unsigned int i;
@@ -983,7 +983,7 @@ static int qe_uart_request_port(struct uart_port *port)
qe_port->us_private = uccs;
qe_port->uccp = uccs->us_regs;
- qe_port->uccup = (struct ucc_uart_pram *) uccs->us_pram;
+ qe_port->uccup = (struct ucc_uart_pram __iomem *)uccs->us_pram;
qe_port->rx_bd_base = uccs->rx_bd;
qe_port->tx_bd_base = uccs->tx_bd;
@@ -1156,7 +1156,7 @@ static void uart_firmware_cont(const struct firmware *fw, void *context)
firmware = (struct qe_firmware *) fw->data;
- if (firmware->header.length != fw->size) {
+ if (be32_to_cpu(firmware->header.length) != fw->size) {
dev_err(dev, "invalid firmware\n");
goto out;
}
@@ -1459,7 +1459,7 @@ out_free:
return ret;
}
-static int ucc_uart_remove(struct platform_device *ofdev)
+static void ucc_uart_remove(struct platform_device *ofdev)
{
struct uart_qe_port *qe_port = platform_get_drvdata(ofdev);
@@ -1470,8 +1470,6 @@ static int ucc_uart_remove(struct platform_device *ofdev)
of_node_put(qe_port->np);
kfree(qe_port);
-
- return 0;
}
static const struct of_device_id ucc_uart_match[] = {
@@ -1492,7 +1490,7 @@ static struct platform_driver ucc_uart_of_driver = {
.of_match_table = ucc_uart_match,
},
.probe = ucc_uart_probe,
- .remove = ucc_uart_remove,
+ .remove_new = ucc_uart_remove,
};
static int __init ucc_uart_init(void)
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 66a45a634158..920762d7b4a4 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1663,10 +1663,8 @@ err_out_unregister_driver:
/**
* cdns_uart_remove - called when the platform driver is unregistered
* @pdev: Pointer to the platform device structure
- *
- * Return: 0 on success, negative errno otherwise
*/
-static int cdns_uart_remove(struct platform_device *pdev)
+static void cdns_uart_remove(struct platform_device *pdev)
{
struct uart_port *port = platform_get_drvdata(pdev);
struct cdns_uart *cdns_uart_data = port->private_data;
@@ -1692,12 +1690,11 @@ static int cdns_uart_remove(struct platform_device *pdev)
if (!--instances)
uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
- return 0;
}
static struct platform_driver cdns_uart_platform_driver = {
.probe = cdns_uart_probe,
- .remove = cdns_uart_remove,
+ .remove_new = cdns_uart_remove,
.driver = {
.name = CDNS_UART_NAME,
.of_match_table = cdns_uart_of_match,
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 6b4a28bcf2f5..02217e3c916b 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -1150,16 +1150,29 @@ EXPORT_SYMBOL(unregister_sysrq_key);
#ifdef CONFIG_PROC_FS
/*
* writing 'C' to /proc/sysrq-trigger is like sysrq-C
+ * Normally, only the first character written is processed.
+ * However, if the first character is an underscore,
+ * all characters are processed.
*/
static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- if (count) {
+ bool bulk = false;
+ size_t i;
+
+ for (i = 0; i < count; i++) {
char c;
- if (get_user(c, buf))
+ if (get_user(c, buf + i))
return -EFAULT;
- __handle_sysrq(c, false);
+
+ if (c == '_')
+ bulk = true;
+ else
+ __handle_sysrq(c, false);
+
+ if (!bulk)
+ break;
}
return count;
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 06414e43e0b5..407b0d87b7c1 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -852,9 +852,9 @@ static ssize_t iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty,
{
void *cookie = NULL;
unsigned long offset = 0;
- char kernel_buf[64];
ssize_t retval = 0;
size_t copied, count = iov_iter_count(to);
+ u8 kernel_buf[64];
do {
ssize_t size = min(count, sizeof(kernel_buf));
@@ -995,7 +995,7 @@ static ssize_t iterate_tty_write(struct tty_ldisc *ld, struct tty_struct *tty,
/* write_buf/write_cnt is protected by the atomic_write_lock mutex */
if (tty->write_cnt < chunk) {
- unsigned char *buf_chunk;
+ u8 *buf_chunk;
if (chunk < 1024)
chunk = 1024;
@@ -1047,6 +1047,7 @@ out:
return ret;
}
+#ifdef CONFIG_PRINT_QUOTA_WARNING
/**
* tty_write_message - write a message to a certain tty, not just the console.
* @tty: the destination tty_struct
@@ -1057,6 +1058,8 @@ out:
* needed.
*
* We must still hold the BTM and test the CLOSING flag for the moment.
+ *
+ * This function is DEPRECATED, do not use in new code.
*/
void tty_write_message(struct tty_struct *tty, char *msg)
{
@@ -1069,6 +1072,7 @@ void tty_write_message(struct tty_struct *tty, char *msg)
tty_write_unlock(tty);
}
}
+#endif
static ssize_t file_tty_write(struct file *file, struct kiocb *iocb, struct iov_iter *from)
{
@@ -1145,7 +1149,7 @@ ssize_t redirected_tty_write(struct kiocb *iocb, struct iov_iter *iter)
*
* Locking: none for xchar method, write ordering for write method.
*/
-int tty_send_xchar(struct tty_struct *tty, char ch)
+int tty_send_xchar(struct tty_struct *tty, u8 ch)
{
bool was_stopped = tty->flow.stopped;
@@ -2274,10 +2278,10 @@ static bool tty_legacy_tiocsti __read_mostly = IS_ENABLED(CONFIG_LEGACY_TIOCSTI)
* * Called functions take tty_ldiscs_lock
* * current->signal->tty check is safe without locks
*/
-static int tiocsti(struct tty_struct *tty, char __user *p)
+static int tiocsti(struct tty_struct *tty, u8 __user *p)
{
- char ch, mbz = 0;
struct tty_ldisc *ld;
+ u8 ch;
if (!tty_legacy_tiocsti && !capable(CAP_SYS_ADMIN))
return -EIO;
@@ -2292,7 +2296,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
return -EIO;
tty_buffer_lock_exclusive(tty->port);
if (ld->ops->receive_buf)
- ld->ops->receive_buf(tty, &ch, &mbz, 1);
+ ld->ops->receive_buf(tty, &ch, NULL, 1);
tty_buffer_unlock_exclusive(tty->port);
tty_ldisc_deref(ld);
return 0;
@@ -2489,6 +2493,9 @@ static int send_break(struct tty_struct *tty, unsigned int duration)
if (!retval) {
msleep_interruptible(duration);
retval = tty->ops->break_ctl(tty, 0);
+ } else if (retval == -EOPNOTSUPP) {
+ /* some drivers can tell only dynamically */
+ retval = 0;
}
tty_write_unlock(tty);
@@ -2499,6 +2506,24 @@ static int send_break(struct tty_struct *tty, unsigned int duration)
}
/**
+ * tty_get_tiocm - get tiocm status register
+ * @tty: tty device
+ *
+ * Obtain the modem status bits from the tty driver if the feature
+ * is supported.
+ */
+int tty_get_tiocm(struct tty_struct *tty)
+{
+ int retval = -ENOTTY;
+
+ if (tty->ops->tiocmget)
+ retval = tty->ops->tiocmget(tty);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(tty_get_tiocm);
+
+/**
* tty_tiocmget - get modem status
* @tty: tty device
* @p: pointer to result
@@ -2510,14 +2535,12 @@ static int send_break(struct tty_struct *tty, unsigned int duration)
*/
static int tty_tiocmget(struct tty_struct *tty, int __user *p)
{
- int retval = -ENOTTY;
+ int retval;
- if (tty->ops->tiocmget) {
- retval = tty->ops->tiocmget(tty);
+ retval = tty_get_tiocm(tty);
+ if (retval >= 0)
+ retval = put_user(retval, p);
- if (retval >= 0)
- retval = put_user(retval, p);
- }
return retval;
}
@@ -3138,7 +3161,7 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
*
* Return: the number of characters successfully output.
*/
-int tty_put_char(struct tty_struct *tty, unsigned char ch)
+int tty_put_char(struct tty_struct *tty, u8 ch)
{
if (tty->ops->put_char)
return tty->ops->put_char(tty, ch);
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 4b499301a3db..85de90eebc7b 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -844,7 +844,7 @@ int tty_mode_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
ret = -EFAULT;
return ret;
case TIOCSLCKTRMIOS:
- if (!capable(CAP_SYS_ADMIN))
+ if (!checkpoint_restore_ns_capable(&init_user_ns))
return -EPERM;
copy_termios_locked(real_tty, &kterm);
if (user_termios_to_kernel_termios(&kterm,
@@ -861,7 +861,7 @@ int tty_mode_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
ret = -EFAULT;
return ret;
case TIOCSLCKTRMIOS:
- if (!capable(CAP_SYS_ADMIN))
+ if (!checkpoint_restore_ns_capable(&init_user_ns))
return -EPERM;
copy_termios_locked(real_tty, &kterm);
if (user_termios_to_kernel_termios_1(&kterm,
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 63c125250961..14cca33d2269 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -171,7 +171,8 @@ EXPORT_SYMBOL_GPL(tty_port_register_device_attr);
* @port: tty_port of the device
* @driver: tty_driver for this device
* @index: index of the tty
- * @device: parent if exists, otherwise NULL
+ * @host: serial port hardware device
+ * @parent: parent if exists, otherwise NULL
* @drvdata: driver data for the device
* @attr_grp: attribute group for the device
*
@@ -180,20 +181,20 @@ EXPORT_SYMBOL_GPL(tty_port_register_device_attr);
*/
struct device *tty_port_register_device_attr_serdev(struct tty_port *port,
struct tty_driver *driver, unsigned index,
- struct device *device, void *drvdata,
+ struct device *host, struct device *parent, void *drvdata,
const struct attribute_group **attr_grp)
{
struct device *dev;
tty_port_link_device(port, driver, index);
- dev = serdev_tty_port_register(port, device, driver, index);
+ dev = serdev_tty_port_register(port, host, parent, driver, index);
if (PTR_ERR(dev) != -ENODEV) {
/* Skip creating cdev if we registered a serdev device */
return dev;
}
- return tty_register_device_attr(driver, index, device, drvdata,
+ return tty_register_device_attr(driver, index, parent, drvdata,
attr_grp);
}
EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev);
@@ -203,17 +204,18 @@ EXPORT_SYMBOL_GPL(tty_port_register_device_attr_serdev);
* @port: tty_port of the device
* @driver: tty_driver for this device
* @index: index of the tty
- * @device: parent if exists, otherwise NULL
+ * @host: serial port hardware controller device
+ * @parent: parent if exists, otherwise NULL
*
* Register a serdev or tty device depending on if the parent device has any
* defined serdev clients or not.
*/
struct device *tty_port_register_device_serdev(struct tty_port *port,
struct tty_driver *driver, unsigned index,
- struct device *device)
+ struct device *host, struct device *parent)
{
return tty_port_register_device_attr_serdev(port, driver, index,
- device, NULL, NULL);
+ host, parent, NULL, NULL);
}
EXPORT_SYMBOL_GPL(tty_port_register_device_serdev);
@@ -245,7 +247,7 @@ int tty_port_alloc_xmit_buf(struct tty_port *port)
/* We may sleep in get_zeroed_page() */
mutex_lock(&port->buf_mutex);
if (port->xmit_buf == NULL) {
- port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+ port->xmit_buf = (u8 *)get_zeroed_page(GFP_KERNEL);
if (port->xmit_buf)
kfifo_init(&port->xmit_fifo, port->xmit_buf, PAGE_SIZE);
}
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 5e39a4f430ee..82d70083fead 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -644,7 +644,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
if (!ct)
return 0;
- unilist = vmemdup_user(list, array_size(sizeof(*unilist), ct));
+ unilist = vmemdup_array_user(list, ct, sizeof(*unilist));
if (IS_ERR(unilist))
return PTR_ERR(unilist);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 12a192e1196b..a2116e135a82 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1772,12 +1772,10 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
return -EINVAL;
if (ct) {
-
- dia = memdup_user(a->kbdiacr,
- sizeof(struct kbdiacr) * ct);
+ dia = memdup_array_user(a->kbdiacr,
+ ct, sizeof(struct kbdiacr));
if (IS_ERR(dia))
return PTR_ERR(dia);
-
}
spin_lock_irqsave(&kbd_event_lock, flags);
@@ -1811,8 +1809,8 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm)
return -EINVAL;
if (ct) {
- buf = memdup_user(a->kbdiacruc,
- ct * sizeof(struct kbdiacruc));
+ buf = memdup_array_user(a->kbdiacruc,
+ ct, sizeof(struct kbdiacruc));
if (IS_ERR(buf))
return PTR_ERR(buf);
}
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 62082d64ece0..2d572f6c8ec8 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -466,13 +466,13 @@ static int uio_open(struct inode *inode, struct file *filep)
mutex_lock(&minor_lock);
idev = idr_find(&uio_idr, iminor(inode));
- mutex_unlock(&minor_lock);
if (!idev) {
ret = -ENODEV;
+ mutex_unlock(&minor_lock);
goto out;
}
-
get_device(&idev->dev);
+ mutex_unlock(&minor_lock);
if (!try_module_get(idev->owner)) {
ret = -ENODEV;
@@ -1064,9 +1064,8 @@ void uio_unregister_device(struct uio_info *info)
wake_up_interruptible(&idev->wait);
kill_fasync(&idev->async_queue, SIGIO, POLL_HUP);
- device_unregister(&idev->dev);
-
uio_free_minor(minor);
+ device_unregister(&idev->dev);
return;
}
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 5812f7ea7f90..16703815be0c 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -546,7 +546,7 @@ MODULE_PARM_DESC(annex,
#define uea_wait(sc, cond, timeo) \
({ \
- int _r = wait_event_interruptible_timeout(sc->sync_q, \
+ int _r = wait_event_freezable_timeout(sc->sync_q, \
(cond) || kthread_should_stop(), timeo); \
if (kthread_should_stop()) \
_r = -ENODEV; \
@@ -1896,7 +1896,6 @@ static int uea_kthread(void *data)
ret = sc->stat(sc);
if (ret != -EAGAIN)
uea_wait(sc, 0, msecs_to_jiffies(1000));
- try_to_freeze();
}
uea_leaves(INS_TO_USBDEV(sc));
return ret;
@@ -2252,7 +2251,7 @@ static ssize_t stat_status_show(struct device *dev, struct device_attribute *att
sc = dev_to_uea(dev);
if (!sc)
goto out;
- ret = snprintf(buf, 10, "%08x\n", sc->stats.phy.state);
+ ret = sysfs_emit(buf, "%08x\n", sc->stats.phy.state);
out:
mutex_unlock(&uea_mutex);
return ret;
@@ -2318,19 +2317,19 @@ static ssize_t stat_human_status_show(struct device *dev,
switch (modem_state) {
case 0:
- ret = sprintf(buf, "Modem is booting\n");
+ ret = sysfs_emit(buf, "Modem is booting\n");
break;
case 1:
- ret = sprintf(buf, "Modem is initializing\n");
+ ret = sysfs_emit(buf, "Modem is initializing\n");
break;
case 2:
- ret = sprintf(buf, "Modem is operational\n");
+ ret = sysfs_emit(buf, "Modem is operational\n");
break;
case 3:
- ret = sprintf(buf, "Modem synchronization failed\n");
+ ret = sysfs_emit(buf, "Modem synchronization failed\n");
break;
default:
- ret = sprintf(buf, "Modem state is unknown\n");
+ ret = sysfs_emit(buf, "Modem state is unknown\n");
break;
}
out:
@@ -2364,7 +2363,7 @@ static ssize_t stat_delin_show(struct device *dev, struct device_attribute *attr
delin = "LOSS";
}
- ret = sprintf(buf, "%s\n", delin);
+ ret = sysfs_emit(buf, "%s\n", delin);
out:
mutex_unlock(&uea_mutex);
return ret;
@@ -2384,7 +2383,7 @@ static ssize_t stat_##name##_show(struct device *dev, \
sc = dev_to_uea(dev); \
if (!sc) \
goto out; \
- ret = snprintf(buf, 10, "%08x\n", sc->stats.phy.name); \
+ ret = sysfs_emit(buf, "%08x\n", sc->stats.phy.name); \
if (reset) \
sc->stats.phy.name = 0; \
out: \
diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c
index 11a5b3437c32..aeca902ab6cc 100644
--- a/drivers/usb/cdns3/cdns3-gadget.c
+++ b/drivers/usb/cdns3/cdns3-gadget.c
@@ -1119,6 +1119,8 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
dma_addr_t trb_dma;
u32 togle_pcs = 1;
int sg_iter = 0;
+ int num_trb_req;
+ int trb_burst;
int num_trb;
int address;
u32 control;
@@ -1126,16 +1128,15 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
u16 total_tdl = 0;
struct scatterlist *s = NULL;
bool sg_supported = !!(request->num_mapped_sgs);
+ u32 ioc = request->no_interrupt ? 0 : TRB_IOC;
+ num_trb_req = sg_supported ? request->num_mapped_sgs : 1;
+
+ /* ISO transfer require each SOF have a TD, each TD include some TRBs */
if (priv_ep->type == USB_ENDPOINT_XFER_ISOC)
- num_trb = priv_ep->interval;
+ num_trb = priv_ep->interval * num_trb_req;
else
- num_trb = sg_supported ? request->num_mapped_sgs : 1;
-
- if (num_trb > priv_ep->free_trbs) {
- priv_ep->flags |= EP_RING_FULL;
- return -ENOBUFS;
- }
+ num_trb = num_trb_req;
priv_req = to_cdns3_request(request);
address = priv_ep->endpoint.desc->bEndpointAddress;
@@ -1184,14 +1185,31 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
link_trb->control = cpu_to_le32(((priv_ep->pcs) ? TRB_CYCLE : 0) |
TRB_TYPE(TRB_LINK) | TRB_TOGGLE | ch_bit);
+
+ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) {
+ /*
+ * ISO require LINK TRB must be first one of TD.
+ * Fill LINK TRBs for left trb space to simply software process logic.
+ */
+ while (priv_ep->enqueue) {
+ *trb = *link_trb;
+ trace_cdns3_prepare_trb(priv_ep, trb);
+
+ cdns3_ep_inc_enq(priv_ep);
+ trb = priv_ep->trb_pool + priv_ep->enqueue;
+ priv_req->trb = trb;
+ }
+ }
+ }
+
+ if (num_trb > priv_ep->free_trbs) {
+ priv_ep->flags |= EP_RING_FULL;
+ return -ENOBUFS;
}
if (priv_dev->dev_ver <= DEV_VER_V2)
togle_pcs = cdns3_wa1_update_guard(priv_ep, trb);
- if (sg_supported)
- s = request->sg;
-
/* set incorrect Cycle Bit for first trb*/
control = priv_ep->pcs ? 0 : TRB_CYCLE;
trb->length = 0;
@@ -1209,6 +1227,9 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
do {
u32 length;
+ if (!(sg_iter % num_trb_req) && sg_supported)
+ s = request->sg;
+
/* fill TRB */
control |= TRB_TYPE(TRB_NORMAL);
if (sg_supported) {
@@ -1223,7 +1244,36 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
total_tdl += DIV_ROUND_UP(length,
priv_ep->endpoint.maxpacket);
- trb->length |= cpu_to_le32(TRB_BURST_LEN(priv_ep->trb_burst_size) |
+ trb_burst = priv_ep->trb_burst_size;
+
+ /*
+ * Supposed DMA cross 4k bounder problem should be fixed at DEV_VER_V2, but still
+ * met problem when do ISO transfer if sg enabled.
+ *
+ * Data pattern likes below when sg enabled, package size is 1k and mult is 2
+ * [UVC Header(8B) ] [data(3k - 8)] ...
+ *
+ * The received data at offset 0xd000 will get 0xc000 data, len 0x70. Error happen
+ * as below pattern:
+ * 0xd000: wrong
+ * 0xe000: wrong
+ * 0xf000: correct
+ * 0x10000: wrong
+ * 0x11000: wrong
+ * 0x12000: correct
+ * ...
+ *
+ * But it is still unclear about why error have not happen below 0xd000, it should
+ * cross 4k bounder. But anyway, the below code can fix this problem.
+ *
+ * To avoid DMA cross 4k bounder at ISO transfer, reduce burst len according to 16.
+ */
+ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && priv_dev->dev_ver <= DEV_VER_V2)
+ if (ALIGN_DOWN(trb->buffer, SZ_4K) !=
+ ALIGN_DOWN(trb->buffer + length, SZ_4K))
+ trb_burst = 16;
+
+ trb->length |= cpu_to_le32(TRB_BURST_LEN(trb_burst) |
TRB_LEN(length));
pcs = priv_ep->pcs ? TRB_CYCLE : 0;
@@ -1235,11 +1285,11 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
control |= pcs;
if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && !priv_ep->dir) {
- control |= TRB_IOC | TRB_ISP;
+ control |= ioc | TRB_ISP;
} else {
/* for last element in TD or in SG list */
if (sg_iter == (num_trb - 1) && sg_iter != 0)
- control |= pcs | TRB_IOC | TRB_ISP;
+ control |= pcs | ioc | TRB_ISP;
}
if (sg_iter)
@@ -1250,7 +1300,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
if (sg_supported) {
trb->control |= cpu_to_le32(TRB_ISP);
/* Don't set chain bit for last TRB */
- if (sg_iter < num_trb - 1)
+ if ((sg_iter % num_trb_req) < num_trb_req - 1)
trb->control |= cpu_to_le32(TRB_CHAIN);
s = sg_next(s);
@@ -1270,7 +1320,7 @@ static int cdns3_ep_run_transfer(struct cdns3_endpoint *priv_ep,
priv_req->num_of_trb = num_trb;
if (sg_iter == 1)
- trb->control |= cpu_to_le32(TRB_IOC | TRB_ISP);
+ trb->control |= cpu_to_le32(ioc | TRB_ISP);
if (priv_dev->dev_ver < DEV_VER_V2 &&
(priv_ep->flags & EP_TDLCHK_EN)) {
@@ -1508,6 +1558,12 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
/* The TRB was changed as link TRB, and the request was handled at ep_dequeue */
while (TRB_FIELD_TO_TYPE(le32_to_cpu(trb->control)) == TRB_LINK) {
+
+ /* ISO ep_traddr may stop at LINK TRB */
+ if (priv_ep->dequeue == cdns3_get_dma_pos(priv_dev, priv_ep) &&
+ priv_ep->type == USB_ENDPOINT_XFER_ISOC)
+ break;
+
trace_cdns3_complete_trb(priv_ep, trb);
cdns3_ep_inc_deq(priv_ep);
trb = priv_ep->trb_pool + priv_ep->dequeue;
@@ -1540,6 +1596,10 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev,
}
if (request_handled) {
+ /* TRBs are duplicated by priv_ep->interval time for ISO IN */
+ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && priv_ep->dir)
+ request->actual /= priv_ep->interval;
+
cdns3_gadget_giveback(priv_ep, priv_req, 0);
request_handled = false;
transfer_end = false;
@@ -2035,11 +2095,10 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable)
bool is_iso_ep = (priv_ep->type == USB_ENDPOINT_XFER_ISOC);
struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
u32 bEndpointAddress = priv_ep->num | priv_ep->dir;
- u32 max_packet_size = 0;
- u8 maxburst = 0;
+ u32 max_packet_size = priv_ep->wMaxPacketSize;
+ u8 maxburst = priv_ep->bMaxBurst;
u32 ep_cfg = 0;
u8 buffering;
- u8 mult = 0;
int ret;
buffering = priv_dev->ep_buf_size - 1;
@@ -2061,8 +2120,7 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable)
break;
default:
ep_cfg = EP_CFG_EPTYPE(USB_ENDPOINT_XFER_ISOC);
- mult = priv_dev->ep_iso_burst - 1;
- buffering = mult + 1;
+ buffering = (priv_ep->bMaxBurst + 1) * (priv_ep->mult + 1) - 1;
}
switch (priv_dev->gadget.speed) {
@@ -2073,17 +2131,8 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable)
max_packet_size = is_iso_ep ? 1024 : 512;
break;
case USB_SPEED_SUPER:
- /* It's limitation that driver assumes in driver. */
- mult = 0;
- max_packet_size = 1024;
- if (priv_ep->type == USB_ENDPOINT_XFER_ISOC) {
- maxburst = priv_dev->ep_iso_burst - 1;
- buffering = (mult + 1) *
- (maxburst + 1);
-
- if (priv_ep->interval > 1)
- buffering++;
- } else {
+ if (priv_ep->type != USB_ENDPOINT_XFER_ISOC) {
+ max_packet_size = 1024;
maxburst = priv_dev->ep_buf_size - 1;
}
break;
@@ -2112,7 +2161,6 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable)
if (priv_dev->dev_ver < DEV_VER_V2)
priv_ep->trb_burst_size = 16;
- mult = min_t(u8, mult, EP_CFG_MULT_MAX);
buffering = min_t(u8, buffering, EP_CFG_BUFFERING_MAX);
maxburst = min_t(u8, maxburst, EP_CFG_MAXBURST_MAX);
@@ -2146,7 +2194,7 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable)
}
ep_cfg |= EP_CFG_MAXPKTSIZE(max_packet_size) |
- EP_CFG_MULT(mult) |
+ EP_CFG_MULT(priv_ep->mult) | /* must match EP setting */
EP_CFG_BUFFERING(buffering) |
EP_CFG_MAXBURST(maxburst);
@@ -2236,6 +2284,13 @@ usb_ep *cdns3_gadget_match_ep(struct usb_gadget *gadget,
priv_ep->type = usb_endpoint_type(desc);
priv_ep->flags |= EP_CLAIMED;
priv_ep->interval = desc->bInterval ? BIT(desc->bInterval - 1) : 0;
+ priv_ep->wMaxPacketSize = usb_endpoint_maxp(desc);
+ priv_ep->mult = USB_EP_MAXP_MULT(priv_ep->wMaxPacketSize);
+ priv_ep->wMaxPacketSize &= USB_ENDPOINT_MAXP_MASK;
+ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC && comp_desc) {
+ priv_ep->mult = USB_SS_MULT(comp_desc->bmAttributes) - 1;
+ priv_ep->bMaxBurst = comp_desc->bMaxBurst;
+ }
spin_unlock_irqrestore(&priv_dev->lock, flags);
return &priv_ep->endpoint;
@@ -3019,22 +3074,40 @@ static int cdns3_gadget_check_config(struct usb_gadget *gadget)
struct cdns3_endpoint *priv_ep;
struct usb_ep *ep;
int n_in = 0;
+ int iso = 0;
+ int out = 1;
int total;
+ int n;
list_for_each_entry(ep, &gadget->ep_list, ep_list) {
priv_ep = ep_to_cdns3_ep(ep);
- if ((priv_ep->flags & EP_CLAIMED) && (ep->address & USB_DIR_IN))
- n_in++;
+ if (!(priv_ep->flags & EP_CLAIMED))
+ continue;
+
+ n = (priv_ep->mult + 1) * (priv_ep->bMaxBurst + 1);
+ if (ep->address & USB_DIR_IN) {
+ /*
+ * ISO transfer: DMA start move data when get ISO, only transfer
+ * data as min(TD size, iso). No benefit for allocate bigger
+ * internal memory than 'iso'.
+ */
+ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC)
+ iso += n;
+ else
+ n_in++;
+ } else {
+ if (priv_ep->type == USB_ENDPOINT_XFER_ISOC)
+ out = max_t(int, out, n);
+ }
}
/* 2KB are reserved for EP0, 1KB for out*/
- total = 2 + n_in + 1;
+ total = 2 + n_in + out + iso;
if (total > priv_dev->onchip_buffers)
return -ENOMEM;
- priv_dev->ep_buf_size = priv_dev->ep_iso_burst =
- (priv_dev->onchip_buffers - 2) / (n_in + 1);
+ priv_dev->ep_buf_size = (priv_dev->onchip_buffers - 2 - iso) / (n_in + out);
return 0;
}
diff --git a/drivers/usb/cdns3/cdns3-gadget.h b/drivers/usb/cdns3/cdns3-gadget.h
index fbe4a8e3aa89..086a7bb83897 100644
--- a/drivers/usb/cdns3/cdns3-gadget.h
+++ b/drivers/usb/cdns3/cdns3-gadget.h
@@ -1168,6 +1168,9 @@ struct cdns3_endpoint {
u8 dir;
u8 num;
u8 type;
+ u8 mult;
+ u8 bMaxBurst;
+ u16 wMaxPacketSize;
int interval;
int free_trbs;
diff --git a/drivers/usb/cdns3/cdns3-plat.c b/drivers/usb/cdns3/cdns3-plat.c
index 2c1aca84f226..3ef8e3c872a3 100644
--- a/drivers/usb/cdns3/cdns3-plat.c
+++ b/drivers/usb/cdns3/cdns3-plat.c
@@ -87,16 +87,20 @@ static int cdns3_plat_probe(struct platform_device *pdev)
cdns->dev_irq = platform_get_irq_byname(pdev, "peripheral");
if (cdns->dev_irq < 0)
- return cdns->dev_irq;
+ return dev_err_probe(dev, cdns->dev_irq,
+ "Failed to get peripheral IRQ\n");
regs = devm_platform_ioremap_resource_byname(pdev, "dev");
if (IS_ERR(regs))
- return PTR_ERR(regs);
+ return dev_err_probe(dev, PTR_ERR(regs),
+ "Failed to get dev base\n");
+
cdns->dev_regs = regs;
cdns->otg_irq = platform_get_irq_byname(pdev, "otg");
if (cdns->otg_irq < 0)
- return cdns->otg_irq;
+ return dev_err_probe(dev, cdns->otg_irq,
+ "Failed to get otg IRQ\n");
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otg");
if (!res) {
@@ -119,7 +123,8 @@ static int cdns3_plat_probe(struct platform_device *pdev)
cdns->usb2_phy = devm_phy_optional_get(dev, "cdns3,usb2-phy");
if (IS_ERR(cdns->usb2_phy))
- return PTR_ERR(cdns->usb2_phy);
+ return dev_err_probe(dev, PTR_ERR(cdns->usb2_phy),
+ "Failed to get cdn3,usb2-phy\n");
ret = phy_init(cdns->usb2_phy);
if (ret)
@@ -127,7 +132,8 @@ static int cdns3_plat_probe(struct platform_device *pdev)
cdns->usb3_phy = devm_phy_optional_get(dev, "cdns3,usb3-phy");
if (IS_ERR(cdns->usb3_phy))
- return PTR_ERR(cdns->usb3_phy);
+ return dev_err_probe(dev, PTR_ERR(cdns->usb3_phy),
+ "Failed to get cdn3,usb3-phy\n");
ret = phy_init(cdns->usb3_phy);
if (ret)
diff --git a/drivers/usb/cdns3/cdns3-starfive.c b/drivers/usb/cdns3/cdns3-starfive.c
index a7265b86e427..c04d196abd87 100644
--- a/drivers/usb/cdns3/cdns3-starfive.c
+++ b/drivers/usb/cdns3/cdns3-starfive.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* cdns3-starfive.c - StarFive specific Glue layer for Cadence USB Controller
*
* Copyright (C) 2023 StarFive Technology Co., Ltd.
diff --git a/drivers/usb/cdns3/cdnsp-debug.h b/drivers/usb/cdns3/cdnsp-debug.h
index ad617b7455b9..cd138acdcce1 100644
--- a/drivers/usb/cdns3/cdnsp-debug.h
+++ b/drivers/usb/cdns3/cdnsp-debug.h
@@ -187,202 +187,202 @@ static inline const char *cdnsp_decode_trb(char *str, size_t size, u32 field0,
switch (type) {
case TRB_LINK:
- ret = snprintf(str, size,
- "LINK %08x%08x intr %ld type '%s' flags %c:%c:%c:%c",
- field1, field0, GET_INTR_TARGET(field2),
- cdnsp_trb_type_string(type),
- field3 & TRB_IOC ? 'I' : 'i',
- field3 & TRB_CHAIN ? 'C' : 'c',
- field3 & TRB_TC ? 'T' : 't',
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size,
+ "LINK %08x%08x intr %ld type '%s' flags %c:%c:%c:%c",
+ field1, field0, GET_INTR_TARGET(field2),
+ cdnsp_trb_type_string(type),
+ field3 & TRB_IOC ? 'I' : 'i',
+ field3 & TRB_CHAIN ? 'C' : 'c',
+ field3 & TRB_TC ? 'T' : 't',
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_TRANSFER:
case TRB_COMPLETION:
case TRB_PORT_STATUS:
case TRB_HC_EVENT:
- ret = snprintf(str, size,
- "ep%d%s(%d) type '%s' TRB %08x%08x status '%s'"
- " len %ld slot %ld flags %c:%c",
- ep_num, ep_id % 2 ? "out" : "in",
- TRB_TO_EP_INDEX(field3),
- cdnsp_trb_type_string(type), field1, field0,
- cdnsp_trb_comp_code_string(GET_COMP_CODE(field2)),
- EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3),
- field3 & EVENT_DATA ? 'E' : 'e',
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size,
+ "ep%d%s(%d) type '%s' TRB %08x%08x status '%s'"
+ " len %ld slot %ld flags %c:%c",
+ ep_num, ep_id % 2 ? "out" : "in",
+ TRB_TO_EP_INDEX(field3),
+ cdnsp_trb_type_string(type), field1, field0,
+ cdnsp_trb_comp_code_string(GET_COMP_CODE(field2)),
+ EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3),
+ field3 & EVENT_DATA ? 'E' : 'e',
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_MFINDEX_WRAP:
- ret = snprintf(str, size, "%s: flags %c",
- cdnsp_trb_type_string(type),
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size, "%s: flags %c",
+ cdnsp_trb_type_string(type),
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_SETUP:
- ret = snprintf(str, size,
- "type '%s' bRequestType %02x bRequest %02x "
- "wValue %02x%02x wIndex %02x%02x wLength %d "
- "length %ld TD size %ld intr %ld Setup ID %ld "
- "flags %c:%c:%c",
- cdnsp_trb_type_string(type),
- field0 & 0xff,
- (field0 & 0xff00) >> 8,
- (field0 & 0xff000000) >> 24,
- (field0 & 0xff0000) >> 16,
- (field1 & 0xff00) >> 8,
- field1 & 0xff,
- (field1 & 0xff000000) >> 16 |
- (field1 & 0xff0000) >> 16,
- TRB_LEN(field2), GET_TD_SIZE(field2),
- GET_INTR_TARGET(field2),
- TRB_SETUPID_TO_TYPE(field3),
- field3 & TRB_IDT ? 'D' : 'd',
- field3 & TRB_IOC ? 'I' : 'i',
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size,
+ "type '%s' bRequestType %02x bRequest %02x "
+ "wValue %02x%02x wIndex %02x%02x wLength %d "
+ "length %ld TD size %ld intr %ld Setup ID %ld "
+ "flags %c:%c:%c",
+ cdnsp_trb_type_string(type),
+ field0 & 0xff,
+ (field0 & 0xff00) >> 8,
+ (field0 & 0xff000000) >> 24,
+ (field0 & 0xff0000) >> 16,
+ (field1 & 0xff00) >> 8,
+ field1 & 0xff,
+ (field1 & 0xff000000) >> 16 |
+ (field1 & 0xff0000) >> 16,
+ TRB_LEN(field2), GET_TD_SIZE(field2),
+ GET_INTR_TARGET(field2),
+ TRB_SETUPID_TO_TYPE(field3),
+ field3 & TRB_IDT ? 'D' : 'd',
+ field3 & TRB_IOC ? 'I' : 'i',
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_DATA:
- ret = snprintf(str, size,
- "type '%s' Buffer %08x%08x length %ld TD size %ld "
- "intr %ld flags %c:%c:%c:%c:%c:%c:%c",
- cdnsp_trb_type_string(type),
- field1, field0, TRB_LEN(field2),
- GET_TD_SIZE(field2),
- GET_INTR_TARGET(field2),
- field3 & TRB_IDT ? 'D' : 'i',
- field3 & TRB_IOC ? 'I' : 'i',
- field3 & TRB_CHAIN ? 'C' : 'c',
- field3 & TRB_NO_SNOOP ? 'S' : 's',
- field3 & TRB_ISP ? 'I' : 'i',
- field3 & TRB_ENT ? 'E' : 'e',
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size,
+ "type '%s' Buffer %08x%08x length %ld TD size %ld "
+ "intr %ld flags %c:%c:%c:%c:%c:%c:%c",
+ cdnsp_trb_type_string(type),
+ field1, field0, TRB_LEN(field2),
+ GET_TD_SIZE(field2),
+ GET_INTR_TARGET(field2),
+ field3 & TRB_IDT ? 'D' : 'i',
+ field3 & TRB_IOC ? 'I' : 'i',
+ field3 & TRB_CHAIN ? 'C' : 'c',
+ field3 & TRB_NO_SNOOP ? 'S' : 's',
+ field3 & TRB_ISP ? 'I' : 'i',
+ field3 & TRB_ENT ? 'E' : 'e',
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_STATUS:
- ret = snprintf(str, size,
- "Buffer %08x%08x length %ld TD size %ld intr"
- "%ld type '%s' flags %c:%c:%c:%c",
- field1, field0, TRB_LEN(field2),
- GET_TD_SIZE(field2),
- GET_INTR_TARGET(field2),
- cdnsp_trb_type_string(type),
- field3 & TRB_IOC ? 'I' : 'i',
- field3 & TRB_CHAIN ? 'C' : 'c',
- field3 & TRB_ENT ? 'E' : 'e',
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size,
+ "Buffer %08x%08x length %ld TD size %ld intr"
+ "%ld type '%s' flags %c:%c:%c:%c",
+ field1, field0, TRB_LEN(field2),
+ GET_TD_SIZE(field2),
+ GET_INTR_TARGET(field2),
+ cdnsp_trb_type_string(type),
+ field3 & TRB_IOC ? 'I' : 'i',
+ field3 & TRB_CHAIN ? 'C' : 'c',
+ field3 & TRB_ENT ? 'E' : 'e',
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_NORMAL:
case TRB_ISOC:
case TRB_EVENT_DATA:
case TRB_TR_NOOP:
- ret = snprintf(str, size,
- "type '%s' Buffer %08x%08x length %ld "
- "TD size %ld intr %ld "
- "flags %c:%c:%c:%c:%c:%c:%c:%c:%c",
- cdnsp_trb_type_string(type),
- field1, field0, TRB_LEN(field2),
- GET_TD_SIZE(field2),
- GET_INTR_TARGET(field2),
- field3 & TRB_BEI ? 'B' : 'b',
- field3 & TRB_IDT ? 'T' : 't',
- field3 & TRB_IOC ? 'I' : 'i',
- field3 & TRB_CHAIN ? 'C' : 'c',
- field3 & TRB_NO_SNOOP ? 'S' : 's',
- field3 & TRB_ISP ? 'I' : 'i',
- field3 & TRB_ENT ? 'E' : 'e',
- field3 & TRB_CYCLE ? 'C' : 'c',
- !(field3 & TRB_EVENT_INVALIDATE) ? 'V' : 'v');
+ ret = scnprintf(str, size,
+ "type '%s' Buffer %08x%08x length %ld "
+ "TD size %ld intr %ld "
+ "flags %c:%c:%c:%c:%c:%c:%c:%c:%c",
+ cdnsp_trb_type_string(type),
+ field1, field0, TRB_LEN(field2),
+ GET_TD_SIZE(field2),
+ GET_INTR_TARGET(field2),
+ field3 & TRB_BEI ? 'B' : 'b',
+ field3 & TRB_IDT ? 'T' : 't',
+ field3 & TRB_IOC ? 'I' : 'i',
+ field3 & TRB_CHAIN ? 'C' : 'c',
+ field3 & TRB_NO_SNOOP ? 'S' : 's',
+ field3 & TRB_ISP ? 'I' : 'i',
+ field3 & TRB_ENT ? 'E' : 'e',
+ field3 & TRB_CYCLE ? 'C' : 'c',
+ !(field3 & TRB_EVENT_INVALIDATE) ? 'V' : 'v');
break;
case TRB_CMD_NOOP:
case TRB_ENABLE_SLOT:
- ret = snprintf(str, size, "%s: flags %c",
- cdnsp_trb_type_string(type),
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size, "%s: flags %c",
+ cdnsp_trb_type_string(type),
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_DISABLE_SLOT:
- ret = snprintf(str, size, "%s: slot %ld flags %c",
- cdnsp_trb_type_string(type),
- TRB_TO_SLOT_ID(field3),
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size, "%s: slot %ld flags %c",
+ cdnsp_trb_type_string(type),
+ TRB_TO_SLOT_ID(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_ADDR_DEV:
- ret = snprintf(str, size,
- "%s: ctx %08x%08x slot %ld flags %c:%c",
- cdnsp_trb_type_string(type), field1, field0,
- TRB_TO_SLOT_ID(field3),
- field3 & TRB_BSR ? 'B' : 'b',
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size,
+ "%s: ctx %08x%08x slot %ld flags %c:%c",
+ cdnsp_trb_type_string(type), field1, field0,
+ TRB_TO_SLOT_ID(field3),
+ field3 & TRB_BSR ? 'B' : 'b',
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_CONFIG_EP:
- ret = snprintf(str, size,
- "%s: ctx %08x%08x slot %ld flags %c:%c",
- cdnsp_trb_type_string(type), field1, field0,
- TRB_TO_SLOT_ID(field3),
- field3 & TRB_DC ? 'D' : 'd',
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size,
+ "%s: ctx %08x%08x slot %ld flags %c:%c",
+ cdnsp_trb_type_string(type), field1, field0,
+ TRB_TO_SLOT_ID(field3),
+ field3 & TRB_DC ? 'D' : 'd',
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_EVAL_CONTEXT:
- ret = snprintf(str, size,
- "%s: ctx %08x%08x slot %ld flags %c",
- cdnsp_trb_type_string(type), field1, field0,
- TRB_TO_SLOT_ID(field3),
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size,
+ "%s: ctx %08x%08x slot %ld flags %c",
+ cdnsp_trb_type_string(type), field1, field0,
+ TRB_TO_SLOT_ID(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_RESET_EP:
case TRB_HALT_ENDPOINT:
- ret = snprintf(str, size,
- "%s: ep%d%s(%d) ctx %08x%08x slot %ld flags %c",
- cdnsp_trb_type_string(type),
- ep_num, ep_id % 2 ? "out" : "in",
- TRB_TO_EP_INDEX(field3), field1, field0,
- TRB_TO_SLOT_ID(field3),
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size,
+ "%s: ep%d%s(%d) ctx %08x%08x slot %ld flags %c",
+ cdnsp_trb_type_string(type),
+ ep_num, ep_id % 2 ? "out" : "in",
+ TRB_TO_EP_INDEX(field3), field1, field0,
+ TRB_TO_SLOT_ID(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_STOP_RING:
- ret = snprintf(str, size,
- "%s: ep%d%s(%d) slot %ld sp %d flags %c",
- cdnsp_trb_type_string(type),
- ep_num, ep_id % 2 ? "out" : "in",
- TRB_TO_EP_INDEX(field3),
- TRB_TO_SLOT_ID(field3),
- TRB_TO_SUSPEND_PORT(field3),
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size,
+ "%s: ep%d%s(%d) slot %ld sp %d flags %c",
+ cdnsp_trb_type_string(type),
+ ep_num, ep_id % 2 ? "out" : "in",
+ TRB_TO_EP_INDEX(field3),
+ TRB_TO_SLOT_ID(field3),
+ TRB_TO_SUSPEND_PORT(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_SET_DEQ:
- ret = snprintf(str, size,
- "%s: ep%d%s(%d) deq %08x%08x stream %ld slot %ld flags %c",
- cdnsp_trb_type_string(type),
- ep_num, ep_id % 2 ? "out" : "in",
- TRB_TO_EP_INDEX(field3), field1, field0,
- TRB_TO_STREAM_ID(field2),
- TRB_TO_SLOT_ID(field3),
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size,
+ "%s: ep%d%s(%d) deq %08x%08x stream %ld slot %ld flags %c",
+ cdnsp_trb_type_string(type),
+ ep_num, ep_id % 2 ? "out" : "in",
+ TRB_TO_EP_INDEX(field3), field1, field0,
+ TRB_TO_STREAM_ID(field2),
+ TRB_TO_SLOT_ID(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_RESET_DEV:
- ret = snprintf(str, size, "%s: slot %ld flags %c",
- cdnsp_trb_type_string(type),
- TRB_TO_SLOT_ID(field3),
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size, "%s: slot %ld flags %c",
+ cdnsp_trb_type_string(type),
+ TRB_TO_SLOT_ID(field3),
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
case TRB_ENDPOINT_NRDY:
temp = TRB_TO_HOST_STREAM(field2);
- ret = snprintf(str, size,
- "%s: ep%d%s(%d) H_SID %x%s%s D_SID %lx flags %c:%c",
- cdnsp_trb_type_string(type),
- ep_num, ep_id % 2 ? "out" : "in",
- TRB_TO_EP_INDEX(field3), temp,
- temp == STREAM_PRIME_ACK ? "(PRIME)" : "",
- temp == STREAM_REJECTED ? "(REJECTED)" : "",
- TRB_TO_DEV_STREAM(field0),
- field3 & TRB_STAT ? 'S' : 's',
- field3 & TRB_CYCLE ? 'C' : 'c');
+ ret = scnprintf(str, size,
+ "%s: ep%d%s(%d) H_SID %x%s%s D_SID %lx flags %c:%c",
+ cdnsp_trb_type_string(type),
+ ep_num, ep_id % 2 ? "out" : "in",
+ TRB_TO_EP_INDEX(field3), temp,
+ temp == STREAM_PRIME_ACK ? "(PRIME)" : "",
+ temp == STREAM_REJECTED ? "(REJECTED)" : "",
+ TRB_TO_DEV_STREAM(field0),
+ field3 & TRB_STAT ? 'S' : 's',
+ field3 & TRB_CYCLE ? 'C' : 'c');
break;
default:
- ret = snprintf(str, size,
- "type '%s' -> raw %08x %08x %08x %08x",
- cdnsp_trb_type_string(type),
- field0, field1, field2, field3);
+ ret = scnprintf(str, size,
+ "type '%s' -> raw %08x %08x %08x %08x",
+ cdnsp_trb_type_string(type),
+ field0, field1, field2, field3);
}
- if (ret >= size)
- pr_info("CDNSP: buffer overflowed.\n");
+ if (ret == size - 1)
+ pr_info("CDNSP: buffer may be truncated.\n");
return str;
}
@@ -465,32 +465,32 @@ static inline const char *cdnsp_decode_portsc(char *str, size_t size,
{
int ret;
- ret = snprintf(str, size, "%s %s %s Link:%s PortSpeed:%d ",
- portsc & PORT_POWER ? "Powered" : "Powered-off",
- portsc & PORT_CONNECT ? "Connected" : "Not-connected",
- portsc & PORT_PED ? "Enabled" : "Disabled",
- cdnsp_portsc_link_state_string(portsc),
- DEV_PORT_SPEED(portsc));
+ ret = scnprintf(str, size, "%s %s %s Link:%s PortSpeed:%d ",
+ portsc & PORT_POWER ? "Powered" : "Powered-off",
+ portsc & PORT_CONNECT ? "Connected" : "Not-connected",
+ portsc & PORT_PED ? "Enabled" : "Disabled",
+ cdnsp_portsc_link_state_string(portsc),
+ DEV_PORT_SPEED(portsc));
if (portsc & PORT_RESET)
- ret += snprintf(str + ret, size - ret, "In-Reset ");
+ ret += scnprintf(str + ret, size - ret, "In-Reset ");
- ret += snprintf(str + ret, size - ret, "Change: ");
+ ret += scnprintf(str + ret, size - ret, "Change: ");
if (portsc & PORT_CSC)
- ret += snprintf(str + ret, size - ret, "CSC ");
+ ret += scnprintf(str + ret, size - ret, "CSC ");
if (portsc & PORT_WRC)
- ret += snprintf(str + ret, size - ret, "WRC ");
+ ret += scnprintf(str + ret, size - ret, "WRC ");
if (portsc & PORT_RC)
- ret += snprintf(str + ret, size - ret, "PRC ");
+ ret += scnprintf(str + ret, size - ret, "PRC ");
if (portsc & PORT_PLC)
- ret += snprintf(str + ret, size - ret, "PLC ");
+ ret += scnprintf(str + ret, size - ret, "PLC ");
if (portsc & PORT_CEC)
- ret += snprintf(str + ret, size - ret, "CEC ");
- ret += snprintf(str + ret, size - ret, "Wake: ");
+ ret += scnprintf(str + ret, size - ret, "CEC ");
+ ret += scnprintf(str + ret, size - ret, "Wake: ");
if (portsc & PORT_WKCONN_E)
- ret += snprintf(str + ret, size - ret, "WCE ");
+ ret += scnprintf(str + ret, size - ret, "WCE ");
if (portsc & PORT_WKDISC_E)
- ret += snprintf(str + ret, size - ret, "WDE ");
+ ret += scnprintf(str + ret, size - ret, "WDE ");
return str;
}
@@ -562,20 +562,20 @@ static inline const char *cdnsp_decode_ep_context(char *str, size_t size,
avg = EP_AVG_TRB_LENGTH(tx_info);
- ret = snprintf(str, size, "State %s mult %d max P. Streams %d %s",
- cdnsp_ep_state_string(ep_state), mult,
- max_pstr, lsa ? "LSA " : "");
+ ret = scnprintf(str, size, "State %s mult %d max P. Streams %d %s",
+ cdnsp_ep_state_string(ep_state), mult,
+ max_pstr, lsa ? "LSA " : "");
- ret += snprintf(str + ret, size - ret,
- "interval %d us max ESIT payload %d CErr %d ",
- (1 << interval) * 125, esit, cerr);
+ ret += scnprintf(str + ret, size - ret,
+ "interval %d us max ESIT payload %d CErr %d ",
+ (1 << interval) * 125, esit, cerr);
- ret += snprintf(str + ret, size - ret,
- "Type %s %sburst %d maxp %d deq %016llx ",
- cdnsp_ep_type_string(ep_type), hid ? "HID" : "",
- burst, maxp, deq);
+ ret += scnprintf(str + ret, size - ret,
+ "Type %s %sburst %d maxp %d deq %016llx ",
+ cdnsp_ep_type_string(ep_type), hid ? "HID" : "",
+ burst, maxp, deq);
- ret += snprintf(str + ret, size - ret, "avg trb len %d", avg);
+ ret += scnprintf(str + ret, size - ret, "avg trb len %d", avg);
return str;
}
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index e28bb2f2612d..ae9a6a17ec6e 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -96,6 +96,7 @@ struct ci_hdrc_imx_data {
struct usb_phy *phy;
struct platform_device *ci_pdev;
struct clk *clk;
+ struct clk *clk_wakeup;
struct imx_usbmisc_data *usbmisc_data;
bool supports_runtime_pm;
bool override_phy_control;
@@ -199,7 +200,7 @@ static int imx_get_clks(struct device *dev)
data->clk_ipg = devm_clk_get(dev, "ipg");
if (IS_ERR(data->clk_ipg)) {
- /* If the platform only needs one clocks */
+ /* If the platform only needs one primary clock */
data->clk = devm_clk_get(dev, NULL);
if (IS_ERR(data->clk)) {
ret = PTR_ERR(data->clk);
@@ -208,6 +209,13 @@ static int imx_get_clks(struct device *dev)
PTR_ERR(data->clk), PTR_ERR(data->clk_ipg));
return ret;
}
+ /* Get wakeup clock. Not all of the platforms need to
+ * handle this clock. So make it optional.
+ */
+ data->clk_wakeup = devm_clk_get_optional(dev, "usb_wakeup_clk");
+ if (IS_ERR(data->clk_wakeup))
+ ret = dev_err_probe(dev, PTR_ERR(data->clk_wakeup),
+ "Failed to get wakeup clk\n");
return ret;
}
@@ -423,6 +431,10 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
if (ret)
goto disable_hsic_regulator;
+ ret = clk_prepare_enable(data->clk_wakeup);
+ if (ret)
+ goto err_wakeup_clk;
+
data->phy = devm_usb_get_phy_by_phandle(dev, "fsl,usbphy", 0);
if (IS_ERR(data->phy)) {
ret = PTR_ERR(data->phy);
@@ -504,6 +516,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
disable_device:
ci_hdrc_remove_device(data->ci_pdev);
err_clk:
+ clk_disable_unprepare(data->clk_wakeup);
+err_wakeup_clk:
imx_disable_unprepare_clks(dev);
disable_hsic_regulator:
if (data->hsic_pad_regulator)
@@ -530,6 +544,7 @@ static void ci_hdrc_imx_remove(struct platform_device *pdev)
usb_phy_shutdown(data->phy);
if (data->ci_pdev) {
imx_disable_unprepare_clks(&pdev->dev);
+ clk_disable_unprepare(data->clk_wakeup);
if (data->plat_data->flags & CI_HDRC_PMQOS)
cpu_latency_qos_remove_request(&data->pm_qos_req);
if (data->hsic_pad_regulator)
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 7ac39a281b8c..41014f93cfdf 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -523,6 +523,13 @@ static irqreturn_t ci_irq_handler(int irq, void *data)
u32 otgsc = 0;
if (ci->in_lpm) {
+ /*
+ * If we already have a wakeup irq pending there,
+ * let's just return to wait resume finished firstly.
+ */
+ if (ci->wakeup_int)
+ return IRQ_HANDLED;
+
disable_irq_nosync(irq);
ci->wakeup_int = true;
pm_runtime_get(ci->dev);
@@ -862,7 +869,7 @@ struct platform_device *ci_hdrc_add_device(struct device *dev,
if (ret)
return ERR_PTR(ret);
- id = ida_simple_get(&ci_ida, 0, 0, GFP_KERNEL);
+ id = ida_alloc(&ci_ida, GFP_KERNEL);
if (id < 0)
return ERR_PTR(id);
@@ -892,7 +899,7 @@ struct platform_device *ci_hdrc_add_device(struct device *dev,
err:
platform_device_put(pdev);
put_id:
- ida_simple_remove(&ci_ida, id);
+ ida_free(&ci_ida, id);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(ci_hdrc_add_device);
@@ -901,7 +908,7 @@ void ci_hdrc_remove_device(struct platform_device *pdev)
{
int id = pdev->id;
platform_device_unregister(pdev);
- ida_simple_remove(&ci_ida, id);
+ ida_free(&ci_ida, id);
}
EXPORT_SYMBOL_GPL(ci_hdrc_remove_device);
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 0b7bd3c643c3..2d7f616270c1 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -688,7 +688,8 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
if ((TD_STATUS_ACTIVE & tmptoken) != 0) {
int n = hw_ep_bit(hwep->num, hwep->dir);
- if (ci->rev == CI_REVISION_24)
+ if (ci->rev == CI_REVISION_24 ||
+ ci->rev == CI_REVISION_22)
if (!hw_read(ci, OP_ENDPTSTAT, BIT(n)))
reprime_dtd(ci, hwep, node);
hwreq->req.status = -EALREADY;
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index a1f4e1ead97f..0e7439dba8fe 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -916,6 +916,9 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state)
struct acm *acm = tty->driver_data;
int retval;
+ if (!(acm->ctrl_caps & USB_CDC_CAP_BRK))
+ return -EOPNOTSUPP;
+
retval = acm_send_break(acm, state ? 0xffff : 0);
if (retval < 0)
dev_dbg(&acm->control->dev,
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index f58a0299fb3b..e01b1913d02b 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -189,13 +189,13 @@ static int usb_create_newid_files(struct usb_driver *usb_drv)
goto exit;
if (usb_drv->probe != NULL) {
- error = driver_create_file(&usb_drv->drvwrap.driver,
+ error = driver_create_file(&usb_drv->driver,
&driver_attr_new_id);
if (error == 0) {
- error = driver_create_file(&usb_drv->drvwrap.driver,
+ error = driver_create_file(&usb_drv->driver,
&driver_attr_remove_id);
if (error)
- driver_remove_file(&usb_drv->drvwrap.driver,
+ driver_remove_file(&usb_drv->driver,
&driver_attr_new_id);
}
}
@@ -209,9 +209,9 @@ static void usb_remove_newid_files(struct usb_driver *usb_drv)
return;
if (usb_drv->probe != NULL) {
- driver_remove_file(&usb_drv->drvwrap.driver,
+ driver_remove_file(&usb_drv->driver,
&driver_attr_remove_id);
- driver_remove_file(&usb_drv->drvwrap.driver,
+ driver_remove_file(&usb_drv->driver,
&driver_attr_new_id);
}
}
@@ -290,7 +290,10 @@ static int usb_probe_device(struct device *dev)
* specialised device drivers prior to setting the
* use_generic_driver bit.
*/
- error = udriver->probe(udev);
+ if (udriver->probe)
+ error = udriver->probe(udev);
+ else if (!udriver->generic_subclass)
+ error = -EINVAL;
if (error == -ENODEV && udriver != &usb_generic_driver &&
(udriver->id_table || udriver->match)) {
udev->use_generic_driver = 1;
@@ -549,7 +552,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
if (!iface->authorized)
return -ENODEV;
- dev->driver = &driver->drvwrap.driver;
+ dev->driver = &driver->driver;
usb_set_intfdata(iface, data);
iface->needs_binding = 0;
@@ -612,7 +615,7 @@ void usb_driver_release_interface(struct usb_driver *driver,
struct device *dev = &iface->dev;
/* this should never happen, don't release something that's not ours */
- if (!dev->driver || dev->driver != &driver->drvwrap.driver)
+ if (!dev->driver || dev->driver != &driver->driver)
return;
/* don't release from within disconnect() */
@@ -947,7 +950,7 @@ static int __usb_bus_reprobe_drivers(struct device *dev, void *data)
int ret;
/* Don't reprobe if current driver isn't usb_generic_driver */
- if (dev->driver != &usb_generic_driver.drvwrap.driver)
+ if (dev->driver != &usb_generic_driver.driver)
return 0;
udev = to_usb_device(dev);
@@ -961,6 +964,11 @@ static int __usb_bus_reprobe_drivers(struct device *dev, void *data)
return 0;
}
+bool is_usb_device_driver(const struct device_driver *drv)
+{
+ return drv->probe == usb_probe_device;
+}
+
/**
* usb_register_device_driver - register a USB device (not interface) driver
* @new_udriver: USB operations for the device driver
@@ -980,15 +988,14 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver,
if (usb_disabled())
return -ENODEV;
- new_udriver->drvwrap.for_devices = 1;
- new_udriver->drvwrap.driver.name = new_udriver->name;
- new_udriver->drvwrap.driver.bus = &usb_bus_type;
- new_udriver->drvwrap.driver.probe = usb_probe_device;
- new_udriver->drvwrap.driver.remove = usb_unbind_device;
- new_udriver->drvwrap.driver.owner = owner;
- new_udriver->drvwrap.driver.dev_groups = new_udriver->dev_groups;
+ new_udriver->driver.name = new_udriver->name;
+ new_udriver->driver.bus = &usb_bus_type;
+ new_udriver->driver.probe = usb_probe_device;
+ new_udriver->driver.remove = usb_unbind_device;
+ new_udriver->driver.owner = owner;
+ new_udriver->driver.dev_groups = new_udriver->dev_groups;
- retval = driver_register(&new_udriver->drvwrap.driver);
+ retval = driver_register(&new_udriver->driver);
if (!retval) {
pr_info("%s: registered new device driver %s\n",
@@ -1020,7 +1027,7 @@ void usb_deregister_device_driver(struct usb_device_driver *udriver)
pr_info("%s: deregistering device driver %s\n",
usbcore_name, udriver->name);
- driver_unregister(&udriver->drvwrap.driver);
+ driver_unregister(&udriver->driver);
}
EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
@@ -1048,18 +1055,17 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
if (usb_disabled())
return -ENODEV;
- new_driver->drvwrap.for_devices = 0;
- new_driver->drvwrap.driver.name = new_driver->name;
- new_driver->drvwrap.driver.bus = &usb_bus_type;
- new_driver->drvwrap.driver.probe = usb_probe_interface;
- new_driver->drvwrap.driver.remove = usb_unbind_interface;
- new_driver->drvwrap.driver.owner = owner;
- new_driver->drvwrap.driver.mod_name = mod_name;
- new_driver->drvwrap.driver.dev_groups = new_driver->dev_groups;
+ new_driver->driver.name = new_driver->name;
+ new_driver->driver.bus = &usb_bus_type;
+ new_driver->driver.probe = usb_probe_interface;
+ new_driver->driver.remove = usb_unbind_interface;
+ new_driver->driver.owner = owner;
+ new_driver->driver.mod_name = mod_name;
+ new_driver->driver.dev_groups = new_driver->dev_groups;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
- retval = driver_register(&new_driver->drvwrap.driver);
+ retval = driver_register(&new_driver->driver);
if (retval)
goto out;
@@ -1074,7 +1080,7 @@ out:
return retval;
out_newid:
- driver_unregister(&new_driver->drvwrap.driver);
+ driver_unregister(&new_driver->driver);
pr_err("%s: error %d registering interface driver %s\n",
usbcore_name, retval, new_driver->name);
@@ -1099,7 +1105,7 @@ void usb_deregister(struct usb_driver *driver)
usbcore_name, driver->name);
usb_remove_newid_files(driver);
- driver_unregister(&driver->drvwrap.driver);
+ driver_unregister(&driver->driver);
usb_free_dynids(driver);
}
EXPORT_SYMBOL_GPL(usb_deregister);
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 740342a2812a..b134bff5c3fe 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -59,10 +59,26 @@ int usb_choose_configuration(struct usb_device *udev)
int num_configs;
int insufficient_power = 0;
struct usb_host_config *c, *best;
+ struct usb_device_driver *udriver;
+
+ /*
+ * If a USB device (not an interface) doesn't have a driver then the
+ * kernel has no business trying to select or install a configuration
+ * for it.
+ */
+ if (!udev->dev.driver)
+ return -1;
+ udriver = to_usb_device_driver(udev->dev.driver);
if (usb_device_is_owned(udev))
return 0;
+ if (udriver->choose_configuration) {
+ i = udriver->choose_configuration(udev);
+ if (i >= 0)
+ return i;
+ }
+
best = NULL;
c = udev->config;
num_configs = udev->descriptor.bNumConfigurations;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 87480a6e6d93..ffd7c99e24a3 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -47,12 +47,24 @@
#define USB_VENDOR_TEXAS_INSTRUMENTS 0x0451
#define USB_PRODUCT_TUSB8041_USB3 0x8140
#define USB_PRODUCT_TUSB8041_USB2 0x8142
-#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01
-#define HUB_QUIRK_DISABLE_AUTOSUSPEND 0x02
+#define USB_VENDOR_MICROCHIP 0x0424
+#define USB_PRODUCT_USB4913 0x4913
+#define USB_PRODUCT_USB4914 0x4914
+#define USB_PRODUCT_USB4915 0x4915
+#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND BIT(0)
+#define HUB_QUIRK_DISABLE_AUTOSUSPEND BIT(1)
+#define HUB_QUIRK_REDUCE_FRAME_INTR_BINTERVAL BIT(2)
#define USB_TP_TRANSMISSION_DELAY 40 /* ns */
#define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */
#define USB_PING_RESPONSE_TIME 400 /* ns */
+#define USB_REDUCE_FRAME_INTR_BINTERVAL 9
+
+/*
+ * The SET_ADDRESS request timeout will be 500 ms when
+ * USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT quirk flag is set.
+ */
+#define USB_SHORT_SET_ADDRESS_REQ_TIMEOUT 500 /* ms */
/* Protect struct usb_device->state and ->children members
* Note: Both are also protected by ->dev.sem, except that ->state can
@@ -1904,6 +1916,14 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
usb_autopm_get_interface_no_resume(intf);
}
+ if ((id->driver_info & HUB_QUIRK_REDUCE_FRAME_INTR_BINTERVAL) &&
+ desc->endpoint[0].desc.bInterval > USB_REDUCE_FRAME_INTR_BINTERVAL) {
+ desc->endpoint[0].desc.bInterval =
+ USB_REDUCE_FRAME_INTR_BINTERVAL;
+ /* Tell the HCD about the interrupt ep's new bInterval */
+ usb_set_interface(hdev, 0, 0);
+ }
+
if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) {
onboard_hub_create_pdevs(hdev, &hub->onboard_hub_devs);
@@ -4626,7 +4646,12 @@ EXPORT_SYMBOL_GPL(usb_ep0_reinit);
static int hub_set_address(struct usb_device *udev, int devnum)
{
int retval;
+ unsigned int timeout_ms = USB_CTRL_SET_TIMEOUT;
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
+
+ if (hub->hdev->quirks & USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT)
+ timeout_ms = USB_SHORT_SET_ADDRESS_REQ_TIMEOUT;
/*
* The host controller will choose the device address,
@@ -4639,11 +4664,11 @@ static int hub_set_address(struct usb_device *udev, int devnum)
if (udev->state != USB_STATE_DEFAULT)
return -EINVAL;
if (hcd->driver->address_device)
- retval = hcd->driver->address_device(hcd, udev);
+ retval = hcd->driver->address_device(hcd, udev, timeout_ms);
else
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
USB_REQ_SET_ADDRESS, 0, devnum, 0,
- NULL, 0, USB_CTRL_SET_TIMEOUT);
+ NULL, 0, timeout_ms);
if (retval == 0) {
update_devnum(udev, devnum);
/* Device now using proper address. */
@@ -5895,6 +5920,21 @@ static const struct usb_device_id hub_id_table[] = {
.idVendor = USB_VENDOR_TEXAS_INSTRUMENTS,
.idProduct = USB_PRODUCT_TUSB8041_USB3,
.driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
+ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_PRODUCT,
+ .idVendor = USB_VENDOR_MICROCHIP,
+ .idProduct = USB_PRODUCT_USB4913,
+ .driver_info = HUB_QUIRK_REDUCE_FRAME_INTR_BINTERVAL},
+ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_PRODUCT,
+ .idVendor = USB_VENDOR_MICROCHIP,
+ .idProduct = USB_PRODUCT_USB4914,
+ .driver_info = HUB_QUIRK_REDUCE_FRAME_INTR_BINTERVAL},
+ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_PRODUCT,
+ .idVendor = USB_VENDOR_MICROCHIP,
+ .idProduct = USB_PRODUCT_USB4915,
+ .driver_info = HUB_QUIRK_REDUCE_FRAME_INTR_BINTERVAL},
{ .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
.bDeviceClass = USB_CLASS_HUB},
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 15e9bd180a1d..b4783574b8e6 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -138,6 +138,9 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp)
case 'o':
flags |= USB_QUIRK_HUB_SLOW_RESET;
break;
+ case 'p':
+ flags |= USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT;
+ break;
/* Ignore unrecognized flag characters */
}
}
@@ -527,6 +530,10 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM },
+ /* APTIV AUTOMOTIVE HUB */
+ { USB_DEVICE(0x2c48, 0x0132), .driver_info =
+ USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT },
+
/* DJI CineSSD */
{ USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 2a938cf47ccd..dc8d9228a5e7 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -431,7 +431,7 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
struct device *dev;
argb.minor = minor;
- argb.drv = &drv->drvwrap.driver;
+ argb.drv = &drv->driver;
dev = bus_find_device(&usb_bus_type, NULL, &argb, __find_interface);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 60363153fc3f..bfecb50773b6 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -175,13 +175,7 @@ static inline int is_root_hub(struct usb_device *udev)
return (udev->parent == NULL);
}
-/* Do the same for device drivers and interface drivers. */
-
-static inline int is_usb_device_driver(struct device_driver *drv)
-{
- return container_of(drv, struct usbdrv_wrap, driver)->
- for_devices;
-}
+extern bool is_usb_device_driver(const struct device_driver *drv);
/* for labeling diagnostics */
extern const char *usbcore_name;
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index fb03162ae9b7..eb677c3cfd0b 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -130,6 +130,7 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg)
p->lpm_clock_gating = false;
p->besl = false;
p->hird_threshold_en = false;
+ p->no_clock_gating = true;
}
static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index b101dbf8c5dc..3e55838c0001 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -277,48 +277,11 @@ int dwc3_core_soft_reset(struct dwc3 *dwc)
/*
* We're resetting only the device side because, if we're in host mode,
* XHCI driver will reset the host block. If dwc3 was configured for
- * host-only mode or current role is host, then we can return early.
+ * host-only mode, then we can return early.
*/
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
return 0;
- /*
- * If the dr_mode is host and the dwc->current_dr_role is not the
- * corresponding DWC3_GCTL_PRTCAP_HOST, then the dwc3_core_init_mode
- * isn't executed yet. Ensure the phy is ready before the controller
- * updates the GCTL.PRTCAPDIR or other settings by soft-resetting
- * the phy.
- *
- * Note: GUSB3PIPECTL[n] and GUSB2PHYCFG[n] are port settings where n
- * is port index. If this is a multiport host, then we need to reset
- * all active ports.
- */
- if (dwc->dr_mode == USB_DR_MODE_HOST) {
- u32 usb3_port;
- u32 usb2_port;
-
- usb3_port = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
- usb3_port |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
- dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), usb3_port);
-
- usb2_port = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
- usb2_port |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), usb2_port);
-
- /* Small delay for phy reset assertion */
- usleep_range(1000, 2000);
-
- usb3_port &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
- dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), usb3_port);
-
- usb2_port &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), usb2_port);
-
- /* Wait for clock synchronization */
- msleep(50);
- return 0;
- }
-
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg |= DWC3_DCTL_CSFTRST;
reg &= ~DWC3_DCTL_RUN_STOP;
@@ -1367,6 +1330,18 @@ static int dwc3_core_init(struct dwc3 *dwc)
dwc3_config_threshold(dwc);
+ /*
+ * Modify this for all supported Super Speed ports when
+ * multiport support is added.
+ */
+ if (hw_mode != DWC3_GHWPARAMS0_MODE_GADGET &&
+ (DWC3_IP_IS(DWC31)) &&
+ dwc->maximum_speed == USB_SPEED_SUPER) {
+ reg = dwc3_readl(dwc->regs, DWC3_LLUCTL);
+ reg |= DWC3_LLUCTL_FORCE_GEN1;
+ dwc3_writel(dwc->regs, DWC3_LLUCTL, reg);
+ }
+
return 0;
err_power_off_phy:
@@ -2340,12 +2315,15 @@ static int dwc3_resume(struct device *dev)
pinctrl_pm_select_default_state(dev);
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+
ret = dwc3_resume_common(dwc, PMSG_RESUME);
- if (ret)
+ if (ret) {
+ pm_runtime_set_suspended(dev);
return ret;
+ }
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
pm_runtime_enable(dev);
return 0;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index efe6caf4d0e8..e3eea965e57b 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -172,6 +172,8 @@
#define DWC3_OEVTEN 0xcc0C
#define DWC3_OSTS 0xcc10
+#define DWC3_LLUCTL 0xd024
+
/* Bit fields */
/* Global SoC Bus Configuration INCRx Register 0 */
@@ -374,6 +376,7 @@
/* Global HWPARAMS4 Register */
#define DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(n) (((n) & (0x0f << 13)) >> 13)
#define DWC3_MAX_HIBER_SCRATCHBUFS 15
+#define DWC3_EXT_BUFF_CONTROL BIT(21)
/* Global HWPARAMS6 Register */
#define DWC3_GHWPARAMS6_BCSUPPORT BIT(14)
@@ -657,6 +660,9 @@
#define DWC3_OSTS_VBUSVLD BIT(1)
#define DWC3_OSTS_CONIDSTS BIT(0)
+/* Force Gen1 speed on Gen2 link */
+#define DWC3_LLUCTL_FORCE_GEN1 BIT(10)
+
/* Structures */
struct dwc3_trb;
diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c
index a1e15f2fffdb..8ee448068503 100644
--- a/drivers/usb/dwc3/dwc3-imx8mp.c
+++ b/drivers/usb/dwc3/dwc3-imx8mp.c
@@ -363,8 +363,10 @@ static int __maybe_unused dwc3_imx8mp_pm_resume(struct device *dev)
}
ret = clk_prepare_enable(dwc3_imx->hsio_clk);
- if (ret)
+ if (ret) {
+ clk_disable_unprepare(dwc3_imx->suspend_clk);
return ret;
+ }
ret = dwc3_imx8mp_resume(dwc3_imx, PMSG_RESUME);
diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c
index fdf6d5d3c2ad..dbd6a5b2b289 100644
--- a/drivers/usb/dwc3/dwc3-qcom.c
+++ b/drivers/usb/dwc3/dwc3-qcom.c
@@ -57,7 +57,7 @@ struct dwc3_acpi_pdata {
u32 qscratch_base_offset;
u32 qscratch_base_size;
u32 dwc3_core_base_size;
- int hs_phy_irq_index;
+ int qusb2_phy_irq_index;
int dp_hs_phy_irq_index;
int dm_hs_phy_irq_index;
int ss_phy_irq_index;
@@ -73,7 +73,7 @@ struct dwc3_qcom {
int num_clocks;
struct reset_control *resets;
- int hs_phy_irq;
+ int qusb2_phy_irq;
int dp_hs_phy_irq;
int dm_hs_phy_irq;
int ss_phy_irq;
@@ -372,7 +372,7 @@ static void dwc3_qcom_disable_wakeup_irq(int irq)
static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
{
- dwc3_qcom_disable_wakeup_irq(qcom->hs_phy_irq);
+ dwc3_qcom_disable_wakeup_irq(qcom->qusb2_phy_irq);
if (qcom->usb2_speed == USB_SPEED_LOW) {
dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
@@ -389,7 +389,7 @@ static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
{
- dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq, 0);
+ dwc3_qcom_enable_wakeup_irq(qcom->qusb2_phy_irq, 0);
/*
* Configure DP/DM line interrupts based on the USB2 device attached to
@@ -542,19 +542,19 @@ static int dwc3_qcom_setup_irq(struct platform_device *pdev)
int irq;
int ret;
- irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq",
- pdata ? pdata->hs_phy_irq_index : -1);
+ irq = dwc3_qcom_get_irq(pdev, "qusb2_phy",
+ pdata ? pdata->qusb2_phy_irq_index : -1);
if (irq > 0) {
/* Keep wakeup interrupts disabled until suspend */
ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
qcom_dwc3_resume_irq,
IRQF_ONESHOT | IRQF_NO_AUTOEN,
- "qcom_dwc3 HS", qcom);
+ "qcom_dwc3 QUSB2", qcom);
if (ret) {
- dev_err(qcom->dev, "hs_phy_irq failed: %d\n", ret);
+ dev_err(qcom->dev, "qusb2_phy_irq failed: %d\n", ret);
return ret;
}
- qcom->hs_phy_irq = irq;
+ qcom->qusb2_phy_irq = irq;
}
irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq",
@@ -1058,7 +1058,7 @@ static const struct dwc3_acpi_pdata sdm845_acpi_pdata = {
.qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
.qscratch_base_size = SDM845_QSCRATCH_SIZE,
.dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
- .hs_phy_irq_index = 1,
+ .qusb2_phy_irq_index = 1,
.dp_hs_phy_irq_index = 4,
.dm_hs_phy_irq_index = 3,
.ss_phy_irq_index = 2
@@ -1068,7 +1068,7 @@ static const struct dwc3_acpi_pdata sdm845_acpi_urs_pdata = {
.qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
.qscratch_base_size = SDM845_QSCRATCH_SIZE,
.dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
- .hs_phy_irq_index = 1,
+ .qusb2_phy_irq_index = 1,
.dp_hs_phy_irq_index = 4,
.dm_hs_phy_irq_index = 3,
.ss_phy_irq_index = 2,
diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index 5b7e92f476de..6095f4dee6ce 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -293,11 +293,15 @@ static int dwc3_xlnx_probe(struct platform_device *pdev)
goto err_clk_put;
pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret < 0)
+ goto err_pm_set_suspended;
+
pm_suspend_ignore_children(dev, false);
- pm_runtime_get_sync(dev);
+ return pm_runtime_resume_and_get(dev);
- return 0;
+err_pm_set_suspended:
+ pm_runtime_set_suspended(dev);
err_clk_put:
clk_bulk_disable_unprepare(priv_data->num_clocks, priv_data->clks);
@@ -315,7 +319,6 @@ static void dwc3_xlnx_remove(struct platform_device *pdev)
clk_bulk_disable_unprepare(priv_data->num_clocks, priv_data->clks);
priv_data->num_clocks = 0;
- pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
pm_runtime_set_suspended(dev);
}
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index b94243237293..6ae8a36f21cf 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -238,7 +238,10 @@ void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
struct dwc3_request *req;
req = next_request(&dep->pending_list);
- dwc3_gadget_giveback(dep, req, -ECONNRESET);
+ if (!dwc->connected)
+ dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+ else
+ dwc3_gadget_giveback(dep, req, -ECONNRESET);
}
dwc->eps[0]->trb_enqueue = 0;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 858fe4c299b7..019368f8e9c4 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -673,6 +673,12 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action)
params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(bInterval_m1);
}
+ if (dep->endpoint.fifo_mode) {
+ if (!(dwc->hwparams.hwparams4 & DWC3_EXT_BUFF_CONTROL))
+ return -EINVAL;
+ params.param1 |= DWC3_DEPCFG_EBC_HWO_NOWB | DWC3_DEPCFG_USE_EBC;
+ }
+
return dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_SETEPCONFIG, &params);
}
@@ -2103,7 +2109,17 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
list_for_each_entry(r, &dep->pending_list, list) {
if (r == req) {
- dwc3_gadget_giveback(dep, req, -ECONNRESET);
+ /*
+ * Explicitly check for EP0/1 as dequeue for those
+ * EPs need to be handled differently. Control EP
+ * only deals with one USB req, and giveback will
+ * occur during dwc3_ep0_stall_and_restart(). EP0
+ * requests are never added to started_list.
+ */
+ if (dep->number > 1)
+ dwc3_gadget_giveback(dep, req, -ECONNRESET);
+ else
+ dwc3_ep0_reset_state(dwc);
goto out;
}
}
@@ -3973,6 +3989,13 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED);
dwc3_ep0_reset_state(dwc);
+
+ /*
+ * Request PM idle to address condition where usage count is
+ * already decremented to zero, but waiting for the disconnect
+ * interrupt to set dwc->connected to FALSE.
+ */
+ pm_request_idle(dwc->dev);
}
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 55a56cf67d73..fd7a4e94397e 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -26,6 +26,8 @@ struct dwc3;
#define DWC3_DEPCFG_XFER_NOT_READY_EN BIT(10)
#define DWC3_DEPCFG_FIFO_ERROR_EN BIT(11)
#define DWC3_DEPCFG_STREAM_EVENT_EN BIT(13)
+#define DWC3_DEPCFG_EBC_HWO_NOWB BIT(14)
+#define DWC3_DEPCFG_USE_EBC BIT(15)
#define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16)
#define DWC3_DEPCFG_STREAM_CAPABLE BIT(24)
#define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25)
diff --git a/drivers/usb/fotg210/fotg210-hcd.c b/drivers/usb/fotg210/fotg210-hcd.c
index 7bf810a0c98a..8c5aaf860635 100644
--- a/drivers/usb/fotg210/fotg210-hcd.c
+++ b/drivers/usb/fotg210/fotg210-hcd.c
@@ -404,9 +404,9 @@ static void qh_lines(struct fotg210_hcd *fotg210, struct fotg210_qh *qh,
else if (td->hw_alt_next != list_end)
mark = '/';
}
- temp = snprintf(next, size,
- "\n\t%p%c%s len=%d %08x urb %p",
- td, mark, ({ char *tmp;
+ temp = scnprintf(next, size,
+ "\n\t%p%c%s len=%d %08x urb %p",
+ td, mark, ({ char *tmp;
switch ((scratch>>8)&0x03) {
case 0:
tmp = "out";
@@ -424,15 +424,11 @@ static void qh_lines(struct fotg210_hcd *fotg210, struct fotg210_qh *qh,
(scratch >> 16) & 0x7fff,
scratch,
td->urb);
- if (size < temp)
- temp = size;
size -= temp;
next += temp;
}
- temp = snprintf(next, size, "\n");
- if (size < temp)
- temp = size;
+ temp = scnprintf(next, size, "\n");
size -= temp;
next += temp;
diff --git a/drivers/usb/fotg210/fotg210-udc.c b/drivers/usb/fotg210/fotg210-udc.c
index f7ea84070554..0bae12e34f9a 100644
--- a/drivers/usb/fotg210/fotg210-udc.c
+++ b/drivers/usb/fotg210/fotg210-udc.c
@@ -1094,10 +1094,10 @@ static int fotg210_udc_stop(struct usb_gadget *g)
/**
* fotg210_vbus_session - Called by external transceiver to enable/disable udc
- * @_gadget: usb gadget
+ * @g: usb gadget
* @is_active: 0 if should disable UDC VBUS, 1 if should enable
*
- * Returns 0
+ * Returns: %0
*/
static int fotg210_vbus_session(struct usb_gadget *g, int is_active)
{
@@ -1122,7 +1122,7 @@ static const struct usb_gadget_ops fotg210_gadget_ops = {
*
* Called by the USB Phy when a cable connect or disconnect is sensed.
*
- * Returns NOTIFY_OK or NOTIFY_DONE
+ * Returns: NOTIFY_OK or NOTIFY_DONE
*/
static int fotg210_phy_event(struct notifier_block *nb, unsigned long action,
void *data)
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 4c639e9ddedc..ce3cfa1f36f5 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -606,10 +606,11 @@ static struct config_group *function_make(
char *instance_name;
int ret;
- ret = snprintf(buf, MAX_NAME_LEN, "%s", name);
- if (ret >= MAX_NAME_LEN)
+ if (strlen(name) >= MAX_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
+ scnprintf(buf, MAX_NAME_LEN, "%s", name);
+
func_name = buf;
instance_name = strchr(func_name, '.');
if (!instance_name) {
@@ -701,10 +702,12 @@ static struct config_group *config_desc_make(
int ret;
gi = container_of(group, struct gadget_info, configs_group);
- ret = snprintf(buf, MAX_NAME_LEN, "%s", name);
- if (ret >= MAX_NAME_LEN)
+
+ if (strlen(name) >= MAX_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
+ scnprintf(buf, MAX_NAME_LEN, "%s", name);
+
num_str = strchr(buf, '.');
if (!num_str) {
pr_err("Unable to locate . in name.bConfigurationValue\n");
@@ -812,7 +815,7 @@ static ssize_t gadget_string_s_show(struct config_item *item, char *page)
struct gadget_string *string = to_gadget_string(item);
int ret;
- ret = snprintf(page, sizeof(string->string), "%s\n", string->string);
+ ret = sysfs_emit(page, "%s\n", string->string);
return ret;
}
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index fdd0fc7b8f25..6bff6cb93789 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -2931,9 +2931,8 @@ static int __ffs_func_bind_do_os_desc(enum ffs_os_desc_type type,
t = &func->function.os_desc_table[desc->bFirstInterfaceNumber];
t->if_id = func->interfaces_nums[desc->bFirstInterfaceNumber];
- memcpy(t->os_desc->ext_compat_id, &desc->CompatibleID,
- ARRAY_SIZE(desc->CompatibleID) +
- ARRAY_SIZE(desc->SubCompatibleID));
+ memcpy(t->os_desc->ext_compat_id, &desc->IDs,
+ sizeof_field(struct usb_ext_compat_desc, IDs));
length = sizeof(*desc);
}
break;
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index 5335845d697b..20c6fbd94f32 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -1177,11 +1177,11 @@ F_MIDI_OPT(out_ports, true, MAX_PORTS);
static ssize_t f_midi_opts_id_show(struct config_item *item, char *page)
{
struct f_midi_opts *opts = to_f_midi_opts(item);
- int result;
+ ssize_t result;
mutex_lock(&opts->lock);
if (opts->id) {
- result = strlcpy(page, opts->id, PAGE_SIZE);
+ result = strscpy(page, opts->id, PAGE_SIZE);
} else {
page[0] = 0;
result = 0;
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index cc0ed29a4adc..a1575a0ca568 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -103,6 +103,16 @@ static inline struct f_ncm *func_to_ncm(struct usb_function *f)
/* Delay for the transmit to wait before sending an unfilled NTB frame. */
#define TX_TIMEOUT_NSECS 300000
+/*
+ * Although max mtu as dictated by u_ether is 15412 bytes, setting
+ * max_segment_sizeto 15426 would not be efficient. If user chooses segment
+ * size to be (>= 8192), then we can't aggregate more than one buffer in each
+ * NTB (assuming each packet coming from network layer is >= 8192 bytes) as ep
+ * maxpacket limit is 16384. So let max_segment_size be limited to 8000 to allow
+ * at least 2 packets to be aggregated reducing wastage of NTB buffer space
+ */
+#define MAX_DATAGRAM_SIZE 8000
+
#define FORMATS_SUPPORTED (USB_CDC_NCM_NTB16_SUPPORTED | \
USB_CDC_NCM_NTB32_SUPPORTED)
@@ -179,7 +189,6 @@ static struct usb_cdc_ether_desc ecm_desc = {
/* this descriptor actually adds value, surprise! */
/* .iMACAddress = DYNAMIC */
.bmEthernetStatistics = cpu_to_le32(0), /* no statistics */
- .wMaxSegmentSize = cpu_to_le16(ETH_FRAME_LEN),
.wNumberMCFilters = cpu_to_le16(0),
.bNumberPowerFilters = 0,
};
@@ -1166,11 +1175,15 @@ static int ncm_unwrap_ntb(struct gether *port,
struct sk_buff *skb2;
int ret = -EINVAL;
unsigned ntb_max = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize);
- unsigned frame_max = le16_to_cpu(ecm_desc.wMaxSegmentSize);
+ unsigned frame_max;
const struct ndp_parser_opts *opts = ncm->parser_opts;
unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0;
int dgram_counter;
int to_process = skb->len;
+ struct f_ncm_opts *ncm_opts;
+
+ ncm_opts = container_of(port->func.fi, struct f_ncm_opts, func_inst);
+ frame_max = ncm_opts->max_segment_size;
parse_ntb:
tmp = (__le16 *)ntb_ptr;
@@ -1430,8 +1443,10 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
mutex_lock(&ncm_opts->lock);
gether_set_gadget(ncm_opts->net, cdev->gadget);
- if (!ncm_opts->bound)
+ if (!ncm_opts->bound) {
+ ncm_opts->net->mtu = (ncm_opts->max_segment_size - ETH_HLEN);
status = gether_register_netdev(ncm_opts->net);
+ }
mutex_unlock(&ncm_opts->lock);
if (status)
@@ -1474,6 +1489,8 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
ncm_data_intf.bInterfaceNumber = status;
ncm_union_desc.bSlaveInterface0 = status;
+ ecm_desc.wMaxSegmentSize = ncm_opts->max_segment_size;
+
status = -ENODEV;
/* allocate instance-specific endpoints */
@@ -1576,11 +1593,56 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ncm);
/* f_ncm_opts_ifname */
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm);
+static ssize_t ncm_opts_max_segment_size_show(struct config_item *item,
+ char *page)
+{
+ struct f_ncm_opts *opts = to_f_ncm_opts(item);
+ u16 segment_size;
+
+ mutex_lock(&opts->lock);
+ segment_size = opts->max_segment_size;
+ mutex_unlock(&opts->lock);
+
+ return sysfs_emit(page, "%u\n", segment_size);
+}
+
+static ssize_t ncm_opts_max_segment_size_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct f_ncm_opts *opts = to_f_ncm_opts(item);
+ u16 segment_size;
+ int ret;
+
+ mutex_lock(&opts->lock);
+ if (opts->refcnt) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = kstrtou16(page, 0, &segment_size);
+ if (ret)
+ goto out;
+
+ if (segment_size > MAX_DATAGRAM_SIZE) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ opts->max_segment_size = segment_size;
+ ret = len;
+out:
+ mutex_unlock(&opts->lock);
+ return ret;
+}
+
+CONFIGFS_ATTR(ncm_opts_, max_segment_size);
+
static struct configfs_attribute *ncm_attrs[] = {
&ncm_opts_attr_dev_addr,
&ncm_opts_attr_host_addr,
&ncm_opts_attr_qmult,
&ncm_opts_attr_ifname,
+ &ncm_opts_attr_max_segment_size,
NULL,
};
@@ -1623,6 +1685,7 @@ static struct usb_function_instance *ncm_alloc_inst(void)
kfree(opts);
return ERR_CAST(net);
}
+ opts->max_segment_size = cpu_to_le16(ETH_FRAME_LEN);
INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop);
descs[0] = &opts->ncm_os_desc;
diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c
index ff33f31bcdf6..37befd6db001 100644
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -1504,8 +1504,8 @@ static ssize_t tcm_usbg_tpg_nexus_show(struct config_item *item, char *page)
ret = -ENODEV;
goto out;
}
- ret = snprintf(page, PAGE_SIZE, "%s\n",
- tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+ ret = sysfs_emit(page, "%s\n",
+ tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
out:
mutex_unlock(&tpg->tpg_mutex);
return ret;
diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
index 6f0e1d803dc2..7de74a3dd392 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -292,6 +292,77 @@ static struct usb_descriptor_header *f_audio_desc[] = {
NULL,
};
+/* Standard ISO OUT Endpoint Descriptor */
+static struct usb_endpoint_descriptor ss_as_out_ep_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_SYNC_ADAPTIVE
+ | USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(UAC1_OUT_EP_MAX_PACKET_SIZE),
+ .bInterval = 4,
+};
+
+static struct usb_ss_ep_comp_descriptor ss_as_out_ep_desc_comp = {
+ .bLength = sizeof(ss_as_out_ep_desc_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 0,
+ .bmAttributes = 0,
+ /* wBytesPerInterval = DYNAMIC */
+};
+
+/* Standard ISO OUT Endpoint Descriptor */
+static struct usb_endpoint_descriptor ss_as_in_ep_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_SYNC_ASYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(UAC1_OUT_EP_MAX_PACKET_SIZE),
+ .bInterval = 4,
+};
+
+static struct usb_ss_ep_comp_descriptor ss_as_in_ep_desc_comp = {
+ .bLength = sizeof(ss_as_in_ep_desc_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 0,
+ .bmAttributes = 0,
+ /* wBytesPerInterval = DYNAMIC */
+};
+
+static struct usb_descriptor_header *f_audio_ss_desc[] = {
+ (struct usb_descriptor_header *)&ac_interface_desc,
+ (struct usb_descriptor_header *)&ac_header_desc,
+
+ (struct usb_descriptor_header *)&usb_out_it_desc,
+ (struct usb_descriptor_header *)&io_out_ot_desc,
+ (struct usb_descriptor_header *)&io_in_it_desc,
+ (struct usb_descriptor_header *)&usb_in_ot_desc,
+
+ (struct usb_descriptor_header *)&as_out_interface_alt_0_desc,
+ (struct usb_descriptor_header *)&as_out_interface_alt_1_desc,
+ (struct usb_descriptor_header *)&as_out_header_desc,
+
+ (struct usb_descriptor_header *)&as_out_type_i_desc,
+
+ //(struct usb_descriptor_header *)&as_out_ep_desc,
+ (struct usb_descriptor_header *)&ss_as_out_ep_desc,
+ (struct usb_descriptor_header *)&ss_as_out_ep_desc_comp,
+ (struct usb_descriptor_header *)&as_iso_out_desc,
+
+ (struct usb_descriptor_header *)&as_in_interface_alt_0_desc,
+ (struct usb_descriptor_header *)&as_in_interface_alt_1_desc,
+ (struct usb_descriptor_header *)&as_in_header_desc,
+
+ (struct usb_descriptor_header *)&as_in_type_i_desc,
+
+ //(struct usb_descriptor_header *)&as_in_ep_desc,
+ (struct usb_descriptor_header *)&ss_as_in_ep_desc,
+ (struct usb_descriptor_header *)&ss_as_in_ep_desc_comp,
+ (struct usb_descriptor_header *)&as_iso_in_desc,
+ NULL,
+};
+
enum {
STR_AC_IF,
STR_USB_OUT_IT,
@@ -1352,6 +1423,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc);
if (!ep)
goto err_free_fu;
+ ss_as_out_ep_desc.bEndpointAddress = as_out_ep_desc.bEndpointAddress;
audio->out_ep = ep;
audio->out_ep->desc = &as_out_ep_desc;
}
@@ -1360,6 +1432,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
ep = usb_ep_autoconfig(cdev->gadget, &as_in_ep_desc);
if (!ep)
goto err_free_fu;
+ ss_as_in_ep_desc.bEndpointAddress = as_in_ep_desc.bEndpointAddress;
audio->in_ep = ep;
audio->in_ep->desc = &as_in_ep_desc;
}
@@ -1367,8 +1440,8 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
setup_descriptor(audio_opts);
/* copy descriptors, and track endpoint copies */
- status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL,
- NULL);
+ status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, f_audio_ss_desc,
+ f_audio_ss_desc);
if (status)
goto err_free_fu;
@@ -1561,7 +1634,7 @@ static ssize_t f_uac1_opts_##name##_show(struct config_item *item, \
int result; \
\
mutex_lock(&opts->lock); \
- result = snprintf(page, sizeof(opts->name), "%s", opts->name); \
+ result = scnprintf(page, sizeof(opts->name), "%s", opts->name); \
mutex_unlock(&opts->lock); \
\
return result; \
@@ -1579,7 +1652,7 @@ static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \
goto end; \
} \
\
- ret = snprintf(opts->name, min(sizeof(opts->name), len), \
+ ret = scnprintf(opts->name, min(sizeof(opts->name), len), \
"%s", page); \
\
end: \
@@ -1685,7 +1758,7 @@ static struct usb_function_instance *f_audio_alloc_inst(void)
opts->req_number = UAC1_DEF_REQ_NUM;
- snprintf(opts->function_name, sizeof(opts->function_name), "AC Interface");
+ scnprintf(opts->function_name, sizeof(opts->function_name), "AC Interface");
return &opts->func_inst;
}
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index f9a0f07a7476..383f6854cfec 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -2045,7 +2045,7 @@ static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \
int result; \
\
mutex_lock(&opts->lock); \
- result = snprintf(page, sizeof(opts->name), "%s", opts->name); \
+ result = scnprintf(page, sizeof(opts->name), "%s", opts->name); \
mutex_unlock(&opts->lock); \
\
return result; \
@@ -2063,7 +2063,7 @@ static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
goto end; \
} \
\
- ret = snprintf(opts->name, min(sizeof(opts->name), len), \
+ ret = scnprintf(opts->name, min(sizeof(opts->name), len), \
"%s", page); \
\
end: \
@@ -2187,7 +2187,7 @@ static struct usb_function_instance *afunc_alloc_inst(void)
opts->req_number = UAC2_DEF_REQ_NUM;
opts->fb_max = FBACK_FAST_MAX;
- snprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink");
+ scnprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink");
opts->p_terminal_type = UAC2_DEF_P_TERM_TYPE;
opts->c_terminal_type = UAC2_DEF_C_TERM_TYPE;
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 786379f1b7b7..929666805bd2 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -263,10 +263,13 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
return 0;
}
-void uvc_function_setup_continue(struct uvc_device *uvc)
+void uvc_function_setup_continue(struct uvc_device *uvc, int disable_ep)
{
struct usb_composite_dev *cdev = uvc->func.config->cdev;
+ if (disable_ep && uvc->video.ep)
+ usb_ep_disable(uvc->video.ep);
+
usb_composite_setup_continue(cdev);
}
@@ -337,15 +340,11 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
if (uvc->state != UVC_STATE_STREAMING)
return 0;
- if (uvc->video.ep)
- usb_ep_disable(uvc->video.ep);
-
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMOFF;
v4l2_event_queue(&uvc->vdev, &v4l2_event);
- uvc->state = UVC_STATE_CONNECTED;
- return 0;
+ return USB_GADGET_DELAYED_STATUS;
case 1:
if (uvc->state != UVC_STATE_CONNECTED)
@@ -722,13 +721,29 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
}
uvc->enable_interrupt_ep = opts->enable_interrupt_ep;
- ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
+ /*
+ * gadget_is_{super|dual}speed() API check UDC controller capitblity. It should pass down
+ * highest speed endpoint descriptor to UDC controller. So UDC controller driver can reserve
+ * enough resource at check_config(), especially mult and maxburst. So UDC driver (such as
+ * cdns3) can know need at least (mult + 1) * (maxburst + 1) * wMaxPacketSize internal
+ * memory for this uvc functions. This is the only straightforward method to resolve the UDC
+ * resource allocation issue in the current gadget framework.
+ */
+ if (gadget_is_superspeed(c->cdev->gadget))
+ ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
+ &uvc_ss_streaming_comp);
+ else if (gadget_is_dualspeed(cdev->gadget))
+ ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
+ else
+ ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
+
if (!ep) {
uvcg_info(f, "Unable to allocate streaming EP\n");
goto error;
}
uvc->video.ep = ep;
+ uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
@@ -960,7 +975,8 @@ static void uvc_free(struct usb_function *f)
struct uvc_device *uvc = to_uvc(f);
struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
func_inst);
- config_item_put(&uvc->header->item);
+ if (!opts->header)
+ config_item_put(&uvc->header->item);
--opts->refcnt;
kfree(uvc);
}
@@ -1052,25 +1068,29 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
uvc->desc.hs_streaming = opts->hs_streaming;
uvc->desc.ss_streaming = opts->ss_streaming;
- streaming = config_group_find_item(&opts->func_inst.group, "streaming");
- if (!streaming)
- goto err_config;
-
- header = config_group_find_item(to_config_group(streaming), "header");
- config_item_put(streaming);
- if (!header)
- goto err_config;
-
- h = config_group_find_item(to_config_group(header), "h");
- config_item_put(header);
- if (!h)
- goto err_config;
-
- uvc->header = to_uvcg_streaming_header(h);
- if (!uvc->header->linked) {
- mutex_unlock(&opts->lock);
- kfree(uvc);
- return ERR_PTR(-EBUSY);
+ if (opts->header) {
+ uvc->header = opts->header;
+ } else {
+ streaming = config_group_find_item(&opts->func_inst.group, "streaming");
+ if (!streaming)
+ goto err_config;
+
+ header = config_group_find_item(to_config_group(streaming), "header");
+ config_item_put(streaming);
+ if (!header)
+ goto err_config;
+
+ h = config_group_find_item(to_config_group(header), "h");
+ config_item_put(header);
+ if (!h)
+ goto err_config;
+
+ uvc->header = to_uvcg_streaming_header(h);
+ if (!uvc->header->linked) {
+ mutex_unlock(&opts->lock);
+ kfree(uvc);
+ return ERR_PTR(-EBUSY);
+ }
}
uvc->desc.extension_units = &opts->extension_units;
diff --git a/drivers/usb/gadget/function/f_uvc.h b/drivers/usb/gadget/function/f_uvc.h
index 1db972d4beeb..083aef0c65c6 100644
--- a/drivers/usb/gadget/function/f_uvc.h
+++ b/drivers/usb/gadget/function/f_uvc.h
@@ -11,7 +11,7 @@
struct uvc_device;
-void uvc_function_setup_continue(struct uvc_device *uvc);
+void uvc_function_setup_continue(struct uvc_device *uvc, int disable_ep);
void uvc_function_connect(struct uvc_device *uvc);
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 9d1c40c152d8..3c5a6f6ac341 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -1163,6 +1163,8 @@ struct net_device *gether_connect(struct gether *link)
if (netif_running(dev->net))
eth_start(dev, GFP_ATOMIC);
+ netif_device_attach(dev->net);
+
/* on error, disable any endpoints */
} else {
(void) usb_ep_disable(link->out_ep);
diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h
index 5408854d8407..49ec095cdb4b 100644
--- a/drivers/usb/gadget/function/u_ncm.h
+++ b/drivers/usb/gadget/function/u_ncm.h
@@ -31,6 +31,8 @@ struct f_ncm_opts {
*/
struct mutex lock;
int refcnt;
+
+ u16 max_segment_size;
};
#endif /* U_NCM_H */
diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h
index 1ce58f61253c..3ac392cbb779 100644
--- a/drivers/usb/gadget/function/u_uvc.h
+++ b/drivers/usb/gadget/function/u_uvc.h
@@ -98,6 +98,12 @@ struct f_uvc_opts {
*/
struct mutex lock;
int refcnt;
+
+ /*
+ * Only for legacy gadget. Shall be NULL for configfs-composed gadgets,
+ * which is guaranteed by alloc_inst implementation of f_uvc doing kzalloc.
+ */
+ struct uvcg_streaming_header *header;
};
#endif /* U_UVC_H */
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 6751de8b63ad..cb35687b11e7 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -81,6 +81,7 @@ struct uvc_request {
struct sg_table sgt;
u8 header[UVCG_REQUEST_HEADER_LEN];
struct uvc_buffer *last_buf;
+ struct list_head list;
};
struct uvc_video {
@@ -101,9 +102,18 @@ struct uvc_video {
unsigned int uvc_num_requests;
/* Requests */
+ bool is_enabled; /* tracks whether video stream is enabled */
unsigned int req_size;
- struct uvc_request *ureq;
+ struct list_head ureqs; /* all uvc_requests allocated by uvc_video */
+
+ /* USB requests that the video pump thread can encode into */
struct list_head req_free;
+
+ /*
+ * USB requests video pump thread has already encoded into. These are
+ * ready to be queued to the endpoint.
+ */
+ struct list_head req_ready;
spinlock_t req_lock;
unsigned int req_int_count;
@@ -177,7 +187,7 @@ struct uvc_file_handle {
* Functions
*/
-extern void uvc_function_setup_continue(struct uvc_device *uvc);
+extern void uvc_function_setup_continue(struct uvc_device *uvc, int disable_ep);
extern void uvc_function_connect(struct uvc_device *uvc);
extern void uvc_function_disconnect(struct uvc_device *uvc);
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 9bf0e985acfa..7e704b2bcfd1 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -3414,7 +3414,7 @@ static ssize_t f_uvc_opts_string_##cname##_show(struct config_item *item,\
int result; \
\
mutex_lock(&opts->lock); \
- result = snprintf(page, sizeof(opts->aname), "%s", opts->aname);\
+ result = scnprintf(page, sizeof(opts->aname), "%s", opts->aname);\
mutex_unlock(&opts->lock); \
\
return result; \
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index 3f0a9795c0d4..c7e5fa4f29e0 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -443,7 +443,7 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
return -EINVAL;
/* Enable UVC video. */
- ret = uvcg_video_enable(video, 1);
+ ret = uvcg_video_enable(video);
if (ret < 0)
return ret;
@@ -451,7 +451,7 @@ uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
* Complete the alternate setting selection setup phase now that
* userspace is ready to provide video frames.
*/
- uvc_function_setup_continue(uvc);
+ uvc_function_setup_continue(uvc, 0);
uvc->state = UVC_STATE_STREAMING;
return 0;
@@ -463,11 +463,18 @@ uvc_v4l2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
struct video_device *vdev = video_devdata(file);
struct uvc_device *uvc = video_get_drvdata(vdev);
struct uvc_video *video = &uvc->video;
+ int ret = 0;
if (type != video->queue.queue.type)
return -EINVAL;
- return uvcg_video_enable(video, 0);
+ ret = uvcg_video_disable(video);
+ if (ret < 0)
+ return ret;
+
+ uvc->state = UVC_STATE_CONNECTED;
+ uvc_function_setup_continue(uvc, 1);
+ return 0;
}
static int
@@ -500,7 +507,7 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
static void uvc_v4l2_disable(struct uvc_device *uvc)
{
uvc_function_disconnect(uvc);
- uvcg_video_enable(&uvc->video, 0);
+ uvcg_video_disable(&uvc->video);
uvcg_free_buffers(&uvc->video.queue);
uvc->func_connected = false;
wake_up_interruptible(&uvc->func_connected_queue);
@@ -647,4 +654,3 @@ const struct v4l2_file_operations uvc_v4l2_fops = {
.get_unmapped_area = uvcg_v4l2_get_unmapped_area,
#endif
};
-
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index 91af3b1ef0d4..dd3241fc6939 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -227,6 +227,28 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
* Request handling
*/
+/*
+ * Callers must take care to hold req_lock when this function may be called
+ * from multiple threads. For example, when frames are streaming to the host.
+ */
+static void
+uvc_video_free_request(struct uvc_request *ureq, struct usb_ep *ep)
+{
+ sg_free_table(&ureq->sgt);
+ if (ureq->req && ep) {
+ usb_ep_free_request(ep, ureq->req);
+ ureq->req = NULL;
+ }
+
+ kfree(ureq->req_buffer);
+ ureq->req_buffer = NULL;
+
+ if (!list_empty(&ureq->list))
+ list_del_init(&ureq->list);
+
+ kfree(ureq);
+}
+
static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
{
int ret;
@@ -247,14 +269,127 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
return ret;
}
+/* This function must be called with video->req_lock held. */
+static int uvcg_video_usb_req_queue(struct uvc_video *video,
+ struct usb_request *req, bool queue_to_ep)
+{
+ bool is_bulk = video->max_payload_size;
+ struct list_head *list = NULL;
+
+ if (!video->is_enabled)
+ return -ENODEV;
+
+ if (queue_to_ep) {
+ struct uvc_request *ureq = req->context;
+ /*
+ * With USB3 handling more requests at a higher speed, we can't
+ * afford to generate an interrupt for every request. Decide to
+ * interrupt:
+ *
+ * - When no more requests are available in the free queue, as
+ * this may be our last chance to refill the endpoint's
+ * request queue.
+ *
+ * - When this is request is the last request for the video
+ * buffer, as we want to start sending the next video buffer
+ * ASAP in case it doesn't get started already in the next
+ * iteration of this loop.
+ *
+ * - Four times over the length of the requests queue (as
+ * indicated by video->uvc_num_requests), as a trade-off
+ * between latency and interrupt load.
+ */
+ if (list_empty(&video->req_free) || ureq->last_buf ||
+ !(video->req_int_count %
+ DIV_ROUND_UP(video->uvc_num_requests, 4))) {
+ video->req_int_count = 0;
+ req->no_interrupt = 0;
+ } else {
+ req->no_interrupt = 1;
+ }
+ video->req_int_count++;
+ return uvcg_video_ep_queue(video, req);
+ }
+ /*
+ * If we're not queuing to the ep, for isoc we're queuing
+ * to the req_ready list, otherwise req_free.
+ */
+ list = is_bulk ? &video->req_free : &video->req_ready;
+ list_add_tail(&req->list, list);
+ return 0;
+}
+
+/*
+ * Must only be called from uvcg_video_enable - since after that we only want to
+ * queue requests to the endpoint from the uvc_video_complete complete handler.
+ * This function is needed in order to 'kick start' the flow of requests from
+ * gadget driver to the usb controller.
+ */
+static void uvc_video_ep_queue_initial_requests(struct uvc_video *video)
+{
+ struct usb_request *req = NULL;
+ unsigned long flags = 0;
+ unsigned int count = 0;
+ int ret = 0;
+
+ /*
+ * We only queue half of the free list since we still want to have
+ * some free usb_requests in the free list for the video_pump async_wq
+ * thread to encode uvc buffers into. Otherwise we could get into a
+ * situation where the free list does not have any usb requests to
+ * encode into - we always end up queueing 0 length requests to the
+ * end point.
+ */
+ unsigned int half_list_size = video->uvc_num_requests / 2;
+
+ spin_lock_irqsave(&video->req_lock, flags);
+ /*
+ * Take these requests off the free list and queue them all to the
+ * endpoint. Since we queue 0 length requests with the req_lock held,
+ * there isn't any 'data' race involved here with the complete handler.
+ */
+ while (count < half_list_size) {
+ req = list_first_entry(&video->req_free, struct usb_request,
+ list);
+ list_del(&req->list);
+ req->length = 0;
+ ret = uvcg_video_ep_queue(video, req);
+ if (ret < 0) {
+ uvcg_queue_cancel(&video->queue, 0);
+ break;
+ }
+ count++;
+ }
+ spin_unlock_irqrestore(&video->req_lock, flags);
+}
+
static void
uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
{
struct uvc_request *ureq = req->context;
struct uvc_video *video = ureq->video;
struct uvc_video_queue *queue = &video->queue;
- struct uvc_device *uvc = video->uvc;
+ struct uvc_buffer *last_buf;
unsigned long flags;
+ bool is_bulk = video->max_payload_size;
+ int ret = 0;
+
+ spin_lock_irqsave(&video->req_lock, flags);
+ if (!video->is_enabled) {
+ /*
+ * When is_enabled is false, uvcg_video_disable() ensures
+ * that in-flight uvc_buffers are returned, so we can
+ * safely call free_request without worrying about
+ * last_buf.
+ */
+ uvc_video_free_request(ureq, ep);
+ spin_unlock_irqrestore(&video->req_lock, flags);
+ return;
+ }
+
+ last_buf = ureq->last_buf;
+ ureq->last_buf = NULL;
+ spin_unlock_irqrestore(&video->req_lock, flags);
switch (req->status) {
case 0:
@@ -277,44 +412,85 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
uvcg_queue_cancel(queue, 0);
}
- if (ureq->last_buf) {
- uvcg_complete_buffer(&video->queue, ureq->last_buf);
- ureq->last_buf = NULL;
+ if (last_buf) {
+ spin_lock_irqsave(&queue->irqlock, flags);
+ uvcg_complete_buffer(queue, last_buf);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
}
spin_lock_irqsave(&video->req_lock, flags);
- list_add_tail(&req->list, &video->req_free);
+ /*
+ * Video stream might have been disabled while we were
+ * processing the current usb_request. So make sure
+ * we're still streaming before queueing the usb_request
+ * back to req_free
+ */
+ if (video->is_enabled) {
+ /*
+ * Here we check whether any request is available in the ready
+ * list. If it is, queue it to the ep and add the current
+ * usb_request to the req_free list - for video_pump to fill in.
+ * Otherwise, just use the current usb_request to queue a 0
+ * length request to the ep. Since we always add to the req_free
+ * list if we dequeue from the ready list, there will never
+ * be a situation where the req_free list is completely out of
+ * requests and cannot recover.
+ */
+ struct usb_request *to_queue = req;
+
+ to_queue->length = 0;
+ if (!list_empty(&video->req_ready)) {
+ to_queue = list_first_entry(&video->req_ready,
+ struct usb_request, list);
+ list_del(&to_queue->list);
+ list_add_tail(&req->list, &video->req_free);
+ /*
+ * Queue work to the wq as well since it is possible that a
+ * buffer may not have been completely encoded with the set of
+ * in-flight usb requests for whih the complete callbacks are
+ * firing.
+ * In that case, if we do not queue work to the worker thread,
+ * the buffer will never be marked as complete - and therefore
+ * not be returned to userpsace. As a result,
+ * dequeue -> queue -> dequeue flow of uvc buffers will not
+ * happen.
+ */
+ queue_work(video->async_wq, &video->pump);
+ }
+ /*
+ * Queue to the endpoint. The actual queueing to ep will
+ * only happen on one thread - the async_wq for bulk endpoints
+ * and this thread for isoc endpoints.
+ */
+ ret = uvcg_video_usb_req_queue(video, to_queue, !is_bulk);
+ if (ret < 0) {
+ /*
+ * Endpoint error, but the stream is still enabled.
+ * Put request back in req_free for it to be cleaned
+ * up later.
+ */
+ list_add_tail(&to_queue->list, &video->req_free);
+ }
+ } else {
+ uvc_video_free_request(ureq, ep);
+ ret = 0;
+ }
spin_unlock_irqrestore(&video->req_lock, flags);
-
- if (uvc->state == UVC_STATE_STREAMING)
- queue_work(video->async_wq, &video->pump);
+ if (ret < 0)
+ uvcg_queue_cancel(queue, 0);
}
static int
uvc_video_free_requests(struct uvc_video *video)
{
- unsigned int i;
-
- if (video->ureq) {
- for (i = 0; i < video->uvc_num_requests; ++i) {
- sg_free_table(&video->ureq[i].sgt);
+ struct uvc_request *ureq, *temp;
- if (video->ureq[i].req) {
- usb_ep_free_request(video->ep, video->ureq[i].req);
- video->ureq[i].req = NULL;
- }
-
- if (video->ureq[i].req_buffer) {
- kfree(video->ureq[i].req_buffer);
- video->ureq[i].req_buffer = NULL;
- }
- }
-
- kfree(video->ureq);
- video->ureq = NULL;
- }
+ list_for_each_entry_safe(ureq, temp, &video->ureqs, list)
+ uvc_video_free_request(ureq, video->ep);
+ INIT_LIST_HEAD(&video->ureqs);
INIT_LIST_HEAD(&video->req_free);
+ INIT_LIST_HEAD(&video->req_ready);
video->req_size = 0;
return 0;
}
@@ -322,6 +498,7 @@ uvc_video_free_requests(struct uvc_video *video)
static int
uvc_video_alloc_requests(struct uvc_video *video)
{
+ struct uvc_request *ureq;
unsigned int req_size;
unsigned int i;
int ret = -ENOMEM;
@@ -332,29 +509,33 @@ uvc_video_alloc_requests(struct uvc_video *video)
* max_t(unsigned int, video->ep->maxburst, 1)
* (video->ep->mult);
- video->ureq = kcalloc(video->uvc_num_requests, sizeof(struct uvc_request), GFP_KERNEL);
- if (video->ureq == NULL)
- return -ENOMEM;
+ for (i = 0; i < video->uvc_num_requests; i++) {
+ ureq = kzalloc(sizeof(struct uvc_request), GFP_KERNEL);
+ if (ureq == NULL)
+ goto error;
+
+ INIT_LIST_HEAD(&ureq->list);
- for (i = 0; i < video->uvc_num_requests; ++i) {
- video->ureq[i].req_buffer = kmalloc(req_size, GFP_KERNEL);
- if (video->ureq[i].req_buffer == NULL)
+ list_add_tail(&ureq->list, &video->ureqs);
+
+ ureq->req_buffer = kmalloc(req_size, GFP_KERNEL);
+ if (ureq->req_buffer == NULL)
goto error;
- video->ureq[i].req = usb_ep_alloc_request(video->ep, GFP_KERNEL);
- if (video->ureq[i].req == NULL)
+ ureq->req = usb_ep_alloc_request(video->ep, GFP_KERNEL);
+ if (ureq->req == NULL)
goto error;
- video->ureq[i].req->buf = video->ureq[i].req_buffer;
- video->ureq[i].req->length = 0;
- video->ureq[i].req->complete = uvc_video_complete;
- video->ureq[i].req->context = &video->ureq[i];
- video->ureq[i].video = video;
- video->ureq[i].last_buf = NULL;
+ ureq->req->buf = ureq->req_buffer;
+ ureq->req->length = 0;
+ ureq->req->complete = uvc_video_complete;
+ ureq->req->context = ureq;
+ ureq->video = video;
+ ureq->last_buf = NULL;
- list_add_tail(&video->ureq[i].req->list, &video->req_free);
+ list_add_tail(&ureq->req->list, &video->req_free);
/* req_size/PAGE_SIZE + 1 for overruns and + 1 for header */
- sg_alloc_table(&video->ureq[i].sgt,
+ sg_alloc_table(&ureq->sgt,
DIV_ROUND_UP(req_size - UVCG_REQUEST_HEADER_LEN,
PAGE_SIZE) + 2, GFP_KERNEL);
}
@@ -387,16 +568,18 @@ static void uvcg_video_pump(struct work_struct *work)
struct usb_request *req = NULL;
struct uvc_buffer *buf;
unsigned long flags;
- bool buf_done;
- int ret;
+ int ret = 0;
+
+ while (true) {
+ if (!video->ep->enabled)
+ return;
- while (video->ep->enabled) {
/*
- * Retrieve the first available USB request, protected by the
- * request lock.
+ * Check is_enabled and retrieve the first available USB
+ * request, protected by the request lock.
*/
spin_lock_irqsave(&video->req_lock, flags);
- if (list_empty(&video->req_free)) {
+ if (!video->is_enabled || list_empty(&video->req_free)) {
spin_unlock_irqrestore(&video->req_lock, flags);
return;
}
@@ -414,15 +597,6 @@ static void uvcg_video_pump(struct work_struct *work)
if (buf != NULL) {
video->encode(req, video, buf);
- buf_done = buf->state == UVC_BUF_STATE_DONE;
- } else if (!(queue->flags & UVC_QUEUE_DISCONNECTED) && !is_bulk) {
- /*
- * No video buffer available; the queue is still connected and
- * we're transferring over ISOC. Queue a 0 length request to
- * prevent missed ISOC transfers.
- */
- req->length = 0;
- buf_done = false;
} else {
/*
* Either the queue has been disconnected or no video buffer
@@ -433,83 +607,139 @@ static void uvcg_video_pump(struct work_struct *work)
break;
}
- /*
- * With USB3 handling more requests at a higher speed, we can't
- * afford to generate an interrupt for every request. Decide to
- * interrupt:
- *
- * - When no more requests are available in the free queue, as
- * this may be our last chance to refill the endpoint's
- * request queue.
- *
- * - When this is request is the last request for the video
- * buffer, as we want to start sending the next video buffer
- * ASAP in case it doesn't get started already in the next
- * iteration of this loop.
- *
- * - Four times over the length of the requests queue (as
- * indicated by video->uvc_num_requests), as a trade-off
- * between latency and interrupt load.
- */
- if (list_empty(&video->req_free) || buf_done ||
- !(video->req_int_count %
- DIV_ROUND_UP(video->uvc_num_requests, 4))) {
- video->req_int_count = 0;
- req->no_interrupt = 0;
- } else {
- req->no_interrupt = 1;
- }
-
- /* Queue the USB request */
- ret = uvcg_video_ep_queue(video, req);
spin_unlock_irqrestore(&queue->irqlock, flags);
+ spin_lock_irqsave(&video->req_lock, flags);
+ /* For bulk end points we queue from the worker thread
+ * since we would preferably not want to wait on requests
+ * to be ready, in the uvcg_video_complete() handler.
+ * For isoc endpoints we add the request to the ready list
+ * and only queue it to the endpoint from the complete handler.
+ */
+ ret = uvcg_video_usb_req_queue(video, req, is_bulk);
+ spin_unlock_irqrestore(&video->req_lock, flags);
+
if (ret < 0) {
uvcg_queue_cancel(queue, 0);
break;
}
- /* Endpoint now owns the request */
+ /* The request is owned by the endpoint / ready list. */
req = NULL;
- video->req_int_count++;
}
if (!req)
return;
spin_lock_irqsave(&video->req_lock, flags);
- list_add_tail(&req->list, &video->req_free);
+ if (video->is_enabled)
+ list_add_tail(&req->list, &video->req_free);
+ else
+ uvc_video_free_request(req->context, video->ep);
spin_unlock_irqrestore(&video->req_lock, flags);
- return;
}
/*
- * Enable or disable the video stream.
+ * Disable the video stream
*/
-int uvcg_video_enable(struct uvc_video *video, int enable)
+int
+uvcg_video_disable(struct uvc_video *video)
{
- unsigned int i;
- int ret;
+ unsigned long flags;
+ struct list_head inflight_bufs;
+ struct usb_request *req, *temp;
+ struct uvc_buffer *buf, *btemp;
+ struct uvc_request *ureq, *utemp;
if (video->ep == NULL) {
uvcg_info(&video->uvc->func,
- "Video enable failed, device is uninitialized.\n");
+ "Video disable failed, device is uninitialized.\n");
return -ENODEV;
}
- if (!enable) {
- cancel_work_sync(&video->pump);
- uvcg_queue_cancel(&video->queue, 0);
+ INIT_LIST_HEAD(&inflight_bufs);
+ spin_lock_irqsave(&video->req_lock, flags);
+ video->is_enabled = false;
+
+ /*
+ * Remove any in-flight buffers from the uvc_requests
+ * because we want to return them before cancelling the
+ * queue. This ensures that we aren't stuck waiting for
+ * all complete callbacks to come through before disabling
+ * vb2 queue.
+ */
+ list_for_each_entry(ureq, &video->ureqs, list) {
+ if (ureq->last_buf) {
+ list_add_tail(&ureq->last_buf->queue, &inflight_bufs);
+ ureq->last_buf = NULL;
+ }
+ }
+ spin_unlock_irqrestore(&video->req_lock, flags);
- for (i = 0; i < video->uvc_num_requests; ++i)
- if (video->ureq && video->ureq[i].req)
- usb_ep_dequeue(video->ep, video->ureq[i].req);
+ cancel_work_sync(&video->pump);
+ uvcg_queue_cancel(&video->queue, 0);
+
+ spin_lock_irqsave(&video->req_lock, flags);
+ /*
+ * Remove all uvc_requests from ureqs with list_del_init
+ * This lets uvc_video_free_request correctly identify
+ * if the uvc_request is attached to a list or not when freeing
+ * memory.
+ */
+ list_for_each_entry_safe(ureq, utemp, &video->ureqs, list)
+ list_del_init(&ureq->list);
+
+ list_for_each_entry_safe(req, temp, &video->req_free, list) {
+ list_del(&req->list);
+ uvc_video_free_request(req->context, video->ep);
+ }
- uvc_video_free_requests(video);
- uvcg_queue_enable(&video->queue, 0);
- return 0;
+ list_for_each_entry_safe(req, temp, &video->req_ready, list) {
+ list_del(&req->list);
+ uvc_video_free_request(req->context, video->ep);
}
+ INIT_LIST_HEAD(&video->ureqs);
+ INIT_LIST_HEAD(&video->req_free);
+ INIT_LIST_HEAD(&video->req_ready);
+ video->req_size = 0;
+ spin_unlock_irqrestore(&video->req_lock, flags);
+
+ /*
+ * Return all the video buffers before disabling the queue.
+ */
+ spin_lock_irqsave(&video->queue.irqlock, flags);
+ list_for_each_entry_safe(buf, btemp, &inflight_bufs, queue) {
+ list_del(&buf->queue);
+ uvcg_complete_buffer(&video->queue, buf);
+ }
+ spin_unlock_irqrestore(&video->queue.irqlock, flags);
+
+ uvcg_queue_enable(&video->queue, 0);
+ return 0;
+}
+
+/*
+ * Enable the video stream.
+ */
+int uvcg_video_enable(struct uvc_video *video)
+{
+ int ret;
+
+ if (video->ep == NULL) {
+ uvcg_info(&video->uvc->func,
+ "Video enable failed, device is uninitialized.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Safe to access request related fields without req_lock because
+ * this is the only thread currently active, and no other
+ * request handling thread will become active until this function
+ * returns.
+ */
+ video->is_enabled = true;
+
if ((ret = uvcg_queue_enable(&video->queue, 1)) < 0)
return ret;
@@ -525,7 +755,7 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
video->req_int_count = 0;
- queue_work(video->async_wq, &video->pump);
+ uvc_video_ep_queue_initial_requests(video);
return ret;
}
@@ -535,7 +765,10 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
*/
int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
{
+ video->is_enabled = false;
+ INIT_LIST_HEAD(&video->ureqs);
INIT_LIST_HEAD(&video->req_free);
+ INIT_LIST_HEAD(&video->req_ready);
spin_lock_init(&video->req_lock);
INIT_WORK(&video->pump, uvcg_video_pump);
diff --git a/drivers/usb/gadget/function/uvc_video.h b/drivers/usb/gadget/function/uvc_video.h
index 03adeefa343b..8ef6259741f1 100644
--- a/drivers/usb/gadget/function/uvc_video.h
+++ b/drivers/usb/gadget/function/uvc_video.h
@@ -14,7 +14,8 @@
struct uvc_video;
-int uvcg_video_enable(struct uvc_video *video, int enable);
+int uvcg_video_enable(struct uvc_video *video);
+int uvcg_video_disable(struct uvc_video *video);
int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc);
diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c
index c06dd1af7a0c..c395438d3978 100644
--- a/drivers/usb/gadget/legacy/webcam.c
+++ b/drivers/usb/gadget/legacy/webcam.c
@@ -12,6 +12,7 @@
#include <linux/usb/video.h>
#include "u_uvc.h"
+#include "uvc_configfs.h"
USB_GADGET_COMPOSITE_OPTIONS();
@@ -84,8 +85,6 @@ static struct usb_device_descriptor webcam_device_descriptor = {
.bNumConfigurations = 0, /* dynamic */
};
-DECLARE_UVC_HEADER_DESCRIPTOR(1);
-
static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = {
.bLength = UVC_DT_HEADER_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
@@ -158,43 +157,112 @@ static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = {
.bmaControls[1][0] = 4,
};
-static const struct uvc_format_uncompressed uvc_format_yuv = {
- .bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED,
- .bFormatIndex = 1,
- .bNumFrameDescriptors = 2,
- .guidFormat =
- { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00,
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71},
- .bBitsPerPixel = 16,
- .bDefaultFrameIndex = 1,
- .bAspectRatioX = 0,
- .bAspectRatioY = 0,
- .bmInterlaceFlags = 0,
- .bCopyProtect = 0,
+static const struct uvcg_color_matching uvcg_color_matching = {
+ .desc = {
+ .bLength = UVC_DT_COLOR_MATCHING_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = UVC_VS_COLORFORMAT,
+ .bColorPrimaries = 1,
+ .bTransferCharacteristics = 1,
+ .bMatrixCoefficients = 4,
+ },
+};
+
+static struct uvcg_uncompressed uvcg_format_yuv = {
+ .fmt = {
+ .type = UVCG_UNCOMPRESSED,
+ /* add to .frames and fill .num_frames at runtime */
+ .color_matching = (struct uvcg_color_matching *)&uvcg_color_matching,
+ },
+ .desc = {
+ .bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED,
+ .bFormatIndex = 1,
+ .bNumFrameDescriptors = 2,
+ .guidFormat = {
+ 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+ },
+ .bBitsPerPixel = 16,
+ .bDefaultFrameIndex = 1,
+ .bAspectRatioX = 0,
+ .bAspectRatioY = 0,
+ .bmInterlaceFlags = 0,
+ .bCopyProtect = 0,
+ },
+};
+
+static struct uvcg_format_ptr uvcg_format_ptr_yuv = {
+ .fmt = &uvcg_format_yuv.fmt,
};
DECLARE_UVC_FRAME_UNCOMPRESSED(1);
DECLARE_UVC_FRAME_UNCOMPRESSED(3);
+#define UVCG_WIDTH_360P 640
+#define UVCG_HEIGHT_360P 360
+#define UVCG_MIN_BITRATE_360P 18432000
+#define UVCG_MAX_BITRATE_360P 55296000
+#define UVCG_MAX_VIDEO_FB_SZ_360P 460800
+#define UVCG_FRM_INTERV_0_360P 666666
+#define UVCG_FRM_INTERV_1_360P 1000000
+#define UVCG_FRM_INTERV_2_360P 5000000
+#define UVCG_DEFAULT_FRM_INTERV_360P UVCG_FRM_INTERV_0_360P
+
static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = {
.bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED,
.bFrameIndex = 1,
.bmCapabilities = 0,
- .wWidth = cpu_to_le16(640),
- .wHeight = cpu_to_le16(360),
- .dwMinBitRate = cpu_to_le32(18432000),
- .dwMaxBitRate = cpu_to_le32(55296000),
- .dwMaxVideoFrameBufferSize = cpu_to_le32(460800),
- .dwDefaultFrameInterval = cpu_to_le32(666666),
+ .wWidth = cpu_to_le16(UVCG_WIDTH_360P),
+ .wHeight = cpu_to_le16(UVCG_HEIGHT_360P),
+ .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_360P),
+ .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_360P),
+ .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_360P),
+ .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_360P),
.bFrameIntervalType = 3,
- .dwFrameInterval[0] = cpu_to_le32(666666),
- .dwFrameInterval[1] = cpu_to_le32(1000000),
- .dwFrameInterval[2] = cpu_to_le32(5000000),
+ .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_360P),
+ .dwFrameInterval[1] = cpu_to_le32(UVCG_FRM_INTERV_1_360P),
+ .dwFrameInterval[2] = cpu_to_le32(UVCG_FRM_INTERV_2_360P),
+};
+
+static u32 uvcg_frame_yuv_360p_dw_frame_interval[] = {
+ [0] = UVCG_FRM_INTERV_0_360P,
+ [1] = UVCG_FRM_INTERV_1_360P,
+ [2] = UVCG_FRM_INTERV_2_360P,
+};
+
+static const struct uvcg_frame uvcg_frame_yuv_360p = {
+ .fmt_type = UVCG_UNCOMPRESSED,
+ .frame = {
+ .b_length = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3),
+ .b_descriptor_type = USB_DT_CS_INTERFACE,
+ .b_descriptor_subtype = UVC_VS_FRAME_UNCOMPRESSED,
+ .b_frame_index = 1,
+ .bm_capabilities = 0,
+ .w_width = UVCG_WIDTH_360P,
+ .w_height = UVCG_HEIGHT_360P,
+ .dw_min_bit_rate = UVCG_MIN_BITRATE_360P,
+ .dw_max_bit_rate = UVCG_MAX_BITRATE_360P,
+ .dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_360P,
+ .dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_360P,
+ .b_frame_interval_type = 3,
+ },
+ .dw_frame_interval = uvcg_frame_yuv_360p_dw_frame_interval,
+};
+
+static struct uvcg_frame_ptr uvcg_frame_ptr_yuv_360p = {
+ .frm = (struct uvcg_frame *)&uvcg_frame_yuv_360p,
};
+#define UVCG_WIDTH_720P 1280
+#define UVCG_HEIGHT_720P 720
+#define UVCG_MIN_BITRATE_720P 29491200
+#define UVCG_MAX_BITRATE_720P 29491200
+#define UVCG_MAX_VIDEO_FB_SZ_720P 1843200
+#define UVCG_FRM_INTERV_0_720P 5000000
+#define UVCG_DEFAULT_FRM_INTERV_720P UVCG_FRM_INTERV_0_720P
static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
.bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
@@ -202,28 +270,66 @@ static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = {
.bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED,
.bFrameIndex = 2,
.bmCapabilities = 0,
- .wWidth = cpu_to_le16(1280),
- .wHeight = cpu_to_le16(720),
- .dwMinBitRate = cpu_to_le32(29491200),
- .dwMaxBitRate = cpu_to_le32(29491200),
- .dwMaxVideoFrameBufferSize = cpu_to_le32(1843200),
- .dwDefaultFrameInterval = cpu_to_le32(5000000),
+ .wWidth = cpu_to_le16(UVCG_WIDTH_720P),
+ .wHeight = cpu_to_le16(UVCG_HEIGHT_720P),
+ .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_720P),
+ .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_720P),
+ .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_720P),
+ .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_720P),
.bFrameIntervalType = 1,
- .dwFrameInterval[0] = cpu_to_le32(5000000),
+ .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_720P),
};
-static const struct uvc_format_mjpeg uvc_format_mjpg = {
- .bLength = UVC_DT_FORMAT_MJPEG_SIZE,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_VS_FORMAT_MJPEG,
- .bFormatIndex = 2,
- .bNumFrameDescriptors = 2,
- .bmFlags = 0,
- .bDefaultFrameIndex = 1,
- .bAspectRatioX = 0,
- .bAspectRatioY = 0,
- .bmInterlaceFlags = 0,
- .bCopyProtect = 0,
+static u32 uvcg_frame_yuv_720p_dw_frame_interval[] = {
+ [0] = UVCG_FRM_INTERV_0_720P,
+};
+
+static const struct uvcg_frame uvcg_frame_yuv_720p = {
+ .fmt_type = UVCG_UNCOMPRESSED,
+ .frame = {
+ .b_length = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1),
+ .b_descriptor_type = USB_DT_CS_INTERFACE,
+ .b_descriptor_subtype = UVC_VS_FRAME_UNCOMPRESSED,
+ .b_frame_index = 2,
+ .bm_capabilities = 0,
+ .w_width = UVCG_WIDTH_720P,
+ .w_height = UVCG_HEIGHT_720P,
+ .dw_min_bit_rate = UVCG_MIN_BITRATE_720P,
+ .dw_max_bit_rate = UVCG_MAX_BITRATE_720P,
+ .dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_720P,
+ .dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_720P,
+ .b_frame_interval_type = 1,
+ },
+ .dw_frame_interval = uvcg_frame_yuv_720p_dw_frame_interval,
+};
+
+static struct uvcg_frame_ptr uvcg_frame_ptr_yuv_720p = {
+ .frm = (struct uvcg_frame *)&uvcg_frame_yuv_720p,
+};
+
+static struct uvcg_mjpeg uvcg_format_mjpeg = {
+ .fmt = {
+ .type = UVCG_MJPEG,
+ /* add to .frames and fill .num_frames at runtime */
+ .color_matching = (struct uvcg_color_matching *)&uvcg_color_matching,
+ },
+ .desc = {
+ .bLength = UVC_DT_FORMAT_MJPEG_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = UVC_VS_FORMAT_MJPEG,
+ .bFormatIndex = 2,
+ .bNumFrameDescriptors = 2,
+ .bmFlags = 0,
+ .bDefaultFrameIndex = 1,
+ .bAspectRatioX = 0,
+ .bAspectRatioY = 0,
+ .bmInterlaceFlags = 0,
+ .bCopyProtect = 0,
+ },
+};
+
+static struct uvcg_format_ptr uvcg_format_ptr_mjpeg = {
+ .fmt = &uvcg_format_mjpeg.fmt,
};
DECLARE_UVC_FRAME_MJPEG(1);
@@ -235,16 +341,45 @@ static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = {
.bDescriptorSubType = UVC_VS_FRAME_MJPEG,
.bFrameIndex = 1,
.bmCapabilities = 0,
- .wWidth = cpu_to_le16(640),
- .wHeight = cpu_to_le16(360),
- .dwMinBitRate = cpu_to_le32(18432000),
- .dwMaxBitRate = cpu_to_le32(55296000),
- .dwMaxVideoFrameBufferSize = cpu_to_le32(460800),
- .dwDefaultFrameInterval = cpu_to_le32(666666),
+ .wWidth = cpu_to_le16(UVCG_WIDTH_360P),
+ .wHeight = cpu_to_le16(UVCG_HEIGHT_360P),
+ .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_360P),
+ .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_360P),
+ .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_360P),
+ .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_360P),
.bFrameIntervalType = 3,
- .dwFrameInterval[0] = cpu_to_le32(666666),
- .dwFrameInterval[1] = cpu_to_le32(1000000),
- .dwFrameInterval[2] = cpu_to_le32(5000000),
+ .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_360P),
+ .dwFrameInterval[1] = cpu_to_le32(UVCG_FRM_INTERV_1_360P),
+ .dwFrameInterval[2] = cpu_to_le32(UVCG_FRM_INTERV_2_360P),
+};
+
+static u32 uvcg_frame_mjpeg_360p_dw_frame_interval[] = {
+ [0] = UVCG_FRM_INTERV_0_360P,
+ [1] = UVCG_FRM_INTERV_1_360P,
+ [2] = UVCG_FRM_INTERV_2_360P,
+};
+
+static const struct uvcg_frame uvcg_frame_mjpeg_360p = {
+ .fmt_type = UVCG_MJPEG,
+ .frame = {
+ .b_length = UVC_DT_FRAME_MJPEG_SIZE(3),
+ .b_descriptor_type = USB_DT_CS_INTERFACE,
+ .b_descriptor_subtype = UVC_VS_FRAME_MJPEG,
+ .b_frame_index = 1,
+ .bm_capabilities = 0,
+ .w_width = UVCG_WIDTH_360P,
+ .w_height = UVCG_HEIGHT_360P,
+ .dw_min_bit_rate = UVCG_MIN_BITRATE_360P,
+ .dw_max_bit_rate = UVCG_MAX_BITRATE_360P,
+ .dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_360P,
+ .dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_360P,
+ .b_frame_interval_type = 3,
+ },
+ .dw_frame_interval = uvcg_frame_mjpeg_360p_dw_frame_interval,
+};
+
+static struct uvcg_frame_ptr uvcg_frame_ptr_mjpeg_360p = {
+ .frm = (struct uvcg_frame *)&uvcg_frame_mjpeg_360p,
};
static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
@@ -253,23 +388,44 @@ static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = {
.bDescriptorSubType = UVC_VS_FRAME_MJPEG,
.bFrameIndex = 2,
.bmCapabilities = 0,
- .wWidth = cpu_to_le16(1280),
- .wHeight = cpu_to_le16(720),
- .dwMinBitRate = cpu_to_le32(29491200),
- .dwMaxBitRate = cpu_to_le32(29491200),
- .dwMaxVideoFrameBufferSize = cpu_to_le32(1843200),
- .dwDefaultFrameInterval = cpu_to_le32(5000000),
+ .wWidth = cpu_to_le16(UVCG_WIDTH_720P),
+ .wHeight = cpu_to_le16(UVCG_HEIGHT_720P),
+ .dwMinBitRate = cpu_to_le32(UVCG_MIN_BITRATE_720P),
+ .dwMaxBitRate = cpu_to_le32(UVCG_MAX_BITRATE_720P),
+ .dwMaxVideoFrameBufferSize = cpu_to_le32(UVCG_MAX_VIDEO_FB_SZ_720P),
+ .dwDefaultFrameInterval = cpu_to_le32(UVCG_DEFAULT_FRM_INTERV_720P),
.bFrameIntervalType = 1,
- .dwFrameInterval[0] = cpu_to_le32(5000000),
+ .dwFrameInterval[0] = cpu_to_le32(UVCG_FRM_INTERV_0_720P),
};
-static const struct uvc_color_matching_descriptor uvc_color_matching = {
- .bLength = UVC_DT_COLOR_MATCHING_SIZE,
- .bDescriptorType = USB_DT_CS_INTERFACE,
- .bDescriptorSubType = UVC_VS_COLORFORMAT,
- .bColorPrimaries = 1,
- .bTransferCharacteristics = 1,
- .bMatrixCoefficients = 4,
+static u32 uvcg_frame_mjpeg_720p_dw_frame_interval[] = {
+ [0] = UVCG_FRM_INTERV_0_720P,
+};
+
+static const struct uvcg_frame uvcg_frame_mjpeg_720p = {
+ .fmt_type = UVCG_MJPEG,
+ .frame = {
+ .b_length = UVC_DT_FRAME_MJPEG_SIZE(1),
+ .b_descriptor_type = USB_DT_CS_INTERFACE,
+ .b_descriptor_subtype = UVC_VS_FRAME_MJPEG,
+ .b_frame_index = 2,
+ .bm_capabilities = 0,
+ .w_width = UVCG_WIDTH_720P,
+ .w_height = UVCG_HEIGHT_720P,
+ .dw_min_bit_rate = UVCG_MIN_BITRATE_720P,
+ .dw_max_bit_rate = UVCG_MAX_BITRATE_720P,
+ .dw_max_video_frame_buffer_size = UVCG_MAX_VIDEO_FB_SZ_720P,
+ .dw_default_frame_interval = UVCG_DEFAULT_FRM_INTERV_720P,
+ .b_frame_interval_type = 1,
+ },
+ .dw_frame_interval = uvcg_frame_mjpeg_720p_dw_frame_interval,
+};
+
+static struct uvcg_frame_ptr uvcg_frame_ptr_mjpeg_720p = {
+ .frm = (struct uvcg_frame *)&uvcg_frame_mjpeg_720p,
+};
+
+static struct uvcg_streaming_header uvcg_streaming_header = {
};
static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
@@ -290,40 +446,40 @@ static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
(const struct uvc_descriptor_header *) &uvc_input_header,
- (const struct uvc_descriptor_header *) &uvc_format_yuv,
+ (const struct uvc_descriptor_header *) &uvcg_format_yuv.desc,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
- (const struct uvc_descriptor_header *) &uvc_color_matching,
- (const struct uvc_descriptor_header *) &uvc_format_mjpg,
+ (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
+ (const struct uvc_descriptor_header *) &uvcg_format_mjpeg.desc,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
- (const struct uvc_descriptor_header *) &uvc_color_matching,
+ (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
NULL,
};
static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
(const struct uvc_descriptor_header *) &uvc_input_header,
- (const struct uvc_descriptor_header *) &uvc_format_yuv,
+ (const struct uvc_descriptor_header *) &uvcg_format_yuv.desc,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
- (const struct uvc_descriptor_header *) &uvc_color_matching,
- (const struct uvc_descriptor_header *) &uvc_format_mjpg,
+ (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
+ (const struct uvc_descriptor_header *) &uvcg_format_mjpeg.desc,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
- (const struct uvc_descriptor_header *) &uvc_color_matching,
+ (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
NULL,
};
static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
(const struct uvc_descriptor_header *) &uvc_input_header,
- (const struct uvc_descriptor_header *) &uvc_format_yuv,
+ (const struct uvc_descriptor_header *) &uvcg_format_yuv.desc,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
- (const struct uvc_descriptor_header *) &uvc_color_matching,
- (const struct uvc_descriptor_header *) &uvc_format_mjpg,
+ (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
+ (const struct uvc_descriptor_header *) &uvcg_format_mjpeg.desc,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
(const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
- (const struct uvc_descriptor_header *) &uvc_color_matching,
+ (const struct uvc_descriptor_header *) &uvcg_color_matching.desc,
NULL,
};
@@ -387,6 +543,23 @@ webcam_bind(struct usb_composite_dev *cdev)
uvc_opts->hs_streaming = uvc_hs_streaming_cls;
uvc_opts->ss_streaming = uvc_ss_streaming_cls;
+ INIT_LIST_HEAD(&uvcg_format_yuv.fmt.frames);
+ list_add_tail(&uvcg_frame_ptr_yuv_360p.entry, &uvcg_format_yuv.fmt.frames);
+ list_add_tail(&uvcg_frame_ptr_yuv_720p.entry, &uvcg_format_yuv.fmt.frames);
+ uvcg_format_yuv.fmt.num_frames = 2;
+
+ INIT_LIST_HEAD(&uvcg_format_mjpeg.fmt.frames);
+ list_add_tail(&uvcg_frame_ptr_mjpeg_360p.entry, &uvcg_format_mjpeg.fmt.frames);
+ list_add_tail(&uvcg_frame_ptr_mjpeg_720p.entry, &uvcg_format_mjpeg.fmt.frames);
+ uvcg_format_mjpeg.fmt.num_frames = 2;
+
+ INIT_LIST_HEAD(&uvcg_streaming_header.formats);
+ list_add_tail(&uvcg_format_ptr_yuv.entry, &uvcg_streaming_header.formats);
+ list_add_tail(&uvcg_format_ptr_mjpeg.entry, &uvcg_streaming_header.formats);
+ uvcg_streaming_header.num_fmt = 2;
+
+ uvc_opts->header = &uvcg_streaming_header;
+
/* Allocate string descriptor numbers ... note that string contents
* can be overridden by the composite_dev glue.
*/
diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c
index 30ea4a9d5301..e3bf17a98b38 100644
--- a/drivers/usb/gadget/udc/at91_udc.c
+++ b/drivers/usb/gadget/udc/at91_udc.c
@@ -1924,7 +1924,7 @@ err_unprepare_fclk:
return retval;
}
-static int at91udc_remove(struct platform_device *pdev)
+static void at91udc_remove(struct platform_device *pdev)
{
struct at91_udc *udc = platform_get_drvdata(pdev);
unsigned long flags;
@@ -1932,8 +1932,11 @@ static int at91udc_remove(struct platform_device *pdev)
DBG("remove\n");
usb_del_gadget_udc(&udc->gadget);
- if (udc->driver)
- return -EBUSY;
+ if (udc->driver) {
+ dev_err(&pdev->dev,
+ "Driver still in use but removing anyhow\n");
+ return;
+ }
spin_lock_irqsave(&udc->lock, flags);
pullup(udc, 0);
@@ -1943,8 +1946,6 @@ static int at91udc_remove(struct platform_device *pdev)
remove_debug_file(udc);
clk_unprepare(udc->fclk);
clk_unprepare(udc->iclk);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -2001,7 +2002,7 @@ static int at91udc_resume(struct platform_device *pdev)
static struct platform_driver at91_udc_driver = {
.probe = at91udc_probe,
- .remove = at91udc_remove,
+ .remove_new = at91udc_remove,
.shutdown = at91udc_shutdown,
.suspend = at91udc_suspend,
.resume = at91udc_resume,
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 02b1bef5e22e..b76885d78e8a 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -94,7 +94,7 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf,
inode_lock(file_inode(file));
list_for_each_entry_safe(req, tmp_req, queue, queue) {
- len = snprintf(tmpbuf, sizeof(tmpbuf),
+ len = scnprintf(tmpbuf, sizeof(tmpbuf),
"%8p %08x %c%c%c %5d %c%c%c\n",
req->req.buf, req->req.length,
req->req.no_interrupt ? 'i' : 'I',
@@ -104,7 +104,6 @@ static ssize_t queue_dbg_read(struct file *file, char __user *buf,
req->submitted ? 'F' : 'f',
req->using_dma ? 'D' : 'd',
req->last_transaction ? 'L' : 'l');
- len = min(len, sizeof(tmpbuf));
if (len > nbytes)
break;
diff --git a/drivers/usb/gadget/udc/cdns2/cdns2-debug.h b/drivers/usb/gadget/udc/cdns2/cdns2-debug.h
index be9ae0d28a40..f5f330004190 100644
--- a/drivers/usb/gadget/udc/cdns2/cdns2-debug.h
+++ b/drivers/usb/gadget/udc/cdns2/cdns2-debug.h
@@ -16,34 +16,34 @@ static inline const char *cdns2_decode_usb_irq(char *str, size_t size,
{
int ret;
- ret = snprintf(str, size, "usbirq: 0x%02x - ", usb_irq);
+ ret = scnprintf(str, size, "usbirq: 0x%02x - ", usb_irq);
if (usb_irq & USBIRQ_SOF)
- ret += snprintf(str + ret, size - ret, "SOF ");
+ ret += scnprintf(str + ret, size - ret, "SOF ");
if (usb_irq & USBIRQ_SUTOK)
- ret += snprintf(str + ret, size - ret, "SUTOK ");
+ ret += scnprintf(str + ret, size - ret, "SUTOK ");
if (usb_irq & USBIRQ_SUDAV)
- ret += snprintf(str + ret, size - ret, "SETUP ");
+ ret += scnprintf(str + ret, size - ret, "SETUP ");
if (usb_irq & USBIRQ_SUSPEND)
- ret += snprintf(str + ret, size - ret, "Suspend ");
+ ret += scnprintf(str + ret, size - ret, "Suspend ");
if (usb_irq & USBIRQ_URESET)
- ret += snprintf(str + ret, size - ret, "Reset ");
+ ret += scnprintf(str + ret, size - ret, "Reset ");
if (usb_irq & USBIRQ_HSPEED)
- ret += snprintf(str + ret, size - ret, "HS ");
+ ret += scnprintf(str + ret, size - ret, "HS ");
if (usb_irq & USBIRQ_LPM)
- ret += snprintf(str + ret, size - ret, "LPM ");
+ ret += scnprintf(str + ret, size - ret, "LPM ");
- ret += snprintf(str + ret, size - ret, ", EXT: 0x%02x - ", ext_irq);
+ ret += scnprintf(str + ret, size - ret, ", EXT: 0x%02x - ", ext_irq);
if (ext_irq & EXTIRQ_WAKEUP)
- ret += snprintf(str + ret, size - ret, "Wakeup ");
+ ret += scnprintf(str + ret, size - ret, "Wakeup ");
if (ext_irq & EXTIRQ_VBUSFAULT_FALL)
- ret += snprintf(str + ret, size - ret, "VBUS_FALL ");
+ ret += scnprintf(str + ret, size - ret, "VBUS_FALL ");
if (ext_irq & EXTIRQ_VBUSFAULT_RISE)
- ret += snprintf(str + ret, size - ret, "VBUS_RISE ");
+ ret += scnprintf(str + ret, size - ret, "VBUS_RISE ");
- if (ret >= size)
- pr_info("CDNS2: buffer overflowed.\n");
+ if (ret == size - 1)
+ pr_info("CDNS2: buffer may be truncated.\n");
return str;
}
@@ -54,28 +54,28 @@ static inline const char *cdns2_decode_dma_irq(char *str, size_t size,
{
int ret;
- ret = snprintf(str, size, "ISTS: %08x, %s: %08x ",
- ep_ists, ep_name, ep_sts);
+ ret = scnprintf(str, size, "ISTS: %08x, %s: %08x ",
+ ep_ists, ep_name, ep_sts);
if (ep_sts & DMA_EP_STS_IOC)
- ret += snprintf(str + ret, size - ret, "IOC ");
+ ret += scnprintf(str + ret, size - ret, "IOC ");
if (ep_sts & DMA_EP_STS_ISP)
- ret += snprintf(str + ret, size - ret, "ISP ");
+ ret += scnprintf(str + ret, size - ret, "ISP ");
if (ep_sts & DMA_EP_STS_DESCMIS)
- ret += snprintf(str + ret, size - ret, "DESCMIS ");
+ ret += scnprintf(str + ret, size - ret, "DESCMIS ");
if (ep_sts & DMA_EP_STS_TRBERR)
- ret += snprintf(str + ret, size - ret, "TRBERR ");
+ ret += scnprintf(str + ret, size - ret, "TRBERR ");
if (ep_sts & DMA_EP_STS_OUTSMM)
- ret += snprintf(str + ret, size - ret, "OUTSMM ");
+ ret += scnprintf(str + ret, size - ret, "OUTSMM ");
if (ep_sts & DMA_EP_STS_ISOERR)
- ret += snprintf(str + ret, size - ret, "ISOERR ");
+ ret += scnprintf(str + ret, size - ret, "ISOERR ");
if (ep_sts & DMA_EP_STS_DBUSY)
- ret += snprintf(str + ret, size - ret, "DBUSY ");
+ ret += scnprintf(str + ret, size - ret, "DBUSY ");
if (DMA_EP_STS_CCS(ep_sts))
- ret += snprintf(str + ret, size - ret, "CCS ");
+ ret += scnprintf(str + ret, size - ret, "CCS ");
- if (ret >= size)
- pr_info("CDNS2: buffer overflowed.\n");
+ if (ret == size - 1)
+ pr_info("CDNS2: buffer may be truncated.\n");
return str;
}
@@ -105,43 +105,43 @@ static inline const char *cdns2_raw_ring(struct cdns2_endpoint *pep,
int ret;
int i;
- ret = snprintf(str, size, "\n\t\tTR for %s:", pep->name);
+ ret = scnprintf(str, size, "\n\t\tTR for %s:", pep->name);
trb = &trbs[ring->dequeue];
dma = cdns2_trb_virt_to_dma(pep, trb);
- ret += snprintf(str + ret, size - ret,
- "\n\t\tRing deq index: %d, trb: V=%p, P=0x%pad\n",
- ring->dequeue, trb, &dma);
+ ret += scnprintf(str + ret, size - ret,
+ "\n\t\tRing deq index: %d, trb: V=%p, P=0x%pad\n",
+ ring->dequeue, trb, &dma);
trb = &trbs[ring->enqueue];
dma = cdns2_trb_virt_to_dma(pep, trb);
- ret += snprintf(str + ret, size - ret,
- "\t\tRing enq index: %d, trb: V=%p, P=0x%pad\n",
- ring->enqueue, trb, &dma);
+ ret += scnprintf(str + ret, size - ret,
+ "\t\tRing enq index: %d, trb: V=%p, P=0x%pad\n",
+ ring->enqueue, trb, &dma);
- ret += snprintf(str + ret, size - ret,
- "\t\tfree trbs: %d, CCS=%d, PCS=%d\n",
- ring->free_trbs, ring->ccs, ring->pcs);
+ ret += scnprintf(str + ret, size - ret,
+ "\t\tfree trbs: %d, CCS=%d, PCS=%d\n",
+ ring->free_trbs, ring->ccs, ring->pcs);
if (TRBS_PER_SEGMENT > 40) {
- ret += snprintf(str + ret, size - ret,
- "\t\tTransfer ring %d too big\n", TRBS_PER_SEGMENT);
+ ret += scnprintf(str + ret, size - ret,
+ "\t\tTransfer ring %d too big\n", TRBS_PER_SEGMENT);
return str;
}
dma = ring->dma;
for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
trb = &trbs[i];
- ret += snprintf(str + ret, size - ret,
- "\t\t@%pad %08x %08x %08x\n", &dma,
- le32_to_cpu(trb->buffer),
- le32_to_cpu(trb->length),
- le32_to_cpu(trb->control));
+ ret += scnprintf(str + ret, size - ret,
+ "\t\t@%pad %08x %08x %08x\n", &dma,
+ le32_to_cpu(trb->buffer),
+ le32_to_cpu(trb->length),
+ le32_to_cpu(trb->control));
dma += sizeof(*trb);
}
- if (ret >= size)
- pr_info("CDNS2: buffer overflowed.\n");
+ if (ret == size - 1)
+ pr_info("CDNS2: buffer may be truncated.\n");
return str;
}
@@ -166,36 +166,36 @@ static inline const char *cdns2_decode_trb(char *str, size_t size, u32 flags,
switch (type) {
case TRB_LINK:
- ret = snprintf(str, size,
- "LINK %08x type '%s' flags %c:%c:%c%c:%c",
- buffer, cdns2_trb_type_string(type),
- flags & TRB_CYCLE ? 'C' : 'c',
- flags & TRB_TOGGLE ? 'T' : 't',
- flags & TRB_CHAIN ? 'C' : 'c',
- flags & TRB_CHAIN ? 'H' : 'h',
- flags & TRB_IOC ? 'I' : 'i');
+ ret = scnprintf(str, size,
+ "LINK %08x type '%s' flags %c:%c:%c%c:%c",
+ buffer, cdns2_trb_type_string(type),
+ flags & TRB_CYCLE ? 'C' : 'c',
+ flags & TRB_TOGGLE ? 'T' : 't',
+ flags & TRB_CHAIN ? 'C' : 'c',
+ flags & TRB_CHAIN ? 'H' : 'h',
+ flags & TRB_IOC ? 'I' : 'i');
break;
case TRB_NORMAL:
- ret = snprintf(str, size,
- "type: '%s', Buffer: %08x, length: %ld, burst len: %ld, "
- "flags %c:%c:%c%c:%c",
- cdns2_trb_type_string(type),
- buffer, TRB_LEN(length),
- TRB_FIELD_TO_BURST(length),
- flags & TRB_CYCLE ? 'C' : 'c',
- flags & TRB_ISP ? 'I' : 'i',
- flags & TRB_CHAIN ? 'C' : 'c',
- flags & TRB_CHAIN ? 'H' : 'h',
- flags & TRB_IOC ? 'I' : 'i');
+ ret = scnprintf(str, size,
+ "type: '%s', Buffer: %08x, length: %ld, burst len: %ld, "
+ "flags %c:%c:%c%c:%c",
+ cdns2_trb_type_string(type),
+ buffer, TRB_LEN(length),
+ TRB_FIELD_TO_BURST(length),
+ flags & TRB_CYCLE ? 'C' : 'c',
+ flags & TRB_ISP ? 'I' : 'i',
+ flags & TRB_CHAIN ? 'C' : 'c',
+ flags & TRB_CHAIN ? 'H' : 'h',
+ flags & TRB_IOC ? 'I' : 'i');
break;
default:
- ret = snprintf(str, size, "type '%s' -> raw %08x %08x %08x",
- cdns2_trb_type_string(type),
- buffer, length, flags);
+ ret = scnprintf(str, size, "type '%s' -> raw %08x %08x %08x",
+ cdns2_trb_type_string(type),
+ buffer, length, flags);
}
- if (ret >= size)
- pr_info("CDNS2: buffer overflowed.\n");
+ if (ret == size - 1)
+ pr_info("CDNS2: buffer may be truncated.\n");
return str;
}
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
index 2693a10eb0c7..e8042c158f6d 100644
--- a/drivers/usb/gadget/udc/fsl_udc_core.c
+++ b/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -1360,7 +1360,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
udc->ep0_dir = USB_DIR_IN;
/* Borrow the per device status_req */
req = udc->status_req;
- /* Fill in the reqest structure */
+ /* Fill in the request structure */
*((u16 *) req->req.buf) = cpu_to_le16(tmp);
req->ep = ep;
@@ -2532,15 +2532,18 @@ err_kfree:
/* Driver removal function
* Free resources and finish pending transactions
*/
-static int fsl_udc_remove(struct platform_device *pdev)
+static void fsl_udc_remove(struct platform_device *pdev)
{
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
DECLARE_COMPLETION_ONSTACK(done);
- if (!udc_controller)
- return -ENODEV;
+ if (!udc_controller) {
+ dev_err(&pdev->dev,
+ "Driver still in use but removing anyhow\n");
+ return;
+ }
udc_controller->done = &done;
usb_del_gadget_udc(&udc_controller->gadget);
@@ -2568,8 +2571,6 @@ static int fsl_udc_remove(struct platform_device *pdev)
*/
if (pdata->exit)
pdata->exit(pdev);
-
- return 0;
}
/*-----------------------------------------------------------------
@@ -2667,7 +2668,7 @@ static const struct platform_device_id fsl_udc_devtype[] = {
MODULE_DEVICE_TABLE(platform, fsl_udc_devtype);
static struct platform_driver udc_driver = {
.probe = fsl_udc_probe,
- .remove = fsl_udc_remove,
+ .remove_new = fsl_udc_remove,
.id_table = fsl_udc_devtype,
/* these suspend and resume are not usb suspend and resume */
.suspend = fsl_udc_suspend,
diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c
index c6dfa7cccc11..fb901be5dac1 100644
--- a/drivers/usb/gadget/udc/gr_udc.c
+++ b/drivers/usb/gadget/udc/gr_udc.c
@@ -2089,15 +2089,18 @@ static void gr_ep_remove(struct gr_udc *dev, int num, int is_in)
ep->tailbuf, ep->tailbuf_paddr);
}
-static int gr_remove(struct platform_device *pdev)
+static void gr_remove(struct platform_device *pdev)
{
struct gr_udc *dev = platform_get_drvdata(pdev);
int i;
if (dev->added)
usb_del_gadget_udc(&dev->gadget); /* Shuts everything down */
- if (dev->driver)
- return -EBUSY;
+ if (dev->driver) {
+ dev_err(&pdev->dev,
+ "Driver still in use but removing anyhow\n");
+ return;
+ }
gr_dfs_delete(dev);
dma_pool_destroy(dev->desc_pool);
@@ -2110,8 +2113,6 @@ static int gr_remove(struct platform_device *pdev)
gr_ep_remove(dev, i, 0);
for (i = 0; i < dev->nepi; i++)
gr_ep_remove(dev, i, 1);
-
- return 0;
}
static int gr_request_irq(struct gr_udc *dev, int irq)
{
@@ -2248,7 +2249,7 @@ static struct platform_driver gr_driver = {
.of_match_table = gr_match,
},
.probe = gr_probe,
- .remove = gr_remove,
+ .remove_new = gr_remove,
};
module_platform_driver(gr_driver);
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index a917cc9a32ab..d5f29f8fe481 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -3174,13 +3174,16 @@ i2c_fail:
return retval;
}
-static int lpc32xx_udc_remove(struct platform_device *pdev)
+static void lpc32xx_udc_remove(struct platform_device *pdev)
{
struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
usb_del_gadget_udc(&udc->gadget);
- if (udc->driver)
- return -EBUSY;
+ if (udc->driver) {
+ dev_err(&pdev->dev,
+ "Driver still in use but removing anyhow\n");
+ return;
+ }
udc_clk_set(udc, 1);
udc_disable(udc);
@@ -3194,8 +3197,6 @@ static int lpc32xx_udc_remove(struct platform_device *pdev)
udc->udca_v_base, udc->udca_p_base);
clk_disable_unprepare(udc->usb_slv_clk);
-
- return 0;
}
#ifdef CONFIG_PM
@@ -3255,7 +3256,7 @@ MODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match);
static struct platform_driver lpc32xx_udc_driver = {
.probe = lpc32xx_udc_probe,
- .remove = lpc32xx_udc_remove,
+ .remove_new = lpc32xx_udc_remove,
.shutdown = lpc32xx_udc_shutdown,
.suspend = lpc32xx_udc_suspend,
.resume = lpc32xx_udc_resume,
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
index d888dcda2bc8..78308b64955d 100644
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ b/drivers/usb/gadget/udc/mv_udc_core.c
@@ -1451,7 +1451,7 @@ udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
req = udc->status_req;
- /* fill in the reqest structure */
+ /* fill in the request structure */
if (empty == false) {
*((u16 *) req->req.buf) = cpu_to_le16(status);
req->req.length = 2;
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c
index df0551ecc810..1ac26cb49ecf 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.c
+++ b/drivers/usb/gadget/udc/pxa25x_udc.c
@@ -2397,12 +2397,15 @@ static void pxa25x_udc_shutdown(struct platform_device *_dev)
pullup_off();
}
-static int pxa25x_udc_remove(struct platform_device *pdev)
+static void pxa25x_udc_remove(struct platform_device *pdev)
{
struct pxa25x_udc *dev = platform_get_drvdata(pdev);
- if (dev->driver)
- return -EBUSY;
+ if (dev->driver) {
+ dev_err(&pdev->dev,
+ "Driver still in use but removing anyhow\n");
+ return;
+ }
usb_del_gadget_udc(&dev->gadget);
dev->pullup = 0;
@@ -2414,7 +2417,6 @@ static int pxa25x_udc_remove(struct platform_device *pdev)
dev->transceiver = NULL;
the_controller = NULL;
- return 0;
}
/*-------------------------------------------------------------------------*/
@@ -2472,7 +2474,7 @@ static int pxa25x_udc_resume(struct platform_device *dev)
static struct platform_driver udc_driver = {
.shutdown = pxa25x_udc_shutdown,
.probe = pxa25x_udc_probe,
- .remove = pxa25x_udc_remove,
+ .remove_new = pxa25x_udc_remove,
.suspend = pxa25x_udc_suspend,
.resume = pxa25x_udc_resume,
.driver = {
diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c
index d152d72de126..9fe4f48b1898 100644
--- a/drivers/usb/host/max3421-hcd.c
+++ b/drivers/usb/host/max3421-hcd.c
@@ -1158,12 +1158,12 @@ dump_eps(struct usb_hcd *hcd)
end = dp + sizeof(ubuf);
*dp = '\0';
list_for_each_entry(urb, &ep->urb_list, urb_list) {
- ret = snprintf(dp, end - dp, " %p(%d.%s %d/%d)", urb,
- usb_pipetype(urb->pipe),
- usb_urb_dir_in(urb) ? "IN" : "OUT",
- urb->actual_length,
- urb->transfer_buffer_length);
- if (ret < 0 || ret >= end - dp)
+ ret = scnprintf(dp, end - dp, " %p(%d.%s %d/%d)", urb,
+ usb_pipetype(urb->pipe),
+ usb_urb_dir_in(urb) ? "IN" : "OUT",
+ urb->actual_length,
+ urb->transfer_buffer_length);
+ if (ret == end - dp - 1)
break; /* error or buffer full */
dp += ret;
}
@@ -1255,9 +1255,9 @@ max3421_handle_irqs(struct usb_hcd *hcd)
end = sbuf + sizeof(sbuf);
*dp = '\0';
for (i = 0; i < 16; ++i) {
- int ret = snprintf(dp, end - dp, " %lu",
- max3421_hcd->err_stat[i]);
- if (ret < 0 || ret >= end - dp)
+ int ret = scnprintf(dp, end - dp, " %lu",
+ max3421_hcd->err_stat[i]);
+ if (ret == end - dp - 1)
break; /* error or buffer full */
dp += ret;
}
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index b40d9238d447..d82935d31126 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c
@@ -6,9 +6,24 @@
*
* Author: Lu Baolu <[email protected]>
*/
+#include <linux/bug.h>
+#include <linux/device.h>
#include <linux/dma-mapping.h>
-#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/kstrtox.h>
+#include <linux/list.h>
#include <linux/nls.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#include <linux/io-64-nonatomic-lo-hi.h>
+
+#include <asm/byteorder.h>
#include "xhci.h"
#include "xhci-trace.h"
@@ -28,7 +43,7 @@ static void dbc_ring_free(struct device *dev, struct xhci_ring *ring)
if (!ring)
return;
- if (ring->first_seg && ring->first_seg->trbs) {
+ if (ring->first_seg) {
dma_free_coherent(dev, TRB_SEGMENT_SIZE,
ring->first_seg->trbs,
ring->first_seg->dma);
@@ -374,13 +389,13 @@ static void xhci_dbc_eps_init(struct xhci_dbc *dbc)
static void xhci_dbc_eps_exit(struct xhci_dbc *dbc)
{
- memset(dbc->eps, 0, sizeof(struct dbc_ep) * ARRAY_SIZE(dbc->eps));
+ memset(dbc->eps, 0, sizeof_field(struct xhci_dbc, eps));
}
static int dbc_erst_alloc(struct device *dev, struct xhci_ring *evt_ring,
struct xhci_erst *erst, gfp_t flags)
{
- erst->entries = dma_alloc_coherent(dev, sizeof(struct xhci_erst_entry),
+ erst->entries = dma_alloc_coherent(dev, sizeof(*erst->entries),
&erst->erst_dma_addr, flags);
if (!erst->entries)
return -ENOMEM;
@@ -394,9 +409,8 @@ static int dbc_erst_alloc(struct device *dev, struct xhci_ring *evt_ring,
static void dbc_erst_free(struct device *dev, struct xhci_erst *erst)
{
- if (erst->entries)
- dma_free_coherent(dev, sizeof(struct xhci_erst_entry),
- erst->entries, erst->erst_dma_addr);
+ dma_free_coherent(dev, sizeof(*erst->entries), erst->entries,
+ erst->erst_dma_addr);
erst->entries = NULL;
}
@@ -495,7 +509,7 @@ static int xhci_dbc_mem_init(struct xhci_dbc *dbc, gfp_t flags)
goto ctx_fail;
/* Allocate the string table: */
- dbc->string_size = sizeof(struct dbc_str_descs);
+ dbc->string_size = sizeof(*dbc->string);
dbc->string = dma_alloc_coherent(dev, dbc->string_size,
&dbc->string_dma, flags);
if (!dbc->string)
@@ -543,11 +557,8 @@ static void xhci_dbc_mem_cleanup(struct xhci_dbc *dbc)
xhci_dbc_eps_exit(dbc);
- if (dbc->string) {
- dma_free_coherent(dbc->dev, dbc->string_size,
- dbc->string, dbc->string_dma);
- dbc->string = NULL;
- }
+ dma_free_coherent(dbc->dev, dbc->string_size, dbc->string, dbc->string_dma);
+ dbc->string = NULL;
dbc_free_ctx(dbc->dev, dbc->ctx);
dbc->ctx = NULL;
@@ -597,7 +608,7 @@ static int xhci_do_dbc_start(struct xhci_dbc *dbc)
static int xhci_do_dbc_stop(struct xhci_dbc *dbc)
{
if (dbc->state == DS_DISABLED)
- return -1;
+ return -EINVAL;
writel(0, &dbc->regs->control);
dbc->state = DS_DISABLED;
@@ -650,11 +661,11 @@ static void xhci_dbc_stop(struct xhci_dbc *dbc)
spin_lock_irqsave(&dbc->lock, flags);
ret = xhci_do_dbc_stop(dbc);
spin_unlock_irqrestore(&dbc->lock, flags);
+ if (ret)
+ return;
- if (!ret) {
- xhci_dbc_mem_cleanup(dbc);
- pm_runtime_put_sync(dbc->dev); /* note, was self.controller */
- }
+ xhci_dbc_mem_cleanup(dbc);
+ pm_runtime_put_sync(dbc->dev); /* note, was self.controller */
}
static void
@@ -914,41 +925,29 @@ static void xhci_dbc_handle_events(struct work_struct *work)
mod_delayed_work(system_wq, &dbc->event_work, 1);
}
+static const char * const dbc_state_strings[DS_MAX] = {
+ [DS_DISABLED] = "disabled",
+ [DS_INITIALIZED] = "initialized",
+ [DS_ENABLED] = "enabled",
+ [DS_CONNECTED] = "connected",
+ [DS_CONFIGURED] = "configured",
+ [DS_STALLED] = "stalled",
+};
+
static ssize_t dbc_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- const char *p;
struct xhci_dbc *dbc;
struct xhci_hcd *xhci;
xhci = hcd_to_xhci(dev_get_drvdata(dev));
dbc = xhci->dbc;
- switch (dbc->state) {
- case DS_DISABLED:
- p = "disabled";
- break;
- case DS_INITIALIZED:
- p = "initialized";
- break;
- case DS_ENABLED:
- p = "enabled";
- break;
- case DS_CONNECTED:
- p = "connected";
- break;
- case DS_CONFIGURED:
- p = "configured";
- break;
- case DS_STALLED:
- p = "stalled";
- break;
- default:
- p = "unknown";
- }
+ if (dbc->state >= ARRAY_SIZE(dbc_state_strings))
+ return sysfs_emit(buf, "unknown\n");
- return sprintf(buf, "%s\n", p);
+ return sysfs_emit(buf, "%s\n", dbc_state_strings[dbc->state]);
}
static ssize_t dbc_store(struct device *dev,
@@ -961,9 +960,9 @@ static ssize_t dbc_store(struct device *dev,
xhci = hcd_to_xhci(dev_get_drvdata(dev));
dbc = xhci->dbc;
- if (!strncmp(buf, "enable", 6))
+ if (sysfs_streq(buf, "enable"))
xhci_dbc_start(dbc);
- else if (!strncmp(buf, "disable", 7))
+ else if (sysfs_streq(buf, "disable"))
xhci_dbc_stop(dbc);
else
return -EINVAL;
@@ -981,7 +980,7 @@ static ssize_t dbc_idVendor_show(struct device *dev,
xhci = hcd_to_xhci(dev_get_drvdata(dev));
dbc = xhci->dbc;
- return sprintf(buf, "%04x\n", dbc->idVendor);
+ return sysfs_emit(buf, "%04x\n", dbc->idVendor);
}
static ssize_t dbc_idVendor_store(struct device *dev,
@@ -993,9 +992,11 @@ static ssize_t dbc_idVendor_store(struct device *dev,
void __iomem *ptr;
u16 value;
u32 dev_info;
+ int ret;
- if (kstrtou16(buf, 0, &value))
- return -EINVAL;
+ ret = kstrtou16(buf, 0, &value);
+ if (ret)
+ return ret;
xhci = hcd_to_xhci(dev_get_drvdata(dev));
dbc = xhci->dbc;
@@ -1021,7 +1022,7 @@ static ssize_t dbc_idProduct_show(struct device *dev,
xhci = hcd_to_xhci(dev_get_drvdata(dev));
dbc = xhci->dbc;
- return sprintf(buf, "%04x\n", dbc->idProduct);
+ return sysfs_emit(buf, "%04x\n", dbc->idProduct);
}
static ssize_t dbc_idProduct_store(struct device *dev,
@@ -1033,9 +1034,11 @@ static ssize_t dbc_idProduct_store(struct device *dev,
void __iomem *ptr;
u32 dev_info;
u16 value;
+ int ret;
- if (kstrtou16(buf, 0, &value))
- return -EINVAL;
+ ret = kstrtou16(buf, 0, &value);
+ if (ret)
+ return ret;
xhci = hcd_to_xhci(dev_get_drvdata(dev));
dbc = xhci->dbc;
@@ -1060,7 +1063,7 @@ static ssize_t dbc_bcdDevice_show(struct device *dev,
xhci = hcd_to_xhci(dev_get_drvdata(dev));
dbc = xhci->dbc;
- return sprintf(buf, "%04x\n", dbc->bcdDevice);
+ return sysfs_emit(buf, "%04x\n", dbc->bcdDevice);
}
static ssize_t dbc_bcdDevice_store(struct device *dev,
@@ -1072,9 +1075,11 @@ static ssize_t dbc_bcdDevice_store(struct device *dev,
void __iomem *ptr;
u32 dev_info;
u16 value;
+ int ret;
- if (kstrtou16(buf, 0, &value))
- return -EINVAL;
+ ret = kstrtou16(buf, 0, &value);
+ if (ret)
+ return ret;
xhci = hcd_to_xhci(dev_get_drvdata(dev));
dbc = xhci->dbc;
@@ -1100,7 +1105,7 @@ static ssize_t dbc_bInterfaceProtocol_show(struct device *dev,
xhci = hcd_to_xhci(dev_get_drvdata(dev));
dbc = xhci->dbc;
- return sprintf(buf, "%02x\n", dbc->bInterfaceProtocol);
+ return sysfs_emit(buf, "%02x\n", dbc->bInterfaceProtocol);
}
static ssize_t dbc_bInterfaceProtocol_store(struct device *dev,
@@ -1114,9 +1119,13 @@ static ssize_t dbc_bInterfaceProtocol_store(struct device *dev,
u8 value;
int ret;
- /* bInterfaceProtocol is 8 bit, but xhci only supports values 0 and 1 */
+ /* bInterfaceProtocol is 8 bit, but... */
ret = kstrtou8(buf, 0, &value);
- if (ret || value > 1)
+ if (ret)
+ return ret;
+
+ /* ...xhci only supports values 0 and 1 */
+ if (value > 1)
return -EINVAL;
xhci = hcd_to_xhci(dev_get_drvdata(dev));
@@ -1139,7 +1148,7 @@ static DEVICE_ATTR_RW(dbc_idProduct);
static DEVICE_ATTR_RW(dbc_bcdDevice);
static DEVICE_ATTR_RW(dbc_bInterfaceProtocol);
-static struct attribute *dbc_dev_attributes[] = {
+static struct attribute *dbc_dev_attrs[] = {
&dev_attr_dbc.attr,
&dev_attr_dbc_idVendor.attr,
&dev_attr_dbc_idProduct.attr,
@@ -1147,10 +1156,7 @@ static struct attribute *dbc_dev_attributes[] = {
&dev_attr_dbc_bInterfaceProtocol.attr,
NULL
};
-
-static const struct attribute_group dbc_dev_attrib_grp = {
- .attrs = dbc_dev_attributes,
-};
+ATTRIBUTE_GROUPS(dbc_dev);
struct xhci_dbc *
xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *driver)
@@ -1176,7 +1182,7 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *
INIT_DELAYED_WORK(&dbc->event_work, xhci_dbc_handle_events);
spin_lock_init(&dbc->lock);
- ret = sysfs_create_group(&dev->kobj, &dbc_dev_attrib_grp);
+ ret = sysfs_create_groups(&dev->kobj, dbc_dev_groups);
if (ret)
goto err;
@@ -1195,7 +1201,7 @@ void xhci_dbc_remove(struct xhci_dbc *dbc)
xhci_dbc_stop(dbc);
/* remove sysfs files */
- sysfs_remove_group(&dbc->dev->kobj, &dbc_dev_attrib_grp);
+ sysfs_remove_groups(&dbc->dev->kobj, dbc_dev_groups);
kfree(dbc);
}
diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h
index 51a7ab3ba0ca..e39e3ae1677a 100644
--- a/drivers/usb/host/xhci-dbgcap.h
+++ b/drivers/usb/host/xhci-dbgcap.h
@@ -82,6 +82,7 @@ enum dbc_state {
DS_CONNECTED,
DS_CONFIGURED,
DS_STALLED,
+ DS_MAX
};
struct dbc_ep {
diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index 6d142cd61bd6..f8ba15e7c225 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -693,7 +693,7 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
"command-ring",
xhci->debugfs_root);
- xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring,
+ xhci_debugfs_create_ring_dir(xhci, &xhci->interrupters[0]->event_ring,
"event-ring",
xhci->debugfs_root);
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 62116586848b..4460fa7e9fab 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -323,6 +323,7 @@ void xhci_initialize_ring_info(struct xhci_ring *ring,
*/
ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
}
+EXPORT_SYMBOL_GPL(xhci_initialize_ring_info);
/* Allocate segments and link them for a ring */
static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
@@ -1739,6 +1740,8 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
}
command->status = 0;
+ /* set default timeout to 5000 ms */
+ command->timeout_ms = XHCI_CMD_DEFAULT_TIMEOUT;
INIT_LIST_HEAD(&command->cmd_list);
return command;
}
@@ -1853,6 +1856,31 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
kfree(ir);
}
+void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrupter *ir)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ unsigned int intr_num;
+
+ /* interrupter 0 is primary interrupter, don't touch it */
+ if (!ir || !ir->intr_num || ir->intr_num >= xhci->max_interrupters)
+ xhci_dbg(xhci, "Invalid secondary interrupter, can't remove\n");
+
+ /* fixme, should we check xhci->interrupter[intr_num] == ir */
+ /* fixme locking */
+
+ spin_lock_irq(&xhci->lock);
+
+ intr_num = ir->intr_num;
+
+ xhci_remove_interrupter(xhci, ir);
+ xhci->interrupters[intr_num] = NULL;
+
+ spin_unlock_irq(&xhci->lock);
+
+ xhci_free_interrupter(xhci, ir);
+}
+EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter);
+
void xhci_mem_cleanup(struct xhci_hcd *xhci)
{
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
@@ -1860,10 +1888,14 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
cancel_delayed_work_sync(&xhci->cmd_timer);
- xhci_remove_interrupter(xhci, xhci->interrupter);
- xhci_free_interrupter(xhci, xhci->interrupter);
- xhci->interrupter = NULL;
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed primary event ring");
+ for (i = 0; i < xhci->max_interrupters; i++) {
+ if (xhci->interrupters[i]) {
+ xhci_remove_interrupter(xhci, xhci->interrupters[i]);
+ xhci_free_interrupter(xhci, xhci->interrupters[i]);
+ xhci->interrupters[i] = NULL;
+ }
+ }
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed interrupters");
if (xhci->cmd_ring)
xhci_ring_free(xhci, xhci->cmd_ring);
@@ -1933,6 +1965,7 @@ no_bw:
for (i = 0; i < xhci->num_port_caps; i++)
kfree(xhci->port_caps[i].psi);
kfree(xhci->port_caps);
+ kfree(xhci->interrupters);
xhci->num_port_caps = 0;
xhci->usb2_rhub.ports = NULL;
@@ -1941,6 +1974,7 @@ no_bw:
xhci->rh_bw = NULL;
xhci->ext_caps = NULL;
xhci->port_caps = NULL;
+ xhci->interrupters = NULL;
xhci->page_size = 0;
xhci->page_shift = 0;
@@ -2246,18 +2280,20 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
}
static struct xhci_interrupter *
-xhci_alloc_interrupter(struct xhci_hcd *xhci, gfp_t flags)
+xhci_alloc_interrupter(struct xhci_hcd *xhci, int segs, gfp_t flags)
{
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
struct xhci_interrupter *ir;
- unsigned int num_segs;
+ unsigned int num_segs = segs;
int ret;
ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
if (!ir)
return NULL;
- num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2),
+ /* number of ring segments should be greater than 0 */
+ if (segs <= 0)
+ num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2),
ERST_MAX_SEGS);
ir->event_ring = xhci_ring_alloc(xhci, num_segs, 1, TYPE_EVENT, 0,
@@ -2292,6 +2328,13 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
return -EINVAL;
}
+ if (xhci->interrupters[intr_num]) {
+ xhci_warn(xhci, "Interrupter %d\n already set up", intr_num);
+ return -EINVAL;
+ }
+
+ xhci->interrupters[intr_num] = ir;
+ ir->intr_num = intr_num;
ir->ir_set = &xhci->run_regs->ir_set[intr_num];
/* set ERST count with the number of entries in the segment table */
@@ -2311,10 +2354,52 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
return 0;
}
+struct xhci_interrupter *
+xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct xhci_interrupter *ir;
+ unsigned int i;
+ int err = -ENOSPC;
+
+ if (!xhci->interrupters || xhci->max_interrupters <= 1)
+ return NULL;
+
+ ir = xhci_alloc_interrupter(xhci, num_seg, GFP_KERNEL);
+ if (!ir)
+ return NULL;
+
+ spin_lock_irq(&xhci->lock);
+
+ /* Find available secondary interrupter, interrupter 0 is reserved for primary */
+ for (i = 1; i < xhci->max_interrupters; i++) {
+ if (xhci->interrupters[i] == NULL) {
+ err = xhci_add_interrupter(xhci, ir, i);
+ break;
+ }
+ }
+
+ spin_unlock_irq(&xhci->lock);
+
+ if (err) {
+ xhci_warn(xhci, "Failed to add secondary interrupter, max interrupters %d\n",
+ xhci->max_interrupters);
+ xhci_free_interrupter(xhci, ir);
+ return NULL;
+ }
+
+ xhci_dbg(xhci, "Add secondary interrupter %d, max interrupters %d\n",
+ i, xhci->max_interrupters);
+
+ return ir;
+}
+EXPORT_SYMBOL_GPL(xhci_create_secondary_interrupter);
+
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
{
- dma_addr_t dma;
+ struct xhci_interrupter *ir;
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
+ dma_addr_t dma;
unsigned int val, val2;
u64 val_64;
u32 page_size, temp;
@@ -2438,11 +2523,14 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
/* Allocate and set up primary interrupter 0 with an event ring. */
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
"Allocating primary event ring");
- xhci->interrupter = xhci_alloc_interrupter(xhci, flags);
- if (!xhci->interrupter)
+ xhci->interrupters = kcalloc_node(xhci->max_interrupters, sizeof(*xhci->interrupters),
+ flags, dev_to_node(dev));
+
+ ir = xhci_alloc_interrupter(xhci, 0, flags);
+ if (!ir)
goto fail;
- if (xhci_add_interrupter(xhci, xhci->interrupter, 0))
+ if (xhci_add_interrupter(xhci, ir, 0))
goto fail;
xhci->isoc_bei_interval = AVOID_BEI_INTERVAL_MAX;
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index bbdf1b0b7be1..3252e3d2d79c 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -7,6 +7,7 @@
* Chunfeng Yun <[email protected]>
*/
+#include <linux/bitfield.h>
#include <linux/dma-mapping.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
@@ -73,6 +74,9 @@
#define FRMCNT_LEV1_RANG (0x12b << 8)
#define FRMCNT_LEV1_RANG_MASK GENMASK(19, 8)
+#define HSCH_CFG1 0x960
+#define SCH3_RXFIFO_DEPTH_MASK GENMASK(21, 20)
+
#define SS_GEN2_EOF_CFG 0x990
#define SSG2EOF_OFFSET 0x3c
@@ -114,6 +118,8 @@
#define SSC_IP_SLEEP_EN BIT(4)
#define SSC_SPM_INT_EN BIT(1)
+#define SCH_FIFO_TO_KB(x) ((x) >> 10)
+
enum ssusb_uwk_vers {
SSUSB_UWK_V1 = 1,
SSUSB_UWK_V2,
@@ -165,6 +171,35 @@ static void xhci_mtk_set_frame_interval(struct xhci_hcd_mtk *mtk)
writel(value, hcd->regs + SS_GEN2_EOF_CFG);
}
+/*
+ * workaround: usb3.2 gen1 isoc rx hw issue
+ * host send out unexpected ACK afer device fininsh a burst transfer with
+ * a short packet.
+ */
+static void xhci_mtk_rxfifo_depth_set(struct xhci_hcd_mtk *mtk)
+{
+ struct usb_hcd *hcd = mtk->hcd;
+ u32 value;
+
+ if (!mtk->rxfifo_depth)
+ return;
+
+ value = readl(hcd->regs + HSCH_CFG1);
+ value &= ~SCH3_RXFIFO_DEPTH_MASK;
+ value |= FIELD_PREP(SCH3_RXFIFO_DEPTH_MASK,
+ SCH_FIFO_TO_KB(mtk->rxfifo_depth) - 1);
+ writel(value, hcd->regs + HSCH_CFG1);
+}
+
+static void xhci_mtk_init_quirk(struct xhci_hcd_mtk *mtk)
+{
+ /* workaround only for mt8195 */
+ xhci_mtk_set_frame_interval(mtk);
+
+ /* workaround for SoCs using SSUSB about before IPM v1.6.0 */
+ xhci_mtk_rxfifo_depth_set(mtk);
+}
+
static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk)
{
struct mu3c_ippc_regs __iomem *ippc = mtk->ippc_regs;
@@ -448,8 +483,7 @@ static int xhci_mtk_setup(struct usb_hcd *hcd)
if (ret)
return ret;
- /* workaround only for mt8195 */
- xhci_mtk_set_frame_interval(mtk);
+ xhci_mtk_init_quirk(mtk);
}
ret = xhci_gen_setup(hcd, xhci_mtk_quirks);
@@ -527,6 +561,8 @@ static int xhci_mtk_probe(struct platform_device *pdev)
of_property_read_u32(node, "mediatek,u2p-dis-msk",
&mtk->u2p_dis_msk);
+ of_property_read_u32(node, "rx-fifo-depth", &mtk->rxfifo_depth);
+
ret = usb_wakeup_of_property_parse(mtk, node);
if (ret) {
dev_err(dev, "failed to parse uwk property\n");
diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h
index 39f7ae7d3087..f5e2bd66bb1b 100644
--- a/drivers/usb/host/xhci-mtk.h
+++ b/drivers/usb/host/xhci-mtk.h
@@ -171,6 +171,8 @@ struct xhci_hcd_mtk {
struct regmap *uwk;
u32 uwk_reg_base;
u32 uwk_vers;
+ /* quirk */
+ u32 rxfifo_depth;
};
static inline struct xhci_hcd_mtk *hcd_to_mtk(struct usb_hcd *hcd)
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index d6fc08e5db8f..b534ca9752be 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -95,10 +95,9 @@ static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
if (hcd->msix_enabled) {
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
- int i;
- for (i = 0; i < xhci->msix_count; i++)
- synchronize_irq(pci_irq_vector(pdev, i));
+ /* for now, the driver only supports one primary interrupter */
+ synchronize_irq(pci_irq_vector(pdev, 0));
}
}
@@ -112,100 +111,18 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci)
if (hcd->irq > 0)
return;
- if (hcd->msix_enabled) {
- int i;
-
- for (i = 0; i < xhci->msix_count; i++)
- free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci));
- } else {
- free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci));
- }
-
+ free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci));
pci_free_irq_vectors(pdev);
hcd->msix_enabled = 0;
}
-/*
- * Set up MSI
- */
-static int xhci_setup_msi(struct xhci_hcd *xhci)
-{
- int ret;
- /*
- * TODO:Check with MSI Soc for sysdev
- */
- struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
-
- ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
- if (ret < 0) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "failed to allocate MSI entry");
- return ret;
- }
-
- ret = request_irq(pdev->irq, xhci_msi_irq,
- 0, "xhci_hcd", xhci_to_hcd(xhci));
- if (ret) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "disable MSI interrupt");
- pci_free_irq_vectors(pdev);
- }
-
- return ret;
-}
-
-/*
- * Set up MSI-X
- */
-static int xhci_setup_msix(struct xhci_hcd *xhci)
-{
- int i, ret;
- struct usb_hcd *hcd = xhci_to_hcd(xhci);
- struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
-
- /*
- * calculate number of msi-x vectors supported.
- * - HCS_MAX_INTRS: the max number of interrupts the host can handle,
- * with max number of interrupters based on the xhci HCSPARAMS1.
- * - num_online_cpus: maximum msi-x vectors per CPUs core.
- * Add additional 1 vector to ensure always available interrupt.
- */
- xhci->msix_count = min(num_online_cpus() + 1,
- HCS_MAX_INTRS(xhci->hcs_params1));
-
- ret = pci_alloc_irq_vectors(pdev, xhci->msix_count, xhci->msix_count,
- PCI_IRQ_MSIX);
- if (ret < 0) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_init,
- "Failed to enable MSI-X");
- return ret;
- }
-
- for (i = 0; i < xhci->msix_count; i++) {
- ret = request_irq(pci_irq_vector(pdev, i), xhci_msi_irq, 0,
- "xhci_hcd", xhci_to_hcd(xhci));
- if (ret)
- goto disable_msix;
- }
-
- hcd->msix_enabled = 1;
- return ret;
-
-disable_msix:
- xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt");
- while (--i >= 0)
- free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci));
- pci_free_irq_vectors(pdev);
- return ret;
-}
-
+/* Try enabling MSI-X with MSI and legacy IRQ as fallback */
static int xhci_try_enable_msi(struct usb_hcd *hcd)
{
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- struct pci_dev *pdev;
int ret;
- pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
/*
* Some Fresco Logic host controllers advertise MSI, but fail to
* generate interrupts. Don't even try to enable MSI.
@@ -218,32 +135,53 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)
free_irq(hcd->irq, hcd);
hcd->irq = 0;
- ret = xhci_setup_msix(xhci);
- if (ret)
- /* fall back to msi*/
- ret = xhci_setup_msi(xhci);
+ /*
+ * calculate number of MSI-X vectors supported.
+ * - HCS_MAX_INTRS: the max number of interrupts the host can handle,
+ * with max number of interrupters based on the xhci HCSPARAMS1.
+ * - num_online_cpus: maximum MSI-X vectors per CPUs core.
+ * Add additional 1 vector to ensure always available interrupt.
+ */
+ xhci->nvecs = min(num_online_cpus() + 1,
+ HCS_MAX_INTRS(xhci->hcs_params1));
- if (!ret) {
- hcd->msi_enabled = 1;
- return 0;
+ /* TODO: Check with MSI Soc for sysdev */
+ xhci->nvecs = pci_alloc_irq_vectors(pdev, 1, xhci->nvecs,
+ PCI_IRQ_MSIX | PCI_IRQ_MSI);
+ if (xhci->nvecs < 0) {
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "failed to allocate IRQ vectors");
+ goto legacy_irq;
}
+ ret = request_irq(pci_irq_vector(pdev, 0), xhci_msi_irq, 0, "xhci_hcd",
+ xhci_to_hcd(xhci));
+ if (ret)
+ goto free_irq_vectors;
+
+ hcd->msi_enabled = 1;
+ hcd->msix_enabled = pdev->msix_enabled;
+ return 0;
+
+free_irq_vectors:
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable %s interrupt",
+ pdev->msix_enabled ? "MSI-X" : "MSI");
+ pci_free_irq_vectors(pdev);
+
+legacy_irq:
if (!pdev->irq) {
xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n");
return -EINVAL;
}
- legacy_irq:
if (!strlen(hcd->irq_descr))
snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
hcd->driver->description, hcd->self.busnum);
- /* fall back to legacy interrupt*/
- ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
- hcd->irq_descr, hcd);
+ /* fall back to legacy interrupt */
+ ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, hcd->irq_descr, hcd);
if (ret) {
- xhci_err(xhci, "request interrupt %d failed\n",
- pdev->irq);
+ xhci_err(xhci, "request interrupt %d failed\n", pdev->irq);
return ret;
}
hcd->irq = pdev->irq;
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 732cdeb73920..f04fde19f551 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -131,6 +131,9 @@ static const struct of_device_id usb_xhci_of_match[] = {
.compatible = "brcm,xhci-brcm-v2",
.data = &xhci_plat_brcm,
}, {
+ .compatible = "brcm,bcm2711-xhci",
+ .data = &xhci_plat_brcm,
+ }, {
.compatible = "brcm,bcm7445-xhci",
.data = &xhci_plat_brcm,
},
@@ -433,7 +436,7 @@ void xhci_plat_remove(struct platform_device *dev)
}
EXPORT_SYMBOL_GPL(xhci_plat_remove);
-static int __maybe_unused xhci_plat_suspend(struct device *dev)
+static int xhci_plat_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -461,7 +464,7 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused xhci_plat_resume(struct device *dev)
+static int xhci_plat_resume_common(struct device *dev, struct pm_message pmsg)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -483,7 +486,7 @@ static int __maybe_unused xhci_plat_resume(struct device *dev)
if (ret)
goto disable_clks;
- ret = xhci_resume(xhci, PMSG_RESUME);
+ ret = xhci_resume(xhci, pmsg);
if (ret)
goto disable_clks;
@@ -502,6 +505,16 @@ disable_clks:
return ret;
}
+static int xhci_plat_resume(struct device *dev)
+{
+ return xhci_plat_resume_common(dev, PMSG_RESUME);
+}
+
+static int xhci_plat_restore(struct device *dev)
+{
+ return xhci_plat_resume_common(dev, PMSG_RESTORE);
+}
+
static int __maybe_unused xhci_plat_runtime_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
@@ -524,7 +537,12 @@ static int __maybe_unused xhci_plat_runtime_resume(struct device *dev)
}
const struct dev_pm_ops xhci_plat_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume)
+ .suspend = pm_sleep_ptr(xhci_plat_suspend),
+ .resume = pm_sleep_ptr(xhci_plat_resume),
+ .freeze = pm_sleep_ptr(xhci_plat_suspend),
+ .thaw = pm_sleep_ptr(xhci_plat_resume),
+ .poweroff = pm_sleep_ptr(xhci_plat_suspend),
+ .restore = pm_sleep_ptr(xhci_plat_restore),
SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend,
xhci_plat_runtime_resume,
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index f3b5e6345858..33806ae966f9 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -366,9 +366,10 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
readl(&xhci->dba->doorbell[0]);
}
-static bool xhci_mod_cmd_timer(struct xhci_hcd *xhci, unsigned long delay)
+static bool xhci_mod_cmd_timer(struct xhci_hcd *xhci)
{
- return mod_delayed_work(system_wq, &xhci->cmd_timer, delay);
+ return mod_delayed_work(system_wq, &xhci->cmd_timer,
+ msecs_to_jiffies(xhci->current_cmd->timeout_ms));
}
static struct xhci_command *xhci_next_queued_cmd(struct xhci_hcd *xhci)
@@ -412,7 +413,7 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci,
if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) &&
!(xhci->xhc_state & XHCI_STATE_DYING)) {
xhci->current_cmd = cur_cmd;
- xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
+ xhci_mod_cmd_timer(xhci);
xhci_ring_cmd_db(xhci);
}
}
@@ -1787,7 +1788,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
if (!list_is_singular(&xhci->cmd_list)) {
xhci->current_cmd = list_first_entry(&cmd->cmd_list,
struct xhci_command, cmd_list);
- xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
+ xhci_mod_cmd_timer(xhci);
} else if (xhci->current_cmd == cmd) {
xhci->current_cmd = NULL;
}
@@ -3060,7 +3061,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
writel(status, &xhci->op_regs->status);
/* This is the handler of the primary interrupter */
- ir = xhci->interrupter;
+ ir = xhci->interrupters[0];
if (!hcd->msi_enabled) {
u32 irq_pending;
irq_pending = readl(&ir->ir_set->irq_pending);
@@ -4287,7 +4288,7 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
/* if there are no other commands queued we start the timeout timer */
if (list_empty(&xhci->cmd_list)) {
xhci->current_cmd = cmd;
- xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT);
+ xhci_mod_cmd_timer(xhci);
}
list_add_tail(&cmd->cmd_list, &xhci->cmd_list);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 884b0898d9c9..c057c42c36f4 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -480,7 +480,7 @@ static int xhci_init(struct usb_hcd *hcd)
static int xhci_run_finished(struct xhci_hcd *xhci)
{
- struct xhci_interrupter *ir = xhci->interrupter;
+ struct xhci_interrupter *ir = xhci->interrupters[0];
unsigned long flags;
u32 temp;
@@ -532,7 +532,7 @@ int xhci_run(struct usb_hcd *hcd)
u64 temp_64;
int ret;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- struct xhci_interrupter *ir = xhci->interrupter;
+ struct xhci_interrupter *ir = xhci->interrupters[0];
/* Start the xHCI host controller running only after the USB 2.0 roothub
* is setup.
*/
@@ -596,7 +596,7 @@ void xhci_stop(struct usb_hcd *hcd)
{
u32 temp;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- struct xhci_interrupter *ir = xhci->interrupter;
+ struct xhci_interrupter *ir = xhci->interrupters[0];
mutex_lock(&xhci->mutex);
@@ -692,36 +692,51 @@ EXPORT_SYMBOL_GPL(xhci_shutdown);
#ifdef CONFIG_PM
static void xhci_save_registers(struct xhci_hcd *xhci)
{
- struct xhci_interrupter *ir = xhci->interrupter;
+ struct xhci_interrupter *ir;
+ unsigned int i;
xhci->s3.command = readl(&xhci->op_regs->command);
xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification);
xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
xhci->s3.config_reg = readl(&xhci->op_regs->config_reg);
- if (!ir)
- return;
+ /* save both primary and all secondary interrupters */
+ /* fixme, shold we lock to prevent race with remove secondary interrupter? */
+ for (i = 0; i < xhci->max_interrupters; i++) {
+ ir = xhci->interrupters[i];
+ if (!ir)
+ continue;
- ir->s3_erst_size = readl(&ir->ir_set->erst_size);
- ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
- ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
- ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
- ir->s3_irq_control = readl(&ir->ir_set->irq_control);
+ ir->s3_erst_size = readl(&ir->ir_set->erst_size);
+ ir->s3_erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
+ ir->s3_erst_dequeue = xhci_read_64(xhci, &ir->ir_set->erst_dequeue);
+ ir->s3_irq_pending = readl(&ir->ir_set->irq_pending);
+ ir->s3_irq_control = readl(&ir->ir_set->irq_control);
+ }
}
static void xhci_restore_registers(struct xhci_hcd *xhci)
{
- struct xhci_interrupter *ir = xhci->interrupter;
+ struct xhci_interrupter *ir;
+ unsigned int i;
writel(xhci->s3.command, &xhci->op_regs->command);
writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
writel(xhci->s3.config_reg, &xhci->op_regs->config_reg);
- writel(ir->s3_erst_size, &ir->ir_set->erst_size);
- xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
- xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
- writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
- writel(ir->s3_irq_control, &ir->ir_set->irq_control);
+
+ /* FIXME should we lock to protect against freeing of interrupters */
+ for (i = 0; i < xhci->max_interrupters; i++) {
+ ir = xhci->interrupters[i];
+ if (!ir)
+ continue;
+
+ writel(ir->s3_erst_size, &ir->ir_set->erst_size);
+ xhci_write_64(xhci, ir->s3_erst_base, &ir->ir_set->erst_base);
+ xhci_write_64(xhci, ir->s3_erst_dequeue, &ir->ir_set->erst_dequeue);
+ writel(ir->s3_irq_pending, &ir->ir_set->irq_pending);
+ writel(ir->s3_irq_control, &ir->ir_set->irq_control);
+ }
}
static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
@@ -1084,7 +1099,7 @@ int xhci_resume(struct xhci_hcd *xhci, pm_message_t msg)
xhci_dbg(xhci, "// Disabling event ring interrupts\n");
temp = readl(&xhci->op_regs->status);
writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
- xhci_disable_interrupter(xhci->interrupter);
+ xhci_disable_interrupter(xhci->interrupters[0]);
xhci_dbg(xhci, "cleaning up memory\n");
xhci_mem_cleanup(xhci);
@@ -1438,10 +1453,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
* descriptor. If the usb_device's max packet size changes after that point,
* we need to issue an evaluate context command and wait on it.
*/
-static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
- unsigned int ep_index, struct urb *urb, gfp_t mem_flags)
+static int xhci_check_ep0_maxpacket(struct xhci_hcd *xhci, struct xhci_virt_device *vdev)
{
- struct xhci_container_ctx *out_ctx;
struct xhci_input_control_ctx *ctrl_ctx;
struct xhci_ep_ctx *ep_ctx;
struct xhci_command *command;
@@ -1449,11 +1462,15 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
int hw_max_packet_size;
int ret = 0;
- out_ctx = xhci->devs[slot_id]->out_ctx;
- ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
+ ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, 0);
hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
- max_packet_size = usb_endpoint_maxp(&urb->dev->ep0.desc);
- if (hw_max_packet_size != max_packet_size) {
+ max_packet_size = usb_endpoint_maxp(&vdev->udev->ep0.desc);
+
+ if (hw_max_packet_size == max_packet_size)
+ return 0;
+
+ switch (max_packet_size) {
+ case 8: case 16: case 32: case 64: case 9:
xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
"Max Packet Size for ep 0 changed.");
xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
@@ -1465,28 +1482,22 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
xhci_dbg_trace(xhci, trace_xhci_dbg_context_change,
"Issuing evaluate context command.");
- /* Set up the input context flags for the command */
- /* FIXME: This won't work if a non-default control endpoint
- * changes max packet sizes.
- */
-
- command = xhci_alloc_command(xhci, true, mem_flags);
+ command = xhci_alloc_command(xhci, true, GFP_KERNEL);
if (!command)
return -ENOMEM;
- command->in_ctx = xhci->devs[slot_id]->in_ctx;
+ command->in_ctx = vdev->in_ctx;
ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__);
ret = -ENOMEM;
- goto command_cleanup;
+ break;
}
/* Set up the modified control endpoint 0 */
- xhci_endpoint_copy(xhci, xhci->devs[slot_id]->in_ctx,
- xhci->devs[slot_id]->out_ctx, ep_index);
+ xhci_endpoint_copy(xhci, vdev->in_ctx, vdev->out_ctx, 0);
- ep_ctx = xhci_get_ep_ctx(xhci, command->in_ctx, ep_index);
+ ep_ctx = xhci_get_ep_ctx(xhci, command->in_ctx, 0);
ep_ctx->ep_info &= cpu_to_le32(~EP_STATE_MASK);/* must clear */
ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET_MASK);
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size));
@@ -1494,17 +1505,20 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
ctrl_ctx->add_flags = cpu_to_le32(EP0_FLAG);
ctrl_ctx->drop_flags = 0;
- ret = xhci_configure_endpoint(xhci, urb->dev, command,
- true, false);
-
- /* Clean up the input context for later use by bandwidth
- * functions.
- */
+ ret = xhci_configure_endpoint(xhci, vdev->udev, command,
+ true, false);
+ /* Clean up the input context for later use by bandwidth functions */
ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG);
-command_cleanup:
- kfree(command->completion);
- kfree(command);
+ break;
+ default:
+ dev_dbg(&vdev->udev->dev, "incorrect max packet size %d for ep0\n",
+ max_packet_size);
+ return -EINVAL;
}
+
+ kfree(command->completion);
+ kfree(command);
+
return ret;
}
@@ -1522,24 +1536,7 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
struct urb_priv *urb_priv;
int num_tds;
- if (!urb)
- return -EINVAL;
- ret = xhci_check_args(hcd, urb->dev, urb->ep,
- true, true, __func__);
- if (ret <= 0)
- return ret ? ret : -EINVAL;
-
- slot_id = urb->dev->slot_id;
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
- ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state;
-
- if (!HCD_HW_ACCESSIBLE(hcd))
- return -ESHUTDOWN;
-
- if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) {
- xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n");
- return -ENODEV;
- }
if (usb_endpoint_xfer_isoc(&urb->ep->desc))
num_tds = urb->number_of_packets;
@@ -1561,22 +1558,27 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
trace_xhci_urb_enqueue(urb);
- if (usb_endpoint_xfer_control(&urb->ep->desc)) {
- /* Check to see if the max packet size for the default control
- * endpoint changed during FS device enumeration
- */
- if (urb->dev->speed == USB_SPEED_FULL) {
- ret = xhci_check_maxpacket(xhci, slot_id,
- ep_index, urb, mem_flags);
- if (ret < 0) {
- xhci_urb_free_priv(urb_priv);
- urb->hcpriv = NULL;
- return ret;
- }
- }
+ spin_lock_irqsave(&xhci->lock, flags);
+
+ ret = xhci_check_args(hcd, urb->dev, urb->ep,
+ true, true, __func__);
+ if (ret <= 0) {
+ ret = ret ? ret : -EINVAL;
+ goto free_priv;
}
- spin_lock_irqsave(&xhci->lock, flags);
+ slot_id = urb->dev->slot_id;
+
+ if (!HCD_HW_ACCESSIBLE(hcd)) {
+ ret = -ESHUTDOWN;
+ goto free_priv;
+ }
+
+ if (xhci->devs[slot_id]->flags & VDEV_PORT_ERROR) {
+ xhci_dbg(xhci, "Can't queue urb, port error, link inactive\n");
+ ret = -ENODEV;
+ goto free_priv;
+ }
if (xhci->xhc_state & XHCI_STATE_DYING) {
xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for non-responsive xHCI host.\n",
@@ -1584,6 +1586,9 @@ static int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag
ret = -ESHUTDOWN;
goto free_priv;
}
+
+ ep_state = &xhci->devs[slot_id]->eps[ep_index].ep_state;
+
if (*ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) {
xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n",
*ep_state);
@@ -3087,6 +3092,9 @@ done:
* of an endpoint that isn't in the halted state this function will issue a
* configure endpoint command with the Drop and Add bits set for the target
* endpoint. Refer to the additional note in xhci spcification section 4.6.8.
+ *
+ * vdev may be lost due to xHC restore error and re-initialization during S3/S4
+ * resume. A new vdev will be allocated later by xhci_discover_or_reset_device()
*/
static void xhci_endpoint_reset(struct usb_hcd *hcd,
@@ -3104,19 +3112,37 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
int err;
xhci = hcd_to_xhci(hcd);
+ ep_index = xhci_get_endpoint_index(&host_ep->desc);
+
+ /*
+ * Usb core assumes a max packet value for ep0 on FS devices until the
+ * real value is read from the descriptor. Core resets Ep0 if values
+ * mismatch. Reconfigure the xhci ep0 endpoint context here in that case
+ */
+ if (usb_endpoint_xfer_control(&host_ep->desc) && ep_index == 0) {
+
+ udev = container_of(host_ep, struct usb_device, ep0);
+ if (udev->speed != USB_SPEED_FULL || !udev->slot_id)
+ return;
+
+ vdev = xhci->devs[udev->slot_id];
+ if (!vdev || vdev->udev != udev)
+ return;
+
+ xhci_check_ep0_maxpacket(xhci, vdev);
+
+ /* Nothing else should be done here for ep0 during ep reset */
+ return;
+ }
+
if (!host_ep->hcpriv)
return;
udev = (struct usb_device *) host_ep->hcpriv;
vdev = xhci->devs[udev->slot_id];
- /*
- * vdev may be lost due to xHC restore error and re-initialization
- * during S3/S4 resume. A new vdev will be allocated later by
- * xhci_discover_or_reset_device()
- */
if (!udev->slot_id || !vdev)
return;
- ep_index = xhci_get_endpoint_index(&host_ep->desc);
+
ep = &vdev->eps[ep_index];
/* Bail out if toggle is already being cleared by a endpoint reset */
@@ -4029,12 +4055,18 @@ disable_slot:
return 0;
}
-/*
- * Issue an Address Device command and optionally send a corresponding
- * SetAddress request to the device.
+/**
+ * xhci_setup_device - issues an Address Device command to assign a unique
+ * USB bus address.
+ * @hcd: USB host controller data structure.
+ * @udev: USB dev structure representing the connected device.
+ * @setup: Enum specifying setup mode: address only or with context.
+ * @timeout_ms: Max wait time (ms) for the command operation to complete.
+ *
+ * Return: 0 if successful; otherwise, negative error code.
*/
static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
- enum xhci_setup_dev setup)
+ enum xhci_setup_dev setup, unsigned int timeout_ms)
{
const char *act = setup == SETUP_CONTEXT_ONLY ? "context" : "address";
unsigned long flags;
@@ -4091,6 +4123,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
}
command->in_ctx = virt_dev->in_ctx;
+ command->timeout_ms = timeout_ms;
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
@@ -4217,14 +4250,16 @@ out:
return ret;
}
-static int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
+static int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev,
+ unsigned int timeout_ms)
{
- return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS);
+ return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS, timeout_ms);
}
static int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev)
{
- return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ONLY);
+ return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ONLY,
+ XHCI_CMD_DEFAULT_TIMEOUT);
}
/*
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 3ea5c092bba7..a5c72a634e6a 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -791,6 +791,8 @@ struct xhci_command {
struct completion *completion;
union xhci_trb *command_trb;
struct list_head cmd_list;
+ /* xHCI command response timeout in milliseconds */
+ unsigned int timeout_ms;
};
/* drop context bitmasks */
@@ -1550,8 +1552,11 @@ struct xhci_td {
unsigned int num_trbs;
};
-/* xHCI command default timeout value */
-#define XHCI_CMD_DEFAULT_TIMEOUT (5 * HZ)
+/*
+ * xHCI command default timeout value in milliseconds.
+ * USB 3.2 spec, section 9.2.6.1
+ */
+#define XHCI_CMD_DEFAULT_TIMEOUT 5000
/* command descriptor */
struct xhci_cd {
@@ -1760,8 +1765,8 @@ struct xhci_hcd {
int page_size;
/* Valid values are 12 to 20, inclusive */
int page_shift;
- /* msi-x vectors */
- int msix_count;
+ /* MSI-X/MSI vectors */
+ int nvecs;
/* optional clocks */
struct clk *clk;
struct clk *reg_clk;
@@ -1769,7 +1774,7 @@ struct xhci_hcd {
struct reset_control *reset;
/* data structures */
struct xhci_device_context_array *dcbaa;
- struct xhci_interrupter *interrupter;
+ struct xhci_interrupter **interrupters;
struct xhci_ring *cmd_ring;
unsigned int cmd_ring_state;
#define CMD_RING_STATE_RUNNING (1 << 0)
@@ -2080,6 +2085,10 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
int type, gfp_t flags);
void xhci_free_container_ctx(struct xhci_hcd *xhci,
struct xhci_container_ctx *ctx);
+struct xhci_interrupter *
+xhci_create_secondary_interrupter(struct usb_hcd *hcd, int num_seg);
+void xhci_remove_secondary_interrupter(struct usb_hcd
+ *hcd, struct xhci_interrupter *ir);
/* xHCI host controller glue */
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 1e3df27bab58..6d28467ce352 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -501,7 +501,6 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
dev->minor, cmd, arg);
retval = 0;
- io_res = 0;
switch (cmd) {
case IOW_WRITE:
if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 ||
diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c
index 2b45404e9732..0dd2b032c90b 100644
--- a/drivers/usb/misc/onboard_usb_hub.c
+++ b/drivers/usb/misc/onboard_usb_hub.c
@@ -5,8 +5,10 @@
* Copyright (c) 2022, Google LLC
*/
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/export.h>
+#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -60,15 +62,22 @@ struct onboard_hub {
bool going_away;
struct list_head udev_list;
struct mutex lock;
+ struct clk *clk;
};
static int onboard_hub_power_on(struct onboard_hub *hub)
{
int err;
+ err = clk_prepare_enable(hub->clk);
+ if (err) {
+ dev_err(hub->dev, "failed to enable clock: %pe\n", ERR_PTR(err));
+ return err;
+ }
+
err = regulator_bulk_enable(hub->pdata->num_supplies, hub->supplies);
if (err) {
- dev_err(hub->dev, "failed to enable supplies: %d\n", err);
+ dev_err(hub->dev, "failed to enable supplies: %pe\n", ERR_PTR(err));
return err;
}
@@ -88,10 +97,12 @@ static int onboard_hub_power_off(struct onboard_hub *hub)
err = regulator_bulk_disable(hub->pdata->num_supplies, hub->supplies);
if (err) {
- dev_err(hub->dev, "failed to disable supplies: %d\n", err);
+ dev_err(hub->dev, "failed to disable supplies: %pe\n", ERR_PTR(err));
return err;
}
+ clk_disable_unprepare(hub->clk);
+
hub->is_powered_on = false;
return 0;
@@ -233,9 +244,9 @@ static void onboard_hub_attach_usb_driver(struct work_struct *work)
{
int err;
- err = driver_attach(&onboard_hub_usbdev_driver.drvwrap.driver);
+ err = driver_attach(&onboard_hub_usbdev_driver.driver);
if (err)
- pr_err("Failed to attach USB driver: %d\n", err);
+ pr_err("Failed to attach USB driver: %pe\n", ERR_PTR(err));
}
static int onboard_hub_probe(struct platform_device *pdev)
@@ -262,10 +273,14 @@ static int onboard_hub_probe(struct platform_device *pdev)
err = devm_regulator_bulk_get(dev, hub->pdata->num_supplies, hub->supplies);
if (err) {
- dev_err(dev, "Failed to get regulator supplies: %d\n", err);
+ dev_err(dev, "Failed to get regulator supplies: %pe\n", ERR_PTR(err));
return err;
}
+ hub->clk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(hub->clk))
+ return dev_err_probe(dev, PTR_ERR(hub->clk), "failed to get clock\n");
+
hub->reset_gpio = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(hub->reset_gpio))
@@ -426,6 +441,7 @@ static void onboard_hub_usbdev_disconnect(struct usb_device *udev)
static const struct usb_device_id onboard_hub_id_table[] = {
{ USB_DEVICE(VENDOR_ID_CYPRESS, 0x6504) }, /* CYUSB33{0,1,2}x/CYUSB230x 3.0 */
{ USB_DEVICE(VENDOR_ID_CYPRESS, 0x6506) }, /* CYUSB33{0,1,2}x/CYUSB230x 2.0 */
+ { USB_DEVICE(VENDOR_ID_CYPRESS, 0x6570) }, /* CY7C6563x 2.0 */
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0608) }, /* Genesys Logic GL850G USB 2.0 */
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0610) }, /* Genesys Logic GL852G USB 2.0 */
{ USB_DEVICE(VENDOR_ID_GENESYS, 0x0620) }, /* Genesys Logic GL3523 USB 3.1 */
diff --git a/drivers/usb/misc/onboard_usb_hub.h b/drivers/usb/misc/onboard_usb_hub.h
index 292110e64a1d..f360d5cf8d8a 100644
--- a/drivers/usb/misc/onboard_usb_hub.h
+++ b/drivers/usb/misc/onboard_usb_hub.h
@@ -36,6 +36,11 @@ static const struct onboard_hub_pdata cypress_hx3_data = {
.num_supplies = 2,
};
+static const struct onboard_hub_pdata cypress_hx2vl_data = {
+ .reset_us = 1,
+ .num_supplies = 1,
+};
+
static const struct onboard_hub_pdata genesys_gl850g_data = {
.reset_us = 3,
.num_supplies = 1,
@@ -61,6 +66,7 @@ static const struct of_device_id onboard_hub_match[] = {
{ .compatible = "usb451,8142", .data = &ti_tusb8041_data, },
{ .compatible = "usb4b4,6504", .data = &cypress_hx3_data, },
{ .compatible = "usb4b4,6506", .data = &cypress_hx3_data, },
+ { .compatible = "usb4b4,6570", .data = &cypress_hx2vl_data, },
{ .compatible = "usb5e3,608", .data = &genesys_gl850g_data, },
{ .compatible = "usb5e3,610", .data = &genesys_gl852g_data, },
{ .compatible = "usb5e3,620", .data = &genesys_gl852g_data, },
diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c
index 7f371ea1248c..26e9b8749d8a 100644
--- a/drivers/usb/misc/qcom_eud.c
+++ b/drivers/usb/misc/qcom_eud.c
@@ -205,6 +205,9 @@ static int eud_probe(struct platform_device *pdev)
return PTR_ERR(chip->mode_mgr);
chip->irq = platform_get_irq(pdev, 0);
+ if (chip->irq < 0)
+ return chip->irq;
+
ret = devm_request_threaded_irq(&pdev->dev, chip->irq, handle_eud_irq,
handle_eud_irq_thread, IRQF_ONESHOT, NULL, chip);
if (ret)
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index c640f98d20c5..9a0649d23693 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -34,6 +34,8 @@
#define YUREX_BUF_SIZE 8
#define YUREX_WRITE_TIMEOUT (HZ*2)
+#define MAX_S64_STRLEN 20 /* {-}922337203685477580{7,8} */
+
/* table of devices that work with this driver */
static struct usb_device_id yurex_table[] = {
{ USB_DEVICE(YUREX_VENDOR_ID, YUREX_PRODUCT_ID) },
@@ -401,7 +403,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
{
struct usb_yurex *dev;
int len = 0;
- char in_buffer[20];
+ char in_buffer[MAX_S64_STRLEN];
unsigned long flags;
dev = file->private_data;
@@ -412,14 +414,16 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
return -ENODEV;
}
+ if (WARN_ON_ONCE(dev->bbu > S64_MAX || dev->bbu < S64_MIN)) {
+ mutex_unlock(&dev->io_mutex);
+ return -EIO;
+ }
+
spin_lock_irqsave(&dev->lock, flags);
- len = snprintf(in_buffer, 20, "%lld\n", dev->bbu);
+ scnprintf(in_buffer, MAX_S64_STRLEN, "%lld\n", dev->bbu);
spin_unlock_irqrestore(&dev->lock, flags);
mutex_unlock(&dev->io_mutex);
- if (WARN_ON_ONCE(len >= sizeof(in_buffer)))
- return -EIO;
-
return simple_read_from_buffer(buffer, count, ppos, in_buffer, len);
}
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index 9ca9305243fe..4e30de4db1c0 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -1250,14 +1250,19 @@ static vm_fault_t mon_bin_vma_fault(struct vm_fault *vmf)
struct mon_reader_bin *rp = vmf->vma->vm_private_data;
unsigned long offset, chunk_idx;
struct page *pageptr;
+ unsigned long flags;
+ spin_lock_irqsave(&rp->b_lock, flags);
offset = vmf->pgoff << PAGE_SHIFT;
- if (offset >= rp->b_size)
+ if (offset >= rp->b_size) {
+ spin_unlock_irqrestore(&rp->b_lock, flags);
return VM_FAULT_SIGBUS;
+ }
chunk_idx = offset / CHUNK_SIZE;
pageptr = rp->b_vec[chunk_idx].pg;
get_page(pageptr);
vmf->page = pageptr;
+ spin_unlock_irqrestore(&rp->b_lock, flags);
return 0;
}
diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c
index 98ab0cc473d6..3c23805ab1a4 100644
--- a/drivers/usb/mon/mon_stat.c
+++ b/drivers/usb/mon/mon_stat.c
@@ -35,9 +35,9 @@ static int mon_stat_open(struct inode *inode, struct file *file)
mbus = inode->i_private;
- sp->slen = snprintf(sp->str, STAT_BUF_SIZE,
- "nreaders %d events %u text_lost %u\n",
- mbus->nreaders, mbus->cnt_events, mbus->cnt_text_lost);
+ sp->slen = scnprintf(sp->str, STAT_BUF_SIZE,
+ "nreaders %d events %u text_lost %u\n",
+ mbus->nreaders, mbus->cnt_events, mbus->cnt_text_lost);
file->private_data = sp;
return 0;
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 39cb14164652..2fe9b95bac1d 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -352,7 +352,7 @@ static int mon_text_open(struct inode *inode, struct file *file)
rp->r.rnf_error = mon_text_error;
rp->r.rnf_complete = mon_text_complete;
- snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp);
+ scnprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp);
rp->e_slab = kmem_cache_create(rp->slab_name,
sizeof(struct mon_event_text), sizeof(long), 0,
mon_text_ctor);
@@ -700,46 +700,28 @@ static const struct file_operations mon_fops_text_u = {
int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
{
- enum { NAMESZ = 10 };
+ enum { NAMESZ = 12 };
char name[NAMESZ];
int busnum = ubus? ubus->busnum: 0;
- int rc;
if (mon_dir == NULL)
return 0;
if (ubus != NULL) {
- rc = snprintf(name, NAMESZ, "%dt", busnum);
- if (rc <= 0 || rc >= NAMESZ)
- goto err_print_t;
+ scnprintf(name, NAMESZ, "%dt", busnum);
mbus->dent_t = debugfs_create_file(name, 0600, mon_dir, mbus,
&mon_fops_text_t);
}
- rc = snprintf(name, NAMESZ, "%du", busnum);
- if (rc <= 0 || rc >= NAMESZ)
- goto err_print_u;
+ scnprintf(name, NAMESZ, "%du", busnum);
mbus->dent_u = debugfs_create_file(name, 0600, mon_dir, mbus,
&mon_fops_text_u);
- rc = snprintf(name, NAMESZ, "%ds", busnum);
- if (rc <= 0 || rc >= NAMESZ)
- goto err_print_s;
+ scnprintf(name, NAMESZ, "%ds", busnum);
mbus->dent_s = debugfs_create_file(name, 0600, mon_dir, mbus,
&mon_fops_stat);
return 1;
-
-err_print_s:
- debugfs_remove(mbus->dent_u);
- mbus->dent_u = NULL;
-err_print_u:
- if (ubus != NULL) {
- debugfs_remove(mbus->dent_t);
- mbus->dent_t = NULL;
- }
-err_print_t:
- return 0;
}
void mon_text_del(struct mon_bus *mbus)
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index 770081b828a4..9ab50f26db60 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -46,15 +46,21 @@ EXPORT_SYMBOL_GPL(usb_phy_generic_unregister);
static int nop_set_suspend(struct usb_phy *x, int suspend)
{
struct usb_phy_generic *nop = dev_get_drvdata(x->dev);
+ int ret = 0;
- if (!IS_ERR(nop->clk)) {
- if (suspend)
+ if (suspend) {
+ if (!IS_ERR(nop->clk))
clk_disable_unprepare(nop->clk);
- else
+ if (!IS_ERR(nop->vcc) && !device_may_wakeup(x->dev))
+ ret = regulator_disable(nop->vcc);
+ } else {
+ if (!IS_ERR(nop->vcc) && !device_may_wakeup(x->dev))
+ ret = regulator_enable(nop->vcc);
+ if (!IS_ERR(nop->clk))
clk_prepare_enable(nop->clk);
}
- return 0;
+ return ret;
}
static void nop_reset(struct usb_phy_generic *nop)
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index acd46b72899e..920a32cd094d 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -388,8 +388,7 @@ static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy)
{
- return IS_ENABLED(CONFIG_USB_OTG) &&
- mxs_phy->phy.last_event == USB_EVENT_ID;
+ return mxs_phy->phy.last_event == USB_EVENT_ID;
}
static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c
index c3ce6b1054f1..da09cff55abc 100644
--- a/drivers/usb/phy/phy-twl6030-usb.c
+++ b/drivers/usb/phy/phy-twl6030-usb.c
@@ -179,16 +179,16 @@ static ssize_t vbus_show(struct device *dev,
switch (twl->linkstat) {
case MUSB_VBUS_VALID:
- ret = snprintf(buf, PAGE_SIZE, "vbus\n");
+ ret = sysfs_emit(buf, "vbus\n");
break;
case MUSB_ID_GROUND:
- ret = snprintf(buf, PAGE_SIZE, "id\n");
+ ret = sysfs_emit(buf, "id\n");
break;
case MUSB_VBUS_OFF:
- ret = snprintf(buf, PAGE_SIZE, "none\n");
+ ret = sysfs_emit(buf, "none\n");
break;
default:
- ret = snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
+ ret = sysfs_emit(buf, "UNKNOWN\n");
}
spin_unlock_irqrestore(&twl->lock, flags);
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 3eb8dc3a1a8f..6c812d01b37d 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -113,7 +113,7 @@ static ssize_t new_id_store(struct device_driver *driver,
if (retval >= 0 && usb_drv->usb_driver != NULL)
retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
usb_drv->usb_driver->id_table,
- &usb_drv->usb_driver->drvwrap.driver,
+ &usb_drv->usb_driver->driver,
buf, count);
return retval;
}
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 17b09f03ef84..f1e91eb7f8a4 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1521,7 +1521,7 @@ int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[]
/* Now set udriver's id_table and look for matches */
udriver->id_table = id_table;
- rc = driver_attach(&udriver->drvwrap.driver);
+ rc = driver_attach(&udriver->driver);
return 0;
err_deregister_drivers:
diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c
index 0774ba22fb66..177fa6cd143a 100644
--- a/drivers/usb/storage/sierra_ms.c
+++ b/drivers/usb/storage/sierra_ms.c
@@ -98,26 +98,26 @@ static ssize_t truinst_show(struct device *dev, struct device_attribute *attr,
struct usb_device *udev = interface_to_usbdev(intf);
int result;
if (swi_tru_install == TRU_FORCE_MS) {
- result = snprintf(buf, PAGE_SIZE, "Forced Mass Storage\n");
+ result = sysfs_emit(buf, "Forced Mass Storage\n");
} else {
swocInfo = kmalloc(sizeof(struct swoc_info), GFP_KERNEL);
if (!swocInfo) {
- snprintf(buf, PAGE_SIZE, "Error\n");
+ sysfs_emit(buf, "Error\n");
return -ENOMEM;
}
result = sierra_get_swoc_info(udev, swocInfo);
if (result < 0) {
dev_dbg(dev, "SWIMS: failed SWoC query\n");
kfree(swocInfo);
- snprintf(buf, PAGE_SIZE, "Error\n");
+ sysfs_emit(buf, "Error\n");
return -EIO;
}
debug_swoc(dev, swocInfo);
- result = snprintf(buf, PAGE_SIZE,
- "REV=%02d SKU=%04X VER=%04X\n",
- swocInfo->rev,
- swocInfo->LinuxSKU,
- swocInfo->LinuxVer);
+ result = sysfs_emit(buf,
+ "REV=%02d SKU=%04X VER=%04X\n",
+ swocInfo->rev,
+ swocInfo->LinuxSKU,
+ swocInfo->LinuxVer);
kfree(swocInfo);
}
return result;
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 696bb0b23599..9707f53cfda9 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -1246,7 +1246,7 @@ static struct usb_driver uas_driver = {
.suspend = uas_suspend,
.resume = uas_resume,
.reset_resume = uas_reset_resume,
- .drvwrap.driver.shutdown = uas_shutdown,
+ .driver.shutdown = uas_shutdown,
.id_table = uas_usb_ids,
};
diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index 16a670828dde..015aa9253353 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -263,11 +263,13 @@ static void typec_altmode_put_partner(struct altmode *altmode)
{
struct altmode *partner = altmode->partner;
struct typec_altmode *adev;
+ struct typec_altmode *partner_adev;
if (!partner)
return;
adev = &altmode->adev;
+ partner_adev = &partner->adev;
if (is_typec_plug(adev->dev.parent)) {
struct typec_plug *plug = to_typec_plug(adev->dev.parent);
@@ -276,7 +278,7 @@ static void typec_altmode_put_partner(struct altmode *altmode)
} else {
partner->partner = NULL;
}
- put_device(&adev->dev);
+ put_device(&partner_adev->dev);
}
/**
@@ -476,7 +478,7 @@ static int altmode_id_get(struct device *dev)
else
ids = &to_typec_port(dev)->mode_ids;
- return ida_simple_get(ids, 0, 0, GFP_KERNEL);
+ return ida_alloc(ids, GFP_KERNEL);
}
static void altmode_id_remove(struct device *dev, int id)
@@ -490,7 +492,7 @@ static void altmode_id_remove(struct device *dev, int id)
else
ids = &to_typec_port(dev)->mode_ids;
- ida_simple_remove(ids, id);
+ ida_free(ids, id);
}
static void typec_altmode_release(struct device *dev)
@@ -1798,7 +1800,7 @@ static void typec_release(struct device *dev)
{
struct typec_port *port = to_typec_port(dev);
- ida_simple_remove(&typec_index_ida, port->id);
+ ida_free(&typec_index_ida, port->id);
ida_destroy(&port->mode_ids);
typec_switch_put(port->sw);
typec_mux_put(port->mux);
@@ -2231,7 +2233,8 @@ void typec_port_register_altmodes(struct typec_port *port,
struct typec_altmode_desc desc;
struct typec_altmode *alt;
size_t index = 0;
- u32 svid, vdo;
+ u16 svid;
+ u32 vdo;
int ret;
altmodes_node = device_get_named_child_node(&port->dev, "altmodes");
@@ -2239,7 +2242,7 @@ void typec_port_register_altmodes(struct typec_port *port,
return; /* No altmodes specified */
fwnode_for_each_child_node(altmodes_node, child) {
- ret = fwnode_property_read_u32(child, "svid", &svid);
+ ret = fwnode_property_read_u16(child, "svid", &svid);
if (ret) {
dev_err(&port->dev, "Error reading svid for altmode %s\n",
fwnode_get_name(child));
@@ -2297,7 +2300,7 @@ struct typec_port *typec_register_port(struct device *parent,
if (!port)
return ERR_PTR(-ENOMEM);
- id = ida_simple_get(&typec_index_ida, 0, 0, GFP_KERNEL);
+ id = ida_alloc(&typec_index_ida, GFP_KERNEL);
if (id < 0) {
kfree(port);
return ERR_PTR(id);
diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig
index 38416fb0cc3c..d2cb5e733e57 100644
--- a/drivers/usb/typec/mux/Kconfig
+++ b/drivers/usb/typec/mux/Kconfig
@@ -56,4 +56,14 @@ config TYPEC_MUX_PTN36502
Say Y or M if your system has a NXP PTN36502 Type-C redriver chip
found on some devices with a Type-C port.
+config TYPEC_MUX_WCD939X_USBSS
+ tristate "Qualcomm WCD939x USBSS Analog Audio Switch driver"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Driver for the Qualcomm WCD939x Audio Codec USBSS domain which
+ provides support for muxing analog audio and sideband signals on a
+ common USB Type-C connector.
+ If compiled as a module, the module will be named wcd939x-usbss.
+
endmenu
diff --git a/drivers/usb/typec/mux/Makefile b/drivers/usb/typec/mux/Makefile
index 9d6a5557b0bd..57dc9ac6f8dc 100644
--- a/drivers/usb/typec/mux/Makefile
+++ b/drivers/usb/typec/mux/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_TYPEC_MUX_PI3USB30532) += pi3usb30532.o
obj-$(CONFIG_TYPEC_MUX_INTEL_PMC) += intel_pmc_mux.o
obj-$(CONFIG_TYPEC_MUX_NB7VPQ904M) += nb7vpq904m.o
obj-$(CONFIG_TYPEC_MUX_PTN36502) += ptn36502.o
+obj-$(CONFIG_TYPEC_MUX_WCD939X_USBSS) += wcd939x-usbss.o
diff --git a/drivers/usb/typec/mux/wcd939x-usbss.c b/drivers/usb/typec/mux/wcd939x-usbss.c
new file mode 100644
index 000000000000..d46c353dfaf2
--- /dev/null
+++ b/drivers/usb/typec/mux/wcd939x-usbss.c
@@ -0,0 +1,779 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (C) 2023 Linaro Ltd.
+ */
+
+#include <linux/bits.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/bitfield.h>
+#include <linux/gpio/consumer.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
+
+#define WCD_USBSS_PMP_OUT1 0x2
+
+#define WCD_USBSS_DP_DN_MISC1 0x20
+
+#define WCD_USBSS_DP_DN_MISC1_DP_PCOMP_2X_DYN_BST_ON_EN BIT(3)
+#define WCD_USBSS_DP_DN_MISC1_DN_PCOMP_2X_DYN_BST_ON_EN BIT(0)
+
+#define WCD_USBSS_MG1_EN 0x24
+
+#define WCD_USBSS_MG1_EN_CT_SNS_EN BIT(1)
+
+#define WCD_USBSS_MG1_BIAS 0x25
+
+#define WCD_USBSS_MG1_BIAS_PCOMP_DYN_BST_EN BIT(3)
+
+#define WCD_USBSS_MG1_MISC 0x27
+
+#define WCD_USBSS_MG1_MISC_PCOMP_2X_DYN_BST_ON_EN BIT(5)
+
+#define WCD_USBSS_MG2_EN 0x28
+
+#define WCD_USBSS_MG2_EN_CT_SNS_EN BIT(1)
+
+#define WCD_USBSS_MG2_BIAS 0x29
+
+#define WCD_USBSS_MG2_BIAS_PCOMP_DYN_BST_EN BIT(3)
+
+#define WCD_USBSS_MG2_MISC 0x30
+
+#define WCD_USBSS_MG2_MISC_PCOMP_2X_DYN_BST_ON_EN BIT(5)
+
+#define WCD_USBSS_DISP_AUXP_THRESH 0x80
+
+#define WCD_USBSS_DISP_AUXP_THRESH_DISP_AUXP_OVPON_CM GENMASK(7, 5)
+
+#define WCD_USBSS_DISP_AUXP_CTL 0x81
+
+#define WCD_USBSS_DISP_AUXP_CTL_LK_CANCEL_TRK_COEFF GENMASK(2, 0)
+
+#define WCD_USBSS_CPLDO_CTL2 0xa1
+
+#define WCD_USBSS_SWITCH_SETTINGS_ENABLE 0x403
+
+#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DEVICE_ENABLE BIT(7)
+#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXP_TO_MGX_SWITCHES BIT(6)
+#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXM_TO_MGX_SWITCHES BIT(5)
+#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DNL_SWITCHES BIT(4)
+#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_DPR_SWITCHES BIT(3)
+#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_SENSE_SWITCHES BIT(2)
+#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_MIC_SWITCHES BIT(1)
+#define WCD_USBSS_SWITCH_SETTINGS_ENABLE_AGND_SWITCHES BIT(0)
+
+#define WCD_USBSS_SWITCH_SELECT0 0x404
+
+#define WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES BIT(7) /* 1-> MG2 */
+#define WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES BIT(6) /* 1-> MG2 */
+#define WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES GENMASK(5, 4)
+#define WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES GENMASK(3, 2)
+#define WCD_USBSS_SWITCH_SELECT0_SENSE_SWITCHES BIT(1) /* 1-> SBU2 */
+#define WCD_USBSS_SWITCH_SELECT0_MIC_SWITCHES BIT(0) /* 1-> MG2 */
+
+#define WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_L 0
+#define WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_DN 1
+#define WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_DN2 2
+
+#define WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_R 0
+#define WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_DP 1
+#define WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_DR2 2
+
+#define WCD_USBSS_SWITCH_SELECT1 0x405
+
+#define WCD_USBSS_SWITCH_SELECT1_AGND_SWITCHES BIT(0) /* 1-> MG2 */
+
+#define WCD_USBSS_DELAY_R_SW 0x40d
+#define WCD_USBSS_DELAY_MIC_SW 0x40e
+#define WCD_USBSS_DELAY_SENSE_SW 0x40f
+#define WCD_USBSS_DELAY_GND_SW 0x410
+#define WCD_USBSS_DELAY_L_SW 0x411
+
+#define WCD_USBSS_FUNCTION_ENABLE 0x413
+
+#define WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT GENMASK(1, 0)
+
+#define WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT_MANUAL 1
+#define WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT_AUDIO_FSM 2
+
+#define WCD_USBSS_EQUALIZER1 0x415
+
+#define WCD_USBSS_EQUALIZER1_EQ_EN BIT(7)
+#define WCD_USBSS_EQUALIZER1_BW_SETTINGS GENMASK(6, 3)
+
+#define WCD_USBSS_USB_SS_CNTL 0x419
+
+#define WCD_USBSS_USB_SS_CNTL_STANDBY_STATE BIT(4)
+#define WCD_USBSS_USB_SS_CNTL_RCO_EN BIT(3)
+#define WCD_USBSS_USB_SS_CNTL_USB_SS_MODE GENMASK(2, 0)
+
+#define WCD_USBSS_USB_SS_CNTL_USB_SS_MODE_AATC 2
+#define WCD_USBSS_USB_SS_CNTL_USB_SS_MODE_USB 5
+
+#define WCD_USBSS_AUDIO_FSM_START 0x433
+
+#define WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG BIT(0)
+
+#define WCD_USBSS_RATIO_SPKR_REXT_L_LSB 0x461
+#define WCD_USBSS_RATIO_SPKR_REXT_L_MSB 0x462
+#define WCD_USBSS_RATIO_SPKR_REXT_R_LSB 0x463
+#define WCD_USBSS_RATIO_SPKR_REXT_R_MSB 0x464
+#define WCD_USBSS_AUD_COEF_L_K0_0 0x475
+#define WCD_USBSS_AUD_COEF_L_K0_1 0x476
+#define WCD_USBSS_AUD_COEF_L_K0_2 0x477
+#define WCD_USBSS_AUD_COEF_L_K1_0 0x478
+#define WCD_USBSS_AUD_COEF_L_K1_1 0x479
+#define WCD_USBSS_AUD_COEF_L_K2_0 0x47a
+#define WCD_USBSS_AUD_COEF_L_K2_1 0x47b
+#define WCD_USBSS_AUD_COEF_L_K3_0 0x47c
+#define WCD_USBSS_AUD_COEF_L_K3_1 0x47d
+#define WCD_USBSS_AUD_COEF_L_K4_0 0x47e
+#define WCD_USBSS_AUD_COEF_L_K4_1 0x47f
+#define WCD_USBSS_AUD_COEF_L_K5_0 0x480
+#define WCD_USBSS_AUD_COEF_L_K5_1 0x481
+#define WCD_USBSS_AUD_COEF_R_K0_0 0x482
+#define WCD_USBSS_AUD_COEF_R_K0_1 0x483
+#define WCD_USBSS_AUD_COEF_R_K0_2 0x484
+#define WCD_USBSS_AUD_COEF_R_K1_0 0x485
+#define WCD_USBSS_AUD_COEF_R_K1_1 0x486
+#define WCD_USBSS_AUD_COEF_R_K2_0 0x487
+#define WCD_USBSS_AUD_COEF_R_K2_1 0x488
+#define WCD_USBSS_AUD_COEF_R_K3_0 0x489
+#define WCD_USBSS_AUD_COEF_R_K3_1 0x48a
+#define WCD_USBSS_AUD_COEF_R_K4_0 0x48b
+#define WCD_USBSS_AUD_COEF_R_K4_1 0x48c
+#define WCD_USBSS_AUD_COEF_R_K5_0 0x48d
+#define WCD_USBSS_AUD_COEF_R_K5_1 0x48e
+#define WCD_USBSS_GND_COEF_L_K0_0 0x48f
+#define WCD_USBSS_GND_COEF_L_K0_1 0x490
+#define WCD_USBSS_GND_COEF_L_K0_2 0x491
+#define WCD_USBSS_GND_COEF_L_K1_0 0x492
+#define WCD_USBSS_GND_COEF_L_K1_1 0x493
+#define WCD_USBSS_GND_COEF_L_K2_0 0x494
+#define WCD_USBSS_GND_COEF_L_K2_1 0x495
+#define WCD_USBSS_GND_COEF_L_K3_0 0x496
+#define WCD_USBSS_GND_COEF_L_K3_1 0x497
+#define WCD_USBSS_GND_COEF_L_K4_0 0x498
+#define WCD_USBSS_GND_COEF_L_K4_1 0x499
+#define WCD_USBSS_GND_COEF_L_K5_0 0x49a
+#define WCD_USBSS_GND_COEF_L_K5_1 0x49b
+#define WCD_USBSS_GND_COEF_R_K0_0 0x49c
+#define WCD_USBSS_GND_COEF_R_K0_1 0x49d
+#define WCD_USBSS_GND_COEF_R_K0_2 0x49e
+#define WCD_USBSS_GND_COEF_R_K1_0 0x49f
+#define WCD_USBSS_GND_COEF_R_K1_1 0x4a0
+#define WCD_USBSS_GND_COEF_R_K2_0 0x4a1
+#define WCD_USBSS_GND_COEF_R_K2_1 0x4a2
+#define WCD_USBSS_GND_COEF_R_K3_0 0x4a3
+#define WCD_USBSS_GND_COEF_R_K3_1 0x4a4
+#define WCD_USBSS_GND_COEF_R_K4_0 0x4a5
+#define WCD_USBSS_GND_COEF_R_K4_1 0x4a6
+#define WCD_USBSS_GND_COEF_R_K5_0 0x4a7
+#define WCD_USBSS_GND_COEF_R_K5_1 0x4a8
+
+#define WCD_USBSS_MAX_REGISTER 0x4c1
+
+struct wcd939x_usbss {
+ struct i2c_client *client;
+ struct gpio_desc *reset_gpio;
+ struct regulator *vdd_supply;
+
+ /* used to serialize concurrent change requests */
+ struct mutex lock;
+
+ struct typec_switch_dev *sw;
+ struct typec_mux_dev *mux;
+
+ struct regmap *regmap;
+
+ struct typec_mux *codec;
+ struct typec_switch *codec_switch;
+
+ enum typec_orientation orientation;
+ unsigned long mode;
+ unsigned int svid;
+};
+
+static const struct regmap_range_cfg wcd939x_usbss_ranges[] = {
+ {
+ .range_min = 0,
+ .range_max = WCD_USBSS_MAX_REGISTER,
+ .selector_reg = 0x0,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 0x100,
+ },
+};
+
+static const struct regmap_config wcd939x_usbss_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = WCD_USBSS_MAX_REGISTER,
+ .ranges = wcd939x_usbss_ranges,
+ .num_ranges = ARRAY_SIZE(wcd939x_usbss_ranges),
+};
+
+/* Linearlizer coefficients for 32ohm load */
+static const struct {
+ unsigned int offset;
+ unsigned int mask;
+ unsigned int value;
+} wcd939x_usbss_coeff_init[] = {
+ { WCD_USBSS_AUD_COEF_L_K5_0, GENMASK(7, 0), 0x39 },
+ { WCD_USBSS_AUD_COEF_R_K5_0, GENMASK(7, 0), 0x39 },
+ { WCD_USBSS_GND_COEF_L_K2_0, GENMASK(7, 0), 0xe8 },
+ { WCD_USBSS_GND_COEF_L_K4_0, GENMASK(7, 0), 0x73 },
+ { WCD_USBSS_GND_COEF_R_K2_0, GENMASK(7, 0), 0xe8 },
+ { WCD_USBSS_GND_COEF_R_K4_0, GENMASK(7, 0), 0x73 },
+ { WCD_USBSS_RATIO_SPKR_REXT_L_LSB, GENMASK(7, 0), 0x00 },
+ { WCD_USBSS_RATIO_SPKR_REXT_L_MSB, GENMASK(6, 0), 0x04 },
+ { WCD_USBSS_RATIO_SPKR_REXT_R_LSB, GENMASK(7, 0), 0x00 },
+ { WCD_USBSS_RATIO_SPKR_REXT_R_MSB, GENMASK(6, 0), 0x04 },
+};
+
+static int wcd939x_usbss_set(struct wcd939x_usbss *usbss)
+{
+ bool reverse = (usbss->orientation == TYPEC_ORIENTATION_REVERSE);
+ bool enable_audio = false;
+ bool enable_usb = false;
+ bool enable_dp = false;
+ int ret;
+
+ /* USB Mode */
+ if (usbss->mode < TYPEC_STATE_MODAL ||
+ (!usbss->svid && (usbss->mode == TYPEC_MODE_USB2 ||
+ usbss->mode == TYPEC_MODE_USB3))) {
+ enable_usb = true;
+ } else if (usbss->svid) {
+ switch (usbss->mode) {
+ /* DP Only */
+ case TYPEC_DP_STATE_C:
+ case TYPEC_DP_STATE_E:
+ enable_dp = true;
+ break;
+
+ /* DP + USB */
+ case TYPEC_DP_STATE_D:
+ case TYPEC_DP_STATE_F:
+ enable_usb = true;
+ enable_dp = true;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ } else if (usbss->mode == TYPEC_MODE_AUDIO) {
+ enable_audio = true;
+ } else {
+ return -EOPNOTSUPP;
+ }
+
+ /* Disable all switches */
+ ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE,
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXP_TO_MGX_SWITCHES |
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXM_TO_MGX_SWITCHES |
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_DPR_SWITCHES |
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_DNL_SWITCHES |
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_SENSE_SWITCHES |
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_MIC_SWITCHES |
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_AGND_SWITCHES);
+ if (ret)
+ return ret;
+
+ /* Clear switches */
+ ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0,
+ WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES |
+ WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES |
+ WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES |
+ WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES |
+ WCD_USBSS_SWITCH_SELECT0_SENSE_SWITCHES |
+ WCD_USBSS_SWITCH_SELECT0_MIC_SWITCHES);
+ if (ret)
+ return ret;
+
+ ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT1,
+ WCD_USBSS_SWITCH_SELECT1_AGND_SWITCHES);
+ if (ret)
+ return ret;
+
+ /* Enable OVP_MG1_BIAS PCOMP_DYN_BST_EN */
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_MG1_BIAS,
+ WCD_USBSS_MG1_BIAS_PCOMP_DYN_BST_EN);
+ if (ret)
+ return ret;
+
+ /* Enable OVP_MG2_BIAS PCOMP_DYN_BST_EN */
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_MG2_BIAS,
+ WCD_USBSS_MG2_BIAS_PCOMP_DYN_BST_EN);
+ if (ret)
+ return ret;
+
+ /* Disable Equalizer in safe mode */
+ ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_EQUALIZER1,
+ WCD_USBSS_EQUALIZER1_EQ_EN);
+ if (ret)
+ return ret;
+
+ /* Start FSM with all disabled, force write */
+ ret = regmap_write_bits(usbss->regmap, WCD_USBSS_AUDIO_FSM_START,
+ WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG,
+ WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG);
+
+ /* 35us to allow the SBU switch to turn off */
+ usleep_range(35, 1000);
+
+ /* Setup Audio Accessory mux/switch */
+ if (enable_audio) {
+ int i;
+
+ /*
+ * AATC switch configuration:
+ * "Normal":
+ * - R: DNR
+ * - L: DNL
+ * - Sense: GSBU2
+ * - Mic: MG1
+ * - AGND: MG2
+ * "Swapped":
+ * - R: DNR
+ * - L: DNL
+ * - Sense: GSBU1
+ * - Mic: MG2
+ * - AGND: MG1
+ * Swapped information is given by the codec MBHC logic
+ */
+
+ /* Set AATC mode */
+ ret = regmap_update_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL,
+ WCD_USBSS_USB_SS_CNTL_USB_SS_MODE,
+ FIELD_PREP(WCD_USBSS_USB_SS_CNTL_USB_SS_MODE,
+ WCD_USBSS_USB_SS_CNTL_USB_SS_MODE_AATC));
+ if (ret)
+ return ret;
+
+ /* Select L for DNL_SWITCHES and R for DPR_SWITCHES */
+ ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0,
+ WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES |
+ WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES,
+ FIELD_PREP(WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES,
+ WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_L) |
+ FIELD_PREP(WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES,
+ WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_R));
+ if (ret)
+ return ret;
+
+ if (reverse)
+ /* Select MG2 for MIC, SBU1 for Sense */
+ ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0,
+ WCD_USBSS_SWITCH_SELECT0_MIC_SWITCHES,
+ WCD_USBSS_SWITCH_SELECT0_MIC_SWITCHES);
+ else
+ /* Select MG1 for MIC, SBU2 for Sense */
+ ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0,
+ WCD_USBSS_SWITCH_SELECT0_SENSE_SWITCHES,
+ WCD_USBSS_SWITCH_SELECT0_SENSE_SWITCHES);
+ if (ret)
+ return ret;
+
+ if (reverse)
+ /* Disable OVP_MG1_BIAS PCOMP_DYN_BST_EN */
+ ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_MG1_BIAS,
+ WCD_USBSS_MG1_BIAS_PCOMP_DYN_BST_EN);
+ else
+ /* Disable OVP_MG2_BIAS PCOMP_DYN_BST_EN */
+ ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_MG2_BIAS,
+ WCD_USBSS_MG2_BIAS_PCOMP_DYN_BST_EN);
+ if (ret)
+ return ret;
+
+ /* Enable SENSE, MIC switches */
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE,
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_SENSE_SWITCHES |
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_MIC_SWITCHES);
+ if (ret)
+ return ret;
+
+ if (reverse)
+ /* Select MG1 for AGND_SWITCHES */
+ ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT1,
+ WCD_USBSS_SWITCH_SELECT1_AGND_SWITCHES);
+ else
+ /* Select MG2 for AGND_SWITCHES */
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT1,
+ WCD_USBSS_SWITCH_SELECT1_AGND_SWITCHES);
+ if (ret)
+ return ret;
+
+ /* Enable AGND switches */
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE,
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_AGND_SWITCHES);
+ if (ret)
+ return ret;
+
+ /* Enable DPR, DNL switches */
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE,
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_DNL_SWITCHES |
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_DPR_SWITCHES);
+ if (ret)
+ return ret;
+
+ /* Setup FSM delays */
+ ret = regmap_write(usbss->regmap, WCD_USBSS_DELAY_L_SW, 0x02);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(usbss->regmap, WCD_USBSS_DELAY_R_SW, 0x02);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(usbss->regmap, WCD_USBSS_DELAY_MIC_SW, 0x01);
+ if (ret)
+ return ret;
+
+ /* Start FSM, force write */
+ ret = regmap_write_bits(usbss->regmap, WCD_USBSS_AUDIO_FSM_START,
+ WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG,
+ WCD_USBSS_AUDIO_FSM_START_AUDIO_FSM_AUDIO_TRIG);
+ if (ret)
+ return ret;
+
+ /* Default Linearlizer coefficients */
+ for (i = 0; i < ARRAY_SIZE(wcd939x_usbss_coeff_init); ++i)
+ regmap_update_bits(usbss->regmap,
+ wcd939x_usbss_coeff_init[i].offset,
+ wcd939x_usbss_coeff_init[i].mask,
+ wcd939x_usbss_coeff_init[i].value);
+
+ return 0;
+ }
+
+ ret = regmap_update_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL,
+ WCD_USBSS_USB_SS_CNTL_USB_SS_MODE,
+ FIELD_PREP(WCD_USBSS_USB_SS_CNTL_USB_SS_MODE,
+ WCD_USBSS_USB_SS_CNTL_USB_SS_MODE_USB));
+ if (ret)
+ return ret;
+
+ /* Enable USB muxes */
+ if (enable_usb) {
+ /* Do not enable Equalizer in safe mode */
+ if (usbss->mode != TYPEC_STATE_SAFE) {
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_EQUALIZER1,
+ WCD_USBSS_EQUALIZER1_EQ_EN);
+ if (ret)
+ return ret;
+ }
+
+ /* Select DN for DNL_SWITCHES and DP for DPR_SWITCHES */
+ ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0,
+ WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES |
+ WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES,
+ FIELD_PREP(WCD_USBSS_SWITCH_SELECT0_DNL_SWITCHES,
+ WCD_USBSS_SWITCH_SELECT0_DNL_SWITCH_DN) |
+ FIELD_PREP(WCD_USBSS_SWITCH_SELECT0_DPR_SWITCHES,
+ WCD_USBSS_SWITCH_SELECT0_DPR_SWITCH_DP));
+ if (ret)
+ return ret;
+
+ /* Enable DNL_SWITCHES and DPR_SWITCHES */
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE,
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_DPR_SWITCHES |
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_DNL_SWITCHES);
+ if (ret)
+ return ret;
+ }
+
+ /* Enable DP AUX muxes */
+ if (enable_dp) {
+ /* Update Leakage Canceller Coefficient for AUXP pins */
+ ret = regmap_update_bits(usbss->regmap, WCD_USBSS_DISP_AUXP_CTL,
+ WCD_USBSS_DISP_AUXP_CTL_LK_CANCEL_TRK_COEFF,
+ FIELD_PREP(WCD_USBSS_DISP_AUXP_CTL_LK_CANCEL_TRK_COEFF,
+ 5));
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_DISP_AUXP_THRESH,
+ WCD_USBSS_DISP_AUXP_THRESH_DISP_AUXP_OVPON_CM);
+ if (ret)
+ return ret;
+
+ if (reverse)
+ /* Select MG2 for AUXP and MG1 for AUXM */
+ ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0,
+ WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES |
+ WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES,
+ WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES);
+ else
+ /* Select MG1 for AUXP and MG2 for AUXM */
+ ret = regmap_update_bits(usbss->regmap, WCD_USBSS_SWITCH_SELECT0,
+ WCD_USBSS_SWITCH_SELECT0_DP_AUXP_SWITCHES |
+ WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES,
+ WCD_USBSS_SWITCH_SELECT0_DP_AUXM_SWITCHES);
+ if (ret)
+ return ret;
+
+ /* Enable DP_AUXP_TO_MGX and DP_AUXM_TO_MGX switches */
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE,
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXP_TO_MGX_SWITCHES |
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_DP_AUXM_TO_MGX_SWITCHES);
+
+ /* 15us to allow the SBU switch to turn on again */
+ usleep_range(15, 1000);
+ }
+
+ return 0;
+}
+
+static int wcd939x_usbss_switch_set(struct typec_switch_dev *sw,
+ enum typec_orientation orientation)
+{
+ struct wcd939x_usbss *usbss = typec_switch_get_drvdata(sw);
+ int ret = 0;
+
+ mutex_lock(&usbss->lock);
+
+ if (usbss->orientation != orientation) {
+ usbss->orientation = orientation;
+
+ ret = wcd939x_usbss_set(usbss);
+ }
+
+ mutex_unlock(&usbss->lock);
+
+ if (ret)
+ return ret;
+
+ /* Report orientation to codec after switch has been done */
+ return typec_switch_set(usbss->codec_switch, orientation);
+}
+
+static int wcd939x_usbss_mux_set(struct typec_mux_dev *mux,
+ struct typec_mux_state *state)
+{
+ struct wcd939x_usbss *usbss = typec_mux_get_drvdata(mux);
+ int ret = 0;
+
+ mutex_lock(&usbss->lock);
+
+ if (usbss->mode != state->mode) {
+ usbss->mode = state->mode;
+
+ if (state->alt)
+ usbss->svid = state->alt->svid;
+ else
+ usbss->svid = 0; // No SVID
+
+ ret = wcd939x_usbss_set(usbss);
+ }
+
+ mutex_unlock(&usbss->lock);
+
+ if (ret)
+ return ret;
+
+ /* Report event to codec after switch has been done */
+ return typec_mux_set(usbss->codec, state);
+}
+
+static int wcd939x_usbss_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct typec_switch_desc sw_desc = { };
+ struct typec_mux_desc mux_desc = { };
+ struct wcd939x_usbss *usbss;
+ int ret;
+
+ usbss = devm_kzalloc(dev, sizeof(*usbss), GFP_KERNEL);
+ if (!usbss)
+ return -ENOMEM;
+
+ usbss->client = client;
+ mutex_init(&usbss->lock);
+
+ usbss->regmap = devm_regmap_init_i2c(client, &wcd939x_usbss_regmap_config);
+ if (IS_ERR(usbss->regmap))
+ return dev_err_probe(dev, PTR_ERR(usbss->regmap), "failed to initialize regmap\n");
+
+ usbss->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(usbss->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(usbss->reset_gpio),
+ "unable to acquire reset gpio\n");
+
+ usbss->vdd_supply = devm_regulator_get_optional(dev, "vdd");
+ if (IS_ERR(usbss->vdd_supply))
+ return PTR_ERR(usbss->vdd_supply);
+
+ /* Get Codec's MUX & Switch devices */
+ usbss->codec = fwnode_typec_mux_get(dev->fwnode);
+ if (IS_ERR(usbss->codec))
+ return dev_err_probe(dev, PTR_ERR(usbss->codec),
+ "failed to acquire codec mode-switch\n");
+
+ usbss->codec_switch = fwnode_typec_switch_get(dev->fwnode);
+ if (IS_ERR(usbss->codec_switch)) {
+ ret = dev_err_probe(dev, PTR_ERR(usbss->codec_switch),
+ "failed to acquire codec orientation-switch\n");
+ goto err_mux_put;
+ }
+
+ usbss->mode = TYPEC_STATE_SAFE;
+ usbss->orientation = TYPEC_ORIENTATION_NONE;
+
+ gpiod_set_value(usbss->reset_gpio, 1);
+
+ ret = regulator_enable(usbss->vdd_supply);
+ if (ret) {
+ dev_err(dev, "Failed to enable vdd: %d\n", ret);
+ goto err_mux_switch;
+ }
+
+ msleep(20);
+
+ gpiod_set_value(usbss->reset_gpio, 0);
+
+ msleep(20);
+
+ /* Disable standby */
+ ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL,
+ WCD_USBSS_USB_SS_CNTL_STANDBY_STATE);
+ if (ret)
+ goto err_regulator_disable;
+
+ /* Set manual mode by default */
+ ret = regmap_update_bits(usbss->regmap, WCD_USBSS_FUNCTION_ENABLE,
+ WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT,
+ FIELD_PREP(WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT,
+ WCD_USBSS_FUNCTION_ENABLE_SOURCE_SELECT_MANUAL));
+ if (ret)
+ goto err_regulator_disable;
+
+ /* Enable dynamic boosting for DP and DN */
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_DP_DN_MISC1,
+ WCD_USBSS_DP_DN_MISC1_DP_PCOMP_2X_DYN_BST_ON_EN |
+ WCD_USBSS_DP_DN_MISC1_DN_PCOMP_2X_DYN_BST_ON_EN);
+ if (ret)
+ goto err_regulator_disable;
+
+ /* Enable dynamic boosting for MG1 OVP */
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_MG1_MISC,
+ WCD_USBSS_MG1_MISC_PCOMP_2X_DYN_BST_ON_EN);
+ if (ret)
+ goto err_regulator_disable;
+
+ /* Enable dynamic boosting for MG2 OVP */
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_MG2_MISC,
+ WCD_USBSS_MG2_MISC_PCOMP_2X_DYN_BST_ON_EN);
+ if (ret)
+ goto err_regulator_disable;
+
+ /* Write 0xFF to WCD_USBSS_CPLDO_CTL2 */
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_CPLDO_CTL2, 0xff);
+ if (ret)
+ goto err_regulator_disable;
+
+ /* Set RCO_EN: WCD_USBSS_USB_SS_CNTL Bit<3> --> 0x0 --> 0x1 */
+ ret = regmap_clear_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL,
+ WCD_USBSS_USB_SS_CNTL_RCO_EN);
+ if (ret)
+ goto err_regulator_disable;
+
+ ret = regmap_set_bits(usbss->regmap, WCD_USBSS_USB_SS_CNTL,
+ WCD_USBSS_USB_SS_CNTL_RCO_EN);
+ if (ret)
+ goto err_regulator_disable;
+
+ /* Disable all switches but enable the mux */
+ ret = regmap_write(usbss->regmap, WCD_USBSS_SWITCH_SETTINGS_ENABLE,
+ WCD_USBSS_SWITCH_SETTINGS_ENABLE_DEVICE_ENABLE);
+ if (ret)
+ goto err_regulator_disable;
+
+ /* Setup in SAFE mode */
+ ret = wcd939x_usbss_set(usbss);
+ if (ret)
+ goto err_regulator_disable;
+
+ sw_desc.drvdata = usbss;
+ sw_desc.fwnode = dev_fwnode(dev);
+ sw_desc.set = wcd939x_usbss_switch_set;
+
+ usbss->sw = typec_switch_register(dev, &sw_desc);
+ if (IS_ERR(usbss->sw)) {
+ ret = dev_err_probe(dev, PTR_ERR(usbss->sw), "failed to register typec switch\n");
+ goto err_regulator_disable;
+ }
+
+ mux_desc.drvdata = usbss;
+ mux_desc.fwnode = dev_fwnode(dev);
+ mux_desc.set = wcd939x_usbss_mux_set;
+
+ usbss->mux = typec_mux_register(dev, &mux_desc);
+ if (IS_ERR(usbss->mux)) {
+ ret = dev_err_probe(dev, PTR_ERR(usbss->mux), "failed to register typec mux\n");
+ goto err_switch_unregister;
+ }
+
+ i2c_set_clientdata(client, usbss);
+
+ return 0;
+
+err_switch_unregister:
+ typec_switch_unregister(usbss->sw);
+
+err_regulator_disable:
+ regulator_disable(usbss->vdd_supply);
+
+err_mux_switch:
+ typec_switch_put(usbss->codec_switch);
+
+err_mux_put:
+ typec_mux_put(usbss->codec);
+
+ return ret;
+}
+
+static void wcd939x_usbss_remove(struct i2c_client *client)
+{
+ struct wcd939x_usbss *usbss = i2c_get_clientdata(client);
+
+ typec_mux_unregister(usbss->mux);
+ typec_switch_unregister(usbss->sw);
+
+ regulator_disable(usbss->vdd_supply);
+
+ typec_switch_put(usbss->codec_switch);
+ typec_mux_put(usbss->codec);
+}
+
+static const struct i2c_device_id wcd939x_usbss_table[] = {
+ { "wcd9390-usbss" },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wcd939x_usbss_table);
+
+static const struct of_device_id wcd939x_usbss_of_table[] = {
+ { .compatible = "qcom,wcd9390-usbss" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wcd939x_usbss_of_table);
+
+static struct i2c_driver wcd939x_usbss_driver = {
+ .driver = {
+ .name = "wcd939x-usbss",
+ .of_match_table = wcd939x_usbss_of_table,
+ },
+ .probe = wcd939x_usbss_probe,
+ .remove = wcd939x_usbss_remove,
+ .id_table = wcd939x_usbss_table,
+};
+module_i2c_driver(wcd939x_usbss_driver);
+
+MODULE_DESCRIPTION("Qualcomm WCD939x USBSS driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/typec/pd.c b/drivers/usb/typec/pd.c
index 85d015cdbe1f..b9cca2be76fc 100644
--- a/drivers/usb/typec/pd.c
+++ b/drivers/usb/typec/pd.c
@@ -468,7 +468,7 @@ static struct device_type pd_capabilities_type = {
/**
* usb_power_delivery_register_capabilities - Register a set of capabilities.
* @pd: The USB PD instance that the capabilities belong to.
- * @desc: Description of the Capablities Message.
+ * @desc: Description of the Capabilities Message.
*
* This function registers a Capabilities Message described in @desc. The
* capabilities will have their own sub-directory under @pd in sysfs.
@@ -571,7 +571,7 @@ static void pd_release(struct device *dev)
{
struct usb_power_delivery *pd = to_usb_power_delivery(dev);
- ida_simple_remove(&pd_ida, pd->id);
+ ida_free(&pd_ida, pd->id);
kfree(pd);
}
@@ -616,7 +616,7 @@ usb_power_delivery_register(struct device *parent, struct usb_power_delivery_des
if (!pd)
return ERR_PTR(-ENOMEM);
- ret = ida_simple_get(&pd_ida, 0, 0, GFP_KERNEL);
+ ret = ida_alloc(&pd_ida, GFP_KERNEL);
if (ret < 0) {
kfree(pd);
return ERR_PTR(ret);
diff --git a/drivers/usb/typec/tcpm/tcpci_maxim_core.c b/drivers/usb/typec/tcpm/tcpci_maxim_core.c
index 9454b12a073c..7fb966fd639b 100644
--- a/drivers/usb/typec/tcpm/tcpci_maxim_core.c
+++ b/drivers/usb/typec/tcpm/tcpci_maxim_core.c
@@ -92,11 +92,16 @@ static void max_tcpci_init_regs(struct max_tcpci_chip *chip)
return;
}
+ /* Vconn Over Current Protection */
+ ret = max_tcpci_write8(chip, TCPC_FAULT_STATUS_MASK, TCPC_FAULT_STATUS_MASK_VCONN_OC);
+ if (ret < 0)
+ return;
+
alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_TX_FAILED |
TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_RX_STATUS | TCPC_ALERT_CC_STATUS |
TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_POWER_STATUS |
/* Enable Extended alert for detecting Fast Role Swap Signal */
- TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS;
+ TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS | TCPC_ALERT_FAULT;
ret = max_tcpci_write16(chip, TCPC_ALERT_MASK, alert_mask);
if (ret < 0) {
@@ -295,6 +300,19 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status)
}
}
+ if (status & TCPC_ALERT_FAULT) {
+ ret = max_tcpci_read8(chip, TCPC_FAULT_STATUS, &reg_status);
+ if (ret < 0)
+ return ret;
+
+ ret = max_tcpci_write8(chip, TCPC_FAULT_STATUS, reg_status);
+ if (ret < 0)
+ return ret;
+
+ if (reg_status & TCPC_FAULT_STATUS_VCONN_OC)
+ tcpm_port_error_recovery(chip->port);
+ }
+
if (status & TCPC_ALERT_EXTND) {
ret = max_tcpci_read8(chip, TCPC_ALERT_EXTENDED, &reg_status);
if (ret < 0)
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index bfb6f9481e87..5945e3a2b0f7 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -251,6 +251,7 @@ enum frs_typec_current {
#define TCPM_FRS_EVENT BIT(3)
#define TCPM_SOURCING_VBUS BIT(4)
#define TCPM_PORT_CLEAN BIT(5)
+#define TCPM_PORT_ERROR BIT(6)
#define LOG_BUFFER_ENTRIES 1024
#define LOG_BUFFER_ENTRY_SIZE 128
@@ -296,6 +297,15 @@ struct pd_pps_data {
bool active;
};
+struct pd_data {
+ struct usb_power_delivery *pd;
+ struct usb_power_delivery_capabilities *source_cap;
+ struct usb_power_delivery_capabilities_desc source_desc;
+ struct usb_power_delivery_capabilities *sink_cap;
+ struct usb_power_delivery_capabilities_desc sink_desc;
+ unsigned int operating_snk_mw;
+};
+
struct tcpm_port {
struct device *dev;
@@ -397,12 +407,14 @@ struct tcpm_port {
unsigned int rx_msgid;
/* USB PD objects */
- struct usb_power_delivery *pd;
+ struct usb_power_delivery **pds;
+ struct pd_data **pd_list;
struct usb_power_delivery_capabilities *port_source_caps;
struct usb_power_delivery_capabilities *port_sink_caps;
struct usb_power_delivery *partner_pd;
struct usb_power_delivery_capabilities *partner_source_caps;
struct usb_power_delivery_capabilities *partner_sink_caps;
+ struct usb_power_delivery *selected_pd;
/* Partner capabilities/requests */
u32 sink_request;
@@ -412,6 +424,7 @@ struct tcpm_port {
unsigned int nr_sink_caps;
/* Local capabilities */
+ unsigned int pd_count;
u32 src_pdo[PDO_MAX_OBJECTS];
unsigned int nr_src_pdo;
u32 snk_pdo[PDO_MAX_OBJECTS];
@@ -2847,7 +2860,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
PD_MSG_CTRL_NOT_SUPP,
NONE_AMS);
} else {
- if (port->send_discover) {
+ if (port->send_discover && port->negotiated_rev < PD_REV30) {
tcpm_queue_message(port, PD_MSG_CTRL_WAIT);
break;
}
@@ -2863,7 +2876,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
PD_MSG_CTRL_NOT_SUPP,
NONE_AMS);
} else {
- if (port->send_discover) {
+ if (port->send_discover && port->negotiated_rev < PD_REV30) {
tcpm_queue_message(port, PD_MSG_CTRL_WAIT);
break;
}
@@ -2872,7 +2885,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
}
break;
case PD_CTRL_VCONN_SWAP:
- if (port->send_discover) {
+ if (port->send_discover && port->negotiated_rev < PD_REV30) {
tcpm_queue_message(port, PD_MSG_CTRL_WAIT);
break;
}
@@ -4401,7 +4414,8 @@ static void run_state_machine(struct tcpm_port *port)
tcpm_set_current_limit(port, tcpm_get_current_limit(port), 5000);
tcpm_swap_complete(port, 0);
tcpm_typec_connect(port);
- mod_enable_frs_delayed_work(port, 0);
+ if (port->pd_capable && port->source_caps[0] & PDO_FIXED_DUAL_ROLE)
+ mod_enable_frs_delayed_work(port, 0);
tcpm_pps_complete(port, port->pps_status);
if (port->ams != NONE_AMS)
@@ -5487,6 +5501,10 @@ static void tcpm_pd_event_handler(struct kthread_work *work)
tcpm_set_state(port, tcpm_default_state(port), 0);
}
}
+ if (events & TCPM_PORT_ERROR) {
+ tcpm_log(port, "port triggering error recovery");
+ tcpm_set_state(port, ERROR_RECOVERY, 0);
+ }
spin_lock(&port->pd_event_lock);
}
@@ -5554,6 +5572,15 @@ bool tcpm_port_is_toggling(struct tcpm_port *port)
}
EXPORT_SYMBOL_GPL(tcpm_port_is_toggling);
+void tcpm_port_error_recovery(struct tcpm_port *port)
+{
+ spin_lock(&port->pd_event_lock);
+ port->pd_events |= TCPM_PORT_ERROR;
+ spin_unlock(&port->pd_event_lock);
+ kthread_queue_work(port->wq, &port->event_work);
+}
+EXPORT_SYMBOL_GPL(tcpm_port_error_recovery);
+
static void tcpm_enable_frs_work(struct kthread_work *work)
{
struct tcpm_port *port = container_of(work, struct tcpm_port, enable_frs);
@@ -6045,12 +6072,114 @@ port_unlock:
return 0;
}
+static struct pd_data *tcpm_find_pd_data(struct tcpm_port *port, struct usb_power_delivery *pd)
+{
+ int i;
+
+ for (i = 0; port->pd_list[i]; i++) {
+ if (port->pd_list[i]->pd == pd)
+ return port->pd_list[i];
+ }
+
+ return ERR_PTR(-ENODATA);
+}
+
+static struct usb_power_delivery **tcpm_pd_get(struct typec_port *p)
+{
+ struct tcpm_port *port = typec_get_drvdata(p);
+
+ return port->pds;
+}
+
+static int tcpm_pd_set(struct typec_port *p, struct usb_power_delivery *pd)
+{
+ struct tcpm_port *port = typec_get_drvdata(p);
+ struct pd_data *data;
+ int i, ret = 0;
+
+ mutex_lock(&port->lock);
+
+ if (port->selected_pd == pd)
+ goto unlock;
+
+ data = tcpm_find_pd_data(port, pd);
+ if (IS_ERR(data)) {
+ ret = PTR_ERR(data);
+ goto unlock;
+ }
+
+ if (data->sink_desc.pdo[0]) {
+ for (i = 0; i < PDO_MAX_OBJECTS && data->sink_desc.pdo[i]; i++)
+ port->snk_pdo[i] = data->sink_desc.pdo[i];
+ port->nr_snk_pdo = i + 1;
+ port->operating_snk_mw = data->operating_snk_mw;
+ }
+
+ if (data->source_desc.pdo[0]) {
+ for (i = 0; i < PDO_MAX_OBJECTS && data->source_desc.pdo[i]; i++)
+ port->snk_pdo[i] = data->source_desc.pdo[i];
+ port->nr_src_pdo = i + 1;
+ }
+
+ switch (port->state) {
+ case SRC_UNATTACHED:
+ case SRC_ATTACH_WAIT:
+ case SRC_TRYWAIT:
+ tcpm_set_cc(port, tcpm_rp_cc(port));
+ break;
+ case SRC_SEND_CAPABILITIES:
+ case SRC_SEND_CAPABILITIES_TIMEOUT:
+ case SRC_NEGOTIATE_CAPABILITIES:
+ case SRC_READY:
+ case SRC_WAIT_NEW_CAPABILITIES:
+ port->caps_count = 0;
+ port->upcoming_state = SRC_SEND_CAPABILITIES;
+ ret = tcpm_ams_start(port, POWER_NEGOTIATION);
+ if (ret == -EAGAIN) {
+ port->upcoming_state = INVALID_STATE;
+ goto unlock;
+ }
+ break;
+ case SNK_NEGOTIATE_CAPABILITIES:
+ case SNK_NEGOTIATE_PPS_CAPABILITIES:
+ case SNK_READY:
+ case SNK_TRANSITION_SINK:
+ case SNK_TRANSITION_SINK_VBUS:
+ if (port->pps_data.active)
+ port->upcoming_state = SNK_NEGOTIATE_PPS_CAPABILITIES;
+ else if (port->pd_capable)
+ port->upcoming_state = SNK_NEGOTIATE_CAPABILITIES;
+ else
+ break;
+
+ port->update_sink_caps = true;
+
+ ret = tcpm_ams_start(port, POWER_NEGOTIATION);
+ if (ret == -EAGAIN) {
+ port->upcoming_state = INVALID_STATE;
+ goto unlock;
+ }
+ break;
+ default:
+ break;
+ }
+
+ port->port_source_caps = data->source_cap;
+ port->port_sink_caps = data->sink_cap;
+ port->selected_pd = pd;
+unlock:
+ mutex_unlock(&port->lock);
+ return ret;
+}
+
static const struct typec_operations tcpm_ops = {
.try_role = tcpm_try_role,
.dr_set = tcpm_dr_set,
.pr_set = tcpm_pr_set,
.vconn_set = tcpm_vconn_set,
- .port_type_set = tcpm_port_type_set
+ .port_type_set = tcpm_port_type_set,
+ .pd_get = tcpm_pd_get,
+ .pd_set = tcpm_pd_set
};
void tcpm_tcpc_reset(struct tcpm_port *port)
@@ -6064,58 +6193,63 @@ EXPORT_SYMBOL_GPL(tcpm_tcpc_reset);
static void tcpm_port_unregister_pd(struct tcpm_port *port)
{
- usb_power_delivery_unregister_capabilities(port->port_sink_caps);
+ int i;
+
port->port_sink_caps = NULL;
- usb_power_delivery_unregister_capabilities(port->port_source_caps);
port->port_source_caps = NULL;
- usb_power_delivery_unregister(port->pd);
- port->pd = NULL;
+ for (i = 0; i < port->pd_count; i++) {
+ usb_power_delivery_unregister_capabilities(port->pd_list[i]->sink_cap);
+ kfree(port->pd_list[i]->sink_cap);
+ usb_power_delivery_unregister_capabilities(port->pd_list[i]->source_cap);
+ kfree(port->pd_list[i]->source_cap);
+ devm_kfree(port->dev, port->pd_list[i]);
+ port->pd_list[i] = NULL;
+ usb_power_delivery_unregister(port->pds[i]);
+ port->pds[i] = NULL;
+ }
}
static int tcpm_port_register_pd(struct tcpm_port *port)
{
struct usb_power_delivery_desc desc = { port->typec_caps.pd_revision };
- struct usb_power_delivery_capabilities_desc caps = { };
struct usb_power_delivery_capabilities *cap;
- int ret;
+ int ret, i;
if (!port->nr_src_pdo && !port->nr_snk_pdo)
return 0;
- port->pd = usb_power_delivery_register(port->dev, &desc);
- if (IS_ERR(port->pd)) {
- ret = PTR_ERR(port->pd);
- goto err_unregister;
- }
-
- if (port->nr_src_pdo) {
- memcpy_and_pad(caps.pdo, sizeof(caps.pdo), port->src_pdo,
- port->nr_src_pdo * sizeof(u32), 0);
- caps.role = TYPEC_SOURCE;
-
- cap = usb_power_delivery_register_capabilities(port->pd, &caps);
- if (IS_ERR(cap)) {
- ret = PTR_ERR(cap);
+ for (i = 0; i < port->pd_count; i++) {
+ port->pds[i] = usb_power_delivery_register(port->dev, &desc);
+ if (IS_ERR(port->pds[i])) {
+ ret = PTR_ERR(port->pds[i]);
goto err_unregister;
}
-
- port->port_source_caps = cap;
- }
-
- if (port->nr_snk_pdo) {
- memcpy_and_pad(caps.pdo, sizeof(caps.pdo), port->snk_pdo,
- port->nr_snk_pdo * sizeof(u32), 0);
- caps.role = TYPEC_SINK;
-
- cap = usb_power_delivery_register_capabilities(port->pd, &caps);
- if (IS_ERR(cap)) {
- ret = PTR_ERR(cap);
- goto err_unregister;
+ port->pd_list[i]->pd = port->pds[i];
+
+ if (port->pd_list[i]->source_desc.pdo[0]) {
+ cap = usb_power_delivery_register_capabilities(port->pds[i],
+ &port->pd_list[i]->source_desc);
+ if (IS_ERR(cap)) {
+ ret = PTR_ERR(cap);
+ goto err_unregister;
+ }
+ port->pd_list[i]->source_cap = cap;
}
- port->port_sink_caps = cap;
+ if (port->pd_list[i]->sink_desc.pdo[0]) {
+ cap = usb_power_delivery_register_capabilities(port->pds[i],
+ &port->pd_list[i]->sink_desc);
+ if (IS_ERR(cap)) {
+ ret = PTR_ERR(cap);
+ goto err_unregister;
+ }
+ port->pd_list[i]->sink_cap = cap;
+ }
}
+ port->port_source_caps = port->pd_list[0]->source_cap;
+ port->port_sink_caps = port->pd_list[0]->sink_cap;
+ port->selected_pd = port->pds[0];
return 0;
err_unregister:
@@ -6124,12 +6258,15 @@ err_unregister:
return ret;
}
-static int tcpm_fw_get_caps(struct tcpm_port *port,
- struct fwnode_handle *fwnode)
+static int tcpm_fw_get_caps(struct tcpm_port *port, struct fwnode_handle *fwnode)
{
+ struct fwnode_handle *capabilities, *child, *caps = NULL;
+ unsigned int nr_src_pdo, nr_snk_pdo;
const char *opmode_str;
- int ret;
- u32 mw, frs_current;
+ u32 *src_pdo, *snk_pdo;
+ u32 uw, frs_current;
+ int ret = 0, i;
+ int mode;
if (!fwnode)
return -EINVAL;
@@ -6147,30 +6284,20 @@ static int tcpm_fw_get_caps(struct tcpm_port *port,
if (ret < 0)
return ret;
+ mode = 0;
+
+ if (fwnode_property_read_bool(fwnode, "accessory-mode-audio"))
+ port->typec_caps.accessory[mode++] = TYPEC_ACCESSORY_AUDIO;
+
+ if (fwnode_property_read_bool(fwnode, "accessory-mode-debug"))
+ port->typec_caps.accessory[mode++] = TYPEC_ACCESSORY_DEBUG;
+
port->port_type = port->typec_caps.type;
port->pd_supported = !fwnode_property_read_bool(fwnode, "pd-disable");
-
port->slow_charger_loop = fwnode_property_read_bool(fwnode, "slow-charger-loop");
- if (port->port_type == TYPEC_PORT_SNK)
- goto sink;
-
- /* Get Source PDOs for the PD port or Source Rp value for the non-PD port */
- if (port->pd_supported) {
- ret = fwnode_property_count_u32(fwnode, "source-pdos");
- if (ret == 0)
- return -EINVAL;
- else if (ret < 0)
- return ret;
+ port->self_powered = fwnode_property_read_bool(fwnode, "self-powered");
- port->nr_src_pdo = min(ret, PDO_MAX_OBJECTS);
- ret = fwnode_property_read_u32_array(fwnode, "source-pdos",
- port->src_pdo, port->nr_src_pdo);
- if (ret)
- return ret;
- ret = tcpm_validate_caps(port, port->src_pdo, port->nr_src_pdo);
- if (ret)
- return ret;
- } else {
+ if (!port->pd_supported) {
ret = fwnode_property_read_string(fwnode, "typec-power-opmode", &opmode_str);
if (ret)
return ret;
@@ -6178,45 +6305,150 @@ static int tcpm_fw_get_caps(struct tcpm_port *port,
if (ret < 0)
return ret;
port->src_rp = tcpm_pwr_opmode_to_rp(ret);
- }
-
- if (port->port_type == TYPEC_PORT_SRC)
return 0;
+ }
-sink:
- port->self_powered = fwnode_property_read_bool(fwnode, "self-powered");
-
- if (!port->pd_supported)
- return 0;
-
- /* Get sink pdos */
- ret = fwnode_property_count_u32(fwnode, "sink-pdos");
- if (ret <= 0)
- return -EINVAL;
-
- port->nr_snk_pdo = min(ret, PDO_MAX_OBJECTS);
- ret = fwnode_property_read_u32_array(fwnode, "sink-pdos",
- port->snk_pdo, port->nr_snk_pdo);
- if ((ret < 0) || tcpm_validate_caps(port, port->snk_pdo,
- port->nr_snk_pdo))
- return -EINVAL;
-
- if (fwnode_property_read_u32(fwnode, "op-sink-microwatt", &mw) < 0)
- return -EINVAL;
- port->operating_snk_mw = mw / 1000;
+ /* The following code are applicable to pd-capable ports, i.e. pd_supported is true. */
/* FRS can only be supported by DRP ports */
if (port->port_type == TYPEC_PORT_DRP) {
ret = fwnode_property_read_u32(fwnode, "new-source-frs-typec-current",
&frs_current);
- if (ret >= 0 && frs_current <= FRS_5V_3A)
+ if (!ret && frs_current <= FRS_5V_3A)
port->new_source_frs_current = frs_current;
+
+ if (ret)
+ ret = 0;
}
+ /* For the backward compatibility, "capabilities" node is optional. */
+ capabilities = fwnode_get_named_child_node(fwnode, "capabilities");
+ if (!capabilities) {
+ port->pd_count = 1;
+ } else {
+ fwnode_for_each_child_node(capabilities, child)
+ port->pd_count++;
+
+ if (!port->pd_count) {
+ ret = -ENODATA;
+ goto put_capabilities;
+ }
+ }
+
+ port->pds = devm_kcalloc(port->dev, port->pd_count, sizeof(struct usb_power_delivery *),
+ GFP_KERNEL);
+ if (!port->pds) {
+ ret = -ENOMEM;
+ goto put_capabilities;
+ }
+
+ port->pd_list = devm_kcalloc(port->dev, port->pd_count, sizeof(struct pd_data *),
+ GFP_KERNEL);
+ if (!port->pd_list) {
+ ret = -ENOMEM;
+ goto put_capabilities;
+ }
+
+ for (i = 0; i < port->pd_count; i++) {
+ port->pd_list[i] = devm_kzalloc(port->dev, sizeof(struct pd_data), GFP_KERNEL);
+ if (!port->pd_list[i]) {
+ ret = -ENOMEM;
+ goto put_capabilities;
+ }
+
+ src_pdo = port->pd_list[i]->source_desc.pdo;
+ port->pd_list[i]->source_desc.role = TYPEC_SOURCE;
+ snk_pdo = port->pd_list[i]->sink_desc.pdo;
+ port->pd_list[i]->sink_desc.role = TYPEC_SINK;
+
+ /* If "capabilities" is NULL, fall back to single pd cap population. */
+ if (!capabilities)
+ caps = fwnode;
+ else
+ caps = fwnode_get_next_child_node(capabilities, caps);
+
+ if (port->port_type != TYPEC_PORT_SNK) {
+ ret = fwnode_property_count_u32(caps, "source-pdos");
+ if (ret == 0) {
+ ret = -EINVAL;
+ goto put_caps;
+ }
+ if (ret < 0)
+ goto put_caps;
+
+ nr_src_pdo = min(ret, PDO_MAX_OBJECTS);
+ ret = fwnode_property_read_u32_array(caps, "source-pdos", src_pdo,
+ nr_src_pdo);
+ if (ret)
+ goto put_caps;
+
+ ret = tcpm_validate_caps(port, src_pdo, nr_src_pdo);
+ if (ret)
+ goto put_caps;
+
+ if (i == 0) {
+ port->nr_src_pdo = nr_src_pdo;
+ memcpy_and_pad(port->src_pdo, sizeof(u32) * PDO_MAX_OBJECTS,
+ port->pd_list[0]->source_desc.pdo,
+ sizeof(u32) * nr_src_pdo,
+ 0);
+ }
+ }
+
+ if (port->port_type != TYPEC_PORT_SRC) {
+ ret = fwnode_property_count_u32(caps, "sink-pdos");
+ if (ret == 0) {
+ ret = -EINVAL;
+ goto put_caps;
+ }
+
+ if (ret < 0)
+ goto put_caps;
+
+ nr_snk_pdo = min(ret, PDO_MAX_OBJECTS);
+ ret = fwnode_property_read_u32_array(caps, "sink-pdos", snk_pdo,
+ nr_snk_pdo);
+ if (ret)
+ goto put_caps;
+
+ ret = tcpm_validate_caps(port, snk_pdo, nr_snk_pdo);
+ if (ret)
+ goto put_caps;
+
+ if (fwnode_property_read_u32(caps, "op-sink-microwatt", &uw) < 0) {
+ ret = -EINVAL;
+ goto put_caps;
+ }
+
+ port->pd_list[i]->operating_snk_mw = uw / 1000;
+
+ if (i == 0) {
+ port->nr_snk_pdo = nr_snk_pdo;
+ memcpy_and_pad(port->snk_pdo, sizeof(u32) * PDO_MAX_OBJECTS,
+ port->pd_list[0]->sink_desc.pdo,
+ sizeof(u32) * nr_snk_pdo,
+ 0);
+ port->operating_snk_mw = port->pd_list[0]->operating_snk_mw;
+ }
+ }
+ }
+
+put_caps:
+ if (caps != fwnode)
+ fwnode_handle_put(caps);
+put_capabilities:
+ fwnode_handle_put(capabilities);
+ return ret;
+}
+
+static int tcpm_fw_get_snk_vdos(struct tcpm_port *port, struct fwnode_handle *fwnode)
+{
+ int ret;
+
/* sink-vdos is optional */
ret = fwnode_property_count_u32(fwnode, "sink-vdos");
if (ret < 0)
- ret = 0;
+ return 0;
port->nr_snk_vdo = min(ret, VDO_MAX_OBJECTS);
if (port->nr_snk_vdo) {
@@ -6584,10 +6816,12 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
err = tcpm_fw_get_caps(port, tcpc->fwnode);
if (err < 0)
goto out_destroy_wq;
+ err = tcpm_fw_get_snk_vdos(port, tcpc->fwnode);
+ if (err < 0)
+ goto out_destroy_wq;
port->try_role = port->typec_caps.prefer_role;
- port->typec_caps.fwnode = tcpc->fwnode;
port->typec_caps.revision = 0x0120; /* Type-C spec release 1.2 */
port->typec_caps.pd_revision = 0x0300; /* USB-PD spec release 3.0 */
port->typec_caps.svdm_version = SVDM_VER_2_0;
@@ -6596,7 +6830,6 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
port->typec_caps.orientation_aware = 1;
port->partner_desc.identity = &port->partner_ident;
- port->port_type = port->typec_caps.type;
port->role_sw = usb_role_switch_get(port->dev);
if (!port->role_sw)
@@ -6615,7 +6848,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
if (err)
goto out_role_sw_put;
- port->typec_caps.pd = port->pd;
+ port->typec_caps.pd = port->pds[0];
port->typec_port = typec_register_port(port->dev, &port->typec_caps);
if (IS_ERR(port->typec_port)) {
diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c
index 196535ad996d..0717cfcd9f8c 100644
--- a/drivers/usb/typec/tipd/core.c
+++ b/drivers/usb/typec/tipd/core.c
@@ -8,6 +8,7 @@
#include <linux/i2c.h>
#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/power_supply.h>
@@ -64,6 +65,9 @@
#define TPS_PBMC_RC 0 /* Return code */
#define TPS_PBMC_DPCS 2 /* device patch complete status */
+/* reset de-assertion to ready for operation */
+#define TPS_SETUP_MS 1000
+
enum {
TPS_PORTINFO_SINK,
TPS_PORTINFO_SINK_ACCESSORY,
@@ -111,6 +115,8 @@ struct tipd_data {
void (*trace_power_status)(u16 status);
void (*trace_status)(u32 status);
int (*apply_patch)(struct tps6598x *tps);
+ int (*init)(struct tps6598x *tps);
+ int (*reset)(struct tps6598x *tps);
};
struct tps6598x {
@@ -119,6 +125,7 @@ struct tps6598x {
struct mutex lock; /* device lock */
u8 i2c_protocol:1;
+ struct gpio_desc *reset;
struct typec_port *port;
struct typec_partner *partner;
struct usb_pd_identity partner_identity;
@@ -323,7 +330,7 @@ static void tps6598x_disconnect(struct tps6598x *tps, u32 status)
}
static int tps6598x_exec_cmd_tmo(struct tps6598x *tps, const char *cmd,
- size_t in_len, u8 *in_data,
+ size_t in_len, const u8 *in_data,
size_t out_len, u8 *out_data,
u32 cmd_timeout_ms, u32 res_delay_ms)
{
@@ -389,7 +396,7 @@ static int tps6598x_exec_cmd_tmo(struct tps6598x *tps, const char *cmd,
}
static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd,
- size_t in_len, u8 *in_data,
+ size_t in_len, const u8 *in_data,
size_t out_len, u8 *out_data)
{
return tps6598x_exec_cmd_tmo(tps, cmd, in_len, in_data,
@@ -866,6 +873,30 @@ tps6598x_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode)
return 0;
}
+static int tps_request_firmware(struct tps6598x *tps, const struct firmware **fw)
+{
+ const char *firmware_name;
+ int ret;
+
+ ret = device_property_read_string(tps->dev, "firmware-name",
+ &firmware_name);
+ if (ret)
+ return ret;
+
+ ret = request_firmware(fw, firmware_name, tps->dev);
+ if (ret) {
+ dev_err(tps->dev, "failed to retrieve \"%s\"\n", firmware_name);
+ return ret;
+ }
+
+ if ((*fw)->size == 0) {
+ release_firmware(*fw);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
static int
tps25750_write_firmware(struct tps6598x *tps,
u8 bpms_addr, const u8 *data, size_t len)
@@ -954,16 +985,9 @@ static int tps25750_start_patch_burst_mode(struct tps6598x *tps)
if (ret)
return ret;
- ret = request_firmware(&fw, firmware_name, tps->dev);
- if (ret) {
- dev_err(tps->dev, "failed to retrieve \"%s\"\n", firmware_name);
+ ret = tps_request_firmware(tps, &fw);
+ if (ret)
return ret;
- }
-
- if (fw->size == 0) {
- ret = -EINVAL;
- goto release_fw;
- }
ret = of_property_match_string(np, "reg-names", "patch-address");
if (ret < 0) {
@@ -1101,6 +1125,76 @@ wait_for_app:
return 0;
};
+static int tps6598x_apply_patch(struct tps6598x *tps)
+{
+ u8 in = TPS_PTCS_CONTENT_DEV | TPS_PTCS_CONTENT_APP;
+ u8 out[TPS_MAX_LEN] = {0};
+ size_t in_len = sizeof(in);
+ size_t copied_bytes = 0;
+ size_t bytes_left;
+ const struct firmware *fw;
+ const char *firmware_name;
+ int ret;
+
+ ret = device_property_read_string(tps->dev, "firmware-name",
+ &firmware_name);
+ if (ret)
+ return ret;
+
+ ret = tps_request_firmware(tps, &fw);
+ if (ret)
+ return ret;
+
+ ret = tps6598x_exec_cmd(tps, "PTCs", in_len, &in,
+ TPS_PTCS_OUT_BYTES, out);
+ if (ret || out[TPS_PTCS_STATUS] == TPS_PTCS_STATUS_FAIL) {
+ if (!ret)
+ ret = -EBUSY;
+ dev_err(tps->dev, "Update start failed (%d)\n", ret);
+ goto release_fw;
+ }
+
+ bytes_left = fw->size;
+ while (bytes_left) {
+ if (bytes_left < TPS_MAX_LEN)
+ in_len = bytes_left;
+ else
+ in_len = TPS_MAX_LEN;
+ ret = tps6598x_exec_cmd(tps, "PTCd", in_len,
+ fw->data + copied_bytes,
+ TPS_PTCD_OUT_BYTES, out);
+ if (ret || out[TPS_PTCD_TRANSFER_STATUS] ||
+ out[TPS_PTCD_LOADING_STATE] == TPS_PTCD_LOAD_ERR) {
+ if (!ret)
+ ret = -EBUSY;
+ dev_err(tps->dev, "Patch download failed (%d)\n", ret);
+ goto release_fw;
+ }
+ copied_bytes += in_len;
+ bytes_left -= in_len;
+ }
+
+ ret = tps6598x_exec_cmd(tps, "PTCc", 0, NULL, TPS_PTCC_OUT_BYTES, out);
+ if (ret || out[TPS_PTCC_DEV] || out[TPS_PTCC_APP]) {
+ if (!ret)
+ ret = -EBUSY;
+ dev_err(tps->dev, "Update completion failed (%d)\n", ret);
+ goto release_fw;
+ }
+ msleep(TPS_SETUP_MS);
+ dev_info(tps->dev, "Firmware update succeeded\n");
+
+release_fw:
+ release_firmware(fw);
+
+ return ret;
+};
+
+static int cd321x_init(struct tps6598x *tps)
+{
+ return 0;
+}
+
static int tps25750_init(struct tps6598x *tps)
{
int ret;
@@ -1119,6 +1213,26 @@ static int tps25750_init(struct tps6598x *tps)
return 0;
}
+static int tps6598x_init(struct tps6598x *tps)
+{
+ return tps->data->apply_patch(tps);
+}
+
+static int cd321x_reset(struct tps6598x *tps)
+{
+ return 0;
+}
+
+static int tps25750_reset(struct tps6598x *tps)
+{
+ return tps6598x_exec_cmd_tmo(tps, "GAID", 0, NULL, 0, NULL, 2000, 0);
+}
+
+static int tps6598x_reset(struct tps6598x *tps)
+{
+ return 0;
+}
+
static int
tps25750_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode)
{
@@ -1182,7 +1296,6 @@ static int tps6598x_probe(struct i2c_client *client)
u32 vid;
int ret;
u64 mask1;
- bool is_tps25750;
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps)
@@ -1191,12 +1304,18 @@ static int tps6598x_probe(struct i2c_client *client)
mutex_init(&tps->lock);
tps->dev = &client->dev;
+ tps->reset = devm_gpiod_get_optional(tps->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(tps->reset))
+ return dev_err_probe(tps->dev, PTR_ERR(tps->reset),
+ "failed to get reset GPIO\n");
+ if (tps->reset)
+ msleep(TPS_SETUP_MS);
+
tps->regmap = devm_regmap_init_i2c(client, &tps6598x_regmap_config);
if (IS_ERR(tps->regmap))
return PTR_ERR(tps->regmap);
- is_tps25750 = device_is_compatible(tps->dev, "ti,tps25750");
- if (!is_tps25750) {
+ if (!device_is_compatible(tps->dev, "ti,tps25750")) {
ret = tps6598x_read32(tps, TPS_REG_VID, &vid);
if (ret < 0 || !vid)
return -ENODEV;
@@ -1239,8 +1358,8 @@ static int tps6598x_probe(struct i2c_client *client)
if (ret < 0)
return ret;
- if (is_tps25750 && ret == TPS_MODE_PTCH) {
- ret = tps25750_init(tps);
+ if (ret == TPS_MODE_PTCH) {
+ ret = tps->data->init(tps);
if (ret)
return ret;
}
@@ -1328,8 +1447,8 @@ err_clear_mask:
tps6598x_write64(tps, TPS_REG_INT_MASK1, 0);
err_reset_controller:
/* Reset PD controller to remove any applied patch */
- if (is_tps25750)
- tps6598x_exec_cmd_tmo(tps, "GAID", 0, NULL, 0, NULL, 2000, 0);
+ tps->data->reset(tps);
+
return ret;
}
@@ -1346,8 +1465,10 @@ static void tps6598x_remove(struct i2c_client *client)
usb_role_switch_put(tps->role_sw);
/* Reset PD controller to remove any applied patch */
- if (device_is_compatible(tps->dev, "ti,tps25750"))
- tps6598x_exec_cmd_tmo(tps, "GAID", 0, NULL, 0, NULL, 2000, 0);
+ tps->data->reset(tps);
+
+ if (tps->reset)
+ gpiod_set_value_cansleep(tps->reset, 1);
}
static int __maybe_unused tps6598x_suspend(struct device *dev)
@@ -1358,6 +1479,8 @@ static int __maybe_unused tps6598x_suspend(struct device *dev)
if (tps->wakeup) {
disable_irq(client->irq);
enable_irq_wake(client->irq);
+ } else if (tps->reset) {
+ gpiod_set_value_cansleep(tps->reset, 1);
}
if (!client->irq)
@@ -1376,8 +1499,8 @@ static int __maybe_unused tps6598x_resume(struct device *dev)
if (ret < 0)
return ret;
- if (device_is_compatible(tps->dev, "ti,tps25750") && ret == TPS_MODE_PTCH) {
- ret = tps25750_init(tps);
+ if (ret == TPS_MODE_PTCH) {
+ ret = tps->data->init(tps);
if (ret)
return ret;
}
@@ -1385,6 +1508,9 @@ static int __maybe_unused tps6598x_resume(struct device *dev)
if (tps->wakeup) {
disable_irq_wake(client->irq);
enable_irq(client->irq);
+ } else if (tps->reset) {
+ gpiod_set_value_cansleep(tps->reset, 0);
+ msleep(TPS_SETUP_MS);
}
if (!client->irq)
@@ -1403,6 +1529,8 @@ static const struct tipd_data cd321x_data = {
.register_port = tps6598x_register_port,
.trace_power_status = trace_tps6598x_power_status,
.trace_status = trace_tps6598x_status,
+ .init = cd321x_init,
+ .reset = cd321x_reset,
};
static const struct tipd_data tps6598x_data = {
@@ -1410,6 +1538,9 @@ static const struct tipd_data tps6598x_data = {
.register_port = tps6598x_register_port,
.trace_power_status = trace_tps6598x_power_status,
.trace_status = trace_tps6598x_status,
+ .apply_patch = tps6598x_apply_patch,
+ .init = tps6598x_init,
+ .reset = tps6598x_reset,
};
static const struct tipd_data tps25750_data = {
@@ -1418,6 +1549,8 @@ static const struct tipd_data tps25750_data = {
.trace_power_status = trace_tps25750_power_status,
.trace_status = trace_tps25750_status,
.apply_patch = tps25750_apply_patch,
+ .init = tps25750_init,
+ .reset = tps25750_reset,
};
static const struct of_device_id tps6598x_of_match[] = {
diff --git a/drivers/usb/typec/tipd/tps6598x.h b/drivers/usb/typec/tipd/tps6598x.h
index 01609bf509e4..89b24519463a 100644
--- a/drivers/usb/typec/tipd/tps6598x.h
+++ b/drivers/usb/typec/tipd/tps6598x.h
@@ -235,4 +235,22 @@
/* SLEEP CONF REG */
#define TPS_SLEEP_CONF_SLEEP_MODE_ALLOWED BIT(0)
+/* Start Patch Download Sequence */
+#define TPS_PTCS_CONTENT_APP BIT(0)
+#define TPS_PTCS_CONTENT_DEV BIT(1)
+#define TPS_PTCS_OUT_BYTES 4
+#define TPS_PTCS_STATUS 1
+
+#define TPS_PTCS_STATUS_FAIL 0x80
+/* Patch Download */
+#define TPS_PTCD_OUT_BYTES 10
+#define TPS_PTCD_TRANSFER_STATUS 1
+#define TPS_PTCD_LOADING_STATE 2
+
+#define TPS_PTCD_LOAD_ERR 0x09
+/* Patch Download Complete */
+#define TPS_PTCC_OUT_BYTES 4
+#define TPS_PTCC_DEV 2
+#define TPS_PTCC_APP 3
+
#endif /* __TPS6598X_H__ */
diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c
index 0a6624d37929..79110a69d697 100644
--- a/drivers/usb/usbip/stub_main.c
+++ b/drivers/usb/usbip/stub_main.c
@@ -377,14 +377,14 @@ static int __init usbip_host_init(void)
goto err_usb_register;
}
- ret = driver_create_file(&stub_driver.drvwrap.driver,
+ ret = driver_create_file(&stub_driver.driver,
&driver_attr_match_busid);
if (ret) {
pr_err("driver_create_file failed\n");
goto err_create_file;
}
- ret = driver_create_file(&stub_driver.drvwrap.driver,
+ ret = driver_create_file(&stub_driver.driver,
&driver_attr_rebind);
if (ret) {
pr_err("driver_create_file failed\n");
@@ -402,10 +402,10 @@ err_usb_register:
static void __exit usbip_host_exit(void)
{
- driver_remove_file(&stub_driver.drvwrap.driver,
+ driver_remove_file(&stub_driver.driver,
&driver_attr_match_busid);
- driver_remove_file(&stub_driver.drvwrap.driver,
+ driver_remove_file(&stub_driver.driver,
&driver_attr_rebind);
/*
diff --git a/drivers/usb/usbip/vudc.h b/drivers/usb/usbip/vudc.h
index 1bd4bc005829..faf61c9c6a98 100644
--- a/drivers/usb/usbip/vudc.h
+++ b/drivers/usb/usbip/vudc.h
@@ -173,6 +173,6 @@ struct vudc_device *alloc_vudc_device(int devid);
void put_vudc_device(struct vudc_device *udc_dev);
int vudc_probe(struct platform_device *pdev);
-int vudc_remove(struct platform_device *pdev);
+void vudc_remove(struct platform_device *pdev);
#endif /* __USBIP_VUDC_H */
diff --git a/drivers/usb/usbip/vudc_dev.c b/drivers/usb/usbip/vudc_dev.c
index 44b04c54c086..f11535020e35 100644
--- a/drivers/usb/usbip/vudc_dev.c
+++ b/drivers/usb/usbip/vudc_dev.c
@@ -628,12 +628,11 @@ out:
return ret;
}
-int vudc_remove(struct platform_device *pdev)
+void vudc_remove(struct platform_device *pdev)
{
struct vudc *udc = platform_get_drvdata(pdev);
usb_del_gadget_udc(&udc->gadget);
cleanup_vudc_hw(udc);
kfree(udc);
- return 0;
}
diff --git a/drivers/usb/usbip/vudc_main.c b/drivers/usb/usbip/vudc_main.c
index 993e721cb840..8bee553e4894 100644
--- a/drivers/usb/usbip/vudc_main.c
+++ b/drivers/usb/usbip/vudc_main.c
@@ -19,7 +19,7 @@ MODULE_PARM_DESC(num, "number of emulated controllers");
static struct platform_driver vudc_driver = {
.probe = vudc_probe,
- .remove = vudc_remove,
+ .remove_new = vudc_remove,
.driver = {
.name = GADGET_NAME,
.dev_groups = vudc_groups,
diff --git a/drivers/vdpa/alibaba/eni_vdpa.c b/drivers/vdpa/alibaba/eni_vdpa.c
index 5a09a09cca70..cce3d1837104 100644
--- a/drivers/vdpa/alibaba/eni_vdpa.c
+++ b/drivers/vdpa/alibaba/eni_vdpa.c
@@ -497,7 +497,7 @@ static int eni_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (!eni_vdpa->vring) {
ret = -ENOMEM;
ENI_ERR(pdev, "failed to allocate virtqueues\n");
- goto err;
+ goto err_remove_vp_legacy;
}
for (i = 0; i < eni_vdpa->queues; i++) {
@@ -509,11 +509,13 @@ static int eni_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ret = vdpa_register_device(&eni_vdpa->vdpa, eni_vdpa->queues);
if (ret) {
ENI_ERR(pdev, "failed to register to vdpa bus\n");
- goto err;
+ goto err_remove_vp_legacy;
}
return 0;
+err_remove_vp_legacy:
+ vp_legacy_remove(&eni_vdpa->ldev);
err:
put_device(&eni_vdpa->vdpa.dev);
return ret;
diff --git a/drivers/vdpa/mlx5/core/mlx5_vdpa.h b/drivers/vdpa/mlx5/core/mlx5_vdpa.h
index 84547d998bcf..50aac8fe57ef 100644
--- a/drivers/vdpa/mlx5/core/mlx5_vdpa.h
+++ b/drivers/vdpa/mlx5/core/mlx5_vdpa.h
@@ -35,6 +35,9 @@ struct mlx5_vdpa_mr {
struct vhost_iotlb *iotlb;
bool user_mr;
+
+ refcount_t refcount;
+ struct list_head mr_list;
};
struct mlx5_vdpa_resources {
@@ -93,6 +96,7 @@ struct mlx5_vdpa_dev {
u32 generation;
struct mlx5_vdpa_mr *mr[MLX5_VDPA_NUM_AS];
+ struct list_head mr_list_head;
/* serialize mr access */
struct mutex mr_mtx;
struct mlx5_control_vq cvq;
@@ -118,8 +122,10 @@ int mlx5_vdpa_destroy_mkey(struct mlx5_vdpa_dev *mvdev, u32 mkey);
struct mlx5_vdpa_mr *mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
struct vhost_iotlb *iotlb);
void mlx5_vdpa_destroy_mr_resources(struct mlx5_vdpa_dev *mvdev);
-void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev,
- struct mlx5_vdpa_mr *mr);
+void mlx5_vdpa_get_mr(struct mlx5_vdpa_dev *mvdev,
+ struct mlx5_vdpa_mr *mr);
+void mlx5_vdpa_put_mr(struct mlx5_vdpa_dev *mvdev,
+ struct mlx5_vdpa_mr *mr);
void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev,
struct mlx5_vdpa_mr *mr,
unsigned int asid);
diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c
index 2197c46e563a..4758914ccf86 100644
--- a/drivers/vdpa/mlx5/core/mr.c
+++ b/drivers/vdpa/mlx5/core/mr.c
@@ -498,32 +498,54 @@ static void destroy_user_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr
static void _mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr)
{
+ if (WARN_ON(!mr))
+ return;
+
if (mr->user_mr)
destroy_user_mr(mvdev, mr);
else
destroy_dma_mr(mvdev, mr);
vhost_iotlb_free(mr->iotlb);
+
+ list_del(&mr->mr_list);
+
+ kfree(mr);
}
-void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev,
- struct mlx5_vdpa_mr *mr)
+static void _mlx5_vdpa_put_mr(struct mlx5_vdpa_dev *mvdev,
+ struct mlx5_vdpa_mr *mr)
{
if (!mr)
return;
+ if (refcount_dec_and_test(&mr->refcount))
+ _mlx5_vdpa_destroy_mr(mvdev, mr);
+}
+
+void mlx5_vdpa_put_mr(struct mlx5_vdpa_dev *mvdev,
+ struct mlx5_vdpa_mr *mr)
+{
mutex_lock(&mvdev->mr_mtx);
+ _mlx5_vdpa_put_mr(mvdev, mr);
+ mutex_unlock(&mvdev->mr_mtx);
+}
- _mlx5_vdpa_destroy_mr(mvdev, mr);
+static void _mlx5_vdpa_get_mr(struct mlx5_vdpa_dev *mvdev,
+ struct mlx5_vdpa_mr *mr)
+{
+ if (!mr)
+ return;
- for (int i = 0; i < MLX5_VDPA_NUM_AS; i++) {
- if (mvdev->mr[i] == mr)
- mvdev->mr[i] = NULL;
- }
+ refcount_inc(&mr->refcount);
+}
+void mlx5_vdpa_get_mr(struct mlx5_vdpa_dev *mvdev,
+ struct mlx5_vdpa_mr *mr)
+{
+ mutex_lock(&mvdev->mr_mtx);
+ _mlx5_vdpa_get_mr(mvdev, mr);
mutex_unlock(&mvdev->mr_mtx);
-
- kfree(mr);
}
void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev,
@@ -534,10 +556,23 @@ void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev,
mutex_lock(&mvdev->mr_mtx);
+ _mlx5_vdpa_put_mr(mvdev, old_mr);
mvdev->mr[asid] = new_mr;
- if (old_mr) {
- _mlx5_vdpa_destroy_mr(mvdev, old_mr);
- kfree(old_mr);
+
+ mutex_unlock(&mvdev->mr_mtx);
+}
+
+static void mlx5_vdpa_show_mr_leaks(struct mlx5_vdpa_dev *mvdev)
+{
+ struct mlx5_vdpa_mr *mr;
+
+ mutex_lock(&mvdev->mr_mtx);
+
+ list_for_each_entry(mr, &mvdev->mr_list_head, mr_list) {
+
+ mlx5_vdpa_warn(mvdev, "mkey still alive after resource delete: "
+ "mr: %p, mkey: 0x%x, refcount: %u\n",
+ mr, mr->mkey, refcount_read(&mr->refcount));
}
mutex_unlock(&mvdev->mr_mtx);
@@ -547,9 +582,11 @@ void mlx5_vdpa_update_mr(struct mlx5_vdpa_dev *mvdev,
void mlx5_vdpa_destroy_mr_resources(struct mlx5_vdpa_dev *mvdev)
{
for (int i = 0; i < MLX5_VDPA_NUM_AS; i++)
- mlx5_vdpa_destroy_mr(mvdev, mvdev->mr[i]);
+ mlx5_vdpa_update_mr(mvdev, NULL, i);
prune_iotlb(mvdev->cvq.iotlb);
+
+ mlx5_vdpa_show_mr_leaks(mvdev);
}
static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
@@ -576,6 +613,8 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
if (err)
goto err_iotlb;
+ list_add_tail(&mr->mr_list, &mvdev->mr_list_head);
+
return 0;
err_iotlb:
@@ -607,6 +646,8 @@ struct mlx5_vdpa_mr *mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
if (err)
goto out_err;
+ refcount_set(&mr->refcount, 1);
+
return mr;
out_err:
@@ -651,7 +692,7 @@ int mlx5_vdpa_reset_mr(struct mlx5_vdpa_dev *mvdev, unsigned int asid)
if (asid >= MLX5_VDPA_NUM_AS)
return -EINVAL;
- mlx5_vdpa_destroy_mr(mvdev, mvdev->mr[asid]);
+ mlx5_vdpa_update_mr(mvdev, NULL, asid);
if (asid == 0 && MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) {
if (mlx5_vdpa_create_dma_mr(mvdev))
diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c
index 26ba7da6b410..778821bab7d9 100644
--- a/drivers/vdpa/mlx5/net/mlx5_vnet.c
+++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c
@@ -120,6 +120,12 @@ struct mlx5_vdpa_virtqueue {
u16 avail_idx;
u16 used_idx;
int fw_state;
+
+ u64 modified_fields;
+
+ struct mlx5_vdpa_mr *vq_mr;
+ struct mlx5_vdpa_mr *desc_mr;
+
struct msi_map map;
/* keep last in the struct */
@@ -943,6 +949,14 @@ static int create_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque
kfree(in);
mvq->virtq_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
+ mlx5_vdpa_get_mr(mvdev, vq_mr);
+ mvq->vq_mr = vq_mr;
+
+ if (vq_desc_mr && MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, desc_group_mkey_supported)) {
+ mlx5_vdpa_get_mr(mvdev, vq_desc_mr);
+ mvq->desc_mr = vq_desc_mr;
+ }
+
return 0;
err_cmd:
@@ -969,6 +983,12 @@ static void destroy_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtq
}
mvq->fw_state = MLX5_VIRTIO_NET_Q_OBJECT_NONE;
umems_destroy(ndev, mvq);
+
+ mlx5_vdpa_put_mr(&ndev->mvdev, mvq->vq_mr);
+ mvq->vq_mr = NULL;
+
+ mlx5_vdpa_put_mr(&ndev->mvdev, mvq->desc_mr);
+ mvq->desc_mr = NULL;
}
static u32 get_rqpn(struct mlx5_vdpa_virtqueue *mvq, bool fw)
@@ -1167,7 +1187,12 @@ err_cmd:
return err;
}
-static bool is_valid_state_change(int oldstate, int newstate)
+static bool is_resumable(struct mlx5_vdpa_net *ndev)
+{
+ return ndev->mvdev.vdev.config->resume;
+}
+
+static bool is_valid_state_change(int oldstate, int newstate, bool resumable)
{
switch (oldstate) {
case MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT:
@@ -1175,25 +1200,43 @@ static bool is_valid_state_change(int oldstate, int newstate)
case MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY:
return newstate == MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND;
case MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND:
+ return resumable ? newstate == MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY : false;
case MLX5_VIRTIO_NET_Q_OBJECT_STATE_ERR:
default:
return false;
}
}
-static int modify_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq, int state)
+static bool modifiable_virtqueue_fields(struct mlx5_vdpa_virtqueue *mvq)
+{
+ /* Only state is always modifiable */
+ if (mvq->modified_fields & ~MLX5_VIRTQ_MODIFY_MASK_STATE)
+ return mvq->fw_state == MLX5_VIRTIO_NET_Q_OBJECT_STATE_INIT ||
+ mvq->fw_state == MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND;
+
+ return true;
+}
+
+static int modify_virtqueue(struct mlx5_vdpa_net *ndev,
+ struct mlx5_vdpa_virtqueue *mvq,
+ int state)
{
int inlen = MLX5_ST_SZ_BYTES(modify_virtio_net_q_in);
u32 out[MLX5_ST_SZ_DW(modify_virtio_net_q_out)] = {};
+ struct mlx5_vdpa_dev *mvdev = &ndev->mvdev;
+ struct mlx5_vdpa_mr *desc_mr = NULL;
+ struct mlx5_vdpa_mr *vq_mr = NULL;
+ bool state_change = false;
void *obj_context;
void *cmd_hdr;
+ void *vq_ctx;
void *in;
int err;
if (mvq->fw_state == MLX5_VIRTIO_NET_Q_OBJECT_NONE)
return 0;
- if (!is_valid_state_change(mvq->fw_state, state))
+ if (!modifiable_virtqueue_fields(mvq))
return -EINVAL;
in = kzalloc(inlen, GFP_KERNEL);
@@ -1208,17 +1251,83 @@ static int modify_virtqueue(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtque
MLX5_SET(general_obj_in_cmd_hdr, cmd_hdr, uid, ndev->mvdev.res.uid);
obj_context = MLX5_ADDR_OF(modify_virtio_net_q_in, in, obj_context);
- MLX5_SET64(virtio_net_q_object, obj_context, modify_field_select,
- MLX5_VIRTQ_MODIFY_MASK_STATE);
- MLX5_SET(virtio_net_q_object, obj_context, state, state);
+ vq_ctx = MLX5_ADDR_OF(virtio_net_q_object, obj_context, virtio_q_context);
+
+ if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_STATE) {
+ if (!is_valid_state_change(mvq->fw_state, state, is_resumable(ndev))) {
+ err = -EINVAL;
+ goto done;
+ }
+
+ MLX5_SET(virtio_net_q_object, obj_context, state, state);
+ state_change = true;
+ }
+
+ if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_ADDRS) {
+ MLX5_SET64(virtio_q, vq_ctx, desc_addr, mvq->desc_addr);
+ MLX5_SET64(virtio_q, vq_ctx, used_addr, mvq->device_addr);
+ MLX5_SET64(virtio_q, vq_ctx, available_addr, mvq->driver_addr);
+ }
+
+ if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_AVAIL_IDX)
+ MLX5_SET(virtio_net_q_object, obj_context, hw_available_index, mvq->avail_idx);
+
+ if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_USED_IDX)
+ MLX5_SET(virtio_net_q_object, obj_context, hw_used_index, mvq->used_idx);
+
+ if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_MKEY) {
+ vq_mr = mvdev->mr[mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP]];
+
+ if (vq_mr)
+ MLX5_SET(virtio_q, vq_ctx, virtio_q_mkey, vq_mr->mkey);
+ else
+ mvq->modified_fields &= ~MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_MKEY;
+ }
+
+ if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_DESC_GROUP_MKEY) {
+ desc_mr = mvdev->mr[mvdev->group2asid[MLX5_VDPA_DATAVQ_DESC_GROUP]];
+
+ if (desc_mr && MLX5_CAP_DEV_VDPA_EMULATION(mvdev->mdev, desc_group_mkey_supported))
+ MLX5_SET(virtio_q, vq_ctx, desc_group_mkey, desc_mr->mkey);
+ else
+ mvq->modified_fields &= ~MLX5_VIRTQ_MODIFY_MASK_DESC_GROUP_MKEY;
+ }
+
+ MLX5_SET64(virtio_net_q_object, obj_context, modify_field_select, mvq->modified_fields);
err = mlx5_cmd_exec(ndev->mvdev.mdev, in, inlen, out, sizeof(out));
- kfree(in);
- if (!err)
+ if (err)
+ goto done;
+
+ if (state_change)
mvq->fw_state = state;
+ if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_MKEY) {
+ mlx5_vdpa_put_mr(mvdev, mvq->vq_mr);
+ mlx5_vdpa_get_mr(mvdev, vq_mr);
+ mvq->vq_mr = vq_mr;
+ }
+
+ if (mvq->modified_fields & MLX5_VIRTQ_MODIFY_MASK_DESC_GROUP_MKEY) {
+ mlx5_vdpa_put_mr(mvdev, mvq->desc_mr);
+ mlx5_vdpa_get_mr(mvdev, desc_mr);
+ mvq->desc_mr = desc_mr;
+ }
+
+ mvq->modified_fields = 0;
+
+done:
+ kfree(in);
return err;
}
+static int modify_virtqueue_state(struct mlx5_vdpa_net *ndev,
+ struct mlx5_vdpa_virtqueue *mvq,
+ unsigned int state)
+{
+ mvq->modified_fields |= MLX5_VIRTQ_MODIFY_MASK_STATE;
+ return modify_virtqueue(ndev, mvq, state);
+}
+
static int counter_set_alloc(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq)
{
u32 in[MLX5_ST_SZ_DW(create_virtio_q_counters_in)] = {};
@@ -1347,7 +1456,7 @@ static int setup_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq)
goto err_vq;
if (mvq->ready) {
- err = modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY);
+ err = modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY);
if (err) {
mlx5_vdpa_warn(&ndev->mvdev, "failed to modify to ready vq idx %d(%d)\n",
idx, err);
@@ -1382,7 +1491,7 @@ static void suspend_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *m
if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY)
return;
- if (modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND))
+ if (modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND))
mlx5_vdpa_warn(&ndev->mvdev, "modify to suspend failed\n");
if (query_virtqueue(ndev, mvq, &attr)) {
@@ -1401,12 +1510,31 @@ static void suspend_vqs(struct mlx5_vdpa_net *ndev)
suspend_vq(ndev, &ndev->vqs[i]);
}
+static void resume_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq)
+{
+ if (!mvq->initialized || !is_resumable(ndev))
+ return;
+
+ if (mvq->fw_state != MLX5_VIRTIO_NET_Q_OBJECT_STATE_SUSPEND)
+ return;
+
+ if (modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY))
+ mlx5_vdpa_warn(&ndev->mvdev, "modify to resume failed for vq %u\n", mvq->index);
+}
+
+static void resume_vqs(struct mlx5_vdpa_net *ndev)
+{
+ for (int i = 0; i < ndev->mvdev.max_vqs; i++)
+ resume_vq(ndev, &ndev->vqs[i]);
+}
+
static void teardown_vq(struct mlx5_vdpa_net *ndev, struct mlx5_vdpa_virtqueue *mvq)
{
if (!mvq->initialized)
return;
suspend_vq(ndev, mvq);
+ mvq->modified_fields = 0;
destroy_virtqueue(ndev, mvq);
dealloc_vector(ndev, mvq);
counter_set_dealloc(ndev, mvq);
@@ -2138,6 +2266,7 @@ static int mlx5_vdpa_set_vq_address(struct vdpa_device *vdev, u16 idx, u64 desc_
mvq->desc_addr = desc_area;
mvq->device_addr = device_area;
mvq->driver_addr = driver_area;
+ mvq->modified_fields |= MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_ADDRS;
return 0;
}
@@ -2207,7 +2336,7 @@ static void mlx5_vdpa_set_vq_ready(struct vdpa_device *vdev, u16 idx, bool ready
if (!ready) {
suspend_vq(ndev, mvq);
} else {
- err = modify_virtqueue(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY);
+ err = modify_virtqueue_state(ndev, mvq, MLX5_VIRTIO_NET_Q_OBJECT_STATE_RDY);
if (err) {
mlx5_vdpa_warn(mvdev, "modify VQ %d to ready failed (%d)\n", idx, err);
ready = false;
@@ -2255,6 +2384,8 @@ static int mlx5_vdpa_set_vq_state(struct vdpa_device *vdev, u16 idx,
mvq->used_idx = state->split.avail_index;
mvq->avail_idx = state->split.avail_index;
+ mvq->modified_fields |= MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_AVAIL_IDX |
+ MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_USED_IDX;
return 0;
}
@@ -2703,24 +2834,35 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev,
unsigned int asid)
{
struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev);
+ bool teardown = !is_resumable(ndev);
int err;
suspend_vqs(ndev);
- err = save_channels_info(ndev);
- if (err)
- return err;
+ if (teardown) {
+ err = save_channels_info(ndev);
+ if (err)
+ return err;
- teardown_driver(ndev);
+ teardown_driver(ndev);
+ }
mlx5_vdpa_update_mr(mvdev, new_mr, asid);
+ for (int i = 0; i < ndev->cur_num_vqs; i++)
+ ndev->vqs[i].modified_fields |= MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_MKEY |
+ MLX5_VIRTQ_MODIFY_MASK_DESC_GROUP_MKEY;
+
if (!(mvdev->status & VIRTIO_CONFIG_S_DRIVER_OK) || mvdev->suspended)
return 0;
- restore_channels_info(ndev);
- err = setup_driver(mvdev);
- if (err)
- return err;
+ if (teardown) {
+ restore_channels_info(ndev);
+ err = setup_driver(mvdev);
+ if (err)
+ return err;
+ }
+
+ resume_vqs(ndev);
return 0;
}
@@ -2804,8 +2946,10 @@ static void clear_vqs_ready(struct mlx5_vdpa_net *ndev)
{
int i;
- for (i = 0; i < ndev->mvdev.max_vqs; i++)
+ for (i = 0; i < ndev->mvdev.max_vqs; i++) {
ndev->vqs[i].ready = false;
+ ndev->vqs[i].modified_fields = 0;
+ }
ndev->mvdev.cvq.ready = false;
}
@@ -2982,7 +3126,7 @@ static int set_map_data(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb,
return mlx5_vdpa_update_cvq_iotlb(mvdev, iotlb, asid);
out_err:
- mlx5_vdpa_destroy_mr(mvdev, new_mr);
+ mlx5_vdpa_put_mr(mvdev, new_mr);
return err;
}
@@ -3229,6 +3373,23 @@ static int mlx5_vdpa_suspend(struct vdpa_device *vdev)
return 0;
}
+static int mlx5_vdpa_resume(struct vdpa_device *vdev)
+{
+ struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev);
+ struct mlx5_vdpa_net *ndev;
+
+ ndev = to_mlx5_vdpa_ndev(mvdev);
+
+ mlx5_vdpa_info(mvdev, "resuming device\n");
+
+ down_write(&ndev->reslock);
+ mvdev->suspended = false;
+ resume_vqs(ndev);
+ register_link_notifier(ndev);
+ up_write(&ndev->reslock);
+ return 0;
+}
+
static int mlx5_set_group_asid(struct vdpa_device *vdev, u32 group,
unsigned int asid)
{
@@ -3285,6 +3446,7 @@ static const struct vdpa_config_ops mlx5_vdpa_ops = {
.get_vq_dma_dev = mlx5_get_vq_dma_dev,
.free = mlx5_vdpa_free,
.suspend = mlx5_vdpa_suspend,
+ .resume = mlx5_vdpa_resume, /* Op disabled if not supported. */
};
static int query_mtu(struct mlx5_core_dev *mdev, u16 *mtu)
@@ -3560,6 +3722,8 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name,
if (err)
goto err_mpfs;
+ INIT_LIST_HEAD(&mvdev->mr_list_head);
+
if (MLX5_CAP_GEN(mvdev->mdev, umem_uid_0)) {
err = mlx5_vdpa_create_dma_mr(mvdev);
if (err)
@@ -3656,6 +3820,9 @@ static int mlx5v_probe(struct auxiliary_device *adev,
if (!MLX5_CAP_DEV_VDPA_EMULATION(mdev, desc_group_mkey_supported))
mgtdev->vdpa_ops.get_vq_desc_group = NULL;
+ if (!MLX5_CAP_DEV_VDPA_EMULATION(mdev, freeze_to_rdy_supported))
+ mgtdev->vdpa_ops.resume = NULL;
+
err = vdpa_mgmtdev_register(&mgtdev->mgtdev);
if (err)
goto reg_err;
diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c
index a7612e0783b3..d0695680b282 100644
--- a/drivers/vdpa/vdpa.c
+++ b/drivers/vdpa/vdpa.c
@@ -131,7 +131,7 @@ static void vdpa_release_dev(struct device *d)
if (ops->free)
ops->free(vdev);
- ida_simple_remove(&vdpa_index_ida, vdev->index);
+ ida_free(&vdpa_index_ida, vdev->index);
kfree(vdev->driver_override);
kfree(vdev);
}
@@ -205,7 +205,7 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent,
return vdev;
err_name:
- ida_simple_remove(&vdpa_index_ida, vdev->index);
+ ida_free(&vdpa_index_ida, vdev->index);
err_ida:
kfree(vdev);
err:
diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
index 6bda6dbb4878..ceae52fd7586 100644
--- a/drivers/vfio/Kconfig
+++ b/drivers/vfio/Kconfig
@@ -80,6 +80,16 @@ config VFIO_VIRQFD
select EVENTFD
default n
+config VFIO_DEBUGFS
+ bool "Export VFIO internals in DebugFS"
+ depends on DEBUG_FS
+ help
+ Allows exposure of VFIO device internals. This option enables
+ the use of debugfs by VFIO drivers as required. The device can
+ cause the VFIO code create a top-level debug/vfio directory
+ during initialization, and then populate a subdirectory with
+ entries as required.
+
source "drivers/vfio/pci/Kconfig"
source "drivers/vfio/platform/Kconfig"
source "drivers/vfio/mdev/Kconfig"
diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
index 68c05705200f..b2fc9fb499d8 100644
--- a/drivers/vfio/Makefile
+++ b/drivers/vfio/Makefile
@@ -7,6 +7,7 @@ vfio-$(CONFIG_VFIO_GROUP) += group.o
vfio-$(CONFIG_IOMMUFD) += iommufd.o
vfio-$(CONFIG_VFIO_CONTAINER) += container.o
vfio-$(CONFIG_VFIO_VIRQFD) += virqfd.o
+vfio-$(CONFIG_VFIO_DEBUGFS) += debugfs.o
obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
diff --git a/drivers/vfio/debugfs.c b/drivers/vfio/debugfs.c
new file mode 100644
index 000000000000..298bd866f157
--- /dev/null
+++ b/drivers/vfio/debugfs.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, HiSilicon Ltd.
+ */
+
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/vfio.h>
+#include "vfio.h"
+
+static struct dentry *vfio_debugfs_root;
+
+static int vfio_device_state_read(struct seq_file *seq, void *data)
+{
+ struct device *vf_dev = seq->private;
+ struct vfio_device *vdev = container_of(vf_dev,
+ struct vfio_device, device);
+ enum vfio_device_mig_state state;
+ int ret;
+
+ BUILD_BUG_ON(VFIO_DEVICE_STATE_NR !=
+ VFIO_DEVICE_STATE_PRE_COPY_P2P + 1);
+
+ ret = vdev->mig_ops->migration_get_state(vdev, &state);
+ if (ret)
+ return -EINVAL;
+
+ switch (state) {
+ case VFIO_DEVICE_STATE_ERROR:
+ seq_puts(seq, "ERROR\n");
+ break;
+ case VFIO_DEVICE_STATE_STOP:
+ seq_puts(seq, "STOP\n");
+ break;
+ case VFIO_DEVICE_STATE_RUNNING:
+ seq_puts(seq, "RUNNING\n");
+ break;
+ case VFIO_DEVICE_STATE_STOP_COPY:
+ seq_puts(seq, "STOP_COPY\n");
+ break;
+ case VFIO_DEVICE_STATE_RESUMING:
+ seq_puts(seq, "RESUMING\n");
+ break;
+ case VFIO_DEVICE_STATE_RUNNING_P2P:
+ seq_puts(seq, "RUNNING_P2P\n");
+ break;
+ case VFIO_DEVICE_STATE_PRE_COPY:
+ seq_puts(seq, "PRE_COPY\n");
+ break;
+ case VFIO_DEVICE_STATE_PRE_COPY_P2P:
+ seq_puts(seq, "PRE_COPY_P2P\n");
+ break;
+ default:
+ seq_puts(seq, "Invalid\n");
+ }
+
+ return 0;
+}
+
+void vfio_device_debugfs_init(struct vfio_device *vdev)
+{
+ struct device *dev = &vdev->device;
+
+ vdev->debug_root = debugfs_create_dir(dev_name(vdev->dev),
+ vfio_debugfs_root);
+
+ if (vdev->mig_ops) {
+ struct dentry *vfio_dev_migration = NULL;
+
+ vfio_dev_migration = debugfs_create_dir("migration",
+ vdev->debug_root);
+ debugfs_create_devm_seqfile(dev, "state", vfio_dev_migration,
+ vfio_device_state_read);
+ }
+}
+
+void vfio_device_debugfs_exit(struct vfio_device *vdev)
+{
+ debugfs_remove_recursive(vdev->debug_root);
+}
+
+void vfio_debugfs_create_root(void)
+{
+ vfio_debugfs_root = debugfs_create_dir("vfio", NULL);
+}
+
+void vfio_debugfs_remove_root(void)
+{
+ debugfs_remove_recursive(vfio_debugfs_root);
+ vfio_debugfs_root = NULL;
+}
diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig
index 8125e5f37832..18c397df566d 100644
--- a/drivers/vfio/pci/Kconfig
+++ b/drivers/vfio/pci/Kconfig
@@ -65,4 +65,6 @@ source "drivers/vfio/pci/hisilicon/Kconfig"
source "drivers/vfio/pci/pds/Kconfig"
+source "drivers/vfio/pci/virtio/Kconfig"
+
endmenu
diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile
index 45167be462d8..046139a4eca5 100644
--- a/drivers/vfio/pci/Makefile
+++ b/drivers/vfio/pci/Makefile
@@ -13,3 +13,5 @@ obj-$(CONFIG_MLX5_VFIO_PCI) += mlx5/
obj-$(CONFIG_HISI_ACC_VFIO_PCI) += hisilicon/
obj-$(CONFIG_PDS_VFIO_PCI) += pds/
+
+obj-$(CONFIG_VIRTIO_VFIO_PCI) += virtio/
diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
index b2f9778c8366..4d27465c8f1a 100644
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
@@ -694,6 +694,7 @@ static ssize_t hisi_acc_vf_resume_write(struct file *filp, const char __user *bu
size_t len, loff_t *pos)
{
struct hisi_acc_vf_migration_file *migf = filp->private_data;
+ u8 *vf_data = (u8 *)&migf->vf_data;
loff_t requested_length;
ssize_t done = 0;
int ret;
@@ -715,7 +716,7 @@ static ssize_t hisi_acc_vf_resume_write(struct file *filp, const char __user *bu
goto out_unlock;
}
- ret = copy_from_user(&migf->vf_data, buf, len);
+ ret = copy_from_user(vf_data + *pos, buf, len);
if (ret) {
done = -EFAULT;
goto out_unlock;
@@ -835,7 +836,9 @@ static ssize_t hisi_acc_vf_save_read(struct file *filp, char __user *buf, size_t
len = min_t(size_t, migf->total_length - *pos, len);
if (len) {
- ret = copy_to_user(buf, &migf->vf_data, len);
+ u8 *vf_data = (u8 *)&migf->vf_data;
+
+ ret = copy_to_user(buf, vf_data + *pos, len);
if (ret) {
done = -EFAULT;
goto out_unlock;
diff --git a/drivers/vfio/pci/pds/dirty.c b/drivers/vfio/pci/pds/dirty.c
index c937aa6f3954..8ddf4346fcd5 100644
--- a/drivers/vfio/pci/pds/dirty.c
+++ b/drivers/vfio/pci/pds/dirty.c
@@ -70,7 +70,7 @@ out_free_region_info:
kfree(region_info);
}
-static int pds_vfio_dirty_alloc_bitmaps(struct pds_vfio_dirty *dirty,
+static int pds_vfio_dirty_alloc_bitmaps(struct pds_vfio_region *region,
unsigned long bytes)
{
unsigned long *host_seq_bmp, *host_ack_bmp;
@@ -85,47 +85,63 @@ static int pds_vfio_dirty_alloc_bitmaps(struct pds_vfio_dirty *dirty,
return -ENOMEM;
}
- dirty->host_seq.bmp = host_seq_bmp;
- dirty->host_ack.bmp = host_ack_bmp;
+ region->host_seq = host_seq_bmp;
+ region->host_ack = host_ack_bmp;
+ region->bmp_bytes = bytes;
return 0;
}
static void pds_vfio_dirty_free_bitmaps(struct pds_vfio_dirty *dirty)
{
- vfree(dirty->host_seq.bmp);
- vfree(dirty->host_ack.bmp);
- dirty->host_seq.bmp = NULL;
- dirty->host_ack.bmp = NULL;
+ if (!dirty->regions)
+ return;
+
+ for (int i = 0; i < dirty->num_regions; i++) {
+ struct pds_vfio_region *region = &dirty->regions[i];
+
+ vfree(region->host_seq);
+ vfree(region->host_ack);
+ region->host_seq = NULL;
+ region->host_ack = NULL;
+ region->bmp_bytes = 0;
+ }
}
static void __pds_vfio_dirty_free_sgl(struct pds_vfio_pci_device *pds_vfio,
- struct pds_vfio_bmp_info *bmp_info)
+ struct pds_vfio_region *region)
{
struct pci_dev *pdev = pds_vfio->vfio_coredev.pdev;
struct device *pdsc_dev = &pci_physfn(pdev)->dev;
- dma_unmap_single(pdsc_dev, bmp_info->sgl_addr,
- bmp_info->num_sge * sizeof(struct pds_lm_sg_elem),
+ dma_unmap_single(pdsc_dev, region->sgl_addr,
+ region->num_sge * sizeof(struct pds_lm_sg_elem),
DMA_BIDIRECTIONAL);
- kfree(bmp_info->sgl);
+ kfree(region->sgl);
- bmp_info->num_sge = 0;
- bmp_info->sgl = NULL;
- bmp_info->sgl_addr = 0;
+ region->num_sge = 0;
+ region->sgl = NULL;
+ region->sgl_addr = 0;
}
static void pds_vfio_dirty_free_sgl(struct pds_vfio_pci_device *pds_vfio)
{
- if (pds_vfio->dirty.host_seq.sgl)
- __pds_vfio_dirty_free_sgl(pds_vfio, &pds_vfio->dirty.host_seq);
- if (pds_vfio->dirty.host_ack.sgl)
- __pds_vfio_dirty_free_sgl(pds_vfio, &pds_vfio->dirty.host_ack);
+ struct pds_vfio_dirty *dirty = &pds_vfio->dirty;
+
+ if (!dirty->regions)
+ return;
+
+ for (int i = 0; i < dirty->num_regions; i++) {
+ struct pds_vfio_region *region = &dirty->regions[i];
+
+ if (region->sgl)
+ __pds_vfio_dirty_free_sgl(pds_vfio, region);
+ }
}
-static int __pds_vfio_dirty_alloc_sgl(struct pds_vfio_pci_device *pds_vfio,
- struct pds_vfio_bmp_info *bmp_info,
- u32 page_count)
+static int pds_vfio_dirty_alloc_sgl(struct pds_vfio_pci_device *pds_vfio,
+ struct pds_vfio_region *region,
+ u32 page_count)
{
struct pci_dev *pdev = pds_vfio->vfio_coredev.pdev;
struct device *pdsc_dev = &pci_physfn(pdev)->dev;
@@ -147,32 +163,81 @@ static int __pds_vfio_dirty_alloc_sgl(struct pds_vfio_pci_device *pds_vfio,
return -EIO;
}
- bmp_info->sgl = sgl;
- bmp_info->num_sge = max_sge;
- bmp_info->sgl_addr = sgl_addr;
+ region->sgl = sgl;
+ region->num_sge = max_sge;
+ region->sgl_addr = sgl_addr;
return 0;
}
-static int pds_vfio_dirty_alloc_sgl(struct pds_vfio_pci_device *pds_vfio,
- u32 page_count)
+static void pds_vfio_dirty_free_regions(struct pds_vfio_dirty *dirty)
{
+ vfree(dirty->regions);
+ dirty->regions = NULL;
+ dirty->num_regions = 0;
+}
+
+static int pds_vfio_dirty_alloc_regions(struct pds_vfio_pci_device *pds_vfio,
+ struct pds_lm_dirty_region_info *region_info,
+ u64 region_page_size, u8 num_regions)
+{
+ struct pci_dev *pdev = pds_vfio->vfio_coredev.pdev;
struct pds_vfio_dirty *dirty = &pds_vfio->dirty;
+ u32 dev_bmp_offset_byte = 0;
int err;
- err = __pds_vfio_dirty_alloc_sgl(pds_vfio, &dirty->host_seq,
- page_count);
- if (err)
- return err;
+ dirty->regions = vcalloc(num_regions, sizeof(struct pds_vfio_region));
+ if (!dirty->regions)
+ return -ENOMEM;
+ dirty->num_regions = num_regions;
+
+ for (int i = 0; i < num_regions; i++) {
+ struct pds_lm_dirty_region_info *ri = &region_info[i];
+ struct pds_vfio_region *region = &dirty->regions[i];
+ u64 region_size, region_start;
+ u32 page_count;
+
+ /* page_count might be adjusted by the device */
+ page_count = le32_to_cpu(ri->page_count);
+ region_start = le64_to_cpu(ri->dma_base);
+ region_size = page_count * region_page_size;
+
+ err = pds_vfio_dirty_alloc_bitmaps(region,
+ page_count / BITS_PER_BYTE);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to alloc dirty bitmaps: %pe\n",
+ ERR_PTR(err));
+ goto out_free_regions;
+ }
- err = __pds_vfio_dirty_alloc_sgl(pds_vfio, &dirty->host_ack,
- page_count);
- if (err) {
- __pds_vfio_dirty_free_sgl(pds_vfio, &dirty->host_seq);
- return err;
+ err = pds_vfio_dirty_alloc_sgl(pds_vfio, region, page_count);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to alloc dirty sg lists: %pe\n",
+ ERR_PTR(err));
+ goto out_free_regions;
+ }
+
+ region->size = region_size;
+ region->start = region_start;
+ region->page_size = region_page_size;
+ region->dev_bmp_offset_start_byte = dev_bmp_offset_byte;
+
+ dev_bmp_offset_byte += page_count / BITS_PER_BYTE;
+ if (dev_bmp_offset_byte % BITS_PER_BYTE) {
+ dev_err(&pdev->dev, "Device bitmap offset is mis-aligned\n");
+ err = -EINVAL;
+ goto out_free_regions;
+ }
}
return 0;
+
+out_free_regions:
+ pds_vfio_dirty_free_bitmaps(dirty);
+ pds_vfio_dirty_free_sgl(pds_vfio);
+ pds_vfio_dirty_free_regions(dirty);
+
+ return err;
}
static int pds_vfio_dirty_enable(struct pds_vfio_pci_device *pds_vfio,
@@ -181,16 +246,14 @@ static int pds_vfio_dirty_enable(struct pds_vfio_pci_device *pds_vfio,
{
struct pci_dev *pdev = pds_vfio->vfio_coredev.pdev;
struct device *pdsc_dev = &pci_physfn(pdev)->dev;
- struct pds_vfio_dirty *dirty = &pds_vfio->dirty;
- u64 region_start, region_size, region_page_size;
struct pds_lm_dirty_region_info *region_info;
struct interval_tree_node *node = NULL;
+ u64 region_page_size = *page_size;
u8 max_regions = 0, num_regions;
dma_addr_t regions_dma = 0;
u32 num_ranges = nnodes;
- u32 page_count;
- u16 len;
int err;
+ u16 len;
dev_dbg(&pdev->dev, "vf%u: Start dirty page tracking\n",
pds_vfio->vf_id);
@@ -217,39 +280,38 @@ static int pds_vfio_dirty_enable(struct pds_vfio_pci_device *pds_vfio,
return -EOPNOTSUPP;
}
- /*
- * Only support 1 region for now. If there are any large gaps in the
- * VM's address regions, then this would be a waste of memory as we are
- * generating 2 bitmaps (ack/seq) from the min address to the max
- * address of the VM's address regions. In the future, if we support
- * more than one region in the device/driver we can split the bitmaps
- * on the largest address region gaps. We can do this split up to the
- * max_regions times returned from the dirty_status command.
- */
- max_regions = 1;
if (num_ranges > max_regions) {
vfio_combine_iova_ranges(ranges, nnodes, max_regions);
num_ranges = max_regions;
}
+ region_info = kcalloc(num_ranges, sizeof(*region_info), GFP_KERNEL);
+ if (!region_info)
+ return -ENOMEM;
+ len = num_ranges * sizeof(*region_info);
+
node = interval_tree_iter_first(ranges, 0, ULONG_MAX);
if (!node)
return -EINVAL;
+ for (int i = 0; i < num_ranges; i++) {
+ struct pds_lm_dirty_region_info *ri = &region_info[i];
+ u64 region_size = node->last - node->start + 1;
+ u64 region_start = node->start;
+ u32 page_count;
- region_size = node->last - node->start + 1;
- region_start = node->start;
- region_page_size = *page_size;
+ page_count = DIV_ROUND_UP(region_size, region_page_size);
- len = sizeof(*region_info);
- region_info = kzalloc(len, GFP_KERNEL);
- if (!region_info)
- return -ENOMEM;
+ ri->dma_base = cpu_to_le64(region_start);
+ ri->page_count = cpu_to_le32(page_count);
+ ri->page_size_log2 = ilog2(region_page_size);
- page_count = DIV_ROUND_UP(region_size, region_page_size);
+ dev_dbg(&pdev->dev,
+ "region_info[%d]: region_start 0x%llx region_end 0x%lx region_size 0x%llx page_count %u page_size %llu\n",
+ i, region_start, node->last, region_size, page_count,
+ region_page_size);
- region_info->dma_base = cpu_to_le64(region_start);
- region_info->page_count = cpu_to_le32(page_count);
- region_info->page_size_log2 = ilog2(region_page_size);
+ node = interval_tree_iter_next(node, 0, ULONG_MAX);
+ }
regions_dma = dma_map_single(pdsc_dev, (void *)region_info, len,
DMA_BIDIRECTIONAL);
@@ -258,39 +320,20 @@ static int pds_vfio_dirty_enable(struct pds_vfio_pci_device *pds_vfio,
goto out_free_region_info;
}
- err = pds_vfio_dirty_enable_cmd(pds_vfio, regions_dma, max_regions);
+ err = pds_vfio_dirty_enable_cmd(pds_vfio, regions_dma, num_ranges);
dma_unmap_single(pdsc_dev, regions_dma, len, DMA_BIDIRECTIONAL);
if (err)
goto out_free_region_info;
- /*
- * page_count might be adjusted by the device,
- * update it before freeing region_info DMA
- */
- page_count = le32_to_cpu(region_info->page_count);
-
- dev_dbg(&pdev->dev,
- "region_info: regions_dma 0x%llx dma_base 0x%llx page_count %u page_size_log2 %u\n",
- regions_dma, region_start, page_count,
- (u8)ilog2(region_page_size));
-
- err = pds_vfio_dirty_alloc_bitmaps(dirty, page_count / BITS_PER_BYTE);
- if (err) {
- dev_err(&pdev->dev, "Failed to alloc dirty bitmaps: %pe\n",
- ERR_PTR(err));
- goto out_free_region_info;
- }
-
- err = pds_vfio_dirty_alloc_sgl(pds_vfio, page_count);
+ err = pds_vfio_dirty_alloc_regions(pds_vfio, region_info,
+ region_page_size, num_ranges);
if (err) {
- dev_err(&pdev->dev, "Failed to alloc dirty sg lists: %pe\n",
- ERR_PTR(err));
- goto out_free_bitmaps;
+ dev_err(&pdev->dev,
+ "Failed to allocate %d regions for tracking dirty regions: %pe\n",
+ num_regions, ERR_PTR(err));
+ goto out_dirty_disable;
}
- dirty->region_start = region_start;
- dirty->region_size = region_size;
- dirty->region_page_size = region_page_size;
pds_vfio_dirty_set_enabled(pds_vfio);
pds_vfio_print_guest_region_info(pds_vfio, max_regions);
@@ -299,8 +342,8 @@ static int pds_vfio_dirty_enable(struct pds_vfio_pci_device *pds_vfio,
return 0;
-out_free_bitmaps:
- pds_vfio_dirty_free_bitmaps(dirty);
+out_dirty_disable:
+ pds_vfio_dirty_disable_cmd(pds_vfio);
out_free_region_info:
kfree(region_info);
return err;
@@ -314,6 +357,7 @@ void pds_vfio_dirty_disable(struct pds_vfio_pci_device *pds_vfio, bool send_cmd)
pds_vfio_dirty_disable_cmd(pds_vfio);
pds_vfio_dirty_free_sgl(pds_vfio);
pds_vfio_dirty_free_bitmaps(&pds_vfio->dirty);
+ pds_vfio_dirty_free_regions(&pds_vfio->dirty);
}
if (send_cmd)
@@ -321,8 +365,9 @@ void pds_vfio_dirty_disable(struct pds_vfio_pci_device *pds_vfio, bool send_cmd)
}
static int pds_vfio_dirty_seq_ack(struct pds_vfio_pci_device *pds_vfio,
- struct pds_vfio_bmp_info *bmp_info,
- u32 offset, u32 bmp_bytes, bool read_seq)
+ struct pds_vfio_region *region,
+ unsigned long *seq_ack_bmp, u32 offset,
+ u32 bmp_bytes, bool read_seq)
{
const char *bmp_type_str = read_seq ? "read_seq" : "write_ack";
u8 dma_dir = read_seq ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
@@ -339,7 +384,7 @@ static int pds_vfio_dirty_seq_ack(struct pds_vfio_pci_device *pds_vfio,
int err;
int i;
- bmp = (void *)((u64)bmp_info->bmp + offset);
+ bmp = (void *)((u64)seq_ack_bmp + offset);
page_offset = offset_in_page(bmp);
bmp -= page_offset;
@@ -375,7 +420,7 @@ static int pds_vfio_dirty_seq_ack(struct pds_vfio_pci_device *pds_vfio,
goto out_free_sg_table;
for_each_sgtable_dma_sg(&sg_table, sg, i) {
- struct pds_lm_sg_elem *sg_elem = &bmp_info->sgl[i];
+ struct pds_lm_sg_elem *sg_elem = &region->sgl[i];
sg_elem->addr = cpu_to_le64(sg_dma_address(sg));
sg_elem->len = cpu_to_le32(sg_dma_len(sg));
@@ -383,15 +428,16 @@ static int pds_vfio_dirty_seq_ack(struct pds_vfio_pci_device *pds_vfio,
num_sge = sg_table.nents;
size = num_sge * sizeof(struct pds_lm_sg_elem);
- dma_sync_single_for_device(pdsc_dev, bmp_info->sgl_addr, size, dma_dir);
- err = pds_vfio_dirty_seq_ack_cmd(pds_vfio, bmp_info->sgl_addr, num_sge,
+ offset += region->dev_bmp_offset_start_byte;
+ dma_sync_single_for_device(pdsc_dev, region->sgl_addr, size, dma_dir);
+ err = pds_vfio_dirty_seq_ack_cmd(pds_vfio, region->sgl_addr, num_sge,
offset, bmp_bytes, read_seq);
if (err)
dev_err(&pdev->dev,
"Dirty bitmap %s failed offset %u bmp_bytes %u num_sge %u DMA 0x%llx: %pe\n",
bmp_type_str, offset, bmp_bytes,
- num_sge, bmp_info->sgl_addr, ERR_PTR(err));
- dma_sync_single_for_cpu(pdsc_dev, bmp_info->sgl_addr, size, dma_dir);
+ num_sge, region->sgl_addr, ERR_PTR(err));
+ dma_sync_single_for_cpu(pdsc_dev, region->sgl_addr, size, dma_dir);
dma_unmap_sgtable(pdsc_dev, &sg_table, dma_dir, 0);
out_free_sg_table:
@@ -403,32 +449,36 @@ out_free_pages:
}
static int pds_vfio_dirty_write_ack(struct pds_vfio_pci_device *pds_vfio,
+ struct pds_vfio_region *region,
u32 offset, u32 len)
{
- return pds_vfio_dirty_seq_ack(pds_vfio, &pds_vfio->dirty.host_ack,
+
+ return pds_vfio_dirty_seq_ack(pds_vfio, region, region->host_ack,
offset, len, WRITE_ACK);
}
static int pds_vfio_dirty_read_seq(struct pds_vfio_pci_device *pds_vfio,
+ struct pds_vfio_region *region,
u32 offset, u32 len)
{
- return pds_vfio_dirty_seq_ack(pds_vfio, &pds_vfio->dirty.host_seq,
+ return pds_vfio_dirty_seq_ack(pds_vfio, region, region->host_seq,
offset, len, READ_SEQ);
}
static int pds_vfio_dirty_process_bitmaps(struct pds_vfio_pci_device *pds_vfio,
+ struct pds_vfio_region *region,
struct iova_bitmap *dirty_bitmap,
u32 bmp_offset, u32 len_bytes)
{
- u64 page_size = pds_vfio->dirty.region_page_size;
- u64 region_start = pds_vfio->dirty.region_start;
+ u64 page_size = region->page_size;
+ u64 region_start = region->start;
u32 bmp_offset_bit;
__le64 *seq, *ack;
int dword_count;
dword_count = len_bytes / sizeof(u64);
- seq = (__le64 *)((u64)pds_vfio->dirty.host_seq.bmp + bmp_offset);
- ack = (__le64 *)((u64)pds_vfio->dirty.host_ack.bmp + bmp_offset);
+ seq = (__le64 *)((u64)region->host_seq + bmp_offset);
+ ack = (__le64 *)((u64)region->host_ack + bmp_offset);
bmp_offset_bit = bmp_offset * 8;
for (int i = 0; i < dword_count; i++) {
@@ -451,12 +501,28 @@ static int pds_vfio_dirty_process_bitmaps(struct pds_vfio_pci_device *pds_vfio,
return 0;
}
+static struct pds_vfio_region *
+pds_vfio_get_region(struct pds_vfio_pci_device *pds_vfio, unsigned long iova)
+{
+ struct pds_vfio_dirty *dirty = &pds_vfio->dirty;
+
+ for (int i = 0; i < dirty->num_regions; i++) {
+ struct pds_vfio_region *region = &dirty->regions[i];
+
+ if (iova >= region->start &&
+ iova < (region->start + region->size))
+ return region;
+ }
+
+ return NULL;
+}
+
static int pds_vfio_dirty_sync(struct pds_vfio_pci_device *pds_vfio,
struct iova_bitmap *dirty_bitmap,
unsigned long iova, unsigned long length)
{
struct device *dev = &pds_vfio->vfio_coredev.pdev->dev;
- struct pds_vfio_dirty *dirty = &pds_vfio->dirty;
+ struct pds_vfio_region *region;
u64 bmp_offset, bmp_bytes;
u64 bitmap_size, pages;
int err;
@@ -469,26 +535,31 @@ static int pds_vfio_dirty_sync(struct pds_vfio_pci_device *pds_vfio,
return -EINVAL;
}
- pages = DIV_ROUND_UP(length, pds_vfio->dirty.region_page_size);
+ region = pds_vfio_get_region(pds_vfio, iova);
+ if (!region) {
+ dev_err(dev, "vf%u: Failed to find region that contains iova 0x%lx length 0x%lx\n",
+ pds_vfio->vf_id, iova, length);
+ return -EINVAL;
+ }
+
+ pages = DIV_ROUND_UP(length, region->page_size);
bitmap_size =
round_up(pages, sizeof(u64) * BITS_PER_BYTE) / BITS_PER_BYTE;
dev_dbg(dev,
"vf%u: iova 0x%lx length %lu page_size %llu pages %llu bitmap_size %llu\n",
- pds_vfio->vf_id, iova, length, pds_vfio->dirty.region_page_size,
+ pds_vfio->vf_id, iova, length, region->page_size,
pages, bitmap_size);
- if (!length || ((dirty->region_start + iova + length) >
- (dirty->region_start + dirty->region_size))) {
+ if (!length || ((iova - region->start + length) > region->size)) {
dev_err(dev, "Invalid iova 0x%lx and/or length 0x%lx to sync\n",
iova, length);
return -EINVAL;
}
/* bitmap is modified in 64 bit chunks */
- bmp_bytes = ALIGN(DIV_ROUND_UP(length / dirty->region_page_size,
- sizeof(u64)),
- sizeof(u64));
+ bmp_bytes = ALIGN(DIV_ROUND_UP(length / region->page_size,
+ sizeof(u64)), sizeof(u64));
if (bmp_bytes != bitmap_size) {
dev_err(dev,
"Calculated bitmap bytes %llu not equal to bitmap size %llu\n",
@@ -496,22 +567,30 @@ static int pds_vfio_dirty_sync(struct pds_vfio_pci_device *pds_vfio,
return -EINVAL;
}
- bmp_offset = DIV_ROUND_UP(iova / dirty->region_page_size, sizeof(u64));
+ if (bmp_bytes > region->bmp_bytes) {
+ dev_err(dev,
+ "Calculated bitmap bytes %llu larger than region's cached bmp_bytes %llu\n",
+ bmp_bytes, region->bmp_bytes);
+ return -EINVAL;
+ }
+
+ bmp_offset = DIV_ROUND_UP((iova - region->start) /
+ region->page_size, sizeof(u64));
dev_dbg(dev,
"Syncing dirty bitmap, iova 0x%lx length 0x%lx, bmp_offset %llu bmp_bytes %llu\n",
iova, length, bmp_offset, bmp_bytes);
- err = pds_vfio_dirty_read_seq(pds_vfio, bmp_offset, bmp_bytes);
+ err = pds_vfio_dirty_read_seq(pds_vfio, region, bmp_offset, bmp_bytes);
if (err)
return err;
- err = pds_vfio_dirty_process_bitmaps(pds_vfio, dirty_bitmap, bmp_offset,
- bmp_bytes);
+ err = pds_vfio_dirty_process_bitmaps(pds_vfio, region, dirty_bitmap,
+ bmp_offset, bmp_bytes);
if (err)
return err;
- err = pds_vfio_dirty_write_ack(pds_vfio, bmp_offset, bmp_bytes);
+ err = pds_vfio_dirty_write_ack(pds_vfio, region, bmp_offset, bmp_bytes);
if (err)
return err;
diff --git a/drivers/vfio/pci/pds/dirty.h b/drivers/vfio/pci/pds/dirty.h
index f78da25d75ca..c8e23018b801 100644
--- a/drivers/vfio/pci/pds/dirty.h
+++ b/drivers/vfio/pci/pds/dirty.h
@@ -4,20 +4,22 @@
#ifndef _DIRTY_H_
#define _DIRTY_H_
-struct pds_vfio_bmp_info {
- unsigned long *bmp;
- u32 bmp_bytes;
+struct pds_vfio_region {
+ unsigned long *host_seq;
+ unsigned long *host_ack;
+ u64 bmp_bytes;
+ u64 size;
+ u64 start;
+ u64 page_size;
struct pds_lm_sg_elem *sgl;
dma_addr_t sgl_addr;
+ u32 dev_bmp_offset_start_byte;
u16 num_sge;
};
struct pds_vfio_dirty {
- struct pds_vfio_bmp_info host_seq;
- struct pds_vfio_bmp_info host_ack;
- u64 region_size;
- u64 region_start;
- u64 region_page_size;
+ struct pds_vfio_region *regions;
+ u8 num_regions;
bool is_enabled;
};
diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c
index e27de61ac9fe..07fea08ea8a2 100644
--- a/drivers/vfio/pci/vfio_pci_rdwr.c
+++ b/drivers/vfio/pci/vfio_pci_rdwr.c
@@ -38,7 +38,7 @@
#define vfio_iowrite8 iowrite8
#define VFIO_IOWRITE(size) \
-static int vfio_pci_iowrite##size(struct vfio_pci_core_device *vdev, \
+int vfio_pci_core_iowrite##size(struct vfio_pci_core_device *vdev, \
bool test_mem, u##size val, void __iomem *io) \
{ \
if (test_mem) { \
@@ -55,7 +55,8 @@ static int vfio_pci_iowrite##size(struct vfio_pci_core_device *vdev, \
up_read(&vdev->memory_lock); \
\
return 0; \
-}
+} \
+EXPORT_SYMBOL_GPL(vfio_pci_core_iowrite##size);
VFIO_IOWRITE(8)
VFIO_IOWRITE(16)
@@ -65,7 +66,7 @@ VFIO_IOWRITE(64)
#endif
#define VFIO_IOREAD(size) \
-static int vfio_pci_ioread##size(struct vfio_pci_core_device *vdev, \
+int vfio_pci_core_ioread##size(struct vfio_pci_core_device *vdev, \
bool test_mem, u##size *val, void __iomem *io) \
{ \
if (test_mem) { \
@@ -82,7 +83,8 @@ static int vfio_pci_ioread##size(struct vfio_pci_core_device *vdev, \
up_read(&vdev->memory_lock); \
\
return 0; \
-}
+} \
+EXPORT_SYMBOL_GPL(vfio_pci_core_ioread##size);
VFIO_IOREAD(8)
VFIO_IOREAD(16)
@@ -119,13 +121,13 @@ static ssize_t do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
if (copy_from_user(&val, buf, 4))
return -EFAULT;
- ret = vfio_pci_iowrite32(vdev, test_mem,
- val, io + off);
+ ret = vfio_pci_core_iowrite32(vdev, test_mem,
+ val, io + off);
if (ret)
return ret;
} else {
- ret = vfio_pci_ioread32(vdev, test_mem,
- &val, io + off);
+ ret = vfio_pci_core_ioread32(vdev, test_mem,
+ &val, io + off);
if (ret)
return ret;
@@ -141,13 +143,13 @@ static ssize_t do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
if (copy_from_user(&val, buf, 2))
return -EFAULT;
- ret = vfio_pci_iowrite16(vdev, test_mem,
- val, io + off);
+ ret = vfio_pci_core_iowrite16(vdev, test_mem,
+ val, io + off);
if (ret)
return ret;
} else {
- ret = vfio_pci_ioread16(vdev, test_mem,
- &val, io + off);
+ ret = vfio_pci_core_ioread16(vdev, test_mem,
+ &val, io + off);
if (ret)
return ret;
@@ -163,13 +165,13 @@ static ssize_t do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
if (copy_from_user(&val, buf, 1))
return -EFAULT;
- ret = vfio_pci_iowrite8(vdev, test_mem,
- val, io + off);
+ ret = vfio_pci_core_iowrite8(vdev, test_mem,
+ val, io + off);
if (ret)
return ret;
} else {
- ret = vfio_pci_ioread8(vdev, test_mem,
- &val, io + off);
+ ret = vfio_pci_core_ioread8(vdev, test_mem,
+ &val, io + off);
if (ret)
return ret;
@@ -200,7 +202,7 @@ static ssize_t do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem,
return done;
}
-static int vfio_pci_setup_barmap(struct vfio_pci_core_device *vdev, int bar)
+int vfio_pci_core_setup_barmap(struct vfio_pci_core_device *vdev, int bar)
{
struct pci_dev *pdev = vdev->pdev;
int ret;
@@ -223,6 +225,7 @@ static int vfio_pci_setup_barmap(struct vfio_pci_core_device *vdev, int bar)
return 0;
}
+EXPORT_SYMBOL_GPL(vfio_pci_core_setup_barmap);
ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
size_t count, loff_t *ppos, bool iswrite)
@@ -262,7 +265,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf,
}
x_end = end;
} else {
- int ret = vfio_pci_setup_barmap(vdev, bar);
+ int ret = vfio_pci_core_setup_barmap(vdev, bar);
if (ret) {
done = ret;
goto out;
@@ -363,21 +366,21 @@ static void vfio_pci_ioeventfd_do_write(struct vfio_pci_ioeventfd *ioeventfd,
{
switch (ioeventfd->count) {
case 1:
- vfio_pci_iowrite8(ioeventfd->vdev, test_mem,
- ioeventfd->data, ioeventfd->addr);
+ vfio_pci_core_iowrite8(ioeventfd->vdev, test_mem,
+ ioeventfd->data, ioeventfd->addr);
break;
case 2:
- vfio_pci_iowrite16(ioeventfd->vdev, test_mem,
- ioeventfd->data, ioeventfd->addr);
+ vfio_pci_core_iowrite16(ioeventfd->vdev, test_mem,
+ ioeventfd->data, ioeventfd->addr);
break;
case 4:
- vfio_pci_iowrite32(ioeventfd->vdev, test_mem,
- ioeventfd->data, ioeventfd->addr);
+ vfio_pci_core_iowrite32(ioeventfd->vdev, test_mem,
+ ioeventfd->data, ioeventfd->addr);
break;
#ifdef iowrite64
case 8:
- vfio_pci_iowrite64(ioeventfd->vdev, test_mem,
- ioeventfd->data, ioeventfd->addr);
+ vfio_pci_core_iowrite64(ioeventfd->vdev, test_mem,
+ ioeventfd->data, ioeventfd->addr);
break;
#endif
}
@@ -438,7 +441,7 @@ int vfio_pci_ioeventfd(struct vfio_pci_core_device *vdev, loff_t offset,
return -EINVAL;
#endif
- ret = vfio_pci_setup_barmap(vdev, bar);
+ ret = vfio_pci_core_setup_barmap(vdev, bar);
if (ret)
return ret;
diff --git a/drivers/vfio/pci/virtio/Kconfig b/drivers/vfio/pci/virtio/Kconfig
new file mode 100644
index 000000000000..bd80eca4a196
--- /dev/null
+++ b/drivers/vfio/pci/virtio/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VIRTIO_VFIO_PCI
+ tristate "VFIO support for VIRTIO NET PCI devices"
+ depends on VIRTIO_PCI && VIRTIO_PCI_ADMIN_LEGACY
+ select VFIO_PCI_CORE
+ help
+ This provides support for exposing VIRTIO NET VF devices which support
+ legacy IO access, using the VFIO framework that can work with a legacy
+ virtio driver in the guest.
+ Based on PCIe spec, VFs do not support I/O Space.
+ As of that this driver emulates I/O BAR in software to let a VF be
+ seen as a transitional device by its users and let it work with
+ a legacy driver.
+
+ If you don't know what to do here, say N.
diff --git a/drivers/vfio/pci/virtio/Makefile b/drivers/vfio/pci/virtio/Makefile
new file mode 100644
index 000000000000..7171105baf33
--- /dev/null
+++ b/drivers/vfio/pci/virtio/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_VIRTIO_VFIO_PCI) += virtio-vfio-pci.o
+virtio-vfio-pci-y := main.o
diff --git a/drivers/vfio/pci/virtio/main.c b/drivers/vfio/pci/virtio/main.c
new file mode 100644
index 000000000000..d5af683837d3
--- /dev/null
+++ b/drivers/vfio/pci/virtio/main.c
@@ -0,0 +1,576 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/vfio.h>
+#include <linux/vfio_pci_core.h>
+#include <linux/virtio_pci.h>
+#include <linux/virtio_net.h>
+#include <linux/virtio_pci_admin.h>
+
+struct virtiovf_pci_core_device {
+ struct vfio_pci_core_device core_device;
+ u8 *bar0_virtual_buf;
+ /* synchronize access to the virtual buf */
+ struct mutex bar_mutex;
+ void __iomem *notify_addr;
+ u64 notify_offset;
+ __le32 pci_base_addr_0;
+ __le16 pci_cmd;
+ u8 bar0_virtual_buf_size;
+ u8 notify_bar;
+};
+
+static int
+virtiovf_issue_legacy_rw_cmd(struct virtiovf_pci_core_device *virtvdev,
+ loff_t pos, char __user *buf,
+ size_t count, bool read)
+{
+ bool msix_enabled =
+ (virtvdev->core_device.irq_type == VFIO_PCI_MSIX_IRQ_INDEX);
+ struct pci_dev *pdev = virtvdev->core_device.pdev;
+ u8 *bar0_buf = virtvdev->bar0_virtual_buf;
+ bool common;
+ u8 offset;
+ int ret;
+
+ common = pos < VIRTIO_PCI_CONFIG_OFF(msix_enabled);
+ /* offset within the relevant configuration area */
+ offset = common ? pos : pos - VIRTIO_PCI_CONFIG_OFF(msix_enabled);
+ mutex_lock(&virtvdev->bar_mutex);
+ if (read) {
+ if (common)
+ ret = virtio_pci_admin_legacy_common_io_read(pdev, offset,
+ count, bar0_buf + pos);
+ else
+ ret = virtio_pci_admin_legacy_device_io_read(pdev, offset,
+ count, bar0_buf + pos);
+ if (ret)
+ goto out;
+ if (copy_to_user(buf, bar0_buf + pos, count))
+ ret = -EFAULT;
+ } else {
+ if (copy_from_user(bar0_buf + pos, buf, count)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (common)
+ ret = virtio_pci_admin_legacy_common_io_write(pdev, offset,
+ count, bar0_buf + pos);
+ else
+ ret = virtio_pci_admin_legacy_device_io_write(pdev, offset,
+ count, bar0_buf + pos);
+ }
+out:
+ mutex_unlock(&virtvdev->bar_mutex);
+ return ret;
+}
+
+static int
+virtiovf_pci_bar0_rw(struct virtiovf_pci_core_device *virtvdev,
+ loff_t pos, char __user *buf,
+ size_t count, bool read)
+{
+ struct vfio_pci_core_device *core_device = &virtvdev->core_device;
+ struct pci_dev *pdev = core_device->pdev;
+ u16 queue_notify;
+ int ret;
+
+ if (!(le16_to_cpu(virtvdev->pci_cmd) & PCI_COMMAND_IO))
+ return -EIO;
+
+ if (pos + count > virtvdev->bar0_virtual_buf_size)
+ return -EINVAL;
+
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret) {
+ pci_info_ratelimited(pdev, "runtime resume failed %d\n", ret);
+ return -EIO;
+ }
+
+ switch (pos) {
+ case VIRTIO_PCI_QUEUE_NOTIFY:
+ if (count != sizeof(queue_notify)) {
+ ret = -EINVAL;
+ goto end;
+ }
+ if (read) {
+ ret = vfio_pci_core_ioread16(core_device, true, &queue_notify,
+ virtvdev->notify_addr);
+ if (ret)
+ goto end;
+ if (copy_to_user(buf, &queue_notify,
+ sizeof(queue_notify))) {
+ ret = -EFAULT;
+ goto end;
+ }
+ } else {
+ if (copy_from_user(&queue_notify, buf, count)) {
+ ret = -EFAULT;
+ goto end;
+ }
+ ret = vfio_pci_core_iowrite16(core_device, true, queue_notify,
+ virtvdev->notify_addr);
+ }
+ break;
+ default:
+ ret = virtiovf_issue_legacy_rw_cmd(virtvdev, pos, buf, count,
+ read);
+ }
+
+end:
+ pm_runtime_put(&pdev->dev);
+ return ret ? ret : count;
+}
+
+static bool range_intersect_range(loff_t range1_start, size_t count1,
+ loff_t range2_start, size_t count2,
+ loff_t *start_offset,
+ size_t *intersect_count,
+ size_t *register_offset)
+{
+ if (range1_start <= range2_start &&
+ range1_start + count1 > range2_start) {
+ *start_offset = range2_start - range1_start;
+ *intersect_count = min_t(size_t, count2,
+ range1_start + count1 - range2_start);
+ *register_offset = 0;
+ return true;
+ }
+
+ if (range1_start > range2_start &&
+ range1_start < range2_start + count2) {
+ *start_offset = 0;
+ *intersect_count = min_t(size_t, count1,
+ range2_start + count2 - range1_start);
+ *register_offset = range1_start - range2_start;
+ return true;
+ }
+
+ return false;
+}
+
+static ssize_t virtiovf_pci_read_config(struct vfio_device *core_vdev,
+ char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct virtiovf_pci_core_device *virtvdev = container_of(
+ core_vdev, struct virtiovf_pci_core_device, core_device.vdev);
+ loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
+ size_t register_offset;
+ loff_t copy_offset;
+ size_t copy_count;
+ __le32 val32;
+ __le16 val16;
+ u8 val8;
+ int ret;
+
+ ret = vfio_pci_core_read(core_vdev, buf, count, ppos);
+ if (ret < 0)
+ return ret;
+
+ if (range_intersect_range(pos, count, PCI_DEVICE_ID, sizeof(val16),
+ &copy_offset, &copy_count, &register_offset)) {
+ val16 = cpu_to_le16(VIRTIO_TRANS_ID_NET);
+ if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset, copy_count))
+ return -EFAULT;
+ }
+
+ if ((le16_to_cpu(virtvdev->pci_cmd) & PCI_COMMAND_IO) &&
+ range_intersect_range(pos, count, PCI_COMMAND, sizeof(val16),
+ &copy_offset, &copy_count, &register_offset)) {
+ if (copy_from_user((void *)&val16 + register_offset, buf + copy_offset,
+ copy_count))
+ return -EFAULT;
+ val16 |= cpu_to_le16(PCI_COMMAND_IO);
+ if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset,
+ copy_count))
+ return -EFAULT;
+ }
+
+ if (range_intersect_range(pos, count, PCI_REVISION_ID, sizeof(val8),
+ &copy_offset, &copy_count, &register_offset)) {
+ /* Transional needs to have revision 0 */
+ val8 = 0;
+ if (copy_to_user(buf + copy_offset, &val8, copy_count))
+ return -EFAULT;
+ }
+
+ if (range_intersect_range(pos, count, PCI_BASE_ADDRESS_0, sizeof(val32),
+ &copy_offset, &copy_count, &register_offset)) {
+ u32 bar_mask = ~(virtvdev->bar0_virtual_buf_size - 1);
+ u32 pci_base_addr_0 = le32_to_cpu(virtvdev->pci_base_addr_0);
+
+ val32 = cpu_to_le32((pci_base_addr_0 & bar_mask) | PCI_BASE_ADDRESS_SPACE_IO);
+ if (copy_to_user(buf + copy_offset, (void *)&val32 + register_offset, copy_count))
+ return -EFAULT;
+ }
+
+ if (range_intersect_range(pos, count, PCI_SUBSYSTEM_ID, sizeof(val16),
+ &copy_offset, &copy_count, &register_offset)) {
+ /*
+ * Transitional devices use the PCI subsystem device id as
+ * virtio device id, same as legacy driver always did.
+ */
+ val16 = cpu_to_le16(VIRTIO_ID_NET);
+ if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset,
+ copy_count))
+ return -EFAULT;
+ }
+
+ if (range_intersect_range(pos, count, PCI_SUBSYSTEM_VENDOR_ID, sizeof(val16),
+ &copy_offset, &copy_count, &register_offset)) {
+ val16 = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET);
+ if (copy_to_user(buf + copy_offset, (void *)&val16 + register_offset,
+ copy_count))
+ return -EFAULT;
+ }
+
+ return count;
+}
+
+static ssize_t
+virtiovf_pci_core_read(struct vfio_device *core_vdev, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct virtiovf_pci_core_device *virtvdev = container_of(
+ core_vdev, struct virtiovf_pci_core_device, core_device.vdev);
+ unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
+ loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
+
+ if (!count)
+ return 0;
+
+ if (index == VFIO_PCI_CONFIG_REGION_INDEX)
+ return virtiovf_pci_read_config(core_vdev, buf, count, ppos);
+
+ if (index == VFIO_PCI_BAR0_REGION_INDEX)
+ return virtiovf_pci_bar0_rw(virtvdev, pos, buf, count, true);
+
+ return vfio_pci_core_read(core_vdev, buf, count, ppos);
+}
+
+static ssize_t virtiovf_pci_write_config(struct vfio_device *core_vdev,
+ const char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct virtiovf_pci_core_device *virtvdev = container_of(
+ core_vdev, struct virtiovf_pci_core_device, core_device.vdev);
+ loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
+ size_t register_offset;
+ loff_t copy_offset;
+ size_t copy_count;
+
+ if (range_intersect_range(pos, count, PCI_COMMAND, sizeof(virtvdev->pci_cmd),
+ &copy_offset, &copy_count,
+ &register_offset)) {
+ if (copy_from_user((void *)&virtvdev->pci_cmd + register_offset,
+ buf + copy_offset,
+ copy_count))
+ return -EFAULT;
+ }
+
+ if (range_intersect_range(pos, count, PCI_BASE_ADDRESS_0,
+ sizeof(virtvdev->pci_base_addr_0),
+ &copy_offset, &copy_count,
+ &register_offset)) {
+ if (copy_from_user((void *)&virtvdev->pci_base_addr_0 + register_offset,
+ buf + copy_offset,
+ copy_count))
+ return -EFAULT;
+ }
+
+ return vfio_pci_core_write(core_vdev, buf, count, ppos);
+}
+
+static ssize_t
+virtiovf_pci_core_write(struct vfio_device *core_vdev, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct virtiovf_pci_core_device *virtvdev = container_of(
+ core_vdev, struct virtiovf_pci_core_device, core_device.vdev);
+ unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
+ loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
+
+ if (!count)
+ return 0;
+
+ if (index == VFIO_PCI_CONFIG_REGION_INDEX)
+ return virtiovf_pci_write_config(core_vdev, buf, count, ppos);
+
+ if (index == VFIO_PCI_BAR0_REGION_INDEX)
+ return virtiovf_pci_bar0_rw(virtvdev, pos, (char __user *)buf, count, false);
+
+ return vfio_pci_core_write(core_vdev, buf, count, ppos);
+}
+
+static int
+virtiovf_pci_ioctl_get_region_info(struct vfio_device *core_vdev,
+ unsigned int cmd, unsigned long arg)
+{
+ struct virtiovf_pci_core_device *virtvdev = container_of(
+ core_vdev, struct virtiovf_pci_core_device, core_device.vdev);
+ unsigned long minsz = offsetofend(struct vfio_region_info, offset);
+ void __user *uarg = (void __user *)arg;
+ struct vfio_region_info info = {};
+
+ if (copy_from_user(&info, uarg, minsz))
+ return -EFAULT;
+
+ if (info.argsz < minsz)
+ return -EINVAL;
+
+ switch (info.index) {
+ case VFIO_PCI_BAR0_REGION_INDEX:
+ info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
+ info.size = virtvdev->bar0_virtual_buf_size;
+ info.flags = VFIO_REGION_INFO_FLAG_READ |
+ VFIO_REGION_INFO_FLAG_WRITE;
+ return copy_to_user(uarg, &info, minsz) ? -EFAULT : 0;
+ default:
+ return vfio_pci_core_ioctl(core_vdev, cmd, arg);
+ }
+}
+
+static long
+virtiovf_vfio_pci_core_ioctl(struct vfio_device *core_vdev, unsigned int cmd,
+ unsigned long arg)
+{
+ switch (cmd) {
+ case VFIO_DEVICE_GET_REGION_INFO:
+ return virtiovf_pci_ioctl_get_region_info(core_vdev, cmd, arg);
+ default:
+ return vfio_pci_core_ioctl(core_vdev, cmd, arg);
+ }
+}
+
+static int
+virtiovf_set_notify_addr(struct virtiovf_pci_core_device *virtvdev)
+{
+ struct vfio_pci_core_device *core_device = &virtvdev->core_device;
+ int ret;
+
+ /*
+ * Setup the BAR where the 'notify' exists to be used by vfio as well
+ * This will let us mmap it only once and use it when needed.
+ */
+ ret = vfio_pci_core_setup_barmap(core_device,
+ virtvdev->notify_bar);
+ if (ret)
+ return ret;
+
+ virtvdev->notify_addr = core_device->barmap[virtvdev->notify_bar] +
+ virtvdev->notify_offset;
+ return 0;
+}
+
+static int virtiovf_pci_open_device(struct vfio_device *core_vdev)
+{
+ struct virtiovf_pci_core_device *virtvdev = container_of(
+ core_vdev, struct virtiovf_pci_core_device, core_device.vdev);
+ struct vfio_pci_core_device *vdev = &virtvdev->core_device;
+ int ret;
+
+ ret = vfio_pci_core_enable(vdev);
+ if (ret)
+ return ret;
+
+ if (virtvdev->bar0_virtual_buf) {
+ /*
+ * Upon close_device() the vfio_pci_core_disable() is called
+ * and will close all the previous mmaps, so it seems that the
+ * valid life cycle for the 'notify' addr is per open/close.
+ */
+ ret = virtiovf_set_notify_addr(virtvdev);
+ if (ret) {
+ vfio_pci_core_disable(vdev);
+ return ret;
+ }
+ }
+
+ vfio_pci_core_finish_enable(vdev);
+ return 0;
+}
+
+static int virtiovf_get_device_config_size(unsigned short device)
+{
+ /* Network card */
+ return offsetofend(struct virtio_net_config, status);
+}
+
+static int virtiovf_read_notify_info(struct virtiovf_pci_core_device *virtvdev)
+{
+ u64 offset;
+ int ret;
+ u8 bar;
+
+ ret = virtio_pci_admin_legacy_io_notify_info(virtvdev->core_device.pdev,
+ VIRTIO_ADMIN_CMD_NOTIFY_INFO_FLAGS_OWNER_MEM,
+ &bar, &offset);
+ if (ret)
+ return ret;
+
+ virtvdev->notify_bar = bar;
+ virtvdev->notify_offset = offset;
+ return 0;
+}
+
+static int virtiovf_pci_init_device(struct vfio_device *core_vdev)
+{
+ struct virtiovf_pci_core_device *virtvdev = container_of(
+ core_vdev, struct virtiovf_pci_core_device, core_device.vdev);
+ struct pci_dev *pdev;
+ int ret;
+
+ ret = vfio_pci_core_init_dev(core_vdev);
+ if (ret)
+ return ret;
+
+ pdev = virtvdev->core_device.pdev;
+ ret = virtiovf_read_notify_info(virtvdev);
+ if (ret)
+ return ret;
+
+ virtvdev->bar0_virtual_buf_size = VIRTIO_PCI_CONFIG_OFF(true) +
+ virtiovf_get_device_config_size(pdev->device);
+ BUILD_BUG_ON(!is_power_of_2(virtvdev->bar0_virtual_buf_size));
+ virtvdev->bar0_virtual_buf = kzalloc(virtvdev->bar0_virtual_buf_size,
+ GFP_KERNEL);
+ if (!virtvdev->bar0_virtual_buf)
+ return -ENOMEM;
+ mutex_init(&virtvdev->bar_mutex);
+ return 0;
+}
+
+static void virtiovf_pci_core_release_dev(struct vfio_device *core_vdev)
+{
+ struct virtiovf_pci_core_device *virtvdev = container_of(
+ core_vdev, struct virtiovf_pci_core_device, core_device.vdev);
+
+ kfree(virtvdev->bar0_virtual_buf);
+ vfio_pci_core_release_dev(core_vdev);
+}
+
+static const struct vfio_device_ops virtiovf_vfio_pci_tran_ops = {
+ .name = "virtio-vfio-pci-trans",
+ .init = virtiovf_pci_init_device,
+ .release = virtiovf_pci_core_release_dev,
+ .open_device = virtiovf_pci_open_device,
+ .close_device = vfio_pci_core_close_device,
+ .ioctl = virtiovf_vfio_pci_core_ioctl,
+ .device_feature = vfio_pci_core_ioctl_feature,
+ .read = virtiovf_pci_core_read,
+ .write = virtiovf_pci_core_write,
+ .mmap = vfio_pci_core_mmap,
+ .request = vfio_pci_core_request,
+ .match = vfio_pci_core_match,
+ .bind_iommufd = vfio_iommufd_physical_bind,
+ .unbind_iommufd = vfio_iommufd_physical_unbind,
+ .attach_ioas = vfio_iommufd_physical_attach_ioas,
+ .detach_ioas = vfio_iommufd_physical_detach_ioas,
+};
+
+static const struct vfio_device_ops virtiovf_vfio_pci_ops = {
+ .name = "virtio-vfio-pci",
+ .init = vfio_pci_core_init_dev,
+ .release = vfio_pci_core_release_dev,
+ .open_device = virtiovf_pci_open_device,
+ .close_device = vfio_pci_core_close_device,
+ .ioctl = vfio_pci_core_ioctl,
+ .device_feature = vfio_pci_core_ioctl_feature,
+ .read = vfio_pci_core_read,
+ .write = vfio_pci_core_write,
+ .mmap = vfio_pci_core_mmap,
+ .request = vfio_pci_core_request,
+ .match = vfio_pci_core_match,
+ .bind_iommufd = vfio_iommufd_physical_bind,
+ .unbind_iommufd = vfio_iommufd_physical_unbind,
+ .attach_ioas = vfio_iommufd_physical_attach_ioas,
+ .detach_ioas = vfio_iommufd_physical_detach_ioas,
+};
+
+static bool virtiovf_bar0_exists(struct pci_dev *pdev)
+{
+ struct resource *res = pdev->resource;
+
+ return res->flags;
+}
+
+static int virtiovf_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ const struct vfio_device_ops *ops = &virtiovf_vfio_pci_ops;
+ struct virtiovf_pci_core_device *virtvdev;
+ int ret;
+
+ if (pdev->is_virtfn && virtio_pci_admin_has_legacy_io(pdev) &&
+ !virtiovf_bar0_exists(pdev))
+ ops = &virtiovf_vfio_pci_tran_ops;
+
+ virtvdev = vfio_alloc_device(virtiovf_pci_core_device, core_device.vdev,
+ &pdev->dev, ops);
+ if (IS_ERR(virtvdev))
+ return PTR_ERR(virtvdev);
+
+ dev_set_drvdata(&pdev->dev, &virtvdev->core_device);
+ ret = vfio_pci_core_register_device(&virtvdev->core_device);
+ if (ret)
+ goto out;
+ return 0;
+out:
+ vfio_put_device(&virtvdev->core_device.vdev);
+ return ret;
+}
+
+static void virtiovf_pci_remove(struct pci_dev *pdev)
+{
+ struct virtiovf_pci_core_device *virtvdev = dev_get_drvdata(&pdev->dev);
+
+ vfio_pci_core_unregister_device(&virtvdev->core_device);
+ vfio_put_device(&virtvdev->core_device.vdev);
+}
+
+static const struct pci_device_id virtiovf_pci_table[] = {
+ /* Only virtio-net is supported/tested so far */
+ { PCI_DRIVER_OVERRIDE_DEVICE_VFIO(PCI_VENDOR_ID_REDHAT_QUMRANET, 0x1041) },
+ {}
+};
+
+MODULE_DEVICE_TABLE(pci, virtiovf_pci_table);
+
+static void virtiovf_pci_aer_reset_done(struct pci_dev *pdev)
+{
+ struct virtiovf_pci_core_device *virtvdev = dev_get_drvdata(&pdev->dev);
+
+ virtvdev->pci_cmd = 0;
+}
+
+static const struct pci_error_handlers virtiovf_err_handlers = {
+ .reset_done = virtiovf_pci_aer_reset_done,
+ .error_detected = vfio_pci_core_aer_err_detected,
+};
+
+static struct pci_driver virtiovf_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = virtiovf_pci_table,
+ .probe = virtiovf_pci_probe,
+ .remove = virtiovf_pci_remove,
+ .err_handler = &virtiovf_err_handlers,
+ .driver_managed_dma = true,
+};
+
+module_pci_driver(virtiovf_pci_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yishai Hadas <[email protected]>");
+MODULE_DESCRIPTION(
+ "VIRTIO VFIO PCI - User Level meta-driver for VIRTIO NET devices");
diff --git a/drivers/vfio/vfio.h b/drivers/vfio/vfio.h
index 307e3f29b527..bde84ad344e5 100644
--- a/drivers/vfio/vfio.h
+++ b/drivers/vfio/vfio.h
@@ -448,4 +448,18 @@ static inline void vfio_device_put_kvm(struct vfio_device *device)
}
#endif
+#ifdef CONFIG_VFIO_DEBUGFS
+void vfio_debugfs_create_root(void);
+void vfio_debugfs_remove_root(void);
+
+void vfio_device_debugfs_init(struct vfio_device *vdev);
+void vfio_device_debugfs_exit(struct vfio_device *vdev);
+#else
+static inline void vfio_debugfs_create_root(void) { }
+static inline void vfio_debugfs_remove_root(void) { }
+
+static inline void vfio_device_debugfs_init(struct vfio_device *vdev) { }
+static inline void vfio_device_debugfs_exit(struct vfio_device *vdev) { }
+#endif /* CONFIG_VFIO_DEBUGFS */
+
#endif
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index eacd6ec04de5..b2854d7939ce 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -1436,7 +1436,7 @@ static int vfio_iommu_map(struct vfio_iommu *iommu, dma_addr_t iova,
list_for_each_entry(d, &iommu->domain_list, next) {
ret = iommu_map(d->domain, iova, (phys_addr_t)pfn << PAGE_SHIFT,
npage << PAGE_SHIFT, prot | IOMMU_CACHE,
- GFP_KERNEL);
+ GFP_KERNEL_ACCOUNT);
if (ret)
goto unwind;
@@ -1750,7 +1750,8 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
}
ret = iommu_map(domain->domain, iova, phys, size,
- dma->prot | IOMMU_CACHE, GFP_KERNEL);
+ dma->prot | IOMMU_CACHE,
+ GFP_KERNEL_ACCOUNT);
if (ret) {
if (!dma->iommu_mapped) {
vfio_unpin_pages_remote(dma, iova,
@@ -1845,7 +1846,8 @@ static void vfio_test_domain_fgsp(struct vfio_domain *domain, struct list_head *
continue;
ret = iommu_map(domain->domain, start, page_to_phys(pages), PAGE_SIZE * 2,
- IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE, GFP_KERNEL);
+ IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE,
+ GFP_KERNEL_ACCOUNT);
if (!ret) {
size_t unmapped = iommu_unmap(domain->domain, start, PAGE_SIZE);
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 8d4995ada74a..1cc93aac99a2 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -311,6 +311,7 @@ static int __vfio_register_dev(struct vfio_device *device,
refcount_set(&device->refcount, 1);
vfio_device_group_register(device);
+ vfio_device_debugfs_init(device);
return 0;
err_out:
@@ -378,6 +379,7 @@ void vfio_unregister_group_dev(struct vfio_device *device)
}
}
+ vfio_device_debugfs_exit(device);
/* Balances vfio_device_set_group in register path */
vfio_device_remove_group(device);
}
@@ -1676,6 +1678,7 @@ static int __init vfio_init(void)
if (ret)
goto err_alloc_dev_chrdev;
+ vfio_debugfs_create_root();
pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
return 0;
@@ -1691,6 +1694,7 @@ err_virqfd:
static void __exit vfio_cleanup(void)
{
+ vfio_debugfs_remove_root();
ida_destroy(&vfio.device_ida);
vfio_cdev_cleanup();
class_destroy(vfio.device_class);
diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
index 173beda74b38..bc4a51e4638b 100644
--- a/drivers/vhost/vdpa.c
+++ b/drivers/vhost/vdpa.c
@@ -59,6 +59,7 @@ struct vhost_vdpa {
int in_batch;
struct vdpa_iova_range range;
u32 batch_asid;
+ bool suspended;
};
static DEFINE_IDA(vhost_vdpa_ida);
@@ -232,6 +233,8 @@ static int _compat_vdpa_reset(struct vhost_vdpa *v)
struct vdpa_device *vdpa = v->vdpa;
u32 flags = 0;
+ v->suspended = false;
+
if (v->vdev.vqs) {
flags |= !vhost_backend_has_feature(v->vdev.vqs[0],
VHOST_BACKEND_F_IOTLB_PERSIST) ?
@@ -590,11 +593,16 @@ static long vhost_vdpa_suspend(struct vhost_vdpa *v)
{
struct vdpa_device *vdpa = v->vdpa;
const struct vdpa_config_ops *ops = vdpa->config;
+ int ret;
if (!ops->suspend)
return -EOPNOTSUPP;
- return ops->suspend(vdpa);
+ ret = ops->suspend(vdpa);
+ if (!ret)
+ v->suspended = true;
+
+ return ret;
}
/* After a successful return of this ioctl the device resumes processing
@@ -605,11 +613,16 @@ static long vhost_vdpa_resume(struct vhost_vdpa *v)
{
struct vdpa_device *vdpa = v->vdpa;
const struct vdpa_config_ops *ops = vdpa->config;
+ int ret;
if (!ops->resume)
return -EOPNOTSUPP;
- return ops->resume(vdpa);
+ ret = ops->resume(vdpa);
+ if (!ret)
+ v->suspended = false;
+
+ return ret;
}
static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
@@ -690,6 +703,9 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
switch (cmd) {
case VHOST_SET_VRING_ADDR:
+ if ((ops->get_status(vdpa) & VIRTIO_CONFIG_S_DRIVER_OK) && !v->suspended)
+ return -EINVAL;
+
if (ops->set_vq_address(vdpa, idx,
(u64)(uintptr_t)vq->desc,
(u64)(uintptr_t)vq->avail,
@@ -698,6 +714,9 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
break;
case VHOST_SET_VRING_BASE:
+ if ((ops->get_status(vdpa) & VIRTIO_CONFIG_S_DRIVER_OK) && !v->suspended)
+ return -EINVAL;
+
if (vhost_has_feature(vq, VIRTIO_F_RING_PACKED)) {
vq_state.packed.last_avail_idx = vq->last_avail_idx & 0x7fff;
vq_state.packed.last_avail_counter = !!(vq->last_avail_idx & 0x8000);
@@ -968,7 +987,8 @@ static int vhost_vdpa_map(struct vhost_vdpa *v, struct vhost_iotlb *iotlb,
r = ops->set_map(vdpa, asid, iotlb);
} else {
r = iommu_map(v->domain, iova, pa, size,
- perm_to_iommu_flags(perm), GFP_KERNEL);
+ perm_to_iommu_flags(perm),
+ GFP_KERNEL_ACCOUNT);
}
if (r) {
vhost_iotlb_del_range(iotlb, iova, iova + size - 1);
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 51387b1ef012..ea2d0d69bd8c 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -235,13 +235,6 @@ config BACKLIGHT_HP700
If you have an HP Jornada 700 series,
say Y to include backlight control driver.
-config BACKLIGHT_CARILLO_RANCH
- tristate "Intel Carillo Ranch Backlight Driver"
- depends on LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578
- help
- If you have a Intel LE80578 (Carillo Ranch) say Y to enable the
- backlight driver.
-
config BACKLIGHT_PWM
tristate "Generic PWM based Backlight Driver"
depends on PWM
@@ -402,6 +395,17 @@ config BACKLIGHT_LP8788
help
This supports TI LP8788 backlight driver.
+config BACKLIGHT_MP3309C
+ tristate "Backlight Driver for MPS MP3309C"
+ depends on I2C && PWM
+ select REGMAP_I2C
+ help
+ This supports MPS MP3309C backlight WLED driver in both PWM and
+ analog/I2C dimming modes.
+
+ To compile this driver as a module, choose M here: the module will
+ be called mp3309c.
+
config BACKLIGHT_PANDORA
tristate "Backlight driver for Pandora console"
depends on TWL4030_CORE
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index f72e1c3c59e9..06966cb20459 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -25,7 +25,6 @@ obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o
obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o
obj-$(CONFIG_BACKLIGHT_AS3711) += as3711_bl.o
obj-$(CONFIG_BACKLIGHT_BD6107) += bd6107.o
-obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o
@@ -44,6 +43,7 @@ obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o
obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o
obj-$(CONFIG_BACKLIGHT_LV5207LP) += lv5207lp.o
obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o
+obj-$(CONFIG_BACKLIGHT_MP3309C) += mp3309c.o
obj-$(CONFIG_BACKLIGHT_MT6370) += mt6370-backlight.o
obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o
obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
deleted file mode 100644
index 781aeecc451d..000000000000
--- a/drivers/video/backlight/cr_bllcd.c
+++ /dev/null
@@ -1,264 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) Intel Corp. 2007.
- * All Rights Reserved.
- *
- * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
- * develop this driver.
- *
- * This file is part of the Carillo Ranch video subsystem driver.
- *
- * Authors:
- * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
- * Alan Hourihane <alanh-at-tungstengraphics-dot-com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/mutex.h>
-#include <linux/fb.h>
-#include <linux/backlight.h>
-#include <linux/lcd.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-/* The LVDS- and panel power controls sits on the
- * GPIO port of the ISA bridge.
- */
-
-#define CRVML_DEVICE_LPC 0x27B8
-#define CRVML_REG_GPIOBAR 0x48
-#define CRVML_REG_GPIOEN 0x4C
-#define CRVML_GPIOEN_BIT (1 << 4)
-#define CRVML_PANEL_PORT 0x38
-#define CRVML_LVDS_ON 0x00000001
-#define CRVML_PANEL_ON 0x00000002
-#define CRVML_BACKLIGHT_OFF 0x00000004
-
-/* The PLL Clock register sits on Host bridge */
-#define CRVML_DEVICE_MCH 0x5001
-#define CRVML_REG_MCHBAR 0x44
-#define CRVML_REG_MCHEN 0x54
-#define CRVML_MCHEN_BIT (1 << 28)
-#define CRVML_MCHMAP_SIZE 4096
-#define CRVML_REG_CLOCK 0xc3c
-#define CRVML_CLOCK_SHIFT 8
-#define CRVML_CLOCK_MASK 0x00000f00
-
-static struct pci_dev *lpc_dev;
-static u32 gpio_bar;
-
-struct cr_panel {
- struct backlight_device *cr_backlight_device;
- struct lcd_device *cr_lcd_device;
-};
-
-static int cr_backlight_set_intensity(struct backlight_device *bd)
-{
- u32 addr = gpio_bar + CRVML_PANEL_PORT;
- u32 cur = inl(addr);
-
- if (backlight_get_brightness(bd) == 0) {
- /* OFF */
- cur |= CRVML_BACKLIGHT_OFF;
- outl(cur, addr);
- } else {
- /* FULL ON */
- cur &= ~CRVML_BACKLIGHT_OFF;
- outl(cur, addr);
- }
-
- return 0;
-}
-
-static int cr_backlight_get_intensity(struct backlight_device *bd)
-{
- u32 addr = gpio_bar + CRVML_PANEL_PORT;
- u32 cur = inl(addr);
- u8 intensity;
-
- if (cur & CRVML_BACKLIGHT_OFF)
- intensity = 0;
- else
- intensity = 1;
-
- return intensity;
-}
-
-static const struct backlight_ops cr_backlight_ops = {
- .get_brightness = cr_backlight_get_intensity,
- .update_status = cr_backlight_set_intensity,
-};
-
-static void cr_panel_on(void)
-{
- u32 addr = gpio_bar + CRVML_PANEL_PORT;
- u32 cur = inl(addr);
-
- if (!(cur & CRVML_PANEL_ON)) {
- /* Make sure LVDS controller is down. */
- if (cur & 0x00000001) {
- cur &= ~CRVML_LVDS_ON;
- outl(cur, addr);
- }
- /* Power up Panel */
- schedule_timeout(HZ / 10);
- cur |= CRVML_PANEL_ON;
- outl(cur, addr);
- }
-
- /* Power up LVDS controller */
-
- if (!(cur & CRVML_LVDS_ON)) {
- schedule_timeout(HZ / 10);
- outl(cur | CRVML_LVDS_ON, addr);
- }
-}
-
-static void cr_panel_off(void)
-{
- u32 addr = gpio_bar + CRVML_PANEL_PORT;
- u32 cur = inl(addr);
-
- /* Power down LVDS controller first to avoid high currents */
- if (cur & CRVML_LVDS_ON) {
- cur &= ~CRVML_LVDS_ON;
- outl(cur, addr);
- }
- if (cur & CRVML_PANEL_ON) {
- schedule_timeout(HZ / 10);
- outl(cur & ~CRVML_PANEL_ON, addr);
- }
-}
-
-static int cr_lcd_set_power(struct lcd_device *ld, int power)
-{
- if (power == FB_BLANK_UNBLANK)
- cr_panel_on();
- if (power == FB_BLANK_POWERDOWN)
- cr_panel_off();
-
- return 0;
-}
-
-static struct lcd_ops cr_lcd_ops = {
- .set_power = cr_lcd_set_power,
-};
-
-static int cr_backlight_probe(struct platform_device *pdev)
-{
- struct backlight_properties props;
- struct backlight_device *bdp;
- struct lcd_device *ldp;
- struct cr_panel *crp;
- u8 dev_en;
-
- lpc_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
- CRVML_DEVICE_LPC, NULL);
- if (!lpc_dev) {
- pr_err("INTEL CARILLO RANCH LPC not found.\n");
- return -ENODEV;
- }
-
- pci_read_config_byte(lpc_dev, CRVML_REG_GPIOEN, &dev_en);
- if (!(dev_en & CRVML_GPIOEN_BIT)) {
- pr_err("Carillo Ranch GPIO device was not enabled.\n");
- pci_dev_put(lpc_dev);
- return -ENODEV;
- }
-
- memset(&props, 0, sizeof(struct backlight_properties));
- props.type = BACKLIGHT_RAW;
- bdp = devm_backlight_device_register(&pdev->dev, "cr-backlight",
- &pdev->dev, NULL, &cr_backlight_ops,
- &props);
- if (IS_ERR(bdp)) {
- pci_dev_put(lpc_dev);
- return PTR_ERR(bdp);
- }
-
- ldp = devm_lcd_device_register(&pdev->dev, "cr-lcd", &pdev->dev, NULL,
- &cr_lcd_ops);
- if (IS_ERR(ldp)) {
- pci_dev_put(lpc_dev);
- return PTR_ERR(ldp);
- }
-
- pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR,
- &gpio_bar);
- gpio_bar &= ~0x3F;
-
- crp = devm_kzalloc(&pdev->dev, sizeof(*crp), GFP_KERNEL);
- if (!crp) {
- pci_dev_put(lpc_dev);
- return -ENOMEM;
- }
-
- crp->cr_backlight_device = bdp;
- crp->cr_lcd_device = ldp;
- crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK;
- crp->cr_backlight_device->props.brightness = 0;
- cr_backlight_set_intensity(crp->cr_backlight_device);
- cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_UNBLANK);
-
- platform_set_drvdata(pdev, crp);
-
- return 0;
-}
-
-static void cr_backlight_remove(struct platform_device *pdev)
-{
- struct cr_panel *crp = platform_get_drvdata(pdev);
-
- crp->cr_backlight_device->props.power = FB_BLANK_POWERDOWN;
- crp->cr_backlight_device->props.brightness = 0;
- crp->cr_backlight_device->props.max_brightness = 0;
- cr_backlight_set_intensity(crp->cr_backlight_device);
- cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_POWERDOWN);
- pci_dev_put(lpc_dev);
-}
-
-static struct platform_driver cr_backlight_driver = {
- .probe = cr_backlight_probe,
- .remove_new = cr_backlight_remove,
- .driver = {
- .name = "cr_backlight",
- },
-};
-
-static struct platform_device *crp;
-
-static int __init cr_backlight_init(void)
-{
- int ret = platform_driver_register(&cr_backlight_driver);
-
- if (ret)
- return ret;
-
- crp = platform_device_register_simple("cr_backlight", -1, NULL, 0);
- if (IS_ERR(crp)) {
- platform_driver_unregister(&cr_backlight_driver);
- return PTR_ERR(crp);
- }
-
- pr_info("Carillo Ranch Backlight Driver Initialized.\n");
-
- return 0;
-}
-
-static void __exit cr_backlight_exit(void)
-{
- platform_device_unregister(crp);
- platform_driver_unregister(&cr_backlight_driver);
-}
-
-module_init(cr_backlight_init);
-module_exit(cr_backlight_exit);
-
-MODULE_AUTHOR("Tungsten Graphics Inc.");
-MODULE_DESCRIPTION("Carillo Ranch Backlight Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/hx8357.c b/drivers/video/backlight/hx8357.c
index f76d2469d490..d7298376cf74 100644
--- a/drivers/video/backlight/hx8357.c
+++ b/drivers/video/backlight/hx8357.c
@@ -6,11 +6,11 @@
*/
#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/lcd.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/of_gpio.h>
#include <linux/spi/spi.h>
#define HX8357_NUM_IM_PINS 3
@@ -83,11 +83,10 @@
#define HX8369_SET_GAMMA_CURVE_RELATED 0xe0
struct hx8357_data {
- unsigned im_pins[HX8357_NUM_IM_PINS];
- unsigned reset;
+ struct gpio_descs *im_pins;
+ struct gpio_desc *reset;
struct spi_device *spi;
int state;
- bool use_im_pins;
};
static u8 hx8357_seq_power[] = {
@@ -321,11 +320,11 @@ static void hx8357_lcd_reset(struct lcd_device *lcdev)
struct hx8357_data *lcd = lcd_get_data(lcdev);
/* Reset the screen */
- gpio_set_value(lcd->reset, 1);
+ gpiod_set_value(lcd->reset, 0);
usleep_range(10000, 12000);
- gpio_set_value(lcd->reset, 0);
+ gpiod_set_value(lcd->reset, 1);
usleep_range(10000, 12000);
- gpio_set_value(lcd->reset, 1);
+ gpiod_set_value(lcd->reset, 0);
/* The controller needs 120ms to recover from reset */
msleep(120);
@@ -340,10 +339,10 @@ static int hx8357_lcd_init(struct lcd_device *lcdev)
* Set the interface selection pins to SPI mode, with three
* wires
*/
- if (lcd->use_im_pins) {
- gpio_set_value_cansleep(lcd->im_pins[0], 1);
- gpio_set_value_cansleep(lcd->im_pins[1], 0);
- gpio_set_value_cansleep(lcd->im_pins[2], 1);
+ if (lcd->im_pins) {
+ gpiod_set_value_cansleep(lcd->im_pins->desc[0], 1);
+ gpiod_set_value_cansleep(lcd->im_pins->desc[1], 0);
+ gpiod_set_value_cansleep(lcd->im_pins->desc[2], 1);
}
ret = hx8357_spi_write_array(lcdev, hx8357_seq_power,
@@ -580,6 +579,7 @@ MODULE_DEVICE_TABLE(of, hx8357_dt_ids);
static int hx8357_probe(struct spi_device *spi)
{
+ struct device *dev = &spi->dev;
struct lcd_device *lcdev;
struct hx8357_data *lcd;
const struct of_device_id *match;
@@ -601,49 +601,19 @@ static int hx8357_probe(struct spi_device *spi)
if (!match || !match->data)
return -EINVAL;
- lcd->reset = of_get_named_gpio(spi->dev.of_node, "gpios-reset", 0);
- if (!gpio_is_valid(lcd->reset)) {
- dev_err(&spi->dev, "Missing dt property: gpios-reset\n");
- return -EINVAL;
- }
+ lcd->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(lcd->reset))
+ return dev_err_probe(dev, PTR_ERR(lcd->reset), "failed to request reset GPIO\n");
+ gpiod_set_consumer_name(lcd->reset, "hx8357-reset");
- ret = devm_gpio_request_one(&spi->dev, lcd->reset,
- GPIOF_OUT_INIT_HIGH,
- "hx8357-reset");
- if (ret) {
- dev_err(&spi->dev,
- "failed to request gpio %d: %d\n",
- lcd->reset, ret);
- return -EINVAL;
- }
+ lcd->im_pins = devm_gpiod_get_array_optional(dev, "im", GPIOD_OUT_LOW);
+ if (IS_ERR(lcd->im_pins))
+ return dev_err_probe(dev, PTR_ERR(lcd->im_pins), "failed to request im GPIOs\n");
+ if (lcd->im_pins->ndescs < HX8357_NUM_IM_PINS)
+ return dev_err_probe(dev, -EINVAL, "not enough im GPIOs\n");
- if (of_property_present(spi->dev.of_node, "im-gpios")) {
- lcd->use_im_pins = 1;
-
- for (i = 0; i < HX8357_NUM_IM_PINS; i++) {
- lcd->im_pins[i] = of_get_named_gpio(spi->dev.of_node,
- "im-gpios", i);
- if (lcd->im_pins[i] == -EPROBE_DEFER) {
- dev_info(&spi->dev, "GPIO requested is not here yet, deferring the probe\n");
- return -EPROBE_DEFER;
- }
- if (!gpio_is_valid(lcd->im_pins[i])) {
- dev_err(&spi->dev, "Missing dt property: im-gpios\n");
- return -EINVAL;
- }
-
- ret = devm_gpio_request_one(&spi->dev, lcd->im_pins[i],
- GPIOF_OUT_INIT_LOW,
- "im_pins");
- if (ret) {
- dev_err(&spi->dev, "failed to request gpio %d: %d\n",
- lcd->im_pins[i], ret);
- return -EINVAL;
- }
- }
- } else {
- lcd->use_im_pins = 0;
- }
+ for (i = 0; i < HX8357_NUM_IM_PINS; i++)
+ gpiod_set_consumer_name(lcd->im_pins->desc[i], "im_pins");
lcdev = devm_lcd_device_register(&spi->dev, "mxsfb", &spi->dev, lcd,
&hx8357_ops);
diff --git a/drivers/video/backlight/ili922x.c b/drivers/video/backlight/ili922x.c
index e7b6bd827986..c8e0e655dc86 100644
--- a/drivers/video/backlight/ili922x.c
+++ b/drivers/video/backlight/ili922x.c
@@ -81,7 +81,7 @@
#define START_RW_WRITE 0
#define START_RW_READ 1
-/**
+/*
* START_BYTE(id, rs, rw)
*
* Set the start byte according to the required operation.
@@ -100,7 +100,7 @@
#define START_BYTE(id, rs, rw) \
(0x70 | (((id) & 0x01) << 2) | (((rs) & 0x01) << 1) | ((rw) & 0x01))
-/**
+/*
* CHECK_FREQ_REG(spi_device s, spi_transfer x) - Check the frequency
* for the SPI transfer. According to the datasheet, the controller
* accept higher frequency for the GRAM transfer, but it requires
@@ -269,6 +269,10 @@ static int ili922x_write(struct spi_device *spi, u8 reg, u16 value)
spi_message_add_tail(&xfer_regindex, &msg);
ret = spi_sync(spi, &msg);
+ if (ret < 0) {
+ dev_err(&spi->dev, "Error sending SPI message 0x%x", ret);
+ return ret;
+ }
spi_message_init(&msg);
tbuf[0] = set_tx_byte(START_BYTE(ili922x_id, START_RS_REG,
diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c
index 8fcb62be597b..a3412c936ca2 100644
--- a/drivers/video/backlight/lm3630a_bl.c
+++ b/drivers/video/backlight/lm3630a_bl.c
@@ -180,7 +180,7 @@ static int lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max)
pchip->pwmd_state.enabled = pchip->pwmd_state.duty_cycle ? true : false;
- return pwm_apply_state(pchip->pwmd, &pchip->pwmd_state);
+ return pwm_apply_might_sleep(pchip->pwmd, &pchip->pwmd_state);
}
/* update and get brightness */
diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c
index da1f124db69c..7075bfab59c4 100644
--- a/drivers/video/backlight/lp855x_bl.c
+++ b/drivers/video/backlight/lp855x_bl.c
@@ -234,7 +234,7 @@ static int lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br)
state.duty_cycle = div_u64(br * state.period, max_br);
state.enabled = state.duty_cycle;
- return pwm_apply_state(lp->pwm, &state);
+ return pwm_apply_might_sleep(lp->pwm, &state);
}
static int lp855x_bl_update_status(struct backlight_device *bl)
diff --git a/drivers/video/backlight/mp3309c.c b/drivers/video/backlight/mp3309c.c
new file mode 100644
index 000000000000..34d71259fac1
--- /dev/null
+++ b/drivers/video/backlight/mp3309c.c
@@ -0,0 +1,444 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for MPS MP3309C White LED driver with I2C interface
+ *
+ * This driver support both analog (by I2C commands) and PWM dimming control
+ * modes.
+ *
+ * Copyright (C) 2023 ASEM Srl
+ * Author: Flavio Suligoi <[email protected]>
+ *
+ * Based on pwm_bl.c
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+
+#define REG_I2C_0 0x00
+#define REG_I2C_1 0x01
+
+#define REG_I2C_0_EN 0x80
+#define REG_I2C_0_D0 0x40
+#define REG_I2C_0_D1 0x20
+#define REG_I2C_0_D2 0x10
+#define REG_I2C_0_D3 0x08
+#define REG_I2C_0_D4 0x04
+#define REG_I2C_0_RSRV1 0x02
+#define REG_I2C_0_RSRV2 0x01
+
+#define REG_I2C_1_RSRV1 0x80
+#define REG_I2C_1_DIMS 0x40
+#define REG_I2C_1_SYNC 0x20
+#define REG_I2C_1_OVP0 0x10
+#define REG_I2C_1_OVP1 0x08
+#define REG_I2C_1_VOS 0x04
+#define REG_I2C_1_LEDO 0x02
+#define REG_I2C_1_OTP 0x01
+
+#define ANALOG_I2C_NUM_LEVELS 32 /* 0..31 */
+#define ANALOG_I2C_REG_MASK 0x7c
+
+#define MP3309C_PWM_DEFAULT_NUM_LEVELS 256 /* 0..255 */
+
+enum mp3309c_status_value {
+ FIRST_POWER_ON,
+ BACKLIGHT_OFF,
+ BACKLIGHT_ON,
+};
+
+enum mp3309c_dimming_mode_value {
+ DIMMING_PWM,
+ DIMMING_ANALOG_I2C,
+};
+
+struct mp3309c_platform_data {
+ unsigned int max_brightness;
+ unsigned int default_brightness;
+ unsigned int *levels;
+ u8 dimming_mode;
+ u8 over_voltage_protection;
+ bool sync_mode;
+ u8 status;
+};
+
+struct mp3309c_chip {
+ struct device *dev;
+ struct mp3309c_platform_data *pdata;
+ struct backlight_device *bl;
+ struct gpio_desc *enable_gpio;
+ struct regmap *regmap;
+ struct pwm_device *pwmd;
+};
+
+static const struct regmap_config mp3309c_regmap = {
+ .name = "mp3309c_regmap",
+ .reg_bits = 8,
+ .reg_stride = 1,
+ .val_bits = 8,
+ .max_register = REG_I2C_1,
+};
+
+static int mp3309c_enable_device(struct mp3309c_chip *chip)
+{
+ u8 reg_val;
+ int ret;
+
+ /* I2C register #0 - Device enable */
+ ret = regmap_update_bits(chip->regmap, REG_I2C_0, REG_I2C_0_EN,
+ REG_I2C_0_EN);
+ if (ret)
+ return ret;
+
+ /*
+ * I2C register #1 - Set working mode:
+ * - set one of the two dimming mode:
+ * - PWM dimming using an external PWM dimming signal
+ * - analog dimming using I2C commands
+ * - enable/disable synchronous mode
+ * - set overvoltage protection (OVP)
+ */
+ reg_val = 0x00;
+ if (chip->pdata->dimming_mode == DIMMING_PWM)
+ reg_val |= REG_I2C_1_DIMS;
+ if (chip->pdata->sync_mode)
+ reg_val |= REG_I2C_1_SYNC;
+ reg_val |= chip->pdata->over_voltage_protection;
+ ret = regmap_write(chip->regmap, REG_I2C_1, reg_val);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mp3309c_bl_update_status(struct backlight_device *bl)
+{
+ struct mp3309c_chip *chip = bl_get_data(bl);
+ int brightness = backlight_get_brightness(bl);
+ struct pwm_state pwmstate;
+ unsigned int analog_val, bits_val;
+ int i, ret;
+
+ if (chip->pdata->dimming_mode == DIMMING_PWM) {
+ /*
+ * PWM control mode
+ */
+ pwm_get_state(chip->pwmd, &pwmstate);
+ pwm_set_relative_duty_cycle(&pwmstate,
+ chip->pdata->levels[brightness],
+ chip->pdata->levels[chip->pdata->max_brightness]);
+ pwmstate.enabled = true;
+ ret = pwm_apply_state(chip->pwmd, &pwmstate);
+ if (ret)
+ return ret;
+
+ switch (chip->pdata->status) {
+ case FIRST_POWER_ON:
+ case BACKLIGHT_OFF:
+ /*
+ * After 20ms of low pwm signal level, the chip turns
+ * off automatically. In this case, before enabling the
+ * chip again, we must wait about 10ms for pwm signal to
+ * stabilize.
+ */
+ if (brightness > 0) {
+ msleep(10);
+ mp3309c_enable_device(chip);
+ chip->pdata->status = BACKLIGHT_ON;
+ } else {
+ chip->pdata->status = BACKLIGHT_OFF;
+ }
+ break;
+ case BACKLIGHT_ON:
+ if (brightness == 0)
+ chip->pdata->status = BACKLIGHT_OFF;
+ break;
+ }
+ } else {
+ /*
+ * Analog (by I2C command) control mode
+ *
+ * The first time, before setting brightness, we must enable the
+ * device
+ */
+ if (chip->pdata->status == FIRST_POWER_ON)
+ mp3309c_enable_device(chip);
+
+ /*
+ * Dimming mode I2C command (fixed dimming range 0..31)
+ *
+ * The 5 bits of the dimming analog value D4..D0 is allocated
+ * in the I2C register #0, in the following way:
+ *
+ * +--+--+--+--+--+--+--+--+
+ * |EN|D0|D1|D2|D3|D4|XX|XX|
+ * +--+--+--+--+--+--+--+--+
+ */
+ analog_val = brightness;
+ bits_val = 0;
+ for (i = 0; i <= 5; i++)
+ bits_val += ((analog_val >> i) & 0x01) << (6 - i);
+ ret = regmap_update_bits(chip->regmap, REG_I2C_0,
+ ANALOG_I2C_REG_MASK, bits_val);
+ if (ret)
+ return ret;
+
+ if (brightness > 0)
+ chip->pdata->status = BACKLIGHT_ON;
+ else
+ chip->pdata->status = BACKLIGHT_OFF;
+ }
+
+ return 0;
+}
+
+static const struct backlight_ops mp3309c_bl_ops = {
+ .update_status = mp3309c_bl_update_status,
+};
+
+static int pm3309c_parse_dt_node(struct mp3309c_chip *chip,
+ struct mp3309c_platform_data *pdata)
+{
+ struct device_node *node = chip->dev->of_node;
+ struct property *prop_pwms;
+ struct property *prop_levels = NULL;
+ int length = 0;
+ int ret, i;
+ unsigned int num_levels, tmp_value;
+
+ if (!node) {
+ dev_err(chip->dev, "failed to get DT node\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Dimming mode: the MP3309C provides two dimming control mode:
+ *
+ * - PWM mode
+ * - Analog by I2C control mode (default)
+ *
+ * I2C control mode is assumed as default but, if the pwms property is
+ * found in the backlight node, the mode switches to PWM mode.
+ */
+ pdata->dimming_mode = DIMMING_ANALOG_I2C;
+ prop_pwms = of_find_property(node, "pwms", &length);
+ if (prop_pwms) {
+ chip->pwmd = devm_pwm_get(chip->dev, NULL);
+ if (IS_ERR(chip->pwmd))
+ return dev_err_probe(chip->dev, PTR_ERR(chip->pwmd),
+ "error getting pwm data\n");
+ pdata->dimming_mode = DIMMING_PWM;
+ pwm_apply_args(chip->pwmd);
+ }
+
+ /*
+ * In I2C control mode the dimming levels (0..31) are fixed by the
+ * hardware, while in PWM control mode they can be chosen by the user,
+ * to allow nonlinear mappings.
+ */
+ if (pdata->dimming_mode == DIMMING_ANALOG_I2C) {
+ /*
+ * Analog (by I2C commands) control mode: fixed 0..31 brightness
+ * levels
+ */
+ num_levels = ANALOG_I2C_NUM_LEVELS;
+
+ /* Enable GPIO used in I2C dimming mode only */
+ chip->enable_gpio = devm_gpiod_get(chip->dev, "enable",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(chip->enable_gpio))
+ return dev_err_probe(chip->dev,
+ PTR_ERR(chip->enable_gpio),
+ "error getting enable gpio\n");
+ } else {
+ /*
+ * PWM control mode: check for brightness level in DT
+ */
+ prop_levels = of_find_property(node, "brightness-levels",
+ &length);
+ if (prop_levels) {
+ /* Read brightness levels from DT */
+ num_levels = length / sizeof(u32);
+ if (num_levels < 2)
+ return -EINVAL;
+ } else {
+ /* Use default brightness levels */
+ num_levels = MP3309C_PWM_DEFAULT_NUM_LEVELS;
+ }
+ }
+
+ /* Fill brightness levels array */
+ pdata->levels = devm_kcalloc(chip->dev, num_levels,
+ sizeof(*pdata->levels), GFP_KERNEL);
+ if (!pdata->levels)
+ return -ENOMEM;
+ if (prop_levels) {
+ ret = of_property_read_u32_array(node, "brightness-levels",
+ pdata->levels,
+ num_levels);
+ if (ret < 0)
+ return ret;
+ } else {
+ for (i = 0; i < num_levels; i++)
+ pdata->levels[i] = i;
+ }
+
+ pdata->max_brightness = num_levels - 1;
+
+ ret = of_property_read_u32(node, "default-brightness",
+ &pdata->default_brightness);
+ if (ret)
+ pdata->default_brightness = pdata->max_brightness;
+ if (pdata->default_brightness > pdata->max_brightness) {
+ dev_err(chip->dev,
+ "default brightness exceeds max brightness\n");
+ pdata->default_brightness = pdata->max_brightness;
+ }
+
+ /*
+ * Over-voltage protection (OVP)
+ *
+ * This (optional) property values are:
+ *
+ * - 13.5V
+ * - 24V
+ * - 35.5V (hardware default setting)
+ *
+ * If missing, the default value for OVP is 35.5V
+ */
+ pdata->over_voltage_protection = REG_I2C_1_OVP1;
+ if (!of_property_read_u32(node, "mps,overvoltage-protection-microvolt",
+ &tmp_value)) {
+ switch (tmp_value) {
+ case 13500000:
+ pdata->over_voltage_protection = 0x00;
+ break;
+ case 24000000:
+ pdata->over_voltage_protection = REG_I2C_1_OVP0;
+ break;
+ case 35500000:
+ pdata->over_voltage_protection = REG_I2C_1_OVP1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ /* Synchronous (default) and non-synchronous mode */
+ pdata->sync_mode = true;
+ if (of_property_read_bool(node, "mps,no-sync-mode"))
+ pdata->sync_mode = false;
+
+ return 0;
+}
+
+static int mp3309c_probe(struct i2c_client *client)
+{
+ struct mp3309c_platform_data *pdata = dev_get_platdata(&client->dev);
+ struct mp3309c_chip *chip;
+ struct backlight_properties props;
+ struct pwm_state pwmstate;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "failed to check i2c functionality\n");
+ return -EOPNOTSUPP;
+ }
+
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->dev = &client->dev;
+
+ chip->regmap = devm_regmap_init_i2c(client, &mp3309c_regmap);
+ if (IS_ERR(chip->regmap))
+ return dev_err_probe(&client->dev, PTR_ERR(chip->regmap),
+ "failed to allocate register map\n");
+
+ i2c_set_clientdata(client, chip);
+
+ if (!pdata) {
+ pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ ret = pm3309c_parse_dt_node(chip, pdata);
+ if (ret)
+ return ret;
+ }
+ chip->pdata = pdata;
+
+ /* Backlight properties */
+ props.brightness = pdata->default_brightness;
+ props.max_brightness = pdata->max_brightness;
+ props.scale = BACKLIGHT_SCALE_LINEAR;
+ props.type = BACKLIGHT_RAW;
+ props.power = FB_BLANK_UNBLANK;
+ props.fb_blank = FB_BLANK_UNBLANK;
+ chip->bl = devm_backlight_device_register(chip->dev, "mp3309c",
+ chip->dev, chip,
+ &mp3309c_bl_ops, &props);
+ if (IS_ERR(chip->bl))
+ return dev_err_probe(chip->dev, PTR_ERR(chip->bl),
+ "error registering backlight device\n");
+
+ /* In PWM dimming mode, enable pwm device */
+ if (chip->pdata->dimming_mode == DIMMING_PWM) {
+ pwm_init_state(chip->pwmd, &pwmstate);
+ pwm_set_relative_duty_cycle(&pwmstate,
+ chip->pdata->default_brightness,
+ chip->pdata->max_brightness);
+ pwmstate.enabled = true;
+ ret = pwm_apply_state(chip->pwmd, &pwmstate);
+ if (ret)
+ return dev_err_probe(chip->dev, ret,
+ "error setting pwm device\n");
+ }
+
+ chip->pdata->status = FIRST_POWER_ON;
+ backlight_update_status(chip->bl);
+
+ return 0;
+}
+
+static void mp3309c_remove(struct i2c_client *client)
+{
+ struct mp3309c_chip *chip = i2c_get_clientdata(client);
+ struct backlight_device *bl = chip->bl;
+
+ bl->props.power = FB_BLANK_POWERDOWN;
+ bl->props.brightness = 0;
+ backlight_update_status(chip->bl);
+}
+
+static const struct of_device_id mp3309c_match_table[] = {
+ { .compatible = "mps,mp3309c", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mp3309c_match_table);
+
+static const struct i2c_device_id mp3309c_id[] = {
+ { "mp3309c", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mp3309c_id);
+
+static struct i2c_driver mp3309c_i2c_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = mp3309c_match_table,
+ },
+ .probe = mp3309c_probe,
+ .remove = mp3309c_remove,
+ .id_table = mp3309c_id,
+};
+
+module_i2c_driver(mp3309c_i2c_driver);
+
+MODULE_DESCRIPTION("Backlight Driver for MPS MP3309C");
+MODULE_AUTHOR("Flavio Suligoi <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 289bd9ce4d36..ffcebf6aa76a 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -103,7 +103,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
pwm_get_state(pb->pwm, &state);
state.duty_cycle = compute_duty_cycle(pb, brightness, &state);
state.enabled = true;
- pwm_apply_state(pb->pwm, &state);
+ pwm_apply_might_sleep(pb->pwm, &state);
pwm_backlight_power_on(pb);
} else {
@@ -120,7 +120,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
* inactive output.
*/
state.enabled = !pb->power_supply && !pb->enable_gpio;
- pwm_apply_state(pb->pwm, &state);
+ pwm_apply_might_sleep(pb->pwm, &state);
}
if (pb->notify_after)
@@ -461,10 +461,9 @@ static int pwm_backlight_probe(struct platform_device *pdev)
if (!data) {
ret = pwm_backlight_parse_dt(&pdev->dev, &defdata);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to find platform data\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to find platform data\n");
data = &defdata;
}
@@ -493,24 +492,27 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
GPIOD_ASIS);
if (IS_ERR(pb->enable_gpio)) {
- ret = PTR_ERR(pb->enable_gpio);
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(pb->enable_gpio),
+ "failed to acquire enable GPIO\n");
goto err_alloc;
}
pb->power_supply = devm_regulator_get_optional(&pdev->dev, "power");
if (IS_ERR(pb->power_supply)) {
ret = PTR_ERR(pb->power_supply);
- if (ret == -ENODEV)
+ if (ret == -ENODEV) {
pb->power_supply = NULL;
- else
+ } else {
+ dev_err_probe(&pdev->dev, ret,
+ "failed to acquire power regulator\n");
goto err_alloc;
+ }
}
pb->pwm = devm_pwm_get(&pdev->dev, NULL);
if (IS_ERR(pb->pwm)) {
- ret = PTR_ERR(pb->pwm);
- if (ret != -EPROBE_DEFER)
- dev_err(&pdev->dev, "unable to request PWM\n");
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(pb->pwm),
+ "unable to request PWM\n");
goto err_alloc;
}
@@ -528,10 +530,10 @@ static int pwm_backlight_probe(struct platform_device *pdev)
if (!state.period && (data->pwm_period_ns > 0))
state.period = data->pwm_period_ns;
- ret = pwm_apply_state(pb->pwm, &state);
+ ret = pwm_apply_might_sleep(pb->pwm, &state);
if (ret) {
- dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
- ret);
+ dev_err_probe(&pdev->dev, ret,
+ "failed to apply initial PWM state");
goto err_alloc;
}
@@ -568,8 +570,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
ret = pwm_backlight_brightness_default(&pdev->dev, data,
state.period);
if (ret < 0) {
- dev_err(&pdev->dev,
- "failed to setup default brightness table\n");
+ dev_err_probe(&pdev->dev, ret,
+ "failed to setup default brightness table\n");
goto err_alloc;
}
@@ -597,8 +599,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb,
&pwm_backlight_ops, &props);
if (IS_ERR(bl)) {
- dev_err(&pdev->dev, "failed to register backlight\n");
- ret = PTR_ERR(bl);
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(bl),
+ "failed to register backlight\n");
goto err_alloc;
}
@@ -633,7 +635,7 @@ static void pwm_backlight_remove(struct platform_device *pdev)
pwm_get_state(pb->pwm, &state);
state.duty_cycle = 0;
state.enabled = false;
- pwm_apply_state(pb->pwm, &state);
+ pwm_apply_might_sleep(pb->pwm, &state);
if (pb->exit)
pb->exit(&pdev->dev);
@@ -649,7 +651,7 @@ static void pwm_backlight_shutdown(struct platform_device *pdev)
pwm_get_state(pb->pwm, &state);
state.duty_cycle = 0;
state.enabled = false;
- pwm_apply_state(pb->pwm, &state);
+ pwm_apply_might_sleep(pb->pwm, &state);
}
#ifdef CONFIG_PM_SLEEP
@@ -673,7 +675,7 @@ static int pwm_backlight_suspend(struct device *dev)
pwm_get_state(pb->pwm, &state);
state.duty_cycle = 0;
state.enabled = false;
- pwm_apply_state(pb->pwm, &state);
+ pwm_apply_might_sleep(pb->pwm, &state);
if (pb->notify_after)
pb->notify_after(pb->dev, 0);
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 83c2d7329ca5..bc31db6ef7d2 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -7,7 +7,7 @@ menu "Console display driver support"
config VGA_CONSOLE
bool "VGA text console" if EXPERT || !X86
- depends on ALPHA || IA64 || X86 || \
+ depends on ALPHA || X86 || \
(ARM && ARCH_FOOTBRIDGE) || \
(MIPS && (MIPS_MALTA || SIBYTE_BCM112X || SIBYTE_SB1250 || SIBYTE_BCM1x80 || SNI_RM))
select APERTURE_HELPERS if (DRM || FB || VFIO_PCI_CORE)
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index d5909a9206ff..2d0bcc1d786e 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -116,24 +116,6 @@ config FB_PM2_FIFO_DISCONNECT
help
Support the Permedia2 FIFO disconnect feature.
-config FB_ARMCLCD
- tristate "ARM PrimeCell PL110 support"
- depends on ARM || ARM64 || COMPILE_TEST
- depends on FB && ARM_AMBA && HAS_IOMEM
- select FB_IOMEM_HELPERS
- select FB_MODE_HELPERS if OF
- select VIDEOMODE_HELPERS if OF
- select BACKLIGHT_CLASS_DEVICE if OF
- help
- This framebuffer device driver is for the ARM PrimeCell PL110
- Colour LCD controller. ARM PrimeCells provide the building
- blocks for System on a Chip devices.
-
- If you want to compile this as a module (=code which can be
- inserted into and removed from the running kernel), say M
- here and read <file:Documentation/kbuild/modules.rst>. The module
- will be called amba-clcd.
-
config FB_ACORN
bool "Acorn VIDC support"
depends on (FB = y) && ARM && ARCH_ACORN
@@ -839,60 +821,6 @@ config FB_I810_I2C
If unsure, say Y.
-config FB_LE80578
- tristate "Intel LE80578 (Vermilion) support"
- depends on FB && PCI && X86
- select FB_IOMEM_HELPERS
- select FB_MODE_HELPERS
- select VIDEO_NOMODESET
- help
- This driver supports the LE80578 (Vermilion Range) chipset
-
-config FB_CARILLO_RANCH
- tristate "Intel Carillo Ranch support"
- depends on FB_LE80578 && FB && PCI && X86
- help
- This driver supports the LE80578 (Carillo Ranch) board
-
-config FB_INTEL
- tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support"
- depends on FB && PCI && X86 && AGP_INTEL && EXPERT
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
- select FB_IOMEM_FOPS
- select FB_MODE_HELPERS
- select BOOT_VESA_SUPPORT if FB_INTEL = y
- select VIDEO_NOMODESET
- depends on !DRM_I915
- help
- This driver supports the on-board graphics built in to the Intel
- 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets.
- Say Y if you have and plan to use such a board.
-
- To make FB_INTEL=Y work you need to say AGP_INTEL=y too.
-
- To compile this driver as a module, choose M here: the
- module will be called intelfb.
-
- For more information, please read <file:Documentation/fb/intelfb.rst>
-
-config FB_INTEL_DEBUG
- bool "Intel driver Debug Messages"
- depends on FB_INTEL
- help
- Say Y here if you want the Intel driver to output all sorts
- of debugging information to provide to the maintainer when
- something goes wrong.
-
-config FB_INTEL_I2C
- bool "DDC/I2C for Intel framebuffer support"
- depends on FB_INTEL
- select FB_DDC
- default y
- help
- Say Y here if you want DDC/I2C support for your on-board Intel graphics.
-
config FB_MATROX
tristate "Matrox acceleration"
depends on FB && PCI
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index 8e15220152bd..3eecd51267fa 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -42,7 +42,6 @@ obj-$(CONFIG_FB_IMSTT) += imsttfb.o
obj-$(CONFIG_FB_FM2) += fm2fb.o
obj-$(CONFIG_FB_VT8623) += vt8623fb.o
obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
-obj-$(CONFIG_FB_LE80578) += vermilion/
obj-$(CONFIG_FB_S3) += s3fb.o
obj-$(CONFIG_FB_ARK) += arkfb.o
obj-$(CONFIG_FB_STI) += stifb.o
@@ -75,7 +74,6 @@ obj-$(CONFIG_FB_HIT) += hitfb.o
obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o
obj-$(CONFIG_FB_PVR2) += pvr2fb.o
obj-$(CONFIG_FB_VOODOO1) += sstfb.o
-obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o
obj-$(CONFIG_FB_68328) += 68328fb.o
obj-$(CONFIG_FB_GBE) += gbefb.o
diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c
deleted file mode 100644
index 47d373f04f3f..000000000000
--- a/drivers/video/fbdev/amba-clcd.c
+++ /dev/null
@@ -1,986 +0,0 @@
-/*
- * linux/drivers/video/amba-clcd.c
- *
- * Copyright (C) 2001 ARM Limited, by David A Rusling
- * Updated to 2.5, Deep Blue Solutions Ltd.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- *
- * ARM PrimeCell PL110 Color LCD Controller
- */
-#include <linux/amba/bus.h>
-#include <linux/amba/clcd.h>
-#include <linux/backlight.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_graph.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <video/display_timing.h>
-#include <video/of_display_timing.h>
-#include <video/videomode.h>
-
-#define to_clcd(info) container_of(info, struct clcd_fb, fb)
-
-/* This is limited to 16 characters when displayed by X startup */
-static const char *clcd_name = "CLCD FB";
-
-static inline void clcdfb_set_start(struct clcd_fb *fb)
-{
- unsigned long ustart = fb->fb.fix.smem_start;
- unsigned long lstart;
-
- ustart += fb->fb.var.yoffset * fb->fb.fix.line_length;
- lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2;
-
- writel(ustart, fb->regs + CLCD_UBAS);
- writel(lstart, fb->regs + CLCD_LBAS);
-}
-
-static void clcdfb_disable(struct clcd_fb *fb)
-{
- u32 val;
-
- if (fb->board->disable)
- fb->board->disable(fb);
-
- if (fb->panel->backlight) {
- fb->panel->backlight->props.power = FB_BLANK_POWERDOWN;
- backlight_update_status(fb->panel->backlight);
- }
-
- val = readl(fb->regs + fb->off_cntl);
- if (val & CNTL_LCDPWR) {
- val &= ~CNTL_LCDPWR;
- writel(val, fb->regs + fb->off_cntl);
-
- msleep(20);
- }
- if (val & CNTL_LCDEN) {
- val &= ~CNTL_LCDEN;
- writel(val, fb->regs + fb->off_cntl);
- }
-
- /*
- * Disable CLCD clock source.
- */
- if (fb->clk_enabled) {
- fb->clk_enabled = false;
- clk_disable(fb->clk);
- }
-}
-
-static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
-{
- /*
- * Enable the CLCD clock source.
- */
- if (!fb->clk_enabled) {
- fb->clk_enabled = true;
- clk_enable(fb->clk);
- }
-
- /*
- * Bring up by first enabling..
- */
- cntl |= CNTL_LCDEN;
- writel(cntl, fb->regs + fb->off_cntl);
-
- msleep(20);
-
- /*
- * and now apply power.
- */
- cntl |= CNTL_LCDPWR;
- writel(cntl, fb->regs + fb->off_cntl);
-
- /*
- * Turn on backlight
- */
- if (fb->panel->backlight) {
- fb->panel->backlight->props.power = FB_BLANK_UNBLANK;
- backlight_update_status(fb->panel->backlight);
- }
-
- /*
- * finally, enable the interface.
- */
- if (fb->board->enable)
- fb->board->enable(fb);
-}
-
-static int
-clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
-{
- u32 caps;
- int ret = 0;
-
- if (fb->panel->caps && fb->board->caps)
- caps = fb->panel->caps & fb->board->caps;
- else {
- /* Old way of specifying what can be used */
- caps = fb->panel->cntl & CNTL_BGR ?
- CLCD_CAP_BGR : CLCD_CAP_RGB;
- /* But mask out 444 modes as they weren't supported */
- caps &= ~CLCD_CAP_444;
- }
-
- /* Only TFT panels can do RGB888/BGR888 */
- if (!(fb->panel->cntl & CNTL_LCDTFT))
- caps &= ~CLCD_CAP_888;
-
- memset(&var->transp, 0, sizeof(var->transp));
-
- var->red.msb_right = 0;
- var->green.msb_right = 0;
- var->blue.msb_right = 0;
-
- switch (var->bits_per_pixel) {
- case 1:
- case 2:
- case 4:
- case 8:
- /* If we can't do 5551, reject */
- caps &= CLCD_CAP_5551;
- if (!caps) {
- ret = -EINVAL;
- break;
- }
-
- var->red.length = var->bits_per_pixel;
- var->red.offset = 0;
- var->green.length = var->bits_per_pixel;
- var->green.offset = 0;
- var->blue.length = var->bits_per_pixel;
- var->blue.offset = 0;
- break;
-
- case 16:
- /* If we can't do 444, 5551 or 565, reject */
- if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) {
- ret = -EINVAL;
- break;
- }
-
- /*
- * Green length can be 4, 5 or 6 depending whether
- * we're operating in 444, 5551 or 565 mode.
- */
- if (var->green.length == 4 && caps & CLCD_CAP_444)
- caps &= CLCD_CAP_444;
- if (var->green.length == 5 && caps & CLCD_CAP_5551)
- caps &= CLCD_CAP_5551;
- else if (var->green.length == 6 && caps & CLCD_CAP_565)
- caps &= CLCD_CAP_565;
- else {
- /*
- * PL110 officially only supports RGB555,
- * but may be wired up to allow RGB565.
- */
- if (caps & CLCD_CAP_565) {
- var->green.length = 6;
- caps &= CLCD_CAP_565;
- } else if (caps & CLCD_CAP_5551) {
- var->green.length = 5;
- caps &= CLCD_CAP_5551;
- } else {
- var->green.length = 4;
- caps &= CLCD_CAP_444;
- }
- }
-
- if (var->green.length >= 5) {
- var->red.length = 5;
- var->blue.length = 5;
- } else {
- var->red.length = 4;
- var->blue.length = 4;
- }
- break;
- case 32:
- /* If we can't do 888, reject */
- caps &= CLCD_CAP_888;
- if (!caps) {
- ret = -EINVAL;
- break;
- }
-
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- /*
- * >= 16bpp displays have separate colour component bitfields
- * encoded in the pixel data. Calculate their position from
- * the bitfield length defined above.
- */
- if (ret == 0 && var->bits_per_pixel >= 16) {
- bool bgr, rgb;
-
- bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0;
- rgb = caps & CLCD_CAP_RGB && var->red.offset == 0;
-
- if (!bgr && !rgb)
- /*
- * The requested format was not possible, try just
- * our capabilities. One of BGR or RGB must be
- * supported.
- */
- bgr = caps & CLCD_CAP_BGR;
-
- if (bgr) {
- var->blue.offset = 0;
- var->green.offset = var->blue.offset + var->blue.length;
- var->red.offset = var->green.offset + var->green.length;
- } else {
- var->red.offset = 0;
- var->green.offset = var->red.offset + var->red.length;
- var->blue.offset = var->green.offset + var->green.length;
- }
- }
-
- return ret;
-}
-
-static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
- struct clcd_fb *fb = to_clcd(info);
- int ret = -EINVAL;
-
- if (fb->board->check)
- ret = fb->board->check(fb, var);
-
- if (ret == 0 &&
- var->xres_virtual * var->bits_per_pixel / 8 *
- var->yres_virtual > fb->fb.fix.smem_len)
- ret = -EINVAL;
-
- if (ret == 0)
- ret = clcdfb_set_bitfields(fb, var);
-
- return ret;
-}
-
-static int clcdfb_set_par(struct fb_info *info)
-{
- struct clcd_fb *fb = to_clcd(info);
- struct clcd_regs regs;
-
- fb->fb.fix.line_length = fb->fb.var.xres_virtual *
- fb->fb.var.bits_per_pixel / 8;
-
- if (fb->fb.var.bits_per_pixel <= 8)
- fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
- else
- fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
-
- fb->board->decode(fb, &regs);
-
- clcdfb_disable(fb);
-
- writel(regs.tim0, fb->regs + CLCD_TIM0);
- writel(regs.tim1, fb->regs + CLCD_TIM1);
- writel(regs.tim2, fb->regs + CLCD_TIM2);
- writel(regs.tim3, fb->regs + CLCD_TIM3);
-
- clcdfb_set_start(fb);
-
- clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);
-
- fb->clcd_cntl = regs.cntl;
-
- clcdfb_enable(fb, regs.cntl);
-
-#ifdef DEBUG
- printk(KERN_INFO
- "CLCD: Registers set to\n"
- " %08x %08x %08x %08x\n"
- " %08x %08x %08x %08x\n",
- readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
- readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
- readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
- readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl));
-#endif
-
- return 0;
-}
-
-static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
-{
- unsigned int mask = (1 << bf->length) - 1;
-
- return (val >> (16 - bf->length) & mask) << bf->offset;
-}
-
-/*
- * Set a single color register. The values supplied have a 16 bit
- * magnitude. Return != 0 for invalid regno.
- */
-static int
-clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
- unsigned int blue, unsigned int transp, struct fb_info *info)
-{
- struct clcd_fb *fb = to_clcd(info);
-
- if (regno < 16)
- fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
- convert_bitfield(blue, &fb->fb.var.blue) |
- convert_bitfield(green, &fb->fb.var.green) |
- convert_bitfield(red, &fb->fb.var.red);
-
- if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
- int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3);
- u32 val, mask, newval;
-
- newval = (red >> 11) & 0x001f;
- newval |= (green >> 6) & 0x03e0;
- newval |= (blue >> 1) & 0x7c00;
-
- /*
- * 3.2.11: if we're configured for big endian
- * byte order, the palette entries are swapped.
- */
- if (fb->clcd_cntl & CNTL_BEBO)
- regno ^= 1;
-
- if (regno & 1) {
- newval <<= 16;
- mask = 0x0000ffff;
- } else {
- mask = 0xffff0000;
- }
-
- val = readl(fb->regs + hw_reg) & mask;
- writel(val | newval, fb->regs + hw_reg);
- }
-
- return regno > 255;
-}
-
-/*
- * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
- * then the caller blanks by setting the CLUT (Color Look Up Table) to all
- * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
- * to e.g. a video mode which doesn't support it. Implements VESA suspend
- * and powerdown modes on hardware that supports disabling hsync/vsync:
- * blank_mode == 2: suspend vsync
- * blank_mode == 3: suspend hsync
- * blank_mode == 4: powerdown
- */
-static int clcdfb_blank(int blank_mode, struct fb_info *info)
-{
- struct clcd_fb *fb = to_clcd(info);
-
- if (blank_mode != 0) {
- clcdfb_disable(fb);
- } else {
- clcdfb_enable(fb, fb->clcd_cntl);
- }
- return 0;
-}
-
-static int clcdfb_mmap(struct fb_info *info,
- struct vm_area_struct *vma)
-{
- struct clcd_fb *fb = to_clcd(info);
- unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT;
- int ret = -EINVAL;
-
- len = info->fix.smem_len;
-
- if (off <= len && vma->vm_end - vma->vm_start <= len - off &&
- fb->board->mmap)
- ret = fb->board->mmap(fb, vma);
-
- return ret;
-}
-
-static const struct fb_ops clcdfb_ops = {
- .owner = THIS_MODULE,
- __FB_DEFAULT_IOMEM_OPS_RDWR,
- .fb_check_var = clcdfb_check_var,
- .fb_set_par = clcdfb_set_par,
- .fb_setcolreg = clcdfb_setcolreg,
- .fb_blank = clcdfb_blank,
- __FB_DEFAULT_IOMEM_OPS_DRAW,
- .fb_mmap = clcdfb_mmap,
-};
-
-static int clcdfb_register(struct clcd_fb *fb)
-{
- int ret;
-
- /*
- * ARM PL111 always has IENB at 0x1c; it's only PL110
- * which is reversed on some platforms.
- */
- if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) {
- fb->off_ienb = CLCD_PL111_IENB;
- fb->off_cntl = CLCD_PL111_CNTL;
- } else {
- fb->off_ienb = CLCD_PL110_IENB;
- fb->off_cntl = CLCD_PL110_CNTL;
- }
-
- fb->clk = clk_get(&fb->dev->dev, NULL);
- if (IS_ERR(fb->clk)) {
- ret = PTR_ERR(fb->clk);
- goto out;
- }
-
- ret = clk_prepare(fb->clk);
- if (ret)
- goto free_clk;
-
- fb->fb.device = &fb->dev->dev;
-
- fb->fb.fix.mmio_start = fb->dev->res.start;
- fb->fb.fix.mmio_len = resource_size(&fb->dev->res);
-
- fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
- if (!fb->regs) {
- printk(KERN_ERR "CLCD: unable to remap registers\n");
- ret = -ENOMEM;
- goto clk_unprep;
- }
-
- fb->fb.fbops = &clcdfb_ops;
- fb->fb.pseudo_palette = fb->cmap;
-
- strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id));
- fb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
- fb->fb.fix.type_aux = 0;
- fb->fb.fix.xpanstep = 0;
- fb->fb.fix.ypanstep = 0;
- fb->fb.fix.ywrapstep = 0;
- fb->fb.fix.accel = FB_ACCEL_NONE;
-
- fb->fb.var.xres = fb->panel->mode.xres;
- fb->fb.var.yres = fb->panel->mode.yres;
- fb->fb.var.xres_virtual = fb->panel->mode.xres;
- fb->fb.var.yres_virtual = fb->panel->mode.yres;
- fb->fb.var.bits_per_pixel = fb->panel->bpp;
- fb->fb.var.grayscale = fb->panel->grayscale;
- fb->fb.var.pixclock = fb->panel->mode.pixclock;
- fb->fb.var.left_margin = fb->panel->mode.left_margin;
- fb->fb.var.right_margin = fb->panel->mode.right_margin;
- fb->fb.var.upper_margin = fb->panel->mode.upper_margin;
- fb->fb.var.lower_margin = fb->panel->mode.lower_margin;
- fb->fb.var.hsync_len = fb->panel->mode.hsync_len;
- fb->fb.var.vsync_len = fb->panel->mode.vsync_len;
- fb->fb.var.sync = fb->panel->mode.sync;
- fb->fb.var.vmode = fb->panel->mode.vmode;
- fb->fb.var.activate = FB_ACTIVATE_NOW;
- fb->fb.var.nonstd = 0;
- fb->fb.var.height = fb->panel->height;
- fb->fb.var.width = fb->panel->width;
- fb->fb.var.accel_flags = 0;
-
- fb->fb.monspecs.hfmin = 0;
- fb->fb.monspecs.hfmax = 100000;
- fb->fb.monspecs.vfmin = 0;
- fb->fb.monspecs.vfmax = 400;
- fb->fb.monspecs.dclkmin = 1000000;
- fb->fb.monspecs.dclkmax = 100000000;
-
- /*
- * Make sure that the bitfields are set appropriately.
- */
- clcdfb_set_bitfields(fb, &fb->fb.var);
-
- /*
- * Allocate colourmap.
- */
- ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0);
- if (ret)
- goto unmap;
-
- /*
- * Ensure interrupts are disabled.
- */
- writel(0, fb->regs + fb->off_ienb);
-
- fb_set_var(&fb->fb, &fb->fb.var);
-
- dev_info(&fb->dev->dev, "%s hardware, %s display\n",
- fb->board->name, fb->panel->mode.name);
-
- ret = register_framebuffer(&fb->fb);
- if (ret == 0)
- goto out;
-
- printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
-
- fb_dealloc_cmap(&fb->fb.cmap);
- unmap:
- iounmap(fb->regs);
- clk_unprep:
- clk_unprepare(fb->clk);
- free_clk:
- clk_put(fb->clk);
- out:
- return ret;
-}
-
-#ifdef CONFIG_OF
-static int clcdfb_of_get_dpi_panel_mode(struct device_node *node,
- struct clcd_panel *clcd_panel)
-{
- int err;
- struct display_timing timing;
- struct videomode video;
-
- err = of_get_display_timing(node, "panel-timing", &timing);
- if (err) {
- pr_err("%pOF: problems parsing panel-timing (%d)\n", node, err);
- return err;
- }
-
- videomode_from_timing(&timing, &video);
-
- err = fb_videomode_from_videomode(&video, &clcd_panel->mode);
- if (err)
- return err;
-
- /* Set up some inversion flags */
- if (timing.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
- clcd_panel->tim2 |= TIM2_IPC;
- else if (!(timing.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE))
- /*
- * To preserve backwards compatibility, the IPC (inverted
- * pixel clock) flag needs to be set on any display that
- * doesn't explicitly specify that the pixel clock is
- * active on the negative or positive edge.
- */
- clcd_panel->tim2 |= TIM2_IPC;
-
- if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
- clcd_panel->tim2 |= TIM2_IHS;
-
- if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW)
- clcd_panel->tim2 |= TIM2_IVS;
-
- if (timing.flags & DISPLAY_FLAGS_DE_LOW)
- clcd_panel->tim2 |= TIM2_IOE;
-
- return 0;
-}
-
-static int clcdfb_snprintf_mode(char *buf, int size, struct fb_videomode *mode)
-{
- return snprintf(buf, size, "%ux%u@%u", mode->xres, mode->yres,
- mode->refresh);
-}
-
-static int clcdfb_of_get_backlight(struct device *dev,
- struct clcd_panel *clcd_panel)
-{
- struct backlight_device *backlight;
-
- /* Look up the optional backlight device */
- backlight = devm_of_find_backlight(dev);
- if (IS_ERR(backlight))
- return PTR_ERR(backlight);
-
- clcd_panel->backlight = backlight;
- return 0;
-}
-
-static int clcdfb_of_get_mode(struct device *dev, struct device_node *panel,
- struct clcd_panel *clcd_panel)
-{
- int err;
- struct fb_videomode *mode;
- char *name;
- int len;
-
- /* Only directly connected DPI panels supported for now */
- if (of_device_is_compatible(panel, "panel-dpi"))
- err = clcdfb_of_get_dpi_panel_mode(panel, clcd_panel);
- else
- err = -ENOENT;
- if (err)
- return err;
- mode = &clcd_panel->mode;
-
- len = clcdfb_snprintf_mode(NULL, 0, mode);
- name = devm_kzalloc(dev, len + 1, GFP_KERNEL);
- if (!name)
- return -ENOMEM;
-
- clcdfb_snprintf_mode(name, len + 1, mode);
- mode->name = name;
-
- return 0;
-}
-
-static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0)
-{
- static struct {
- unsigned int part;
- u32 r0, g0, b0;
- u32 caps;
- } panels[] = {
- { 0x110, 1, 7, 13, CLCD_CAP_5551 },
- { 0x110, 0, 8, 16, CLCD_CAP_888 },
- { 0x110, 16, 8, 0, CLCD_CAP_888 },
- { 0x111, 4, 14, 20, CLCD_CAP_444 },
- { 0x111, 3, 11, 19, CLCD_CAP_444 | CLCD_CAP_5551 },
- { 0x111, 3, 10, 19, CLCD_CAP_444 | CLCD_CAP_5551 |
- CLCD_CAP_565 },
- { 0x111, 0, 8, 16, CLCD_CAP_444 | CLCD_CAP_5551 |
- CLCD_CAP_565 | CLCD_CAP_888 },
- };
- int i;
-
- /* Bypass pixel clock divider */
- fb->panel->tim2 |= TIM2_BCD;
-
- /* TFT display, vert. comp. interrupt at the start of the back porch */
- fb->panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
-
- fb->panel->caps = 0;
-
- /* Match the setup with known variants */
- for (i = 0; i < ARRAY_SIZE(panels) && !fb->panel->caps; i++) {
- if (amba_part(fb->dev) != panels[i].part)
- continue;
- if (g0 != panels[i].g0)
- continue;
- if (r0 == panels[i].r0 && b0 == panels[i].b0)
- fb->panel->caps = panels[i].caps;
- }
-
- /*
- * If we actually physically connected the R lines to B and
- * vice versa
- */
- if (r0 != 0 && b0 == 0)
- fb->panel->bgr_connection = true;
-
- return fb->panel->caps ? 0 : -EINVAL;
-}
-
-static int clcdfb_of_init_display(struct clcd_fb *fb)
-{
- struct device_node *endpoint, *panel;
- int err;
- unsigned int bpp;
- u32 max_bandwidth;
- u32 tft_r0b0g0[3];
-
- fb->panel = devm_kzalloc(&fb->dev->dev, sizeof(*fb->panel), GFP_KERNEL);
- if (!fb->panel)
- return -ENOMEM;
-
- /*
- * Fetch the panel endpoint.
- */
- endpoint = of_graph_get_next_endpoint(fb->dev->dev.of_node, NULL);
- if (!endpoint)
- return -ENODEV;
-
- panel = of_graph_get_remote_port_parent(endpoint);
- if (!panel) {
- err = -ENODEV;
- goto out_endpoint_put;
- }
-
- err = clcdfb_of_get_backlight(&fb->dev->dev, fb->panel);
- if (err)
- goto out_panel_put;
-
- err = clcdfb_of_get_mode(&fb->dev->dev, panel, fb->panel);
- if (err)
- goto out_panel_put;
-
- err = of_property_read_u32(fb->dev->dev.of_node, "max-memory-bandwidth",
- &max_bandwidth);
- if (!err) {
- /*
- * max_bandwidth is in bytes per second and pixclock in
- * pico-seconds, so the maximum allowed bits per pixel is
- * 8 * max_bandwidth / (PICOS2KHZ(pixclock) * 1000)
- * Rearrange this calculation to avoid overflow and then ensure
- * result is a valid format.
- */
- bpp = max_bandwidth / (1000 / 8)
- / PICOS2KHZ(fb->panel->mode.pixclock);
- bpp = rounddown_pow_of_two(bpp);
- if (bpp > 32)
- bpp = 32;
- } else
- bpp = 32;
- fb->panel->bpp = bpp;
-
-#ifdef CONFIG_CPU_BIG_ENDIAN
- fb->panel->cntl |= CNTL_BEBO;
-#endif
- fb->panel->width = -1;
- fb->panel->height = -1;
-
- if (of_property_read_u32_array(endpoint,
- "arm,pl11x,tft-r0g0b0-pads",
- tft_r0b0g0, ARRAY_SIZE(tft_r0b0g0)) != 0) {
- err = -ENOENT;
- goto out_panel_put;
- }
-
- of_node_put(panel);
- of_node_put(endpoint);
-
- return clcdfb_of_init_tft_panel(fb, tft_r0b0g0[0],
- tft_r0b0g0[1], tft_r0b0g0[2]);
-out_panel_put:
- of_node_put(panel);
-out_endpoint_put:
- of_node_put(endpoint);
- return err;
-}
-
-static int clcdfb_of_vram_setup(struct clcd_fb *fb)
-{
- int err;
- struct device_node *memory;
- u64 size;
-
- err = clcdfb_of_init_display(fb);
- if (err)
- return err;
-
- memory = of_parse_phandle(fb->dev->dev.of_node, "memory-region", 0);
- if (!memory)
- return -ENODEV;
-
- fb->fb.screen_base = of_iomap(memory, 0);
- if (!fb->fb.screen_base) {
- of_node_put(memory);
- return -ENOMEM;
- }
-
- fb->fb.fix.smem_start = of_translate_address(memory,
- of_get_address(memory, 0, &size, NULL));
- fb->fb.fix.smem_len = size;
- of_node_put(memory);
-
- return 0;
-}
-
-static int clcdfb_of_vram_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
-{
- unsigned long off, user_size, kernel_size;
-
-
- off = vma->vm_pgoff << PAGE_SHIFT;
- user_size = vma->vm_end - vma->vm_start;
- kernel_size = fb->fb.fix.smem_len;
-
- if (off >= kernel_size || user_size > (kernel_size - off))
- return -ENXIO;
-
- return remap_pfn_range(vma, vma->vm_start,
- __phys_to_pfn(fb->fb.fix.smem_start) + vma->vm_pgoff,
- user_size,
- pgprot_writecombine(vma->vm_page_prot));
-}
-
-static void clcdfb_of_vram_remove(struct clcd_fb *fb)
-{
- iounmap(fb->fb.screen_base);
-}
-
-static int clcdfb_of_dma_setup(struct clcd_fb *fb)
-{
- unsigned long framesize;
- dma_addr_t dma;
- int err;
-
- err = clcdfb_of_init_display(fb);
- if (err)
- return err;
-
- framesize = PAGE_ALIGN(fb->panel->mode.xres * fb->panel->mode.yres *
- fb->panel->bpp / 8);
- fb->fb.screen_base = dma_alloc_coherent(&fb->dev->dev, framesize,
- &dma, GFP_KERNEL);
- if (!fb->fb.screen_base)
- return -ENOMEM;
-
- fb->fb.fix.smem_start = dma;
- fb->fb.fix.smem_len = framesize;
-
- return 0;
-}
-
-static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
-{
- vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
-
- return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base,
- fb->fb.fix.smem_start, fb->fb.fix.smem_len);
-}
-
-static void clcdfb_of_dma_remove(struct clcd_fb *fb)
-{
- dma_free_coherent(&fb->dev->dev, fb->fb.fix.smem_len,
- fb->fb.screen_base, fb->fb.fix.smem_start);
-}
-
-static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
-{
- struct clcd_board *board = devm_kzalloc(&dev->dev, sizeof(*board),
- GFP_KERNEL);
- struct device_node *node = dev->dev.of_node;
-
- if (!board)
- return NULL;
-
- board->name = of_node_full_name(node);
- board->caps = CLCD_CAP_ALL;
- board->check = clcdfb_check;
- board->decode = clcdfb_decode;
- if (of_property_present(node, "memory-region")) {
- board->setup = clcdfb_of_vram_setup;
- board->mmap = clcdfb_of_vram_mmap;
- board->remove = clcdfb_of_vram_remove;
- } else {
- board->setup = clcdfb_of_dma_setup;
- board->mmap = clcdfb_of_dma_mmap;
- board->remove = clcdfb_of_dma_remove;
- }
-
- return board;
-}
-#else
-static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
-{
- return NULL;
-}
-#endif
-
-static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
-{
- struct clcd_board *board = dev_get_platdata(&dev->dev);
- struct clcd_fb *fb;
- int ret;
-
- if (!board)
- board = clcdfb_of_get_board(dev);
-
- if (!board)
- return -EINVAL;
-
- ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
- if (ret)
- goto out;
-
- ret = amba_request_regions(dev, NULL);
- if (ret) {
- printk(KERN_ERR "CLCD: unable to reserve regs region\n");
- goto out;
- }
-
- fb = kzalloc(sizeof(*fb), GFP_KERNEL);
- if (!fb) {
- ret = -ENOMEM;
- goto free_region;
- }
-
- fb->dev = dev;
- fb->board = board;
-
- dev_info(&fb->dev->dev, "PL%03x designer %02x rev%u at 0x%08llx\n",
- amba_part(dev), amba_manf(dev), amba_rev(dev),
- (unsigned long long)dev->res.start);
-
- ret = fb->board->setup(fb);
- if (ret)
- goto free_fb;
-
- ret = clcdfb_register(fb);
- if (ret == 0) {
- amba_set_drvdata(dev, fb);
- goto out;
- }
-
- fb->board->remove(fb);
- free_fb:
- kfree(fb);
- free_region:
- amba_release_regions(dev);
- out:
- return ret;
-}
-
-static void clcdfb_remove(struct amba_device *dev)
-{
- struct clcd_fb *fb = amba_get_drvdata(dev);
-
- clcdfb_disable(fb);
- unregister_framebuffer(&fb->fb);
- if (fb->fb.cmap.len)
- fb_dealloc_cmap(&fb->fb.cmap);
- iounmap(fb->regs);
- clk_unprepare(fb->clk);
- clk_put(fb->clk);
-
- fb->board->remove(fb);
-
- kfree(fb);
-
- amba_release_regions(dev);
-}
-
-static const struct amba_id clcdfb_id_table[] = {
- {
- .id = 0x00041110,
- .mask = 0x000ffffe,
- },
- { 0, 0 },
-};
-
-MODULE_DEVICE_TABLE(amba, clcdfb_id_table);
-
-static struct amba_driver clcd_driver = {
- .drv = {
- .name = "clcd-pl11x",
- },
- .probe = clcdfb_probe,
- .remove = clcdfb_remove,
- .id_table = clcdfb_id_table,
-};
-
-static int __init amba_clcdfb_init(void)
-{
- if (fb_get_options("ambafb", NULL))
- return -ENODEV;
-
- return amba_driver_register(&clcd_driver);
-}
-
-module_init(amba_clcdfb_init);
-
-static void __exit amba_clcdfb_exit(void)
-{
- amba_driver_unregister(&clcd_driver);
-}
-
-module_exit(amba_clcdfb_exit);
-
-MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c
index 1b0b85e59e5e..dae96c9f61cf 100644
--- a/drivers/video/fbdev/core/fb_defio.c
+++ b/drivers/video/fbdev/core/fb_defio.c
@@ -132,11 +132,7 @@ int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasy
return 0;
inode_lock(inode);
- /* Kill off the delayed work */
- cancel_delayed_work_sync(&info->deferred_work);
-
- /* Run it immediately */
- schedule_delayed_work(&info->deferred_work, 0);
+ flush_delayed_work(&info->deferred_work);
inode_unlock(inode);
return 0;
@@ -319,7 +315,7 @@ static void fb_deferred_io_lastclose(struct fb_info *info)
struct page *page;
int i;
- cancel_delayed_work_sync(&info->deferred_work);
+ flush_delayed_work(&info->deferred_work);
/* clear out the mapping that we setup */
for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) {
diff --git a/drivers/video/fbdev/fsl-diu-fb.c b/drivers/video/fbdev/fsl-diu-fb.c
index 0bced82fa494..0191141657fd 100644
--- a/drivers/video/fbdev/fsl-diu-fb.c
+++ b/drivers/video/fbdev/fsl-diu-fb.c
@@ -877,7 +877,7 @@ static int map_video_memory(struct fb_info *info)
}
mutex_lock(&info->mm_lock);
info->screen_base = p;
- info->fix.smem_start = virt_to_phys(info->screen_base);
+ info->fix.smem_start = virt_to_phys((__force const void *)info->screen_base);
info->fix.smem_len = smem_len;
mutex_unlock(&info->mm_lock);
info->screen_size = info->fix.smem_len;
diff --git a/drivers/video/fbdev/hgafb.c b/drivers/video/fbdev/hgafb.c
index 10728259dac2..264c8cedba15 100644
--- a/drivers/video/fbdev/hgafb.c
+++ b/drivers/video/fbdev/hgafb.c
@@ -364,6 +364,8 @@ error:
* hgafb_open - open the framebuffer device
* @info: pointer to fb_info object containing info for current hga board
* @init: open by console system or userland.
+ *
+ * Returns: %0
*/
static int hgafb_open(struct fb_info *info, int init)
@@ -378,6 +380,8 @@ static int hgafb_open(struct fb_info *info, int init)
* hgafb_release - open the framebuffer device
* @info: pointer to fb_info object containing info for current hga board
* @init: open by console system or userland.
+ *
+ * Returns: %0
*/
static int hgafb_release(struct fb_info *info, int init)
@@ -399,6 +403,8 @@ static int hgafb_release(struct fb_info *info, int init)
* This callback function is used to set the color registers of a HGA
* board. Since we have only two fixed colors only @regno is checked.
* A zero is returned on success and 1 for failure.
+ *
+ * Returns: %0
*/
static int hgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
@@ -410,14 +416,15 @@ static int hgafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
}
/**
- * hga_pan_display - pan or wrap the display
+ * hgafb_pan_display - pan or wrap the display
* @var:contains new xoffset, yoffset and vmode values
* @info:pointer to fb_info object containing info for current hga board
*
* This function looks only at xoffset, yoffset and the %FB_VMODE_YWRAP
* flag in @var. If input parameters are correct it calls hga_pan() to
* program the hardware. @info->var is updated to the new values.
- * A zero is returned on success and %-EINVAL for failure.
+ *
+ * Returns: %0 on success or %-EINVAL for failure.
*/
static int hgafb_pan_display(struct fb_var_screeninfo *var,
@@ -449,6 +456,8 @@ static int hgafb_pan_display(struct fb_var_screeninfo *var,
* @blank_mode == 2 means suspend vsync,
* @blank_mode == 3 means suspend hsync,
* @blank_mode == 4 means powerdown.
+ *
+ * Returns: %0
*/
static int hgafb_blank(int blank_mode, struct fb_info *info)
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 6a29d2594b91..c26ee6fd73c9 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -48,7 +48,6 @@
#include <linux/aperture.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/screen_info.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/completion.h>
@@ -975,7 +974,8 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
struct pci_dev *pdev = NULL;
void __iomem *fb_virt;
int gen2vm = efi_enabled(EFI_BOOT);
- resource_size_t base, size;
+ resource_size_t base = 0;
+ resource_size_t size = 0;
phys_addr_t paddr;
int ret;
@@ -1010,9 +1010,6 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
goto getmem_done;
}
pr_info("Unable to allocate enough contiguous physical memory on Gen 1 VM. Using MMIO instead.\n");
- } else if (IS_ENABLED(CONFIG_SYSFB)) {
- base = screen_info.lfb_base;
- size = screen_info.lfb_size;
} else {
goto err1;
}
@@ -1056,16 +1053,13 @@ static int hvfb_getmem(struct hv_device *hdev, struct fb_info *info)
info->screen_size = dio_fb_size;
getmem_done:
- aperture_remove_conflicting_devices(base, size, KBUILD_MODNAME);
+ if (base && size)
+ aperture_remove_conflicting_devices(base, size, KBUILD_MODNAME);
+ else
+ aperture_remove_all_conflicting_devices(KBUILD_MODNAME);
- if (!gen2vm) {
+ if (!gen2vm)
pci_dev_put(pdev);
- } else if (IS_ENABLED(CONFIG_SYSFB)) {
- /* framebuffer is reallocated, clear screen_info to avoid misuse from kexec */
- screen_info.lfb_size = 0;
- screen_info.lfb_base = 0;
- screen_info.orig_video_isVGA = 0;
- }
return 0;
diff --git a/drivers/video/fbdev/imxfb.c b/drivers/video/fbdev/imxfb.c
index 84201c9608d3..a4dbc72f93c3 100644
--- a/drivers/video/fbdev/imxfb.c
+++ b/drivers/video/fbdev/imxfb.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Freescale i.MX Frame Buffer device driver
*
* Copyright (C) 2004 Sascha Hauer, Pengutronix
* Based on acornfb.c Copyright (C) Russell King.
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- *
* Please direct your questions and comments on this driver to the following
* email address:
*
@@ -34,6 +31,7 @@
#include <linux/math64.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/bitfield.h>
#include <linux/regulator/consumer.h>
@@ -41,12 +39,6 @@
#include <video/of_videomode.h>
#include <video/videomode.h>
-#define PCR_TFT (1 << 31)
-#define PCR_BPIX_8 (3 << 25)
-#define PCR_BPIX_12 (4 << 25)
-#define PCR_BPIX_16 (5 << 25)
-#define PCR_BPIX_18 (6 << 25)
-
struct imx_fb_videomode {
struct fb_videomode mode;
u32 pcr;
@@ -64,42 +56,50 @@ struct imx_fb_videomode {
#define LCDC_SSA 0x00
#define LCDC_SIZE 0x04
-#define SIZE_XMAX(x) ((((x) >> 4) & 0x3f) << 20)
+#define SIZE_XMAX_MASK GENMASK(25, 20)
-#define YMAX_MASK_IMX1 0x1ff
-#define YMAX_MASK_IMX21 0x3ff
+#define YMAX_MASK_IMX1 GENMASK(8, 0)
+#define YMAX_MASK_IMX21 GENMASK(9, 0)
#define LCDC_VPW 0x08
-#define VPW_VPW(x) ((x) & 0x3ff)
+#define VPW_VPW_MASK GENMASK(9, 0)
#define LCDC_CPOS 0x0C
-#define CPOS_CC1 (1<<31)
-#define CPOS_CC0 (1<<30)
-#define CPOS_OP (1<<28)
-#define CPOS_CXP(x) (((x) & 3ff) << 16)
+#define CPOS_CC1 BIT(31)
+#define CPOS_CC0 BIT(30)
+#define CPOS_OP BIT(28)
+#define CPOS_CXP_MASK GENMASK(25, 16)
#define LCDC_LCWHB 0x10
-#define LCWHB_BK_EN (1<<31)
-#define LCWHB_CW(w) (((w) & 0x1f) << 24)
-#define LCWHB_CH(h) (((h) & 0x1f) << 16)
-#define LCWHB_BD(x) ((x) & 0xff)
+#define LCWHB_BK_EN BIT(31)
+#define LCWHB_CW_MASK GENMASK(28, 24)
+#define LCWHB_CH_MASK GENMASK(20, 16)
+#define LCWHB_BD_MASK GENMASK(7, 0)
#define LCDC_LCHCC 0x14
#define LCDC_PCR 0x18
+#define PCR_TFT BIT(31)
+#define PCR_COLOR BIT(30)
+#define PCR_BPIX_MASK GENMASK(27, 25)
+#define PCR_BPIX_8 3
+#define PCR_BPIX_12 4
+#define PCR_BPIX_16 5
+#define PCR_BPIX_18 6
+#define PCR_PCD_MASK GENMASK(5, 0)
#define LCDC_HCR 0x1C
-#define HCR_H_WIDTH(x) (((x) & 0x3f) << 26)
-#define HCR_H_WAIT_1(x) (((x) & 0xff) << 8)
-#define HCR_H_WAIT_2(x) ((x) & 0xff)
+#define HCR_H_WIDTH_MASK GENMASK(31, 26)
+#define HCR_H_WAIT_1_MASK GENMASK(15, 8)
+#define HCR_H_WAIT_2_MASK GENMASK(7, 0)
#define LCDC_VCR 0x20
-#define VCR_V_WIDTH(x) (((x) & 0x3f) << 26)
-#define VCR_V_WAIT_1(x) (((x) & 0xff) << 8)
-#define VCR_V_WAIT_2(x) ((x) & 0xff)
+#define VCR_V_WIDTH_MASK GENMASK(31, 26)
+#define VCR_V_WAIT_1_MASK GENMASK(15, 8)
+#define VCR_V_WAIT_2_MASK GENMASK(7, 0)
#define LCDC_POS 0x24
-#define POS_POS(x) ((x) & 1f)
+#define POS_POS_MASK GENMASK(4, 0)
#define LCDC_LSCR1 0x28
/* bit fields in imxfb.h */
@@ -112,24 +112,24 @@ struct imx_fb_videomode {
#define LCDC_RMCR 0x34
-#define RMCR_LCDC_EN_MX1 (1<<1)
+#define RMCR_LCDC_EN_MX1 BIT(1)
-#define RMCR_SELF_REF (1<<0)
+#define RMCR_SELF_REF BIT(0)
#define LCDC_LCDICR 0x38
-#define LCDICR_INT_SYN (1<<2)
-#define LCDICR_INT_CON (1)
+#define LCDICR_INT_SYN BIT(2)
+#define LCDICR_INT_CON BIT(0)
#define LCDC_LCDISR 0x40
-#define LCDISR_UDR_ERR (1<<3)
-#define LCDISR_ERR_RES (1<<2)
-#define LCDISR_EOF (1<<1)
-#define LCDISR_BOF (1<<0)
+#define LCDISR_UDR_ERR BIT(3)
+#define LCDISR_ERR_RES BIT(2)
+#define LCDISR_EOF BIT(1)
+#define LCDISR_BOF BIT(0)
#define IMXFB_LSCR1_DEFAULT 0x00120300
#define LCDC_LAUSCR 0x80
-#define LAUSCR_AUS_MODE (1<<31)
+#define LAUSCR_AUS_MODE BIT(31)
/* Used fb-mode. Can be set on kernel command line, therefore file-static. */
static const char *fb_mode;
@@ -150,6 +150,12 @@ enum imxfb_type {
IMX21_FB,
};
+enum imxfb_panel_type {
+ PANEL_TYPE_MONOCHROME,
+ PANEL_TYPE_CSTN,
+ PANEL_TYPE_TFT,
+};
+
struct imxfb_info {
struct platform_device *pdev;
void __iomem *regs;
@@ -157,6 +163,7 @@ struct imxfb_info {
struct clk *clk_ahb;
struct clk *clk_per;
enum imxfb_type devtype;
+ enum imxfb_panel_type panel_type;
bool enabled;
/*
@@ -273,10 +280,10 @@ static int imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
struct imxfb_info *fbi = info->par;
u_int val, ret = 1;
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
if (regno < fbi->palette_size) {
val = (CNVT_TOHW(red, 4) << 8) |
- (CNVT_TOHW(green,4) << 4) |
+ (CNVT_TOHW(green, 4) << 4) |
CNVT_TOHW(blue, 4);
writel(val, fbi->regs + 0x800 + (regno << 2));
@@ -405,23 +412,23 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
pcr = (unsigned int)tmp;
- if (--pcr > 0x3F) {
- pcr = 0x3F;
- printk(KERN_WARNING "Must limit pixel clock to %luHz\n",
- lcd_clk / pcr);
+ if (--pcr > PCR_PCD_MASK) {
+ pcr = PCR_PCD_MASK;
+ dev_warn(&fbi->pdev->dev, "Must limit pixel clock to %luHz\n",
+ lcd_clk / pcr);
}
switch (var->bits_per_pixel) {
case 32:
- pcr |= PCR_BPIX_18;
+ pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_18);
rgb = &def_rgb_18;
break;
case 16:
default:
if (is_imx1_fb(fbi))
- pcr |= PCR_BPIX_12;
+ pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_12);
else
- pcr |= PCR_BPIX_16;
+ pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_16);
if (imxfb_mode->pcr & PCR_TFT)
rgb = &def_rgb_16_tft;
@@ -429,13 +436,13 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
rgb = &def_rgb_16_stn;
break;
case 8:
- pcr |= PCR_BPIX_8;
+ pcr |= FIELD_PREP(PCR_BPIX_MASK, PCR_BPIX_8);
rgb = &def_rgb_8;
break;
}
/* add sync polarities */
- pcr |= imxfb_mode->pcr & ~(0x3f | (7 << 25));
+ pcr |= imxfb_mode->pcr & ~(PCR_PCD_MASK | PCR_BPIX_MASK);
fbi->pcr = pcr;
/*
@@ -444,6 +451,13 @@ static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
if (!is_imx1_fb(fbi) && imxfb_mode->aus_mode)
fbi->lauscr = LAUSCR_AUS_MODE;
+ if (imxfb_mode->pcr & PCR_TFT)
+ fbi->panel_type = PANEL_TYPE_TFT;
+ else if (imxfb_mode->pcr & PCR_COLOR)
+ fbi->panel_type = PANEL_TYPE_CSTN;
+ else
+ fbi->panel_type = PANEL_TYPE_MONOCHROME;
+
/*
* Copy the RGB parameters for this display
* from the machine specific parameters.
@@ -506,7 +520,7 @@ static int imxfb_enable_controller(struct imxfb_info *fbi)
writel(fbi->map_dma, fbi->regs + LCDC_SSA);
/* panning offset 0 (0 pixel offset) */
- writel(0x00000000, fbi->regs + LCDC_POS);
+ writel(FIELD_PREP(POS_POS_MASK, 0), fbi->regs + LCDC_POS);
/* disable hardware cursor */
writel(readl(fbi->regs + LCDC_CPOS) & ~(CPOS_CC0 | CPOS_CC1),
@@ -562,7 +576,7 @@ static int imxfb_blank(int blank, struct fb_info *info)
{
struct imxfb_info *fbi = info->par;
- pr_debug("imxfb_blank: blank=%d\n", blank);
+ pr_debug("%s: blank=%d\n", __func__, blank);
switch (blank) {
case FB_BLANK_POWERDOWN:
@@ -596,6 +610,7 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
{
struct imxfb_info *fbi = info->par;
u32 ymax_mask = is_imx1_fb(fbi) ? YMAX_MASK_IMX1 : YMAX_MASK_IMX21;
+ u8 left_margin_low;
pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
var->xres, var->hsync_len,
@@ -604,49 +619,59 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
var->yres, var->vsync_len,
var->upper_margin, var->lower_margin);
+ if (fbi->panel_type == PANEL_TYPE_TFT)
+ left_margin_low = 3;
+ else if (fbi->panel_type == PANEL_TYPE_CSTN)
+ left_margin_low = 2;
+ else
+ left_margin_low = 0;
+
#if DEBUG_VAR
if (var->xres < 16 || var->xres > 1024)
- printk(KERN_ERR "%s: invalid xres %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid xres %d\n",
info->fix.id, var->xres);
if (var->hsync_len < 1 || var->hsync_len > 64)
- printk(KERN_ERR "%s: invalid hsync_len %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid hsync_len %d\n",
info->fix.id, var->hsync_len);
- if (var->left_margin < 3 || var->left_margin > 255)
- printk(KERN_ERR "%s: invalid left_margin %d\n",
+ if (var->left_margin < left_margin_low || var->left_margin > 255)
+ dev_err(&fbi->pdev->dev, "%s: invalid left_margin %d\n",
info->fix.id, var->left_margin);
if (var->right_margin < 1 || var->right_margin > 255)
- printk(KERN_ERR "%s: invalid right_margin %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid right_margin %d\n",
info->fix.id, var->right_margin);
if (var->yres < 1 || var->yres > ymax_mask)
- printk(KERN_ERR "%s: invalid yres %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid yres %d\n",
info->fix.id, var->yres);
if (var->vsync_len > 100)
- printk(KERN_ERR "%s: invalid vsync_len %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid vsync_len %d\n",
info->fix.id, var->vsync_len);
if (var->upper_margin > 63)
- printk(KERN_ERR "%s: invalid upper_margin %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid upper_margin %d\n",
info->fix.id, var->upper_margin);
if (var->lower_margin > 255)
- printk(KERN_ERR "%s: invalid lower_margin %d\n",
+ dev_err(&fbi->pdev->dev, "%s: invalid lower_margin %d\n",
info->fix.id, var->lower_margin);
#endif
/* physical screen start address */
- writel(VPW_VPW(var->xres * var->bits_per_pixel / 8 / 4),
- fbi->regs + LCDC_VPW);
+ writel(FIELD_PREP(VPW_VPW_MASK,
+ var->xres * var->bits_per_pixel / 8 / 4),
+ fbi->regs + LCDC_VPW);
- writel(HCR_H_WIDTH(var->hsync_len - 1) |
- HCR_H_WAIT_1(var->right_margin - 1) |
- HCR_H_WAIT_2(var->left_margin - 3),
- fbi->regs + LCDC_HCR);
+ writel(FIELD_PREP(HCR_H_WIDTH_MASK, var->hsync_len - 1) |
+ FIELD_PREP(HCR_H_WAIT_1_MASK, var->right_margin - 1) |
+ FIELD_PREP(HCR_H_WAIT_2_MASK,
+ var->left_margin - left_margin_low),
+ fbi->regs + LCDC_HCR);
- writel(VCR_V_WIDTH(var->vsync_len) |
- VCR_V_WAIT_1(var->lower_margin) |
- VCR_V_WAIT_2(var->upper_margin),
- fbi->regs + LCDC_VCR);
+ writel(FIELD_PREP(VCR_V_WIDTH_MASK, var->vsync_len) |
+ FIELD_PREP(VCR_V_WAIT_1_MASK, var->lower_margin) |
+ FIELD_PREP(VCR_V_WAIT_2_MASK, var->upper_margin),
+ fbi->regs + LCDC_VCR);
- writel(SIZE_XMAX(var->xres) | (var->yres & ymax_mask),
- fbi->regs + LCDC_SIZE);
+ writel(FIELD_PREP(SIZE_XMAX_MASK, var->xres >> 4) |
+ (var->yres & ymax_mask),
+ fbi->regs + LCDC_SIZE);
writel(fbi->pcr, fbi->regs + LCDC_PCR);
if (fbi->pwmr)
@@ -669,8 +694,6 @@ static int imxfb_init_fbinfo(struct platform_device *pdev)
struct imxfb_info *fbi = info->par;
struct device_node *np;
- pr_debug("%s\n",__func__);
-
info->pseudo_palette = devm_kmalloc_array(&pdev->dev, 16,
sizeof(u32), GFP_KERNEL);
if (!info->pseudo_palette)
@@ -678,6 +701,7 @@ static int imxfb_init_fbinfo(struct platform_device *pdev)
memset(fbi, 0, sizeof(struct imxfb_info));
+ fbi->pdev = pdev;
fbi->devtype = pdev->id_entry->driver_data;
strscpy(info->fix.id, IMX_NAME, sizeof(info->fix.id));
@@ -922,8 +946,10 @@ static int imxfb_probe(struct platform_device *pdev)
if (ret)
goto failed_init;
- /* Calculate maximum bytes used per pixel. In most cases this should
- * be the same as m->bpp/8 */
+ /*
+ * Calculate maximum bytes used per pixel. In most cases this should
+ * be the same as m->bpp/8
+ */
m = &fbi->mode[0];
bytes_per_pixel = (m->bpp + 7) / 8;
for (i = 0; i < fbi->num_modes; i++, m++)
@@ -1021,7 +1047,6 @@ static int imxfb_probe(struct platform_device *pdev)
lcd->props.max_contrast = 0xff;
imxfb_enable_controller(fbi);
- fbi->pdev = pdev;
return 0;
diff --git a/drivers/video/fbdev/intelfb/Makefile b/drivers/video/fbdev/intelfb/Makefile
deleted file mode 100644
index 7ff2debb31af..000000000000
--- a/drivers/video/fbdev/intelfb/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_FB_INTEL) += intelfb.o
-
-intelfb-y := intelfbdrv.o intelfbhw.o
-intelfb-$(CONFIG_FB_INTEL_I2C) += intelfb_i2c.o
-intelfb-objs := $(intelfb-y)
-
-ccflags-$(CONFIG_FB_INTEL_DEBUG) := -DDEBUG -DREGDUMP
diff --git a/drivers/video/fbdev/intelfb/intelfb.h b/drivers/video/fbdev/intelfb/intelfb.h
deleted file mode 100644
index 5de703902a21..000000000000
--- a/drivers/video/fbdev/intelfb/intelfb.h
+++ /dev/null
@@ -1,382 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _INTELFB_H
-#define _INTELFB_H
-
-/* $DHD: intelfb/intelfb.h,v 1.40 2003/06/27 15:06:25 dawes Exp $ */
-
-#include <linux/agp_backend.h>
-#include <linux/fb.h>
-
-#ifdef CONFIG_FB_INTEL_I2C
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#endif
-
-/*** Version/name ***/
-#define INTELFB_VERSION "0.9.6"
-#define INTELFB_MODULE_NAME "intelfb"
-#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/945GME/965G/965GM"
-
-
-/*** Debug/feature defines ***/
-
-#ifndef DEBUG
-#define DEBUG 0
-#endif
-
-#ifndef VERBOSE
-#define VERBOSE 0
-#endif
-
-#ifndef REGDUMP
-#define REGDUMP 0
-#endif
-
-#ifndef DETECT_VGA_CLASS_ONLY
-#define DETECT_VGA_CLASS_ONLY 1
-#endif
-
-#ifndef ALLOCATE_FOR_PANNING
-#define ALLOCATE_FOR_PANNING 1
-#endif
-
-#ifndef PREFERRED_MODE
-#define PREFERRED_MODE "1024x768-32@70"
-#endif
-
-/*** hw-related values ***/
-
-/* Resource Allocation */
-#define INTELFB_FB_ACQUIRED 1
-#define INTELFB_MMIO_ACQUIRED 2
-
-/* PCI ids for supported devices */
-#define PCI_DEVICE_ID_INTEL_830M 0x3577
-#define PCI_DEVICE_ID_INTEL_845G 0x2562
-#define PCI_DEVICE_ID_INTEL_85XGM 0x3582
-#define PCI_DEVICE_ID_INTEL_854 0x358E
-#define PCI_DEVICE_ID_INTEL_865G 0x2572
-#define PCI_DEVICE_ID_INTEL_915G 0x2582
-#define PCI_DEVICE_ID_INTEL_915GM 0x2592
-#define PCI_DEVICE_ID_INTEL_945G 0x2772
-#define PCI_DEVICE_ID_INTEL_945GM 0x27A2
-#define PCI_DEVICE_ID_INTEL_945GME 0x27AE
-#define PCI_DEVICE_ID_INTEL_965G 0x29A2
-#define PCI_DEVICE_ID_INTEL_965GM 0x2A02
-
-/* Size of MMIO region */
-#define INTEL_REG_SIZE 0x80000
-
-#define STRIDE_ALIGNMENT 16
-#define STRIDE_ALIGNMENT_I9XX 64
-
-#define PALETTE_8_ENTRIES 256
-
-
-/*** Macros ***/
-
-/* basic arithmetic */
-#define KB(x) ((x) * 1024)
-#define MB(x) ((x) * 1024 * 1024)
-#define BtoKB(x) ((x) / 1024)
-#define BtoMB(x) ((x) / 1024 / 1024)
-
-#define GTT_PAGE_SIZE KB(4)
-
-#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y))
-#define ROUND_DOWN_TO(x, y) ((x) / (y) * (y))
-#define ROUND_UP_TO_PAGE(x) ROUND_UP_TO((x), GTT_PAGE_SIZE)
-#define ROUND_DOWN_TO_PAGE(x) ROUND_DOWN_TO((x), GTT_PAGE_SIZE)
-
-/* messages */
-#define PFX INTELFB_MODULE_NAME ": "
-
-#define ERR_MSG(fmt, args...) printk(KERN_ERR PFX fmt, ## args)
-#define WRN_MSG(fmt, args...) printk(KERN_WARNING PFX fmt, ## args)
-#define NOT_MSG(fmt, args...) printk(KERN_NOTICE PFX fmt, ## args)
-#define INF_MSG(fmt, args...) printk(KERN_INFO PFX fmt, ## args)
-#if DEBUG
-#define DBG_MSG(fmt, args...) printk(KERN_DEBUG PFX fmt, ## args)
-#else
-#define DBG_MSG(fmt, args...) while (0) printk(fmt, ## args)
-#endif
-
-/* get commonly used pointers */
-#define GET_DINFO(info) (info)->par
-
-/* misc macros */
-#define ACCEL(d, i) \
- ((d)->accel && !(d)->ring_lockup && \
- ((i)->var.accel_flags & FB_ACCELF_TEXT))
-
-/*#define NOACCEL_CHIPSET(d) \
- ((d)->chipset != INTEL_865G)*/
-#define NOACCEL_CHIPSET(d) \
- (0)
-
-#define FIXED_MODE(d) ((d)->fixed_mode)
-
-/*** Driver parameters ***/
-
-#define RINGBUFFER_SIZE KB(64)
-#define HW_CURSOR_SIZE KB(4)
-
-/* Intel agpgart driver */
-#define AGP_PHYSICAL_MEMORY 2
-
-/* store information about an Ixxx DVO */
-/* The i830->i865 use multiple DVOs with multiple i2cs */
-/* the i915, i945 have a single sDVO i2c bus - which is different */
-#define MAX_OUTPUTS 6
-
-/* these are outputs from the chip - integrated only
- external chips are via DVO or SDVO output */
-#define INTELFB_OUTPUT_UNUSED 0
-#define INTELFB_OUTPUT_ANALOG 1
-#define INTELFB_OUTPUT_DVO 2
-#define INTELFB_OUTPUT_SDVO 3
-#define INTELFB_OUTPUT_LVDS 4
-#define INTELFB_OUTPUT_TVOUT 5
-
-#define INTELFB_DVO_CHIP_NONE 0
-#define INTELFB_DVO_CHIP_LVDS 1
-#define INTELFB_DVO_CHIP_TMDS 2
-#define INTELFB_DVO_CHIP_TVOUT 4
-
-#define INTELFB_OUTPUT_PIPE_NC 0
-#define INTELFB_OUTPUT_PIPE_A 1
-#define INTELFB_OUTPUT_PIPE_B 2
-
-/*** Data Types ***/
-
-/* supported chipsets */
-enum intel_chips {
- INTEL_830M,
- INTEL_845G,
- INTEL_85XGM,
- INTEL_852GM,
- INTEL_852GME,
- INTEL_854,
- INTEL_855GM,
- INTEL_855GME,
- INTEL_865G,
- INTEL_915G,
- INTEL_915GM,
- INTEL_945G,
- INTEL_945GM,
- INTEL_945GME,
- INTEL_965G,
- INTEL_965GM,
-};
-
-struct intelfb_hwstate {
- u32 vga0_divisor;
- u32 vga1_divisor;
- u32 vga_pd;
- u32 dpll_a;
- u32 dpll_b;
- u32 fpa0;
- u32 fpa1;
- u32 fpb0;
- u32 fpb1;
- u32 palette_a[PALETTE_8_ENTRIES];
- u32 palette_b[PALETTE_8_ENTRIES];
- u32 htotal_a;
- u32 hblank_a;
- u32 hsync_a;
- u32 vtotal_a;
- u32 vblank_a;
- u32 vsync_a;
- u32 src_size_a;
- u32 bclrpat_a;
- u32 htotal_b;
- u32 hblank_b;
- u32 hsync_b;
- u32 vtotal_b;
- u32 vblank_b;
- u32 vsync_b;
- u32 src_size_b;
- u32 bclrpat_b;
- u32 adpa;
- u32 dvoa;
- u32 dvob;
- u32 dvoc;
- u32 dvoa_srcdim;
- u32 dvob_srcdim;
- u32 dvoc_srcdim;
- u32 lvds;
- u32 pipe_a_conf;
- u32 pipe_b_conf;
- u32 disp_arb;
- u32 cursor_a_control;
- u32 cursor_b_control;
- u32 cursor_a_base;
- u32 cursor_b_base;
- u32 cursor_size;
- u32 disp_a_ctrl;
- u32 disp_b_ctrl;
- u32 disp_a_base;
- u32 disp_b_base;
- u32 cursor_a_palette[4];
- u32 cursor_b_palette[4];
- u32 disp_a_stride;
- u32 disp_b_stride;
- u32 vgacntrl;
- u32 add_id;
- u32 swf0x[7];
- u32 swf1x[7];
- u32 swf3x[3];
- u32 fence[8];
- u32 instpm;
- u32 mem_mode;
- u32 fw_blc_0;
- u32 fw_blc_1;
- u16 hwstam;
- u16 ier;
- u16 iir;
- u16 imr;
-};
-
-struct intelfb_heap_data {
- u32 physical;
- u8 __iomem *virtual;
- u32 offset; /* in GATT pages */
- u32 size; /* in bytes */
-};
-
-#ifdef CONFIG_FB_INTEL_I2C
-struct intelfb_i2c_chan {
- struct intelfb_info *dinfo;
- u32 reg;
- struct i2c_adapter adapter;
- struct i2c_algo_bit_data algo;
-};
-#endif
-
-struct intelfb_output_rec {
- int type;
- int pipe;
- int flags;
-
-#ifdef CONFIG_FB_INTEL_I2C
- struct intelfb_i2c_chan i2c_bus;
- struct intelfb_i2c_chan ddc_bus;
-#endif
-};
-
-struct intelfb_vsync {
- wait_queue_head_t wait;
- unsigned int count;
- int pan_display;
- u32 pan_offset;
-};
-
-struct intelfb_info {
- struct fb_info *info;
- const struct fb_ops *fbops;
- struct pci_dev *pdev;
-
- struct intelfb_hwstate save_state;
-
- /* agpgart structs */
- struct agp_memory *gtt_fb_mem; /* use all stolen memory or vram */
- struct agp_memory *gtt_ring_mem; /* ring buffer */
- struct agp_memory *gtt_cursor_mem; /* hw cursor */
-
- /* use a gart reserved fb mem */
- u8 fbmem_gart;
-
- int wc_cookie;
-
- /* heap data */
- struct intelfb_heap_data aperture;
- struct intelfb_heap_data fb;
- struct intelfb_heap_data ring;
- struct intelfb_heap_data cursor;
-
- /* mmio regs */
- u32 mmio_base_phys;
- u8 __iomem *mmio_base;
-
- /* fb start offset (in bytes) */
- u32 fb_start;
-
- /* ring buffer */
- u32 ring_head;
- u32 ring_tail;
- u32 ring_tail_mask;
- u32 ring_space;
- u32 ring_lockup;
-
- /* palette */
- u32 pseudo_palette[16];
-
- /* chip info */
- int pci_chipset;
- int chipset;
- const char *name;
- int mobile;
-
- /* current mode */
- int bpp, depth;
- u32 visual;
- int xres, yres, pitch;
- int pixclock;
-
- /* current pipe */
- int pipe;
-
- /* some flags */
- int accel;
- int hwcursor;
- int fixed_mode;
- int ring_active;
- int flag;
- unsigned long irq_flags;
- int open;
-
- /* vsync */
- struct intelfb_vsync vsync;
- spinlock_t int_lock;
-
- /* hw cursor */
- int cursor_on;
- int cursor_blanked;
- u8 cursor_src[64];
-
- /* initial parameters */
- int initial_vga;
- struct fb_var_screeninfo initial_var;
- u32 initial_fb_base;
- u32 initial_video_ram;
- u32 initial_pitch;
-
- /* driver registered */
- int registered;
-
- /* index into plls */
- int pll_index;
-
- /* outputs */
- int num_outputs;
- struct intelfb_output_rec output[MAX_OUTPUTS];
-};
-
-#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G) || \
- ((dinfo)->chipset == INTEL_915GM) || \
- ((dinfo)->chipset == INTEL_945G) || \
- ((dinfo)->chipset == INTEL_945GM) || \
- ((dinfo)->chipset == INTEL_945GME) || \
- ((dinfo)->chipset == INTEL_965G) || \
- ((dinfo)->chipset == INTEL_965GM))
-
-/*** function prototypes ***/
-
-extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
-
-#ifdef CONFIG_FB_INTEL_I2C
-extern void intelfb_create_i2c_busses(struct intelfb_info *dinfo);
-extern void intelfb_delete_i2c_busses(struct intelfb_info *dinfo);
-#endif
-
-#endif /* _INTELFB_H */
diff --git a/drivers/video/fbdev/intelfb/intelfb_i2c.c b/drivers/video/fbdev/intelfb/intelfb_i2c.c
deleted file mode 100644
index 3300bd31d9d7..000000000000
--- a/drivers/video/fbdev/intelfb/intelfb_i2c.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/**************************************************************************
-
- Copyright 2006 Dave Airlie <[email protected]>
-
-All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-on the rights to use, copy, modify, merge, publish, distribute, sub
-license, and/or sell copies of the Software, and to permit persons to whom
-the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice (including the next
-paragraph) shall be included in all copies or substantial portions of the
-Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
-THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-**************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/fb.h>
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-#include <asm/io.h>
-
-#include "intelfb.h"
-#include "intelfbhw.h"
-
-/* bit locations in the registers */
-#define SCL_DIR_MASK 0x0001
-#define SCL_DIR 0x0002
-#define SCL_VAL_MASK 0x0004
-#define SCL_VAL_OUT 0x0008
-#define SCL_VAL_IN 0x0010
-#define SDA_DIR_MASK 0x0100
-#define SDA_DIR 0x0200
-#define SDA_VAL_MASK 0x0400
-#define SDA_VAL_OUT 0x0800
-#define SDA_VAL_IN 0x1000
-
-static void intelfb_gpio_setscl(void *data, int state)
-{
- struct intelfb_i2c_chan *chan = data;
- struct intelfb_info *dinfo = chan->dinfo;
- u32 val;
-
- OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) |
- SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK);
- val = INREG(chan->reg);
-}
-
-static void intelfb_gpio_setsda(void *data, int state)
-{
- struct intelfb_i2c_chan *chan = data;
- struct intelfb_info *dinfo = chan->dinfo;
- u32 val;
-
- OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) |
- SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK);
- val = INREG(chan->reg);
-}
-
-static int intelfb_gpio_getscl(void *data)
-{
- struct intelfb_i2c_chan *chan = data;
- struct intelfb_info *dinfo = chan->dinfo;
- u32 val;
-
- OUTREG(chan->reg, SCL_DIR_MASK);
- OUTREG(chan->reg, 0);
- val = INREG(chan->reg);
- return ((val & SCL_VAL_IN) != 0);
-}
-
-static int intelfb_gpio_getsda(void *data)
-{
- struct intelfb_i2c_chan *chan = data;
- struct intelfb_info *dinfo = chan->dinfo;
- u32 val;
-
- OUTREG(chan->reg, SDA_DIR_MASK);
- OUTREG(chan->reg, 0);
- val = INREG(chan->reg);
- return ((val & SDA_VAL_IN) != 0);
-}
-
-static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo,
- struct intelfb_i2c_chan *chan,
- const u32 reg, const char *name,
- int class)
-{
- int rc;
-
- chan->dinfo = dinfo;
- chan->reg = reg;
- snprintf(chan->adapter.name, sizeof(chan->adapter.name),
- "intelfb %s", name);
- chan->adapter.class = class;
- chan->adapter.owner = THIS_MODULE;
- chan->adapter.algo_data = &chan->algo;
- chan->adapter.dev.parent = &chan->dinfo->pdev->dev;
- chan->algo.setsda = intelfb_gpio_setsda;
- chan->algo.setscl = intelfb_gpio_setscl;
- chan->algo.getsda = intelfb_gpio_getsda;
- chan->algo.getscl = intelfb_gpio_getscl;
- chan->algo.udelay = 40;
- chan->algo.timeout = 20;
- chan->algo.data = chan;
-
- i2c_set_adapdata(&chan->adapter, chan);
-
- /* Raise SCL and SDA */
- intelfb_gpio_setsda(chan, 1);
- intelfb_gpio_setscl(chan, 1);
- udelay(20);
-
- rc = i2c_bit_add_bus(&chan->adapter);
- if (rc == 0)
- DBG_MSG("I2C bus %s registered.\n", name);
- else
- WRN_MSG("Failed to register I2C bus %s.\n", name);
- return rc;
-}
-
-void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
-{
- int i = 0;
-
- /* everyone has at least a single analog output */
- dinfo->num_outputs = 1;
- dinfo->output[i].type = INTELFB_OUTPUT_ANALOG;
-
- /* setup the DDC bus for analog output */
- intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA,
- "CRTDDC_A", I2C_CLASS_DDC);
- i++;
-
- /* need to add the output busses for each device
- - this function is very incomplete
- - i915GM has LVDS and TVOUT for example
- */
- switch(dinfo->chipset) {
- case INTEL_830M:
- case INTEL_845G:
- case INTEL_854:
- case INTEL_855GM:
- case INTEL_865G:
- dinfo->output[i].type = INTELFB_OUTPUT_DVO;
- intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus,
- GPIOD, "DVODDC_D", I2C_CLASS_DDC);
- intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus,
- GPIOE, "DVOI2C_E", 0);
- i++;
- break;
- case INTEL_915G:
- case INTEL_915GM:
- /* has some LVDS + tv-out */
- case INTEL_945G:
- case INTEL_945GM:
- case INTEL_945GME:
- case INTEL_965G:
- case INTEL_965GM:
- /* SDVO ports have a single control bus - 2 devices */
- dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
- intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus,
- GPIOE, "SDVOCTRL_E", 0);
- /* TODO: initialize the SDVO */
- /* I830SDVOInit(pScrn, i, DVOB); */
- i++;
-
- /* set up SDVOC */
- dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
- dinfo->output[i].i2c_bus = dinfo->output[i - 1].i2c_bus;
- /* TODO: initialize the SDVO */
- /* I830SDVOInit(pScrn, i, DVOC); */
- i++;
- break;
- }
- dinfo->num_outputs = i;
-}
-
-void intelfb_delete_i2c_busses(struct intelfb_info *dinfo)
-{
- int i;
-
- for (i = 0; i < MAX_OUTPUTS; i++) {
- if (dinfo->output[i].i2c_bus.dinfo) {
- i2c_del_adapter(&dinfo->output[i].i2c_bus.adapter);
- dinfo->output[i].i2c_bus.dinfo = NULL;
- }
- if (dinfo->output[i].ddc_bus.dinfo) {
- i2c_del_adapter(&dinfo->output[i].ddc_bus.adapter);
- dinfo->output[i].ddc_bus.dinfo = NULL;
- }
- }
-}
diff --git a/drivers/video/fbdev/intelfb/intelfbdrv.c b/drivers/video/fbdev/intelfb/intelfbdrv.c
deleted file mode 100644
index d29d80a16295..000000000000
--- a/drivers/video/fbdev/intelfb/intelfbdrv.c
+++ /dev/null
@@ -1,1680 +0,0 @@
-/*
- * intelfb
- *
- * Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/
- * 945G/945GM/945GME/965G/965GM integrated graphics chips.
- *
- * Copyright © 2002, 2003 David Dawes <[email protected]>
- * 2004 Sylvain Meyer
- * 2006 David Airlie
- *
- * This driver consists of two parts. The first part (intelfbdrv.c) provides
- * the basic fbdev interfaces, is derived in part from the radeonfb and
- * vesafb drivers, and is covered by the GPL. The second part (intelfbhw.c)
- * provides the code to program the hardware. Most of it is derived from
- * the i810/i830 XFree86 driver. The HW-specific code is covered here
- * under a dual license (GPL and MIT/XFree86 license).
- *
- * Author: David Dawes
- *
- */
-
-/* $DHD: intelfb/intelfbdrv.c,v 1.20 2003/06/27 15:17:40 dawes Exp $ */
-
-/*
- * Changes:
- * 01/2003 - Initial driver (0.1.0), no mode switching, no acceleration.
- * This initial version is a basic core that works a lot like
- * the vesafb driver. It must be built-in to the kernel,
- * and the initial video mode must be set with vga=XXX at
- * boot time. (David Dawes)
- *
- * 01/2003 - Version 0.2.0: Mode switching added, colormap support
- * implemented, Y panning, and soft screen blanking implemented.
- * No acceleration yet. (David Dawes)
- *
- * 01/2003 - Version 0.3.0: fbcon acceleration support added. Module
- * option handling added. (David Dawes)
- *
- * 01/2003 - Version 0.4.0: fbcon HW cursor support added. (David Dawes)
- *
- * 01/2003 - Version 0.4.1: Add auto-generation of built-in modes.
- * (David Dawes)
- *
- * 02/2003 - Version 0.4.2: Add check for active non-CRT devices, and
- * mode validation checks. (David Dawes)
- *
- * 02/2003 - Version 0.4.3: Check when the VC is in graphics mode so that
- * acceleration is disabled while an XFree86 server is running.
- * (David Dawes)
- *
- * 02/2003 - Version 0.4.4: Monitor DPMS support. (David Dawes)
- *
- * 02/2003 - Version 0.4.5: Basic XFree86 + fbdev working. (David Dawes)
- *
- * 02/2003 - Version 0.5.0: Modify to work with the 2.5.32 kernel as well
- * as 2.4.x kernels. (David Dawes)
- *
- * 02/2003 - Version 0.6.0: Split out HW-specifics into a separate file.
- * (David Dawes)
- *
- * 02/2003 - Version 0.7.0: Test on 852GM/855GM. Acceleration and HW
- * cursor are disabled on this platform. (David Dawes)
- *
- * 02/2003 - Version 0.7.1: Test on 845G. Acceleration is disabled
- * on this platform. (David Dawes)
- *
- * 02/2003 - Version 0.7.2: Test on 830M. Acceleration and HW
- * cursor are disabled on this platform. (David Dawes)
- *
- * 02/2003 - Version 0.7.3: Fix 8-bit modes for mobile platforms
- * (David Dawes)
- *
- * 02/2003 - Version 0.7.4: Add checks for FB and FBCON_HAS_CFB* configured
- * in the kernel, and add mode bpp verification and default
- * bpp selection based on which FBCON_HAS_CFB* are configured.
- * (David Dawes)
- *
- * 02/2003 - Version 0.7.5: Add basic package/install scripts based on the
- * DRI packaging scripts. (David Dawes)
- *
- * 04/2003 - Version 0.7.6: Fix typo that affects builds with SMP-enabled
- * kernels. (David Dawes, reported by Anupam).
- *
- * 06/2003 - Version 0.7.7:
- * Fix Makefile.kernel build problem (Tsutomu Yasuda).
- * Fix mis-placed #endif (2.4.21 kernel).
- *
- * 09/2004 - Version 0.9.0 - by Sylvain Meyer
- * Port to linux 2.6 kernel fbdev
- * Fix HW accel and HW cursor on i845G
- * Use of agpgart for fb memory reservation
- * Add mtrr support
- *
- * 10/2004 - Version 0.9.1
- * Use module_param instead of old MODULE_PARM
- * Some cleanup
- *
- * 11/2004 - Version 0.9.2
- * Add vram option to reserve more memory than stolen by BIOS
- * Fix intelfbhw_pan_display typo
- * Add __initdata annotations
- *
- * 04/2008 - Version 0.9.5
- * Add support for 965G/965GM. (Maik Broemme <[email protected]>)
- *
- * 08/2008 - Version 0.9.6
- * Add support for 945GME. (Phil Endecott <[email protected]>)
- */
-
-#include <linux/aperture.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/pagemap.h>
-#include <linux/screen_info.h>
-
-#include <asm/io.h>
-
-#include "intelfb.h"
-#include "intelfbhw.h"
-#include "../edid.h"
-
-static void get_initial_mode(struct intelfb_info *dinfo);
-static void update_dinfo(struct intelfb_info *dinfo,
- struct fb_var_screeninfo *var);
-static int intelfb_open(struct fb_info *info, int user);
-static int intelfb_release(struct fb_info *info, int user);
-static int intelfb_check_var(struct fb_var_screeninfo *var,
- struct fb_info *info);
-static int intelfb_set_par(struct fb_info *info);
-static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info);
-
-static int intelfb_blank(int blank, struct fb_info *info);
-static int intelfb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info);
-
-static void intelfb_fillrect(struct fb_info *info,
- const struct fb_fillrect *rect);
-static void intelfb_copyarea(struct fb_info *info,
- const struct fb_copyarea *region);
-static void intelfb_imageblit(struct fb_info *info,
- const struct fb_image *image);
-static int intelfb_cursor(struct fb_info *info,
- struct fb_cursor *cursor);
-
-static int intelfb_sync(struct fb_info *info);
-
-static int intelfb_ioctl(struct fb_info *info,
- unsigned int cmd, unsigned long arg);
-
-static int intelfb_pci_register(struct pci_dev *pdev,
- const struct pci_device_id *ent);
-static void intelfb_pci_unregister(struct pci_dev *pdev);
-static int intelfb_set_fbinfo(struct intelfb_info *dinfo);
-
-/*
- * Limiting the class to PCI_CLASS_DISPLAY_VGA prevents function 1 of the
- * mobile chipsets from being registered.
- */
-#if DETECT_VGA_CLASS_ONLY
-#define INTELFB_CLASS_MASK ~0 << 8
-#else
-#define INTELFB_CLASS_MASK 0
-#endif
-
-static const struct pci_device_id intelfb_pci_table[] = {
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_830M, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_830M },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_845G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_845G },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_85XGM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_85XGM },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_865G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_865G },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_854, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_854 },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915G },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GME, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GME },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965G },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965GM },
- { 0, }
-};
-
-/* Global data */
-static int num_registered = 0;
-
-/* fb ops */
-static const struct fb_ops intel_fb_ops = {
- .owner = THIS_MODULE,
- .fb_open = intelfb_open,
- .fb_release = intelfb_release,
- __FB_DEFAULT_IOMEM_OPS_RDWR,
- .fb_check_var = intelfb_check_var,
- .fb_set_par = intelfb_set_par,
- .fb_setcolreg = intelfb_setcolreg,
- .fb_blank = intelfb_blank,
- .fb_pan_display = intelfb_pan_display,
- .fb_fillrect = intelfb_fillrect,
- .fb_copyarea = intelfb_copyarea,
- .fb_imageblit = intelfb_imageblit,
- .fb_cursor = intelfb_cursor,
- .fb_sync = intelfb_sync,
- .fb_ioctl = intelfb_ioctl,
- __FB_DEFAULT_IOMEM_OPS_MMAP,
-};
-
-/* PCI driver module table */
-static struct pci_driver intelfb_driver = {
- .name = "intelfb",
- .id_table = intelfb_pci_table,
- .probe = intelfb_pci_register,
- .remove = intelfb_pci_unregister,
-};
-
-/* Module description/parameters */
-MODULE_AUTHOR("David Dawes <[email protected]>, "
- "Sylvain Meyer <[email protected]>");
-MODULE_DESCRIPTION("Framebuffer driver for Intel(R) " SUPPORTED_CHIPSETS
- " chipsets");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_DEVICE_TABLE(pci, intelfb_pci_table);
-
-static bool accel = 1;
-static int vram = 4;
-static bool hwcursor = 0;
-static bool mtrr = 1;
-static bool fixed = 0;
-static bool noinit = 0;
-static bool noregister = 0;
-static bool probeonly = 0;
-static bool idonly = 0;
-static int bailearly = 0;
-static int voffset = 48;
-static char *mode = NULL;
-
-module_param(accel, bool, S_IRUGO);
-MODULE_PARM_DESC(accel, "Enable hardware acceleration");
-module_param(vram, int, S_IRUGO);
-MODULE_PARM_DESC(vram, "System RAM to allocate to framebuffer in MiB");
-module_param(voffset, int, S_IRUGO);
-MODULE_PARM_DESC(voffset, "Offset of framebuffer in MiB");
-module_param(hwcursor, bool, S_IRUGO);
-MODULE_PARM_DESC(hwcursor, "Enable HW cursor");
-module_param(mtrr, bool, S_IRUGO);
-MODULE_PARM_DESC(mtrr, "Enable MTRR support");
-module_param(fixed, bool, S_IRUGO);
-MODULE_PARM_DESC(fixed, "Disable mode switching");
-module_param(noinit, bool, 0);
-MODULE_PARM_DESC(noinit, "Don't initialise graphics mode when loading");
-module_param(noregister, bool, 0);
-MODULE_PARM_DESC(noregister, "Don't register, just probe and exit (debug)");
-module_param(probeonly, bool, 0);
-MODULE_PARM_DESC(probeonly, "Do a minimal probe (debug)");
-module_param(idonly, bool, 0);
-MODULE_PARM_DESC(idonly, "Just identify without doing anything else (debug)");
-module_param(bailearly, int, 0);
-MODULE_PARM_DESC(bailearly, "Bail out early, depending on value (debug)");
-module_param(mode, charp, S_IRUGO);
-MODULE_PARM_DESC(mode,
- "Initial video mode \"<xres>x<yres>[-<depth>][@<refresh>]\"");
-
-#ifndef MODULE
-#define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name)))
-#define OPT_INTVAL(opt, name) simple_strtoul(opt + strlen(name) + 1, NULL, 0)
-#define OPT_STRVAL(opt, name) (opt + strlen(name))
-
-static __inline__ char * get_opt_string(const char *this_opt, const char *name)
-{
- const char *p;
- int i;
- char *ret;
-
- p = OPT_STRVAL(this_opt, name);
- i = 0;
- while (p[i] && p[i] != ' ' && p[i] != ',')
- i++;
- ret = kmalloc(i + 1, GFP_KERNEL);
- if (ret) {
- strncpy(ret, p, i);
- ret[i] = '\0';
- }
- return ret;
-}
-
-static __inline__ int get_opt_int(const char *this_opt, const char *name,
- int *ret)
-{
- if (!ret)
- return 0;
-
- if (!OPT_EQUAL(this_opt, name))
- return 0;
-
- *ret = OPT_INTVAL(this_opt, name);
- return 1;
-}
-
-static __inline__ int get_opt_bool(const char *this_opt, const char *name,
- bool *ret)
-{
- if (!ret)
- return 0;
-
- if (OPT_EQUAL(this_opt, name)) {
- if (this_opt[strlen(name)] == '=')
- *ret = simple_strtoul(this_opt + strlen(name) + 1,
- NULL, 0);
- else
- *ret = 1;
- } else {
- if (OPT_EQUAL(this_opt, "no") && OPT_EQUAL(this_opt + 2, name))
- *ret = 0;
- else
- return 0;
- }
- return 1;
-}
-
-static int __init intelfb_setup(char *options)
-{
- char *this_opt;
-
- DBG_MSG("intelfb_setup\n");
-
- if (!options || !*options) {
- DBG_MSG("no options\n");
- return 0;
- } else
- DBG_MSG("options: %s\n", options);
-
- /*
- * These are the built-in options analogous to the module parameters
- * defined above.
- *
- * The syntax is:
- *
- * video=intelfb:[mode][,<param>=<val>] ...
- *
- * e.g.,
- *
- * video=intelfb:1024x768-16@75,accel=0
- */
-
- while ((this_opt = strsep(&options, ","))) {
- if (!*this_opt)
- continue;
- if (get_opt_bool(this_opt, "accel", &accel))
- ;
- else if (get_opt_int(this_opt, "vram", &vram))
- ;
- else if (get_opt_bool(this_opt, "hwcursor", &hwcursor))
- ;
- else if (get_opt_bool(this_opt, "mtrr", &mtrr))
- ;
- else if (get_opt_bool(this_opt, "fixed", &fixed))
- ;
- else if (get_opt_bool(this_opt, "init", &noinit))
- noinit = !noinit;
- else if (OPT_EQUAL(this_opt, "mode="))
- mode = get_opt_string(this_opt, "mode=");
- else
- mode = this_opt;
- }
-
- return 0;
-}
-
-#endif
-
-static int __init intelfb_init(void)
-{
-#ifndef MODULE
- char *option = NULL;
-#endif
-
- DBG_MSG("intelfb_init\n");
-
- INF_MSG("Framebuffer driver for "
- "Intel(R) " SUPPORTED_CHIPSETS " chipsets\n");
- INF_MSG("Version " INTELFB_VERSION "\n");
-
- if (idonly)
- return -ENODEV;
-
- if (fb_modesetting_disabled("intelfb"))
- return -ENODEV;
-
-#ifndef MODULE
- if (fb_get_options("intelfb", &option))
- return -ENODEV;
- intelfb_setup(option);
-#endif
-
- return pci_register_driver(&intelfb_driver);
-}
-
-static void __exit intelfb_exit(void)
-{
- DBG_MSG("intelfb_exit\n");
- pci_unregister_driver(&intelfb_driver);
-}
-
-module_init(intelfb_init);
-module_exit(intelfb_exit);
-
-/***************************************************************
- * driver init / cleanup *
- ***************************************************************/
-
-static void cleanup(struct intelfb_info *dinfo)
-{
- DBG_MSG("cleanup\n");
-
- if (!dinfo)
- return;
-
- intelfbhw_disable_irq(dinfo);
-
- fb_dealloc_cmap(&dinfo->info->cmap);
- kfree(dinfo->info->pixmap.addr);
-
- if (dinfo->registered)
- unregister_framebuffer(dinfo->info);
-
- arch_phys_wc_del(dinfo->wc_cookie);
-
- if (dinfo->fbmem_gart && dinfo->gtt_fb_mem) {
- agp_unbind_memory(dinfo->gtt_fb_mem);
- agp_free_memory(dinfo->gtt_fb_mem);
- }
- if (dinfo->gtt_cursor_mem) {
- agp_unbind_memory(dinfo->gtt_cursor_mem);
- agp_free_memory(dinfo->gtt_cursor_mem);
- }
- if (dinfo->gtt_ring_mem) {
- agp_unbind_memory(dinfo->gtt_ring_mem);
- agp_free_memory(dinfo->gtt_ring_mem);
- }
-
-#ifdef CONFIG_FB_INTEL_I2C
- /* un-register I2C bus */
- intelfb_delete_i2c_busses(dinfo);
-#endif
-
- if (dinfo->mmio_base)
- iounmap((void __iomem *)dinfo->mmio_base);
- if (dinfo->aperture.virtual)
- iounmap((void __iomem *)dinfo->aperture.virtual);
-
- if (dinfo->flag & INTELFB_MMIO_ACQUIRED)
- release_mem_region(dinfo->mmio_base_phys, INTEL_REG_SIZE);
- if (dinfo->flag & INTELFB_FB_ACQUIRED)
- release_mem_region(dinfo->aperture.physical,
- dinfo->aperture.size);
- framebuffer_release(dinfo->info);
-}
-
-#define bailout(dinfo) do { \
- DBG_MSG("bailout\n"); \
- cleanup(dinfo); \
- INF_MSG("Not going to register framebuffer, exiting...\n"); \
- return -ENODEV; \
-} while (0)
-
-
-static int intelfb_pci_register(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct fb_info *info;
- struct intelfb_info *dinfo;
- int i, err, dvo;
- int aperture_size, stolen_size = 0;
- struct agp_kern_info gtt_info;
- int agp_memtype;
- const char *s;
- struct agp_bridge_data *bridge;
- int aperture_bar = 0;
- int mmio_bar = 1;
- int offset;
-
- DBG_MSG("intelfb_pci_register\n");
-
- err = aperture_remove_conflicting_pci_devices(pdev, "intelfb");
- if (err)
- return err;
-
- num_registered++;
- if (num_registered != 1) {
- ERR_MSG("Attempted to register %d devices "
- "(should be only 1).\n", num_registered);
- return -ENODEV;
- }
-
- info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev);
- if (!info)
- return -ENOMEM;
-
- if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) {
- ERR_MSG("Could not allocate cmap for intelfb_info.\n");
- goto err_out_cmap;
- }
-
- dinfo = info->par;
- dinfo->info = info;
- dinfo->fbops = &intel_fb_ops;
- dinfo->pdev = pdev;
-
- /* Reserve pixmap space. */
- info->pixmap.addr = kzalloc(64 * 1024, GFP_KERNEL);
- if (info->pixmap.addr == NULL) {
- ERR_MSG("Cannot reserve pixmap memory.\n");
- goto err_out_pixmap;
- }
-
- /* set early this option because it could be changed by tv encoder
- driver */
- dinfo->fixed_mode = fixed;
-
- /* Enable device. */
- if ((err = pci_enable_device(pdev))) {
- ERR_MSG("Cannot enable device.\n");
- cleanup(dinfo);
- return -ENODEV;
- }
-
- /* Set base addresses. */
- if ((ent->device == PCI_DEVICE_ID_INTEL_915G) ||
- (ent->device == PCI_DEVICE_ID_INTEL_915GM) ||
- (ent->device == PCI_DEVICE_ID_INTEL_945G) ||
- (ent->device == PCI_DEVICE_ID_INTEL_945GM) ||
- (ent->device == PCI_DEVICE_ID_INTEL_945GME) ||
- (ent->device == PCI_DEVICE_ID_INTEL_965G) ||
- (ent->device == PCI_DEVICE_ID_INTEL_965GM)) {
-
- aperture_bar = 2;
- mmio_bar = 0;
- }
- dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar);
- dinfo->aperture.size = pci_resource_len(pdev, aperture_bar);
- dinfo->mmio_base_phys = pci_resource_start(pdev, mmio_bar);
- DBG_MSG("fb aperture: 0x%llx/0x%llx, MMIO region: 0x%llx/0x%llx\n",
- (unsigned long long)pci_resource_start(pdev, aperture_bar),
- (unsigned long long)pci_resource_len(pdev, aperture_bar),
- (unsigned long long)pci_resource_start(pdev, mmio_bar),
- (unsigned long long)pci_resource_len(pdev, mmio_bar));
-
- /* Reserve the fb and MMIO regions */
- if (!request_mem_region(dinfo->aperture.physical, dinfo->aperture.size,
- INTELFB_MODULE_NAME)) {
- ERR_MSG("Cannot reserve FB region.\n");
- cleanup(dinfo);
- return -ENODEV;
- }
-
- dinfo->flag |= INTELFB_FB_ACQUIRED;
-
- if (!request_mem_region(dinfo->mmio_base_phys,
- INTEL_REG_SIZE,
- INTELFB_MODULE_NAME)) {
- ERR_MSG("Cannot reserve MMIO region.\n");
- cleanup(dinfo);
- return -ENODEV;
- }
-
- dinfo->flag |= INTELFB_MMIO_ACQUIRED;
-
- /* Get the chipset info. */
- dinfo->pci_chipset = pdev->device;
-
- if (intelfbhw_get_chipset(pdev, dinfo)) {
- cleanup(dinfo);
- return -ENODEV;
- }
-
- if (intelfbhw_get_memory(pdev, &aperture_size, &stolen_size)) {
- cleanup(dinfo);
- return -ENODEV;
- }
-
- INF_MSG("%02x:%02x.%d: %s, aperture size %dMB, "
- "stolen memory %dkB\n",
- pdev->bus->number, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn), dinfo->name,
- BtoMB(aperture_size), BtoKB(stolen_size));
-
- /* Set these from the options. */
- dinfo->accel = accel;
- dinfo->hwcursor = hwcursor;
-
- if (NOACCEL_CHIPSET(dinfo) && dinfo->accel == 1) {
- INF_MSG("Acceleration is not supported for the %s chipset.\n",
- dinfo->name);
- dinfo->accel = 0;
- }
-
- /* Framebuffer parameters - Use all the stolen memory if >= vram */
- if (ROUND_UP_TO_PAGE(stolen_size) >= MB(vram)) {
- dinfo->fb.size = ROUND_UP_TO_PAGE(stolen_size);
- dinfo->fbmem_gart = 0;
- } else {
- dinfo->fb.size = MB(vram);
- dinfo->fbmem_gart = 1;
- }
-
- /* Allocate space for the ring buffer and HW cursor if enabled. */
- if (dinfo->accel) {
- dinfo->ring.size = RINGBUFFER_SIZE;
- dinfo->ring_tail_mask = dinfo->ring.size - 1;
- }
- if (dinfo->hwcursor)
- dinfo->cursor.size = HW_CURSOR_SIZE;
-
- /* Use agpgart to manage the GATT */
- if (!(bridge = agp_backend_acquire(pdev))) {
- ERR_MSG("cannot acquire agp\n");
- cleanup(dinfo);
- return -ENODEV;
- }
-
- /* get the current gatt info */
- if (agp_copy_info(bridge, &gtt_info)) {
- ERR_MSG("cannot get agp info\n");
- agp_backend_release(bridge);
- cleanup(dinfo);
- return -ENODEV;
- }
-
- if (MB(voffset) < stolen_size)
- offset = (stolen_size >> 12);
- else
- offset = ROUND_UP_TO_PAGE(MB(voffset))/GTT_PAGE_SIZE;
-
- /* set the mem offsets - set them after the already used pages */
- if (dinfo->accel)
- dinfo->ring.offset = offset + gtt_info.current_memory;
- if (dinfo->hwcursor)
- dinfo->cursor.offset = offset +
- + gtt_info.current_memory + (dinfo->ring.size >> 12);
- if (dinfo->fbmem_gart)
- dinfo->fb.offset = offset +
- + gtt_info.current_memory + (dinfo->ring.size >> 12)
- + (dinfo->cursor.size >> 12);
-
- /* Allocate memories (which aren't stolen) */
- /* Map the fb and MMIO regions */
- /* ioremap only up to the end of used aperture */
- dinfo->aperture.virtual = (u8 __iomem *)ioremap_wc
- (dinfo->aperture.physical, ((offset + dinfo->fb.offset) << 12)
- + dinfo->fb.size);
- if (!dinfo->aperture.virtual) {
- ERR_MSG("Cannot remap FB region.\n");
- agp_backend_release(bridge);
- cleanup(dinfo);
- return -ENODEV;
- }
-
- dinfo->mmio_base =
- (u8 __iomem *)ioremap(dinfo->mmio_base_phys,
- INTEL_REG_SIZE);
- if (!dinfo->mmio_base) {
- ERR_MSG("Cannot remap MMIO region.\n");
- agp_backend_release(bridge);
- cleanup(dinfo);
- return -ENODEV;
- }
-
- if (dinfo->accel) {
- if (!(dinfo->gtt_ring_mem =
- agp_allocate_memory(bridge, dinfo->ring.size >> 12,
- AGP_NORMAL_MEMORY))) {
- ERR_MSG("cannot allocate ring buffer memory\n");
- agp_backend_release(bridge);
- cleanup(dinfo);
- return -ENOMEM;
- }
- if (agp_bind_memory(dinfo->gtt_ring_mem,
- dinfo->ring.offset)) {
- ERR_MSG("cannot bind ring buffer memory\n");
- agp_backend_release(bridge);
- cleanup(dinfo);
- return -EBUSY;
- }
- dinfo->ring.physical = dinfo->aperture.physical
- + (dinfo->ring.offset << 12);
- dinfo->ring.virtual = dinfo->aperture.virtual
- + (dinfo->ring.offset << 12);
- dinfo->ring_head = 0;
- }
- if (dinfo->hwcursor) {
- agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY
- : AGP_NORMAL_MEMORY;
- if (!(dinfo->gtt_cursor_mem =
- agp_allocate_memory(bridge, dinfo->cursor.size >> 12,
- agp_memtype))) {
- ERR_MSG("cannot allocate cursor memory\n");
- agp_backend_release(bridge);
- cleanup(dinfo);
- return -ENOMEM;
- }
- if (agp_bind_memory(dinfo->gtt_cursor_mem,
- dinfo->cursor.offset)) {
- ERR_MSG("cannot bind cursor memory\n");
- agp_backend_release(bridge);
- cleanup(dinfo);
- return -EBUSY;
- }
- if (dinfo->mobile)
- dinfo->cursor.physical
- = dinfo->gtt_cursor_mem->physical;
- else
- dinfo->cursor.physical = dinfo->aperture.physical
- + (dinfo->cursor.offset << 12);
- dinfo->cursor.virtual = dinfo->aperture.virtual
- + (dinfo->cursor.offset << 12);
- }
- if (dinfo->fbmem_gart) {
- if (!(dinfo->gtt_fb_mem =
- agp_allocate_memory(bridge, dinfo->fb.size >> 12,
- AGP_NORMAL_MEMORY))) {
- WRN_MSG("cannot allocate framebuffer memory - use "
- "the stolen one\n");
- dinfo->fbmem_gart = 0;
- }
- if (agp_bind_memory(dinfo->gtt_fb_mem,
- dinfo->fb.offset)) {
- WRN_MSG("cannot bind framebuffer memory - use "
- "the stolen one\n");
- dinfo->fbmem_gart = 0;
- }
- }
-
- /* update framebuffer memory parameters */
- if (!dinfo->fbmem_gart)
- dinfo->fb.offset = 0; /* starts at offset 0 */
- dinfo->fb.physical = dinfo->aperture.physical
- + (dinfo->fb.offset << 12);
- dinfo->fb.virtual = dinfo->aperture.virtual + (dinfo->fb.offset << 12);
- dinfo->fb_start = dinfo->fb.offset << 12;
-
- /* release agpgart */
- agp_backend_release(bridge);
-
- if (mtrr)
- dinfo->wc_cookie = arch_phys_wc_add(dinfo->aperture.physical,
- dinfo->aperture.size);
-
- DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%p)\n",
- dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size,
- dinfo->fb.virtual);
- DBG_MSG("MMIO: 0x%x/0x%x (0x%p)\n",
- dinfo->mmio_base_phys, INTEL_REG_SIZE,
- dinfo->mmio_base);
- DBG_MSG("ring buffer: 0x%x/0x%x (0x%p)\n",
- dinfo->ring.physical, dinfo->ring.size,
- dinfo->ring.virtual);
- DBG_MSG("HW cursor: 0x%x/0x%x (0x%p) (offset 0x%x) (phys 0x%x)\n",
- dinfo->cursor.physical, dinfo->cursor.size,
- dinfo->cursor.virtual, dinfo->cursor.offset,
- dinfo->cursor.physical);
-
- DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, "
- "noinit = %d\n", vram, accel, hwcursor, fixed, noinit);
- DBG_MSG("options: mode = \"%s\"\n", mode ? mode : "");
-
- if (probeonly)
- bailout(dinfo);
-
- /*
- * Check if the LVDS port or any DVO ports are enabled. If so,
- * don't allow mode switching
- */
- dvo = intelfbhw_check_non_crt(dinfo);
- if (dvo) {
- dinfo->fixed_mode = 1;
- WRN_MSG("Non-CRT device is enabled ( ");
- i = 0;
- while (dvo) {
- if (dvo & 1) {
- s = intelfbhw_dvo_to_string(1 << i);
- if (s)
- printk("%s ", s);
- }
- dvo >>= 1;
- ++i;
- }
- printk("). Disabling mode switching.\n");
- }
-
- if (bailearly == 1)
- bailout(dinfo);
-
- if (FIXED_MODE(dinfo) &&
- screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) {
- ERR_MSG("Video mode must be programmed at boot time.\n");
- cleanup(dinfo);
- return -ENODEV;
- }
-
- if (bailearly == 2)
- bailout(dinfo);
-
- /* Initialise dinfo and related data. */
- /* If an initial mode was programmed at boot time, get its details. */
- if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB)
- get_initial_mode(dinfo);
-
- if (bailearly == 3)
- bailout(dinfo);
-
- if (FIXED_MODE(dinfo)) /* remap fb address */
- update_dinfo(dinfo, &dinfo->initial_var);
-
- if (bailearly == 4)
- bailout(dinfo);
-
-
- if (intelfb_set_fbinfo(dinfo)) {
- cleanup(dinfo);
- return -ENODEV;
- }
-
- if (bailearly == 5)
- bailout(dinfo);
-
-#ifdef CONFIG_FB_INTEL_I2C
- /* register I2C bus */
- intelfb_create_i2c_busses(dinfo);
-#endif
-
- if (bailearly == 6)
- bailout(dinfo);
-
- pci_set_drvdata(pdev, dinfo);
-
- /* Save the initial register state. */
- i = intelfbhw_read_hw_state(dinfo, &dinfo->save_state,
- bailearly > 6 ? bailearly - 6 : 0);
- if (i != 0) {
- DBG_MSG("intelfbhw_read_hw_state returned %d\n", i);
- bailout(dinfo);
- }
-
- intelfbhw_print_hw_state(dinfo, &dinfo->save_state);
-
- if (bailearly == 18)
- bailout(dinfo);
-
- /* read active pipe */
- dinfo->pipe = intelfbhw_active_pipe(&dinfo->save_state);
-
- /* Cursor initialisation */
- if (dinfo->hwcursor) {
- intelfbhw_cursor_init(dinfo);
- intelfbhw_cursor_reset(dinfo);
- }
-
- if (bailearly == 19)
- bailout(dinfo);
-
- /* 2d acceleration init */
- if (dinfo->accel)
- intelfbhw_2d_start(dinfo);
-
- if (bailearly == 20)
- bailout(dinfo);
-
- if (noregister)
- bailout(dinfo);
-
- if (register_framebuffer(dinfo->info) < 0) {
- ERR_MSG("Cannot register framebuffer.\n");
- cleanup(dinfo);
- return -ENODEV;
- }
-
- dinfo->registered = 1;
- dinfo->open = 0;
-
- init_waitqueue_head(&dinfo->vsync.wait);
- spin_lock_init(&dinfo->int_lock);
- dinfo->irq_flags = 0;
- dinfo->vsync.pan_display = 0;
- dinfo->vsync.pan_offset = 0;
-
- return 0;
-
-err_out_pixmap:
- fb_dealloc_cmap(&info->cmap);
-err_out_cmap:
- framebuffer_release(info);
- return -ENODEV;
-}
-
-static void intelfb_pci_unregister(struct pci_dev *pdev)
-{
- struct intelfb_info *dinfo = pci_get_drvdata(pdev);
-
- DBG_MSG("intelfb_pci_unregister\n");
-
- if (!dinfo)
- return;
-
- cleanup(dinfo);
-}
-
-/***************************************************************
- * helper functions *
- ***************************************************************/
-
-__inline__ int intelfb_var_to_depth(const struct fb_var_screeninfo *var)
-{
- DBG_MSG("intelfb_var_to_depth: bpp: %d, green.length is %d\n",
- var->bits_per_pixel, var->green.length);
-
- switch (var->bits_per_pixel) {
- case 16:
- return (var->green.length == 6) ? 16 : 15;
- case 32:
- return 24;
- default:
- return var->bits_per_pixel;
- }
-}
-
-
-static __inline__ int var_to_refresh(const struct fb_var_screeninfo *var)
-{
- int xtot = var->xres + var->left_margin + var->right_margin +
- var->hsync_len;
- int ytot = var->yres + var->upper_margin + var->lower_margin +
- var->vsync_len;
-
- return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot;
-}
-
-/***************************************************************
- * Various initialisation functions *
- ***************************************************************/
-
-static void get_initial_mode(struct intelfb_info *dinfo)
-{
- struct fb_var_screeninfo *var;
- int xtot, ytot;
-
- DBG_MSG("get_initial_mode\n");
-
- dinfo->initial_vga = 1;
- dinfo->initial_fb_base = screen_info.lfb_base;
- dinfo->initial_video_ram = screen_info.lfb_size * KB(64);
- dinfo->initial_pitch = screen_info.lfb_linelength;
-
- var = &dinfo->initial_var;
- memset(var, 0, sizeof(*var));
- var->xres = screen_info.lfb_width;
- var->yres = screen_info.lfb_height;
- var->bits_per_pixel = screen_info.lfb_depth;
- switch (screen_info.lfb_depth) {
- case 15:
- var->bits_per_pixel = 16;
- break;
- case 24:
- var->bits_per_pixel = 32;
- break;
- }
-
- DBG_MSG("Initial info: FB is 0x%x/0x%x (%d kByte)\n",
- dinfo->initial_fb_base, dinfo->initial_video_ram,
- BtoKB(dinfo->initial_video_ram));
-
- DBG_MSG("Initial info: mode is %dx%d-%d (%d)\n",
- var->xres, var->yres, var->bits_per_pixel,
- dinfo->initial_pitch);
-
- /* Dummy timing values (assume 60Hz) */
- var->left_margin = (var->xres / 8) & 0xf8;
- var->right_margin = 32;
- var->upper_margin = 16;
- var->lower_margin = 4;
- var->hsync_len = (var->xres / 8) & 0xf8;
- var->vsync_len = 4;
-
- xtot = var->xres + var->left_margin +
- var->right_margin + var->hsync_len;
- ytot = var->yres + var->upper_margin +
- var->lower_margin + var->vsync_len;
- var->pixclock = 10000000 / xtot * 1000 / ytot * 100 / 60;
-
- var->height = -1;
- var->width = -1;
-
- if (var->bits_per_pixel > 8) {
- var->red.offset = screen_info.red_pos;
- var->red.length = screen_info.red_size;
- var->green.offset = screen_info.green_pos;
- var->green.length = screen_info.green_size;
- var->blue.offset = screen_info.blue_pos;
- var->blue.length = screen_info.blue_size;
- var->transp.offset = screen_info.rsvd_pos;
- var->transp.length = screen_info.rsvd_size;
- } else {
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- }
-}
-
-static int intelfb_init_var(struct intelfb_info *dinfo)
-{
- struct fb_var_screeninfo *var;
- int msrc = 0;
-
- DBG_MSG("intelfb_init_var\n");
-
- var = &dinfo->info->var;
- if (FIXED_MODE(dinfo)) {
- memcpy(var, &dinfo->initial_var,
- sizeof(struct fb_var_screeninfo));
- msrc = 5;
- } else {
- const u8 *edid_s = fb_firmware_edid(&dinfo->pdev->dev);
- u8 *edid_d = NULL;
-
- if (edid_s) {
- edid_d = kmemdup(edid_s, EDID_LENGTH, GFP_KERNEL);
-
- if (edid_d) {
- fb_edid_to_monspecs(edid_d,
- &dinfo->info->monspecs);
- kfree(edid_d);
- }
- }
-
- if (mode) {
- printk("intelfb: Looking for mode in private "
- "database\n");
- msrc = fb_find_mode(var, dinfo->info, mode,
- dinfo->info->monspecs.modedb,
- dinfo->info->monspecs.modedb_len,
- NULL, 0);
-
- if (msrc && msrc > 1) {
- printk("intelfb: No mode in private database, "
- "intelfb: looking for mode in global "
- "database ");
- msrc = fb_find_mode(var, dinfo->info, mode,
- NULL, 0, NULL, 0);
-
- if (msrc)
- msrc |= 8;
- }
-
- }
-
- if (!msrc)
- msrc = fb_find_mode(var, dinfo->info, PREFERRED_MODE,
- NULL, 0, NULL, 0);
- }
-
- if (!msrc) {
- ERR_MSG("Cannot find a suitable video mode.\n");
- return 1;
- }
-
- INF_MSG("Initial video mode is %dx%d-%d@%d.\n", var->xres, var->yres,
- var->bits_per_pixel, var_to_refresh(var));
-
- DBG_MSG("Initial video mode is from %d.\n", msrc);
-
-#if ALLOCATE_FOR_PANNING
- /* Allow use of half of the video ram for panning */
- var->xres_virtual = var->xres;
- var->yres_virtual =
- dinfo->fb.size / 2 / (var->bits_per_pixel * var->xres);
- if (var->yres_virtual < var->yres)
- var->yres_virtual = var->yres;
-#else
- var->yres_virtual = var->yres;
-#endif
-
- if (dinfo->accel)
- var->accel_flags |= FB_ACCELF_TEXT;
- else
- var->accel_flags &= ~FB_ACCELF_TEXT;
-
- return 0;
-}
-
-static int intelfb_set_fbinfo(struct intelfb_info *dinfo)
-{
- struct fb_info *info = dinfo->info;
-
- DBG_MSG("intelfb_set_fbinfo\n");
-
- info->fbops = &intel_fb_ops;
- info->pseudo_palette = dinfo->pseudo_palette;
-
- info->pixmap.size = 64*1024;
- info->pixmap.buf_align = 8;
- info->pixmap.access_align = 32;
- info->pixmap.flags = FB_PIXMAP_SYSTEM;
-
- if (intelfb_init_var(dinfo))
- return 1;
-
- info->pixmap.scan_align = 1;
- strcpy(info->fix.id, dinfo->name);
- info->fix.smem_start = dinfo->fb.physical;
- info->fix.smem_len = dinfo->fb.size;
- info->fix.type = FB_TYPE_PACKED_PIXELS;
- info->fix.type_aux = 0;
- info->fix.xpanstep = 8;
- info->fix.ypanstep = 1;
- info->fix.ywrapstep = 0;
- info->fix.mmio_start = dinfo->mmio_base_phys;
- info->fix.mmio_len = INTEL_REG_SIZE;
- info->fix.accel = FB_ACCEL_I830;
- update_dinfo(dinfo, &info->var);
-
- return 0;
-}
-
-/* Update dinfo to match the active video mode. */
-static void update_dinfo(struct intelfb_info *dinfo,
- struct fb_var_screeninfo *var)
-{
- DBG_MSG("update_dinfo\n");
-
- dinfo->bpp = var->bits_per_pixel;
- dinfo->depth = intelfb_var_to_depth(var);
- dinfo->xres = var->xres;
- dinfo->yres = var->xres;
- dinfo->pixclock = var->pixclock;
-
- dinfo->info->fix.visual = dinfo->visual;
- dinfo->info->fix.line_length = dinfo->pitch;
-
- switch (dinfo->bpp) {
- case 8:
- dinfo->visual = FB_VISUAL_PSEUDOCOLOR;
- dinfo->pitch = var->xres_virtual;
- break;
- case 16:
- dinfo->visual = FB_VISUAL_TRUECOLOR;
- dinfo->pitch = var->xres_virtual * 2;
- break;
- case 32:
- dinfo->visual = FB_VISUAL_TRUECOLOR;
- dinfo->pitch = var->xres_virtual * 4;
- break;
- }
-
- /* Make sure the line length is a aligned correctly. */
- if (IS_I9XX(dinfo))
- dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT_I9XX);
- else
- dinfo->pitch = ROUND_UP_TO(dinfo->pitch, STRIDE_ALIGNMENT);
-
- if (FIXED_MODE(dinfo))
- dinfo->pitch = dinfo->initial_pitch;
-
- dinfo->info->screen_base = (char __iomem *)dinfo->fb.virtual;
- dinfo->info->fix.line_length = dinfo->pitch;
- dinfo->info->fix.visual = dinfo->visual;
-}
-
-/* fbops functions */
-
-/***************************************************************
- * fbdev interface *
- ***************************************************************/
-
-static int intelfb_open(struct fb_info *info, int user)
-{
- struct intelfb_info *dinfo = GET_DINFO(info);
-
- if (user)
- dinfo->open++;
-
- return 0;
-}
-
-static int intelfb_release(struct fb_info *info, int user)
-{
- struct intelfb_info *dinfo = GET_DINFO(info);
-
- if (user) {
- dinfo->open--;
- msleep(1);
- if (!dinfo->open)
- intelfbhw_disable_irq(dinfo);
- }
-
- return 0;
-}
-
-static int intelfb_check_var(struct fb_var_screeninfo *var,
- struct fb_info *info)
-{
- int change_var = 0;
- struct fb_var_screeninfo v;
- struct intelfb_info *dinfo;
- static int first = 1;
- int i;
- /* Good pitches to allow tiling. Don't care about pitches < 1024. */
- static const int pitches[] = {
- 128 * 8,
- 128 * 16,
- 128 * 32,
- 128 * 64,
- 0
- };
-
- DBG_MSG("intelfb_check_var: accel_flags is %d\n", var->accel_flags);
-
- dinfo = GET_DINFO(info);
-
- if (!var->pixclock)
- return -EINVAL;
-
- /* update the pitch */
- if (intelfbhw_validate_mode(dinfo, var) != 0)
- return -EINVAL;
-
- v = *var;
-
- for (i = 0; pitches[i] != 0; i++) {
- if (pitches[i] >= v.xres_virtual) {
- v.xres_virtual = pitches[i];
- break;
- }
- }
-
- /* Check for a supported bpp. */
- if (v.bits_per_pixel <= 8)
- v.bits_per_pixel = 8;
- else if (v.bits_per_pixel <= 16) {
- if (v.bits_per_pixel == 16)
- v.green.length = 6;
- v.bits_per_pixel = 16;
- } else if (v.bits_per_pixel <= 32)
- v.bits_per_pixel = 32;
- else
- return -EINVAL;
-
- change_var = ((info->var.xres != var->xres) ||
- (info->var.yres != var->yres) ||
- (info->var.xres_virtual != var->xres_virtual) ||
- (info->var.yres_virtual != var->yres_virtual) ||
- (info->var.bits_per_pixel != var->bits_per_pixel) ||
- memcmp(&info->var.red, &var->red, sizeof(var->red)) ||
- memcmp(&info->var.green, &var->green,
- sizeof(var->green)) ||
- memcmp(&info->var.blue, &var->blue, sizeof(var->blue)));
-
- if (FIXED_MODE(dinfo) &&
- (change_var ||
- var->yres_virtual > dinfo->initial_var.yres_virtual ||
- var->yres_virtual < dinfo->initial_var.yres ||
- var->xoffset || var->nonstd)) {
- if (first) {
- ERR_MSG("Changing the video mode is not supported.\n");
- first = 0;
- }
- return -EINVAL;
- }
-
- switch (intelfb_var_to_depth(&v)) {
- case 8:
- v.red.offset = v.green.offset = v.blue.offset = 0;
- v.red.length = v.green.length = v.blue.length = 8;
- v.transp.offset = v.transp.length = 0;
- break;
- case 15:
- v.red.offset = 10;
- v.green.offset = 5;
- v.blue.offset = 0;
- v.red.length = v.green.length = v.blue.length = 5;
- v.transp.offset = v.transp.length = 0;
- break;
- case 16:
- v.red.offset = 11;
- v.green.offset = 5;
- v.blue.offset = 0;
- v.red.length = 5;
- v.green.length = 6;
- v.blue.length = 5;
- v.transp.offset = v.transp.length = 0;
- break;
- case 24:
- v.red.offset = 16;
- v.green.offset = 8;
- v.blue.offset = 0;
- v.red.length = v.green.length = v.blue.length = 8;
- v.transp.offset = v.transp.length = 0;
- break;
- case 32:
- v.red.offset = 16;
- v.green.offset = 8;
- v.blue.offset = 0;
- v.red.length = v.green.length = v.blue.length = 8;
- v.transp.offset = 24;
- v.transp.length = 8;
- break;
- }
-
- if (v.xoffset > v.xres_virtual - v.xres)
- v.xoffset = v.xres_virtual - v.xres;
- if (v.yoffset > v.yres_virtual - v.yres)
- v.yoffset = v.yres_virtual - v.yres;
-
- v.red.msb_right = v.green.msb_right = v.blue.msb_right =
- v.transp.msb_right = 0;
-
- *var = v;
-
- return 0;
-}
-
-static int intelfb_set_par(struct fb_info *info)
-{
- struct intelfb_hwstate *hw;
- struct intelfb_info *dinfo = GET_DINFO(info);
-
- if (FIXED_MODE(dinfo)) {
- ERR_MSG("Changing the video mode is not supported.\n");
- return -EINVAL;
- }
-
- hw = kmalloc(sizeof(*hw), GFP_ATOMIC);
- if (!hw)
- return -ENOMEM;
-
- DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres,
- info->var.yres, info->var.bits_per_pixel);
-
- /*
- * Disable VCO prior to timing register change.
- */
- OUTREG(DPLL_A, INREG(DPLL_A) & ~DPLL_VCO_ENABLE);
-
- intelfb_blank(FB_BLANK_POWERDOWN, info);
-
- if (ACCEL(dinfo, info))
- intelfbhw_2d_stop(dinfo);
-
- memcpy(hw, &dinfo->save_state, sizeof(*hw));
- if (intelfbhw_mode_to_hw(dinfo, hw, &info->var))
- goto invalid_mode;
- if (intelfbhw_program_mode(dinfo, hw, 0))
- goto invalid_mode;
-
-#if REGDUMP > 0
- intelfbhw_read_hw_state(dinfo, hw, 0);
- intelfbhw_print_hw_state(dinfo, hw);
-#endif
-
- update_dinfo(dinfo, &info->var);
-
- if (ACCEL(dinfo, info))
- intelfbhw_2d_start(dinfo);
-
- intelfb_pan_display(&info->var, info);
-
- intelfb_blank(FB_BLANK_UNBLANK, info);
-
- if (ACCEL(dinfo, info)) {
- info->flags = FBINFO_HWACCEL_YPAN |
- FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
- FBINFO_HWACCEL_IMAGEBLIT;
- } else
- info->flags = FBINFO_HWACCEL_YPAN;
-
- kfree(hw);
- return 0;
-invalid_mode:
- kfree(hw);
- return -EINVAL;
-}
-
-static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info)
-{
- struct intelfb_info *dinfo = GET_DINFO(info);
-
-#if VERBOSE > 0
- DBG_MSG("intelfb_setcolreg: regno %d, depth %d\n", regno, dinfo->depth);
-#endif
-
- if (regno > 255)
- return 1;
-
- if (dinfo->depth == 8) {
- red >>= 8;
- green >>= 8;
- blue >>= 8;
-
- intelfbhw_setcolreg(dinfo, regno, red, green, blue,
- transp);
- }
-
- if (regno < 16) {
- switch (dinfo->depth) {
- case 15:
- dinfo->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
- ((green & 0xf800) >> 6) |
- ((blue & 0xf800) >> 11);
- break;
- case 16:
- dinfo->pseudo_palette[regno] = (red & 0xf800) |
- ((green & 0xfc00) >> 5) |
- ((blue & 0xf800) >> 11);
- break;
- case 24:
- dinfo->pseudo_palette[regno] = ((red & 0xff00) << 8) |
- (green & 0xff00) |
- ((blue & 0xff00) >> 8);
- break;
- }
- }
-
- return 0;
-}
-
-static int intelfb_blank(int blank, struct fb_info *info)
-{
- intelfbhw_do_blank(blank, info);
- return 0;
-}
-
-static int intelfb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info)
-{
- intelfbhw_pan_display(var, info);
- return 0;
-}
-
-/* When/if we have our own ioctls. */
-static int intelfb_ioctl(struct fb_info *info, unsigned int cmd,
- unsigned long arg)
-{
- int retval = 0;
- struct intelfb_info *dinfo = GET_DINFO(info);
- u32 pipe = 0;
-
- switch (cmd) {
- case FBIO_WAITFORVSYNC:
- if (get_user(pipe, (__u32 __user *)arg))
- return -EFAULT;
-
- retval = intelfbhw_wait_for_vsync(dinfo, pipe);
- break;
- default:
- break;
- }
-
- return retval;
-}
-
-static void intelfb_fillrect (struct fb_info *info,
- const struct fb_fillrect *rect)
-{
- struct intelfb_info *dinfo = GET_DINFO(info);
- u32 rop, color;
-
-#if VERBOSE > 0
- DBG_MSG("intelfb_fillrect\n");
-#endif
-
- if (!ACCEL(dinfo, info) || dinfo->depth == 4) {
- cfb_fillrect(info, rect);
- return;
- }
-
- if (rect->rop == ROP_COPY)
- rop = PAT_ROP_GXCOPY;
- else /* ROP_XOR */
- rop = PAT_ROP_GXXOR;
-
- if (dinfo->depth != 8)
- color = dinfo->pseudo_palette[rect->color];
- else
- color = rect->color;
-
- intelfbhw_do_fillrect(dinfo, rect->dx, rect->dy,
- rect->width, rect->height, color,
- dinfo->pitch, info->var.bits_per_pixel,
- rop);
-}
-
-static void intelfb_copyarea(struct fb_info *info,
- const struct fb_copyarea *region)
-{
- struct intelfb_info *dinfo = GET_DINFO(info);
-
-#if VERBOSE > 0
- DBG_MSG("intelfb_copyarea\n");
-#endif
-
- if (!ACCEL(dinfo, info) || dinfo->depth == 4) {
- cfb_copyarea(info, region);
- return;
- }
-
- intelfbhw_do_bitblt(dinfo, region->sx, region->sy, region->dx,
- region->dy, region->width, region->height,
- dinfo->pitch, info->var.bits_per_pixel);
-}
-
-static void intelfb_imageblit(struct fb_info *info,
- const struct fb_image *image)
-{
- struct intelfb_info *dinfo = GET_DINFO(info);
- u32 fgcolor, bgcolor;
-
-#if VERBOSE > 0
- DBG_MSG("intelfb_imageblit\n");
-#endif
-
- if (!ACCEL(dinfo, info) || dinfo->depth == 4
- || image->depth != 1) {
- cfb_imageblit(info, image);
- return;
- }
-
- if (dinfo->depth != 8) {
- fgcolor = dinfo->pseudo_palette[image->fg_color];
- bgcolor = dinfo->pseudo_palette[image->bg_color];
- } else {
- fgcolor = image->fg_color;
- bgcolor = image->bg_color;
- }
-
- if (!intelfbhw_do_drawglyph(dinfo, fgcolor, bgcolor, image->width,
- image->height, image->data,
- image->dx, image->dy,
- dinfo->pitch, info->var.bits_per_pixel)) {
- cfb_imageblit(info, image);
- return;
- }
-}
-
-static int intelfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
-{
- struct intelfb_info *dinfo = GET_DINFO(info);
- u32 physical;
-#if VERBOSE > 0
- DBG_MSG("intelfb_cursor\n");
-#endif
-
- if (!dinfo->hwcursor)
- return -ENODEV;
-
- intelfbhw_cursor_hide(dinfo);
-
- /* If XFree killed the cursor - restore it */
- physical = (dinfo->mobile || IS_I9XX(dinfo)) ? dinfo->cursor.physical :
- (dinfo->cursor.offset << 12);
-
- if (INREG(CURSOR_A_BASEADDR) != physical) {
- u32 fg, bg;
-
- DBG_MSG("the cursor was killed - restore it !!\n");
- DBG_MSG("size %d, %d pos %d, %d\n",
- cursor->image.width, cursor->image.height,
- cursor->image.dx, cursor->image.dy);
-
- intelfbhw_cursor_init(dinfo);
- intelfbhw_cursor_reset(dinfo);
- intelfbhw_cursor_setpos(dinfo, cursor->image.dx,
- cursor->image.dy);
-
- if (dinfo->depth != 8) {
- fg =dinfo->pseudo_palette[cursor->image.fg_color];
- bg =dinfo->pseudo_palette[cursor->image.bg_color];
- } else {
- fg = cursor->image.fg_color;
- bg = cursor->image.bg_color;
- }
- intelfbhw_cursor_setcolor(dinfo, bg, fg);
- intelfbhw_cursor_load(dinfo, cursor->image.width,
- cursor->image.height,
- dinfo->cursor_src);
-
- if (cursor->enable)
- intelfbhw_cursor_show(dinfo);
- return 0;
- }
-
- if (cursor->set & FB_CUR_SETPOS) {
- u32 dx, dy;
-
- dx = cursor->image.dx - info->var.xoffset;
- dy = cursor->image.dy - info->var.yoffset;
-
- intelfbhw_cursor_setpos(dinfo, dx, dy);
- }
-
- if (cursor->set & FB_CUR_SETSIZE) {
- if (cursor->image.width > 64 || cursor->image.height > 64)
- return -ENXIO;
-
- intelfbhw_cursor_reset(dinfo);
- }
-
- if (cursor->set & FB_CUR_SETCMAP) {
- u32 fg, bg;
-
- if (dinfo->depth != 8) {
- fg = dinfo->pseudo_palette[cursor->image.fg_color];
- bg = dinfo->pseudo_palette[cursor->image.bg_color];
- } else {
- fg = cursor->image.fg_color;
- bg = cursor->image.bg_color;
- }
-
- intelfbhw_cursor_setcolor(dinfo, bg, fg);
- }
-
- if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
- u32 s_pitch = (ROUND_UP_TO(cursor->image.width, 8) / 8);
- u32 size = s_pitch * cursor->image.height;
- u8 *dat = (u8 *) cursor->image.data;
- u8 *msk = (u8 *) cursor->mask;
- u8 src[64];
- u32 i;
-
- if (cursor->image.depth != 1)
- return -ENXIO;
-
- switch (cursor->rop) {
- case ROP_XOR:
- for (i = 0; i < size; i++)
- src[i] = dat[i] ^ msk[i];
- break;
- case ROP_COPY:
- default:
- for (i = 0; i < size; i++)
- src[i] = dat[i] & msk[i];
- break;
- }
-
- /* save the bitmap to restore it when XFree will
- make the cursor dirty */
- memcpy(dinfo->cursor_src, src, size);
-
- intelfbhw_cursor_load(dinfo, cursor->image.width,
- cursor->image.height, src);
- }
-
- if (cursor->enable)
- intelfbhw_cursor_show(dinfo);
-
- return 0;
-}
-
-static int intelfb_sync(struct fb_info *info)
-{
- struct intelfb_info *dinfo = GET_DINFO(info);
-
-#if VERBOSE > 0
- DBG_MSG("intelfb_sync\n");
-#endif
-
- if (dinfo->ring_lockup)
- return 0;
-
- intelfbhw_do_sync(dinfo);
- return 0;
-}
-
diff --git a/drivers/video/fbdev/intelfb/intelfbhw.c b/drivers/video/fbdev/intelfb/intelfbhw.c
deleted file mode 100644
index 2086e06532ee..000000000000
--- a/drivers/video/fbdev/intelfb/intelfbhw.c
+++ /dev/null
@@ -1,2115 +0,0 @@
-/*
- * intelfb
- *
- * Linux framebuffer driver for Intel(R) 865G integrated graphics chips.
- *
- * Copyright © 2002, 2003 David Dawes <[email protected]>
- * 2004 Sylvain Meyer
- *
- * This driver consists of two parts. The first part (intelfbdrv.c) provides
- * the basic fbdev interfaces, is derived in part from the radeonfb and
- * vesafb drivers, and is covered by the GPL. The second part (intelfbhw.c)
- * provides the code to program the hardware. Most of it is derived from
- * the i810/i830 XFree86 driver. The HW-specific code is covered here
- * under a dual license (GPL and MIT/XFree86 license).
- *
- * Author: David Dawes
- *
- */
-
-/* $DHD: intelfb/intelfbhw.c,v 1.9 2003/06/27 15:06:25 dawes Exp $ */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/pagemap.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-
-#include "intelfb.h"
-#include "intelfbhw.h"
-
-struct pll_min_max {
- int min_m, max_m, min_m1, max_m1;
- int min_m2, max_m2, min_n, max_n;
- int min_p, max_p, min_p1, max_p1;
- int min_vco, max_vco, p_transition_clk, ref_clk;
- int p_inc_lo, p_inc_hi;
-};
-
-#define PLLS_I8xx 0
-#define PLLS_I9xx 1
-#define PLLS_MAX 2
-
-static struct pll_min_max plls[PLLS_MAX] = {
- { 108, 140, 18, 26,
- 6, 16, 3, 16,
- 4, 128, 0, 31,
- 930000, 1400000, 165000, 48000,
- 4, 2 }, /* I8xx */
-
- { 75, 120, 10, 20,
- 5, 9, 4, 7,
- 5, 80, 1, 8,
- 1400000, 2800000, 200000, 96000,
- 10, 5 } /* I9xx */
-};
-
-int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
-{
- u32 tmp;
- if (!pdev || !dinfo)
- return 1;
-
- switch (pdev->device) {
- case PCI_DEVICE_ID_INTEL_830M:
- dinfo->name = "Intel(R) 830M";
- dinfo->chipset = INTEL_830M;
- dinfo->mobile = 1;
- dinfo->pll_index = PLLS_I8xx;
- return 0;
- case PCI_DEVICE_ID_INTEL_845G:
- dinfo->name = "Intel(R) 845G";
- dinfo->chipset = INTEL_845G;
- dinfo->mobile = 0;
- dinfo->pll_index = PLLS_I8xx;
- return 0;
- case PCI_DEVICE_ID_INTEL_854:
- dinfo->mobile = 1;
- dinfo->name = "Intel(R) 854";
- dinfo->chipset = INTEL_854;
- return 0;
- case PCI_DEVICE_ID_INTEL_85XGM:
- tmp = 0;
- dinfo->mobile = 1;
- dinfo->pll_index = PLLS_I8xx;
- pci_read_config_dword(pdev, INTEL_85X_CAPID, &tmp);
- switch ((tmp >> INTEL_85X_VARIANT_SHIFT) &
- INTEL_85X_VARIANT_MASK) {
- case INTEL_VAR_855GME:
- dinfo->name = "Intel(R) 855GME";
- dinfo->chipset = INTEL_855GME;
- return 0;
- case INTEL_VAR_855GM:
- dinfo->name = "Intel(R) 855GM";
- dinfo->chipset = INTEL_855GM;
- return 0;
- case INTEL_VAR_852GME:
- dinfo->name = "Intel(R) 852GME";
- dinfo->chipset = INTEL_852GME;
- return 0;
- case INTEL_VAR_852GM:
- dinfo->name = "Intel(R) 852GM";
- dinfo->chipset = INTEL_852GM;
- return 0;
- default:
- dinfo->name = "Intel(R) 852GM/855GM";
- dinfo->chipset = INTEL_85XGM;
- return 0;
- }
- break;
- case PCI_DEVICE_ID_INTEL_865G:
- dinfo->name = "Intel(R) 865G";
- dinfo->chipset = INTEL_865G;
- dinfo->mobile = 0;
- dinfo->pll_index = PLLS_I8xx;
- return 0;
- case PCI_DEVICE_ID_INTEL_915G:
- dinfo->name = "Intel(R) 915G";
- dinfo->chipset = INTEL_915G;
- dinfo->mobile = 0;
- dinfo->pll_index = PLLS_I9xx;
- return 0;
- case PCI_DEVICE_ID_INTEL_915GM:
- dinfo->name = "Intel(R) 915GM";
- dinfo->chipset = INTEL_915GM;
- dinfo->mobile = 1;
- dinfo->pll_index = PLLS_I9xx;
- return 0;
- case PCI_DEVICE_ID_INTEL_945G:
- dinfo->name = "Intel(R) 945G";
- dinfo->chipset = INTEL_945G;
- dinfo->mobile = 0;
- dinfo->pll_index = PLLS_I9xx;
- return 0;
- case PCI_DEVICE_ID_INTEL_945GM:
- dinfo->name = "Intel(R) 945GM";
- dinfo->chipset = INTEL_945GM;
- dinfo->mobile = 1;
- dinfo->pll_index = PLLS_I9xx;
- return 0;
- case PCI_DEVICE_ID_INTEL_945GME:
- dinfo->name = "Intel(R) 945GME";
- dinfo->chipset = INTEL_945GME;
- dinfo->mobile = 1;
- dinfo->pll_index = PLLS_I9xx;
- return 0;
- case PCI_DEVICE_ID_INTEL_965G:
- dinfo->name = "Intel(R) 965G";
- dinfo->chipset = INTEL_965G;
- dinfo->mobile = 0;
- dinfo->pll_index = PLLS_I9xx;
- return 0;
- case PCI_DEVICE_ID_INTEL_965GM:
- dinfo->name = "Intel(R) 965GM";
- dinfo->chipset = INTEL_965GM;
- dinfo->mobile = 1;
- dinfo->pll_index = PLLS_I9xx;
- return 0;
- default:
- return 1;
- }
-}
-
-int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
- int *stolen_size)
-{
- struct pci_dev *bridge_dev;
- u16 tmp;
- int stolen_overhead;
-
- if (!pdev || !aperture_size || !stolen_size)
- return 1;
-
- /* Find the bridge device. It is always 0:0.0 */
- bridge_dev = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus), 0,
- PCI_DEVFN(0, 0));
- if (!bridge_dev) {
- ERR_MSG("cannot find bridge device\n");
- return 1;
- }
-
- /* Get the fb aperture size and "stolen" memory amount. */
- tmp = 0;
- pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
- pci_dev_put(bridge_dev);
-
- switch (pdev->device) {
- case PCI_DEVICE_ID_INTEL_915G:
- case PCI_DEVICE_ID_INTEL_915GM:
- case PCI_DEVICE_ID_INTEL_945G:
- case PCI_DEVICE_ID_INTEL_945GM:
- case PCI_DEVICE_ID_INTEL_945GME:
- case PCI_DEVICE_ID_INTEL_965G:
- case PCI_DEVICE_ID_INTEL_965GM:
- /*
- * 915, 945 and 965 chipsets support 64MB, 128MB or 256MB
- * aperture. Determine size from PCI resource length.
- */
- *aperture_size = pci_resource_len(pdev, 2);
- break;
- default:
- if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
- *aperture_size = MB(64);
- else
- *aperture_size = MB(128);
- break;
- }
-
- /* Stolen memory size is reduced by the GTT and the popup.
- GTT is 1K per MB of aperture size, and popup is 4K. */
- stolen_overhead = (*aperture_size / MB(1)) + 4;
- switch(pdev->device) {
- case PCI_DEVICE_ID_INTEL_830M:
- case PCI_DEVICE_ID_INTEL_845G:
- switch (tmp & INTEL_830_GMCH_GMS_MASK) {
- case INTEL_830_GMCH_GMS_STOLEN_512:
- *stolen_size = KB(512) - KB(stolen_overhead);
- return 0;
- case INTEL_830_GMCH_GMS_STOLEN_1024:
- *stolen_size = MB(1) - KB(stolen_overhead);
- return 0;
- case INTEL_830_GMCH_GMS_STOLEN_8192:
- *stolen_size = MB(8) - KB(stolen_overhead);
- return 0;
- case INTEL_830_GMCH_GMS_LOCAL:
- ERR_MSG("only local memory found\n");
- return 1;
- case INTEL_830_GMCH_GMS_DISABLED:
- ERR_MSG("video memory is disabled\n");
- return 1;
- default:
- ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n",
- tmp & INTEL_830_GMCH_GMS_MASK);
- return 1;
- }
- break;
- default:
- switch (tmp & INTEL_855_GMCH_GMS_MASK) {
- case INTEL_855_GMCH_GMS_STOLEN_1M:
- *stolen_size = MB(1) - KB(stolen_overhead);
- return 0;
- case INTEL_855_GMCH_GMS_STOLEN_4M:
- *stolen_size = MB(4) - KB(stolen_overhead);
- return 0;
- case INTEL_855_GMCH_GMS_STOLEN_8M:
- *stolen_size = MB(8) - KB(stolen_overhead);
- return 0;
- case INTEL_855_GMCH_GMS_STOLEN_16M:
- *stolen_size = MB(16) - KB(stolen_overhead);
- return 0;
- case INTEL_855_GMCH_GMS_STOLEN_32M:
- *stolen_size = MB(32) - KB(stolen_overhead);
- return 0;
- case INTEL_915G_GMCH_GMS_STOLEN_48M:
- *stolen_size = MB(48) - KB(stolen_overhead);
- return 0;
- case INTEL_915G_GMCH_GMS_STOLEN_64M:
- *stolen_size = MB(64) - KB(stolen_overhead);
- return 0;
- case INTEL_855_GMCH_GMS_DISABLED:
- ERR_MSG("video memory is disabled\n");
- return 0;
- default:
- ERR_MSG("unexpected GMCH_GMS value: 0x%02x\n",
- tmp & INTEL_855_GMCH_GMS_MASK);
- return 1;
- }
- }
-}
-
-int intelfbhw_check_non_crt(struct intelfb_info *dinfo)
-{
- int dvo = 0;
-
- if (INREG(LVDS) & PORT_ENABLE)
- dvo |= LVDS_PORT;
- if (INREG(DVOA) & PORT_ENABLE)
- dvo |= DVOA_PORT;
- if (INREG(DVOB) & PORT_ENABLE)
- dvo |= DVOB_PORT;
- if (INREG(DVOC) & PORT_ENABLE)
- dvo |= DVOC_PORT;
-
- return dvo;
-}
-
-const char * intelfbhw_dvo_to_string(int dvo)
-{
- if (dvo & DVOA_PORT)
- return "DVO port A";
- else if (dvo & DVOB_PORT)
- return "DVO port B";
- else if (dvo & DVOC_PORT)
- return "DVO port C";
- else if (dvo & LVDS_PORT)
- return "LVDS port";
- else
- return NULL;
-}
-
-
-int intelfbhw_validate_mode(struct intelfb_info *dinfo,
- struct fb_var_screeninfo *var)
-{
- int bytes_per_pixel;
- int tmp;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_validate_mode\n");
-#endif
-
- bytes_per_pixel = var->bits_per_pixel / 8;
- if (bytes_per_pixel == 3)
- bytes_per_pixel = 4;
-
- /* Check if enough video memory. */
- tmp = var->yres_virtual * var->xres_virtual * bytes_per_pixel;
- if (tmp > dinfo->fb.size) {
- WRN_MSG("Not enough video ram for mode "
- "(%d KByte vs %d KByte).\n",
- BtoKB(tmp), BtoKB(dinfo->fb.size));
- return 1;
- }
-
- /* Check if x/y limits are OK. */
- if (var->xres - 1 > HACTIVE_MASK) {
- WRN_MSG("X resolution too large (%d vs %d).\n",
- var->xres, HACTIVE_MASK + 1);
- return 1;
- }
- if (var->yres - 1 > VACTIVE_MASK) {
- WRN_MSG("Y resolution too large (%d vs %d).\n",
- var->yres, VACTIVE_MASK + 1);
- return 1;
- }
- if (var->xres < 4) {
- WRN_MSG("X resolution too small (%d vs 4).\n", var->xres);
- return 1;
- }
- if (var->yres < 4) {
- WRN_MSG("Y resolution too small (%d vs 4).\n", var->yres);
- return 1;
- }
-
- /* Check for doublescan modes. */
- if (var->vmode & FB_VMODE_DOUBLE) {
- WRN_MSG("Mode is double-scan.\n");
- return 1;
- }
-
- if ((var->vmode & FB_VMODE_INTERLACED) && (var->yres & 1)) {
- WRN_MSG("Odd number of lines in interlaced mode\n");
- return 1;
- }
-
- /* Check if clock is OK. */
- tmp = 1000000000 / var->pixclock;
- if (tmp < MIN_CLOCK) {
- WRN_MSG("Pixel clock is too low (%d MHz vs %d MHz).\n",
- (tmp + 500) / 1000, MIN_CLOCK / 1000);
- return 1;
- }
- if (tmp > MAX_CLOCK) {
- WRN_MSG("Pixel clock is too high (%d MHz vs %d MHz).\n",
- (tmp + 500) / 1000, MAX_CLOCK / 1000);
- return 1;
- }
-
- return 0;
-}
-
-int intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
-{
- struct intelfb_info *dinfo = GET_DINFO(info);
- u32 offset, xoffset, yoffset;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_pan_display\n");
-#endif
-
- xoffset = ROUND_DOWN_TO(var->xoffset, 8);
- yoffset = var->yoffset;
-
- if ((xoffset + info->var.xres > info->var.xres_virtual) ||
- (yoffset + info->var.yres > info->var.yres_virtual))
- return -EINVAL;
-
- offset = (yoffset * dinfo->pitch) +
- (xoffset * info->var.bits_per_pixel) / 8;
-
- offset += dinfo->fb.offset << 12;
-
- dinfo->vsync.pan_offset = offset;
- if ((var->activate & FB_ACTIVATE_VBL) &&
- !intelfbhw_enable_irq(dinfo))
- dinfo->vsync.pan_display = 1;
- else {
- dinfo->vsync.pan_display = 0;
- OUTREG(DSPABASE, offset);
- }
-
- return 0;
-}
-
-/* Blank the screen. */
-void intelfbhw_do_blank(int blank, struct fb_info *info)
-{
- struct intelfb_info *dinfo = GET_DINFO(info);
- u32 tmp;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_do_blank: blank is %d\n", blank);
-#endif
-
- /* Turn plane A on or off */
- tmp = INREG(DSPACNTR);
- if (blank)
- tmp &= ~DISPPLANE_PLANE_ENABLE;
- else
- tmp |= DISPPLANE_PLANE_ENABLE;
- OUTREG(DSPACNTR, tmp);
- /* Flush */
- tmp = INREG(DSPABASE);
- OUTREG(DSPABASE, tmp);
-
- /* Turn off/on the HW cursor */
-#if VERBOSE > 0
- DBG_MSG("cursor_on is %d\n", dinfo->cursor_on);
-#endif
- if (dinfo->cursor_on) {
- if (blank)
- intelfbhw_cursor_hide(dinfo);
- else
- intelfbhw_cursor_show(dinfo);
- dinfo->cursor_on = 1;
- }
- dinfo->cursor_blanked = blank;
-
- /* Set DPMS level */
- tmp = INREG(ADPA) & ~ADPA_DPMS_CONTROL_MASK;
- switch (blank) {
- case FB_BLANK_UNBLANK:
- case FB_BLANK_NORMAL:
- tmp |= ADPA_DPMS_D0;
- break;
- case FB_BLANK_VSYNC_SUSPEND:
- tmp |= ADPA_DPMS_D1;
- break;
- case FB_BLANK_HSYNC_SUSPEND:
- tmp |= ADPA_DPMS_D2;
- break;
- case FB_BLANK_POWERDOWN:
- tmp |= ADPA_DPMS_D3;
- break;
- }
- OUTREG(ADPA, tmp);
-
- return;
-}
-
-
-/* Check which pipe is connected to an active display plane. */
-int intelfbhw_active_pipe(const struct intelfb_hwstate *hw)
-{
- int pipe = -1;
-
- /* keep old default behaviour - prefer PIPE_A */
- if (hw->disp_b_ctrl & DISPPLANE_PLANE_ENABLE) {
- pipe = (hw->disp_b_ctrl >> DISPPLANE_SEL_PIPE_SHIFT);
- pipe &= PIPE_MASK;
- if (unlikely(pipe == PIPE_A))
- return PIPE_A;
- }
- if (hw->disp_a_ctrl & DISPPLANE_PLANE_ENABLE) {
- pipe = (hw->disp_a_ctrl >> DISPPLANE_SEL_PIPE_SHIFT);
- pipe &= PIPE_MASK;
- if (likely(pipe == PIPE_A))
- return PIPE_A;
- }
- /* Impossible that no pipe is selected - return PIPE_A */
- WARN_ON(pipe == -1);
- if (unlikely(pipe == -1))
- pipe = PIPE_A;
-
- return pipe;
-}
-
-void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
- unsigned red, unsigned green, unsigned blue,
- unsigned transp)
-{
- u32 palette_reg = (dinfo->pipe == PIPE_A) ?
- PALETTE_A : PALETTE_B;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_setcolreg: %d: (%d, %d, %d)\n",
- regno, red, green, blue);
-#endif
-
- OUTREG(palette_reg + (regno << 2),
- (red << PALETTE_8_RED_SHIFT) |
- (green << PALETTE_8_GREEN_SHIFT) |
- (blue << PALETTE_8_BLUE_SHIFT));
-}
-
-
-int intelfbhw_read_hw_state(struct intelfb_info *dinfo,
- struct intelfb_hwstate *hw, int flag)
-{
- int i;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_read_hw_state\n");
-#endif
-
- if (!hw || !dinfo)
- return -1;
-
- /* Read in as much of the HW state as possible. */
- hw->vga0_divisor = INREG(VGA0_DIVISOR);
- hw->vga1_divisor = INREG(VGA1_DIVISOR);
- hw->vga_pd = INREG(VGAPD);
- hw->dpll_a = INREG(DPLL_A);
- hw->dpll_b = INREG(DPLL_B);
- hw->fpa0 = INREG(FPA0);
- hw->fpa1 = INREG(FPA1);
- hw->fpb0 = INREG(FPB0);
- hw->fpb1 = INREG(FPB1);
-
- if (flag == 1)
- return flag;
-
-#if 0
- /* This seems to be a problem with the 852GM/855GM */
- for (i = 0; i < PALETTE_8_ENTRIES; i++) {
- hw->palette_a[i] = INREG(PALETTE_A + (i << 2));
- hw->palette_b[i] = INREG(PALETTE_B + (i << 2));
- }
-#endif
-
- if (flag == 2)
- return flag;
-
- hw->htotal_a = INREG(HTOTAL_A);
- hw->hblank_a = INREG(HBLANK_A);
- hw->hsync_a = INREG(HSYNC_A);
- hw->vtotal_a = INREG(VTOTAL_A);
- hw->vblank_a = INREG(VBLANK_A);
- hw->vsync_a = INREG(VSYNC_A);
- hw->src_size_a = INREG(SRC_SIZE_A);
- hw->bclrpat_a = INREG(BCLRPAT_A);
- hw->htotal_b = INREG(HTOTAL_B);
- hw->hblank_b = INREG(HBLANK_B);
- hw->hsync_b = INREG(HSYNC_B);
- hw->vtotal_b = INREG(VTOTAL_B);
- hw->vblank_b = INREG(VBLANK_B);
- hw->vsync_b = INREG(VSYNC_B);
- hw->src_size_b = INREG(SRC_SIZE_B);
- hw->bclrpat_b = INREG(BCLRPAT_B);
-
- if (flag == 3)
- return flag;
-
- hw->adpa = INREG(ADPA);
- hw->dvoa = INREG(DVOA);
- hw->dvob = INREG(DVOB);
- hw->dvoc = INREG(DVOC);
- hw->dvoa_srcdim = INREG(DVOA_SRCDIM);
- hw->dvob_srcdim = INREG(DVOB_SRCDIM);
- hw->dvoc_srcdim = INREG(DVOC_SRCDIM);
- hw->lvds = INREG(LVDS);
-
- if (flag == 4)
- return flag;
-
- hw->pipe_a_conf = INREG(PIPEACONF);
- hw->pipe_b_conf = INREG(PIPEBCONF);
- hw->disp_arb = INREG(DISPARB);
-
- if (flag == 5)
- return flag;
-
- hw->cursor_a_control = INREG(CURSOR_A_CONTROL);
- hw->cursor_b_control = INREG(CURSOR_B_CONTROL);
- hw->cursor_a_base = INREG(CURSOR_A_BASEADDR);
- hw->cursor_b_base = INREG(CURSOR_B_BASEADDR);
-
- if (flag == 6)
- return flag;
-
- for (i = 0; i < 4; i++) {
- hw->cursor_a_palette[i] = INREG(CURSOR_A_PALETTE0 + (i << 2));
- hw->cursor_b_palette[i] = INREG(CURSOR_B_PALETTE0 + (i << 2));
- }
-
- if (flag == 7)
- return flag;
-
- hw->cursor_size = INREG(CURSOR_SIZE);
-
- if (flag == 8)
- return flag;
-
- hw->disp_a_ctrl = INREG(DSPACNTR);
- hw->disp_b_ctrl = INREG(DSPBCNTR);
- hw->disp_a_base = INREG(DSPABASE);
- hw->disp_b_base = INREG(DSPBBASE);
- hw->disp_a_stride = INREG(DSPASTRIDE);
- hw->disp_b_stride = INREG(DSPBSTRIDE);
-
- if (flag == 9)
- return flag;
-
- hw->vgacntrl = INREG(VGACNTRL);
-
- if (flag == 10)
- return flag;
-
- hw->add_id = INREG(ADD_ID);
-
- if (flag == 11)
- return flag;
-
- for (i = 0; i < 7; i++) {
- hw->swf0x[i] = INREG(SWF00 + (i << 2));
- hw->swf1x[i] = INREG(SWF10 + (i << 2));
- if (i < 3)
- hw->swf3x[i] = INREG(SWF30 + (i << 2));
- }
-
- for (i = 0; i < 8; i++)
- hw->fence[i] = INREG(FENCE + (i << 2));
-
- hw->instpm = INREG(INSTPM);
- hw->mem_mode = INREG(MEM_MODE);
- hw->fw_blc_0 = INREG(FW_BLC_0);
- hw->fw_blc_1 = INREG(FW_BLC_1);
-
- hw->hwstam = INREG16(HWSTAM);
- hw->ier = INREG16(IER);
- hw->iir = INREG16(IIR);
- hw->imr = INREG16(IMR);
-
- return 0;
-}
-
-
-static int calc_vclock3(int index, int m, int n, int p)
-{
- if (p == 0 || n == 0)
- return 0;
- return plls[index].ref_clk * m / n / p;
-}
-
-static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2,
- int lvds)
-{
- struct pll_min_max *pll = &plls[index];
- u32 m, vco, p;
-
- m = (5 * (m1 + 2)) + (m2 + 2);
- n += 2;
- vco = pll->ref_clk * m / n;
-
- if (index == PLLS_I8xx)
- p = ((p1 + 2) * (1 << (p2 + 1)));
- else
- p = ((p1) * (p2 ? 5 : 10));
- return vco / p;
-}
-
-#if REGDUMP
-static void intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll,
- int *o_p1, int *o_p2)
-{
- int p1, p2;
-
- if (IS_I9XX(dinfo)) {
- if (dpll & DPLL_P1_FORCE_DIV2)
- p1 = 1;
- else
- p1 = (dpll >> DPLL_P1_SHIFT) & 0xff;
-
- p1 = ffs(p1);
-
- p2 = (dpll >> DPLL_I9XX_P2_SHIFT) & DPLL_P2_MASK;
- } else {
- if (dpll & DPLL_P1_FORCE_DIV2)
- p1 = 0;
- else
- p1 = (dpll >> DPLL_P1_SHIFT) & DPLL_P1_MASK;
- p2 = (dpll >> DPLL_P2_SHIFT) & DPLL_P2_MASK;
- }
-
- *o_p1 = p1;
- *o_p2 = p2;
-}
-#endif
-
-
-void intelfbhw_print_hw_state(struct intelfb_info *dinfo,
- struct intelfb_hwstate *hw)
-{
-#if REGDUMP
- int i, m1, m2, n, p1, p2;
- int index = dinfo->pll_index;
- DBG_MSG("intelfbhw_print_hw_state\n");
-
- if (!hw)
- return;
- /* Read in as much of the HW state as possible. */
- printk("hw state dump start\n");
- printk(" VGA0_DIVISOR: 0x%08x\n", hw->vga0_divisor);
- printk(" VGA1_DIVISOR: 0x%08x\n", hw->vga1_divisor);
- printk(" VGAPD: 0x%08x\n", hw->vga_pd);
- n = (hw->vga0_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
- m1 = (hw->vga0_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
- m2 = (hw->vga0_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
-
- intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2);
-
- printk(" VGA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
- m1, m2, n, p1, p2);
- printk(" VGA0: clock is %d\n",
- calc_vclock(index, m1, m2, n, p1, p2, 0));
-
- n = (hw->vga1_divisor >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
- m1 = (hw->vga1_divisor >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
- m2 = (hw->vga1_divisor >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
-
- intelfbhw_get_p1p2(dinfo, hw->vga_pd, &p1, &p2);
- printk(" VGA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
- m1, m2, n, p1, p2);
- printk(" VGA1: clock is %d\n",
- calc_vclock(index, m1, m2, n, p1, p2, 0));
-
- printk(" DPLL_A: 0x%08x\n", hw->dpll_a);
- printk(" DPLL_B: 0x%08x\n", hw->dpll_b);
- printk(" FPA0: 0x%08x\n", hw->fpa0);
- printk(" FPA1: 0x%08x\n", hw->fpa1);
- printk(" FPB0: 0x%08x\n", hw->fpb0);
- printk(" FPB1: 0x%08x\n", hw->fpb1);
-
- n = (hw->fpa0 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
- m1 = (hw->fpa0 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
- m2 = (hw->fpa0 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
-
- intelfbhw_get_p1p2(dinfo, hw->dpll_a, &p1, &p2);
-
- printk(" PLLA0: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
- m1, m2, n, p1, p2);
- printk(" PLLA0: clock is %d\n",
- calc_vclock(index, m1, m2, n, p1, p2, 0));
-
- n = (hw->fpa1 >> FP_N_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
- m1 = (hw->fpa1 >> FP_M1_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
- m2 = (hw->fpa1 >> FP_M2_DIVISOR_SHIFT) & FP_DIVISOR_MASK;
-
- intelfbhw_get_p1p2(dinfo, hw->dpll_a, &p1, &p2);
-
- printk(" PLLA1: (m1, m2, n, p1, p2) = (%d, %d, %d, %d, %d)\n",
- m1, m2, n, p1, p2);
- printk(" PLLA1: clock is %d\n",
- calc_vclock(index, m1, m2, n, p1, p2, 0));
-
-#if 0
- printk(" PALETTE_A:\n");
- for (i = 0; i < PALETTE_8_ENTRIES)
- printk(" %3d: 0x%08x\n", i, hw->palette_a[i]);
- printk(" PALETTE_B:\n");
- for (i = 0; i < PALETTE_8_ENTRIES)
- printk(" %3d: 0x%08x\n", i, hw->palette_b[i]);
-#endif
-
- printk(" HTOTAL_A: 0x%08x\n", hw->htotal_a);
- printk(" HBLANK_A: 0x%08x\n", hw->hblank_a);
- printk(" HSYNC_A: 0x%08x\n", hw->hsync_a);
- printk(" VTOTAL_A: 0x%08x\n", hw->vtotal_a);
- printk(" VBLANK_A: 0x%08x\n", hw->vblank_a);
- printk(" VSYNC_A: 0x%08x\n", hw->vsync_a);
- printk(" SRC_SIZE_A: 0x%08x\n", hw->src_size_a);
- printk(" BCLRPAT_A: 0x%08x\n", hw->bclrpat_a);
- printk(" HTOTAL_B: 0x%08x\n", hw->htotal_b);
- printk(" HBLANK_B: 0x%08x\n", hw->hblank_b);
- printk(" HSYNC_B: 0x%08x\n", hw->hsync_b);
- printk(" VTOTAL_B: 0x%08x\n", hw->vtotal_b);
- printk(" VBLANK_B: 0x%08x\n", hw->vblank_b);
- printk(" VSYNC_B: 0x%08x\n", hw->vsync_b);
- printk(" SRC_SIZE_B: 0x%08x\n", hw->src_size_b);
- printk(" BCLRPAT_B: 0x%08x\n", hw->bclrpat_b);
-
- printk(" ADPA: 0x%08x\n", hw->adpa);
- printk(" DVOA: 0x%08x\n", hw->dvoa);
- printk(" DVOB: 0x%08x\n", hw->dvob);
- printk(" DVOC: 0x%08x\n", hw->dvoc);
- printk(" DVOA_SRCDIM: 0x%08x\n", hw->dvoa_srcdim);
- printk(" DVOB_SRCDIM: 0x%08x\n", hw->dvob_srcdim);
- printk(" DVOC_SRCDIM: 0x%08x\n", hw->dvoc_srcdim);
- printk(" LVDS: 0x%08x\n", hw->lvds);
-
- printk(" PIPEACONF: 0x%08x\n", hw->pipe_a_conf);
- printk(" PIPEBCONF: 0x%08x\n", hw->pipe_b_conf);
- printk(" DISPARB: 0x%08x\n", hw->disp_arb);
-
- printk(" CURSOR_A_CONTROL: 0x%08x\n", hw->cursor_a_control);
- printk(" CURSOR_B_CONTROL: 0x%08x\n", hw->cursor_b_control);
- printk(" CURSOR_A_BASEADDR: 0x%08x\n", hw->cursor_a_base);
- printk(" CURSOR_B_BASEADDR: 0x%08x\n", hw->cursor_b_base);
-
- printk(" CURSOR_A_PALETTE: ");
- for (i = 0; i < 4; i++) {
- printk("0x%08x", hw->cursor_a_palette[i]);
- if (i < 3)
- printk(", ");
- }
- printk("\n");
- printk(" CURSOR_B_PALETTE: ");
- for (i = 0; i < 4; i++) {
- printk("0x%08x", hw->cursor_b_palette[i]);
- if (i < 3)
- printk(", ");
- }
- printk("\n");
-
- printk(" CURSOR_SIZE: 0x%08x\n", hw->cursor_size);
-
- printk(" DSPACNTR: 0x%08x\n", hw->disp_a_ctrl);
- printk(" DSPBCNTR: 0x%08x\n", hw->disp_b_ctrl);
- printk(" DSPABASE: 0x%08x\n", hw->disp_a_base);
- printk(" DSPBBASE: 0x%08x\n", hw->disp_b_base);
- printk(" DSPASTRIDE: 0x%08x\n", hw->disp_a_stride);
- printk(" DSPBSTRIDE: 0x%08x\n", hw->disp_b_stride);
-
- printk(" VGACNTRL: 0x%08x\n", hw->vgacntrl);
- printk(" ADD_ID: 0x%08x\n", hw->add_id);
-
- for (i = 0; i < 7; i++) {
- printk(" SWF0%d 0x%08x\n", i,
- hw->swf0x[i]);
- }
- for (i = 0; i < 7; i++) {
- printk(" SWF1%d 0x%08x\n", i,
- hw->swf1x[i]);
- }
- for (i = 0; i < 3; i++) {
- printk(" SWF3%d 0x%08x\n", i,
- hw->swf3x[i]);
- }
- for (i = 0; i < 8; i++)
- printk(" FENCE%d 0x%08x\n", i,
- hw->fence[i]);
-
- printk(" INSTPM 0x%08x\n", hw->instpm);
- printk(" MEM_MODE 0x%08x\n", hw->mem_mode);
- printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0);
- printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1);
-
- printk(" HWSTAM 0x%04x\n", hw->hwstam);
- printk(" IER 0x%04x\n", hw->ier);
- printk(" IIR 0x%04x\n", hw->iir);
- printk(" IMR 0x%04x\n", hw->imr);
- printk("hw state dump end\n");
-#endif
-}
-
-
-
-/* Split the M parameter into M1 and M2. */
-static int splitm(int index, unsigned int m, unsigned int *retm1,
- unsigned int *retm2)
-{
- int m1, m2;
- int testm;
- struct pll_min_max *pll = &plls[index];
-
- /* no point optimising too much - brute force m */
- for (m1 = pll->min_m1; m1 < pll->max_m1 + 1; m1++) {
- for (m2 = pll->min_m2; m2 < pll->max_m2 + 1; m2++) {
- testm = (5 * (m1 + 2)) + (m2 + 2);
- if (testm == m) {
- *retm1 = (unsigned int)m1;
- *retm2 = (unsigned int)m2;
- return 0;
- }
- }
- }
- return 1;
-}
-
-/* Split the P parameter into P1 and P2. */
-static int splitp(int index, unsigned int p, unsigned int *retp1,
- unsigned int *retp2)
-{
- int p1, p2;
- struct pll_min_max *pll = &plls[index];
-
- if (index == PLLS_I9xx) {
- p2 = (p % 10) ? 1 : 0;
-
- p1 = p / (p2 ? 5 : 10);
-
- *retp1 = (unsigned int)p1;
- *retp2 = (unsigned int)p2;
- return 0;
- }
-
- if (p % 4 == 0)
- p2 = 1;
- else
- p2 = 0;
- p1 = (p / (1 << (p2 + 1))) - 2;
- if (p % 4 == 0 && p1 < pll->min_p1) {
- p2 = 0;
- p1 = (p / (1 << (p2 + 1))) - 2;
- }
- if (p1 < pll->min_p1 || p1 > pll->max_p1 ||
- (p1 + 2) * (1 << (p2 + 1)) != p) {
- return 1;
- } else {
- *retp1 = (unsigned int)p1;
- *retp2 = (unsigned int)p2;
- return 0;
- }
-}
-
-static int calc_pll_params(int index, int clock, u32 *retm1, u32 *retm2,
- u32 *retn, u32 *retp1, u32 *retp2, u32 *retclock)
-{
- u32 m1, m2, n, p1, p2, n1, testm;
- u32 f_vco, p, p_best = 0, m, f_out = 0;
- u32 err_best = 10000000;
- u32 n_best = 0, m_best = 0, f_err;
- u32 p_min, p_max, p_inc, div_max;
- struct pll_min_max *pll = &plls[index];
-
- DBG_MSG("Clock is %d\n", clock);
-
- div_max = pll->max_vco / clock;
-
- p_inc = (clock <= pll->p_transition_clk) ? pll->p_inc_lo : pll->p_inc_hi;
- p_min = p_inc;
- p_max = ROUND_DOWN_TO(div_max, p_inc);
- if (p_min < pll->min_p)
- p_min = pll->min_p;
- if (p_max > pll->max_p)
- p_max = pll->max_p;
-
- DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc);
-
- p = p_min;
- do {
- if (splitp(index, p, &p1, &p2)) {
- WRN_MSG("cannot split p = %d\n", p);
- p += p_inc;
- continue;
- }
- n = pll->min_n;
- f_vco = clock * p;
-
- do {
- m = ROUND_UP_TO(f_vco * n, pll->ref_clk) / pll->ref_clk;
- if (m < pll->min_m)
- m = pll->min_m + 1;
- if (m > pll->max_m)
- m = pll->max_m - 1;
- for (testm = m - 1; testm <= m; testm++) {
- f_out = calc_vclock3(index, testm, n, p);
- if (splitm(index, testm, &m1, &m2)) {
- WRN_MSG("cannot split m = %d\n",
- testm);
- continue;
- }
- if (clock > f_out)
- f_err = clock - f_out;
- else/* slightly bias the error for bigger clocks */
- f_err = f_out - clock + 1;
-
- if (f_err < err_best) {
- m_best = testm;
- n_best = n;
- p_best = p;
- err_best = f_err;
- }
- }
- n++;
- } while ((n <= pll->max_n) && (f_out >= clock));
- p += p_inc;
- } while ((p <= p_max));
-
- if (!m_best) {
- WRN_MSG("cannot find parameters for clock %d\n", clock);
- return 1;
- }
- m = m_best;
- n = n_best;
- p = p_best;
- splitm(index, m, &m1, &m2);
- splitp(index, p, &p1, &p2);
- n1 = n - 2;
-
- DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), "
- "f: %d (%d), VCO: %d\n",
- m, m1, m2, n, n1, p, p1, p2,
- calc_vclock3(index, m, n, p),
- calc_vclock(index, m1, m2, n1, p1, p2, 0),
- calc_vclock3(index, m, n, p) * p);
- *retm1 = m1;
- *retm2 = m2;
- *retn = n1;
- *retp1 = p1;
- *retp2 = p2;
- *retclock = calc_vclock(index, m1, m2, n1, p1, p2, 0);
-
- return 0;
-}
-
-static __inline__ int check_overflow(u32 value, u32 limit,
- const char *description)
-{
- if (value > limit) {
- WRN_MSG("%s value %d exceeds limit %d\n",
- description, value, limit);
- return 1;
- }
- return 0;
-}
-
-/* It is assumed that hw is filled in with the initial state information. */
-int intelfbhw_mode_to_hw(struct intelfb_info *dinfo,
- struct intelfb_hwstate *hw,
- struct fb_var_screeninfo *var)
-{
- int pipe = intelfbhw_active_pipe(hw);
- u32 *dpll, *fp0, *fp1;
- u32 m1, m2, n, p1, p2, clock_target, clock;
- u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive;
- u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive;
- u32 vsync_pol, hsync_pol;
- u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf;
- u32 stride_alignment;
-
- DBG_MSG("intelfbhw_mode_to_hw\n");
-
- /* Disable VGA */
- hw->vgacntrl |= VGA_DISABLE;
-
- /* Set which pipe's registers will be set. */
- if (pipe == PIPE_B) {
- dpll = &hw->dpll_b;
- fp0 = &hw->fpb0;
- fp1 = &hw->fpb1;
- hs = &hw->hsync_b;
- hb = &hw->hblank_b;
- ht = &hw->htotal_b;
- vs = &hw->vsync_b;
- vb = &hw->vblank_b;
- vt = &hw->vtotal_b;
- ss = &hw->src_size_b;
- pipe_conf = &hw->pipe_b_conf;
- } else {
- dpll = &hw->dpll_a;
- fp0 = &hw->fpa0;
- fp1 = &hw->fpa1;
- hs = &hw->hsync_a;
- hb = &hw->hblank_a;
- ht = &hw->htotal_a;
- vs = &hw->vsync_a;
- vb = &hw->vblank_a;
- vt = &hw->vtotal_a;
- ss = &hw->src_size_a;
- pipe_conf = &hw->pipe_a_conf;
- }
-
- /* Use ADPA register for sync control. */
- hw->adpa &= ~ADPA_USE_VGA_HVPOLARITY;
-
- /* sync polarity */
- hsync_pol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ?
- ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW;
- vsync_pol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ?
- ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW;
- hw->adpa &= ~((ADPA_SYNC_ACTIVE_MASK << ADPA_VSYNC_ACTIVE_SHIFT) |
- (ADPA_SYNC_ACTIVE_MASK << ADPA_HSYNC_ACTIVE_SHIFT));
- hw->adpa |= (hsync_pol << ADPA_HSYNC_ACTIVE_SHIFT) |
- (vsync_pol << ADPA_VSYNC_ACTIVE_SHIFT);
-
- /* Connect correct pipe to the analog port DAC */
- hw->adpa &= ~(PIPE_MASK << ADPA_PIPE_SELECT_SHIFT);
- hw->adpa |= (pipe << ADPA_PIPE_SELECT_SHIFT);
-
- /* Set DPMS state to D0 (on) */
- hw->adpa &= ~ADPA_DPMS_CONTROL_MASK;
- hw->adpa |= ADPA_DPMS_D0;
-
- hw->adpa |= ADPA_DAC_ENABLE;
-
- *dpll |= (DPLL_VCO_ENABLE | DPLL_VGA_MODE_DISABLE);
- *dpll &= ~(DPLL_RATE_SELECT_MASK | DPLL_REFERENCE_SELECT_MASK);
- *dpll |= (DPLL_REFERENCE_DEFAULT | DPLL_RATE_SELECT_FP0);
-
- /* Desired clock in kHz */
- clock_target = 1000000000 / var->pixclock;
-
- if (calc_pll_params(dinfo->pll_index, clock_target, &m1, &m2,
- &n, &p1, &p2, &clock)) {
- WRN_MSG("calc_pll_params failed\n");
- return 1;
- }
-
- /* Check for overflow. */
- if (check_overflow(p1, DPLL_P1_MASK, "PLL P1 parameter"))
- return 1;
- if (check_overflow(p2, DPLL_P2_MASK, "PLL P2 parameter"))
- return 1;
- if (check_overflow(m1, FP_DIVISOR_MASK, "PLL M1 parameter"))
- return 1;
- if (check_overflow(m2, FP_DIVISOR_MASK, "PLL M2 parameter"))
- return 1;
- if (check_overflow(n, FP_DIVISOR_MASK, "PLL N parameter"))
- return 1;
-
- *dpll &= ~DPLL_P1_FORCE_DIV2;
- *dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) |
- (DPLL_P1_MASK << DPLL_P1_SHIFT));
-
- if (IS_I9XX(dinfo)) {
- *dpll |= (p2 << DPLL_I9XX_P2_SHIFT);
- *dpll |= (1 << (p1 - 1)) << DPLL_P1_SHIFT;
- } else
- *dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);
-
- *fp0 = (n << FP_N_DIVISOR_SHIFT) |
- (m1 << FP_M1_DIVISOR_SHIFT) |
- (m2 << FP_M2_DIVISOR_SHIFT);
- *fp1 = *fp0;
-
- hw->dvob &= ~PORT_ENABLE;
- hw->dvoc &= ~PORT_ENABLE;
-
- /* Use display plane A. */
- hw->disp_a_ctrl |= DISPPLANE_PLANE_ENABLE;
- hw->disp_a_ctrl &= ~DISPPLANE_GAMMA_ENABLE;
- hw->disp_a_ctrl &= ~DISPPLANE_PIXFORMAT_MASK;
- switch (intelfb_var_to_depth(var)) {
- case 8:
- hw->disp_a_ctrl |= DISPPLANE_8BPP | DISPPLANE_GAMMA_ENABLE;
- break;
- case 15:
- hw->disp_a_ctrl |= DISPPLANE_15_16BPP;
- break;
- case 16:
- hw->disp_a_ctrl |= DISPPLANE_16BPP;
- break;
- case 24:
- hw->disp_a_ctrl |= DISPPLANE_32BPP_NO_ALPHA;
- break;
- }
- hw->disp_a_ctrl &= ~(PIPE_MASK << DISPPLANE_SEL_PIPE_SHIFT);
- hw->disp_a_ctrl |= (pipe << DISPPLANE_SEL_PIPE_SHIFT);
-
- /* Set CRTC registers. */
- hactive = var->xres;
- hsync_start = hactive + var->right_margin;
- hsync_end = hsync_start + var->hsync_len;
- htotal = hsync_end + var->left_margin;
- hblank_start = hactive;
- hblank_end = htotal;
-
- DBG_MSG("H: act %d, ss %d, se %d, tot %d bs %d, be %d\n",
- hactive, hsync_start, hsync_end, htotal, hblank_start,
- hblank_end);
-
- vactive = var->yres;
- if (var->vmode & FB_VMODE_INTERLACED)
- vactive--; /* the chip adds 2 halflines automatically */
- vsync_start = vactive + var->lower_margin;
- vsync_end = vsync_start + var->vsync_len;
- vtotal = vsync_end + var->upper_margin;
- vblank_start = vactive;
- vblank_end = vsync_end + 1;
-
- DBG_MSG("V: act %d, ss %d, se %d, tot %d bs %d, be %d\n",
- vactive, vsync_start, vsync_end, vtotal, vblank_start,
- vblank_end);
-
- /* Adjust for register values, and check for overflow. */
- hactive--;
- if (check_overflow(hactive, HACTIVE_MASK, "CRTC hactive"))
- return 1;
- hsync_start--;
- if (check_overflow(hsync_start, HSYNCSTART_MASK, "CRTC hsync_start"))
- return 1;
- hsync_end--;
- if (check_overflow(hsync_end, HSYNCEND_MASK, "CRTC hsync_end"))
- return 1;
- htotal--;
- if (check_overflow(htotal, HTOTAL_MASK, "CRTC htotal"))
- return 1;
- hblank_start--;
- if (check_overflow(hblank_start, HBLANKSTART_MASK, "CRTC hblank_start"))
- return 1;
- hblank_end--;
- if (check_overflow(hblank_end, HBLANKEND_MASK, "CRTC hblank_end"))
- return 1;
-
- vactive--;
- if (check_overflow(vactive, VACTIVE_MASK, "CRTC vactive"))
- return 1;
- vsync_start--;
- if (check_overflow(vsync_start, VSYNCSTART_MASK, "CRTC vsync_start"))
- return 1;
- vsync_end--;
- if (check_overflow(vsync_end, VSYNCEND_MASK, "CRTC vsync_end"))
- return 1;
- vtotal--;
- if (check_overflow(vtotal, VTOTAL_MASK, "CRTC vtotal"))
- return 1;
- vblank_start--;
- if (check_overflow(vblank_start, VBLANKSTART_MASK, "CRTC vblank_start"))
- return 1;
- vblank_end--;
- if (check_overflow(vblank_end, VBLANKEND_MASK, "CRTC vblank_end"))
- return 1;
-
- *ht = (htotal << HTOTAL_SHIFT) | (hactive << HACTIVE_SHIFT);
- *hb = (hblank_start << HBLANKSTART_SHIFT) |
- (hblank_end << HSYNCEND_SHIFT);
- *hs = (hsync_start << HSYNCSTART_SHIFT) | (hsync_end << HSYNCEND_SHIFT);
-
- *vt = (vtotal << VTOTAL_SHIFT) | (vactive << VACTIVE_SHIFT);
- *vb = (vblank_start << VBLANKSTART_SHIFT) |
- (vblank_end << VSYNCEND_SHIFT);
- *vs = (vsync_start << VSYNCSTART_SHIFT) | (vsync_end << VSYNCEND_SHIFT);
- *ss = (hactive << SRC_SIZE_HORIZ_SHIFT) |
- (vactive << SRC_SIZE_VERT_SHIFT);
-
- hw->disp_a_stride = dinfo->pitch;
- DBG_MSG("pitch is %d\n", hw->disp_a_stride);
-
- hw->disp_a_base = hw->disp_a_stride * var->yoffset +
- var->xoffset * var->bits_per_pixel / 8;
-
- hw->disp_a_base += dinfo->fb.offset << 12;
-
- /* Check stride alignment. */
- stride_alignment = IS_I9XX(dinfo) ? STRIDE_ALIGNMENT_I9XX :
- STRIDE_ALIGNMENT;
- if (hw->disp_a_stride % stride_alignment != 0) {
- WRN_MSG("display stride %d has bad alignment %d\n",
- hw->disp_a_stride, stride_alignment);
- return 1;
- }
-
- /* Set the palette to 8-bit mode. */
- *pipe_conf &= ~PIPECONF_GAMMA;
-
- if (var->vmode & FB_VMODE_INTERLACED)
- *pipe_conf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
- else
- *pipe_conf &= ~PIPECONF_INTERLACE_MASK;
-
- return 0;
-}
-
-/* Program a (non-VGA) video mode. */
-int intelfbhw_program_mode(struct intelfb_info *dinfo,
- const struct intelfb_hwstate *hw, int blank)
-{
- u32 tmp;
- const u32 *dpll, *fp0, *fp1, *pipe_conf;
- const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss;
- u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg, pipe_stat_reg;
- u32 hsync_reg, htotal_reg, hblank_reg;
- u32 vsync_reg, vtotal_reg, vblank_reg;
- u32 src_size_reg;
- u32 count, tmp_val[3];
-
- /* Assume single pipe */
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_program_mode\n");
-#endif
-
- /* Disable VGA */
- tmp = INREG(VGACNTRL);
- tmp |= VGA_DISABLE;
- OUTREG(VGACNTRL, tmp);
-
- dinfo->pipe = intelfbhw_active_pipe(hw);
-
- if (dinfo->pipe == PIPE_B) {
- dpll = &hw->dpll_b;
- fp0 = &hw->fpb0;
- fp1 = &hw->fpb1;
- pipe_conf = &hw->pipe_b_conf;
- hs = &hw->hsync_b;
- hb = &hw->hblank_b;
- ht = &hw->htotal_b;
- vs = &hw->vsync_b;
- vb = &hw->vblank_b;
- vt = &hw->vtotal_b;
- ss = &hw->src_size_b;
- dpll_reg = DPLL_B;
- fp0_reg = FPB0;
- fp1_reg = FPB1;
- pipe_conf_reg = PIPEBCONF;
- pipe_stat_reg = PIPEBSTAT;
- hsync_reg = HSYNC_B;
- htotal_reg = HTOTAL_B;
- hblank_reg = HBLANK_B;
- vsync_reg = VSYNC_B;
- vtotal_reg = VTOTAL_B;
- vblank_reg = VBLANK_B;
- src_size_reg = SRC_SIZE_B;
- } else {
- dpll = &hw->dpll_a;
- fp0 = &hw->fpa0;
- fp1 = &hw->fpa1;
- pipe_conf = &hw->pipe_a_conf;
- hs = &hw->hsync_a;
- hb = &hw->hblank_a;
- ht = &hw->htotal_a;
- vs = &hw->vsync_a;
- vb = &hw->vblank_a;
- vt = &hw->vtotal_a;
- ss = &hw->src_size_a;
- dpll_reg = DPLL_A;
- fp0_reg = FPA0;
- fp1_reg = FPA1;
- pipe_conf_reg = PIPEACONF;
- pipe_stat_reg = PIPEASTAT;
- hsync_reg = HSYNC_A;
- htotal_reg = HTOTAL_A;
- hblank_reg = HBLANK_A;
- vsync_reg = VSYNC_A;
- vtotal_reg = VTOTAL_A;
- vblank_reg = VBLANK_A;
- src_size_reg = SRC_SIZE_A;
- }
-
- /* turn off pipe */
- tmp = INREG(pipe_conf_reg);
- tmp &= ~PIPECONF_ENABLE;
- OUTREG(pipe_conf_reg, tmp);
-
- count = 0;
- do {
- tmp_val[count % 3] = INREG(PIPEA_DSL);
- if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1] == tmp_val[2]))
- break;
- count++;
- udelay(1);
- if (count % 200 == 0) {
- tmp = INREG(pipe_conf_reg);
- tmp &= ~PIPECONF_ENABLE;
- OUTREG(pipe_conf_reg, tmp);
- }
- } while (count < 2000);
-
- OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
-
- /* Disable planes A and B. */
- tmp = INREG(DSPACNTR);
- tmp &= ~DISPPLANE_PLANE_ENABLE;
- OUTREG(DSPACNTR, tmp);
- tmp = INREG(DSPBCNTR);
- tmp &= ~DISPPLANE_PLANE_ENABLE;
- OUTREG(DSPBCNTR, tmp);
-
- /* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */
- mdelay(20);
-
- OUTREG(DVOB, INREG(DVOB) & ~PORT_ENABLE);
- OUTREG(DVOC, INREG(DVOC) & ~PORT_ENABLE);
- OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);
-
- /* Disable Sync */
- tmp = INREG(ADPA);
- tmp &= ~ADPA_DPMS_CONTROL_MASK;
- tmp |= ADPA_DPMS_D3;
- OUTREG(ADPA, tmp);
-
- /* do some funky magic - xyzzy */
- OUTREG(0x61204, 0xabcd0000);
-
- /* turn off PLL */
- tmp = INREG(dpll_reg);
- tmp &= ~DPLL_VCO_ENABLE;
- OUTREG(dpll_reg, tmp);
-
- /* Set PLL parameters */
- OUTREG(fp0_reg, *fp0);
- OUTREG(fp1_reg, *fp1);
-
- /* Enable PLL */
- OUTREG(dpll_reg, *dpll);
-
- /* Set DVOs B/C */
- OUTREG(DVOB, hw->dvob);
- OUTREG(DVOC, hw->dvoc);
-
- /* undo funky magic */
- OUTREG(0x61204, 0x00000000);
-
- /* Set ADPA */
- OUTREG(ADPA, INREG(ADPA) | ADPA_DAC_ENABLE);
- OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3);
-
- /* Set pipe parameters */
- OUTREG(hsync_reg, *hs);
- OUTREG(hblank_reg, *hb);
- OUTREG(htotal_reg, *ht);
- OUTREG(vsync_reg, *vs);
- OUTREG(vblank_reg, *vb);
- OUTREG(vtotal_reg, *vt);
- OUTREG(src_size_reg, *ss);
-
- switch (dinfo->info->var.vmode & (FB_VMODE_INTERLACED |
- FB_VMODE_ODD_FLD_FIRST)) {
- case FB_VMODE_INTERLACED | FB_VMODE_ODD_FLD_FIRST:
- OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_ODD_EN);
- break;
- case FB_VMODE_INTERLACED: /* even lines first */
- OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_EVEN_EN);
- break;
- default: /* non-interlaced */
- OUTREG(pipe_stat_reg, 0xFFFF); /* clear all status bits only */
- }
- /* Enable pipe */
- OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
-
- /* Enable sync */
- tmp = INREG(ADPA);
- tmp &= ~ADPA_DPMS_CONTROL_MASK;
- tmp |= ADPA_DPMS_D0;
- OUTREG(ADPA, tmp);
-
- /* setup display plane */
- if (dinfo->pdev->device == PCI_DEVICE_ID_INTEL_830M) {
- /*
- * i830M errata: the display plane must be enabled
- * to allow writes to the other bits in the plane
- * control register.
- */
- tmp = INREG(DSPACNTR);
- if ((tmp & DISPPLANE_PLANE_ENABLE) != DISPPLANE_PLANE_ENABLE) {
- tmp |= DISPPLANE_PLANE_ENABLE;
- OUTREG(DSPACNTR, tmp);
- OUTREG(DSPACNTR,
- hw->disp_a_ctrl|DISPPLANE_PLANE_ENABLE);
- mdelay(1);
- }
- }
-
- OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE);
- OUTREG(DSPASTRIDE, hw->disp_a_stride);
- OUTREG(DSPABASE, hw->disp_a_base);
-
- /* Enable plane */
- if (!blank) {
- tmp = INREG(DSPACNTR);
- tmp |= DISPPLANE_PLANE_ENABLE;
- OUTREG(DSPACNTR, tmp);
- OUTREG(DSPABASE, hw->disp_a_base);
- }
-
- return 0;
-}
-
-/* forward declarations */
-static void refresh_ring(struct intelfb_info *dinfo);
-static void reset_state(struct intelfb_info *dinfo);
-static void do_flush(struct intelfb_info *dinfo);
-
-static u32 get_ring_space(struct intelfb_info *dinfo)
-{
- u32 ring_space;
-
- if (dinfo->ring_tail >= dinfo->ring_head)
- ring_space = dinfo->ring.size -
- (dinfo->ring_tail - dinfo->ring_head);
- else
- ring_space = dinfo->ring_head - dinfo->ring_tail;
-
- if (ring_space > RING_MIN_FREE)
- ring_space -= RING_MIN_FREE;
- else
- ring_space = 0;
-
- return ring_space;
-}
-
-static int wait_ring(struct intelfb_info *dinfo, int n)
-{
- int i = 0;
- unsigned long end;
- u32 last_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
-
-#if VERBOSE > 0
- DBG_MSG("wait_ring: %d\n", n);
-#endif
-
- end = jiffies + (HZ * 3);
- while (dinfo->ring_space < n) {
- dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
- dinfo->ring_space = get_ring_space(dinfo);
-
- if (dinfo->ring_head != last_head) {
- end = jiffies + (HZ * 3);
- last_head = dinfo->ring_head;
- }
- i++;
- if (time_before(end, jiffies)) {
- if (!i) {
- /* Try again */
- reset_state(dinfo);
- refresh_ring(dinfo);
- do_flush(dinfo);
- end = jiffies + (HZ * 3);
- i = 1;
- } else {
- WRN_MSG("ring buffer : space: %d wanted %d\n",
- dinfo->ring_space, n);
- WRN_MSG("lockup - turning off hardware "
- "acceleration\n");
- dinfo->ring_lockup = 1;
- break;
- }
- }
- udelay(1);
- }
- return i;
-}
-
-static void do_flush(struct intelfb_info *dinfo)
-{
- START_RING(2);
- OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE);
- OUT_RING(MI_NOOP);
- ADVANCE_RING();
-}
-
-void intelfbhw_do_sync(struct intelfb_info *dinfo)
-{
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_do_sync\n");
-#endif
-
- if (!dinfo->accel)
- return;
-
- /*
- * Send a flush, then wait until the ring is empty. This is what
- * the XFree86 driver does, and actually it doesn't seem a lot worse
- * than the recommended method (both have problems).
- */
- do_flush(dinfo);
- wait_ring(dinfo, dinfo->ring.size - RING_MIN_FREE);
- dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE;
-}
-
-static void refresh_ring(struct intelfb_info *dinfo)
-{
-#if VERBOSE > 0
- DBG_MSG("refresh_ring\n");
-#endif
-
- dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
- dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK;
- dinfo->ring_space = get_ring_space(dinfo);
-}
-
-static void reset_state(struct intelfb_info *dinfo)
-{
- int i;
- u32 tmp;
-
-#if VERBOSE > 0
- DBG_MSG("reset_state\n");
-#endif
-
- for (i = 0; i < FENCE_NUM; i++)
- OUTREG(FENCE + (i << 2), 0);
-
- /* Flush the ring buffer if it's enabled. */
- tmp = INREG(PRI_RING_LENGTH);
- if (tmp & RING_ENABLE) {
-#if VERBOSE > 0
- DBG_MSG("reset_state: ring was enabled\n");
-#endif
- refresh_ring(dinfo);
- intelfbhw_do_sync(dinfo);
- DO_RING_IDLE();
- }
-
- OUTREG(PRI_RING_LENGTH, 0);
- OUTREG(PRI_RING_HEAD, 0);
- OUTREG(PRI_RING_TAIL, 0);
- OUTREG(PRI_RING_START, 0);
-}
-
-/* Stop the 2D engine, and turn off the ring buffer. */
-void intelfbhw_2d_stop(struct intelfb_info *dinfo)
-{
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n",
- dinfo->accel, dinfo->ring_active);
-#endif
-
- if (!dinfo->accel)
- return;
-
- dinfo->ring_active = 0;
- reset_state(dinfo);
-}
-
-/*
- * Enable the ring buffer, and initialise the 2D engine.
- * It is assumed that the graphics engine has been stopped by previously
- * calling intelfb_2d_stop().
- */
-void intelfbhw_2d_start(struct intelfb_info *dinfo)
-{
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n",
- dinfo->accel, dinfo->ring_active);
-#endif
-
- if (!dinfo->accel)
- return;
-
- /* Initialise the primary ring buffer. */
- OUTREG(PRI_RING_LENGTH, 0);
- OUTREG(PRI_RING_TAIL, 0);
- OUTREG(PRI_RING_HEAD, 0);
-
- OUTREG(PRI_RING_START, dinfo->ring.physical & RING_START_MASK);
- OUTREG(PRI_RING_LENGTH,
- ((dinfo->ring.size - GTT_PAGE_SIZE) & RING_LENGTH_MASK) |
- RING_NO_REPORT | RING_ENABLE);
- refresh_ring(dinfo);
- dinfo->ring_active = 1;
-}
-
-/* 2D fillrect (solid fill or invert) */
-void intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w,
- u32 h, u32 color, u32 pitch, u32 bpp, u32 rop)
-{
- u32 br00, br09, br13, br14, br16;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_do_fillrect: (%d,%d) %dx%d, c 0x%06x, p %d bpp %d, "
- "rop 0x%02x\n", x, y, w, h, color, pitch, bpp, rop);
-#endif
-
- br00 = COLOR_BLT_CMD;
- br09 = dinfo->fb_start + (y * pitch + x * (bpp / 8));
- br13 = (rop << ROP_SHIFT) | pitch;
- br14 = (h << HEIGHT_SHIFT) | ((w * (bpp / 8)) << WIDTH_SHIFT);
- br16 = color;
-
- switch (bpp) {
- case 8:
- br13 |= COLOR_DEPTH_8;
- break;
- case 16:
- br13 |= COLOR_DEPTH_16;
- break;
- case 32:
- br13 |= COLOR_DEPTH_32;
- br00 |= WRITE_ALPHA | WRITE_RGB;
- break;
- }
-
- START_RING(6);
- OUT_RING(br00);
- OUT_RING(br13);
- OUT_RING(br14);
- OUT_RING(br09);
- OUT_RING(br16);
- OUT_RING(MI_NOOP);
- ADVANCE_RING();
-
-#if VERBOSE > 0
- DBG_MSG("ring = 0x%08x, 0x%08x (%d)\n", dinfo->ring_head,
- dinfo->ring_tail, dinfo->ring_space);
-#endif
-}
-
-void
-intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury,
- u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch, u32 bpp)
-{
- u32 br00, br09, br11, br12, br13, br22, br23, br26;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_do_bitblt: (%d,%d)->(%d,%d) %dx%d, p %d bpp %d\n",
- curx, cury, dstx, dsty, w, h, pitch, bpp);
-#endif
-
- br00 = XY_SRC_COPY_BLT_CMD;
- br09 = dinfo->fb_start;
- br11 = (pitch << PITCH_SHIFT);
- br12 = dinfo->fb_start;
- br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT);
- br22 = (dstx << WIDTH_SHIFT) | (dsty << HEIGHT_SHIFT);
- br23 = ((dstx + w) << WIDTH_SHIFT) |
- ((dsty + h) << HEIGHT_SHIFT);
- br26 = (curx << WIDTH_SHIFT) | (cury << HEIGHT_SHIFT);
-
- switch (bpp) {
- case 8:
- br13 |= COLOR_DEPTH_8;
- break;
- case 16:
- br13 |= COLOR_DEPTH_16;
- break;
- case 32:
- br13 |= COLOR_DEPTH_32;
- br00 |= WRITE_ALPHA | WRITE_RGB;
- break;
- }
-
- START_RING(8);
- OUT_RING(br00);
- OUT_RING(br13);
- OUT_RING(br22);
- OUT_RING(br23);
- OUT_RING(br09);
- OUT_RING(br26);
- OUT_RING(br11);
- OUT_RING(br12);
- ADVANCE_RING();
-}
-
-int intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w,
- u32 h, const u8* cdat, u32 x, u32 y, u32 pitch,
- u32 bpp)
-{
- int nbytes, ndwords, pad, tmp;
- u32 br00, br09, br13, br18, br19, br22, br23;
- int dat, ix, iy, iw;
- int i, j;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_do_drawglyph: (%d,%d) %dx%d\n", x, y, w, h);
-#endif
-
- /* size in bytes of a padded scanline */
- nbytes = ROUND_UP_TO(w, 16) / 8;
-
- /* Total bytes of padded scanline data to write out. */
- nbytes = nbytes * h;
-
- /*
- * Check if the glyph data exceeds the immediate mode limit.
- * It would take a large font (1K pixels) to hit this limit.
- */
- if (nbytes > MAX_MONO_IMM_SIZE)
- return 0;
-
- /* Src data is packaged a dword (32-bit) at a time. */
- ndwords = ROUND_UP_TO(nbytes, 4) / 4;
-
- /*
- * Ring has to be padded to a quad word. But because the command starts
- with 7 bytes, pad only if there is an even number of ndwords
- */
- pad = !(ndwords % 2);
-
- tmp = (XY_MONO_SRC_IMM_BLT_CMD & DW_LENGTH_MASK) + ndwords;
- br00 = (XY_MONO_SRC_IMM_BLT_CMD & ~DW_LENGTH_MASK) | tmp;
- br09 = dinfo->fb_start;
- br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT);
- br18 = bg;
- br19 = fg;
- br22 = (x << WIDTH_SHIFT) | (y << HEIGHT_SHIFT);
- br23 = ((x + w) << WIDTH_SHIFT) | ((y + h) << HEIGHT_SHIFT);
-
- switch (bpp) {
- case 8:
- br13 |= COLOR_DEPTH_8;
- break;
- case 16:
- br13 |= COLOR_DEPTH_16;
- break;
- case 32:
- br13 |= COLOR_DEPTH_32;
- br00 |= WRITE_ALPHA | WRITE_RGB;
- break;
- }
-
- START_RING(8 + ndwords);
- OUT_RING(br00);
- OUT_RING(br13);
- OUT_RING(br22);
- OUT_RING(br23);
- OUT_RING(br09);
- OUT_RING(br18);
- OUT_RING(br19);
- ix = iy = 0;
- iw = ROUND_UP_TO(w, 8) / 8;
- while (ndwords--) {
- dat = 0;
- for (j = 0; j < 2; ++j) {
- for (i = 0; i < 2; ++i) {
- if (ix != iw || i == 0)
- dat |= cdat[iy*iw + ix++] << (i+j*2)*8;
- }
- if (ix == iw && iy != (h-1)) {
- ix = 0;
- ++iy;
- }
- }
- OUT_RING(dat);
- }
- if (pad)
- OUT_RING(MI_NOOP);
- ADVANCE_RING();
-
- return 1;
-}
-
-/* HW cursor functions. */
-void intelfbhw_cursor_init(struct intelfb_info *dinfo)
-{
- u32 tmp;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_cursor_init\n");
-#endif
-
- if (dinfo->mobile || IS_I9XX(dinfo)) {
- if (!dinfo->cursor.physical)
- return;
- tmp = INREG(CURSOR_A_CONTROL);
- tmp &= ~(CURSOR_MODE_MASK | CURSOR_MOBILE_GAMMA_ENABLE |
- CURSOR_MEM_TYPE_LOCAL |
- (1 << CURSOR_PIPE_SELECT_SHIFT));
- tmp |= CURSOR_MODE_DISABLE;
- OUTREG(CURSOR_A_CONTROL, tmp);
- OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
- } else {
- tmp = INREG(CURSOR_CONTROL);
- tmp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE |
- CURSOR_ENABLE | CURSOR_STRIDE_MASK);
- tmp |= CURSOR_FORMAT_3C;
- OUTREG(CURSOR_CONTROL, tmp);
- OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.offset << 12);
- tmp = (64 << CURSOR_SIZE_H_SHIFT) |
- (64 << CURSOR_SIZE_V_SHIFT);
- OUTREG(CURSOR_SIZE, tmp);
- }
-}
-
-void intelfbhw_cursor_hide(struct intelfb_info *dinfo)
-{
- u32 tmp;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_cursor_hide\n");
-#endif
-
- dinfo->cursor_on = 0;
- if (dinfo->mobile || IS_I9XX(dinfo)) {
- if (!dinfo->cursor.physical)
- return;
- tmp = INREG(CURSOR_A_CONTROL);
- tmp &= ~CURSOR_MODE_MASK;
- tmp |= CURSOR_MODE_DISABLE;
- OUTREG(CURSOR_A_CONTROL, tmp);
- /* Flush changes */
- OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
- } else {
- tmp = INREG(CURSOR_CONTROL);
- tmp &= ~CURSOR_ENABLE;
- OUTREG(CURSOR_CONTROL, tmp);
- }
-}
-
-void intelfbhw_cursor_show(struct intelfb_info *dinfo)
-{
- u32 tmp;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_cursor_show\n");
-#endif
-
- dinfo->cursor_on = 1;
-
- if (dinfo->cursor_blanked)
- return;
-
- if (dinfo->mobile || IS_I9XX(dinfo)) {
- if (!dinfo->cursor.physical)
- return;
- tmp = INREG(CURSOR_A_CONTROL);
- tmp &= ~CURSOR_MODE_MASK;
- tmp |= CURSOR_MODE_64_4C_AX;
- OUTREG(CURSOR_A_CONTROL, tmp);
- /* Flush changes */
- OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
- } else {
- tmp = INREG(CURSOR_CONTROL);
- tmp |= CURSOR_ENABLE;
- OUTREG(CURSOR_CONTROL, tmp);
- }
-}
-
-void intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y)
-{
- u32 tmp;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_cursor_setpos: (%d, %d)\n", x, y);
-#endif
-
- /*
- * Sets the position. The coordinates are assumed to already
- * have any offset adjusted. Assume that the cursor is never
- * completely off-screen, and that x, y are always >= 0.
- */
-
- tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) |
- ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
- OUTREG(CURSOR_A_POSITION, tmp);
-
- if (IS_I9XX(dinfo))
- OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);
-}
-
-void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg)
-{
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_cursor_setcolor\n");
-#endif
-
- OUTREG(CURSOR_A_PALETTE0, bg & CURSOR_PALETTE_MASK);
- OUTREG(CURSOR_A_PALETTE1, fg & CURSOR_PALETTE_MASK);
- OUTREG(CURSOR_A_PALETTE2, fg & CURSOR_PALETTE_MASK);
- OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK);
-}
-
-void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height,
- u8 *data)
-{
- u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual;
- int i, j, w = width / 8;
- int mod = width % 8, t_mask, d_mask;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_cursor_load\n");
-#endif
-
- if (!dinfo->cursor.virtual)
- return;
-
- t_mask = 0xff >> mod;
- d_mask = ~(0xff >> mod);
- for (i = height; i--; ) {
- for (j = 0; j < w; j++) {
- writeb(0x00, addr + j);
- writeb(*(data++), addr + j+8);
- }
- if (mod) {
- writeb(t_mask, addr + j);
- writeb(*(data++) & d_mask, addr + j+8);
- }
- addr += 16;
- }
-}
-
-void intelfbhw_cursor_reset(struct intelfb_info *dinfo)
-{
- u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual;
- int i, j;
-
-#if VERBOSE > 0
- DBG_MSG("intelfbhw_cursor_reset\n");
-#endif
-
- if (!dinfo->cursor.virtual)
- return;
-
- for (i = 64; i--; ) {
- for (j = 0; j < 8; j++) {
- writeb(0xff, addr + j+0);
- writeb(0x00, addr + j+8);
- }
- addr += 16;
- }
-}
-
-static irqreturn_t intelfbhw_irq(int irq, void *dev_id)
-{
- u16 tmp;
- struct intelfb_info *dinfo = dev_id;
-
- spin_lock(&dinfo->int_lock);
-
- tmp = INREG16(IIR);
- if (dinfo->info->var.vmode & FB_VMODE_INTERLACED)
- tmp &= PIPE_A_EVENT_INTERRUPT;
- else
- tmp &= VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */
-
- if (tmp == 0) {
- spin_unlock(&dinfo->int_lock);
- return IRQ_RETVAL(0); /* not us */
- }
-
- /* clear status bits 0-15 ASAP and don't touch bits 16-31 */
- OUTREG(PIPEASTAT, INREG(PIPEASTAT));
-
- OUTREG16(IIR, tmp);
- if (dinfo->vsync.pan_display) {
- dinfo->vsync.pan_display = 0;
- OUTREG(DSPABASE, dinfo->vsync.pan_offset);
- }
-
- dinfo->vsync.count++;
- wake_up_interruptible(&dinfo->vsync.wait);
-
- spin_unlock(&dinfo->int_lock);
-
- return IRQ_RETVAL(1);
-}
-
-int intelfbhw_enable_irq(struct intelfb_info *dinfo)
-{
- u16 tmp;
- if (!test_and_set_bit(0, &dinfo->irq_flags)) {
- if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED,
- "intelfb", dinfo)) {
- clear_bit(0, &dinfo->irq_flags);
- return -EINVAL;
- }
-
- spin_lock_irq(&dinfo->int_lock);
- OUTREG16(HWSTAM, 0xfffe); /* i830 DRM uses ffff */
- OUTREG16(IMR, 0);
- } else
- spin_lock_irq(&dinfo->int_lock);
-
- if (dinfo->info->var.vmode & FB_VMODE_INTERLACED)
- tmp = PIPE_A_EVENT_INTERRUPT;
- else
- tmp = VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */
- if (tmp != INREG16(IER)) {
- DBG_MSG("changing IER to 0x%X\n", tmp);
- OUTREG16(IER, tmp);
- }
-
- spin_unlock_irq(&dinfo->int_lock);
- return 0;
-}
-
-void intelfbhw_disable_irq(struct intelfb_info *dinfo)
-{
- if (test_and_clear_bit(0, &dinfo->irq_flags)) {
- if (dinfo->vsync.pan_display) {
- dinfo->vsync.pan_display = 0;
- OUTREG(DSPABASE, dinfo->vsync.pan_offset);
- }
- spin_lock_irq(&dinfo->int_lock);
- OUTREG16(HWSTAM, 0xffff);
- OUTREG16(IMR, 0xffff);
- OUTREG16(IER, 0x0);
-
- OUTREG16(IIR, INREG16(IIR)); /* clear IRQ requests */
- spin_unlock_irq(&dinfo->int_lock);
-
- free_irq(dinfo->pdev->irq, dinfo);
- }
-}
-
-int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe)
-{
- struct intelfb_vsync *vsync;
- unsigned int count;
- int ret;
-
- switch (pipe) {
- case 0:
- vsync = &dinfo->vsync;
- break;
- default:
- return -ENODEV;
- }
-
- ret = intelfbhw_enable_irq(dinfo);
- if (ret)
- return ret;
-
- count = vsync->count;
- ret = wait_event_interruptible_timeout(vsync->wait,
- count != vsync->count, HZ / 10);
- if (ret < 0)
- return ret;
- if (ret == 0) {
- DBG_MSG("wait_for_vsync timed out!\n");
- return -ETIMEDOUT;
- }
-
- return 0;
-}
diff --git a/drivers/video/fbdev/intelfb/intelfbhw.h b/drivers/video/fbdev/intelfb/intelfbhw.h
deleted file mode 100644
index 216ca20f259f..000000000000
--- a/drivers/video/fbdev/intelfb/intelfbhw.h
+++ /dev/null
@@ -1,609 +0,0 @@
-#ifndef _INTELFBHW_H
-#define _INTELFBHW_H
-
-/* $DHD: intelfb/intelfbhw.h,v 1.5 2003/06/27 15:06:25 dawes Exp $ */
-
-
-/*** HW-specific data ***/
-
-/* Information about the 852GM/855GM variants */
-#define INTEL_85X_CAPID 0x44
-#define INTEL_85X_VARIANT_MASK 0x7
-#define INTEL_85X_VARIANT_SHIFT 5
-#define INTEL_VAR_855GME 0x0
-#define INTEL_VAR_855GM 0x4
-#define INTEL_VAR_852GME 0x2
-#define INTEL_VAR_852GM 0x5
-
-/* Information about DVO/LVDS Ports */
-#define DVOA_PORT 0x1
-#define DVOB_PORT 0x2
-#define DVOC_PORT 0x4
-#define LVDS_PORT 0x8
-
-/*
- * The Bridge device's PCI config space has information about the
- * fb aperture size and the amount of pre-reserved memory.
- */
-#define INTEL_GMCH_CTRL 0x52
-#define INTEL_GMCH_ENABLED 0x4
-#define INTEL_GMCH_MEM_MASK 0x1
-#define INTEL_GMCH_MEM_64M 0x1
-#define INTEL_GMCH_MEM_128M 0
-
-#define INTEL_830_GMCH_GMS_MASK (0x7 << 4)
-#define INTEL_830_GMCH_GMS_DISABLED (0x0 << 4)
-#define INTEL_830_GMCH_GMS_LOCAL (0x1 << 4)
-#define INTEL_830_GMCH_GMS_STOLEN_512 (0x2 << 4)
-#define INTEL_830_GMCH_GMS_STOLEN_1024 (0x3 << 4)
-#define INTEL_830_GMCH_GMS_STOLEN_8192 (0x4 << 4)
-
-#define INTEL_855_GMCH_GMS_MASK (0x7 << 4)
-#define INTEL_855_GMCH_GMS_DISABLED (0x0 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_1M (0x1 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_4M (0x2 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_8M (0x3 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_16M (0x4 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_32M (0x5 << 4)
-
-#define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4)
-#define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4)
-
-/* HW registers */
-
-/* Fence registers */
-#define FENCE 0x2000
-#define FENCE_NUM 8
-
-/* Primary ring buffer */
-#define PRI_RING_TAIL 0x2030
-#define RING_TAIL_MASK 0x001ffff8
-#define RING_INUSE 0x1
-
-#define PRI_RING_HEAD 0x2034
-#define RING_HEAD_WRAP_MASK 0x7ff
-#define RING_HEAD_WRAP_SHIFT 21
-#define RING_HEAD_MASK 0x001ffffc
-
-#define PRI_RING_START 0x2038
-#define RING_START_MASK 0xfffff000
-
-#define PRI_RING_LENGTH 0x203c
-#define RING_LENGTH_MASK 0x001ff000
-#define RING_REPORT_MASK (0x3 << 1)
-#define RING_NO_REPORT (0x0 << 1)
-#define RING_REPORT_64K (0x1 << 1)
-#define RING_REPORT_4K (0x2 << 1)
-#define RING_REPORT_128K (0x3 << 1)
-#define RING_ENABLE 0x1
-
-/*
- * Tail can't wrap to any closer than RING_MIN_FREE bytes of the head,
- * and the last RING_MIN_FREE bytes need to be padded with MI_NOOP
- */
-#define RING_MIN_FREE 64
-
-#define IPEHR 0x2088
-
-#define INSTDONE 0x2090
-#define PRI_RING_EMPTY 1
-
-#define HWSTAM 0x2098
-#define IER 0x20A0
-#define IIR 0x20A4
-#define IMR 0x20A8
-#define VSYNC_PIPE_A_INTERRUPT (1 << 7)
-#define PIPE_A_EVENT_INTERRUPT (1 << 6)
-#define VSYNC_PIPE_B_INTERRUPT (1 << 5)
-#define PIPE_B_EVENT_INTERRUPT (1 << 4)
-#define HOST_PORT_EVENT_INTERRUPT (1 << 3)
-#define CAPTURE_EVENT_INTERRUPT (1 << 2)
-#define USER_DEFINED_INTERRUPT (1 << 1)
-#define BREAKPOINT_INTERRUPT 1
-
-#define INSTPM 0x20c0
-#define SYNC_FLUSH_ENABLE (1 << 5)
-
-#define INSTPS 0x20c4
-
-#define MEM_MODE 0x20cc
-
-#define MASK_SHIFT 16
-
-#define FW_BLC_0 0x20d8
-#define FW_DISPA_WM_SHIFT 0
-#define FW_DISPA_WM_MASK 0x3f
-#define FW_DISPA_BL_SHIFT 8
-#define FW_DISPA_BL_MASK 0xf
-#define FW_DISPB_WM_SHIFT 16
-#define FW_DISPB_WM_MASK 0x1f
-#define FW_DISPB_BL_SHIFT 24
-#define FW_DISPB_BL_MASK 0x7
-
-#define FW_BLC_1 0x20dc
-#define FW_DISPC_WM_SHIFT 0
-#define FW_DISPC_WM_MASK 0x1f
-#define FW_DISPC_BL_SHIFT 8
-#define FW_DISPC_BL_MASK 0x7
-
-#define GPIOA 0x5010
-#define GPIOB 0x5014
-#define GPIOC 0x5018 /* this may be external DDC on i830 */
-#define GPIOD 0x501C /* this is DVO DDC */
-#define GPIOE 0x5020 /* this is DVO i2C */
-#define GPIOF 0x5024
-
-/* PLL registers */
-#define VGA0_DIVISOR 0x06000
-#define VGA1_DIVISOR 0x06004
-#define VGAPD 0x06010
-#define VGAPD_0_P1_SHIFT 0
-#define VGAPD_0_P1_FORCE_DIV2 (1 << 5)
-#define VGAPD_0_P2_SHIFT 7
-#define VGAPD_1_P1_SHIFT 8
-#define VGAPD_1_P1_FORCE_DIV2 (1 << 13)
-#define VGAPD_1_P2_SHIFT 15
-
-#define DPLL_A 0x06014
-#define DPLL_B 0x06018
-#define DPLL_VCO_ENABLE (1 << 31)
-#define DPLL_2X_CLOCK_ENABLE (1 << 30)
-#define DPLL_SYNCLOCK_ENABLE (1 << 29)
-#define DPLL_VGA_MODE_DISABLE (1 << 28)
-#define DPLL_P2_MASK 1
-#define DPLL_P2_SHIFT 23
-#define DPLL_I9XX_P2_SHIFT 24
-#define DPLL_P1_FORCE_DIV2 (1 << 21)
-#define DPLL_P1_MASK 0x1f
-#define DPLL_P1_SHIFT 16
-#define DPLL_REFERENCE_SELECT_MASK (0x3 << 13)
-#define DPLL_REFERENCE_DEFAULT (0x0 << 13)
-#define DPLL_REFERENCE_TVCLK (0x2 << 13)
-#define DPLL_RATE_SELECT_MASK (1 << 8)
-#define DPLL_RATE_SELECT_FP0 (0 << 8)
-#define DPLL_RATE_SELECT_FP1 (1 << 8)
-
-#define FPA0 0x06040
-#define FPA1 0x06044
-#define FPB0 0x06048
-#define FPB1 0x0604c
-#define FP_DIVISOR_MASK 0x3f
-#define FP_N_DIVISOR_SHIFT 16
-#define FP_M1_DIVISOR_SHIFT 8
-#define FP_M2_DIVISOR_SHIFT 0
-
-/* PLL parameters (these are for 852GM/855GM/865G, check earlier chips). */
-/* Clock values are in units of kHz */
-#define PLL_REFCLK 48000
-#define MIN_CLOCK 25000
-#define MAX_CLOCK 350000
-
-/* Two pipes */
-#define PIPE_A 0
-#define PIPE_B 1
-#define PIPE_MASK 1
-
-/* palette registers */
-#define PALETTE_A 0x0a000
-#define PALETTE_B 0x0a800
-#ifndef PALETTE_8_ENTRIES
-#define PALETTE_8_ENTRIES 256
-#endif
-#define PALETTE_8_SIZE (PALETTE_8_ENTRIES * 4)
-#define PALETTE_10_ENTRIES 128
-#define PALETTE_10_SIZE (PALETTE_10_ENTRIES * 8)
-#define PALETTE_8_MASK 0xff
-#define PALETTE_8_RED_SHIFT 16
-#define PALETTE_8_GREEN_SHIFT 8
-#define PALETTE_8_BLUE_SHIFT 0
-
-/* CRTC registers */
-#define HTOTAL_A 0x60000
-#define HBLANK_A 0x60004
-#define HSYNC_A 0x60008
-#define VTOTAL_A 0x6000c
-#define VBLANK_A 0x60010
-#define VSYNC_A 0x60014
-#define SRC_SIZE_A 0x6001c
-#define BCLRPAT_A 0x60020
-
-#define HTOTAL_B 0x61000
-#define HBLANK_B 0x61004
-#define HSYNC_B 0x61008
-#define VTOTAL_B 0x6100c
-#define VBLANK_B 0x61010
-#define VSYNC_B 0x61014
-#define SRC_SIZE_B 0x6101c
-#define BCLRPAT_B 0x61020
-
-#define HTOTAL_MASK 0xfff
-#define HTOTAL_SHIFT 16
-#define HACTIVE_MASK 0x7ff
-#define HACTIVE_SHIFT 0
-#define HBLANKEND_MASK 0xfff
-#define HBLANKEND_SHIFT 16
-#define HBLANKSTART_MASK 0xfff
-#define HBLANKSTART_SHIFT 0
-#define HSYNCEND_MASK 0xfff
-#define HSYNCEND_SHIFT 16
-#define HSYNCSTART_MASK 0xfff
-#define HSYNCSTART_SHIFT 0
-#define VTOTAL_MASK 0xfff
-#define VTOTAL_SHIFT 16
-#define VACTIVE_MASK 0x7ff
-#define VACTIVE_SHIFT 0
-#define VBLANKEND_MASK 0xfff
-#define VBLANKEND_SHIFT 16
-#define VBLANKSTART_MASK 0xfff
-#define VBLANKSTART_SHIFT 0
-#define VSYNCEND_MASK 0xfff
-#define VSYNCEND_SHIFT 16
-#define VSYNCSTART_MASK 0xfff
-#define VSYNCSTART_SHIFT 0
-#define SRC_SIZE_HORIZ_MASK 0x7ff
-#define SRC_SIZE_HORIZ_SHIFT 16
-#define SRC_SIZE_VERT_MASK 0x7ff
-#define SRC_SIZE_VERT_SHIFT 0
-
-#define ADPA 0x61100
-#define ADPA_DAC_ENABLE (1 << 31)
-#define ADPA_DAC_DISABLE 0
-#define ADPA_PIPE_SELECT_SHIFT 30
-#define ADPA_USE_VGA_HVPOLARITY (1 << 15)
-#define ADPA_SETS_HVPOLARITY 0
-#define ADPA_DPMS_CONTROL_MASK (0x3 << 10)
-#define ADPA_DPMS_D0 (0x0 << 10)
-#define ADPA_DPMS_D2 (0x1 << 10)
-#define ADPA_DPMS_D1 (0x2 << 10)
-#define ADPA_DPMS_D3 (0x3 << 10)
-#define ADPA_VSYNC_ACTIVE_SHIFT 4
-#define ADPA_HSYNC_ACTIVE_SHIFT 3
-#define ADPA_SYNC_ACTIVE_MASK 1
-#define ADPA_SYNC_ACTIVE_HIGH 1
-#define ADPA_SYNC_ACTIVE_LOW 0
-
-#define DVOA 0x61120
-#define DVOB 0x61140
-#define DVOC 0x61160
-#define LVDS 0x61180
-#define PORT_ENABLE (1 << 31)
-#define PORT_PIPE_SELECT_SHIFT 30
-#define PORT_TV_FLAGS_MASK 0xFF
-#define PORT_TV_FLAGS 0xC4 /* ripped from my BIOS
- to understand and correct */
-
-#define DVOA_SRCDIM 0x61124
-#define DVOB_SRCDIM 0x61144
-#define DVOC_SRCDIM 0x61164
-
-#define PIPEA_DSL 0x70000
-#define PIPEB_DSL 0x71000
-#define PIPEACONF 0x70008
-#define PIPEBCONF 0x71008
-#define PIPEASTAT 0x70024 /* bits 0-15 are "write 1 to clear" */
-#define PIPEBSTAT 0x71024
-
-#define PIPECONF_ENABLE (1 << 31)
-#define PIPECONF_DISABLE 0
-#define PIPECONF_DOUBLE_WIDE (1 << 30)
-#define PIPECONF_SINGLE_WIDE 0
-#define PIPECONF_LOCKED (1 << 25)
-#define PIPECONF_UNLOCKED 0
-#define PIPECONF_GAMMA (1 << 24)
-#define PIPECONF_PALETTE 0
-#define PIPECONF_PROGRESSIVE (0 << 21)
-#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21)
-#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
-#define PIPECONF_INTERLACE_MASK (7 << 21)
-
-/* enable bits, write 1 to enable */
-#define PIPESTAT_FIFO_UNDERRUN (1 << 31)
-#define PIPESTAT_CRC_ERROR_EN (1 << 29)
-#define PIPESTAT_CRC_DONE_EN (1 << 28)
-#define PIPESTAT_HOTPLUG_EN (1 << 26)
-#define PIPESTAT_VERTICAL_SYNC_EN (1 << 25)
-#define PIPESTAT_DISPLINE_COMP_EN (1 << 24)
-#define PIPESTAT_FLD_EVT_ODD_EN (1 << 21)
-#define PIPESTAT_FLD_EVT_EVEN_EN (1 << 20)
-#define PIPESTAT_TV_HOTPLUG_EN (1 << 18)
-#define PIPESTAT_VBLANK_EN (1 << 17)
-#define PIPESTAT_OVL_UPDATE_EN (1 << 16)
-/* status bits, write 1 to clear */
-#define PIPESTAT_HOTPLUG_STATE (1 << 15)
-#define PIPESTAT_CRC_ERROR (1 << 13)
-#define PIPESTAT_CRC_DONE (1 << 12)
-#define PIPESTAT_HOTPLUG (1 << 10)
-#define PIPESTAT_VSYNC (1 << 9)
-#define PIPESTAT_DISPLINE_COMP (1 << 8)
-#define PIPESTAT_FLD_EVT_ODD (1 << 5)
-#define PIPESTAT_FLD_EVT_EVEN (1 << 4)
-#define PIPESTAT_TV_HOTPLUG (1 << 2)
-#define PIPESTAT_VBLANK (1 << 1)
-#define PIPESTAT_OVL_UPDATE (1 << 0)
-
-#define DISPARB 0x70030
-#define DISPARB_AEND_MASK 0x1ff
-#define DISPARB_AEND_SHIFT 0
-#define DISPARB_BEND_MASK 0x3ff
-#define DISPARB_BEND_SHIFT 9
-
-/* Desktop HW cursor */
-#define CURSOR_CONTROL 0x70080
-#define CURSOR_ENABLE (1 << 31)
-#define CURSOR_GAMMA_ENABLE (1 << 30)
-#define CURSOR_STRIDE_MASK (0x3 << 28)
-#define CURSOR_STRIDE_256 (0x0 << 28)
-#define CURSOR_STRIDE_512 (0x1 << 28)
-#define CURSOR_STRIDE_1K (0x2 << 28)
-#define CURSOR_STRIDE_2K (0x3 << 28)
-#define CURSOR_FORMAT_MASK (0x7 << 24)
-#define CURSOR_FORMAT_2C (0x0 << 24)
-#define CURSOR_FORMAT_3C (0x1 << 24)
-#define CURSOR_FORMAT_4C (0x2 << 24)
-#define CURSOR_FORMAT_ARGB (0x4 << 24)
-#define CURSOR_FORMAT_XRGB (0x5 << 24)
-
-/* Mobile HW cursor (and i810) */
-#define CURSOR_A_CONTROL CURSOR_CONTROL
-#define CURSOR_B_CONTROL 0x700c0
-#define CURSOR_MODE_MASK 0x27
-#define CURSOR_MODE_DISABLE 0
-#define CURSOR_MODE_64_3C 0x04
-#define CURSOR_MODE_64_4C_AX 0x05
-#define CURSOR_MODE_64_4C 0x06
-#define CURSOR_MODE_64_32B_AX 0x07
-#define CURSOR_MODE_64_ARGB_AX 0x27
-#define CURSOR_PIPE_SELECT_SHIFT 28
-#define CURSOR_MOBILE_GAMMA_ENABLE (1 << 26)
-#define CURSOR_MEM_TYPE_LOCAL (1 << 25)
-
-/* All platforms (desktop has no pipe B) */
-#define CURSOR_A_BASEADDR 0x70084
-#define CURSOR_B_BASEADDR 0x700c4
-#define CURSOR_BASE_MASK 0xffffff00
-
-#define CURSOR_A_POSITION 0x70088
-#define CURSOR_B_POSITION 0x700c8
-#define CURSOR_POS_SIGN (1 << 15)
-#define CURSOR_POS_MASK 0x7ff
-#define CURSOR_X_SHIFT 0
-#define CURSOR_Y_SHIFT 16
-
-#define CURSOR_A_PALETTE0 0x70090
-#define CURSOR_A_PALETTE1 0x70094
-#define CURSOR_A_PALETTE2 0x70098
-#define CURSOR_A_PALETTE3 0x7009c
-#define CURSOR_B_PALETTE0 0x700d0
-#define CURSOR_B_PALETTE1 0x700d4
-#define CURSOR_B_PALETTE2 0x700d8
-#define CURSOR_B_PALETTE3 0x700dc
-#define CURSOR_COLOR_MASK 0xff
-#define CURSOR_RED_SHIFT 16
-#define CURSOR_GREEN_SHIFT 8
-#define CURSOR_BLUE_SHIFT 0
-#define CURSOR_PALETTE_MASK 0xffffff
-
-/* Desktop only */
-#define CURSOR_SIZE 0x700a0
-#define CURSOR_SIZE_MASK 0x3ff
-#define CURSOR_SIZE_H_SHIFT 0
-#define CURSOR_SIZE_V_SHIFT 12
-
-#define DSPACNTR 0x70180
-#define DSPBCNTR 0x71180
-#define DISPPLANE_PLANE_ENABLE (1 << 31)
-#define DISPPLANE_PLANE_DISABLE 0
-#define DISPPLANE_GAMMA_ENABLE (1<<30)
-#define DISPPLANE_GAMMA_DISABLE 0
-#define DISPPLANE_PIXFORMAT_MASK (0xf<<26)
-#define DISPPLANE_8BPP (0x2<<26)
-#define DISPPLANE_15_16BPP (0x4<<26)
-#define DISPPLANE_16BPP (0x5<<26)
-#define DISPPLANE_32BPP_NO_ALPHA (0x6<<26)
-#define DISPPLANE_32BPP (0x7<<26)
-#define DISPPLANE_STEREO_ENABLE (1<<25)
-#define DISPPLANE_STEREO_DISABLE 0
-#define DISPPLANE_SEL_PIPE_SHIFT 24
-#define DISPPLANE_SRC_KEY_ENABLE (1<<22)
-#define DISPPLANE_SRC_KEY_DISABLE 0
-#define DISPPLANE_LINE_DOUBLE (1<<20)
-#define DISPPLANE_NO_LINE_DOUBLE 0
-#define DISPPLANE_STEREO_POLARITY_FIRST 0
-#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
-/* plane B only */
-#define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15)
-#define DISPPLANE_ALPHA_TRANS_DISABLE 0
-#define DISPPLANE_SPRITE_ABOVE_DISPLAYA 0
-#define DISPPLANE_SPRITE_ABOVE_OVERLAY 1
-
-#define DSPABASE 0x70184
-#define DSPASTRIDE 0x70188
-
-#define DSPBBASE 0x71184
-#define DSPBSTRIDE 0x71188
-
-#define VGACNTRL 0x71400
-#define VGA_DISABLE (1 << 31)
-#define VGA_ENABLE 0
-#define VGA_PIPE_SELECT_SHIFT 29
-#define VGA_PALETTE_READ_SELECT 23
-#define VGA_PALETTE_A_WRITE_DISABLE (1 << 22)
-#define VGA_PALETTE_B_WRITE_DISABLE (1 << 21)
-#define VGA_LEGACY_PALETTE (1 << 20)
-#define VGA_6BIT_DAC 0
-#define VGA_8BIT_DAC (1 << 20)
-
-#define ADD_ID 0x71408
-#define ADD_ID_MASK 0xff
-
-/* BIOS scratch area registers (830M and 845G). */
-#define SWF0 0x71410
-#define SWF1 0x71414
-#define SWF2 0x71418
-#define SWF3 0x7141c
-#define SWF4 0x71420
-#define SWF5 0x71424
-#define SWF6 0x71428
-
-/* BIOS scratch area registers (852GM, 855GM, 865G). */
-#define SWF00 0x70410
-#define SWF01 0x70414
-#define SWF02 0x70418
-#define SWF03 0x7041c
-#define SWF04 0x70420
-#define SWF05 0x70424
-#define SWF06 0x70428
-
-#define SWF10 SWF0
-#define SWF11 SWF1
-#define SWF12 SWF2
-#define SWF13 SWF3
-#define SWF14 SWF4
-#define SWF15 SWF5
-#define SWF16 SWF6
-
-#define SWF30 0x72414
-#define SWF31 0x72418
-#define SWF32 0x7241c
-
-/* Memory Commands */
-#define MI_NOOP (0x00 << 23)
-#define MI_NOOP_WRITE_ID (1 << 22)
-#define MI_NOOP_ID_MASK ((1 << 22) - 1)
-
-#define MI_FLUSH (0x04 << 23)
-#define MI_WRITE_DIRTY_STATE (1 << 4)
-#define MI_END_SCENE (1 << 3)
-#define MI_INHIBIT_RENDER_CACHE_FLUSH (1 << 2)
-#define MI_INVALIDATE_MAP_CACHE (1 << 0)
-
-#define MI_STORE_DWORD_IMM ((0x20 << 23) | 1)
-
-/* 2D Commands */
-#define COLOR_BLT_CMD ((2 << 29) | (0x40 << 22) | 3)
-#define XY_COLOR_BLT_CMD ((2 << 29) | (0x50 << 22) | 4)
-#define XY_SETUP_CLIP_BLT_CMD ((2 << 29) | (0x03 << 22) | 1)
-#define XY_SRC_COPY_BLT_CMD ((2 << 29) | (0x53 << 22) | 6)
-#define SRC_COPY_BLT_CMD ((2 << 29) | (0x43 << 22) | 4)
-#define XY_MONO_PAT_BLT_CMD ((2 << 29) | (0x52 << 22) | 7)
-#define XY_MONO_SRC_BLT_CMD ((2 << 29) | (0x54 << 22) | 6)
-#define XY_MONO_SRC_IMM_BLT_CMD ((2 << 29) | (0x71 << 22) | 5)
-#define TXT_IMM_BLT_CMD ((2 << 29) | (0x30 << 22) | 2)
-#define SETUP_BLT_CMD ((2 << 29) | (0x00 << 22) | 6)
-
-#define DW_LENGTH_MASK 0xff
-
-#define WRITE_ALPHA (1 << 21)
-#define WRITE_RGB (1 << 20)
-#define VERT_SEED (3 << 8)
-#define HORIZ_SEED (3 << 12)
-
-#define COLOR_DEPTH_8 (0 << 24)
-#define COLOR_DEPTH_16 (1 << 24)
-#define COLOR_DEPTH_32 (3 << 24)
-
-#define SRC_ROP_GXCOPY 0xcc
-#define SRC_ROP_GXXOR 0x66
-
-#define PAT_ROP_GXCOPY 0xf0
-#define PAT_ROP_GXXOR 0x5a
-
-#define PITCH_SHIFT 0
-#define ROP_SHIFT 16
-#define WIDTH_SHIFT 0
-#define HEIGHT_SHIFT 16
-
-/* in bytes */
-#define MAX_MONO_IMM_SIZE 128
-
-
-/*** Macros ***/
-
-/* I/O macros */
-#define INREG8(addr) readb((u8 __iomem *)(dinfo->mmio_base + (addr)))
-#define INREG16(addr) readw((u16 __iomem *)(dinfo->mmio_base + (addr)))
-#define INREG(addr) readl((u32 __iomem *)(dinfo->mmio_base + (addr)))
-#define OUTREG8(addr, val) writeb((val),(u8 __iomem *)(dinfo->mmio_base + \
- (addr)))
-#define OUTREG16(addr, val) writew((val),(u16 __iomem *)(dinfo->mmio_base + \
- (addr)))
-#define OUTREG(addr, val) writel((val),(u32 __iomem *)(dinfo->mmio_base + \
- (addr)))
-
-/* Ring buffer macros */
-#define OUT_RING(n) do { \
- writel((n), (u32 __iomem *)(dinfo->ring.virtual + dinfo->ring_tail));\
- dinfo->ring_tail += 4; \
- dinfo->ring_tail &= dinfo->ring_tail_mask; \
-} while (0)
-
-#define START_RING(n) do { \
- if (dinfo->ring_space < (n) * 4) \
- wait_ring(dinfo,(n) * 4); \
- dinfo->ring_space -= (n) * 4; \
-} while (0)
-
-#define ADVANCE_RING() do { \
- OUTREG(PRI_RING_TAIL, dinfo->ring_tail); \
-} while (0)
-
-#define DO_RING_IDLE() do { \
- u32 head, tail; \
- do { \
- head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK; \
- tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK; \
- udelay(10); \
- } while (head != tail); \
-} while (0)
-
-
-/* function protoypes */
-extern int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo);
-extern int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
- int *stolen_size);
-extern int intelfbhw_check_non_crt(struct intelfb_info *dinfo);
-extern const char *intelfbhw_dvo_to_string(int dvo);
-extern int intelfbhw_validate_mode(struct intelfb_info *dinfo,
- struct fb_var_screeninfo *var);
-extern int intelfbhw_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info);
-extern void intelfbhw_do_blank(int blank, struct fb_info *info);
-extern void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
- unsigned red, unsigned green, unsigned blue,
- unsigned transp);
-extern int intelfbhw_read_hw_state(struct intelfb_info *dinfo,
- struct intelfb_hwstate *hw, int flag);
-extern void intelfbhw_print_hw_state(struct intelfb_info *dinfo,
- struct intelfb_hwstate *hw);
-extern int intelfbhw_mode_to_hw(struct intelfb_info *dinfo,
- struct intelfb_hwstate *hw,
- struct fb_var_screeninfo *var);
-extern int intelfbhw_program_mode(struct intelfb_info *dinfo,
- const struct intelfb_hwstate *hw, int blank);
-extern void intelfbhw_do_sync(struct intelfb_info *dinfo);
-extern void intelfbhw_2d_stop(struct intelfb_info *dinfo);
-extern void intelfbhw_2d_start(struct intelfb_info *dinfo);
-extern void intelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y,
- u32 w, u32 h, u32 color, u32 pitch, u32 bpp,
- u32 rop);
-extern void intelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury,
- u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch,
- u32 bpp);
-extern int intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg,
- u32 w, u32 h, const u8* cdat, u32 x, u32 y,
- u32 pitch, u32 bpp);
-extern void intelfbhw_cursor_init(struct intelfb_info *dinfo);
-extern void intelfbhw_cursor_hide(struct intelfb_info *dinfo);
-extern void intelfbhw_cursor_show(struct intelfb_info *dinfo);
-extern void intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y);
-extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg,
- u32 fg);
-extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
- int height, u8 *data);
-extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo);
-extern int intelfbhw_enable_irq(struct intelfb_info *dinfo);
-extern void intelfbhw_disable_irq(struct intelfb_info *dinfo);
-extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe);
-extern int intelfbhw_active_pipe(const struct intelfb_hwstate *hw);
-
-#endif /* _INTELFBHW_H */
diff --git a/drivers/video/fbdev/mmp/hw/mmp_spi.c b/drivers/video/fbdev/mmp/hw/mmp_spi.c
index 16401eb95c6c..0f8f0312a7c4 100644
--- a/drivers/video/fbdev/mmp/hw/mmp_spi.c
+++ b/drivers/video/fbdev/mmp/hw/mmp_spi.c
@@ -91,7 +91,7 @@ static int lcd_spi_setup(struct spi_device *spi)
writel(tmp, reg_base + LCD_SPU_SPI_CTRL);
/*
- * After set mode it need a time to pull up the spi singals,
+ * After set mode it needs some time to pull up the spi signals,
* or it would cause the wrong waveform when send spi command,
* especially on pxa910h
*/
diff --git a/drivers/video/fbdev/sis/sis_main.c b/drivers/video/fbdev/sis/sis_main.c
index 6ad47b6b6004..803ccb6aa479 100644
--- a/drivers/video/fbdev/sis/sis_main.c
+++ b/drivers/video/fbdev/sis/sis_main.c
@@ -27,7 +27,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/screen_info.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/selection.h>
@@ -257,36 +256,6 @@ static void sisfb_search_mode(char *name, bool quiet)
printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
}
-#ifndef MODULE
-static void sisfb_get_vga_mode_from_kernel(void)
-{
-#ifdef CONFIG_X86
- char mymode[32];
- int mydepth = screen_info.lfb_depth;
-
- if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
-
- if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
- (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
- (mydepth >= 8) && (mydepth <= 32) ) {
-
- if(mydepth == 24) mydepth = 32;
-
- sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
- screen_info.lfb_height,
- mydepth);
-
- printk(KERN_DEBUG
- "sisfb: Using vga mode %s pre-set by kernel as default\n",
- mymode);
-
- sisfb_search_mode(mymode, true);
- }
-#endif
- return;
-}
-#endif
-
static void __init
sisfb_search_crt2type(const char *name)
{
@@ -5901,12 +5870,6 @@ static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ivideo->subsysvendor = pdev->subsystem_vendor;
ivideo->subsysdevice = pdev->subsystem_device;
-#ifndef MODULE
- if(sisfb_mode_idx == -1) {
- sisfb_get_vga_mode_from_kernel();
- }
-#endif
-
ivideo->chip = chipinfo->chip;
ivideo->chip_real_id = chipinfo->chip;
ivideo->sisvga_engine = chipinfo->vgaengine;
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index 5ae48e36fccb..1a4f90ea7d5a 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -347,7 +347,7 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
pwm_init_state(par->pwm, &pwmstate);
pwm_set_relative_duty_cycle(&pwmstate, 50, 100);
- pwm_apply_state(par->pwm, &pwmstate);
+ pwm_apply_might_sleep(par->pwm, &pwmstate);
/* Enable the PWM */
pwm_enable(par->pwm);
diff --git a/drivers/video/fbdev/stifb.c b/drivers/video/fbdev/stifb.c
index 548d992f8cb1..2de0e675fd15 100644
--- a/drivers/video/fbdev/stifb.c
+++ b/drivers/video/fbdev/stifb.c
@@ -103,7 +103,7 @@ typedef struct {
} ngle_rom_t;
struct stifb_info {
- struct fb_info info;
+ struct fb_info *info;
unsigned int id;
ngle_rom_t ngle_rom;
struct sti_struct *sti;
@@ -153,15 +153,15 @@ static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
#define REG_44 0x210030
#define REG_45 0x210034
-#define READ_BYTE(fb,reg) gsc_readb((fb)->info.fix.mmio_start + (reg))
-#define READ_WORD(fb,reg) gsc_readl((fb)->info.fix.mmio_start + (reg))
+#define READ_BYTE(fb, reg) gsc_readb((fb)->info->fix.mmio_start + (reg))
+#define READ_WORD(fb, reg) gsc_readl((fb)->info->fix.mmio_start + (reg))
#ifndef DEBUG_STIFB_REGS
# define DEBUG_OFF()
# define DEBUG_ON()
-# define WRITE_BYTE(value,fb,reg) gsc_writeb((value),(fb)->info.fix.mmio_start + (reg))
-# define WRITE_WORD(value,fb,reg) gsc_writel((value),(fb)->info.fix.mmio_start + (reg))
+# define WRITE_BYTE(value, fb, reg) gsc_writeb((value), (fb)->info->fix.mmio_start + (reg))
+# define WRITE_WORD(value, fb, reg) gsc_writel((value), (fb)->info->fix.mmio_start + (reg))
#else
static int debug_on = 1;
# define DEBUG_OFF() debug_on=0
@@ -169,11 +169,11 @@ static int __initdata stifb_bpp_pref[MAX_STI_ROMS];
# define WRITE_BYTE(value,fb,reg) do { if (debug_on) \
printk(KERN_DEBUG "%30s: WRITE_BYTE(0x%06x) = 0x%02x (old=0x%02x)\n", \
__func__, reg, value, READ_BYTE(fb,reg)); \
- gsc_writeb((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
+ gsc_writeb((value), (fb)->info->fix.mmio_start + (reg)); } while (0)
# define WRITE_WORD(value,fb,reg) do { if (debug_on) \
printk(KERN_DEBUG "%30s: WRITE_WORD(0x%06x) = 0x%08x (old=0x%08x)\n", \
__func__, reg, value, READ_WORD(fb,reg)); \
- gsc_writel((value),(fb)->info.fix.mmio_start + (reg)); } while (0)
+ gsc_writel((value), (fb)->info->fix.mmio_start + (reg)); } while (0)
#endif /* DEBUG_STIFB_REGS */
@@ -210,13 +210,13 @@ SETUP_FB(struct stifb_info *fb)
reg10_value = 0x13601000;
break;
case S9000_ID_A1439A:
- if (fb->info.var.bits_per_pixel == 32)
+ if (fb->info->var.bits_per_pixel == 32)
reg10_value = 0xBBA0A000;
else
reg10_value = 0x13601000;
break;
case S9000_ID_HCRX:
- if (fb->info.var.bits_per_pixel == 32)
+ if (fb->info->var.bits_per_pixel == 32)
reg10_value = 0xBBA0A000;
else
reg10_value = 0x13602000;
@@ -254,7 +254,7 @@ static void
FINISH_IMAGE_COLORMAP_ACCESS(struct stifb_info *fb)
{
WRITE_WORD(0x400, fb, REG_2);
- if (fb->info.var.bits_per_pixel == 32) {
+ if (fb->info->var.bits_per_pixel == 32) {
WRITE_WORD(0x83000100, fb, REG_1);
} else {
if (fb->id == S9000_ID_ARTIST || fb->id == CRT_ID_VISUALIZE_EG)
@@ -503,7 +503,7 @@ static void
ngleSetupAttrPlanes(struct stifb_info *fb, int BufferNumber)
{
SETUP_ATTR_ACCESS(fb, BufferNumber);
- SET_ATTR_SIZE(fb, fb->info.var.xres, fb->info.var.yres);
+ SET_ATTR_SIZE(fb, fb->info->var.xres, fb->info->var.yres);
FINISH_ATTR_ACCESS(fb);
SETUP_FB(fb);
}
@@ -526,9 +526,9 @@ rattlerSetupPlanes(struct stifb_info *fb)
SETUP_FB(fb);
fb->id = saved_id;
- for (y = 0; y < fb->info.var.yres; ++y)
- fb_memset_io(fb->info.screen_base + y * fb->info.fix.line_length,
- 0xff, fb->info.var.xres * fb->info.var.bits_per_pixel/8);
+ for (y = 0; y < fb->info->var.yres; ++y)
+ fb_memset_io(fb->info->screen_base + y * fb->info->fix.line_length,
+ 0xff, fb->info->var.xres * fb->info->var.bits_per_pixel/8);
CRX24_SET_OVLY_MASK(fb);
SETUP_FB(fb);
@@ -607,7 +607,7 @@ setHyperLutBltCtl(struct stifb_info *fb, int offsetWithinLut, int length)
lutBltCtl.fields.lutType = HYPER_CMAP_TYPE;
/* Expect lutIndex to be 0 or 1 for image cmaps, 2 or 3 for overlay cmaps */
- if (fb->info.var.bits_per_pixel == 8)
+ if (fb->info->var.bits_per_pixel == 8)
lutBltCtl.fields.lutOffset = 2 * 256;
else
lutBltCtl.fields.lutOffset = 0 * 256;
@@ -688,7 +688,7 @@ ngleResetAttrPlanes(struct stifb_info *fb, unsigned int ctlPlaneReg)
DataDynamic, MaskOtc,
BGx(0), FGx(0)));
packed_dst = 0;
- packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
+ packed_len = (fb->info->var.xres << 16) | fb->info->var.yres;
GET_FIFO_SLOTS(fb, nFreeFifoSlots, 2);
NGLE_SET_DSTXY(fb, packed_dst);
SET_LENXY_START_RECFILL(fb, packed_len);
@@ -738,7 +738,7 @@ ngleClearOverlayPlanes(struct stifb_info *fb, int mask, int data)
NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, mask);
packed_dst = 0;
- packed_len = (fb->info.var.xres << 16) | fb->info.var.yres;
+ packed_len = (fb->info->var.xres << 16) | fb->info->var.yres;
NGLE_SET_DSTXY(fb, packed_dst);
/* Write zeroes to overlay planes */
@@ -760,7 +760,7 @@ hyperResetPlanes(struct stifb_info *fb, int enable)
NGLE_LOCK(fb);
if (IS_24_DEVICE(fb))
- if (fb->info.var.bits_per_pixel == 32)
+ if (fb->info->var.bits_per_pixel == 32)
controlPlaneReg = 0x04000F00;
else
controlPlaneReg = 0x00000F00; /* 0x00000800 should be enough, but lets clear all 4 bits */
@@ -890,7 +890,7 @@ SETUP_HCRX(struct stifb_info *fb)
GET_FIFO_SLOTS(fb, nFreeFifoSlots, 7);
if (IS_24_DEVICE(fb)) {
- hyperbowl = (fb->info.var.bits_per_pixel == 32) ?
+ hyperbowl = (fb->info->var.bits_per_pixel == 32) ?
HYPERBOWL_MODE01_8_24_LUT0_TRANSPARENT_LUT1_OPAQUE :
HYPERBOWL_MODE01_8_24_LUT0_OPAQUE_LUT1_OPAQUE;
@@ -924,21 +924,21 @@ SETUP_HCRX(struct stifb_info *fb)
static int
stifb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
- struct stifb_info *fb = container_of(info, struct stifb_info, info);
+ struct stifb_info *fb = info->par;
- if (var->xres != fb->info.var.xres ||
- var->yres != fb->info.var.yres ||
- var->bits_per_pixel != fb->info.var.bits_per_pixel)
+ if (var->xres != fb->info->var.xres ||
+ var->yres != fb->info->var.yres ||
+ var->bits_per_pixel != fb->info->var.bits_per_pixel)
return -EINVAL;
var->xres_virtual = var->xres;
var->yres_virtual = var->yres;
var->xoffset = 0;
var->yoffset = 0;
- var->grayscale = fb->info.var.grayscale;
- var->red.length = fb->info.var.red.length;
- var->green.length = fb->info.var.green.length;
- var->blue.length = fb->info.var.blue.length;
+ var->grayscale = fb->info->var.grayscale;
+ var->red.length = fb->info->var.red.length;
+ var->green.length = fb->info->var.green.length;
+ var->blue.length = fb->info->var.blue.length;
return 0;
}
@@ -947,7 +947,7 @@ static int
stifb_setcolreg(u_int regno, u_int red, u_int green,
u_int blue, u_int transp, struct fb_info *info)
{
- struct stifb_info *fb = container_of(info, struct stifb_info, info);
+ struct stifb_info *fb = info->par;
u32 color;
if (regno >= NR_PALETTE)
@@ -961,7 +961,7 @@ stifb_setcolreg(u_int regno, u_int red, u_int green,
START_IMAGE_COLORMAP_ACCESS(fb);
- if (unlikely(fb->info.var.grayscale)) {
+ if (unlikely(fb->info->var.grayscale)) {
/* gray = 0.30*R + 0.59*G + 0.11*B */
color = ((red * 77) +
(green * 151) +
@@ -972,10 +972,10 @@ stifb_setcolreg(u_int regno, u_int red, u_int green,
(blue));
}
- if (fb->info.fix.visual == FB_VISUAL_DIRECTCOLOR) {
- struct fb_var_screeninfo *var = &fb->info.var;
+ if (fb->info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ struct fb_var_screeninfo *var = &fb->info->var;
if (regno < 16)
- ((u32 *)fb->info.pseudo_palette)[regno] =
+ ((u32 *)fb->info->pseudo_palette)[regno] =
regno << var->red.offset |
regno << var->green.offset |
regno << var->blue.offset;
@@ -1007,7 +1007,7 @@ stifb_setcolreg(u_int regno, u_int red, u_int green,
static int
stifb_blank(int blank_mode, struct fb_info *info)
{
- struct stifb_info *fb = container_of(info, struct stifb_info, info);
+ struct stifb_info *fb = info->par;
int enable = (blank_mode == 0) ? ENABLE : DISABLE;
switch (fb->id) {
@@ -1036,12 +1036,12 @@ stifb_blank(int blank_mode, struct fb_info *info)
static void
stifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
- struct stifb_info *fb = container_of(info, struct stifb_info, info);
+ struct stifb_info *fb = info->par;
SETUP_COPYAREA(fb);
SETUP_HW(fb);
- if (fb->info.var.bits_per_pixel == 32) {
+ if (fb->info->var.bits_per_pixel == 32) {
WRITE_WORD(0xBBA0A000, fb, REG_10);
NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
@@ -1075,15 +1075,15 @@ stifb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
static void
stifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
- struct stifb_info *fb = container_of(info, struct stifb_info, info);
+ struct stifb_info *fb = info->par;
if (rect->rop != ROP_COPY ||
- (fb->id == S9000_ID_HCRX && fb->info.var.bits_per_pixel == 32))
+ (fb->id == S9000_ID_HCRX && fb->info->var.bits_per_pixel == 32))
return cfb_fillrect(info, rect);
SETUP_HW(fb);
- if (fb->info.var.bits_per_pixel == 32) {
+ if (fb->info->var.bits_per_pixel == 32) {
WRITE_WORD(0xBBA0A000, fb, REG_10);
NGLE_REALLY_SET_IMAGE_PLANEMASK(fb, 0xffffffff);
@@ -1141,7 +1141,7 @@ stifb_init_display(struct stifb_info *fb)
switch (id) {
case S9000_ID_A1659A:
case S9000_ID_A1439A:
- if (fb->info.var.bits_per_pixel == 32)
+ if (fb->info->var.bits_per_pixel == 32)
ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
else {
ngleSetupAttrPlanes(fb, BUFF1_CMAP0);
@@ -1151,7 +1151,7 @@ stifb_init_display(struct stifb_info *fb)
break;
case S9000_ID_ARTIST:
case CRT_ID_VISUALIZE_EG:
- if (fb->info.var.bits_per_pixel == 32)
+ if (fb->info->var.bits_per_pixel == 32)
ngleSetupAttrPlanes(fb, BUFF1_CMAP3);
else {
ngleSetupAttrPlanes(fb, ARTIST_CMAP0);
@@ -1193,11 +1193,11 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
char *dev_name;
int bpp, xres, yres;
- fb = kzalloc(sizeof(*fb), GFP_ATOMIC);
- if (!fb)
+ info = framebuffer_alloc(sizeof(*fb), sti->dev);
+ if (!info)
return -ENOMEM;
-
- info = &fb->info;
+ fb = info->par;
+ fb->info = info;
/* set struct to a known state */
fix = &info->fix;
@@ -1389,11 +1389,10 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
}
/* save for primary gfx device detection & unregister_framebuffer() */
- sti->info = info;
- if (register_framebuffer(&fb->info) < 0)
+ if (register_framebuffer(fb->info) < 0)
goto out_err4;
- fb_info(&fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
+ fb_info(fb->info, "%s %dx%d-%d frame buffer device, %s, id: %04x, mmio: 0x%04lx\n",
fix->id,
var->xres,
var->yres,
@@ -1402,6 +1401,8 @@ static int __init stifb_init_fb(struct sti_struct *sti, int bpp_pref)
fb->id,
fix->mmio_start);
+ dev_set_drvdata(sti->dev, info);
+
return 0;
@@ -1414,8 +1415,7 @@ out_err2:
out_err1:
iounmap(info->screen_base);
out_err0:
- kfree(fb);
- sti->info = NULL;
+ framebuffer_release(info);
return -ENXIO;
}
@@ -1480,17 +1480,20 @@ stifb_cleanup(void)
sti = sti_get_rom(i);
if (!sti)
break;
- if (sti->info) {
- struct fb_info *info = sti->info;
- unregister_framebuffer(sti->info);
+ if (sti->dev) {
+ struct fb_info *info = dev_get_drvdata(sti->dev);
+
+ if (!info)
+ continue;
+ unregister_framebuffer(info);
release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
release_mem_region(info->fix.smem_start, info->fix.smem_len);
if (info->screen_base)
iounmap(info->screen_base);
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
+ dev_set_drvdata(sti->dev, NULL);
}
- sti->info = NULL;
}
}
diff --git a/drivers/video/fbdev/vermilion/Makefile b/drivers/video/fbdev/vermilion/Makefile
deleted file mode 100644
index 22e9e4635a00..000000000000
--- a/drivers/video/fbdev/vermilion/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_FB_LE80578) += vmlfb.o
-obj-$(CONFIG_FB_CARILLO_RANCH) += crvml.o
-
-vmlfb-objs := vermilion.o
-crvml-objs := cr_pll.o
diff --git a/drivers/video/fbdev/vermilion/cr_pll.c b/drivers/video/fbdev/vermilion/cr_pll.c
deleted file mode 100644
index 79d42b23d850..000000000000
--- a/drivers/video/fbdev/vermilion/cr_pll.c
+++ /dev/null
@@ -1,195 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) Intel Corp. 2007.
- * All Rights Reserved.
- *
- * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
- * develop this driver.
- *
- * This file is part of the Carillo Ranch video subsystem driver.
- *
- * Authors:
- * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
- * Alan Hourihane <alanh-at-tungstengraphics-dot-com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/errno.h>
-#include <linux/fb.h>
-#include "vermilion.h"
-
-/* The PLL Clock register sits on Host bridge */
-#define CRVML_DEVICE_MCH 0x5001
-#define CRVML_REG_MCHBAR 0x44
-#define CRVML_REG_MCHEN 0x54
-#define CRVML_MCHEN_BIT (1 << 28)
-#define CRVML_MCHMAP_SIZE 4096
-#define CRVML_REG_CLOCK 0xc3c
-#define CRVML_CLOCK_SHIFT 8
-#define CRVML_CLOCK_MASK 0x00000f00
-
-static struct pci_dev *mch_dev;
-static u32 mch_bar;
-static void __iomem *mch_regs_base;
-static u32 saved_clock;
-
-static const unsigned crvml_clocks[] = {
- 6750,
- 13500,
- 27000,
- 29700,
- 37125,
- 54000,
- 59400,
- 74250,
- 120000
- /*
- * There are more clocks, but they are disabled on the CR board.
- */
-};
-
-static const u32 crvml_clock_bits[] = {
- 0x0a,
- 0x09,
- 0x08,
- 0x07,
- 0x06,
- 0x05,
- 0x04,
- 0x03,
- 0x0b
-};
-
-static const unsigned crvml_num_clocks = ARRAY_SIZE(crvml_clocks);
-
-static int crvml_sys_restore(struct vml_sys *sys)
-{
- void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
-
- iowrite32(saved_clock, clock_reg);
- ioread32(clock_reg);
-
- return 0;
-}
-
-static int crvml_sys_save(struct vml_sys *sys)
-{
- void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
-
- saved_clock = ioread32(clock_reg);
-
- return 0;
-}
-
-static int crvml_nearest_index(const struct vml_sys *sys, int clock)
-{
- int i;
- int cur_index = 0;
- int cur_diff;
- int diff;
-
- cur_diff = clock - crvml_clocks[0];
- cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
- for (i = 1; i < crvml_num_clocks; ++i) {
- diff = clock - crvml_clocks[i];
- diff = (diff < 0) ? -diff : diff;
- if (diff < cur_diff) {
- cur_index = i;
- cur_diff = diff;
- }
- }
- return cur_index;
-}
-
-static int crvml_nearest_clock(const struct vml_sys *sys, int clock)
-{
- return crvml_clocks[crvml_nearest_index(sys, clock)];
-}
-
-static int crvml_set_clock(struct vml_sys *sys, int clock)
-{
- void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
- int index;
- u32 clock_val;
-
- index = crvml_nearest_index(sys, clock);
-
- if (crvml_clocks[index] != clock)
- return -EINVAL;
-
- clock_val = ioread32(clock_reg) & ~CRVML_CLOCK_MASK;
- clock_val = crvml_clock_bits[index] << CRVML_CLOCK_SHIFT;
- iowrite32(clock_val, clock_reg);
- ioread32(clock_reg);
-
- return 0;
-}
-
-static struct vml_sys cr_pll_ops = {
- .name = "Carillo Ranch",
- .save = crvml_sys_save,
- .restore = crvml_sys_restore,
- .set_clock = crvml_set_clock,
- .nearest_clock = crvml_nearest_clock,
-};
-
-static int __init cr_pll_init(void)
-{
- int err;
- u32 dev_en;
-
- mch_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
- CRVML_DEVICE_MCH, NULL);
- if (!mch_dev) {
- printk(KERN_ERR
- "Could not find Carillo Ranch MCH device.\n");
- return -ENODEV;
- }
-
- pci_read_config_dword(mch_dev, CRVML_REG_MCHEN, &dev_en);
- if (!(dev_en & CRVML_MCHEN_BIT)) {
- printk(KERN_ERR
- "Carillo Ranch MCH device was not enabled.\n");
- pci_dev_put(mch_dev);
- return -ENODEV;
- }
-
- pci_read_config_dword(mch_dev, CRVML_REG_MCHBAR,
- &mch_bar);
- mch_regs_base =
- ioremap(mch_bar, CRVML_MCHMAP_SIZE);
- if (!mch_regs_base) {
- printk(KERN_ERR
- "Carillo Ranch MCH device was not enabled.\n");
- pci_dev_put(mch_dev);
- return -ENODEV;
- }
-
- err = vmlfb_register_subsys(&cr_pll_ops);
- if (err) {
- printk(KERN_ERR
- "Carillo Ranch failed to initialize vml_sys.\n");
- iounmap(mch_regs_base);
- pci_dev_put(mch_dev);
- return err;
- }
-
- return 0;
-}
-
-static void __exit cr_pll_exit(void)
-{
- vmlfb_unregister_subsys(&cr_pll_ops);
-
- iounmap(mch_regs_base);
- pci_dev_put(mch_dev);
-}
-
-module_init(cr_pll_init);
-module_exit(cr_pll_exit);
-
-MODULE_AUTHOR("Tungsten Graphics Inc.");
-MODULE_DESCRIPTION("Carillo Ranch PLL Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/vermilion/vermilion.c b/drivers/video/fbdev/vermilion/vermilion.c
deleted file mode 100644
index 974da83b37dc..000000000000
--- a/drivers/video/fbdev/vermilion/vermilion.c
+++ /dev/null
@@ -1,1175 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) Intel Corp. 2007.
- * All Rights Reserved.
- *
- * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
- * develop this driver.
- *
- * This file is part of the Vermilion Range fb driver.
- *
- * Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
- * Michel Dänzer <michel-at-tungstengraphics-dot-com>
- * Alan Hourihane <alanh-at-tungstengraphics-dot-com>
- */
-
-#include <linux/aperture.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/fb.h>
-#include <linux/pci.h>
-#include <asm/set_memory.h>
-#include <asm/tlbflush.h>
-#include <linux/mmzone.h>
-
-/* #define VERMILION_DEBUG */
-
-#include "vermilion.h"
-
-#define MODULE_NAME "vmlfb"
-
-#define VML_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16)
-
-static struct mutex vml_mutex;
-static struct list_head global_no_mode;
-static struct list_head global_has_mode;
-static struct fb_ops vmlfb_ops;
-static struct vml_sys *subsys = NULL;
-static char *vml_default_mode = "1024x768@60";
-static const struct fb_videomode defaultmode = {
- NULL, 60, 1024, 768, 12896, 144, 24, 29, 3, 136, 6,
- 0, FB_VMODE_NONINTERLACED
-};
-
-static u32 vml_mem_requested = (10 * 1024 * 1024);
-static u32 vml_mem_contig = (4 * 1024 * 1024);
-static u32 vml_mem_min = (4 * 1024 * 1024);
-
-static u32 vml_clocks[] = {
- 6750,
- 13500,
- 27000,
- 29700,
- 37125,
- 54000,
- 59400,
- 74250,
- 120000,
- 148500
-};
-
-static u32 vml_num_clocks = ARRAY_SIZE(vml_clocks);
-
-/*
- * Allocate a contiguous vram area and make its linear kernel map
- * uncached.
- */
-
-static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order,
- unsigned min_order)
-{
- gfp_t flags;
- unsigned long i;
-
- max_order++;
- do {
- /*
- * Really try hard to get the needed memory.
- * We need memory below the first 32MB, so we
- * add the __GFP_DMA flag that guarantees that we are
- * below the first 16MB.
- */
-
- flags = __GFP_DMA | __GFP_HIGH | __GFP_KSWAPD_RECLAIM;
- va->logical =
- __get_free_pages(flags, --max_order);
- } while (va->logical == 0 && max_order > min_order);
-
- if (!va->logical)
- return -ENOMEM;
-
- va->phys = virt_to_phys((void *)va->logical);
- va->size = PAGE_SIZE << max_order;
- va->order = max_order;
-
- /*
- * It seems like __get_free_pages only ups the usage count
- * of the first page. This doesn't work with fault mapping, so
- * up the usage count once more (XXX: should use split_page or
- * compound page).
- */
-
- memset((void *)va->logical, 0x00, va->size);
- for (i = va->logical; i < va->logical + va->size; i += PAGE_SIZE) {
- get_page(virt_to_page(i));
- }
-
- /*
- * Change caching policy of the linear kernel map to avoid
- * mapping type conflicts with user-space mappings.
- */
- set_pages_uc(virt_to_page(va->logical), va->size >> PAGE_SHIFT);
-
- printk(KERN_DEBUG MODULE_NAME
- ": Allocated %ld bytes vram area at 0x%08lx\n",
- va->size, va->phys);
-
- return 0;
-}
-
-/*
- * Free a contiguous vram area and reset its linear kernel map
- * mapping type.
- */
-
-static void vmlfb_free_vram_area(struct vram_area *va)
-{
- unsigned long j;
-
- if (va->logical) {
-
- /*
- * Reset the linear kernel map caching policy.
- */
-
- set_pages_wb(virt_to_page(va->logical),
- va->size >> PAGE_SHIFT);
-
- /*
- * Decrease the usage count on the pages we've used
- * to compensate for upping when allocating.
- */
-
- for (j = va->logical; j < va->logical + va->size;
- j += PAGE_SIZE) {
- (void)put_page_testzero(virt_to_page(j));
- }
-
- printk(KERN_DEBUG MODULE_NAME
- ": Freeing %ld bytes vram area at 0x%08lx\n",
- va->size, va->phys);
- free_pages(va->logical, va->order);
-
- va->logical = 0;
- }
-}
-
-/*
- * Free allocated vram.
- */
-
-static void vmlfb_free_vram(struct vml_info *vinfo)
-{
- int i;
-
- for (i = 0; i < vinfo->num_areas; ++i) {
- vmlfb_free_vram_area(&vinfo->vram[i]);
- }
- vinfo->num_areas = 0;
-}
-
-/*
- * Allocate vram. Currently we try to allocate contiguous areas from the
- * __GFP_DMA zone and puzzle them together. A better approach would be to
- * allocate one contiguous area for scanout and use one-page allocations for
- * offscreen areas. This requires user-space and GPU virtual mappings.
- */
-
-static int vmlfb_alloc_vram(struct vml_info *vinfo,
- size_t requested,
- size_t min_total, size_t min_contig)
-{
- int i, j;
- int order;
- int contiguous;
- int err;
- struct vram_area *va;
- struct vram_area *va2;
-
- vinfo->num_areas = 0;
- for (i = 0; i < VML_VRAM_AREAS; ++i) {
- va = &vinfo->vram[i];
- order = 0;
-
- while (requested > (PAGE_SIZE << order) && order <= MAX_PAGE_ORDER)
- order++;
-
- err = vmlfb_alloc_vram_area(va, order, 0);
-
- if (err)
- break;
-
- if (i == 0) {
- vinfo->vram_start = va->phys;
- vinfo->vram_logical = (void __iomem *) va->logical;
- vinfo->vram_contig_size = va->size;
- vinfo->num_areas = 1;
- } else {
- contiguous = 0;
-
- for (j = 0; j < i; ++j) {
- va2 = &vinfo->vram[j];
- if (va->phys + va->size == va2->phys ||
- va2->phys + va2->size == va->phys) {
- contiguous = 1;
- break;
- }
- }
-
- if (contiguous) {
- vinfo->num_areas++;
- if (va->phys < vinfo->vram_start) {
- vinfo->vram_start = va->phys;
- vinfo->vram_logical =
- (void __iomem *)va->logical;
- }
- vinfo->vram_contig_size += va->size;
- } else {
- vmlfb_free_vram_area(va);
- break;
- }
- }
-
- if (requested < va->size)
- break;
- else
- requested -= va->size;
- }
-
- if (vinfo->vram_contig_size > min_total &&
- vinfo->vram_contig_size > min_contig) {
-
- printk(KERN_DEBUG MODULE_NAME
- ": Contiguous vram: %ld bytes at physical 0x%08lx.\n",
- (unsigned long)vinfo->vram_contig_size,
- (unsigned long)vinfo->vram_start);
-
- return 0;
- }
-
- printk(KERN_ERR MODULE_NAME
- ": Could not allocate requested minimal amount of vram.\n");
-
- vmlfb_free_vram(vinfo);
-
- return -ENOMEM;
-}
-
-/*
- * Find the GPU to use with our display controller.
- */
-
-static int vmlfb_get_gpu(struct vml_par *par)
-{
- mutex_lock(&vml_mutex);
-
- par->gpu = pci_get_device(PCI_VENDOR_ID_INTEL, VML_DEVICE_GPU, NULL);
-
- if (!par->gpu) {
- mutex_unlock(&vml_mutex);
- return -ENODEV;
- }
-
- mutex_unlock(&vml_mutex);
-
- if (pci_enable_device(par->gpu) < 0) {
- pci_dev_put(par->gpu);
- return -ENODEV;
- }
-
- return 0;
-}
-
-/*
- * Find a contiguous vram area that contains a given offset from vram start.
- */
-static int vmlfb_vram_offset(struct vml_info *vinfo, unsigned long offset)
-{
- unsigned long aoffset;
- unsigned i;
-
- for (i = 0; i < vinfo->num_areas; ++i) {
- aoffset = offset - (vinfo->vram[i].phys - vinfo->vram_start);
-
- if (aoffset < vinfo->vram[i].size) {
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
-/*
- * Remap the MMIO register spaces of the VDC and the GPU.
- */
-
-static int vmlfb_enable_mmio(struct vml_par *par)
-{
- int err;
-
- par->vdc_mem_base = pci_resource_start(par->vdc, 0);
- par->vdc_mem_size = pci_resource_len(par->vdc, 0);
- if (!request_mem_region(par->vdc_mem_base, par->vdc_mem_size, "vmlfb")) {
- printk(KERN_ERR MODULE_NAME
- ": Could not claim display controller MMIO.\n");
- return -EBUSY;
- }
- par->vdc_mem = ioremap(par->vdc_mem_base, par->vdc_mem_size);
- if (par->vdc_mem == NULL) {
- printk(KERN_ERR MODULE_NAME
- ": Could not map display controller MMIO.\n");
- err = -ENOMEM;
- goto out_err_0;
- }
-
- par->gpu_mem_base = pci_resource_start(par->gpu, 0);
- par->gpu_mem_size = pci_resource_len(par->gpu, 0);
- if (!request_mem_region(par->gpu_mem_base, par->gpu_mem_size, "vmlfb")) {
- printk(KERN_ERR MODULE_NAME ": Could not claim GPU MMIO.\n");
- err = -EBUSY;
- goto out_err_1;
- }
- par->gpu_mem = ioremap(par->gpu_mem_base, par->gpu_mem_size);
- if (par->gpu_mem == NULL) {
- printk(KERN_ERR MODULE_NAME ": Could not map GPU MMIO.\n");
- err = -ENOMEM;
- goto out_err_2;
- }
-
- return 0;
-
-out_err_2:
- release_mem_region(par->gpu_mem_base, par->gpu_mem_size);
-out_err_1:
- iounmap(par->vdc_mem);
-out_err_0:
- release_mem_region(par->vdc_mem_base, par->vdc_mem_size);
- return err;
-}
-
-/*
- * Unmap the VDC and GPU register spaces.
- */
-
-static void vmlfb_disable_mmio(struct vml_par *par)
-{
- iounmap(par->gpu_mem);
- release_mem_region(par->gpu_mem_base, par->gpu_mem_size);
- iounmap(par->vdc_mem);
- release_mem_region(par->vdc_mem_base, par->vdc_mem_size);
-}
-
-/*
- * Release and uninit the VDC and GPU.
- */
-
-static void vmlfb_release_devices(struct vml_par *par)
-{
- if (atomic_dec_and_test(&par->refcount)) {
- pci_disable_device(par->gpu);
- pci_disable_device(par->vdc);
- }
-}
-
-/*
- * Free up allocated resources for a device.
- */
-
-static void vml_pci_remove(struct pci_dev *dev)
-{
- struct fb_info *info;
- struct vml_info *vinfo;
- struct vml_par *par;
-
- info = pci_get_drvdata(dev);
- if (info) {
- vinfo = container_of(info, struct vml_info, info);
- par = vinfo->par;
- mutex_lock(&vml_mutex);
- unregister_framebuffer(info);
- fb_dealloc_cmap(&info->cmap);
- vmlfb_free_vram(vinfo);
- vmlfb_disable_mmio(par);
- vmlfb_release_devices(par);
- kfree(vinfo);
- kfree(par);
- mutex_unlock(&vml_mutex);
- }
-}
-
-static void vmlfb_set_pref_pixel_format(struct fb_var_screeninfo *var)
-{
- switch (var->bits_per_pixel) {
- case 16:
- var->blue.offset = 0;
- var->blue.length = 5;
- var->green.offset = 5;
- var->green.length = 5;
- var->red.offset = 10;
- var->red.length = 5;
- var->transp.offset = 15;
- var->transp.length = 1;
- break;
- case 32:
- var->blue.offset = 0;
- var->blue.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->red.offset = 16;
- var->red.length = 8;
- var->transp.offset = 24;
- var->transp.length = 0;
- break;
- default:
- break;
- }
-
- var->blue.msb_right = var->green.msb_right =
- var->red.msb_right = var->transp.msb_right = 0;
-}
-
-/*
- * Device initialization.
- * We initialize one vml_par struct per device and one vml_info
- * struct per pipe. Currently we have only one pipe.
- */
-
-static int vml_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct vml_info *vinfo;
- struct fb_info *info;
- struct vml_par *par;
- int err;
-
- err = aperture_remove_conflicting_pci_devices(dev, "vmlfb");
- if (err)
- return err;
-
- par = kzalloc(sizeof(*par), GFP_KERNEL);
- if (par == NULL)
- return -ENOMEM;
-
- vinfo = kzalloc(sizeof(*vinfo), GFP_KERNEL);
- if (vinfo == NULL) {
- err = -ENOMEM;
- goto out_err_0;
- }
-
- vinfo->par = par;
- par->vdc = dev;
- atomic_set(&par->refcount, 1);
-
- switch (id->device) {
- case VML_DEVICE_VDC:
- if ((err = vmlfb_get_gpu(par)))
- goto out_err_1;
- pci_set_drvdata(dev, &vinfo->info);
- break;
- default:
- err = -ENODEV;
- goto out_err_1;
- }
-
- info = &vinfo->info;
- info->flags = FBINFO_PARTIAL_PAN_OK;
-
- err = vmlfb_enable_mmio(par);
- if (err)
- goto out_err_2;
-
- err = vmlfb_alloc_vram(vinfo, vml_mem_requested,
- vml_mem_contig, vml_mem_min);
- if (err)
- goto out_err_3;
-
- strcpy(info->fix.id, "Vermilion Range");
- info->fix.mmio_start = 0;
- info->fix.mmio_len = 0;
- info->fix.smem_start = vinfo->vram_start;
- info->fix.smem_len = vinfo->vram_contig_size;
- info->fix.type = FB_TYPE_PACKED_PIXELS;
- info->fix.visual = FB_VISUAL_TRUECOLOR;
- info->fix.ypanstep = 1;
- info->fix.xpanstep = 1;
- info->fix.ywrapstep = 0;
- info->fix.accel = FB_ACCEL_NONE;
- info->screen_base = vinfo->vram_logical;
- info->pseudo_palette = vinfo->pseudo_palette;
- info->par = par;
- info->fbops = &vmlfb_ops;
- info->device = &dev->dev;
-
- INIT_LIST_HEAD(&vinfo->head);
- vinfo->pipe_disabled = 1;
- vinfo->cur_blank_mode = FB_BLANK_UNBLANK;
-
- info->var.grayscale = 0;
- info->var.bits_per_pixel = 16;
- vmlfb_set_pref_pixel_format(&info->var);
-
- if (!fb_find_mode
- (&info->var, info, vml_default_mode, NULL, 0, &defaultmode, 16)) {
- printk(KERN_ERR MODULE_NAME ": Could not find initial mode\n");
- }
-
- if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) {
- err = -ENOMEM;
- goto out_err_4;
- }
-
- err = register_framebuffer(info);
- if (err) {
- printk(KERN_ERR MODULE_NAME ": Register framebuffer error.\n");
- goto out_err_5;
- }
-
- printk("Initialized vmlfb\n");
-
- return 0;
-
-out_err_5:
- fb_dealloc_cmap(&info->cmap);
-out_err_4:
- vmlfb_free_vram(vinfo);
-out_err_3:
- vmlfb_disable_mmio(par);
-out_err_2:
- vmlfb_release_devices(par);
-out_err_1:
- kfree(vinfo);
-out_err_0:
- kfree(par);
- return err;
-}
-
-static int vmlfb_open(struct fb_info *info, int user)
-{
- /*
- * Save registers here?
- */
- return 0;
-}
-
-static int vmlfb_release(struct fb_info *info, int user)
-{
- /*
- * Restore registers here.
- */
-
- return 0;
-}
-
-static int vml_nearest_clock(int clock)
-{
-
- int i;
- int cur_index;
- int cur_diff;
- int diff;
-
- cur_index = 0;
- cur_diff = clock - vml_clocks[0];
- cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
- for (i = 1; i < vml_num_clocks; ++i) {
- diff = clock - vml_clocks[i];
- diff = (diff < 0) ? -diff : diff;
- if (diff < cur_diff) {
- cur_index = i;
- cur_diff = diff;
- }
- }
- return vml_clocks[cur_index];
-}
-
-static int vmlfb_check_var_locked(struct fb_var_screeninfo *var,
- struct vml_info *vinfo)
-{
- u32 pitch;
- u64 mem;
- int nearest_clock;
- int clock;
- int clock_diff;
- struct fb_var_screeninfo v;
-
- v = *var;
- clock = PICOS2KHZ(var->pixclock);
-
- if (subsys && subsys->nearest_clock) {
- nearest_clock = subsys->nearest_clock(subsys, clock);
- } else {
- nearest_clock = vml_nearest_clock(clock);
- }
-
- /*
- * Accept a 20% diff.
- */
-
- clock_diff = nearest_clock - clock;
- clock_diff = (clock_diff < 0) ? -clock_diff : clock_diff;
- if (clock_diff > clock / 5) {
-#if 0
- printk(KERN_DEBUG MODULE_NAME ": Diff failure. %d %d\n",clock_diff,clock);
-#endif
- return -EINVAL;
- }
-
- v.pixclock = KHZ2PICOS(nearest_clock);
-
- if (var->xres > VML_MAX_XRES || var->yres > VML_MAX_YRES) {
- printk(KERN_DEBUG MODULE_NAME ": Resolution failure.\n");
- return -EINVAL;
- }
- if (var->xres_virtual > VML_MAX_XRES_VIRTUAL) {
- printk(KERN_DEBUG MODULE_NAME
- ": Virtual resolution failure.\n");
- return -EINVAL;
- }
- switch (v.bits_per_pixel) {
- case 0 ... 16:
- v.bits_per_pixel = 16;
- break;
- case 17 ... 32:
- v.bits_per_pixel = 32;
- break;
- default:
- printk(KERN_DEBUG MODULE_NAME ": Invalid bpp: %d.\n",
- var->bits_per_pixel);
- return -EINVAL;
- }
-
- pitch = ALIGN((var->xres * var->bits_per_pixel) >> 3, 0x40);
- mem = (u64)pitch * var->yres_virtual;
- if (mem > vinfo->vram_contig_size) {
- return -ENOMEM;
- }
-
- switch (v.bits_per_pixel) {
- case 16:
- if (var->blue.offset != 0 ||
- var->blue.length != 5 ||
- var->green.offset != 5 ||
- var->green.length != 5 ||
- var->red.offset != 10 ||
- var->red.length != 5 ||
- var->transp.offset != 15 || var->transp.length != 1) {
- vmlfb_set_pref_pixel_format(&v);
- }
- break;
- case 32:
- if (var->blue.offset != 0 ||
- var->blue.length != 8 ||
- var->green.offset != 8 ||
- var->green.length != 8 ||
- var->red.offset != 16 ||
- var->red.length != 8 ||
- (var->transp.length != 0 && var->transp.length != 8) ||
- (var->transp.length == 8 && var->transp.offset != 24)) {
- vmlfb_set_pref_pixel_format(&v);
- }
- break;
- default:
- return -EINVAL;
- }
-
- *var = v;
-
- return 0;
-}
-
-static int vmlfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
- struct vml_info *vinfo = container_of(info, struct vml_info, info);
- int ret;
-
- mutex_lock(&vml_mutex);
- ret = vmlfb_check_var_locked(var, vinfo);
- mutex_unlock(&vml_mutex);
-
- return ret;
-}
-
-static void vml_wait_vblank(struct vml_info *vinfo)
-{
- /* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */
- mdelay(20);
-}
-
-static void vmlfb_disable_pipe(struct vml_info *vinfo)
-{
- struct vml_par *par = vinfo->par;
-
- /* Disable the MDVO pad */
- VML_WRITE32(par, VML_RCOMPSTAT, 0);
- while (!(VML_READ32(par, VML_RCOMPSTAT) & VML_MDVO_VDC_I_RCOMP)) ;
-
- /* Disable display planes */
- VML_WRITE32(par, VML_DSPCCNTR,
- VML_READ32(par, VML_DSPCCNTR) & ~VML_GFX_ENABLE);
- (void)VML_READ32(par, VML_DSPCCNTR);
- /* Wait for vblank for the disable to take effect */
- vml_wait_vblank(vinfo);
-
- /* Next, disable display pipes */
- VML_WRITE32(par, VML_PIPEACONF, 0);
- (void)VML_READ32(par, VML_PIPEACONF);
-
- vinfo->pipe_disabled = 1;
-}
-
-#ifdef VERMILION_DEBUG
-static void vml_dump_regs(struct vml_info *vinfo)
-{
- struct vml_par *par = vinfo->par;
-
- printk(KERN_DEBUG MODULE_NAME ": Modesetting register dump:\n");
- printk(KERN_DEBUG MODULE_NAME ": \tHTOTAL_A : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_HTOTAL_A));
- printk(KERN_DEBUG MODULE_NAME ": \tHBLANK_A : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_HBLANK_A));
- printk(KERN_DEBUG MODULE_NAME ": \tHSYNC_A : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_HSYNC_A));
- printk(KERN_DEBUG MODULE_NAME ": \tVTOTAL_A : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_VTOTAL_A));
- printk(KERN_DEBUG MODULE_NAME ": \tVBLANK_A : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_VBLANK_A));
- printk(KERN_DEBUG MODULE_NAME ": \tVSYNC_A : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_VSYNC_A));
- printk(KERN_DEBUG MODULE_NAME ": \tDSPCSTRIDE : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_DSPCSTRIDE));
- printk(KERN_DEBUG MODULE_NAME ": \tDSPCSIZE : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_DSPCSIZE));
- printk(KERN_DEBUG MODULE_NAME ": \tDSPCPOS : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_DSPCPOS));
- printk(KERN_DEBUG MODULE_NAME ": \tDSPARB : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_DSPARB));
- printk(KERN_DEBUG MODULE_NAME ": \tDSPCADDR : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_DSPCADDR));
- printk(KERN_DEBUG MODULE_NAME ": \tBCLRPAT_A : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_BCLRPAT_A));
- printk(KERN_DEBUG MODULE_NAME ": \tCANVSCLR_A : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_CANVSCLR_A));
- printk(KERN_DEBUG MODULE_NAME ": \tPIPEASRC : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_PIPEASRC));
- printk(KERN_DEBUG MODULE_NAME ": \tPIPEACONF : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_PIPEACONF));
- printk(KERN_DEBUG MODULE_NAME ": \tDSPCCNTR : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_DSPCCNTR));
- printk(KERN_DEBUG MODULE_NAME ": \tRCOMPSTAT : 0x%08x\n",
- (unsigned)VML_READ32(par, VML_RCOMPSTAT));
- printk(KERN_DEBUG MODULE_NAME ": End of modesetting register dump.\n");
-}
-#endif
-
-static int vmlfb_set_par_locked(struct vml_info *vinfo)
-{
- struct vml_par *par = vinfo->par;
- struct fb_info *info = &vinfo->info;
- struct fb_var_screeninfo *var = &info->var;
- u32 htotal, hactive, hblank_start, hblank_end, hsync_start, hsync_end;
- u32 vtotal, vactive, vblank_start, vblank_end, vsync_start, vsync_end;
- u32 dspcntr;
- int clock;
-
- vinfo->bytes_per_pixel = var->bits_per_pixel >> 3;
- vinfo->stride = ALIGN(var->xres_virtual * vinfo->bytes_per_pixel, 0x40);
- info->fix.line_length = vinfo->stride;
-
- if (!subsys)
- return 0;
-
- htotal =
- var->xres + var->right_margin + var->hsync_len + var->left_margin;
- hactive = var->xres;
- hblank_start = var->xres;
- hblank_end = htotal;
- hsync_start = hactive + var->right_margin;
- hsync_end = hsync_start + var->hsync_len;
-
- vtotal =
- var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
- vactive = var->yres;
- vblank_start = var->yres;
- vblank_end = vtotal;
- vsync_start = vactive + var->lower_margin;
- vsync_end = vsync_start + var->vsync_len;
-
- dspcntr = VML_GFX_ENABLE | VML_GFX_GAMMABYPASS;
- clock = PICOS2KHZ(var->pixclock);
-
- if (subsys->nearest_clock) {
- clock = subsys->nearest_clock(subsys, clock);
- } else {
- clock = vml_nearest_clock(clock);
- }
- printk(KERN_DEBUG MODULE_NAME
- ": Set mode Hfreq : %d kHz, Vfreq : %d Hz.\n", clock / htotal,
- ((clock / htotal) * 1000) / vtotal);
-
- switch (var->bits_per_pixel) {
- case 16:
- dspcntr |= VML_GFX_ARGB1555;
- break;
- case 32:
- if (var->transp.length == 8)
- dspcntr |= VML_GFX_ARGB8888 | VML_GFX_ALPHAMULT;
- else
- dspcntr |= VML_GFX_RGB0888;
- break;
- default:
- return -EINVAL;
- }
-
- vmlfb_disable_pipe(vinfo);
- mb();
-
- if (subsys->set_clock)
- subsys->set_clock(subsys, clock);
- else
- return -EINVAL;
-
- VML_WRITE32(par, VML_HTOTAL_A, ((htotal - 1) << 16) | (hactive - 1));
- VML_WRITE32(par, VML_HBLANK_A,
- ((hblank_end - 1) << 16) | (hblank_start - 1));
- VML_WRITE32(par, VML_HSYNC_A,
- ((hsync_end - 1) << 16) | (hsync_start - 1));
- VML_WRITE32(par, VML_VTOTAL_A, ((vtotal - 1) << 16) | (vactive - 1));
- VML_WRITE32(par, VML_VBLANK_A,
- ((vblank_end - 1) << 16) | (vblank_start - 1));
- VML_WRITE32(par, VML_VSYNC_A,
- ((vsync_end - 1) << 16) | (vsync_start - 1));
- VML_WRITE32(par, VML_DSPCSTRIDE, vinfo->stride);
- VML_WRITE32(par, VML_DSPCSIZE,
- ((var->yres - 1) << 16) | (var->xres - 1));
- VML_WRITE32(par, VML_DSPCPOS, 0x00000000);
- VML_WRITE32(par, VML_DSPARB, VML_FIFO_DEFAULT);
- VML_WRITE32(par, VML_BCLRPAT_A, 0x00000000);
- VML_WRITE32(par, VML_CANVSCLR_A, 0x00000000);
- VML_WRITE32(par, VML_PIPEASRC,
- ((var->xres - 1) << 16) | (var->yres - 1));
-
- wmb();
- VML_WRITE32(par, VML_PIPEACONF, VML_PIPE_ENABLE);
- wmb();
- VML_WRITE32(par, VML_DSPCCNTR, dspcntr);
- wmb();
- VML_WRITE32(par, VML_DSPCADDR, (u32) vinfo->vram_start +
- var->yoffset * vinfo->stride +
- var->xoffset * vinfo->bytes_per_pixel);
-
- VML_WRITE32(par, VML_RCOMPSTAT, VML_MDVO_PAD_ENABLE);
-
- while (!(VML_READ32(par, VML_RCOMPSTAT) &
- (VML_MDVO_VDC_I_RCOMP | VML_MDVO_PAD_ENABLE))) ;
-
- vinfo->pipe_disabled = 0;
-#ifdef VERMILION_DEBUG
- vml_dump_regs(vinfo);
-#endif
-
- return 0;
-}
-
-static int vmlfb_set_par(struct fb_info *info)
-{
- struct vml_info *vinfo = container_of(info, struct vml_info, info);
- int ret;
-
- mutex_lock(&vml_mutex);
- list_move(&vinfo->head, (subsys) ? &global_has_mode : &global_no_mode);
- ret = vmlfb_set_par_locked(vinfo);
-
- mutex_unlock(&vml_mutex);
- return ret;
-}
-
-static int vmlfb_blank_locked(struct vml_info *vinfo)
-{
- struct vml_par *par = vinfo->par;
- u32 cur = VML_READ32(par, VML_PIPEACONF);
-
- switch (vinfo->cur_blank_mode) {
- case FB_BLANK_UNBLANK:
- if (vinfo->pipe_disabled) {
- vmlfb_set_par_locked(vinfo);
- }
- VML_WRITE32(par, VML_PIPEACONF, cur & ~VML_PIPE_FORCE_BORDER);
- (void)VML_READ32(par, VML_PIPEACONF);
- break;
- case FB_BLANK_NORMAL:
- if (vinfo->pipe_disabled) {
- vmlfb_set_par_locked(vinfo);
- }
- VML_WRITE32(par, VML_PIPEACONF, cur | VML_PIPE_FORCE_BORDER);
- (void)VML_READ32(par, VML_PIPEACONF);
- break;
- case FB_BLANK_VSYNC_SUSPEND:
- case FB_BLANK_HSYNC_SUSPEND:
- if (!vinfo->pipe_disabled) {
- vmlfb_disable_pipe(vinfo);
- }
- break;
- case FB_BLANK_POWERDOWN:
- if (!vinfo->pipe_disabled) {
- vmlfb_disable_pipe(vinfo);
- }
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int vmlfb_blank(int blank_mode, struct fb_info *info)
-{
- struct vml_info *vinfo = container_of(info, struct vml_info, info);
- int ret;
-
- mutex_lock(&vml_mutex);
- vinfo->cur_blank_mode = blank_mode;
- ret = vmlfb_blank_locked(vinfo);
- mutex_unlock(&vml_mutex);
- return ret;
-}
-
-static int vmlfb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info)
-{
- struct vml_info *vinfo = container_of(info, struct vml_info, info);
- struct vml_par *par = vinfo->par;
-
- mutex_lock(&vml_mutex);
- VML_WRITE32(par, VML_DSPCADDR, (u32) vinfo->vram_start +
- var->yoffset * vinfo->stride +
- var->xoffset * vinfo->bytes_per_pixel);
- (void)VML_READ32(par, VML_DSPCADDR);
- mutex_unlock(&vml_mutex);
-
- return 0;
-}
-
-static int vmlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info)
-{
- u32 v;
-
- if (regno >= 16)
- return -EINVAL;
-
- if (info->var.grayscale) {
- red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
- }
-
- if (info->fix.visual != FB_VISUAL_TRUECOLOR)
- return -EINVAL;
-
- red = VML_TOHW(red, info->var.red.length);
- blue = VML_TOHW(blue, info->var.blue.length);
- green = VML_TOHW(green, info->var.green.length);
- transp = VML_TOHW(transp, info->var.transp.length);
-
- v = (red << info->var.red.offset) |
- (green << info->var.green.offset) |
- (blue << info->var.blue.offset) |
- (transp << info->var.transp.offset);
-
- switch (info->var.bits_per_pixel) {
- case 16:
- ((u32 *) info->pseudo_palette)[regno] = v;
- break;
- case 24:
- case 32:
- ((u32 *) info->pseudo_palette)[regno] = v;
- break;
- }
- return 0;
-}
-
-static int vmlfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-{
- struct vml_info *vinfo = container_of(info, struct vml_info, info);
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- int ret;
- unsigned long prot;
-
- vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
-
- ret = vmlfb_vram_offset(vinfo, offset);
- if (ret)
- return -EINVAL;
-
- prot = pgprot_val(vma->vm_page_prot) & ~_PAGE_CACHE_MASK;
- pgprot_val(vma->vm_page_prot) =
- prot | cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS);
-
- return vm_iomap_memory(vma, vinfo->vram_start,
- vinfo->vram_contig_size);
-}
-
-static int vmlfb_sync(struct fb_info *info)
-{
- return 0;
-}
-
-static int vmlfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
-{
- return -EINVAL; /* just to force soft_cursor() call */
-}
-
-static struct fb_ops vmlfb_ops = {
- .owner = THIS_MODULE,
- .fb_open = vmlfb_open,
- .fb_release = vmlfb_release,
- __FB_DEFAULT_IOMEM_OPS_RDWR,
- .fb_check_var = vmlfb_check_var,
- .fb_set_par = vmlfb_set_par,
- .fb_blank = vmlfb_blank,
- .fb_pan_display = vmlfb_pan_display,
- __FB_DEFAULT_IOMEM_OPS_DRAW,
- .fb_cursor = vmlfb_cursor,
- .fb_sync = vmlfb_sync,
- .fb_mmap = vmlfb_mmap,
- .fb_setcolreg = vmlfb_setcolreg
-};
-
-static const struct pci_device_id vml_ids[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_INTEL, VML_DEVICE_VDC)},
- {0}
-};
-
-static struct pci_driver vmlfb_pci_driver = {
- .name = "vmlfb",
- .id_table = vml_ids,
- .probe = vml_pci_probe,
- .remove = vml_pci_remove,
-};
-
-static void __exit vmlfb_cleanup(void)
-{
- pci_unregister_driver(&vmlfb_pci_driver);
-}
-
-static int __init vmlfb_init(void)
-{
-
-#ifndef MODULE
- char *option = NULL;
-#endif
-
- if (fb_modesetting_disabled("vmlfb"))
- return -ENODEV;
-
-#ifndef MODULE
- if (fb_get_options(MODULE_NAME, &option))
- return -ENODEV;
-#endif
-
- printk(KERN_DEBUG MODULE_NAME ": initializing\n");
- mutex_init(&vml_mutex);
- INIT_LIST_HEAD(&global_no_mode);
- INIT_LIST_HEAD(&global_has_mode);
-
- return pci_register_driver(&vmlfb_pci_driver);
-}
-
-int vmlfb_register_subsys(struct vml_sys *sys)
-{
- struct vml_info *entry;
- struct list_head *list;
- u32 save_activate;
-
- mutex_lock(&vml_mutex);
- if (subsys != NULL) {
- subsys->restore(subsys);
- }
- subsys = sys;
- subsys->save(subsys);
-
- /*
- * We need to restart list traversal for each item, since we
- * release the list mutex in the loop.
- */
-
- list = global_no_mode.next;
- while (list != &global_no_mode) {
- list_del_init(list);
- entry = list_entry(list, struct vml_info, head);
-
- /*
- * First, try the current mode which might not be
- * completely validated with respect to the pixel clock.
- */
-
- if (!vmlfb_check_var_locked(&entry->info.var, entry)) {
- vmlfb_set_par_locked(entry);
- list_add_tail(list, &global_has_mode);
- } else {
-
- /*
- * Didn't work. Try to find another mode,
- * that matches this subsys.
- */
-
- mutex_unlock(&vml_mutex);
- save_activate = entry->info.var.activate;
- entry->info.var.bits_per_pixel = 16;
- vmlfb_set_pref_pixel_format(&entry->info.var);
- if (fb_find_mode(&entry->info.var,
- &entry->info,
- vml_default_mode, NULL, 0, NULL, 16)) {
- entry->info.var.activate |=
- FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
- fb_set_var(&entry->info, &entry->info.var);
- } else {
- printk(KERN_ERR MODULE_NAME
- ": Sorry. no mode found for this subsys.\n");
- }
- entry->info.var.activate = save_activate;
- mutex_lock(&vml_mutex);
- }
- vmlfb_blank_locked(entry);
- list = global_no_mode.next;
- }
- mutex_unlock(&vml_mutex);
-
- printk(KERN_DEBUG MODULE_NAME ": Registered %s subsystem.\n",
- subsys->name ? subsys->name : "unknown");
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(vmlfb_register_subsys);
-
-void vmlfb_unregister_subsys(struct vml_sys *sys)
-{
- struct vml_info *entry, *next;
-
- mutex_lock(&vml_mutex);
- if (subsys != sys) {
- mutex_unlock(&vml_mutex);
- return;
- }
- subsys->restore(subsys);
- subsys = NULL;
- list_for_each_entry_safe(entry, next, &global_has_mode, head) {
- printk(KERN_DEBUG MODULE_NAME ": subsys disable pipe\n");
- vmlfb_disable_pipe(entry);
- list_move_tail(&entry->head, &global_no_mode);
- }
- mutex_unlock(&vml_mutex);
-}
-
-EXPORT_SYMBOL_GPL(vmlfb_unregister_subsys);
-
-module_init(vmlfb_init);
-module_exit(vmlfb_cleanup);
-
-MODULE_AUTHOR("Tungsten Graphics");
-MODULE_DESCRIPTION("Initialization of the Vermilion display devices");
-MODULE_VERSION("1.0.0");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/vermilion/vermilion.h b/drivers/video/fbdev/vermilion/vermilion.h
deleted file mode 100644
index 19cbbe76aba7..000000000000
--- a/drivers/video/fbdev/vermilion/vermilion.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (c) Intel Corp. 2007.
- * All Rights Reserved.
- *
- * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
- * develop this driver.
- *
- * This file is part of the Vermilion Range fb driver.
- *
- * Authors:
- * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
- */
-
-#ifndef _VERMILION_H_
-#define _VERMILION_H_
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/atomic.h>
-#include <linux/mutex.h>
-
-#define VML_DEVICE_GPU 0x5002
-#define VML_DEVICE_VDC 0x5009
-
-#define VML_VRAM_AREAS 3
-#define VML_MAX_XRES 1024
-#define VML_MAX_YRES 768
-#define VML_MAX_XRES_VIRTUAL 1040
-
-/*
- * Display controller registers:
- */
-
-/* Display controller 10-bit color representation */
-
-#define VML_R_MASK 0x3FF00000
-#define VML_R_SHIFT 20
-#define VML_G_MASK 0x000FFC00
-#define VML_G_SHIFT 10
-#define VML_B_MASK 0x000003FF
-#define VML_B_SHIFT 0
-
-/* Graphics plane control */
-#define VML_DSPCCNTR 0x00072180
-#define VML_GFX_ENABLE 0x80000000
-#define VML_GFX_GAMMABYPASS 0x40000000
-#define VML_GFX_ARGB1555 0x0C000000
-#define VML_GFX_RGB0888 0x18000000
-#define VML_GFX_ARGB8888 0x1C000000
-#define VML_GFX_ALPHACONST 0x02000000
-#define VML_GFX_ALPHAMULT 0x01000000
-#define VML_GFX_CONST_ALPHA 0x000000FF
-
-/* Graphics plane start address. Pixel aligned. */
-#define VML_DSPCADDR 0x00072184
-
-/* Graphics plane stride register. */
-#define VML_DSPCSTRIDE 0x00072188
-
-/* Graphics plane position register. */
-#define VML_DSPCPOS 0x0007218C
-#define VML_POS_YMASK 0x0FFF0000
-#define VML_POS_YSHIFT 16
-#define VML_POS_XMASK 0x00000FFF
-#define VML_POS_XSHIFT 0
-
-/* Graphics plane height and width */
-#define VML_DSPCSIZE 0x00072190
-#define VML_SIZE_HMASK 0x0FFF0000
-#define VML_SIZE_HSHIFT 16
-#define VML_SISE_WMASK 0x00000FFF
-#define VML_SIZE_WSHIFT 0
-
-/* Graphics plane gamma correction lookup table registers (129 * 32 bits) */
-#define VML_DSPCGAMLUT 0x00072200
-
-/* Pixel video output configuration register */
-#define VML_PVOCONFIG 0x00061140
-#define VML_CONFIG_BASE 0x80000000
-#define VML_CONFIG_PIXEL_SWAP 0x04000000
-#define VML_CONFIG_DE_INV 0x01000000
-#define VML_CONFIG_HREF_INV 0x00400000
-#define VML_CONFIG_VREF_INV 0x00100000
-#define VML_CONFIG_CLK_INV 0x00040000
-#define VML_CONFIG_CLK_DIV2 0x00010000
-#define VML_CONFIG_ESTRB_INV 0x00008000
-
-/* Pipe A Horizontal total register */
-#define VML_HTOTAL_A 0x00060000
-#define VML_HTOTAL_MASK 0x1FFF0000
-#define VML_HTOTAL_SHIFT 16
-#define VML_HTOTAL_VAL 8192
-#define VML_HACTIVE_MASK 0x000007FF
-#define VML_HACTIVE_SHIFT 0
-#define VML_HACTIVE_VAL 4096
-
-/* Pipe A Horizontal Blank register */
-#define VML_HBLANK_A 0x00060004
-#define VML_HBLANK_END_MASK 0x1FFF0000
-#define VML_HBLANK_END_SHIFT 16
-#define VML_HBLANK_END_VAL 8192
-#define VML_HBLANK_START_MASK 0x00001FFF
-#define VML_HBLANK_START_SHIFT 0
-#define VML_HBLANK_START_VAL 8192
-
-/* Pipe A Horizontal Sync register */
-#define VML_HSYNC_A 0x00060008
-#define VML_HSYNC_END_MASK 0x1FFF0000
-#define VML_HSYNC_END_SHIFT 16
-#define VML_HSYNC_END_VAL 8192
-#define VML_HSYNC_START_MASK 0x00001FFF
-#define VML_HSYNC_START_SHIFT 0
-#define VML_HSYNC_START_VAL 8192
-
-/* Pipe A Vertical total register */
-#define VML_VTOTAL_A 0x0006000C
-#define VML_VTOTAL_MASK 0x1FFF0000
-#define VML_VTOTAL_SHIFT 16
-#define VML_VTOTAL_VAL 8192
-#define VML_VACTIVE_MASK 0x000007FF
-#define VML_VACTIVE_SHIFT 0
-#define VML_VACTIVE_VAL 4096
-
-/* Pipe A Vertical Blank register */
-#define VML_VBLANK_A 0x00060010
-#define VML_VBLANK_END_MASK 0x1FFF0000
-#define VML_VBLANK_END_SHIFT 16
-#define VML_VBLANK_END_VAL 8192
-#define VML_VBLANK_START_MASK 0x00001FFF
-#define VML_VBLANK_START_SHIFT 0
-#define VML_VBLANK_START_VAL 8192
-
-/* Pipe A Vertical Sync register */
-#define VML_VSYNC_A 0x00060014
-#define VML_VSYNC_END_MASK 0x1FFF0000
-#define VML_VSYNC_END_SHIFT 16
-#define VML_VSYNC_END_VAL 8192
-#define VML_VSYNC_START_MASK 0x00001FFF
-#define VML_VSYNC_START_SHIFT 0
-#define VML_VSYNC_START_VAL 8192
-
-/* Pipe A Source Image size (minus one - equal to active size)
- * Programmable while pipe is enabled.
- */
-#define VML_PIPEASRC 0x0006001C
-#define VML_PIPEASRC_HMASK 0x0FFF0000
-#define VML_PIPEASRC_HSHIFT 16
-#define VML_PIPEASRC_VMASK 0x00000FFF
-#define VML_PIPEASRC_VSHIFT 0
-
-/* Pipe A Border Color Pattern register (10 bit color) */
-#define VML_BCLRPAT_A 0x00060020
-
-/* Pipe A Canvas Color register (10 bit color) */
-#define VML_CANVSCLR_A 0x00060024
-
-/* Pipe A Configuration register */
-#define VML_PIPEACONF 0x00070008
-#define VML_PIPE_BASE 0x00000000
-#define VML_PIPE_ENABLE 0x80000000
-#define VML_PIPE_FORCE_BORDER 0x02000000
-#define VML_PIPE_PLANES_OFF 0x00080000
-#define VML_PIPE_ARGB_OUTPUT_MODE 0x00040000
-
-/* Pipe A FIFO setting */
-#define VML_DSPARB 0x00070030
-#define VML_FIFO_DEFAULT 0x00001D9C
-
-/* MDVO rcomp status & pads control register */
-#define VML_RCOMPSTAT 0x00070048
-#define VML_MDVO_VDC_I_RCOMP 0x80000000
-#define VML_MDVO_POWERSAVE_OFF 0x00000008
-#define VML_MDVO_PAD_ENABLE 0x00000004
-#define VML_MDVO_PULLDOWN_ENABLE 0x00000001
-
-struct vml_par {
- struct pci_dev *vdc;
- u64 vdc_mem_base;
- u64 vdc_mem_size;
- char __iomem *vdc_mem;
-
- struct pci_dev *gpu;
- u64 gpu_mem_base;
- u64 gpu_mem_size;
- char __iomem *gpu_mem;
-
- atomic_t refcount;
-};
-
-struct vram_area {
- unsigned long logical;
- unsigned long phys;
- unsigned long size;
- unsigned order;
-};
-
-struct vml_info {
- struct fb_info info;
- struct vml_par *par;
- struct list_head head;
- struct vram_area vram[VML_VRAM_AREAS];
- u64 vram_start;
- u64 vram_contig_size;
- u32 num_areas;
- void __iomem *vram_logical;
- u32 pseudo_palette[16];
- u32 stride;
- u32 bytes_per_pixel;
- atomic_t vmas;
- int cur_blank_mode;
- int pipe_disabled;
-};
-
-/*
- * Subsystem
- */
-
-struct vml_sys {
- char *name;
-
- /*
- * Save / Restore;
- */
-
- int (*save) (struct vml_sys * sys);
- int (*restore) (struct vml_sys * sys);
-
- /*
- * PLL programming;
- */
-
- int (*set_clock) (struct vml_sys * sys, int clock);
- int (*nearest_clock) (const struct vml_sys * sys, int clock);
-};
-
-extern int vmlfb_register_subsys(struct vml_sys *sys);
-extern void vmlfb_unregister_subsys(struct vml_sys *sys);
-
-#define VML_READ32(_par, _offset) \
- (ioread32((_par)->vdc_mem + (_offset)))
-#define VML_WRITE32(_par, _offset, _value) \
- iowrite32(_value, (_par)->vdc_mem + (_offset))
-
-#endif
diff --git a/drivers/video/logo/pnmtologo.c b/drivers/video/logo/pnmtologo.c
index ada5ef6e51b7..2434a25afb64 100644
--- a/drivers/video/logo/pnmtologo.c
+++ b/drivers/video/logo/pnmtologo.c
@@ -249,10 +249,10 @@ static void write_footer(void)
fputs("\n};\n\n", out);
fprintf(out, "const struct linux_logo %s __initconst = {\n", logoname);
fprintf(out, "\t.type\t\t= %s,\n", logo_types[logo_type]);
- fprintf(out, "\t.width\t\t= %d,\n", logo_width);
- fprintf(out, "\t.height\t\t= %d,\n", logo_height);
+ fprintf(out, "\t.width\t\t= %u,\n", logo_width);
+ fprintf(out, "\t.height\t\t= %u,\n", logo_height);
if (logo_type == LINUX_LOGO_CLUT224) {
- fprintf(out, "\t.clutsize\t= %d,\n", logo_clutsize);
+ fprintf(out, "\t.clutsize\t= %u,\n", logo_clutsize);
fprintf(out, "\t.clut\t\t= %s_clut,\n", logoname);
}
fprintf(out, "\t.data\t\t= %s_data\n", logoname);
diff --git a/drivers/video/sticore.c b/drivers/video/sticore.c
index c3765ad6eedf..7115b325817f 100644
--- a/drivers/video/sticore.c
+++ b/drivers/video/sticore.c
@@ -1041,6 +1041,9 @@ static int __init sticore_pa_init(struct parisc_device *dev)
print_pa_hwpath(dev, sti->pa_path);
sticore_check_for_default_sti(sti, sti->pa_path);
+
+ sti->dev = &dev->dev;
+
return 0;
}
@@ -1084,6 +1087,8 @@ static int sticore_pci_init(struct pci_dev *pd, const struct pci_device_id *ent)
pr_warn("Unable to handle STI device '%s'\n", pci_name(pd));
return -ENODEV;
}
+
+ sti->dev = &pd->dev;
#endif /* CONFIG_PCI */
return 0;
diff --git a/drivers/virt/vboxguest/vboxguest_core.c b/drivers/virt/vboxguest/vboxguest_core.c
index dfd69bd77f53..c6e9855998ab 100644
--- a/drivers/virt/vboxguest/vboxguest_core.c
+++ b/drivers/virt/vboxguest/vboxguest_core.c
@@ -33,16 +33,15 @@
VMMDEV_REQUESTOR_CON_DONT_KNOW | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN)
/**
- * Reserves memory in which the VMM can relocate any guest mappings
- * that are floating around.
+ * vbg_guest_mappings_init - Reserves memory in which the VMM can
+ * relocate any guest mappings that are floating around.
+ * @gdev: The Guest extension device.
*
* This operation is a little bit tricky since the VMM might not accept
* just any address because of address clashes between the three contexts
* it operates in, so we try several times.
*
* Failure to reserve the guest mappings is ignored.
- *
- * @gdev: The Guest extension device.
*/
static void vbg_guest_mappings_init(struct vbg_dev *gdev)
{
@@ -125,7 +124,7 @@ out:
}
/**
- * Undo what vbg_guest_mappings_init did.
+ * vbg_guest_mappings_exit - Undo what vbg_guest_mappings_init did.
*
* @gdev: The Guest extension device.
*/
@@ -166,9 +165,10 @@ static void vbg_guest_mappings_exit(struct vbg_dev *gdev)
}
/**
- * Report the guest information to the host.
- * Return: 0 or negative errno value.
+ * vbg_report_guest_info - Report the guest information to the host.
* @gdev: The Guest extension device.
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_report_guest_info(struct vbg_dev *gdev)
{
@@ -229,10 +229,11 @@ out_free:
}
/**
- * Report the guest driver status to the host.
- * Return: 0 or negative errno value.
+ * vbg_report_driver_status - Report the guest driver status to the host.
* @gdev: The Guest extension device.
* @active: Flag whether the driver is now active or not.
+ *
+ * Return: 0 or negative errno value.
*/
static int vbg_report_driver_status(struct vbg_dev *gdev, bool active)
{
@@ -261,10 +262,12 @@ static int vbg_report_driver_status(struct vbg_dev *gdev, bool active)
}
/**
- * Inflate the balloon by one chunk. The caller owns the balloon mutex.
- * Return: 0 or negative errno value.
+ * vbg_balloon_inflate - Inflate the balloon by one chunk. The caller
+ * owns the balloon mutex.
* @gdev: The Guest extension device.
* @chunk_idx: Index of the chunk.
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_balloon_inflate(struct vbg_dev *gdev, u32 chunk_idx)
{
@@ -312,10 +315,12 @@ out_error:
}
/**
- * Deflate the balloon by one chunk. The caller owns the balloon mutex.
- * Return: 0 or negative errno value.
+ * vbg_balloon_deflate - Deflate the balloon by one chunk. The caller
+ * owns the balloon mutex.
* @gdev: The Guest extension device.
* @chunk_idx: Index of the chunk.
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_balloon_deflate(struct vbg_dev *gdev, u32 chunk_idx)
{
@@ -344,7 +349,7 @@ static int vbg_balloon_deflate(struct vbg_dev *gdev, u32 chunk_idx)
return 0;
}
-/**
+/*
* Respond to VMMDEV_EVENT_BALLOON_CHANGE_REQUEST events, query the size
* the host wants the balloon to be and adjust accordingly.
*/
@@ -409,7 +414,7 @@ static void vbg_balloon_work(struct work_struct *work)
}
}
-/**
+/*
* Callback for heartbeat timer.
*/
static void vbg_heartbeat_timer(struct timer_list *t)
@@ -422,11 +427,12 @@ static void vbg_heartbeat_timer(struct timer_list *t)
}
/**
- * Configure the host to check guest's heartbeat
- * and get heartbeat interval from the host.
- * Return: 0 or negative errno value.
+ * vbg_heartbeat_host_config - Configure the host to check guest's heartbeat
+ * and get heartbeat interval from the host.
* @gdev: The Guest extension device.
* @enabled: Set true to enable guest heartbeat checks on host.
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_heartbeat_host_config(struct vbg_dev *gdev, bool enabled)
{
@@ -449,9 +455,11 @@ static int vbg_heartbeat_host_config(struct vbg_dev *gdev, bool enabled)
}
/**
- * Initializes the heartbeat timer. This feature may be disabled by the host.
- * Return: 0 or negative errno value.
+ * vbg_heartbeat_init - Initializes the heartbeat timer. This feature
+ * may be disabled by the host.
* @gdev: The Guest extension device.
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_heartbeat_init(struct vbg_dev *gdev)
{
@@ -481,7 +489,8 @@ static int vbg_heartbeat_init(struct vbg_dev *gdev)
}
/**
- * Cleanup hearbeat code, stop HB timer and disable host heartbeat checking.
+ * vbg_heartbeat_exit - Cleanup heartbeat code, stop HB timer and disable
+ * host heartbeat checking.
* @gdev: The Guest extension device.
*/
static void vbg_heartbeat_exit(struct vbg_dev *gdev)
@@ -493,11 +502,12 @@ static void vbg_heartbeat_exit(struct vbg_dev *gdev)
}
/**
- * Applies a change to the bit usage tracker.
- * Return: true if the mask changed, false if not.
+ * vbg_track_bit_usage - Applies a change to the bit usage tracker.
* @tracker: The bit usage tracker.
* @changed: The bits to change.
* @previous: The previous value of the bits.
+ *
+ * Return: %true if the mask changed, %false if not.
*/
static bool vbg_track_bit_usage(struct vbg_bit_usage_tracker *tracker,
u32 changed, u32 previous)
@@ -529,10 +539,12 @@ static bool vbg_track_bit_usage(struct vbg_bit_usage_tracker *tracker,
}
/**
- * Init and termination worker for resetting the (host) event filter on the host
- * Return: 0 or negative errno value.
+ * vbg_reset_host_event_filter - Init and termination worker for
+ * resetting the (host) event filter on the host
* @gdev: The Guest extension device.
* @fixed_events: Fixed events (init time).
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_reset_host_event_filter(struct vbg_dev *gdev,
u32 fixed_events)
@@ -556,12 +568,8 @@ static int vbg_reset_host_event_filter(struct vbg_dev *gdev,
}
/**
- * Changes the event filter mask for the given session.
- *
- * This is called in response to VBG_IOCTL_CHANGE_FILTER_MASK as well as to
- * do session cleanup. Takes the session mutex.
- *
- * Return: 0 or negative errno value.
+ * vbg_set_session_event_filter - Changes the event filter mask for the
+ * given session.
* @gdev: The Guest extension device.
* @session: The session.
* @or_mask: The events to add.
@@ -570,6 +578,11 @@ static int vbg_reset_host_event_filter(struct vbg_dev *gdev,
* This tweaks the error handling so we perform
* proper session cleanup even if the host
* misbehaves.
+ *
+ * This is called in response to VBG_IOCTL_CHANGE_FILTER_MASK as well as to
+ * do session cleanup. Takes the session mutex.
+ *
+ * Return: 0 or negative errno value.
*/
static int vbg_set_session_event_filter(struct vbg_dev *gdev,
struct vbg_session *session,
@@ -637,9 +650,11 @@ out:
}
/**
- * Init and termination worker for set guest capabilities to zero on the host.
- * Return: 0 or negative errno value.
+ * vbg_reset_host_capabilities - Init and termination worker for set
+ * guest capabilities to zero on the host.
* @gdev: The Guest extension device.
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_reset_host_capabilities(struct vbg_dev *gdev)
{
@@ -662,12 +677,14 @@ static int vbg_reset_host_capabilities(struct vbg_dev *gdev)
}
/**
- * Set guest capabilities on the host.
- * Must be called with gdev->session_mutex hold.
- * Return: 0 or negative errno value.
+ * vbg_set_host_capabilities - Set guest capabilities on the host.
* @gdev: The Guest extension device.
* @session: The session.
* @session_termination: Set if we're called by the session cleanup code.
+ *
+ * Must be called with gdev->session_mutex hold.
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_set_host_capabilities(struct vbg_dev *gdev,
struct vbg_session *session,
@@ -704,9 +721,8 @@ static int vbg_set_host_capabilities(struct vbg_dev *gdev,
}
/**
- * Acquire (get exclusive access) guest capabilities for a session.
- * Takes the session mutex.
- * Return: 0 or negative errno value.
+ * vbg_acquire_session_capabilities - Acquire (get exclusive access)
+ * guest capabilities for a session.
* @gdev: The Guest extension device.
* @session: The session.
* @flags: Flags (VBGL_IOC_AGC_FLAGS_XXX).
@@ -716,6 +732,10 @@ static int vbg_set_host_capabilities(struct vbg_dev *gdev,
* This tweaks the error handling so we perform
* proper session cleanup even if the host
* misbehaves.
+ *
+ * Takes the session mutex.
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_acquire_session_capabilities(struct vbg_dev *gdev,
struct vbg_session *session,
@@ -811,8 +831,8 @@ out:
}
/**
- * Sets the guest capabilities for a session. Takes the session mutex.
- * Return: 0 or negative errno value.
+ * vbg_set_session_capabilities - Sets the guest capabilities for a
+ * session. Takes the session mutex.
* @gdev: The Guest extension device.
* @session: The session.
* @or_mask: The capabilities to add.
@@ -821,6 +841,8 @@ out:
* This tweaks the error handling so we perform
* proper session cleanup even if the host
* misbehaves.
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_set_session_capabilities(struct vbg_dev *gdev,
struct vbg_session *session,
@@ -866,9 +888,10 @@ out:
}
/**
- * vbg_query_host_version get the host feature mask and version information.
- * Return: 0 or negative errno value.
+ * vbg_query_host_version - get the host feature mask and version information.
* @gdev: The Guest extension device.
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_query_host_version(struct vbg_dev *gdev)
{
@@ -905,19 +928,18 @@ out:
}
/**
- * Initializes the VBoxGuest device extension when the
- * device driver is loaded.
+ * vbg_core_init - Initializes the VBoxGuest device extension when the
+ * device driver is loaded.
+ * @gdev: The Guest extension device.
+ * @fixed_events: Events that will be enabled upon init and no client
+ * will ever be allowed to mask.
*
* The native code locates the VMMDev on the PCI bus and retrieve
* the MMIO and I/O port ranges, this function will take care of
* mapping the MMIO memory (if present). Upon successful return
* the native code should set up the interrupt handler.
*
- * Return: 0 or negative errno value.
- *
- * @gdev: The Guest extension device.
- * @fixed_events: Events that will be enabled upon init and no client
- * will ever be allowed to mask.
+ * Return: %0 or negative errno value.
*/
int vbg_core_init(struct vbg_dev *gdev, u32 fixed_events)
{
@@ -1017,11 +1039,12 @@ err_free_reqs:
}
/**
- * Call this on exit to clean-up vboxguest-core managed resources.
+ * vbg_core_exit - Call this on exit to clean-up vboxguest-core managed
+ * resources.
+ * @gdev: The Guest extension device.
*
* The native code should call this before the driver is loaded,
* but don't call this on shutdown.
- * @gdev: The Guest extension device.
*/
void vbg_core_exit(struct vbg_dev *gdev)
{
@@ -1046,12 +1069,13 @@ void vbg_core_exit(struct vbg_dev *gdev)
}
/**
- * Creates a VBoxGuest user session.
+ * vbg_core_open_session - Creates a VBoxGuest user session.
+ * @gdev: The Guest extension device.
+ * @requestor: VMMDEV_REQUESTOR_* flags
*
* vboxguest_linux.c calls this when userspace opens the char-device.
+ *
* Return: A pointer to the new session or an ERR_PTR on error.
- * @gdev: The Guest extension device.
- * @requestor: VMMDEV_REQUESTOR_* flags
*/
struct vbg_session *vbg_core_open_session(struct vbg_dev *gdev, u32 requestor)
{
@@ -1068,7 +1092,7 @@ struct vbg_session *vbg_core_open_session(struct vbg_dev *gdev, u32 requestor)
}
/**
- * Closes a VBoxGuest session.
+ * vbg_core_close_session - Closes a VBoxGuest session.
* @session: The session to close (and free).
*/
void vbg_core_close_session(struct vbg_session *session)
@@ -1250,11 +1274,13 @@ static int vbg_ioctl_interrupt_all_wait_events(struct vbg_dev *gdev,
}
/**
- * Checks if the VMM request is allowed in the context of the given session.
- * Return: 0 or negative errno value.
+ * vbg_req_allowed - Checks if the VMM request is allowed in the
+ * context of the given session.
* @gdev: The Guest extension device.
* @session: The calling session.
* @req: The request.
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_req_allowed(struct vbg_dev *gdev, struct vbg_session *session,
const struct vmmdev_request_header *req)
@@ -1670,11 +1696,12 @@ static int vbg_ioctl_write_core_dump(struct vbg_dev *gdev,
}
/**
- * Common IOCtl for user to kernel communication.
- * Return: 0 or negative errno value.
+ * vbg_core_ioctl - Common IOCtl for user to kernel communication.
* @session: The client session.
* @req: The requested function.
* @data: The i/o data buffer, minimum size sizeof(struct vbg_ioctl_hdr).
+ *
+ * Return: %0 or negative errno value.
*/
int vbg_core_ioctl(struct vbg_session *session, unsigned int req, void *data)
{
@@ -1744,11 +1771,12 @@ int vbg_core_ioctl(struct vbg_session *session, unsigned int req, void *data)
}
/**
- * Report guest supported mouse-features to the host.
+ * vbg_core_set_mouse_status - Report guest supported mouse-features to the host.
*
- * Return: 0 or negative errno value.
* @gdev: The Guest extension device.
* @features: The set of features to report to the host.
+ *
+ * Return: %0 or negative errno value.
*/
int vbg_core_set_mouse_status(struct vbg_dev *gdev, u32 features)
{
@@ -1772,7 +1800,7 @@ int vbg_core_set_mouse_status(struct vbg_dev *gdev, u32 features)
return vbg_status_code_to_errno(rc);
}
-/** Core interrupt service routine. */
+/* Core interrupt service routine. */
irqreturn_t vbg_core_isr(int irq, void *dev_id)
{
struct vbg_dev *gdev = dev_id;
diff --git a/drivers/virt/vboxguest/vboxguest_linux.c b/drivers/virt/vboxguest/vboxguest_linux.c
index c47e62dc55da..8c92ea5b7305 100644
--- a/drivers/virt/vboxguest/vboxguest_linux.c
+++ b/drivers/virt/vboxguest/vboxguest_linux.c
@@ -81,10 +81,11 @@ static int vbg_misc_device_user_open(struct inode *inode, struct file *filp)
}
/**
- * Close device.
- * Return: 0 on success, negated errno on failure.
+ * vbg_misc_device_close - Close device.
* @inode: Pointer to inode info structure.
* @filp: Associated file pointer.
+ *
+ * Return: %0 on success, negated errno on failure.
*/
static int vbg_misc_device_close(struct inode *inode, struct file *filp)
{
@@ -94,11 +95,12 @@ static int vbg_misc_device_close(struct inode *inode, struct file *filp)
}
/**
- * Device I/O Control entry point.
- * Return: 0 on success, negated errno on failure.
+ * vbg_misc_device_ioctl - Device I/O Control entry point.
* @filp: Associated file pointer.
* @req: The request specified to ioctl().
* @arg: The argument specified to ioctl().
+ *
+ * Return: %0 on success, negated errno on failure.
*/
static long vbg_misc_device_ioctl(struct file *filp, unsigned int req,
unsigned long arg)
@@ -173,7 +175,7 @@ out:
return ret;
}
-/** The file_operations structures. */
+/* The file_operations structures. */
static const struct file_operations vbg_misc_device_fops = {
.owner = THIS_MODULE,
.open = vbg_misc_device_open,
@@ -193,7 +195,7 @@ static const struct file_operations vbg_misc_device_user_fops = {
#endif
};
-/**
+/*
* Called when the input device is first opened.
*
* Sets up absolute mouse reporting.
@@ -206,7 +208,7 @@ static int vbg_input_open(struct input_dev *input)
return vbg_core_set_mouse_status(gdev, feat);
}
-/**
+/*
* Called if all open handles to the input device are closed.
*
* Disables absolute reporting.
@@ -218,7 +220,7 @@ static void vbg_input_close(struct input_dev *input)
vbg_core_set_mouse_status(gdev, 0);
}
-/**
+/*
* Creates the kernel input device.
*
* Return: 0 on success, negated errno on failure.
@@ -277,7 +279,7 @@ static struct attribute *vbg_pci_attrs[] = {
};
ATTRIBUTE_GROUPS(vbg_pci);
-/**
+/*
* Does the PCI detection and init of the device.
*
* Return: 0 on success, negated errno on failure.
@@ -453,7 +455,7 @@ void vbg_put_gdev(struct vbg_dev *gdev)
}
EXPORT_SYMBOL(vbg_put_gdev);
-/**
+/*
* Callback for mouse events.
*
* This is called at the end of the ISR, after leaving the event spinlock, if
diff --git a/drivers/virt/vboxguest/vboxguest_utils.c b/drivers/virt/vboxguest/vboxguest_utils.c
index 8d195e3f8301..1c02b3c0d934 100644
--- a/drivers/virt/vboxguest/vboxguest_utils.c
+++ b/drivers/virt/vboxguest/vboxguest_utils.c
@@ -237,14 +237,16 @@ static int hgcm_call_preprocess_linaddr(
}
/**
- * Preprocesses the HGCM call, validate parameters, alloc bounce buffers and
- * figure out how much extra storage we need for page lists.
- * Return: 0 or negative errno value.
+ * hgcm_call_preprocess - Preprocesses the HGCM call, validate parameters,
+ * alloc bounce buffers and figure out how much extra storage we need for
+ * page lists.
* @src_parm: Pointer to source function call parameters
* @parm_count: Number of function call parameters.
* @bounce_bufs_ret: Where to return the allocated bouncebuffer array
* @extra: Where to return the extra request space needed for
* physical page lists.
+ *
+ * Return: %0 or negative errno value.
*/
static int hgcm_call_preprocess(
const struct vmmdev_hgcm_function_parameter *src_parm,
@@ -301,10 +303,11 @@ static int hgcm_call_preprocess(
}
/**
- * Translates linear address types to page list direction flags.
+ * hgcm_call_linear_addr_type_to_pagelist_flags - Translates linear address
+ * types to page list direction flags.
+ * @type: The type.
*
* Return: page list flags.
- * @type: The type.
*/
static u32 hgcm_call_linear_addr_type_to_pagelist_flags(
enum vmmdev_hgcm_function_parameter_type type)
@@ -369,7 +372,8 @@ static void hgcm_call_init_linaddr(struct vmmdev_hgcm_call *call,
}
/**
- * Initializes the call request that we're sending to the host.
+ * hgcm_call_init_call - Initializes the call request that we're sending
+ * to the host.
* @call: The call to initialize.
* @client_id: The client ID of the caller.
* @function: The function number of the function to call.
@@ -425,7 +429,9 @@ static void hgcm_call_init_call(
}
/**
- * Tries to cancel a pending HGCM call.
+ * hgcm_cancel_call - Tries to cancel a pending HGCM call.
+ * @gdev: The VBoxGuest device extension.
+ * @call: The call to cancel.
*
* Return: VBox status code
*/
@@ -459,13 +465,15 @@ static int hgcm_cancel_call(struct vbg_dev *gdev, struct vmmdev_hgcm_call *call)
}
/**
- * Performs the call and completion wait.
- * Return: 0 or negative errno value.
+ * vbg_hgcm_do_call - Performs the call and completion wait.
* @gdev: The VBoxGuest device extension.
* @call: The call to execute.
* @timeout_ms: Timeout in ms.
+ * @interruptible: whether this call is interruptible
* @leak_it: Where to return the leak it / free it, indicator.
* Cancellation fun.
+ *
+ * Return: %0 or negative errno value.
*/
static int vbg_hgcm_do_call(struct vbg_dev *gdev, struct vmmdev_hgcm_call *call,
u32 timeout_ms, bool interruptible, bool *leak_it)
@@ -545,13 +553,14 @@ static int vbg_hgcm_do_call(struct vbg_dev *gdev, struct vmmdev_hgcm_call *call,
}
/**
- * Copies the result of the call back to the caller info structure and user
- * buffers.
- * Return: 0 or negative errno value.
+ * hgcm_call_copy_back_result - Copies the result of the call back to
+ * the caller info structure and user buffers.
* @call: HGCM call request.
* @dst_parm: Pointer to function call parameters destination.
* @parm_count: Number of function call parameters.
* @bounce_bufs: The bouncebuffer array.
+ *
+ * Return: %0 or negative errno value.
*/
static int hgcm_call_copy_back_result(
const struct vmmdev_hgcm_call *call,
diff --git a/drivers/virt/vmgenid.c b/drivers/virt/vmgenid.c
index a1c467a0e9f7..b67a28da4702 100644
--- a/drivers/virt/vmgenid.c
+++ b/drivers/virt/vmgenid.c
@@ -68,6 +68,7 @@ out:
static void vmgenid_notify(struct acpi_device *device, u32 event)
{
struct vmgenid_state *state = acpi_driver_data(device);
+ char *envp[] = { "NEW_VMGENID=1", NULL };
u8 old_id[VMGENID_SIZE];
memcpy(old_id, state->this_id, sizeof(old_id));
@@ -75,6 +76,7 @@ static void vmgenid_notify(struct acpi_device *device, u32 event)
if (!memcmp(old_id, state->this_id, sizeof(old_id)))
return;
add_vmfork_randomness(state->this_id, sizeof(state->this_id));
+ kobject_uevent_env(&device->dev.kobj, KOBJ_CHANGE, envp);
}
static const struct acpi_device_id vmgenid_ids[] = {
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 0a53a61231c2..c17193544268 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -60,6 +60,11 @@ config VIRTIO_PCI
If unsure, say M.
+config VIRTIO_PCI_ADMIN_LEGACY
+ bool
+ depends on VIRTIO_PCI && (X86 || COMPILE_TEST)
+ default y
+
config VIRTIO_PCI_LEGACY
bool "Support for legacy virtio draft 0.9.X and older devices"
default y
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index 8e98d24917cc..73ace62af440 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o
obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o
virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o
+virtio_pci-$(CONFIG_VIRTIO_PCI_ADMIN_LEGACY) += virtio_pci_admin_legacy_io.o
obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
obj-$(CONFIG_VIRTIO_VDPA) += virtio_vdpa.o
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index 3893dc29eb26..f4080692b351 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -302,9 +302,15 @@ static int virtio_dev_probe(struct device *_d)
if (err)
goto err;
+ if (dev->config->create_avq) {
+ err = dev->config->create_avq(dev);
+ if (err)
+ goto err;
+ }
+
err = drv->probe(dev);
if (err)
- goto err;
+ goto err_probe;
/* If probe didn't do it, mark device DRIVER_OK ourselves. */
if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK))
@@ -316,6 +322,10 @@ static int virtio_dev_probe(struct device *_d)
virtio_config_enable(dev);
return 0;
+
+err_probe:
+ if (dev->config->destroy_avq)
+ dev->config->destroy_avq(dev);
err:
virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
return err;
@@ -331,6 +341,9 @@ static void virtio_dev_remove(struct device *_d)
drv->remove(dev);
+ if (dev->config->destroy_avq)
+ dev->config->destroy_avq(dev);
+
/* Driver should have reset device. */
WARN_ON_ONCE(dev->config->get_status(dev));
@@ -489,13 +502,20 @@ EXPORT_SYMBOL_GPL(unregister_virtio_device);
int virtio_device_freeze(struct virtio_device *dev)
{
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
+ int ret;
virtio_config_disable(dev);
dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
- if (drv && drv->freeze)
- return drv->freeze(dev);
+ if (drv && drv->freeze) {
+ ret = drv->freeze(dev);
+ if (ret)
+ return ret;
+ }
+
+ if (dev->config->destroy_avq)
+ dev->config->destroy_avq(dev);
return 0;
}
@@ -532,10 +552,16 @@ int virtio_device_restore(struct virtio_device *dev)
if (ret)
goto err;
+ if (dev->config->create_avq) {
+ ret = dev->config->create_avq(dev);
+ if (ret)
+ goto err;
+ }
+
if (drv->restore) {
ret = drv->restore(dev);
if (ret)
- goto err;
+ goto err_restore;
}
/* If restore didn't do it, mark device DRIVER_OK ourselves. */
@@ -546,6 +572,9 @@ int virtio_device_restore(struct virtio_device *dev)
return 0;
+err_restore:
+ if (dev->config->destroy_avq)
+ dev->config->destroy_avq(dev);
err:
virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
return ret;
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 59cdc0292dce..1f5b3dd31fcf 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -119,6 +119,11 @@ struct virtio_balloon {
/* Free page reporting device */
struct virtqueue *reporting_vq;
struct page_reporting_dev_info pr_dev_info;
+
+ /* State for keeping the wakeup_source active while adjusting the balloon */
+ spinlock_t adjustment_lock;
+ bool adjustment_signal_pending;
+ bool adjustment_in_progress;
};
static const struct virtio_device_id id_table[] = {
@@ -437,6 +442,31 @@ static void virtio_balloon_queue_free_page_work(struct virtio_balloon *vb)
queue_work(vb->balloon_wq, &vb->report_free_page_work);
}
+static void start_update_balloon_size(struct virtio_balloon *vb)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&vb->adjustment_lock, flags);
+ vb->adjustment_signal_pending = true;
+ if (!vb->adjustment_in_progress) {
+ vb->adjustment_in_progress = true;
+ pm_stay_awake(vb->vdev->dev.parent);
+ }
+ spin_unlock_irqrestore(&vb->adjustment_lock, flags);
+
+ queue_work(system_freezable_wq, &vb->update_balloon_size_work);
+}
+
+static void end_update_balloon_size(struct virtio_balloon *vb)
+{
+ spin_lock_irq(&vb->adjustment_lock);
+ if (!vb->adjustment_signal_pending && vb->adjustment_in_progress) {
+ vb->adjustment_in_progress = false;
+ pm_relax(vb->vdev->dev.parent);
+ }
+ spin_unlock_irq(&vb->adjustment_lock);
+}
+
static void virtballoon_changed(struct virtio_device *vdev)
{
struct virtio_balloon *vb = vdev->priv;
@@ -444,8 +474,7 @@ static void virtballoon_changed(struct virtio_device *vdev)
spin_lock_irqsave(&vb->stop_update_lock, flags);
if (!vb->stop_update) {
- queue_work(system_freezable_wq,
- &vb->update_balloon_size_work);
+ start_update_balloon_size(vb);
virtio_balloon_queue_free_page_work(vb);
}
spin_unlock_irqrestore(&vb->stop_update_lock, flags);
@@ -476,19 +505,25 @@ static void update_balloon_size_func(struct work_struct *work)
vb = container_of(work, struct virtio_balloon,
update_balloon_size_work);
- diff = towards_target(vb);
- if (!diff)
- return;
+ spin_lock_irq(&vb->adjustment_lock);
+ vb->adjustment_signal_pending = false;
+ spin_unlock_irq(&vb->adjustment_lock);
- if (diff > 0)
- diff -= fill_balloon(vb, diff);
- else
- diff += leak_balloon(vb, -diff);
- update_balloon_size(vb);
+ diff = towards_target(vb);
+
+ if (diff) {
+ if (diff > 0)
+ diff -= fill_balloon(vb, diff);
+ else
+ diff += leak_balloon(vb, -diff);
+ update_balloon_size(vb);
+ }
if (diff)
queue_work(system_freezable_wq, work);
+ else
+ end_update_balloon_size(vb);
}
static int init_vqs(struct virtio_balloon *vb)
@@ -992,6 +1027,8 @@ static int virtballoon_probe(struct virtio_device *vdev)
goto out_unregister_oom;
}
+ spin_lock_init(&vb->adjustment_lock);
+
virtio_device_ready(vdev);
if (towards_target(vb))
diff --git a/drivers/virtio/virtio_pci_admin_legacy_io.c b/drivers/virtio/virtio_pci_admin_legacy_io.c
new file mode 100644
index 000000000000..819cfbbc67c3
--- /dev/null
+++ b/drivers/virtio/virtio_pci_admin_legacy_io.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved
+ */
+
+#include <linux/virtio_pci_admin.h>
+#include "virtio_pci_common.h"
+
+/*
+ * virtio_pci_admin_has_legacy_io - Checks whether the legacy IO
+ * commands are supported
+ * @dev: VF pci_dev
+ *
+ * Returns true on success.
+ */
+bool virtio_pci_admin_has_legacy_io(struct pci_dev *pdev)
+{
+ struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev);
+ struct virtio_pci_device *vp_dev;
+
+ if (!virtio_dev)
+ return false;
+
+ if (!virtio_has_feature(virtio_dev, VIRTIO_F_ADMIN_VQ))
+ return false;
+
+ vp_dev = to_vp_device(virtio_dev);
+
+ if ((vp_dev->admin_vq.supported_cmds & VIRTIO_LEGACY_ADMIN_CMD_BITMAP) ==
+ VIRTIO_LEGACY_ADMIN_CMD_BITMAP)
+ return true;
+ return false;
+}
+EXPORT_SYMBOL_GPL(virtio_pci_admin_has_legacy_io);
+
+static int virtio_pci_admin_legacy_io_write(struct pci_dev *pdev, u16 opcode,
+ u8 offset, u8 size, u8 *buf)
+{
+ struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev);
+ struct virtio_admin_cmd_legacy_wr_data *data;
+ struct virtio_admin_cmd cmd = {};
+ struct scatterlist data_sg;
+ int vf_id;
+ int ret;
+
+ if (!virtio_dev)
+ return -ENODEV;
+
+ vf_id = pci_iov_vf_id(pdev);
+ if (vf_id < 0)
+ return vf_id;
+
+ data = kzalloc(sizeof(*data) + size, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->offset = offset;
+ memcpy(data->registers, buf, size);
+ sg_init_one(&data_sg, data, sizeof(*data) + size);
+ cmd.opcode = cpu_to_le16(opcode);
+ cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV);
+ cmd.group_member_id = cpu_to_le64(vf_id + 1);
+ cmd.data_sg = &data_sg;
+ ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
+
+ kfree(data);
+ return ret;
+}
+
+/*
+ * virtio_pci_admin_legacy_io_write_common - Write legacy common configuration
+ * of a member device
+ * @dev: VF pci_dev
+ * @offset: starting byte offset within the common configuration area to write to
+ * @size: size of the data to write
+ * @buf: buffer which holds the data
+ *
+ * Note: caller must serialize access for the given device.
+ * Returns 0 on success, or negative on failure.
+ */
+int virtio_pci_admin_legacy_common_io_write(struct pci_dev *pdev, u8 offset,
+ u8 size, u8 *buf)
+{
+ return virtio_pci_admin_legacy_io_write(pdev,
+ VIRTIO_ADMIN_CMD_LEGACY_COMMON_CFG_WRITE,
+ offset, size, buf);
+}
+EXPORT_SYMBOL_GPL(virtio_pci_admin_legacy_common_io_write);
+
+/*
+ * virtio_pci_admin_legacy_io_write_device - Write legacy device configuration
+ * of a member device
+ * @dev: VF pci_dev
+ * @offset: starting byte offset within the device configuration area to write to
+ * @size: size of the data to write
+ * @buf: buffer which holds the data
+ *
+ * Note: caller must serialize access for the given device.
+ * Returns 0 on success, or negative on failure.
+ */
+int virtio_pci_admin_legacy_device_io_write(struct pci_dev *pdev, u8 offset,
+ u8 size, u8 *buf)
+{
+ return virtio_pci_admin_legacy_io_write(pdev,
+ VIRTIO_ADMIN_CMD_LEGACY_DEV_CFG_WRITE,
+ offset, size, buf);
+}
+EXPORT_SYMBOL_GPL(virtio_pci_admin_legacy_device_io_write);
+
+static int virtio_pci_admin_legacy_io_read(struct pci_dev *pdev, u16 opcode,
+ u8 offset, u8 size, u8 *buf)
+{
+ struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev);
+ struct virtio_admin_cmd_legacy_rd_data *data;
+ struct scatterlist data_sg, result_sg;
+ struct virtio_admin_cmd cmd = {};
+ int vf_id;
+ int ret;
+
+ if (!virtio_dev)
+ return -ENODEV;
+
+ vf_id = pci_iov_vf_id(pdev);
+ if (vf_id < 0)
+ return vf_id;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->offset = offset;
+ sg_init_one(&data_sg, data, sizeof(*data));
+ sg_init_one(&result_sg, buf, size);
+ cmd.opcode = cpu_to_le16(opcode);
+ cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV);
+ cmd.group_member_id = cpu_to_le64(vf_id + 1);
+ cmd.data_sg = &data_sg;
+ cmd.result_sg = &result_sg;
+ ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
+
+ kfree(data);
+ return ret;
+}
+
+/*
+ * virtio_pci_admin_legacy_device_io_read - Read legacy device configuration of
+ * a member device
+ * @dev: VF pci_dev
+ * @offset: starting byte offset within the device configuration area to read from
+ * @size: size of the data to be read
+ * @buf: buffer to hold the returned data
+ *
+ * Note: caller must serialize access for the given device.
+ * Returns 0 on success, or negative on failure.
+ */
+int virtio_pci_admin_legacy_device_io_read(struct pci_dev *pdev, u8 offset,
+ u8 size, u8 *buf)
+{
+ return virtio_pci_admin_legacy_io_read(pdev,
+ VIRTIO_ADMIN_CMD_LEGACY_DEV_CFG_READ,
+ offset, size, buf);
+}
+EXPORT_SYMBOL_GPL(virtio_pci_admin_legacy_device_io_read);
+
+/*
+ * virtio_pci_admin_legacy_common_io_read - Read legacy common configuration of
+ * a member device
+ * @dev: VF pci_dev
+ * @offset: starting byte offset within the common configuration area to read from
+ * @size: size of the data to be read
+ * @buf: buffer to hold the returned data
+ *
+ * Note: caller must serialize access for the given device.
+ * Returns 0 on success, or negative on failure.
+ */
+int virtio_pci_admin_legacy_common_io_read(struct pci_dev *pdev, u8 offset,
+ u8 size, u8 *buf)
+{
+ return virtio_pci_admin_legacy_io_read(pdev,
+ VIRTIO_ADMIN_CMD_LEGACY_COMMON_CFG_READ,
+ offset, size, buf);
+}
+EXPORT_SYMBOL_GPL(virtio_pci_admin_legacy_common_io_read);
+
+/*
+ * virtio_pci_admin_legacy_io_notify_info - Read the queue notification
+ * information for legacy interface
+ * @dev: VF pci_dev
+ * @req_bar_flags: requested bar flags
+ * @bar: on output the BAR number of the owner or member device
+ * @bar_offset: on output the offset within bar
+ *
+ * Returns 0 on success, or negative on failure.
+ */
+int virtio_pci_admin_legacy_io_notify_info(struct pci_dev *pdev,
+ u8 req_bar_flags, u8 *bar,
+ u64 *bar_offset)
+{
+ struct virtio_device *virtio_dev = virtio_pci_vf_get_pf_dev(pdev);
+ struct virtio_admin_cmd_notify_info_result *result;
+ struct virtio_admin_cmd cmd = {};
+ struct scatterlist result_sg;
+ int vf_id;
+ int ret;
+
+ if (!virtio_dev)
+ return -ENODEV;
+
+ vf_id = pci_iov_vf_id(pdev);
+ if (vf_id < 0)
+ return vf_id;
+
+ result = kzalloc(sizeof(*result), GFP_KERNEL);
+ if (!result)
+ return -ENOMEM;
+
+ sg_init_one(&result_sg, result, sizeof(*result));
+ cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_LEGACY_NOTIFY_INFO);
+ cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV);
+ cmd.group_member_id = cpu_to_le64(vf_id + 1);
+ cmd.result_sg = &result_sg;
+ ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
+ if (!ret) {
+ struct virtio_admin_cmd_notify_info_data *entry;
+ int i;
+
+ ret = -ENOENT;
+ for (i = 0; i < VIRTIO_ADMIN_CMD_MAX_NOTIFY_INFO; i++) {
+ entry = &result->entries[i];
+ if (entry->flags == VIRTIO_ADMIN_CMD_NOTIFY_INFO_FLAGS_END)
+ break;
+ if (entry->flags != req_bar_flags)
+ continue;
+ *bar = entry->bar;
+ *bar_offset = le64_to_cpu(entry->offset);
+ ret = 0;
+ break;
+ }
+ }
+
+ kfree(result);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(virtio_pci_admin_legacy_io_notify_info);
diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c
index 7a5593997e0e..b655fccaf773 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -236,6 +236,9 @@ void vp_del_vqs(struct virtio_device *vdev)
int i;
list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
+ if (vp_dev->is_avq(vdev, vq->index))
+ continue;
+
if (vp_dev->per_vq_vectors) {
int v = vp_dev->vqs[vq->index]->msix_vector;
@@ -492,8 +495,40 @@ static int virtio_pci_restore(struct device *dev)
return virtio_device_restore(&vp_dev->vdev);
}
+static bool vp_supports_pm_no_reset(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ u16 pmcsr;
+
+ if (!pci_dev->pm_cap)
+ return false;
+
+ pci_read_config_word(pci_dev, pci_dev->pm_cap + PCI_PM_CTRL, &pmcsr);
+ if (PCI_POSSIBLE_ERROR(pmcsr)) {
+ dev_err(dev, "Unable to query pmcsr");
+ return false;
+ }
+
+ return pmcsr & PCI_PM_CTRL_NO_SOFT_RESET;
+}
+
+static int virtio_pci_suspend(struct device *dev)
+{
+ return vp_supports_pm_no_reset(dev) ? 0 : virtio_pci_freeze(dev);
+}
+
+static int virtio_pci_resume(struct device *dev)
+{
+ return vp_supports_pm_no_reset(dev) ? 0 : virtio_pci_restore(dev);
+}
+
static const struct dev_pm_ops virtio_pci_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(virtio_pci_freeze, virtio_pci_restore)
+ .suspend = virtio_pci_suspend,
+ .resume = virtio_pci_resume,
+ .freeze = virtio_pci_freeze,
+ .thaw = virtio_pci_restore,
+ .poweroff = virtio_pci_freeze,
+ .restore = virtio_pci_restore,
};
#endif
@@ -642,6 +677,17 @@ static struct pci_driver virtio_pci_driver = {
.sriov_configure = virtio_pci_sriov_configure,
};
+struct virtio_device *virtio_pci_vf_get_pf_dev(struct pci_dev *pdev)
+{
+ struct virtio_pci_device *pf_vp_dev;
+
+ pf_vp_dev = pci_iov_get_pf_drvdata(pdev, &virtio_pci_driver);
+ if (IS_ERR(pf_vp_dev))
+ return NULL;
+
+ return &pf_vp_dev->vdev;
+}
+
module_pci_driver(virtio_pci_driver);
MODULE_AUTHOR("Anthony Liguori <[email protected]>");
diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h
index 4b773bd7c58c..7fef52bee455 100644
--- a/drivers/virtio/virtio_pci_common.h
+++ b/drivers/virtio/virtio_pci_common.h
@@ -29,6 +29,7 @@
#include <linux/virtio_pci_modern.h>
#include <linux/highmem.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
struct virtio_pci_vq_info {
/* the actual virtqueue */
@@ -41,6 +42,17 @@ struct virtio_pci_vq_info {
unsigned int msix_vector;
};
+struct virtio_pci_admin_vq {
+ /* Virtqueue info associated with this admin queue. */
+ struct virtio_pci_vq_info info;
+ /* serializing admin commands execution and virtqueue deletion */
+ struct mutex cmd_lock;
+ u64 supported_cmds;
+ /* Name of the admin queue: avq.$vq_index. */
+ char name[10];
+ u16 vq_index;
+};
+
/* Our device structure */
struct virtio_pci_device {
struct virtio_device vdev;
@@ -58,9 +70,13 @@ struct virtio_pci_device {
spinlock_t lock;
struct list_head virtqueues;
- /* array of all queues for house-keeping */
+ /* Array of all virtqueues reported in the
+ * PCI common config num_queues field
+ */
struct virtio_pci_vq_info **vqs;
+ struct virtio_pci_admin_vq admin_vq;
+
/* MSI-X support */
int msix_enabled;
int intx_enabled;
@@ -86,6 +102,7 @@ struct virtio_pci_device {
void (*del_vq)(struct virtio_pci_vq_info *info);
u16 (*config_vector)(struct virtio_pci_device *vp_dev, u16 vector);
+ bool (*is_avq)(struct virtio_device *vdev, unsigned int index);
};
/* Constants for MSI-X */
@@ -139,4 +156,27 @@ static inline void virtio_pci_legacy_remove(struct virtio_pci_device *vp_dev)
int virtio_pci_modern_probe(struct virtio_pci_device *);
void virtio_pci_modern_remove(struct virtio_pci_device *);
+struct virtio_device *virtio_pci_vf_get_pf_dev(struct pci_dev *pdev);
+
+#define VIRTIO_LEGACY_ADMIN_CMD_BITMAP \
+ (BIT_ULL(VIRTIO_ADMIN_CMD_LEGACY_COMMON_CFG_WRITE) | \
+ BIT_ULL(VIRTIO_ADMIN_CMD_LEGACY_COMMON_CFG_READ) | \
+ BIT_ULL(VIRTIO_ADMIN_CMD_LEGACY_DEV_CFG_WRITE) | \
+ BIT_ULL(VIRTIO_ADMIN_CMD_LEGACY_DEV_CFG_READ) | \
+ BIT_ULL(VIRTIO_ADMIN_CMD_LEGACY_NOTIFY_INFO))
+
+/* Unlike modern drivers which support hardware virtio devices, legacy drivers
+ * assume software-based devices: e.g. they don't use proper memory barriers
+ * on ARM, use big endian on PPC, etc. X86 drivers are mostly ok though, more
+ * or less by chance. For now, only support legacy IO on X86.
+ */
+#ifdef CONFIG_VIRTIO_PCI_ADMIN_LEGACY
+#define VIRTIO_ADMIN_CMD_BITMAP VIRTIO_LEGACY_ADMIN_CMD_BITMAP
+#else
+#define VIRTIO_ADMIN_CMD_BITMAP 0
+#endif
+
+int vp_modern_admin_cmd_exec(struct virtio_device *vdev,
+ struct virtio_admin_cmd *cmd);
+
#endif
diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c
index ee6a386d250b..f62b530aa3b5 100644
--- a/drivers/virtio/virtio_pci_modern.c
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -19,6 +19,8 @@
#define VIRTIO_RING_NO_LEGACY
#include "virtio_pci_common.h"
+#define VIRTIO_AVQ_SGS_MAX 4
+
static u64 vp_get_features(struct virtio_device *vdev)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
@@ -26,6 +28,187 @@ static u64 vp_get_features(struct virtio_device *vdev)
return vp_modern_get_features(&vp_dev->mdev);
}
+static bool vp_is_avq(struct virtio_device *vdev, unsigned int index)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+ if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
+ return false;
+
+ return index == vp_dev->admin_vq.vq_index;
+}
+
+static int virtqueue_exec_admin_cmd(struct virtio_pci_admin_vq *admin_vq,
+ u16 opcode,
+ struct scatterlist **sgs,
+ unsigned int out_num,
+ unsigned int in_num,
+ void *data)
+{
+ struct virtqueue *vq;
+ int ret, len;
+
+ vq = admin_vq->info.vq;
+ if (!vq)
+ return -EIO;
+
+ if (opcode != VIRTIO_ADMIN_CMD_LIST_QUERY &&
+ opcode != VIRTIO_ADMIN_CMD_LIST_USE &&
+ !((1ULL << opcode) & admin_vq->supported_cmds))
+ return -EOPNOTSUPP;
+
+ ret = virtqueue_add_sgs(vq, sgs, out_num, in_num, data, GFP_KERNEL);
+ if (ret < 0)
+ return -EIO;
+
+ if (unlikely(!virtqueue_kick(vq)))
+ return -EIO;
+
+ while (!virtqueue_get_buf(vq, &len) &&
+ !virtqueue_is_broken(vq))
+ cpu_relax();
+
+ if (virtqueue_is_broken(vq))
+ return -EIO;
+
+ return 0;
+}
+
+int vp_modern_admin_cmd_exec(struct virtio_device *vdev,
+ struct virtio_admin_cmd *cmd)
+{
+ struct scatterlist *sgs[VIRTIO_AVQ_SGS_MAX], hdr, stat;
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ struct virtio_admin_cmd_status *va_status;
+ unsigned int out_num = 0, in_num = 0;
+ struct virtio_admin_cmd_hdr *va_hdr;
+ u16 status;
+ int ret;
+
+ if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
+ return -EOPNOTSUPP;
+
+ va_status = kzalloc(sizeof(*va_status), GFP_KERNEL);
+ if (!va_status)
+ return -ENOMEM;
+
+ va_hdr = kzalloc(sizeof(*va_hdr), GFP_KERNEL);
+ if (!va_hdr) {
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ va_hdr->opcode = cmd->opcode;
+ va_hdr->group_type = cmd->group_type;
+ va_hdr->group_member_id = cmd->group_member_id;
+
+ /* Add header */
+ sg_init_one(&hdr, va_hdr, sizeof(*va_hdr));
+ sgs[out_num] = &hdr;
+ out_num++;
+
+ if (cmd->data_sg) {
+ sgs[out_num] = cmd->data_sg;
+ out_num++;
+ }
+
+ /* Add return status */
+ sg_init_one(&stat, va_status, sizeof(*va_status));
+ sgs[out_num + in_num] = &stat;
+ in_num++;
+
+ if (cmd->result_sg) {
+ sgs[out_num + in_num] = cmd->result_sg;
+ in_num++;
+ }
+
+ mutex_lock(&vp_dev->admin_vq.cmd_lock);
+ ret = virtqueue_exec_admin_cmd(&vp_dev->admin_vq,
+ le16_to_cpu(cmd->opcode),
+ sgs, out_num, in_num, sgs);
+ mutex_unlock(&vp_dev->admin_vq.cmd_lock);
+
+ if (ret) {
+ dev_err(&vdev->dev,
+ "Failed to execute command on admin vq: %d\n.", ret);
+ goto err_cmd_exec;
+ }
+
+ status = le16_to_cpu(va_status->status);
+ if (status != VIRTIO_ADMIN_STATUS_OK) {
+ dev_err(&vdev->dev,
+ "admin command error: status(%#x) qualifier(%#x)\n",
+ status, le16_to_cpu(va_status->status_qualifier));
+ ret = -status;
+ }
+
+err_cmd_exec:
+ kfree(va_hdr);
+err_alloc:
+ kfree(va_status);
+ return ret;
+}
+
+static void virtio_pci_admin_cmd_list_init(struct virtio_device *virtio_dev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(virtio_dev);
+ struct virtio_admin_cmd cmd = {};
+ struct scatterlist result_sg;
+ struct scatterlist data_sg;
+ __le64 *data;
+ int ret;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return;
+
+ sg_init_one(&result_sg, data, sizeof(*data));
+ cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_LIST_QUERY);
+ cmd.group_type = cpu_to_le16(VIRTIO_ADMIN_GROUP_TYPE_SRIOV);
+ cmd.result_sg = &result_sg;
+
+ ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
+ if (ret)
+ goto end;
+
+ *data &= cpu_to_le64(VIRTIO_ADMIN_CMD_BITMAP);
+ sg_init_one(&data_sg, data, sizeof(*data));
+ cmd.opcode = cpu_to_le16(VIRTIO_ADMIN_CMD_LIST_USE);
+ cmd.data_sg = &data_sg;
+ cmd.result_sg = NULL;
+
+ ret = vp_modern_admin_cmd_exec(virtio_dev, &cmd);
+ if (ret)
+ goto end;
+
+ vp_dev->admin_vq.supported_cmds = le64_to_cpu(*data);
+end:
+ kfree(data);
+}
+
+static void vp_modern_avq_activate(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ struct virtio_pci_admin_vq *admin_vq = &vp_dev->admin_vq;
+
+ if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
+ return;
+
+ __virtqueue_unbreak(admin_vq->info.vq);
+ virtio_pci_admin_cmd_list_init(vdev);
+}
+
+static void vp_modern_avq_deactivate(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ struct virtio_pci_admin_vq *admin_vq = &vp_dev->admin_vq;
+
+ if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
+ return;
+
+ __virtqueue_break(admin_vq->info.vq);
+}
+
static void vp_transport_features(struct virtio_device *vdev, u64 features)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
@@ -37,6 +220,9 @@ static void vp_transport_features(struct virtio_device *vdev, u64 features)
if (features & BIT_ULL(VIRTIO_F_RING_RESET))
__virtio_set_bit(vdev, VIRTIO_F_RING_RESET);
+
+ if (features & BIT_ULL(VIRTIO_F_ADMIN_VQ))
+ __virtio_set_bit(vdev, VIRTIO_F_ADMIN_VQ);
}
static int __vp_check_common_size_one_feature(struct virtio_device *vdev, u32 fbit,
@@ -69,6 +255,9 @@ static int vp_check_common_size(struct virtio_device *vdev)
if (vp_check_common_size_one_feature(vdev, VIRTIO_F_RING_RESET, queue_reset))
return -EINVAL;
+ if (vp_check_common_size_one_feature(vdev, VIRTIO_F_ADMIN_VQ, admin_queue_num))
+ return -EINVAL;
+
return 0;
}
@@ -195,6 +384,8 @@ static void vp_set_status(struct virtio_device *vdev, u8 status)
/* We should never be setting status to 0. */
BUG_ON(status == 0);
vp_modern_set_status(&vp_dev->mdev, status);
+ if (status & VIRTIO_CONFIG_S_DRIVER_OK)
+ vp_modern_avq_activate(vdev);
}
static void vp_reset(struct virtio_device *vdev)
@@ -211,6 +402,9 @@ static void vp_reset(struct virtio_device *vdev)
*/
while (vp_modern_get_status(mdev))
msleep(1);
+
+ vp_modern_avq_deactivate(vdev);
+
/* Flush pending VQ/configuration callbacks. */
vp_synchronize_vectors(vdev);
}
@@ -345,6 +539,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
bool (*notify)(struct virtqueue *vq);
struct virtqueue *vq;
+ bool is_avq;
u16 num;
int err;
@@ -353,11 +548,13 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
else
notify = vp_notify;
- if (index >= vp_modern_get_num_queues(mdev))
+ is_avq = vp_is_avq(&vp_dev->vdev, index);
+ if (index >= vp_modern_get_num_queues(mdev) && !is_avq)
return ERR_PTR(-EINVAL);
+ num = is_avq ?
+ VIRTIO_AVQ_SGS_MAX : vp_modern_get_queue_size(mdev, index);
/* Check if queue is either not available or already active. */
- num = vp_modern_get_queue_size(mdev, index);
if (!num || vp_modern_get_queue_enable(mdev, index))
return ERR_PTR(-ENOENT);
@@ -383,6 +580,12 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
goto err;
}
+ if (is_avq) {
+ mutex_lock(&vp_dev->admin_vq.cmd_lock);
+ vp_dev->admin_vq.info.vq = vq;
+ mutex_unlock(&vp_dev->admin_vq.cmd_lock);
+ }
+
return vq;
err:
@@ -418,6 +621,12 @@ static void del_vq(struct virtio_pci_vq_info *info)
struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
+ if (vp_is_avq(&vp_dev->vdev, vq->index)) {
+ mutex_lock(&vp_dev->admin_vq.cmd_lock);
+ vp_dev->admin_vq.info.vq = NULL;
+ mutex_unlock(&vp_dev->admin_vq.cmd_lock);
+ }
+
if (vp_dev->msix_enabled)
vp_modern_queue_vector(mdev, vq->index,
VIRTIO_MSI_NO_VECTOR);
@@ -527,6 +736,45 @@ static bool vp_get_shm_region(struct virtio_device *vdev,
return true;
}
+static int vp_modern_create_avq(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ struct virtio_pci_admin_vq *avq;
+ struct virtqueue *vq;
+ u16 admin_q_num;
+
+ if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
+ return 0;
+
+ admin_q_num = vp_modern_avq_num(&vp_dev->mdev);
+ if (!admin_q_num)
+ return -EINVAL;
+
+ avq = &vp_dev->admin_vq;
+ avq->vq_index = vp_modern_avq_index(&vp_dev->mdev);
+ sprintf(avq->name, "avq.%u", avq->vq_index);
+ vq = vp_dev->setup_vq(vp_dev, &vp_dev->admin_vq.info, avq->vq_index, NULL,
+ avq->name, NULL, VIRTIO_MSI_NO_VECTOR);
+ if (IS_ERR(vq)) {
+ dev_err(&vdev->dev, "failed to setup admin virtqueue, err=%ld",
+ PTR_ERR(vq));
+ return PTR_ERR(vq);
+ }
+
+ vp_modern_set_queue_enable(&vp_dev->mdev, avq->info.vq->index, true);
+ return 0;
+}
+
+static void vp_modern_destroy_avq(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+ if (!virtio_has_feature(vdev, VIRTIO_F_ADMIN_VQ))
+ return;
+
+ vp_dev->del_vq(&vp_dev->admin_vq.info);
+}
+
static const struct virtio_config_ops virtio_pci_config_nodev_ops = {
.get = NULL,
.set = NULL,
@@ -545,6 +793,8 @@ static const struct virtio_config_ops virtio_pci_config_nodev_ops = {
.get_shm_region = vp_get_shm_region,
.disable_vq_and_reset = vp_modern_disable_vq_and_reset,
.enable_vq_after_reset = vp_modern_enable_vq_after_reset,
+ .create_avq = vp_modern_create_avq,
+ .destroy_avq = vp_modern_destroy_avq,
};
static const struct virtio_config_ops virtio_pci_config_ops = {
@@ -565,6 +815,8 @@ static const struct virtio_config_ops virtio_pci_config_ops = {
.get_shm_region = vp_get_shm_region,
.disable_vq_and_reset = vp_modern_disable_vq_and_reset,
.enable_vq_after_reset = vp_modern_enable_vq_after_reset,
+ .create_avq = vp_modern_create_avq,
+ .destroy_avq = vp_modern_destroy_avq,
};
/* the PCI probing function */
@@ -588,9 +840,11 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev)
vp_dev->config_vector = vp_config_vector;
vp_dev->setup_vq = setup_vq;
vp_dev->del_vq = del_vq;
+ vp_dev->is_avq = vp_is_avq;
vp_dev->isr = mdev->isr;
vp_dev->vdev.id = mdev->id;
+ mutex_init(&vp_dev->admin_vq.cmd_lock);
return 0;
}
@@ -598,5 +852,6 @@ void virtio_pci_modern_remove(struct virtio_pci_device *vp_dev)
{
struct virtio_pci_modern_device *mdev = &vp_dev->mdev;
+ mutex_destroy(&vp_dev->admin_vq.cmd_lock);
vp_modern_remove(mdev);
}
diff --git a/drivers/virtio/virtio_pci_modern_dev.c b/drivers/virtio/virtio_pci_modern_dev.c
index 7de8b1ebabac..0d3dbfaf4b23 100644
--- a/drivers/virtio/virtio_pci_modern_dev.c
+++ b/drivers/virtio/virtio_pci_modern_dev.c
@@ -207,6 +207,10 @@ static inline void check_offsets(void)
offsetof(struct virtio_pci_modern_common_cfg, queue_notify_data));
BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_RESET !=
offsetof(struct virtio_pci_modern_common_cfg, queue_reset));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_ADM_Q_IDX !=
+ offsetof(struct virtio_pci_modern_common_cfg, admin_queue_index));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_ADM_Q_NUM !=
+ offsetof(struct virtio_pci_modern_common_cfg, admin_queue_num));
}
/*
@@ -296,7 +300,7 @@ int vp_modern_probe(struct virtio_pci_modern_device *mdev)
mdev->common = vp_modern_map_capability(mdev, common,
sizeof(struct virtio_pci_common_cfg), 4, 0,
offsetofend(struct virtio_pci_modern_common_cfg,
- queue_reset),
+ admin_queue_num),
&mdev->common_len, NULL);
if (!mdev->common)
goto err_map_common;
@@ -719,6 +723,24 @@ void __iomem *vp_modern_map_vq_notify(struct virtio_pci_modern_device *mdev,
}
EXPORT_SYMBOL_GPL(vp_modern_map_vq_notify);
+u16 vp_modern_avq_num(struct virtio_pci_modern_device *mdev)
+{
+ struct virtio_pci_modern_common_cfg __iomem *cfg;
+
+ cfg = (struct virtio_pci_modern_common_cfg __iomem *)mdev->common;
+ return vp_ioread16(&cfg->admin_queue_num);
+}
+EXPORT_SYMBOL_GPL(vp_modern_avq_num);
+
+u16 vp_modern_avq_index(struct virtio_pci_modern_device *mdev)
+{
+ struct virtio_pci_modern_common_cfg __iomem *cfg;
+
+ cfg = (struct virtio_pci_modern_common_cfg __iomem *)mdev->common;
+ return vp_ioread16(&cfg->admin_queue_index);
+}
+EXPORT_SYMBOL_GPL(vp_modern_avq_index);
+
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("Modern Virtio PCI Device");
MODULE_AUTHOR("Jason Wang <[email protected]>");
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index ad316573288a..513c0b114337 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -5,6 +5,17 @@
menu "1-wire Bus Masters"
+config W1_MASTER_AMD_AXI
+ tristate "AMD AXI 1-wire bus host"
+ help
+ Say Y here is you want to support the AMD AXI 1-wire IP core.
+ This driver makes use of the programmable logic IP to perform
+ correctly timed 1 wire transactions without relying on GPIO timing
+ through the kernel.
+
+ This driver can also be built as a module. If so, the module will be
+ called amd_w1_axi.
+
config W1_MASTER_MATROX
tristate "Matrox G400 transport layer for 1-wire"
depends on PCI
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile
index c5d85a827e52..6c5a21f9b88c 100644
--- a/drivers/w1/masters/Makefile
+++ b/drivers/w1/masters/Makefile
@@ -3,6 +3,7 @@
# Makefile for 1-wire bus master drivers.
#
+obj-$(CONFIG_W1_MASTER_AMD_AXI) += amd_axi_w1.o
obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o
obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o
obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o
diff --git a/drivers/w1/masters/amd_axi_w1.c b/drivers/w1/masters/amd_axi_w1.c
new file mode 100644
index 000000000000..4d3a68ca9263
--- /dev/null
+++ b/drivers/w1/masters/amd_axi_w1.c
@@ -0,0 +1,396 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * amd_axi_w1 - AMD 1Wire programmable logic bus host driver
+ *
+ * Copyright (C) 2022-2023 Advanced Micro Devices, Inc. All Rights Reserved.
+ */
+
+#include <linux/atomic.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include <linux/w1.h>
+
+/* 1-wire AMD IP definition */
+#define AXIW1_IPID 0x10ee4453
+/* Registers offset */
+#define AXIW1_INST_REG 0x0
+#define AXIW1_CTRL_REG 0x4
+#define AXIW1_IRQE_REG 0x8
+#define AXIW1_STAT_REG 0xC
+#define AXIW1_DATA_REG 0x10
+#define AXIW1_IPVER_REG 0x18
+#define AXIW1_IPID_REG 0x1C
+/* Instructions */
+#define AXIW1_INITPRES 0x0800
+#define AXIW1_READBIT 0x0C00
+#define AXIW1_WRITEBIT 0x0E00
+#define AXIW1_READBYTE 0x0D00
+#define AXIW1_WRITEBYTE 0x0F00
+/* Status flag masks */
+#define AXIW1_DONE BIT(0)
+#define AXIW1_READY BIT(4)
+#define AXIW1_PRESENCE BIT(31)
+#define AXIW1_MAJORVER_MASK GENMASK(23, 8)
+#define AXIW1_MINORVER_MASK GENMASK(7, 0)
+/* Control flag */
+#define AXIW1_GO BIT(0)
+#define AXI_CLEAR 0
+#define AXI_RESET BIT(31)
+#define AXIW1_READDATA BIT(0)
+/* Interrupt Enable */
+#define AXIW1_READY_IRQ_EN BIT(4)
+#define AXIW1_DONE_IRQ_EN BIT(0)
+
+#define AXIW1_TIMEOUT msecs_to_jiffies(100)
+
+#define DRIVER_NAME "amd_axi_w1"
+
+struct amd_axi_w1_local {
+ struct device *dev;
+ void __iomem *base_addr;
+ int irq;
+ atomic_t flag; /* Set on IRQ, cleared once serviced */
+ wait_queue_head_t wait_queue;
+ struct w1_bus_master bus_host;
+};
+
+/**
+ * amd_axi_w1_wait_irq_interruptible_timeout() - Wait for IRQ with timeout.
+ *
+ * @amd_axi_w1_local: Pointer to device structure
+ * @IRQ: IRQ channel to wait on
+ *
+ * Return: %0 - OK, %-EINTR - Interrupted, %-EBUSY - Timed out
+ */
+static int amd_axi_w1_wait_irq_interruptible_timeout(struct amd_axi_w1_local *amd_axi_w1_local,
+ u32 IRQ)
+{
+ int ret;
+
+ /* Enable the IRQ requested and wait for flag to indicate it's been triggered */
+ iowrite32(IRQ, amd_axi_w1_local->base_addr + AXIW1_IRQE_REG);
+ ret = wait_event_interruptible_timeout(amd_axi_w1_local->wait_queue,
+ atomic_read(&amd_axi_w1_local->flag) != 0,
+ AXIW1_TIMEOUT);
+ if (ret < 0) {
+ dev_err(amd_axi_w1_local->dev, "Wait IRQ Interrupted\n");
+ return -EINTR;
+ }
+
+ if (!ret) {
+ dev_err(amd_axi_w1_local->dev, "Wait IRQ Timeout\n");
+ return -EBUSY;
+ }
+
+ atomic_set(&amd_axi_w1_local->flag, 0);
+ return 0;
+}
+
+/**
+ * amd_axi_w1_touch_bit() - Performs the touch-bit function - write a 0 or 1 and reads the level.
+ *
+ * @data: Pointer to device structure
+ * @bit: The level to write
+ *
+ * Return: The level read
+ */
+static u8 amd_axi_w1_touch_bit(void *data, u8 bit)
+{
+ struct amd_axi_w1_local *amd_axi_w1_local = data;
+ u8 val = 0;
+ int rc;
+
+ /* Wait for READY signal to be 1 to ensure 1-wire IP is ready */
+ while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_READY) == 0) {
+ rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local,
+ AXIW1_READY_IRQ_EN);
+ if (rc < 0)
+ return 1; /* Callee doesn't test for error. Return inactive bus state */
+ }
+
+ if (bit)
+ /* Read. Write read Bit command in register 0 */
+ iowrite32(AXIW1_READBIT, amd_axi_w1_local->base_addr + AXIW1_INST_REG);
+ else
+ /* Write. Write tx Bit command in instruction register with bit to transmit */
+ iowrite32(AXIW1_WRITEBIT + (bit & 0x01),
+ amd_axi_w1_local->base_addr + AXIW1_INST_REG);
+
+ /* Write Go signal and clear control reset signal in control register */
+ iowrite32(AXIW1_GO, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG);
+
+ /* Wait for done signal to be 1 */
+ while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_DONE) != 1) {
+ rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local, AXIW1_DONE_IRQ_EN);
+ if (rc < 0)
+ return 1; /* Callee doesn't test for error. Return inactive bus state */
+ }
+
+ /* If read, Retrieve data from register */
+ if (bit)
+ val = (u8)(ioread32(amd_axi_w1_local->base_addr + AXIW1_DATA_REG) & AXIW1_READDATA);
+
+ /* Clear Go signal in register 1 */
+ iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG);
+
+ return val;
+}
+
+/**
+ * amd_axi_w1_read_byte - Performs the read byte function.
+ *
+ * @data: Pointer to device structure
+ * Return: The value read
+ */
+static u8 amd_axi_w1_read_byte(void *data)
+{
+ struct amd_axi_w1_local *amd_axi_w1_local = data;
+ u8 val = 0;
+ int rc;
+
+ /* Wait for READY signal to be 1 to ensure 1-wire IP is ready */
+ while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_READY) == 0) {
+ rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local,
+ AXIW1_READY_IRQ_EN);
+ if (rc < 0)
+ return 0xFF; /* Return inactive bus state */
+ }
+
+ /* Write read Byte command in instruction register*/
+ iowrite32(AXIW1_READBYTE, amd_axi_w1_local->base_addr + AXIW1_INST_REG);
+
+ /* Write Go signal and clear control reset signal in control register */
+ iowrite32(AXIW1_GO, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG);
+
+ /* Wait for done signal to be 1 */
+ while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_DONE) != 1) {
+ rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local, AXIW1_DONE_IRQ_EN);
+ if (rc < 0)
+ return 0xFF; /* Return inactive bus state */
+ }
+
+ /* Retrieve LSB bit in data register to get RX byte */
+ val = (u8)(ioread32(amd_axi_w1_local->base_addr + AXIW1_DATA_REG) & 0x000000FF);
+
+ /* Clear Go signal in control register */
+ iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG);
+
+ return val;
+}
+
+/**
+ * amd_axi_w1_write_byte - Performs the write byte function.
+ *
+ * @data: The ds2482 channel pointer
+ * @val: The value to write
+ */
+static void amd_axi_w1_write_byte(void *data, u8 val)
+{
+ struct amd_axi_w1_local *amd_axi_w1_local = data;
+ int rc;
+
+ /* Wait for READY signal to be 1 to ensure 1-wire IP is ready */
+ while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_READY) == 0) {
+ rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local,
+ AXIW1_READY_IRQ_EN);
+ if (rc < 0)
+ return;
+ }
+
+ /* Write tx Byte command in instruction register with bit to transmit */
+ iowrite32(AXIW1_WRITEBYTE + val, amd_axi_w1_local->base_addr + AXIW1_INST_REG);
+
+ /* Write Go signal and clear control reset signal in register 1 */
+ iowrite32(AXIW1_GO, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG);
+
+ /* Wait for done signal to be 1 */
+ while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_DONE) != 1) {
+ rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local,
+ AXIW1_DONE_IRQ_EN);
+ if (rc < 0)
+ return;
+ }
+
+ /* Clear Go signal in control register */
+ iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG);
+}
+
+/**
+ * amd_axi_w1_reset_bus() - Issues a reset bus sequence.
+ *
+ * @data: the bus host data struct
+ * Return: 0=Device present, 1=No device present or error
+ */
+static u8 amd_axi_w1_reset_bus(void *data)
+{
+ struct amd_axi_w1_local *amd_axi_w1_local = data;
+ u8 val = 0;
+ int rc;
+
+ /* Reset 1-wire Axi IP */
+ iowrite32(AXI_RESET, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG);
+
+ /* Wait for READY signal to be 1 to ensure 1-wire IP is ready */
+ while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_READY) == 0) {
+ rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local,
+ AXIW1_READY_IRQ_EN);
+ if (rc < 0)
+ return 1; /* Something went wrong with the hardware */
+ }
+ /* Write Initialization command in instruction register */
+ iowrite32(AXIW1_INITPRES, amd_axi_w1_local->base_addr + AXIW1_INST_REG);
+
+ /* Write Go signal and clear control reset signal in register 1 */
+ iowrite32(AXIW1_GO, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG);
+
+ /* Wait for done signal to be 1 */
+ while ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_DONE) != 1) {
+ rc = amd_axi_w1_wait_irq_interruptible_timeout(amd_axi_w1_local, AXIW1_DONE_IRQ_EN);
+ if (rc < 0)
+ return 1; /* Something went wrong with the hardware */
+ }
+ /* Retrieve MSB bit in status register to get failure bit */
+ if ((ioread32(amd_axi_w1_local->base_addr + AXIW1_STAT_REG) & AXIW1_PRESENCE) != 0)
+ val = 1;
+
+ /* Clear Go signal in control register */
+ iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG);
+
+ return val;
+}
+
+/* Reset the 1-wire AXI IP. Put the IP in reset state and clear registers */
+static void amd_axi_w1_reset(struct amd_axi_w1_local *amd_axi_w1_local)
+{
+ iowrite32(AXI_RESET, amd_axi_w1_local->base_addr + AXIW1_CTRL_REG);
+ iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_INST_REG);
+ iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_IRQE_REG);
+ iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_STAT_REG);
+ iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_DATA_REG);
+}
+
+static irqreturn_t amd_axi_w1_irq(int irq, void *lp)
+{
+ struct amd_axi_w1_local *amd_axi_w1_local = lp;
+
+ /* Reset interrupt trigger */
+ iowrite32(AXI_CLEAR, amd_axi_w1_local->base_addr + AXIW1_IRQE_REG);
+
+ atomic_set(&amd_axi_w1_local->flag, 1);
+ wake_up_interruptible(&amd_axi_w1_local->wait_queue);
+
+ return IRQ_HANDLED;
+}
+
+static int amd_axi_w1_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct amd_axi_w1_local *lp;
+ struct clk *clk;
+ u32 ver_major, ver_minor;
+ int val, rc = 0;
+
+ lp = devm_kzalloc(dev, sizeof(*lp), GFP_KERNEL);
+ if (!lp)
+ return -ENOMEM;
+
+ lp->dev = dev;
+ lp->base_addr = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(lp->base_addr))
+ return PTR_ERR(lp->base_addr);
+
+ lp->irq = platform_get_irq(pdev, 0);
+ if (lp->irq < 0)
+ return lp->irq;
+
+ rc = devm_request_irq(dev, lp->irq, &amd_axi_w1_irq, IRQF_TRIGGER_HIGH, DRIVER_NAME, lp);
+ if (rc)
+ return rc;
+
+ /* Initialize wait queue and flag */
+ init_waitqueue_head(&lp->wait_queue);
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ /* Verify IP presence in HW */
+ if (ioread32(lp->base_addr + AXIW1_IPID_REG) != AXIW1_IPID) {
+ dev_err(dev, "AMD 1-wire IP not detected in hardware\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Allow for future driver expansion supporting new hardware features
+ * This driver currently only supports hardware 1.x, but include logic
+ * to detect if a potentially incompatible future version is used
+ * by reading major version ID. It is highly undesirable for new IP versions
+ * to break the API, but this code will at least allow for graceful failure
+ * should that happen. Future new features can be enabled by hardware
+ * incrementing the minor version and augmenting the driver to detect capability
+ * using the minor version number
+ */
+ val = ioread32(lp->base_addr + AXIW1_IPVER_REG);
+ ver_major = FIELD_GET(AXIW1_MAJORVER_MASK, val);
+ ver_minor = FIELD_GET(AXIW1_MINORVER_MASK, val);
+
+ if (ver_major != 1) {
+ dev_err(dev, "AMD AXI W1 host version %u.%u is not supported by this driver",
+ ver_major, ver_minor);
+ return -ENODEV;
+ }
+
+ lp->bus_host.data = lp;
+ lp->bus_host.touch_bit = amd_axi_w1_touch_bit;
+ lp->bus_host.read_byte = amd_axi_w1_read_byte;
+ lp->bus_host.write_byte = amd_axi_w1_write_byte;
+ lp->bus_host.reset_bus = amd_axi_w1_reset_bus;
+
+ amd_axi_w1_reset(lp);
+
+ platform_set_drvdata(pdev, lp);
+ rc = w1_add_master_device(&lp->bus_host);
+ if (rc) {
+ dev_err(dev, "Could not add host device\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static void amd_axi_w1_remove(struct platform_device *pdev)
+{
+ struct amd_axi_w1_local *lp = platform_get_drvdata(pdev);
+
+ w1_remove_master_device(&lp->bus_host);
+}
+
+static const struct of_device_id amd_axi_w1_of_match[] = {
+ { .compatible = "amd,axi-1wire-host" },
+ { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(of, amd_axi_w1_of_match);
+
+static struct platform_driver amd_axi_w1_driver = {
+ .probe = amd_axi_w1_probe,
+ .remove_new = amd_axi_w1_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = amd_axi_w1_of_match,
+ },
+};
+module_platform_driver(amd_axi_w1_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kris Chaplin <[email protected]>");
+MODULE_DESCRIPTION("Driver for AMD AXI 1 Wire IP core");
diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c
index 5f5b97e24700..e1cac0730cbb 100644
--- a/drivers/w1/masters/ds2490.c
+++ b/drivers/w1/masters/ds2490.c
@@ -98,6 +98,8 @@
#define ST_EPOF 0x80
/* Status transfer size, 16 bytes status, 16 byte result flags */
#define ST_SIZE 0x20
+/* 1-wire data i/o fifo size, 128 bytes */
+#define FIFO_SIZE 0x80
/* Result Register flags */
#define RR_DETECT 0xA5 /* New device detected */
@@ -614,14 +616,11 @@ static int ds_read_byte(struct ds_device *dev, u8 *byte)
return 0;
}
-static int ds_read_block(struct ds_device *dev, u8 *buf, int len)
+static int read_block_chunk(struct ds_device *dev, u8 *buf, int len)
{
struct ds_status st;
int err;
- if (len > 64*1024)
- return -E2BIG;
-
memset(buf, 0xFF, len);
err = ds_send_data(dev, buf, len);
@@ -640,6 +639,24 @@ static int ds_read_block(struct ds_device *dev, u8 *buf, int len)
return err;
}
+static int ds_read_block(struct ds_device *dev, u8 *buf, int len)
+{
+ int err, to_read, rem = len;
+
+ if (len > 64 * 1024)
+ return -E2BIG;
+
+ do {
+ to_read = rem <= FIFO_SIZE ? rem : FIFO_SIZE;
+ err = read_block_chunk(dev, &buf[len - rem], to_read);
+ if (err < 0)
+ return err;
+ rem -= to_read;
+ } while (rem);
+
+ return err;
+}
+
static int ds_write_block(struct ds_device *dev, u8 *buf, int len)
{
int err;
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index e45acb6d916e..05c67038ed20 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -9,7 +9,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/w1-gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of_platform.h>
#include <linux/err.h>
@@ -18,27 +17,33 @@
#include <linux/w1.h>
+struct w1_gpio_ddata {
+ struct gpio_desc *gpiod;
+ struct gpio_desc *pullup_gpiod;
+ unsigned int pullup_duration;
+};
+
static u8 w1_gpio_set_pullup(void *data, int delay)
{
- struct w1_gpio_platform_data *pdata = data;
+ struct w1_gpio_ddata *ddata = data;
if (delay) {
- pdata->pullup_duration = delay;
+ ddata->pullup_duration = delay;
} else {
- if (pdata->pullup_duration) {
+ if (ddata->pullup_duration) {
/*
* This will OVERRIDE open drain emulation and force-pull
* the line high for some time.
*/
- gpiod_set_raw_value(pdata->gpiod, 1);
- msleep(pdata->pullup_duration);
+ gpiod_set_raw_value(ddata->gpiod, 1);
+ msleep(ddata->pullup_duration);
/*
* This will simply set the line as input since we are doing
* open drain emulation in the GPIO library.
*/
- gpiod_set_value(pdata->gpiod, 1);
+ gpiod_set_value(ddata->gpiod, 1);
}
- pdata->pullup_duration = 0;
+ ddata->pullup_duration = 0;
}
return 0;
@@ -46,16 +51,16 @@ static u8 w1_gpio_set_pullup(void *data, int delay)
static void w1_gpio_write_bit(void *data, u8 bit)
{
- struct w1_gpio_platform_data *pdata = data;
+ struct w1_gpio_ddata *ddata = data;
- gpiod_set_value(pdata->gpiod, bit);
+ gpiod_set_value(ddata->gpiod, bit);
}
static u8 w1_gpio_read_bit(void *data)
{
- struct w1_gpio_platform_data *pdata = data;
+ struct w1_gpio_ddata *ddata = data;
- return gpiod_get_value(pdata->gpiod) ? 1 : 0;
+ return gpiod_get_value(ddata->gpiod) ? 1 : 0;
}
#if defined(CONFIG_OF)
@@ -69,58 +74,48 @@ MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids);
static int w1_gpio_probe(struct platform_device *pdev)
{
struct w1_bus_master *master;
- struct w1_gpio_platform_data *pdata;
+ struct w1_gpio_ddata *ddata;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
/* Enforce open drain mode by default */
enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
int err;
- if (of_have_populated_dt()) {
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
-
- /*
- * This parameter means that something else than the gpiolib has
- * already set the line into open drain mode, so we should just
- * driver it high/low like we are in full control of the line and
- * open drain will happen transparently.
- */
- if (of_property_present(np, "linux,open-drain"))
- gflags = GPIOD_OUT_LOW;
-
- pdev->dev.platform_data = pdata;
- }
- pdata = dev_get_platdata(dev);
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
- if (!pdata) {
- dev_err(dev, "No configuration data\n");
- return -ENXIO;
- }
+ /*
+ * This parameter means that something else than the gpiolib has
+ * already set the line into open drain mode, so we should just
+ * driver it high/low like we are in full control of the line and
+ * open drain will happen transparently.
+ */
+ if (of_property_present(np, "linux,open-drain"))
+ gflags = GPIOD_OUT_LOW;
master = devm_kzalloc(dev, sizeof(struct w1_bus_master),
GFP_KERNEL);
if (!master)
return -ENOMEM;
- pdata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags);
- if (IS_ERR(pdata->gpiod)) {
+ ddata->gpiod = devm_gpiod_get_index(dev, NULL, 0, gflags);
+ if (IS_ERR(ddata->gpiod)) {
dev_err(dev, "gpio_request (pin) failed\n");
- return PTR_ERR(pdata->gpiod);
+ return PTR_ERR(ddata->gpiod);
}
- pdata->pullup_gpiod =
+ ddata->pullup_gpiod =
devm_gpiod_get_index_optional(dev, NULL, 1, GPIOD_OUT_LOW);
- if (IS_ERR(pdata->pullup_gpiod)) {
+ if (IS_ERR(ddata->pullup_gpiod)) {
dev_err(dev, "gpio_request_one "
"(ext_pullup_enable_pin) failed\n");
- return PTR_ERR(pdata->pullup_gpiod);
+ return PTR_ERR(ddata->pullup_gpiod);
}
- master->data = pdata;
+ master->data = ddata;
master->read_bit = w1_gpio_read_bit;
- gpiod_direction_output(pdata->gpiod, 1);
+ gpiod_direction_output(ddata->gpiod, 1);
master->write_bit = w1_gpio_write_bit;
/*
@@ -138,11 +133,8 @@ static int w1_gpio_probe(struct platform_device *pdev)
return err;
}
- if (pdata->enable_external_pullup)
- pdata->enable_external_pullup(1);
-
- if (pdata->pullup_gpiod)
- gpiod_set_value(pdata->pullup_gpiod, 1);
+ if (ddata->pullup_gpiod)
+ gpiod_set_value(ddata->pullup_gpiod, 1);
platform_set_drvdata(pdev, master);
@@ -152,45 +144,19 @@ static int w1_gpio_probe(struct platform_device *pdev)
static int w1_gpio_remove(struct platform_device *pdev)
{
struct w1_bus_master *master = platform_get_drvdata(pdev);
- struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
-
- if (pdata->enable_external_pullup)
- pdata->enable_external_pullup(0);
+ struct w1_gpio_ddata *ddata = master->data;
- if (pdata->pullup_gpiod)
- gpiod_set_value(pdata->pullup_gpiod, 0);
+ if (ddata->pullup_gpiod)
+ gpiod_set_value(ddata->pullup_gpiod, 0);
w1_remove_master_device(master);
return 0;
}
-static int __maybe_unused w1_gpio_suspend(struct device *dev)
-{
- struct w1_gpio_platform_data *pdata = dev_get_platdata(dev);
-
- if (pdata->enable_external_pullup)
- pdata->enable_external_pullup(0);
-
- return 0;
-}
-
-static int __maybe_unused w1_gpio_resume(struct device *dev)
-{
- struct w1_gpio_platform_data *pdata = dev_get_platdata(dev);
-
- if (pdata->enable_external_pullup)
- pdata->enable_external_pullup(1);
-
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(w1_gpio_pm_ops, w1_gpio_suspend, w1_gpio_resume);
-
static struct platform_driver w1_gpio_driver = {
.driver = {
.name = "w1-gpio",
- .pm = &w1_gpio_pm_ops,
.of_match_table = of_match_ptr(w1_gpio_dt_ids),
},
.probe = w1_gpio_probe,
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c
index 9f21fd98f799..250b7f7ec429 100644
--- a/drivers/w1/slaves/w1_ds2433.c
+++ b/drivers/w1/slaves/w1_ds2433.c
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * w1_ds2433.c - w1 family 23 (DS2433) driver
+ * w1_ds2433.c - w1 family 23 (DS2433) & 43 (DS28EC20) eeprom driver
*
* Copyright (c) 2005 Ben Gardner <[email protected]>
+ * Copyright (c) 2023 Marc Ferland <[email protected]>
*/
#include <linux/kernel.h>
@@ -23,23 +24,45 @@
#include <linux/w1.h>
#define W1_EEPROM_DS2433 0x23
+#define W1_EEPROM_DS28EC20 0x43
+
+#define W1_EEPROM_DS2433_SIZE 512
+#define W1_EEPROM_DS28EC20_SIZE 2560
-#define W1_EEPROM_SIZE 512
-#define W1_PAGE_COUNT 16
#define W1_PAGE_SIZE 32
#define W1_PAGE_BITS 5
#define W1_PAGE_MASK 0x1F
-
-#define W1_F23_TIME 300
+#define W1_VALIDCRC_MAX 96
#define W1_F23_READ_EEPROM 0xF0
#define W1_F23_WRITE_SCRATCH 0x0F
#define W1_F23_READ_SCRATCH 0xAA
#define W1_F23_COPY_SCRATCH 0x55
+struct ds2433_config {
+ size_t eeprom_size; /* eeprom size in bytes */
+ unsigned int page_count; /* number of 256 bits pages */
+ unsigned int tprog; /* time in ms for page programming */
+};
+
+static const struct ds2433_config config_f23 = {
+ .eeprom_size = W1_EEPROM_DS2433_SIZE,
+ .page_count = 16,
+ .tprog = 5,
+};
+
+static const struct ds2433_config config_f43 = {
+ .eeprom_size = W1_EEPROM_DS28EC20_SIZE,
+ .page_count = 80,
+ .tprog = 10,
+};
+
struct w1_f23_data {
- u8 memory[W1_EEPROM_SIZE];
- u32 validcrc;
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+ u8 *memory;
+ DECLARE_BITMAP(validcrc, W1_VALIDCRC_MAX);
+#endif
+ const struct ds2433_config *cfg;
};
/*
@@ -64,11 +87,11 @@ static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
u8 wrbuf[3];
int off = block * W1_PAGE_SIZE;
- if (data->validcrc & (1 << block))
+ if (test_bit(block, data->validcrc))
return 0;
if (w1_reset_select_slave(sl)) {
- data->validcrc = 0;
+ bitmap_zero(data->validcrc, data->cfg->page_count);
return -EIO;
}
@@ -80,7 +103,7 @@ static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
/* cache the block if the CRC is valid */
if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID)
- data->validcrc |= (1 << block);
+ set_bit(block, data->validcrc);
return 0;
}
@@ -98,7 +121,7 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
u8 wrbuf[3];
#endif
- count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE);
+ count = w1_f23_fix_count(off, count, bin_attr->size);
if (!count)
return 0;
@@ -153,9 +176,7 @@ out_up:
*/
static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
{
-#ifdef CONFIG_W1_SLAVE_DS2433_CRC
struct w1_f23_data *f23 = sl->family_data;
-#endif
u8 wrbuf[4];
u8 rdbuf[W1_PAGE_SIZE + 3];
u8 es = (addr + len - 1) & 0x1f;
@@ -191,13 +212,13 @@ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
wrbuf[3] = es;
w1_write_block(sl->master, wrbuf, 4);
- /* Sleep for 5 ms to wait for the write to complete */
- msleep(5);
+ /* Sleep for tprog ms to wait for the write to complete */
+ msleep(f23->cfg->tprog);
/* Reset the bus to wake up the EEPROM (this may not be needed) */
w1_reset_bus(sl->master);
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
- f23->validcrc &= ~(1 << (addr >> W1_PAGE_BITS));
+ clear_bit(addr >> W1_PAGE_BITS, f23->validcrc);
#endif
return 0;
}
@@ -209,7 +230,7 @@ static ssize_t eeprom_write(struct file *filp, struct kobject *kobj,
struct w1_slave *sl = kobj_to_w1_slave(kobj);
int addr, len, idx;
- count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE);
+ count = w1_f23_fix_count(off, count, bin_attr->size);
if (!count)
return 0;
@@ -253,10 +274,22 @@ out_up:
return count;
}
-static BIN_ATTR_RW(eeprom, W1_EEPROM_SIZE);
+static struct bin_attribute bin_attr_f23_eeprom = {
+ .attr = { .name = "eeprom", .mode = 0644 },
+ .read = eeprom_read,
+ .write = eeprom_write,
+ .size = W1_EEPROM_DS2433_SIZE,
+};
+
+static struct bin_attribute bin_attr_f43_eeprom = {
+ .attr = { .name = "eeprom", .mode = 0644 },
+ .read = eeprom_read,
+ .write = eeprom_write,
+ .size = W1_EEPROM_DS28EC20_SIZE,
+};
static struct bin_attribute *w1_f23_bin_attributes[] = {
- &bin_attr_eeprom,
+ &bin_attr_f23_eeprom,
NULL,
};
@@ -269,26 +302,63 @@ static const struct attribute_group *w1_f23_groups[] = {
NULL,
};
+static struct bin_attribute *w1_f43_bin_attributes[] = {
+ &bin_attr_f43_eeprom,
+ NULL,
+};
+
+static const struct attribute_group w1_f43_group = {
+ .bin_attrs = w1_f43_bin_attributes,
+};
+
+static const struct attribute_group *w1_f43_groups[] = {
+ &w1_f43_group,
+ NULL,
+};
+
static int w1_f23_add_slave(struct w1_slave *sl)
{
-#ifdef CONFIG_W1_SLAVE_DS2433_CRC
struct w1_f23_data *data;
data = kzalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
+
+ switch (sl->family->fid) {
+ case W1_EEPROM_DS2433:
+ data->cfg = &config_f23;
+ break;
+ case W1_EEPROM_DS28EC20:
+ data->cfg = &config_f43;
+ break;
+ }
+
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+ if (data->cfg->page_count > W1_VALIDCRC_MAX) {
+ dev_err(&sl->dev, "page count too big for crc bitmap\n");
+ kfree(data);
+ return -EINVAL;
+ }
+ data->memory = kzalloc(data->cfg->eeprom_size, GFP_KERNEL);
+ if (!data->memory) {
+ kfree(data);
+ return -ENOMEM;
+ }
+ bitmap_zero(data->validcrc, data->cfg->page_count);
+#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
sl->family_data = data;
-#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
return 0;
}
static void w1_f23_remove_slave(struct w1_slave *sl)
{
-#ifdef CONFIG_W1_SLAVE_DS2433_CRC
- kfree(sl->family_data);
+ struct w1_f23_data *data = sl->family_data;
sl->family_data = NULL;
-#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+ kfree(data->memory);
+#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
+ kfree(data);
}
static const struct w1_family_ops w1_f23_fops = {
@@ -297,13 +367,53 @@ static const struct w1_family_ops w1_f23_fops = {
.groups = w1_f23_groups,
};
+static const struct w1_family_ops w1_f43_fops = {
+ .add_slave = w1_f23_add_slave,
+ .remove_slave = w1_f23_remove_slave,
+ .groups = w1_f43_groups,
+};
+
static struct w1_family w1_family_23 = {
.fid = W1_EEPROM_DS2433,
.fops = &w1_f23_fops,
};
-module_w1_family(w1_family_23);
+
+static struct w1_family w1_family_43 = {
+ .fid = W1_EEPROM_DS28EC20,
+ .fops = &w1_f43_fops,
+};
+
+static int __init w1_ds2433_init(void)
+{
+ int err;
+
+ err = w1_register_family(&w1_family_23);
+ if (err)
+ return err;
+
+ err = w1_register_family(&w1_family_43);
+ if (err)
+ goto err_43;
+
+ return 0;
+
+err_43:
+ w1_unregister_family(&w1_family_23);
+ return err;
+}
+
+static void __exit w1_ds2433_exit(void)
+{
+ w1_unregister_family(&w1_family_23);
+ w1_unregister_family(&w1_family_43);
+}
+
+module_init(w1_ds2433_init);
+module_exit(w1_ds2433_exit);
MODULE_AUTHOR("Ben Gardner <[email protected]>");
-MODULE_DESCRIPTION("w1 family 23 driver for DS2433, 4kb EEPROM");
+MODULE_AUTHOR("Marc Ferland <[email protected]>");
+MODULE_DESCRIPTION("w1 family 23/43 driver for DS2433 (4kb) and DS28EC20 (20kb)");
MODULE_LICENSE("GPL");
MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS2433));
+MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS28EC20));
diff --git a/drivers/xen/gntdev-dmabuf.c b/drivers/xen/gntdev-dmabuf.c
index 4440e626b797..42adc2c1e06b 100644
--- a/drivers/xen/gntdev-dmabuf.c
+++ b/drivers/xen/gntdev-dmabuf.c
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/dma-buf.h>
+#include <linux/dma-direct.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/uaccess.h>
@@ -50,7 +51,7 @@ struct gntdev_dmabuf {
/* Number of pages this buffer has. */
int nr_pages;
- /* Pages of this buffer. */
+ /* Pages of this buffer (only for dma-buf export). */
struct page **pages;
};
@@ -484,7 +485,7 @@ out:
/* DMA buffer import support. */
static int
-dmabuf_imp_grant_foreign_access(struct page **pages, u32 *refs,
+dmabuf_imp_grant_foreign_access(unsigned long *gfns, u32 *refs,
int count, int domid)
{
grant_ref_t priv_gref_head;
@@ -507,7 +508,7 @@ dmabuf_imp_grant_foreign_access(struct page **pages, u32 *refs,
}
gnttab_grant_foreign_access_ref(cur_ref, domid,
- xen_page_to_gfn(pages[i]), 0);
+ gfns[i], 0);
refs[i] = cur_ref;
}
@@ -529,7 +530,6 @@ static void dmabuf_imp_end_foreign_access(u32 *refs, int count)
static void dmabuf_imp_free_storage(struct gntdev_dmabuf *gntdev_dmabuf)
{
- kfree(gntdev_dmabuf->pages);
kfree(gntdev_dmabuf->u.imp.refs);
kfree(gntdev_dmabuf);
}
@@ -549,12 +549,6 @@ static struct gntdev_dmabuf *dmabuf_imp_alloc_storage(int count)
if (!gntdev_dmabuf->u.imp.refs)
goto fail;
- gntdev_dmabuf->pages = kcalloc(count,
- sizeof(gntdev_dmabuf->pages[0]),
- GFP_KERNEL);
- if (!gntdev_dmabuf->pages)
- goto fail;
-
gntdev_dmabuf->nr_pages = count;
for (i = 0; i < count; i++)
@@ -576,7 +570,8 @@ dmabuf_imp_to_refs(struct gntdev_dmabuf_priv *priv, struct device *dev,
struct dma_buf *dma_buf;
struct dma_buf_attachment *attach;
struct sg_table *sgt;
- struct sg_page_iter sg_iter;
+ struct sg_dma_page_iter sg_iter;
+ unsigned long *gfns;
int i;
dma_buf = dma_buf_get(fd);
@@ -624,26 +619,31 @@ dmabuf_imp_to_refs(struct gntdev_dmabuf_priv *priv, struct device *dev,
gntdev_dmabuf->u.imp.sgt = sgt;
- /* Now convert sgt to array of pages and check for page validity. */
+ gfns = kcalloc(count, sizeof(*gfns), GFP_KERNEL);
+ if (!gfns) {
+ ret = ERR_PTR(-ENOMEM);
+ goto fail_unmap;
+ }
+
+ /*
+ * Now convert sgt to array of gfns without accessing underlying pages.
+ * It is not allowed to access the underlying struct page of an sg table
+ * exported by DMA-buf, but since we deal with special Xen dma device here
+ * (not a normal physical one) look at the dma addresses in the sg table
+ * and then calculate gfns directly from them.
+ */
i = 0;
- for_each_sgtable_page(sgt, &sg_iter, 0) {
- struct page *page = sg_page_iter_page(&sg_iter);
- /*
- * Check if page is valid: this can happen if we are given
- * a page from VRAM or other resources which are not backed
- * by a struct page.
- */
- if (!pfn_valid(page_to_pfn(page))) {
- ret = ERR_PTR(-EINVAL);
- goto fail_unmap;
- }
+ for_each_sgtable_dma_page(sgt, &sg_iter, 0) {
+ dma_addr_t addr = sg_page_iter_dma_address(&sg_iter);
+ unsigned long pfn = bfn_to_pfn(XEN_PFN_DOWN(dma_to_phys(dev, addr)));
- gntdev_dmabuf->pages[i++] = page;
+ gfns[i++] = pfn_to_gfn(pfn);
}
- ret = ERR_PTR(dmabuf_imp_grant_foreign_access(gntdev_dmabuf->pages,
+ ret = ERR_PTR(dmabuf_imp_grant_foreign_access(gfns,
gntdev_dmabuf->u.imp.refs,
count, domid));
+ kfree(gfns);
if (IS_ERR(ret))
goto fail_end_access;
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
index d4b251925796..32835b4b9bc5 100644
--- a/drivers/xen/xenbus/xenbus_client.c
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -119,11 +119,13 @@ EXPORT_SYMBOL_GPL(xenbus_strstate);
* @callback: callback to register
*
* Register a @watch on the given path, using the given xenbus_watch structure
- * for storage, and the given @callback function as the callback. Return 0 on
- * success, or -errno on error. On success, the given @path will be saved as
- * @watch->node, and remains the caller's to free. On error, @watch->node will
+ * for storage, and the given @callback function as the callback. On success,
+ * the given @path will be saved as @watch->node, and remains the
+ * caller's to free. On error, @watch->node will
* be NULL, the device will switch to %XenbusStateClosing, and the error will
* be saved in the store.
+ *
+ * Returns: %0 on success or -errno on error
*/
int xenbus_watch_path(struct xenbus_device *dev, const char *path,
struct xenbus_watch *watch,
@@ -160,12 +162,14 @@ EXPORT_SYMBOL_GPL(xenbus_watch_path);
* @pathfmt: format of path to watch
*
* Register a watch on the given @path, using the given xenbus_watch
- * structure for storage, and the given @callback function as the callback.
- * Return 0 on success, or -errno on error. On success, the watched path
- * (@path/@path2) will be saved as @watch->node, and becomes the caller's to
- * kfree(). On error, watch->node will be NULL, so the caller has nothing to
+ * structure for storage, and the given @callback function as the
+ * callback. On success, the watched path (@path/@path2) will be saved
+ * as @watch->node, and becomes the caller's to kfree().
+ * On error, watch->node will be NULL, so the caller has nothing to
* free, the device will switch to %XenbusStateClosing, and the error will be
* saved in the store.
+ *
+ * Returns: %0 on success or -errno on error
*/
int xenbus_watch_pathfmt(struct xenbus_device *dev,
struct xenbus_watch *watch,
@@ -255,13 +259,15 @@ abort:
}
/**
- * xenbus_switch_state
+ * xenbus_switch_state - save the new state of a driver
* @dev: xenbus device
* @state: new state
*
* Advertise in the store a change of the given driver to the given new_state.
- * Return 0 on success, or -errno on error. On error, the device will switch
- * to XenbusStateClosing, and the error will be saved in the store.
+ * On error, the device will switch to XenbusStateClosing, and the error
+ * will be saved in the store.
+ *
+ * Returns: %0 on success or -errno on error
*/
int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
{
@@ -305,7 +311,7 @@ static void xenbus_va_dev_error(struct xenbus_device *dev, int err,
}
/**
- * xenbus_dev_error
+ * xenbus_dev_error - place an error message into the store
* @dev: xenbus device
* @err: error to report
* @fmt: error message format
@@ -324,7 +330,7 @@ void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...)
EXPORT_SYMBOL_GPL(xenbus_dev_error);
/**
- * xenbus_dev_fatal
+ * xenbus_dev_fatal - put an error messages into the store and then shutdown
* @dev: xenbus device
* @err: error to report
* @fmt: error message format
@@ -346,7 +352,7 @@ void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...)
}
EXPORT_SYMBOL_GPL(xenbus_dev_fatal);
-/**
+/*
* Equivalent to xenbus_dev_fatal(dev, err, fmt, args), but helps
* avoiding recursion within xenbus_switch_state.
*/
@@ -453,7 +459,7 @@ void xenbus_teardown_ring(void **vaddr, unsigned int nr_pages,
}
EXPORT_SYMBOL_GPL(xenbus_teardown_ring);
-/**
+/*
* Allocate an event channel for the given xenbus_device, assigning the newly
* created local port to *port. Return 0 on success, or -errno on error. On
* error, the device will switch to XenbusStateClosing, and the error will be
@@ -479,7 +485,7 @@ int xenbus_alloc_evtchn(struct xenbus_device *dev, evtchn_port_t *port)
EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn);
-/**
+/*
* Free an existing event channel. Returns 0 on success or -errno on error.
*/
int xenbus_free_evtchn(struct xenbus_device *dev, evtchn_port_t port)
@@ -499,7 +505,7 @@ EXPORT_SYMBOL_GPL(xenbus_free_evtchn);
/**
- * xenbus_map_ring_valloc
+ * xenbus_map_ring_valloc - allocate & map pages of VA space
* @dev: xenbus device
* @gnt_refs: grant reference array
* @nr_grefs: number of grant references
@@ -507,10 +513,11 @@ EXPORT_SYMBOL_GPL(xenbus_free_evtchn);
*
* Map @nr_grefs pages of memory into this domain from another
* domain's grant table. xenbus_map_ring_valloc allocates @nr_grefs
- * pages of virtual address space, maps the pages to that address, and
- * sets *vaddr to that address. Returns 0 on success, and -errno on
- * error. If an error is returned, device will switch to
+ * pages of virtual address space, maps the pages to that address, and sets
+ * *vaddr to that address. If an error is returned, device will switch to
* XenbusStateClosing and the error message will be saved in XenStore.
+ *
+ * Returns: %0 on success or -errno on error
*/
int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs,
unsigned int nr_grefs, void **vaddr)
@@ -599,14 +606,15 @@ static int __xenbus_map_ring(struct xenbus_device *dev,
}
/**
- * xenbus_unmap_ring
+ * xenbus_unmap_ring - unmap memory from another domain
* @dev: xenbus device
* @handles: grant handle array
* @nr_handles: number of handles in the array
* @vaddrs: addresses to unmap
*
* Unmap memory in this domain that was imported from another domain.
- * Returns 0 on success and returns GNTST_* on error
+ *
+ * Returns: %0 on success or GNTST_* on error
* (see xen/include/interface/grant_table.h).
*/
static int xenbus_unmap_ring(struct xenbus_device *dev, grant_handle_t *handles,
@@ -712,7 +720,7 @@ static int xenbus_map_ring_hvm(struct xenbus_device *dev,
}
/**
- * xenbus_unmap_ring_vfree
+ * xenbus_unmap_ring_vfree - unmap a page of memory from another domain
* @dev: xenbus device
* @vaddr: addr to unmap
*
@@ -720,7 +728,8 @@ static int xenbus_map_ring_hvm(struct xenbus_device *dev,
* Unmap a page of memory in this domain that was imported from another domain.
* Use xenbus_unmap_ring_vfree if you mapped in your memory with
* xenbus_map_ring_valloc (it will free the virtual address space).
- * Returns 0 on success and returns GNTST_* on error
+ *
+ * Returns: %0 on success or GNTST_* on error
* (see xen/include/interface/grant_table.h).
*/
int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
@@ -916,10 +925,10 @@ static int xenbus_unmap_ring_hvm(struct xenbus_device *dev, void *vaddr)
}
/**
- * xenbus_read_driver_state
+ * xenbus_read_driver_state - read state from a store path
* @path: path for driver
*
- * Return the state of the driver rooted at the given store path, or
+ * Returns: the state of the driver rooted at the given store path, or
* XenbusStateUnknown if no state can be read.
*/
enum xenbus_state xenbus_read_driver_state(const char *path)
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index d26222b7eefe..0496cb5b6eab 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -79,7 +79,7 @@ static struct file *__anon_inode_getfile(const char *name,
const struct file_operations *fops,
void *priv, int flags,
const struct inode *context_inode,
- bool secure)
+ bool make_inode)
{
struct inode *inode;
struct file *file;
@@ -87,7 +87,7 @@ static struct file *__anon_inode_getfile(const char *name,
if (fops->owner && !try_module_get(fops->owner))
return ERR_PTR(-ENOENT);
- if (secure) {
+ if (make_inode) {
inode = anon_inode_make_secure_inode(name, context_inode);
if (IS_ERR(inode)) {
file = ERR_CAST(inode);
@@ -149,13 +149,10 @@ struct file *anon_inode_getfile(const char *name,
EXPORT_SYMBOL_GPL(anon_inode_getfile);
/**
- * anon_inode_getfile_secure - Like anon_inode_getfile(), but creates a new
+ * anon_inode_create_getfile - Like anon_inode_getfile(), but creates a new
* !S_PRIVATE anon inode rather than reuse the
* singleton anon inode and calls the
- * inode_init_security_anon() LSM hook. This
- * allows for both the inode to have its own
- * security context and for the LSM to enforce
- * policy on the inode's creation.
+ * inode_init_security_anon() LSM hook.
*
* @name: [in] name of the "class" of the new file
* @fops: [in] file operations for the new file
@@ -164,11 +161,21 @@ EXPORT_SYMBOL_GPL(anon_inode_getfile);
* @context_inode:
* [in] the logical relationship with the new inode (optional)
*
+ * Create a new anonymous inode and file pair. This can be done for two
+ * reasons:
+ *
+ * - for the inode to have its own security context, so that LSMs can enforce
+ * policy on the inode's creation;
+ *
+ * - if the caller needs a unique inode, for example in order to customize
+ * the size returned by fstat()
+ *
* The LSM may use @context_inode in inode_init_security_anon(), but a
- * reference to it is not held. Returns the newly created file* or an error
- * pointer. See the anon_inode_getfile() documentation for more information.
+ * reference to it is not held.
+ *
+ * Returns the newly created file* or an error pointer.
*/
-struct file *anon_inode_getfile_secure(const char *name,
+struct file *anon_inode_create_getfile(const char *name,
const struct file_operations *fops,
void *priv, int flags,
const struct inode *context_inode)
@@ -176,12 +183,13 @@ struct file *anon_inode_getfile_secure(const char *name,
return __anon_inode_getfile(name, fops, priv, flags,
context_inode, true);
}
+EXPORT_SYMBOL_GPL(anon_inode_create_getfile);
static int __anon_inode_getfd(const char *name,
const struct file_operations *fops,
void *priv, int flags,
const struct inode *context_inode,
- bool secure)
+ bool make_inode)
{
int error, fd;
struct file *file;
@@ -192,7 +200,7 @@ static int __anon_inode_getfd(const char *name,
fd = error;
file = __anon_inode_getfile(name, fops, priv, flags, context_inode,
- secure);
+ make_inode);
if (IS_ERR(file)) {
error = PTR_ERR(file);
goto err_put_unused_fd;
@@ -231,10 +239,9 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
EXPORT_SYMBOL_GPL(anon_inode_getfd);
/**
- * anon_inode_getfd_secure - Like anon_inode_getfd(), but creates a new
+ * anon_inode_create_getfd - Like anon_inode_getfd(), but creates a new
* !S_PRIVATE anon inode rather than reuse the singleton anon inode, and calls
- * the inode_init_security_anon() LSM hook. This allows the inode to have its
- * own security context and for a LSM to reject creation of the inode.
+ * the inode_init_security_anon() LSM hook.
*
* @name: [in] name of the "class" of the new file
* @fops: [in] file operations for the new file
@@ -243,16 +250,26 @@ EXPORT_SYMBOL_GPL(anon_inode_getfd);
* @context_inode:
* [in] the logical relationship with the new inode (optional)
*
+ * Create a new anonymous inode and file pair. This can be done for two
+ * reasons:
+ *
+ * - for the inode to have its own security context, so that LSMs can enforce
+ * policy on the inode's creation;
+ *
+ * - if the caller needs a unique inode, for example in order to customize
+ * the size returned by fstat()
+ *
* The LSM may use @context_inode in inode_init_security_anon(), but a
* reference to it is not held.
+ *
+ * Returns a newly created file descriptor or an error code.
*/
-int anon_inode_getfd_secure(const char *name, const struct file_operations *fops,
+int anon_inode_create_getfd(const char *name, const struct file_operations *fops,
void *priv, int flags,
const struct inode *context_inode)
{
return __anon_inode_getfd(name, fops, priv, flags, context_inode, true);
}
-EXPORT_SYMBOL_GPL(anon_inode_getfd_secure);
static int __init anon_inode_init(void)
{
diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c
index 946cc610eef5..1cbc5807bc80 100644
--- a/fs/bcachefs/fs-ioctl.c
+++ b/fs/bcachefs/fs-ioctl.c
@@ -443,33 +443,36 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
struct bch_ioctl_subvolume arg)
{
+ const char __user *name = (void __user *)(unsigned long)arg.dst_ptr;
struct path path;
struct inode *dir;
+ struct dentry *victim;
int ret = 0;
if (arg.flags)
return -EINVAL;
- ret = user_path_at(arg.dirfd,
- (const char __user *)(unsigned long)arg.dst_ptr,
- LOOKUP_FOLLOW, &path);
- if (ret)
- return ret;
+ victim = user_path_locked_at(arg.dirfd, name, &path);
+ if (IS_ERR(victim))
+ return PTR_ERR(victim);
- if (path.dentry->d_sb->s_fs_info != c) {
+ if (victim->d_sb->s_fs_info != c) {
ret = -EXDEV;
goto err;
}
-
- dir = path.dentry->d_parent->d_inode;
-
- ret = __bch2_unlink(dir, path.dentry, true);
- if (ret)
+ if (!d_is_positive(victim)) {
+ ret = -ENOENT;
goto err;
-
- fsnotify_rmdir(dir, path.dentry);
- d_delete(path.dentry);
+ }
+ dir = d_inode(path.dentry);
+ ret = __bch2_unlink(dir, victim, true);
+ if (!ret) {
+ fsnotify_rmdir(dir, victim);
+ d_delete(victim);
+ }
+ inode_unlock(dir);
err:
+ dput(victim);
path_put(&path);
return ret;
}
diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c
index e918decb3735..0356c88252bd 100644
--- a/fs/exfat/balloc.c
+++ b/fs/exfat/balloc.c
@@ -5,42 +5,23 @@
#include <linux/blkdev.h>
#include <linux/slab.h>
+#include <linux/bitmap.h>
#include <linux/buffer_head.h>
#include "exfat_raw.h"
#include "exfat_fs.h"
-static const unsigned char free_bit[] = {
- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/* 0 ~ 19*/
- 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3,/* 20 ~ 39*/
- 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/* 40 ~ 59*/
- 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/* 60 ~ 79*/
- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2,/* 80 ~ 99*/
- 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3,/*100 ~ 119*/
- 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*120 ~ 139*/
- 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,/*140 ~ 159*/
- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/*160 ~ 179*/
- 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3,/*180 ~ 199*/
- 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*200 ~ 219*/
- 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/*220 ~ 239*/
- 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /*240 ~ 254*/
-};
-
-static const unsigned char used_bit[] = {
- 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3,/* 0 ~ 19*/
- 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4,/* 20 ~ 39*/
- 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,/* 40 ~ 59*/
- 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,/* 60 ~ 79*/
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,/* 80 ~ 99*/
- 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,/*100 ~ 119*/
- 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,/*120 ~ 139*/
- 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,/*140 ~ 159*/
- 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,/*160 ~ 179*/
- 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,/*180 ~ 199*/
- 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,/*200 ~ 219*/
- 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,/*220 ~ 239*/
- 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 /*240 ~ 255*/
-};
+#if BITS_PER_LONG == 32
+#define __le_long __le32
+#define lel_to_cpu(A) le32_to_cpu(A)
+#define cpu_to_lel(A) cpu_to_le32(A)
+#elif BITS_PER_LONG == 64
+#define __le_long __le64
+#define lel_to_cpu(A) le64_to_cpu(A)
+#define cpu_to_lel(A) cpu_to_le64(A)
+#else
+#error "BITS_PER_LONG not 32 or 64"
+#endif
/*
* Allocation Bitmap Management Functions
@@ -200,32 +181,35 @@ unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu)
{
unsigned int i, map_i, map_b, ent_idx;
unsigned int clu_base, clu_free;
- unsigned char k, clu_mask;
+ unsigned long clu_bits, clu_mask;
struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ __le_long bitval;
WARN_ON(clu < EXFAT_FIRST_CLUSTER);
- ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
- clu_base = BITMAP_ENT_TO_CLUSTER(ent_idx & ~(BITS_PER_BYTE_MASK));
+ ent_idx = ALIGN_DOWN(CLUSTER_TO_BITMAP_ENT(clu), BITS_PER_LONG);
+ clu_base = BITMAP_ENT_TO_CLUSTER(ent_idx);
clu_mask = IGNORED_BITS_REMAINED(clu, clu_base);
map_i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
map_b = BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent_idx);
for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters;
- i += BITS_PER_BYTE) {
- k = *(sbi->vol_amap[map_i]->b_data + map_b);
+ i += BITS_PER_LONG) {
+ bitval = *(__le_long *)(sbi->vol_amap[map_i]->b_data + map_b);
if (clu_mask > 0) {
- k |= clu_mask;
+ bitval |= cpu_to_lel(clu_mask);
clu_mask = 0;
}
- if (k < 0xFF) {
- clu_free = clu_base + free_bit[k];
+ if (lel_to_cpu(bitval) != ULONG_MAX) {
+ clu_bits = lel_to_cpu(bitval);
+ clu_free = clu_base + ffz(clu_bits);
if (clu_free < sbi->num_clusters)
return clu_free;
}
- clu_base += BITS_PER_BYTE;
+ clu_base += BITS_PER_LONG;
+ map_b += sizeof(long);
- if (++map_b >= sb->s_blocksize ||
+ if (map_b >= sb->s_blocksize ||
clu_base >= sbi->num_clusters) {
if (++map_i >= sbi->map_sectors) {
clu_base = EXFAT_FIRST_CLUSTER;
@@ -244,25 +228,24 @@ int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count)
unsigned int count = 0;
unsigned int i, map_i = 0, map_b = 0;
unsigned int total_clus = EXFAT_DATA_CLUSTER_COUNT(sbi);
- unsigned int last_mask = total_clus & BITS_PER_BYTE_MASK;
- unsigned char clu_bits;
- const unsigned char last_bit_mask[] = {0, 0b00000001, 0b00000011,
- 0b00000111, 0b00001111, 0b00011111, 0b00111111, 0b01111111};
+ unsigned int last_mask = total_clus & (BITS_PER_LONG - 1);
+ unsigned long *bitmap, clu_bits;
total_clus &= ~last_mask;
- for (i = 0; i < total_clus; i += BITS_PER_BYTE) {
- clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b);
- count += used_bit[clu_bits];
- if (++map_b >= (unsigned int)sb->s_blocksize) {
+ for (i = 0; i < total_clus; i += BITS_PER_LONG) {
+ bitmap = (void *)(sbi->vol_amap[map_i]->b_data + map_b);
+ count += hweight_long(*bitmap);
+ map_b += sizeof(long);
+ if (map_b >= (unsigned int)sb->s_blocksize) {
map_i++;
map_b = 0;
}
}
if (last_mask) {
- clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b);
- clu_bits &= last_bit_mask[last_mask];
- count += used_bit[clu_bits];
+ bitmap = (void *)(sbi->vol_amap[map_i]->b_data + map_b);
+ clu_bits = lel_to_cpu(*(__le_long *)bitmap);
+ count += hweight_long(clu_bits & BITMAP_LAST_WORD_MASK(last_mask));
}
*ret_count = count;
diff --git a/fs/exfat/exfat_fs.h b/fs/exfat/exfat_fs.h
index a7a2c35d74fb..9474cd50da6d 100644
--- a/fs/exfat/exfat_fs.h
+++ b/fs/exfat/exfat_fs.h
@@ -135,8 +135,7 @@ enum {
#define BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent) (ent & BITS_PER_SECTOR_MASK(sb))
#define BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent) \
((ent / BITS_PER_BYTE) & ((sb)->s_blocksize - 1))
-#define BITS_PER_BYTE_MASK 0x7
-#define IGNORED_BITS_REMAINED(clu, clu_base) ((1 << ((clu) - (clu_base))) - 1)
+#define IGNORED_BITS_REMAINED(clu, clu_base) ((1UL << ((clu) - (clu_base))) - 1)
#define ES_ENTRY_NUM(name_len) (ES_IDX_LAST_FILENAME(name_len) + 1)
/* 19 entries = 1 file entry + 1 stream entry + 17 filename entries */
@@ -208,6 +207,7 @@ struct exfat_dir_entry {
unsigned char flags;
unsigned short attr;
loff_t size;
+ loff_t valid_size;
unsigned int num_subdirs;
struct timespec64 atime;
struct timespec64 mtime;
@@ -317,6 +317,7 @@ struct exfat_inode_info {
loff_t i_size_aligned;
/* on-disk position of directory entry or 0 */
loff_t i_pos;
+ loff_t valid_size;
/* hash by i_location */
struct hlist_node i_hash_fat;
/* protect bmap against truncate */
diff --git a/fs/exfat/file.c b/fs/exfat/file.c
index bfdfafe00993..d25a96a148af 100644
--- a/fs/exfat/file.c
+++ b/fs/exfat/file.c
@@ -11,37 +11,76 @@
#include <linux/fsnotify.h>
#include <linux/security.h>
#include <linux/msdos_fs.h>
+#include <linux/writeback.h>
#include "exfat_raw.h"
#include "exfat_fs.h"
static int exfat_cont_expand(struct inode *inode, loff_t size)
{
- struct address_space *mapping = inode->i_mapping;
- loff_t start = i_size_read(inode), count = size - i_size_read(inode);
- int err, err2;
+ int ret;
+ unsigned int num_clusters, new_num_clusters, last_clu;
+ struct exfat_inode_info *ei = EXFAT_I(inode);
+ struct super_block *sb = inode->i_sb;
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ struct exfat_chain clu;
- err = generic_cont_expand_simple(inode, size);
- if (err)
- return err;
+ ret = inode_newsize_ok(inode, size);
+ if (ret)
+ return ret;
+
+ num_clusters = EXFAT_B_TO_CLU_ROUND_UP(ei->i_size_ondisk, sbi);
+ new_num_clusters = EXFAT_B_TO_CLU_ROUND_UP(size, sbi);
+
+ if (new_num_clusters == num_clusters)
+ goto out;
+
+ exfat_chain_set(&clu, ei->start_clu, num_clusters, ei->flags);
+ ret = exfat_find_last_cluster(sb, &clu, &last_clu);
+ if (ret)
+ return ret;
+
+ clu.dir = (last_clu == EXFAT_EOF_CLUSTER) ?
+ EXFAT_EOF_CLUSTER : last_clu + 1;
+ clu.size = 0;
+ clu.flags = ei->flags;
+
+ ret = exfat_alloc_cluster(inode, new_num_clusters - num_clusters,
+ &clu, IS_DIRSYNC(inode));
+ if (ret)
+ return ret;
+
+ /* Append new clusters to chain */
+ if (clu.flags != ei->flags) {
+ exfat_chain_cont_cluster(sb, ei->start_clu, num_clusters);
+ ei->flags = ALLOC_FAT_CHAIN;
+ }
+ if (clu.flags == ALLOC_FAT_CHAIN)
+ if (exfat_ent_set(sb, last_clu, clu.dir))
+ goto free_clu;
+ if (num_clusters == 0)
+ ei->start_clu = clu.dir;
+
+out:
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
- mark_inode_dirty(inode);
+ /* Expanded range not zeroed, do not update valid_size */
+ i_size_write(inode, size);
- if (!IS_SYNC(inode))
- return 0;
+ ei->i_size_aligned = round_up(size, sb->s_blocksize);
+ ei->i_size_ondisk = ei->i_size_aligned;
+ inode->i_blocks = round_up(size, sbi->cluster_size) >> 9;
- err = filemap_fdatawrite_range(mapping, start, start + count - 1);
- err2 = sync_mapping_buffers(mapping);
- if (!err)
- err = err2;
- err2 = write_inode_now(inode, 1);
- if (!err)
- err = err2;
- if (err)
- return err;
+ if (IS_DIRSYNC(inode))
+ return write_inode_now(inode, 1);
+
+ mark_inode_dirty(inode);
- return filemap_fdatawait_range(mapping, start, start + count - 1);
+ return 0;
+
+free_clu:
+ exfat_free_cluster(inode, &clu);
+ return -EIO;
}
static bool exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode)
@@ -146,6 +185,9 @@ int __exfat_truncate(struct inode *inode)
ei->start_clu = EXFAT_EOF_CLUSTER;
}
+ if (i_size_read(inode) < ei->valid_size)
+ ei->valid_size = i_size_read(inode);
+
if (ei->type == TYPE_FILE)
ei->attr |= EXFAT_ATTR_ARCHIVE;
@@ -474,15 +516,124 @@ int exfat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
return blkdev_issue_flush(inode->i_sb->s_bdev);
}
+static int exfat_file_zeroed_range(struct file *file, loff_t start, loff_t end)
+{
+ int err;
+ struct inode *inode = file_inode(file);
+ struct address_space *mapping = inode->i_mapping;
+ const struct address_space_operations *ops = mapping->a_ops;
+
+ while (start < end) {
+ u32 zerofrom, len;
+ struct page *page = NULL;
+
+ zerofrom = start & (PAGE_SIZE - 1);
+ len = PAGE_SIZE - zerofrom;
+ if (start + len > end)
+ len = end - start;
+
+ err = ops->write_begin(file, mapping, start, len, &page, NULL);
+ if (err)
+ goto out;
+
+ zero_user_segment(page, zerofrom, zerofrom + len);
+
+ err = ops->write_end(file, mapping, start, len, len, page, NULL);
+ if (err < 0)
+ goto out;
+ start += len;
+
+ balance_dirty_pages_ratelimited(mapping);
+ cond_resched();
+ }
+
+out:
+ return err;
+}
+
+static ssize_t exfat_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+ ssize_t ret;
+ struct file *file = iocb->ki_filp;
+ struct inode *inode = file_inode(file);
+ struct exfat_inode_info *ei = EXFAT_I(inode);
+ loff_t pos = iocb->ki_pos;
+ loff_t valid_size;
+
+ inode_lock(inode);
+
+ valid_size = ei->valid_size;
+
+ ret = generic_write_checks(iocb, iter);
+ if (ret < 0)
+ goto unlock;
+
+ if (pos > valid_size) {
+ ret = exfat_file_zeroed_range(file, valid_size, pos);
+ if (ret < 0 && ret != -ENOSPC) {
+ exfat_err(inode->i_sb,
+ "write: fail to zero from %llu to %llu(%zd)",
+ valid_size, pos, ret);
+ }
+ if (ret < 0)
+ goto unlock;
+ }
+
+ ret = __generic_file_write_iter(iocb, iter);
+ if (ret < 0)
+ goto unlock;
+
+ inode_unlock(inode);
+
+ if (pos > valid_size)
+ pos = valid_size;
+
+ if (iocb_is_dsync(iocb) && iocb->ki_pos > pos) {
+ ssize_t err = vfs_fsync_range(file, pos, iocb->ki_pos - 1,
+ iocb->ki_flags & IOCB_SYNC);
+ if (err < 0)
+ return err;
+ }
+
+ return ret;
+
+unlock:
+ inode_unlock(inode);
+
+ return ret;
+}
+
+static int exfat_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int ret;
+ struct inode *inode = file_inode(file);
+ struct exfat_inode_info *ei = EXFAT_I(inode);
+ loff_t start = ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
+ loff_t end = min_t(loff_t, i_size_read(inode),
+ start + vma->vm_end - vma->vm_start);
+
+ if ((vma->vm_flags & VM_WRITE) && ei->valid_size < end) {
+ ret = exfat_file_zeroed_range(file, ei->valid_size, end);
+ if (ret < 0) {
+ exfat_err(inode->i_sb,
+ "mmap: fail to zero from %llu to %llu(%d)",
+ start, end, ret);
+ return ret;
+ }
+ }
+
+ return generic_file_mmap(file, vma);
+}
+
const struct file_operations exfat_file_operations = {
.llseek = generic_file_llseek,
.read_iter = generic_file_read_iter,
- .write_iter = generic_file_write_iter,
+ .write_iter = exfat_file_write_iter,
.unlocked_ioctl = exfat_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = exfat_compat_ioctl,
#endif
- .mmap = generic_file_mmap,
+ .mmap = exfat_file_mmap,
.fsync = exfat_file_fsync,
.splice_read = filemap_splice_read,
.splice_write = iter_file_splice_write,
diff --git a/fs/exfat/inode.c b/fs/exfat/inode.c
index e7ff58b8e68c..522edcbb2ce4 100644
--- a/fs/exfat/inode.c
+++ b/fs/exfat/inode.c
@@ -75,8 +75,17 @@ int __exfat_write_inode(struct inode *inode, int sync)
if (ei->start_clu == EXFAT_EOF_CLUSTER)
on_disk_size = 0;
- ep2->dentry.stream.valid_size = cpu_to_le64(on_disk_size);
- ep2->dentry.stream.size = ep2->dentry.stream.valid_size;
+ ep2->dentry.stream.size = cpu_to_le64(on_disk_size);
+ /*
+ * mmap write does not use exfat_write_end(), valid_size may be
+ * extended to the sector-aligned length in exfat_get_block().
+ * So we need to fixup valid_size to the writren length.
+ */
+ if (on_disk_size < ei->valid_size)
+ ep2->dentry.stream.valid_size = ep2->dentry.stream.size;
+ else
+ ep2->dentry.stream.valid_size = cpu_to_le64(ei->valid_size);
+
if (on_disk_size) {
ep2->dentry.stream.flags = ei->flags;
ep2->dentry.stream.start_clu = cpu_to_le32(ei->start_clu);
@@ -278,6 +287,7 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
unsigned int cluster, sec_offset;
sector_t last_block;
sector_t phys = 0;
+ sector_t valid_blks;
loff_t pos;
mutex_lock(&sbi->s_lock);
@@ -306,17 +316,32 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
mapped_blocks = sbi->sect_per_clus - sec_offset;
max_blocks = min(mapped_blocks, max_blocks);
- /* Treat newly added block / cluster */
- if (iblock < last_block)
- create = 0;
-
- if (create || buffer_delay(bh_result)) {
- pos = EXFAT_BLK_TO_B((iblock + 1), sb);
+ pos = EXFAT_BLK_TO_B((iblock + 1), sb);
+ if ((create && iblock >= last_block) || buffer_delay(bh_result)) {
if (ei->i_size_ondisk < pos)
ei->i_size_ondisk = pos;
}
+ map_bh(bh_result, sb, phys);
+ if (buffer_delay(bh_result))
+ clear_buffer_delay(bh_result);
+
if (create) {
+ valid_blks = EXFAT_B_TO_BLK_ROUND_UP(ei->valid_size, sb);
+
+ if (iblock + max_blocks < valid_blks) {
+ /* The range has been written, map it */
+ goto done;
+ } else if (iblock < valid_blks) {
+ /*
+ * The range has been partially written,
+ * map the written part.
+ */
+ max_blocks = valid_blks - iblock;
+ goto done;
+ }
+
+ /* The area has not been written, map and mark as new. */
err = exfat_map_new_buffer(ei, bh_result, pos);
if (err) {
exfat_fs_error(sb,
@@ -324,11 +349,58 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
pos, ei->i_size_aligned);
goto unlock_ret;
}
- }
- if (buffer_delay(bh_result))
- clear_buffer_delay(bh_result);
- map_bh(bh_result, sb, phys);
+ ei->valid_size = EXFAT_BLK_TO_B(iblock + max_blocks, sb);
+ mark_inode_dirty(inode);
+ } else {
+ valid_blks = EXFAT_B_TO_BLK(ei->valid_size, sb);
+
+ if (iblock + max_blocks < valid_blks) {
+ /* The range has been written, map it */
+ goto done;
+ } else if (iblock < valid_blks) {
+ /*
+ * The area has been partially written,
+ * map the written part.
+ */
+ max_blocks = valid_blks - iblock;
+ goto done;
+ } else if (iblock == valid_blks &&
+ (ei->valid_size & (sb->s_blocksize - 1))) {
+ /*
+ * The block has been partially written,
+ * zero the unwritten part and map the block.
+ */
+ loff_t size, off;
+
+ max_blocks = 1;
+
+ /*
+ * For direct read, the unwritten part will be zeroed in
+ * exfat_direct_IO()
+ */
+ if (!bh_result->b_folio)
+ goto done;
+
+ pos -= sb->s_blocksize;
+ size = ei->valid_size - pos;
+ off = pos & (PAGE_SIZE - 1);
+
+ folio_set_bh(bh_result, bh_result->b_folio, off);
+ err = bh_read(bh_result, 0);
+ if (err < 0)
+ goto unlock_ret;
+
+ folio_zero_segment(bh_result->b_folio, off + size,
+ off + sb->s_blocksize);
+ } else {
+ /*
+ * The range has not been written, clear the mapped flag
+ * to only zero the cache and do not read from disk.
+ */
+ clear_buffer_mapped(bh_result);
+ }
+ }
done:
bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb);
unlock_ret:
@@ -343,6 +415,17 @@ static int exfat_read_folio(struct file *file, struct folio *folio)
static void exfat_readahead(struct readahead_control *rac)
{
+ struct address_space *mapping = rac->mapping;
+ struct inode *inode = mapping->host;
+ struct exfat_inode_info *ei = EXFAT_I(inode);
+ loff_t pos = readahead_pos(rac);
+
+ /* Range cross valid_size, read it page by page. */
+ if (ei->valid_size < i_size_read(inode) &&
+ pos <= ei->valid_size &&
+ ei->valid_size < pos + readahead_length(rac))
+ return;
+
mpage_readahead(rac, exfat_get_block);
}
@@ -370,9 +453,7 @@ static int exfat_write_begin(struct file *file, struct address_space *mapping,
int ret;
*pagep = NULL;
- ret = cont_write_begin(file, mapping, pos, len, pagep, fsdata,
- exfat_get_block,
- &EXFAT_I(mapping->host)->i_size_ondisk);
+ ret = block_write_begin(mapping, pos, len, pagep, exfat_get_block);
if (ret < 0)
exfat_write_failed(mapping, pos+len);
@@ -400,6 +481,11 @@ static int exfat_write_end(struct file *file, struct address_space *mapping,
if (err < len)
exfat_write_failed(mapping, pos+len);
+ if (!(err < 0) && pos + err > ei->valid_size) {
+ ei->valid_size = pos + err;
+ mark_inode_dirty(inode);
+ }
+
if (!(err < 0) && !(ei->attr & EXFAT_ATTR_ARCHIVE)) {
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
ei->attr |= EXFAT_ATTR_ARCHIVE;
@@ -413,6 +499,8 @@ static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
{
struct address_space *mapping = iocb->ki_filp->f_mapping;
struct inode *inode = mapping->host;
+ struct exfat_inode_info *ei = EXFAT_I(inode);
+ loff_t pos = iocb->ki_pos;
loff_t size = iocb->ki_pos + iov_iter_count(iter);
int rw = iov_iter_rw(iter);
ssize_t ret;
@@ -436,8 +524,21 @@ static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
* condition of exfat_get_block() and ->truncate().
*/
ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block);
- if (ret < 0 && (rw & WRITE))
- exfat_write_failed(mapping, size);
+ if (ret < 0) {
+ if (rw == WRITE)
+ exfat_write_failed(mapping, size);
+
+ if (ret != -EIOCBQUEUED)
+ return ret;
+ } else
+ size = pos + ret;
+
+ /* zero the unwritten part in the partially written block */
+ if (rw == READ && pos < ei->valid_size && ei->valid_size < size) {
+ iov_iter_revert(iter, size - ei->valid_size);
+ iov_iter_zero(size - ei->valid_size, iter);
+ }
+
return ret;
}
@@ -537,6 +638,7 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
ei->start_clu = info->start_clu;
ei->flags = info->flags;
ei->type = info->type;
+ ei->valid_size = info->valid_size;
ei->version = 0;
ei->hint_stat.eidx = 0;
diff --git a/fs/exfat/namei.c b/fs/exfat/namei.c
index 5d737e0b639a..9c549fd11fc8 100644
--- a/fs/exfat/namei.c
+++ b/fs/exfat/namei.c
@@ -406,6 +406,7 @@ static int exfat_find_empty_entry(struct inode *inode,
i_size_write(inode, size);
ei->i_size_ondisk += sbi->cluster_size;
ei->i_size_aligned += sbi->cluster_size;
+ ei->valid_size += sbi->cluster_size;
ei->flags = p_dir->flags;
inode->i_blocks += sbi->cluster_size >> 9;
}
@@ -558,6 +559,8 @@ static int exfat_add_entry(struct inode *inode, const char *path,
info->size = clu_size;
info->num_subdirs = EXFAT_MIN_SUBDIR;
}
+ info->valid_size = info->size;
+
memset(&info->crtime, 0, sizeof(info->crtime));
memset(&info->mtime, 0, sizeof(info->mtime));
memset(&info->atime, 0, sizeof(info->atime));
@@ -660,6 +663,8 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
info->type = exfat_get_entry_type(ep);
info->attr = le16_to_cpu(ep->dentry.file.attr);
info->size = le64_to_cpu(ep2->dentry.stream.valid_size);
+ info->valid_size = le64_to_cpu(ep2->dentry.stream.valid_size);
+ info->size = le64_to_cpu(ep2->dentry.stream.size);
if (info->size == 0) {
info->flags = ALLOC_NO_FAT_CHAIN;
info->start_clu = EXFAT_EOF_CLUSTER;
@@ -1288,6 +1293,7 @@ static int __exfat_rename(struct inode *old_parent_inode,
}
i_size_write(new_inode, 0);
+ new_ei->valid_size = 0;
new_ei->start_clu = EXFAT_EOF_CLUSTER;
new_ei->flags = ALLOC_NO_FAT_CHAIN;
}
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index d00d21a8b53a..d45ab0992ae5 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -4880,6 +4880,7 @@ free_sbi:
if (sbi->s_chksum_driver)
crypto_free_shash(sbi->s_chksum_driver);
kfree(sbi);
+ sb->s_fs_info = NULL;
/* give only one another chance */
if (retry_cnt > 0 && skip_recovery) {
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 8b2bd65d70e7..bce1d7ac95ca 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -54,9 +54,9 @@ static bool kernfs_lockdep(struct kernfs_node *kn)
static int kernfs_name_locked(struct kernfs_node *kn, char *buf, size_t buflen)
{
if (!kn)
- return strlcpy(buf, "(null)", buflen);
+ return strscpy(buf, "(null)", buflen);
- return strlcpy(buf, kn->parent ? kn->name : "/", buflen);
+ return strscpy(buf, kn->parent ? kn->name : "/", buflen);
}
/* kernfs_node_depth - compute depth from @from to @to */
@@ -127,7 +127,7 @@ static struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a,
*
* [3] when @kn_to is %NULL result will be "(null)"
*
- * Return: the length of the full path. If the full length is equal to or
+ * Return: the length of the constructed path. If the path would have been
* greater than @buflen, @buf contains the truncated path with the trailing
* '\0'. On error, -errno is returned.
*/
@@ -138,16 +138,17 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to,
struct kernfs_node *kn, *common;
const char parent_str[] = "/..";
size_t depth_from, depth_to, len = 0;
+ ssize_t copied;
int i, j;
if (!kn_to)
- return strlcpy(buf, "(null)", buflen);
+ return strscpy(buf, "(null)", buflen);
if (!kn_from)
kn_from = kernfs_root(kn_to)->kn;
if (kn_from == kn_to)
- return strlcpy(buf, "/", buflen);
+ return strscpy(buf, "/", buflen);
common = kernfs_common_ancestor(kn_from, kn_to);
if (WARN_ON(!common))
@@ -158,18 +159,19 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to,
buf[0] = '\0';
- for (i = 0; i < depth_from; i++)
- len += strlcpy(buf + len, parent_str,
- len < buflen ? buflen - len : 0);
+ for (i = 0; i < depth_from; i++) {
+ copied = strscpy(buf + len, parent_str, buflen - len);
+ if (copied < 0)
+ return copied;
+ len += copied;
+ }
/* Calculate how many bytes we need for the rest */
for (i = depth_to - 1; i >= 0; i--) {
for (kn = kn_to, j = 0; j < i; j++)
kn = kn->parent;
- len += strlcpy(buf + len, "/",
- len < buflen ? buflen - len : 0);
- len += strlcpy(buf + len, kn->name,
- len < buflen ? buflen - len : 0);
+
+ len += scnprintf(buf + len, buflen - len, "/%s", kn->name);
}
return len;
@@ -182,12 +184,12 @@ static int kernfs_path_from_node_locked(struct kernfs_node *kn_to,
* @buflen: size of @buf
*
* Copies the name of @kn into @buf of @buflen bytes. The behavior is
- * similar to strlcpy().
+ * similar to strscpy().
*
* Fills buffer with "(null)" if @kn is %NULL.
*
- * Return: the length of @kn's name and if @buf isn't long enough,
- * it's filled up to @buflen-1 and nul terminated.
+ * Return: the resulting length of @buf. If @buf isn't long enough,
+ * it's filled up to @buflen-1 and nul terminated, and returns -E2BIG.
*
* This function can be called from any context.
*/
@@ -214,7 +216,7 @@ int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen)
* path (which includes '..'s) as needed to reach from @from to @to is
* returned.
*
- * Return: the length of the full path. If the full length is equal to or
+ * Return: the length of the constructed path. If the path would have been
* greater than @buflen, @buf contains the truncated path with the trailing
* '\0'. On error, -errno is returned.
*/
@@ -265,12 +267,10 @@ void pr_cont_kernfs_path(struct kernfs_node *kn)
sz = kernfs_path_from_node(kn, NULL, kernfs_pr_cont_buf,
sizeof(kernfs_pr_cont_buf));
if (sz < 0) {
- pr_cont("(error)");
- goto out;
- }
-
- if (sz >= sizeof(kernfs_pr_cont_buf)) {
- pr_cont("(name too long)");
+ if (sz == -E2BIG)
+ pr_cont("(name too long)");
+ else
+ pr_cont("(error)");
goto out;
}
@@ -676,6 +676,18 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
{
struct kernfs_node *kn;
+ if (parent->mode & S_ISGID) {
+ /* this code block imitates inode_init_owner() for
+ * kernfs
+ */
+
+ if (parent->iattr)
+ gid = parent->iattr->ia_gid;
+
+ if (flags & KERNFS_DIR)
+ mode |= S_ISGID;
+ }
+
kn = __kernfs_new_node(kernfs_root(parent), parent,
name, mode, uid, gid, flags);
if (kn) {
@@ -850,16 +862,16 @@ static struct kernfs_node *kernfs_walk_ns(struct kernfs_node *parent,
const unsigned char *path,
const void *ns)
{
- size_t len;
+ ssize_t len;
char *p, *name;
lockdep_assert_held_read(&kernfs_root(parent)->kernfs_rwsem);
spin_lock_irq(&kernfs_pr_cont_lock);
- len = strlcpy(kernfs_pr_cont_buf, path, sizeof(kernfs_pr_cont_buf));
+ len = strscpy(kernfs_pr_cont_buf, path, sizeof(kernfs_pr_cont_buf));
- if (len >= sizeof(kernfs_pr_cont_buf)) {
+ if (len < 0) {
spin_unlock_irq(&kernfs_pr_cont_lock);
return NULL;
}
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index f0cb729e9a97..ffa4565c275a 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -447,7 +447,7 @@ static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma)
* warnings and we don't want to add spurious locking dependency
* between the two. Check whether mmap is actually implemented
* without grabbing @of->mutex by testing HAS_MMAP flag. See the
- * comment in kernfs_file_open() for more details.
+ * comment in kernfs_fop_open() for more details.
*/
if (!(of->kn->flags & KERNFS_HAS_MMAP))
return -ENODEV;
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index 4628edde2e7e..0c93cad0f0ac 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -125,9 +125,6 @@ static struct dentry *__kernfs_fh_to_dentry(struct super_block *sb,
inode = kernfs_get_inode(sb, kn);
kernfs_put(kn);
- if (!inode)
- return ERR_PTR(-ESTALE);
-
return d_obtain_alias(inode);
}
diff --git a/fs/namei.c b/fs/namei.c
index 5c318d657503..4e0de939fea1 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2572,13 +2572,13 @@ static int filename_parentat(int dfd, struct filename *name,
}
/* does lookup, returns the object with parent locked */
-static struct dentry *__kern_path_locked(struct filename *name, struct path *path)
+static struct dentry *__kern_path_locked(int dfd, struct filename *name, struct path *path)
{
struct dentry *d;
struct qstr last;
int type, error;
- error = filename_parentat(AT_FDCWD, name, 0, path, &last, &type);
+ error = filename_parentat(dfd, name, 0, path, &last, &type);
if (error)
return ERR_PTR(error);
if (unlikely(type != LAST_NORM)) {
@@ -2597,12 +2597,22 @@ static struct dentry *__kern_path_locked(struct filename *name, struct path *pat
struct dentry *kern_path_locked(const char *name, struct path *path)
{
struct filename *filename = getname_kernel(name);
- struct dentry *res = __kern_path_locked(filename, path);
+ struct dentry *res = __kern_path_locked(AT_FDCWD, filename, path);
putname(filename);
return res;
}
+struct dentry *user_path_locked_at(int dfd, const char __user *name, struct path *path)
+{
+ struct filename *filename = getname(name);
+ struct dentry *res = __kern_path_locked(dfd, filename, path);
+
+ putname(filename);
+ return res;
+}
+EXPORT_SYMBOL(user_path_locked_at);
+
int kern_path(const char *name, unsigned int flags, struct path *path)
{
struct filename *filename = getname_kernel(name);
diff --git a/fs/namespace.c b/fs/namespace.c
index ef1fd6829814..437f60e96d40 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -5042,13 +5042,12 @@ static struct mount *listmnt_next(struct mount *curr)
return node_to_mount(rb_next(&curr->mnt_node));
}
-static ssize_t do_listmount(struct mount *first, struct path *orig, u64 mnt_id,
- u64 __user *buf, size_t bufsize,
- const struct path *root)
+static ssize_t do_listmount(struct mount *first, struct path *orig,
+ u64 mnt_parent_id, u64 __user *mnt_ids,
+ size_t nr_mnt_ids, const struct path *root)
{
struct mount *r;
- ssize_t ctr;
- int err;
+ ssize_t ret;
/*
* Don't trigger audit denials. We just want to determine what
@@ -5058,50 +5057,57 @@ static ssize_t do_listmount(struct mount *first, struct path *orig, u64 mnt_id,
!ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN))
return -EPERM;
- err = security_sb_statfs(orig->dentry);
- if (err)
- return err;
+ ret = security_sb_statfs(orig->dentry);
+ if (ret)
+ return ret;
- for (ctr = 0, r = first; r && ctr < bufsize; r = listmnt_next(r)) {
- if (r->mnt_id_unique == mnt_id)
+ for (ret = 0, r = first; r && nr_mnt_ids; r = listmnt_next(r)) {
+ if (r->mnt_id_unique == mnt_parent_id)
continue;
if (!is_path_reachable(r, r->mnt.mnt_root, orig))
continue;
- ctr = array_index_nospec(ctr, bufsize);
- if (put_user(r->mnt_id_unique, buf + ctr))
+ if (put_user(r->mnt_id_unique, mnt_ids))
return -EFAULT;
- if (check_add_overflow(ctr, 1, &ctr))
- return -ERANGE;
+ mnt_ids++;
+ nr_mnt_ids--;
+ ret++;
}
- return ctr;
+ return ret;
}
-SYSCALL_DEFINE4(listmount, const struct mnt_id_req __user *, req,
- u64 __user *, buf, size_t, bufsize, unsigned int, flags)
+SYSCALL_DEFINE4(listmount, const struct mnt_id_req __user *, req, u64 __user *,
+ mnt_ids, size_t, nr_mnt_ids, unsigned int, flags)
{
struct mnt_namespace *ns = current->nsproxy->mnt_ns;
struct mnt_id_req kreq;
struct mount *first;
struct path root, orig;
- u64 mnt_id, last_mnt_id;
+ u64 mnt_parent_id, last_mnt_id;
+ const size_t maxcount = (size_t)-1 >> 3;
ssize_t ret;
if (flags)
return -EINVAL;
+ if (unlikely(nr_mnt_ids > maxcount))
+ return -EFAULT;
+
+ if (!access_ok(mnt_ids, nr_mnt_ids * sizeof(*mnt_ids)))
+ return -EFAULT;
+
ret = copy_mnt_id_req(req, &kreq);
if (ret)
return ret;
- mnt_id = kreq.mnt_id;
+ mnt_parent_id = kreq.mnt_id;
last_mnt_id = kreq.param;
down_read(&namespace_sem);
get_fs_root(current->fs, &root);
- if (mnt_id == LSMT_ROOT) {
+ if (mnt_parent_id == LSMT_ROOT) {
orig = root;
} else {
ret = -ENOENT;
- orig.mnt = lookup_mnt_in_ns(mnt_id, ns);
+ orig.mnt = lookup_mnt_in_ns(mnt_parent_id, ns);
if (!orig.mnt)
goto err;
orig.dentry = orig.mnt->mnt_root;
@@ -5111,7 +5117,7 @@ SYSCALL_DEFINE4(listmount, const struct mnt_id_req __user *, req,
else
first = mnt_find_id_at(ns, last_mnt_id + 1);
- ret = do_listmount(first, &orig, mnt_id, buf, bufsize, &root);
+ ret = do_listmount(first, &orig, mnt_parent_id, mnt_ids, nr_mnt_ids, &root);
err:
path_put(&root);
up_read(&namespace_sem);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 62b16f42d5d2..3f78ebbb795f 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -2432,7 +2432,6 @@ static long pagemap_scan_flush_buffer(struct pagemap_scan_private *p)
static long do_pagemap_scan(struct mm_struct *mm, unsigned long uarg)
{
- struct mmu_notifier_range range;
struct pagemap_scan_private p = {0};
unsigned long walk_start;
size_t n_ranges_out = 0;
@@ -2448,15 +2447,9 @@ static long do_pagemap_scan(struct mm_struct *mm, unsigned long uarg)
if (ret)
return ret;
- /* Protection change for the range is going to happen. */
- if (p.arg.flags & PM_SCAN_WP_MATCHING) {
- mmu_notifier_range_init(&range, MMU_NOTIFY_PROTECTION_VMA, 0,
- mm, p.arg.start, p.arg.end);
- mmu_notifier_invalidate_range_start(&range);
- }
-
for (walk_start = p.arg.start; walk_start < p.arg.end;
walk_start = p.arg.walk_end) {
+ struct mmu_notifier_range range;
long n_out;
if (fatal_signal_pending(current)) {
@@ -2467,8 +2460,20 @@ static long do_pagemap_scan(struct mm_struct *mm, unsigned long uarg)
ret = mmap_read_lock_killable(mm);
if (ret)
break;
+
+ /* Protection change for the range is going to happen. */
+ if (p.arg.flags & PM_SCAN_WP_MATCHING) {
+ mmu_notifier_range_init(&range, MMU_NOTIFY_PROTECTION_VMA, 0,
+ mm, walk_start, p.arg.end);
+ mmu_notifier_invalidate_range_start(&range);
+ }
+
ret = walk_page_range(mm, walk_start, p.arg.end,
&pagemap_scan_ops, &p);
+
+ if (p.arg.flags & PM_SCAN_WP_MATCHING)
+ mmu_notifier_invalidate_range_end(&range);
+
mmap_read_unlock(mm);
n_out = pagemap_scan_flush_buffer(&p);
@@ -2494,9 +2499,6 @@ static long do_pagemap_scan(struct mm_struct *mm, unsigned long uarg)
if (pagemap_scan_writeback_args(&p.arg, uarg))
ret = -EFAULT;
- if (p.arg.flags & PM_SCAN_WP_MATCHING)
- mmu_notifier_invalidate_range_end(&range);
-
kfree(p.vec_buf);
return ret;
}
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index b6b6796e1616..4df2afa551dc 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -81,7 +81,7 @@ void sysfs_remove_dir(struct kobject *kobj)
struct kernfs_node *kn = kobj->sd;
/*
- * In general, kboject owner is responsible for ensuring removal
+ * In general, kobject owner is responsible for ensuring removal
* doesn't race with other operations and sysfs doesn't provide any
* protection; however, when @kobj is used as a symlink target, the
* symlinking entity usually doesn't own @kobj and thus has no
diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c
index f0677ea0ec24..6795fda2af19 100644
--- a/fs/tracefs/event_inode.c
+++ b/fs/tracefs/event_inode.c
@@ -32,6 +32,10 @@
*/
static DEFINE_MUTEX(eventfs_mutex);
+/* Choose something "unique" ;-) */
+#define EVENTFS_FILE_INODE_INO 0x12c4e37
+#define EVENTFS_DIR_INODE_INO 0x134b2f5
+
/*
* The eventfs_inode (ei) itself is protected by SRCU. It is released from
* its parent's list and will have is_freed set (under eventfs_mutex).
@@ -45,6 +49,7 @@ enum {
EVENTFS_SAVE_MODE = BIT(16),
EVENTFS_SAVE_UID = BIT(17),
EVENTFS_SAVE_GID = BIT(18),
+ EVENTFS_TOPLEVEL = BIT(19),
};
#define EVENTFS_MODE_MASK (EVENTFS_SAVE_MODE - 1)
@@ -52,9 +57,7 @@ enum {
static struct dentry *eventfs_root_lookup(struct inode *dir,
struct dentry *dentry,
unsigned int flags);
-static int dcache_dir_open_wrapper(struct inode *inode, struct file *file);
-static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx);
-static int eventfs_release(struct inode *inode, struct file *file);
+static int eventfs_iterate(struct file *file, struct dir_context *ctx);
static void update_attr(struct eventfs_attr *attr, struct iattr *iattr)
{
@@ -94,7 +97,7 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,
/* Preallocate the children mode array if necessary */
if (!(dentry->d_inode->i_mode & S_IFDIR)) {
if (!ei->entry_attrs) {
- ei->entry_attrs = kzalloc(sizeof(*ei->entry_attrs) * ei->nr_entries,
+ ei->entry_attrs = kcalloc(ei->nr_entries, sizeof(*ei->entry_attrs),
GFP_NOFS);
if (!ei->entry_attrs) {
ret = -ENOMEM;
@@ -117,10 +120,17 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,
* The events directory dentry is never freed, unless its
* part of an instance that is deleted. It's attr is the
* default for its child files and directories.
- * Do not update it. It's not used for its own mode or ownership
+ * Do not update it. It's not used for its own mode or ownership.
*/
- if (!ei->is_events)
+ if (ei->is_events) {
+ /* But it still needs to know if it was modified */
+ if (iattr->ia_valid & ATTR_UID)
+ ei->attr.mode |= EVENTFS_SAVE_UID;
+ if (iattr->ia_valid & ATTR_GID)
+ ei->attr.mode |= EVENTFS_SAVE_GID;
+ } else {
update_attr(&ei->attr, iattr);
+ }
} else {
name = dentry->d_name.name;
@@ -138,9 +148,66 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,
return ret;
}
+static void update_top_events_attr(struct eventfs_inode *ei, struct dentry *dentry)
+{
+ struct inode *inode;
+
+ /* Only update if the "events" was on the top level */
+ if (!ei || !(ei->attr.mode & EVENTFS_TOPLEVEL))
+ return;
+
+ /* Get the tracefs root inode. */
+ inode = d_inode(dentry->d_sb->s_root);
+ ei->attr.uid = inode->i_uid;
+ ei->attr.gid = inode->i_gid;
+}
+
+static void set_top_events_ownership(struct inode *inode)
+{
+ struct tracefs_inode *ti = get_tracefs(inode);
+ struct eventfs_inode *ei = ti->private;
+ struct dentry *dentry;
+
+ /* The top events directory doesn't get automatically updated */
+ if (!ei || !ei->is_events || !(ei->attr.mode & EVENTFS_TOPLEVEL))
+ return;
+
+ dentry = ei->dentry;
+
+ update_top_events_attr(ei, dentry);
+
+ if (!(ei->attr.mode & EVENTFS_SAVE_UID))
+ inode->i_uid = ei->attr.uid;
+
+ if (!(ei->attr.mode & EVENTFS_SAVE_GID))
+ inode->i_gid = ei->attr.gid;
+}
+
+static int eventfs_get_attr(struct mnt_idmap *idmap,
+ const struct path *path, struct kstat *stat,
+ u32 request_mask, unsigned int flags)
+{
+ struct dentry *dentry = path->dentry;
+ struct inode *inode = d_backing_inode(dentry);
+
+ set_top_events_ownership(inode);
+
+ generic_fillattr(idmap, request_mask, inode, stat);
+ return 0;
+}
+
+static int eventfs_permission(struct mnt_idmap *idmap,
+ struct inode *inode, int mask)
+{
+ set_top_events_ownership(inode);
+ return generic_permission(idmap, inode, mask);
+}
+
static const struct inode_operations eventfs_root_dir_inode_operations = {
.lookup = eventfs_root_lookup,
.setattr = eventfs_set_attr,
+ .getattr = eventfs_get_attr,
+ .permission = eventfs_permission,
};
static const struct inode_operations eventfs_file_inode_operations = {
@@ -148,11 +215,9 @@ static const struct inode_operations eventfs_file_inode_operations = {
};
static const struct file_operations eventfs_file_operations = {
- .open = dcache_dir_open_wrapper,
.read = generic_read_dir,
- .iterate_shared = dcache_readdir_wrapper,
+ .iterate_shared = eventfs_iterate,
.llseek = generic_file_llseek,
- .release = eventfs_release,
};
/* Return the evenfs_inode of the "events" directory */
@@ -178,6 +243,8 @@ static struct eventfs_inode *eventfs_find_events(struct dentry *dentry)
} while (!ei->is_events);
mutex_unlock(&eventfs_mutex);
+ update_top_events_attr(ei, dentry);
+
return ei;
}
@@ -289,6 +356,9 @@ static struct dentry *create_file(const char *name, umode_t mode,
inode->i_fop = fop;
inode->i_private = data;
+ /* All files will have the same inode number */
+ inode->i_ino = EVENTFS_FILE_INODE_INO;
+
ti = get_tracefs(inode);
ti->flags |= TRACEFS_EVENT_INODE;
d_instantiate(dentry, inode);
@@ -325,6 +395,9 @@ static struct dentry *create_dir(struct eventfs_inode *ei, struct dentry *parent
inode->i_op = &eventfs_root_dir_inode_operations;
inode->i_fop = &eventfs_file_operations;
+ /* All directories will have the same inode number */
+ inode->i_ino = EVENTFS_DIR_INODE_INO;
+
ti = get_tracefs(inode);
ti->flags |= TRACEFS_EVENT_INODE;
@@ -390,16 +463,14 @@ void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry)
* @mode: The mode of the file.
* @data: The data to use to set the inode of the file with on open()
* @fops: The fops of the file to be created.
- * @lookup: If called by the lookup routine, in which case, dput() the created dentry.
*
* Create a dentry for a file of an eventfs_inode @ei and place it into the
- * address located at @e_dentry. If the @e_dentry already has a dentry, then
- * just do a dget() on it and return. Otherwise create the dentry and attach it.
+ * address located at @e_dentry.
*/
static struct dentry *
create_file_dentry(struct eventfs_inode *ei, int idx,
struct dentry *parent, const char *name, umode_t mode, void *data,
- const struct file_operations *fops, bool lookup)
+ const struct file_operations *fops)
{
struct eventfs_attr *attr = NULL;
struct dentry **e_dentry = &ei->d_children[idx];
@@ -414,9 +485,7 @@ create_file_dentry(struct eventfs_inode *ei, int idx,
}
/* If the e_dentry already has a dentry, use it */
if (*e_dentry) {
- /* lookup does not need to up the ref count */
- if (!lookup)
- dget(*e_dentry);
+ dget(*e_dentry);
mutex_unlock(&eventfs_mutex);
return *e_dentry;
}
@@ -441,13 +510,12 @@ create_file_dentry(struct eventfs_inode *ei, int idx,
* way to being freed, don't return it. If e_dentry is NULL
* it means it was already freed.
*/
- if (ei->is_freed)
+ if (ei->is_freed) {
dentry = NULL;
- else
+ } else {
dentry = *e_dentry;
- /* The lookup does not need to up the dentry refcount */
- if (dentry && !lookup)
dget(dentry);
+ }
mutex_unlock(&eventfs_mutex);
return dentry;
}
@@ -465,9 +533,6 @@ create_file_dentry(struct eventfs_inode *ei, int idx,
}
mutex_unlock(&eventfs_mutex);
- if (lookup)
- dput(dentry);
-
return dentry;
}
@@ -500,13 +565,12 @@ static void eventfs_post_create_dir(struct eventfs_inode *ei)
* @pei: The eventfs_inode parent of ei.
* @ei: The eventfs_inode to create the directory for
* @parent: The dentry of the parent of this directory
- * @lookup: True if this is called by the lookup code
*
* This creates and attaches a directory dentry to the eventfs_inode @ei.
*/
static struct dentry *
create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei,
- struct dentry *parent, bool lookup)
+ struct dentry *parent)
{
struct dentry *dentry = NULL;
@@ -518,11 +582,9 @@ create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei,
return NULL;
}
if (ei->dentry) {
- /* If the dentry already has a dentry, use it */
+ /* If the eventfs_inode already has a dentry, use it */
dentry = ei->dentry;
- /* lookup does not need to up the ref count */
- if (!lookup)
- dget(dentry);
+ dget(dentry);
mutex_unlock(&eventfs_mutex);
return dentry;
}
@@ -542,7 +604,7 @@ create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei,
* way to being freed.
*/
dentry = ei->dentry;
- if (dentry && !lookup)
+ if (dentry)
dget(dentry);
mutex_unlock(&eventfs_mutex);
return dentry;
@@ -562,9 +624,6 @@ create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei,
}
mutex_unlock(&eventfs_mutex);
- if (lookup)
- dput(dentry);
-
return dentry;
}
@@ -589,8 +648,8 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
struct eventfs_inode *ei;
struct dentry *ei_dentry = NULL;
struct dentry *ret = NULL;
+ struct dentry *d;
const char *name = dentry->d_name.name;
- bool created = false;
umode_t mode;
void *data;
int idx;
@@ -626,13 +685,10 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
ret = simple_lookup(dir, dentry, flags);
if (IS_ERR(ret))
goto out;
- create_dir_dentry(ei, ei_child, ei_dentry, true);
- created = true;
- break;
- }
-
- if (created)
+ d = create_dir_dentry(ei, ei_child, ei_dentry);
+ dput(d);
goto out;
+ }
for (i = 0; i < ei->nr_entries; i++) {
entry = &ei->entries[i];
@@ -650,8 +706,8 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
ret = simple_lookup(dir, dentry, flags);
if (IS_ERR(ret))
goto out;
- create_file_dentry(ei, i, ei_dentry, name, mode, cdata,
- fops, true);
+ d = create_file_dentry(ei, i, ei_dentry, name, mode, cdata, fops);
+ dput(d);
break;
}
}
@@ -660,172 +716,107 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
return ret;
}
-struct dentry_list {
- void *cursor;
- struct dentry **dentries;
-};
-
-/**
- * eventfs_release - called to release eventfs file/dir
- * @inode: inode to be released
- * @file: file to be released (not used)
- */
-static int eventfs_release(struct inode *inode, struct file *file)
-{
- struct tracefs_inode *ti;
- struct dentry_list *dlist = file->private_data;
- void *cursor;
- int i;
-
- ti = get_tracefs(inode);
- if (!(ti->flags & TRACEFS_EVENT_INODE))
- return -EINVAL;
-
- if (WARN_ON_ONCE(!dlist))
- return -EINVAL;
-
- for (i = 0; dlist->dentries && dlist->dentries[i]; i++) {
- dput(dlist->dentries[i]);
- }
-
- cursor = dlist->cursor;
- kfree(dlist->dentries);
- kfree(dlist);
- file->private_data = cursor;
- return dcache_dir_close(inode, file);
-}
-
-static int add_dentries(struct dentry ***dentries, struct dentry *d, int cnt)
-{
- struct dentry **tmp;
-
- tmp = krealloc(*dentries, sizeof(d) * (cnt + 2), GFP_NOFS);
- if (!tmp)
- return -1;
- tmp[cnt] = d;
- tmp[cnt + 1] = NULL;
- *dentries = tmp;
- return 0;
-}
-
-/**
- * dcache_dir_open_wrapper - eventfs open wrapper
- * @inode: not used
- * @file: dir to be opened (to create it's children)
- *
- * Used to dynamic create file/dir with-in @file, all the
- * file/dir will be created. If already created then references
- * will be increased
+/*
+ * Walk the children of a eventfs_inode to fill in getdents().
*/
-static int dcache_dir_open_wrapper(struct inode *inode, struct file *file)
+static int eventfs_iterate(struct file *file, struct dir_context *ctx)
{
const struct file_operations *fops;
+ struct inode *f_inode = file_inode(file);
const struct eventfs_entry *entry;
struct eventfs_inode *ei_child;
struct tracefs_inode *ti;
struct eventfs_inode *ei;
- struct dentry_list *dlist;
- struct dentry **dentries = NULL;
- struct dentry *parent = file_dentry(file);
- struct dentry *d;
- struct inode *f_inode = file_inode(file);
- const char *name = parent->d_name.name;
+ const char *name;
umode_t mode;
- void *data;
- int cnt = 0;
int idx;
- int ret;
- int i;
- int r;
+ int ret = -EINVAL;
+ int ino;
+ int i, r, c;
+
+ if (!dir_emit_dots(file, ctx))
+ return 0;
ti = get_tracefs(f_inode);
if (!(ti->flags & TRACEFS_EVENT_INODE))
return -EINVAL;
- if (WARN_ON_ONCE(file->private_data))
- return -EINVAL;
+ c = ctx->pos - 2;
idx = srcu_read_lock(&eventfs_srcu);
mutex_lock(&eventfs_mutex);
ei = READ_ONCE(ti->private);
+ if (ei && ei->is_freed)
+ ei = NULL;
mutex_unlock(&eventfs_mutex);
- if (!ei) {
- srcu_read_unlock(&eventfs_srcu, idx);
- return -EINVAL;
- }
-
-
- data = ei->data;
+ if (!ei)
+ goto out;
- dlist = kmalloc(sizeof(*dlist), GFP_KERNEL);
- if (!dlist) {
- srcu_read_unlock(&eventfs_srcu, idx);
- return -ENOMEM;
- }
+ /*
+ * Need to create the dentries and inodes to have a consistent
+ * inode number.
+ */
+ ret = 0;
- inode_lock(parent->d_inode);
- list_for_each_entry_srcu(ei_child, &ei->children, list,
- srcu_read_lock_held(&eventfs_srcu)) {
- d = create_dir_dentry(ei, ei_child, parent, false);
- if (d) {
- ret = add_dentries(&dentries, d, cnt);
- if (ret < 0)
- break;
- cnt++;
- }
- }
+ /* Start at 'c' to jump over already read entries */
+ for (i = c; i < ei->nr_entries; i++, ctx->pos++) {
+ void *cdata = ei->data;
- for (i = 0; i < ei->nr_entries; i++) {
- void *cdata = data;
entry = &ei->entries[i];
name = entry->name;
+
mutex_lock(&eventfs_mutex);
- /* If ei->is_freed, then the event itself may be too */
- if (!ei->is_freed)
- r = entry->callback(name, &mode, &cdata, &fops);
- else
- r = -1;
+ /* If ei->is_freed then just bail here, nothing more to do */
+ if (ei->is_freed) {
+ mutex_unlock(&eventfs_mutex);
+ goto out;
+ }
+ r = entry->callback(name, &mode, &cdata, &fops);
mutex_unlock(&eventfs_mutex);
if (r <= 0)
continue;
- d = create_file_dentry(ei, i, parent, name, mode, cdata, fops, false);
- if (d) {
- ret = add_dentries(&dentries, d, cnt);
- if (ret < 0)
- break;
- cnt++;
+
+ ino = EVENTFS_FILE_INODE_INO;
+
+ if (!dir_emit(ctx, name, strlen(name), ino, DT_REG))
+ goto out;
+ }
+
+ /* Subtract the skipped entries above */
+ c -= min((unsigned int)c, (unsigned int)ei->nr_entries);
+
+ list_for_each_entry_srcu(ei_child, &ei->children, list,
+ srcu_read_lock_held(&eventfs_srcu)) {
+
+ if (c > 0) {
+ c--;
+ continue;
}
+
+ ctx->pos++;
+
+ if (ei_child->is_freed)
+ continue;
+
+ name = ei_child->name;
+
+ ino = EVENTFS_DIR_INODE_INO;
+
+ if (!dir_emit(ctx, name, strlen(name), ino, DT_DIR))
+ goto out_dec;
}
- inode_unlock(parent->d_inode);
+ ret = 1;
+ out:
srcu_read_unlock(&eventfs_srcu, idx);
- ret = dcache_dir_open(inode, file);
- /*
- * dcache_dir_open() sets file->private_data to a dentry cursor.
- * Need to save that but also save all the dentries that were
- * opened by this function.
- */
- dlist->cursor = file->private_data;
- dlist->dentries = dentries;
- file->private_data = dlist;
return ret;
-}
-
-/*
- * This just sets the file->private_data back to the cursor and back.
- */
-static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx)
-{
- struct dentry_list *dlist = file->private_data;
- int ret;
- file->private_data = dlist->cursor;
- ret = dcache_readdir(file, ctx);
- dlist->cursor = file->private_data;
- file->private_data = dlist;
- return ret;
+ out_dec:
+ /* Incremented ctx->pos without adding something, reset it */
+ ctx->pos--;
+ goto out;
}
/**
@@ -883,7 +874,7 @@ struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode
}
if (size) {
- ei->d_children = kzalloc(sizeof(*ei->d_children) * size, GFP_KERNEL);
+ ei->d_children = kcalloc(size, sizeof(*ei->d_children), GFP_KERNEL);
if (!ei->d_children) {
kfree_const(ei->name);
kfree(ei);
@@ -950,7 +941,7 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
goto fail;
if (size) {
- ei->d_children = kzalloc(sizeof(*ei->d_children) * size, GFP_KERNEL);
+ ei->d_children = kcalloc(size, sizeof(*ei->d_children), GFP_KERNEL);
if (!ei->d_children)
goto fail;
}
@@ -968,6 +959,14 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
uid = d_inode(dentry->d_parent)->i_uid;
gid = d_inode(dentry->d_parent)->i_gid;
+ /*
+ * If the events directory is of the top instance, then parent
+ * is NULL. Set the attr.mode to reflect this and its permissions will
+ * default to the tracefs root dentry.
+ */
+ if (!parent)
+ ei->attr.mode = EVENTFS_TOPLEVEL;
+
/* This is used as the default ownership of the files and directories */
ei->attr.uid = uid;
ei->attr.gid = gid;
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index ad20e6af938d..e1b172c0e091 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -91,6 +91,7 @@ static int tracefs_syscall_mkdir(struct mnt_idmap *idmap,
struct inode *inode, struct dentry *dentry,
umode_t mode)
{
+ struct tracefs_inode *ti;
char *name;
int ret;
@@ -99,6 +100,15 @@ static int tracefs_syscall_mkdir(struct mnt_idmap *idmap,
return -ENOMEM;
/*
+ * This is a new directory that does not take the default of
+ * the rootfs. It becomes the default permissions for all the
+ * files and directories underneath it.
+ */
+ ti = get_tracefs(inode);
+ ti->flags |= TRACEFS_INSTANCE_INODE;
+ ti->private = inode;
+
+ /*
* The mkdir call can call the generic functions that create
* the files within the tracefs system. It is up to the individual
* mkdir routine to handle races.
@@ -141,10 +151,76 @@ static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry)
return ret;
}
-static const struct inode_operations tracefs_dir_inode_operations = {
+static void set_tracefs_inode_owner(struct inode *inode)
+{
+ struct tracefs_inode *ti = get_tracefs(inode);
+ struct inode *root_inode = ti->private;
+
+ /*
+ * If this inode has never been referenced, then update
+ * the permissions to the superblock.
+ */
+ if (!(ti->flags & TRACEFS_UID_PERM_SET))
+ inode->i_uid = root_inode->i_uid;
+
+ if (!(ti->flags & TRACEFS_GID_PERM_SET))
+ inode->i_gid = root_inode->i_gid;
+}
+
+static int tracefs_permission(struct mnt_idmap *idmap,
+ struct inode *inode, int mask)
+{
+ set_tracefs_inode_owner(inode);
+ return generic_permission(idmap, inode, mask);
+}
+
+static int tracefs_getattr(struct mnt_idmap *idmap,
+ const struct path *path, struct kstat *stat,
+ u32 request_mask, unsigned int flags)
+{
+ struct inode *inode = d_backing_inode(path->dentry);
+
+ set_tracefs_inode_owner(inode);
+ generic_fillattr(idmap, request_mask, inode, stat);
+ return 0;
+}
+
+static int tracefs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+ struct iattr *attr)
+{
+ unsigned int ia_valid = attr->ia_valid;
+ struct inode *inode = d_inode(dentry);
+ struct tracefs_inode *ti = get_tracefs(inode);
+
+ if (ia_valid & ATTR_UID)
+ ti->flags |= TRACEFS_UID_PERM_SET;
+
+ if (ia_valid & ATTR_GID)
+ ti->flags |= TRACEFS_GID_PERM_SET;
+
+ return simple_setattr(idmap, dentry, attr);
+}
+
+static const struct inode_operations tracefs_instance_dir_inode_operations = {
.lookup = simple_lookup,
.mkdir = tracefs_syscall_mkdir,
.rmdir = tracefs_syscall_rmdir,
+ .permission = tracefs_permission,
+ .getattr = tracefs_getattr,
+ .setattr = tracefs_setattr,
+};
+
+static const struct inode_operations tracefs_dir_inode_operations = {
+ .lookup = simple_lookup,
+ .permission = tracefs_permission,
+ .getattr = tracefs_getattr,
+ .setattr = tracefs_setattr,
+};
+
+static const struct inode_operations tracefs_file_inode_operations = {
+ .permission = tracefs_permission,
+ .getattr = tracefs_getattr,
+ .setattr = tracefs_setattr,
};
struct inode *tracefs_get_inode(struct super_block *sb)
@@ -183,82 +259,6 @@ struct tracefs_fs_info {
struct tracefs_mount_opts mount_opts;
};
-static void change_gid(struct dentry *dentry, kgid_t gid)
-{
- if (!dentry->d_inode)
- return;
- dentry->d_inode->i_gid = gid;
-}
-
-/*
- * Taken from d_walk, but without he need for handling renames.
- * Nothing can be renamed while walking the list, as tracefs
- * does not support renames. This is only called when mounting
- * or remounting the file system, to set all the files to
- * the given gid.
- */
-static void set_gid(struct dentry *parent, kgid_t gid)
-{
- struct dentry *this_parent, *dentry;
-
- this_parent = parent;
- spin_lock(&this_parent->d_lock);
-
- change_gid(this_parent, gid);
-repeat:
- dentry = d_first_child(this_parent);
-resume:
- hlist_for_each_entry_from(dentry, d_sib) {
- struct tracefs_inode *ti;
-
- /* Note, getdents() can add a cursor dentry with no inode */
- if (!dentry->d_inode)
- continue;
-
- spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-
- change_gid(dentry, gid);
-
- /* If this is the events directory, update that too */
- ti = get_tracefs(dentry->d_inode);
- if (ti && (ti->flags & TRACEFS_EVENT_INODE))
- eventfs_update_gid(dentry, gid);
-
- if (!hlist_empty(&dentry->d_children)) {
- spin_unlock(&this_parent->d_lock);
- spin_release(&dentry->d_lock.dep_map, _RET_IP_);
- this_parent = dentry;
- spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_);
- goto repeat;
- }
- spin_unlock(&dentry->d_lock);
- }
- /*
- * All done at this level ... ascend and resume the search.
- */
- rcu_read_lock();
-ascend:
- if (this_parent != parent) {
- dentry = this_parent;
- this_parent = dentry->d_parent;
-
- spin_unlock(&dentry->d_lock);
- spin_lock(&this_parent->d_lock);
-
- /* go into the first sibling still alive */
- hlist_for_each_entry_continue(dentry, d_sib) {
- if (likely(!(dentry->d_flags & DCACHE_DENTRY_KILLED))) {
- rcu_read_unlock();
- goto resume;
- }
- }
- goto ascend;
- }
- rcu_read_unlock();
- spin_unlock(&this_parent->d_lock);
- return;
-}
-
static int tracefs_parse_options(char *data, struct tracefs_mount_opts *opts)
{
substring_t args[MAX_OPT_ARGS];
@@ -331,10 +331,8 @@ static int tracefs_apply_options(struct super_block *sb, bool remount)
if (!remount || opts->opts & BIT(Opt_uid))
inode->i_uid = opts->uid;
- if (!remount || opts->opts & BIT(Opt_gid)) {
- /* Set all the group ids to the mount option */
- set_gid(sb->s_root, opts->gid);
- }
+ if (!remount || opts->opts & BIT(Opt_gid))
+ inode->i_gid = opts->gid;
return 0;
}
@@ -568,6 +566,26 @@ struct dentry *eventfs_end_creating(struct dentry *dentry)
return dentry;
}
+/* Find the inode that this will use for default */
+static struct inode *instance_inode(struct dentry *parent, struct inode *inode)
+{
+ struct tracefs_inode *ti;
+
+ /* If parent is NULL then use root inode */
+ if (!parent)
+ return d_inode(inode->i_sb->s_root);
+
+ /* Find the inode that is flagged as an instance or the root inode */
+ while (!IS_ROOT(parent)) {
+ ti = get_tracefs(d_inode(parent));
+ if (ti->flags & TRACEFS_INSTANCE_INODE)
+ break;
+ parent = parent->d_parent;
+ }
+
+ return d_inode(parent);
+}
+
/**
* tracefs_create_file - create a file in the tracefs filesystem
* @name: a pointer to a string containing the name of the file to create.
@@ -598,6 +616,7 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
struct dentry *parent, void *data,
const struct file_operations *fops)
{
+ struct tracefs_inode *ti;
struct dentry *dentry;
struct inode *inode;
@@ -616,7 +635,11 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
if (unlikely(!inode))
return tracefs_failed_creating(dentry);
+ ti = get_tracefs(inode);
+ ti->private = instance_inode(parent, inode);
+
inode->i_mode = mode;
+ inode->i_op = &tracefs_file_inode_operations;
inode->i_fop = fops ? fops : &tracefs_file_operations;
inode->i_private = data;
inode->i_uid = d_inode(dentry->d_parent)->i_uid;
@@ -629,6 +652,7 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
static struct dentry *__create_dir(const char *name, struct dentry *parent,
const struct inode_operations *ops)
{
+ struct tracefs_inode *ti;
struct dentry *dentry = tracefs_start_creating(name, parent);
struct inode *inode;
@@ -646,6 +670,9 @@ static struct dentry *__create_dir(const char *name, struct dentry *parent,
inode->i_uid = d_inode(dentry->d_parent)->i_uid;
inode->i_gid = d_inode(dentry->d_parent)->i_gid;
+ ti = get_tracefs(inode);
+ ti->private = instance_inode(parent, inode);
+
/* directory inodes start off with i_nlink == 2 (for "." entry) */
inc_nlink(inode);
d_instantiate(dentry, inode);
@@ -676,7 +703,7 @@ struct dentry *tracefs_create_dir(const char *name, struct dentry *parent)
if (security_locked_down(LOCKDOWN_TRACEFS))
return NULL;
- return __create_dir(name, parent, &simple_dir_inode_operations);
+ return __create_dir(name, parent, &tracefs_dir_inode_operations);
}
/**
@@ -707,7 +734,7 @@ __init struct dentry *tracefs_create_instance_dir(const char *name,
if (WARN_ON(tracefs_ops.mkdir || tracefs_ops.rmdir))
return NULL;
- dentry = __create_dir(name, parent, &tracefs_dir_inode_operations);
+ dentry = __create_dir(name, parent, &tracefs_instance_dir_inode_operations);
if (!dentry)
return NULL;
diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h
index 42bdeb471a07..12b7d0150ae9 100644
--- a/fs/tracefs/internal.h
+++ b/fs/tracefs/internal.h
@@ -5,6 +5,9 @@
enum {
TRACEFS_EVENT_INODE = BIT(1),
TRACEFS_EVENT_TOP_INODE = BIT(2),
+ TRACEFS_GID_PERM_SET = BIT(3),
+ TRACEFS_UID_PERM_SET = BIT(4),
+ TRACEFS_INSTANCE_INODE = BIT(5),
};
struct tracefs_inode {
diff --git a/fs/ubifs/auth.c b/fs/ubifs/auth.c
index 0d561ecb6869..a4a0158f712d 100644
--- a/fs/ubifs/auth.c
+++ b/fs/ubifs/auth.c
@@ -18,7 +18,7 @@
#include "ubifs.h"
/**
- * ubifs_node_calc_hash - calculate the hash of a UBIFS node
+ * __ubifs_node_calc_hash - calculate the hash of a UBIFS node
* @c: UBIFS file-system description object
* @node: the node to calculate a hash for
* @hash: the returned hash
@@ -507,28 +507,13 @@ out:
*/
int ubifs_hmac_wkm(struct ubifs_info *c, u8 *hmac)
{
- SHASH_DESC_ON_STACK(shash, c->hmac_tfm);
- int err;
const char well_known_message[] = "UBIFS";
if (!ubifs_authenticated(c))
return 0;
- shash->tfm = c->hmac_tfm;
-
- err = crypto_shash_init(shash);
- if (err)
- return err;
-
- err = crypto_shash_update(shash, well_known_message,
- sizeof(well_known_message) - 1);
- if (err < 0)
- return err;
-
- err = crypto_shash_final(shash, hmac);
- if (err)
- return err;
- return 0;
+ return crypto_shash_tfm_digest(c->hmac_tfm, well_known_message,
+ sizeof(well_known_message) - 1, hmac);
}
/*
diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c
index c4fc1047fc07..5b3a840098b0 100644
--- a/fs/ubifs/commit.c
+++ b/fs/ubifs/commit.c
@@ -70,18 +70,29 @@ static int nothing_to_commit(struct ubifs_info *c)
return 0;
/*
+ * Increasing @c->dirty_pn_cnt/@c->dirty_nn_cnt and marking
+ * nnodes/pnodes as dirty in run_gc() could race with following
+ * checking, which leads inconsistent states between @c->nroot
+ * and @c->dirty_pn_cnt/@c->dirty_nn_cnt, holding @c->lp_mutex
+ * to avoid that.
+ */
+ mutex_lock(&c->lp_mutex);
+ /*
* Even though the TNC is clean, the LPT tree may have dirty nodes. For
* example, this may happen if the budgeting subsystem invoked GC to
* make some free space, and the GC found an LEB with only dirty and
* free space. In this case GC would just change the lprops of this
* LEB (by turning all space into free space) and unmap it.
*/
- if (c->nroot && test_bit(DIRTY_CNODE, &c->nroot->flags))
+ if (c->nroot && test_bit(DIRTY_CNODE, &c->nroot->flags)) {
+ mutex_unlock(&c->lp_mutex);
return 0;
+ }
ubifs_assert(c, atomic_long_read(&c->dirty_zn_cnt) == 0);
ubifs_assert(c, c->dirty_pn_cnt == 0);
ubifs_assert(c, c->dirty_nn_cnt == 0);
+ mutex_unlock(&c->lp_mutex);
return 1;
}
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 3b13c648d490..e413a9cf8ee3 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -1234,6 +1234,8 @@ out_cancel:
dir_ui->ui_size = dir->i_size;
mutex_unlock(&dir_ui->ui_mutex);
out_inode:
+ /* Free inode->i_link before inode is marked as bad. */
+ fscrypt_free_inode(inode);
make_bad_inode(inode);
iput(inode);
out_fname:
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 2d2b39f843ce..5029eb3390a5 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -318,8 +318,9 @@ static int write_begin_slow(struct address_space *mapping,
* This is a helper function for 'ubifs_write_begin()' which allocates budget
* for the operation. The budget is allocated differently depending on whether
* this is appending, whether the page is dirty or not, and so on. This
- * function leaves the @ui->ui_mutex locked in case of appending. Returns zero
- * in case of success and %-ENOSPC in case of failure.
+ * function leaves the @ui->ui_mutex locked in case of appending.
+ *
+ * Returns: %0 in case of success and %-ENOSPC in case of failure.
*/
static int allocate_budget(struct ubifs_info *c, struct page *page,
struct ubifs_inode *ui, int appending)
@@ -600,7 +601,7 @@ out:
* @bu: bulk-read information
* @n: next zbranch slot
*
- * This function returns %0 on success and a negative error code on failure.
+ * Returns: %0 on success and a negative error code on failure.
*/
static int populate_page(struct ubifs_info *c, struct page *page,
struct bu_info *bu, int *n)
@@ -711,7 +712,7 @@ out_err:
* @bu: bulk-read information
* @page1: first page to read
*
- * This function returns %1 if the bulk-read is done, otherwise %0 is returned.
+ * Returns: %1 if the bulk-read is done, otherwise %0 is returned.
*/
static int ubifs_do_bulk_read(struct ubifs_info *c, struct bu_info *bu,
struct page *page1)
@@ -821,7 +822,9 @@ out_bu_off:
* Some flash media are capable of reading sequentially at faster rates. UBIFS
* bulk-read facility is designed to take advantage of that, by reading in one
* go consecutive data nodes that are also located consecutively in the same
- * LEB. This function returns %1 if a bulk-read is done and %0 otherwise.
+ * LEB.
+ *
+ * Returns: %1 if a bulk-read is done and %0 otherwise.
*/
static int ubifs_bulk_read(struct page *page)
{
@@ -1109,7 +1112,9 @@ static void do_attr_changes(struct inode *inode, const struct iattr *attr)
* @attr: inode attribute changes description
*
* This function implements VFS '->setattr()' call when the inode is truncated
- * to a smaller size. Returns zero in case of success and a negative error code
+ * to a smaller size.
+ *
+ * Returns: %0 in case of success and a negative error code
* in case of failure.
*/
static int do_truncation(struct ubifs_info *c, struct inode *inode,
@@ -1215,7 +1220,9 @@ out_budg:
* @attr: inode attribute changes description
*
* This function implements VFS '->setattr()' call for all cases except
- * truncations to smaller size. Returns zero in case of success and a negative
+ * truncations to smaller size.
+ *
+ * Returns: %0 in case of success and a negative
* error code in case of failure.
*/
static int do_setattr(struct ubifs_info *c, struct inode *inode,
@@ -1360,6 +1367,8 @@ out:
* This helper function checks if the inode mtime/ctime should be updated or
* not. If current values of the time-stamps are within the UBIFS inode time
* granularity, they are not updated. This is an optimization.
+ *
+ * Returns: %1 if time update is needed, %0 if not
*/
static inline int mctime_update_needed(const struct inode *inode,
const struct timespec64 *now)
@@ -1375,11 +1384,12 @@ static inline int mctime_update_needed(const struct inode *inode,
/**
* ubifs_update_time - update time of inode.
* @inode: inode to update
- * @time: timespec structure to hold the current time value
* @flags: time updating control flag determines updating
* which time fields of @inode
*
* This function updates time of the inode.
+ *
+ * Returns: %0 for success or a negative error code otherwise.
*/
int ubifs_update_time(struct inode *inode, int flags)
{
@@ -1413,7 +1423,9 @@ int ubifs_update_time(struct inode *inode, int flags)
* @inode: inode to update
*
* This function updates mtime and ctime of the inode if it is not equivalent to
- * current time. Returns zero in case of success and a negative error code in
+ * current time.
+ *
+ * Returns: %0 in case of success and a negative error code in
* case of failure.
*/
static int update_mctime(struct inode *inode)
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index c59d47fe7939..17da28d6247a 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -365,6 +365,7 @@ static void destroy_replay_list(struct ubifs_info *c)
* @lnum: node logical eraseblock number
* @offs: node offset
* @len: node length
+ * @hash: node hash
* @key: node key
* @sqnum: sequence number
* @deletion: non-zero if this is a deletion
@@ -417,6 +418,7 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
* @lnum: node logical eraseblock number
* @offs: node offset
* @len: node length
+ * @hash: node hash
* @key: node key
* @name: directory entry name
* @nlen: directory entry name length
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 4fcefe5ef7cb..959551ff9a95 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -1032,7 +1032,7 @@ static int resolve_userfault_fork(struct userfaultfd_ctx *new,
{
int fd;
- fd = anon_inode_getfd_secure("[userfaultfd]", &userfaultfd_fops, new,
+ fd = anon_inode_create_getfd("[userfaultfd]", &userfaultfd_fops, new,
O_RDONLY | (new->flags & UFFD_SHARED_FCNTL_FLAGS), inode);
if (fd < 0)
return fd;
@@ -2260,7 +2260,8 @@ static int new_userfaultfd(int flags)
/* prevent the mm struct to be freed */
mmgrab(ctx->mm);
- fd = anon_inode_getfd_secure("[userfaultfd]", &userfaultfd_fops, ctx,
+ /* Create a new inode so that the LSM can block the creation. */
+ fd = anon_inode_create_getfd("[userfaultfd]", &userfaultfd_fops, ctx,
O_RDONLY | (flags & UFFD_SHARED_FCNTL_FLAGS), NULL);
if (fd < 0) {
mmdrop(ctx->mm);
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 2b3ae51f950d..e4d24d3f9abb 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -719,6 +719,8 @@ struct acpi_pci_root {
/* helper */
+struct iommu_ops;
+
bool acpi_dma_supported(const struct acpi_device *adev);
enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
int acpi_iommu_fwspec_init(struct device *dev, u32 id,
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index 3751ae69432f..9775384d61c6 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -1046,6 +1046,8 @@ struct acpi_madt_generic_interrupt {
/* ACPI_MADT_ENABLED (1) Processor is usable if set */
#define ACPI_MADT_PERFORMANCE_IRQ_MODE (1<<1) /* 01: Performance Interrupt Mode */
#define ACPI_MADT_VGIC_IRQ_MODE (1<<2) /* 02: VGIC Maintenance Interrupt mode */
+#define ACPI_MADT_GICC_ONLINE_CAPABLE (1<<3) /* 03: Processor is online capable */
+#define ACPI_MADT_GICC_NON_COHERENT (1<<4) /* 04: GIC redistributor is not coherent */
/* 12: Generic Distributor (ACPI 5.0 + ACPI 6.0 changes) */
@@ -1090,21 +1092,27 @@ struct acpi_madt_generic_msi_frame {
struct acpi_madt_generic_redistributor {
struct acpi_subtable_header header;
- u16 reserved; /* reserved - must be zero */
+ u8 flags;
+ u8 reserved; /* reserved - must be zero */
u64 base_address;
u32 length;
};
+#define ACPI_MADT_GICR_NON_COHERENT (1)
+
/* 15: Generic Translator (ACPI 6.0) */
struct acpi_madt_generic_translator {
struct acpi_subtable_header header;
- u16 reserved; /* reserved - must be zero */
+ u8 flags;
+ u8 reserved; /* reserved - must be zero */
u32 translation_id;
u64 base_address;
u32 reserved2;
};
+#define ACPI_MADT_ITS_NON_COHERENT (1)
+
/* 16: Multiprocessor wakeup (ACPI 6.4) */
struct acpi_madt_multiproc_wakeup {
diff --git a/include/asm-generic/cacheflush.h b/include/asm-generic/cacheflush.h
index 84ec53ccc450..7ee8a179d103 100644
--- a/include/asm-generic/cacheflush.h
+++ b/include/asm-generic/cacheflush.h
@@ -91,6 +91,12 @@ static inline void flush_cache_vmap(unsigned long start, unsigned long end)
}
#endif
+#ifndef flush_cache_vmap_early
+static inline void flush_cache_vmap_early(unsigned long start, unsigned long end)
+{
+}
+#endif
+
#ifndef flush_cache_vunmap
static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
{
diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h
index 387767f4e298..fd09819da2ec 100644
--- a/include/dt-bindings/clock/g12a-clkc.h
+++ b/include/dt-bindings/clock/g12a-clkc.h
@@ -279,5 +279,13 @@
#define CLKID_MIPI_DSI_PXCLK_DIV 268
#define CLKID_MIPI_DSI_PXCLK_SEL 269
#define CLKID_MIPI_DSI_PXCLK 270
+#define CLKID_CTS_ENCL 271
+#define CLKID_CTS_ENCL_SEL 272
+#define CLKID_MIPI_ISP_DIV 273
+#define CLKID_MIPI_ISP_SEL 274
+#define CLKID_MIPI_ISP 275
+#define CLKID_MIPI_ISP_GATE 276
+#define CLKID_MIPI_ISP_CSI_PHY0 277
+#define CLKID_MIPI_ISP_CSI_PHY1 278
#endif /* __G12A_CLKC_H */
diff --git a/include/dt-bindings/clock/mediatek,mt7988-clk.h b/include/dt-bindings/clock/mediatek,mt7988-clk.h
new file mode 100644
index 000000000000..63376e40f14d
--- /dev/null
+++ b/include/dt-bindings/clock/mediatek,mt7988-clk.h
@@ -0,0 +1,280 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2023 MediaTek Inc.
+ * Author: Sam Shih <[email protected]>
+ * Author: Xiufeng Li <[email protected]>
+ */
+
+#ifndef _DT_BINDINGS_CLK_MT7988_H
+#define _DT_BINDINGS_CLK_MT7988_H
+
+/* APMIXEDSYS */
+
+#define CLK_APMIXED_NETSYSPLL 0
+#define CLK_APMIXED_MPLL 1
+#define CLK_APMIXED_MMPLL 2
+#define CLK_APMIXED_APLL2 3
+#define CLK_APMIXED_NET1PLL 4
+#define CLK_APMIXED_NET2PLL 5
+#define CLK_APMIXED_WEDMCUPLL 6
+#define CLK_APMIXED_SGMPLL 7
+#define CLK_APMIXED_ARM_B 8
+#define CLK_APMIXED_CCIPLL2_B 9
+#define CLK_APMIXED_USXGMIIPLL 10
+#define CLK_APMIXED_MSDCPLL 11
+
+/* TOPCKGEN */
+
+#define CLK_TOP_XTAL 0
+#define CLK_TOP_XTAL_D2 1
+#define CLK_TOP_RTC_32K 2
+#define CLK_TOP_RTC_32P7K 3
+#define CLK_TOP_MPLL_D2 4
+#define CLK_TOP_MPLL_D3_D2 5
+#define CLK_TOP_MPLL_D4 6
+#define CLK_TOP_MPLL_D8 7
+#define CLK_TOP_MPLL_D8_D2 8
+#define CLK_TOP_MMPLL_D2 9
+#define CLK_TOP_MMPLL_D3_D5 10
+#define CLK_TOP_MMPLL_D4 11
+#define CLK_TOP_MMPLL_D6_D2 12
+#define CLK_TOP_MMPLL_D8 13
+#define CLK_TOP_APLL2_D4 14
+#define CLK_TOP_NET1PLL_D4 15
+#define CLK_TOP_NET1PLL_D5 16
+#define CLK_TOP_NET1PLL_D5_D2 17
+#define CLK_TOP_NET1PLL_D5_D4 18
+#define CLK_TOP_NET1PLL_D8 19
+#define CLK_TOP_NET1PLL_D8_D2 20
+#define CLK_TOP_NET1PLL_D8_D4 21
+#define CLK_TOP_NET1PLL_D8_D8 22
+#define CLK_TOP_NET1PLL_D8_D16 23
+#define CLK_TOP_NET2PLL_D2 24
+#define CLK_TOP_NET2PLL_D4 25
+#define CLK_TOP_NET2PLL_D4_D4 26
+#define CLK_TOP_NET2PLL_D4_D8 27
+#define CLK_TOP_NET2PLL_D6 28
+#define CLK_TOP_NET2PLL_D8 29
+#define CLK_TOP_NETSYS_SEL 30
+#define CLK_TOP_NETSYS_500M_SEL 31
+#define CLK_TOP_NETSYS_2X_SEL 32
+#define CLK_TOP_NETSYS_GSW_SEL 33
+#define CLK_TOP_ETH_GMII_SEL 34
+#define CLK_TOP_NETSYS_MCU_SEL 35
+#define CLK_TOP_NETSYS_PAO_2X_SEL 36
+#define CLK_TOP_EIP197_SEL 37
+#define CLK_TOP_AXI_INFRA_SEL 38
+#define CLK_TOP_UART_SEL 39
+#define CLK_TOP_EMMC_250M_SEL 40
+#define CLK_TOP_EMMC_400M_SEL 41
+#define CLK_TOP_SPI_SEL 42
+#define CLK_TOP_SPIM_MST_SEL 43
+#define CLK_TOP_NFI1X_SEL 44
+#define CLK_TOP_SPINFI_SEL 45
+#define CLK_TOP_PWM_SEL 46
+#define CLK_TOP_I2C_SEL 47
+#define CLK_TOP_PCIE_MBIST_250M_SEL 48
+#define CLK_TOP_PEXTP_TL_SEL 49
+#define CLK_TOP_PEXTP_TL_P1_SEL 50
+#define CLK_TOP_PEXTP_TL_P2_SEL 51
+#define CLK_TOP_PEXTP_TL_P3_SEL 52
+#define CLK_TOP_USB_SYS_SEL 53
+#define CLK_TOP_USB_SYS_P1_SEL 54
+#define CLK_TOP_USB_XHCI_SEL 55
+#define CLK_TOP_USB_XHCI_P1_SEL 56
+#define CLK_TOP_USB_FRMCNT_SEL 57
+#define CLK_TOP_USB_FRMCNT_P1_SEL 58
+#define CLK_TOP_AUD_SEL 59
+#define CLK_TOP_A1SYS_SEL 60
+#define CLK_TOP_AUD_L_SEL 61
+#define CLK_TOP_A_TUNER_SEL 62
+#define CLK_TOP_SSPXTP_SEL 63
+#define CLK_TOP_USB_PHY_SEL 64
+#define CLK_TOP_USXGMII_SBUS_0_SEL 65
+#define CLK_TOP_USXGMII_SBUS_1_SEL 66
+#define CLK_TOP_SGM_0_SEL 67
+#define CLK_TOP_SGM_SBUS_0_SEL 68
+#define CLK_TOP_SGM_1_SEL 69
+#define CLK_TOP_SGM_SBUS_1_SEL 70
+#define CLK_TOP_XFI_PHY_0_XTAL_SEL 71
+#define CLK_TOP_XFI_PHY_1_XTAL_SEL 72
+#define CLK_TOP_SYSAXI_SEL 73
+#define CLK_TOP_SYSAPB_SEL 74
+#define CLK_TOP_ETH_REFCK_50M_SEL 75
+#define CLK_TOP_ETH_SYS_200M_SEL 76
+#define CLK_TOP_ETH_SYS_SEL 77
+#define CLK_TOP_ETH_XGMII_SEL 78
+#define CLK_TOP_BUS_TOPS_SEL 79
+#define CLK_TOP_NPU_TOPS_SEL 80
+#define CLK_TOP_DRAMC_SEL 81
+#define CLK_TOP_DRAMC_MD32_SEL 82
+#define CLK_TOP_INFRA_F26M_SEL 83
+#define CLK_TOP_PEXTP_P0_SEL 84
+#define CLK_TOP_PEXTP_P1_SEL 85
+#define CLK_TOP_PEXTP_P2_SEL 86
+#define CLK_TOP_PEXTP_P3_SEL 87
+#define CLK_TOP_DA_XTP_GLB_P0_SEL 88
+#define CLK_TOP_DA_XTP_GLB_P1_SEL 89
+#define CLK_TOP_DA_XTP_GLB_P2_SEL 90
+#define CLK_TOP_DA_XTP_GLB_P3_SEL 91
+#define CLK_TOP_CKM_SEL 92
+#define CLK_TOP_DA_SEL 93
+#define CLK_TOP_PEXTP_SEL 94
+#define CLK_TOP_TOPS_P2_26M_SEL 95
+#define CLK_TOP_MCUSYS_BACKUP_625M_SEL 96
+#define CLK_TOP_NETSYS_SYNC_250M_SEL 97
+#define CLK_TOP_MACSEC_SEL 98
+#define CLK_TOP_NETSYS_TOPS_400M_SEL 99
+#define CLK_TOP_NETSYS_PPEFB_250M_SEL 100
+#define CLK_TOP_NETSYS_WARP_SEL 101
+#define CLK_TOP_ETH_MII_SEL 102
+#define CLK_TOP_NPU_SEL 103
+#define CLK_TOP_AUD_I2S_M 104
+
+/* MCUSYS */
+
+#define CLK_MCU_BUS_DIV_SEL 0
+#define CLK_MCU_ARM_DIV_SEL 1
+
+/* INFRACFG_AO */
+
+#define CLK_INFRA_MUX_UART0_SEL 0
+#define CLK_INFRA_MUX_UART1_SEL 1
+#define CLK_INFRA_MUX_UART2_SEL 2
+#define CLK_INFRA_MUX_SPI0_SEL 3
+#define CLK_INFRA_MUX_SPI1_SEL 4
+#define CLK_INFRA_MUX_SPI2_SEL 5
+#define CLK_INFRA_PWM_SEL 6
+#define CLK_INFRA_PWM_CK1_SEL 7
+#define CLK_INFRA_PWM_CK2_SEL 8
+#define CLK_INFRA_PWM_CK3_SEL 9
+#define CLK_INFRA_PWM_CK4_SEL 10
+#define CLK_INFRA_PWM_CK5_SEL 11
+#define CLK_INFRA_PWM_CK6_SEL 12
+#define CLK_INFRA_PWM_CK7_SEL 13
+#define CLK_INFRA_PWM_CK8_SEL 14
+#define CLK_INFRA_PCIE_GFMUX_TL_O_P0_SEL 15
+#define CLK_INFRA_PCIE_GFMUX_TL_O_P1_SEL 16
+#define CLK_INFRA_PCIE_GFMUX_TL_O_P2_SEL 17
+#define CLK_INFRA_PCIE_GFMUX_TL_O_P3_SEL 18
+
+/* INFRACFG */
+
+#define CLK_INFRA_PCIE_PERI_26M_CK_P0 19
+#define CLK_INFRA_PCIE_PERI_26M_CK_P1 20
+#define CLK_INFRA_PCIE_PERI_26M_CK_P2 21
+#define CLK_INFRA_PCIE_PERI_26M_CK_P3 22
+#define CLK_INFRA_66M_GPT_BCK 23
+#define CLK_INFRA_66M_PWM_HCK 24
+#define CLK_INFRA_66M_PWM_BCK 25
+#define CLK_INFRA_66M_PWM_CK1 26
+#define CLK_INFRA_66M_PWM_CK2 27
+#define CLK_INFRA_66M_PWM_CK3 28
+#define CLK_INFRA_66M_PWM_CK4 29
+#define CLK_INFRA_66M_PWM_CK5 30
+#define CLK_INFRA_66M_PWM_CK6 31
+#define CLK_INFRA_66M_PWM_CK7 32
+#define CLK_INFRA_66M_PWM_CK8 33
+#define CLK_INFRA_133M_CQDMA_BCK 34
+#define CLK_INFRA_66M_AUD_SLV_BCK 35
+#define CLK_INFRA_AUD_26M 36
+#define CLK_INFRA_AUD_L 37
+#define CLK_INFRA_AUD_AUD 38
+#define CLK_INFRA_AUD_EG2 39
+#define CLK_INFRA_DRAMC_F26M 40
+#define CLK_INFRA_133M_DBG_ACKM 41
+#define CLK_INFRA_66M_AP_DMA_BCK 42
+#define CLK_INFRA_66M_SEJ_BCK 43
+#define CLK_INFRA_PRE_CK_SEJ_F13M 44
+#define CLK_INFRA_26M_THERM_SYSTEM 45
+#define CLK_INFRA_I2C_BCK 46
+#define CLK_INFRA_52M_UART0_CK 47
+#define CLK_INFRA_52M_UART1_CK 48
+#define CLK_INFRA_52M_UART2_CK 49
+#define CLK_INFRA_NFI 50
+#define CLK_INFRA_SPINFI 51
+#define CLK_INFRA_66M_NFI_HCK 52
+#define CLK_INFRA_104M_SPI0 53
+#define CLK_INFRA_104M_SPI1 54
+#define CLK_INFRA_104M_SPI2_BCK 55
+#define CLK_INFRA_66M_SPI0_HCK 56
+#define CLK_INFRA_66M_SPI1_HCK 57
+#define CLK_INFRA_66M_SPI2_HCK 58
+#define CLK_INFRA_66M_FLASHIF_AXI 59
+#define CLK_INFRA_RTC 60
+#define CLK_INFRA_26M_ADC_BCK 61
+#define CLK_INFRA_RC_ADC 62
+#define CLK_INFRA_MSDC400 63
+#define CLK_INFRA_MSDC2_HCK 64
+#define CLK_INFRA_133M_MSDC_0_HCK 65
+#define CLK_INFRA_66M_MSDC_0_HCK 66
+#define CLK_INFRA_133M_CPUM_BCK 67
+#define CLK_INFRA_BIST2FPC 68
+#define CLK_INFRA_I2C_X16W_MCK_CK_P1 69
+#define CLK_INFRA_I2C_X16W_PCK_CK_P1 70
+#define CLK_INFRA_133M_USB_HCK 71
+#define CLK_INFRA_133M_USB_HCK_CK_P1 72
+#define CLK_INFRA_66M_USB_HCK 73
+#define CLK_INFRA_66M_USB_HCK_CK_P1 74
+#define CLK_INFRA_USB_SYS 75
+#define CLK_INFRA_USB_SYS_CK_P1 76
+#define CLK_INFRA_USB_REF 77
+#define CLK_INFRA_USB_CK_P1 78
+#define CLK_INFRA_USB_FRMCNT 79
+#define CLK_INFRA_USB_FRMCNT_CK_P1 80
+#define CLK_INFRA_USB_PIPE 81
+#define CLK_INFRA_USB_PIPE_CK_P1 82
+#define CLK_INFRA_USB_UTMI 83
+#define CLK_INFRA_USB_UTMI_CK_P1 84
+#define CLK_INFRA_USB_XHCI 85
+#define CLK_INFRA_USB_XHCI_CK_P1 86
+#define CLK_INFRA_PCIE_GFMUX_TL_P0 87
+#define CLK_INFRA_PCIE_GFMUX_TL_P1 88
+#define CLK_INFRA_PCIE_GFMUX_TL_P2 89
+#define CLK_INFRA_PCIE_GFMUX_TL_P3 90
+#define CLK_INFRA_PCIE_PIPE_P0 91
+#define CLK_INFRA_PCIE_PIPE_P1 92
+#define CLK_INFRA_PCIE_PIPE_P2 93
+#define CLK_INFRA_PCIE_PIPE_P3 94
+#define CLK_INFRA_133M_PCIE_CK_P0 95
+#define CLK_INFRA_133M_PCIE_CK_P1 96
+#define CLK_INFRA_133M_PCIE_CK_P2 97
+#define CLK_INFRA_133M_PCIE_CK_P3 98
+
+/* ETHDMA */
+
+#define CLK_ETHDMA_XGP1_EN 0
+#define CLK_ETHDMA_XGP2_EN 1
+#define CLK_ETHDMA_XGP3_EN 2
+#define CLK_ETHDMA_FE_EN 3
+#define CLK_ETHDMA_GP2_EN 4
+#define CLK_ETHDMA_GP1_EN 5
+#define CLK_ETHDMA_GP3_EN 6
+#define CLK_ETHDMA_ESW_EN 7
+#define CLK_ETHDMA_CRYPT0_EN 8
+#define CLK_ETHDMA_NR_CLK 9
+
+/* SGMIISYS_0 */
+
+#define CLK_SGM0_TX_EN 0
+#define CLK_SGM0_RX_EN 1
+#define CLK_SGMII0_NR_CLK 2
+
+/* SGMIISYS_1 */
+
+#define CLK_SGM1_TX_EN 0
+#define CLK_SGM1_RX_EN 1
+#define CLK_SGMII1_NR_CLK 2
+
+/* ETHWARP */
+
+#define CLK_ETHWARP_WOCPU2_EN 0
+#define CLK_ETHWARP_WOCPU1_EN 1
+#define CLK_ETHWARP_WOCPU0_EN 2
+#define CLK_ETHWARP_NR_CLK 3
+
+/* XFIPLL */
+#define CLK_XFIPLL_PLL 0
+#define CLK_XFIPLL_PLL_EN 1
+
+#endif /* _DT_BINDINGS_CLK_MT7988_H */
diff --git a/include/dt-bindings/clock/qcom,gcc-msm8939.h b/include/dt-bindings/clock/qcom,gcc-msm8939.h
index 2d545ed0d35a..9a9bc55b49af 100644
--- a/include/dt-bindings/clock/qcom,gcc-msm8939.h
+++ b/include/dt-bindings/clock/qcom,gcc-msm8939.h
@@ -193,6 +193,12 @@
#define GCC_VENUS0_CORE1_VCODEC0_CLK 184
#define GCC_OXILI_TIMER_CLK 185
#define SYSTEM_MM_NOC_BFDCD_CLK_SRC 186
+#define CSI2_CLK_SRC 187
+#define GCC_CAMSS_CSI2_AHB_CLK 188
+#define GCC_CAMSS_CSI2_CLK 189
+#define GCC_CAMSS_CSI2PHY_CLK 190
+#define GCC_CAMSS_CSI2PIX_CLK 191
+#define GCC_CAMSS_CSI2RDI_CLK 192
/* Indexes for GDSCs */
#define BIMC_GDSC 0
diff --git a/include/dt-bindings/clock/qcom,qdu1000-ecpricc.h b/include/dt-bindings/clock/qcom,qdu1000-ecpricc.h
new file mode 100644
index 000000000000..731e404a2ce6
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,qdu1000-ecpricc.h
@@ -0,0 +1,147 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_ECPRI_CC_QDU1000_H
+#define _DT_BINDINGS_CLK_QCOM_ECPRI_CC_QDU1000_H
+
+/* ECPRI_CC clocks */
+#define ECPRI_CC_PLL0 0
+#define ECPRI_CC_PLL1 1
+#define ECPRI_CC_ECPRI_CG_CLK 2
+#define ECPRI_CC_ECPRI_CLK_SRC 3
+#define ECPRI_CC_ECPRI_DMA_CLK 4
+#define ECPRI_CC_ECPRI_DMA_CLK_SRC 5
+#define ECPRI_CC_ECPRI_DMA_NOC_CLK 6
+#define ECPRI_CC_ECPRI_FAST_CLK 7
+#define ECPRI_CC_ECPRI_FAST_CLK_SRC 8
+#define ECPRI_CC_ECPRI_FAST_DIV2_CLK 9
+#define ECPRI_CC_ECPRI_FAST_DIV2_CLK_SRC 10
+#define ECPRI_CC_ECPRI_FAST_DIV2_NOC_CLK 11
+#define ECPRI_CC_ECPRI_FR_CLK 12
+#define ECPRI_CC_ECPRI_ORAN_CLK_SRC 13
+#define ECPRI_CC_ECPRI_ORAN_DIV2_CLK 14
+#define ECPRI_CC_ETH_100G_C2C0_HM_FF_CLK_SRC 15
+#define ECPRI_CC_ETH_100G_C2C0_UDP_FIFO_CLK 16
+#define ECPRI_CC_ETH_100G_C2C1_UDP_FIFO_CLK 17
+#define ECPRI_CC_ETH_100G_C2C_0_HM_FF_0_CLK 18
+#define ECPRI_CC_ETH_100G_C2C_0_HM_FF_1_CLK 19
+#define ECPRI_CC_ETH_100G_C2C_HM_FF_0_DIV_CLK_SRC 20
+#define ECPRI_CC_ETH_100G_C2C_HM_FF_1_DIV_CLK_SRC 21
+#define ECPRI_CC_ETH_100G_C2C_HM_MACSEC_CLK 22
+#define ECPRI_CC_ETH_100G_C2C_HM_MACSEC_CLK_SRC 23
+#define ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_0_CLK 24
+#define ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_0_DIV_CLK_SRC 25
+#define ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_1_CLK 26
+#define ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_1_DIV_CLK_SRC 27
+#define ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_CLK_SRC 28
+#define ECPRI_CC_ETH_100G_DBG_C2C_UDP_FIFO_CLK 29
+#define ECPRI_CC_ETH_100G_FH0_HM_FF_CLK_SRC 30
+#define ECPRI_CC_ETH_100G_FH0_MACSEC_CLK_SRC 31
+#define ECPRI_CC_ETH_100G_FH1_HM_FF_CLK_SRC 32
+#define ECPRI_CC_ETH_100G_FH1_MACSEC_CLK_SRC 33
+#define ECPRI_CC_ETH_100G_FH2_HM_FF_CLK_SRC 34
+#define ECPRI_CC_ETH_100G_FH2_MACSEC_CLK_SRC 35
+#define ECPRI_CC_ETH_100G_FH_0_HM_FF_0_CLK 36
+#define ECPRI_CC_ETH_100G_FH_0_HM_FF_0_DIV_CLK_SRC 37
+#define ECPRI_CC_ETH_100G_FH_0_HM_FF_1_CLK 38
+#define ECPRI_CC_ETH_100G_FH_0_HM_FF_1_DIV_CLK_SRC 39
+#define ECPRI_CC_ETH_100G_FH_0_HM_FF_2_CLK 40
+#define ECPRI_CC_ETH_100G_FH_0_HM_FF_2_DIV_CLK_SRC 41
+#define ECPRI_CC_ETH_100G_FH_0_HM_FF_3_CLK 42
+#define ECPRI_CC_ETH_100G_FH_0_HM_FF_3_DIV_CLK_SRC 43
+#define ECPRI_CC_ETH_100G_FH_0_UDP_FIFO_CLK 44
+#define ECPRI_CC_ETH_100G_FH_1_HM_FF_0_CLK 45
+#define ECPRI_CC_ETH_100G_FH_1_HM_FF_0_DIV_CLK_SRC 46
+#define ECPRI_CC_ETH_100G_FH_1_HM_FF_1_CLK 47
+#define ECPRI_CC_ETH_100G_FH_1_HM_FF_1_DIV_CLK_SRC 48
+#define ECPRI_CC_ETH_100G_FH_1_HM_FF_2_CLK 49
+#define ECPRI_CC_ETH_100G_FH_1_HM_FF_2_DIV_CLK_SRC 50
+#define ECPRI_CC_ETH_100G_FH_1_HM_FF_3_CLK 51
+#define ECPRI_CC_ETH_100G_FH_1_HM_FF_3_DIV_CLK_SRC 52
+#define ECPRI_CC_ETH_100G_FH_1_UDP_FIFO_CLK 53
+#define ECPRI_CC_ETH_100G_FH_2_HM_FF_0_CLK 54
+#define ECPRI_CC_ETH_100G_FH_2_HM_FF_0_DIV_CLK_SRC 55
+#define ECPRI_CC_ETH_100G_FH_2_HM_FF_1_CLK 56
+#define ECPRI_CC_ETH_100G_FH_2_HM_FF_1_DIV_CLK_SRC 57
+#define ECPRI_CC_ETH_100G_FH_2_HM_FF_2_CLK 58
+#define ECPRI_CC_ETH_100G_FH_2_HM_FF_2_DIV_CLK_SRC 59
+#define ECPRI_CC_ETH_100G_FH_2_HM_FF_3_CLK 60
+#define ECPRI_CC_ETH_100G_FH_2_HM_FF_3_DIV_CLK_SRC 61
+#define ECPRI_CC_ETH_100G_FH_2_UDP_FIFO_CLK 62
+#define ECPRI_CC_ETH_100G_FH_MACSEC_0_CLK 63
+#define ECPRI_CC_ETH_100G_FH_MACSEC_1_CLK 64
+#define ECPRI_CC_ETH_100G_FH_MACSEC_2_CLK 65
+#define ECPRI_CC_ETH_100G_MAC_C2C_HM_REF_CLK 66
+#define ECPRI_CC_ETH_100G_MAC_C2C_HM_REF_CLK_SRC 67
+#define ECPRI_CC_ETH_100G_MAC_DBG_C2C_HM_REF_CLK 68
+#define ECPRI_CC_ETH_100G_MAC_DBG_C2C_HM_REF_CLK_SRC 69
+#define ECPRI_CC_ETH_100G_MAC_FH0_HM_REF_CLK 70
+#define ECPRI_CC_ETH_100G_MAC_FH0_HM_REF_CLK_SRC 71
+#define ECPRI_CC_ETH_100G_MAC_FH1_HM_REF_CLK 72
+#define ECPRI_CC_ETH_100G_MAC_FH1_HM_REF_CLK_SRC 73
+#define ECPRI_CC_ETH_100G_MAC_FH2_HM_REF_CLK 74
+#define ECPRI_CC_ETH_100G_MAC_FH2_HM_REF_CLK_SRC 75
+#define ECPRI_CC_ETH_DBG_NFAPI_AXI_CLK 76
+#define ECPRI_CC_ETH_DBG_NOC_AXI_CLK 77
+#define ECPRI_CC_ETH_PHY_0_OCK_SRAM_CLK 78
+#define ECPRI_CC_ETH_PHY_1_OCK_SRAM_CLK 79
+#define ECPRI_CC_ETH_PHY_2_OCK_SRAM_CLK 80
+#define ECPRI_CC_ETH_PHY_3_OCK_SRAM_CLK 81
+#define ECPRI_CC_ETH_PHY_4_OCK_SRAM_CLK 82
+#define ECPRI_CC_MSS_EMAC_CLK 83
+#define ECPRI_CC_MSS_EMAC_CLK_SRC 84
+#define ECPRI_CC_MSS_ORAN_CLK 85
+#define ECPRI_CC_PHY0_LANE0_RX_CLK 86
+#define ECPRI_CC_PHY0_LANE0_TX_CLK 87
+#define ECPRI_CC_PHY0_LANE1_RX_CLK 88
+#define ECPRI_CC_PHY0_LANE1_TX_CLK 89
+#define ECPRI_CC_PHY0_LANE2_RX_CLK 90
+#define ECPRI_CC_PHY0_LANE2_TX_CLK 91
+#define ECPRI_CC_PHY0_LANE3_RX_CLK 92
+#define ECPRI_CC_PHY0_LANE3_TX_CLK 93
+#define ECPRI_CC_PHY1_LANE0_RX_CLK 94
+#define ECPRI_CC_PHY1_LANE0_TX_CLK 95
+#define ECPRI_CC_PHY1_LANE1_RX_CLK 96
+#define ECPRI_CC_PHY1_LANE1_TX_CLK 97
+#define ECPRI_CC_PHY1_LANE2_RX_CLK 98
+#define ECPRI_CC_PHY1_LANE2_TX_CLK 99
+#define ECPRI_CC_PHY1_LANE3_RX_CLK 100
+#define ECPRI_CC_PHY1_LANE3_TX_CLK 101
+#define ECPRI_CC_PHY2_LANE0_RX_CLK 102
+#define ECPRI_CC_PHY2_LANE0_TX_CLK 103
+#define ECPRI_CC_PHY2_LANE1_RX_CLK 104
+#define ECPRI_CC_PHY2_LANE1_TX_CLK 105
+#define ECPRI_CC_PHY2_LANE2_RX_CLK 106
+#define ECPRI_CC_PHY2_LANE2_TX_CLK 107
+#define ECPRI_CC_PHY2_LANE3_RX_CLK 108
+#define ECPRI_CC_PHY2_LANE3_TX_CLK 109
+#define ECPRI_CC_PHY3_LANE0_RX_CLK 110
+#define ECPRI_CC_PHY3_LANE0_TX_CLK 111
+#define ECPRI_CC_PHY3_LANE1_RX_CLK 112
+#define ECPRI_CC_PHY3_LANE1_TX_CLK 113
+#define ECPRI_CC_PHY3_LANE2_RX_CLK 114
+#define ECPRI_CC_PHY3_LANE2_TX_CLK 115
+#define ECPRI_CC_PHY3_LANE3_RX_CLK 116
+#define ECPRI_CC_PHY3_LANE3_TX_CLK 117
+#define ECPRI_CC_PHY4_LANE0_RX_CLK 118
+#define ECPRI_CC_PHY4_LANE0_TX_CLK 119
+#define ECPRI_CC_PHY4_LANE1_RX_CLK 120
+#define ECPRI_CC_PHY4_LANE1_TX_CLK 121
+#define ECPRI_CC_PHY4_LANE2_RX_CLK 122
+#define ECPRI_CC_PHY4_LANE2_TX_CLK 123
+#define ECPRI_CC_PHY4_LANE3_RX_CLK 124
+#define ECPRI_CC_PHY4_LANE3_TX_CLK 125
+
+/* ECPRI_CC resets */
+#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ECPRI_SS_BCR 0
+#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_C2C_BCR 1
+#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH0_BCR 2
+#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH1_BCR 3
+#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH2_BCR 4
+#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_WRAPPER_TOP_BCR 5
+#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_MODEM_BCR 6
+#define ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_NOC_BCR 7
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,videocc-sm8150.h b/include/dt-bindings/clock/qcom,videocc-sm8150.h
index e24ee840cfdb..c557b78dc572 100644
--- a/include/dt-bindings/clock/qcom,videocc-sm8150.h
+++ b/include/dt-bindings/clock/qcom,videocc-sm8150.h
@@ -16,6 +16,10 @@
/* VIDEO_CC Resets */
#define VIDEO_CC_MVSC_CORE_CLK_BCR 0
+#define VIDEO_CC_INTERFACE_BCR 1
+#define VIDEO_CC_MVS0_BCR 2
+#define VIDEO_CC_MVS1_BCR 3
+#define VIDEO_CC_MVSC_BCR 4
/* VIDEO_CC GDSCRs */
#define VENUS_GDSC 0
diff --git a/include/dt-bindings/clock/sophgo,cv1800.h b/include/dt-bindings/clock/sophgo,cv1800.h
new file mode 100644
index 000000000000..cfbeca25a650
--- /dev/null
+++ b/include/dt-bindings/clock/sophgo,cv1800.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+/*
+ * Copyright (C) 2023 Sophgo Ltd.
+ */
+
+#ifndef __DT_BINDINGS_SOPHGO_CV1800_CLK_H__
+#define __DT_BINDINGS_SOPHGO_CV1800_CLK_H__
+
+#define CLK_MPLL 0
+#define CLK_TPLL 1
+#define CLK_FPLL 2
+#define CLK_MIPIMPLL 3
+#define CLK_A0PLL 4
+#define CLK_DISPPLL 5
+#define CLK_CAM0PLL 6
+#define CLK_CAM1PLL 7
+
+#define CLK_MIPIMPLL_D3 8
+#define CLK_CAM0PLL_D2 9
+#define CLK_CAM0PLL_D3 10
+
+#define CLK_TPU 11
+#define CLK_TPU_FAB 12
+#define CLK_AHB_ROM 13
+#define CLK_DDR_AXI_REG 14
+#define CLK_RTC_25M 15
+#define CLK_SRC_RTC_SYS_0 16
+#define CLK_TEMPSEN 17
+#define CLK_SARADC 18
+#define CLK_EFUSE 19
+#define CLK_APB_EFUSE 20
+#define CLK_DEBUG 21
+#define CLK_AP_DEBUG 22
+#define CLK_XTAL_MISC 23
+#define CLK_AXI4_EMMC 24
+#define CLK_EMMC 25
+#define CLK_EMMC_100K 26
+#define CLK_AXI4_SD0 27
+#define CLK_SD0 28
+#define CLK_SD0_100K 29
+#define CLK_AXI4_SD1 30
+#define CLK_SD1 31
+#define CLK_SD1_100K 32
+#define CLK_SPI_NAND 33
+#define CLK_ETH0_500M 34
+#define CLK_AXI4_ETH0 35
+#define CLK_ETH1_500M 36
+#define CLK_AXI4_ETH1 37
+#define CLK_APB_GPIO 38
+#define CLK_APB_GPIO_INTR 39
+#define CLK_GPIO_DB 40
+#define CLK_AHB_SF 41
+#define CLK_AHB_SF1 42
+#define CLK_A24M 43
+#define CLK_AUDSRC 44
+#define CLK_APB_AUDSRC 45
+#define CLK_SDMA_AXI 46
+#define CLK_SDMA_AUD0 47
+#define CLK_SDMA_AUD1 48
+#define CLK_SDMA_AUD2 49
+#define CLK_SDMA_AUD3 50
+#define CLK_I2C 51
+#define CLK_APB_I2C 52
+#define CLK_APB_I2C0 53
+#define CLK_APB_I2C1 54
+#define CLK_APB_I2C2 55
+#define CLK_APB_I2C3 56
+#define CLK_APB_I2C4 57
+#define CLK_APB_WDT 58
+#define CLK_PWM_SRC 59
+#define CLK_PWM 60
+#define CLK_SPI 61
+#define CLK_APB_SPI0 62
+#define CLK_APB_SPI1 63
+#define CLK_APB_SPI2 64
+#define CLK_APB_SPI3 65
+#define CLK_1M 66
+#define CLK_CAM0_200 67
+#define CLK_PM 68
+#define CLK_TIMER0 69
+#define CLK_TIMER1 70
+#define CLK_TIMER2 71
+#define CLK_TIMER3 72
+#define CLK_TIMER4 73
+#define CLK_TIMER5 74
+#define CLK_TIMER6 75
+#define CLK_TIMER7 76
+#define CLK_UART0 77
+#define CLK_APB_UART0 78
+#define CLK_UART1 79
+#define CLK_APB_UART1 80
+#define CLK_UART2 81
+#define CLK_APB_UART2 82
+#define CLK_UART3 83
+#define CLK_APB_UART3 84
+#define CLK_UART4 85
+#define CLK_APB_UART4 86
+#define CLK_APB_I2S0 87
+#define CLK_APB_I2S1 88
+#define CLK_APB_I2S2 89
+#define CLK_APB_I2S3 90
+#define CLK_AXI4_USB 91
+#define CLK_APB_USB 92
+#define CLK_USB_125M 93
+#define CLK_USB_33K 94
+#define CLK_USB_12M 95
+#define CLK_AXI4 96
+#define CLK_AXI6 97
+#define CLK_DSI_ESC 98
+#define CLK_AXI_VIP 99
+#define CLK_SRC_VIP_SYS_0 100
+#define CLK_SRC_VIP_SYS_1 101
+#define CLK_SRC_VIP_SYS_2 102
+#define CLK_SRC_VIP_SYS_3 103
+#define CLK_SRC_VIP_SYS_4 104
+#define CLK_CSI_BE_VIP 105
+#define CLK_CSI_MAC0_VIP 106
+#define CLK_CSI_MAC1_VIP 107
+#define CLK_CSI_MAC2_VIP 108
+#define CLK_CSI0_RX_VIP 109
+#define CLK_CSI1_RX_VIP 110
+#define CLK_ISP_TOP_VIP 111
+#define CLK_IMG_D_VIP 112
+#define CLK_IMG_V_VIP 113
+#define CLK_SC_TOP_VIP 114
+#define CLK_SC_D_VIP 115
+#define CLK_SC_V1_VIP 116
+#define CLK_SC_V2_VIP 117
+#define CLK_SC_V3_VIP 118
+#define CLK_DWA_VIP 119
+#define CLK_BT_VIP 120
+#define CLK_DISP_VIP 121
+#define CLK_DSI_MAC_VIP 122
+#define CLK_LVDS0_VIP 123
+#define CLK_LVDS1_VIP 124
+#define CLK_PAD_VI_VIP 125
+#define CLK_PAD_VI1_VIP 126
+#define CLK_PAD_VI2_VIP 127
+#define CLK_CFG_REG_VIP 128
+#define CLK_VIP_IP0 129
+#define CLK_VIP_IP1 130
+#define CLK_VIP_IP2 131
+#define CLK_VIP_IP3 132
+#define CLK_IVE_VIP 133
+#define CLK_RAW_VIP 134
+#define CLK_OSDC_VIP 135
+#define CLK_CAM0_VIP 136
+#define CLK_AXI_VIDEO_CODEC 137
+#define CLK_VC_SRC0 138
+#define CLK_VC_SRC1 139
+#define CLK_VC_SRC2 140
+#define CLK_H264C 141
+#define CLK_APB_H264C 142
+#define CLK_H265C 143
+#define CLK_APB_H265C 144
+#define CLK_JPEG 145
+#define CLK_APB_JPEG 146
+#define CLK_CAM0 147
+#define CLK_CAM1 148
+#define CLK_WGN 149
+#define CLK_WGN0 150
+#define CLK_WGN1 151
+#define CLK_WGN2 152
+#define CLK_KEYSCAN 153
+#define CLK_CFG_REG_VC 154
+#define CLK_C906_0 155
+#define CLK_C906_1 156
+#define CLK_A53 157
+#define CLK_CPU_AXI0 158
+#define CLK_CPU_GIC 159
+#define CLK_XTAL_AP 160
+
+// Only for CV181x
+#define CLK_DISP_SRC_VIP 161
+
+#endif /* __DT_BINDINGS_SOPHGO_CV1800_CLK_H__ */
diff --git a/include/dt-bindings/clock/st,stm32mp25-rcc.h b/include/dt-bindings/clock/st,stm32mp25-rcc.h
new file mode 100644
index 000000000000..b6cf05ad4be6
--- /dev/null
+++ b/include/dt-bindings/clock/st,stm32mp25-rcc.h
@@ -0,0 +1,492 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+/*
+ * Copyright (C) STMicroelectronics 2023 - All Rights Reserved
+ * Author: Gabriel Fernandez <[email protected]>
+ */
+
+#ifndef _DT_BINDINGS_STM32MP25_CLKS_H_
+#define _DT_BINDINGS_STM32MP25_CLKS_H_
+
+/* INTERNAL/EXTERNAL OSCILLATORS */
+#define HSI_CK 0
+#define HSE_CK 1
+#define MSI_CK 2
+#define LSI_CK 3
+#define LSE_CK 4
+#define I2S_CK 5
+#define RTC_CK 6
+#define SPDIF_CK_SYMB 7
+
+/* PLL CLOCKS */
+#define PLL1_CK 8
+#define PLL2_CK 9
+#define PLL3_CK 10
+#define PLL4_CK 11
+#define PLL5_CK 12
+#define PLL6_CK 13
+#define PLL7_CK 14
+#define PLL8_CK 15
+
+#define CK_CPU1 16
+
+/* APB DIV CLOCKS */
+#define CK_ICN_APB1 17
+#define CK_ICN_APB2 18
+#define CK_ICN_APB3 19
+#define CK_ICN_APB4 20
+#define CK_ICN_APBDBG 21
+
+/* GLOBAL TIMER */
+#define TIMG1_CK 22
+#define TIMG2_CK 23
+
+/* FLEXGEN CLOCKS */
+#define CK_ICN_HS_MCU 24
+#define CK_ICN_SDMMC 25
+#define CK_ICN_DDR 26
+#define CK_ICN_DISPLAY 27
+#define CK_ICN_HSL 28
+#define CK_ICN_NIC 29
+#define CK_ICN_VID 30
+#define CK_FLEXGEN_07 31
+#define CK_FLEXGEN_08 32
+#define CK_FLEXGEN_09 33
+#define CK_FLEXGEN_10 34
+#define CK_FLEXGEN_11 35
+#define CK_FLEXGEN_12 36
+#define CK_FLEXGEN_13 37
+#define CK_FLEXGEN_14 38
+#define CK_FLEXGEN_15 39
+#define CK_FLEXGEN_16 40
+#define CK_FLEXGEN_17 41
+#define CK_FLEXGEN_18 42
+#define CK_FLEXGEN_19 43
+#define CK_FLEXGEN_20 44
+#define CK_FLEXGEN_21 45
+#define CK_FLEXGEN_22 46
+#define CK_FLEXGEN_23 47
+#define CK_FLEXGEN_24 48
+#define CK_FLEXGEN_25 49
+#define CK_FLEXGEN_26 50
+#define CK_FLEXGEN_27 51
+#define CK_FLEXGEN_28 52
+#define CK_FLEXGEN_29 53
+#define CK_FLEXGEN_30 54
+#define CK_FLEXGEN_31 55
+#define CK_FLEXGEN_32 56
+#define CK_FLEXGEN_33 57
+#define CK_FLEXGEN_34 58
+#define CK_FLEXGEN_35 59
+#define CK_FLEXGEN_36 60
+#define CK_FLEXGEN_37 61
+#define CK_FLEXGEN_38 62
+#define CK_FLEXGEN_39 63
+#define CK_FLEXGEN_40 64
+#define CK_FLEXGEN_41 65
+#define CK_FLEXGEN_42 66
+#define CK_FLEXGEN_43 67
+#define CK_FLEXGEN_44 68
+#define CK_FLEXGEN_45 69
+#define CK_FLEXGEN_46 70
+#define CK_FLEXGEN_47 71
+#define CK_FLEXGEN_48 72
+#define CK_FLEXGEN_49 73
+#define CK_FLEXGEN_50 74
+#define CK_FLEXGEN_51 75
+#define CK_FLEXGEN_52 76
+#define CK_FLEXGEN_53 77
+#define CK_FLEXGEN_54 78
+#define CK_FLEXGEN_55 79
+#define CK_FLEXGEN_56 80
+#define CK_FLEXGEN_57 81
+#define CK_FLEXGEN_58 82
+#define CK_FLEXGEN_59 83
+#define CK_FLEXGEN_60 84
+#define CK_FLEXGEN_61 85
+#define CK_FLEXGEN_62 86
+#define CK_FLEXGEN_63 87
+
+/* LOW SPEED MCU CLOCK */
+#define CK_ICN_LS_MCU 88
+
+#define CK_BUS_STM500 89
+#define CK_BUS_FMC 90
+#define CK_BUS_GPU 91
+#define CK_BUS_ETH1 92
+#define CK_BUS_ETH2 93
+#define CK_BUS_PCIE 94
+#define CK_BUS_DDRPHYC 95
+#define CK_BUS_SYSCPU1 96
+#define CK_BUS_ETHSW 97
+#define CK_BUS_HPDMA1 98
+#define CK_BUS_HPDMA2 99
+#define CK_BUS_HPDMA3 100
+#define CK_BUS_ADC12 101
+#define CK_BUS_ADC3 102
+#define CK_BUS_IPCC1 103
+#define CK_BUS_CCI 104
+#define CK_BUS_CRC 105
+#define CK_BUS_MDF1 106
+#define CK_BUS_OSPIIOM 107
+#define CK_BUS_BKPSRAM 108
+#define CK_BUS_HASH 109
+#define CK_BUS_RNG 110
+#define CK_BUS_CRYP1 111
+#define CK_BUS_CRYP2 112
+#define CK_BUS_SAES 113
+#define CK_BUS_PKA 114
+#define CK_BUS_GPIOA 115
+#define CK_BUS_GPIOB 116
+#define CK_BUS_GPIOC 117
+#define CK_BUS_GPIOD 118
+#define CK_BUS_GPIOE 119
+#define CK_BUS_GPIOF 120
+#define CK_BUS_GPIOG 121
+#define CK_BUS_GPIOH 122
+#define CK_BUS_GPIOI 123
+#define CK_BUS_GPIOJ 124
+#define CK_BUS_GPIOK 125
+#define CK_BUS_LPSRAM1 126
+#define CK_BUS_LPSRAM2 127
+#define CK_BUS_LPSRAM3 128
+#define CK_BUS_GPIOZ 129
+#define CK_BUS_LPDMA 130
+#define CK_BUS_HSEM 131
+#define CK_BUS_IPCC2 132
+#define CK_BUS_RTC 133
+#define CK_BUS_SPI8 134
+#define CK_BUS_LPUART1 135
+#define CK_BUS_I2C8 136
+#define CK_BUS_LPTIM3 137
+#define CK_BUS_LPTIM4 138
+#define CK_BUS_LPTIM5 139
+#define CK_BUS_IWDG5 140
+#define CK_BUS_WWDG2 141
+#define CK_BUS_I3C4 142
+#define CK_BUS_TIM2 143
+#define CK_BUS_TIM3 144
+#define CK_BUS_TIM4 145
+#define CK_BUS_TIM5 146
+#define CK_BUS_TIM6 147
+#define CK_BUS_TIM7 148
+#define CK_BUS_TIM10 149
+#define CK_BUS_TIM11 150
+#define CK_BUS_TIM12 151
+#define CK_BUS_TIM13 152
+#define CK_BUS_TIM14 153
+#define CK_BUS_LPTIM1 154
+#define CK_BUS_LPTIM2 155
+#define CK_BUS_SPI2 156
+#define CK_BUS_SPI3 157
+#define CK_BUS_SPDIFRX 158
+#define CK_BUS_USART2 159
+#define CK_BUS_USART3 160
+#define CK_BUS_UART4 161
+#define CK_BUS_UART5 162
+#define CK_BUS_I2C1 163
+#define CK_BUS_I2C2 164
+#define CK_BUS_I2C3 165
+#define CK_BUS_I2C4 166
+#define CK_BUS_I2C5 167
+#define CK_BUS_I2C6 168
+#define CK_BUS_I2C7 169
+#define CK_BUS_I3C1 170
+#define CK_BUS_I3C2 171
+#define CK_BUS_I3C3 172
+#define CK_BUS_TIM1 173
+#define CK_BUS_TIM8 174
+#define CK_BUS_TIM15 175
+#define CK_BUS_TIM16 176
+#define CK_BUS_TIM17 177
+#define CK_BUS_TIM20 178
+#define CK_BUS_SAI1 179
+#define CK_BUS_SAI2 180
+#define CK_BUS_SAI3 181
+#define CK_BUS_SAI4 182
+#define CK_BUS_USART1 183
+#define CK_BUS_USART6 184
+#define CK_BUS_UART7 185
+#define CK_BUS_UART8 186
+#define CK_BUS_UART9 187
+#define CK_BUS_FDCAN 188
+#define CK_BUS_SPI1 189
+#define CK_BUS_SPI4 190
+#define CK_BUS_SPI5 191
+#define CK_BUS_SPI6 192
+#define CK_BUS_SPI7 193
+#define CK_BUS_BSEC 194
+#define CK_BUS_IWDG1 195
+#define CK_BUS_IWDG2 196
+#define CK_BUS_IWDG3 197
+#define CK_BUS_IWDG4 198
+#define CK_BUS_WWDG1 199
+#define CK_BUS_VREF 200
+#define CK_BUS_DTS 201
+#define CK_BUS_SERC 202
+#define CK_BUS_HDP 203
+#define CK_BUS_IS2M 204
+#define CK_BUS_DSI 205
+#define CK_BUS_LTDC 206
+#define CK_BUS_CSI 207
+#define CK_BUS_DCMIPP 208
+#define CK_BUS_DDRC 209
+#define CK_BUS_DDRCFG 210
+#define CK_BUS_GICV2M 211
+#define CK_BUS_USBTC 212
+#define CK_BUS_USB3PCIEPHY 214
+#define CK_BUS_STGEN 215
+#define CK_BUS_VDEC 216
+#define CK_BUS_VENC 217
+#define CK_SYSDBG 218
+#define CK_KER_TIM2 219
+#define CK_KER_TIM3 220
+#define CK_KER_TIM4 221
+#define CK_KER_TIM5 222
+#define CK_KER_TIM6 223
+#define CK_KER_TIM7 224
+#define CK_KER_TIM10 225
+#define CK_KER_TIM11 226
+#define CK_KER_TIM12 227
+#define CK_KER_TIM13 228
+#define CK_KER_TIM14 229
+#define CK_KER_TIM1 230
+#define CK_KER_TIM8 231
+#define CK_KER_TIM15 232
+#define CK_KER_TIM16 233
+#define CK_KER_TIM17 234
+#define CK_KER_TIM20 235
+#define CK_BUS_SYSRAM 236
+#define CK_BUS_VDERAM 237
+#define CK_BUS_RETRAM 238
+#define CK_BUS_OSPI1 239
+#define CK_BUS_OSPI2 240
+#define CK_BUS_OTFD1 241
+#define CK_BUS_OTFD2 242
+#define CK_BUS_SRAM1 243
+#define CK_BUS_SRAM2 244
+#define CK_BUS_SDMMC1 245
+#define CK_BUS_SDMMC2 246
+#define CK_BUS_SDMMC3 247
+#define CK_BUS_DDR 248
+#define CK_BUS_RISAF4 249
+#define CK_BUS_USB2OHCI 250
+#define CK_BUS_USB2EHCI 251
+#define CK_BUS_USB3DR 252
+#define CK_KER_LPTIM1 253
+#define CK_KER_LPTIM2 254
+#define CK_KER_USART2 255
+#define CK_KER_UART4 256
+#define CK_KER_USART3 257
+#define CK_KER_UART5 258
+#define CK_KER_SPI2 259
+#define CK_KER_SPI3 260
+#define CK_KER_SPDIFRX 261
+#define CK_KER_I2C1 262
+#define CK_KER_I2C2 263
+#define CK_KER_I3C1 264
+#define CK_KER_I3C2 265
+#define CK_KER_I2C3 266
+#define CK_KER_I2C5 267
+#define CK_KER_I3C3 268
+#define CK_KER_I2C4 269
+#define CK_KER_I2C6 270
+#define CK_KER_I2C7 271
+#define CK_KER_SPI1 272
+#define CK_KER_SPI4 273
+#define CK_KER_SPI5 274
+#define CK_KER_SPI6 275
+#define CK_KER_SPI7 276
+#define CK_KER_USART1 277
+#define CK_KER_USART6 278
+#define CK_KER_UART7 279
+#define CK_KER_UART8 280
+#define CK_KER_UART9 281
+#define CK_KER_MDF1 282
+#define CK_KER_SAI1 283
+#define CK_KER_SAI2 284
+#define CK_KER_SAI3 285
+#define CK_KER_SAI4 286
+#define CK_KER_FDCAN 287
+#define CK_KER_DSIBLANE 288
+#define CK_KER_DSIPHY 289
+#define CK_KER_CSI 290
+#define CK_KER_CSITXESC 291
+#define CK_KER_CSIPHY 292
+#define CK_KER_LVDSPHY 293
+#define CK_KER_STGEN 294
+#define CK_KER_USB3PCIEPHY 295
+#define CK_KER_USB2PHY2EN 296
+#define CK_KER_I3C4 297
+#define CK_KER_SPI8 298
+#define CK_KER_I2C8 299
+#define CK_KER_LPUART1 300
+#define CK_KER_LPTIM3 301
+#define CK_KER_LPTIM4 302
+#define CK_KER_LPTIM5 303
+#define CK_KER_TSDBG 304
+#define CK_KER_TPIU 305
+#define CK_BUS_ETR 306
+#define CK_BUS_SYSATB 307
+#define CK_KER_ADC12 308
+#define CK_KER_ADC3 309
+#define CK_KER_OSPI1 310
+#define CK_KER_OSPI2 311
+#define CK_KER_FMC 312
+#define CK_KER_SDMMC1 313
+#define CK_KER_SDMMC2 314
+#define CK_KER_SDMMC3 315
+#define CK_KER_ETH1 316
+#define CK_KER_ETH2 317
+#define CK_KER_ETH1PTP 318
+#define CK_KER_ETH2PTP 319
+#define CK_KER_USB2PHY1 320
+#define CK_KER_USB2PHY2 321
+#define CK_KER_ETHSW 322
+#define CK_KER_ETHSWREF 323
+#define CK_MCO1 324
+#define CK_MCO2 325
+#define CK_KER_DTS 326
+#define CK_ETH1_RX 327
+#define CK_ETH1_TX 328
+#define CK_ETH1_MAC 329
+#define CK_ETH2_RX 330
+#define CK_ETH2_TX 331
+#define CK_ETH2_MAC 332
+#define CK_ETH1_STP 333
+#define CK_ETH2_STP 334
+#define CK_KER_USBTC 335
+#define CK_BUS_ADF1 336
+#define CK_KER_ADF1 337
+#define CK_BUS_LVDS 338
+#define CK_KER_LTDC 339
+#define CK_KER_GPU 340
+#define CK_BUS_ETHSWACMCFG 341
+#define CK_BUS_ETHSWACMMSG 342
+#define HSE_DIV2_CK 343
+
+#define STM32MP25_LAST_CLK 344
+
+#define CK_SCMI_ICN_HS_MCU 0
+#define CK_SCMI_ICN_SDMMC 1
+#define CK_SCMI_ICN_DDR 2
+#define CK_SCMI_ICN_DISPLAY 3
+#define CK_SCMI_ICN_HSL 4
+#define CK_SCMI_ICN_NIC 5
+#define CK_SCMI_ICN_VID 6
+#define CK_SCMI_FLEXGEN_07 7
+#define CK_SCMI_FLEXGEN_08 8
+#define CK_SCMI_FLEXGEN_09 9
+#define CK_SCMI_FLEXGEN_10 10
+#define CK_SCMI_FLEXGEN_11 11
+#define CK_SCMI_FLEXGEN_12 12
+#define CK_SCMI_FLEXGEN_13 13
+#define CK_SCMI_FLEXGEN_14 14
+#define CK_SCMI_FLEXGEN_15 15
+#define CK_SCMI_FLEXGEN_16 16
+#define CK_SCMI_FLEXGEN_17 17
+#define CK_SCMI_FLEXGEN_18 18
+#define CK_SCMI_FLEXGEN_19 19
+#define CK_SCMI_FLEXGEN_20 20
+#define CK_SCMI_FLEXGEN_21 21
+#define CK_SCMI_FLEXGEN_22 22
+#define CK_SCMI_FLEXGEN_23 23
+#define CK_SCMI_FLEXGEN_24 24
+#define CK_SCMI_FLEXGEN_25 25
+#define CK_SCMI_FLEXGEN_26 26
+#define CK_SCMI_FLEXGEN_27 27
+#define CK_SCMI_FLEXGEN_28 28
+#define CK_SCMI_FLEXGEN_29 29
+#define CK_SCMI_FLEXGEN_30 30
+#define CK_SCMI_FLEXGEN_31 31
+#define CK_SCMI_FLEXGEN_32 32
+#define CK_SCMI_FLEXGEN_33 33
+#define CK_SCMI_FLEXGEN_34 34
+#define CK_SCMI_FLEXGEN_35 35
+#define CK_SCMI_FLEXGEN_36 36
+#define CK_SCMI_FLEXGEN_37 37
+#define CK_SCMI_FLEXGEN_38 38
+#define CK_SCMI_FLEXGEN_39 39
+#define CK_SCMI_FLEXGEN_40 40
+#define CK_SCMI_FLEXGEN_41 41
+#define CK_SCMI_FLEXGEN_42 42
+#define CK_SCMI_FLEXGEN_43 43
+#define CK_SCMI_FLEXGEN_44 44
+#define CK_SCMI_FLEXGEN_45 45
+#define CK_SCMI_FLEXGEN_46 46
+#define CK_SCMI_FLEXGEN_47 47
+#define CK_SCMI_FLEXGEN_48 48
+#define CK_SCMI_FLEXGEN_49 49
+#define CK_SCMI_FLEXGEN_50 50
+#define CK_SCMI_FLEXGEN_51 51
+#define CK_SCMI_FLEXGEN_52 52
+#define CK_SCMI_FLEXGEN_53 53
+#define CK_SCMI_FLEXGEN_54 54
+#define CK_SCMI_FLEXGEN_55 55
+#define CK_SCMI_FLEXGEN_56 56
+#define CK_SCMI_FLEXGEN_57 57
+#define CK_SCMI_FLEXGEN_58 58
+#define CK_SCMI_FLEXGEN_59 59
+#define CK_SCMI_FLEXGEN_60 60
+#define CK_SCMI_FLEXGEN_61 61
+#define CK_SCMI_FLEXGEN_62 62
+#define CK_SCMI_FLEXGEN_63 63
+#define CK_SCMI_ICN_LS_MCU 64
+#define CK_SCMI_HSE 65
+#define CK_SCMI_LSE 66
+#define CK_SCMI_HSI 67
+#define CK_SCMI_LSI 68
+#define CK_SCMI_MSI 69
+#define CK_SCMI_HSE_DIV2 70
+#define CK_SCMI_CPU1 71
+#define CK_SCMI_SYSCPU1 72
+#define CK_SCMI_PLL2 73
+#define CK_SCMI_PLL3 74
+#define CK_SCMI_RTC 75
+#define CK_SCMI_RTCCK 76
+#define CK_SCMI_ICN_APB1 77
+#define CK_SCMI_ICN_APB2 78
+#define CK_SCMI_ICN_APB3 79
+#define CK_SCMI_ICN_APB4 80
+#define CK_SCMI_ICN_APBDBG 81
+#define CK_SCMI_TIMG1 82
+#define CK_SCMI_TIMG2 83
+#define CK_SCMI_BKPSRAM 84
+#define CK_SCMI_BSEC 85
+#define CK_SCMI_ETR 87
+#define CK_SCMI_FMC 88
+#define CK_SCMI_GPIOA 89
+#define CK_SCMI_GPIOB 90
+#define CK_SCMI_GPIOC 91
+#define CK_SCMI_GPIOD 92
+#define CK_SCMI_GPIOE 93
+#define CK_SCMI_GPIOF 94
+#define CK_SCMI_GPIOG 95
+#define CK_SCMI_GPIOH 96
+#define CK_SCMI_GPIOI 97
+#define CK_SCMI_GPIOJ 98
+#define CK_SCMI_GPIOK 99
+#define CK_SCMI_GPIOZ 100
+#define CK_SCMI_HPDMA1 101
+#define CK_SCMI_HPDMA2 102
+#define CK_SCMI_HPDMA3 103
+#define CK_SCMI_HSEM 104
+#define CK_SCMI_IPCC1 105
+#define CK_SCMI_IPCC2 106
+#define CK_SCMI_LPDMA 107
+#define CK_SCMI_RETRAM 108
+#define CK_SCMI_SRAM1 109
+#define CK_SCMI_SRAM2 110
+#define CK_SCMI_LPSRAM1 111
+#define CK_SCMI_LPSRAM2 112
+#define CK_SCMI_LPSRAM3 113
+#define CK_SCMI_VDERAM 114
+#define CK_SCMI_SYSRAM 115
+#define CK_SCMI_OSPI1 116
+#define CK_SCMI_OSPI2 117
+#define CK_SCMI_TPIU 118
+#define CK_SCMI_SYSDBG 119
+#define CK_SCMI_SYSATB 120
+#define CK_SCMI_TSDBG 121
+#define CK_SCMI_STM500 122
+
+#endif /* _DT_BINDINGS_STM32MP25_CLKS_H_ */
diff --git a/include/dt-bindings/power/meson-g12a-power.h b/include/dt-bindings/power/meson-g12a-power.h
index 44ec0c50e340..01fd0ac4dd08 100644
--- a/include/dt-bindings/power/meson-g12a-power.h
+++ b/include/dt-bindings/power/meson-g12a-power.h
@@ -10,5 +10,6 @@
#define PWRC_G12A_VPU_ID 0
#define PWRC_G12A_ETH_ID 1
#define PWRC_G12A_NNA_ID 2
+#define PWRC_G12A_ISP_ID 3
#endif
diff --git a/include/dt-bindings/reset/mediatek,mt7988-resets.h b/include/dt-bindings/reset/mediatek,mt7988-resets.h
new file mode 100644
index 000000000000..493301971367
--- /dev/null
+++ b/include/dt-bindings/reset/mediatek,mt7988-resets.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) 2023 Daniel Golle <[email protected]>
+ * Author: Daniel Golle <[email protected]>
+ */
+
+#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT7988
+#define _DT_BINDINGS_RESET_CONTROLLER_MT7988
+
+/* ETHWARP resets */
+#define MT7988_ETHWARP_RST_SWITCH 0
+
+#endif /* _DT_BINDINGS_RESET_CONTROLLER_MT7988 */
diff --git a/include/dt-bindings/reset/st,stm32mp25-rcc.h b/include/dt-bindings/reset/st,stm32mp25-rcc.h
new file mode 100644
index 000000000000..d5615930bcc8
--- /dev/null
+++ b/include/dt-bindings/reset/st,stm32mp25-rcc.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+/*
+ * Copyright (C) STMicroelectronics 2023 - All Rights Reserved
+ * Author(s): Gabriel Fernandez <[email protected]>
+ */
+
+#ifndef _DT_BINDINGS_STM32MP25_RESET_H_
+#define _DT_BINDINGS_STM32MP25_RESET_H_
+
+#define TIM1_R 0
+#define TIM2_R 1
+#define TIM3_R 2
+#define TIM4_R 3
+#define TIM5_R 4
+#define TIM6_R 5
+#define TIM7_R 6
+#define TIM8_R 7
+#define TIM10_R 8
+#define TIM11_R 9
+#define TIM12_R 10
+#define TIM13_R 11
+#define TIM14_R 12
+#define TIM15_R 13
+#define TIM16_R 14
+#define TIM17_R 15
+#define TIM20_R 16
+#define LPTIM1_R 17
+#define LPTIM2_R 18
+#define LPTIM3_R 19
+#define LPTIM4_R 20
+#define LPTIM5_R 21
+#define SPI1_R 22
+#define SPI2_R 23
+#define SPI3_R 24
+#define SPI4_R 25
+#define SPI5_R 26
+#define SPI6_R 27
+#define SPI7_R 28
+#define SPI8_R 29
+#define SPDIFRX_R 30
+#define USART1_R 31
+#define USART2_R 32
+#define USART3_R 33
+#define UART4_R 34
+#define UART5_R 35
+#define USART6_R 36
+#define UART7_R 37
+#define UART8_R 38
+#define UART9_R 39
+#define LPUART1_R 40
+#define IS2M_R 41
+#define I2C1_R 42
+#define I2C2_R 43
+#define I2C3_R 44
+#define I2C4_R 45
+#define I2C5_R 46
+#define I2C6_R 47
+#define I2C7_R 48
+#define I2C8_R 49
+#define SAI1_R 50
+#define SAI2_R 51
+#define SAI3_R 52
+#define SAI4_R 53
+#define MDF1_R 54
+#define MDF2_R 55
+#define FDCAN_R 56
+#define HDP_R 57
+#define ADC12_R 58
+#define ADC3_R 59
+#define ETH1_R 60
+#define ETH2_R 61
+#define USB2_R 62
+#define USB2PHY1_R 63
+#define USB2PHY2_R 64
+#define USB3DR_R 65
+#define USB3PCIEPHY_R 66
+#define USBTC_R 67
+#define ETHSW_R 68
+#define SDMMC1_R 69
+#define SDMMC1DLL_R 70
+#define SDMMC2_R 71
+#define SDMMC2DLL_R 72
+#define SDMMC3_R 73
+#define SDMMC3DLL_R 74
+#define GPU_R 75
+#define LTDC_R 76
+#define DSI_R 77
+#define LVDS_R 78
+#define CSI_R 79
+#define DCMIPP_R 80
+#define CCI_R 81
+#define VDEC_R 82
+#define VENC_R 83
+#define WWDG1_R 84
+#define WWDG2_R 85
+#define VREF_R 86
+#define DTS_R 87
+#define CRC_R 88
+#define SERC_R 89
+#define OSPIIOM_R 90
+#define I3C1_R 91
+#define I3C2_R 92
+#define I3C3_R 93
+#define I3C4_R 94
+#define IWDG2_KER_R 95
+#define IWDG4_KER_R 96
+#define RNG_R 97
+#define PKA_R 98
+#define SAES_R 99
+#define HASH_R 100
+#define CRYP1_R 101
+#define CRYP2_R 102
+#define PCIE_R 103
+#define OSPI1_R 104
+#define OSPI1DLL_R 105
+#define OSPI2_R 106
+#define OSPI2DLL_R 107
+#define FMC_R 108
+#define DBG_R 109
+#define GPIOA_R 110
+#define GPIOB_R 111
+#define GPIOC_R 112
+#define GPIOD_R 113
+#define GPIOE_R 114
+#define GPIOF_R 115
+#define GPIOG_R 116
+#define GPIOH_R 117
+#define GPIOI_R 118
+#define GPIOJ_R 119
+#define GPIOK_R 120
+#define GPIOZ_R 121
+#define HPDMA1_R 122
+#define HPDMA2_R 123
+#define HPDMA3_R 124
+#define LPDMA_R 125
+#define HSEM_R 126
+#define IPCC1_R 127
+#define IPCC2_R 128
+#define C2_HOLDBOOT_R 129
+#define C1_HOLDBOOT_R 130
+#define C1_R 131
+#define C1P1POR_R 132
+#define C1P1_R 133
+#define C2_R 134
+#define C3_R 135
+#define SYS_R 136
+#define VSW_R 137
+#define C1MS_R 138
+#define DDRCP_R 139
+#define DDRCAPB_R 140
+#define DDRPHYCAPB_R 141
+#define DDRCFG_R 142
+#define DDR_R 143
+
+#define STM32MP25_LAST_RESET 144
+
+#define RST_SCMI_C1_R 0
+#define RST_SCMI_C2_R 1
+#define RST_SCMI_C1_HOLDBOOT_R 2
+#define RST_SCMI_C2_HOLDBOOT_R 3
+#define RST_SCMI_FMC 4
+#define RST_SCMI_OSPI1 5
+#define RST_SCMI_OSPI1DLL 6
+#define RST_SCMI_OSPI2 7
+#define RST_SCMI_OSPI2DLL 8
+
+#endif /* _DT_BINDINGS_STM32MP25_RESET_H_ */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 118a18b7ff84..b7165e52b3c6 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -15,6 +15,7 @@
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/uuid.h>
+#include <linux/node.h>
struct irq_domain;
struct irq_domain_ops;
@@ -431,6 +432,16 @@ int thermal_acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp);
int thermal_acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp);
#endif
+#ifdef CONFIG_ACPI_HMAT
+int acpi_get_genport_coordinates(u32 uid, struct access_coordinate *coord);
+#else
+static inline int acpi_get_genport_coordinates(u32 uid,
+ struct access_coordinate *coord)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
#ifdef CONFIG_ACPI_NUMA
int acpi_map_pxm_to_node(int pxm);
int acpi_get_node(acpi_handle handle);
diff --git a/include/linux/aer.h b/include/linux/aer.h
index f6ea2f57d808..ae0fae70d4bd 100644
--- a/include/linux/aer.h
+++ b/include/linux/aer.h
@@ -19,10 +19,10 @@
struct pci_dev;
struct aer_header_log_regs {
- unsigned int dw0;
- unsigned int dw1;
- unsigned int dw2;
- unsigned int dw3;
+ u32 dw0;
+ u32 dw1;
+ u32 dw2;
+ u32 dw3;
};
struct aer_capability_regs {
diff --git a/include/linux/amba/clcd-regs.h b/include/linux/amba/clcd-regs.h
deleted file mode 100644
index 421b0fa90d6a..000000000000
--- a/include/linux/amba/clcd-regs.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * David A Rusling
- *
- * Copyright (C) 2001 ARM Limited
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#ifndef AMBA_CLCD_REGS_H
-#define AMBA_CLCD_REGS_H
-
-/*
- * CLCD Controller Internal Register addresses
- */
-#define CLCD_TIM0 0x00000000
-#define CLCD_TIM1 0x00000004
-#define CLCD_TIM2 0x00000008
-#define CLCD_TIM3 0x0000000c
-#define CLCD_UBAS 0x00000010
-#define CLCD_LBAS 0x00000014
-
-#define CLCD_PL110_IENB 0x00000018
-#define CLCD_PL110_CNTL 0x0000001c
-#define CLCD_PL110_STAT 0x00000020
-#define CLCD_PL110_INTR 0x00000024
-#define CLCD_PL110_UCUR 0x00000028
-#define CLCD_PL110_LCUR 0x0000002C
-
-#define CLCD_PL111_CNTL 0x00000018
-#define CLCD_PL111_IENB 0x0000001c
-#define CLCD_PL111_RIS 0x00000020
-#define CLCD_PL111_MIS 0x00000024
-#define CLCD_PL111_ICR 0x00000028
-#define CLCD_PL111_UCUR 0x0000002c
-#define CLCD_PL111_LCUR 0x00000030
-
-#define CLCD_PALL 0x00000200
-#define CLCD_PALETTE 0x00000200
-
-#define TIM2_PCD_LO_MASK GENMASK(4, 0)
-#define TIM2_PCD_LO_BITS 5
-#define TIM2_CLKSEL (1 << 5)
-#define TIM2_ACB_MASK GENMASK(10, 6)
-#define TIM2_IVS (1 << 11)
-#define TIM2_IHS (1 << 12)
-#define TIM2_IPC (1 << 13)
-#define TIM2_IOE (1 << 14)
-#define TIM2_BCD (1 << 26)
-#define TIM2_PCD_HI_MASK GENMASK(31, 27)
-#define TIM2_PCD_HI_BITS 5
-#define TIM2_PCD_HI_SHIFT 27
-
-#define CNTL_LCDEN (1 << 0)
-#define CNTL_LCDBPP1 (0 << 1)
-#define CNTL_LCDBPP2 (1 << 1)
-#define CNTL_LCDBPP4 (2 << 1)
-#define CNTL_LCDBPP8 (3 << 1)
-#define CNTL_LCDBPP16 (4 << 1)
-#define CNTL_LCDBPP16_565 (6 << 1)
-#define CNTL_LCDBPP16_444 (7 << 1)
-#define CNTL_LCDBPP24 (5 << 1)
-#define CNTL_LCDBW (1 << 4)
-#define CNTL_LCDTFT (1 << 5)
-#define CNTL_LCDMONO8 (1 << 6)
-#define CNTL_LCDDUAL (1 << 7)
-#define CNTL_BGR (1 << 8)
-#define CNTL_BEBO (1 << 9)
-#define CNTL_BEPO (1 << 10)
-#define CNTL_LCDPWR (1 << 11)
-#define CNTL_LCDVCOMP(x) ((x) << 12)
-#define CNTL_LDMAFIFOTIME (1 << 15)
-#define CNTL_WATERMARK (1 << 16)
-
-/* ST Microelectronics variant bits */
-#define CNTL_ST_1XBPP_444 0x0
-#define CNTL_ST_1XBPP_5551 (1 << 17)
-#define CNTL_ST_1XBPP_565 (1 << 18)
-#define CNTL_ST_CDWID_12 0x0
-#define CNTL_ST_CDWID_16 (1 << 19)
-#define CNTL_ST_CDWID_18 (1 << 20)
-#define CNTL_ST_CDWID_24 ((1 << 19)|(1 << 20))
-#define CNTL_ST_CEAEN (1 << 21)
-#define CNTL_ST_LCDBPP24_PACKED (6 << 1)
-
-#endif /* AMBA_CLCD_REGS_H */
diff --git a/include/linux/amba/clcd.h b/include/linux/amba/clcd.h
deleted file mode 100644
index b6e0cbeaf533..000000000000
--- a/include/linux/amba/clcd.h
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * linux/include/asm-arm/hardware/amba_clcd.h -- Integrator LCD panel.
- *
- * David A Rusling
- *
- * Copyright (C) 2001 ARM Limited
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-#include <linux/fb.h>
-#include <linux/amba/clcd-regs.h>
-
-enum {
- /* individual formats */
- CLCD_CAP_RGB444 = (1 << 0),
- CLCD_CAP_RGB5551 = (1 << 1),
- CLCD_CAP_RGB565 = (1 << 2),
- CLCD_CAP_RGB888 = (1 << 3),
- CLCD_CAP_BGR444 = (1 << 4),
- CLCD_CAP_BGR5551 = (1 << 5),
- CLCD_CAP_BGR565 = (1 << 6),
- CLCD_CAP_BGR888 = (1 << 7),
-
- /* connection layouts */
- CLCD_CAP_444 = CLCD_CAP_RGB444 | CLCD_CAP_BGR444,
- CLCD_CAP_5551 = CLCD_CAP_RGB5551 | CLCD_CAP_BGR5551,
- CLCD_CAP_565 = CLCD_CAP_RGB565 | CLCD_CAP_BGR565,
- CLCD_CAP_888 = CLCD_CAP_RGB888 | CLCD_CAP_BGR888,
-
- /* red/blue ordering */
- CLCD_CAP_RGB = CLCD_CAP_RGB444 | CLCD_CAP_RGB5551 |
- CLCD_CAP_RGB565 | CLCD_CAP_RGB888,
- CLCD_CAP_BGR = CLCD_CAP_BGR444 | CLCD_CAP_BGR5551 |
- CLCD_CAP_BGR565 | CLCD_CAP_BGR888,
-
- CLCD_CAP_ALL = CLCD_CAP_BGR | CLCD_CAP_RGB,
-};
-
-struct backlight_device;
-
-struct clcd_panel {
- struct fb_videomode mode;
- signed short width; /* width in mm */
- signed short height; /* height in mm */
- u32 tim2;
- u32 tim3;
- u32 cntl;
- u32 caps;
- unsigned int bpp:8,
- fixedtimings:1,
- grayscale:1;
- unsigned int connector;
- struct backlight_device *backlight;
- /*
- * If the B/R lines are switched between the CLCD
- * and the panel we need to know this and not try to
- * compensate with the BGR bit in the control register.
- */
- bool bgr_connection;
-};
-
-struct clcd_regs {
- u32 tim0;
- u32 tim1;
- u32 tim2;
- u32 tim3;
- u32 cntl;
- unsigned long pixclock;
-};
-
-struct clcd_fb;
-
-/*
- * the board-type specific routines
- */
-struct clcd_board {
- const char *name;
-
- /*
- * Optional. Hardware capability flags.
- */
- u32 caps;
-
- /*
- * Optional. Check whether the var structure is acceptable
- * for this display.
- */
- int (*check)(struct clcd_fb *fb, struct fb_var_screeninfo *var);
-
- /*
- * Compulsory. Decode fb->fb.var into regs->*. In the case of
- * fixed timing, set regs->* to the register values required.
- */
- void (*decode)(struct clcd_fb *fb, struct clcd_regs *regs);
-
- /*
- * Optional. Disable any extra display hardware.
- */
- void (*disable)(struct clcd_fb *);
-
- /*
- * Optional. Enable any extra display hardware.
- */
- void (*enable)(struct clcd_fb *);
-
- /*
- * Setup platform specific parts of CLCD driver
- */
- int (*setup)(struct clcd_fb *);
-
- /*
- * mmap the framebuffer memory
- */
- int (*mmap)(struct clcd_fb *, struct vm_area_struct *);
-
- /*
- * Remove platform specific parts of CLCD driver
- */
- void (*remove)(struct clcd_fb *);
-};
-
-struct amba_device;
-struct clk;
-
-/* this data structure describes each frame buffer device we find */
-struct clcd_fb {
- struct fb_info fb;
- struct amba_device *dev;
- struct clk *clk;
- struct clcd_panel *panel;
- struct clcd_board *board;
- void *board_data;
- void __iomem *regs;
- u16 off_ienb;
- u16 off_cntl;
- u32 clcd_cntl;
- u32 cmap[16];
- bool clk_enabled;
-};
-
-static inline void clcdfb_decode(struct clcd_fb *fb, struct clcd_regs *regs)
-{
- struct fb_var_screeninfo *var = &fb->fb.var;
- u32 val, cpl;
-
- /*
- * Program the CLCD controller registers and start the CLCD
- */
- val = ((var->xres / 16) - 1) << 2;
- val |= (var->hsync_len - 1) << 8;
- val |= (var->right_margin - 1) << 16;
- val |= (var->left_margin - 1) << 24;
- regs->tim0 = val;
-
- val = var->yres;
- if (fb->panel->cntl & CNTL_LCDDUAL)
- val /= 2;
- val -= 1;
- val |= (var->vsync_len - 1) << 10;
- val |= var->lower_margin << 16;
- val |= var->upper_margin << 24;
- regs->tim1 = val;
-
- val = fb->panel->tim2;
- val |= var->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : TIM2_IHS;
- val |= var->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : TIM2_IVS;
-
- cpl = var->xres_virtual;
- if (fb->panel->cntl & CNTL_LCDTFT) /* TFT */
- /* / 1 */;
- else if (!var->grayscale) /* STN color */
- cpl = cpl * 8 / 3;
- else if (fb->panel->cntl & CNTL_LCDMONO8) /* STN monochrome, 8bit */
- cpl /= 8;
- else /* STN monochrome, 4bit */
- cpl /= 4;
-
- regs->tim2 = val | ((cpl - 1) << 16);
-
- regs->tim3 = fb->panel->tim3;
-
- val = fb->panel->cntl;
- if (var->grayscale)
- val |= CNTL_LCDBW;
-
- if (fb->panel->caps && fb->board->caps && var->bits_per_pixel >= 16) {
- /*
- * if board and panel supply capabilities, we can support
- * changing BGR/RGB depending on supplied parameters. Here
- * we switch to what the framebuffer is providing if need
- * be, so if the framebuffer is BGR but the display connection
- * is RGB (first case) we switch it around. Vice versa mutatis
- * mutandis if the framebuffer is RGB but the display connection
- * is BGR, we flip it around.
- */
- if (var->red.offset == 0)
- val &= ~CNTL_BGR;
- else
- val |= CNTL_BGR;
- if (fb->panel->bgr_connection)
- val ^= CNTL_BGR;
- }
-
- switch (var->bits_per_pixel) {
- case 1:
- val |= CNTL_LCDBPP1;
- break;
- case 2:
- val |= CNTL_LCDBPP2;
- break;
- case 4:
- val |= CNTL_LCDBPP4;
- break;
- case 8:
- val |= CNTL_LCDBPP8;
- break;
- case 16:
- /*
- * PL110 cannot choose between 5551 and 565 modes in its
- * control register. It is possible to use 565 with
- * custom external wiring.
- */
- if (amba_part(fb->dev) == 0x110 ||
- var->green.length == 5)
- val |= CNTL_LCDBPP16;
- else if (var->green.length == 6)
- val |= CNTL_LCDBPP16_565;
- else
- val |= CNTL_LCDBPP16_444;
- break;
- case 32:
- val |= CNTL_LCDBPP24;
- break;
- }
-
- regs->cntl = val;
- regs->pixclock = var->pixclock;
-}
-
-static inline int clcdfb_check(struct clcd_fb *fb, struct fb_var_screeninfo *var)
-{
- var->xres_virtual = var->xres = (var->xres + 15) & ~15;
- var->yres_virtual = var->yres = (var->yres + 1) & ~1;
-
-#define CHECK(e,l,h) (var->e < l || var->e > h)
- if (CHECK(right_margin, (5+1), 256) || /* back porch */
- CHECK(left_margin, (5+1), 256) || /* front porch */
- CHECK(hsync_len, (5+1), 256) ||
- var->xres > 4096 ||
- var->lower_margin > 255 || /* back porch */
- var->upper_margin > 255 || /* front porch */
- var->vsync_len > 32 ||
- var->yres > 1024)
- return -EINVAL;
-#undef CHECK
-
- /* single panel mode: PCD = max(PCD, 1) */
- /* dual panel mode: PCD = max(PCD, 5) */
-
- /*
- * You can't change the grayscale setting, and
- * we can only do non-interlaced video.
- */
- if (var->grayscale != fb->fb.var.grayscale ||
- (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
- return -EINVAL;
-
-#define CHECK(e) (var->e != fb->fb.var.e)
- if (fb->panel->fixedtimings &&
- (CHECK(xres) ||
- CHECK(yres) ||
- CHECK(bits_per_pixel) ||
- CHECK(pixclock) ||
- CHECK(left_margin) ||
- CHECK(right_margin) ||
- CHECK(upper_margin) ||
- CHECK(lower_margin) ||
- CHECK(hsync_len) ||
- CHECK(vsync_len) ||
- CHECK(sync)))
- return -EINVAL;
-#undef CHECK
-
- var->nonstd = 0;
- var->accel_flags = 0;
-
- return 0;
-}
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index a1307b58cc2c..9120de05ead0 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -10,6 +10,11 @@
#ifndef ASM_ARM_HARDWARE_SERIAL_AMBA_H
#define ASM_ARM_HARDWARE_SERIAL_AMBA_H
+#ifndef __ASSEMBLY__
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#endif
+
#include <linux/types.h>
/* -------------------------------------------------------------------------------
@@ -70,141 +75,145 @@
#define ZX_UART011_ICR 0x4c
#define ZX_UART011_DMACR 0x50
-#define UART011_DR_OE (1 << 11)
-#define UART011_DR_BE (1 << 10)
-#define UART011_DR_PE (1 << 9)
-#define UART011_DR_FE (1 << 8)
-
-#define UART01x_RSR_OE 0x08
-#define UART01x_RSR_BE 0x04
-#define UART01x_RSR_PE 0x02
-#define UART01x_RSR_FE 0x01
-
-#define UART011_FR_RI 0x100
-#define UART011_FR_TXFE 0x080
-#define UART011_FR_RXFF 0x040
-#define UART01x_FR_TXFF 0x020
-#define UART01x_FR_RXFE 0x010
-#define UART01x_FR_BUSY 0x008
-#define UART01x_FR_DCD 0x004
-#define UART01x_FR_DSR 0x002
-#define UART01x_FR_CTS 0x001
+#define UART011_DR_OE BIT(11)
+#define UART011_DR_BE BIT(10)
+#define UART011_DR_PE BIT(9)
+#define UART011_DR_FE BIT(8)
+
+#define UART01x_RSR_OE BIT(3)
+#define UART01x_RSR_BE BIT(2)
+#define UART01x_RSR_PE BIT(1)
+#define UART01x_RSR_FE BIT(0)
+
+#define UART011_FR_RI BIT(8)
+#define UART011_FR_TXFE BIT(7)
+#define UART011_FR_RXFF BIT(6)
+#define UART01x_FR_TXFF (1 << 5) /* used in ASM */
+#define UART01x_FR_RXFE BIT(4)
+#define UART01x_FR_BUSY (1 << 3) /* used in ASM */
+#define UART01x_FR_DCD BIT(2)
+#define UART01x_FR_DSR BIT(1)
+#define UART01x_FR_CTS BIT(0)
#define UART01x_FR_TMSK (UART01x_FR_TXFF + UART01x_FR_BUSY)
/*
* Some bits of Flag Register on ZTE device have different position from
* standard ones.
*/
-#define ZX_UART01x_FR_BUSY 0x100
-#define ZX_UART01x_FR_DSR 0x008
-#define ZX_UART01x_FR_CTS 0x002
-#define ZX_UART011_FR_RI 0x001
-
-#define UART011_CR_CTSEN 0x8000 /* CTS hardware flow control */
-#define UART011_CR_RTSEN 0x4000 /* RTS hardware flow control */
-#define UART011_CR_OUT2 0x2000 /* OUT2 */
-#define UART011_CR_OUT1 0x1000 /* OUT1 */
-#define UART011_CR_RTS 0x0800 /* RTS */
-#define UART011_CR_DTR 0x0400 /* DTR */
-#define UART011_CR_RXE 0x0200 /* receive enable */
-#define UART011_CR_TXE 0x0100 /* transmit enable */
-#define UART011_CR_LBE 0x0080 /* loopback enable */
-#define UART010_CR_RTIE 0x0040
-#define UART010_CR_TIE 0x0020
-#define UART010_CR_RIE 0x0010
-#define UART010_CR_MSIE 0x0008
-#define ST_UART011_CR_OVSFACT 0x0008 /* Oversampling factor */
-#define UART01x_CR_IIRLP 0x0004 /* SIR low power mode */
-#define UART01x_CR_SIREN 0x0002 /* SIR enable */
-#define UART01x_CR_UARTEN 0x0001 /* UART enable */
-
-#define UART011_LCRH_SPS 0x80
+#define ZX_UART01x_FR_BUSY BIT(8)
+#define ZX_UART01x_FR_DSR BIT(3)
+#define ZX_UART01x_FR_CTS BIT(1)
+#define ZX_UART011_FR_RI BIT(0)
+
+#define UART011_CR_CTSEN BIT(15) /* CTS hardware flow control */
+#define UART011_CR_RTSEN BIT(14) /* RTS hardware flow control */
+#define UART011_CR_OUT2 BIT(13) /* OUT2 */
+#define UART011_CR_OUT1 BIT(12) /* OUT1 */
+#define UART011_CR_RTS BIT(11) /* RTS */
+#define UART011_CR_DTR BIT(10) /* DTR */
+#define UART011_CR_RXE BIT(9) /* receive enable */
+#define UART011_CR_TXE BIT(8) /* transmit enable */
+#define UART011_CR_LBE BIT(7) /* loopback enable */
+#define UART010_CR_RTIE BIT(6)
+#define UART010_CR_TIE BIT(5)
+#define UART010_CR_RIE BIT(4)
+#define UART010_CR_MSIE BIT(3)
+#define ST_UART011_CR_OVSFACT BIT(3) /* Oversampling factor */
+#define UART01x_CR_IIRLP BIT(2) /* SIR low power mode */
+#define UART01x_CR_SIREN BIT(1) /* SIR enable */
+#define UART01x_CR_UARTEN BIT(0) /* UART enable */
+
+#define UART011_LCRH_SPS BIT(7)
#define UART01x_LCRH_WLEN_8 0x60
#define UART01x_LCRH_WLEN_7 0x40
#define UART01x_LCRH_WLEN_6 0x20
#define UART01x_LCRH_WLEN_5 0x00
-#define UART01x_LCRH_FEN 0x10
-#define UART01x_LCRH_STP2 0x08
-#define UART01x_LCRH_EPS 0x04
-#define UART01x_LCRH_PEN 0x02
-#define UART01x_LCRH_BRK 0x01
-
-#define ST_UART011_DMAWM_RX_1 (0 << 3)
-#define ST_UART011_DMAWM_RX_2 (1 << 3)
-#define ST_UART011_DMAWM_RX_4 (2 << 3)
-#define ST_UART011_DMAWM_RX_8 (3 << 3)
-#define ST_UART011_DMAWM_RX_16 (4 << 3)
-#define ST_UART011_DMAWM_RX_32 (5 << 3)
-#define ST_UART011_DMAWM_RX_48 (6 << 3)
-#define ST_UART011_DMAWM_TX_1 0
-#define ST_UART011_DMAWM_TX_2 1
-#define ST_UART011_DMAWM_TX_4 2
-#define ST_UART011_DMAWM_TX_8 3
-#define ST_UART011_DMAWM_TX_16 4
-#define ST_UART011_DMAWM_TX_32 5
-#define ST_UART011_DMAWM_TX_48 6
-
-#define UART010_IIR_RTIS 0x08
-#define UART010_IIR_TIS 0x04
-#define UART010_IIR_RIS 0x02
-#define UART010_IIR_MIS 0x01
-
-#define UART011_IFLS_RX1_8 (0 << 3)
-#define UART011_IFLS_RX2_8 (1 << 3)
-#define UART011_IFLS_RX4_8 (2 << 3)
-#define UART011_IFLS_RX6_8 (3 << 3)
-#define UART011_IFLS_RX7_8 (4 << 3)
-#define UART011_IFLS_TX1_8 (0 << 0)
-#define UART011_IFLS_TX2_8 (1 << 0)
-#define UART011_IFLS_TX4_8 (2 << 0)
-#define UART011_IFLS_TX6_8 (3 << 0)
-#define UART011_IFLS_TX7_8 (4 << 0)
+#define UART01x_LCRH_FEN BIT(4)
+#define UART01x_LCRH_STP2 BIT(3)
+#define UART01x_LCRH_EPS BIT(2)
+#define UART01x_LCRH_PEN BIT(1)
+#define UART01x_LCRH_BRK BIT(0)
+
+#define ST_UART011_DMAWM_RX GENMASK(5, 3)
+#define ST_UART011_DMAWM_RX_1 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 0)
+#define ST_UART011_DMAWM_RX_2 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 1)
+#define ST_UART011_DMAWM_RX_4 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 2)
+#define ST_UART011_DMAWM_RX_8 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 3)
+#define ST_UART011_DMAWM_RX_16 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 4)
+#define ST_UART011_DMAWM_RX_32 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 5)
+#define ST_UART011_DMAWM_RX_48 FIELD_PREP_CONST(ST_UART011_DMAWM_RX, 6)
+#define ST_UART011_DMAWM_TX GENMASK(2, 0)
+#define ST_UART011_DMAWM_TX_1 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 0)
+#define ST_UART011_DMAWM_TX_2 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 1)
+#define ST_UART011_DMAWM_TX_4 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 2)
+#define ST_UART011_DMAWM_TX_8 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 3)
+#define ST_UART011_DMAWM_TX_16 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 4)
+#define ST_UART011_DMAWM_TX_32 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 5)
+#define ST_UART011_DMAWM_TX_48 FIELD_PREP_CONST(ST_UART011_DMAWM_TX, 6)
+
+#define UART010_IIR_RTIS BIT(3)
+#define UART010_IIR_TIS BIT(2)
+#define UART010_IIR_RIS BIT(1)
+#define UART010_IIR_MIS BIT(0)
+
+#define UART011_IFLS_RXIFLSEL GENMASK(5, 3)
+#define UART011_IFLS_RX1_8 FIELD_PREP_CONST(UART011_IFLS_RXIFLSEL, 0)
+#define UART011_IFLS_RX2_8 FIELD_PREP_CONST(UART011_IFLS_RXIFLSEL, 1)
+#define UART011_IFLS_RX4_8 FIELD_PREP_CONST(UART011_IFLS_RXIFLSEL, 2)
+#define UART011_IFLS_RX6_8 FIELD_PREP_CONST(UART011_IFLS_RXIFLSEL, 3)
+#define UART011_IFLS_RX7_8 FIELD_PREP_CONST(UART011_IFLS_RXIFLSEL, 4)
+#define UART011_IFLS_TXIFLSEL GENMASK(2, 0)
+#define UART011_IFLS_TX1_8 FIELD_PREP_CONST(UART011_IFLS_TXIFLSEL, 0)
+#define UART011_IFLS_TX2_8 FIELD_PREP_CONST(UART011_IFLS_TXIFLSEL, 1)
+#define UART011_IFLS_TX4_8 FIELD_PREP_CONST(UART011_IFLS_TXIFLSEL, 2)
+#define UART011_IFLS_TX6_8 FIELD_PREP_CONST(UART011_IFLS_TXIFLSEL, 3)
+#define UART011_IFLS_TX7_8 FIELD_PREP_CONST(UART011_IFLS_TXIFLSEL, 4)
/* special values for ST vendor with deeper fifo */
-#define UART011_IFLS_RX_HALF (5 << 3)
-#define UART011_IFLS_TX_HALF (5 << 0)
-
-#define UART011_OEIM (1 << 10) /* overrun error interrupt mask */
-#define UART011_BEIM (1 << 9) /* break error interrupt mask */
-#define UART011_PEIM (1 << 8) /* parity error interrupt mask */
-#define UART011_FEIM (1 << 7) /* framing error interrupt mask */
-#define UART011_RTIM (1 << 6) /* receive timeout interrupt mask */
-#define UART011_TXIM (1 << 5) /* transmit interrupt mask */
-#define UART011_RXIM (1 << 4) /* receive interrupt mask */
-#define UART011_DSRMIM (1 << 3) /* DSR interrupt mask */
-#define UART011_DCDMIM (1 << 2) /* DCD interrupt mask */
-#define UART011_CTSMIM (1 << 1) /* CTS interrupt mask */
-#define UART011_RIMIM (1 << 0) /* RI interrupt mask */
-
-#define UART011_OEIS (1 << 10) /* overrun error interrupt status */
-#define UART011_BEIS (1 << 9) /* break error interrupt status */
-#define UART011_PEIS (1 << 8) /* parity error interrupt status */
-#define UART011_FEIS (1 << 7) /* framing error interrupt status */
-#define UART011_RTIS (1 << 6) /* receive timeout interrupt status */
-#define UART011_TXIS (1 << 5) /* transmit interrupt status */
-#define UART011_RXIS (1 << 4) /* receive interrupt status */
-#define UART011_DSRMIS (1 << 3) /* DSR interrupt status */
-#define UART011_DCDMIS (1 << 2) /* DCD interrupt status */
-#define UART011_CTSMIS (1 << 1) /* CTS interrupt status */
-#define UART011_RIMIS (1 << 0) /* RI interrupt status */
-
-#define UART011_OEIC (1 << 10) /* overrun error interrupt clear */
-#define UART011_BEIC (1 << 9) /* break error interrupt clear */
-#define UART011_PEIC (1 << 8) /* parity error interrupt clear */
-#define UART011_FEIC (1 << 7) /* framing error interrupt clear */
-#define UART011_RTIC (1 << 6) /* receive timeout interrupt clear */
-#define UART011_TXIC (1 << 5) /* transmit interrupt clear */
-#define UART011_RXIC (1 << 4) /* receive interrupt clear */
-#define UART011_DSRMIC (1 << 3) /* DSR interrupt clear */
-#define UART011_DCDMIC (1 << 2) /* DCD interrupt clear */
-#define UART011_CTSMIC (1 << 1) /* CTS interrupt clear */
-#define UART011_RIMIC (1 << 0) /* RI interrupt clear */
-
-#define UART011_DMAONERR (1 << 2) /* disable dma on error */
-#define UART011_TXDMAE (1 << 1) /* enable transmit dma */
-#define UART011_RXDMAE (1 << 0) /* enable receive dma */
-
-#define UART01x_RSR_ANY (UART01x_RSR_OE|UART01x_RSR_BE|UART01x_RSR_PE|UART01x_RSR_FE)
-#define UART01x_FR_MODEM_ANY (UART01x_FR_DCD|UART01x_FR_DSR|UART01x_FR_CTS)
+#define UART011_IFLS_RX_HALF FIELD_PREP_CONST(UART011_IFLS_RXIFLSEL, 5)
+#define UART011_IFLS_TX_HALF FIELD_PREP_CONST(UART011_IFLS_TXIFLSEL, 5)
+
+#define UART011_OEIM BIT(10) /* overrun error interrupt mask */
+#define UART011_BEIM BIT(9) /* break error interrupt mask */
+#define UART011_PEIM BIT(8) /* parity error interrupt mask */
+#define UART011_FEIM BIT(7) /* framing error interrupt mask */
+#define UART011_RTIM BIT(6) /* receive timeout interrupt mask */
+#define UART011_TXIM BIT(5) /* transmit interrupt mask */
+#define UART011_RXIM BIT(4) /* receive interrupt mask */
+#define UART011_DSRMIM BIT(3) /* DSR interrupt mask */
+#define UART011_DCDMIM BIT(2) /* DCD interrupt mask */
+#define UART011_CTSMIM BIT(1) /* CTS interrupt mask */
+#define UART011_RIMIM BIT(0) /* RI interrupt mask */
+
+#define UART011_OEIS BIT(10) /* overrun error interrupt status */
+#define UART011_BEIS BIT(9) /* break error interrupt status */
+#define UART011_PEIS BIT(8) /* parity error interrupt status */
+#define UART011_FEIS BIT(7) /* framing error interrupt status */
+#define UART011_RTIS BIT(6) /* receive timeout interrupt status */
+#define UART011_TXIS BIT(5) /* transmit interrupt status */
+#define UART011_RXIS BIT(4) /* receive interrupt status */
+#define UART011_DSRMIS BIT(3) /* DSR interrupt status */
+#define UART011_DCDMIS BIT(2) /* DCD interrupt status */
+#define UART011_CTSMIS BIT(1) /* CTS interrupt status */
+#define UART011_RIMIS BIT(0) /* RI interrupt status */
+
+#define UART011_OEIC BIT(10) /* overrun error interrupt clear */
+#define UART011_BEIC BIT(9) /* break error interrupt clear */
+#define UART011_PEIC BIT(8) /* parity error interrupt clear */
+#define UART011_FEIC BIT(7) /* framing error interrupt clear */
+#define UART011_RTIC BIT(6) /* receive timeout interrupt clear */
+#define UART011_TXIC BIT(5) /* transmit interrupt clear */
+#define UART011_RXIC BIT(4) /* receive interrupt clear */
+#define UART011_DSRMIC BIT(3) /* DSR interrupt clear */
+#define UART011_DCDMIC BIT(2) /* DCD interrupt clear */
+#define UART011_CTSMIC BIT(1) /* CTS interrupt clear */
+#define UART011_RIMIC BIT(0) /* RI interrupt clear */
+
+#define UART011_DMAONERR BIT(2) /* disable dma on error */
+#define UART011_TXDMAE BIT(1) /* enable transmit dma */
+#define UART011_RXDMAE BIT(0) /* enable receive dma */
+
+#define UART01x_RSR_ANY (UART01x_RSR_OE | UART01x_RSR_BE | UART01x_RSR_PE | UART01x_RSR_FE)
+#define UART01x_FR_MODEM_ANY (UART01x_FR_DCD | UART01x_FR_DSR | UART01x_FR_CTS)
#ifndef __ASSEMBLY__
struct amba_device; /* in uncompress this is included but amba/bus.h is not */
@@ -220,8 +229,8 @@ struct amba_pl011_data {
bool dma_rx_poll_enable;
unsigned int dma_rx_poll_rate;
unsigned int dma_rx_poll_timeout;
- void (*init) (void);
- void (*exit) (void);
+ void (*init)(void);
+ void (*exit)(void);
};
#endif
diff --git a/include/linux/amd-pmf-io.h b/include/linux/amd-pmf-io.h
new file mode 100644
index 000000000000..b4f818205216
--- /dev/null
+++ b/include/linux/amd-pmf-io.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AMD Platform Management Framework Interface
+ *
+ * Copyright (c) 2023, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Authors: Shyam Sundar S K <[email protected]>
+ * Basavaraj Natikar <[email protected]>
+ */
+
+#ifndef AMD_PMF_IO_H
+#define AMD_PMF_IO_H
+
+#include <linux/types.h>
+
+/**
+ * enum sfh_message_type - Query the SFH message type
+ * @MT_HPD: Message ID to know the Human presence info from MP2 FW
+ * @MT_ALS: Message ID to know the Ambient light info from MP2 FW
+ */
+enum sfh_message_type {
+ MT_HPD,
+ MT_ALS,
+};
+
+/**
+ * enum sfh_hpd_info - Query the Human presence information
+ * @SFH_NOT_DETECTED: Check the HPD connection information from MP2 FW
+ * @SFH_USER_PRESENT: Check if the user is present from HPD sensor
+ * @SFH_USER_AWAY: Check if the user is away from HPD sensor
+ */
+enum sfh_hpd_info {
+ SFH_NOT_DETECTED,
+ SFH_USER_PRESENT,
+ SFH_USER_AWAY,
+};
+
+/**
+ * struct amd_sfh_info - get HPD sensor info from MP2 FW
+ * @ambient_light: Populates the ambient light information
+ * @user_present: Populates the user presence information
+ */
+struct amd_sfh_info {
+ u32 ambient_light;
+ u8 user_present;
+};
+
+int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op);
+#endif
diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h
index 5deaddbd7927..93a5f16d03f3 100644
--- a/include/linux/anon_inodes.h
+++ b/include/linux/anon_inodes.h
@@ -15,13 +15,13 @@ struct inode;
struct file *anon_inode_getfile(const char *name,
const struct file_operations *fops,
void *priv, int flags);
-struct file *anon_inode_getfile_secure(const char *name,
+struct file *anon_inode_create_getfile(const char *name,
const struct file_operations *fops,
void *priv, int flags,
const struct inode *context_inode);
int anon_inode_getfd(const char *name, const struct file_operations *fops,
void *priv, int flags);
-int anon_inode_getfd_secure(const char *name,
+int anon_inode_create_getfd(const char *name,
const struct file_operations *fops,
void *priv, int flags,
const struct inode *context_inode);
diff --git a/include/linux/cdx/cdx_bus.h b/include/linux/cdx/cdx_bus.h
index 94ad2c9017c9..6355a36a3f81 100644
--- a/include/linux/cdx/cdx_bus.h
+++ b/include/linux/cdx/cdx_bus.h
@@ -113,6 +113,7 @@ struct cdx_controller {
* @dev_num: Device number for this device
* @res: array of MMIO region entries
* @res_attr: resource binary attribute
+ * @debugfs_dir: debugfs directory for this device
* @res_count: number of valid MMIO regions
* @dma_mask: Default DMA mask
* @flags: CDX device flags
@@ -135,6 +136,8 @@ struct cdx_device {
u8 bus_num;
u8 dev_num;
struct resource res[MAX_CDX_DEV_RESOURCES];
+ struct bin_attribute *res_attr[MAX_CDX_DEV_RESOURCES];
+ struct dentry *debugfs_dir;
u8 res_count;
u64 dma_mask;
u16 flags;
@@ -147,6 +150,15 @@ struct cdx_device {
#define to_cdx_device(_dev) \
container_of(_dev, struct cdx_device, dev)
+#define cdx_resource_start(dev, num) ((dev)->res[(num)].start)
+#define cdx_resource_end(dev, num) ((dev)->res[(num)].end)
+#define cdx_resource_flags(dev, num) ((dev)->res[(num)].flags)
+#define cdx_resource_len(dev, num) \
+ ((cdx_resource_start((dev), (num)) == 0 && \
+ cdx_resource_end((dev), (num)) == \
+ cdx_resource_start((dev), (num))) ? 0 : \
+ (cdx_resource_end((dev), (num)) - \
+ cdx_resource_start((dev), (num)) + 1))
/**
* struct cdx_driver - CDX device driver
* @driver: Generic device driver
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index ace3a4ce2fc9..1293c38ddb7f 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -448,8 +448,8 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
*/
#define clk_hw_register_fixed_rate_with_accuracy_parent_hw(dev, name, \
parent_hw, flags, fixed_rate, fixed_accuracy) \
- __clk_hw_register_fixed_rate((dev), NULL, (name), NULL, (parent_hw) \
- NULL, NULL, (flags), (fixed_rate), \
+ __clk_hw_register_fixed_rate((dev), NULL, (name), NULL, (parent_hw), \
+ NULL, (flags), (fixed_rate), \
(fixed_accuracy), 0, false)
/**
* clk_hw_register_fixed_rate_with_accuracy_parent_data - register fixed-rate
diff --git a/include/linux/container.h b/include/linux/container.h
index 2566a1baa736..dd00cc918a92 100644
--- a/include/linux/container.h
+++ b/include/linux/container.h
@@ -12,7 +12,7 @@
#include <linux/device.h>
/* drivers/base/power/container.c */
-extern struct bus_type container_subsys;
+extern const struct bus_type container_subsys;
struct container_dev {
struct device dev;
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index a269fffaf991..a4cb7dd6ca23 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -64,6 +64,7 @@ enum coresight_dev_subtype_source {
CORESIGHT_DEV_SUBTYPE_SOURCE_PROC,
CORESIGHT_DEV_SUBTYPE_SOURCE_BUS,
CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE,
+ CORESIGHT_DEV_SUBTYPE_SOURCE_TPDM,
CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS,
};
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index fc8094419084..dcb89c987164 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -80,6 +80,7 @@ extern __printf(4, 5)
struct device *cpu_device_create(struct device *parent, void *drvdata,
const struct attribute_group **groups,
const char *fmt, ...);
+extern bool arch_cpu_is_hotpluggable(int cpu);
extern int arch_register_cpu(int cpu);
extern void arch_unregister_cpu(int cpu);
#ifdef CONFIG_HOTPLUG_CPU
@@ -88,6 +89,10 @@ extern ssize_t arch_cpu_probe(const char *, size_t);
extern ssize_t arch_cpu_release(const char *, size_t);
#endif
+#ifdef CONFIG_GENERIC_CPU_DEVICES
+DECLARE_PER_CPU(struct cpu, cpu_devices);
+#endif
+
/*
* These states are not related to the core CPU hotplug mechanism. They are
* used by various (sub)architectures to track internal state
diff --git a/include/linux/cxl-event.h b/include/linux/cxl-event.h
new file mode 100644
index 000000000000..91125eca4c8a
--- /dev/null
+++ b/include/linux/cxl-event.h
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2023 Intel Corporation. */
+#ifndef _LINUX_CXL_EVENT_H
+#define _LINUX_CXL_EVENT_H
+
+/*
+ * Common Event Record Format
+ * CXL rev 3.0 section 8.2.9.2.1; Table 8-42
+ */
+struct cxl_event_record_hdr {
+ u8 length;
+ u8 flags[3];
+ __le16 handle;
+ __le16 related_handle;
+ __le64 timestamp;
+ u8 maint_op_class;
+ u8 reserved[15];
+} __packed;
+
+#define CXL_EVENT_RECORD_DATA_LENGTH 0x50
+struct cxl_event_generic {
+ struct cxl_event_record_hdr hdr;
+ u8 data[CXL_EVENT_RECORD_DATA_LENGTH];
+} __packed;
+
+/*
+ * General Media Event Record
+ * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43
+ */
+#define CXL_EVENT_GEN_MED_COMP_ID_SIZE 0x10
+struct cxl_event_gen_media {
+ struct cxl_event_record_hdr hdr;
+ __le64 phys_addr;
+ u8 descriptor;
+ u8 type;
+ u8 transaction_type;
+ u8 validity_flags[2];
+ u8 channel;
+ u8 rank;
+ u8 device[3];
+ u8 component_id[CXL_EVENT_GEN_MED_COMP_ID_SIZE];
+ u8 reserved[46];
+} __packed;
+
+/*
+ * DRAM Event Record - DER
+ * CXL rev 3.0 section 8.2.9.2.1.2; Table 3-44
+ */
+#define CXL_EVENT_DER_CORRECTION_MASK_SIZE 0x20
+struct cxl_event_dram {
+ struct cxl_event_record_hdr hdr;
+ __le64 phys_addr;
+ u8 descriptor;
+ u8 type;
+ u8 transaction_type;
+ u8 validity_flags[2];
+ u8 channel;
+ u8 rank;
+ u8 nibble_mask[3];
+ u8 bank_group;
+ u8 bank;
+ u8 row[3];
+ u8 column[2];
+ u8 correction_mask[CXL_EVENT_DER_CORRECTION_MASK_SIZE];
+ u8 reserved[0x17];
+} __packed;
+
+/*
+ * Get Health Info Record
+ * CXL rev 3.0 section 8.2.9.8.3.1; Table 8-100
+ */
+struct cxl_get_health_info {
+ u8 health_status;
+ u8 media_status;
+ u8 add_status;
+ u8 life_used;
+ u8 device_temp[2];
+ u8 dirty_shutdown_cnt[4];
+ u8 cor_vol_err_cnt[4];
+ u8 cor_per_err_cnt[4];
+} __packed;
+
+/*
+ * Memory Module Event Record
+ * CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45
+ */
+struct cxl_event_mem_module {
+ struct cxl_event_record_hdr hdr;
+ u8 event_type;
+ struct cxl_get_health_info info;
+ u8 reserved[0x3d];
+} __packed;
+
+union cxl_event {
+ struct cxl_event_generic generic;
+ struct cxl_event_gen_media gen_media;
+ struct cxl_event_dram dram;
+ struct cxl_event_mem_module mem_module;
+} __packed;
+
+/*
+ * Common Event Record Format; in event logs
+ * CXL rev 3.0 section 8.2.9.2.1; Table 8-42
+ */
+struct cxl_event_record_raw {
+ uuid_t id;
+ union cxl_event event;
+} __packed;
+
+enum cxl_event_type {
+ CXL_CPER_EVENT_GENERIC,
+ CXL_CPER_EVENT_GEN_MEDIA,
+ CXL_CPER_EVENT_DRAM,
+ CXL_CPER_EVENT_MEM_MODULE,
+};
+
+#define CPER_CXL_DEVICE_ID_VALID BIT(0)
+#define CPER_CXL_DEVICE_SN_VALID BIT(1)
+#define CPER_CXL_COMP_EVENT_LOG_VALID BIT(2)
+struct cxl_cper_event_rec {
+ struct {
+ u32 length;
+ u64 validation_bits;
+ struct cper_cxl_event_devid {
+ u16 vendor_id;
+ u16 device_id;
+ u8 func_num;
+ u8 device_num;
+ u8 bus_num;
+ u16 segment_num;
+ u16 slot_num; /* bits 2:0 reserved */
+ u8 reserved;
+ } __packed device_id;
+ struct cper_cxl_event_sn {
+ u32 lower_dw;
+ u32 upper_dw;
+ } __packed dev_serial_num;
+ } __packed hdr;
+
+ union cxl_event event;
+} __packed;
+
+typedef void (*cxl_cper_callback)(enum cxl_event_type type,
+ struct cxl_cper_event_rec *rec);
+
+#ifdef CONFIG_ACPI_APEI_GHES
+int cxl_cper_register_callback(cxl_cper_callback callback);
+int cxl_cper_unregister_callback(cxl_cper_callback callback);
+#else
+static inline int cxl_cper_register_callback(cxl_cper_callback callback)
+{
+ return 0;
+}
+
+static inline int cxl_cper_unregister_callback(cxl_cper_callback callback)
+{
+ return 0;
+}
+#endif
+
+#endif /* _LINUX_CXL_EVENT_H */
diff --git a/include/linux/device.h b/include/linux/device.h
index 6c83294395ac..97c4b046c09d 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -42,7 +42,6 @@ struct class;
struct subsys_private;
struct device_node;
struct fwnode_handle;
-struct iommu_ops;
struct iommu_group;
struct dev_pin_info;
struct dev_iommu;
@@ -63,7 +62,7 @@ struct msi_device_data;
*/
struct subsys_interface {
const char *name;
- struct bus_type *subsys;
+ const struct bus_type *subsys;
struct list_head node;
int (*add_dev)(struct device *dev, struct subsys_interface *sif);
void (*remove_dev)(struct device *dev, struct subsys_interface *sif);
@@ -72,9 +71,9 @@ struct subsys_interface {
int subsys_interface_register(struct subsys_interface *sif);
void subsys_interface_unregister(struct subsys_interface *sif);
-int subsys_system_register(struct bus_type *subsys,
+int subsys_system_register(const struct bus_type *subsys,
const struct attribute_group **groups);
-int subsys_virtual_register(struct bus_type *subsys,
+int subsys_virtual_register(const struct bus_type *subsys,
const struct attribute_group **groups);
/*
@@ -662,7 +661,6 @@ struct device_physical_location {
* @id: device instance
* @devres_lock: Spinlock to protect the resource of the device.
* @devres_head: The resources list of the device.
- * @knode_class: The node used to add the device to the class list.
* @class: The class of the device.
* @groups: Optional attribute groups.
* @release: Callback to free the device after all references have
@@ -1073,7 +1071,6 @@ int device_rename(struct device *dev, const char *new_name);
int device_move(struct device *dev, struct device *new_parent,
enum dpm_order dpm_order);
int device_change_owner(struct device *dev, kuid_t kuid, kgid_t kgid);
-int device_is_dependent(struct device *dev, void *target);
static inline bool device_supports_offline(struct device *dev)
{
diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h
index ae10c4322754..5ef4ec1c36c3 100644
--- a/include/linux/device/bus.h
+++ b/include/linux/device/bus.h
@@ -62,9 +62,6 @@ struct fwnode_handle;
* this bus.
* @pm: Power management operations of this bus, callback the specific
* device driver's pm-ops.
- * @iommu_ops: IOMMU specific operations for this bus, used to attach IOMMU
- * driver implementations to a bus and allow the driver to do
- * bus-specific setup
* @need_parent_lock: When probing or removing a device on this bus, the
* device core should lock the device's parent.
*
@@ -104,8 +101,6 @@ struct bus_type {
const struct dev_pm_ops *pm;
- const struct iommu_ops *iommu_ops;
-
bool need_parent_lock;
};
@@ -232,7 +227,7 @@ bus_find_device_by_acpi_dev(const struct bus_type *bus, const void *adev)
int bus_for_each_drv(const struct bus_type *bus, struct device_driver *start,
void *data, int (*fn)(struct device_driver *, void *));
-void bus_sort_breadthfirst(struct bus_type *bus,
+void bus_sort_breadthfirst(const struct bus_type *bus,
int (*compare)(const struct device *a,
const struct device *b));
/*
diff --git a/include/linux/device/class.h b/include/linux/device/class.h
index abf3d3bfb6fe..c576b49c55c2 100644
--- a/include/linux/device/class.h
+++ b/include/linux/device/class.h
@@ -40,8 +40,6 @@ struct fwnode_handle;
* for the devices belonging to the class. Usually tied to
* device's namespace.
* @pm: The default device power management operations of this class.
- * @p: The private data of the driver core, no one other than the
- * driver core can touch this.
*
* A class is a higher-level view of a device that abstracts out low-level
* implementation details. Drivers may see a SCSI disk or an ATA disk, but,
diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h
index f2fc203fb8a1..4abc60f04209 100644
--- a/include/linux/dma-map-ops.h
+++ b/include/linux/dma-map-ops.h
@@ -11,6 +11,7 @@
#include <linux/slab.h>
struct cma;
+struct iommu_ops;
/*
* Values for struct dma_map_ops.flags:
@@ -426,10 +427,10 @@ bool arch_dma_unmap_sg_direct(struct device *dev, struct scatterlist *sg,
#ifdef CONFIG_ARCH_HAS_SETUP_DMA_OPS
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
- const struct iommu_ops *iommu, bool coherent);
+ bool coherent);
#else
static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base,
- u64 size, const struct iommu_ops *iommu, bool coherent)
+ u64 size, bool coherent)
{
}
#endif /* CONFIG_ARCH_HAS_SETUP_DMA_OPS */
@@ -443,10 +444,10 @@ static inline void arch_teardown_dma_ops(struct device *dev)
#endif /* CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS */
#ifdef CONFIG_DMA_API_DEBUG
-void dma_debug_add_bus(struct bus_type *bus);
+void dma_debug_add_bus(const struct bus_type *bus);
void debug_dma_dump_mappings(struct device *dev);
#else
-static inline void dma_debug_add_bus(struct bus_type *bus)
+static inline void dma_debug_add_bus(const struct bus_type *bus)
{
}
static inline void debug_dma_dump_mappings(struct device *dev)
diff --git a/include/linux/edac.h b/include/linux/edac.h
index 1174beb94ab6..b4ee8961e623 100644
--- a/include/linux/edac.h
+++ b/include/linux/edac.h
@@ -30,7 +30,7 @@ struct device;
extern int edac_op_state;
-struct bus_type *edac_get_sysfs_subsys(void);
+const struct bus_type *edac_get_sysfs_subsys(void);
static inline void opstate_init(void)
{
@@ -495,7 +495,7 @@ struct edac_raw_error_desc {
*/
struct mem_ctl_info {
struct device dev;
- struct bus_type *bus;
+ const struct bus_type *bus;
struct list_head link; /* for global list of mem_ctl_info structs */
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index bd3fc75d4f14..dd9f2d765e68 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -75,7 +75,7 @@ void fw_csr_iterator_init(struct fw_csr_iterator *ci, const u32 *p);
int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value);
int fw_csr_string(const u32 *directory, int key, char *buf, size_t size);
-extern struct bus_type fw_bus_type;
+extern const struct bus_type fw_bus_type;
struct fw_card_driver;
struct fw_node;
diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h
index d1ea3898564c..9a7e52739251 100644
--- a/include/linux/firmware/xlnx-zynqmp.h
+++ b/include/linux/firmware/xlnx-zynqmp.h
@@ -32,6 +32,7 @@
#define PM_SIP_SVC 0xC2000000
/* PM API versions */
+#define PM_API_VERSION_1 1
#define PM_API_VERSION_2 2
#define PM_PINCTRL_PARAM_SET_VERSION 2
@@ -47,6 +48,9 @@
#define FAMILY_CODE_MASK GENMASK(27, 21)
#define SUB_FAMILY_CODE_MASK GENMASK(20, 19)
+#define API_ID_MASK GENMASK(7, 0)
+#define MODULE_ID_MASK GENMASK(11, 8)
+
/* ATF only commands */
#define TF_A_PM_REGISTER_SGI 0xa04
#define PM_GET_TRUSTZONE_VERSION 0xa03
@@ -91,10 +95,18 @@
/*
* Node IDs for the Error Events.
*/
-#define EVENT_ERROR_PMC_ERR1 (0x28100000U)
-#define EVENT_ERROR_PMC_ERR2 (0x28104000U)
-#define EVENT_ERROR_PSM_ERR1 (0x28108000U)
-#define EVENT_ERROR_PSM_ERR2 (0x2810C000U)
+#define VERSAL_EVENT_ERROR_PMC_ERR1 (0x28100000U)
+#define VERSAL_EVENT_ERROR_PMC_ERR2 (0x28104000U)
+#define VERSAL_EVENT_ERROR_PSM_ERR1 (0x28108000U)
+#define VERSAL_EVENT_ERROR_PSM_ERR2 (0x2810C000U)
+
+#define VERSAL_NET_EVENT_ERROR_PMC_ERR1 (0x28100000U)
+#define VERSAL_NET_EVENT_ERROR_PMC_ERR2 (0x28104000U)
+#define VERSAL_NET_EVENT_ERROR_PMC_ERR3 (0x28108000U)
+#define VERSAL_NET_EVENT_ERROR_PSM_ERR1 (0x2810C000U)
+#define VERSAL_NET_EVENT_ERROR_PSM_ERR2 (0x28110000U)
+#define VERSAL_NET_EVENT_ERROR_PSM_ERR3 (0x28114000U)
+#define VERSAL_NET_EVENT_ERROR_PSM_ERR4 (0x28118000U)
/* ZynqMP SD tap delay tuning */
#define SD_ITAPDLY 0xFF180314
@@ -112,6 +124,12 @@
#define XPM_EVENT_ERROR_MASK_NOC_NCR BIT(13)
#define XPM_EVENT_ERROR_MASK_NOC_CR BIT(12)
+enum pm_module_id {
+ PM_MODULE_ID = 0x0,
+ XSEM_MODULE_ID = 0x3,
+ TF_A_MODULE_ID = 0xa,
+};
+
enum pm_api_cb_id {
PM_INIT_SUSPEND_CB = 30,
PM_ACKNOWLEDGE_CB = 31,
@@ -119,6 +137,7 @@ enum pm_api_cb_id {
};
enum pm_api_id {
+ PM_API_FEATURES = 0,
PM_GET_API_VERSION = 1,
PM_REGISTER_NOTIFIER = 5,
PM_FORCE_POWERDOWN = 8,
@@ -138,7 +157,6 @@ enum pm_api_id {
PM_SECURE_SHA = 26,
PM_PINCTRL_REQUEST = 28,
PM_PINCTRL_RELEASE = 29,
- PM_PINCTRL_GET_FUNCTION = 30,
PM_PINCTRL_SET_FUNCTION = 31,
PM_PINCTRL_CONFIG_PARAM_GET = 32,
PM_PINCTRL_CONFIG_PARAM_SET = 33,
@@ -149,8 +167,6 @@ enum pm_api_id {
PM_CLOCK_GETSTATE = 38,
PM_CLOCK_SETDIVIDER = 39,
PM_CLOCK_GETDIVIDER = 40,
- PM_CLOCK_SETRATE = 41,
- PM_CLOCK_GETRATE = 42,
PM_CLOCK_SETPARENT = 43,
PM_CLOCK_GETPARENT = 44,
PM_FPGA_READ = 46,
@@ -161,7 +177,9 @@ enum pm_api_id {
/* PMU-FW return status codes */
enum pm_ret_status {
XST_PM_SUCCESS = 0,
+ XST_PM_INVALID_VERSION = 4,
XST_PM_NO_FEATURE = 19,
+ XST_PM_INVALID_CRC = 301,
XST_PM_INTERNAL = 2000,
XST_PM_CONFLICT = 2001,
XST_PM_NO_ACCESS = 2002,
@@ -509,20 +527,18 @@ struct zynqmp_pm_query_data {
u32 arg3;
};
-int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1,
- u32 arg2, u32 arg3, u32 *ret_payload);
+int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...);
#if IS_REACHABLE(CONFIG_ZYNQMP_FIRMWARE)
int zynqmp_pm_get_api_version(u32 *version);
int zynqmp_pm_get_chipid(u32 *idcode, u32 *version);
+int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily);
int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out);
int zynqmp_pm_clock_enable(u32 clock_id);
int zynqmp_pm_clock_disable(u32 clock_id);
int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state);
int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider);
int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider);
-int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate);
-int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate);
int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id);
int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id);
int zynqmp_pm_set_pll_frac_mode(u32 clk_id, u32 mode);
@@ -559,7 +575,6 @@ int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype);
int zynqmp_pm_set_boot_health_status(u32 value);
int zynqmp_pm_pinctrl_request(const u32 pin);
int zynqmp_pm_pinctrl_release(const u32 pin);
-int zynqmp_pm_pinctrl_get_function(const u32 pin, u32 *id);
int zynqmp_pm_pinctrl_set_function(const u32 pin, const u32 id);
int zynqmp_pm_pinctrl_get_config(const u32 pin, const u32 param,
u32 *value);
@@ -596,6 +611,11 @@ static inline int zynqmp_pm_get_chipid(u32 *idcode, u32 *version)
return -ENODEV;
}
+static inline int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily)
+{
+ return -ENODEV;
+}
+
static inline int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata,
u32 *out)
{
@@ -627,16 +647,6 @@ static inline int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)
return -ENODEV;
}
-static inline int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate)
-{
- return -ENODEV;
-}
-
-static inline int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate)
-{
- return -ENODEV;
-}
-
static inline int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id)
{
return -ENODEV;
@@ -806,11 +816,6 @@ static inline int zynqmp_pm_pinctrl_release(const u32 pin)
return -ENODEV;
}
-static inline int zynqmp_pm_pinctrl_get_function(const u32 pin, u32 *id)
-{
- return -ENODEV;
-}
-
static inline int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id)
{
return -ENODEV;
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 11e6434b8e71..8300a5286988 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -100,6 +100,7 @@ static inline int fsnotify_file(struct file *file, __u32 mask)
return fsnotify_parent(path->dentry, mask, path, FSNOTIFY_EVENT_PATH);
}
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
/*
* fsnotify_file_area_perm - permission hook before access to file range
*/
@@ -145,6 +146,24 @@ static inline int fsnotify_open_perm(struct file *file)
return fsnotify_file(file, FS_OPEN_PERM);
}
+#else
+static inline int fsnotify_file_area_perm(struct file *file, int perm_mask,
+ const loff_t *ppos, size_t count)
+{
+ return 0;
+}
+
+static inline int fsnotify_file_perm(struct file *file, int perm_mask)
+{
+ return 0;
+}
+
+static inline int fsnotify_open_perm(struct file *file)
+{
+ return 0;
+}
+#endif
+
/*
* fsnotify_link_count - inode's link count changed
*/
diff --git a/include/linux/fw_table.h b/include/linux/fw_table.h
index ca49947f0a77..95421860397a 100644
--- a/include/linux/fw_table.h
+++ b/include/linux/fw_table.h
@@ -25,16 +25,35 @@ struct acpi_subtable_proc {
int count;
};
+union fw_table_header {
+ struct acpi_table_header acpi;
+ struct acpi_table_cdat cdat;
+};
+
union acpi_subtable_headers {
struct acpi_subtable_header common;
struct acpi_hmat_structure hmat;
struct acpi_prmt_module_header prmt;
struct acpi_cedt_header cedt;
+ struct acpi_cdat_header cdat;
};
int acpi_parse_entries_array(char *id, unsigned long table_size,
- struct acpi_table_header *table_header,
+ union fw_table_header *table_header,
struct acpi_subtable_proc *proc,
int proc_num, unsigned int max_entries);
+int cdat_table_parse(enum acpi_cdat_type type,
+ acpi_tbl_entry_handler_arg handler_arg, void *arg,
+ struct acpi_table_cdat *table_header);
+
+/* CXL is the only non-ACPI consumer of the FIRMWARE_TABLE library */
+#if IS_ENABLED(CONFIG_ACPI) && !IS_ENABLED(CONFIG_CXL_BUS)
+#define EXPORT_SYMBOL_FWTBL_LIB(x) EXPORT_SYMBOL_ACPI_LIB(x)
+#define __init_or_fwtbl_lib __init_or_acpilib
+#else
+#define EXPORT_SYMBOL_FWTBL_LIB(x) EXPORT_SYMBOL_NS_GPL(x, CXL)
+#define __init_or_fwtbl_lib
+#endif
+
#endif
diff --git a/include/linux/hid.h b/include/linux/hid.h
index bf43f3ff6664..7c26db874ff0 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -912,7 +912,7 @@ extern bool hid_ignore(struct hid_device *);
extern int hid_add_device(struct hid_device *);
extern void hid_destroy_device(struct hid_device *);
-extern struct bus_type hid_bus_type;
+extern const struct bus_type hid_bus_type;
extern int __must_check __hid_register_driver(struct hid_driver *,
struct module *, const char *mod_name);
diff --git a/include/linux/hid_bpf.h b/include/linux/hid_bpf.h
index e9afb61e6ee0..840cd254172d 100644
--- a/include/linux/hid_bpf.h
+++ b/include/linux/hid_bpf.h
@@ -115,7 +115,7 @@ struct hid_bpf_ops {
size_t len, enum hid_report_type rtype,
enum hid_class_request reqtype);
struct module *owner;
- struct bus_type *bus_type;
+ const struct bus_type *bus_type;
};
extern struct hid_bpf_ops *hid_bpf_ops;
diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h
index 84ed77c04940..e119f11948ef 100644
--- a/include/linux/i3c/device.h
+++ b/include/linux/i3c/device.h
@@ -54,6 +54,7 @@ enum i3c_hdr_mode {
* struct i3c_priv_xfer - I3C SDR private transfer
* @rnw: encodes the transfer direction. true for a read, false for a write
* @len: transfer length in bytes of the transfer
+ * @actual_len: actual length in bytes are transferred by the controller
* @data: input/output buffer
* @data.in: input buffer. Must point to a DMA-able buffer
* @data.out: output buffer. Must point to a DMA-able buffer
@@ -62,6 +63,7 @@ enum i3c_hdr_mode {
struct i3c_priv_xfer {
u8 rnw;
u16 len;
+ u16 actual_len;
union {
void *in;
const void *out;
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index 24c1863b86e2..0ca27dd86956 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -76,7 +76,6 @@ struct i2c_dev_boardinfo {
/**
* struct i2c_dev_desc - I2C device descriptor
* @common: common part of the I2C device descriptor
- * @boardinfo: pointer to the boardinfo attached to this I2C device
* @dev: I2C device object registered to the I2C framework
* @addr: I2C device address
* @lvr: LVR (Legacy Virtual Register) needed by the I3C core to know about
@@ -434,6 +433,8 @@ struct i3c_bus {
* for a future IBI
* This method is mandatory only if ->request_ibi is not
* NULL.
+ * @enable_hotjoin: enable hot join event detect.
+ * @disable_hotjoin: disable hot join event detect.
*/
struct i3c_master_controller_ops {
int (*bus_init)(struct i3c_master_controller *master);
@@ -460,6 +461,8 @@ struct i3c_master_controller_ops {
int (*disable_ibi)(struct i3c_dev_desc *dev);
void (*recycle_ibi_slot)(struct i3c_dev_desc *dev,
struct i3c_ibi_slot *slot);
+ int (*enable_hotjoin)(struct i3c_master_controller *master);
+ int (*disable_hotjoin)(struct i3c_master_controller *master);
};
/**
@@ -473,6 +476,7 @@ struct i3c_master_controller_ops {
* @ops: master operations. See &struct i3c_master_controller_ops
* @secondary: true if the master is a secondary master
* @init_done: true when the bus initialization is done
+ * @hotjoin: true if the master support hotjoin
* @boardinfo.i3c: list of I3C boardinfo objects
* @boardinfo.i2c: list of I2C boardinfo objects
* @boardinfo: board-level information attached to devices connected on the bus
@@ -495,6 +499,7 @@ struct i3c_master_controller {
const struct i3c_master_controller_ops *ops;
unsigned int secondary : 1;
unsigned int init_done : 1;
+ unsigned int hotjoin: 1;
struct {
struct list_head i3c;
struct list_head i2c;
@@ -551,6 +556,8 @@ int i3c_master_register(struct i3c_master_controller *master,
const struct i3c_master_controller_ops *ops,
bool secondary);
void i3c_master_unregister(struct i3c_master_controller *master);
+int i3c_master_enable_hotjoin(struct i3c_master_controller *master);
+int i3c_master_disable_hotjoin(struct i3c_master_controller *master);
/**
* i3c_dev_get_master_data() - get master private data attached to an I3C
diff --git a/include/linux/iio/adc/adi-axi-adc.h b/include/linux/iio/adc/adi-axi-adc.h
index 52620e5b8052..b7904992d561 100644
--- a/include/linux/iio/adc/adi-axi-adc.h
+++ b/include/linux/iio/adc/adi-axi-adc.h
@@ -41,6 +41,7 @@ struct adi_axi_adc_chip_info {
* @reg_access IIO debugfs_reg_access hook for the client ADC
* @read_raw IIO read_raw hook for the client ADC
* @write_raw IIO write_raw hook for the client ADC
+ * @read_avail IIO read_avail hook for the client ADC
*/
struct adi_axi_adc_conv {
const struct adi_axi_adc_chip_info *chip_info;
@@ -54,6 +55,9 @@ struct adi_axi_adc_conv {
int (*write_raw)(struct adi_axi_adc_conv *conv,
struct iio_chan_spec const *chan,
int val, int val2, long mask);
+ int (*read_avail)(struct adi_axi_adc_conv *conv,
+ struct iio_chan_spec const *chan,
+ const int **val, int *type, int *length, long mask);
};
struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev,
diff --git a/include/linux/iio/buffer-dma.h b/include/linux/iio/buffer-dma.h
index 6564bdcdac66..18d3702fa95d 100644
--- a/include/linux/iio/buffer-dma.h
+++ b/include/linux/iio/buffer-dma.h
@@ -19,14 +19,12 @@ struct device;
/**
* enum iio_block_state - State of a struct iio_dma_buffer_block
- * @IIO_BLOCK_STATE_DEQUEUED: Block is not queued
* @IIO_BLOCK_STATE_QUEUED: Block is on the incoming queue
* @IIO_BLOCK_STATE_ACTIVE: Block is currently being processed by the DMA
* @IIO_BLOCK_STATE_DONE: Block is on the outgoing queue
* @IIO_BLOCK_STATE_DEAD: Block has been marked as to be freed
*/
enum iio_block_state {
- IIO_BLOCK_STATE_DEQUEUED,
IIO_BLOCK_STATE_QUEUED,
IIO_BLOCK_STATE_ACTIVE,
IIO_BLOCK_STATE_DONE,
@@ -73,12 +71,15 @@ struct iio_dma_buffer_block {
* @active_block: Block being used in read()
* @pos: Read offset in the active block
* @block_size: Size of each block
+ * @next_dequeue: index of next block that will be dequeued
*/
struct iio_dma_buffer_queue_fileio {
struct iio_dma_buffer_block *blocks[2];
struct iio_dma_buffer_block *active_block;
size_t pos;
size_t block_size;
+
+ unsigned int next_dequeue;
};
/**
@@ -93,7 +94,6 @@ struct iio_dma_buffer_queue_fileio {
* list and typically also a list of active blocks in the part that handles
* the DMA controller
* @incoming: List of buffers on the incoming queue
- * @outgoing: List of buffers on the outgoing queue
* @active: Whether the buffer is currently active
* @fileio: FileIO state
*/
@@ -105,7 +105,6 @@ struct iio_dma_buffer_queue {
struct mutex lock;
spinlock_t list_lock;
struct list_head incoming;
- struct list_head outgoing;
bool active;
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index d0ce3b71106a..c5b36d2c1e73 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -434,13 +434,7 @@ struct iio_trigger; /* forward declaration */
* @update_scan_mode: function to configure device and scan buffer when
* channels have changed
* @debugfs_reg_access: function to read or write register value of device
- * @of_xlate: function pointer to obtain channel specifier index.
- * When #iio-cells is greater than '0', the driver could
- * provide a custom of_xlate function that reads the
- * *args* and returns the appropriate index in registered
- * IIO channels array.
* @fwnode_xlate: fwnode based function pointer to obtain channel specifier index.
- * Functionally the same as @of_xlate.
* @hwfifo_set_watermark: function pointer to set the current hardware
* fifo watermark level; see hwfifo_* entries in
* Documentation/ABI/testing/sysfs-bus-iio for details on
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
index 117bde7d6ad7..d89982c98368 100644
--- a/include/linux/iio/types.h
+++ b/include/linux/iio/types.h
@@ -68,6 +68,7 @@ enum iio_chan_info_enum {
IIO_CHAN_INFO_THERMOCOUPLE_TYPE,
IIO_CHAN_INFO_CALIBAMBIENT,
IIO_CHAN_INFO_ZEROPOINT,
+ IIO_CHAN_INFO_TROUGH,
};
#endif /* _IIO_TYPES_H_ */
diff --git a/include/linux/intel-ish-client-if.h b/include/linux/intel-ish-client-if.h
index f45f13304add..771622650247 100644
--- a/include/linux/intel-ish-client-if.h
+++ b/include/linux/intel-ish-client-if.h
@@ -94,6 +94,9 @@ int ishtp_cl_link(struct ishtp_cl *cl);
void ishtp_cl_unlink(struct ishtp_cl *cl);
int ishtp_cl_disconnect(struct ishtp_cl *cl);
int ishtp_cl_connect(struct ishtp_cl *cl);
+int ishtp_cl_establish_connection(struct ishtp_cl *cl, const guid_t *uuid,
+ int tx_size, int rx_size, bool reset);
+void ishtp_cl_destroy_connection(struct ishtp_cl *cl, bool reset);
int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length);
int ishtp_cl_flush_queues(struct ishtp_cl *cl);
int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb);
diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h
index 25142a0e2fc2..86cf1f7ae389 100644
--- a/include/linux/io-pgtable.h
+++ b/include/linux/io-pgtable.h
@@ -100,6 +100,30 @@ struct io_pgtable_cfg {
const struct iommu_flush_ops *tlb;
struct device *iommu_dev;
+ /**
+ * @alloc: Custom page allocator.
+ *
+ * Optional hook used to allocate page tables. If this function is NULL,
+ * @free must be NULL too.
+ *
+ * Memory returned should be zeroed and suitable for dma_map_single() and
+ * virt_to_phys().
+ *
+ * Not all formats support custom page allocators. Before considering
+ * passing a non-NULL value, make sure the chosen page format supports
+ * this feature.
+ */
+ void *(*alloc)(void *cookie, size_t size, gfp_t gfp);
+
+ /**
+ * @free: Custom page de-allocator.
+ *
+ * Optional hook used to free page tables allocated with the @alloc
+ * hook. Must be non-NULL if @alloc is not NULL, must be NULL
+ * otherwise.
+ */
+ void (*free)(void *cookie, void *pages, size_t size);
+
/* Low-level data specific to the table format */
union {
struct {
@@ -242,15 +266,25 @@ io_pgtable_tlb_add_page(struct io_pgtable *iop,
}
/**
+ * enum io_pgtable_caps - IO page table backend capabilities.
+ */
+enum io_pgtable_caps {
+ /** @IO_PGTABLE_CAP_CUSTOM_ALLOCATOR: Backend accepts custom page table allocators. */
+ IO_PGTABLE_CAP_CUSTOM_ALLOCATOR = BIT(0),
+};
+
+/**
* struct io_pgtable_init_fns - Alloc/free a set of page tables for a
* particular format.
*
* @alloc: Allocate a set of page tables described by cfg.
* @free: Free the page tables associated with iop.
+ * @caps: Combination of @io_pgtable_caps flags encoding the backend capabilities.
*/
struct io_pgtable_init_fns {
struct io_pgtable *(*alloc)(struct io_pgtable_cfg *cfg, void *cookie);
void (*free)(struct io_pgtable *iop);
+ u32 caps;
};
extern struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s1_init_fns;
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 6291aa7b079b..1ea2a820e1eb 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -106,7 +106,7 @@ struct iommu_domain {
unsigned type;
const struct iommu_domain_ops *ops;
const struct iommu_dirty_ops *dirty_ops;
-
+ const struct iommu_ops *owner; /* Whose domain_alloc we came from */
unsigned long pgsize_bitmap; /* Bitmap of page sizes in use */
struct iommu_domain_geometry geometry;
struct iommu_dma_cookie *iova_cookie;
@@ -121,6 +121,11 @@ struct iommu_domain {
struct { /* IOMMU_DOMAIN_SVA */
struct mm_struct *mm;
int users;
+ /*
+ * Next iommu_domain in mm->iommu_mm->sva-domains list
+ * protected by iommu_sva_lock.
+ */
+ struct list_head next;
};
};
};
@@ -285,6 +290,23 @@ struct iommu_user_data {
};
/**
+ * struct iommu_user_data_array - iommu driver specific user space data array
+ * @type: The data type of all the entries in the user buffer array
+ * @uptr: Pointer to the user buffer array
+ * @entry_len: The fixed-width length of an entry in the array, in bytes
+ * @entry_num: The number of total entries in the array
+ *
+ * The user buffer includes an array of requests with format defined in
+ * include/uapi/linux/iommufd.h
+ */
+struct iommu_user_data_array {
+ unsigned int type;
+ void __user *uptr;
+ size_t entry_len;
+ u32 entry_num;
+};
+
+/**
* __iommu_copy_struct_from_user - Copy iommu driver specific user space data
* @dst_data: Pointer to an iommu driver specific user data that is defined in
* include/uapi/linux/iommufd.h
@@ -325,6 +347,57 @@ static inline int __iommu_copy_struct_from_user(
offsetofend(typeof(*kdst), min_last))
/**
+ * __iommu_copy_struct_from_user_array - Copy iommu driver specific user space
+ * data from an iommu_user_data_array
+ * @dst_data: Pointer to an iommu driver specific user data that is defined in
+ * include/uapi/linux/iommufd.h
+ * @src_array: Pointer to a struct iommu_user_data_array for a user space array
+ * @data_type: The data type of the @dst_data. Must match with @src_array.type
+ * @index: Index to the location in the array to copy user data from
+ * @data_len: Length of current user data structure, i.e. sizeof(struct _dst)
+ * @min_len: Initial length of user data structure for backward compatibility.
+ * This should be offsetofend using the last member in the user data
+ * struct that was initially added to include/uapi/linux/iommufd.h
+ */
+static inline int __iommu_copy_struct_from_user_array(
+ void *dst_data, const struct iommu_user_data_array *src_array,
+ unsigned int data_type, unsigned int index, size_t data_len,
+ size_t min_len)
+{
+ struct iommu_user_data src_data;
+
+ if (WARN_ON(!src_array || index >= src_array->entry_num))
+ return -EINVAL;
+ if (!src_array->entry_num)
+ return -EINVAL;
+ src_data.uptr = src_array->uptr + src_array->entry_len * index;
+ src_data.len = src_array->entry_len;
+ src_data.type = src_array->type;
+
+ return __iommu_copy_struct_from_user(dst_data, &src_data, data_type,
+ data_len, min_len);
+}
+
+/**
+ * iommu_copy_struct_from_user_array - Copy iommu driver specific user space
+ * data from an iommu_user_data_array
+ * @kdst: Pointer to an iommu driver specific user data that is defined in
+ * include/uapi/linux/iommufd.h
+ * @user_array: Pointer to a struct iommu_user_data_array for a user space
+ * array
+ * @data_type: The data type of the @kdst. Must match with @user_array->type
+ * @index: Index to the location in the array to copy user data from
+ * @min_last: The last member of the data structure @kdst points in the
+ * initial version.
+ * Return 0 for success, otherwise -error.
+ */
+#define iommu_copy_struct_from_user_array(kdst, user_array, data_type, index, \
+ min_last) \
+ __iommu_copy_struct_from_user_array( \
+ kdst, user_array, data_type, index, sizeof(*(kdst)), \
+ offsetofend(typeof(*(kdst)), min_last))
+
+/**
* struct iommu_ops - iommu ops and capabilities
* @capable: check capability
* @hw_info: report iommu hardware information. The data buffer returned by this
@@ -440,6 +513,13 @@ struct iommu_ops {
* @iotlb_sync_map: Sync mappings created recently using @map to the hardware
* @iotlb_sync: Flush all queued ranges from the hardware TLBs and empty flush
* queue
+ * @cache_invalidate_user: Flush hardware cache for user space IO page table.
+ * The @domain must be IOMMU_DOMAIN_NESTED. The @array
+ * passes in the cache invalidation requests, in form
+ * of a driver data structure. The driver must update
+ * array->entry_num to report the number of handled
+ * invalidation requests. The driver data structure
+ * must be defined in include/uapi/linux/iommufd.h
* @iova_to_phys: translate iova to physical address
* @enforce_cache_coherency: Prevent any kind of DMA from bypassing IOMMU_CACHE,
* including no-snoop TLPs on PCIe or other platform
@@ -465,6 +545,8 @@ struct iommu_domain_ops {
size_t size);
void (*iotlb_sync)(struct iommu_domain *domain,
struct iommu_iotlb_gather *iotlb_gather);
+ int (*cache_invalidate_user)(struct iommu_domain *domain,
+ struct iommu_user_data_array *array);
phys_addr_t (*iova_to_phys)(struct iommu_domain *domain,
dma_addr_t iova);
@@ -812,6 +894,11 @@ struct iommu_sva {
struct iommu_domain *domain;
};
+struct iommu_mm_data {
+ u32 pasid;
+ struct list_head sva_domains;
+};
+
int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
const struct iommu_ops *ops);
void iommu_fwspec_free(struct device *dev);
@@ -840,10 +927,7 @@ static inline void *dev_iommu_priv_get(struct device *dev)
return NULL;
}
-static inline void dev_iommu_priv_set(struct device *dev, void *priv)
-{
- dev->iommu->priv = priv;
-}
+void dev_iommu_priv_set(struct device *dev, void *priv);
extern struct mutex iommu_probe_device_lock;
int iommu_probe_device(struct device *dev);
@@ -1337,15 +1421,33 @@ static inline bool tegra_dev_iommu_get_stream_id(struct device *dev, u32 *stream
return false;
}
-#ifdef CONFIG_IOMMU_SVA
+#ifdef CONFIG_IOMMU_MM_DATA
static inline void mm_pasid_init(struct mm_struct *mm)
{
- mm->pasid = IOMMU_PASID_INVALID;
+ /*
+ * During dup_mm(), a new mm will be memcpy'd from an old one and that makes
+ * the new mm and the old one point to a same iommu_mm instance. When either
+ * one of the two mms gets released, the iommu_mm instance is freed, leaving
+ * the other mm running into a use-after-free/double-free problem. To avoid
+ * the problem, zeroing the iommu_mm pointer of a new mm is needed here.
+ */
+ mm->iommu_mm = NULL;
}
+
static inline bool mm_valid_pasid(struct mm_struct *mm)
{
- return mm->pasid != IOMMU_PASID_INVALID;
+ return READ_ONCE(mm->iommu_mm);
+}
+
+static inline u32 mm_get_enqcmd_pasid(struct mm_struct *mm)
+{
+ struct iommu_mm_data *iommu_mm = READ_ONCE(mm->iommu_mm);
+
+ if (!iommu_mm)
+ return IOMMU_PASID_INVALID;
+ return iommu_mm->pasid;
}
+
void mm_pasid_drop(struct mm_struct *mm);
struct iommu_sva *iommu_sva_bind_device(struct device *dev,
struct mm_struct *mm);
@@ -1368,6 +1470,12 @@ static inline u32 iommu_sva_get_pasid(struct iommu_sva *handle)
}
static inline void mm_pasid_init(struct mm_struct *mm) {}
static inline bool mm_valid_pasid(struct mm_struct *mm) { return false; }
+
+static inline u32 mm_get_enqcmd_pasid(struct mm_struct *mm)
+{
+ return IOMMU_PASID_INVALID;
+}
+
static inline void mm_pasid_drop(struct mm_struct *mm) {}
#endif /* CONFIG_IOMMU_SVA */
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 4944136efaa2..7e7fd25b09b3 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -80,8 +80,8 @@
/* Two fragments for cross MMIO pages. */
#define KVM_MAX_MMIO_FRAGMENTS 2
-#ifndef KVM_ADDRESS_SPACE_NUM
-#define KVM_ADDRESS_SPACE_NUM 1
+#ifndef KVM_MAX_NR_ADDRESS_SPACES
+#define KVM_MAX_NR_ADDRESS_SPACES 1
#endif
/*
@@ -253,9 +253,10 @@ bool kvm_setup_async_pf(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu);
#endif
-#ifdef KVM_ARCH_WANT_MMU_NOTIFIER
+#ifdef CONFIG_KVM_GENERIC_MMU_NOTIFIER
union kvm_mmu_notifier_arg {
pte_t pte;
+ unsigned long attributes;
};
struct kvm_gfn_range {
@@ -588,8 +589,20 @@ struct kvm_memory_slot {
u32 flags;
short id;
u16 as_id;
+
+#ifdef CONFIG_KVM_PRIVATE_MEM
+ struct {
+ struct file __rcu *file;
+ pgoff_t pgoff;
+ } gmem;
+#endif
};
+static inline bool kvm_slot_can_be_private(const struct kvm_memory_slot *slot)
+{
+ return slot && (slot->flags & KVM_MEM_GUEST_MEMFD);
+}
+
static inline bool kvm_slot_dirty_track_enabled(const struct kvm_memory_slot *slot)
{
return slot->flags & KVM_MEM_LOG_DIRTY_PAGES;
@@ -677,13 +690,29 @@ bool kvm_arch_irqchip_in_kernel(struct kvm *kvm);
#define KVM_MEM_SLOTS_NUM SHRT_MAX
#define KVM_USER_MEM_SLOTS (KVM_MEM_SLOTS_NUM - KVM_INTERNAL_MEM_SLOTS)
-#ifndef __KVM_VCPU_MULTIPLE_ADDRESS_SPACE
+#if KVM_MAX_NR_ADDRESS_SPACES == 1
+static inline int kvm_arch_nr_memslot_as_ids(struct kvm *kvm)
+{
+ return KVM_MAX_NR_ADDRESS_SPACES;
+}
+
static inline int kvm_arch_vcpu_memslots_id(struct kvm_vcpu *vcpu)
{
return 0;
}
#endif
+/*
+ * Arch code must define kvm_arch_has_private_mem if support for private memory
+ * is enabled.
+ */
+#if !defined(kvm_arch_has_private_mem) && !IS_ENABLED(CONFIG_KVM_PRIVATE_MEM)
+static inline bool kvm_arch_has_private_mem(struct kvm *kvm)
+{
+ return false;
+}
+#endif
+
struct kvm_memslots {
u64 generation;
atomic_long_t last_used_slot;
@@ -721,9 +750,9 @@ struct kvm {
struct mm_struct *mm; /* userspace tied to this vm */
unsigned long nr_memslot_pages;
/* The two memslot sets - active and inactive (per address space) */
- struct kvm_memslots __memslots[KVM_ADDRESS_SPACE_NUM][2];
+ struct kvm_memslots __memslots[KVM_MAX_NR_ADDRESS_SPACES][2];
/* The current active memslot set for each address space */
- struct kvm_memslots __rcu *memslots[KVM_ADDRESS_SPACE_NUM];
+ struct kvm_memslots __rcu *memslots[KVM_MAX_NR_ADDRESS_SPACES];
struct xarray vcpu_array;
/*
* Protected by slots_lock, but can be read outside if an
@@ -753,7 +782,7 @@ struct kvm {
struct list_head vm_list;
struct mutex lock;
struct kvm_io_bus __rcu *buses[KVM_NR_BUSES];
-#ifdef CONFIG_HAVE_KVM_EVENTFD
+#ifdef CONFIG_HAVE_KVM_IRQCHIP
struct {
spinlock_t lock;
struct list_head items;
@@ -761,8 +790,8 @@ struct kvm {
struct list_head resampler_list;
struct mutex resampler_lock;
} irqfds;
- struct list_head ioeventfds;
#endif
+ struct list_head ioeventfds;
struct kvm_vm_stat stat;
struct kvm_arch arch;
refcount_t users_count;
@@ -778,17 +807,16 @@ struct kvm {
* Update side is protected by irq_lock.
*/
struct kvm_irq_routing_table __rcu *irq_routing;
-#endif
-#ifdef CONFIG_HAVE_KVM_IRQFD
+
struct hlist_head irq_ack_notifier_list;
#endif
-#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
+#ifdef CONFIG_KVM_GENERIC_MMU_NOTIFIER
struct mmu_notifier mmu_notifier;
unsigned long mmu_invalidate_seq;
long mmu_invalidate_in_progress;
- unsigned long mmu_invalidate_range_start;
- unsigned long mmu_invalidate_range_end;
+ gfn_t mmu_invalidate_range_start;
+ gfn_t mmu_invalidate_range_end;
#endif
struct list_head devices;
u64 manual_dirty_log_protect;
@@ -807,6 +835,10 @@ struct kvm {
#ifdef CONFIG_HAVE_KVM_PM_NOTIFIER
struct notifier_block pm_notifier;
#endif
+#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
+ /* Protected by slots_locks (for writes) and RCU (for reads) */
+ struct xarray mem_attr_array;
+#endif
char stats_id[KVM_STATS_NAME_SIZE];
};
@@ -965,7 +997,7 @@ static inline void kvm_arch_post_irq_routing_update(struct kvm *kvm)
}
#endif
-#ifdef CONFIG_HAVE_KVM_IRQFD
+#ifdef CONFIG_HAVE_KVM_IRQCHIP
int kvm_irqfd_init(void);
void kvm_irqfd_exit(void);
#else
@@ -989,7 +1021,7 @@ void kvm_put_kvm_no_destroy(struct kvm *kvm);
static inline struct kvm_memslots *__kvm_memslots(struct kvm *kvm, int as_id)
{
- as_id = array_index_nospec(as_id, KVM_ADDRESS_SPACE_NUM);
+ as_id = array_index_nospec(as_id, KVM_MAX_NR_ADDRESS_SPACES);
return srcu_dereference_check(kvm->memslots[as_id], &kvm->srcu,
lockdep_is_held(&kvm->slots_lock) ||
!refcount_read(&kvm->users_count));
@@ -1146,9 +1178,9 @@ enum kvm_mr_change {
};
int kvm_set_memory_region(struct kvm *kvm,
- const struct kvm_userspace_memory_region *mem);
+ const struct kvm_userspace_memory_region2 *mem);
int __kvm_set_memory_region(struct kvm *kvm,
- const struct kvm_userspace_memory_region *mem);
+ const struct kvm_userspace_memory_region2 *mem);
void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot);
void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen);
int kvm_arch_prepare_memory_region(struct kvm *kvm,
@@ -1392,10 +1424,10 @@ void kvm_mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc);
void *kvm_mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc);
#endif
-void kvm_mmu_invalidate_begin(struct kvm *kvm, unsigned long start,
- unsigned long end);
-void kvm_mmu_invalidate_end(struct kvm *kvm, unsigned long start,
- unsigned long end);
+void kvm_mmu_invalidate_begin(struct kvm *kvm);
+void kvm_mmu_invalidate_range_add(struct kvm *kvm, gfn_t start, gfn_t end);
+void kvm_mmu_invalidate_end(struct kvm *kvm);
+bool kvm_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range);
long kvm_arch_dev_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg);
@@ -1947,7 +1979,7 @@ extern const struct _kvm_stats_desc kvm_vm_stats_desc[];
extern const struct kvm_stats_header kvm_vcpu_stats_header;
extern const struct _kvm_stats_desc kvm_vcpu_stats_desc[];
-#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
+#ifdef CONFIG_KVM_GENERIC_MMU_NOTIFIER
static inline int mmu_invalidate_retry(struct kvm *kvm, unsigned long mmu_seq)
{
if (unlikely(kvm->mmu_invalidate_in_progress))
@@ -1970,9 +2002,9 @@ static inline int mmu_invalidate_retry(struct kvm *kvm, unsigned long mmu_seq)
return 0;
}
-static inline int mmu_invalidate_retry_hva(struct kvm *kvm,
+static inline int mmu_invalidate_retry_gfn(struct kvm *kvm,
unsigned long mmu_seq,
- unsigned long hva)
+ gfn_t gfn)
{
lockdep_assert_held(&kvm->mmu_lock);
/*
@@ -1981,10 +2013,20 @@ static inline int mmu_invalidate_retry_hva(struct kvm *kvm,
* that might be being invalidated. Note that it may include some false
* positives, due to shortcuts when handing concurrent invalidations.
*/
- if (unlikely(kvm->mmu_invalidate_in_progress) &&
- hva >= kvm->mmu_invalidate_range_start &&
- hva < kvm->mmu_invalidate_range_end)
- return 1;
+ if (unlikely(kvm->mmu_invalidate_in_progress)) {
+ /*
+ * Dropping mmu_lock after bumping mmu_invalidate_in_progress
+ * but before updating the range is a KVM bug.
+ */
+ if (WARN_ON_ONCE(kvm->mmu_invalidate_range_start == INVALID_GPA ||
+ kvm->mmu_invalidate_range_end == INVALID_GPA))
+ return 1;
+
+ if (gfn >= kvm->mmu_invalidate_range_start &&
+ gfn < kvm->mmu_invalidate_range_end)
+ return 1;
+ }
+
if (kvm->mmu_invalidate_seq != mmu_seq)
return 1;
return 0;
@@ -2013,12 +2055,10 @@ static inline void kvm_free_irq_routing(struct kvm *kvm) {}
int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
-#ifdef CONFIG_HAVE_KVM_EVENTFD
-
void kvm_eventfd_init(struct kvm *kvm);
int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args);
-#ifdef CONFIG_HAVE_KVM_IRQFD
+#ifdef CONFIG_HAVE_KVM_IRQCHIP
int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args);
void kvm_irqfd_release(struct kvm *kvm);
bool kvm_notify_irqfd_resampler(struct kvm *kvm,
@@ -2039,31 +2079,7 @@ static inline bool kvm_notify_irqfd_resampler(struct kvm *kvm,
{
return false;
}
-#endif
-
-#else
-
-static inline void kvm_eventfd_init(struct kvm *kvm) {}
-
-static inline int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)
-{
- return -EINVAL;
-}
-
-static inline void kvm_irqfd_release(struct kvm *kvm) {}
-
-#ifdef CONFIG_HAVE_KVM_IRQCHIP
-static inline void kvm_irq_routing_update(struct kvm *kvm)
-{
-}
-#endif
-
-static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
-{
- return -ENOSYS;
-}
-
-#endif /* CONFIG_HAVE_KVM_EVENTFD */
+#endif /* CONFIG_HAVE_KVM_IRQCHIP */
void kvm_arch_irq_routing_update(struct kvm *kvm);
@@ -2318,4 +2334,57 @@ static inline void kvm_account_pgtable_pages(void *virt, int nr)
/* Max number of entries allowed for each kvm dirty ring */
#define KVM_DIRTY_RING_MAX_ENTRIES 65536
+static inline void kvm_prepare_memory_fault_exit(struct kvm_vcpu *vcpu,
+ gpa_t gpa, gpa_t size,
+ bool is_write, bool is_exec,
+ bool is_private)
+{
+ vcpu->run->exit_reason = KVM_EXIT_MEMORY_FAULT;
+ vcpu->run->memory_fault.gpa = gpa;
+ vcpu->run->memory_fault.size = size;
+
+ /* RWX flags are not (yet) defined or communicated to userspace. */
+ vcpu->run->memory_fault.flags = 0;
+ if (is_private)
+ vcpu->run->memory_fault.flags |= KVM_MEMORY_EXIT_FLAG_PRIVATE;
+}
+
+#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
+static inline unsigned long kvm_get_memory_attributes(struct kvm *kvm, gfn_t gfn)
+{
+ return xa_to_value(xa_load(&kvm->mem_attr_array, gfn));
+}
+
+bool kvm_range_has_memory_attributes(struct kvm *kvm, gfn_t start, gfn_t end,
+ unsigned long attrs);
+bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm,
+ struct kvm_gfn_range *range);
+bool kvm_arch_post_set_memory_attributes(struct kvm *kvm,
+ struct kvm_gfn_range *range);
+
+static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn)
+{
+ return IS_ENABLED(CONFIG_KVM_PRIVATE_MEM) &&
+ kvm_get_memory_attributes(kvm, gfn) & KVM_MEMORY_ATTRIBUTE_PRIVATE;
+}
+#else
+static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn)
+{
+ return false;
+}
+#endif /* CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES */
+
+#ifdef CONFIG_KVM_PRIVATE_MEM
+int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
+ gfn_t gfn, kvm_pfn_t *pfn, int *max_order);
+#else
+static inline int kvm_gmem_get_pfn(struct kvm *kvm,
+ struct kvm_memory_slot *slot, gfn_t gfn,
+ kvm_pfn_t *pfn, int *max_order)
+{
+ KVM_BUG_ON(1, kvm);
+ return -EIO;
+}
+#endif /* CONFIG_KVM_PRIVATE_MEM */
+
#endif
diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
index 6f4737d5046a..9d1f7835d8c1 100644
--- a/include/linux/kvm_types.h
+++ b/include/linux/kvm_types.h
@@ -6,6 +6,7 @@
struct kvm;
struct kvm_async_pf;
struct kvm_device_ops;
+struct kvm_gfn_range;
struct kvm_interrupt;
struct kvm_irq_routing_table;
struct kvm_memory_slot;
diff --git a/include/linux/leds.h b/include/linux/leds.h
index aa16dc2a8230..4754b02d3a2c 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -527,23 +527,6 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
return led_cdev->trigger_data;
}
-/**
- * led_trigger_rename_static - rename a trigger
- * @name: the new trigger name
- * @trig: the LED trigger to rename
- *
- * Change a LED trigger name by copying the string passed in
- * name into current trigger name, which MUST be large
- * enough for the new string.
- *
- * Note that name must NOT point to the same string used
- * during LED registration, as that could lead to races.
- *
- * This is meant to be used on triggers with statically
- * allocated name.
- */
-void led_trigger_rename_static(const char *name, struct led_trigger *trig);
-
#define module_led_trigger(__led_trigger) \
module_driver(__led_trigger, led_trigger_register, \
led_trigger_unregister)
@@ -588,6 +571,9 @@ enum led_trigger_netdev_modes {
TRIGGER_NETDEV_LINK_10,
TRIGGER_NETDEV_LINK_100,
TRIGGER_NETDEV_LINK_1000,
+ TRIGGER_NETDEV_LINK_2500,
+ TRIGGER_NETDEV_LINK_5000,
+ TRIGGER_NETDEV_LINK_10000,
TRIGGER_NETDEV_HALF_DUPLEX,
TRIGGER_NETDEV_FULL_DUPLEX,
TRIGGER_NETDEV_TX,
diff --git a/include/linux/maple.h b/include/linux/maple.h
index 9b140272ee16..9aae44efcfd4 100644
--- a/include/linux/maple.h
+++ b/include/linux/maple.h
@@ -5,7 +5,6 @@
#include <mach/maple.h>
struct device;
-extern struct bus_type maple_bus_type;
/* Maple Bus command and response codes */
enum maple_code {
diff --git a/include/linux/memory-tiers.h b/include/linux/memory-tiers.h
index 1e39d27bee41..69e781900082 100644
--- a/include/linux/memory-tiers.h
+++ b/include/linux/memory-tiers.h
@@ -33,7 +33,7 @@ struct memory_dev_type {
struct kref kref;
};
-struct node_hmem_attrs;
+struct access_coordinate;
#ifdef CONFIG_NUMA
extern bool numa_demotion_enabled;
@@ -45,9 +45,9 @@ void clear_node_memory_type(int node, struct memory_dev_type *memtype);
int register_mt_adistance_algorithm(struct notifier_block *nb);
int unregister_mt_adistance_algorithm(struct notifier_block *nb);
int mt_calc_adistance(int node, int *adist);
-int mt_set_default_dram_perf(int nid, struct node_hmem_attrs *perf,
+int mt_set_default_dram_perf(int nid, struct access_coordinate *perf,
const char *source);
-int mt_perf_to_adistance(struct node_hmem_attrs *perf, int *adist);
+int mt_perf_to_adistance(struct access_coordinate *perf, int *adist);
#ifdef CONFIG_MIGRATION
int next_demotion_node(int node);
void node_get_allowed_targets(pg_data_t *pgdat, nodemask_t *targets);
@@ -126,13 +126,13 @@ static inline int mt_calc_adistance(int node, int *adist)
return NOTIFY_DONE;
}
-static inline int mt_set_default_dram_perf(int nid, struct node_hmem_attrs *perf,
+static inline int mt_set_default_dram_perf(int nid, struct access_coordinate *perf,
const char *source)
{
return -EIO;
}
-static inline int mt_perf_to_adistance(struct node_hmem_attrs *perf, int *adist)
+static inline int mt_perf_to_adistance(struct access_coordinate *perf, int *adist)
{
return -EIO;
}
diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h
index 311f7d3d2323..54444ff2a5de 100644
--- a/include/linux/mfd/max77693-private.h
+++ b/include/linux/mfd/max77693-private.h
@@ -405,7 +405,7 @@ enum max77693_haptic_reg {
MAX77693_HAPTIC_REG_END,
};
-/* max77693-pmic LSCNFG configuraton register */
+/* max77693-pmic LSCNFG configuration register */
#define MAX77693_PMIC_LOW_SYS_MASK 0x80
#define MAX77693_PMIC_LOW_SYS_SHIFT 7
diff --git a/include/linux/mfd/max77843-private.h b/include/linux/mfd/max77843-private.h
index 0bc7454c4dbe..2fb4db67f110 100644
--- a/include/linux/mfd/max77843-private.h
+++ b/include/linux/mfd/max77843-private.h
@@ -198,7 +198,7 @@ enum max77843_irq_muic {
#define MAX77843_MCONFIG_MEN_MASK BIT(MCONFIG_MEN_SHIFT)
#define MAX77843_MCONFIG_PDIV_MASK (0x3 << MCONFIG_PDIV_SHIFT)
-/* Max77843 charger insterrupts */
+/* Max77843 charger interrupts */
#define MAX77843_CHG_BYP_I BIT(0)
#define MAX77843_CHG_BATP_I BIT(2)
#define MAX77843_CHG_BAT_I BIT(3)
diff --git a/include/linux/mfd/si476x-platform.h b/include/linux/mfd/si476x-platform.h
index 18363b773d07..cb99e16ca947 100644
--- a/include/linux/mfd/si476x-platform.h
+++ b/include/linux/mfd/si476x-platform.h
@@ -10,7 +10,7 @@
#ifndef __SI476X_PLATFORM_H__
#define __SI476X_PLATFORM_H__
-/* It is possible to select one of the four adresses using pins A0
+/* It is possible to select one of the four addresses using pins A0
* and A1 on SI476x */
#define SI476X_I2C_ADDR_1 0x60
#define SI476X_I2C_ADDR_2 0x61
diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h
index 701925db75b3..f67ef0a4e041 100644
--- a/include/linux/mfd/tps65910.h
+++ b/include/linux/mfd/tps65910.h
@@ -749,7 +749,7 @@
#define VDDCTRL_ST_SHIFT 0
-/*Register VDDCTRL_OP (0x28) bit definitios */
+/*Register VDDCTRL_OP (0x28) bit definitions */
#define VDDCTRL_OP_CMD_MASK 0x80
#define VDDCTRL_OP_CMD_SHIFT 7
#define VDDCTRL_OP_SEL_MASK 0x7F
diff --git a/include/linux/mhi.h b/include/linux/mhi.h
index 039943ec4d4e..d0f9b522f328 100644
--- a/include/linux/mhi.h
+++ b/include/linux/mhi.h
@@ -266,6 +266,7 @@ struct mhi_event_config {
* struct mhi_controller_config - Root MHI controller configuration
* @max_channels: Maximum number of channels supported
* @timeout_ms: Timeout value for operations. 0 means use default
+ * @ready_timeout_ms: Timeout value for waiting device to be ready (optional)
* @buf_len: Size of automatically allocated buffers. 0 means use default
* @num_channels: Number of channels defined in @ch_cfg
* @ch_cfg: Array of defined channels
@@ -277,6 +278,7 @@ struct mhi_event_config {
struct mhi_controller_config {
u32 max_channels;
u32 timeout_ms;
+ u32 ready_timeout_ms;
u32 buf_len;
u32 num_channels;
const struct mhi_channel_config *ch_cfg;
@@ -330,6 +332,7 @@ struct mhi_controller_config {
* @pm_mutex: Mutex for suspend/resume operation
* @pm_lock: Lock for protecting MHI power management state
* @timeout_ms: Timeout in ms for state transitions
+ * @ready_timeout_ms: Timeout in ms for waiting device to be ready (optional)
* @pm_state: MHI power management state
* @db_access: DB access states
* @ee: MHI device execution environment
@@ -419,6 +422,7 @@ struct mhi_controller {
struct mutex pm_mutex;
rwlock_t pm_lock;
u32 timeout_ms;
+ u32 ready_timeout_ms;
u32 pm_state;
u32 db_access;
enum mhi_ee_type ee;
diff --git a/include/linux/mhi_ep.h b/include/linux/mhi_ep.h
index f198a8ac7ee7..11bf3212f782 100644
--- a/include/linux/mhi_ep.h
+++ b/include/linux/mhi_ep.h
@@ -50,6 +50,27 @@ struct mhi_ep_db_info {
};
/**
+ * struct mhi_ep_buf_info - MHI Endpoint transfer buffer info
+ * @mhi_dev: MHI device associated with this buffer
+ * @dev_addr: Address of the buffer in endpoint
+ * @host_addr: Address of the bufffer in host
+ * @size: Size of the buffer
+ * @code: Transfer completion code
+ * @cb: Callback to be executed by controller drivers after transfer completion (async)
+ * @cb_buf: Opaque buffer to be passed to the callback
+ */
+struct mhi_ep_buf_info {
+ struct mhi_ep_device *mhi_dev;
+ void *dev_addr;
+ u64 host_addr;
+ size_t size;
+ int code;
+
+ void (*cb)(struct mhi_ep_buf_info *buf_info);
+ void *cb_buf;
+};
+
+/**
* struct mhi_ep_cntrl - MHI Endpoint controller structure
* @cntrl_dev: Pointer to the struct device of physical bus acting as the MHI
* Endpoint controller
@@ -82,8 +103,10 @@ struct mhi_ep_db_info {
* @raise_irq: CB function for raising IRQ to the host
* @alloc_map: CB function for allocating memory in endpoint for storing host context and mapping it
* @unmap_free: CB function to unmap and free the allocated memory in endpoint for storing host context
- * @read_from_host: CB function for reading from host memory from endpoint
- * @write_to_host: CB function for writing to host memory from endpoint
+ * @read_sync: CB function for reading from host memory synchronously
+ * @write_sync: CB function for writing to host memory synchronously
+ * @read_async: CB function for reading from host memory asynchronously
+ * @write_async: CB function for writing to host memory asynchronously
* @mhi_state: MHI Endpoint state
* @max_chan: Maximum channels supported by the endpoint controller
* @mru: MRU (Maximum Receive Unit) value of the endpoint controller
@@ -128,14 +151,19 @@ struct mhi_ep_cntrl {
struct work_struct reset_work;
struct work_struct cmd_ring_work;
struct work_struct ch_ring_work;
+ struct kmem_cache *ring_item_cache;
+ struct kmem_cache *ev_ring_el_cache;
+ struct kmem_cache *tre_buf_cache;
void (*raise_irq)(struct mhi_ep_cntrl *mhi_cntrl, u32 vector);
int (*alloc_map)(struct mhi_ep_cntrl *mhi_cntrl, u64 pci_addr, phys_addr_t *phys_ptr,
void __iomem **virt, size_t size);
void (*unmap_free)(struct mhi_ep_cntrl *mhi_cntrl, u64 pci_addr, phys_addr_t phys,
void __iomem *virt, size_t size);
- int (*read_from_host)(struct mhi_ep_cntrl *mhi_cntrl, u64 from, void *to, size_t size);
- int (*write_to_host)(struct mhi_ep_cntrl *mhi_cntrl, void *from, u64 to, size_t size);
+ int (*read_sync)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info);
+ int (*write_sync)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info);
+ int (*read_async)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info);
+ int (*write_async)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info);
enum mhi_state mhi_state;
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index 7ee5b79ff3d6..8c55ff351e5f 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -691,6 +691,7 @@ enum mlx5_sw_icm_type {
MLX5_SW_ICM_TYPE_STEERING,
MLX5_SW_ICM_TYPE_HEADER_MODIFY,
MLX5_SW_ICM_TYPE_HEADER_MODIFY_PATTERN,
+ MLX5_SW_ICM_TYPE_SW_ENCAP,
};
#define MLX5_MAX_RESERVED_GIDS 8
diff --git a/include/linux/mlx5/eswitch.h b/include/linux/mlx5/eswitch.h
index 950d2431a53c..df73a2ccc9af 100644
--- a/include/linux/mlx5/eswitch.h
+++ b/include/linux/mlx5/eswitch.h
@@ -7,6 +7,7 @@
#define _MLX5_ESWITCH_
#include <linux/mlx5/driver.h>
+#include <linux/mlx5/vport.h>
#include <net/devlink.h>
#define MLX5_ESWITCH_MANAGER(mdev) MLX5_CAP_GEN(mdev, eswitch_manager)
@@ -210,4 +211,11 @@ static inline bool is_mdev_switchdev_mode(struct mlx5_core_dev *dev)
return mlx5_eswitch_mode(dev) == MLX5_ESWITCH_OFFLOADS;
}
+/* The returned number is valid only when the dev is eswitch manager. */
+static inline u16 mlx5_eswitch_manager_vport(struct mlx5_core_dev *dev)
+{
+ return mlx5_core_is_ecpf_esw_manager(dev) ?
+ MLX5_VPORT_ECPF : MLX5_VPORT_PF;
+}
+
#endif
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index fee20fc010c2..bf5320b28b8b 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -1193,7 +1193,8 @@ struct mlx5_ifc_device_mem_cap_bits {
u8 log_sw_icm_alloc_granularity[0x6];
u8 log_steering_sw_icm_size[0x8];
- u8 reserved_at_120[0x18];
+ u8 log_indirect_encap_sw_icm_size[0x8];
+ u8 reserved_at_128[0x10];
u8 log_header_modify_pattern_sw_icm_size[0x8];
u8 header_modify_sw_icm_start_address[0x40];
@@ -1204,7 +1205,11 @@ struct mlx5_ifc_device_mem_cap_bits {
u8 memic_operations[0x20];
- u8 reserved_at_220[0x5e0];
+ u8 reserved_at_220[0x20];
+
+ u8 indirect_encap_sw_icm_start_address[0x40];
+
+ u8 reserved_at_280[0x580];
};
struct mlx5_ifc_device_event_cap_bits {
@@ -1236,7 +1241,8 @@ struct mlx5_ifc_virtio_emulation_cap_bits {
u8 reserved_at_c0[0x13];
u8 desc_group_mkey_supported[0x1];
- u8 reserved_at_d4[0xc];
+ u8 freeze_to_rdy_supported[0x1];
+ u8 reserved_at_d5[0xb];
u8 reserved_at_e0[0x20];
diff --git a/include/linux/mlx5/mlx5_ifc_vdpa.h b/include/linux/mlx5/mlx5_ifc_vdpa.h
index b86d51a855f6..40371c916cf9 100644
--- a/include/linux/mlx5/mlx5_ifc_vdpa.h
+++ b/include/linux/mlx5/mlx5_ifc_vdpa.h
@@ -145,6 +145,10 @@ enum {
MLX5_VIRTQ_MODIFY_MASK_STATE = (u64)1 << 0,
MLX5_VIRTQ_MODIFY_MASK_DIRTY_BITMAP_PARAMS = (u64)1 << 3,
MLX5_VIRTQ_MODIFY_MASK_DIRTY_BITMAP_DUMP_ENABLE = (u64)1 << 4,
+ MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_ADDRS = (u64)1 << 6,
+ MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_AVAIL_IDX = (u64)1 << 7,
+ MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_USED_IDX = (u64)1 << 8,
+ MLX5_VIRTQ_MODIFY_MASK_VIRTIO_Q_MKEY = (u64)1 << 11,
MLX5_VIRTQ_MODIFY_MASK_DESC_GROUP_MKEY = (u64)1 << 14,
};
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index b2d3a88a34d1..8b611e13153e 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -730,6 +730,7 @@ struct mm_cid {
#endif
struct kioctx_table;
+struct iommu_mm_data;
struct mm_struct {
struct {
/*
@@ -941,8 +942,8 @@ struct mm_struct {
#endif
struct work_struct async_put_work;
-#ifdef CONFIG_IOMMU_SVA
- u32 pasid;
+#ifdef CONFIG_IOMMU_MM_DATA
+ struct iommu_mm_data *iommu_mm;
#endif
#ifdef CONFIG_KSM
/*
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 7b12eebc5586..f34407cc2788 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -32,6 +32,7 @@ struct mmc_csd {
unsigned int r2w_factor;
unsigned int max_dtr;
unsigned int erase_size; /* In sectors */
+ unsigned int wp_grp_size;
unsigned int read_blkbits;
unsigned int write_blkbits;
unsigned int capacity;
@@ -52,9 +53,6 @@ struct mmc_ext_csd {
u8 part_config;
u8 cache_ctrl;
u8 rst_n_function;
- u8 max_packed_writes;
- u8 max_packed_reads;
- u8 packed_event_en;
unsigned int part_time; /* Units: ms */
unsigned int sa_timeout; /* Units: 100ns */
unsigned int generic_cmd6_time; /* Units: 10ms */
@@ -306,6 +304,7 @@ struct mmc_card {
unsigned int eg_boundary; /* don't cross erase-group boundaries */
unsigned int erase_arg; /* erase / trim / discard */
u8 erased_byte; /* value of erased bytes */
+ unsigned int wp_grp_size; /* write group size in sectors */
u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 6efec0b9820c..2c7928a50907 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -27,7 +27,6 @@ struct mmc_command {
u32 opcode;
u32 arg;
#define MMC_CMD23_ARG_REL_WR (1 << 31)
-#define MMC_CMD23_ARG_PACKED ((0 << 31) | (1 << 30))
#define MMC_CMD23_ARG_TAG_REQ (1 << 29)
u32 resp[4];
unsigned int flags; /* expected response type */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 6f7993803ee7..cf2bcb5da30d 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -257,8 +257,6 @@ static inline bool mmc_ready_for_data(u32 status)
#define EXT_CSD_FLUSH_CACHE 32 /* W */
#define EXT_CSD_CACHE_CTRL 33 /* R/W */
#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */
-#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */
-#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */
#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */
#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */
#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */
@@ -321,8 +319,6 @@ static inline bool mmc_ready_for_data(u32 status)
#define EXT_CSD_SUPPORTED_MODE 493 /* RO */
#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
-#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
-#define EXT_CSD_MAX_PACKED_READS 501 /* RO */
#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */
#define EXT_CSD_HPI_FEATURES 503 /* RO */
@@ -402,18 +398,12 @@ static inline bool mmc_ready_for_data(u32 status)
#define EXT_CSD_PWR_CL_8BIT_SHIFT 4
#define EXT_CSD_PWR_CL_4BIT_SHIFT 0
-#define EXT_CSD_PACKED_EVENT_EN BIT(3)
-
/*
* EXCEPTION_EVENT_STATUS field
*/
#define EXT_CSD_URGENT_BKOPS BIT(0)
#define EXT_CSD_DYNCAP_NEEDED BIT(1)
#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2)
-#define EXT_CSD_PACKED_FAILURE BIT(3)
-
-#define EXT_CSD_PACKED_GENERIC_ERROR BIT(0)
-#define EXT_CSD_PACKED_INDEXED_ERROR BIT(1)
/*
* BKOPS status level
diff --git a/include/linux/moxtet.h b/include/linux/moxtet.h
index 79184948fab4..ac577699edfd 100644
--- a/include/linux/moxtet.h
+++ b/include/linux/moxtet.h
@@ -35,8 +35,6 @@ enum turris_mox_module_id {
#define MOXTET_NIRQS 16
-extern struct bus_type moxtet_type;
-
struct moxtet {
struct device *dev;
struct mutex lock;
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 3100371b5e32..74e0cc14ebf8 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -66,6 +66,7 @@ extern struct dentry *kern_path_create(int, const char *, struct path *, unsigne
extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
extern void done_path_create(struct path *, struct dentry *);
extern struct dentry *kern_path_locked(const char *, struct path *);
+extern struct dentry *user_path_locked_at(int , const char __user *, struct path *);
int vfs_path_parent_lookup(struct filename *filename, unsigned int flags,
struct path *parent, struct qstr *last, int *type,
const struct path *root);
diff --git a/include/linux/node.h b/include/linux/node.h
index 427a5975cf40..25b66d705ee2 100644
--- a/include/linux/node.h
+++ b/include/linux/node.h
@@ -20,14 +20,14 @@
#include <linux/list.h>
/**
- * struct node_hmem_attrs - heterogeneous memory performance attributes
+ * struct access_coordinate - generic performance coordinates container
*
* @read_bandwidth: Read bandwidth in MB/s
* @write_bandwidth: Write bandwidth in MB/s
* @read_latency: Read latency in nanoseconds
* @write_latency: Write latency in nanoseconds
*/
-struct node_hmem_attrs {
+struct access_coordinate {
unsigned int read_bandwidth;
unsigned int write_bandwidth;
unsigned int read_latency;
@@ -65,7 +65,7 @@ struct node_cache_attrs {
#ifdef CONFIG_HMEM_REPORTING
void node_add_cache(unsigned int nid, struct node_cache_attrs *cache_attrs);
-void node_set_perf_attrs(unsigned int nid, struct node_hmem_attrs *hmem_attrs,
+void node_set_perf_attrs(unsigned int nid, struct access_coordinate *coord,
unsigned access);
#else
static inline void node_add_cache(unsigned int nid,
@@ -74,7 +74,7 @@ static inline void node_add_cache(unsigned int nid,
}
static inline void node_set_perf_attrs(unsigned int nid,
- struct node_hmem_attrs *hmem_attrs,
+ struct access_coordinate *coord,
unsigned access)
{
}
diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
index 6ec4b9743e25..34c0e58dfa26 100644
--- a/include/linux/nvmem-consumer.h
+++ b/include/linux/nvmem-consumer.h
@@ -81,6 +81,7 @@ int nvmem_device_cell_write(struct nvmem_device *nvmem,
struct nvmem_cell_info *info, void *buf);
const char *nvmem_dev_name(struct nvmem_device *nvmem);
+size_t nvmem_dev_size(struct nvmem_device *nvmem);
void nvmem_add_cell_lookups(struct nvmem_cell_lookup *entries,
size_t nentries);
@@ -247,7 +248,6 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
const char *id);
struct nvmem_device *of_nvmem_device_get(struct device_node *np,
const char *name);
-struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem);
#else
static inline struct nvmem_cell *of_nvmem_cell_get(struct device_node *np,
const char *id)
@@ -260,12 +260,6 @@ static inline struct nvmem_device *of_nvmem_device_get(struct device_node *np,
{
return ERR_PTR(-EOPNOTSUPP);
}
-
-static inline struct device_node *
-of_nvmem_layout_get_container(struct nvmem_device *nvmem)
-{
- return NULL;
-}
#endif /* CONFIG_NVMEM && CONFIG_OF */
#endif /* ifndef _LINUX_NVMEM_CONSUMER_H */
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index e3930835235b..f0ba0e03218f 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -9,6 +9,7 @@
#ifndef _LINUX_NVMEM_PROVIDER_H
#define _LINUX_NVMEM_PROVIDER_H
+#include <linux/device.h>
#include <linux/device/driver.h>
#include <linux/err.h>
#include <linux/errno.h>
@@ -83,6 +84,8 @@ struct nvmem_cell_info {
* @cells: Optional array of pre-defined NVMEM cells.
* @ncells: Number of elements in cells.
* @add_legacy_fixed_of_cells: Read fixed NVMEM cells from old OF syntax.
+ * @fixup_dt_cell_info: Will be called before a cell is added. Can be
+ * used to modify the nvmem_cell_info.
* @keepout: Optional array of keepout ranges (sorted ascending by start).
* @nkeepout: Number of elements in the keepout array.
* @type: Type of the nvmem storage
@@ -113,6 +116,8 @@ struct nvmem_config {
const struct nvmem_cell_info *cells;
int ncells;
bool add_legacy_fixed_of_cells;
+ void (*fixup_dt_cell_info)(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *cell);
const struct nvmem_keepout *keepout;
unsigned int nkeepout;
enum nvmem_type type;
@@ -154,15 +159,11 @@ struct nvmem_cell_table {
/**
* struct nvmem_layout - NVMEM layout definitions
*
- * @name: Layout name.
- * @of_match_table: Open firmware match table.
+ * @dev: Device-model layout device.
+ * @nvmem: The underlying NVMEM device
* @add_cells: Will be called if a nvmem device is found which
* has this layout. The function will add layout
* specific cells with nvmem_add_one_cell().
- * @fixup_cell_info: Will be called before a cell is added. Can be
- * used to modify the nvmem_cell_info.
- * @owner: Pointer to struct module.
- * @node: List node.
*
* A nvmem device can hold a well defined structure which can just be
* evaluated during runtime. For example a TLV list, or a list of "name=val"
@@ -170,17 +171,15 @@ struct nvmem_cell_table {
* cells.
*/
struct nvmem_layout {
- const char *name;
- const struct of_device_id *of_match_table;
- int (*add_cells)(struct device *dev, struct nvmem_device *nvmem,
- struct nvmem_layout *layout);
- void (*fixup_cell_info)(struct nvmem_device *nvmem,
- struct nvmem_layout *layout,
- struct nvmem_cell_info *cell);
-
- /* private */
- struct module *owner;
- struct list_head node;
+ struct device dev;
+ struct nvmem_device *nvmem;
+ int (*add_cells)(struct nvmem_layout *layout);
+};
+
+struct nvmem_layout_driver {
+ struct device_driver driver;
+ int (*probe)(struct nvmem_layout *layout);
+ void (*remove)(struct nvmem_layout *layout);
};
#if IS_ENABLED(CONFIG_NVMEM)
@@ -197,13 +196,14 @@ void nvmem_del_cell_table(struct nvmem_cell_table *table);
int nvmem_add_one_cell(struct nvmem_device *nvmem,
const struct nvmem_cell_info *info);
-int __nvmem_layout_register(struct nvmem_layout *layout, struct module *owner);
-#define nvmem_layout_register(layout) \
- __nvmem_layout_register(layout, THIS_MODULE)
+int nvmem_layout_register(struct nvmem_layout *layout);
void nvmem_layout_unregister(struct nvmem_layout *layout);
-const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem,
- struct nvmem_layout *layout);
+int nvmem_layout_driver_register(struct nvmem_layout_driver *drv);
+void nvmem_layout_driver_unregister(struct nvmem_layout_driver *drv);
+#define module_nvmem_layout_driver(__nvmem_layout_driver) \
+ module_driver(__nvmem_layout_driver, nvmem_layout_driver_register, \
+ nvmem_layout_driver_unregister)
#else
@@ -235,17 +235,27 @@ static inline int nvmem_layout_register(struct nvmem_layout *layout)
static inline void nvmem_layout_unregister(struct nvmem_layout *layout) {}
-static inline const void *
-nvmem_layout_get_match_data(struct nvmem_device *nvmem,
- struct nvmem_layout *layout)
+#endif /* CONFIG_NVMEM */
+
+#if IS_ENABLED(CONFIG_NVMEM) && IS_ENABLED(CONFIG_OF)
+
+/**
+ * of_nvmem_layout_get_container() - Get OF node of layout container
+ *
+ * @nvmem: nvmem device
+ *
+ * Return: a node pointer with refcount incremented or NULL if no
+ * container exists. Use of_node_put() on it when done.
+ */
+struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem);
+
+#else /* CONFIG_NVMEM && CONFIG_OF */
+
+static inline struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
{
return NULL;
}
-#endif /* CONFIG_NVMEM */
-
-#define module_nvmem_layout_driver(__layout_driver) \
- module_driver(__layout_driver, nvmem_layout_register, \
- nvmem_layout_unregister)
+#endif /* CONFIG_NVMEM && CONFIG_OF */
#endif /* ifndef _LINUX_NVMEM_PROVIDER_H */
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
index 2c7a3d4bc775..a72661e47faa 100644
--- a/include/linux/of_device.h
+++ b/include/linux/of_device.h
@@ -40,6 +40,9 @@ static inline int of_dma_configure(struct device *dev,
{
return of_dma_configure_id(dev, np, force_dma, NULL);
}
+
+void of_device_make_bus_id(struct device *dev);
+
#else /* CONFIG_OF */
static inline int of_driver_match_device(struct device *dev,
@@ -82,6 +85,9 @@ static inline int of_dma_configure(struct device *dev,
{
return 0;
}
+
+static inline void of_device_make_bus_id(struct device *dev) {}
+
#endif /* CONFIG_OF */
#endif /* _LINUX_OF_DEVICE_H */
diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h
index 9a5e6b410dd2..e61cbbe12dac 100644
--- a/include/linux/of_iommu.h
+++ b/include/linux/of_iommu.h
@@ -8,20 +8,19 @@ struct iommu_ops;
#ifdef CONFIG_OF_IOMMU
-extern const struct iommu_ops *of_iommu_configure(struct device *dev,
- struct device_node *master_np,
- const u32 *id);
+extern int of_iommu_configure(struct device *dev, struct device_node *master_np,
+ const u32 *id);
extern void of_iommu_get_resv_regions(struct device *dev,
struct list_head *list);
#else
-static inline const struct iommu_ops *of_iommu_configure(struct device *dev,
- struct device_node *master_np,
- const u32 *id)
+static inline int of_iommu_configure(struct device *dev,
+ struct device_node *master_np,
+ const u32 *id)
{
- return NULL;
+ return -ENODEV;
}
static inline void of_iommu_get_resv_regions(struct device *dev,
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 06142ff7f9ce..2df35e65557d 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -206,6 +206,7 @@ enum mapping_flags {
AS_RELEASE_ALWAYS, /* Call ->release_folio(), even if no private data */
AS_STABLE_WRITES, /* must wait for writeback before modifying
folio contents */
+ AS_UNMOVABLE, /* The mapping cannot be moved, ever */
};
/**
@@ -306,6 +307,22 @@ static inline void mapping_clear_stable_writes(struct address_space *mapping)
clear_bit(AS_STABLE_WRITES, &mapping->flags);
}
+static inline void mapping_set_unmovable(struct address_space *mapping)
+{
+ /*
+ * It's expected unmovable mappings are also unevictable. Compaction
+ * migrate scanner (isolate_migratepages_block()) relies on this to
+ * reduce page locking.
+ */
+ set_bit(AS_UNEVICTABLE, &mapping->flags);
+ set_bit(AS_UNMOVABLE, &mapping->flags);
+}
+
+static inline bool mapping_unmovable(struct address_space *mapping)
+{
+ return test_bit(AS_UNMOVABLE, &mapping->flags);
+}
+
static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
{
return mapping->gfp_mask;
diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
index 6b1301e2498e..3a4860bd2758 100644
--- a/include/linux/pci-ecam.h
+++ b/include/linux/pci-ecam.h
@@ -93,6 +93,6 @@ extern const struct pci_ecam_ops loongson_pci_ecam_ops; /* Loongson PCIe */
#if IS_ENABLED(CONFIG_PCI_HOST_COMMON)
/* for DT-based PCI controllers that support ECAM */
int pci_host_common_probe(struct platform_device *pdev);
-int pci_host_common_remove(struct platform_device *pdev);
+void pci_host_common_remove(struct platform_device *pdev);
#endif
#endif
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index 5cb694031072..40ea18f5aa02 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -19,13 +19,6 @@ enum pci_epc_interface_type {
SECONDARY_INTERFACE,
};
-enum pci_epc_irq_type {
- PCI_EPC_IRQ_UNKNOWN,
- PCI_EPC_IRQ_LEGACY,
- PCI_EPC_IRQ_MSI,
- PCI_EPC_IRQ_MSIX,
-};
-
static inline const char *
pci_epc_interface_string(enum pci_epc_interface_type type)
{
@@ -79,7 +72,7 @@ struct pci_epc_ops {
u16 interrupts, enum pci_barno, u32 offset);
int (*get_msix)(struct pci_epc *epc, u8 func_no, u8 vfunc_no);
int (*raise_irq)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
- enum pci_epc_irq_type type, u16 interrupt_num);
+ unsigned int type, u16 interrupt_num);
int (*map_msi_irq)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
phys_addr_t phys_addr, u8 interrupt_num,
u32 entry_size, u32 *msi_data,
@@ -122,7 +115,7 @@ struct pci_epc_mem {
* struct pci_epc - represents the PCI EPC device
* @dev: PCI EPC device
* @pci_epf: list of endpoint functions present in this EPC device
- * list_lock: Mutex for protecting pci_epf list
+ * @list_lock: Mutex for protecting pci_epf list
* @ops: function pointers for performing endpoint operations
* @windows: array of address space of the endpoint controller
* @mem: first window of the endpoint controller, which corresponds to
@@ -229,7 +222,7 @@ int pci_epc_map_msi_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
phys_addr_t phys_addr, u8 interrupt_num,
u32 entry_size, u32 *msi_data, u32 *msi_addr_offset);
int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
- enum pci_epc_irq_type type, u16 interrupt_num);
+ unsigned int type, u16 interrupt_num);
int pci_epc_start(struct pci_epc *epc);
void pci_epc_stop(struct pci_epc *epc);
const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 3f44b6aec477..77b146e0f672 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -68,7 +68,7 @@ struct pci_epf_ops {
};
/**
- * struct pci_epf_event_ops - Callbacks for capturing the EPC events
+ * struct pci_epc_event_ops - Callbacks for capturing the EPC events
* @core_init: Callback for the EPC initialization complete event
* @link_up: Callback for the EPC link up event
* @link_down: Callback for the EPC link down event
@@ -98,7 +98,7 @@ struct pci_epf_driver {
void (*remove)(struct pci_epf *epf);
struct device_driver driver;
- struct pci_epf_ops *ops;
+ const struct pci_epf_ops *ops;
struct module *owner;
struct list_head epf_group;
const struct pci_epf_device_id *id_table;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 58a4c976c39b..add9368e6314 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -715,6 +715,7 @@ static inline bool pci_is_bridge(struct pci_dev *dev)
/**
* pci_is_vga - check if the PCI device is a VGA device
+ * @pdev: PCI device
*
* The PCI Code and ID Assignment spec, r1.15, secs 1.4 and 1.1, define
* VGA Base Class and Sub-Classes:
@@ -885,7 +886,6 @@ struct module;
/**
* struct pci_driver - PCI driver structure
- * @node: List of driver structures.
* @name: Driver name.
* @id_table: Pointer to table of device IDs the driver is
* interested in. Most drivers should export this
@@ -940,7 +940,6 @@ struct module;
* own I/O address space.
*/
struct pci_driver {
- struct list_head node;
const char *name;
const struct pci_device_id *id_table; /* Must be non-NULL for probe to be called */
int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */
@@ -1073,11 +1072,13 @@ enum {
PCI_SCAN_ALL_PCIE_DEVS = 0x00000040, /* Scan all, not just dev 0 */
};
-#define PCI_IRQ_LEGACY (1 << 0) /* Allow legacy interrupts */
+#define PCI_IRQ_INTX (1 << 0) /* Allow INTx interrupts */
#define PCI_IRQ_MSI (1 << 1) /* Allow MSI interrupts */
#define PCI_IRQ_MSIX (1 << 2) /* Allow MSI-X interrupts */
#define PCI_IRQ_AFFINITY (1 << 3) /* Auto-assign affinity */
+#define PCI_IRQ_LEGACY PCI_IRQ_INTX /* Deprecated! Use PCI_IRQ_INTX */
+
/* These external functions are only available when PCI support is enabled */
#ifdef CONFIG_PCI
@@ -1170,6 +1171,7 @@ int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge);
u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp);
struct pci_dev *pci_dev_get(struct pci_dev *dev);
void pci_dev_put(struct pci_dev *dev);
+DEFINE_FREE(pci_dev_put, struct pci_dev *, if (_T) pci_dev_put(_T))
void pci_remove_bus(struct pci_bus *b);
void pci_stop_and_remove_bus_device(struct pci_dev *dev);
void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev);
@@ -1366,6 +1368,7 @@ int pcie_set_mps(struct pci_dev *dev, int mps);
u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
enum pci_bus_speed *speed,
enum pcie_link_width *width);
+int pcie_link_speed_mbps(struct pci_dev *pdev);
void pcie_print_link_status(struct pci_dev *dev);
int pcie_reset_flr(struct pci_dev *dev, bool probe);
int pcie_flr(struct pci_dev *dev);
@@ -1876,6 +1879,7 @@ void pci_cfg_access_unlock(struct pci_dev *dev);
void pci_dev_lock(struct pci_dev *dev);
int pci_dev_trylock(struct pci_dev *dev);
void pci_dev_unlock(struct pci_dev *dev);
+DEFINE_GUARD(pci_dev, struct pci_dev *, pci_dev_lock(_T), pci_dev_unlock(_T))
/*
* PCI domain support. Sometimes called PCI segment (eg by ACPI),
@@ -2132,14 +2136,14 @@ int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma);
(pci_resource_end((dev), (bar)) ? \
resource_size(pci_resource_n((dev), (bar))) : 0)
-#define __pci_dev_for_each_res0(dev, res, ...) \
- for (unsigned int __b = 0; \
- res = pci_resource_n(dev, __b), __b < PCI_NUM_RESOURCES; \
+#define __pci_dev_for_each_res0(dev, res, ...) \
+ for (unsigned int __b = 0; \
+ __b < PCI_NUM_RESOURCES && (res = pci_resource_n(dev, __b)); \
__b++)
-#define __pci_dev_for_each_res1(dev, res, __b) \
- for (__b = 0; \
- res = pci_resource_n(dev, __b), __b < PCI_NUM_RESOURCES; \
+#define __pci_dev_for_each_res1(dev, res, __b) \
+ for (__b = 0; \
+ __b < PCI_NUM_RESOURCES && (res = pci_resource_n(dev, __b)); \
__b++)
#define pci_dev_for_each_resource(dev, res, ...) \
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 466cf477551a..f6d0e3513948 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -299,6 +299,27 @@ static inline pmd_t pmdp_get(pmd_t *pmdp)
}
#endif
+#ifndef pudp_get
+static inline pud_t pudp_get(pud_t *pudp)
+{
+ return READ_ONCE(*pudp);
+}
+#endif
+
+#ifndef p4dp_get
+static inline p4d_t p4dp_get(p4d_t *p4dp)
+{
+ return READ_ONCE(*p4dp);
+}
+#endif
+
+#ifndef pgdp_get
+static inline pgd_t pgdp_get(pgd_t *pgdp)
+{
+ return READ_ONCE(*pgdp);
+}
+#endif
+
#ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
unsigned long address,
diff --git a/include/linux/pinctrl/machine.h b/include/linux/pinctrl/machine.h
index ee8803f6ad07..673e96df453b 100644
--- a/include/linux/pinctrl/machine.h
+++ b/include/linux/pinctrl/machine.h
@@ -47,7 +47,7 @@ struct pinctrl_map_mux {
struct pinctrl_map_configs {
const char *group_or_pin;
unsigned long *configs;
- unsigned num_configs;
+ unsigned int num_configs;
};
/**
@@ -154,13 +154,13 @@ struct pinctrl_map;
#ifdef CONFIG_PINCTRL
extern int pinctrl_register_mappings(const struct pinctrl_map *map,
- unsigned num_maps);
+ unsigned int num_maps);
extern void pinctrl_unregister_mappings(const struct pinctrl_map *map);
extern void pinctrl_provide_dummies(void);
#else
static inline int pinctrl_register_mappings(const struct pinctrl_map *map,
- unsigned num_maps)
+ unsigned int num_maps)
{
return 0;
}
diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h
index d74b7a4ea154..a65d3d078e58 100644
--- a/include/linux/pinctrl/pinconf-generic.h
+++ b/include/linux/pinctrl/pinconf-generic.h
@@ -193,17 +193,17 @@ struct pinconf_generic_params {
int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
struct device_node *np, struct pinctrl_map **map,
- unsigned *reserved_maps, unsigned *num_maps,
+ unsigned int *reserved_maps, unsigned int *num_maps,
enum pinctrl_map_type type);
int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np_config, struct pinctrl_map **map,
- unsigned *num_maps, enum pinctrl_map_type type);
+ unsigned int *num_maps, enum pinctrl_map_type type);
void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev,
- struct pinctrl_map *map, unsigned num_maps);
+ struct pinctrl_map *map, unsigned int num_maps);
static inline int pinconf_generic_dt_node_to_map_group(struct pinctrl_dev *pctldev,
struct device_node *np_config, struct pinctrl_map **map,
- unsigned *num_maps)
+ unsigned int *num_maps)
{
return pinconf_generic_dt_node_to_map(pctldev, np_config, map, num_maps,
PIN_MAP_TYPE_CONFIGS_GROUP);
@@ -211,7 +211,7 @@ static inline int pinconf_generic_dt_node_to_map_group(struct pinctrl_dev *pctld
static inline int pinconf_generic_dt_node_to_map_pin(struct pinctrl_dev *pctldev,
struct device_node *np_config, struct pinctrl_map **map,
- unsigned *num_maps)
+ unsigned int *num_maps)
{
return pinconf_generic_dt_node_to_map(pctldev, np_config, map, num_maps,
PIN_MAP_TYPE_CONFIGS_PIN);
diff --git a/include/linux/pinctrl/pinconf.h b/include/linux/pinctrl/pinconf.h
index f8a8215e9021..770ec2221156 100644
--- a/include/linux/pinctrl/pinconf.h
+++ b/include/linux/pinctrl/pinconf.h
@@ -40,25 +40,25 @@ struct pinconf_ops {
bool is_generic;
#endif
int (*pin_config_get) (struct pinctrl_dev *pctldev,
- unsigned pin,
+ unsigned int pin,
unsigned long *config);
int (*pin_config_set) (struct pinctrl_dev *pctldev,
- unsigned pin,
+ unsigned int pin,
unsigned long *configs,
- unsigned num_configs);
+ unsigned int num_configs);
int (*pin_config_group_get) (struct pinctrl_dev *pctldev,
- unsigned selector,
+ unsigned int selector,
unsigned long *config);
int (*pin_config_group_set) (struct pinctrl_dev *pctldev,
- unsigned selector,
+ unsigned int selector,
unsigned long *configs,
- unsigned num_configs);
+ unsigned int num_configs);
void (*pin_config_dbg_show) (struct pinctrl_dev *pctldev,
struct seq_file *s,
- unsigned offset);
+ unsigned int offset);
void (*pin_config_group_dbg_show) (struct pinctrl_dev *pctldev,
struct seq_file *s,
- unsigned selector);
+ unsigned int selector);
void (*pin_config_config_dbg_show) (struct pinctrl_dev *pctldev,
struct seq_file *s,
unsigned long config);
diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
index 4d252ea00ed1..9a8189ffd0f2 100644
--- a/include/linux/pinctrl/pinctrl.h
+++ b/include/linux/pinctrl/pinctrl.h
@@ -54,7 +54,7 @@ struct pingroup {
* @drv_data: driver-defined per-pin data. pinctrl core does not touch this
*/
struct pinctrl_pin_desc {
- unsigned number;
+ unsigned int number;
const char *name;
void *drv_data;
};
@@ -82,7 +82,7 @@ struct pinctrl_gpio_range {
unsigned int base;
unsigned int pin_base;
unsigned int npins;
- unsigned const *pins;
+ unsigned int const *pins;
struct gpio_chip *gc;
};
@@ -108,18 +108,18 @@ struct pinctrl_gpio_range {
struct pinctrl_ops {
int (*get_groups_count) (struct pinctrl_dev *pctldev);
const char *(*get_group_name) (struct pinctrl_dev *pctldev,
- unsigned selector);
+ unsigned int selector);
int (*get_group_pins) (struct pinctrl_dev *pctldev,
- unsigned selector,
- const unsigned **pins,
- unsigned *num_pins);
+ unsigned int selector,
+ const unsigned int **pins,
+ unsigned int *num_pins);
void (*pin_dbg_show) (struct pinctrl_dev *pctldev, struct seq_file *s,
- unsigned offset);
+ unsigned int offset);
int (*dt_node_to_map) (struct pinctrl_dev *pctldev,
struct device_node *np_config,
- struct pinctrl_map **map, unsigned *num_maps);
+ struct pinctrl_map **map, unsigned int *num_maps);
void (*dt_free_map) (struct pinctrl_dev *pctldev,
- struct pinctrl_map *map, unsigned num_maps);
+ struct pinctrl_map *map, unsigned int num_maps);
};
/**
@@ -193,7 +193,7 @@ extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range);
extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *ranges,
- unsigned nranges);
+ unsigned int nranges);
extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range);
@@ -203,8 +203,8 @@ extern struct pinctrl_gpio_range *
pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
unsigned int pin);
extern int pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
- const char *pin_group, const unsigned **pins,
- unsigned *num_pins);
+ const char *pin_group, const unsigned int **pins,
+ unsigned int *num_pins);
/**
* struct pinfunction - Description about a function
diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h
index a7e370965c53..d6f7b58d6ad0 100644
--- a/include/linux/pinctrl/pinmux.h
+++ b/include/linux/pinctrl/pinmux.h
@@ -57,26 +57,26 @@ struct pinctrl_gpio_range;
* the pin request.
*/
struct pinmux_ops {
- int (*request) (struct pinctrl_dev *pctldev, unsigned offset);
- int (*free) (struct pinctrl_dev *pctldev, unsigned offset);
+ int (*request) (struct pinctrl_dev *pctldev, unsigned int offset);
+ int (*free) (struct pinctrl_dev *pctldev, unsigned int offset);
int (*get_functions_count) (struct pinctrl_dev *pctldev);
const char *(*get_function_name) (struct pinctrl_dev *pctldev,
- unsigned selector);
+ unsigned int selector);
int (*get_function_groups) (struct pinctrl_dev *pctldev,
- unsigned selector,
- const char * const **groups,
- unsigned *num_groups);
- int (*set_mux) (struct pinctrl_dev *pctldev, unsigned func_selector,
- unsigned group_selector);
+ unsigned int selector,
+ const char * const **groups,
+ unsigned int *num_groups);
+ int (*set_mux) (struct pinctrl_dev *pctldev, unsigned int func_selector,
+ unsigned int group_selector);
int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned offset);
+ unsigned int offset);
void (*gpio_disable_free) (struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned offset);
+ unsigned int offset);
int (*gpio_set_direction) (struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned offset,
+ unsigned int offset,
bool input);
bool strict;
};
diff --git a/include/linux/platform_data/si5351.h b/include/linux/platform_data/si5351.h
index c71a2dd66143..5f412a615532 100644
--- a/include/linux/platform_data/si5351.h
+++ b/include/linux/platform_data/si5351.h
@@ -105,10 +105,12 @@ struct si5351_clkout_config {
* @clk_xtal: xtal input clock
* @clk_clkin: clkin input clock
* @pll_src: array of pll source clock setting
+ * @pll_reset: array indicating if plls should be reset after setting the rate
* @clkout: array of clkout configuration
*/
struct si5351_platform_data {
enum si5351_pll_src pll_src[2];
+ bool pll_reset[2];
struct si5351_clkout_config clkout[8];
};
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 92a4f69de0e8..a2f3e53a8196 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -681,6 +681,7 @@ struct dev_pm_info {
bool wakeup_path:1;
bool syscore:1;
bool no_pm_callbacks:1; /* Owned by the PM core */
+ bool async_in_progress:1; /* Owned by the PM core */
unsigned int must_resume:1; /* Owned by the PM core */
unsigned int may_skip_resume:1; /* Set by subsystems */
#else
diff --git a/include/linux/pm_clock.h b/include/linux/pm_clock.h
index ada3a0ab10bf..68669ce18720 100644
--- a/include/linux/pm_clock.h
+++ b/include/linux/pm_clock.h
@@ -91,10 +91,10 @@ static inline int devm_pm_clk_create(struct device *dev)
#endif
#ifdef CONFIG_HAVE_CLK
-extern void pm_clk_add_notifier(struct bus_type *bus,
+extern void pm_clk_add_notifier(const struct bus_type *bus,
struct pm_clk_notifier_block *clknb);
#else
-static inline void pm_clk_add_notifier(struct bus_type *bus,
+static inline void pm_clk_add_notifier(const struct bus_type *bus,
struct pm_clk_notifier_block *clknb)
{
}
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 34663d0d5c55..b97c5e9820f9 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -118,7 +118,6 @@ struct genpd_power_state {
};
struct genpd_lock_ops;
-struct dev_pm_opp;
struct opp_table;
struct generic_pm_domain {
@@ -146,8 +145,6 @@ struct generic_pm_domain {
int (*power_on)(struct generic_pm_domain *domain);
struct raw_notifier_head power_notifiers; /* Power on/off notifiers */
struct opp_table *opp_table; /* OPP table of the genpd */
- unsigned int (*opp_to_performance_state)(struct generic_pm_domain *genpd,
- struct dev_pm_opp *opp);
int (*set_performance_state)(struct generic_pm_domain *genpd,
unsigned int state);
struct gpd_dev_ops dev_ops;
@@ -348,8 +345,6 @@ int of_genpd_remove_subdomain(struct of_phandle_args *parent_spec,
struct generic_pm_domain *of_genpd_remove_last(struct device_node *np);
int of_genpd_parse_idle_states(struct device_node *dn,
struct genpd_power_state **states, int *n);
-unsigned int pm_genpd_opp_to_performance_state(struct device *genpd_dev,
- struct dev_pm_opp *opp);
int genpd_dev_pm_attach(struct device *dev);
struct device *genpd_dev_pm_attach_by_id(struct device *dev,
@@ -395,13 +390,6 @@ static inline int of_genpd_parse_idle_states(struct device_node *dn,
return -ENODEV;
}
-static inline unsigned int
-pm_genpd_opp_to_performance_state(struct device *genpd_dev,
- struct dev_pm_opp *opp)
-{
- return 0;
-}
-
static inline int genpd_dev_pm_attach(struct device *dev)
{
return 0;
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index 267fb8a4fb6e..ddbe7c3ca4ce 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -435,7 +435,7 @@ struct pnp_protocol {
#define protocol_for_each_dev(protocol, dev) \
list_for_each_entry(dev, &(protocol)->devices, protocol_list)
-extern struct bus_type pnp_bus_type;
+extern const struct bus_type pnp_bus_type;
#if defined(CONFIG_PNP)
diff --git a/include/linux/property.h b/include/linux/property.h
index 1f1166133e6b..e6516d0b7d52 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -124,6 +124,18 @@ static inline bool device_is_compatible(const struct device *dev, const char *co
return fwnode_device_is_compatible(dev_fwnode(dev), compat);
}
+int fwnode_property_match_property_string(const struct fwnode_handle *fwnode,
+ const char *propname,
+ const char * const *array, size_t n);
+
+static inline
+int device_property_match_property_string(const struct device *dev,
+ const char *propname,
+ const char * const *array, size_t n)
+{
+ return fwnode_property_match_property_string(dev_fwnode(dev), propname, array, n);
+}
+
int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode,
const char *prop, const char *nargs_prop,
unsigned int nargs, unsigned int index,
@@ -135,6 +147,7 @@ struct fwnode_handle *fwnode_find_reference(const struct fwnode_handle *fwnode,
const char *fwnode_get_name(const struct fwnode_handle *fwnode);
const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode);
+bool fwnode_name_eq(const struct fwnode_handle *fwnode, const char *name);
struct fwnode_handle *fwnode_get_parent(const struct fwnode_handle *fwnode);
struct fwnode_handle *fwnode_get_next_parent(struct fwnode_handle *fwnode);
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index cda3597b84f2..fcc2c4496f73 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -69,7 +69,6 @@ struct pwm_state {
* @label: name of the PWM device
* @flags: flags associated with the PWM device
* @hwpwm: per-chip relative index of the PWM device
- * @pwm: global index of the PWM device
* @chip: PWM chip providing this PWM device
* @args: PWM arguments
* @state: last applied state
@@ -79,7 +78,6 @@ struct pwm_device {
const char *label;
unsigned long flags;
unsigned int hwpwm;
- unsigned int pwm;
struct pwm_chip *chip;
struct pwm_args args;
@@ -93,8 +91,8 @@ struct pwm_device {
* @state: state to fill with the current PWM state
*
* The returned PWM state represents the state that was applied by a previous call to
- * pwm_apply_state(). Drivers may have to slightly tweak that state before programming it to
- * hardware. If pwm_apply_state() was never called, this returns either the current hardware
+ * pwm_apply_might_sleep(). Drivers may have to slightly tweak that state before programming it to
+ * hardware. If pwm_apply_might_sleep() was never called, this returns either the current hardware
* state (if supported) or the default settings.
*/
static inline void pwm_get_state(const struct pwm_device *pwm,
@@ -112,12 +110,6 @@ static inline bool pwm_is_enabled(const struct pwm_device *pwm)
return state.enabled;
}
-static inline void pwm_set_period(struct pwm_device *pwm, u64 period)
-{
- if (pwm)
- pwm->state.period = period;
-}
-
static inline u64 pwm_get_period(const struct pwm_device *pwm)
{
struct pwm_state state;
@@ -127,12 +119,6 @@ static inline u64 pwm_get_period(const struct pwm_device *pwm)
return state.period;
}
-static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty)
-{
- if (pwm)
- pwm->state.duty_cycle = duty;
-}
-
static inline u64 pwm_get_duty_cycle(const struct pwm_device *pwm)
{
struct pwm_state state;
@@ -158,20 +144,20 @@ static inline void pwm_get_args(const struct pwm_device *pwm,
}
/**
- * pwm_init_state() - prepare a new state to be applied with pwm_apply_state()
+ * pwm_init_state() - prepare a new state to be applied with pwm_apply_might_sleep()
* @pwm: PWM device
* @state: state to fill with the prepared PWM state
*
* This functions prepares a state that can later be tweaked and applied
- * to the PWM device with pwm_apply_state(). This is a convenient function
+ * to the PWM device with pwm_apply_might_sleep(). This is a convenient function
* that first retrieves the current PWM state and the replaces the period
* and polarity fields with the reference values defined in pwm->args.
* Once the function returns, you can adjust the ->enabled and ->duty_cycle
- * fields according to your needs before calling pwm_apply_state().
+ * fields according to your needs before calling pwm_apply_might_sleep().
*
* ->duty_cycle is initially set to zero to avoid cases where the current
* ->duty_cycle value exceed the pwm_args->period one, which would trigger
- * an error if the user calls pwm_apply_state() without adjusting ->duty_cycle
+ * an error if the user calls pwm_apply_might_sleep() without adjusting ->duty_cycle
* first.
*/
static inline void pwm_init_state(const struct pwm_device *pwm,
@@ -227,7 +213,7 @@ pwm_get_relative_duty_cycle(const struct pwm_state *state, unsigned int scale)
*
* pwm_init_state(pwm, &state);
* pwm_set_relative_duty_cycle(&state, 50, 100);
- * pwm_apply_state(pwm, &state);
+ * pwm_apply_might_sleep(pwm, &state);
*
* This functions returns -EINVAL if @duty_cycle and/or @scale are
* inconsistent (@scale == 0 or @duty_cycle > @scale).
@@ -282,32 +268,33 @@ struct pwm_ops {
* @dev: device providing the PWMs
* @ops: callbacks for this PWM controller
* @owner: module providing this chip
- * @base: number of first PWM controlled by this chip
+ * @id: unique number of this PWM chip
* @npwm: number of PWMs controlled by this chip
* @of_xlate: request a PWM device given a device tree PWM specifier
* @of_pwm_n_cells: number of cells expected in the device tree PWM specifier
- * @list: list node for internal use
+ * @atomic: can the driver's ->apply() be called in atomic context
* @pwms: array of PWM devices allocated by the framework
*/
struct pwm_chip {
struct device *dev;
const struct pwm_ops *ops;
struct module *owner;
- int base;
+ unsigned int id;
unsigned int npwm;
struct pwm_device * (*of_xlate)(struct pwm_chip *chip,
const struct of_phandle_args *args);
unsigned int of_pwm_n_cells;
+ bool atomic;
/* only used internally by the PWM framework */
- struct list_head list;
struct pwm_device *pwms;
};
#if IS_ENABLED(CONFIG_PWM)
/* PWM user APIs */
-int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state);
+int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state);
+int pwm_apply_atomic(struct pwm_device *pwm, const struct pwm_state *state);
int pwm_adjust_config(struct pwm_device *pwm);
/**
@@ -335,7 +322,7 @@ static inline int pwm_config(struct pwm_device *pwm, int duty_ns,
state.duty_cycle = duty_ns;
state.period = period_ns;
- return pwm_apply_state(pwm, &state);
+ return pwm_apply_might_sleep(pwm, &state);
}
/**
@@ -356,7 +343,7 @@ static inline int pwm_enable(struct pwm_device *pwm)
return 0;
state.enabled = true;
- return pwm_apply_state(pwm, &state);
+ return pwm_apply_might_sleep(pwm, &state);
}
/**
@@ -375,7 +362,18 @@ static inline void pwm_disable(struct pwm_device *pwm)
return;
state.enabled = false;
- pwm_apply_state(pwm, &state);
+ pwm_apply_might_sleep(pwm, &state);
+}
+
+/**
+ * pwm_might_sleep() - is pwm_apply_atomic() supported?
+ * @pwm: PWM device
+ *
+ * Returns: false if pwm_apply_atomic() can be called from atomic context.
+ */
+static inline bool pwm_might_sleep(struct pwm_device *pwm)
+{
+ return !pwm->chip->atomic;
}
/* PWM provider APIs */
@@ -406,16 +404,27 @@ struct pwm_device *devm_fwnode_pwm_get(struct device *dev,
struct fwnode_handle *fwnode,
const char *con_id);
#else
-static inline int pwm_apply_state(struct pwm_device *pwm,
- const struct pwm_state *state)
+static inline bool pwm_might_sleep(struct pwm_device *pwm)
+{
+ return true;
+}
+
+static inline int pwm_apply_might_sleep(struct pwm_device *pwm,
+ const struct pwm_state *state)
{
might_sleep();
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
+}
+
+static inline int pwm_apply_atomic(struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ return -EOPNOTSUPP;
}
static inline int pwm_adjust_config(struct pwm_device *pwm)
{
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
static inline int pwm_config(struct pwm_device *pwm, int duty_ns,
@@ -524,7 +533,14 @@ static inline void pwm_apply_args(struct pwm_device *pwm)
state.period = pwm->args.period;
state.usage_power = false;
- pwm_apply_state(pwm, &state);
+ pwm_apply_might_sleep(pwm, &state);
+}
+
+/* only for backwards-compatibility, new code should not use this */
+static inline int pwm_apply_state(struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ return pwm_apply_might_sleep(pwm, state);
}
struct pwm_lookup {
diff --git a/include/linux/rcu_notifier.h b/include/linux/rcu_notifier.h
index ebf371364581..5640f024773b 100644
--- a/include/linux/rcu_notifier.h
+++ b/include/linux/rcu_notifier.h
@@ -13,7 +13,7 @@
#define RCU_STALL_NOTIFY_NORM 1
#define RCU_STALL_NOTIFY_EXP 2
-#ifdef CONFIG_RCU_STALL_COMMON
+#if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
#include <linux/notifier.h>
#include <linux/types.h>
@@ -21,12 +21,12 @@
int rcu_stall_chain_notifier_register(struct notifier_block *n);
int rcu_stall_chain_notifier_unregister(struct notifier_block *n);
-#else // #ifdef CONFIG_RCU_STALL_COMMON
+#else // #if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
// No RCU CPU stall warnings in Tiny RCU.
static inline int rcu_stall_chain_notifier_register(struct notifier_block *n) { return -EEXIST; }
static inline int rcu_stall_chain_notifier_unregister(struct notifier_block *n) { return -ENOENT; }
-#endif // #else // #ifdef CONFIG_RCU_STALL_COMMON
+#endif // #else // #if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
#endif /* __LINUX_RCU_NOTIFIER_H */
diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index d29740be4833..3dc1e58865f7 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -355,7 +355,7 @@ static inline void list_splice_tail_init_rcu(struct list_head *list,
})
/**
- * list_next_or_null_rcu - get the first element from a list
+ * list_next_or_null_rcu - get the next element from a list
* @head: the head for the list.
* @ptr: the list head to take the next element from.
* @type: the type of the struct this is embedded in.
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index f7206b2623c9..0746b1b0b663 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -34,9 +34,6 @@
#define ULONG_CMP_GE(a, b) (ULONG_MAX / 2 >= (a) - (b))
#define ULONG_CMP_LT(a, b) (ULONG_MAX / 2 < (a) - (b))
-#define ulong2long(a) (*(long *)(&(a)))
-#define USHORT_CMP_GE(a, b) (USHRT_MAX / 2 >= (unsigned short)((a) - (b)))
-#define USHORT_CMP_LT(a, b) (USHRT_MAX / 2 < (unsigned short)((a) - (b)))
/* Exported common interfaces */
void call_rcu(struct rcu_head *head, rcu_callback_t func);
@@ -301,6 +298,11 @@ static inline void rcu_lock_acquire(struct lockdep_map *map)
lock_acquire(map, 0, 0, 2, 0, NULL, _THIS_IP_);
}
+static inline void rcu_try_lock_acquire(struct lockdep_map *map)
+{
+ lock_acquire(map, 0, 1, 2, 0, NULL, _THIS_IP_);
+}
+
static inline void rcu_lock_release(struct lockdep_map *map)
{
lock_release(map, _THIS_IP_);
@@ -315,6 +317,7 @@ int rcu_read_lock_any_held(void);
#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
# define rcu_lock_acquire(a) do { } while (0)
+# define rcu_try_lock_acquire(a) do { } while (0)
# define rcu_lock_release(a) do { } while (0)
static inline int rcu_read_lock_held(void)
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 782e14f62201..fa802db216f9 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -141,6 +141,7 @@ int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
bool ring_buffer_iter_dropped(struct ring_buffer_iter *iter);
unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu);
+unsigned long ring_buffer_max_event_size(struct trace_buffer *buffer);
void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu);
void ring_buffer_reset_online_cpus(struct trace_buffer *buffer);
@@ -191,15 +192,24 @@ bool ring_buffer_time_stamp_abs(struct trace_buffer *buffer);
size_t ring_buffer_nr_pages(struct trace_buffer *buffer, int cpu);
size_t ring_buffer_nr_dirty_pages(struct trace_buffer *buffer, int cpu);
-void *ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu);
-void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu, void *data);
-int ring_buffer_read_page(struct trace_buffer *buffer, void **data_page,
+struct buffer_data_read_page;
+struct buffer_data_read_page *
+ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu);
+void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu,
+ struct buffer_data_read_page *page);
+int ring_buffer_read_page(struct trace_buffer *buffer,
+ struct buffer_data_read_page *data_page,
size_t len, int cpu, int full);
+void *ring_buffer_read_page_data(struct buffer_data_read_page *page);
struct trace_seq;
int ring_buffer_print_entry_header(struct trace_seq *s);
-int ring_buffer_print_page_header(struct trace_seq *s);
+int ring_buffer_print_page_header(struct trace_buffer *buffer, struct trace_seq *s);
+
+int ring_buffer_subbuf_order_get(struct trace_buffer *buffer);
+int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order);
+int ring_buffer_subbuf_size_get(struct trace_buffer *buffer);
enum ring_buffer_flags {
RB_FL_OVERWRITE = 1 << 0,
diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h
index 534038d962e4..4612ef09a0c7 100644
--- a/include/linux/rtsx_pci.h
+++ b/include/linux/rtsx_pci.h
@@ -60,6 +60,7 @@
#define SD_EXIST (1 << 16)
#define DELINK_INT GPIO0_INT
#define MS_OC_INT (1 << 23)
+#define SD_OVP_INT (1 << 23)
#define SD_OC_INT (1 << 22)
#define CARD_INT (XD_INT | MS_INT | SD_INT)
@@ -80,6 +81,7 @@
#define OC_INT_EN (1 << 23)
#define DELINK_INT_EN GPIO0_INT_EN
#define MS_OC_INT_EN (1 << 23)
+#define SD_OVP_INT_EN (1 << 23)
#define SD_OC_INT_EN (1 << 22)
#define RTSX_DUM_REG 0x1C
@@ -583,6 +585,7 @@
#define OBFF_DISABLE 0x00
#define CDRESUMECTL 0xFE52
+#define CDGW 0xFE53
#define WAKE_SEL_CTL 0xFE54
#define PCLK_CTL 0xFE55
#define PCLK_MODE_SEL 0x20
@@ -764,6 +767,9 @@
#define SD_VIO_LDO_1V8 0x40
#define SD_VIO_LDO_3V3 0x70
+#define RTS5264_AUTOLOAD_CFG2 0xFF7D
+#define RTS5264_CHIP_RST_N_SEL (1 << 6)
+
#define RTS5260_AUTOLOAD_CFG4 0xFF7F
#define RTS5260_MIMO_DISABLE 0x8A
/*RTS5261*/
@@ -1261,6 +1267,7 @@ struct rtsx_pcr {
u8 dma_error_count;
u8 ocp_stat;
u8 ocp_stat2;
+ u8 ovp_stat;
u8 rtd3_en;
};
@@ -1271,6 +1278,7 @@ struct rtsx_pcr {
#define PID_5260 0x5260
#define PID_5261 0x5261
#define PID_5228 0x5228
+#define PID_5264 0x5264
#define CHK_PCI_PID(pcr, pid) ((pcr)->pci->device == (pid))
#define PCI_VID(pcr) ((pcr)->pci->vendor)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 9a66147915b2..cdb8ea53c365 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -957,7 +957,7 @@ struct task_struct {
/* Recursion prevention for eventfd_signal() */
unsigned in_eventfd:1;
#endif
-#ifdef CONFIG_IOMMU_SVA
+#ifdef CONFIG_ARCH_HAS_CPU_PASID
unsigned pasid_activated:1;
#endif
#ifdef CONFIG_CPU_SUP_INTEL
diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index 5fb1f12c33f9..c44f4b47b945 100644
--- a/include/linux/seq_buf.h
+++ b/include/linux/seq_buf.h
@@ -22,9 +22,8 @@ struct seq_buf {
};
#define DECLARE_SEQ_BUF(NAME, SIZE) \
- char __ ## NAME ## _buffer[SIZE] = ""; \
struct seq_buf NAME = { \
- .buffer = &__ ## NAME ## _buffer, \
+ .buffer = (char[SIZE]) { 0 }, \
.size = SIZE, \
}
diff --git a/include/linux/serdev.h b/include/linux/serdev.h
index f5f97fa25e8a..3fab88ba265e 100644
--- a/include/linux/serdev.h
+++ b/include/linux/serdev.h
@@ -27,7 +27,7 @@ struct serdev_device;
* not sleep.
*/
struct serdev_device_ops {
- int (*receive_buf)(struct serdev_device *, const unsigned char *, size_t);
+ ssize_t (*receive_buf)(struct serdev_device *, const u8 *, size_t);
void (*write_wakeup)(struct serdev_device *);
};
@@ -82,7 +82,7 @@ enum serdev_parity {
* serdev controller structures
*/
struct serdev_controller_ops {
- int (*write_buf)(struct serdev_controller *, const unsigned char *, size_t);
+ ssize_t (*write_buf)(struct serdev_controller *, const u8 *, size_t);
void (*write_flush)(struct serdev_controller *);
int (*write_room)(struct serdev_controller *);
int (*open)(struct serdev_controller *);
@@ -99,12 +99,14 @@ struct serdev_controller_ops {
/**
* struct serdev_controller - interface to the serdev controller
* @dev: Driver model representation of the device.
+ * @host: Serial port hardware controller device
* @nr: number identifier for this controller/bus.
* @serdev: Pointer to slave device for this controller.
* @ops: Controller operations.
*/
struct serdev_controller {
struct device dev;
+ struct device *host;
unsigned int nr;
struct serdev_device *serdev;
const struct serdev_controller_ops *ops;
@@ -167,7 +169,9 @@ struct serdev_device *serdev_device_alloc(struct serdev_controller *);
int serdev_device_add(struct serdev_device *);
void serdev_device_remove(struct serdev_device *);
-struct serdev_controller *serdev_controller_alloc(struct device *, size_t);
+struct serdev_controller *serdev_controller_alloc(struct device *host,
+ struct device *parent,
+ size_t size);
int serdev_controller_add(struct serdev_controller *);
void serdev_controller_remove(struct serdev_controller *);
@@ -181,9 +185,9 @@ static inline void serdev_controller_write_wakeup(struct serdev_controller *ctrl
serdev->ops->write_wakeup(serdev);
}
-static inline int serdev_controller_receive_buf(struct serdev_controller *ctrl,
- const unsigned char *data,
- size_t count)
+static inline ssize_t serdev_controller_receive_buf(struct serdev_controller *ctrl,
+ const u8 *data,
+ size_t count)
{
struct serdev_device *serdev = ctrl->serdev;
@@ -200,13 +204,13 @@ void serdev_device_close(struct serdev_device *);
int devm_serdev_device_open(struct device *, struct serdev_device *);
unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int);
void serdev_device_set_flow_control(struct serdev_device *, bool);
-int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_t);
+int serdev_device_write_buf(struct serdev_device *, const u8 *, size_t);
void serdev_device_wait_until_sent(struct serdev_device *, long);
int serdev_device_get_tiocm(struct serdev_device *);
int serdev_device_set_tiocm(struct serdev_device *, int, int);
int serdev_device_break_ctl(struct serdev_device *serdev, int break_state);
void serdev_device_write_wakeup(struct serdev_device *);
-int serdev_device_write(struct serdev_device *, const unsigned char *, size_t, long);
+ssize_t serdev_device_write(struct serdev_device *, const u8 *, size_t, long);
void serdev_device_write_flush(struct serdev_device *);
int serdev_device_write_room(struct serdev_device *);
@@ -244,7 +248,7 @@ static inline unsigned int serdev_device_set_baudrate(struct serdev_device *sdev
}
static inline void serdev_device_set_flow_control(struct serdev_device *sdev, bool enable) {}
static inline int serdev_device_write_buf(struct serdev_device *serdev,
- const unsigned char *buf,
+ const u8 *buf,
size_t count)
{
return -ENODEV;
@@ -262,8 +266,9 @@ static inline int serdev_device_break_ctl(struct serdev_device *serdev, int brea
{
return -EOPNOTSUPP;
}
-static inline int serdev_device_write(struct serdev_device *sdev, const unsigned char *buf,
- size_t count, unsigned long timeout)
+static inline ssize_t serdev_device_write(struct serdev_device *sdev,
+ const u8 *buf, size_t count,
+ unsigned long timeout)
{
return -ENODEV;
}
@@ -311,11 +316,13 @@ struct tty_driver;
#ifdef CONFIG_SERIAL_DEV_CTRL_TTYPORT
struct device *serdev_tty_port_register(struct tty_port *port,
+ struct device *host,
struct device *parent,
struct tty_driver *drv, int idx);
int serdev_tty_port_unregister(struct tty_port *port);
#else
static inline struct device *serdev_tty_port_register(struct tty_port *port,
+ struct device *host,
struct device *parent,
struct tty_driver *drv, int idx)
{
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 89f7b6c63598..536b2581d3e2 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -852,9 +852,9 @@ static inline unsigned long uart_fifo_timeout(struct uart_port *port)
}
/* Base timer interval for polling */
-static inline int uart_poll_timeout(struct uart_port *port)
+static inline unsigned long uart_poll_timeout(struct uart_port *port)
{
- int timeout = uart_fifo_timeout(port);
+ unsigned long timeout = uart_fifo_timeout(port);
return timeout > 6 ? (timeout / 2 - 2) : 1;
}
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
index 2a4ce4144f9f..28e8c8bd3944 100644
--- a/include/linux/spmi.h
+++ b/include/linux/spmi.h
@@ -120,6 +120,9 @@ static inline void spmi_controller_put(struct spmi_controller *ctrl)
int spmi_controller_add(struct spmi_controller *ctrl);
void spmi_controller_remove(struct spmi_controller *ctrl);
+struct spmi_controller *devm_spmi_controller_alloc(struct device *parent, size_t size);
+int devm_spmi_controller_add(struct device *parent, struct spmi_controller *ctrl);
+
/**
* struct spmi_driver - SPMI slave device driver
* @driver: SPMI device drivers should initialize name and owner field of
diff --git a/include/linux/srcu.h b/include/linux/srcu.h
index 127ef3b2e607..236610e4a8fa 100644
--- a/include/linux/srcu.h
+++ b/include/linux/srcu.h
@@ -229,7 +229,7 @@ static inline int srcu_read_lock_nmisafe(struct srcu_struct *ssp) __acquires(ssp
srcu_check_nmi_safety(ssp, true);
retval = __srcu_read_lock_nmisafe(ssp);
- rcu_lock_acquire(&ssp->dep_map);
+ rcu_try_lock_acquire(&ssp->dep_map);
return retval;
}
diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h
index 42b249b4c24b..8cd8c38cf3f3 100644
--- a/include/linux/surface_aggregator/device.h
+++ b/include/linux/surface_aggregator/device.h
@@ -193,7 +193,6 @@ struct ssam_device_driver {
#ifdef CONFIG_SURFACE_AGGREGATOR_BUS
-extern struct bus_type ssam_bus_type;
extern const struct device_type ssam_device_type;
/**
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 5c0dbef55792..cdba4d0c6d4a 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -414,7 +414,7 @@ asmlinkage long sys_statmount(const struct mnt_id_req __user *req,
struct statmount __user *buf, size_t bufsize,
unsigned int flags);
asmlinkage long sys_listmount(const struct mnt_id_req __user *req,
- u64 __user *buf, size_t bufsize,
+ u64 __user *mnt_ids, size_t nr_mnt_ids,
unsigned int flags);
asmlinkage long sys_truncate(const char __user *path, long length);
asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index bf84595a4e86..b7a3deb372fd 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -32,6 +32,7 @@
struct thermal_zone_device;
struct thermal_cooling_device;
struct thermal_instance;
+struct thermal_debugfs;
struct thermal_attr;
enum thermal_trend {
@@ -102,7 +103,7 @@ struct thermal_cooling_device_ops {
struct thermal_cooling_device {
int id;
- char *type;
+ const char *type;
unsigned long max_state;
struct device device;
struct device_node *np;
@@ -113,6 +114,9 @@ struct thermal_cooling_device {
struct mutex lock; /* protect thermal_instances list */
struct list_head thermal_instances;
struct list_head node;
+#ifdef CONFIG_THERMAL_DEBUGFS
+ struct thermal_debugfs *debugfs;
+#endif
};
/**
@@ -189,6 +193,9 @@ struct thermal_zone_device {
struct list_head node;
struct delayed_work poll_queue;
enum thermal_notify_event notify_event;
+#ifdef CONFIG_THERMAL_DEBUGFS
+ struct thermal_debugfs *debugfs;
+#endif
bool suspended;
};
diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h
index 6151c210d987..2c835e5c41f6 100644
--- a/include/linux/thunderbolt.h
+++ b/include/linux/thunderbolt.h
@@ -86,7 +86,7 @@ struct tb {
unsigned long privdata[];
};
-extern struct bus_type tb_bus_type;
+extern const struct bus_type tb_bus_type;
extern struct device_type tb_service_type;
extern struct device_type tb_xdomain_type;
diff --git a/include/linux/trace.h b/include/linux/trace.h
index 2a70a447184c..fdcd76b7be83 100644
--- a/include/linux/trace.h
+++ b/include/linux/trace.h
@@ -51,7 +51,7 @@ int trace_array_printk(struct trace_array *tr, unsigned long ip,
const char *fmt, ...);
int trace_array_init_printk(struct trace_array *tr);
void trace_array_put(struct trace_array *tr);
-struct trace_array *trace_array_get_by_name(const char *name);
+struct trace_array *trace_array_get_by_name(const char *name, const char *systems);
int trace_array_destroy(struct trace_array *tr);
/* For osnoise tracer */
@@ -84,7 +84,7 @@ static inline int trace_array_init_printk(struct trace_array *tr)
static inline void trace_array_put(struct trace_array *tr)
{
}
-static inline struct trace_array *trace_array_get_by_name(const char *name)
+static inline struct trace_array *trace_array_get_by_name(const char *name, const char *systems)
{
return NULL;
}
diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h
index 3691e0e76a1a..9ec229dfddaa 100644
--- a/include/linux/trace_seq.h
+++ b/include/linux/trace_seq.h
@@ -8,11 +8,14 @@
/*
* Trace sequences are used to allow a function to call several other functions
- * to create a string of data to use (up to a max of PAGE_SIZE).
+ * to create a string of data to use.
*/
+#define TRACE_SEQ_BUFFER_SIZE (PAGE_SIZE * 2 - \
+ (sizeof(struct seq_buf) + sizeof(size_t) + sizeof(int)))
+
struct trace_seq {
- char buffer[PAGE_SIZE];
+ char buffer[TRACE_SEQ_BUFFER_SIZE];
struct seq_buf seq;
size_t readpos;
int full;
@@ -21,7 +24,7 @@ struct trace_seq {
static inline void
trace_seq_init(struct trace_seq *s)
{
- seq_buf_init(&s->seq, s->buffer, PAGE_SIZE);
+ seq_buf_init(&s->seq, s->buffer, TRACE_SEQ_BUFFER_SIZE);
s->full = 0;
s->readpos = 0;
}
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 4b6340ac2af2..8c76fd97d4ad 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -242,7 +242,7 @@ struct tty_struct {
void *driver_data;
spinlock_t files_lock;
int write_cnt;
- unsigned char *write_buf;
+ u8 *write_buf;
struct list_head tty_files;
@@ -393,8 +393,10 @@ extern const struct class tty_class;
* tty_kref_get - get a tty reference
* @tty: tty device
*
- * Returns: a new reference to a tty object. The caller must hold sufficient
- * locks/counts to ensure that their existing reference cannot go away
+ * Returns: a new reference to a tty object
+ *
+ * Locking: The caller must hold sufficient locks/counts to ensure that their
+ * existing reference cannot go away.
*/
static inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
{
@@ -408,8 +410,8 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout);
void stop_tty(struct tty_struct *tty);
void start_tty(struct tty_struct *tty);
void tty_write_message(struct tty_struct *tty, char *msg);
-int tty_send_xchar(struct tty_struct *tty, char ch);
-int tty_put_char(struct tty_struct *tty, unsigned char c);
+int tty_send_xchar(struct tty_struct *tty, u8 ch);
+int tty_put_char(struct tty_struct *tty, u8 c);
unsigned int tty_chars_in_buffer(struct tty_struct *tty);
unsigned int tty_write_room(struct tty_struct *tty);
void tty_driver_flush_buffer(struct tty_struct *tty);
@@ -419,6 +421,7 @@ bool tty_unthrottle_safe(struct tty_struct *tty);
int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
int tty_get_icount(struct tty_struct *tty,
struct serial_icounter_struct *icount);
+int tty_get_tiocm(struct tty_struct *tty);
int is_current_pgrp_orphaned(void);
void tty_hangup(struct tty_struct *tty);
void tty_vhangup(struct tty_struct *tty);
@@ -436,12 +439,11 @@ void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud,
* tty_get_baud_rate - get tty bit rates
* @tty: tty to query
*
- * Returns: the baud rate as an integer for this terminal. The termios lock
- * must be held by the caller and the terminal bit flags may be updated.
+ * Returns: the baud rate as an integer for this terminal
*
- * Locking: none
+ * Locking: The termios lock must be held by the caller.
*/
-static inline speed_t tty_get_baud_rate(struct tty_struct *tty)
+static inline speed_t tty_get_baud_rate(const struct tty_struct *tty)
{
return tty_termios_baud_rate(&tty->termios);
}
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 18beff0cec1a..7372124fbf90 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -72,8 +72,7 @@ struct serial_struct;
* is closed for the last time freeing up the resources. This is
* actually the second part of shutdown for routines that might sleep.
*
- * @write: ``ssize_t ()(struct tty_struct *tty, const unsigned char *buf,
- * size_t count)``
+ * @write: ``ssize_t ()(struct tty_struct *tty, const u8 *buf, size_t count)``
*
* This routine is called by the kernel to write a series (@count) of
* characters (@buf) to the @tty device. The characters may come from
@@ -85,7 +84,7 @@ struct serial_struct;
*
* Optional: Required for writable devices. May not sleep.
*
- * @put_char: ``int ()(struct tty_struct *tty, unsigned char ch)``
+ * @put_char: ``int ()(struct tty_struct *tty, u8 ch)``
*
* This routine is called by the kernel to write a single character @ch to
* the @tty device. If the kernel uses this routine, it must call the
@@ -243,7 +242,7 @@ struct serial_struct;
* Optional: If not provided, the device is assumed to have no FIFO.
* Usually correct to invoke via tty_wait_until_sent(). May sleep.
*
- * @send_xchar: ``void ()(struct tty_struct *tty, char ch)``
+ * @send_xchar: ``void ()(struct tty_struct *tty, u8 ch)``
*
* This routine is used to send a high-priority XON/XOFF character (@ch)
* to the @tty device.
@@ -375,7 +374,7 @@ struct tty_operations {
void (*flush_buffer)(struct tty_struct *tty);
void (*set_ldisc)(struct tty_struct *tty);
void (*wait_until_sent)(struct tty_struct *tty, int timeout);
- void (*send_xchar)(struct tty_struct *tty, char ch);
+ void (*send_xchar)(struct tty_struct *tty, u8 ch);
int (*tiocmget)(struct tty_struct *tty);
int (*tiocmset)(struct tty_struct *tty,
unsigned int set, unsigned int clear);
diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h
index 6b367eb17979..1b861f2100b6 100644
--- a/include/linux/tty_port.h
+++ b/include/linux/tty_port.h
@@ -114,8 +114,8 @@ struct tty_port {
unsigned char console:1;
struct mutex mutex;
struct mutex buf_mutex;
- unsigned char *xmit_buf;
- DECLARE_KFIFO_PTR(xmit_fifo, unsigned char);
+ u8 *xmit_buf;
+ DECLARE_KFIFO_PTR(xmit_fifo, u8);
unsigned int close_delay;
unsigned int closing_wait;
int drain_delay;
@@ -149,10 +149,10 @@ struct device *tty_port_register_device_attr(struct tty_port *port,
const struct attribute_group **attr_grp);
struct device *tty_port_register_device_serdev(struct tty_port *port,
struct tty_driver *driver, unsigned index,
- struct device *device);
+ struct device *host, struct device *parent);
struct device *tty_port_register_device_attr_serdev(struct tty_port *port,
struct tty_driver *driver, unsigned index,
- struct device *device, void *drvdata,
+ struct device *host, struct device *parent, void *drvdata,
const struct attribute_group **attr_grp);
void tty_port_unregister_device(struct tty_port *port,
struct tty_driver *driver, unsigned index);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 8c61643acd49..9e52179872a5 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -632,7 +632,6 @@ struct usb3_lpm_parameters {
* @reset_resume: needs reset instead of resume
* @port_is_suspended: the upstream port is suspended (L2 or U3)
* @slot_id: Slot ID assigned by xHCI
- * @removable: Device can be physically removed from this port
* @l1_params: best effor service latency for USB2 L1 LPM state, and L1 timeout.
* @u1_params: exit latencies for USB3 U1 LPM state, and hub-initiated timeout.
* @u2_params: exit latencies for USB3 U2 LPM state, and hub-initiated timeout.
@@ -1145,16 +1144,6 @@ extern ssize_t usb_store_new_id(struct usb_dynids *dynids,
extern ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf);
/**
- * struct usbdrv_wrap - wrapper for driver-model structure
- * @driver: The driver-model core driver structure.
- * @for_devices: Non-zero for device drivers, 0 for interface drivers.
- */
-struct usbdrv_wrap {
- struct device_driver driver;
- int for_devices;
-};
-
-/**
* struct usb_driver - identifies USB interface driver to usbcore
* @name: The driver name should be unique among USB drivers,
* and should normally be the same as the module name.
@@ -1194,7 +1183,7 @@ struct usbdrv_wrap {
* is bound to the driver.
* @dynids: used internally to hold the list of dynamically added device
* ids for this driver.
- * @drvwrap: Driver-model core structure wrapper.
+ * @driver: The driver-model core driver structure.
* @no_dynamic_id: if set to 1, the USB core will not allow dynamic ids to be
* added to this driver by preventing the sysfs file from being created.
* @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
@@ -1242,13 +1231,13 @@ struct usb_driver {
const struct attribute_group **dev_groups;
struct usb_dynids dynids;
- struct usbdrv_wrap drvwrap;
+ struct device_driver driver;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
unsigned int disable_hub_initiated_lpm:1;
unsigned int soft_unbind:1;
};
-#define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)
+#define to_usb_driver(d) container_of(d, struct usb_driver, driver)
/**
* struct usb_device_driver - identifies USB device driver to usbcore
@@ -1264,9 +1253,12 @@ struct usb_driver {
* module is being unloaded.
* @suspend: Called when the device is going to be suspended by the system.
* @resume: Called when the device is being resumed by the system.
+ * @choose_configuration: If non-NULL, called instead of the default
+ * usb_choose_configuration(). If this returns an error then we'll go
+ * on to call the normal usb_choose_configuration().
* @dev_groups: Attributes attached to the device that will be created once it
* is bound to the driver.
- * @drvwrap: Driver-model core structure wrapper.
+ * @driver: The driver-model core driver structure.
* @id_table: used with @match() to select better matching driver at
* probe() time.
* @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
@@ -1275,7 +1267,7 @@ struct usb_driver {
* resume and suspend functions will be called in addition to the driver's
* own, so this part of the setup does not need to be replicated.
*
- * USB drivers must provide all the fields listed above except drvwrap,
+ * USB drivers must provide all the fields listed above except driver,
* match, and id_table.
*/
struct usb_device_driver {
@@ -1287,14 +1279,17 @@ struct usb_device_driver {
int (*suspend) (struct usb_device *udev, pm_message_t message);
int (*resume) (struct usb_device *udev, pm_message_t message);
+
+ int (*choose_configuration) (struct usb_device *udev);
+
const struct attribute_group **dev_groups;
- struct usbdrv_wrap drvwrap;
+ struct device_driver driver;
const struct usb_device_id *id_table;
unsigned int supports_autosuspend:1;
unsigned int generic_subclass:1;
};
#define to_usb_device_driver(d) container_of(d, struct usb_device_driver, \
- drvwrap.driver)
+ driver)
/**
* struct usb_class_driver - identifies a USB driver that wants to use the USB major number
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 6532beb587b1..a771ccc038ac 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -236,6 +236,7 @@ struct usb_ep {
unsigned max_streams:16;
unsigned mult:2;
unsigned maxburst:5;
+ unsigned fifo_mode:1;
u8 address;
const struct usb_endpoint_descriptor *desc;
const struct usb_ss_ep_comp_descriptor *comp_desc;
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 00724b4f6e12..cd77fc6095a1 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -372,8 +372,9 @@ struct hc_driver {
* or bandwidth constraints.
*/
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
- /* Returns the hardware-chosen device address */
- int (*address_device)(struct usb_hcd *, struct usb_device *udev);
+ /* Set the hardware-chosen device address */
+ int (*address_device)(struct usb_hcd *, struct usb_device *udev,
+ unsigned int timeout_ms);
/* prepares the hardware to send commands to the device */
int (*enable_device)(struct usb_hcd *, struct usb_device *udev);
/* Notifies the HCD after a hub descriptor is fetched.
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index eeb7c2157c72..59409c1fc3de 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -72,4 +72,7 @@
/* device has endpoints that should be ignored */
#define USB_QUIRK_ENDPOINT_IGNORE BIT(15)
+/* short SET_ADDRESS request timeout */
+#define USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT BIT(16)
+
#endif /* __LINUX_USB_QUIRKS_H */
diff --git a/include/linux/usb/tcpci.h b/include/linux/usb/tcpci.h
index 83376473ac76..467e8045e9f8 100644
--- a/include/linux/usb/tcpci.h
+++ b/include/linux/usb/tcpci.h
@@ -36,7 +36,9 @@
#define TCPC_ALERT_MASK 0x12
#define TCPC_POWER_STATUS_MASK 0x14
-#define TCPC_FAULT_STATUS_MASK 0x15
+
+#define TCPC_FAULT_STATUS_MASK 0x15
+#define TCPC_FAULT_STATUS_MASK_VCONN_OC BIT(1)
#define TCPC_EXTENDED_STATUS_MASK 0x16
#define TCPC_EXTENDED_STATUS_MASK_VSAFE0V BIT(0)
@@ -104,6 +106,7 @@
#define TCPC_FAULT_STATUS 0x1f
#define TCPC_FAULT_STATUS_ALL_REG_RST_TO_DEFAULT BIT(7)
+#define TCPC_FAULT_STATUS_VCONN_OC BIT(1)
#define TCPC_ALERT_EXTENDED 0x21
diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h
index ab7ca872950b..65fac5e1f317 100644
--- a/include/linux/usb/tcpm.h
+++ b/include/linux/usb/tcpm.h
@@ -173,5 +173,6 @@ void tcpm_pd_hard_reset(struct tcpm_port *port);
void tcpm_tcpc_reset(struct tcpm_port *port);
void tcpm_port_clean(struct tcpm_port *port);
bool tcpm_port_is_toggling(struct tcpm_port *port);
+void tcpm_port_error_recovery(struct tcpm_port *port);
#endif /* __LINUX_USB_TCPM_H */
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index a65b2513f8cd..89b265bc6ec3 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -69,6 +69,13 @@ struct vfio_device {
u8 iommufd_attached:1;
#endif
u8 cdev_opened:1;
+#ifdef CONFIG_DEBUG_FS
+ /*
+ * debug_root is a static property of the vfio_device
+ * which must be set prior to registering the vfio_device.
+ */
+ struct dentry *debug_root;
+#endif
};
/**
diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h
index 562e8754869d..85e84b92751b 100644
--- a/include/linux/vfio_pci_core.h
+++ b/include/linux/vfio_pci_core.h
@@ -127,7 +127,27 @@ int vfio_pci_core_match(struct vfio_device *core_vdev, char *buf);
int vfio_pci_core_enable(struct vfio_pci_core_device *vdev);
void vfio_pci_core_disable(struct vfio_pci_core_device *vdev);
void vfio_pci_core_finish_enable(struct vfio_pci_core_device *vdev);
+int vfio_pci_core_setup_barmap(struct vfio_pci_core_device *vdev, int bar);
pci_ers_result_t vfio_pci_core_aer_err_detected(struct pci_dev *pdev,
pci_channel_state_t state);
+#define VFIO_IOWRITE_DECLATION(size) \
+int vfio_pci_core_iowrite##size(struct vfio_pci_core_device *vdev, \
+ bool test_mem, u##size val, void __iomem *io);
+
+VFIO_IOWRITE_DECLATION(8)
+VFIO_IOWRITE_DECLATION(16)
+VFIO_IOWRITE_DECLATION(32)
+#ifdef iowrite64
+VFIO_IOWRITE_DECLATION(64)
+#endif
+
+#define VFIO_IOREAD_DECLATION(size) \
+int vfio_pci_core_ioread##size(struct vfio_pci_core_device *vdev, \
+ bool test_mem, u##size *val, void __iomem *io);
+
+VFIO_IOREAD_DECLATION(8)
+VFIO_IOREAD_DECLATION(16)
+VFIO_IOREAD_DECLATION(32)
+
#endif /* VFIO_PCI_CORE_H */
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 4cc614a38376..b0201747a263 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -103,6 +103,14 @@ int virtqueue_resize(struct virtqueue *vq, u32 num,
int virtqueue_reset(struct virtqueue *vq,
void (*recycle)(struct virtqueue *vq, void *buf));
+struct virtio_admin_cmd {
+ __le16 opcode;
+ __le16 group_type;
+ __le64 group_member_id;
+ struct scatterlist *data_sg;
+ struct scatterlist *result_sg;
+};
+
/**
* struct virtio_device - representation of a device using virtio
* @index: unique position on the virtio bus
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index 2b3438de2c4d..da9b271b54db 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -93,6 +93,8 @@ typedef void vq_callback_t(struct virtqueue *);
* Returns 0 on success or error status
* If disable_vq_and_reset is set, then enable_vq_after_reset must also be
* set.
+ * @create_avq: create admin virtqueue resource.
+ * @destroy_avq: destroy admin virtqueue resource.
*/
struct virtio_config_ops {
void (*get)(struct virtio_device *vdev, unsigned offset,
@@ -120,6 +122,8 @@ struct virtio_config_ops {
struct virtio_shm_region *region, u8 id);
int (*disable_vq_and_reset)(struct virtqueue *vq);
int (*enable_vq_after_reset)(struct virtqueue *vq);
+ int (*create_avq)(struct virtio_device *vdev);
+ void (*destroy_avq)(struct virtio_device *vdev);
};
/* If driver didn't advertise the feature, it will never appear. */
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
deleted file mode 100644
index d2e2785af602..000000000000
--- a/include/linux/virtio_console.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
- * anyone can use the definitions to implement compatible drivers/servers:
- *
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of IBM nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Copyright (C) Red Hat, Inc., 2009, 2010, 2011
- * Copyright (C) Amit Shah <[email protected]>, 2009, 2010, 2011
- */
-#ifndef _LINUX_VIRTIO_CONSOLE_H
-#define _LINUX_VIRTIO_CONSOLE_H
-
-#include <uapi/linux/virtio_console.h>
-
-int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
-#endif /* _LINUX_VIRTIO_CONSOLE_H */
diff --git a/include/linux/virtio_pci_admin.h b/include/linux/virtio_pci_admin.h
new file mode 100644
index 000000000000..f4a100a0fe2e
--- /dev/null
+++ b/include/linux/virtio_pci_admin.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_VIRTIO_PCI_ADMIN_H
+#define _LINUX_VIRTIO_PCI_ADMIN_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#ifdef CONFIG_VIRTIO_PCI_ADMIN_LEGACY
+bool virtio_pci_admin_has_legacy_io(struct pci_dev *pdev);
+int virtio_pci_admin_legacy_common_io_write(struct pci_dev *pdev, u8 offset,
+ u8 size, u8 *buf);
+int virtio_pci_admin_legacy_common_io_read(struct pci_dev *pdev, u8 offset,
+ u8 size, u8 *buf);
+int virtio_pci_admin_legacy_device_io_write(struct pci_dev *pdev, u8 offset,
+ u8 size, u8 *buf);
+int virtio_pci_admin_legacy_device_io_read(struct pci_dev *pdev, u8 offset,
+ u8 size, u8 *buf);
+int virtio_pci_admin_legacy_io_notify_info(struct pci_dev *pdev,
+ u8 req_bar_flags, u8 *bar,
+ u64 *bar_offset);
+#endif
+
+#endif /* _LINUX_VIRTIO_PCI_ADMIN_H */
diff --git a/include/linux/virtio_pci_modern.h b/include/linux/virtio_pci_modern.h
index a09e13a577a9..c0b1b1ca1163 100644
--- a/include/linux/virtio_pci_modern.h
+++ b/include/linux/virtio_pci_modern.h
@@ -125,4 +125,6 @@ int vp_modern_probe(struct virtio_pci_modern_device *mdev);
void vp_modern_remove(struct virtio_pci_modern_device *mdev);
int vp_modern_get_queue_reset(struct virtio_pci_modern_device *mdev, u16 index);
void vp_modern_set_queue_reset(struct virtio_pci_modern_device *mdev, u16 index);
+u16 vp_modern_avq_num(struct virtio_pci_modern_device *mdev);
+u16 vp_modern_avq_index(struct virtio_pci_modern_device *mdev);
#endif
diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h
deleted file mode 100644
index 3495fd0dc790..000000000000
--- a/include/linux/w1-gpio.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * w1-gpio interface to platform code
- *
- * Copyright (C) 2007 Ville Syrjala <[email protected]>
- */
-#ifndef _LINUX_W1_GPIO_H
-#define _LINUX_W1_GPIO_H
-
-struct gpio_desc;
-
-/**
- * struct w1_gpio_platform_data - Platform-dependent data for w1-gpio
- */
-struct w1_gpio_platform_data {
- struct gpio_desc *gpiod;
- struct gpio_desc *pullup_gpiod;
- void (*enable_external_pullup)(int enable);
- unsigned int pullup_duration;
-};
-
-#endif /* _LINUX_W1_GPIO_H */
diff --git a/include/media/cec.h b/include/media/cec.h
index 53e4b2eb2b26..d77982685116 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -207,7 +207,20 @@ struct cec_adap_ops {
* passthrough mode.
* @log_addrs: current logical addresses
* @conn_info: current connector info
- * @tx_timeouts: number of transmit timeouts
+ * @tx_timeout_cnt: count the number of Timed Out transmits.
+ * Reset to 0 when this is reported in cec_adap_status().
+ * @tx_low_drive_cnt: count the number of Low Drive transmits.
+ * Reset to 0 when this is reported in cec_adap_status().
+ * @tx_error_cnt: count the number of Error transmits.
+ * Reset to 0 when this is reported in cec_adap_status().
+ * @tx_arb_lost_cnt: count the number of Arb Lost transmits.
+ * Reset to 0 when this is reported in cec_adap_status().
+ * @tx_low_drive_log_cnt: number of logged Low Drive transmits since the
+ * adapter was enabled. Used to avoid flooding the kernel
+ * log if this happens a lot.
+ * @tx_error_log_cnt: number of logged Error transmits since the adapter was
+ * enabled. Used to avoid flooding the kernel log if this
+ * happens a lot.
* @notifier: CEC notifier
* @pin: CEC pin status struct
* @cec_dir: debugfs cec directory
@@ -262,7 +275,12 @@ struct cec_adapter {
struct cec_log_addrs log_addrs;
struct cec_connector_info conn_info;
- u32 tx_timeouts;
+ u32 tx_timeout_cnt;
+ u32 tx_low_drive_cnt;
+ u32 tx_error_cnt;
+ u32 tx_arb_lost_cnt;
+ u32 tx_low_drive_log_cnt;
+ u32 tx_error_log_cnt;
#ifdef CONFIG_CEC_NOTIFIER
struct cec_notifier *notifier;
diff --git a/include/media/v4l2-cci.h b/include/media/v4l2-cci.h
index 0f6803e4b17e..4e96e90ee636 100644
--- a/include/media/v4l2-cci.h
+++ b/include/media/v4l2-cci.h
@@ -7,6 +7,8 @@
#ifndef _V4L2_CCI_H
#define _V4L2_CCI_H
+#include <linux/bitfield.h>
+#include <linux/bits.h>
#include <linux/types.h>
struct i2c_client;
@@ -32,12 +34,26 @@ struct cci_reg_sequence {
#define CCI_REG_ADDR_MASK GENMASK(15, 0)
#define CCI_REG_WIDTH_SHIFT 16
#define CCI_REG_WIDTH_MASK GENMASK(19, 16)
+/*
+ * Private CCI register flags, for the use of drivers.
+ */
+#define CCI_REG_PRIVATE_SHIFT 28U
+#define CCI_REG_PRIVATE_MASK GENMASK(31U, CCI_REG_PRIVATE_SHIFT)
+
+#define CCI_REG_WIDTH_BYTES(x) FIELD_GET(CCI_REG_WIDTH_MASK, x)
+#define CCI_REG_WIDTH(x) (CCI_REG_WIDTH_BYTES(x) << 3)
+#define CCI_REG_ADDR(x) FIELD_GET(CCI_REG_ADDR_MASK, x)
+#define CCI_REG_LE BIT(20)
#define CCI_REG8(x) ((1 << CCI_REG_WIDTH_SHIFT) | (x))
#define CCI_REG16(x) ((2 << CCI_REG_WIDTH_SHIFT) | (x))
#define CCI_REG24(x) ((3 << CCI_REG_WIDTH_SHIFT) | (x))
#define CCI_REG32(x) ((4 << CCI_REG_WIDTH_SHIFT) | (x))
#define CCI_REG64(x) ((8 << CCI_REG_WIDTH_SHIFT) | (x))
+#define CCI_REG16_LE(x) (CCI_REG_LE | (2U << CCI_REG_WIDTH_SHIFT) | (x))
+#define CCI_REG24_LE(x) (CCI_REG_LE | (3U << CCI_REG_WIDTH_SHIFT) | (x))
+#define CCI_REG32_LE(x) (CCI_REG_LE | (4U << CCI_REG_WIDTH_SHIFT) | (x))
+#define CCI_REG64_LE(x) (CCI_REG_LE | (8U << CCI_REG_WIDTH_SHIFT) | (x))
/**
* cci_read() - Read a value from a single CCI register
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index d278836fd9cb..acf5be24a5ca 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -425,7 +425,7 @@ __v4l2_find_nearest_size(const void *array, size_t array_size,
/**
* v4l2_g_parm_cap - helper routine for vidioc_g_parm to fill this in by
- * calling the g_frame_interval op of the given subdev. It only works
+ * calling the get_frame_interval op of the given subdev. It only works
* for V4L2_BUF_TYPE_VIDEO_CAPTURE(_MPLANE), hence the _cap in the
* function name.
*
@@ -438,7 +438,7 @@ int v4l2_g_parm_cap(struct video_device *vdev,
/**
* v4l2_s_parm_cap - helper routine for vidioc_s_parm to fill this in by
- * calling the s_frame_interval op of the given subdev. It only works
+ * calling the set_frame_interval op of the given subdev. It only works
* for V4L2_BUF_TYPE_VIDEO_CAPTURE(_MPLANE), hence the _cap in the
* function name.
*
diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h
index d6c8eb2b5201..7f1af1f7f912 100644
--- a/include/media/v4l2-mem2mem.h
+++ b/include/media/v4l2-mem2mem.h
@@ -84,6 +84,12 @@ struct v4l2_m2m_queue_ctx {
* @last_src_buf: indicate the last source buffer for draining
* @next_buf_last: next capture queud buffer will be tagged as last
* @has_stopped: indicate the device has been stopped
+ * @ignore_cap_streaming: If true, job_ready can be called even if the CAPTURE
+ * queue is not streaming. This allows firmware to
+ * analyze the bitstream header which arrives on the
+ * OUTPUT queue. The driver must implement the job_ready
+ * callback correctly to make sure that the requirements
+ * for actual decoding are met.
* @m2m_dev: opaque pointer to the internal data to handle M2M context
* @cap_q_ctx: Capture (output to memory) queue context
* @out_q_ctx: Output (input from memory) queue context
@@ -106,6 +112,7 @@ struct v4l2_m2m_ctx {
struct vb2_v4l2_buffer *last_src_buf;
bool next_buf_last;
bool has_stopped;
+ bool ignore_cap_streaming;
/* internal use only */
struct v4l2_m2m_dev *m2m_dev;
@@ -661,7 +668,7 @@ v4l2_m2m_next_dst_buf(struct v4l2_m2m_ctx *m2m_ctx)
struct vb2_v4l2_buffer *v4l2_m2m_last_buf(struct v4l2_m2m_queue_ctx *q_ctx);
/**
- * v4l2_m2m_last_src_buf() - return last destination buffer from the list of
+ * v4l2_m2m_last_src_buf() - return last source buffer from the list of
* ready buffers
*
* @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index c1f90c1223a7..a9e6b8146279 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -452,12 +452,6 @@ enum v4l2_subdev_pre_streamon_flags {
*
* @g_pixelaspect: callback to return the pixelaspect ratio.
*
- * @g_frame_interval: callback for VIDIOC_SUBDEV_G_FRAME_INTERVAL()
- * ioctl handler code.
- *
- * @s_frame_interval: callback for VIDIOC_SUBDEV_S_FRAME_INTERVAL()
- * ioctl handler code.
- *
* @s_dv_timings: Set custom dv timings in the sub device. This is used
* when sub device is capable of setting detailed timing information
* in the hardware to generate/detect the video signal.
@@ -496,10 +490,6 @@ struct v4l2_subdev_video_ops {
int (*g_input_status)(struct v4l2_subdev *sd, u32 *status);
int (*s_stream)(struct v4l2_subdev *sd, int enable);
int (*g_pixelaspect)(struct v4l2_subdev *sd, struct v4l2_fract *aspect);
- int (*g_frame_interval)(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval);
- int (*s_frame_interval)(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *interval);
int (*s_dv_timings)(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings);
int (*g_dv_timings)(struct v4l2_subdev *sd,
@@ -688,21 +678,16 @@ struct v4l2_subdev_ir_ops {
/**
* struct v4l2_subdev_pad_config - Used for storing subdev pad information.
*
- * @try_fmt: &struct v4l2_mbus_framefmt
- * @try_crop: &struct v4l2_rect to be used for crop
- * @try_compose: &struct v4l2_rect to be used for compose
- *
- * This structure only needs to be passed to the pad op if the 'which' field
- * of the main argument is set to %V4L2_SUBDEV_FORMAT_TRY. For
- * %V4L2_SUBDEV_FORMAT_ACTIVE it is safe to pass %NULL.
- *
- * Note: This struct is also used in active state, and the 'try' prefix is
- * historical and to be removed.
+ * @format: &struct v4l2_mbus_framefmt
+ * @crop: &struct v4l2_rect to be used for crop
+ * @compose: &struct v4l2_rect to be used for compose
+ * @interval: frame interval
*/
struct v4l2_subdev_pad_config {
- struct v4l2_mbus_framefmt try_fmt;
- struct v4l2_rect try_crop;
- struct v4l2_rect try_compose;
+ struct v4l2_mbus_framefmt format;
+ struct v4l2_rect crop;
+ struct v4l2_rect compose;
+ struct v4l2_fract interval;
};
/**
@@ -714,6 +699,7 @@ struct v4l2_subdev_pad_config {
* @fmt: &struct v4l2_mbus_framefmt
* @crop: &struct v4l2_rect to be used for crop
* @compose: &struct v4l2_rect to be used for compose
+ * @interval: frame interval
*
* This structure stores configuration for a stream.
*/
@@ -725,6 +711,7 @@ struct v4l2_subdev_stream_config {
struct v4l2_mbus_framefmt fmt;
struct v4l2_rect crop;
struct v4l2_rect compose;
+ struct v4l2_fract interval;
};
/**
@@ -756,6 +743,7 @@ struct v4l2_subdev_krouting {
*
* @_lock: default for 'lock'
* @lock: mutex for the state. May be replaced by the user.
+ * @sd: the sub-device which the state is related to
* @pads: &struct v4l2_subdev_pad_config array
* @routing: routing table for the subdev
* @stream_configs: stream configurations (only for V4L2_SUBDEV_FL_STREAMS)
@@ -768,6 +756,7 @@ struct v4l2_subdev_state {
/* lock for the struct v4l2_subdev_state fields */
struct mutex _lock;
struct mutex *lock;
+ struct v4l2_subdev *sd;
struct v4l2_subdev_pad_config *pads;
struct v4l2_subdev_krouting routing;
struct v4l2_subdev_stream_configs stream_configs;
@@ -776,7 +765,6 @@ struct v4l2_subdev_state {
/**
* struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations
*
- * @init_cfg: initialize the pad config to default values
* @enum_mbus_code: callback for VIDIOC_SUBDEV_ENUM_MBUS_CODE() ioctl handler
* code.
* @enum_frame_size: callback for VIDIOC_SUBDEV_ENUM_FRAME_SIZE() ioctl handler
@@ -793,6 +781,12 @@ struct v4l2_subdev_state {
*
* @set_selection: callback for VIDIOC_SUBDEV_S_SELECTION() ioctl handler code.
*
+ * @get_frame_interval: callback for VIDIOC_SUBDEV_G_FRAME_INTERVAL()
+ * ioctl handler code.
+ *
+ * @set_frame_interval: callback for VIDIOC_SUBDEV_S_FRAME_INTERVAL()
+ * ioctl handler code.
+ *
* @get_edid: callback for VIDIOC_SUBDEV_G_EDID() ioctl handler code.
*
* @set_edid: callback for VIDIOC_SUBDEV_S_EDID() ioctl handler code.
@@ -841,8 +835,6 @@ struct v4l2_subdev_state {
* directly, use v4l2_subdev_disable_streams() instead.
*/
struct v4l2_subdev_pad_ops {
- int (*init_cfg)(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state);
int (*enum_mbus_code)(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_mbus_code_enum *code);
@@ -864,6 +856,12 @@ struct v4l2_subdev_pad_ops {
int (*set_selection)(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_selection *sel);
+ int (*get_frame_interval)(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_interval *interval);
+ int (*set_frame_interval)(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_interval *interval);
int (*get_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid);
int (*set_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid);
int (*dv_timings_cap)(struct v4l2_subdev *sd,
@@ -919,6 +917,8 @@ struct v4l2_subdev_ops {
/**
* struct v4l2_subdev_internal_ops - V4L2 subdev internal ops
*
+ * @init_state: initialize the subdev state to default values
+ *
* @registered: called when this subdev is registered. When called the v4l2_dev
* field is set to the correct v4l2_device.
*
@@ -944,6 +944,8 @@ struct v4l2_subdev_ops {
* these ops.
*/
struct v4l2_subdev_internal_ops {
+ int (*init_state)(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state);
int (*registered)(struct v4l2_subdev *sd);
void (*unregistered)(struct v4l2_subdev *sd);
int (*open)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh);
@@ -1142,83 +1144,6 @@ struct v4l2_subdev_fh {
#define to_v4l2_subdev_fh(fh) \
container_of(fh, struct v4l2_subdev_fh, vfh)
-#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-
-/**
- * v4l2_subdev_get_pad_format - ancillary routine to call
- * &struct v4l2_subdev_pad_config->try_fmt
- *
- * @sd: pointer to &struct v4l2_subdev
- * @state: pointer to &struct v4l2_subdev_state
- * @pad: index of the pad in the &struct v4l2_subdev_state->pads array
- */
-static inline struct v4l2_mbus_framefmt *
-v4l2_subdev_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state,
- unsigned int pad)
-{
- if (WARN_ON(!state))
- return NULL;
- if (WARN_ON(pad >= sd->entity.num_pads))
- pad = 0;
- return &state->pads[pad].try_fmt;
-}
-
-/**
- * v4l2_subdev_get_pad_crop - ancillary routine to call
- * &struct v4l2_subdev_pad_config->try_crop
- *
- * @sd: pointer to &struct v4l2_subdev
- * @state: pointer to &struct v4l2_subdev_state.
- * @pad: index of the pad in the &struct v4l2_subdev_state->pads array.
- */
-static inline struct v4l2_rect *
-v4l2_subdev_get_pad_crop(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state,
- unsigned int pad)
-{
- if (WARN_ON(!state))
- return NULL;
- if (WARN_ON(pad >= sd->entity.num_pads))
- pad = 0;
- return &state->pads[pad].try_crop;
-}
-
-/**
- * v4l2_subdev_get_pad_compose - ancillary routine to call
- * &struct v4l2_subdev_pad_config->try_compose
- *
- * @sd: pointer to &struct v4l2_subdev
- * @state: pointer to &struct v4l2_subdev_state.
- * @pad: index of the pad in the &struct v4l2_subdev_state->pads array.
- */
-static inline struct v4l2_rect *
-v4l2_subdev_get_pad_compose(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state,
- unsigned int pad)
-{
- if (WARN_ON(!state))
- return NULL;
- if (WARN_ON(pad >= sd->entity.num_pads))
- pad = 0;
- return &state->pads[pad].try_compose;
-}
-
-/*
- * Temprary helpers until uses of v4l2_subdev_get_try_* functions have been
- * renamed
- */
-#define v4l2_subdev_get_try_format(sd, state, pad) \
- v4l2_subdev_get_pad_format(sd, state, pad)
-
-#define v4l2_subdev_get_try_crop(sd, state, pad) \
- v4l2_subdev_get_pad_crop(sd, state, pad)
-
-#define v4l2_subdev_get_try_compose(sd, state, pad) \
- v4l2_subdev_get_pad_compose(sd, state, pad)
-
-#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */
-
extern const struct v4l2_file_operations v4l2_subdev_fops;
/**
@@ -1392,88 +1317,105 @@ int __v4l2_subdev_init_finalize(struct v4l2_subdev *sd, const char *name,
*/
void v4l2_subdev_cleanup(struct v4l2_subdev *sd);
-/**
- * v4l2_subdev_lock_state() - Locks the subdev state
- * @state: The subdevice state
- *
- * Locks the given subdev state.
- *
- * The state must be unlocked with v4l2_subdev_unlock_state() after use.
+/*
+ * A macro to generate the macro or function name for sub-devices state access
+ * wrapper macros below.
*/
-static inline void v4l2_subdev_lock_state(struct v4l2_subdev_state *state)
-{
- mutex_lock(state->lock);
-}
+#define __v4l2_subdev_state_gen_call(NAME, _1, ARG, ...) \
+ __v4l2_subdev_state_get_ ## NAME ## ARG
/**
- * v4l2_subdev_unlock_state() - Unlocks the subdev state
- * @state: The subdevice state
+ * v4l2_subdev_state_get_format() - Get pointer to a stream format
+ * @state: subdevice state
+ * @pad: pad id
+ * @...: stream id (optional argument)
*
- * Unlocks the given subdev state.
+ * This returns a pointer to &struct v4l2_mbus_framefmt for the given pad +
+ * stream in the subdev state.
+ *
+ * For stream-unaware drivers the format for the corresponding pad is returned.
+ * If the pad does not exist, NULL is returned.
*/
-static inline void v4l2_subdev_unlock_state(struct v4l2_subdev_state *state)
-{
- mutex_unlock(state->lock);
-}
+/*
+ * Wrap v4l2_subdev_state_get_format(), allowing the function to be called with
+ * two or three arguments. The purpose of the __v4l2_subdev_state_get_format()
+ * macro below is to come up with the name of the function or macro to call,
+ * using the last two arguments (_stream and _pad). The selected function or
+ * macro is then called using the arguments specified by the caller. A similar
+ * arrangement is used for v4l2_subdev_state_crop() and
+ * v4l2_subdev_state_compose() below.
+ */
+#define v4l2_subdev_state_get_format(state, pad, ...) \
+ __v4l2_subdev_state_gen_call(format, ##__VA_ARGS__, , _pad) \
+ (state, pad, ##__VA_ARGS__)
+#define __v4l2_subdev_state_get_format_pad(state, pad) \
+ __v4l2_subdev_state_get_format(state, pad, 0)
+struct v4l2_mbus_framefmt *
+__v4l2_subdev_state_get_format(struct v4l2_subdev_state *state,
+ unsigned int pad, u32 stream);
/**
- * v4l2_subdev_get_unlocked_active_state() - Checks that the active subdev state
- * is unlocked and returns it
- * @sd: The subdevice
+ * v4l2_subdev_state_get_crop() - Get pointer to a stream crop rectangle
+ * @state: subdevice state
+ * @pad: pad id
+ * @...: stream id (optional argument)
*
- * Returns the active state for the subdevice, or NULL if the subdev does not
- * support active state. If the state is not NULL, calls
- * lockdep_assert_not_held() to issue a warning if the state is locked.
+ * This returns a pointer to crop rectangle for the given pad + stream in the
+ * subdev state.
*
- * This function is to be used e.g. when getting the active state for the sole
- * purpose of passing it forward, without accessing the state fields.
+ * For stream-unaware drivers the crop rectangle for the corresponding pad is
+ * returned. If the pad does not exist, NULL is returned.
*/
-static inline struct v4l2_subdev_state *
-v4l2_subdev_get_unlocked_active_state(struct v4l2_subdev *sd)
-{
- if (sd->active_state)
- lockdep_assert_not_held(sd->active_state->lock);
- return sd->active_state;
-}
+#define v4l2_subdev_state_get_crop(state, pad, ...) \
+ __v4l2_subdev_state_gen_call(crop, ##__VA_ARGS__, , _pad) \
+ (state, pad, ##__VA_ARGS__)
+#define __v4l2_subdev_state_get_crop_pad(state, pad) \
+ __v4l2_subdev_state_get_crop(state, pad, 0)
+struct v4l2_rect *
+__v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad,
+ u32 stream);
/**
- * v4l2_subdev_get_locked_active_state() - Checks that the active subdev state
- * is locked and returns it
- *
- * @sd: The subdevice
+ * v4l2_subdev_state_get_compose() - Get pointer to a stream compose rectangle
+ * @state: subdevice state
+ * @pad: pad id
+ * @...: stream id (optional argument)
*
- * Returns the active state for the subdevice, or NULL if the subdev does not
- * support active state. If the state is not NULL, calls lockdep_assert_held()
- * to issue a warning if the state is not locked.
+ * This returns a pointer to compose rectangle for the given pad + stream in the
+ * subdev state.
*
- * This function is to be used when the caller knows that the active state is
- * already locked.
+ * For stream-unaware drivers the compose rectangle for the corresponding pad is
+ * returned. If the pad does not exist, NULL is returned.
*/
-static inline struct v4l2_subdev_state *
-v4l2_subdev_get_locked_active_state(struct v4l2_subdev *sd)
-{
- if (sd->active_state)
- lockdep_assert_held(sd->active_state->lock);
- return sd->active_state;
-}
+#define v4l2_subdev_state_get_compose(state, pad, ...) \
+ __v4l2_subdev_state_gen_call(compose, ##__VA_ARGS__, , _pad) \
+ (state, pad, ##__VA_ARGS__)
+#define __v4l2_subdev_state_get_compose_pad(state, pad) \
+ __v4l2_subdev_state_get_compose(state, pad, 0)
+struct v4l2_rect *
+__v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state,
+ unsigned int pad, u32 stream);
/**
- * v4l2_subdev_lock_and_get_active_state() - Locks and returns the active subdev
- * state for the subdevice
- * @sd: The subdevice
+ * v4l2_subdev_state_get_interval() - Get pointer to a stream frame interval
+ * @state: subdevice state
+ * @pad: pad id
+ * @...: stream id (optional argument)
*
- * Returns the locked active state for the subdevice, or NULL if the subdev
- * does not support active state.
+ * This returns a pointer to the frame interval for the given pad + stream in
+ * the subdev state.
*
- * The state must be unlocked with v4l2_subdev_unlock_state() after use.
+ * For stream-unaware drivers the frame interval for the corresponding pad is
+ * returned. If the pad does not exist, NULL is returned.
*/
-static inline struct v4l2_subdev_state *
-v4l2_subdev_lock_and_get_active_state(struct v4l2_subdev *sd)
-{
- if (sd->active_state)
- v4l2_subdev_lock_state(sd->active_state);
- return sd->active_state;
-}
+#define v4l2_subdev_state_get_interval(state, pad, ...) \
+ __v4l2_subdev_state_gen_call(interval, ##__VA_ARGS__, , _pad) \
+ (state, pad, ##__VA_ARGS__)
+#define __v4l2_subdev_state_get_interval_pad(state, pad) \
+ __v4l2_subdev_state_get_interval(state, pad, 0)
+struct v4l2_fract *
+__v4l2_subdev_state_get_interval(struct v4l2_subdev_state *state,
+ unsigned int pad, u32 stream);
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
@@ -1495,6 +1437,24 @@ int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format);
/**
+ * v4l2_subdev_get_frame_interval() - Fill frame interval based on state
+ * @sd: subdevice
+ * @state: subdevice state
+ * @fi: pointer to &struct v4l2_subdev_frame_interval
+ *
+ * Fill @fi->interval field based on the information in the @fi struct.
+ *
+ * This function can be used by the subdev drivers which support active state to
+ * implement v4l2_subdev_pad_ops.get_frame_interval if the subdev driver does
+ * not need to do anything special in their get_frame_interval op.
+ *
+ * Returns 0 on success, error value otherwise.
+ */
+int v4l2_subdev_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_interval *fi);
+
+/**
* v4l2_subdev_set_routing() - Set given routing to subdev state
* @sd: The subdevice
* @state: The subdevice state
@@ -1540,52 +1500,6 @@ int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd,
const struct v4l2_mbus_framefmt *fmt);
/**
- * v4l2_subdev_state_get_stream_format() - Get pointer to a stream format
- * @state: subdevice state
- * @pad: pad id
- * @stream: stream id
- *
- * This returns a pointer to &struct v4l2_mbus_framefmt for the given pad +
- * stream in the subdev state.
- *
- * If the state does not contain the given pad + stream, NULL is returned.
- */
-struct v4l2_mbus_framefmt *
-v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state,
- unsigned int pad, u32 stream);
-
-/**
- * v4l2_subdev_state_get_stream_crop() - Get pointer to a stream crop rectangle
- * @state: subdevice state
- * @pad: pad id
- * @stream: stream id
- *
- * This returns a pointer to crop rectangle for the given pad + stream in the
- * subdev state.
- *
- * If the state does not contain the given pad + stream, NULL is returned.
- */
-struct v4l2_rect *
-v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state,
- unsigned int pad, u32 stream);
-
-/**
- * v4l2_subdev_state_get_stream_compose() - Get pointer to a stream compose
- * rectangle
- * @state: subdevice state
- * @pad: pad id
- * @stream: stream id
- *
- * This returns a pointer to compose rectangle for the given pad + stream in the
- * subdev state.
- *
- * If the state does not contain the given pad + stream, NULL is returned.
- */
-struct v4l2_rect *
-v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state,
- unsigned int pad, u32 stream);
-
-/**
* v4l2_subdev_routing_find_opposite_end() - Find the opposite stream
* @routing: routing used to find the opposite side
* @pad: pad id
@@ -1787,6 +1701,89 @@ int v4l2_subdev_s_stream_helper(struct v4l2_subdev *sd, int enable);
#endif /* CONFIG_MEDIA_CONTROLLER */
/**
+ * v4l2_subdev_lock_state() - Locks the subdev state
+ * @state: The subdevice state
+ *
+ * Locks the given subdev state.
+ *
+ * The state must be unlocked with v4l2_subdev_unlock_state() after use.
+ */
+static inline void v4l2_subdev_lock_state(struct v4l2_subdev_state *state)
+{
+ mutex_lock(state->lock);
+}
+
+/**
+ * v4l2_subdev_unlock_state() - Unlocks the subdev state
+ * @state: The subdevice state
+ *
+ * Unlocks the given subdev state.
+ */
+static inline void v4l2_subdev_unlock_state(struct v4l2_subdev_state *state)
+{
+ mutex_unlock(state->lock);
+}
+
+/**
+ * v4l2_subdev_get_unlocked_active_state() - Checks that the active subdev state
+ * is unlocked and returns it
+ * @sd: The subdevice
+ *
+ * Returns the active state for the subdevice, or NULL if the subdev does not
+ * support active state. If the state is not NULL, calls
+ * lockdep_assert_not_held() to issue a warning if the state is locked.
+ *
+ * This function is to be used e.g. when getting the active state for the sole
+ * purpose of passing it forward, without accessing the state fields.
+ */
+static inline struct v4l2_subdev_state *
+v4l2_subdev_get_unlocked_active_state(struct v4l2_subdev *sd)
+{
+ if (sd->active_state)
+ lockdep_assert_not_held(sd->active_state->lock);
+ return sd->active_state;
+}
+
+/**
+ * v4l2_subdev_get_locked_active_state() - Checks that the active subdev state
+ * is locked and returns it
+ *
+ * @sd: The subdevice
+ *
+ * Returns the active state for the subdevice, or NULL if the subdev does not
+ * support active state. If the state is not NULL, calls lockdep_assert_held()
+ * to issue a warning if the state is not locked.
+ *
+ * This function is to be used when the caller knows that the active state is
+ * already locked.
+ */
+static inline struct v4l2_subdev_state *
+v4l2_subdev_get_locked_active_state(struct v4l2_subdev *sd)
+{
+ if (sd->active_state)
+ lockdep_assert_held(sd->active_state->lock);
+ return sd->active_state;
+}
+
+/**
+ * v4l2_subdev_lock_and_get_active_state() - Locks and returns the active subdev
+ * state for the subdevice
+ * @sd: The subdevice
+ *
+ * Returns the locked active state for the subdevice, or NULL if the subdev
+ * does not support active state.
+ *
+ * The state must be unlocked with v4l2_subdev_unlock_state() after use.
+ */
+static inline struct v4l2_subdev_state *
+v4l2_subdev_lock_and_get_active_state(struct v4l2_subdev *sd)
+{
+ if (sd->active_state)
+ v4l2_subdev_lock_state(sd->active_state);
+ return sd->active_state;
+}
+
+/**
* v4l2_subdev_init - initializes the sub-device struct
*
* @sd: pointer to the &struct v4l2_subdev to be initialized
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 4b6a9d2ea372..56719a26a46c 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -402,7 +402,7 @@ struct vb2_buffer {
* by calling vb2_buffer_done() with %VB2_BUF_STATE_QUEUED.
* If you need a minimum number of buffers before you can
* start streaming, then set
- * &vb2_queue->min_buffers_needed. If that is non-zero
+ * &vb2_queue->min_queued_buffers. If that is non-zero
* then @start_streaming won't be called until at least
* that many buffers have been queued up by userspace.
* @stop_streaming: called when 'streaming' state must be disabled; driver
@@ -546,10 +546,13 @@ struct vb2_buf_ops {
* @gfp_flags: additional gfp flags used when allocating the buffers.
* Typically this is 0, but it may be e.g. %GFP_DMA or %__GFP_DMA32
* to force the buffer allocation to a specific memory zone.
- * @min_buffers_needed: the minimum number of buffers needed before
+ * @min_queued_buffers: the minimum number of queued buffers needed before
* @start_streaming can be called. Used when a DMA engine
* cannot be started unless at least this number of buffers
* have been queued into the driver.
+ * VIDIOC_REQBUFS will ensure at least @min_queued_buffers
+ * buffers will be allocated. Note that VIDIOC_CREATE_BUFS will not
+ * modify the requested buffer count.
*/
/*
* Private elements (won't appear at the uAPI book):
@@ -558,6 +561,9 @@ struct vb2_buf_ops {
* @dma_dir: DMA mapping direction.
* @bufs: videobuf2 buffer structures
* @num_buffers: number of allocated/used buffers
+ * @max_num_buffers: upper limit of number of allocated/used buffers.
+ * If set to 0 v4l2 core will change it VB2_MAX_FRAME
+ * for backward compatibility.
* @queued_list: list of buffers currently queued from userspace
* @queued_count: number of buffers queued and ready for streaming.
* @owned_by_drv_count: number of buffers owned by the driver
@@ -611,7 +617,7 @@ struct vb2_queue {
unsigned int buf_struct_size;
u32 timestamp_flags;
gfp_t gfp_flags;
- u32 min_buffers_needed;
+ u32 min_queued_buffers;
struct device *alloc_devs[VB2_MAX_PLANES];
@@ -619,8 +625,9 @@ struct vb2_queue {
struct mutex mmap_lock;
unsigned int memory;
enum dma_data_direction dma_dir;
- struct vb2_buffer *bufs[VB2_MAX_FRAME];
+ struct vb2_buffer **bufs;
unsigned int num_buffers;
+ unsigned int max_num_buffers;
struct list_head queued_list;
unsigned int queued_count;
@@ -747,7 +754,7 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q);
/**
* vb2_core_querybuf() - query video buffer information.
* @q: pointer to &struct vb2_queue with videobuf2 queue.
- * @index: id number of the buffer.
+ * @vb: pointer to struct &vb2_buffer.
* @pb: buffer struct passed from userspace.
*
* Videobuf2 core helper to implement VIDIOC_QUERYBUF() operation. It is called
@@ -759,7 +766,7 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q);
*
* Return: returns zero on success; an error code otherwise.
*/
-void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb);
+void vb2_core_querybuf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb);
/**
* vb2_core_reqbufs() - Initiate streaming.
@@ -823,7 +830,7 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
* vb2_core_prepare_buf() - Pass ownership of a buffer from userspace
* to the kernel.
* @q: pointer to &struct vb2_queue with videobuf2 queue.
- * @index: id number of the buffer.
+ * @vb: pointer to struct &vb2_buffer.
* @pb: buffer structure passed from userspace to
* &v4l2_ioctl_ops->vidioc_prepare_buf handler in driver.
*
@@ -839,13 +846,13 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
*
* Return: returns zero on success; an error code otherwise.
*/
-int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb);
+int vb2_core_prepare_buf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb);
/**
* vb2_core_qbuf() - Queue a buffer from userspace
*
* @q: pointer to &struct vb2_queue with videobuf2 queue.
- * @index: id number of the buffer
+ * @vb: pointer to struct &vb2_buffer.
* @pb: buffer structure passed from userspace to
* v4l2_ioctl_ops->vidioc_qbuf handler in driver
* @req: pointer to &struct media_request, may be NULL.
@@ -867,7 +874,7 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb);
*
* Return: returns zero on success; an error code otherwise.
*/
-int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
+int vb2_core_qbuf(struct vb2_queue *q, struct vb2_buffer *vb, void *pb,
struct media_request *req);
/**
@@ -931,7 +938,7 @@ int vb2_core_streamoff(struct vb2_queue *q, unsigned int type);
* @fd: pointer to the file descriptor associated with DMABUF
* (set by driver).
* @type: buffer type.
- * @index: id number of the buffer.
+ * @vb: pointer to struct &vb2_buffer.
* @plane: index of the plane to be exported, 0 for single plane queues
* @flags: file flags for newly created file, as defined at
* include/uapi/asm-generic/fcntl.h.
@@ -945,7 +952,7 @@ int vb2_core_streamoff(struct vb2_queue *q, unsigned int type);
* Return: returns zero on success; an error code otherwise.
*/
int vb2_core_expbuf(struct vb2_queue *q, int *fd, unsigned int type,
- unsigned int index, unsigned int plane, unsigned int flags);
+ struct vb2_buffer *vb, unsigned int plane, unsigned int flags);
/**
* vb2_core_queue_init() - initialize a videobuf2 queue
@@ -1140,6 +1147,15 @@ static inline bool vb2_fileio_is_active(struct vb2_queue *q)
}
/**
+ * vb2_get_num_buffers() - get the number of buffer in a queue
+ * @q: pointer to &struct vb2_queue with videobuf2 queue.
+ */
+static inline unsigned int vb2_get_num_buffers(struct vb2_queue *q)
+{
+ return q->num_buffers;
+}
+
+/**
* vb2_is_busy() - return busy status of the queue.
* @q: pointer to &struct vb2_queue with videobuf2 queue.
*
@@ -1147,7 +1163,7 @@ static inline bool vb2_fileio_is_active(struct vb2_queue *q)
*/
static inline bool vb2_is_busy(struct vb2_queue *q)
{
- return (q->num_buffers > 0);
+ return vb2_get_num_buffers(q) > 0;
}
/**
@@ -1239,6 +1255,12 @@ static inline void vb2_clear_last_buffer_dequeued(struct vb2_queue *q)
static inline struct vb2_buffer *vb2_get_buffer(struct vb2_queue *q,
unsigned int index)
{
+ if (!q->bufs)
+ return NULL;
+
+ if (index >= q->max_num_buffers)
+ return NULL;
+
if (index < q->num_buffers)
return q->bufs[index];
return NULL;
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 76f2fd2645b7..27684135bb4d 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -66,6 +66,7 @@ enum {
GDMA_DEVICE_NONE = 0,
GDMA_DEVICE_HWC = 1,
GDMA_DEVICE_MANA = 2,
+ GDMA_DEVICE_MANA_IB = 3,
};
struct gdma_resource {
@@ -149,6 +150,7 @@ struct gdma_general_req {
#define GDMA_MESSAGE_V1 1
#define GDMA_MESSAGE_V2 2
+#define GDMA_MESSAGE_V3 3
struct gdma_general_resp {
struct gdma_resp_hdr hdr;
@@ -390,6 +392,9 @@ struct gdma_context {
/* Azure network adapter */
struct gdma_dev mana;
+
+ /* Azure RDMA adapter */
+ struct gdma_dev mana_ib;
};
#define MAX_NUM_GDMA_DEVICES 4
diff --git a/include/soc/qcom/qcom-spmi-pmic.h b/include/soc/qcom/qcom-spmi-pmic.h
index c47cc71a999e..17a0a8c3d656 100644
--- a/include/soc/qcom/qcom-spmi-pmic.h
+++ b/include/soc/qcom/qcom-spmi-pmic.h
@@ -31,6 +31,7 @@
#define PM8998_SUBTYPE 0x14
#define PMI8998_SUBTYPE 0x15
#define PM8005_SUBTYPE 0x18
+#define PM8937_SUBTYPE 0x19
#define PM660L_SUBTYPE 0x1a
#define PM660_SUBTYPE 0x1b
#define PM8150_SUBTYPE 0x1e
diff --git a/include/trace/events/kvm.h b/include/trace/events/kvm.h
index 3bd31ea23fee..011fba6b5552 100644
--- a/include/trace/events/kvm.h
+++ b/include/trace/events/kvm.h
@@ -62,7 +62,7 @@ TRACE_EVENT(kvm_vcpu_wakeup,
__entry->valid ? "valid" : "invalid")
);
-#if defined(CONFIG_HAVE_KVM_IRQFD)
+#if defined(CONFIG_HAVE_KVM_IRQCHIP)
TRACE_EVENT(kvm_set_irq,
TP_PROTO(unsigned int gsi, int level, int irq_source_id),
TP_ARGS(gsi, level, irq_source_id),
@@ -82,7 +82,7 @@ TRACE_EVENT(kvm_set_irq,
TP_printk("gsi %u level %d source %d",
__entry->gsi, __entry->level, __entry->irq_source_id)
);
-#endif /* defined(CONFIG_HAVE_KVM_IRQFD) */
+#endif /* defined(CONFIG_HAVE_KVM_IRQCHIP) */
#if defined(__KVM_HAVE_IOAPIC)
#define kvm_deliver_mode \
@@ -170,7 +170,7 @@ TRACE_EVENT(kvm_msi_set_irq,
#endif /* defined(__KVM_HAVE_IOAPIC) */
-#if defined(CONFIG_HAVE_KVM_IRQFD)
+#if defined(CONFIG_HAVE_KVM_IRQCHIP)
#ifdef kvm_irqchips
#define kvm_ack_irq_string "irqchip %s pin %u"
@@ -197,7 +197,7 @@ TRACE_EVENT(kvm_ack_irq,
TP_printk(kvm_ack_irq_string, kvm_ack_irq_parm)
);
-#endif /* defined(CONFIG_HAVE_KVM_IRQFD) */
+#endif /* defined(CONFIG_HAVE_KVM_IRQCHIP) */
diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h
index 5f636b5afcd7..d44a8118b2ed 100644
--- a/include/uapi/linux/android/binder.h
+++ b/include/uapi/linux/android/binder.h
@@ -251,20 +251,22 @@ struct binder_extended_error {
__s32 param;
};
-#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
-#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
-#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32)
-#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
-#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
-#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
-#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
-#define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info)
-#define BINDER_GET_NODE_INFO_FOR_REF _IOWR('b', 12, struct binder_node_info_for_ref)
-#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object)
-#define BINDER_FREEZE _IOW('b', 14, struct binder_freeze_info)
-#define BINDER_GET_FROZEN_INFO _IOWR('b', 15, struct binder_frozen_status_info)
-#define BINDER_ENABLE_ONEWAY_SPAM_DETECTION _IOW('b', 16, __u32)
-#define BINDER_GET_EXTENDED_ERROR _IOWR('b', 17, struct binder_extended_error)
+enum {
+ BINDER_WRITE_READ = _IOWR('b', 1, struct binder_write_read),
+ BINDER_SET_IDLE_TIMEOUT = _IOW('b', 3, __s64),
+ BINDER_SET_MAX_THREADS = _IOW('b', 5, __u32),
+ BINDER_SET_IDLE_PRIORITY = _IOW('b', 6, __s32),
+ BINDER_SET_CONTEXT_MGR = _IOW('b', 7, __s32),
+ BINDER_THREAD_EXIT = _IOW('b', 8, __s32),
+ BINDER_VERSION = _IOWR('b', 9, struct binder_version),
+ BINDER_GET_NODE_DEBUG_INFO = _IOWR('b', 11, struct binder_node_debug_info),
+ BINDER_GET_NODE_INFO_FOR_REF = _IOWR('b', 12, struct binder_node_info_for_ref),
+ BINDER_SET_CONTEXT_MGR_EXT = _IOW('b', 13, struct flat_binder_object),
+ BINDER_FREEZE = _IOW('b', 14, struct binder_freeze_info),
+ BINDER_GET_FROZEN_INFO = _IOWR('b', 15, struct binder_frozen_status_info),
+ BINDER_ENABLE_ONEWAY_SPAM_DETECTION = _IOW('b', 16, __u32),
+ BINDER_GET_EXTENDED_ERROR = _IOWR('b', 17, struct binder_extended_error),
+};
/*
* NOTE: Two special error codes you should check for when calling
diff --git a/include/uapi/linux/cxl_mem.h b/include/uapi/linux/cxl_mem.h
index 14bc6e742148..42066f4eb890 100644
--- a/include/uapi/linux/cxl_mem.h
+++ b/include/uapi/linux/cxl_mem.h
@@ -46,6 +46,7 @@
___C(GET_SCAN_MEDIA_CAPS, "Get Scan Media Capabilities"), \
___DEPRECATED(SCAN_MEDIA, "Scan Media"), \
___DEPRECATED(GET_SCAN_MEDIA, "Get Scan Media Results"), \
+ ___C(GET_TIMESTAMP, "Get Timestamp"), \
___C(MAX, "invalid / last command")
#define ___C(a, b) CXL_MEM_COMMAND_ID_##a
diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h
index 9c2ffdcd6623..5060963707b1 100644
--- a/include/uapi/linux/iio/types.h
+++ b/include/uapi/linux/iio/types.h
@@ -91,6 +91,8 @@ enum iio_modifier {
IIO_MOD_CO2,
IIO_MOD_VOC,
IIO_MOD_LIGHT_UV,
+ IIO_MOD_LIGHT_UVA,
+ IIO_MOD_LIGHT_UVB,
IIO_MOD_LIGHT_DUV,
IIO_MOD_PM1,
IIO_MOD_PM2P5,
diff --git a/include/uapi/linux/iommufd.h b/include/uapi/linux/iommufd.h
index 0b2bc6252e2c..1dfeaa2e649e 100644
--- a/include/uapi/linux/iommufd.h
+++ b/include/uapi/linux/iommufd.h
@@ -49,6 +49,7 @@ enum {
IOMMUFD_CMD_GET_HW_INFO,
IOMMUFD_CMD_HWPT_SET_DIRTY_TRACKING,
IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP,
+ IOMMUFD_CMD_HWPT_INVALIDATE,
};
/**
@@ -613,4 +614,82 @@ struct iommu_hwpt_get_dirty_bitmap {
#define IOMMU_HWPT_GET_DIRTY_BITMAP _IO(IOMMUFD_TYPE, \
IOMMUFD_CMD_HWPT_GET_DIRTY_BITMAP)
+/**
+ * enum iommu_hwpt_invalidate_data_type - IOMMU HWPT Cache Invalidation
+ * Data Type
+ * @IOMMU_HWPT_INVALIDATE_DATA_VTD_S1: Invalidation data for VTD_S1
+ */
+enum iommu_hwpt_invalidate_data_type {
+ IOMMU_HWPT_INVALIDATE_DATA_VTD_S1,
+};
+
+/**
+ * enum iommu_hwpt_vtd_s1_invalidate_flags - Flags for Intel VT-d
+ * stage-1 cache invalidation
+ * @IOMMU_VTD_INV_FLAGS_LEAF: Indicates whether the invalidation applies
+ * to all-levels page structure cache or just
+ * the leaf PTE cache.
+ */
+enum iommu_hwpt_vtd_s1_invalidate_flags {
+ IOMMU_VTD_INV_FLAGS_LEAF = 1 << 0,
+};
+
+/**
+ * struct iommu_hwpt_vtd_s1_invalidate - Intel VT-d cache invalidation
+ * (IOMMU_HWPT_INVALIDATE_DATA_VTD_S1)
+ * @addr: The start address of the range to be invalidated. It needs to
+ * be 4KB aligned.
+ * @npages: Number of contiguous 4K pages to be invalidated.
+ * @flags: Combination of enum iommu_hwpt_vtd_s1_invalidate_flags
+ * @__reserved: Must be 0
+ *
+ * The Intel VT-d specific invalidation data for user-managed stage-1 cache
+ * invalidation in nested translation. Userspace uses this structure to
+ * tell the impacted cache scope after modifying the stage-1 page table.
+ *
+ * Invalidating all the caches related to the page table by setting @addr
+ * to be 0 and @npages to be U64_MAX.
+ *
+ * The device TLB will be invalidated automatically if ATS is enabled.
+ */
+struct iommu_hwpt_vtd_s1_invalidate {
+ __aligned_u64 addr;
+ __aligned_u64 npages;
+ __u32 flags;
+ __u32 __reserved;
+};
+
+/**
+ * struct iommu_hwpt_invalidate - ioctl(IOMMU_HWPT_INVALIDATE)
+ * @size: sizeof(struct iommu_hwpt_invalidate)
+ * @hwpt_id: ID of a nested HWPT for cache invalidation
+ * @data_uptr: User pointer to an array of driver-specific cache invalidation
+ * data.
+ * @data_type: One of enum iommu_hwpt_invalidate_data_type, defining the data
+ * type of all the entries in the invalidation request array. It
+ * should be a type supported by the hwpt pointed by @hwpt_id.
+ * @entry_len: Length (in bytes) of a request entry in the request array
+ * @entry_num: Input the number of cache invalidation requests in the array.
+ * Output the number of requests successfully handled by kernel.
+ * @__reserved: Must be 0.
+ *
+ * Invalidate the iommu cache for user-managed page table. Modifications on a
+ * user-managed page table should be followed by this operation to sync cache.
+ * Each ioctl can support one or more cache invalidation requests in the array
+ * that has a total size of @entry_len * @entry_num.
+ *
+ * An empty invalidation request array by setting @entry_num==0 is allowed, and
+ * @entry_len and @data_uptr would be ignored in this case. This can be used to
+ * check if the given @data_type is supported or not by kernel.
+ */
+struct iommu_hwpt_invalidate {
+ __u32 size;
+ __u32 hwpt_id;
+ __aligned_u64 data_uptr;
+ __u32 data_type;
+ __u32 entry_len;
+ __u32 entry_num;
+ __u32 __reserved;
+};
+#define IOMMU_HWPT_INVALIDATE _IO(IOMMUFD_TYPE, IOMMUFD_CMD_HWPT_INVALIDATE)
#endif
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 211b86de35ac..c3308536482b 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -16,76 +16,6 @@
#define KVM_API_VERSION 12
-/* *** Deprecated interfaces *** */
-
-#define KVM_TRC_SHIFT 16
-
-#define KVM_TRC_ENTRYEXIT (1 << KVM_TRC_SHIFT)
-#define KVM_TRC_HANDLER (1 << (KVM_TRC_SHIFT + 1))
-
-#define KVM_TRC_VMENTRY (KVM_TRC_ENTRYEXIT + 0x01)
-#define KVM_TRC_VMEXIT (KVM_TRC_ENTRYEXIT + 0x02)
-#define KVM_TRC_PAGE_FAULT (KVM_TRC_HANDLER + 0x01)
-
-#define KVM_TRC_HEAD_SIZE 12
-#define KVM_TRC_CYCLE_SIZE 8
-#define KVM_TRC_EXTRA_MAX 7
-
-#define KVM_TRC_INJ_VIRQ (KVM_TRC_HANDLER + 0x02)
-#define KVM_TRC_REDELIVER_EVT (KVM_TRC_HANDLER + 0x03)
-#define KVM_TRC_PEND_INTR (KVM_TRC_HANDLER + 0x04)
-#define KVM_TRC_IO_READ (KVM_TRC_HANDLER + 0x05)
-#define KVM_TRC_IO_WRITE (KVM_TRC_HANDLER + 0x06)
-#define KVM_TRC_CR_READ (KVM_TRC_HANDLER + 0x07)
-#define KVM_TRC_CR_WRITE (KVM_TRC_HANDLER + 0x08)
-#define KVM_TRC_DR_READ (KVM_TRC_HANDLER + 0x09)
-#define KVM_TRC_DR_WRITE (KVM_TRC_HANDLER + 0x0A)
-#define KVM_TRC_MSR_READ (KVM_TRC_HANDLER + 0x0B)
-#define KVM_TRC_MSR_WRITE (KVM_TRC_HANDLER + 0x0C)
-#define KVM_TRC_CPUID (KVM_TRC_HANDLER + 0x0D)
-#define KVM_TRC_INTR (KVM_TRC_HANDLER + 0x0E)
-#define KVM_TRC_NMI (KVM_TRC_HANDLER + 0x0F)
-#define KVM_TRC_VMMCALL (KVM_TRC_HANDLER + 0x10)
-#define KVM_TRC_HLT (KVM_TRC_HANDLER + 0x11)
-#define KVM_TRC_CLTS (KVM_TRC_HANDLER + 0x12)
-#define KVM_TRC_LMSW (KVM_TRC_HANDLER + 0x13)
-#define KVM_TRC_APIC_ACCESS (KVM_TRC_HANDLER + 0x14)
-#define KVM_TRC_TDP_FAULT (KVM_TRC_HANDLER + 0x15)
-#define KVM_TRC_GTLB_WRITE (KVM_TRC_HANDLER + 0x16)
-#define KVM_TRC_STLB_WRITE (KVM_TRC_HANDLER + 0x17)
-#define KVM_TRC_STLB_INVAL (KVM_TRC_HANDLER + 0x18)
-#define KVM_TRC_PPC_INSTR (KVM_TRC_HANDLER + 0x19)
-
-struct kvm_user_trace_setup {
- __u32 buf_size;
- __u32 buf_nr;
-};
-
-#define __KVM_DEPRECATED_MAIN_W_0x06 \
- _IOW(KVMIO, 0x06, struct kvm_user_trace_setup)
-#define __KVM_DEPRECATED_MAIN_0x07 _IO(KVMIO, 0x07)
-#define __KVM_DEPRECATED_MAIN_0x08 _IO(KVMIO, 0x08)
-
-#define __KVM_DEPRECATED_VM_R_0x70 _IOR(KVMIO, 0x70, struct kvm_assigned_irq)
-
-struct kvm_breakpoint {
- __u32 enabled;
- __u32 padding;
- __u64 address;
-};
-
-struct kvm_debug_guest {
- __u32 enabled;
- __u32 pad;
- struct kvm_breakpoint breakpoints[4];
- __u32 singlestep;
-};
-
-#define __KVM_DEPRECATED_VCPU_W_0x87 _IOW(KVMIO, 0x87, struct kvm_debug_guest)
-
-/* *** End of deprecated interfaces *** */
-
-
/* for KVM_SET_USER_MEMORY_REGION */
struct kvm_userspace_memory_region {
__u32 slot;
@@ -95,6 +25,19 @@ struct kvm_userspace_memory_region {
__u64 userspace_addr; /* start of the userspace allocated memory */
};
+/* for KVM_SET_USER_MEMORY_REGION2 */
+struct kvm_userspace_memory_region2 {
+ __u32 slot;
+ __u32 flags;
+ __u64 guest_phys_addr;
+ __u64 memory_size;
+ __u64 userspace_addr;
+ __u64 guest_memfd_offset;
+ __u32 guest_memfd;
+ __u32 pad1;
+ __u64 pad2[14];
+};
+
/*
* The bit 0 ~ bit 15 of kvm_userspace_memory_region::flags are visible for
* userspace, other bits are reserved for kvm internal use which are defined
@@ -102,6 +45,7 @@ struct kvm_userspace_memory_region {
*/
#define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0)
#define KVM_MEM_READONLY (1UL << 1)
+#define KVM_MEM_GUEST_MEMFD (1UL << 2)
/* for KVM_IRQ_LINE */
struct kvm_irq_level {
@@ -265,6 +209,7 @@ struct kvm_xen_exit {
#define KVM_EXIT_RISCV_CSR 36
#define KVM_EXIT_NOTIFY 37
#define KVM_EXIT_LOONGARCH_IOCSR 38
+#define KVM_EXIT_MEMORY_FAULT 39
/* For KVM_EXIT_INTERNAL_ERROR */
/* Emulate instruction failed. */
@@ -518,6 +463,13 @@ struct kvm_run {
#define KVM_NOTIFY_CONTEXT_INVALID (1 << 0)
__u32 flags;
} notify;
+ /* KVM_EXIT_MEMORY_FAULT */
+ struct {
+#define KVM_MEMORY_EXIT_FLAG_PRIVATE (1ULL << 3)
+ __u64 flags;
+ __u64 gpa;
+ __u64 size;
+ } memory_fault;
/* Fix the size of the union. */
char padding[256];
};
@@ -945,9 +897,6 @@ struct kvm_ppc_resize_hpt {
*/
#define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */
#define KVM_GET_SUPPORTED_CPUID _IOWR(KVMIO, 0x05, struct kvm_cpuid2)
-#define KVM_TRACE_ENABLE __KVM_DEPRECATED_MAIN_W_0x06
-#define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07
-#define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08
#define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2)
#define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list)
@@ -1201,6 +1150,11 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE 228
#define KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 229
#define KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES 230
+#define KVM_CAP_USER_MEMORY2 231
+#define KVM_CAP_MEMORY_FAULT_INFO 232
+#define KVM_CAP_MEMORY_ATTRIBUTES 233
+#define KVM_CAP_GUEST_MEMFD 234
+#define KVM_CAP_VM_TYPES 235
#ifdef KVM_CAP_IRQ_ROUTING
@@ -1291,6 +1245,7 @@ struct kvm_x86_mce {
#define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4)
#define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5)
#define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6)
+#define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE (1 << 7)
struct kvm_xen_hvm_config {
__u32 flags;
@@ -1483,6 +1438,8 @@ struct kvm_vfio_spapr_tce {
struct kvm_userspace_memory_region)
#define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47)
#define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO, 0x48, __u64)
+#define KVM_SET_USER_MEMORY_REGION2 _IOW(KVMIO, 0x49, \
+ struct kvm_userspace_memory_region2)
/* enable ucontrol for s390 */
struct kvm_s390_ucas_mapping {
@@ -1507,20 +1464,8 @@ struct kvm_s390_ucas_mapping {
_IOW(KVMIO, 0x67, struct kvm_coalesced_mmio_zone)
#define KVM_UNREGISTER_COALESCED_MMIO \
_IOW(KVMIO, 0x68, struct kvm_coalesced_mmio_zone)
-#define KVM_ASSIGN_PCI_DEVICE _IOR(KVMIO, 0x69, \
- struct kvm_assigned_pci_dev)
#define KVM_SET_GSI_ROUTING _IOW(KVMIO, 0x6a, struct kvm_irq_routing)
-/* deprecated, replaced by KVM_ASSIGN_DEV_IRQ */
-#define KVM_ASSIGN_IRQ __KVM_DEPRECATED_VM_R_0x70
-#define KVM_ASSIGN_DEV_IRQ _IOW(KVMIO, 0x70, struct kvm_assigned_irq)
#define KVM_REINJECT_CONTROL _IO(KVMIO, 0x71)
-#define KVM_DEASSIGN_PCI_DEVICE _IOW(KVMIO, 0x72, \
- struct kvm_assigned_pci_dev)
-#define KVM_ASSIGN_SET_MSIX_NR _IOW(KVMIO, 0x73, \
- struct kvm_assigned_msix_nr)
-#define KVM_ASSIGN_SET_MSIX_ENTRY _IOW(KVMIO, 0x74, \
- struct kvm_assigned_msix_entry)
-#define KVM_DEASSIGN_DEV_IRQ _IOW(KVMIO, 0x75, struct kvm_assigned_irq)
#define KVM_IRQFD _IOW(KVMIO, 0x76, struct kvm_irqfd)
#define KVM_CREATE_PIT2 _IOW(KVMIO, 0x77, struct kvm_pit_config)
#define KVM_SET_BOOT_CPU_ID _IO(KVMIO, 0x78)
@@ -1537,9 +1482,6 @@ struct kvm_s390_ucas_mapping {
* KVM_CAP_VM_TSC_CONTROL to set defaults for a VM */
#define KVM_SET_TSC_KHZ _IO(KVMIO, 0xa2)
#define KVM_GET_TSC_KHZ _IO(KVMIO, 0xa3)
-/* Available with KVM_CAP_PCI_2_3 */
-#define KVM_ASSIGN_SET_INTX_MASK _IOW(KVMIO, 0xa4, \
- struct kvm_assigned_pci_dev)
/* Available with KVM_CAP_SIGNAL_MSI */
#define KVM_SIGNAL_MSI _IOW(KVMIO, 0xa5, struct kvm_msi)
/* Available with KVM_CAP_PPC_GET_SMMU_INFO */
@@ -1592,8 +1534,6 @@ struct kvm_s390_ucas_mapping {
#define KVM_SET_SREGS _IOW(KVMIO, 0x84, struct kvm_sregs)
#define KVM_TRANSLATE _IOWR(KVMIO, 0x85, struct kvm_translation)
#define KVM_INTERRUPT _IOW(KVMIO, 0x86, struct kvm_interrupt)
-/* KVM_DEBUG_GUEST is no longer supported, use KVM_SET_GUEST_DEBUG instead */
-#define KVM_DEBUG_GUEST __KVM_DEPRECATED_VCPU_W_0x87
#define KVM_GET_MSRS _IOWR(KVMIO, 0x88, struct kvm_msrs)
#define KVM_SET_MSRS _IOW(KVMIO, 0x89, struct kvm_msrs)
#define KVM_SET_CPUID _IOW(KVMIO, 0x8a, struct kvm_cpuid)
@@ -2267,4 +2207,24 @@ struct kvm_s390_zpci_op {
/* flags for kvm_s390_zpci_op->u.reg_aen.flags */
#define KVM_S390_ZPCIOP_REGAEN_HOST (1 << 0)
+/* Available with KVM_CAP_MEMORY_ATTRIBUTES */
+#define KVM_SET_MEMORY_ATTRIBUTES _IOW(KVMIO, 0xd2, struct kvm_memory_attributes)
+
+struct kvm_memory_attributes {
+ __u64 address;
+ __u64 size;
+ __u64 attributes;
+ __u64 flags;
+};
+
+#define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3)
+
+#define KVM_CREATE_GUEST_MEMFD _IOWR(KVMIO, 0xd4, struct kvm_create_guest_memfd)
+
+struct kvm_create_guest_memfd {
+ __u64 size;
+ __u64 flags;
+ __u64 reserved[6];
+};
+
#endif /* __LINUX_KVM_H */
diff --git a/include/uapi/linux/mei.h b/include/uapi/linux/mei.h
index 171c5cce3641..68a0272e99b7 100644
--- a/include/uapi/linux/mei.h
+++ b/include/uapi/linux/mei.h
@@ -100,14 +100,14 @@ struct mei_connect_client_data_vtag {
* a FW client on a tagged channel. From this point on, every read
* and write will communicate with the associated FW client
* on the tagged channel.
- * Upone close() the communication is terminated.
+ * Upon close() the communication is terminated.
*
* The IOCTL argument is a struct with a union that contains
* the input parameter and the output parameter for this IOCTL.
*
* The input parameter is UUID of the FW Client, a vtag [0,255].
* The output parameter is the properties of the FW client
- * (FW protocool version and max message size).
+ * (FW protocol version and max message size).
*
* Clients that do not support tagged connection
* will respond with -EOPNOTSUPP.
diff --git a/include/uapi/linux/nsm.h b/include/uapi/linux/nsm.h
new file mode 100644
index 000000000000..e529f232f6c0
--- /dev/null
+++ b/include/uapi/linux/nsm.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ */
+
+#ifndef __UAPI_LINUX_NSM_H
+#define __UAPI_LINUX_NSM_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define NSM_MAGIC 0x0A
+
+#define NSM_REQUEST_MAX_SIZE 0x1000
+#define NSM_RESPONSE_MAX_SIZE 0x3000
+
+struct nsm_iovec {
+ __u64 addr; /* Virtual address of target buffer */
+ __u64 len; /* Length of target buffer */
+};
+
+/* Raw NSM message. Only available with CAP_SYS_ADMIN. */
+struct nsm_raw {
+ /* Request from user */
+ struct nsm_iovec request;
+ /* Response to user */
+ struct nsm_iovec response;
+};
+#define NSM_IOCTL_RAW _IOWR(NSM_MAGIC, 0x0, struct nsm_raw)
+
+#endif /* __UAPI_LINUX_NSM_H */
diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h
index f9c1af8d141b..94b46b043b53 100644
--- a/include/uapi/linux/pcitest.h
+++ b/include/uapi/linux/pcitest.h
@@ -11,7 +11,8 @@
#define __UAPI_LINUX_PCITEST_H
#define PCITEST_BAR _IO('P', 0x1)
-#define PCITEST_LEGACY_IRQ _IO('P', 0x2)
+#define PCITEST_INTX_IRQ _IO('P', 0x2)
+#define PCITEST_LEGACY_IRQ PCITEST_INTX_IRQ
#define PCITEST_MSI _IOW('P', 0x3, int)
#define PCITEST_WRITE _IOW('P', 0x4, unsigned long)
#define PCITEST_READ _IOW('P', 0x5, unsigned long)
diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h
index 53bc1af67a41..9086367db043 100644
--- a/include/uapi/linux/serial.h
+++ b/include/uapi/linux/serial.h
@@ -11,6 +11,7 @@
#ifndef _UAPI_LINUX_SERIAL_H
#define _UAPI_LINUX_SERIAL_H
+#include <linux/const.h>
#include <linux/types.h>
#include <linux/tty_flags.h>
@@ -137,17 +138,19 @@ struct serial_icounter_struct {
* * %SER_RS485_ADDRB - Enable RS485 addressing mode.
* * %SER_RS485_ADDR_RECV - Receive address filter (enables @addr_recv). Requires %SER_RS485_ADDRB.
* * %SER_RS485_ADDR_DEST - Destination address (enables @addr_dest). Requires %SER_RS485_ADDRB.
+ * * %SER_RS485_MODE_RS422 - Enable RS422. Requires %SER_RS485_ENABLED.
*/
struct serial_rs485 {
__u32 flags;
-#define SER_RS485_ENABLED (1 << 0)
-#define SER_RS485_RTS_ON_SEND (1 << 1)
-#define SER_RS485_RTS_AFTER_SEND (1 << 2)
-#define SER_RS485_RX_DURING_TX (1 << 4)
-#define SER_RS485_TERMINATE_BUS (1 << 5)
-#define SER_RS485_ADDRB (1 << 6)
-#define SER_RS485_ADDR_RECV (1 << 7)
-#define SER_RS485_ADDR_DEST (1 << 8)
+#define SER_RS485_ENABLED _BITUL(0)
+#define SER_RS485_RTS_ON_SEND _BITUL(1)
+#define SER_RS485_RTS_AFTER_SEND _BITUL(2)
+#define SER_RS485_RX_DURING_TX _BITUL(3)
+#define SER_RS485_TERMINATE_BUS _BITUL(4)
+#define SER_RS485_ADDRB _BITUL(5)
+#define SER_RS485_ADDR_RECV _BITUL(6)
+#define SER_RS485_ADDR_DEST _BITUL(7)
+#define SER_RS485_MODE_RS422 _BITUL(8)
__u32 delay_rts_before_send;
__u32 delay_rts_after_send;
diff --git a/include/uapi/linux/thp7312.h b/include/uapi/linux/thp7312.h
new file mode 100644
index 000000000000..2b629e05daf9
--- /dev/null
+++ b/include/uapi/linux/thp7312.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+/*
+ * THine THP7312 user space header file.
+ *
+ * Copyright (C) 2021 THine Electronics, Inc.
+ * Copyright (C) 2023 Ideas on Board Oy
+ */
+
+#ifndef __UAPI_THP7312_H_
+#define __UAPI_THP7312_H_
+
+#include <linux/v4l2-controls.h>
+
+#define V4L2_CID_THP7312_LOW_LIGHT_COMPENSATION (V4L2_CID_USER_THP7312_BASE + 0x01)
+#define V4L2_CID_THP7312_AUTO_FOCUS_METHOD (V4L2_CID_USER_THP7312_BASE + 0x02)
+#define V4L2_CID_THP7312_NOISE_REDUCTION_AUTO (V4L2_CID_USER_THP7312_BASE + 0x03)
+#define V4L2_CID_THP7312_NOISE_REDUCTION_ABSOLUTE (V4L2_CID_USER_THP7312_BASE + 0x04)
+
+#endif /* __UAPI_THP7312_H_ */
diff --git a/include/uapi/linux/usb/functionfs.h b/include/uapi/linux/usb/functionfs.h
index d77ee6b65328..078098e73fd3 100644
--- a/include/uapi/linux/usb/functionfs.h
+++ b/include/uapi/linux/usb/functionfs.h
@@ -73,8 +73,10 @@ struct usb_os_desc_header {
struct usb_ext_compat_desc {
__u8 bFirstInterfaceNumber;
__u8 Reserved1;
- __u8 CompatibleID[8];
- __u8 SubCompatibleID[8];
+ __struct_group(/* no tag */, IDs, /* no attrs */,
+ __u8 CompatibleID[8];
+ __u8 SubCompatibleID[8];
+ );
__u8 Reserved2[6];
};
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 68db66d4aae8..99c3f5e99da7 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -209,6 +209,12 @@ enum v4l2_colorfx {
*/
#define V4L2_CID_USER_NPCM_BASE (V4L2_CID_USER_BASE + 0x11b0)
+/*
+ * The base for THine THP7312 driver controls.
+ * We reserve 32 controls for this driver.
+ */
+#define V4L2_CID_USER_THP7312_BASE (V4L2_CID_USER_BASE + 0x11c0)
+
/* MPEG-class control IDs */
/* The MPEG controls are applicable to all codec controls
* and the 'MPEG' part of the define is historical */
diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
index b383c2fe0cf3..7048c51581c6 100644
--- a/include/uapi/linux/v4l2-subdev.h
+++ b/include/uapi/linux/v4l2-subdev.h
@@ -116,13 +116,15 @@ struct v4l2_subdev_frame_size_enum {
* @pad: pad number, as reported by the media API
* @interval: frame interval in seconds
* @stream: stream number, defined in subdev routing
+ * @which: interval type (from enum v4l2_subdev_format_whence)
* @reserved: drivers and applications must zero this array
*/
struct v4l2_subdev_frame_interval {
__u32 pad;
struct v4l2_fract interval;
__u32 stream;
- __u32 reserved[8];
+ __u32 which;
+ __u32 reserved[7];
};
/**
@@ -133,7 +135,7 @@ struct v4l2_subdev_frame_interval {
* @width: frame width in pixels
* @height: frame height in pixels
* @interval: frame interval in seconds
- * @which: format type (from enum v4l2_subdev_format_whence)
+ * @which: interval type (from enum v4l2_subdev_format_whence)
* @stream: stream number, defined in subdev routing
* @reserved: drivers and applications must zero this array
*/
@@ -239,7 +241,14 @@ struct v4l2_subdev_routing {
* set (which is the default), the 'stream' fields will be forced to 0 by the
* kernel.
*/
- #define V4L2_SUBDEV_CLIENT_CAP_STREAMS (1ULL << 0)
+#define V4L2_SUBDEV_CLIENT_CAP_STREAMS (1ULL << 0)
+
+/*
+ * The client is aware of the struct v4l2_subdev_frame_interval which field. If
+ * this is not set (which is the default), the which field is forced to
+ * V4L2_SUBDEV_FORMAT_ACTIVE by the kernel.
+ */
+#define V4L2_SUBDEV_CLIENT_CAP_INTERVAL_USES_WHICH (1ULL << 1)
/**
* struct v4l2_subdev_client_capability - Capabilities of the client accessing
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 7f5fb010226d..2b68e6cdf190 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -1219,6 +1219,7 @@ enum vfio_device_mig_state {
VFIO_DEVICE_STATE_RUNNING_P2P = 5,
VFIO_DEVICE_STATE_PRE_COPY = 6,
VFIO_DEVICE_STATE_PRE_COPY_P2P = 7,
+ VFIO_DEVICE_STATE_NR,
};
/**
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index c3d4e490ce7c..68e7ac178cc2 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1035,6 +1035,7 @@ struct v4l2_requestbuffers {
#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4)
#define V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF (1 << 5)
#define V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS (1 << 6)
+#define V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS (1 << 7)
/**
* struct v4l2_plane - plane info for multi-planar buffers
@@ -1816,7 +1817,7 @@ struct v4l2_ext_control {
__s64 __user *p_s64;
struct v4l2_area __user *p_area;
struct v4l2_ctrl_h264_sps __user *p_h264_sps;
- struct v4l2_ctrl_h264_pps *p_h264_pps;
+ struct v4l2_ctrl_h264_pps __user *p_h264_pps;
struct v4l2_ctrl_h264_scaling_matrix __user *p_h264_scaling_matrix;
struct v4l2_ctrl_h264_pred_weights __user *p_h264_pred_weights;
struct v4l2_ctrl_h264_slice_params __user *p_h264_slice_params;
@@ -1837,6 +1838,8 @@ struct v4l2_ext_control {
struct v4l2_ctrl_av1_tile_group_entry __user *p_av1_tile_group_entry;
struct v4l2_ctrl_av1_frame __user *p_av1_frame;
struct v4l2_ctrl_av1_film_grain __user *p_av1_film_grain;
+ struct v4l2_ctrl_hdr10_cll_info __user *p_hdr10_cll_info;
+ struct v4l2_ctrl_hdr10_mastering_display __user *p_hdr10_mastering_display;
void __user *ptr;
};
} __attribute__ ((packed));
@@ -2605,6 +2608,9 @@ struct v4l2_dbg_chip_info {
* @flags: additional buffer management attributes (ignored unless the
* queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability
* and configured for MMAP streaming I/O).
+ * @max_num_buffers: if V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS capability flag is set
+ * this field indicate the maximum possible number of buffers
+ * for this queue.
* @reserved: future extensions
*/
struct v4l2_create_buffers {
@@ -2614,7 +2620,8 @@ struct v4l2_create_buffers {
struct v4l2_format format;
__u32 capabilities;
__u32 flags;
- __u32 reserved[6];
+ __u32 max_num_buffers;
+ __u32 reserved[5];
};
/*
diff --git a/include/uapi/linux/virtio_config.h b/include/uapi/linux/virtio_config.h
index 8881aea60f6f..2445f365bce7 100644
--- a/include/uapi/linux/virtio_config.h
+++ b/include/uapi/linux/virtio_config.h
@@ -52,7 +52,7 @@
* rest are per-device feature bits.
*/
#define VIRTIO_TRANSPORT_F_START 28
-#define VIRTIO_TRANSPORT_F_END 41
+#define VIRTIO_TRANSPORT_F_END 42
#ifndef VIRTIO_CONFIG_NO_LEGACY
/* Do we get callbacks when the ring is completely used, even if we've
@@ -114,4 +114,10 @@
* This feature indicates that the driver can reset a queue individually.
*/
#define VIRTIO_F_RING_RESET 40
+
+/*
+ * This feature indicates that the device support administration virtqueues.
+ */
+#define VIRTIO_F_ADMIN_VQ 41
+
#endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */
diff --git a/include/uapi/linux/virtio_pci.h b/include/uapi/linux/virtio_pci.h
index 44f4dd2add18..ef3810dee7ef 100644
--- a/include/uapi/linux/virtio_pci.h
+++ b/include/uapi/linux/virtio_pci.h
@@ -175,6 +175,9 @@ struct virtio_pci_modern_common_cfg {
__le16 queue_notify_data; /* read-write */
__le16 queue_reset; /* read-write */
+
+ __le16 admin_queue_index; /* read-only */
+ __le16 admin_queue_num; /* read-only */
};
/* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
@@ -215,7 +218,72 @@ struct virtio_pci_cfg_cap {
#define VIRTIO_PCI_COMMON_Q_USEDHI 52
#define VIRTIO_PCI_COMMON_Q_NDATA 56
#define VIRTIO_PCI_COMMON_Q_RESET 58
+#define VIRTIO_PCI_COMMON_ADM_Q_IDX 60
+#define VIRTIO_PCI_COMMON_ADM_Q_NUM 62
#endif /* VIRTIO_PCI_NO_MODERN */
+/* Admin command status. */
+#define VIRTIO_ADMIN_STATUS_OK 0
+
+/* Admin command opcode. */
+#define VIRTIO_ADMIN_CMD_LIST_QUERY 0x0
+#define VIRTIO_ADMIN_CMD_LIST_USE 0x1
+
+/* Admin command group type. */
+#define VIRTIO_ADMIN_GROUP_TYPE_SRIOV 0x1
+
+/* Transitional device admin command. */
+#define VIRTIO_ADMIN_CMD_LEGACY_COMMON_CFG_WRITE 0x2
+#define VIRTIO_ADMIN_CMD_LEGACY_COMMON_CFG_READ 0x3
+#define VIRTIO_ADMIN_CMD_LEGACY_DEV_CFG_WRITE 0x4
+#define VIRTIO_ADMIN_CMD_LEGACY_DEV_CFG_READ 0x5
+#define VIRTIO_ADMIN_CMD_LEGACY_NOTIFY_INFO 0x6
+
+struct __packed virtio_admin_cmd_hdr {
+ __le16 opcode;
+ /*
+ * 1 - SR-IOV
+ * 2-65535 - reserved
+ */
+ __le16 group_type;
+ /* Unused, reserved for future extensions. */
+ __u8 reserved1[12];
+ __le64 group_member_id;
+};
+
+struct __packed virtio_admin_cmd_status {
+ __le16 status;
+ __le16 status_qualifier;
+ /* Unused, reserved for future extensions. */
+ __u8 reserved2[4];
+};
+
+struct __packed virtio_admin_cmd_legacy_wr_data {
+ __u8 offset; /* Starting offset of the register(s) to write. */
+ __u8 reserved[7];
+ __u8 registers[];
+};
+
+struct __packed virtio_admin_cmd_legacy_rd_data {
+ __u8 offset; /* Starting offset of the register(s) to read. */
+};
+
+#define VIRTIO_ADMIN_CMD_NOTIFY_INFO_FLAGS_END 0
+#define VIRTIO_ADMIN_CMD_NOTIFY_INFO_FLAGS_OWNER_DEV 0x1
+#define VIRTIO_ADMIN_CMD_NOTIFY_INFO_FLAGS_OWNER_MEM 0x2
+
+#define VIRTIO_ADMIN_CMD_MAX_NOTIFY_INFO 4
+
+struct __packed virtio_admin_cmd_notify_info_data {
+ __u8 flags; /* 0 = end of list, 1 = owner device, 2 = member device */
+ __u8 bar; /* BAR of the member or the owner device */
+ __u8 padding[6];
+ __le64 offset; /* Offset within bar. */
+};
+
+struct virtio_admin_cmd_notify_info_result {
+ struct virtio_admin_cmd_notify_info_data entries[VIRTIO_ADMIN_CMD_MAX_NOTIFY_INFO];
+};
+
#endif
diff --git a/include/uapi/linux/virtio_pmem.h b/include/uapi/linux/virtio_pmem.h
index d676b3620383..ede4f3564977 100644
--- a/include/uapi/linux/virtio_pmem.h
+++ b/include/uapi/linux/virtio_pmem.h
@@ -14,6 +14,13 @@
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
+/* Feature bits */
+/* guest physical address range will be indicated as shared memory region 0 */
+#define VIRTIO_PMEM_F_SHMEM_REGION 0
+
+/* shmid of the shared memory region corresponding to the pmem */
+#define VIRTIO_PMEM_SHMEM_REGION_ID 0
+
struct virtio_pmem_config {
__le64 start;
__le64 size;
diff --git a/include/uapi/rdma/bnxt_re-abi.h b/include/uapi/rdma/bnxt_re-abi.h
index 6e7c67a0cca3..c0c34aca90ec 100644
--- a/include/uapi/rdma/bnxt_re-abi.h
+++ b/include/uapi/rdma/bnxt_re-abi.h
@@ -54,6 +54,8 @@ enum {
BNXT_RE_UCNTX_CMASK_HAVE_MODE = 0x02ULL,
BNXT_RE_UCNTX_CMASK_WC_DPI_ENABLED = 0x04ULL,
BNXT_RE_UCNTX_CMASK_DBR_PACING_ENABLED = 0x08ULL,
+ BNXT_RE_UCNTX_CMASK_POW2_DISABLED = 0x10ULL,
+ BNXT_RE_COMP_MASK_UCNTX_HW_RETX_ENABLED = 0x40,
};
enum bnxt_re_wqe_mode {
@@ -62,6 +64,14 @@ enum bnxt_re_wqe_mode {
BNXT_QPLIB_WQE_MODE_INVALID = 0x02,
};
+enum {
+ BNXT_RE_COMP_MASK_REQ_UCNTX_POW2_SUPPORT = 0x01,
+};
+
+struct bnxt_re_uctx_req {
+ __aligned_u64 comp_mask;
+};
+
struct bnxt_re_uctx_resp {
__u32 dev_id;
__u32 max_qp;
@@ -92,11 +102,16 @@ struct bnxt_re_cq_req {
__aligned_u64 cq_handle;
};
+enum bnxt_re_cq_mask {
+ BNXT_RE_CQ_TOGGLE_PAGE_SUPPORT = 0x1,
+};
+
struct bnxt_re_cq_resp {
__u32 cqid;
__u32 tail;
__u32 phase;
__u32 rsvd;
+ __aligned_u64 comp_mask;
};
struct bnxt_re_resize_cq_req {
@@ -133,6 +148,7 @@ enum bnxt_re_shpg_offt {
enum bnxt_re_objects {
BNXT_RE_OBJECT_ALLOC_PAGE = (1U << UVERBS_ID_NS_SHIFT),
BNXT_RE_OBJECT_NOTIFY_DRV,
+ BNXT_RE_OBJECT_GET_TOGGLE_MEM,
};
enum bnxt_re_alloc_page_type {
@@ -161,4 +177,29 @@ enum bnxt_re_alloc_page_methods {
enum bnxt_re_notify_drv_methods {
BNXT_RE_METHOD_NOTIFY_DRV = (1U << UVERBS_ID_NS_SHIFT),
};
+
+/* Toggle mem */
+
+enum bnxt_re_get_toggle_mem_type {
+ BNXT_RE_CQ_TOGGLE_MEM = 0,
+ BNXT_RE_SRQ_TOGGLE_MEM,
+};
+
+enum bnxt_re_var_toggle_mem_attrs {
+ BNXT_RE_TOGGLE_MEM_HANDLE = (1U << UVERBS_ID_NS_SHIFT),
+ BNXT_RE_TOGGLE_MEM_TYPE,
+ BNXT_RE_TOGGLE_MEM_RES_ID,
+ BNXT_RE_TOGGLE_MEM_MMAP_PAGE,
+ BNXT_RE_TOGGLE_MEM_MMAP_OFFSET,
+ BNXT_RE_TOGGLE_MEM_MMAP_LENGTH,
+};
+
+enum bnxt_re_toggle_mem_attrs {
+ BNXT_RE_RELEASE_TOGGLE_MEM_HANDLE = (1U << UVERBS_ID_NS_SHIFT),
+};
+
+enum bnxt_re_toggle_mem_methods {
+ BNXT_RE_METHOD_GET_TOGGLE_MEM = (1U << UVERBS_ID_NS_SHIFT),
+ BNXT_RE_METHOD_RELEASE_TOGGLE_MEM,
+};
#endif /* __BNXT_RE_UVERBS_ABI_H__*/
diff --git a/include/uapi/rdma/efa-abi.h b/include/uapi/rdma/efa-abi.h
index d94c32f28804..701e2d567e41 100644
--- a/include/uapi/rdma/efa-abi.h
+++ b/include/uapi/rdma/efa-abi.h
@@ -1,12 +1,13 @@
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */
/*
- * Copyright 2018-2023 Amazon.com, Inc. or its affiliates. All rights reserved.
+ * Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All rights reserved.
*/
#ifndef EFA_ABI_USER_H
#define EFA_ABI_USER_H
#include <linux/types.h>
+#include <rdma/ib_user_ioctl_cmds.h>
/*
* Increment this value if any changes that break userspace ABI
@@ -134,4 +135,22 @@ struct efa_ibv_ex_query_device_resp {
__u32 device_caps;
};
+enum {
+ EFA_QUERY_MR_VALIDITY_RECV_IC_ID = 1 << 0,
+ EFA_QUERY_MR_VALIDITY_RDMA_READ_IC_ID = 1 << 1,
+ EFA_QUERY_MR_VALIDITY_RDMA_RECV_IC_ID = 1 << 2,
+};
+
+enum efa_query_mr_attrs {
+ EFA_IB_ATTR_QUERY_MR_HANDLE = (1U << UVERBS_ID_NS_SHIFT),
+ EFA_IB_ATTR_QUERY_MR_RESP_IC_ID_VALIDITY,
+ EFA_IB_ATTR_QUERY_MR_RESP_RECV_IC_ID,
+ EFA_IB_ATTR_QUERY_MR_RESP_RDMA_READ_IC_ID,
+ EFA_IB_ATTR_QUERY_MR_RESP_RDMA_RECV_IC_ID,
+};
+
+enum efa_mr_methods {
+ EFA_IB_METHOD_MR_QUERY = (1U << UVERBS_ID_NS_SHIFT),
+};
+
#endif /* EFA_ABI_USER_H */
diff --git a/include/uapi/rdma/hns-abi.h b/include/uapi/rdma/hns-abi.h
index ce0f37f83416..c996e151081e 100644
--- a/include/uapi/rdma/hns-abi.h
+++ b/include/uapi/rdma/hns-abi.h
@@ -125,4 +125,9 @@ struct hns_roce_ib_alloc_pd_resp {
__u32 pdn;
};
+struct hns_roce_ib_create_ah_resp {
+ __u8 dmac[6];
+ __u8 reserved[2];
+};
+
#endif /* HNS_ABI_USER_H */
diff --git a/include/uapi/rdma/mlx5-abi.h b/include/uapi/rdma/mlx5-abi.h
index a96b7d2770e1..d4f6a36dffb0 100644
--- a/include/uapi/rdma/mlx5-abi.h
+++ b/include/uapi/rdma/mlx5-abi.h
@@ -37,6 +37,7 @@
#include <linux/types.h>
#include <linux/if_ether.h> /* For ETH_ALEN. */
#include <rdma/ib_user_ioctl_verbs.h>
+#include <rdma/mlx5_user_ioctl_verbs.h>
enum {
MLX5_QP_FLAG_SIGNATURE = 1 << 0,
@@ -275,6 +276,7 @@ struct mlx5_ib_query_device_resp {
__u32 tunnel_offloads_caps; /* enum mlx5_ib_tunnel_offloads */
struct mlx5_ib_dci_streams_caps dci_streams_caps;
__u16 reserved;
+ struct mlx5_ib_uapi_reg reg_c0;
};
enum mlx5_ib_create_cq_flags {
diff --git a/include/uapi/rdma/mlx5_user_ioctl_verbs.h b/include/uapi/rdma/mlx5_user_ioctl_verbs.h
index 7af9e09ea556..3189c7f08d17 100644
--- a/include/uapi/rdma/mlx5_user_ioctl_verbs.h
+++ b/include/uapi/rdma/mlx5_user_ioctl_verbs.h
@@ -64,6 +64,7 @@ enum mlx5_ib_uapi_dm_type {
MLX5_IB_UAPI_DM_TYPE_STEERING_SW_ICM,
MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_SW_ICM,
MLX5_IB_UAPI_DM_TYPE_HEADER_MODIFY_PATTERN_SW_ICM,
+ MLX5_IB_UAPI_DM_TYPE_ENCAP_SW_ICM,
};
enum mlx5_ib_uapi_devx_create_event_channel_flags {
diff --git a/include/video/sticore.h b/include/video/sticore.h
index 012b5b46ad7d..823666af1871 100644
--- a/include/video/sticore.h
+++ b/include/video/sticore.h
@@ -2,7 +2,7 @@
#ifndef STICORE_H
#define STICORE_H
-struct fb_info;
+struct device;
/* generic STI structures & functions */
@@ -367,8 +367,8 @@ struct sti_struct {
/* PCI data structures (pg. 17ff from sti.pdf) */
u8 rm_entry[16]; /* pci region mapper array == pci config space offset */
- /* pointer to the fb_info where this STI device is used */
- struct fb_info *info;
+ /* pointer to the parent device */
+ struct device *dev;
/* pointer to all internal data */
struct sti_all_data *sti_data;
diff --git a/include/xen/interface/io/displif.h b/include/xen/interface/io/displif.h
index 18417b017869..60e42d3b760e 100644
--- a/include/xen/interface/io/displif.h
+++ b/include/xen/interface/io/displif.h
@@ -537,7 +537,7 @@ struct xendispl_dbuf_create_req {
struct xendispl_page_directory {
grant_ref_t gref_dir_next_page;
- grant_ref_t gref[1]; /* Variable length */
+ grant_ref_t gref[];
};
/*
diff --git a/include/xen/interface/io/ring.h b/include/xen/interface/io/ring.h
index ba4c4274b714..4fef1efcdcab 100644
--- a/include/xen/interface/io/ring.h
+++ b/include/xen/interface/io/ring.h
@@ -95,7 +95,7 @@ struct __name##_sring { \
RING_IDX req_prod, req_event; \
RING_IDX rsp_prod, rsp_event; \
uint8_t __pad[48]; \
- union __name##_sring_entry ring[1]; /* variable-length */ \
+ union __name##_sring_entry ring[]; \
}; \
\
/* "Front" end's private variables */ \
diff --git a/include/xen/interface/io/sndif.h b/include/xen/interface/io/sndif.h
index 445657cdb1de..b818517588b5 100644
--- a/include/xen/interface/io/sndif.h
+++ b/include/xen/interface/io/sndif.h
@@ -659,7 +659,7 @@ struct xensnd_open_req {
struct xensnd_page_directory {
grant_ref_t gref_dir_next_page;
- grant_ref_t gref[1]; /* Variable length */
+ grant_ref_t gref[];
};
/*
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 5fdef94f0864..279ad28bf4fb 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -510,7 +510,10 @@ struct file_system_type rootfs_fs_type = {
void __init init_rootfs(void)
{
- if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] &&
- (!root_fs_names || strstr(root_fs_names, "tmpfs")))
- is_tmpfs = true;
+ if (IS_ENABLED(CONFIG_TMPFS)) {
+ if (!saved_root_name[0] && !root_fs_names)
+ is_tmpfs = true;
+ else if (root_fs_names && !!strstr(root_fs_names, "tmpfs"))
+ is_tmpfs = true;
+ }
}
diff --git a/init/initramfs.c b/init/initramfs.c
index 8d0fd946cdd2..76deb48c38cb 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -574,6 +574,16 @@ extern unsigned long __initramfs_size;
#include <linux/initrd.h>
#include <linux/kexec.h>
+static ssize_t raw_read(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t pos, size_t count)
+{
+ memcpy(buf, attr->private + pos, count);
+ return count;
+}
+
+static BIN_ATTR(initrd, 0440, raw_read, NULL, 0);
+
void __init reserve_initrd_mem(void)
{
phys_addr_t start;
@@ -715,8 +725,14 @@ done:
* If the initrd region is overlapped with crashkernel reserved region,
* free only memory that is not part of crashkernel region.
*/
- if (!do_retain_initrd && initrd_start && !kexec_free_initrd())
+ if (!do_retain_initrd && initrd_start && !kexec_free_initrd()) {
free_initrd_mem(initrd_start, initrd_end);
+ } else if (do_retain_initrd && initrd_start) {
+ bin_attr_initrd.size = initrd_end - initrd_start;
+ bin_attr_initrd.private = (void *)initrd_start;
+ if (sysfs_create_bin_file(firmware_kobj, &bin_attr_initrd))
+ pr_err("Failed to create initrd sysfs file");
+ }
initrd_start = 0;
initrd_end = 0;
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index 09b6d860deba..86761ec623f9 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -3787,7 +3787,8 @@ static int io_uring_install_fd(struct file *file)
*/
static struct file *io_uring_get_file(struct io_ring_ctx *ctx)
{
- return anon_inode_getfile_secure("[io_uring]", &io_uring_fops, ctx,
+ /* Create a new inode so that the LSM can block the creation. */
+ return anon_inode_create_getfile("[io_uring]", &io_uring_fops, ctx,
O_RDWR | O_CLOEXEC, NULL);
}
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index 04d11a7dd95f..520a11cb12f4 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -802,7 +802,7 @@ void cgroup1_release_agent(struct work_struct *work)
goto out_free;
ret = cgroup_path_ns(cgrp, pathbuf, PATH_MAX, &init_cgroup_ns);
- if (ret < 0 || ret >= PATH_MAX)
+ if (ret < 0)
goto out_free;
argv[0] = agentbuf;
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 8f3cef1a4d8a..a66c088c851c 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -1906,7 +1906,7 @@ int cgroup_show_path(struct seq_file *sf, struct kernfs_node *kf_node,
len = kernfs_path_from_node(kf_node, ns_cgroup->kn, buf, PATH_MAX);
spin_unlock_irq(&css_set_lock);
- if (len >= PATH_MAX)
+ if (len == -E2BIG)
len = -ERANGE;
else if (len > 0) {
seq_escape(sf, buf, " \t\n\\");
@@ -4182,20 +4182,6 @@ static struct kernfs_ops cgroup_kf_ops = {
.seq_show = cgroup_seqfile_show,
};
-/* set uid and gid of cgroup dirs and files to that of the creator */
-static int cgroup_kn_set_ugid(struct kernfs_node *kn)
-{
- struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
- .ia_uid = current_fsuid(),
- .ia_gid = current_fsgid(), };
-
- if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
- gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
- return 0;
-
- return kernfs_setattr(kn, &iattr);
-}
-
static void cgroup_file_notify_timer(struct timer_list *timer)
{
cgroup_file_notify(container_of(timer, struct cgroup_file,
@@ -4208,25 +4194,18 @@ static int cgroup_add_file(struct cgroup_subsys_state *css, struct cgroup *cgrp,
char name[CGROUP_FILE_NAME_MAX];
struct kernfs_node *kn;
struct lock_class_key *key = NULL;
- int ret;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
key = &cft->lockdep_key;
#endif
kn = __kernfs_create_file(cgrp->kn, cgroup_file_name(cgrp, cft, name),
cgroup_file_mode(cft),
- GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+ current_fsuid(), current_fsgid(),
0, cft->kf_ops, cft,
NULL, key);
if (IS_ERR(kn))
return PTR_ERR(kn);
- ret = cgroup_kn_set_ugid(kn);
- if (ret) {
- kernfs_remove(kn);
- return ret;
- }
-
if (cft->file_offset) {
struct cgroup_file *cfile = (void *)css + cft->file_offset;
@@ -5629,7 +5608,9 @@ static struct cgroup *cgroup_create(struct cgroup *parent, const char *name,
goto out_cancel_ref;
/* create the directory */
- kn = kernfs_create_dir(parent->kn, name, mode, cgrp);
+ kn = kernfs_create_dir_ns(parent->kn, name, mode,
+ current_fsuid(), current_fsgid(),
+ cgrp, NULL);
if (IS_ERR(kn)) {
ret = PTR_ERR(kn);
goto out_stat_exit;
@@ -5774,10 +5755,6 @@ int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name, umode_t mode)
*/
kernfs_get(cgrp->kn);
- ret = cgroup_kn_set_ugid(cgrp->kn);
- if (ret)
- goto out_destroy;
-
ret = css_populate_dir(&cgrp->self);
if (ret)
goto out_destroy;
@@ -6316,7 +6293,7 @@ int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns,
if (cgroup_on_dfl(cgrp) || !(tsk->flags & PF_EXITING)) {
retval = cgroup_path_ns_locked(cgrp, buf, PATH_MAX,
current->nsproxy->cgroup_ns);
- if (retval >= PATH_MAX)
+ if (retval == -E2BIG)
retval = -ENAMETOOLONG;
if (retval < 0)
goto out_unlock;
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index dfbb16aca9f4..ba36c073304a 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -5092,7 +5092,7 @@ int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns,
retval = cgroup_path_ns(css->cgroup, buf, PATH_MAX,
current->nsproxy->cgroup_ns);
css_put(css);
- if (retval >= PATH_MAX)
+ if (retval == -E2BIG)
retval = -ENAMETOOLONG;
if (retval < 0)
goto out_free;
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index d48315667752..75cd6a736d03 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -376,7 +376,6 @@ static int __init reserve_crashkernel_low(unsigned long long low_size)
crashk_low_res.start = low_base;
crashk_low_res.end = low_base + low_size - 1;
- insert_resource(&iomem_resource, &crashk_low_res);
#endif
return 0;
}
@@ -458,8 +457,19 @@ retry:
crashk_res.start = crash_base;
crashk_res.end = crash_base + crash_size - 1;
- insert_resource(&iomem_resource, &crashk_res);
}
+
+static __init int insert_crashkernel_resources(void)
+{
+ if (crashk_res.start < crashk_res.end)
+ insert_resource(&iomem_resource, &crashk_res);
+
+ if (crashk_low_res.start < crashk_low_res.end)
+ insert_resource(&iomem_resource, &crashk_low_res);
+
+ return 0;
+}
+early_initcall(insert_crashkernel_resources);
#endif
int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
@@ -867,7 +877,7 @@ subsys_initcall(crash_notes_memory_init);
* regions are online. So mutex lock __crash_hotplug_lock is used to
* serialize the crash hotplug handling specifically.
*/
-DEFINE_MUTEX(__crash_hotplug_lock);
+static DEFINE_MUTEX(__crash_hotplug_lock);
#define crash_hotplug_lock() mutex_lock(&__crash_hotplug_lock)
#define crash_hotplug_unlock() mutex_unlock(&__crash_hotplug_lock)
diff --git a/kernel/dma/debug.c b/kernel/dma/debug.c
index 3de494375b7b..a6e3792b15f8 100644
--- a/kernel/dma/debug.c
+++ b/kernel/dma/debug.c
@@ -62,7 +62,8 @@ enum map_err_types {
* @pfn: page frame of the start address
* @offset: offset of mapping relative to pfn
* @map_err_type: track whether dma_mapping_error() was checked
- * @stacktrace: support backtraces when a violation is detected
+ * @stack_len: number of backtrace entries in @stack_entries
+ * @stack_entries: stack of backtrace history
*/
struct dma_debug_entry {
struct list_head list;
@@ -876,7 +877,7 @@ static int dma_debug_device_change(struct notifier_block *nb, unsigned long acti
return 0;
}
-void dma_debug_add_bus(struct bus_type *bus)
+void dma_debug_add_bus(const struct bus_type *bus)
{
struct notifier_block *nb;
diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
index 97c298b210bc..b079a9a8e087 100644
--- a/kernel/dma/swiotlb.c
+++ b/kernel/dma/swiotlb.c
@@ -1136,6 +1136,9 @@ static int swiotlb_find_slots(struct device *dev, phys_addr_t orig_addr,
int cpu, i;
int index;
+ if (alloc_size > IO_TLB_SEGSIZE * IO_TLB_SIZE)
+ return -1;
+
cpu = raw_smp_processor_id();
for (i = 0; i < default_nareas; ++i) {
index = swiotlb_search_area(dev, cpu, i, orig_addr, alloc_size,
diff --git a/kernel/fork.c b/kernel/fork.c
index c981fa6171c1..47ff3b35352e 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1173,7 +1173,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
tsk->use_memdelay = 0;
#endif
-#ifdef CONFIG_IOMMU_SVA
+#ifdef CONFIG_ARCH_HAS_CPU_PASID
tsk->pasid_activated = 0;
#endif
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index a08031b57a61..d08fc7b5db97 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -1257,6 +1257,7 @@ int kernel_kexec(void)
kexec_in_progress = true;
kernel_restart_prepare("kexec reboot");
migrate_to_reboot_cpu();
+ syscore_shutdown();
/*
* migrate_to_reboot_cpu() disables CPU hotplug assuming that
diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c
index 69d3cd2cfc3b..415d81e6ce70 100644
--- a/kernel/locking/locktorture.c
+++ b/kernel/locking/locktorture.c
@@ -124,7 +124,7 @@ struct call_rcu_chain {
struct rcu_head crc_rh;
bool crc_stop;
};
-struct call_rcu_chain *call_rcu_chain;
+struct call_rcu_chain *call_rcu_chain_list;
/* Forward reference. */
static void lock_torture_cleanup(void);
@@ -1074,12 +1074,12 @@ static int call_rcu_chain_init(void)
if (call_rcu_chains <= 0)
return 0;
- call_rcu_chain = kcalloc(call_rcu_chains, sizeof(*call_rcu_chain), GFP_KERNEL);
- if (!call_rcu_chain)
+ call_rcu_chain_list = kcalloc(call_rcu_chains, sizeof(*call_rcu_chain_list), GFP_KERNEL);
+ if (!call_rcu_chain_list)
return -ENOMEM;
for (i = 0; i < call_rcu_chains; i++) {
- call_rcu_chain[i].crc_stop = false;
- call_rcu(&call_rcu_chain[i].crc_rh, call_rcu_chain_cb);
+ call_rcu_chain_list[i].crc_stop = false;
+ call_rcu(&call_rcu_chain_list[i].crc_rh, call_rcu_chain_cb);
}
return 0;
}
@@ -1089,13 +1089,13 @@ static void call_rcu_chain_cleanup(void)
{
int i;
- if (!call_rcu_chain)
+ if (!call_rcu_chain_list)
return;
for (i = 0; i < call_rcu_chains; i++)
- smp_store_release(&call_rcu_chain[i].crc_stop, true);
+ smp_store_release(&call_rcu_chain_list[i].crc_stop, true);
rcu_barrier();
- kfree(call_rcu_chain);
- call_rcu_chain = NULL;
+ kfree(call_rcu_chain_list);
+ call_rcu_chain_list = NULL;
}
static void lock_torture_cleanup(void)
diff --git a/kernel/rcu/Kconfig.debug b/kernel/rcu/Kconfig.debug
index 2984de629f74..9b0b52e1836f 100644
--- a/kernel/rcu/Kconfig.debug
+++ b/kernel/rcu/Kconfig.debug
@@ -105,6 +105,31 @@ config RCU_CPU_STALL_CPUTIME
The boot option rcupdate.rcu_cpu_stall_cputime has the same function
as this one, but will override this if it exists.
+config RCU_CPU_STALL_NOTIFIER
+ bool "Provide RCU CPU-stall notifiers"
+ depends on RCU_STALL_COMMON
+ depends on DEBUG_KERNEL
+ depends on RCU_EXPERT
+ default n
+ help
+ WARNING: You almost certainly do not want this!!!
+
+ Enable RCU CPU-stall notifiers, which are invoked just before
+ printing the RCU CPU stall warning. As such, bugs in notifier
+ callbacks can prevent stall warnings from being printed.
+ And the whole reason that a stall warning is being printed is
+ that something is hung up somewhere. Therefore, the notifier
+ callbacks must be written extremely carefully, preferably
+ containing only lockless code. After all, it is quite possible
+ that the whole reason that the RCU CPU stall is happening in
+ the first place is that someone forgot to release whatever lock
+ that you are thinking of acquiring. In which case, having your
+ notifier callback acquire that lock will hang, preventing the
+ RCU CPU stall warning from appearing.
+
+ Say Y here if you want RCU CPU stall notifiers (you don't want them)
+ Say N if you are unsure.
+
config RCU_TRACE
bool "Enable tracing for RCU"
depends on DEBUG_KERNEL
diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h
index b531c33e9545..f94f65877f2b 100644
--- a/kernel/rcu/rcu.h
+++ b/kernel/rcu/rcu.h
@@ -262,6 +262,8 @@ static inline bool rcu_stall_is_suppressed_at_boot(void)
return rcu_cpu_stall_suppress_at_boot && !rcu_inkernel_boot_has_ended();
}
+extern int rcu_cpu_stall_notifiers;
+
#ifdef CONFIG_RCU_STALL_COMMON
extern int rcu_cpu_stall_ftrace_dump;
@@ -659,10 +661,10 @@ static inline bool rcu_cpu_beenfullyonline(int cpu) { return true; }
bool rcu_cpu_beenfullyonline(int cpu);
#endif
-#ifdef CONFIG_RCU_STALL_COMMON
+#if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
int rcu_stall_notifier_call_chain(unsigned long val, void *v);
-#else // #ifdef CONFIG_RCU_STALL_COMMON
+#else // #if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
static inline int rcu_stall_notifier_call_chain(unsigned long val, void *v) { return NOTIFY_DONE; }
-#endif // #else // #ifdef CONFIG_RCU_STALL_COMMON
+#endif // #else // #if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
#endif /* __LINUX_RCU_H */
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 30fc9d34e329..7567ca8e743c 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -2450,10 +2450,12 @@ static int rcu_torture_stall(void *args)
unsigned long stop_at;
VERBOSE_TOROUT_STRING("rcu_torture_stall task started");
- ret = rcu_stall_chain_notifier_register(&rcu_torture_stall_block);
- if (ret)
- pr_info("%s: rcu_stall_chain_notifier_register() returned %d, %sexpected.\n",
- __func__, ret, !IS_ENABLED(CONFIG_RCU_STALL_COMMON) ? "un" : "");
+ if (rcu_cpu_stall_notifiers) {
+ ret = rcu_stall_chain_notifier_register(&rcu_torture_stall_block);
+ if (ret)
+ pr_info("%s: rcu_stall_chain_notifier_register() returned %d, %sexpected.\n",
+ __func__, ret, !IS_ENABLED(CONFIG_RCU_STALL_COMMON) ? "un" : "");
+ }
if (stall_cpu_holdoff > 0) {
VERBOSE_TOROUT_STRING("rcu_torture_stall begin holdoff");
schedule_timeout_interruptible(stall_cpu_holdoff * HZ);
@@ -2497,7 +2499,7 @@ static int rcu_torture_stall(void *args)
cur_ops->readunlock(idx);
}
pr_alert("%s end.\n", __func__);
- if (!ret) {
+ if (rcu_cpu_stall_notifiers && !ret) {
ret = rcu_stall_chain_notifier_unregister(&rcu_torture_stall_block);
if (ret)
pr_info("%s: rcu_stall_chain_notifier_unregister() returned %d.\n", __func__, ret);
@@ -3872,7 +3874,9 @@ rcu_torture_init(void)
}
if (fqs_duration < 0)
fqs_duration = 0;
- if (fqs_duration) {
+ if (fqs_holdoff < 0)
+ fqs_holdoff = 0;
+ if (fqs_duration && fqs_holdoff) {
/* Create the fqs thread */
firsterr = torture_create_kthread(rcu_torture_fqs, NULL,
fqs_task);
diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c
index 560e99ec5333..0351a4e83529 100644
--- a/kernel/rcu/srcutree.c
+++ b/kernel/rcu/srcutree.c
@@ -772,20 +772,10 @@ EXPORT_SYMBOL_GPL(__srcu_read_unlock_nmisafe);
*/
static void srcu_gp_start(struct srcu_struct *ssp)
{
- struct srcu_data *sdp;
int state;
- if (smp_load_acquire(&ssp->srcu_sup->srcu_size_state) < SRCU_SIZE_WAIT_BARRIER)
- sdp = per_cpu_ptr(ssp->sda, get_boot_cpu_id());
- else
- sdp = this_cpu_ptr(ssp->sda);
lockdep_assert_held(&ACCESS_PRIVATE(ssp->srcu_sup, lock));
WARN_ON_ONCE(ULONG_CMP_GE(ssp->srcu_sup->srcu_gp_seq, ssp->srcu_sup->srcu_gp_seq_needed));
- spin_lock_rcu_node(sdp); /* Interrupts already disabled. */
- rcu_segcblist_advance(&sdp->srcu_cblist,
- rcu_seq_current(&ssp->srcu_sup->srcu_gp_seq));
- WARN_ON_ONCE(!rcu_segcblist_segempty(&sdp->srcu_cblist, RCU_NEXT_TAIL));
- spin_unlock_rcu_node(sdp); /* Interrupts remain disabled. */
WRITE_ONCE(ssp->srcu_sup->srcu_gp_start, jiffies);
WRITE_ONCE(ssp->srcu_sup->srcu_n_exp_nodelay, 0);
smp_mb(); /* Order prior store to ->srcu_gp_seq_needed vs. GP start. */
@@ -1271,9 +1261,11 @@ static unsigned long srcu_gp_start_if_needed(struct srcu_struct *ssp,
* period (gp_num = X + 8). So acceleration fails.
*/
s = rcu_seq_snap(&ssp->srcu_sup->srcu_gp_seq);
- rcu_segcblist_advance(&sdp->srcu_cblist,
- rcu_seq_current(&ssp->srcu_sup->srcu_gp_seq));
- WARN_ON_ONCE(!rcu_segcblist_accelerate(&sdp->srcu_cblist, s) && rhp);
+ if (rhp) {
+ rcu_segcblist_advance(&sdp->srcu_cblist,
+ rcu_seq_current(&ssp->srcu_sup->srcu_gp_seq));
+ WARN_ON_ONCE(!rcu_segcblist_accelerate(&sdp->srcu_cblist, s));
+ }
if (ULONG_CMP_LT(sdp->srcu_gp_seq_needed, s)) {
sdp->srcu_gp_seq_needed = s;
needgp = true;
@@ -1723,6 +1715,11 @@ static void srcu_invoke_callbacks(struct work_struct *work)
WARN_ON_ONCE(!rcu_segcblist_segempty(&sdp->srcu_cblist, RCU_NEXT_TAIL));
rcu_segcblist_advance(&sdp->srcu_cblist,
rcu_seq_current(&ssp->srcu_sup->srcu_gp_seq));
+ /*
+ * Although this function is theoretically re-entrant, concurrent
+ * callbacks invocation is disallowed to avoid executing an SRCU barrier
+ * too early.
+ */
if (sdp->srcu_cblist_invoking ||
!rcu_segcblist_ready_cbs(&sdp->srcu_cblist)) {
spin_unlock_irq_rcu_node(sdp);
@@ -1753,6 +1750,7 @@ static void srcu_invoke_callbacks(struct work_struct *work)
sdp->srcu_cblist_invoking = false;
more = rcu_segcblist_ready_cbs(&sdp->srcu_cblist);
spin_unlock_irq_rcu_node(sdp);
+ /* An SRCU barrier or callbacks from previous nesting work pending */
if (more)
srcu_schedule_cbs_sdp(sdp, 0);
}
diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
index f54d5782eca0..732ad5b39946 100644
--- a/kernel/rcu/tasks.h
+++ b/kernel/rcu/tasks.h
@@ -975,7 +975,7 @@ static void check_holdout_task(struct task_struct *t,
t->rcu_tasks_nvcsw != READ_ONCE(t->nvcsw) ||
!rcu_tasks_is_holdout(t) ||
(IS_ENABLED(CONFIG_NO_HZ_FULL) &&
- !is_idle_task(t) && t->rcu_tasks_idle_cpu >= 0)) {
+ !is_idle_task(t) && READ_ONCE(t->rcu_tasks_idle_cpu) >= 0)) {
WRITE_ONCE(t->rcu_tasks_holdout, false);
list_del_init(&t->rcu_tasks_holdout_list);
put_task_struct(t);
@@ -993,7 +993,7 @@ static void check_holdout_task(struct task_struct *t,
t, ".I"[is_idle_task(t)],
"N."[cpu < 0 || !tick_nohz_full_cpu(cpu)],
t->rcu_tasks_nvcsw, t->nvcsw, t->rcu_tasks_holdout,
- t->rcu_tasks_idle_cpu, cpu);
+ data_race(t->rcu_tasks_idle_cpu), cpu);
sched_show_task(t);
}
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 3ac3c846105f..1ae851777806 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -2338,6 +2338,8 @@ void rcu_force_quiescent_state(void)
struct rcu_node *rnp;
struct rcu_node *rnp_old = NULL;
+ if (!rcu_gp_in_progress())
+ return;
/* Funnel through hierarchy to reduce memory contention. */
rnp = raw_cpu_read(rcu_data.mynode);
for (; rnp != NULL; rnp = rnp->parent) {
diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h
index ac8e86babe44..5d666428546b 100644
--- a/kernel/rcu/tree_stall.h
+++ b/kernel/rcu/tree_stall.h
@@ -1061,6 +1061,7 @@ static int __init rcu_sysrq_init(void)
}
early_initcall(rcu_sysrq_init);
+#ifdef CONFIG_RCU_CPU_STALL_NOTIFIER
//////////////////////////////////////////////////////////////////////////////
//
@@ -1081,7 +1082,13 @@ static ATOMIC_NOTIFIER_HEAD(rcu_cpu_stall_notifier_list);
*/
int rcu_stall_chain_notifier_register(struct notifier_block *n)
{
- return atomic_notifier_chain_register(&rcu_cpu_stall_notifier_list, n);
+ int rcsn = rcu_cpu_stall_notifiers;
+
+ WARN(1, "Adding %pS() to RCU stall notifier list (%s).\n", n->notifier_call,
+ rcsn ? "possibly suppressing RCU CPU stall warnings" : "failed, so all is well");
+ if (rcsn)
+ return atomic_notifier_chain_register(&rcu_cpu_stall_notifier_list, n);
+ return -EEXIST;
}
EXPORT_SYMBOL_GPL(rcu_stall_chain_notifier_register);
@@ -1115,3 +1122,5 @@ int rcu_stall_notifier_call_chain(unsigned long val, void *v)
{
return atomic_notifier_call_chain(&rcu_cpu_stall_notifier_list, val, v);
}
+
+#endif // #ifdef CONFIG_RCU_CPU_STALL_NOTIFIER
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
index c534d6806d3d..46aaaa9fe339 100644
--- a/kernel/rcu/update.c
+++ b/kernel/rcu/update.c
@@ -538,9 +538,15 @@ long torture_sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
EXPORT_SYMBOL_GPL(torture_sched_setaffinity);
#endif
+int rcu_cpu_stall_notifiers __read_mostly; // !0 = provide stall notifiers (rarely useful)
+EXPORT_SYMBOL_GPL(rcu_cpu_stall_notifiers);
+
#ifdef CONFIG_RCU_STALL_COMMON
int rcu_cpu_stall_ftrace_dump __read_mostly;
module_param(rcu_cpu_stall_ftrace_dump, int, 0644);
+#ifdef CONFIG_RCU_CPU_STALL_NOTIFIER
+module_param(rcu_cpu_stall_notifiers, int, 0444);
+#endif // #ifdef CONFIG_RCU_CPU_STALL_NOTIFIER
int rcu_cpu_stall_suppress __read_mostly; // !0 = suppress stall warnings.
EXPORT_SYMBOL_GPL(rcu_cpu_stall_suppress);
module_param(rcu_cpu_stall_suppress, int, 0644);
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index 95c3c097083e..eece6244f9d2 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -133,7 +133,11 @@ unsigned long get_capacity_ref_freq(struct cpufreq_policy *policy)
if (arch_scale_freq_invariant())
return policy->cpuinfo.max_freq;
- return policy->cur;
+ /*
+ * Apply a 25% margin so that we select a higher frequency than
+ * the current one before the CPU is fully busy:
+ */
+ return policy->cur + (policy->cur >> 2);
}
/**
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 9286f88fcd32..13aaf5e85b81 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -27,6 +27,7 @@
#include <linux/cpu.h>
#include <linux/oom.h>
+#include <asm/local64.h>
#include <asm/local.h>
/*
@@ -317,6 +318,11 @@ struct buffer_data_page {
unsigned char data[] RB_ALIGN_DATA; /* data of buffer page */
};
+struct buffer_data_read_page {
+ unsigned order; /* order of the page */
+ struct buffer_data_page *data; /* actual data, stored in this page */
+};
+
/*
* Note, the buffer_page list must be first. The buffer pages
* are allocated in cache lines, which means that each buffer
@@ -331,6 +337,7 @@ struct buffer_page {
unsigned read; /* index for next read */
local_t entries; /* entries on this page */
unsigned long real_end; /* real end of data */
+ unsigned order; /* order of the page */
struct buffer_data_page *page; /* Actual data page */
};
@@ -361,7 +368,7 @@ static __always_inline unsigned int rb_page_commit(struct buffer_page *bpage)
static void free_buffer_page(struct buffer_page *bpage)
{
- free_page((unsigned long)bpage->page);
+ free_pages((unsigned long)bpage->page, bpage->order);
kfree(bpage);
}
@@ -373,41 +380,6 @@ static inline bool test_time_stamp(u64 delta)
return !!(delta & TS_DELTA_TEST);
}
-#define BUF_PAGE_SIZE (PAGE_SIZE - BUF_PAGE_HDR_SIZE)
-
-/* Max payload is BUF_PAGE_SIZE - header (8bytes) */
-#define BUF_MAX_DATA_SIZE (BUF_PAGE_SIZE - (sizeof(u32) * 2))
-
-int ring_buffer_print_page_header(struct trace_seq *s)
-{
- struct buffer_data_page field;
-
- trace_seq_printf(s, "\tfield: u64 timestamp;\t"
- "offset:0;\tsize:%u;\tsigned:%u;\n",
- (unsigned int)sizeof(field.time_stamp),
- (unsigned int)is_signed_type(u64));
-
- trace_seq_printf(s, "\tfield: local_t commit;\t"
- "offset:%u;\tsize:%u;\tsigned:%u;\n",
- (unsigned int)offsetof(typeof(field), commit),
- (unsigned int)sizeof(field.commit),
- (unsigned int)is_signed_type(long));
-
- trace_seq_printf(s, "\tfield: int overwrite;\t"
- "offset:%u;\tsize:%u;\tsigned:%u;\n",
- (unsigned int)offsetof(typeof(field), commit),
- 1,
- (unsigned int)is_signed_type(long));
-
- trace_seq_printf(s, "\tfield: char data;\t"
- "offset:%u;\tsize:%u;\tsigned:%u;\n",
- (unsigned int)offsetof(typeof(field), data),
- (unsigned int)BUF_PAGE_SIZE,
- (unsigned int)is_signed_type(char));
-
- return !trace_seq_has_overflowed(s);
-}
-
struct rb_irq_work {
struct irq_work work;
wait_queue_head_t waiters;
@@ -463,27 +435,9 @@ enum {
RB_CTX_MAX
};
-#if BITS_PER_LONG == 32
-#define RB_TIME_32
-#endif
-
-/* To test on 64 bit machines */
-//#define RB_TIME_32
-
-#ifdef RB_TIME_32
-
-struct rb_time_struct {
- local_t cnt;
- local_t top;
- local_t bottom;
- local_t msb;
-};
-#else
-#include <asm/local64.h>
struct rb_time_struct {
local64_t time;
};
-#endif
typedef struct rb_time_struct rb_time_t;
#define MAX_NEST 5
@@ -557,6 +511,10 @@ struct trace_buffer {
struct rb_irq_work irq_work;
bool time_stamp_abs;
+
+ unsigned int subbuf_size;
+ unsigned int subbuf_order;
+ unsigned int max_data_size;
};
struct ring_buffer_iter {
@@ -570,150 +528,48 @@ struct ring_buffer_iter {
u64 read_stamp;
u64 page_stamp;
struct ring_buffer_event *event;
+ size_t event_size;
int missed_events;
};
-#ifdef RB_TIME_32
-
-/*
- * On 32 bit machines, local64_t is very expensive. As the ring
- * buffer doesn't need all the features of a true 64 bit atomic,
- * on 32 bit, it uses these functions (64 still uses local64_t).
- *
- * For the ring buffer, 64 bit required operations for the time is
- * the following:
- *
- * - Reads may fail if it interrupted a modification of the time stamp.
- * It will succeed if it did not interrupt another write even if
- * the read itself is interrupted by a write.
- * It returns whether it was successful or not.
- *
- * - Writes always succeed and will overwrite other writes and writes
- * that were done by events interrupting the current write.
- *
- * - A write followed by a read of the same time stamp will always succeed,
- * but may not contain the same value.
- *
- * - A cmpxchg will fail if it interrupted another write or cmpxchg.
- * Other than that, it acts like a normal cmpxchg.
- *
- * The 60 bit time stamp is broken up by 30 bits in a top and bottom half
- * (bottom being the least significant 30 bits of the 60 bit time stamp).
- *
- * The two most significant bits of each half holds a 2 bit counter (0-3).
- * Each update will increment this counter by one.
- * When reading the top and bottom, if the two counter bits match then the
- * top and bottom together make a valid 60 bit number.
- */
-#define RB_TIME_SHIFT 30
-#define RB_TIME_VAL_MASK ((1 << RB_TIME_SHIFT) - 1)
-#define RB_TIME_MSB_SHIFT 60
-
-static inline int rb_time_cnt(unsigned long val)
+int ring_buffer_print_page_header(struct trace_buffer *buffer, struct trace_seq *s)
{
- return (val >> RB_TIME_SHIFT) & 3;
-}
-
-static inline u64 rb_time_val(unsigned long top, unsigned long bottom)
-{
- u64 val;
-
- val = top & RB_TIME_VAL_MASK;
- val <<= RB_TIME_SHIFT;
- val |= bottom & RB_TIME_VAL_MASK;
-
- return val;
-}
-
-static inline bool __rb_time_read(rb_time_t *t, u64 *ret, unsigned long *cnt)
-{
- unsigned long top, bottom, msb;
- unsigned long c;
-
- /*
- * If the read is interrupted by a write, then the cnt will
- * be different. Loop until both top and bottom have been read
- * without interruption.
- */
- do {
- c = local_read(&t->cnt);
- top = local_read(&t->top);
- bottom = local_read(&t->bottom);
- msb = local_read(&t->msb);
- } while (c != local_read(&t->cnt));
-
- *cnt = rb_time_cnt(top);
-
- /* If top, msb or bottom counts don't match, this interrupted a write */
- if (*cnt != rb_time_cnt(msb) || *cnt != rb_time_cnt(bottom))
- return false;
-
- /* The shift to msb will lose its cnt bits */
- *ret = rb_time_val(top, bottom) | ((u64)msb << RB_TIME_MSB_SHIFT);
- return true;
-}
-
-static bool rb_time_read(rb_time_t *t, u64 *ret)
-{
- unsigned long cnt;
-
- return __rb_time_read(t, ret, &cnt);
-}
-
-static inline unsigned long rb_time_val_cnt(unsigned long val, unsigned long cnt)
-{
- return (val & RB_TIME_VAL_MASK) | ((cnt & 3) << RB_TIME_SHIFT);
-}
-
-static inline void rb_time_split(u64 val, unsigned long *top, unsigned long *bottom,
- unsigned long *msb)
-{
- *top = (unsigned long)((val >> RB_TIME_SHIFT) & RB_TIME_VAL_MASK);
- *bottom = (unsigned long)(val & RB_TIME_VAL_MASK);
- *msb = (unsigned long)(val >> RB_TIME_MSB_SHIFT);
-}
+ struct buffer_data_page field;
-static inline void rb_time_val_set(local_t *t, unsigned long val, unsigned long cnt)
-{
- val = rb_time_val_cnt(val, cnt);
- local_set(t, val);
-}
+ trace_seq_printf(s, "\tfield: u64 timestamp;\t"
+ "offset:0;\tsize:%u;\tsigned:%u;\n",
+ (unsigned int)sizeof(field.time_stamp),
+ (unsigned int)is_signed_type(u64));
-static void rb_time_set(rb_time_t *t, u64 val)
-{
- unsigned long cnt, top, bottom, msb;
+ trace_seq_printf(s, "\tfield: local_t commit;\t"
+ "offset:%u;\tsize:%u;\tsigned:%u;\n",
+ (unsigned int)offsetof(typeof(field), commit),
+ (unsigned int)sizeof(field.commit),
+ (unsigned int)is_signed_type(long));
- rb_time_split(val, &top, &bottom, &msb);
+ trace_seq_printf(s, "\tfield: int overwrite;\t"
+ "offset:%u;\tsize:%u;\tsigned:%u;\n",
+ (unsigned int)offsetof(typeof(field), commit),
+ 1,
+ (unsigned int)is_signed_type(long));
- /* Writes always succeed with a valid number even if it gets interrupted. */
- do {
- cnt = local_inc_return(&t->cnt);
- rb_time_val_set(&t->top, top, cnt);
- rb_time_val_set(&t->bottom, bottom, cnt);
- rb_time_val_set(&t->msb, val >> RB_TIME_MSB_SHIFT, cnt);
- } while (cnt != local_read(&t->cnt));
-}
+ trace_seq_printf(s, "\tfield: char data;\t"
+ "offset:%u;\tsize:%u;\tsigned:%u;\n",
+ (unsigned int)offsetof(typeof(field), data),
+ (unsigned int)buffer->subbuf_size,
+ (unsigned int)is_signed_type(char));
-static inline bool
-rb_time_read_cmpxchg(local_t *l, unsigned long expect, unsigned long set)
-{
- return local_try_cmpxchg(l, &expect, set);
+ return !trace_seq_has_overflowed(s);
}
-#else /* 64 bits */
-
-/* local64_t always succeeds */
-
-static inline bool rb_time_read(rb_time_t *t, u64 *ret)
+static inline void rb_time_read(rb_time_t *t, u64 *ret)
{
*ret = local64_read(&t->time);
- return true;
}
static void rb_time_set(rb_time_t *t, u64 val)
{
local64_set(&t->time, val);
}
-#endif
/*
* Enable this to make sure that the event passed to
@@ -820,10 +676,7 @@ u64 ring_buffer_event_time_stamp(struct trace_buffer *buffer,
WARN_ONCE(1, "nest (%d) greater than max", nest);
fail:
- /* Can only fail on 32 bit */
- if (!rb_time_read(&cpu_buffer->write_stamp, &ts))
- /* Screw it, just read the current time */
- ts = rb_time_stamp(cpu_buffer->buffer);
+ rb_time_read(&cpu_buffer->write_stamp, &ts);
return ts;
}
@@ -1619,10 +1472,12 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
list_add(&bpage->list, pages);
- page = alloc_pages_node(cpu_to_node(cpu_buffer->cpu), mflags, 0);
+ page = alloc_pages_node(cpu_to_node(cpu_buffer->cpu), mflags,
+ cpu_buffer->buffer->subbuf_order);
if (!page)
goto free_pages;
bpage->page = page_address(page);
+ bpage->order = cpu_buffer->buffer->subbuf_order;
rb_init_page(bpage->page);
if (user_thread && fatal_signal_pending(current))
@@ -1701,7 +1556,8 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
rb_check_bpage(cpu_buffer, bpage);
cpu_buffer->reader_page = bpage;
- page = alloc_pages_node(cpu_to_node(cpu), GFP_KERNEL, 0);
+
+ page = alloc_pages_node(cpu_to_node(cpu), GFP_KERNEL, cpu_buffer->buffer->subbuf_order);
if (!page)
goto fail_free_reader;
bpage->page = page_address(page);
@@ -1784,7 +1640,14 @@ struct trace_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
if (!zalloc_cpumask_var(&buffer->cpumask, GFP_KERNEL))
goto fail_free_buffer;
- nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
+ /* Default buffer page size - one system page */
+ buffer->subbuf_order = 0;
+ buffer->subbuf_size = PAGE_SIZE - BUF_PAGE_HDR_SIZE;
+
+ /* Max payload is buffer page size - header (8bytes) */
+ buffer->max_data_size = buffer->subbuf_size - (sizeof(u32) * 2);
+
+ nr_pages = DIV_ROUND_UP(size, buffer->subbuf_size);
buffer->flags = flags;
buffer->clock = trace_clock_local;
buffer->reader_lock_key = key;
@@ -2103,7 +1966,7 @@ static void update_pages_handler(struct work_struct *work)
* @size: the new size.
* @cpu_id: the cpu buffer to resize
*
- * Minimum size is 2 * BUF_PAGE_SIZE.
+ * Minimum size is 2 * buffer->subbuf_size.
*
* Returns 0 on success and < 0 on failure.
*/
@@ -2125,7 +1988,7 @@ int ring_buffer_resize(struct trace_buffer *buffer, unsigned long size,
!cpumask_test_cpu(cpu_id, buffer->cpumask))
return 0;
- nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
+ nr_pages = DIV_ROUND_UP(size, buffer->subbuf_size);
/* we need a minimum of two pages */
if (nr_pages < 2)
@@ -2372,7 +2235,7 @@ rb_iter_head_event(struct ring_buffer_iter *iter)
*/
barrier();
- if ((iter->head + length) > commit || length > BUF_PAGE_SIZE)
+ if ((iter->head + length) > commit || length > iter->event_size)
/* Writer corrupted the read? */
goto reset;
@@ -2412,11 +2275,13 @@ rb_commit_index(struct ring_buffer_per_cpu *cpu_buffer)
}
static __always_inline unsigned
-rb_event_index(struct ring_buffer_event *event)
+rb_event_index(struct ring_buffer_per_cpu *cpu_buffer, struct ring_buffer_event *event)
{
unsigned long addr = (unsigned long)event;
- return (addr & ~PAGE_MASK) - BUF_PAGE_HDR_SIZE;
+ addr &= (PAGE_SIZE << cpu_buffer->buffer->subbuf_order) - 1;
+
+ return addr - BUF_PAGE_HDR_SIZE;
}
static void rb_inc_iter(struct ring_buffer_iter *iter)
@@ -2605,6 +2470,7 @@ static inline void
rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer,
unsigned long tail, struct rb_event_info *info)
{
+ unsigned long bsize = READ_ONCE(cpu_buffer->buffer->subbuf_size);
struct buffer_page *tail_page = info->tail_page;
struct ring_buffer_event *event;
unsigned long length = info->length;
@@ -2613,13 +2479,13 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer,
* Only the event that crossed the page boundary
* must fill the old tail_page with padding.
*/
- if (tail >= BUF_PAGE_SIZE) {
+ if (tail >= bsize) {
/*
* If the page was filled, then we still need
* to update the real_end. Reset it to zero
* and the reader will ignore it.
*/
- if (tail == BUF_PAGE_SIZE)
+ if (tail == bsize)
tail_page->real_end = 0;
local_sub(length, &tail_page->write);
@@ -2647,7 +2513,7 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer,
* If we are less than the minimum size, we don't need to
* worry about it.
*/
- if (tail > (BUF_PAGE_SIZE - RB_EVNT_MIN_SIZE)) {
+ if (tail > (bsize - RB_EVNT_MIN_SIZE)) {
/* No room for any events */
/* Mark the rest of the page with padding */
@@ -2662,19 +2528,19 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer,
}
/* Put in a discarded event */
- event->array[0] = (BUF_PAGE_SIZE - tail) - RB_EVNT_HDR_SIZE;
+ event->array[0] = (bsize - tail) - RB_EVNT_HDR_SIZE;
event->type_len = RINGBUF_TYPE_PADDING;
/* time delta must be non zero */
event->time_delta = 1;
/* account for padding bytes */
- local_add(BUF_PAGE_SIZE - tail, &cpu_buffer->entries_bytes);
+ local_add(bsize - tail, &cpu_buffer->entries_bytes);
/* Make sure the padding is visible before the tail_page->write update */
smp_wmb();
/* Set write to end of buffer */
- length = (tail + length) - BUF_PAGE_SIZE;
+ length = (tail + length) - bsize;
local_sub(length, &tail_page->write);
}
@@ -2788,7 +2654,8 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer,
/* Slow path */
static struct ring_buffer_event *
-rb_add_time_stamp(struct ring_buffer_event *event, u64 delta, bool abs)
+rb_add_time_stamp(struct ring_buffer_per_cpu *cpu_buffer,
+ struct ring_buffer_event *event, u64 delta, bool abs)
{
if (abs)
event->type_len = RINGBUF_TYPE_TIME_STAMP;
@@ -2796,7 +2663,7 @@ rb_add_time_stamp(struct ring_buffer_event *event, u64 delta, bool abs)
event->type_len = RINGBUF_TYPE_TIME_EXTEND;
/* Not the first event on the page, or not delta? */
- if (abs || rb_event_index(event)) {
+ if (abs || rb_event_index(cpu_buffer, event)) {
event->time_delta = delta & TS_MASK;
event->array[0] = delta >> TS_SHIFT;
} else {
@@ -2826,7 +2693,7 @@ rb_check_timestamp(struct ring_buffer_per_cpu *cpu_buffer,
(unsigned long long)info->ts,
(unsigned long long)info->before,
(unsigned long long)info->after,
- (unsigned long long)(rb_time_read(&cpu_buffer->write_stamp, &write_stamp) ? write_stamp : 0),
+ (unsigned long long)({rb_time_read(&cpu_buffer->write_stamp, &write_stamp); write_stamp;}),
sched_clock_stable() ? "" :
"If you just came from a suspend/resume,\n"
"please switch to the trace global clock:\n"
@@ -2870,7 +2737,7 @@ static void rb_add_timestamp(struct ring_buffer_per_cpu *cpu_buffer,
if (!abs)
info->delta = 0;
}
- *event = rb_add_time_stamp(*event, info->delta, abs);
+ *event = rb_add_time_stamp(cpu_buffer, *event, info->delta, abs);
*length -= RB_LEN_TIME_EXTEND;
*delta = 0;
}
@@ -2954,10 +2821,10 @@ rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer,
struct buffer_page *bpage;
unsigned long addr;
- new_index = rb_event_index(event);
+ new_index = rb_event_index(cpu_buffer, event);
old_index = new_index + rb_event_ts_length(event);
addr = (unsigned long)event;
- addr &= PAGE_MASK;
+ addr &= ~((PAGE_SIZE << cpu_buffer->buffer->subbuf_order) - 1);
bpage = READ_ONCE(cpu_buffer->tail_page);
@@ -3344,6 +3211,76 @@ EXPORT_SYMBOL_GPL(ring_buffer_unlock_commit);
#define CHECK_FULL_PAGE 1L
#ifdef CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS
+
+static const char *show_irq_str(int bits)
+{
+ const char *type[] = {
+ ".", // 0
+ "s", // 1
+ "h", // 2
+ "Hs", // 3
+ "n", // 4
+ "Ns", // 5
+ "Nh", // 6
+ "NHs", // 7
+ };
+
+ return type[bits];
+}
+
+/* Assume this is an trace event */
+static const char *show_flags(struct ring_buffer_event *event)
+{
+ struct trace_entry *entry;
+ int bits = 0;
+
+ if (rb_event_data_length(event) - RB_EVNT_HDR_SIZE < sizeof(*entry))
+ return "X";
+
+ entry = ring_buffer_event_data(event);
+
+ if (entry->flags & TRACE_FLAG_SOFTIRQ)
+ bits |= 1;
+
+ if (entry->flags & TRACE_FLAG_HARDIRQ)
+ bits |= 2;
+
+ if (entry->flags & TRACE_FLAG_NMI)
+ bits |= 4;
+
+ return show_irq_str(bits);
+}
+
+static const char *show_irq(struct ring_buffer_event *event)
+{
+ struct trace_entry *entry;
+
+ if (rb_event_data_length(event) - RB_EVNT_HDR_SIZE < sizeof(*entry))
+ return "";
+
+ entry = ring_buffer_event_data(event);
+ if (entry->flags & TRACE_FLAG_IRQS_OFF)
+ return "d";
+ return "";
+}
+
+static const char *show_interrupt_level(void)
+{
+ unsigned long pc = preempt_count();
+ unsigned char level = 0;
+
+ if (pc & SOFTIRQ_OFFSET)
+ level |= 1;
+
+ if (pc & HARDIRQ_MASK)
+ level |= 2;
+
+ if (pc & NMI_MASK)
+ level |= 4;
+
+ return show_irq_str(level);
+}
+
static void dump_buffer_page(struct buffer_data_page *bpage,
struct rb_event_info *info,
unsigned long tail)
@@ -3364,34 +3301,57 @@ static void dump_buffer_page(struct buffer_data_page *bpage,
case RINGBUF_TYPE_TIME_EXTEND:
delta = rb_event_time_stamp(event);
ts += delta;
- pr_warn(" [%lld] delta:%lld TIME EXTEND\n", ts, delta);
+ pr_warn(" 0x%x: [%lld] delta:%lld TIME EXTEND\n",
+ e, ts, delta);
break;
case RINGBUF_TYPE_TIME_STAMP:
delta = rb_event_time_stamp(event);
ts = rb_fix_abs_ts(delta, ts);
- pr_warn(" [%lld] absolute:%lld TIME STAMP\n", ts, delta);
+ pr_warn(" 0x%x: [%lld] absolute:%lld TIME STAMP\n",
+ e, ts, delta);
break;
case RINGBUF_TYPE_PADDING:
ts += event->time_delta;
- pr_warn(" [%lld] delta:%d PADDING\n", ts, event->time_delta);
+ pr_warn(" 0x%x: [%lld] delta:%d PADDING\n",
+ e, ts, event->time_delta);
break;
case RINGBUF_TYPE_DATA:
ts += event->time_delta;
- pr_warn(" [%lld] delta:%d\n", ts, event->time_delta);
+ pr_warn(" 0x%x: [%lld] delta:%d %s%s\n",
+ e, ts, event->time_delta,
+ show_flags(event), show_irq(event));
break;
default:
break;
}
}
+ pr_warn("expected end:0x%lx last event actually ended at:0x%x\n", tail, e);
}
static DEFINE_PER_CPU(atomic_t, checking);
static atomic_t ts_dump;
+#define buffer_warn_return(fmt, ...) \
+ do { \
+ /* If another report is happening, ignore this one */ \
+ if (atomic_inc_return(&ts_dump) != 1) { \
+ atomic_dec(&ts_dump); \
+ goto out; \
+ } \
+ atomic_inc(&cpu_buffer->record_disabled); \
+ pr_warn(fmt, ##__VA_ARGS__); \
+ dump_buffer_page(bpage, info, tail); \
+ atomic_dec(&ts_dump); \
+ /* There's some cases in boot up that this can happen */ \
+ if (WARN_ON_ONCE(system_state != SYSTEM_BOOTING)) \
+ /* Do not re-enable checking */ \
+ return; \
+ } while (0)
+
/*
* Check if the current event time stamp matches the deltas on
* the buffer page.
@@ -3445,7 +3405,12 @@ static void check_buffer(struct ring_buffer_per_cpu *cpu_buffer,
case RINGBUF_TYPE_TIME_STAMP:
delta = rb_event_time_stamp(event);
- ts = rb_fix_abs_ts(delta, ts);
+ delta = rb_fix_abs_ts(delta, ts);
+ if (delta < ts) {
+ buffer_warn_return("[CPU: %d]ABSOLUTE TIME WENT BACKWARDS: last ts: %lld absolute ts: %lld\n",
+ cpu_buffer->cpu, ts, delta);
+ }
+ ts = delta;
break;
case RINGBUF_TYPE_PADDING:
@@ -3462,23 +3427,11 @@ static void check_buffer(struct ring_buffer_per_cpu *cpu_buffer,
}
if ((full && ts > info->ts) ||
(!full && ts + info->delta != info->ts)) {
- /* If another report is happening, ignore this one */
- if (atomic_inc_return(&ts_dump) != 1) {
- atomic_dec(&ts_dump);
- goto out;
- }
- atomic_inc(&cpu_buffer->record_disabled);
- /* There's some cases in boot up that this can happen */
- WARN_ON_ONCE(system_state != SYSTEM_BOOTING);
- pr_warn("[CPU: %d]TIME DOES NOT MATCH expected:%lld actual:%lld delta:%lld before:%lld after:%lld%s\n",
- cpu_buffer->cpu,
- ts + info->delta, info->ts, info->delta,
- info->before, info->after,
- full ? " (full)" : "");
- dump_buffer_page(bpage, info, tail);
- atomic_dec(&ts_dump);
- /* Do not re-enable checking */
- return;
+ buffer_warn_return("[CPU: %d]TIME DOES NOT MATCH expected:%lld actual:%lld delta:%lld before:%lld after:%lld%s context:%s\n",
+ cpu_buffer->cpu,
+ ts + info->delta, info->ts, info->delta,
+ info->before, info->after,
+ full ? " (full)" : "", show_interrupt_level());
}
out:
atomic_dec(this_cpu_ptr(&checking));
@@ -3498,16 +3451,14 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
struct ring_buffer_event *event;
struct buffer_page *tail_page;
unsigned long tail, write, w;
- bool a_ok;
- bool b_ok;
/* Don't let the compiler play games with cpu_buffer->tail_page */
tail_page = info->tail_page = READ_ONCE(cpu_buffer->tail_page);
/*A*/ w = local_read(&tail_page->write) & RB_WRITE_MASK;
barrier();
- b_ok = rb_time_read(&cpu_buffer->before_stamp, &info->before);
- a_ok = rb_time_read(&cpu_buffer->write_stamp, &info->after);
+ rb_time_read(&cpu_buffer->before_stamp, &info->before);
+ rb_time_read(&cpu_buffer->write_stamp, &info->after);
barrier();
info->ts = rb_time_stamp(cpu_buffer->buffer);
@@ -3522,7 +3473,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
if (!w) {
/* Use the sub-buffer timestamp */
info->delta = 0;
- } else if (unlikely(!a_ok || !b_ok || info->before != info->after)) {
+ } else if (unlikely(info->before != info->after)) {
info->add_timestamp |= RB_ADD_STAMP_FORCE | RB_ADD_STAMP_EXTEND;
info->length += RB_LEN_TIME_EXTEND;
} else {
@@ -3544,7 +3495,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
tail = write - info->length;
/* See if we shot pass the end of this buffer page */
- if (unlikely(write > BUF_PAGE_SIZE)) {
+ if (unlikely(write > cpu_buffer->buffer->subbuf_size)) {
check_buffer(cpu_buffer, info, CHECK_FULL_PAGE);
return rb_move_tail(cpu_buffer, tail, info);
}
@@ -3571,8 +3522,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
/* SLOW PATH - Interrupted between A and C */
/* Save the old before_stamp */
- a_ok = rb_time_read(&cpu_buffer->before_stamp, &info->before);
- RB_WARN_ON(cpu_buffer, !a_ok);
+ rb_time_read(&cpu_buffer->before_stamp, &info->before);
/*
* Read a new timestamp and update the before_stamp to make
@@ -3584,9 +3534,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
rb_time_set(&cpu_buffer->before_stamp, ts);
barrier();
- /*E*/ a_ok = rb_time_read(&cpu_buffer->write_stamp, &info->after);
- /* Was interrupted before here, write_stamp must be valid */
- RB_WARN_ON(cpu_buffer, !a_ok);
+ /*E*/ rb_time_read(&cpu_buffer->write_stamp, &info->after);
barrier();
/*F*/ if (write == (local_read(&tail_page->write) & RB_WRITE_MASK) &&
info->after == info->before && info->after < ts) {
@@ -3678,7 +3626,7 @@ rb_reserve_next_event(struct trace_buffer *buffer,
if (ring_buffer_time_stamp_abs(cpu_buffer->buffer)) {
add_ts_default = RB_ADD_STAMP_ABSOLUTE;
info.length += RB_LEN_TIME_EXTEND;
- if (info.length > BUF_MAX_DATA_SIZE)
+ if (info.length > cpu_buffer->buffer->max_data_size)
goto out_fail;
} else {
add_ts_default = RB_ADD_STAMP_NONE;
@@ -3753,7 +3701,7 @@ ring_buffer_lock_reserve(struct trace_buffer *buffer, unsigned long length)
if (unlikely(atomic_read(&cpu_buffer->record_disabled)))
goto out;
- if (unlikely(length > BUF_MAX_DATA_SIZE))
+ if (unlikely(length > buffer->max_data_size))
goto out;
if (unlikely(trace_recursive_lock(cpu_buffer)))
@@ -3787,7 +3735,7 @@ rb_decrement_entry(struct ring_buffer_per_cpu *cpu_buffer,
struct buffer_page *bpage = cpu_buffer->commit_page;
struct buffer_page *start;
- addr &= PAGE_MASK;
+ addr &= ~((PAGE_SIZE << cpu_buffer->buffer->subbuf_order) - 1);
/* Do the likely case first */
if (likely(bpage->page == (void *)addr)) {
@@ -3903,7 +3851,7 @@ int ring_buffer_write(struct trace_buffer *buffer,
if (atomic_read(&cpu_buffer->record_disabled))
goto out;
- if (length > BUF_MAX_DATA_SIZE)
+ if (length > buffer->max_data_size)
goto out;
if (unlikely(trace_recursive_lock(cpu_buffer)))
@@ -4483,6 +4431,7 @@ static struct buffer_page *
rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
{
struct buffer_page *reader = NULL;
+ unsigned long bsize = READ_ONCE(cpu_buffer->buffer->subbuf_size);
unsigned long overwrite;
unsigned long flags;
int nr_loops = 0;
@@ -4618,7 +4567,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
#define USECS_WAIT 1000000
for (nr_loops = 0; nr_loops < USECS_WAIT; nr_loops++) {
/* If the write is past the end of page, a writer is still updating it */
- if (likely(!reader || rb_page_write(reader) <= BUF_PAGE_SIZE))
+ if (likely(!reader || rb_page_write(reader) <= bsize))
break;
udelay(1);
@@ -5062,7 +5011,8 @@ ring_buffer_read_prepare(struct trace_buffer *buffer, int cpu, gfp_t flags)
return NULL;
/* Holds the entire event: data and meta data */
- iter->event = kmalloc(BUF_PAGE_SIZE, flags);
+ iter->event_size = buffer->subbuf_size;
+ iter->event = kmalloc(iter->event_size, flags);
if (!iter->event) {
kfree(iter);
return NULL;
@@ -5178,19 +5128,28 @@ EXPORT_SYMBOL_GPL(ring_buffer_iter_advance);
*/
unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu)
{
- /*
- * Earlier, this method returned
- * BUF_PAGE_SIZE * buffer->nr_pages
- * Since the nr_pages field is now removed, we have converted this to
- * return the per cpu buffer value.
- */
if (!cpumask_test_cpu(cpu, buffer->cpumask))
return 0;
- return BUF_PAGE_SIZE * buffer->buffers[cpu]->nr_pages;
+ return buffer->subbuf_size * buffer->buffers[cpu]->nr_pages;
}
EXPORT_SYMBOL_GPL(ring_buffer_size);
+/**
+ * ring_buffer_max_event_size - return the max data size of an event
+ * @buffer: The ring buffer.
+ *
+ * Returns the maximum size an event can be.
+ */
+unsigned long ring_buffer_max_event_size(struct trace_buffer *buffer)
+{
+ /* If abs timestamp is requested, events have a timestamp too */
+ if (ring_buffer_time_stamp_abs(buffer))
+ return buffer->max_data_size - RB_LEN_TIME_EXTEND;
+ return buffer->max_data_size;
+}
+EXPORT_SYMBOL_GPL(ring_buffer_max_event_size);
+
static void rb_clear_buffer_page(struct buffer_page *page)
{
local_set(&page->write, 0);
@@ -5461,6 +5420,9 @@ int ring_buffer_swap_cpu(struct trace_buffer *buffer_a,
if (cpu_buffer_a->nr_pages != cpu_buffer_b->nr_pages)
goto out;
+ if (buffer_a->subbuf_order != buffer_b->subbuf_order)
+ goto out;
+
ret = -EAGAIN;
if (atomic_read(&buffer_a->record_disabled))
@@ -5532,40 +5494,48 @@ EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu);
* Returns:
* The page allocated, or ERR_PTR
*/
-void *ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu)
+struct buffer_data_read_page *
+ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu)
{
struct ring_buffer_per_cpu *cpu_buffer;
- struct buffer_data_page *bpage = NULL;
+ struct buffer_data_read_page *bpage = NULL;
unsigned long flags;
struct page *page;
if (!cpumask_test_cpu(cpu, buffer->cpumask))
return ERR_PTR(-ENODEV);
+ bpage = kzalloc(sizeof(*bpage), GFP_KERNEL);
+ if (!bpage)
+ return ERR_PTR(-ENOMEM);
+
+ bpage->order = buffer->subbuf_order;
cpu_buffer = buffer->buffers[cpu];
local_irq_save(flags);
arch_spin_lock(&cpu_buffer->lock);
if (cpu_buffer->free_page) {
- bpage = cpu_buffer->free_page;
+ bpage->data = cpu_buffer->free_page;
cpu_buffer->free_page = NULL;
}
arch_spin_unlock(&cpu_buffer->lock);
local_irq_restore(flags);
- if (bpage)
+ if (bpage->data)
goto out;
- page = alloc_pages_node(cpu_to_node(cpu),
- GFP_KERNEL | __GFP_NORETRY, 0);
- if (!page)
+ page = alloc_pages_node(cpu_to_node(cpu), GFP_KERNEL | __GFP_NORETRY,
+ cpu_buffer->buffer->subbuf_order);
+ if (!page) {
+ kfree(bpage);
return ERR_PTR(-ENOMEM);
+ }
- bpage = page_address(page);
+ bpage->data = page_address(page);
out:
- rb_init_page(bpage);
+ rb_init_page(bpage->data);
return bpage;
}
@@ -5575,14 +5545,15 @@ EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page);
* ring_buffer_free_read_page - free an allocated read page
* @buffer: the buffer the page was allocate for
* @cpu: the cpu buffer the page came from
- * @data: the page to free
+ * @data_page: the page to free
*
* Free a page allocated from ring_buffer_alloc_read_page.
*/
-void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu, void *data)
+void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu,
+ struct buffer_data_read_page *data_page)
{
struct ring_buffer_per_cpu *cpu_buffer;
- struct buffer_data_page *bpage = data;
+ struct buffer_data_page *bpage = data_page->data;
struct page *page = virt_to_page(bpage);
unsigned long flags;
@@ -5591,8 +5562,12 @@ void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu, void *data
cpu_buffer = buffer->buffers[cpu];
- /* If the page is still in use someplace else, we can't reuse it */
- if (page_ref_count(page) > 1)
+ /*
+ * If the page is still in use someplace else, or order of the page
+ * is different from the subbuffer order of the buffer -
+ * we can't reuse it
+ */
+ if (page_ref_count(page) > 1 || data_page->order != buffer->subbuf_order)
goto out;
local_irq_save(flags);
@@ -5607,7 +5582,8 @@ void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu, void *data
local_irq_restore(flags);
out:
- free_page((unsigned long)bpage);
+ free_pages((unsigned long)bpage, data_page->order);
+ kfree(data_page);
}
EXPORT_SYMBOL_GPL(ring_buffer_free_read_page);
@@ -5628,9 +5604,10 @@ EXPORT_SYMBOL_GPL(ring_buffer_free_read_page);
* rpage = ring_buffer_alloc_read_page(buffer, cpu);
* if (IS_ERR(rpage))
* return PTR_ERR(rpage);
- * ret = ring_buffer_read_page(buffer, &rpage, len, cpu, 0);
+ * ret = ring_buffer_read_page(buffer, rpage, len, cpu, 0);
* if (ret >= 0)
- * process_page(rpage, ret);
+ * process_page(ring_buffer_read_page_data(rpage), ret);
+ * ring_buffer_free_read_page(buffer, cpu, rpage);
*
* When @full is set, the function will not return true unless
* the writer is off the reader page.
@@ -5645,7 +5622,8 @@ EXPORT_SYMBOL_GPL(ring_buffer_free_read_page);
* <0 if no data has been transferred.
*/
int ring_buffer_read_page(struct trace_buffer *buffer,
- void **data_page, size_t len, int cpu, int full)
+ struct buffer_data_read_page *data_page,
+ size_t len, int cpu, int full)
{
struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu];
struct ring_buffer_event *event;
@@ -5670,10 +5648,12 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
len -= BUF_PAGE_HDR_SIZE;
- if (!data_page)
+ if (!data_page || !data_page->data)
+ goto out;
+ if (data_page->order != buffer->subbuf_order)
goto out;
- bpage = *data_page;
+ bpage = data_page->data;
if (!bpage)
goto out;
@@ -5767,11 +5747,11 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
/* swap the pages */
rb_init_page(bpage);
bpage = reader->page;
- reader->page = *data_page;
+ reader->page = data_page->data;
local_set(&reader->write, 0);
local_set(&reader->entries, 0);
reader->read = 0;
- *data_page = bpage;
+ data_page->data = bpage;
/*
* Use the real_end for the data size,
@@ -5793,7 +5773,7 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
/* If there is room at the end of the page to save the
* missed events, then record it there.
*/
- if (BUF_PAGE_SIZE - commit >= sizeof(missed_events)) {
+ if (buffer->subbuf_size - commit >= sizeof(missed_events)) {
memcpy(&bpage->data[commit], &missed_events,
sizeof(missed_events));
local_add(RB_MISSED_STORED, &bpage->commit);
@@ -5805,8 +5785,8 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
/*
* This page may be off to user land. Zero it out here.
*/
- if (commit < BUF_PAGE_SIZE)
- memset(&bpage->data[commit], 0, BUF_PAGE_SIZE - commit);
+ if (commit < buffer->subbuf_size)
+ memset(&bpage->data[commit], 0, buffer->subbuf_size - commit);
out_unlock:
raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
@@ -5816,6 +5796,209 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
}
EXPORT_SYMBOL_GPL(ring_buffer_read_page);
+/**
+ * ring_buffer_read_page_data - get pointer to the data in the page.
+ * @page: the page to get the data from
+ *
+ * Returns pointer to the actual data in this page.
+ */
+void *ring_buffer_read_page_data(struct buffer_data_read_page *page)
+{
+ return page->data;
+}
+EXPORT_SYMBOL_GPL(ring_buffer_read_page_data);
+
+/**
+ * ring_buffer_subbuf_size_get - get size of the sub buffer.
+ * @buffer: the buffer to get the sub buffer size from
+ *
+ * Returns size of the sub buffer, in bytes.
+ */
+int ring_buffer_subbuf_size_get(struct trace_buffer *buffer)
+{
+ return buffer->subbuf_size + BUF_PAGE_HDR_SIZE;
+}
+EXPORT_SYMBOL_GPL(ring_buffer_subbuf_size_get);
+
+/**
+ * ring_buffer_subbuf_order_get - get order of system sub pages in one buffer page.
+ * @buffer: The ring_buffer to get the system sub page order from
+ *
+ * By default, one ring buffer sub page equals to one system page. This parameter
+ * is configurable, per ring buffer. The size of the ring buffer sub page can be
+ * extended, but must be an order of system page size.
+ *
+ * Returns the order of buffer sub page size, in system pages:
+ * 0 means the sub buffer size is 1 system page and so forth.
+ * In case of an error < 0 is returned.
+ */
+int ring_buffer_subbuf_order_get(struct trace_buffer *buffer)
+{
+ if (!buffer)
+ return -EINVAL;
+
+ return buffer->subbuf_order;
+}
+EXPORT_SYMBOL_GPL(ring_buffer_subbuf_order_get);
+
+/**
+ * ring_buffer_subbuf_order_set - set the size of ring buffer sub page.
+ * @buffer: The ring_buffer to set the new page size.
+ * @order: Order of the system pages in one sub buffer page
+ *
+ * By default, one ring buffer pages equals to one system page. This API can be
+ * used to set new size of the ring buffer page. The size must be order of
+ * system page size, that's why the input parameter @order is the order of
+ * system pages that are allocated for one ring buffer page:
+ * 0 - 1 system page
+ * 1 - 2 system pages
+ * 3 - 4 system pages
+ * ...
+ *
+ * Returns 0 on success or < 0 in case of an error.
+ */
+int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
+{
+ struct ring_buffer_per_cpu *cpu_buffer;
+ struct buffer_page *bpage, *tmp;
+ int old_order, old_size;
+ int nr_pages;
+ int psize;
+ int err;
+ int cpu;
+
+ if (!buffer || order < 0)
+ return -EINVAL;
+
+ if (buffer->subbuf_order == order)
+ return 0;
+
+ psize = (1 << order) * PAGE_SIZE;
+ if (psize <= BUF_PAGE_HDR_SIZE)
+ return -EINVAL;
+
+ old_order = buffer->subbuf_order;
+ old_size = buffer->subbuf_size;
+
+ /* prevent another thread from changing buffer sizes */
+ mutex_lock(&buffer->mutex);
+ atomic_inc(&buffer->record_disabled);
+
+ /* Make sure all commits have finished */
+ synchronize_rcu();
+
+ buffer->subbuf_order = order;
+ buffer->subbuf_size = psize - BUF_PAGE_HDR_SIZE;
+
+ /* Make sure all new buffers are allocated, before deleting the old ones */
+ for_each_buffer_cpu(buffer, cpu) {
+
+ if (!cpumask_test_cpu(cpu, buffer->cpumask))
+ continue;
+
+ cpu_buffer = buffer->buffers[cpu];
+
+ /* Update the number of pages to match the new size */
+ nr_pages = old_size * buffer->buffers[cpu]->nr_pages;
+ nr_pages = DIV_ROUND_UP(nr_pages, buffer->subbuf_size);
+
+ /* we need a minimum of two pages */
+ if (nr_pages < 2)
+ nr_pages = 2;
+
+ cpu_buffer->nr_pages_to_update = nr_pages;
+
+ /* Include the reader page */
+ nr_pages++;
+
+ /* Allocate the new size buffer */
+ INIT_LIST_HEAD(&cpu_buffer->new_pages);
+ if (__rb_allocate_pages(cpu_buffer, nr_pages,
+ &cpu_buffer->new_pages)) {
+ /* not enough memory for new pages */
+ err = -ENOMEM;
+ goto error;
+ }
+ }
+
+ for_each_buffer_cpu(buffer, cpu) {
+
+ if (!cpumask_test_cpu(cpu, buffer->cpumask))
+ continue;
+
+ cpu_buffer = buffer->buffers[cpu];
+
+ /* Clear the head bit to make the link list normal to read */
+ rb_head_page_deactivate(cpu_buffer);
+
+ /* Now walk the list and free all the old sub buffers */
+ list_for_each_entry_safe(bpage, tmp, cpu_buffer->pages, list) {
+ list_del_init(&bpage->list);
+ free_buffer_page(bpage);
+ }
+ /* The above loop stopped an the last page needing to be freed */
+ bpage = list_entry(cpu_buffer->pages, struct buffer_page, list);
+ free_buffer_page(bpage);
+
+ /* Free the current reader page */
+ free_buffer_page(cpu_buffer->reader_page);
+
+ /* One page was allocated for the reader page */
+ cpu_buffer->reader_page = list_entry(cpu_buffer->new_pages.next,
+ struct buffer_page, list);
+ list_del_init(&cpu_buffer->reader_page->list);
+
+ /* The cpu_buffer pages are a link list with no head */
+ cpu_buffer->pages = cpu_buffer->new_pages.next;
+ cpu_buffer->new_pages.next->prev = cpu_buffer->new_pages.prev;
+ cpu_buffer->new_pages.prev->next = cpu_buffer->new_pages.next;
+
+ /* Clear the new_pages list */
+ INIT_LIST_HEAD(&cpu_buffer->new_pages);
+
+ cpu_buffer->head_page
+ = list_entry(cpu_buffer->pages, struct buffer_page, list);
+ cpu_buffer->tail_page = cpu_buffer->commit_page = cpu_buffer->head_page;
+
+ cpu_buffer->nr_pages = cpu_buffer->nr_pages_to_update;
+ cpu_buffer->nr_pages_to_update = 0;
+
+ free_pages((unsigned long)cpu_buffer->free_page, old_order);
+ cpu_buffer->free_page = NULL;
+
+ rb_head_page_activate(cpu_buffer);
+
+ rb_check_pages(cpu_buffer);
+ }
+
+ atomic_dec(&buffer->record_disabled);
+ mutex_unlock(&buffer->mutex);
+
+ return 0;
+
+error:
+ buffer->subbuf_order = old_order;
+ buffer->subbuf_size = old_size;
+
+ atomic_dec(&buffer->record_disabled);
+ mutex_unlock(&buffer->mutex);
+
+ for_each_buffer_cpu(buffer, cpu) {
+ cpu_buffer = buffer->buffers[cpu];
+
+ if (!cpu_buffer->nr_pages_to_update)
+ continue;
+
+ list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages, list) {
+ list_del_init(&bpage->list);
+ free_buffer_page(bpage);
+ }
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(ring_buffer_subbuf_order_set);
+
/*
* We only allocate new buffers, never free them if the CPU goes down.
* If we were to free the buffer, then the user would lose any trace that was in
diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c
index aef34673d79d..008187ebd7fe 100644
--- a/kernel/trace/ring_buffer_benchmark.c
+++ b/kernel/trace/ring_buffer_benchmark.c
@@ -104,10 +104,11 @@ static enum event_status read_event(int cpu)
static enum event_status read_page(int cpu)
{
+ struct buffer_data_read_page *bpage;
struct ring_buffer_event *event;
struct rb_page *rpage;
unsigned long commit;
- void *bpage;
+ int page_size;
int *entry;
int ret;
int inc;
@@ -117,14 +118,15 @@ static enum event_status read_page(int cpu)
if (IS_ERR(bpage))
return EVENT_DROPPED;
- ret = ring_buffer_read_page(buffer, &bpage, PAGE_SIZE, cpu, 1);
+ page_size = ring_buffer_subbuf_size_get(buffer);
+ ret = ring_buffer_read_page(buffer, bpage, page_size, cpu, 1);
if (ret >= 0) {
- rpage = bpage;
+ rpage = ring_buffer_read_page_data(bpage);
/* The commit may have missed event flags set, clear them */
commit = local_read(&rpage->commit) & 0xfffff;
for (i = 0; i < commit && !test_error ; i += inc) {
- if (i >= (PAGE_SIZE - offsetof(struct rb_page, data))) {
+ if (i >= (page_size - offsetof(struct rb_page, data))) {
TEST_ERROR();
break;
}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index a0defe156b57..2a7c6fd934e9 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1263,10 +1263,17 @@ static void set_buffer_entries(struct array_buffer *buf, unsigned long val);
int tracing_alloc_snapshot_instance(struct trace_array *tr)
{
+ int order;
int ret;
if (!tr->allocated_snapshot) {
+ /* Make the snapshot buffer have the same order as main buffer */
+ order = ring_buffer_subbuf_order_get(tr->array_buffer.buffer);
+ ret = ring_buffer_subbuf_order_set(tr->max_buffer.buffer, order);
+ if (ret < 0)
+ return ret;
+
/* allocate spare buffer */
ret = resize_buffer_duplicate_size(&tr->max_buffer,
&tr->array_buffer, RING_BUFFER_ALL_CPUS);
@@ -1286,6 +1293,7 @@ static void free_snapshot(struct trace_array *tr)
* The max_tr ring buffer has some state (e.g. ring->clock) and
* we want preserve it.
*/
+ ring_buffer_subbuf_order_set(tr->max_buffer.buffer, 0);
ring_buffer_resize(tr->max_buffer.buffer, 1, RING_BUFFER_ALL_CPUS);
set_buffer_entries(&tr->max_buffer, 1);
tracing_reset_online_cpus(&tr->max_buffer);
@@ -3767,7 +3775,7 @@ static bool trace_safe_str(struct trace_iterator *iter, const char *str,
/* OK if part of the temp seq buffer */
if ((addr >= (unsigned long)iter->tmp_seq.buffer) &&
- (addr < (unsigned long)iter->tmp_seq.buffer + PAGE_SIZE))
+ (addr < (unsigned long)iter->tmp_seq.buffer + TRACE_SEQ_BUFFER_SIZE))
return true;
/* Core rodata can not be freed */
@@ -5032,7 +5040,7 @@ static int tracing_release(struct inode *inode, struct file *file)
return 0;
}
-static int tracing_release_generic_tr(struct inode *inode, struct file *file)
+int tracing_release_generic_tr(struct inode *inode, struct file *file)
{
struct trace_array *tr = inode->i_private;
@@ -6946,8 +6954,8 @@ waitagain:
goto out;
}
- if (cnt >= PAGE_SIZE)
- cnt = PAGE_SIZE - 1;
+ if (cnt >= TRACE_SEQ_BUFFER_SIZE)
+ cnt = TRACE_SEQ_BUFFER_SIZE - 1;
/* reset all but tr, trace, and overruns */
trace_iterator_reset(iter);
@@ -7292,8 +7300,9 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
enum event_trigger_type tt = ETT_NONE;
struct trace_buffer *buffer;
struct print_entry *entry;
+ int meta_size;
ssize_t written;
- int size;
+ size_t size;
int len;
/* Used in tracing_mark_raw_write() as well */
@@ -7306,23 +7315,44 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
if (!(tr->trace_flags & TRACE_ITER_MARKERS))
return -EINVAL;
- if (cnt > TRACE_BUF_SIZE)
- cnt = TRACE_BUF_SIZE;
-
- BUILD_BUG_ON(TRACE_BUF_SIZE >= PAGE_SIZE);
+ if ((ssize_t)cnt < 0)
+ return -EINVAL;
- size = sizeof(*entry) + cnt + 2; /* add '\0' and possible '\n' */
+ meta_size = sizeof(*entry) + 2; /* add '\0' and possible '\n' */
+ again:
+ size = cnt + meta_size;
/* If less than "<faulted>", then make sure we can still add that */
if (cnt < FAULTED_SIZE)
size += FAULTED_SIZE - cnt;
+ if (size > TRACE_SEQ_BUFFER_SIZE) {
+ cnt -= size - TRACE_SEQ_BUFFER_SIZE;
+ goto again;
+ }
+
buffer = tr->array_buffer.buffer;
event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
tracing_gen_ctx());
- if (unlikely(!event))
+ if (unlikely(!event)) {
+ /*
+ * If the size was greater than what was allowed, then
+ * make it smaller and try again.
+ */
+ if (size > ring_buffer_max_event_size(buffer)) {
+ /* cnt < FAULTED size should never be bigger than max */
+ if (WARN_ON_ONCE(cnt < FAULTED_SIZE))
+ return -EBADF;
+ cnt = ring_buffer_max_event_size(buffer) - meta_size;
+ /* The above should only happen once */
+ if (WARN_ON_ONCE(cnt + meta_size == size))
+ return -EBADF;
+ goto again;
+ }
+
/* Ring buffer disabled, return as if not open for write */
return -EBADF;
+ }
entry = ring_buffer_event_data(event);
entry->ip = _THIS_IP_;
@@ -7357,9 +7387,6 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
return written;
}
-/* Limit it for now to 3K (including tag) */
-#define RAW_DATA_MAX_SIZE (1024*3)
-
static ssize_t
tracing_mark_raw_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *fpos)
@@ -7381,19 +7408,18 @@ tracing_mark_raw_write(struct file *filp, const char __user *ubuf,
return -EINVAL;
/* The marker must at least have a tag id */
- if (cnt < sizeof(unsigned int) || cnt > RAW_DATA_MAX_SIZE)
+ if (cnt < sizeof(unsigned int))
return -EINVAL;
- if (cnt > TRACE_BUF_SIZE)
- cnt = TRACE_BUF_SIZE;
-
- BUILD_BUG_ON(TRACE_BUF_SIZE >= PAGE_SIZE);
-
size = sizeof(*entry) + cnt;
if (cnt < FAULT_SIZE_ID)
size += FAULT_SIZE_ID - cnt;
buffer = tr->array_buffer.buffer;
+
+ if (size > ring_buffer_max_event_size(buffer))
+ return -EINVAL;
+
event = __trace_buffer_lock_reserve(buffer, TRACE_RAW_DATA, size,
tracing_gen_ctx());
if (!event)
@@ -7578,6 +7604,7 @@ struct ftrace_buffer_info {
struct trace_iterator iter;
void *spare;
unsigned int spare_cpu;
+ unsigned int spare_size;
unsigned int read;
};
@@ -8282,6 +8309,8 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
{
struct ftrace_buffer_info *info = filp->private_data;
struct trace_iterator *iter = &info->iter;
+ void *trace_data;
+ int page_size;
ssize_t ret = 0;
ssize_t size;
@@ -8293,6 +8322,17 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
return -EBUSY;
#endif
+ page_size = ring_buffer_subbuf_size_get(iter->array_buffer->buffer);
+
+ /* Make sure the spare matches the current sub buffer size */
+ if (info->spare) {
+ if (page_size != info->spare_size) {
+ ring_buffer_free_read_page(iter->array_buffer->buffer,
+ info->spare_cpu, info->spare);
+ info->spare = NULL;
+ }
+ }
+
if (!info->spare) {
info->spare = ring_buffer_alloc_read_page(iter->array_buffer->buffer,
iter->cpu_file);
@@ -8301,19 +8341,20 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
info->spare = NULL;
} else {
info->spare_cpu = iter->cpu_file;
+ info->spare_size = page_size;
}
}
if (!info->spare)
return ret;
/* Do we have previous read data to read? */
- if (info->read < PAGE_SIZE)
+ if (info->read < page_size)
goto read;
again:
trace_access_lock(iter->cpu_file);
ret = ring_buffer_read_page(iter->array_buffer->buffer,
- &info->spare,
+ info->spare,
count,
iter->cpu_file, 0);
trace_access_unlock(iter->cpu_file);
@@ -8334,11 +8375,11 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
info->read = 0;
read:
- size = PAGE_SIZE - info->read;
+ size = page_size - info->read;
if (size > count)
size = count;
-
- ret = copy_to_user(ubuf, info->spare + info->read, size);
+ trace_data = ring_buffer_read_page_data(info->spare);
+ ret = copy_to_user(ubuf, trace_data + info->read, size);
if (ret == size)
return -EFAULT;
@@ -8449,6 +8490,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
.spd_release = buffer_spd_release,
};
struct buffer_ref *ref;
+ int page_size;
int entries, i;
ssize_t ret = 0;
@@ -8457,13 +8499,14 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
return -EBUSY;
#endif
- if (*ppos & (PAGE_SIZE - 1))
+ page_size = ring_buffer_subbuf_size_get(iter->array_buffer->buffer);
+ if (*ppos & (page_size - 1))
return -EINVAL;
- if (len & (PAGE_SIZE - 1)) {
- if (len < PAGE_SIZE)
+ if (len & (page_size - 1)) {
+ if (len < page_size)
return -EINVAL;
- len &= PAGE_MASK;
+ len &= (~(page_size - 1));
}
if (splice_grow_spd(pipe, &spd))
@@ -8473,7 +8516,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
trace_access_lock(iter->cpu_file);
entries = ring_buffer_entries_cpu(iter->array_buffer->buffer, iter->cpu_file);
- for (i = 0; i < spd.nr_pages_max && len && entries; i++, len -= PAGE_SIZE) {
+ for (i = 0; i < spd.nr_pages_max && len && entries; i++, len -= page_size) {
struct page *page;
int r;
@@ -8494,7 +8537,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
}
ref->cpu = iter->cpu_file;
- r = ring_buffer_read_page(ref->buffer, &ref->page,
+ r = ring_buffer_read_page(ref->buffer, ref->page,
len, iter->cpu_file, 1);
if (r < 0) {
ring_buffer_free_read_page(ref->buffer, ref->cpu,
@@ -8503,14 +8546,14 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
break;
}
- page = virt_to_page(ref->page);
+ page = virt_to_page(ring_buffer_read_page_data(ref->page));
spd.pages[i] = page;
- spd.partial[i].len = PAGE_SIZE;
+ spd.partial[i].len = page_size;
spd.partial[i].offset = 0;
spd.partial[i].private = (unsigned long)ref;
spd.nr_pages++;
- *ppos += PAGE_SIZE;
+ *ppos += page_size;
entries = ring_buffer_entries_cpu(iter->array_buffer->buffer, iter->cpu_file);
}
@@ -9354,6 +9397,103 @@ static const struct file_operations buffer_percent_fops = {
.llseek = default_llseek,
};
+static ssize_t
+buffer_subbuf_size_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ struct trace_array *tr = filp->private_data;
+ size_t size;
+ char buf[64];
+ int order;
+ int r;
+
+ order = ring_buffer_subbuf_order_get(tr->array_buffer.buffer);
+ size = (PAGE_SIZE << order) / 1024;
+
+ r = sprintf(buf, "%zd\n", size);
+
+ return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+}
+
+static ssize_t
+buffer_subbuf_size_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct trace_array *tr = filp->private_data;
+ unsigned long val;
+ int old_order;
+ int order;
+ int pages;
+ int ret;
+
+ ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
+ if (ret)
+ return ret;
+
+ val *= 1024; /* value passed in is in KB */
+
+ pages = DIV_ROUND_UP(val, PAGE_SIZE);
+ order = fls(pages - 1);
+
+ /* limit between 1 and 128 system pages */
+ if (order < 0 || order > 7)
+ return -EINVAL;
+
+ /* Do not allow tracing while changing the order of the ring buffer */
+ tracing_stop_tr(tr);
+
+ old_order = ring_buffer_subbuf_order_get(tr->array_buffer.buffer);
+ if (old_order == order)
+ goto out;
+
+ ret = ring_buffer_subbuf_order_set(tr->array_buffer.buffer, order);
+ if (ret)
+ goto out;
+
+#ifdef CONFIG_TRACER_MAX_TRACE
+
+ if (!tr->allocated_snapshot)
+ goto out_max;
+
+ ret = ring_buffer_subbuf_order_set(tr->max_buffer.buffer, order);
+ if (ret) {
+ /* Put back the old order */
+ cnt = ring_buffer_subbuf_order_set(tr->array_buffer.buffer, old_order);
+ if (WARN_ON_ONCE(cnt)) {
+ /*
+ * AARGH! We are left with different orders!
+ * The max buffer is our "snapshot" buffer.
+ * When a tracer needs a snapshot (one of the
+ * latency tracers), it swaps the max buffer
+ * with the saved snap shot. We succeeded to
+ * update the order of the main buffer, but failed to
+ * update the order of the max buffer. But when we tried
+ * to reset the main buffer to the original size, we
+ * failed there too. This is very unlikely to
+ * happen, but if it does, warn and kill all
+ * tracing.
+ */
+ tracing_disabled = 1;
+ }
+ goto out;
+ }
+ out_max:
+#endif
+ (*ppos)++;
+ out:
+ if (ret)
+ cnt = ret;
+ tracing_start_tr(tr);
+ return cnt;
+}
+
+static const struct file_operations buffer_subbuf_size_fops = {
+ .open = tracing_open_generic_tr,
+ .read = buffer_subbuf_size_read,
+ .write = buffer_subbuf_size_write,
+ .release = tracing_release_generic_tr,
+ .llseek = default_llseek,
+};
+
static struct dentry *trace_instance_dir;
static void
@@ -9504,7 +9644,8 @@ static int trace_array_create_dir(struct trace_array *tr)
return ret;
}
-static struct trace_array *trace_array_create(const char *name)
+static struct trace_array *
+trace_array_create_systems(const char *name, const char *systems)
{
struct trace_array *tr;
int ret;
@@ -9524,6 +9665,12 @@ static struct trace_array *trace_array_create(const char *name)
if (!zalloc_cpumask_var(&tr->pipe_cpumask, GFP_KERNEL))
goto out_free_tr;
+ if (systems) {
+ tr->system_names = kstrdup_const(systems, GFP_KERNEL);
+ if (!tr->system_names)
+ goto out_free_tr;
+ }
+
tr->trace_flags = global_trace.trace_flags & ~ZEROED_TRACE_FLAGS;
cpumask_copy(tr->tracing_cpumask, cpu_all_mask);
@@ -9570,12 +9717,18 @@ static struct trace_array *trace_array_create(const char *name)
free_trace_buffers(tr);
free_cpumask_var(tr->pipe_cpumask);
free_cpumask_var(tr->tracing_cpumask);
+ kfree_const(tr->system_names);
kfree(tr->name);
kfree(tr);
return ERR_PTR(ret);
}
+static struct trace_array *trace_array_create(const char *name)
+{
+ return trace_array_create_systems(name, NULL);
+}
+
static int instance_mkdir(const char *name)
{
struct trace_array *tr;
@@ -9601,6 +9754,7 @@ out_unlock:
/**
* trace_array_get_by_name - Create/Lookup a trace array, given its name.
* @name: The name of the trace array to be looked up/created.
+ * @systems: A list of systems to create event directories for (NULL for all)
*
* Returns pointer to trace array with given name.
* NULL, if it cannot be created.
@@ -9614,7 +9768,7 @@ out_unlock:
* trace_array_put() is called, user space can not delete it.
*
*/
-struct trace_array *trace_array_get_by_name(const char *name)
+struct trace_array *trace_array_get_by_name(const char *name, const char *systems)
{
struct trace_array *tr;
@@ -9626,7 +9780,7 @@ struct trace_array *trace_array_get_by_name(const char *name)
goto out_unlock;
}
- tr = trace_array_create(name);
+ tr = trace_array_create_systems(name, systems);
if (IS_ERR(tr))
tr = NULL;
@@ -9673,6 +9827,7 @@ static int __remove_instance(struct trace_array *tr)
free_cpumask_var(tr->pipe_cpumask);
free_cpumask_var(tr->tracing_cpumask);
+ kfree_const(tr->system_names);
kfree(tr->name);
kfree(tr);
@@ -9805,6 +9960,9 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
trace_create_file("buffer_percent", TRACE_MODE_WRITE, d_tracer,
tr, &buffer_percent_fops);
+ trace_create_file("buffer_subbuf_size_kb", TRACE_MODE_WRITE, d_tracer,
+ tr, &buffer_subbuf_size_fops);
+
create_trace_options_dir(tr);
#ifdef CONFIG_TRACER_MAX_TRACE
@@ -10391,7 +10549,7 @@ __init static void enable_instances(void)
if (IS_ENABLED(CONFIG_TRACER_MAX_TRACE))
do_allocate_snapshot(tok);
- tr = trace_array_get_by_name(tok);
+ tr = trace_array_get_by_name(tok, NULL);
if (!tr) {
pr_warn("Failed to create instance buffer %s\n", curr_str);
continue;
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 0489e72c8169..00f873910c5d 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -377,6 +377,7 @@ struct trace_array {
unsigned char trace_flags_index[TRACE_FLAGS_MAX_SIZE];
unsigned int flags;
raw_spinlock_t start_lock;
+ const char *system_names;
struct list_head err_log;
struct dentry *dir;
struct dentry *options;
@@ -615,6 +616,7 @@ void tracing_reset_all_online_cpus(void);
void tracing_reset_all_online_cpus_unlocked(void);
int tracing_open_generic(struct inode *inode, struct file *filp);
int tracing_open_generic_tr(struct inode *inode, struct file *filp);
+int tracing_release_generic_tr(struct inode *inode, struct file *file);
int tracing_open_file_tr(struct inode *inode, struct file *filp);
int tracing_release_file_tr(struct inode *inode, struct file *filp);
int tracing_single_release_file_tr(struct inode *inode, struct file *filp);
diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c
index 7ccc7a8e155b..dbe29b4c6a7a 100644
--- a/kernel/trace/trace_boot.c
+++ b/kernel/trace/trace_boot.c
@@ -633,7 +633,7 @@ trace_boot_init_instances(struct xbc_node *node)
if (!p || *p == '\0')
continue;
- tr = trace_array_get_by_name(p);
+ tr = trace_array_get_by_name(p, NULL);
if (!tr) {
pr_err("Failed to get trace instance %s\n", p);
continue;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index f29e815ca5b2..7c364b87352e 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1893,9 +1893,9 @@ subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
}
static ssize_t
-show_header(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
+show_header_page_file(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
{
- int (*func)(struct trace_seq *s) = filp->private_data;
+ struct trace_array *tr = filp->private_data;
struct trace_seq *s;
int r;
@@ -1908,7 +1908,31 @@ show_header(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
trace_seq_init(s);
- func(s);
+ ring_buffer_print_page_header(tr->array_buffer.buffer, s);
+ r = simple_read_from_buffer(ubuf, cnt, ppos,
+ s->buffer, trace_seq_used(s));
+
+ kfree(s);
+
+ return r;
+}
+
+static ssize_t
+show_header_event_file(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ struct trace_seq *s;
+ int r;
+
+ if (*ppos)
+ return 0;
+
+ s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+
+ trace_seq_init(s);
+
+ ring_buffer_print_entry_header(s);
r = simple_read_from_buffer(ubuf, cnt, ppos,
s->buffer, trace_seq_used(s));
@@ -2165,10 +2189,18 @@ static const struct file_operations ftrace_tr_enable_fops = {
.release = subsystem_release,
};
-static const struct file_operations ftrace_show_header_fops = {
- .open = tracing_open_generic,
- .read = show_header,
+static const struct file_operations ftrace_show_header_page_fops = {
+ .open = tracing_open_generic_tr,
+ .read = show_header_page_file,
+ .llseek = default_llseek,
+ .release = tracing_release_generic_tr,
+};
+
+static const struct file_operations ftrace_show_header_event_fops = {
+ .open = tracing_open_generic_tr,
+ .read = show_header_event_file,
.llseek = default_llseek,
+ .release = tracing_release_generic_tr,
};
static int
@@ -2896,6 +2928,27 @@ void trace_event_eval_update(struct trace_eval_map **map, int len)
up_write(&trace_event_sem);
}
+static bool event_in_systems(struct trace_event_call *call,
+ const char *systems)
+{
+ const char *system;
+ const char *p;
+
+ if (!systems)
+ return true;
+
+ system = call->class->system;
+ p = strstr(systems, system);
+ if (!p)
+ return false;
+
+ if (p != systems && !isspace(*(p - 1)) && *(p - 1) != ',')
+ return false;
+
+ p += strlen(system);
+ return !*p || isspace(*p) || *p == ',';
+}
+
static struct trace_event_file *
trace_create_new_event(struct trace_event_call *call,
struct trace_array *tr)
@@ -2905,9 +2958,12 @@ trace_create_new_event(struct trace_event_call *call,
struct trace_event_file *file;
unsigned int first;
+ if (!event_in_systems(call, tr->system_names))
+ return NULL;
+
file = kmem_cache_alloc(file_cachep, GFP_TRACE);
if (!file)
- return NULL;
+ return ERR_PTR(-ENOMEM);
pid_list = rcu_dereference_protected(tr->filtered_pids,
lockdep_is_held(&event_mutex));
@@ -2972,8 +3028,17 @@ __trace_add_new_event(struct trace_event_call *call, struct trace_array *tr)
struct trace_event_file *file;
file = trace_create_new_event(call, tr);
+ /*
+ * trace_create_new_event() returns ERR_PTR(-ENOMEM) if failed
+ * allocation, or NULL if the event is not part of the tr->system_names.
+ * When the event is not part of the tr->system_names, return zero, not
+ * an error.
+ */
if (!file)
- return -ENOMEM;
+ return 0;
+
+ if (IS_ERR(file))
+ return PTR_ERR(file);
if (eventdir_initialized)
return event_create_dir(tr->event_dir, file);
@@ -3012,8 +3077,17 @@ __trace_early_add_new_event(struct trace_event_call *call,
int ret;
file = trace_create_new_event(call, tr);
+ /*
+ * trace_create_new_event() returns ERR_PTR(-ENOMEM) if failed
+ * allocation, or NULL if the event is not part of the tr->system_names.
+ * When the event is not part of the tr->system_names, return zero, not
+ * an error.
+ */
if (!file)
- return -ENOMEM;
+ return 0;
+
+ if (IS_ERR(file))
+ return PTR_ERR(file);
ret = event_define_fields(call);
if (ret)
@@ -3752,17 +3826,16 @@ static int events_callback(const char *name, umode_t *mode, void **data,
return 1;
}
- if (strcmp(name, "header_page") == 0)
- *data = ring_buffer_print_page_header;
-
- else if (strcmp(name, "header_event") == 0)
- *data = ring_buffer_print_entry_header;
+ if (strcmp(name, "header_page") == 0) {
+ *mode = TRACE_MODE_READ;
+ *fops = &ftrace_show_header_page_fops;
- else
+ } else if (strcmp(name, "header_event") == 0) {
+ *mode = TRACE_MODE_READ;
+ *fops = &ftrace_show_header_event_fops;
+ } else
return 0;
- *mode = TRACE_MODE_READ;
- *fops = &ftrace_show_header_fops;
return 1;
}
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 5ecf3c8bde20..6ece1308d36a 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -4805,36 +4805,35 @@ static int parse_actions(struct hist_trigger_data *hist_data)
int len;
for (i = 0; i < hist_data->attrs->n_actions; i++) {
+ enum handler_id hid = 0;
+ char *action_str;
+
str = hist_data->attrs->action_str[i];
- if ((len = str_has_prefix(str, "onmatch("))) {
- char *action_str = str + len;
+ if ((len = str_has_prefix(str, "onmatch(")))
+ hid = HANDLER_ONMATCH;
+ else if ((len = str_has_prefix(str, "onmax(")))
+ hid = HANDLER_ONMAX;
+ else if ((len = str_has_prefix(str, "onchange(")))
+ hid = HANDLER_ONCHANGE;
- data = onmatch_parse(tr, action_str);
- if (IS_ERR(data)) {
- ret = PTR_ERR(data);
- break;
- }
- } else if ((len = str_has_prefix(str, "onmax("))) {
- char *action_str = str + len;
+ action_str = str + len;
- data = track_data_parse(hist_data, action_str,
- HANDLER_ONMAX);
- if (IS_ERR(data)) {
- ret = PTR_ERR(data);
- break;
- }
- } else if ((len = str_has_prefix(str, "onchange("))) {
- char *action_str = str + len;
+ switch (hid) {
+ case HANDLER_ONMATCH:
+ data = onmatch_parse(tr, action_str);
+ break;
+ case HANDLER_ONMAX:
+ case HANDLER_ONCHANGE:
+ data = track_data_parse(hist_data, action_str, hid);
+ break;
+ default:
+ data = ERR_PTR(-EINVAL);
+ break;
+ }
- data = track_data_parse(hist_data, action_str,
- HANDLER_ONCHANGE);
- if (IS_ERR(data)) {
- ret = PTR_ERR(data);
- break;
- }
- } else {
- ret = -EINVAL;
+ if (IS_ERR(data)) {
+ ret = PTR_ERR(data);
break;
}
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 52f8b537dd0a..c4c6e0e0068b 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -487,8 +487,8 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)
return -EINVAL;
if (within_notrace_func(tk)) {
- pr_warn("Could not probe notrace function %s\n",
- trace_kprobe_symbol(tk));
+ pr_warn("Could not probe notrace function %ps\n",
+ (void *)trace_kprobe_address(tk));
return -EINVAL;
}
diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
index 7be97229ddf8..c158d65a8a88 100644
--- a/kernel/trace/trace_seq.c
+++ b/kernel/trace/trace_seq.c
@@ -13,9 +13,6 @@
* trace_seq_init() more than once to reset the trace_seq to start
* from scratch.
*
- * The buffer size is currently PAGE_SIZE, although it may become dynamic
- * in the future.
- *
* A write to the buffer will either succeed or fail. That is, unlike
* sprintf() there will not be a partial write (well it may write into
* the buffer but it wont update the pointers). This allows users to
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 97ce28f4d154..ba25129563ad 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -378,6 +378,8 @@ config DEBUG_INFO_BTF
depends on !GCC_PLUGIN_RANDSTRUCT || COMPILE_TEST
depends on BPF_SYSCALL
depends on !DEBUG_INFO_DWARF5 || PAHOLE_VERSION >= 121
+ # pahole uses elfutils, which does not have support for Hexagon relocations
+ depends on !HEXAGON
help
Generate deduplicated BTF type information from DWARF debug info.
Turning this on expects presence of pahole tool, which will convert
diff --git a/lib/fw_table.c b/lib/fw_table.c
index c49a09ee3853..c3569d2ba503 100644
--- a/lib/fw_table.c
+++ b/lib/fw_table.c
@@ -12,12 +12,14 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/fw_table.h>
enum acpi_subtable_type {
ACPI_SUBTABLE_COMMON,
ACPI_SUBTABLE_HMAT,
ACPI_SUBTABLE_PRMT,
ACPI_SUBTABLE_CEDT,
+ CDAT_SUBTABLE,
};
struct acpi_subtable_entry {
@@ -25,7 +27,7 @@ struct acpi_subtable_entry {
enum acpi_subtable_type type;
};
-static unsigned long __init_or_acpilib
+static unsigned long __init_or_fwtbl_lib
acpi_get_entry_type(struct acpi_subtable_entry *entry)
{
switch (entry->type) {
@@ -37,11 +39,13 @@ acpi_get_entry_type(struct acpi_subtable_entry *entry)
return 0;
case ACPI_SUBTABLE_CEDT:
return entry->hdr->cedt.type;
+ case CDAT_SUBTABLE:
+ return entry->hdr->cdat.type;
}
return 0;
}
-static unsigned long __init_or_acpilib
+static unsigned long __init_or_fwtbl_lib
acpi_get_entry_length(struct acpi_subtable_entry *entry)
{
switch (entry->type) {
@@ -53,11 +57,16 @@ acpi_get_entry_length(struct acpi_subtable_entry *entry)
return entry->hdr->prmt.length;
case ACPI_SUBTABLE_CEDT:
return entry->hdr->cedt.length;
+ case CDAT_SUBTABLE: {
+ __le16 length = (__force __le16)entry->hdr->cdat.length;
+
+ return le16_to_cpu(length);
+ }
}
return 0;
}
-static unsigned long __init_or_acpilib
+static unsigned long __init_or_fwtbl_lib
acpi_get_subtable_header_length(struct acpi_subtable_entry *entry)
{
switch (entry->type) {
@@ -69,11 +78,13 @@ acpi_get_subtable_header_length(struct acpi_subtable_entry *entry)
return sizeof(entry->hdr->prmt);
case ACPI_SUBTABLE_CEDT:
return sizeof(entry->hdr->cedt);
+ case CDAT_SUBTABLE:
+ return sizeof(entry->hdr->cdat);
}
return 0;
}
-static enum acpi_subtable_type __init_or_acpilib
+static enum acpi_subtable_type __init_or_fwtbl_lib
acpi_get_subtable_type(char *id)
{
if (strncmp(id, ACPI_SIG_HMAT, 4) == 0)
@@ -82,12 +93,27 @@ acpi_get_subtable_type(char *id)
return ACPI_SUBTABLE_PRMT;
if (strncmp(id, ACPI_SIG_CEDT, 4) == 0)
return ACPI_SUBTABLE_CEDT;
+ if (strncmp(id, ACPI_SIG_CDAT, 4) == 0)
+ return CDAT_SUBTABLE;
return ACPI_SUBTABLE_COMMON;
}
-static __init_or_acpilib int call_handler(struct acpi_subtable_proc *proc,
- union acpi_subtable_headers *hdr,
- unsigned long end)
+static unsigned long __init_or_fwtbl_lib
+acpi_table_get_length(enum acpi_subtable_type type,
+ union fw_table_header *header)
+{
+ if (type == CDAT_SUBTABLE) {
+ __le32 length = (__force __le32)header->cdat.length;
+
+ return le32_to_cpu(length);
+ }
+
+ return header->acpi.length;
+}
+
+static __init_or_fwtbl_lib int call_handler(struct acpi_subtable_proc *proc,
+ union acpi_subtable_headers *hdr,
+ unsigned long end)
{
if (proc->handler)
return proc->handler(hdr, end);
@@ -119,22 +145,25 @@ static __init_or_acpilib int call_handler(struct acpi_subtable_proc *proc,
* On success returns sum of all matching entries for all proc handlers.
* Otherwise, -ENODEV or -EINVAL is returned.
*/
-int __init_or_acpilib
+int __init_or_fwtbl_lib
acpi_parse_entries_array(char *id, unsigned long table_size,
- struct acpi_table_header *table_header,
+ union fw_table_header *table_header,
struct acpi_subtable_proc *proc,
int proc_num, unsigned int max_entries)
{
unsigned long table_end, subtable_len, entry_len;
struct acpi_subtable_entry entry;
+ enum acpi_subtable_type type;
int count = 0;
int i;
- table_end = (unsigned long)table_header + table_header->length;
+ type = acpi_get_subtable_type(id);
+ table_end = (unsigned long)table_header +
+ acpi_table_get_length(type, table_header);
/* Parse all entries looking for a match. */
- entry.type = acpi_get_subtable_type(id);
+ entry.type = type;
entry.hdr = (union acpi_subtable_headers *)
((unsigned long)table_header + table_size);
subtable_len = acpi_get_subtable_header_length(&entry);
@@ -174,3 +203,25 @@ acpi_parse_entries_array(char *id, unsigned long table_size,
return count;
}
+
+int __init_or_fwtbl_lib
+cdat_table_parse(enum acpi_cdat_type type,
+ acpi_tbl_entry_handler_arg handler_arg,
+ void *arg,
+ struct acpi_table_cdat *table_header)
+{
+ struct acpi_subtable_proc proc = {
+ .id = type,
+ .handler_arg = handler_arg,
+ .arg = arg,
+ };
+
+ if (!table_header)
+ return -EINVAL;
+
+ return acpi_parse_entries_array(ACPI_SIG_CDAT,
+ sizeof(struct acpi_table_cdat),
+ (union fw_table_header *)table_header,
+ &proc, 1, 0);
+}
+EXPORT_SYMBOL_FWTBL_LIB(cdat_table_parse);
diff --git a/mm/Kconfig b/mm/Kconfig
index 1902cfe4cc4f..ffc3a2ba3a8c 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -1258,6 +1258,9 @@ config LOCK_MM_AND_FIND_VMA
bool
depends on !STACK_GROWSUP
+config IOMMU_MM_DATA
+ bool
+
source "mm/damon/Kconfig"
endmenu
diff --git a/mm/compaction.c b/mm/compaction.c
index 27ada42924d5..4add68d40e8d 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -882,6 +882,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
/* Time to isolate some pages for migration */
for (; low_pfn < end_pfn; low_pfn++) {
+ bool is_dirty, is_unevictable;
if (skip_on_failure && low_pfn >= next_skip_pfn) {
/*
@@ -1079,8 +1080,10 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
if (!folio_test_lru(folio))
goto isolate_fail_put;
+ is_unevictable = folio_test_unevictable(folio);
+
/* Compaction might skip unevictable pages but CMA takes them */
- if (!(mode & ISOLATE_UNEVICTABLE) && folio_test_unevictable(folio))
+ if (!(mode & ISOLATE_UNEVICTABLE) && is_unevictable)
goto isolate_fail_put;
/*
@@ -1092,26 +1095,42 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
if ((mode & ISOLATE_ASYNC_MIGRATE) && folio_test_writeback(folio))
goto isolate_fail_put;
- if ((mode & ISOLATE_ASYNC_MIGRATE) && folio_test_dirty(folio)) {
- bool migrate_dirty;
+ is_dirty = folio_test_dirty(folio);
+
+ if (((mode & ISOLATE_ASYNC_MIGRATE) && is_dirty) ||
+ (mapping && is_unevictable)) {
+ bool migrate_dirty = true;
+ bool is_unmovable;
/*
* Only folios without mappings or that have
- * a ->migrate_folio callback are possible to
- * migrate without blocking. However, we may
- * be racing with truncation, which can free
- * the mapping. Truncation holds the folio lock
- * until after the folio is removed from the page
- * cache so holding it ourselves is sufficient.
+ * a ->migrate_folio callback are possible to migrate
+ * without blocking.
+ *
+ * Folios from unmovable mappings are not migratable.
+ *
+ * However, we can be racing with truncation, which can
+ * free the mapping that we need to check. Truncation
+ * holds the folio lock until after the folio is removed
+ * from the page so holding it ourselves is sufficient.
+ *
+ * To avoid locking the folio just to check unmovable,
+ * assume every unmovable folio is also unevictable,
+ * which is a cheaper test. If our assumption goes
+ * wrong, it's not a correctness bug, just potentially
+ * wasted cycles.
*/
if (!folio_trylock(folio))
goto isolate_fail_put;
mapping = folio_mapping(folio);
- migrate_dirty = !mapping ||
- mapping->a_ops->migrate_folio;
+ if ((mode & ISOLATE_ASYNC_MIGRATE) && is_dirty) {
+ migrate_dirty = !mapping ||
+ mapping->a_ops->migrate_folio;
+ }
+ is_unmovable = mapping && mapping_unmovable(mapping);
folio_unlock(folio);
- if (!migrate_dirty)
+ if (!migrate_dirty || is_unmovable)
goto isolate_fail_put;
}
diff --git a/mm/init-mm.c b/mm/init-mm.c
index cfd367822cdd..24c809379274 100644
--- a/mm/init-mm.c
+++ b/mm/init-mm.c
@@ -44,9 +44,6 @@ struct mm_struct init_mm = {
#endif
.user_ns = &init_user_ns,
.cpu_bitmap = CPU_BITS_NONE,
-#ifdef CONFIG_IOMMU_SVA
- .pasid = IOMMU_PASID_INVALID,
-#endif
INIT_MM_CONTEXT(init_mm)
};
diff --git a/mm/kasan/generic.c b/mm/kasan/generic.c
index 24c13dfb1e94..df6627f62402 100644
--- a/mm/kasan/generic.c
+++ b/mm/kasan/generic.c
@@ -487,6 +487,7 @@ void kasan_init_object_meta(struct kmem_cache *cache, const void *object)
__memset(alloc_meta, 0, sizeof(*alloc_meta));
/*
+ * Prepare the lock for saving auxiliary stack traces.
* Temporarily disable KASAN bug reporting to allow instrumented
* raw_spin_lock_init to access aux_lock, which resides inside
* of a redzone.
@@ -510,8 +511,13 @@ static void release_alloc_meta(struct kasan_alloc_meta *meta)
stack_depot_put(meta->aux_stack[0]);
stack_depot_put(meta->aux_stack[1]);
- /* Zero out alloc meta to mark it as invalid. */
- __memset(meta, 0, sizeof(*meta));
+ /*
+ * Zero out alloc meta to mark it as invalid but keep aux_lock
+ * initialized to avoid having to reinitialize it when another object
+ * is allocated in the same slot.
+ */
+ __memset(&meta->alloc_track, 0, sizeof(meta->alloc_track));
+ __memset(meta->aux_stack, 0, sizeof(meta->aux_stack));
}
static void release_free_meta(const void *object, struct kasan_free_meta *meta)
diff --git a/mm/memblock.c b/mm/memblock.c
index 8c194d8afeec..abd92869874d 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1885,7 +1885,7 @@ int __init_memblock memblock_search_pfn_nid(unsigned long pfn,
int mid = memblock_search(type, PFN_PHYS(pfn));
if (mid == -1)
- return -1;
+ return NUMA_NO_NODE;
*start_pfn = PFN_DOWN(type->regions[mid].base);
*end_pfn = PFN_DOWN(type->regions[mid].base + type->regions[mid].size);
diff --git a/mm/memory-tiers.c b/mm/memory-tiers.c
index 8d5291add2bc..5462d9e3c84c 100644
--- a/mm/memory-tiers.c
+++ b/mm/memory-tiers.c
@@ -109,7 +109,7 @@ static struct demotion_nodes *node_demotion __read_mostly;
static BLOCKING_NOTIFIER_HEAD(mt_adistance_algorithms);
static bool default_dram_perf_error;
-static struct node_hmem_attrs default_dram_perf;
+static struct access_coordinate default_dram_perf;
static int default_dram_perf_ref_nid = NUMA_NO_NODE;
static const char *default_dram_perf_ref_source;
@@ -601,15 +601,15 @@ void clear_node_memory_type(int node, struct memory_dev_type *memtype)
}
EXPORT_SYMBOL_GPL(clear_node_memory_type);
-static void dump_hmem_attrs(struct node_hmem_attrs *attrs, const char *prefix)
+static void dump_hmem_attrs(struct access_coordinate *coord, const char *prefix)
{
pr_info(
"%sread_latency: %u, write_latency: %u, read_bandwidth: %u, write_bandwidth: %u\n",
- prefix, attrs->read_latency, attrs->write_latency,
- attrs->read_bandwidth, attrs->write_bandwidth);
+ prefix, coord->read_latency, coord->write_latency,
+ coord->read_bandwidth, coord->write_bandwidth);
}
-int mt_set_default_dram_perf(int nid, struct node_hmem_attrs *perf,
+int mt_set_default_dram_perf(int nid, struct access_coordinate *perf,
const char *source)
{
int rc = 0;
@@ -666,7 +666,7 @@ out:
return rc;
}
-int mt_perf_to_adistance(struct node_hmem_attrs *perf, int *adist)
+int mt_perf_to_adistance(struct access_coordinate *perf, int *adist)
{
if (default_dram_perf_error)
return -EIO;
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index b3c0ff52bb72..21890994c1d3 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -101,9 +101,11 @@ static int set_memmap_mode(const char *val, const struct kernel_param *kp)
static int get_memmap_mode(char *buffer, const struct kernel_param *kp)
{
- if (*((int *)kp->arg) == MEMMAP_ON_MEMORY_FORCE)
- return sprintf(buffer, "force\n");
- return param_get_bool(buffer, kp);
+ int mode = *((int *)kp->arg);
+
+ if (mode == MEMMAP_ON_MEMORY_FORCE)
+ return sprintf(buffer, "force\n");
+ return sprintf(buffer, "%c\n", mode ? 'Y' : 'N');
}
static const struct kernel_param_ops memmap_mode_ops = {
diff --git a/mm/migrate.c b/mm/migrate.c
index bde8273cf15b..cc9f2bcd73b4 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -962,6 +962,8 @@ static int move_to_new_folio(struct folio *dst, struct folio *src,
if (!mapping)
rc = migrate_folio(mapping, dst, src, mode);
+ else if (mapping_unmovable(mapping))
+ rc = -EOPNOTSUPP;
else if (mapping->a_ops->migrate_folio)
/*
* Most folios have a mapping and most filesystems
diff --git a/mm/mm_init.c b/mm/mm_init.c
index 89dc29f1e6c6..2c19f5515e36 100644
--- a/mm/mm_init.c
+++ b/mm/mm_init.c
@@ -26,6 +26,7 @@
#include <linux/pgtable.h>
#include <linux/swap.h>
#include <linux/cma.h>
+#include <linux/crash_dump.h>
#include "internal.h"
#include "slab.h"
#include "shuffle.h"
@@ -381,6 +382,11 @@ static void __init find_zone_movable_pfns_for_nodes(void)
goto out;
}
+ if (is_kdump_kernel()) {
+ pr_warn("The system is under kdump, ignore kernelcore=mirror.\n");
+ goto out;
+ }
+
for_each_mem_region(r) {
if (memblock_is_mirror(r))
continue;
diff --git a/mm/percpu.c b/mm/percpu.c
index 7b97d31df767..4e11fc1e6def 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -3333,13 +3333,7 @@ int __init pcpu_page_first_chunk(size_t reserved_size, pcpu_fc_cpu_to_node_fn_t
if (rc < 0)
panic("failed to map percpu area, err=%d\n", rc);
- /*
- * FIXME: Archs with virtual cache should flush local
- * cache for the linear mapping here - something
- * equivalent to flush_cache_vmap() on the local cpu.
- * flush_cache_vmap() can't be used as most supporting
- * data structures are not set up yet.
- */
+ flush_cache_vmap_early(unit_addr, unit_addr + ai->unit_size);
/* copy static data */
memcpy((void *)unit_addr, __per_cpu_load, ai->static_size);
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 216ab4c8621f..20e3b0d9cf7e 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -1393,6 +1393,12 @@ ssize_t move_pages(struct userfaultfd_ctx *ctx, struct mm_struct *mm,
err = -ENOENT;
break;
}
+ /* Avoid moving zeropages for now */
+ if (is_huge_zero_pmd(*src_pmd)) {
+ spin_unlock(ptl);
+ err = -EBUSY;
+ break;
+ }
/* Check if we can move the pmd without splitting it. */
if (move_splits_huge_pmd(dst_addr, src_addr, src_start + len) ||
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 94ec913dfb76..69c75c041fe1 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -1041,7 +1041,7 @@ static void rfcomm_tty_flush_buffer(struct tty_struct *tty)
tty_wakeup(tty);
}
-static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
+static void rfcomm_tty_send_xchar(struct tty_struct *tty, u8 ch)
{
BT_DBG("tty %p ch %c", tty, ch);
}
diff --git a/samples/ftrace/sample-trace-array.c b/samples/ftrace/sample-trace-array.c
index 6aba02a31c96..d0ee9001c7b3 100644
--- a/samples/ftrace/sample-trace-array.c
+++ b/samples/ftrace/sample-trace-array.c
@@ -105,7 +105,7 @@ static int __init sample_trace_array_init(void)
* NOTE: This function increments the reference counter
* associated with the trace array - "tr".
*/
- tr = trace_array_get_by_name("sample-instance");
+ tr = trace_array_get_by_name("sample-instance", "sched,timer,kprobes");
if (!tr)
return -1;
diff --git a/samples/v4l/v4l2-pci-skeleton.c b/samples/v4l/v4l2-pci-skeleton.c
index 69ef788d9e3b..4fc2063b9f59 100644
--- a/samples/v4l/v4l2-pci-skeleton.c
+++ b/samples/v4l/v4l2-pci-skeleton.c
@@ -155,6 +155,7 @@ static int queue_setup(struct vb2_queue *vq,
unsigned int sizes[], struct device *alloc_devs[])
{
struct skeleton *skel = vb2_get_drv_priv(vq);
+ unsigned int q_num_bufs = vb2_get_num_buffers(vq);
skel->field = skel->format.field;
if (skel->field == V4L2_FIELD_ALTERNATE) {
@@ -167,8 +168,8 @@ static int queue_setup(struct vb2_queue *vq,
skel->field = V4L2_FIELD_TOP;
}
- if (vq->num_buffers + *nbuffers < 3)
- *nbuffers = 3 - vq->num_buffers;
+ if (q_num_bufs + *nbuffers < 3)
+ *nbuffers = 3 - q_num_bufs;
if (*nplanes)
return sizes[0] < skel->format.sizeimage ? -EINVAL : 0;
@@ -820,7 +821,7 @@ static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* available before it can be started. The start_streaming() op
* won't be called until at least this many buffers are queued up.
*/
- q->min_buffers_needed = 2;
+ q->min_queued_buffers = 2;
/*
* The serialization lock for the streaming ioctls. This is the same
* as the main serialization lock, but if some of the non-streaming
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index f8343b34a28b..9c4c4a61bc83 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -512,6 +512,7 @@ our $Attribute = qr{
__ro_after_init|
__kprobes|
$InitAttribute|
+ __aligned\s*\(.*\)|
____cacheline_aligned|
____cacheline_aligned_in_smp|
____cacheline_internodealigned_in_smp|
diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh
index cb980b144ca1..fa5be6f57b00 100755
--- a/scripts/decode_stacktrace.sh
+++ b/scripts/decode_stacktrace.sh
@@ -16,6 +16,21 @@ elif type c++filt >/dev/null 2>&1 ; then
cppfilt_opts=-i
fi
+UTIL_SUFFIX=
+if [[ -z ${LLVM:-} ]]; then
+ UTIL_PREFIX=${CROSS_COMPILE:-}
+else
+ UTIL_PREFIX=llvm-
+ if [[ ${LLVM} == */ ]]; then
+ UTIL_PREFIX=${LLVM}${UTIL_PREFIX}
+ elif [[ ${LLVM} == -* ]]; then
+ UTIL_SUFFIX=${LLVM}
+ fi
+fi
+
+READELF=${UTIL_PREFIX}readelf${UTIL_SUFFIX}
+ADDR2LINE=${UTIL_PREFIX}addr2line${UTIL_SUFFIX}
+
if [[ $1 == "-r" ]] ; then
vmlinux=""
basepath="auto"
@@ -75,7 +90,7 @@ find_module() {
if [[ "$modpath" != "" ]] ; then
for fn in $(find "$modpath" -name "${module//_/[-_]}.ko*") ; do
- if readelf -WS "$fn" | grep -qwF .debug_line ; then
+ if ${READELF} -WS "$fn" | grep -qwF .debug_line ; then
echo $fn
return
fi
@@ -169,7 +184,7 @@ parse_symbol() {
if [[ $aarray_support == true && "${cache[$module,$address]+isset}" == "isset" ]]; then
local code=${cache[$module,$address]}
else
- local code=$(${CROSS_COMPILE}addr2line -i -e "$objfile" "$address" 2>/dev/null)
+ local code=$(${ADDR2LINE} -i -e "$objfile" "$address" 2>/dev/null)
if [[ $aarray_support == true ]]; then
cache[$module,$address]=$code
fi
diff --git a/scripts/tags.sh b/scripts/tags.sh
index a70d43723146..191e0461d6d5 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -3,7 +3,7 @@
# Generate tags or cscope files
# Usage tags.sh <mode>
#
-# mode may be any of: tags, TAGS, cscope
+# mode may be any of: tags, gtags, TAGS, cscope
#
# Uses the following environment variables:
# SUBARCH, SRCARCH, srctree
@@ -50,7 +50,7 @@ fi
find_arch_sources()
{
for i in $archincludedir; do
- prune="$prune -wholename $i -prune -o"
+ local prune="$prune ( -path $i ) -prune -o"
done
find ${tree}arch/$1 $ignore $prune -name "$2" -not -type l -print;
}
@@ -58,7 +58,7 @@ find_arch_sources()
# find sources in arch/$1/include
find_arch_include_sources()
{
- include=$(find ${tree}arch/$1/ -name include -type d -print);
+ local include=$(find ${tree}arch/$1/ -name include -type d -print);
if [ -n "$include" ]; then
archincludedir="$archincludedir $include"
find $include $ignore -name "$2" -not -type l -print;
@@ -81,21 +81,16 @@ find_other_sources()
-name "$1" -not -type l -print;
}
-find_sources()
-{
- find_arch_sources $1 "$2"
-}
-
all_sources()
{
find_arch_include_sources ${SRCARCH} '*.[chS]'
- if [ ! -z "$archinclude" ]; then
+ if [ -n "$archinclude" ]; then
find_arch_include_sources $archinclude '*.[chS]'
fi
find_include_sources '*.[chS]'
for arch in $ALLSOURCE_ARCHS
do
- find_sources $arch '*.[chS]'
+ find_arch_sources $arch '*.[chS]'
done
find_other_sources '*.[chS]'
}
@@ -125,7 +120,7 @@ all_kconfigs()
find ${tree}arch/ -maxdepth 1 $ignore \
-name "Kconfig*" -not -type l -print;
for arch in $ALLSOURCE_ARCHS; do
- find_sources $arch 'Kconfig*'
+ find_arch_sources $arch 'Kconfig*'
done
find_other_sources 'Kconfig*'
}
diff --git a/sound/drivers/serial-generic.c b/sound/drivers/serial-generic.c
index c8db6c75d133..d6e5aafd697c 100644
--- a/sound/drivers/serial-generic.c
+++ b/sound/drivers/serial-generic.c
@@ -100,8 +100,8 @@ static void snd_serial_generic_write_wakeup(struct serdev_device *serdev)
snd_serial_generic_tx_wakeup(drvdata);
}
-static int snd_serial_generic_receive_buf(struct serdev_device *serdev,
- const unsigned char *buf, size_t count)
+static ssize_t snd_serial_generic_receive_buf(struct serdev_device *serdev,
+ const u8 *buf, size_t count)
{
int ret;
struct snd_serial_generic *drvdata = serdev_device_get_drvdata(serdev);
diff --git a/tools/counter/Build b/tools/counter/Build
index 33f4a51d715e..4bbadb7ec93a 100644
--- a/tools/counter/Build
+++ b/tools/counter/Build
@@ -1 +1,2 @@
counter_example-y += counter_example.o
+counter_watch_events-y += counter_watch_events.o
diff --git a/tools/counter/Makefile b/tools/counter/Makefile
index b2c2946f44c9..d82d35a520f6 100644
--- a/tools/counter/Makefile
+++ b/tools/counter/Makefile
@@ -12,9 +12,10 @@ endif
# (this improves performance and avoids hard-to-debug behaviour);
MAKEFLAGS += -r
-override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
+override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include \
+ -I$(srctree)/tools/include
-ALL_TARGETS := counter_example
+ALL_TARGETS := counter_example counter_watch_events
ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
all: $(ALL_PROGRAMS)
@@ -37,12 +38,19 @@ $(COUNTER_EXAMPLE): prepare FORCE
$(OUTPUT)counter_example: $(COUNTER_EXAMPLE)
$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
+COUNTER_WATCH_EVENTS := $(OUTPUT)counter_watch_events.o
+$(COUNTER_WATCH_EVENTS): prepare FORCE
+ $(Q)$(MAKE) $(build)=counter_watch_events
+$(OUTPUT)counter_watch_events: $(COUNTER_WATCH_EVENTS)
+ $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
+
clean:
rm -f $(ALL_PROGRAMS)
rm -rf $(OUTPUT)include/linux/counter.h
rm -df $(OUTPUT)include/linux
rm -df $(OUTPUT)include
find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete
+ find $(or $(OUTPUT),.) -name '\.*.o.cmd' -delete
install: $(ALL_PROGRAMS)
install -d -m 755 $(DESTDIR)$(bindir); \
diff --git a/tools/counter/counter_watch_events.c b/tools/counter/counter_watch_events.c
new file mode 100644
index 000000000000..107631e0f2e3
--- /dev/null
+++ b/tools/counter/counter_watch_events.c
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Counter Watch Events - Test various counter watch events in a userspace application
+ *
+ * Copyright (C) STMicroelectronics 2023 - All Rights Reserved
+ * Author: Fabrice Gasnier <[email protected]>.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <linux/counter.h>
+#include <linux/kernel.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+static struct counter_watch simple_watch[] = {
+ {
+ /* Component data: Count 0 count */
+ .component.type = COUNTER_COMPONENT_COUNT,
+ .component.scope = COUNTER_SCOPE_COUNT,
+ .component.parent = 0,
+ /* Event type: overflow or underflow */
+ .event = COUNTER_EVENT_OVERFLOW_UNDERFLOW,
+ /* Device event channel 0 */
+ .channel = 0,
+ },
+};
+
+static const char * const counter_event_type_name[] = {
+ "COUNTER_EVENT_OVERFLOW",
+ "COUNTER_EVENT_UNDERFLOW",
+ "COUNTER_EVENT_OVERFLOW_UNDERFLOW",
+ "COUNTER_EVENT_THRESHOLD",
+ "COUNTER_EVENT_INDEX",
+ "COUNTER_EVENT_CHANGE_OF_STATE",
+ "COUNTER_EVENT_CAPTURE",
+};
+
+static const char * const counter_component_type_name[] = {
+ "COUNTER_COMPONENT_NONE",
+ "COUNTER_COMPONENT_SIGNAL",
+ "COUNTER_COMPONENT_COUNT",
+ "COUNTER_COMPONENT_FUNCTION",
+ "COUNTER_COMPONENT_SYNAPSE_ACTION",
+ "COUNTER_COMPONENT_EXTENSION",
+};
+
+static const char * const counter_scope_name[] = {
+ "COUNTER_SCOPE_DEVICE",
+ "COUNTER_SCOPE_SIGNAL",
+ "COUNTER_SCOPE_COUNT",
+};
+
+static void print_watch(struct counter_watch *watch, int nwatch)
+{
+ int i;
+
+ /* prints the watch array in C-like structure */
+ printf("watch[%d] = {\n", nwatch);
+ for (i = 0; i < nwatch; i++) {
+ printf(" [%d] =\t{\n"
+ "\t\t.component.type = %s\n"
+ "\t\t.component.scope = %s\n"
+ "\t\t.component.parent = %d\n"
+ "\t\t.component.id = %d\n"
+ "\t\t.event = %s\n"
+ "\t\t.channel = %d\n"
+ "\t},\n",
+ i,
+ counter_component_type_name[watch[i].component.type],
+ counter_scope_name[watch[i].component.scope],
+ watch[i].component.parent,
+ watch[i].component.id,
+ counter_event_type_name[watch[i].event],
+ watch[i].channel);
+ }
+ printf("};\n");
+}
+
+static void print_usage(void)
+{
+ fprintf(stderr, "Usage:\n\n"
+ "counter_watch_events [options] [-w <watchoptions>]\n"
+ "counter_watch_events [options] [-w <watch1 options>] [-w <watch2 options>]...\n"
+ "\n"
+ "When no --watch option has been provided, simple watch example is used:\n"
+ "counter_watch_events [options] -w comp_count,scope_count,evt_ovf_udf\n"
+ "\n"
+ "Test various watch events for given counter device.\n"
+ "\n"
+ "Options:\n"
+ " -d, --debug Prints debug information\n"
+ " -h, --help Prints usage\n"
+ " -n, --device-num <n> Use /dev/counter<n> [default: /dev/counter0]\n"
+ " -l, --loop <n> Loop for <n> events [default: 0 (forever)]\n"
+ " -w, --watch <watchoptions> comma-separated list of watch options\n"
+ "\n"
+ "Watch options:\n"
+ " scope_device (COUNTER_SCOPE_DEVICE) [default: scope_device]\n"
+ " scope_signal (COUNTER_SCOPE_SIGNAL)\n"
+ " scope_count (COUNTER_SCOPE_COUNT)\n"
+ "\n"
+ " comp_none (COUNTER_COMPONENT_NONE) [default: comp_none]\n"
+ " comp_signal (COUNTER_COMPONENT_SIGNAL)\n"
+ " comp_count (COUNTER_COMPONENT_COUNT)\n"
+ " comp_function (COUNTER_COMPONENT_FUNCTION)\n"
+ " comp_synapse_action (COUNTER_COMPONENT_SYNAPSE_ACTION)\n"
+ " comp_extension (COUNTER_COMPONENT_EXTENSION)\n"
+ "\n"
+ " evt_ovf (COUNTER_EVENT_OVERFLOW) [default: evt_ovf]\n"
+ " evt_udf (COUNTER_EVENT_UNDERFLOW)\n"
+ " evt_ovf_udf (COUNTER_EVENT_OVERFLOW_UNDERFLOW)\n"
+ " evt_threshold (COUNTER_EVENT_THRESHOLD)\n"
+ " evt_index (COUNTER_EVENT_INDEX)\n"
+ " evt_change_of_state (COUNTER_EVENT_CHANGE_OF_STATE)\n"
+ " evt_capture (COUNTER_EVENT_CAPTURE)\n"
+ "\n"
+ " chan=<n> channel <n> for this watch [default: 0]\n"
+ " id=<n> component id <n> for this watch [default: 0]\n"
+ " parent=<n> component parent <n> for this watch [default: 0]\n"
+ "\n"
+ "Example with two watched events:\n\n"
+ "counter_watch_events -d \\\n"
+ "\t-w comp_count,scope_count,evt_ovf_udf \\\n"
+ "\t-w comp_extension,scope_count,evt_capture,id=7,chan=3\n"
+ );
+}
+
+static const struct option longopts[] = {
+ { "debug", no_argument, 0, 'd' },
+ { "help", no_argument, 0, 'h' },
+ { "device-num", required_argument, 0, 'n' },
+ { "loop", required_argument, 0, 'l' },
+ { "watch", required_argument, 0, 'w' },
+ { },
+};
+
+/* counter watch subopts */
+enum {
+ WATCH_SCOPE_DEVICE,
+ WATCH_SCOPE_SIGNAL,
+ WATCH_SCOPE_COUNT,
+ WATCH_COMPONENT_NONE,
+ WATCH_COMPONENT_SIGNAL,
+ WATCH_COMPONENT_COUNT,
+ WATCH_COMPONENT_FUNCTION,
+ WATCH_COMPONENT_SYNAPSE_ACTION,
+ WATCH_COMPONENT_EXTENSION,
+ WATCH_EVENT_OVERFLOW,
+ WATCH_EVENT_UNDERFLOW,
+ WATCH_EVENT_OVERFLOW_UNDERFLOW,
+ WATCH_EVENT_THRESHOLD,
+ WATCH_EVENT_INDEX,
+ WATCH_EVENT_CHANGE_OF_STATE,
+ WATCH_EVENT_CAPTURE,
+ WATCH_CHANNEL,
+ WATCH_ID,
+ WATCH_PARENT,
+ WATCH_SUBOPTS_MAX,
+};
+
+static char * const counter_watch_subopts[WATCH_SUBOPTS_MAX + 1] = {
+ /* component.scope */
+ [WATCH_SCOPE_DEVICE] = "scope_device",
+ [WATCH_SCOPE_SIGNAL] = "scope_signal",
+ [WATCH_SCOPE_COUNT] = "scope_count",
+ /* component.type */
+ [WATCH_COMPONENT_NONE] = "comp_none",
+ [WATCH_COMPONENT_SIGNAL] = "comp_signal",
+ [WATCH_COMPONENT_COUNT] = "comp_count",
+ [WATCH_COMPONENT_FUNCTION] = "comp_function",
+ [WATCH_COMPONENT_SYNAPSE_ACTION] = "comp_synapse_action",
+ [WATCH_COMPONENT_EXTENSION] = "comp_extension",
+ /* event */
+ [WATCH_EVENT_OVERFLOW] = "evt_ovf",
+ [WATCH_EVENT_UNDERFLOW] = "evt_udf",
+ [WATCH_EVENT_OVERFLOW_UNDERFLOW] = "evt_ovf_udf",
+ [WATCH_EVENT_THRESHOLD] = "evt_threshold",
+ [WATCH_EVENT_INDEX] = "evt_index",
+ [WATCH_EVENT_CHANGE_OF_STATE] = "evt_change_of_state",
+ [WATCH_EVENT_CAPTURE] = "evt_capture",
+ /* channel, id, parent */
+ [WATCH_CHANNEL] = "chan",
+ [WATCH_ID] = "id",
+ [WATCH_PARENT] = "parent",
+ /* Empty entry ends the opts array */
+ NULL
+};
+
+int main(int argc, char **argv)
+{
+ int c, fd, i, ret, rc = 0, debug = 0, loop = 0, dev_num = 0, nwatch = 0;
+ struct counter_event event_data;
+ char *device_name = NULL, *subopts, *value;
+ struct counter_watch *watches;
+
+ /*
+ * 1st pass:
+ * - list watch events number to allocate the watch array.
+ * - parse normal options (other than watch options)
+ */
+ while ((c = getopt_long(argc, argv, "dhn:l:w:", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'h':
+ print_usage();
+ return EXIT_SUCCESS;
+ case 'n':
+ dev_num = strtoul(optarg, NULL, 10);
+ if (errno) {
+ perror("strtol failed: --device-num <n>\n");
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'l':
+ loop = strtol(optarg, NULL, 10);
+ if (errno) {
+ perror("strtol failed: --loop <n>\n");
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'w':
+ nwatch++;
+ break;
+ default:
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (nwatch) {
+ watches = calloc(nwatch, sizeof(*watches));
+ if (!watches) {
+ perror("Error allocating watches\n");
+ return EXIT_FAILURE;
+ }
+ } else {
+ /* default to simple watch example */
+ watches = simple_watch;
+ nwatch = ARRAY_SIZE(simple_watch);
+ }
+
+ /* 2nd pass: parse watch sub-options to fill in watch array */
+ optind = 1;
+ i = 0;
+ while ((c = getopt_long(argc, argv, "dhn:l:w:", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'w':
+ subopts = optarg;
+ while (*subopts != '\0') {
+ ret = getsubopt(&subopts, counter_watch_subopts, &value);
+ switch (ret) {
+ case WATCH_SCOPE_DEVICE:
+ case WATCH_SCOPE_SIGNAL:
+ case WATCH_SCOPE_COUNT:
+ /* match with counter_scope */
+ watches[i].component.scope = ret;
+ break;
+ case WATCH_COMPONENT_NONE:
+ case WATCH_COMPONENT_SIGNAL:
+ case WATCH_COMPONENT_COUNT:
+ case WATCH_COMPONENT_FUNCTION:
+ case WATCH_COMPONENT_SYNAPSE_ACTION:
+ case WATCH_COMPONENT_EXTENSION:
+ /* match counter_component_type: subtract enum value */
+ ret -= WATCH_COMPONENT_NONE;
+ watches[i].component.type = ret;
+ break;
+ case WATCH_EVENT_OVERFLOW:
+ case WATCH_EVENT_UNDERFLOW:
+ case WATCH_EVENT_OVERFLOW_UNDERFLOW:
+ case WATCH_EVENT_THRESHOLD:
+ case WATCH_EVENT_INDEX:
+ case WATCH_EVENT_CHANGE_OF_STATE:
+ case WATCH_EVENT_CAPTURE:
+ /* match counter_event_type: subtract enum value */
+ ret -= WATCH_EVENT_OVERFLOW;
+ watches[i].event = ret;
+ break;
+ case WATCH_CHANNEL:
+ if (!value) {
+ fprintf(stderr, "Invalid chan=<number>\n");
+ rc = EXIT_FAILURE;
+ goto err_free_watches;
+ }
+ watches[i].channel = strtoul(value, NULL, 10);
+ if (errno) {
+ perror("strtoul failed: chan=<number>\n");
+ rc = EXIT_FAILURE;
+ goto err_free_watches;
+ }
+ break;
+ case WATCH_ID:
+ if (!value) {
+ fprintf(stderr, "Invalid id=<number>\n");
+ rc = EXIT_FAILURE;
+ goto err_free_watches;
+ }
+ watches[i].component.id = strtoul(value, NULL, 10);
+ if (errno) {
+ perror("strtoul failed: id=<number>\n");
+ rc = EXIT_FAILURE;
+ goto err_free_watches;
+ }
+ break;
+ case WATCH_PARENT:
+ if (!value) {
+ fprintf(stderr, "Invalid parent=<number>\n");
+ rc = EXIT_FAILURE;
+ goto err_free_watches;
+ }
+ watches[i].component.parent = strtoul(value, NULL, 10);
+ if (errno) {
+ perror("strtoul failed: parent=<number>\n");
+ rc = EXIT_FAILURE;
+ goto err_free_watches;
+ }
+ break;
+ default:
+ fprintf(stderr, "Unknown suboption '%s'\n", value);
+ rc = EXIT_FAILURE;
+ goto err_free_watches;
+ }
+ }
+ i++;
+ break;
+ }
+ }
+
+ if (debug)
+ print_watch(watches, nwatch);
+
+ ret = asprintf(&device_name, "/dev/counter%d", dev_num);
+ if (ret < 0) {
+ fprintf(stderr, "asprintf failed\n");
+ rc = EXIT_FAILURE;
+ goto err_free_watches;
+ }
+
+ if (debug)
+ printf("Opening %s\n", device_name);
+
+ fd = open(device_name, O_RDWR);
+ if (fd == -1) {
+ fprintf(stderr, "Unable to open %s: %s\n", device_name, strerror(errno));
+ free(device_name);
+ rc = EXIT_FAILURE;
+ goto err_free_watches;
+ }
+ free(device_name);
+
+ for (i = 0; i < nwatch; i++) {
+ ret = ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches + i);
+ if (ret == -1) {
+ fprintf(stderr, "Error adding watches[%d]: %s\n", i,
+ strerror(errno));
+ rc = EXIT_FAILURE;
+ goto err_close;
+ }
+ }
+
+ ret = ioctl(fd, COUNTER_ENABLE_EVENTS_IOCTL);
+ if (ret == -1) {
+ perror("Error enabling events");
+ rc = EXIT_FAILURE;
+ goto err_close;
+ }
+
+ for (i = 0; loop <= 0 || i < loop; i++) {
+ ret = read(fd, &event_data, sizeof(event_data));
+ if (ret == -1) {
+ perror("Failed to read event data");
+ rc = EXIT_FAILURE;
+ goto err_close;
+ }
+
+ if (ret != sizeof(event_data)) {
+ fprintf(stderr, "Failed to read event data (got: %d)\n", ret);
+ rc = EXIT_FAILURE;
+ goto err_close;
+ }
+
+ printf("Timestamp: %llu\tData: %llu\t event: %s\tch: %d\n",
+ event_data.timestamp, event_data.value,
+ counter_event_type_name[event_data.watch.event],
+ event_data.watch.channel);
+
+ if (event_data.status) {
+ fprintf(stderr, "Error %d: %s\n", event_data.status,
+ strerror(event_data.status));
+ }
+ }
+
+err_close:
+ close(fd);
+err_free_watches:
+ if (watches != simple_watch)
+ free(watches);
+
+ return rc;
+}
diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c
index 2eaaa7123b04..8073c9e4fe46 100644
--- a/tools/iio/iio_event_monitor.c
+++ b/tools/iio/iio_event_monitor.c
@@ -105,6 +105,8 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_LIGHT_GREEN] = "green",
[IIO_MOD_LIGHT_BLUE] = "blue",
[IIO_MOD_LIGHT_UV] = "uv",
+ [IIO_MOD_LIGHT_UVA] = "uva",
+ [IIO_MOD_LIGHT_UVB] = "uvb",
[IIO_MOD_LIGHT_DUV] = "duv",
[IIO_MOD_QUATERNION] = "quaternion",
[IIO_MOD_TEMP_AMBIENT] = "ambient",
diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild
index 95dc58b94178..0b12c36902d8 100644
--- a/tools/testing/cxl/Kbuild
+++ b/tools/testing/cxl/Kbuild
@@ -58,6 +58,7 @@ cxl_core-y += $(CXL_CORE_SRC)/mbox.o
cxl_core-y += $(CXL_CORE_SRC)/pci.o
cxl_core-y += $(CXL_CORE_SRC)/hdm.o
cxl_core-y += $(CXL_CORE_SRC)/pmu.o
+cxl_core-y += $(CXL_CORE_SRC)/cdat.o
cxl_core-$(CONFIG_TRACING) += $(CXL_CORE_SRC)/trace.o
cxl_core-$(CONFIG_CXL_REGION) += $(CXL_CORE_SRC)/region.o
cxl_core-y += config_check.o
diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c
index f4e517a0c774..a3cdbb2be038 100644
--- a/tools/testing/cxl/test/cxl.c
+++ b/tools/testing/cxl/test/cxl.c
@@ -68,15 +68,19 @@ static struct acpi_device acpi0017_mock;
static struct acpi_device host_bridge[NR_BRIDGES] = {
[0] = {
.handle = &host_bridge[0],
+ .pnp.unique_id = "0",
},
[1] = {
.handle = &host_bridge[1],
+ .pnp.unique_id = "1",
},
[2] = {
.handle = &host_bridge[2],
+ .pnp.unique_id = "2",
},
[3] = {
.handle = &host_bridge[3],
+ .pnp.unique_id = "3",
},
};
diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c
index ee61fa3a2411..35ee41e435ab 100644
--- a/tools/testing/cxl/test/mem.c
+++ b/tools/testing/cxl/test/mem.c
@@ -251,7 +251,8 @@ static int mock_get_event(struct device *dev, struct cxl_mbox_cmd *cmd)
for (i = 0; i < CXL_TEST_EVENT_CNT && !event_log_empty(log); i++) {
memcpy(&pl->records[i], event_get_current(log),
sizeof(pl->records[i]));
- pl->records[i].hdr.handle = event_get_cur_event_handle(log);
+ pl->records[i].event.generic.hdr.handle =
+ event_get_cur_event_handle(log);
log->cur_idx++;
}
@@ -337,87 +338,109 @@ static void cxl_mock_event_trigger(struct device *dev)
}
struct cxl_event_record_raw maint_needed = {
- .hdr = {
- .id = UUID_INIT(0xBA5EBA11, 0xABCD, 0xEFEB,
- 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
- .length = sizeof(struct cxl_event_record_raw),
- .flags[0] = CXL_EVENT_RECORD_FLAG_MAINT_NEEDED,
- /* .handle = Set dynamically */
- .related_handle = cpu_to_le16(0xa5b6),
+ .id = UUID_INIT(0xBA5EBA11, 0xABCD, 0xEFEB,
+ 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
+ .event.generic = {
+ .hdr = {
+ .length = sizeof(struct cxl_event_record_raw),
+ .flags[0] = CXL_EVENT_RECORD_FLAG_MAINT_NEEDED,
+ /* .handle = Set dynamically */
+ .related_handle = cpu_to_le16(0xa5b6),
+ },
+ .data = { 0xDE, 0xAD, 0xBE, 0xEF },
},
- .data = { 0xDE, 0xAD, 0xBE, 0xEF },
};
struct cxl_event_record_raw hardware_replace = {
- .hdr = {
- .id = UUID_INIT(0xABCDEFEB, 0xBA11, 0xBA5E,
- 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
- .length = sizeof(struct cxl_event_record_raw),
- .flags[0] = CXL_EVENT_RECORD_FLAG_HW_REPLACE,
- /* .handle = Set dynamically */
- .related_handle = cpu_to_le16(0xb6a5),
+ .id = UUID_INIT(0xABCDEFEB, 0xBA11, 0xBA5E,
+ 0xa5, 0x5a, 0xa5, 0x5a, 0xa5, 0xa5, 0x5a, 0xa5),
+ .event.generic = {
+ .hdr = {
+ .length = sizeof(struct cxl_event_record_raw),
+ .flags[0] = CXL_EVENT_RECORD_FLAG_HW_REPLACE,
+ /* .handle = Set dynamically */
+ .related_handle = cpu_to_le16(0xb6a5),
+ },
+ .data = { 0xDE, 0xAD, 0xBE, 0xEF },
},
- .data = { 0xDE, 0xAD, 0xBE, 0xEF },
};
-struct cxl_event_gen_media gen_media = {
- .hdr = {
- .id = UUID_INIT(0xfbcd0a77, 0xc260, 0x417f,
- 0x85, 0xa9, 0x08, 0x8b, 0x16, 0x21, 0xeb, 0xa6),
- .length = sizeof(struct cxl_event_gen_media),
- .flags[0] = CXL_EVENT_RECORD_FLAG_PERMANENT,
- /* .handle = Set dynamically */
- .related_handle = cpu_to_le16(0),
+struct cxl_test_gen_media {
+ uuid_t id;
+ struct cxl_event_gen_media rec;
+} __packed;
+
+struct cxl_test_gen_media gen_media = {
+ .id = CXL_EVENT_GEN_MEDIA_UUID,
+ .rec = {
+ .hdr = {
+ .length = sizeof(struct cxl_test_gen_media),
+ .flags[0] = CXL_EVENT_RECORD_FLAG_PERMANENT,
+ /* .handle = Set dynamically */
+ .related_handle = cpu_to_le16(0),
+ },
+ .phys_addr = cpu_to_le64(0x2000),
+ .descriptor = CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT,
+ .type = CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR,
+ .transaction_type = CXL_GMER_TRANS_HOST_WRITE,
+ /* .validity_flags = <set below> */
+ .channel = 1,
+ .rank = 30
},
- .phys_addr = cpu_to_le64(0x2000),
- .descriptor = CXL_GMER_EVT_DESC_UNCORECTABLE_EVENT,
- .type = CXL_GMER_MEM_EVT_TYPE_DATA_PATH_ERROR,
- .transaction_type = CXL_GMER_TRANS_HOST_WRITE,
- /* .validity_flags = <set below> */
- .channel = 1,
- .rank = 30
};
-struct cxl_event_dram dram = {
- .hdr = {
- .id = UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab,
- 0xb8, 0xaf, 0x4e, 0x9b, 0xfb, 0x5c, 0x96, 0x24),
- .length = sizeof(struct cxl_event_dram),
- .flags[0] = CXL_EVENT_RECORD_FLAG_PERF_DEGRADED,
- /* .handle = Set dynamically */
- .related_handle = cpu_to_le16(0),
+struct cxl_test_dram {
+ uuid_t id;
+ struct cxl_event_dram rec;
+} __packed;
+
+struct cxl_test_dram dram = {
+ .id = CXL_EVENT_DRAM_UUID,
+ .rec = {
+ .hdr = {
+ .length = sizeof(struct cxl_test_dram),
+ .flags[0] = CXL_EVENT_RECORD_FLAG_PERF_DEGRADED,
+ /* .handle = Set dynamically */
+ .related_handle = cpu_to_le16(0),
+ },
+ .phys_addr = cpu_to_le64(0x8000),
+ .descriptor = CXL_GMER_EVT_DESC_THRESHOLD_EVENT,
+ .type = CXL_GMER_MEM_EVT_TYPE_INV_ADDR,
+ .transaction_type = CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB,
+ /* .validity_flags = <set below> */
+ .channel = 1,
+ .bank_group = 5,
+ .bank = 2,
+ .column = {0xDE, 0xAD},
},
- .phys_addr = cpu_to_le64(0x8000),
- .descriptor = CXL_GMER_EVT_DESC_THRESHOLD_EVENT,
- .type = CXL_GMER_MEM_EVT_TYPE_INV_ADDR,
- .transaction_type = CXL_GMER_TRANS_INTERNAL_MEDIA_SCRUB,
- /* .validity_flags = <set below> */
- .channel = 1,
- .bank_group = 5,
- .bank = 2,
- .column = {0xDE, 0xAD},
};
-struct cxl_event_mem_module mem_module = {
- .hdr = {
- .id = UUID_INIT(0xfe927475, 0xdd59, 0x4339,
- 0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74),
- .length = sizeof(struct cxl_event_mem_module),
- /* .handle = Set dynamically */
- .related_handle = cpu_to_le16(0),
+struct cxl_test_mem_module {
+ uuid_t id;
+ struct cxl_event_mem_module rec;
+} __packed;
+
+struct cxl_test_mem_module mem_module = {
+ .id = CXL_EVENT_MEM_MODULE_UUID,
+ .rec = {
+ .hdr = {
+ .length = sizeof(struct cxl_test_mem_module),
+ /* .handle = Set dynamically */
+ .related_handle = cpu_to_le16(0),
+ },
+ .event_type = CXL_MMER_TEMP_CHANGE,
+ .info = {
+ .health_status = CXL_DHI_HS_PERFORMANCE_DEGRADED,
+ .media_status = CXL_DHI_MS_ALL_DATA_LOST,
+ .add_status = (CXL_DHI_AS_CRITICAL << 2) |
+ (CXL_DHI_AS_WARNING << 4) |
+ (CXL_DHI_AS_WARNING << 5),
+ .device_temp = { 0xDE, 0xAD},
+ .dirty_shutdown_cnt = { 0xde, 0xad, 0xbe, 0xef },
+ .cor_vol_err_cnt = { 0xde, 0xad, 0xbe, 0xef },
+ .cor_per_err_cnt = { 0xde, 0xad, 0xbe, 0xef },
+ }
},
- .event_type = CXL_MMER_TEMP_CHANGE,
- .info = {
- .health_status = CXL_DHI_HS_PERFORMANCE_DEGRADED,
- .media_status = CXL_DHI_MS_ALL_DATA_LOST,
- .add_status = (CXL_DHI_AS_CRITICAL << 2) |
- (CXL_DHI_AS_WARNING << 4) |
- (CXL_DHI_AS_WARNING << 5),
- .device_temp = { 0xDE, 0xAD},
- .dirty_shutdown_cnt = { 0xde, 0xad, 0xbe, 0xef },
- .cor_vol_err_cnt = { 0xde, 0xad, 0xbe, 0xef },
- .cor_per_err_cnt = { 0xde, 0xad, 0xbe, 0xef },
- }
};
static int mock_set_timestamp(struct cxl_dev_state *cxlds,
@@ -439,11 +462,11 @@ static int mock_set_timestamp(struct cxl_dev_state *cxlds,
static void cxl_mock_add_event_logs(struct mock_event_store *mes)
{
put_unaligned_le16(CXL_GMER_VALID_CHANNEL | CXL_GMER_VALID_RANK,
- &gen_media.validity_flags);
+ &gen_media.rec.validity_flags);
put_unaligned_le16(CXL_DER_VALID_CHANNEL | CXL_DER_VALID_BANK_GROUP |
CXL_DER_VALID_BANK | CXL_DER_VALID_COLUMN,
- &dram.validity_flags);
+ &dram.rec.validity_flags);
mes_add_event(mes, CXL_EVENT_TYPE_INFO, &maint_needed);
mes_add_event(mes, CXL_EVENT_TYPE_INFO,
diff --git a/tools/testing/nvdimm/test/Kbuild b/tools/testing/nvdimm/test/Kbuild
index 197bcb2b7f35..003d48f5f24f 100644
--- a/tools/testing/nvdimm/test/Kbuild
+++ b/tools/testing/nvdimm/test/Kbuild
@@ -7,6 +7,7 @@ obj-m += nfit_test_iomap.o
ifeq ($(CONFIG_ACPI_NFIT),m)
nfit_test-y := nfit.o
+ obj-m += ndtest.o
else
nfit_test-y := ndtest.o
endif
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/ringbuffer_subbuf_size.tc b/tools/testing/selftests/ftrace/test.d/00basic/ringbuffer_subbuf_size.tc
new file mode 100644
index 000000000000..d44d09a33a74
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/00basic/ringbuffer_subbuf_size.tc
@@ -0,0 +1,95 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Change the ringbuffer sub-buffer size
+# requires: buffer_subbuf_size_kb
+# flags: instance
+
+get_buffer_data_size() {
+ sed -ne 's/^.*data.*size:\([0-9][0-9]*\).*/\1/p' events/header_page
+}
+
+get_buffer_data_offset() {
+ sed -ne 's/^.*data.*offset:\([0-9][0-9]*\).*/\1/p' events/header_page
+}
+
+get_event_header_size() {
+ type_len=`sed -ne 's/^.*type_len.*:[^0-9]*\([0-9][0-9]*\).*/\1/p' events/header_event`
+ time_len=`sed -ne 's/^.*time_delta.*:[^0-9]*\([0-9][0-9]*\).*/\1/p' events/header_event`
+ array_len=`sed -ne 's/^.*array.*:[^0-9]*\([0-9][0-9]*\).*/\1/p' events/header_event`
+ total_bits=$((type_len+time_len+array_len))
+ total_bits=$((total_bits+7))
+ echo $((total_bits/8))
+}
+
+get_print_event_buf_offset() {
+ sed -ne 's/^.*buf.*offset:\([0-9][0-9]*\).*/\1/p' events/ftrace/print/format
+}
+
+event_header_size=`get_event_header_size`
+print_header_size=`get_print_event_buf_offset`
+
+data_offset=`get_buffer_data_offset`
+
+marker_meta=$((event_header_size+print_header_size))
+
+make_str() {
+ cnt=$1
+ printf -- 'X%.0s' $(seq $cnt)
+}
+
+write_buffer() {
+ size=$1
+
+ str=`make_str $size`
+
+ # clear the buffer
+ echo > trace
+
+ # write the string into the marker
+ echo $str > trace_marker
+
+ echo $str
+}
+
+test_buffer() {
+ size_kb=$1
+ page_size=$((size_kb*1024))
+
+ size=`get_buffer_data_size`
+
+ # the size must be greater than or equal to page_size - data_offset
+ page_size=$((page_size-data_offset))
+ if [ $size -lt $page_size ]; then
+ exit fail
+ fi
+
+ # Now add a little more the meta data overhead will overflow
+
+ str=`write_buffer $size`
+
+ # Make sure the line was broken
+ new_str=`awk ' /tracing_mark_write:/ { sub(/^.*tracing_mark_write: /,"");printf "%s", $0; exit}' trace`
+
+ if [ "$new_str" = "$str" ]; then
+ exit fail;
+ fi
+
+ # Make sure the entire line can be found
+ new_str=`awk ' /tracing_mark_write:/ { sub(/^.*tracing_mark_write: /,"");printf "%s", $0; }' trace`
+
+ if [ "$new_str" != "$str" ]; then
+ exit fail;
+ fi
+}
+
+ORIG=`cat buffer_subbuf_size_kb`
+
+# Could test bigger sizes than 32K, but then creating the string
+# to write into the ring buffer takes too long
+for a in 4 8 16 32 ; do
+ echo $a > buffer_subbuf_size_kb
+ test_buffer $a
+done
+
+echo $ORIG > buffer_subbuf_size_kb
+
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/trace_marker.tc b/tools/testing/selftests/ftrace/test.d/00basic/trace_marker.tc
new file mode 100644
index 000000000000..9aa0db2b84fc
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/00basic/trace_marker.tc
@@ -0,0 +1,82 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Basic tests on writing to trace_marker
+# requires: trace_marker
+# flags: instance
+
+get_buffer_data_size() {
+ sed -ne 's/^.*data.*size:\([0-9][0-9]*\).*/\1/p' events/header_page
+}
+
+get_buffer_data_offset() {
+ sed -ne 's/^.*data.*offset:\([0-9][0-9]*\).*/\1/p' events/header_page
+}
+
+get_event_header_size() {
+ type_len=`sed -ne 's/^.*type_len.*:[^0-9]*\([0-9][0-9]*\).*/\1/p' events/header_event`
+ time_len=`sed -ne 's/^.*time_delta.*:[^0-9]*\([0-9][0-9]*\).*/\1/p' events/header_event`
+ array_len=`sed -ne 's/^.*array.*:[^0-9]*\([0-9][0-9]*\).*/\1/p' events/header_event`
+ total_bits=$((type_len+time_len+array_len))
+ total_bits=$((total_bits+7))
+ echo $((total_bits/8))
+}
+
+get_print_event_buf_offset() {
+ sed -ne 's/^.*buf.*offset:\([0-9][0-9]*\).*/\1/p' events/ftrace/print/format
+}
+
+event_header_size=`get_event_header_size`
+print_header_size=`get_print_event_buf_offset`
+
+data_offset=`get_buffer_data_offset`
+
+marker_meta=$((event_header_size+print_header_size))
+
+make_str() {
+ cnt=$1
+ # subtract two for \n\0 as marker adds these
+ cnt=$((cnt-2))
+ printf -- 'X%.0s' $(seq $cnt)
+}
+
+write_buffer() {
+ size=$1
+
+ str=`make_str $size`
+
+ # clear the buffer
+ echo > trace
+
+ # write the string into the marker
+ echo -n $str > trace_marker
+
+ echo $str
+}
+
+test_buffer() {
+
+ size=`get_buffer_data_size`
+ oneline_size=$((size-marker_meta))
+ echo size = $size
+ echo meta size = $marker_meta
+
+ # Now add a little more the meta data overhead will overflow
+
+ str=`write_buffer $size`
+
+ # Make sure the line was broken
+ new_str=`awk ' /tracing_mark_write:/ { sub(/^.*tracing_mark_write: /,"");printf "%s", $0; exit}' trace`
+
+ if [ "$new_str" = "$str" ]; then
+ exit fail;
+ fi
+
+ # Make sure the entire line can be found
+ new_str=`awk ' /tracing_mark_write:/ { sub(/^.*tracing_mark_write: /,"");printf "%s", $0; }' trace`
+
+ if [ "$new_str" != "$str" ]; then
+ exit fail;
+ fi
+}
+
+test_buffer
diff --git a/tools/testing/selftests/hid/tests/base.py b/tools/testing/selftests/hid/tests/base.py
index 1305cfc9646e..51433063b227 100644
--- a/tools/testing/selftests/hid/tests/base.py
+++ b/tools/testing/selftests/hid/tests/base.py
@@ -14,7 +14,7 @@ import logging
from hidtools.device.base_device import BaseDevice, EvdevMatch, SysfsFile
from pathlib import Path
-from typing import Final
+from typing import Final, List, Tuple
logger = logging.getLogger("hidtools.test.base")
@@ -155,7 +155,7 @@ class BaseTestCase:
# if any module is not available (not compiled), the test will skip.
# Each element is a tuple '(kernel driver name, kernel module)',
# for example ("playstation", "hid-playstation")
- kernel_modules = []
+ kernel_modules: List[Tuple[str, str]] = []
def assertInputEventsIn(self, expected_events, effective_events):
effective_events = effective_events.copy()
@@ -238,8 +238,7 @@ class BaseTestCase:
try:
with HIDTestUdevRule.instance():
with new_uhdev as self.uhdev:
- skip_cond = request.node.get_closest_marker("skip_if_uhdev")
- if skip_cond:
+ for skip_cond in request.node.iter_markers("skip_if_uhdev"):
test, message, *rest = skip_cond.args
if test(self.uhdev):
diff --git a/tools/testing/selftests/hid/tests/test_mouse.py b/tools/testing/selftests/hid/tests/test_mouse.py
index fd2ba62e783a..66daf7e5975c 100644
--- a/tools/testing/selftests/hid/tests/test_mouse.py
+++ b/tools/testing/selftests/hid/tests/test_mouse.py
@@ -52,13 +52,13 @@ class BaseMouse(base.UHIDTestDevice):
:param reportID: the numeric report ID for this report, if needed
"""
if buttons is not None:
- l, r, m = buttons
- if l is not None:
- self.left = l
- if r is not None:
- self.right = r
- if m is not None:
- self.middle = m
+ left, right, middle = buttons
+ if left is not None:
+ self.left = left
+ if right is not None:
+ self.right = right
+ if middle is not None:
+ self.middle = middle
left = self.left
right = self.right
middle = self.middle
diff --git a/tools/testing/selftests/hid/tests/test_tablet.py b/tools/testing/selftests/hid/tests/test_tablet.py
index 303ffff9ee8d..903f19f7cbe9 100644
--- a/tools/testing/selftests/hid/tests/test_tablet.py
+++ b/tools/testing/selftests/hid/tests/test_tablet.py
@@ -13,62 +13,133 @@ from hidtools.util import BusType
import libevdev
import logging
import pytest
-from typing import Dict, Tuple
+from typing import Dict, List, Optional, Tuple
logger = logging.getLogger("hidtools.test.tablet")
+class BtnTouch(Enum):
+ """Represents whether the BTN_TOUCH event is set to True or False"""
+
+ DOWN = True
+ UP = False
+
+
+class ToolType(Enum):
+ PEN = libevdev.EV_KEY.BTN_TOOL_PEN
+ RUBBER = libevdev.EV_KEY.BTN_TOOL_RUBBER
+
+
+class BtnPressed(Enum):
+ """Represents whether a button is pressed on the stylus"""
+
+ PRIMARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS
+ SECONDARY_PRESSED = libevdev.EV_KEY.BTN_STYLUS2
+
+
class PenState(Enum):
"""Pen states according to Microsoft reference:
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
- """
- PEN_IS_OUT_OF_RANGE = (False, None)
- PEN_IS_IN_RANGE = (False, libevdev.EV_KEY.BTN_TOOL_PEN)
- PEN_IS_IN_CONTACT = (True, libevdev.EV_KEY.BTN_TOOL_PEN)
- PEN_IS_IN_RANGE_WITH_ERASING_INTENT = (False, libevdev.EV_KEY.BTN_TOOL_RUBBER)
- PEN_IS_ERASING = (True, libevdev.EV_KEY.BTN_TOOL_RUBBER)
+ We extend it with the various buttons when we need to check them.
+ """
- def __init__(self, touch, tool):
- self.touch = touch
- self.tool = tool
+ PEN_IS_OUT_OF_RANGE = BtnTouch.UP, None, None
+ PEN_IS_IN_RANGE = BtnTouch.UP, ToolType.PEN, None
+ PEN_IS_IN_RANGE_WITH_BUTTON = BtnTouch.UP, ToolType.PEN, BtnPressed.PRIMARY_PRESSED
+ PEN_IS_IN_RANGE_WITH_SECOND_BUTTON = (
+ BtnTouch.UP,
+ ToolType.PEN,
+ BtnPressed.SECONDARY_PRESSED,
+ )
+ PEN_IS_IN_CONTACT = BtnTouch.DOWN, ToolType.PEN, None
+ PEN_IS_IN_CONTACT_WITH_BUTTON = (
+ BtnTouch.DOWN,
+ ToolType.PEN,
+ BtnPressed.PRIMARY_PRESSED,
+ )
+ PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON = (
+ BtnTouch.DOWN,
+ ToolType.PEN,
+ BtnPressed.SECONDARY_PRESSED,
+ )
+ PEN_IS_IN_RANGE_WITH_ERASING_INTENT = BtnTouch.UP, ToolType.RUBBER, None
+ PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_BUTTON = (
+ BtnTouch.UP,
+ ToolType.RUBBER,
+ BtnPressed.PRIMARY_PRESSED,
+ )
+ PEN_IS_IN_RANGE_WITH_ERASING_INTENT_WITH_SECOND_BUTTON = (
+ BtnTouch.UP,
+ ToolType.RUBBER,
+ BtnPressed.SECONDARY_PRESSED,
+ )
+ PEN_IS_ERASING = BtnTouch.DOWN, ToolType.RUBBER, None
+ PEN_IS_ERASING_WITH_BUTTON = (
+ BtnTouch.DOWN,
+ ToolType.RUBBER,
+ BtnPressed.PRIMARY_PRESSED,
+ )
+ PEN_IS_ERASING_WITH_SECOND_BUTTON = (
+ BtnTouch.DOWN,
+ ToolType.RUBBER,
+ BtnPressed.SECONDARY_PRESSED,
+ )
+
+ def __init__(self, touch: BtnTouch, tool: Optional[ToolType], button: Optional[BtnPressed]):
+ self.touch = touch # type: ignore
+ self.tool = tool # type: ignore
+ self.button = button # type: ignore
@classmethod
def from_evdev(cls, evdev) -> "PenState":
- touch = bool(evdev.value[libevdev.EV_KEY.BTN_TOUCH])
+ touch = BtnTouch(evdev.value[libevdev.EV_KEY.BTN_TOUCH])
tool = None
+ button = None
if (
evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
and not evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
):
- tool = libevdev.EV_KEY.BTN_TOOL_RUBBER
+ tool = ToolType(libevdev.EV_KEY.BTN_TOOL_RUBBER)
elif (
evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
and not evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
):
- tool = libevdev.EV_KEY.BTN_TOOL_PEN
+ tool = ToolType(libevdev.EV_KEY.BTN_TOOL_PEN)
elif (
evdev.value[libevdev.EV_KEY.BTN_TOOL_PEN]
or evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER]
):
raise ValueError("2 tools are not allowed")
- return cls((touch, tool))
+ # we take only the highest button in account
+ for b in [libevdev.EV_KEY.BTN_STYLUS, libevdev.EV_KEY.BTN_STYLUS2]:
+ if bool(evdev.value[b]):
+ button = BtnPressed(b)
- def apply(self, events) -> "PenState":
+ # the kernel tends to insert an EV_SYN once removing the tool, so
+ # the button will be released after
+ if tool is None:
+ button = None
+
+ return cls((touch, tool, button)) # type: ignore
+
+ def apply(self, events: List[libevdev.InputEvent], strict: bool) -> "PenState":
if libevdev.EV_SYN.SYN_REPORT in events:
raise ValueError("EV_SYN is in the event sequence")
touch = self.touch
touch_found = False
tool = self.tool
tool_found = False
+ button = self.button
+ button_found = False
for ev in events:
if ev == libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH):
if touch_found:
raise ValueError(f"duplicated BTN_TOUCH in {events}")
touch_found = True
- touch = bool(ev.value)
+ touch = BtnTouch(ev.value)
elif ev in (
libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN),
libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_RUBBER),
@@ -76,35 +147,55 @@ class PenState(Enum):
if tool_found:
raise ValueError(f"duplicated BTN_TOOL_* in {events}")
tool_found = True
- if ev.value:
- tool = ev.code
- else:
- tool = None
-
- new_state = PenState((touch, tool))
- assert (
- new_state in self.valid_transitions()
- ), f"moving from {self} to {new_state} is forbidden"
+ tool = ToolType(ev.code) if ev.value else None
+ elif ev in (
+ libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS),
+ libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS2),
+ ):
+ if button_found:
+ raise ValueError(f"duplicated BTN_STYLUS* in {events}")
+ button_found = True
+ button = BtnPressed(ev.code) if ev.value else None
+
+ # the kernel tends to insert an EV_SYN once removing the tool, so
+ # the button will be released after
+ if tool is None:
+ button = None
+
+ new_state = PenState((touch, tool, button)) # type: ignore
+ if strict:
+ assert (
+ new_state in self.valid_transitions()
+ ), f"moving from {self} to {new_state} is forbidden"
+ else:
+ assert (
+ new_state in self.historically_tolerated_transitions()
+ ), f"moving from {self} to {new_state} is forbidden"
return new_state
def valid_transitions(self) -> Tuple["PenState", ...]:
- """Following the state machine in the URL above, with a couple of addition
- for skipping the in-range state, due to historical reasons.
+ """Following the state machine in the URL above.
Note that those transitions are from the evdev point of view, not HID"""
if self == PenState.PEN_IS_OUT_OF_RANGE:
return (
PenState.PEN_IS_OUT_OF_RANGE,
PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
+ PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
PenState.PEN_IS_ERASING,
)
if self == PenState.PEN_IS_IN_RANGE:
return (
PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
PenState.PEN_IS_OUT_OF_RANGE,
PenState.PEN_IS_IN_CONTACT,
)
@@ -112,8 +203,9 @@ class PenState(Enum):
if self == PenState.PEN_IS_IN_CONTACT:
return (
PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
+ PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
PenState.PEN_IS_IN_RANGE,
- PenState.PEN_IS_OUT_OF_RANGE,
)
if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
@@ -127,113 +219,126 @@ class PenState(Enum):
return (
PenState.PEN_IS_ERASING,
PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
+ )
+
+ if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
+ return (
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_IN_RANGE,
PenState.PEN_IS_OUT_OF_RANGE,
+ PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
)
- return tuple()
+ if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
+ return (
+ PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
+ PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ )
+ if self == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON:
+ return (
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_OUT_OF_RANGE,
+ PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
+ )
-class Data(object):
- pass
+ if self == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON:
+ return (
+ PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ )
+ return tuple()
-class Pen(object):
- def __init__(self, x, y):
- self.x = x
- self.y = y
- self.tipswitch = False
- self.tippressure = 15
- self.azimuth = 0
- self.inrange = False
- self.width = 10
- self.height = 10
- self.barrelswitch = False
- self.invert = False
- self.eraser = False
- self.x_tilt = 0
- self.y_tilt = 0
- self.twist = 0
- self._old_values = None
- self.current_state = None
+ def historically_tolerated_transitions(self) -> Tuple["PenState", ...]:
+ """Following the state machine in the URL above, with a couple of addition
+ for skipping the in-range state, due to historical reasons.
- def _restore(self):
- if self._old_values is not None:
- for i in [
- "x",
- "y",
- "tippressure",
- "azimuth",
- "width",
- "height",
- "twist",
- "x_tilt",
- "y_tilt",
- ]:
- setattr(self, i, getattr(self._old_values, i))
+ Note that those transitions are from the evdev point of view, not HID"""
+ if self == PenState.PEN_IS_OUT_OF_RANGE:
+ return (
+ PenState.PEN_IS_OUT_OF_RANGE,
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
+ PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
+ PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_ERASING,
+ )
- def move_to(self, state):
- # fill in the previous values
- if self.current_state == PenState.PEN_IS_OUT_OF_RANGE:
- self._restore()
+ if self == PenState.PEN_IS_IN_RANGE:
+ return (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_OUT_OF_RANGE,
+ PenState.PEN_IS_IN_CONTACT,
+ )
- print(f"\n *** pen is moving to {state} ***")
+ if self == PenState.PEN_IS_IN_CONTACT:
+ return (
+ PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
+ PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_OUT_OF_RANGE,
+ )
- if state == PenState.PEN_IS_OUT_OF_RANGE:
- self._old_values = copy.copy(self)
- self.x = 0
- self.y = 0
- self.tipswitch = False
- self.tippressure = 0
- self.azimuth = 0
- self.inrange = False
- self.width = 0
- self.height = 0
- self.invert = False
- self.eraser = False
- self.x_tilt = 0
- self.y_tilt = 0
- self.twist = 0
- elif state == PenState.PEN_IS_IN_RANGE:
- self.tipswitch = False
- self.inrange = True
- self.invert = False
- self.eraser = False
- elif state == PenState.PEN_IS_IN_CONTACT:
- self.tipswitch = True
- self.inrange = True
- self.invert = False
- self.eraser = False
- elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
- self.tipswitch = False
- self.inrange = True
- self.invert = True
- self.eraser = False
- elif state == PenState.PEN_IS_ERASING:
- self.tipswitch = False
- self.inrange = True
- self.invert = True
- self.eraser = True
+ if self == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
+ return (
+ PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
+ PenState.PEN_IS_OUT_OF_RANGE,
+ PenState.PEN_IS_ERASING,
+ )
- self.current_state = state
+ if self == PenState.PEN_IS_ERASING:
+ return (
+ PenState.PEN_IS_ERASING,
+ PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT,
+ PenState.PEN_IS_OUT_OF_RANGE,
+ )
- def __assert_axis(self, evdev, axis, value):
- if (
- axis == libevdev.EV_KEY.BTN_TOOL_RUBBER
- and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None
- ):
- return
+ if self == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
+ return (
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_OUT_OF_RANGE,
+ PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
+ )
- assert (
- evdev.value[axis] == value
- ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"
+ if self == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
+ return (
+ PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
+ PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_OUT_OF_RANGE,
+ )
- def assert_expected_input_events(self, evdev):
- assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x
- assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y
- assert self.current_state == PenState.from_evdev(evdev)
+ if self == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON:
+ return (
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_OUT_OF_RANGE,
+ PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
+ )
+
+ if self == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON:
+ return (
+ PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_OUT_OF_RANGE,
+ )
+
+ return tuple()
@staticmethod
- def legal_transitions() -> Dict[str, Tuple[PenState, ...]]:
+ def legal_transitions() -> Dict[str, Tuple["PenState", ...]]:
"""This is the first half of the Windows Pen Implementation state machine:
we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
@@ -259,7 +364,7 @@ class Pen(object):
}
@staticmethod
- def legal_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]:
+ def legal_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:
"""This is the second half of the Windows Pen Implementation state machine:
we now have Invert and Erase bits, so move in/out or proximity with the intend
to erase.
@@ -297,7 +402,106 @@ class Pen(object):
}
@staticmethod
- def tolerated_transitions() -> Dict[str, Tuple[PenState, ...]]:
+ def legal_transitions_with_primary_button() -> Dict[str, Tuple["PenState", ...]]:
+ """We revisit the Windows Pen Implementation state machine:
+ we now have a primary button.
+ """
+ return {
+ "hover-button": (PenState.PEN_IS_IN_RANGE_WITH_BUTTON,),
+ "hover-button -> out-of-range": (
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_OUT_OF_RANGE,
+ ),
+ "in-range -> button-press": (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ ),
+ "in-range -> button-press -> button-release": (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_IN_RANGE,
+ ),
+ "in-range -> touch -> button-press -> button-release": (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
+ PenState.PEN_IS_IN_CONTACT,
+ ),
+ "in-range -> touch -> button-press -> release -> button-release": (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_IN_RANGE,
+ ),
+ "in-range -> button-press -> touch -> release -> button-release": (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_IN_RANGE,
+ ),
+ "in-range -> button-press -> touch -> button-release -> release": (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_RANGE_WITH_BUTTON,
+ PenState.PEN_IS_IN_CONTACT_WITH_BUTTON,
+ PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_RANGE,
+ ),
+ }
+
+ @staticmethod
+ def legal_transitions_with_secondary_button() -> Dict[str, Tuple["PenState", ...]]:
+ """We revisit the Windows Pen Implementation state machine:
+ we now have a secondary button.
+ Note: we don't looks for 2 buttons interactions.
+ """
+ return {
+ "hover-button": (PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,),
+ "hover-button -> out-of-range": (
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_OUT_OF_RANGE,
+ ),
+ "in-range -> button-press": (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ ),
+ "in-range -> button-press -> button-release": (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_RANGE,
+ ),
+ "in-range -> touch -> button-press -> button-release": (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_CONTACT,
+ ),
+ "in-range -> touch -> button-press -> release -> button-release": (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_RANGE,
+ ),
+ "in-range -> button-press -> touch -> release -> button-release": (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_RANGE,
+ ),
+ "in-range -> button-press -> touch -> button-release -> release": (
+ PenState.PEN_IS_IN_RANGE,
+ PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON,
+ PenState.PEN_IS_IN_CONTACT,
+ PenState.PEN_IS_IN_RANGE,
+ ),
+ }
+
+ @staticmethod
+ def tolerated_transitions() -> Dict[str, Tuple["PenState", ...]]:
"""This is not adhering to the Windows Pen Implementation state machine
but we should expect the kernel to behave properly, mostly for historical
reasons."""
@@ -310,7 +514,7 @@ class Pen(object):
}
@staticmethod
- def tolerated_transitions_with_invert() -> Dict[str, Tuple[PenState, ...]]:
+ def tolerated_transitions_with_invert() -> Dict[str, Tuple["PenState", ...]]:
"""This is the second half of the Windows Pen Implementation state machine:
we now have Invert and Erase bits, so move in/out or proximity with the intend
to erase.
@@ -325,7 +529,7 @@ class Pen(object):
}
@staticmethod
- def broken_transitions() -> Dict[str, Tuple[PenState, ...]]:
+ def broken_transitions() -> Dict[str, Tuple["PenState", ...]]:
"""Those tests are definitely not part of the Windows specification.
However, a half broken device might export those transitions.
For example, a pen that has the eraser button might wobble between
@@ -363,6 +567,61 @@ class Pen(object):
}
+class Pen(object):
+ def __init__(self, x, y):
+ self.x = x
+ self.y = y
+ self.tipswitch = False
+ self.tippressure = 15
+ self.azimuth = 0
+ self.inrange = False
+ self.width = 10
+ self.height = 10
+ self.barrelswitch = False
+ self.secondarybarrelswitch = False
+ self.invert = False
+ self.eraser = False
+ self.xtilt = 1
+ self.ytilt = 1
+ self.twist = 1
+ self._old_values = None
+ self.current_state = None
+
+ def restore(self):
+ if self._old_values is not None:
+ for i in [
+ "x",
+ "y",
+ "tippressure",
+ "azimuth",
+ "width",
+ "height",
+ "twist",
+ "xtilt",
+ "ytilt",
+ ]:
+ setattr(self, i, getattr(self._old_values, i))
+
+ def backup(self):
+ self._old_values = copy.copy(self)
+
+ def __assert_axis(self, evdev, axis, value):
+ if (
+ axis == libevdev.EV_KEY.BTN_TOOL_RUBBER
+ and evdev.value[libevdev.EV_KEY.BTN_TOOL_RUBBER] is None
+ ):
+ return
+
+ assert (
+ evdev.value[axis] == value
+ ), f"assert evdev.value[{axis}] ({evdev.value[axis]}) != {value}"
+
+ def assert_expected_input_events(self, evdev):
+ assert evdev.value[libevdev.EV_ABS.ABS_X] == self.x
+ assert evdev.value[libevdev.EV_ABS.ABS_Y] == self.y
+ assert self.current_state == PenState.from_evdev(evdev)
+
+
class PenDigitizer(base.UHIDTestDevice):
def __init__(
self,
@@ -388,6 +647,89 @@ class PenDigitizer(base.UHIDTestDevice):
continue
self.fields = [f.usage_name for f in r]
+ def move_to(self, pen, state):
+ # fill in the previous values
+ if pen.current_state == PenState.PEN_IS_OUT_OF_RANGE:
+ pen.restore()
+
+ print(f"\n *** pen is moving to {state} ***")
+
+ if state == PenState.PEN_IS_OUT_OF_RANGE:
+ pen.backup()
+ pen.x = 0
+ pen.y = 0
+ pen.tipswitch = False
+ pen.tippressure = 0
+ pen.azimuth = 0
+ pen.inrange = False
+ pen.width = 0
+ pen.height = 0
+ pen.invert = False
+ pen.eraser = False
+ pen.xtilt = 0
+ pen.ytilt = 0
+ pen.twist = 0
+ pen.barrelswitch = False
+ pen.secondarybarrelswitch = False
+ elif state == PenState.PEN_IS_IN_RANGE:
+ pen.tipswitch = False
+ pen.inrange = True
+ pen.invert = False
+ pen.eraser = False
+ pen.barrelswitch = False
+ pen.secondarybarrelswitch = False
+ elif state == PenState.PEN_IS_IN_CONTACT:
+ pen.tipswitch = True
+ pen.inrange = True
+ pen.invert = False
+ pen.eraser = False
+ pen.barrelswitch = False
+ pen.secondarybarrelswitch = False
+ elif state == PenState.PEN_IS_IN_RANGE_WITH_BUTTON:
+ pen.tipswitch = False
+ pen.inrange = True
+ pen.invert = False
+ pen.eraser = False
+ pen.barrelswitch = True
+ pen.secondarybarrelswitch = False
+ elif state == PenState.PEN_IS_IN_CONTACT_WITH_BUTTON:
+ pen.tipswitch = True
+ pen.inrange = True
+ pen.invert = False
+ pen.eraser = False
+ pen.barrelswitch = True
+ pen.secondarybarrelswitch = False
+ elif state == PenState.PEN_IS_IN_RANGE_WITH_SECOND_BUTTON:
+ pen.tipswitch = False
+ pen.inrange = True
+ pen.invert = False
+ pen.eraser = False
+ pen.barrelswitch = False
+ pen.secondarybarrelswitch = True
+ elif state == PenState.PEN_IS_IN_CONTACT_WITH_SECOND_BUTTON:
+ pen.tipswitch = True
+ pen.inrange = True
+ pen.invert = False
+ pen.eraser = False
+ pen.barrelswitch = False
+ pen.secondarybarrelswitch = True
+ elif state == PenState.PEN_IS_IN_RANGE_WITH_ERASING_INTENT:
+ pen.tipswitch = False
+ pen.inrange = True
+ pen.invert = True
+ pen.eraser = False
+ pen.barrelswitch = False
+ pen.secondarybarrelswitch = False
+ elif state == PenState.PEN_IS_ERASING:
+ pen.tipswitch = False
+ pen.inrange = True
+ pen.invert = False
+ pen.eraser = True
+ pen.barrelswitch = False
+ pen.secondarybarrelswitch = False
+
+ pen.current_state = state
+
def event(self, pen):
rs = []
r = self.create_report(application=self.cur_application, data=pen)
@@ -435,10 +777,14 @@ class BaseTest:
self.debug_reports(r, uhdev, events)
return events
- def validate_transitions(self, from_state, pen, evdev, events):
+ def validate_transitions(
+ self, from_state, pen, evdev, events, allow_intermediate_states
+ ):
# check that the final state is correct
pen.assert_expected_input_events(evdev)
+ state = from_state
+
# check that the transitions are valid
sync_events = []
while libevdev.InputEvent(libevdev.EV_SYN.SYN_REPORT) in events:
@@ -448,12 +794,12 @@ class BaseTest:
events = events[idx + 1 :]
# now check for a valid transition
- from_state = from_state.apply(sync_events)
+ state = state.apply(sync_events, not allow_intermediate_states)
if events:
- from_state = from_state.apply(sync_events)
+ state = state.apply(sync_events, not allow_intermediate_states)
- def _test_states(self, state_list, scribble):
+ def _test_states(self, state_list, scribble, allow_intermediate_states):
"""Internal method to test against a list of
transition between states.
state_list is a list of PenState objects
@@ -466,9 +812,11 @@ class BaseTest:
cur_state = PenState.PEN_IS_OUT_OF_RANGE
p = Pen(50, 60)
- p.move_to(PenState.PEN_IS_OUT_OF_RANGE)
+ uhdev.move_to(p, PenState.PEN_IS_OUT_OF_RANGE)
events = self.post(uhdev, p)
- self.validate_transitions(cur_state, p, evdev, events)
+ self.validate_transitions(
+ cur_state, p, evdev, events, allow_intermediate_states
+ )
cur_state = p.current_state
@@ -477,38 +825,77 @@ class BaseTest:
p.x += 1
p.y -= 1
events = self.post(uhdev, p)
- self.validate_transitions(cur_state, p, evdev, events)
+ self.validate_transitions(
+ cur_state, p, evdev, events, allow_intermediate_states
+ )
assert len(events) >= 3 # X, Y, SYN
- p.move_to(state)
+ uhdev.move_to(p, state)
if scribble and state != PenState.PEN_IS_OUT_OF_RANGE:
p.x += 1
p.y -= 1
events = self.post(uhdev, p)
- self.validate_transitions(cur_state, p, evdev, events)
+ self.validate_transitions(
+ cur_state, p, evdev, events, allow_intermediate_states
+ )
cur_state = p.current_state
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
@pytest.mark.parametrize(
"state_list",
- [pytest.param(v, id=k) for k, v in Pen.legal_transitions().items()],
+ [pytest.param(v, id=k) for k, v in PenState.legal_transitions().items()],
)
def test_valid_pen_states(self, state_list, scribble):
"""This is the first half of the Windows Pen Implementation state machine:
we don't have Invert nor Erase bits, so just move in/out-of-range or proximity.
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
"""
- self._test_states(state_list, scribble)
+ self._test_states(state_list, scribble, allow_intermediate_states=False)
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
@pytest.mark.parametrize(
"state_list",
- [pytest.param(v, id=k) for k, v in Pen.tolerated_transitions().items()],
+ [
+ pytest.param(v, id=k)
+ for k, v in PenState.tolerated_transitions().items()
+ ],
)
def test_tolerated_pen_states(self, state_list, scribble):
"""This is not adhering to the Windows Pen Implementation state machine
but we should expect the kernel to behave properly, mostly for historical
reasons."""
- self._test_states(state_list, scribble)
+ self._test_states(state_list, scribble, allow_intermediate_states=True)
+
+ @pytest.mark.skip_if_uhdev(
+ lambda uhdev: "Barrel Switch" not in uhdev.fields,
+ "Device not compatible, missing Barrel Switch usage",
+ )
+ @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
+ @pytest.mark.parametrize(
+ "state_list",
+ [
+ pytest.param(v, id=k)
+ for k, v in PenState.legal_transitions_with_primary_button().items()
+ ],
+ )
+ def test_valid_primary_button_pen_states(self, state_list, scribble):
+ """Rework the transition state machine by adding the primary button."""
+ self._test_states(state_list, scribble, allow_intermediate_states=False)
+
+ @pytest.mark.skip_if_uhdev(
+ lambda uhdev: "Secondary Barrel Switch" not in uhdev.fields,
+ "Device not compatible, missing Secondary Barrel Switch usage",
+ )
+ @pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
+ @pytest.mark.parametrize(
+ "state_list",
+ [
+ pytest.param(v, id=k)
+ for k, v in PenState.legal_transitions_with_secondary_button().items()
+ ],
+ )
+ def test_valid_secondary_button_pen_states(self, state_list, scribble):
+ """Rework the transition state machine by adding the secondary button."""
+ self._test_states(state_list, scribble, allow_intermediate_states=False)
@pytest.mark.skip_if_uhdev(
lambda uhdev: "Invert" not in uhdev.fields,
@@ -519,7 +906,7 @@ class BaseTest:
"state_list",
[
pytest.param(v, id=k)
- for k, v in Pen.legal_transitions_with_invert().items()
+ for k, v in PenState.legal_transitions_with_invert().items()
],
)
def test_valid_invert_pen_states(self, state_list, scribble):
@@ -528,7 +915,7 @@ class BaseTest:
to erase.
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
"""
- self._test_states(state_list, scribble)
+ self._test_states(state_list, scribble, allow_intermediate_states=False)
@pytest.mark.skip_if_uhdev(
lambda uhdev: "Invert" not in uhdev.fields,
@@ -539,7 +926,7 @@ class BaseTest:
"state_list",
[
pytest.param(v, id=k)
- for k, v in Pen.tolerated_transitions_with_invert().items()
+ for k, v in PenState.tolerated_transitions_with_invert().items()
],
)
def test_tolerated_invert_pen_states(self, state_list, scribble):
@@ -548,7 +935,7 @@ class BaseTest:
to erase.
https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/windows-pen-states
"""
- self._test_states(state_list, scribble)
+ self._test_states(state_list, scribble, allow_intermediate_states=True)
@pytest.mark.skip_if_uhdev(
lambda uhdev: "Invert" not in uhdev.fields,
@@ -557,7 +944,7 @@ class BaseTest:
@pytest.mark.parametrize("scribble", [True, False], ids=["scribble", "static"])
@pytest.mark.parametrize(
"state_list",
- [pytest.param(v, id=k) for k, v in Pen.broken_transitions().items()],
+ [pytest.param(v, id=k) for k, v in PenState.broken_transitions().items()],
)
def test_tolerated_broken_pen_states(self, state_list, scribble):
"""Those tests are definitely not part of the Windows specification.
@@ -565,102 +952,7 @@ class BaseTest:
For example, a pen that has the eraser button might wobble between
touching and erasing if the tablet doesn't enforce the Windows
state machine."""
- self._test_states(state_list, scribble)
-
- @pytest.mark.skip_if_uhdev(
- lambda uhdev: "Barrel Switch" not in uhdev.fields,
- "Device not compatible, missing Barrel Switch usage",
- )
- def test_primary_button(self):
- """Primary button (stylus) pressed, reports as pressed even while hovering.
- Actual reporting from the device: hid=TIPSWITCH,BARRELSWITCH,INRANGE (code=TOUCH,STYLUS,PEN):
- { 0, 0, 1 } <- hover
- { 0, 1, 1 } <- primary button pressed
- { 0, 1, 1 } <- liftoff
- { 0, 0, 0 } <- leaves
- """
-
- uhdev = self.uhdev
- evdev = uhdev.get_evdev()
-
- p = Pen(50, 60)
- p.inrange = True
- events = self.post(uhdev, p)
- assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 1) in events
- assert evdev.value[libevdev.EV_ABS.ABS_X] == 50
- assert evdev.value[libevdev.EV_ABS.ABS_Y] == 60
- assert not evdev.value[libevdev.EV_KEY.BTN_STYLUS]
-
- p.barrelswitch = True
- events = self.post(uhdev, p)
- assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 1) in events
-
- p.x += 1
- p.y -= 1
- events = self.post(uhdev, p)
- assert len(events) == 3 # X, Y, SYN
- assert libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 51) in events
- assert libevdev.InputEvent(libevdev.EV_ABS.ABS_Y, 59) in events
-
- p.barrelswitch = False
- events = self.post(uhdev, p)
- assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 0) in events
-
- p.inrange = False
- events = self.post(uhdev, p)
- assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 0) in events
-
- @pytest.mark.skip_if_uhdev(
- lambda uhdev: "Barrel Switch" not in uhdev.fields,
- "Device not compatible, missing Barrel Switch usage",
- )
- def test_contact_primary_button(self):
- """Primary button (stylus) pressed, reports as pressed even while hovering.
- Actual reporting from the device: hid=TIPSWITCH,BARRELSWITCH,INRANGE (code=TOUCH,STYLUS,PEN):
- { 0, 0, 1 } <- hover
- { 0, 1, 1 } <- primary button pressed
- { 1, 1, 1 } <- touch-down
- { 1, 1, 1 } <- still touch, scribble on the screen
- { 0, 1, 1 } <- liftoff
- { 0, 0, 0 } <- leaves
- """
-
- uhdev = self.uhdev
- evdev = uhdev.get_evdev()
-
- p = Pen(50, 60)
- p.inrange = True
- events = self.post(uhdev, p)
- assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 1) in events
- assert evdev.value[libevdev.EV_ABS.ABS_X] == 50
- assert evdev.value[libevdev.EV_ABS.ABS_Y] == 60
- assert not evdev.value[libevdev.EV_KEY.BTN_STYLUS]
-
- p.barrelswitch = True
- events = self.post(uhdev, p)
- assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 1) in events
-
- p.tipswitch = True
- events = self.post(uhdev, p)
- assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
- assert evdev.value[libevdev.EV_KEY.BTN_STYLUS]
-
- p.x += 1
- p.y -= 1
- events = self.post(uhdev, p)
- assert len(events) == 3 # X, Y, SYN
- assert libevdev.InputEvent(libevdev.EV_ABS.ABS_X, 51) in events
- assert libevdev.InputEvent(libevdev.EV_ABS.ABS_Y, 59) in events
-
- p.tipswitch = False
- events = self.post(uhdev, p)
- assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0) in events
-
- p.barrelswitch = False
- p.inrange = False
- events = self.post(uhdev, p)
- assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOOL_PEN, 0) in events
- assert libevdev.InputEvent(libevdev.EV_KEY.BTN_STYLUS, 0) in events
+ self._test_states(state_list, scribble, allow_intermediate_states=True)
class GXTP_pen(PenDigitizer):
diff --git a/tools/testing/selftests/hid/tests/test_wacom_generic.py b/tools/testing/selftests/hid/tests/test_wacom_generic.py
index f92fe8e02c1b..352fc39f3c6c 100644
--- a/tools/testing/selftests/hid/tests/test_wacom_generic.py
+++ b/tools/testing/selftests/hid/tests/test_wacom_generic.py
@@ -27,6 +27,7 @@ from .descriptors_wacom import (
)
import attr
+from collections import namedtuple
from enum import Enum
from hidtools.hut import HUT
from hidtools.hid import HidUnit
@@ -862,6 +863,8 @@ class TestPTHX60_Pen(TestOpaqueCTLTablet):
class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest):
+ ContactIds = namedtuple("ContactIds", "contact_id, tracking_id, slot_num")
+
def create_device(self):
return test_multitouch.Digitizer(
"DTH 2452",
@@ -869,6 +872,57 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
input_info=(0x3, 0x056A, 0x0383),
)
+ def make_contact(self, contact_id=0, t=0):
+ """
+ Make a single touch contact that can move over time.
+
+ Creates a touch object that has a well-known position in space that
+ does not overlap with other contacts. The value of `t` may be
+ incremented over time to move the point along a linear path.
+ """
+ x = 50 + 10 * contact_id + t
+ y = 100 + 100 * contact_id + t
+ return test_multitouch.Touch(contact_id, x, y)
+
+ def make_contacts(self, n, t=0):
+ """
+ Make multiple touch contacts that can move over time.
+
+ Returns a list of `n` touch objects that are positioned at well-known
+ locations. The value of `t` may be incremented over time to move the
+ points along a linear path.
+ """
+ return [ self.make_contact(id, t) for id in range(0, n) ]
+
+ def assert_contact(self, uhdev, evdev, contact_ids, t=0):
+ """
+ Assert properties of a contact generated by make_contact.
+ """
+ contact_id = contact_ids.contact_id
+ tracking_id = contact_ids.tracking_id
+ slot_num = contact_ids.slot_num
+
+ x = 50 + 10 * contact_id + t
+ y = 100 + 100 * contact_id + t
+
+ # If the data isn't supposed to be stored in any slots, there is
+ # nothing we can check for in the evdev stream.
+ if slot_num is None:
+ assert tracking_id == -1
+ return
+
+ assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == tracking_id
+ if tracking_id != -1:
+ assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_X] == x
+ assert evdev.slots[slot_num][libevdev.EV_ABS.ABS_MT_POSITION_Y] == y
+
+ def assert_contacts(self, uhdev, evdev, data, t=0):
+ """
+ Assert properties of a list of contacts generated by make_contacts.
+ """
+ for contact_ids in data:
+ self.assert_contact(uhdev, evdev, contact_ids, t)
+
def test_contact_id_0(self):
"""
Bring a finger in contact with the tablet, then hold it down and remove it.
@@ -909,7 +963,7 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
Ensure that the confidence bit being set to false should not result in a touch event.
"""
uhdev = self.uhdev
- evdev = uhdev.get_evdev()
+ _evdev = uhdev.get_evdev()
t0 = test_multitouch.Touch(1, 50, 100)
t0.confidence = False
@@ -917,6 +971,228 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
events = uhdev.next_sync_events()
self.debug_reports(r, uhdev, events)
- slot = self.get_slot(uhdev, t0, 0)
+ _slot = self.get_slot(uhdev, t0, 0)
+
+ assert not events
+
+ def test_confidence_multitouch(self):
+ """
+ Bring multiple fingers in contact with the tablet, some with the
+ confidence bit set, and some without.
+
+ Ensure that all confident touches are reported and that all non-
+ confident touches are ignored.
+ """
+ uhdev = self.uhdev
+ evdev = uhdev.get_evdev()
+
+ touches = self.make_contacts(5)
+ touches[0].confidence = False
+ touches[2].confidence = False
+ touches[4].confidence = False
+
+ r = uhdev.event(touches)
+ events = uhdev.next_sync_events()
+ self.debug_reports(r, uhdev, events)
+
+ assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 1) in events
+
+ self.assert_contacts(uhdev, evdev,
+ [ self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None),
+ self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0),
+ self.ContactIds(contact_id = 2, tracking_id = -1, slot_num = None),
+ self.ContactIds(contact_id = 3, tracking_id = 1, slot_num = 1),
+ self.ContactIds(contact_id = 4, tracking_id = -1, slot_num = None) ])
+
+ def confidence_change_assert_playback(self, uhdev, evdev, timeline):
+ """
+ Assert proper behavior of contacts that move and change tipswitch /
+ confidence status over time.
+
+ Given a `timeline` list of touch states to iterate over, verify
+ that the contacts move and are reported as up/down as expected
+ by the state of the tipswitch and confidence bits.
+ """
+ t = 0
+
+ for state in timeline:
+ touches = self.make_contacts(len(state), t)
+
+ for item in zip(touches, state):
+ item[0].tipswitch = item[1][1]
+ item[0].confidence = item[1][2]
+
+ r = uhdev.event(touches)
+ events = uhdev.next_sync_events()
+ self.debug_reports(r, uhdev, events)
+
+ ids = [ x[0] for x in state ]
+ self.assert_contacts(uhdev, evdev, ids, t)
+
+ t += 1
+
+ def test_confidence_loss_a(self):
+ """
+ Transition a confident contact to a non-confident contact by
+ first clearing the tipswitch.
+
+ Ensure that the driver reports the transitioned contact as
+ being removed and that other contacts continue to report
+ normally. This mode of confidence loss is used by the
+ DTH-2452.
+ """
+ uhdev = self.uhdev
+ evdev = uhdev.get_evdev()
+
+ self.confidence_change_assert_playback(uhdev, evdev, [
+ # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
+ # Both fingers confidently in contact
+ [(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
+
+ # t=1: Contact 0 == !Down + confident; Contact 1 == Down + confident
+ # First finger looses confidence and clears only the tipswitch flag
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, True),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
+
+ # t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident
+ # First finger has lost confidence and has both flags cleared
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
+
+ # t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident
+ # First finger has lost confidence and has both flags cleared
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)]
+ ])
+
+ def test_confidence_loss_b(self):
+ """
+ Transition a confident contact to a non-confident contact by
+ cleraing both tipswitch and confidence bits simultaneously.
+
+ Ensure that the driver reports the transitioned contact as
+ being removed and that other contacts continue to report
+ normally. This mode of confidence loss is used by some
+ AES devices.
+ """
+ uhdev = self.uhdev
+ evdev = uhdev.get_evdev()
+
+ self.confidence_change_assert_playback(uhdev, evdev, [
+ # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
+ # Both fingers confidently in contact
+ [(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
+
+ # t=1: Contact 0 == !Down + !confident; Contact 1 == Down + confident
+ # First finger looses confidence and has both flags cleared simultaneously
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
+
+ # t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident
+ # First finger has lost confidence and has both flags cleared
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
+
+ # t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident
+ # First finger has lost confidence and has both flags cleared
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)]
+ ])
+
+ def test_confidence_loss_c(self):
+ """
+ Transition a confident contact to a non-confident contact by
+ clearing only the confidence bit.
+
+ Ensure that the driver reports the transitioned contact as
+ being removed and that other contacts continue to report
+ normally.
+ """
+ uhdev = self.uhdev
+ evdev = uhdev.get_evdev()
+
+ self.confidence_change_assert_playback(uhdev, evdev, [
+ # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
+ # Both fingers confidently in contact
+ [(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
+
+ # t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident
+ # First finger looses confidence and clears only the confidence flag
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), True, False),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
+
+ # t=2: Contact 0 == !Down + !confident; Contact 1 == Down + confident
+ # First finger has lost confidence and has both flags cleared
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
+
+ # t=3: Contact 0 == !Down + !confident; Contact 1 == Down + confident
+ # First finger has lost confidence and has both flags cleared
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, False),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)]
+ ])
+
+ def test_confidence_gain_a(self):
+ """
+ Transition a contact that was always non-confident to confident.
+
+ Ensure that the confident contact is reported normally.
+ """
+ uhdev = self.uhdev
+ evdev = uhdev.get_evdev()
+
+ self.confidence_change_assert_playback(uhdev, evdev, [
+ # t=0: Contact 0 == Down + !confident; Contact 1 == Down + confident
+ # Only second finger is confidently in contact
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None), True, False),
+ (self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)],
+
+ # t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident
+ # First finger gains confidence
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = None), True, False),
+ (self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)],
+
+ # t=2: Contact 0 == Down + confident; Contact 1 == Down + confident
+ # First finger remains confident
+ [(self.ContactIds(contact_id = 0, tracking_id = 1, slot_num = 1), True, True),
+ (self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)],
+
+ # t=3: Contact 0 == Down + confident; Contact 1 == Down + confident
+ # First finger remains confident
+ [(self.ContactIds(contact_id = 0, tracking_id = 1, slot_num = 1), True, True),
+ (self.ContactIds(contact_id = 1, tracking_id = 0, slot_num = 0), True, True)]
+ ])
+
+ def test_confidence_gain_b(self):
+ """
+ Transition a contact from non-confident to confident.
+
+ Ensure that the confident contact is reported normally.
+ """
+ uhdev = self.uhdev
+ evdev = uhdev.get_evdev()
- assert not events \ No newline at end of file
+ self.confidence_change_assert_playback(uhdev, evdev, [
+ # t=0: Contact 0 == Down + confident; Contact 1 == Down + confident
+ # First and second finger confidently in contact
+ [(self.ContactIds(contact_id = 0, tracking_id = 0, slot_num = 0), True, True),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
+
+ # t=1: Contact 0 == Down + !confident; Contact 1 == Down + confident
+ # Firtst finger looses confidence
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), True, False),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
+
+ # t=2: Contact 0 == Down + confident; Contact 1 == Down + confident
+ # First finger gains confidence
+ [(self.ContactIds(contact_id = 0, tracking_id = 2, slot_num = 0), True, True),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)],
+
+ # t=3: Contact 0 == !Down + confident; Contact 1 == Down + confident
+ # First finger goes up
+ [(self.ContactIds(contact_id = 0, tracking_id = -1, slot_num = 0), False, True),
+ (self.ContactIds(contact_id = 1, tracking_id = 1, slot_num = 1), True, True)]
+ ])
diff --git a/tools/testing/selftests/hid/vmtest.sh b/tools/testing/selftests/hid/vmtest.sh
index 4da48bf6b328..db534e9099a8 100755
--- a/tools/testing/selftests/hid/vmtest.sh
+++ b/tools/testing/selftests/hid/vmtest.sh
@@ -19,12 +19,12 @@ esac
SCRIPT_DIR="$(dirname $(realpath $0))"
OUTPUT_DIR="$SCRIPT_DIR/results"
KCONFIG_REL_PATHS=("${SCRIPT_DIR}/config" "${SCRIPT_DIR}/config.common" "${SCRIPT_DIR}/config.${ARCH}")
-B2C_URL="https://gitlab.freedesktop.org/mupuf/boot2container/-/raw/master/vm2c.py"
+B2C_URL="https://gitlab.freedesktop.org/gfx-ci/boot2container/-/raw/main/vm2c.py"
NUM_COMPILE_JOBS="$(nproc)"
LOG_FILE_BASE="$(date +"hid_selftests.%Y-%m-%d_%H-%M-%S")"
LOG_FILE="${LOG_FILE_BASE}.log"
EXIT_STATUS_FILE="${LOG_FILE_BASE}.exit_status"
-CONTAINER_IMAGE="registry.freedesktop.org/libevdev/hid-tools/fedora/37:2023-02-17.1"
+CONTAINER_IMAGE="registry.freedesktop.org/bentiss/hid/fedora/39:2023-11-22.1"
TARGETS="${TARGETS:=$(basename ${SCRIPT_DIR})}"
DEFAULT_COMMAND="pip3 install hid-tools; make -C tools/testing/selftests TARGETS=${TARGETS} run_tests"
@@ -32,7 +32,7 @@ DEFAULT_COMMAND="pip3 install hid-tools; make -C tools/testing/selftests TARGETS
usage()
{
cat <<EOF
-Usage: $0 [-i] [-s] [-d <output_dir>] -- [<command>]
+Usage: $0 [-j N] [-s] [-b] [-d <output_dir>] -- [<command>]
<command> is the command you would normally run when you are in
the source kernel direcory. e.g:
@@ -55,6 +55,7 @@ Options:
-u) Update the boot2container script to a newer version.
-d) Update the output directory (default: ${OUTPUT_DIR})
+ -b) Run only the build steps for the kernel and the selftests
-j) Number of jobs for compilation, similar to -j in make
(default: ${NUM_COMPILE_JOBS})
-s) Instead of powering off the VM, start an interactive
@@ -191,8 +192,9 @@ main()
local command="${DEFAULT_COMMAND}"
local update_b2c="no"
local debug_shell="no"
+ local build_only="no"
- while getopts ':hsud:j:' opt; do
+ while getopts ':hsud:j:b' opt; do
case ${opt} in
u)
update_b2c="yes"
@@ -207,6 +209,9 @@ main()
command="/bin/sh"
debug_shell="yes"
;;
+ b)
+ build_only="yes"
+ ;;
h)
usage
exit 0
@@ -226,8 +231,7 @@ main()
shift $((OPTIND -1))
# trap 'catch "$?"' EXIT
-
- if [[ "${debug_shell}" == "no" ]]; then
+ if [[ "${build_only}" == "no" && "${debug_shell}" == "no" ]]; then
if [[ $# -eq 0 ]]; then
echo "No command specified, will run ${DEFAULT_COMMAND} in the vm"
else
@@ -267,24 +271,26 @@ main()
update_kconfig "${kernel_checkout}" "${kconfig_file}"
recompile_kernel "${kernel_checkout}" "${make_command}"
+ update_selftests "${kernel_checkout}" "${make_command}"
- if [[ "${update_b2c}" == "no" && ! -f "${b2c}" ]]; then
- echo "vm2c script not found in ${b2c}"
- update_b2c="yes"
- fi
+ if [[ "${build_only}" == "no" ]]; then
+ if [[ "${update_b2c}" == "no" && ! -f "${b2c}" ]]; then
+ echo "vm2c script not found in ${b2c}"
+ update_b2c="yes"
+ fi
- if [[ "${update_b2c}" == "yes" ]]; then
- download $B2C_URL $b2c
- chmod +x $b2c
- fi
+ if [[ "${update_b2c}" == "yes" ]]; then
+ download $B2C_URL $b2c
+ chmod +x $b2c
+ fi
- update_selftests "${kernel_checkout}" "${make_command}"
- run_vm "${kernel_checkout}" $b2c "${kernel_bzimage}" "${command}"
- if [[ "${debug_shell}" != "yes" ]]; then
- echo "Logs saved in ${OUTPUT_DIR}/${LOG_FILE}"
- fi
+ run_vm "${kernel_checkout}" $b2c "${kernel_bzimage}" "${command}"
+ if [[ "${debug_shell}" != "yes" ]]; then
+ echo "Logs saved in ${OUTPUT_DIR}/${LOG_FILE}"
+ fi
- exit $(cat ${OUTPUT_DIR}/${EXIT_STATUS_FILE})
+ exit $(cat ${OUTPUT_DIR}/${EXIT_STATUS_FILE})
+ fi
}
main "$@"
diff --git a/tools/testing/selftests/iommu/iommufd.c b/tools/testing/selftests/iommu/iommufd.c
index 6ed328c863c4..1a881e7a21d1 100644
--- a/tools/testing/selftests/iommu/iommufd.c
+++ b/tools/testing/selftests/iommu/iommufd.c
@@ -116,6 +116,7 @@ TEST_F(iommufd, cmd_length)
TEST_LENGTH(iommu_destroy, IOMMU_DESTROY, id);
TEST_LENGTH(iommu_hw_info, IOMMU_GET_HW_INFO, __reserved);
TEST_LENGTH(iommu_hwpt_alloc, IOMMU_HWPT_ALLOC, __reserved);
+ TEST_LENGTH(iommu_hwpt_invalidate, IOMMU_HWPT_INVALIDATE, __reserved);
TEST_LENGTH(iommu_ioas_alloc, IOMMU_IOAS_ALLOC, out_ioas_id);
TEST_LENGTH(iommu_ioas_iova_ranges, IOMMU_IOAS_IOVA_RANGES,
out_iova_alignment);
@@ -271,7 +272,9 @@ TEST_F(iommufd_ioas, alloc_hwpt_nested)
struct iommu_hwpt_selftest data = {
.iotlb = IOMMU_TEST_IOTLB_DEFAULT,
};
+ struct iommu_hwpt_invalidate_selftest inv_reqs[2] = {};
uint32_t nested_hwpt_id[2] = {};
+ uint32_t num_inv;
uint32_t parent_hwpt_id = 0;
uint32_t parent_hwpt_id_not_work = 0;
uint32_t test_hwpt_id = 0;
@@ -330,6 +333,10 @@ TEST_F(iommufd_ioas, alloc_hwpt_nested)
&nested_hwpt_id[1],
IOMMU_HWPT_DATA_SELFTEST, &data,
sizeof(data));
+ test_cmd_hwpt_check_iotlb_all(nested_hwpt_id[0],
+ IOMMU_TEST_IOTLB_DEFAULT);
+ test_cmd_hwpt_check_iotlb_all(nested_hwpt_id[1],
+ IOMMU_TEST_IOTLB_DEFAULT);
/* Negative test: a nested hwpt on top of a nested hwpt */
test_err_hwpt_alloc_nested(EINVAL, self->device_id,
@@ -340,6 +347,151 @@ TEST_F(iommufd_ioas, alloc_hwpt_nested)
EXPECT_ERRNO(EBUSY,
_test_ioctl_destroy(self->fd, parent_hwpt_id));
+ /* hwpt_invalidate only supports a user-managed hwpt (nested) */
+ num_inv = 1;
+ test_err_hwpt_invalidate(ENOENT, parent_hwpt_id, inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ sizeof(*inv_reqs), &num_inv);
+ assert(!num_inv);
+
+ /* Check data_type by passing zero-length array */
+ num_inv = 0;
+ test_cmd_hwpt_invalidate(nested_hwpt_id[0], inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ sizeof(*inv_reqs), &num_inv);
+ assert(!num_inv);
+
+ /* Negative test: Invalid data_type */
+ num_inv = 1;
+ test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST_INVALID,
+ sizeof(*inv_reqs), &num_inv);
+ assert(!num_inv);
+
+ /* Negative test: structure size sanity */
+ num_inv = 1;
+ test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ sizeof(*inv_reqs) + 1, &num_inv);
+ assert(!num_inv);
+
+ num_inv = 1;
+ test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ 1, &num_inv);
+ assert(!num_inv);
+
+ /* Negative test: invalid flag is passed */
+ num_inv = 1;
+ inv_reqs[0].flags = 0xffffffff;
+ test_err_hwpt_invalidate(EOPNOTSUPP, nested_hwpt_id[0], inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ sizeof(*inv_reqs), &num_inv);
+ assert(!num_inv);
+
+ /* Negative test: invalid data_uptr when array is not empty */
+ num_inv = 1;
+ inv_reqs[0].flags = 0;
+ test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], NULL,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ sizeof(*inv_reqs), &num_inv);
+ assert(!num_inv);
+
+ /* Negative test: invalid entry_len when array is not empty */
+ num_inv = 1;
+ inv_reqs[0].flags = 0;
+ test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ 0, &num_inv);
+ assert(!num_inv);
+
+ /* Negative test: invalid iotlb_id */
+ num_inv = 1;
+ inv_reqs[0].flags = 0;
+ inv_reqs[0].iotlb_id = MOCK_NESTED_DOMAIN_IOTLB_ID_MAX + 1;
+ test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ sizeof(*inv_reqs), &num_inv);
+ assert(!num_inv);
+
+ /*
+ * Invalidate the 1st iotlb entry but fail the 2nd request
+ * due to invalid flags configuration in the 2nd request.
+ */
+ num_inv = 2;
+ inv_reqs[0].flags = 0;
+ inv_reqs[0].iotlb_id = 0;
+ inv_reqs[1].flags = 0xffffffff;
+ inv_reqs[1].iotlb_id = 1;
+ test_err_hwpt_invalidate(EOPNOTSUPP, nested_hwpt_id[0], inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ sizeof(*inv_reqs), &num_inv);
+ assert(num_inv == 1);
+ test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 0, 0);
+ test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 1,
+ IOMMU_TEST_IOTLB_DEFAULT);
+ test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 2,
+ IOMMU_TEST_IOTLB_DEFAULT);
+ test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 3,
+ IOMMU_TEST_IOTLB_DEFAULT);
+
+ /*
+ * Invalidate the 1st iotlb entry but fail the 2nd request
+ * due to invalid iotlb_id configuration in the 2nd request.
+ */
+ num_inv = 2;
+ inv_reqs[0].flags = 0;
+ inv_reqs[0].iotlb_id = 0;
+ inv_reqs[1].flags = 0;
+ inv_reqs[1].iotlb_id = MOCK_NESTED_DOMAIN_IOTLB_ID_MAX + 1;
+ test_err_hwpt_invalidate(EINVAL, nested_hwpt_id[0], inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ sizeof(*inv_reqs), &num_inv);
+ assert(num_inv == 1);
+ test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 0, 0);
+ test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 1,
+ IOMMU_TEST_IOTLB_DEFAULT);
+ test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 2,
+ IOMMU_TEST_IOTLB_DEFAULT);
+ test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 3,
+ IOMMU_TEST_IOTLB_DEFAULT);
+
+ /* Invalidate the 2nd iotlb entry and verify */
+ num_inv = 1;
+ inv_reqs[0].flags = 0;
+ inv_reqs[0].iotlb_id = 1;
+ test_cmd_hwpt_invalidate(nested_hwpt_id[0], inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ sizeof(*inv_reqs), &num_inv);
+ assert(num_inv == 1);
+ test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 0, 0);
+ test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 1, 0);
+ test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 2,
+ IOMMU_TEST_IOTLB_DEFAULT);
+ test_cmd_hwpt_check_iotlb(nested_hwpt_id[0], 3,
+ IOMMU_TEST_IOTLB_DEFAULT);
+
+ /* Invalidate the 3rd and 4th iotlb entries and verify */
+ num_inv = 2;
+ inv_reqs[0].flags = 0;
+ inv_reqs[0].iotlb_id = 2;
+ inv_reqs[1].flags = 0;
+ inv_reqs[1].iotlb_id = 3;
+ test_cmd_hwpt_invalidate(nested_hwpt_id[0], inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ sizeof(*inv_reqs), &num_inv);
+ assert(num_inv == 2);
+ test_cmd_hwpt_check_iotlb_all(nested_hwpt_id[0], 0);
+
+ /* Invalidate all iotlb entries for nested_hwpt_id[1] and verify */
+ num_inv = 1;
+ inv_reqs[0].flags = IOMMU_TEST_INVALIDATE_FLAG_ALL;
+ test_cmd_hwpt_invalidate(nested_hwpt_id[1], inv_reqs,
+ IOMMU_HWPT_INVALIDATE_DATA_SELFTEST,
+ sizeof(*inv_reqs), &num_inv);
+ assert(num_inv == 1);
+ test_cmd_hwpt_check_iotlb_all(nested_hwpt_id[1], 0);
+
/* Attach device to nested_hwpt_id[0] that then will be busy */
test_cmd_mock_domain_replace(self->stdev_id, nested_hwpt_id[0]);
EXPECT_ERRNO(EBUSY,
diff --git a/tools/testing/selftests/iommu/iommufd_utils.h b/tools/testing/selftests/iommu/iommufd_utils.h
index ad9202335656..c646264aa41f 100644
--- a/tools/testing/selftests/iommu/iommufd_utils.h
+++ b/tools/testing/selftests/iommu/iommufd_utils.h
@@ -195,6 +195,61 @@ static int _test_cmd_hwpt_alloc(int fd, __u32 device_id, __u32 pt_id,
_test_cmd_hwpt_alloc(self->fd, device_id, pt_id, flags, \
hwpt_id, data_type, data, data_len))
+#define test_cmd_hwpt_check_iotlb(hwpt_id, iotlb_id, expected) \
+ ({ \
+ struct iommu_test_cmd test_cmd = { \
+ .size = sizeof(test_cmd), \
+ .op = IOMMU_TEST_OP_MD_CHECK_IOTLB, \
+ .id = hwpt_id, \
+ .check_iotlb = { \
+ .id = iotlb_id, \
+ .iotlb = expected, \
+ }, \
+ }; \
+ ASSERT_EQ(0, \
+ ioctl(self->fd, \
+ _IOMMU_TEST_CMD(IOMMU_TEST_OP_MD_CHECK_IOTLB), \
+ &test_cmd)); \
+ })
+
+#define test_cmd_hwpt_check_iotlb_all(hwpt_id, expected) \
+ ({ \
+ int i; \
+ for (i = 0; i < MOCK_NESTED_DOMAIN_IOTLB_NUM; i++) \
+ test_cmd_hwpt_check_iotlb(hwpt_id, i, expected); \
+ })
+
+static int _test_cmd_hwpt_invalidate(int fd, __u32 hwpt_id, void *reqs,
+ uint32_t data_type, uint32_t lreq,
+ uint32_t *nreqs)
+{
+ struct iommu_hwpt_invalidate cmd = {
+ .size = sizeof(cmd),
+ .hwpt_id = hwpt_id,
+ .data_type = data_type,
+ .data_uptr = (uint64_t)reqs,
+ .entry_len = lreq,
+ .entry_num = *nreqs,
+ };
+ int rc = ioctl(fd, IOMMU_HWPT_INVALIDATE, &cmd);
+ *nreqs = cmd.entry_num;
+ return rc;
+}
+
+#define test_cmd_hwpt_invalidate(hwpt_id, reqs, data_type, lreq, nreqs) \
+ ({ \
+ ASSERT_EQ(0, \
+ _test_cmd_hwpt_invalidate(self->fd, hwpt_id, reqs, \
+ data_type, lreq, nreqs)); \
+ })
+#define test_err_hwpt_invalidate(_errno, hwpt_id, reqs, data_type, lreq, \
+ nreqs) \
+ ({ \
+ EXPECT_ERRNO(_errno, _test_cmd_hwpt_invalidate( \
+ self->fd, hwpt_id, reqs, \
+ data_type, lreq, nreqs)); \
+ })
+
static int _test_cmd_access_replace_ioas(int fd, __u32 access_id,
unsigned int ioas_id)
{
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index 3e0c36b8ddd5..492e937fab00 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -77,11 +77,12 @@ TEST_GEN_PROGS_x86_64 += x86_64/hyperv_svm_test
TEST_GEN_PROGS_x86_64 += x86_64/hyperv_tlb_flush
TEST_GEN_PROGS_x86_64 += x86_64/kvm_clock_test
TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test
-TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test
TEST_GEN_PROGS_x86_64 += x86_64/monitor_mwait_test
TEST_GEN_PROGS_x86_64 += x86_64/nested_exceptions_test
TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test
TEST_GEN_PROGS_x86_64 += x86_64/pmu_event_filter_test
+TEST_GEN_PROGS_x86_64 += x86_64/private_mem_conversions_test
+TEST_GEN_PROGS_x86_64 += x86_64/private_mem_kvm_exits_test
TEST_GEN_PROGS_x86_64 += x86_64/set_boot_cpu_id
TEST_GEN_PROGS_x86_64 += x86_64/set_sregs_test
TEST_GEN_PROGS_x86_64 += x86_64/smaller_maxphyaddr_emulation_test
@@ -124,6 +125,7 @@ TEST_GEN_PROGS_x86_64 += access_tracking_perf_test
TEST_GEN_PROGS_x86_64 += demand_paging_test
TEST_GEN_PROGS_x86_64 += dirty_log_test
TEST_GEN_PROGS_x86_64 += dirty_log_perf_test
+TEST_GEN_PROGS_x86_64 += guest_memfd_test
TEST_GEN_PROGS_x86_64 += guest_print_test
TEST_GEN_PROGS_x86_64 += hardware_disable_test
TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus
@@ -184,12 +186,13 @@ TEST_GEN_PROGS_s390x += kvm_binary_stats_test
TEST_GEN_PROGS_riscv += demand_paging_test
TEST_GEN_PROGS_riscv += dirty_log_test
-TEST_GEN_PROGS_riscv += guest_print_test
TEST_GEN_PROGS_riscv += get-reg-list
+TEST_GEN_PROGS_riscv += guest_print_test
+TEST_GEN_PROGS_riscv += kvm_binary_stats_test
TEST_GEN_PROGS_riscv += kvm_create_max_vcpus
TEST_GEN_PROGS_riscv += kvm_page_table_test
TEST_GEN_PROGS_riscv += set_memory_region_test
-TEST_GEN_PROGS_riscv += kvm_binary_stats_test
+TEST_GEN_PROGS_riscv += steal_time
SPLIT_TESTS += get-reg-list
diff --git a/tools/testing/selftests/kvm/aarch64/page_fault_test.c b/tools/testing/selftests/kvm/aarch64/page_fault_test.c
index eb4217b7c768..08a5ca5bed56 100644
--- a/tools/testing/selftests/kvm/aarch64/page_fault_test.c
+++ b/tools/testing/selftests/kvm/aarch64/page_fault_test.c
@@ -705,7 +705,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
print_test_banner(mode, p);
- vm = ____vm_create(mode);
+ vm = ____vm_create(VM_SHAPE(mode));
setup_memslots(vm, p);
kvm_vm_elf_load(vm, program_invocation_name);
setup_ucall(vm);
diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c
index 936f3a8d1b83..6cbecf499767 100644
--- a/tools/testing/selftests/kvm/dirty_log_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_test.c
@@ -699,7 +699,7 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, struct kvm_vcpu **vcpu,
pr_info("Testing guest mode: %s\n", vm_guest_mode_string(mode));
- vm = __vm_create(mode, 1, extra_mem_pages);
+ vm = __vm_create(VM_SHAPE(mode), 1, extra_mem_pages);
log_mode_create_vm_done(vm);
*vcpu = vm_vcpu_add(vm, 0, guest_code);
diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c
new file mode 100644
index 000000000000..c78a98c1a915
--- /dev/null
+++ b/tools/testing/selftests/kvm/guest_memfd_test.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright Intel Corporation, 2023
+ *
+ * Author: Chao Peng <[email protected]>
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include <linux/bitmap.h>
+#include <linux/falloc.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "test_util.h"
+#include "kvm_util_base.h"
+
+static void test_file_read_write(int fd)
+{
+ char buf[64];
+
+ TEST_ASSERT(read(fd, buf, sizeof(buf)) < 0,
+ "read on a guest_mem fd should fail");
+ TEST_ASSERT(write(fd, buf, sizeof(buf)) < 0,
+ "write on a guest_mem fd should fail");
+ TEST_ASSERT(pread(fd, buf, sizeof(buf), 0) < 0,
+ "pread on a guest_mem fd should fail");
+ TEST_ASSERT(pwrite(fd, buf, sizeof(buf), 0) < 0,
+ "pwrite on a guest_mem fd should fail");
+}
+
+static void test_mmap(int fd, size_t page_size)
+{
+ char *mem;
+
+ mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ TEST_ASSERT_EQ(mem, MAP_FAILED);
+}
+
+static void test_file_size(int fd, size_t page_size, size_t total_size)
+{
+ struct stat sb;
+ int ret;
+
+ ret = fstat(fd, &sb);
+ TEST_ASSERT(!ret, "fstat should succeed");
+ TEST_ASSERT_EQ(sb.st_size, total_size);
+ TEST_ASSERT_EQ(sb.st_blksize, page_size);
+}
+
+static void test_fallocate(int fd, size_t page_size, size_t total_size)
+{
+ int ret;
+
+ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, total_size);
+ TEST_ASSERT(!ret, "fallocate with aligned offset and size should succeed");
+
+ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
+ page_size - 1, page_size);
+ TEST_ASSERT(ret, "fallocate with unaligned offset should fail");
+
+ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, total_size, page_size);
+ TEST_ASSERT(ret, "fallocate beginning at total_size should fail");
+
+ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, total_size + page_size, page_size);
+ TEST_ASSERT(ret, "fallocate beginning after total_size should fail");
+
+ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
+ total_size, page_size);
+ TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) at total_size should succeed");
+
+ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
+ total_size + page_size, page_size);
+ TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) after total_size should succeed");
+
+ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
+ page_size, page_size - 1);
+ TEST_ASSERT(ret, "fallocate with unaligned size should fail");
+
+ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
+ page_size, page_size);
+ TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) with aligned offset and size should succeed");
+
+ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, page_size, page_size);
+ TEST_ASSERT(!ret, "fallocate to restore punched hole should succeed");
+}
+
+static void test_invalid_punch_hole(int fd, size_t page_size, size_t total_size)
+{
+ struct {
+ off_t offset;
+ off_t len;
+ } testcases[] = {
+ {0, 1},
+ {0, page_size - 1},
+ {0, page_size + 1},
+
+ {1, 1},
+ {1, page_size - 1},
+ {1, page_size},
+ {1, page_size + 1},
+
+ {page_size, 1},
+ {page_size, page_size - 1},
+ {page_size, page_size + 1},
+ };
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(testcases); i++) {
+ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
+ testcases[i].offset, testcases[i].len);
+ TEST_ASSERT(ret == -1 && errno == EINVAL,
+ "PUNCH_HOLE with !PAGE_SIZE offset (%lx) and/or length (%lx) should fail",
+ testcases[i].offset, testcases[i].len);
+ }
+}
+
+static void test_create_guest_memfd_invalid(struct kvm_vm *vm)
+{
+ size_t page_size = getpagesize();
+ uint64_t flag;
+ size_t size;
+ int fd;
+
+ for (size = 1; size < page_size; size++) {
+ fd = __vm_create_guest_memfd(vm, size, 0);
+ TEST_ASSERT(fd == -1 && errno == EINVAL,
+ "guest_memfd() with non-page-aligned page size '0x%lx' should fail with EINVAL",
+ size);
+ }
+
+ for (flag = 0; flag; flag <<= 1) {
+ fd = __vm_create_guest_memfd(vm, page_size, flag);
+ TEST_ASSERT(fd == -1 && errno == EINVAL,
+ "guest_memfd() with flag '0x%lx' should fail with EINVAL",
+ flag);
+ }
+}
+
+static void test_create_guest_memfd_multiple(struct kvm_vm *vm)
+{
+ int fd1, fd2, ret;
+ struct stat st1, st2;
+
+ fd1 = __vm_create_guest_memfd(vm, 4096, 0);
+ TEST_ASSERT(fd1 != -1, "memfd creation should succeed");
+
+ ret = fstat(fd1, &st1);
+ TEST_ASSERT(ret != -1, "memfd fstat should succeed");
+ TEST_ASSERT(st1.st_size == 4096, "memfd st_size should match requested size");
+
+ fd2 = __vm_create_guest_memfd(vm, 8192, 0);
+ TEST_ASSERT(fd2 != -1, "memfd creation should succeed");
+
+ ret = fstat(fd2, &st2);
+ TEST_ASSERT(ret != -1, "memfd fstat should succeed");
+ TEST_ASSERT(st2.st_size == 8192, "second memfd st_size should match requested size");
+
+ ret = fstat(fd1, &st1);
+ TEST_ASSERT(ret != -1, "memfd fstat should succeed");
+ TEST_ASSERT(st1.st_size == 4096, "first memfd st_size should still match requested size");
+ TEST_ASSERT(st1.st_ino != st2.st_ino, "different memfd should have different inode numbers");
+}
+
+int main(int argc, char *argv[])
+{
+ size_t page_size;
+ size_t total_size;
+ int fd;
+ struct kvm_vm *vm;
+
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_GUEST_MEMFD));
+
+ page_size = getpagesize();
+ total_size = page_size * 4;
+
+ vm = vm_create_barebones();
+
+ test_create_guest_memfd_invalid(vm);
+ test_create_guest_memfd_multiple(vm);
+
+ fd = vm_create_guest_memfd(vm, total_size, 0);
+
+ test_file_read_write(fd);
+ test_mmap(fd, page_size);
+ test_file_size(fd, page_size, total_size);
+ test_fallocate(fd, page_size, total_size);
+ test_invalid_punch_hole(fd, page_size, total_size);
+
+ close(fd);
+}
diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h
index c42d683102c7..cf20e44e86f2 100644
--- a/tools/testing/selftests/kvm/include/aarch64/processor.h
+++ b/tools/testing/selftests/kvm/include/aarch64/processor.h
@@ -119,8 +119,8 @@ enum {
/* Access flag update enable/disable */
#define TCR_EL1_HA (1ULL << 39)
-void aarch64_get_supported_page_sizes(uint32_t ipa,
- bool *ps4k, bool *ps16k, bool *ps64k);
+void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k,
+ uint32_t *ipa16k, uint32_t *ipa64k);
void vm_init_descriptor_tables(struct kvm_vm *vm);
void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu);
diff --git a/tools/testing/selftests/kvm/include/guest_modes.h b/tools/testing/selftests/kvm/include/guest_modes.h
index b691df33e64e..63f5167397cc 100644
--- a/tools/testing/selftests/kvm/include/guest_modes.h
+++ b/tools/testing/selftests/kvm/include/guest_modes.h
@@ -11,8 +11,8 @@ struct guest_mode {
extern struct guest_mode guest_modes[NUM_VM_MODES];
-#define guest_mode_append(mode, supported, enabled) ({ \
- guest_modes[mode] = (struct guest_mode){ supported, enabled }; \
+#define guest_mode_append(mode, enabled) ({ \
+ guest_modes[mode] = (struct guest_mode){ (enabled), (enabled) }; \
})
void guest_modes_append_default(void);
diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h
index a18db6a7b3cf..9e5afc472c14 100644
--- a/tools/testing/selftests/kvm/include/kvm_util_base.h
+++ b/tools/testing/selftests/kvm/include/kvm_util_base.h
@@ -44,7 +44,7 @@ typedef uint64_t vm_paddr_t; /* Virtual Machine (Guest) physical address */
typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */
struct userspace_mem_region {
- struct kvm_userspace_memory_region region;
+ struct kvm_userspace_memory_region2 region;
struct sparsebit *unused_phy_pages;
int fd;
off_t offset;
@@ -129,6 +129,7 @@ struct vcpu_reg_sublist {
const char *name;
long capability;
int feature;
+ int feature_type;
bool finalize;
__u64 *regs;
__u64 regs_n;
@@ -171,6 +172,7 @@ static inline struct userspace_mem_region *vm_get_mem_region(struct kvm_vm *vm,
enum vm_guest_mode {
VM_MODE_P52V48_4K,
+ VM_MODE_P52V48_16K,
VM_MODE_P52V48_64K,
VM_MODE_P48V48_4K,
VM_MODE_P48V48_16K,
@@ -188,6 +190,23 @@ enum vm_guest_mode {
NUM_VM_MODES,
};
+struct vm_shape {
+ enum vm_guest_mode mode;
+ unsigned int type;
+};
+
+#define VM_TYPE_DEFAULT 0
+
+#define VM_SHAPE(__mode) \
+({ \
+ struct vm_shape shape = { \
+ .mode = (__mode), \
+ .type = VM_TYPE_DEFAULT \
+ }; \
+ \
+ shape; \
+})
+
#if defined(__aarch64__)
extern enum vm_guest_mode vm_mode_default;
@@ -220,6 +239,8 @@ extern enum vm_guest_mode vm_mode_default;
#endif
+#define VM_SHAPE_DEFAULT VM_SHAPE(VM_MODE_DEFAULT)
+
#define MIN_PAGE_SIZE (1U << MIN_PAGE_SHIFT)
#define PTES_PER_MIN_PAGE ptes_per_page(MIN_PAGE_SIZE)
@@ -248,6 +269,13 @@ static inline bool kvm_has_cap(long cap)
#define __KVM_SYSCALL_ERROR(_name, _ret) \
"%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno)
+/*
+ * Use the "inner", double-underscore macro when reporting errors from within
+ * other macros so that the name of ioctl() and not its literal numeric value
+ * is printed on error. The "outer" macro is strongly preferred when reporting
+ * errors "directly", i.e. without an additional layer of macros, as it reduces
+ * the probability of passing in the wrong string.
+ */
#define __KVM_IOCTL_ERROR(_name, _ret) __KVM_SYSCALL_ERROR(_name, _ret)
#define KVM_IOCTL_ERROR(_ioctl, _ret) __KVM_IOCTL_ERROR(#_ioctl, _ret)
@@ -260,17 +288,13 @@ static inline bool kvm_has_cap(long cap)
#define __kvm_ioctl(kvm_fd, cmd, arg) \
kvm_do_ioctl(kvm_fd, cmd, arg)
-
-#define _kvm_ioctl(kvm_fd, cmd, name, arg) \
+#define kvm_ioctl(kvm_fd, cmd, arg) \
({ \
int ret = __kvm_ioctl(kvm_fd, cmd, arg); \
\
- TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); \
+ TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(#cmd, ret)); \
})
-#define kvm_ioctl(kvm_fd, cmd, arg) \
- _kvm_ioctl(kvm_fd, cmd, #cmd, arg)
-
static __always_inline void static_assert_is_vm(struct kvm_vm *vm) { }
#define __vm_ioctl(vm, cmd, arg) \
@@ -279,17 +303,42 @@ static __always_inline void static_assert_is_vm(struct kvm_vm *vm) { }
kvm_do_ioctl((vm)->fd, cmd, arg); \
})
-#define _vm_ioctl(vm, cmd, name, arg) \
+/*
+ * Assert that a VM or vCPU ioctl() succeeded, with extra magic to detect if
+ * the ioctl() failed because KVM killed/bugged the VM. To detect a dead VM,
+ * probe KVM_CAP_USER_MEMORY, which (a) has been supported by KVM since before
+ * selftests existed and (b) should never outright fail, i.e. is supposed to
+ * return 0 or 1. If KVM kills a VM, KVM returns -EIO for all ioctl()s for the
+ * VM and its vCPUs, including KVM_CHECK_EXTENSION.
+ */
+#define __TEST_ASSERT_VM_VCPU_IOCTL(cond, name, ret, vm) \
+do { \
+ int __errno = errno; \
+ \
+ static_assert_is_vm(vm); \
+ \
+ if (cond) \
+ break; \
+ \
+ if (errno == EIO && \
+ __vm_ioctl(vm, KVM_CHECK_EXTENSION, (void *)KVM_CAP_USER_MEMORY) < 0) { \
+ TEST_ASSERT(errno == EIO, "KVM killed the VM, should return -EIO"); \
+ TEST_FAIL("KVM killed/bugged the VM, check the kernel log for clues"); \
+ } \
+ errno = __errno; \
+ TEST_ASSERT(cond, __KVM_IOCTL_ERROR(name, ret)); \
+} while (0)
+
+#define TEST_ASSERT_VM_VCPU_IOCTL(cond, cmd, ret, vm) \
+ __TEST_ASSERT_VM_VCPU_IOCTL(cond, #cmd, ret, vm)
+
+#define vm_ioctl(vm, cmd, arg) \
({ \
int ret = __vm_ioctl(vm, cmd, arg); \
\
- TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); \
+ __TEST_ASSERT_VM_VCPU_IOCTL(!ret, #cmd, ret, vm); \
})
-#define vm_ioctl(vm, cmd, arg) \
- _vm_ioctl(vm, cmd, #cmd, arg)
-
-
static __always_inline void static_assert_is_vcpu(struct kvm_vcpu *vcpu) { }
#define __vcpu_ioctl(vcpu, cmd, arg) \
@@ -298,16 +347,13 @@ static __always_inline void static_assert_is_vcpu(struct kvm_vcpu *vcpu) { }
kvm_do_ioctl((vcpu)->fd, cmd, arg); \
})
-#define _vcpu_ioctl(vcpu, cmd, name, arg) \
+#define vcpu_ioctl(vcpu, cmd, arg) \
({ \
int ret = __vcpu_ioctl(vcpu, cmd, arg); \
\
- TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); \
+ __TEST_ASSERT_VM_VCPU_IOCTL(!ret, #cmd, ret, (vcpu)->vm); \
})
-#define vcpu_ioctl(vcpu, cmd, arg) \
- _vcpu_ioctl(vcpu, cmd, #cmd, arg)
-
/*
* Looks up and returns the value corresponding to the capability
* (KVM_CAP_*) given by cap.
@@ -316,7 +362,7 @@ static inline int vm_check_cap(struct kvm_vm *vm, long cap)
{
int ret = __vm_ioctl(vm, KVM_CHECK_EXTENSION, (void *)cap);
- TEST_ASSERT(ret >= 0, KVM_IOCTL_ERROR(KVM_CHECK_EXTENSION, ret));
+ TEST_ASSERT_VM_VCPU_IOCTL(ret >= 0, KVM_CHECK_EXTENSION, ret, vm);
return ret;
}
@@ -333,6 +379,54 @@ static inline void vm_enable_cap(struct kvm_vm *vm, uint32_t cap, uint64_t arg0)
vm_ioctl(vm, KVM_ENABLE_CAP, &enable_cap);
}
+static inline void vm_set_memory_attributes(struct kvm_vm *vm, uint64_t gpa,
+ uint64_t size, uint64_t attributes)
+{
+ struct kvm_memory_attributes attr = {
+ .attributes = attributes,
+ .address = gpa,
+ .size = size,
+ .flags = 0,
+ };
+
+ /*
+ * KVM_SET_MEMORY_ATTRIBUTES overwrites _all_ attributes. These flows
+ * need significant enhancements to support multiple attributes.
+ */
+ TEST_ASSERT(!attributes || attributes == KVM_MEMORY_ATTRIBUTE_PRIVATE,
+ "Update me to support multiple attributes!");
+
+ vm_ioctl(vm, KVM_SET_MEMORY_ATTRIBUTES, &attr);
+}
+
+
+static inline void vm_mem_set_private(struct kvm_vm *vm, uint64_t gpa,
+ uint64_t size)
+{
+ vm_set_memory_attributes(vm, gpa, size, KVM_MEMORY_ATTRIBUTE_PRIVATE);
+}
+
+static inline void vm_mem_set_shared(struct kvm_vm *vm, uint64_t gpa,
+ uint64_t size)
+{
+ vm_set_memory_attributes(vm, gpa, size, 0);
+}
+
+void vm_guest_mem_fallocate(struct kvm_vm *vm, uint64_t gpa, uint64_t size,
+ bool punch_hole);
+
+static inline void vm_guest_mem_punch_hole(struct kvm_vm *vm, uint64_t gpa,
+ uint64_t size)
+{
+ vm_guest_mem_fallocate(vm, gpa, size, true);
+}
+
+static inline void vm_guest_mem_allocate(struct kvm_vm *vm, uint64_t gpa,
+ uint64_t size)
+{
+ vm_guest_mem_fallocate(vm, gpa, size, false);
+}
+
void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size);
const char *vm_guest_mode_string(uint32_t i);
@@ -375,7 +469,7 @@ static inline int vm_get_stats_fd(struct kvm_vm *vm)
{
int fd = __vm_ioctl(vm, KVM_GET_STATS_FD, NULL);
- TEST_ASSERT(fd >= 0, KVM_IOCTL_ERROR(KVM_GET_STATS_FD, fd));
+ TEST_ASSERT_VM_VCPU_IOCTL(fd >= 0, KVM_GET_STATS_FD, fd, vm);
return fd;
}
@@ -431,14 +525,44 @@ static inline uint64_t vm_get_stat(struct kvm_vm *vm, const char *stat_name)
void vm_create_irqchip(struct kvm_vm *vm);
+static inline int __vm_create_guest_memfd(struct kvm_vm *vm, uint64_t size,
+ uint64_t flags)
+{
+ struct kvm_create_guest_memfd guest_memfd = {
+ .size = size,
+ .flags = flags,
+ };
+
+ return __vm_ioctl(vm, KVM_CREATE_GUEST_MEMFD, &guest_memfd);
+}
+
+static inline int vm_create_guest_memfd(struct kvm_vm *vm, uint64_t size,
+ uint64_t flags)
+{
+ int fd = __vm_create_guest_memfd(vm, size, flags);
+
+ TEST_ASSERT(fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_GUEST_MEMFD, fd));
+ return fd;
+}
+
void vm_set_user_memory_region(struct kvm_vm *vm, uint32_t slot, uint32_t flags,
uint64_t gpa, uint64_t size, void *hva);
int __vm_set_user_memory_region(struct kvm_vm *vm, uint32_t slot, uint32_t flags,
uint64_t gpa, uint64_t size, void *hva);
+void vm_set_user_memory_region2(struct kvm_vm *vm, uint32_t slot, uint32_t flags,
+ uint64_t gpa, uint64_t size, void *hva,
+ uint32_t guest_memfd, uint64_t guest_memfd_offset);
+int __vm_set_user_memory_region2(struct kvm_vm *vm, uint32_t slot, uint32_t flags,
+ uint64_t gpa, uint64_t size, void *hva,
+ uint32_t guest_memfd, uint64_t guest_memfd_offset);
+
void vm_userspace_mem_region_add(struct kvm_vm *vm,
enum vm_mem_backing_src_type src_type,
uint64_t guest_paddr, uint32_t slot, uint64_t npages,
uint32_t flags);
+void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
+ uint64_t guest_paddr, uint32_t slot, uint64_t npages,
+ uint32_t flags, int guest_memfd_fd, uint64_t guest_memfd_offset);
void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags);
void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa);
@@ -587,7 +711,7 @@ static inline int vcpu_get_stats_fd(struct kvm_vcpu *vcpu)
{
int fd = __vcpu_ioctl(vcpu, KVM_GET_STATS_FD, NULL);
- TEST_ASSERT(fd >= 0, KVM_IOCTL_ERROR(KVM_GET_STATS_FD, fd));
+ TEST_ASSERT_VM_VCPU_IOCTL(fd >= 0, KVM_CHECK_EXTENSION, fd, vcpu->vm);
return fd;
}
@@ -713,21 +837,33 @@ vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm);
* __vm_create() does NOT create vCPUs, @nr_runnable_vcpus is used purely to
* calculate the amount of memory needed for per-vCPU data, e.g. stacks.
*/
-struct kvm_vm *____vm_create(enum vm_guest_mode mode);
-struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint32_t nr_runnable_vcpus,
+struct kvm_vm *____vm_create(struct vm_shape shape);
+struct kvm_vm *__vm_create(struct vm_shape shape, uint32_t nr_runnable_vcpus,
uint64_t nr_extra_pages);
static inline struct kvm_vm *vm_create_barebones(void)
{
- return ____vm_create(VM_MODE_DEFAULT);
+ return ____vm_create(VM_SHAPE_DEFAULT);
}
+#ifdef __x86_64__
+static inline struct kvm_vm *vm_create_barebones_protected_vm(void)
+{
+ const struct vm_shape shape = {
+ .mode = VM_MODE_DEFAULT,
+ .type = KVM_X86_SW_PROTECTED_VM,
+ };
+
+ return ____vm_create(shape);
+}
+#endif
+
static inline struct kvm_vm *vm_create(uint32_t nr_runnable_vcpus)
{
- return __vm_create(VM_MODE_DEFAULT, nr_runnable_vcpus, 0);
+ return __vm_create(VM_SHAPE_DEFAULT, nr_runnable_vcpus, 0);
}
-struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus,
+struct kvm_vm *__vm_create_with_vcpus(struct vm_shape shape, uint32_t nr_vcpus,
uint64_t extra_mem_pages,
void *guest_code, struct kvm_vcpu *vcpus[]);
@@ -735,17 +871,27 @@ static inline struct kvm_vm *vm_create_with_vcpus(uint32_t nr_vcpus,
void *guest_code,
struct kvm_vcpu *vcpus[])
{
- return __vm_create_with_vcpus(VM_MODE_DEFAULT, nr_vcpus, 0,
+ return __vm_create_with_vcpus(VM_SHAPE_DEFAULT, nr_vcpus, 0,
guest_code, vcpus);
}
+
+struct kvm_vm *__vm_create_shape_with_one_vcpu(struct vm_shape shape,
+ struct kvm_vcpu **vcpu,
+ uint64_t extra_mem_pages,
+ void *guest_code);
+
/*
* Create a VM with a single vCPU with reasonable defaults and @extra_mem_pages
* additional pages of guest memory. Returns the VM and vCPU (via out param).
*/
-struct kvm_vm *__vm_create_with_one_vcpu(struct kvm_vcpu **vcpu,
- uint64_t extra_mem_pages,
- void *guest_code);
+static inline struct kvm_vm *__vm_create_with_one_vcpu(struct kvm_vcpu **vcpu,
+ uint64_t extra_mem_pages,
+ void *guest_code)
+{
+ return __vm_create_shape_with_one_vcpu(VM_SHAPE_DEFAULT, vcpu,
+ extra_mem_pages, guest_code);
+}
static inline struct kvm_vm *vm_create_with_one_vcpu(struct kvm_vcpu **vcpu,
void *guest_code)
@@ -753,6 +899,13 @@ static inline struct kvm_vm *vm_create_with_one_vcpu(struct kvm_vcpu **vcpu,
return __vm_create_with_one_vcpu(vcpu, 0, guest_code);
}
+static inline struct kvm_vm *vm_create_shape_with_one_vcpu(struct vm_shape shape,
+ struct kvm_vcpu **vcpu,
+ void *guest_code)
+{
+ return __vm_create_shape_with_one_vcpu(shape, vcpu, 0, guest_code);
+}
+
struct kvm_vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm);
void kvm_pin_this_task_to_pcpu(uint32_t pcpu);
@@ -776,10 +929,6 @@ vm_adjust_num_guest_pages(enum vm_guest_mode mode, unsigned int num_guest_pages)
return n;
}
-struct kvm_userspace_memory_region *
-kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start,
- uint64_t end);
-
#define sync_global_to_guest(vm, g) ({ \
typeof(g) *_p = addr_gva2hva(vm, (vm_vaddr_t)&(g)); \
memcpy(_p, &(g), sizeof(g)); \
diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h
index 5b62a3d2aa9b..a0f9efe5a2a8 100644
--- a/tools/testing/selftests/kvm/include/riscv/processor.h
+++ b/tools/testing/selftests/kvm/include/riscv/processor.h
@@ -10,10 +10,10 @@
#include "kvm_util.h"
#include <linux/stringify.h>
-static inline uint64_t __kvm_reg_id(uint64_t type, uint64_t idx,
- uint64_t size)
+static inline uint64_t __kvm_reg_id(uint64_t type, uint64_t subtype,
+ uint64_t idx, uint64_t size)
{
- return KVM_REG_RISCV | type | idx | size;
+ return KVM_REG_RISCV | type | subtype | idx | size;
}
#if __riscv_xlen == 64
@@ -22,24 +22,30 @@ static inline uint64_t __kvm_reg_id(uint64_t type, uint64_t idx,
#define KVM_REG_SIZE_ULONG KVM_REG_SIZE_U32
#endif
-#define RISCV_CONFIG_REG(name) __kvm_reg_id(KVM_REG_RISCV_CONFIG, \
- KVM_REG_RISCV_CONFIG_REG(name), \
- KVM_REG_SIZE_ULONG)
+#define RISCV_CONFIG_REG(name) __kvm_reg_id(KVM_REG_RISCV_CONFIG, 0, \
+ KVM_REG_RISCV_CONFIG_REG(name), \
+ KVM_REG_SIZE_ULONG)
-#define RISCV_CORE_REG(name) __kvm_reg_id(KVM_REG_RISCV_CORE, \
- KVM_REG_RISCV_CORE_REG(name), \
- KVM_REG_SIZE_ULONG)
+#define RISCV_CORE_REG(name) __kvm_reg_id(KVM_REG_RISCV_CORE, 0, \
+ KVM_REG_RISCV_CORE_REG(name), \
+ KVM_REG_SIZE_ULONG)
-#define RISCV_CSR_REG(name) __kvm_reg_id(KVM_REG_RISCV_CSR, \
- KVM_REG_RISCV_CSR_REG(name), \
- KVM_REG_SIZE_ULONG)
+#define RISCV_GENERAL_CSR_REG(name) __kvm_reg_id(KVM_REG_RISCV_CSR, \
+ KVM_REG_RISCV_CSR_GENERAL, \
+ KVM_REG_RISCV_CSR_REG(name), \
+ KVM_REG_SIZE_ULONG)
-#define RISCV_TIMER_REG(name) __kvm_reg_id(KVM_REG_RISCV_TIMER, \
- KVM_REG_RISCV_TIMER_REG(name), \
- KVM_REG_SIZE_U64)
+#define RISCV_TIMER_REG(name) __kvm_reg_id(KVM_REG_RISCV_TIMER, 0, \
+ KVM_REG_RISCV_TIMER_REG(name), \
+ KVM_REG_SIZE_U64)
-#define RISCV_ISA_EXT_REG(idx) __kvm_reg_id(KVM_REG_RISCV_ISA_EXT, \
- idx, KVM_REG_SIZE_ULONG)
+#define RISCV_ISA_EXT_REG(idx) __kvm_reg_id(KVM_REG_RISCV_ISA_EXT, \
+ KVM_REG_RISCV_ISA_SINGLE, \
+ idx, KVM_REG_SIZE_ULONG)
+
+#define RISCV_SBI_EXT_REG(idx) __kvm_reg_id(KVM_REG_RISCV_SBI_EXT, \
+ KVM_REG_RISCV_SBI_SINGLE, \
+ idx, KVM_REG_SIZE_ULONG)
/* L3 index Bit[47:39] */
#define PGTBL_L3_INDEX_MASK 0x0000FF8000000000ULL
@@ -102,6 +108,17 @@ static inline uint64_t __kvm_reg_id(uint64_t type, uint64_t idx,
#define SATP_ASID_SHIFT 44
#define SATP_ASID_MASK _AC(0xFFFF, UL)
+/* SBI return error codes */
+#define SBI_SUCCESS 0
+#define SBI_ERR_FAILURE -1
+#define SBI_ERR_NOT_SUPPORTED -2
+#define SBI_ERR_INVALID_PARAM -3
+#define SBI_ERR_DENIED -4
+#define SBI_ERR_INVALID_ADDRESS -5
+#define SBI_ERR_ALREADY_AVAILABLE -6
+#define SBI_ERR_ALREADY_STARTED -7
+#define SBI_ERR_ALREADY_STOPPED -8
+
#define SBI_EXT_EXPERIMENTAL_START 0x08000000
#define SBI_EXT_EXPERIMENTAL_END 0x08FFFFFF
@@ -109,6 +126,15 @@ static inline uint64_t __kvm_reg_id(uint64_t type, uint64_t idx,
#define KVM_RISCV_SELFTESTS_SBI_UCALL 0
#define KVM_RISCV_SELFTESTS_SBI_UNEXP 1
+enum sbi_ext_id {
+ SBI_EXT_BASE = 0x10,
+ SBI_EXT_STA = 0x535441,
+};
+
+enum sbi_ext_base_fid {
+ SBI_EXT_BASE_PROBE_EXT = 3,
+};
+
struct sbiret {
long error;
long value;
@@ -119,4 +145,6 @@ struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
unsigned long arg3, unsigned long arg4,
unsigned long arg5);
+bool guest_sbi_probe_extension(int extid, long *out_val);
+
#endif /* SELFTEST_KVM_PROCESSOR_H */
diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h
index 8e5f413a593d..71a41fa924b7 100644
--- a/tools/testing/selftests/kvm/include/test_util.h
+++ b/tools/testing/selftests/kvm/include/test_util.h
@@ -142,6 +142,11 @@ static inline bool backing_src_is_shared(enum vm_mem_backing_src_type t)
return vm_mem_backing_src_alias(t)->flag & MAP_SHARED;
}
+static inline bool backing_src_can_be_huge(enum vm_mem_backing_src_type t)
+{
+ return t != VM_MEM_SRC_ANONYMOUS && t != VM_MEM_SRC_SHMEM;
+}
+
/* Aligns x up to the next multiple of size. Size must be a power of 2. */
static inline uint64_t align_up(uint64_t x, uint64_t size)
{
@@ -186,7 +191,7 @@ static inline uint32_t atoi_non_negative(const char *name, const char *num_str)
}
int guest_vsnprintf(char *buf, int n, const char *fmt, va_list args);
-int guest_snprintf(char *buf, int n, const char *fmt, ...);
+__printf(3, 4) int guest_snprintf(char *buf, int n, const char *fmt, ...);
char *strdup_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2), nonnull(1)));
diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h
index ce33d306c2cb..d9d6581b8d4f 100644
--- a/tools/testing/selftests/kvm/include/ucall_common.h
+++ b/tools/testing/selftests/kvm/include/ucall_common.h
@@ -34,9 +34,10 @@ void ucall_arch_do_ucall(vm_vaddr_t uc);
void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu);
void ucall(uint64_t cmd, int nargs, ...);
-void ucall_fmt(uint64_t cmd, const char *fmt, ...);
-void ucall_assert(uint64_t cmd, const char *exp, const char *file,
- unsigned int line, const char *fmt, ...);
+__printf(2, 3) void ucall_fmt(uint64_t cmd, const char *fmt, ...);
+__printf(5, 6) void ucall_assert(uint64_t cmd, const char *exp,
+ const char *file, unsigned int line,
+ const char *fmt, ...);
uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc);
void ucall_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa);
int ucall_nr_pages_required(uint64_t page_size);
@@ -52,6 +53,17 @@ int ucall_nr_pages_required(uint64_t page_size);
#define GUEST_SYNC_ARGS(stage, arg1, arg2, arg3, arg4) \
ucall(UCALL_SYNC, 6, "hello", stage, arg1, arg2, arg3, arg4)
#define GUEST_SYNC(stage) ucall(UCALL_SYNC, 2, "hello", stage)
+#define GUEST_SYNC1(arg0) ucall(UCALL_SYNC, 1, arg0)
+#define GUEST_SYNC2(arg0, arg1) ucall(UCALL_SYNC, 2, arg0, arg1)
+#define GUEST_SYNC3(arg0, arg1, arg2) \
+ ucall(UCALL_SYNC, 3, arg0, arg1, arg2)
+#define GUEST_SYNC4(arg0, arg1, arg2, arg3) \
+ ucall(UCALL_SYNC, 4, arg0, arg1, arg2, arg3)
+#define GUEST_SYNC5(arg0, arg1, arg2, arg3, arg4) \
+ ucall(UCALL_SYNC, 5, arg0, arg1, arg2, arg3, arg4)
+#define GUEST_SYNC6(arg0, arg1, arg2, arg3, arg4, arg5) \
+ ucall(UCALL_SYNC, 6, arg0, arg1, arg2, arg3, arg4, arg5)
+
#define GUEST_PRINTF(_fmt, _args...) ucall_fmt(UCALL_PRINTF, _fmt, ##_args)
#define GUEST_DONE() ucall(UCALL_DONE, 0)
diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h
index 25bc61dac5fb..a84863503fcb 100644
--- a/tools/testing/selftests/kvm/include/x86_64/processor.h
+++ b/tools/testing/selftests/kvm/include/x86_64/processor.h
@@ -15,6 +15,7 @@
#include <asm/msr-index.h>
#include <asm/prctl.h>
+#include <linux/kvm_para.h>
#include <linux/stringify.h>
#include "../kvm_util.h"
@@ -1194,6 +1195,20 @@ uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t __xen_hypercall(uint64_t nr, uint64_t a0, void *a1);
void xen_hypercall(uint64_t nr, uint64_t a0, void *a1);
+static inline uint64_t __kvm_hypercall_map_gpa_range(uint64_t gpa,
+ uint64_t size, uint64_t flags)
+{
+ return kvm_hypercall(KVM_HC_MAP_GPA_RANGE, gpa, size >> PAGE_SHIFT, flags, 0);
+}
+
+static inline void kvm_hypercall_map_gpa_range(uint64_t gpa, uint64_t size,
+ uint64_t flags)
+{
+ uint64_t ret = __kvm_hypercall_map_gpa_range(gpa, size, flags);
+
+ GUEST_ASSERT(!ret);
+}
+
void __vm_xsave_require_permission(uint64_t xfeature, const char *name);
#define vm_xsave_require_permission(xfeature) \
diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c
index 69f26d80c821..e37dc9c21888 100644
--- a/tools/testing/selftests/kvm/kvm_page_table_test.c
+++ b/tools/testing/selftests/kvm/kvm_page_table_test.c
@@ -254,7 +254,7 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg)
/* Create a VM with enough guest pages */
guest_num_pages = test_mem_size / guest_page_size;
- vm = __vm_create_with_vcpus(mode, nr_vcpus, guest_num_pages,
+ vm = __vm_create_with_vcpus(VM_SHAPE(mode), nr_vcpus, guest_num_pages,
guest_code, test_args.vcpus);
/* Align down GPA of the testing memslot */
diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c
index 6fe12e985ba5..41c776b642c0 100644
--- a/tools/testing/selftests/kvm/lib/aarch64/processor.c
+++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c
@@ -12,6 +12,7 @@
#include "kvm_util.h"
#include "processor.h"
#include <linux/bitfield.h>
+#include <linux/sizes.h>
#define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN 0xac0000
@@ -58,13 +59,25 @@ static uint64_t pte_index(struct kvm_vm *vm, vm_vaddr_t gva)
return (gva >> vm->page_shift) & mask;
}
+static inline bool use_lpa2_pte_format(struct kvm_vm *vm)
+{
+ return (vm->page_size == SZ_4K || vm->page_size == SZ_16K) &&
+ (vm->pa_bits > 48 || vm->va_bits > 48);
+}
+
static uint64_t addr_pte(struct kvm_vm *vm, uint64_t pa, uint64_t attrs)
{
uint64_t pte;
- pte = pa & GENMASK(47, vm->page_shift);
- if (vm->page_shift == 16)
- pte |= FIELD_GET(GENMASK(51, 48), pa) << 12;
+ if (use_lpa2_pte_format(vm)) {
+ pte = pa & GENMASK(49, vm->page_shift);
+ pte |= FIELD_GET(GENMASK(51, 50), pa) << 8;
+ attrs &= ~GENMASK(9, 8);
+ } else {
+ pte = pa & GENMASK(47, vm->page_shift);
+ if (vm->page_shift == 16)
+ pte |= FIELD_GET(GENMASK(51, 48), pa) << 12;
+ }
pte |= attrs;
return pte;
@@ -74,9 +87,14 @@ static uint64_t pte_addr(struct kvm_vm *vm, uint64_t pte)
{
uint64_t pa;
- pa = pte & GENMASK(47, vm->page_shift);
- if (vm->page_shift == 16)
- pa |= FIELD_GET(GENMASK(15, 12), pte) << 48;
+ if (use_lpa2_pte_format(vm)) {
+ pa = pte & GENMASK(49, vm->page_shift);
+ pa |= FIELD_GET(GENMASK(9, 8), pte) << 50;
+ } else {
+ pa = pte & GENMASK(47, vm->page_shift);
+ if (vm->page_shift == 16)
+ pa |= FIELD_GET(GENMASK(15, 12), pte) << 48;
+ }
return pa;
}
@@ -266,9 +284,6 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
/* Configure base granule size */
switch (vm->mode) {
- case VM_MODE_P52V48_4K:
- TEST_FAIL("AArch64 does not support 4K sized pages "
- "with 52-bit physical address ranges");
case VM_MODE_PXXV48_4K:
TEST_FAIL("AArch64 does not support 4K sized pages "
"with ANY-bit physical address ranges");
@@ -278,12 +293,14 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
case VM_MODE_P36V48_64K:
tcr_el1 |= 1ul << 14; /* TG0 = 64KB */
break;
+ case VM_MODE_P52V48_16K:
case VM_MODE_P48V48_16K:
case VM_MODE_P40V48_16K:
case VM_MODE_P36V48_16K:
case VM_MODE_P36V47_16K:
tcr_el1 |= 2ul << 14; /* TG0 = 16KB */
break;
+ case VM_MODE_P52V48_4K:
case VM_MODE_P48V48_4K:
case VM_MODE_P40V48_4K:
case VM_MODE_P36V48_4K:
@@ -297,6 +314,8 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
/* Configure output size */
switch (vm->mode) {
+ case VM_MODE_P52V48_4K:
+ case VM_MODE_P52V48_16K:
case VM_MODE_P52V48_64K:
tcr_el1 |= 6ul << 32; /* IPS = 52 bits */
ttbr0_el1 |= FIELD_GET(GENMASK(51, 48), vm->pgd) << 2;
@@ -325,6 +344,8 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
/* TCR_EL1 |= IRGN0:WBWA | ORGN0:WBWA | SH0:Inner-Shareable */;
tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12);
tcr_el1 |= (64 - vm->va_bits) /* T0SZ */;
+ if (use_lpa2_pte_format(vm))
+ tcr_el1 |= (1ul << 59) /* DS */;
vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1);
vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1);
@@ -492,12 +513,24 @@ uint32_t guest_get_vcpuid(void)
return read_sysreg(tpidr_el1);
}
-void aarch64_get_supported_page_sizes(uint32_t ipa,
- bool *ps4k, bool *ps16k, bool *ps64k)
+static uint32_t max_ipa_for_page_size(uint32_t vm_ipa, uint32_t gran,
+ uint32_t not_sup_val, uint32_t ipa52_min_val)
+{
+ if (gran == not_sup_val)
+ return 0;
+ else if (gran >= ipa52_min_val && vm_ipa >= 52)
+ return 52;
+ else
+ return min(vm_ipa, 48U);
+}
+
+void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k,
+ uint32_t *ipa16k, uint32_t *ipa64k)
{
struct kvm_vcpu_init preferred_init;
int kvm_fd, vm_fd, vcpu_fd, err;
uint64_t val;
+ uint32_t gran;
struct kvm_one_reg reg = {
.id = KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1),
.addr = (uint64_t)&val,
@@ -518,9 +551,17 @@ void aarch64_get_supported_page_sizes(uint32_t ipa,
err = ioctl(vcpu_fd, KVM_GET_ONE_REG, &reg);
TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd));
- *ps4k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val) != 0xf;
- *ps64k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val) == 0;
- *ps16k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val) != 0;
+ gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val);
+ *ipa4k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN4_NI,
+ ID_AA64MMFR0_EL1_TGRAN4_52_BIT);
+
+ gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val);
+ *ipa64k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN64_NI,
+ ID_AA64MMFR0_EL1_TGRAN64_IMP);
+
+ gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val);
+ *ipa16k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN16_NI,
+ ID_AA64MMFR0_EL1_TGRAN16_52_BIT);
close(vcpu_fd);
close(vm_fd);
diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c
index 1df3ce4b16fd..b04901e55138 100644
--- a/tools/testing/selftests/kvm/lib/guest_modes.c
+++ b/tools/testing/selftests/kvm/lib/guest_modes.c
@@ -14,37 +14,33 @@ struct guest_mode guest_modes[NUM_VM_MODES];
void guest_modes_append_default(void)
{
#ifndef __aarch64__
- guest_mode_append(VM_MODE_DEFAULT, true, true);
+ guest_mode_append(VM_MODE_DEFAULT, true);
#else
{
unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE);
- bool ps4k, ps16k, ps64k;
+ uint32_t ipa4k, ipa16k, ipa64k;
int i;
- aarch64_get_supported_page_sizes(limit, &ps4k, &ps16k, &ps64k);
+ aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k);
- vm_mode_default = NUM_VM_MODES;
+ guest_mode_append(VM_MODE_P52V48_4K, ipa4k >= 52);
+ guest_mode_append(VM_MODE_P52V48_16K, ipa16k >= 52);
+ guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52);
- if (limit >= 52)
- guest_mode_append(VM_MODE_P52V48_64K, ps64k, ps64k);
- if (limit >= 48) {
- guest_mode_append(VM_MODE_P48V48_4K, ps4k, ps4k);
- guest_mode_append(VM_MODE_P48V48_16K, ps16k, ps16k);
- guest_mode_append(VM_MODE_P48V48_64K, ps64k, ps64k);
- }
- if (limit >= 40) {
- guest_mode_append(VM_MODE_P40V48_4K, ps4k, ps4k);
- guest_mode_append(VM_MODE_P40V48_16K, ps16k, ps16k);
- guest_mode_append(VM_MODE_P40V48_64K, ps64k, ps64k);
- if (ps4k)
- vm_mode_default = VM_MODE_P40V48_4K;
- }
- if (limit >= 36) {
- guest_mode_append(VM_MODE_P36V48_4K, ps4k, ps4k);
- guest_mode_append(VM_MODE_P36V48_16K, ps16k, ps16k);
- guest_mode_append(VM_MODE_P36V48_64K, ps64k, ps64k);
- guest_mode_append(VM_MODE_P36V47_16K, ps16k, ps16k);
- }
+ guest_mode_append(VM_MODE_P48V48_4K, ipa4k >= 48);
+ guest_mode_append(VM_MODE_P48V48_16K, ipa16k >= 48);
+ guest_mode_append(VM_MODE_P48V48_64K, ipa64k >= 48);
+
+ guest_mode_append(VM_MODE_P40V48_4K, ipa4k >= 40);
+ guest_mode_append(VM_MODE_P40V48_16K, ipa16k >= 40);
+ guest_mode_append(VM_MODE_P40V48_64K, ipa64k >= 40);
+
+ guest_mode_append(VM_MODE_P36V48_4K, ipa4k >= 36);
+ guest_mode_append(VM_MODE_P36V48_16K, ipa16k >= 36);
+ guest_mode_append(VM_MODE_P36V48_64K, ipa64k >= 36);
+ guest_mode_append(VM_MODE_P36V47_16K, ipa16k >= 36);
+
+ vm_mode_default = ipa4k >= 40 ? VM_MODE_P40V48_4K : NUM_VM_MODES;
/*
* Pick the first supported IPA size if the default
@@ -72,7 +68,7 @@ void guest_modes_append_default(void)
close(kvm_fd);
/* Starting with z13 we have 47bits of physical address */
if (info.ibc >= 0x30)
- guest_mode_append(VM_MODE_P47V64_4K, true, true);
+ guest_mode_append(VM_MODE_P47V64_4K, true);
}
#endif
#ifdef __riscv
@@ -80,9 +76,9 @@ void guest_modes_append_default(void)
unsigned int sz = kvm_check_cap(KVM_CAP_VM_GPA_BITS);
if (sz >= 52)
- guest_mode_append(VM_MODE_P52V48_4K, true, true);
+ guest_mode_append(VM_MODE_P52V48_4K, true);
if (sz >= 48)
- guest_mode_append(VM_MODE_P48V48_4K, true, true);
+ guest_mode_append(VM_MODE_P48V48_4K, true);
}
#endif
}
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 7a8af1821f5d..e066d584c656 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -148,6 +148,7 @@ const char *vm_guest_mode_string(uint32_t i)
{
static const char * const strings[] = {
[VM_MODE_P52V48_4K] = "PA-bits:52, VA-bits:48, 4K pages",
+ [VM_MODE_P52V48_16K] = "PA-bits:52, VA-bits:48, 16K pages",
[VM_MODE_P52V48_64K] = "PA-bits:52, VA-bits:48, 64K pages",
[VM_MODE_P48V48_4K] = "PA-bits:48, VA-bits:48, 4K pages",
[VM_MODE_P48V48_16K] = "PA-bits:48, VA-bits:48, 16K pages",
@@ -173,6 +174,7 @@ const char *vm_guest_mode_string(uint32_t i)
const struct vm_guest_mode_params vm_guest_mode_params[] = {
[VM_MODE_P52V48_4K] = { 52, 48, 0x1000, 12 },
+ [VM_MODE_P52V48_16K] = { 52, 48, 0x4000, 14 },
[VM_MODE_P52V48_64K] = { 52, 48, 0x10000, 16 },
[VM_MODE_P48V48_4K] = { 48, 48, 0x1000, 12 },
[VM_MODE_P48V48_16K] = { 48, 48, 0x4000, 14 },
@@ -209,7 +211,7 @@ __weak void vm_vaddr_populate_bitmap(struct kvm_vm *vm)
(1ULL << (vm->va_bits - 1)) >> vm->page_shift);
}
-struct kvm_vm *____vm_create(enum vm_guest_mode mode)
+struct kvm_vm *____vm_create(struct vm_shape shape)
{
struct kvm_vm *vm;
@@ -221,13 +223,13 @@ struct kvm_vm *____vm_create(enum vm_guest_mode mode)
vm->regions.hva_tree = RB_ROOT;
hash_init(vm->regions.slot_hash);
- vm->mode = mode;
- vm->type = 0;
+ vm->mode = shape.mode;
+ vm->type = shape.type;
- vm->pa_bits = vm_guest_mode_params[mode].pa_bits;
- vm->va_bits = vm_guest_mode_params[mode].va_bits;
- vm->page_size = vm_guest_mode_params[mode].page_size;
- vm->page_shift = vm_guest_mode_params[mode].page_shift;
+ vm->pa_bits = vm_guest_mode_params[vm->mode].pa_bits;
+ vm->va_bits = vm_guest_mode_params[vm->mode].va_bits;
+ vm->page_size = vm_guest_mode_params[vm->mode].page_size;
+ vm->page_shift = vm_guest_mode_params[vm->mode].page_shift;
/* Setup mode specific traits. */
switch (vm->mode) {
@@ -251,6 +253,7 @@ struct kvm_vm *____vm_create(enum vm_guest_mode mode)
case VM_MODE_P36V48_64K:
vm->pgtable_levels = 3;
break;
+ case VM_MODE_P52V48_16K:
case VM_MODE_P48V48_16K:
case VM_MODE_P40V48_16K:
case VM_MODE_P36V48_16K:
@@ -265,7 +268,7 @@ struct kvm_vm *____vm_create(enum vm_guest_mode mode)
/*
* Ignore KVM support for 5-level paging (vm->va_bits == 57),
* it doesn't take effect unless a CR4.LA57 is set, which it
- * isn't for this VM_MODE.
+ * isn't for this mode (48-bit virtual address space).
*/
TEST_ASSERT(vm->va_bits == 48 || vm->va_bits == 57,
"Linear address width (%d bits) not supported",
@@ -285,10 +288,11 @@ struct kvm_vm *____vm_create(enum vm_guest_mode mode)
vm->pgtable_levels = 5;
break;
default:
- TEST_FAIL("Unknown guest mode, mode: 0x%x", mode);
+ TEST_FAIL("Unknown guest mode: 0x%x", vm->mode);
}
#ifdef __aarch64__
+ TEST_ASSERT(!vm->type, "ARM doesn't support test-provided types");
if (vm->pa_bits != 40)
vm->type = KVM_VM_TYPE_ARM_IPA_SIZE(vm->pa_bits);
#endif
@@ -347,19 +351,19 @@ static uint64_t vm_nr_pages_required(enum vm_guest_mode mode,
return vm_adjust_num_guest_pages(mode, nr_pages);
}
-struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint32_t nr_runnable_vcpus,
+struct kvm_vm *__vm_create(struct vm_shape shape, uint32_t nr_runnable_vcpus,
uint64_t nr_extra_pages)
{
- uint64_t nr_pages = vm_nr_pages_required(mode, nr_runnable_vcpus,
+ uint64_t nr_pages = vm_nr_pages_required(shape.mode, nr_runnable_vcpus,
nr_extra_pages);
struct userspace_mem_region *slot0;
struct kvm_vm *vm;
int i;
- pr_debug("%s: mode='%s' pages='%ld'\n", __func__,
- vm_guest_mode_string(mode), nr_pages);
+ pr_debug("%s: mode='%s' type='%d', pages='%ld'\n", __func__,
+ vm_guest_mode_string(shape.mode), shape.type, nr_pages);
- vm = ____vm_create(mode);
+ vm = ____vm_create(shape);
vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0, 0, nr_pages, 0);
for (i = 0; i < NR_MEM_REGIONS; i++)
@@ -400,7 +404,7 @@ struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint32_t nr_runnable_vcpus,
* extra_mem_pages is only used to calculate the maximum page table size,
* no real memory allocation for non-slot0 memory in this function.
*/
-struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus,
+struct kvm_vm *__vm_create_with_vcpus(struct vm_shape shape, uint32_t nr_vcpus,
uint64_t extra_mem_pages,
void *guest_code, struct kvm_vcpu *vcpus[])
{
@@ -409,7 +413,7 @@ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus
TEST_ASSERT(!nr_vcpus || vcpus, "Must provide vCPU array");
- vm = __vm_create(mode, nr_vcpus, extra_mem_pages);
+ vm = __vm_create(shape, nr_vcpus, extra_mem_pages);
for (i = 0; i < nr_vcpus; ++i)
vcpus[i] = vm_vcpu_add(vm, i, guest_code);
@@ -417,15 +421,15 @@ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus
return vm;
}
-struct kvm_vm *__vm_create_with_one_vcpu(struct kvm_vcpu **vcpu,
- uint64_t extra_mem_pages,
- void *guest_code)
+struct kvm_vm *__vm_create_shape_with_one_vcpu(struct vm_shape shape,
+ struct kvm_vcpu **vcpu,
+ uint64_t extra_mem_pages,
+ void *guest_code)
{
struct kvm_vcpu *vcpus[1];
struct kvm_vm *vm;
- vm = __vm_create_with_vcpus(VM_MODE_DEFAULT, 1, extra_mem_pages,
- guest_code, vcpus);
+ vm = __vm_create_with_vcpus(shape, 1, extra_mem_pages, guest_code, vcpus);
*vcpu = vcpus[0];
return vm;
@@ -453,8 +457,9 @@ void kvm_vm_restart(struct kvm_vm *vmp)
vm_create_irqchip(vmp);
hash_for_each(vmp->regions.slot_hash, ctr, region, slot_node) {
- int ret = ioctl(vmp->fd, KVM_SET_USER_MEMORY_REGION, &region->region);
- TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n"
+ int ret = ioctl(vmp->fd, KVM_SET_USER_MEMORY_REGION2, &region->region);
+
+ TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION2 IOCTL failed,\n"
" rc: %i errno: %i\n"
" slot: %u flags: 0x%x\n"
" guest_phys_addr: 0x%llx size: 0x%llx",
@@ -590,35 +595,6 @@ userspace_mem_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end)
return NULL;
}
-/*
- * KVM Userspace Memory Region Find
- *
- * Input Args:
- * vm - Virtual Machine
- * start - Starting VM physical address
- * end - Ending VM physical address, inclusive.
- *
- * Output Args: None
- *
- * Return:
- * Pointer to overlapping region, NULL if no such region.
- *
- * Public interface to userspace_mem_region_find. Allows tests to look up
- * the memslot datastructure for a given range of guest physical memory.
- */
-struct kvm_userspace_memory_region *
-kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start,
- uint64_t end)
-{
- struct userspace_mem_region *region;
-
- region = userspace_mem_region_find(vm, start, end);
- if (!region)
- return NULL;
-
- return &region->region;
-}
-
__weak void vcpu_arch_free(struct kvm_vcpu *vcpu)
{
@@ -686,7 +662,7 @@ static void __vm_mem_region_delete(struct kvm_vm *vm,
}
region->region.memory_size = 0;
- vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION, &region->region);
+ vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, &region->region);
sparsebit_free(&region->unused_phy_pages);
ret = munmap(region->mmap_start, region->mmap_size);
@@ -697,6 +673,8 @@ static void __vm_mem_region_delete(struct kvm_vm *vm,
TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret));
close(region->fd);
}
+ if (region->region.guest_memfd >= 0)
+ close(region->region.guest_memfd);
free(region);
}
@@ -898,36 +876,44 @@ void vm_set_user_memory_region(struct kvm_vm *vm, uint32_t slot, uint32_t flags,
errno, strerror(errno));
}
-/*
- * VM Userspace Memory Region Add
- *
- * Input Args:
- * vm - Virtual Machine
- * src_type - Storage source for this region.
- * NULL to use anonymous memory.
- * guest_paddr - Starting guest physical address
- * slot - KVM region slot
- * npages - Number of physical pages
- * flags - KVM memory region flags (e.g. KVM_MEM_LOG_DIRTY_PAGES)
- *
- * Output Args: None
- *
- * Return: None
- *
- * Allocates a memory area of the number of pages specified by npages
- * and maps it to the VM specified by vm, at a starting physical address
- * given by guest_paddr. The region is created with a KVM region slot
- * given by slot, which must be unique and < KVM_MEM_SLOTS_NUM. The
- * region is created with the flags given by flags.
- */
-void vm_userspace_mem_region_add(struct kvm_vm *vm,
- enum vm_mem_backing_src_type src_type,
- uint64_t guest_paddr, uint32_t slot, uint64_t npages,
- uint32_t flags)
+int __vm_set_user_memory_region2(struct kvm_vm *vm, uint32_t slot, uint32_t flags,
+ uint64_t gpa, uint64_t size, void *hva,
+ uint32_t guest_memfd, uint64_t guest_memfd_offset)
+{
+ struct kvm_userspace_memory_region2 region = {
+ .slot = slot,
+ .flags = flags,
+ .guest_phys_addr = gpa,
+ .memory_size = size,
+ .userspace_addr = (uintptr_t)hva,
+ .guest_memfd = guest_memfd,
+ .guest_memfd_offset = guest_memfd_offset,
+ };
+
+ return ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION2, &region);
+}
+
+void vm_set_user_memory_region2(struct kvm_vm *vm, uint32_t slot, uint32_t flags,
+ uint64_t gpa, uint64_t size, void *hva,
+ uint32_t guest_memfd, uint64_t guest_memfd_offset)
+{
+ int ret = __vm_set_user_memory_region2(vm, slot, flags, gpa, size, hva,
+ guest_memfd, guest_memfd_offset);
+
+ TEST_ASSERT(!ret, "KVM_SET_USER_MEMORY_REGION2 failed, errno = %d (%s)",
+ errno, strerror(errno));
+}
+
+
+/* FIXME: This thing needs to be ripped apart and rewritten. */
+void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,
+ uint64_t guest_paddr, uint32_t slot, uint64_t npages,
+ uint32_t flags, int guest_memfd, uint64_t guest_memfd_offset)
{
int ret;
struct userspace_mem_region *region;
size_t backing_src_pagesz = get_backing_src_pagesz(src_type);
+ size_t mem_size = npages * vm->page_size;
size_t alignment;
TEST_ASSERT(vm_adjust_num_guest_pages(vm->mode, npages) == npages,
@@ -980,7 +966,7 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
/* Allocate and initialize new mem region structure. */
region = calloc(1, sizeof(*region));
TEST_ASSERT(region != NULL, "Insufficient Memory");
- region->mmap_size = npages * vm->page_size;
+ region->mmap_size = mem_size;
#ifdef __s390x__
/* On s390x, the host address must be aligned to 1M (due to PGSTEs) */
@@ -1027,14 +1013,38 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
/* As needed perform madvise */
if ((src_type == VM_MEM_SRC_ANONYMOUS ||
src_type == VM_MEM_SRC_ANONYMOUS_THP) && thp_configured()) {
- ret = madvise(region->host_mem, npages * vm->page_size,
+ ret = madvise(region->host_mem, mem_size,
src_type == VM_MEM_SRC_ANONYMOUS ? MADV_NOHUGEPAGE : MADV_HUGEPAGE);
TEST_ASSERT(ret == 0, "madvise failed, addr: %p length: 0x%lx src_type: %s",
- region->host_mem, npages * vm->page_size,
+ region->host_mem, mem_size,
vm_mem_backing_src_alias(src_type)->name);
}
region->backing_src_type = src_type;
+
+ if (flags & KVM_MEM_GUEST_MEMFD) {
+ if (guest_memfd < 0) {
+ uint32_t guest_memfd_flags = 0;
+ TEST_ASSERT(!guest_memfd_offset,
+ "Offset must be zero when creating new guest_memfd");
+ guest_memfd = vm_create_guest_memfd(vm, mem_size, guest_memfd_flags);
+ } else {
+ /*
+ * Install a unique fd for each memslot so that the fd
+ * can be closed when the region is deleted without
+ * needing to track if the fd is owned by the framework
+ * or by the caller.
+ */
+ guest_memfd = dup(guest_memfd);
+ TEST_ASSERT(guest_memfd >= 0, __KVM_SYSCALL_ERROR("dup()", guest_memfd));
+ }
+
+ region->region.guest_memfd = guest_memfd;
+ region->region.guest_memfd_offset = guest_memfd_offset;
+ } else {
+ region->region.guest_memfd = -1;
+ }
+
region->unused_phy_pages = sparsebit_alloc();
sparsebit_set_num(region->unused_phy_pages,
guest_paddr >> vm->page_shift, npages);
@@ -1043,13 +1053,14 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
region->region.guest_phys_addr = guest_paddr;
region->region.memory_size = npages * vm->page_size;
region->region.userspace_addr = (uintptr_t) region->host_mem;
- ret = __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION, &region->region);
- TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n"
+ ret = __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, &region->region);
+ TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION2 IOCTL failed,\n"
" rc: %i errno: %i\n"
" slot: %u flags: 0x%x\n"
- " guest_phys_addr: 0x%lx size: 0x%lx",
+ " guest_phys_addr: 0x%lx size: 0x%lx guest_memfd: %d\n",
ret, errno, slot, flags,
- guest_paddr, (uint64_t) region->region.memory_size);
+ guest_paddr, (uint64_t) region->region.memory_size,
+ region->region.guest_memfd);
/* Add to quick lookup data structures */
vm_userspace_mem_region_gpa_insert(&vm->regions.gpa_tree, region);
@@ -1070,6 +1081,14 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm,
}
}
+void vm_userspace_mem_region_add(struct kvm_vm *vm,
+ enum vm_mem_backing_src_type src_type,
+ uint64_t guest_paddr, uint32_t slot,
+ uint64_t npages, uint32_t flags)
+{
+ vm_mem_add(vm, src_type, guest_paddr, slot, npages, flags, -1, 0);
+}
+
/*
* Memslot to region
*
@@ -1126,9 +1145,9 @@ void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags)
region->region.flags = flags;
- ret = __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION, &region->region);
+ ret = __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, &region->region);
- TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n"
+ TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION2 IOCTL failed,\n"
" rc: %i errno: %i slot: %u flags: 0x%x",
ret, errno, slot, flags);
}
@@ -1156,9 +1175,9 @@ void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa)
region->region.guest_phys_addr = new_gpa;
- ret = __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION, &region->region);
+ ret = __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, &region->region);
- TEST_ASSERT(!ret, "KVM_SET_USER_MEMORY_REGION failed\n"
+ TEST_ASSERT(!ret, "KVM_SET_USER_MEMORY_REGION2 failed\n"
"ret: %i errno: %i slot: %u new_gpa: 0x%lx",
ret, errno, slot, new_gpa);
}
@@ -1181,6 +1200,34 @@ void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot)
__vm_mem_region_delete(vm, memslot2region(vm, slot), true);
}
+void vm_guest_mem_fallocate(struct kvm_vm *vm, uint64_t base, uint64_t size,
+ bool punch_hole)
+{
+ const int mode = FALLOC_FL_KEEP_SIZE | (punch_hole ? FALLOC_FL_PUNCH_HOLE : 0);
+ struct userspace_mem_region *region;
+ uint64_t end = base + size;
+ uint64_t gpa, len;
+ off_t fd_offset;
+ int ret;
+
+ for (gpa = base; gpa < end; gpa += len) {
+ uint64_t offset;
+
+ region = userspace_mem_region_find(vm, gpa, gpa);
+ TEST_ASSERT(region && region->region.flags & KVM_MEM_GUEST_MEMFD,
+ "Private memory region not found for GPA 0x%lx", gpa);
+
+ offset = gpa - region->region.guest_phys_addr;
+ fd_offset = region->region.guest_memfd_offset + offset;
+ len = min_t(uint64_t, end - gpa, region->region.memory_size - offset);
+
+ ret = fallocate(region->region.guest_memfd, mode, fd_offset, len);
+ TEST_ASSERT(!ret, "fallocate() failed to %s at %lx (len = %lu), fd = %d, mode = %x, offset = %lx\n",
+ punch_hole ? "punch hole" : "allocate", gpa, len,
+ region->region.guest_memfd, mode, fd_offset);
+ }
+}
+
/* Returns the size of a vCPU's kvm_run structure. */
static int vcpu_mmap_sz(void)
{
@@ -1227,7 +1274,7 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
vcpu->vm = vm;
vcpu->id = vcpu_id;
vcpu->fd = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)(unsigned long)vcpu_id);
- TEST_ASSERT(vcpu->fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, vcpu->fd));
+ TEST_ASSERT_VM_VCPU_IOCTL(vcpu->fd >= 0, KVM_CREATE_VCPU, vcpu->fd, vm);
TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->run), "vcpu mmap size "
"smaller than expected, vcpu_mmap_sz: %i expected_min: %zi",
diff --git a/tools/testing/selftests/kvm/lib/memstress.c b/tools/testing/selftests/kvm/lib/memstress.c
index df457452d146..d05487e5a371 100644
--- a/tools/testing/selftests/kvm/lib/memstress.c
+++ b/tools/testing/selftests/kvm/lib/memstress.c
@@ -168,7 +168,8 @@ struct kvm_vm *memstress_create_vm(enum vm_guest_mode mode, int nr_vcpus,
* The memory is also added to memslot 0, but that's a benign side
* effect as KVM allows aliasing HVAs in meslots.
*/
- vm = __vm_create_with_vcpus(mode, nr_vcpus, slot0_pages + guest_num_pages,
+ vm = __vm_create_with_vcpus(VM_SHAPE(mode), nr_vcpus,
+ slot0_pages + guest_num_pages,
memstress_guest_code, vcpus);
args->vm = vm;
diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c
index d146ca71e0c0..7ca736fb4194 100644
--- a/tools/testing/selftests/kvm/lib/riscv/processor.c
+++ b/tools/testing/selftests/kvm/lib/riscv/processor.c
@@ -201,7 +201,7 @@ void riscv_vcpu_mmu_setup(struct kvm_vcpu *vcpu)
satp = (vm->pgd >> PGTBL_PAGE_SIZE_SHIFT) & SATP_PPN;
satp |= SATP_MODE_48;
- vcpu_set_reg(vcpu, RISCV_CSR_REG(satp), satp);
+ vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(satp), satp);
}
void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent)
@@ -315,7 +315,7 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.pc), (unsigned long)guest_code);
/* Setup default exception vector of guest */
- vcpu_set_reg(vcpu, RISCV_CSR_REG(stvec), (unsigned long)guest_unexp_trap);
+ vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(stvec), (unsigned long)guest_unexp_trap);
return vcpu;
}
@@ -367,3 +367,48 @@ void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...)
void assert_on_unhandled_exception(struct kvm_vcpu *vcpu)
{
}
+
+struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
+ unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4,
+ unsigned long arg5)
+{
+ register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
+ register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
+ register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
+ register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
+ register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
+ register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
+ register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
+ register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
+ struct sbiret ret;
+
+ asm volatile (
+ "ecall"
+ : "+r" (a0), "+r" (a1)
+ : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
+ : "memory");
+ ret.error = a0;
+ ret.value = a1;
+
+ return ret;
+}
+
+bool guest_sbi_probe_extension(int extid, long *out_val)
+{
+ struct sbiret ret;
+
+ ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_PROBE_EXT, extid,
+ 0, 0, 0, 0, 0);
+
+ __GUEST_ASSERT(!ret.error || ret.error == SBI_ERR_NOT_SUPPORTED,
+ "ret.error=%ld, ret.value=%ld\n", ret.error, ret.value);
+
+ if (ret.error == SBI_ERR_NOT_SUPPORTED)
+ return false;
+
+ if (out_val)
+ *out_val = ret.value;
+
+ return true;
+}
diff --git a/tools/testing/selftests/kvm/lib/riscv/ucall.c b/tools/testing/selftests/kvm/lib/riscv/ucall.c
index fe6d1004f018..14ee17151a59 100644
--- a/tools/testing/selftests/kvm/lib/riscv/ucall.c
+++ b/tools/testing/selftests/kvm/lib/riscv/ucall.c
@@ -10,32 +10,6 @@
#include "kvm_util.h"
#include "processor.h"
-struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
- unsigned long arg1, unsigned long arg2,
- unsigned long arg3, unsigned long arg4,
- unsigned long arg5)
-{
- register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
- register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
- register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
- register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
- register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
- register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
- register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
- register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
- struct sbiret ret;
-
- asm volatile (
- "ecall"
- : "+r" (a0), "+r" (a1)
- : "r" (a2), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7)
- : "memory");
- ret.error = a0;
- ret.value = a1;
-
- return ret;
-}
-
void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c
index 25de4b8bc347..6652108816db 100644
--- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
+++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
@@ -12,6 +12,11 @@
#define REG_MASK (KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK)
+enum {
+ VCPU_FEATURE_ISA_EXT = 0,
+ VCPU_FEATURE_SBI_EXT,
+};
+
static bool isa_ext_cant_disable[KVM_RISCV_ISA_EXT_MAX];
bool filter_reg(__u64 reg)
@@ -28,31 +33,47 @@ bool filter_reg(__u64 reg)
*
* Note: The below list is alphabetically sorted.
*/
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_A:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_C:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_D:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_F:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_H:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_I:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_M:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_V:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SMSTATEEN:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SSAIA:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SSTC:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SVINVAL:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SVNAPOT:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SVPBMT:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBA:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBB:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBS:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICBOM:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICBOZ:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICNTR:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICOND:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICSR:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIFENCEI:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIHINTPAUSE:
- case KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIHPM:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_A:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_C:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_D:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_F:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_H:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_I:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_M:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_V:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SMSTATEEN:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SSAIA:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SSTC:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SVINVAL:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SVNAPOT:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SVPBMT:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZBA:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZBB:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZBS:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOM:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOZ:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICNTR:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICOND:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICSR:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZIFENCEI:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZIHINTPAUSE:
+ case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZIHPM:
+ /*
+ * Like ISA_EXT registers, SBI_EXT registers are only visible when the
+ * host supports them and disabling them does not affect the visibility
+ * of the SBI_EXT register itself.
+ */
+ case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_V01:
+ case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_TIME:
+ case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_IPI:
+ case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_RFENCE:
+ case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_SRST:
+ case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_HSM:
+ case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_PMU:
+ case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_DBCN:
+ case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_STA:
+ case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_EXPERIMENTAL:
+ case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_VENDOR:
return true;
/* AIA registers are always available when Ssaia can't be disabled */
case KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(siselect):
@@ -75,12 +96,12 @@ bool check_reject_set(int err)
return err == EINVAL;
}
-static inline bool vcpu_has_ext(struct kvm_vcpu *vcpu, int ext)
+static bool vcpu_has_ext(struct kvm_vcpu *vcpu, uint64_t ext_id)
{
int ret;
unsigned long value;
- ret = __vcpu_get_reg(vcpu, RISCV_ISA_EXT_REG(ext), &value);
+ ret = __vcpu_get_reg(vcpu, ext_id, &value);
return (ret) ? false : !!value;
}
@@ -88,6 +109,7 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
{
unsigned long isa_ext_state[KVM_RISCV_ISA_EXT_MAX] = { 0 };
struct vcpu_reg_sublist *s;
+ uint64_t feature;
int rc;
for (int i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++)
@@ -103,15 +125,31 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
isa_ext_cant_disable[i] = true;
}
+ for (int i = 0; i < KVM_RISCV_SBI_EXT_MAX; i++) {
+ rc = __vcpu_set_reg(vcpu, RISCV_SBI_EXT_REG(i), 0);
+ TEST_ASSERT(!rc || (rc == -1 && errno == ENOENT), "Unexpected error");
+ }
+
for_each_sublist(c, s) {
if (!s->feature)
continue;
+ switch (s->feature_type) {
+ case VCPU_FEATURE_ISA_EXT:
+ feature = RISCV_ISA_EXT_REG(s->feature);
+ break;
+ case VCPU_FEATURE_SBI_EXT:
+ feature = RISCV_SBI_EXT_REG(s->feature);
+ break;
+ default:
+ TEST_FAIL("Unknown feature type");
+ }
+
/* Try to enable the desired extension */
- __vcpu_set_reg(vcpu, RISCV_ISA_EXT_REG(s->feature), 1);
+ __vcpu_set_reg(vcpu, feature, 1);
/* Double check whether the desired extension was enabled */
- __TEST_REQUIRE(vcpu_has_ext(vcpu, s->feature),
+ __TEST_REQUIRE(vcpu_has_ext(vcpu, feature),
"%s not available, skipping tests\n", s->name);
}
}
@@ -335,15 +373,10 @@ static const char *fp_d_id_to_str(const char *prefix, __u64 id)
}
#define KVM_ISA_EXT_ARR(ext) \
-[KVM_RISCV_ISA_EXT_##ext] = "KVM_RISCV_ISA_EXT_" #ext
+[KVM_RISCV_ISA_EXT_##ext] = "KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_" #ext
-static const char *isa_ext_id_to_str(const char *prefix, __u64 id)
+static const char *isa_ext_single_id_to_str(__u64 reg_off)
{
- /* reg_off is the offset into unsigned long kvm_isa_ext_arr[] */
- __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_ISA_EXT);
-
- assert((id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_ISA_EXT);
-
static const char * const kvm_isa_ext_reg_name[] = {
KVM_ISA_EXT_ARR(A),
KVM_ISA_EXT_ARR(C),
@@ -373,11 +406,48 @@ static const char *isa_ext_id_to_str(const char *prefix, __u64 id)
};
if (reg_off >= ARRAY_SIZE(kvm_isa_ext_reg_name))
- return strdup_printf("%lld /* UNKNOWN */", reg_off);
+ return strdup_printf("KVM_REG_RISCV_ISA_SINGLE | %lld /* UNKNOWN */", reg_off);
return kvm_isa_ext_reg_name[reg_off];
}
+static const char *isa_ext_multi_id_to_str(__u64 reg_subtype, __u64 reg_off)
+{
+ const char *unknown = "";
+
+ if (reg_off > KVM_REG_RISCV_ISA_MULTI_REG_LAST)
+ unknown = " /* UNKNOWN */";
+
+ switch (reg_subtype) {
+ case KVM_REG_RISCV_ISA_MULTI_EN:
+ return strdup_printf("KVM_REG_RISCV_ISA_MULTI_EN | %lld%s", reg_off, unknown);
+ case KVM_REG_RISCV_ISA_MULTI_DIS:
+ return strdup_printf("KVM_REG_RISCV_ISA_MULTI_DIS | %lld%s", reg_off, unknown);
+ }
+
+ return strdup_printf("%lld | %lld /* UNKNOWN */", reg_subtype, reg_off);
+}
+
+static const char *isa_ext_id_to_str(const char *prefix, __u64 id)
+{
+ __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_ISA_EXT);
+ __u64 reg_subtype = reg_off & KVM_REG_RISCV_SUBTYPE_MASK;
+
+ assert((id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_ISA_EXT);
+
+ reg_off &= ~KVM_REG_RISCV_SUBTYPE_MASK;
+
+ switch (reg_subtype) {
+ case KVM_REG_RISCV_ISA_SINGLE:
+ return isa_ext_single_id_to_str(reg_off);
+ case KVM_REG_RISCV_ISA_MULTI_EN:
+ case KVM_REG_RISCV_ISA_MULTI_DIS:
+ return isa_ext_multi_id_to_str(reg_subtype, reg_off);
+ }
+
+ return strdup_printf("%lld | %lld /* UNKNOWN */", reg_subtype, reg_off);
+}
+
#define KVM_SBI_EXT_ARR(ext) \
[ext] = "KVM_REG_RISCV_SBI_SINGLE | " #ext
@@ -392,6 +462,7 @@ static const char *sbi_ext_single_id_to_str(__u64 reg_off)
KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_SRST),
KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_HSM),
KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_PMU),
+ KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_STA),
KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_EXPERIMENTAL),
KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_VENDOR),
KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_DBCN),
@@ -440,6 +511,32 @@ static const char *sbi_ext_id_to_str(const char *prefix, __u64 id)
return strdup_printf("%lld | %lld /* UNKNOWN */", reg_subtype, reg_off);
}
+static const char *sbi_sta_id_to_str(__u64 reg_off)
+{
+ switch (reg_off) {
+ case 0: return "KVM_REG_RISCV_SBI_STA | KVM_REG_RISCV_SBI_STA_REG(shmem_lo)";
+ case 1: return "KVM_REG_RISCV_SBI_STA | KVM_REG_RISCV_SBI_STA_REG(shmem_hi)";
+ }
+ return strdup_printf("KVM_REG_RISCV_SBI_STA | %lld /* UNKNOWN */", reg_off);
+}
+
+static const char *sbi_id_to_str(const char *prefix, __u64 id)
+{
+ __u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_SBI_STATE);
+ __u64 reg_subtype = reg_off & KVM_REG_RISCV_SUBTYPE_MASK;
+
+ assert((id & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_SBI_STATE);
+
+ reg_off &= ~KVM_REG_RISCV_SUBTYPE_MASK;
+
+ switch (reg_subtype) {
+ case KVM_REG_RISCV_SBI_STA:
+ return sbi_sta_id_to_str(reg_off);
+ }
+
+ return strdup_printf("%lld | %lld /* UNKNOWN */", reg_subtype, reg_off);
+}
+
void print_reg(const char *prefix, __u64 id)
{
const char *reg_size = NULL;
@@ -496,6 +593,10 @@ void print_reg(const char *prefix, __u64 id)
printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_SBI_EXT | %s,\n",
reg_size, sbi_ext_id_to_str(prefix, id));
break;
+ case KVM_REG_RISCV_SBI_STATE:
+ printf("\tKVM_REG_RISCV | %s | KVM_REG_RISCV_SBI_STATE | %s,\n",
+ reg_size, sbi_id_to_str(prefix, id));
+ break;
default:
printf("\tKVM_REG_RISCV | %s | 0x%llx /* UNKNOWN */,\n",
reg_size, id & ~REG_MASK);
@@ -561,18 +662,6 @@ static __u64 base_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_TIMER | KVM_REG_RISCV_TIMER_REG(time),
KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_TIMER | KVM_REG_RISCV_TIMER_REG(compare),
KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_TIMER | KVM_REG_RISCV_TIMER_REG(state),
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_V01,
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_TIME,
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_IPI,
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_RFENCE,
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_SRST,
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_HSM,
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_PMU,
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_EXPERIMENTAL,
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_VENDOR,
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_DBCN,
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_MULTI_EN | 0,
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_MULTI_DIS | 0,
};
/*
@@ -583,66 +672,31 @@ static __u64 base_skips_set[] = {
KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_TIMER | KVM_REG_RISCV_TIMER_REG(state),
};
-static __u64 h_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_H,
+static __u64 sbi_base_regs[] = {
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_V01,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_TIME,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_IPI,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_RFENCE,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_SRST,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_HSM,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_EXPERIMENTAL,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_VENDOR,
+};
+
+static __u64 sbi_sta_regs[] = {
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_STA,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_STA | KVM_REG_RISCV_SBI_STA_REG(shmem_lo),
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_STA | KVM_REG_RISCV_SBI_STA_REG(shmem_hi),
};
static __u64 zicbom_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(zicbom_block_size),
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICBOM,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOM,
};
static __u64 zicboz_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(zicboz_block_size),
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICBOZ,
-};
-
-static __u64 svpbmt_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SVPBMT,
-};
-
-static __u64 sstc_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SSTC,
-};
-
-static __u64 svinval_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SVINVAL,
-};
-
-static __u64 zihintpause_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIHINTPAUSE,
-};
-
-static __u64 zba_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBA,
-};
-
-static __u64 zbb_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBB,
-};
-
-static __u64 zbs_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZBS,
-};
-
-static __u64 zicntr_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICNTR,
-};
-
-static __u64 zicond_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICOND,
-};
-
-static __u64 zicsr_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZICSR,
-};
-
-static __u64 zifencei_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIFENCEI,
-};
-
-static __u64 zihpm_regs[] = {
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_ZIHPM,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOZ,
};
static __u64 aia_regs[] = {
@@ -653,12 +707,12 @@ static __u64 aia_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(siph),
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio1h),
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio2h),
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SSAIA,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SSAIA,
};
static __u64 smstateen_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_SMSTATEEN | KVM_REG_RISCV_CSR_SMSTATEEN_REG(sstateen0),
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_SMSTATEEN,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_SMSTATEEN,
};
static __u64 fp_f_regs[] = {
@@ -695,7 +749,7 @@ static __u64 fp_f_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[30]),
KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(f[31]),
KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_F | KVM_REG_RISCV_FP_F_REG(fcsr),
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_F,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_F,
};
static __u64 fp_d_regs[] = {
@@ -732,224 +786,142 @@ static __u64 fp_d_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[30]),
KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(f[31]),
KVM_REG_RISCV | KVM_REG_SIZE_U32 | KVM_REG_RISCV_FP_D | KVM_REG_RISCV_FP_D_REG(fcsr),
- KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_RISCV_ISA_EXT_D,
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_D,
};
-#define BASE_SUBLIST \
+#define SUBLIST_BASE \
{"base", .regs = base_regs, .regs_n = ARRAY_SIZE(base_regs), \
.skips_set = base_skips_set, .skips_set_n = ARRAY_SIZE(base_skips_set),}
-#define H_REGS_SUBLIST \
- {"h", .feature = KVM_RISCV_ISA_EXT_H, .regs = h_regs, .regs_n = ARRAY_SIZE(h_regs),}
-#define ZICBOM_REGS_SUBLIST \
+#define SUBLIST_SBI_BASE \
+ {"sbi-base", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_V01, \
+ .regs = sbi_base_regs, .regs_n = ARRAY_SIZE(sbi_base_regs),}
+#define SUBLIST_SBI_STA \
+ {"sbi-sta", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_STA, \
+ .regs = sbi_sta_regs, .regs_n = ARRAY_SIZE(sbi_sta_regs),}
+#define SUBLIST_ZICBOM \
{"zicbom", .feature = KVM_RISCV_ISA_EXT_ZICBOM, .regs = zicbom_regs, .regs_n = ARRAY_SIZE(zicbom_regs),}
-#define ZICBOZ_REGS_SUBLIST \
+#define SUBLIST_ZICBOZ \
{"zicboz", .feature = KVM_RISCV_ISA_EXT_ZICBOZ, .regs = zicboz_regs, .regs_n = ARRAY_SIZE(zicboz_regs),}
-#define SVPBMT_REGS_SUBLIST \
- {"svpbmt", .feature = KVM_RISCV_ISA_EXT_SVPBMT, .regs = svpbmt_regs, .regs_n = ARRAY_SIZE(svpbmt_regs),}
-#define SSTC_REGS_SUBLIST \
- {"sstc", .feature = KVM_RISCV_ISA_EXT_SSTC, .regs = sstc_regs, .regs_n = ARRAY_SIZE(sstc_regs),}
-#define SVINVAL_REGS_SUBLIST \
- {"svinval", .feature = KVM_RISCV_ISA_EXT_SVINVAL, .regs = svinval_regs, .regs_n = ARRAY_SIZE(svinval_regs),}
-#define ZIHINTPAUSE_REGS_SUBLIST \
- {"zihintpause", .feature = KVM_RISCV_ISA_EXT_ZIHINTPAUSE, .regs = zihintpause_regs, .regs_n = ARRAY_SIZE(zihintpause_regs),}
-#define ZBA_REGS_SUBLIST \
- {"zba", .feature = KVM_RISCV_ISA_EXT_ZBA, .regs = zba_regs, .regs_n = ARRAY_SIZE(zba_regs),}
-#define ZBB_REGS_SUBLIST \
- {"zbb", .feature = KVM_RISCV_ISA_EXT_ZBB, .regs = zbb_regs, .regs_n = ARRAY_SIZE(zbb_regs),}
-#define ZBS_REGS_SUBLIST \
- {"zbs", .feature = KVM_RISCV_ISA_EXT_ZBS, .regs = zbs_regs, .regs_n = ARRAY_SIZE(zbs_regs),}
-#define ZICNTR_REGS_SUBLIST \
- {"zicntr", .feature = KVM_RISCV_ISA_EXT_ZICNTR, .regs = zicntr_regs, .regs_n = ARRAY_SIZE(zicntr_regs),}
-#define ZICOND_REGS_SUBLIST \
- {"zicond", .feature = KVM_RISCV_ISA_EXT_ZICOND, .regs = zicond_regs, .regs_n = ARRAY_SIZE(zicond_regs),}
-#define ZICSR_REGS_SUBLIST \
- {"zicsr", .feature = KVM_RISCV_ISA_EXT_ZICSR, .regs = zicsr_regs, .regs_n = ARRAY_SIZE(zicsr_regs),}
-#define ZIFENCEI_REGS_SUBLIST \
- {"zifencei", .feature = KVM_RISCV_ISA_EXT_ZIFENCEI, .regs = zifencei_regs, .regs_n = ARRAY_SIZE(zifencei_regs),}
-#define ZIHPM_REGS_SUBLIST \
- {"zihpm", .feature = KVM_RISCV_ISA_EXT_ZIHPM, .regs = zihpm_regs, .regs_n = ARRAY_SIZE(zihpm_regs),}
-#define AIA_REGS_SUBLIST \
+#define SUBLIST_AIA \
{"aia", .feature = KVM_RISCV_ISA_EXT_SSAIA, .regs = aia_regs, .regs_n = ARRAY_SIZE(aia_regs),}
-#define SMSTATEEN_REGS_SUBLIST \
+#define SUBLIST_SMSTATEEN \
{"smstateen", .feature = KVM_RISCV_ISA_EXT_SMSTATEEN, .regs = smstateen_regs, .regs_n = ARRAY_SIZE(smstateen_regs),}
-#define FP_F_REGS_SUBLIST \
+#define SUBLIST_FP_F \
{"fp_f", .feature = KVM_RISCV_ISA_EXT_F, .regs = fp_f_regs, \
.regs_n = ARRAY_SIZE(fp_f_regs),}
-#define FP_D_REGS_SUBLIST \
+#define SUBLIST_FP_D \
{"fp_d", .feature = KVM_RISCV_ISA_EXT_D, .regs = fp_d_regs, \
.regs_n = ARRAY_SIZE(fp_d_regs),}
-static struct vcpu_reg_list h_config = {
- .sublists = {
- BASE_SUBLIST,
- H_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list zicbom_config = {
- .sublists = {
- BASE_SUBLIST,
- ZICBOM_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list zicboz_config = {
- .sublists = {
- BASE_SUBLIST,
- ZICBOZ_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list svpbmt_config = {
- .sublists = {
- BASE_SUBLIST,
- SVPBMT_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list sstc_config = {
- .sublists = {
- BASE_SUBLIST,
- SSTC_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list svinval_config = {
- .sublists = {
- BASE_SUBLIST,
- SVINVAL_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list zihintpause_config = {
- .sublists = {
- BASE_SUBLIST,
- ZIHINTPAUSE_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list zba_config = {
- .sublists = {
- BASE_SUBLIST,
- ZBA_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list zbb_config = {
- .sublists = {
- BASE_SUBLIST,
- ZBB_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list zbs_config = {
- .sublists = {
- BASE_SUBLIST,
- ZBS_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list zicntr_config = {
- .sublists = {
- BASE_SUBLIST,
- ZICNTR_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list zicond_config = {
- .sublists = {
- BASE_SUBLIST,
- ZICOND_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list zicsr_config = {
- .sublists = {
- BASE_SUBLIST,
- ZICSR_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list zifencei_config = {
- .sublists = {
- BASE_SUBLIST,
- ZIFENCEI_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list zihpm_config = {
- .sublists = {
- BASE_SUBLIST,
- ZIHPM_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list aia_config = {
- .sublists = {
- BASE_SUBLIST,
- AIA_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list smstateen_config = {
- .sublists = {
- BASE_SUBLIST,
- SMSTATEEN_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list fp_f_config = {
- .sublists = {
- BASE_SUBLIST,
- FP_F_REGS_SUBLIST,
- {0},
- },
-};
-
-static struct vcpu_reg_list fp_d_config = {
- .sublists = {
- BASE_SUBLIST,
- FP_D_REGS_SUBLIST,
- {0},
- },
-};
+#define KVM_ISA_EXT_SIMPLE_CONFIG(ext, extu) \
+static __u64 regs_##ext[] = { \
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | \
+ KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | \
+ KVM_RISCV_ISA_EXT_##extu, \
+}; \
+static struct vcpu_reg_list config_##ext = { \
+ .sublists = { \
+ SUBLIST_BASE, \
+ { \
+ .name = #ext, \
+ .feature = KVM_RISCV_ISA_EXT_##extu, \
+ .regs = regs_##ext, \
+ .regs_n = ARRAY_SIZE(regs_##ext), \
+ }, \
+ {0}, \
+ }, \
+} \
+
+#define KVM_SBI_EXT_SIMPLE_CONFIG(ext, extu) \
+static __u64 regs_sbi_##ext[] = { \
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | \
+ KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | \
+ KVM_RISCV_SBI_EXT_##extu, \
+}; \
+static struct vcpu_reg_list config_sbi_##ext = { \
+ .sublists = { \
+ SUBLIST_BASE, \
+ { \
+ .name = "sbi-"#ext, \
+ .feature_type = VCPU_FEATURE_SBI_EXT, \
+ .feature = KVM_RISCV_SBI_EXT_##extu, \
+ .regs = regs_sbi_##ext, \
+ .regs_n = ARRAY_SIZE(regs_sbi_##ext), \
+ }, \
+ {0}, \
+ }, \
+} \
+
+#define KVM_ISA_EXT_SUBLIST_CONFIG(ext, extu) \
+static struct vcpu_reg_list config_##ext = { \
+ .sublists = { \
+ SUBLIST_BASE, \
+ SUBLIST_##extu, \
+ {0}, \
+ }, \
+} \
+
+#define KVM_SBI_EXT_SUBLIST_CONFIG(ext, extu) \
+static struct vcpu_reg_list config_sbi_##ext = { \
+ .sublists = { \
+ SUBLIST_BASE, \
+ SUBLIST_SBI_##extu, \
+ {0}, \
+ }, \
+} \
+
+/* Note: The below list is alphabetically sorted. */
+
+KVM_SBI_EXT_SUBLIST_CONFIG(base, BASE);
+KVM_SBI_EXT_SUBLIST_CONFIG(sta, STA);
+KVM_SBI_EXT_SIMPLE_CONFIG(pmu, PMU);
+KVM_SBI_EXT_SIMPLE_CONFIG(dbcn, DBCN);
+
+KVM_ISA_EXT_SUBLIST_CONFIG(aia, AIA);
+KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, FP_F);
+KVM_ISA_EXT_SUBLIST_CONFIG(fp_d, FP_D);
+KVM_ISA_EXT_SIMPLE_CONFIG(h, H);
+KVM_ISA_EXT_SUBLIST_CONFIG(smstateen, SMSTATEEN);
+KVM_ISA_EXT_SIMPLE_CONFIG(sstc, SSTC);
+KVM_ISA_EXT_SIMPLE_CONFIG(svinval, SVINVAL);
+KVM_ISA_EXT_SIMPLE_CONFIG(svnapot, SVNAPOT);
+KVM_ISA_EXT_SIMPLE_CONFIG(svpbmt, SVPBMT);
+KVM_ISA_EXT_SIMPLE_CONFIG(zba, ZBA);
+KVM_ISA_EXT_SIMPLE_CONFIG(zbb, ZBB);
+KVM_ISA_EXT_SIMPLE_CONFIG(zbs, ZBS);
+KVM_ISA_EXT_SUBLIST_CONFIG(zicbom, ZICBOM);
+KVM_ISA_EXT_SUBLIST_CONFIG(zicboz, ZICBOZ);
+KVM_ISA_EXT_SIMPLE_CONFIG(zicntr, ZICNTR);
+KVM_ISA_EXT_SIMPLE_CONFIG(zicond, ZICOND);
+KVM_ISA_EXT_SIMPLE_CONFIG(zicsr, ZICSR);
+KVM_ISA_EXT_SIMPLE_CONFIG(zifencei, ZIFENCEI);
+KVM_ISA_EXT_SIMPLE_CONFIG(zihintpause, ZIHINTPAUSE);
+KVM_ISA_EXT_SIMPLE_CONFIG(zihpm, ZIHPM);
struct vcpu_reg_list *vcpu_configs[] = {
- &h_config,
- &zicbom_config,
- &zicboz_config,
- &svpbmt_config,
- &sstc_config,
- &svinval_config,
- &zihintpause_config,
- &zba_config,
- &zbb_config,
- &zbs_config,
- &zicntr_config,
- &zicond_config,
- &zicsr_config,
- &zifencei_config,
- &zihpm_config,
- &aia_config,
- &smstateen_config,
- &fp_f_config,
- &fp_d_config,
+ &config_sbi_base,
+ &config_sbi_sta,
+ &config_sbi_pmu,
+ &config_sbi_dbcn,
+ &config_aia,
+ &config_fp_f,
+ &config_fp_d,
+ &config_h,
+ &config_smstateen,
+ &config_sstc,
+ &config_svinval,
+ &config_svnapot,
+ &config_svpbmt,
+ &config_zba,
+ &config_zbb,
+ &config_zbs,
+ &config_zicbom,
+ &config_zicboz,
+ &config_zicntr,
+ &config_zicond,
+ &config_zicsr,
+ &config_zifencei,
+ &config_zihintpause,
+ &config_zihpm,
};
int vcpu_configs_n = ARRAY_SIZE(vcpu_configs);
diff --git a/tools/testing/selftests/kvm/s390x/cmma_test.c b/tools/testing/selftests/kvm/s390x/cmma_test.c
index c8e0a6495a63..626a2b8a2037 100644
--- a/tools/testing/selftests/kvm/s390x/cmma_test.c
+++ b/tools/testing/selftests/kvm/s390x/cmma_test.c
@@ -94,11 +94,6 @@ static void guest_dirty_test_data(void)
);
}
-static struct kvm_vm *create_vm(void)
-{
- return ____vm_create(VM_MODE_DEFAULT);
-}
-
static void create_main_memslot(struct kvm_vm *vm)
{
int i;
@@ -157,7 +152,7 @@ static struct kvm_vm *create_vm_two_memslots(void)
{
struct kvm_vm *vm;
- vm = create_vm();
+ vm = vm_create_barebones();
create_memslots(vm);
@@ -276,7 +271,7 @@ static void assert_exit_was_hypercall(struct kvm_vcpu *vcpu)
static void test_migration_mode(void)
{
- struct kvm_vm *vm = create_vm();
+ struct kvm_vm *vm = vm_create_barebones();
struct kvm_vcpu *vcpu;
u64 orig_psw;
int rc;
@@ -670,7 +665,7 @@ struct testdef {
*/
static int machine_has_cmma(void)
{
- struct kvm_vm *vm = create_vm();
+ struct kvm_vm *vm = vm_create_barebones();
int r;
r = !__kvm_has_device_attr(vm->fd, KVM_S390_VM_MEM_CTRL, KVM_S390_VM_MEM_ENABLE_CMMA);
diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c
index b32960189f5f..075b80dbe237 100644
--- a/tools/testing/selftests/kvm/set_memory_region_test.c
+++ b/tools/testing/selftests/kvm/set_memory_region_test.c
@@ -157,17 +157,17 @@ static void guest_code_move_memory_region(void)
*/
val = guest_spin_on_val(0);
__GUEST_ASSERT(val == 1 || val == MMIO_VAL,
- "Expected '1' or MMIO ('%llx'), got '%llx'", MMIO_VAL, val);
+ "Expected '1' or MMIO ('%lx'), got '%lx'", MMIO_VAL, val);
/* Spin until the misaligning memory region move completes. */
val = guest_spin_on_val(MMIO_VAL);
__GUEST_ASSERT(val == 1 || val == 0,
- "Expected '0' or '1' (no MMIO), got '%llx'", val);
+ "Expected '0' or '1' (no MMIO), got '%lx'", val);
/* Spin until the memory region starts to get re-aligned. */
val = guest_spin_on_val(0);
__GUEST_ASSERT(val == 1 || val == MMIO_VAL,
- "Expected '1' or MMIO ('%llx'), got '%llx'", MMIO_VAL, val);
+ "Expected '1' or MMIO ('%lx'), got '%lx'", MMIO_VAL, val);
/* Spin until the re-aligning memory region move completes. */
val = guest_spin_on_val(MMIO_VAL);
@@ -326,6 +326,55 @@ static void test_zero_memory_regions(void)
}
#endif /* __x86_64__ */
+static void test_invalid_memory_region_flags(void)
+{
+ uint32_t supported_flags = KVM_MEM_LOG_DIRTY_PAGES;
+ const uint32_t v2_only_flags = KVM_MEM_GUEST_MEMFD;
+ struct kvm_vm *vm;
+ int r, i;
+
+#if defined __aarch64__ || defined __x86_64__
+ supported_flags |= KVM_MEM_READONLY;
+#endif
+
+#ifdef __x86_64__
+ if (kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SW_PROTECTED_VM))
+ vm = vm_create_barebones_protected_vm();
+ else
+#endif
+ vm = vm_create_barebones();
+
+ if (kvm_check_cap(KVM_CAP_MEMORY_ATTRIBUTES) & KVM_MEMORY_ATTRIBUTE_PRIVATE)
+ supported_flags |= KVM_MEM_GUEST_MEMFD;
+
+ for (i = 0; i < 32; i++) {
+ if ((supported_flags & BIT(i)) && !(v2_only_flags & BIT(i)))
+ continue;
+
+ r = __vm_set_user_memory_region(vm, 0, BIT(i),
+ 0, MEM_REGION_SIZE, NULL);
+
+ TEST_ASSERT(r && errno == EINVAL,
+ "KVM_SET_USER_MEMORY_REGION should have failed on v2 only flag 0x%lx", BIT(i));
+
+ if (supported_flags & BIT(i))
+ continue;
+
+ r = __vm_set_user_memory_region2(vm, 0, BIT(i),
+ 0, MEM_REGION_SIZE, NULL, 0, 0);
+ TEST_ASSERT(r && errno == EINVAL,
+ "KVM_SET_USER_MEMORY_REGION2 should have failed on unsupported flag 0x%lx", BIT(i));
+ }
+
+ if (supported_flags & KVM_MEM_GUEST_MEMFD) {
+ r = __vm_set_user_memory_region2(vm, 0,
+ KVM_MEM_LOG_DIRTY_PAGES | KVM_MEM_GUEST_MEMFD,
+ 0, MEM_REGION_SIZE, NULL, 0, 0);
+ TEST_ASSERT(r && errno == EINVAL,
+ "KVM_SET_USER_MEMORY_REGION2 should have failed, dirty logging private memory is unsupported");
+ }
+}
+
/*
* Test it can be added memory slots up to KVM_CAP_NR_MEMSLOTS, then any
* tentative to add further slots should fail.
@@ -385,13 +434,105 @@ static void test_add_max_memory_regions(void)
kvm_vm_free(vm);
}
+
+#ifdef __x86_64__
+static void test_invalid_guest_memfd(struct kvm_vm *vm, int memfd,
+ size_t offset, const char *msg)
+{
+ int r = __vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD,
+ MEM_REGION_GPA, MEM_REGION_SIZE,
+ 0, memfd, offset);
+ TEST_ASSERT(r == -1 && errno == EINVAL, "%s", msg);
+}
+
+static void test_add_private_memory_region(void)
+{
+ struct kvm_vm *vm, *vm2;
+ int memfd, i;
+
+ pr_info("Testing ADD of KVM_MEM_GUEST_MEMFD memory regions\n");
+
+ vm = vm_create_barebones_protected_vm();
+
+ test_invalid_guest_memfd(vm, vm->kvm_fd, 0, "KVM fd should fail");
+ test_invalid_guest_memfd(vm, vm->fd, 0, "VM's fd should fail");
+
+ memfd = kvm_memfd_alloc(MEM_REGION_SIZE, false);
+ test_invalid_guest_memfd(vm, memfd, 0, "Regular memfd() should fail");
+ close(memfd);
+
+ vm2 = vm_create_barebones_protected_vm();
+ memfd = vm_create_guest_memfd(vm2, MEM_REGION_SIZE, 0);
+ test_invalid_guest_memfd(vm, memfd, 0, "Other VM's guest_memfd() should fail");
+
+ vm_set_user_memory_region2(vm2, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD,
+ MEM_REGION_GPA, MEM_REGION_SIZE, 0, memfd, 0);
+ close(memfd);
+ kvm_vm_free(vm2);
+
+ memfd = vm_create_guest_memfd(vm, MEM_REGION_SIZE, 0);
+ for (i = 1; i < PAGE_SIZE; i++)
+ test_invalid_guest_memfd(vm, memfd, i, "Unaligned offset should fail");
+
+ vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD,
+ MEM_REGION_GPA, MEM_REGION_SIZE, 0, memfd, 0);
+ close(memfd);
+
+ kvm_vm_free(vm);
+}
+
+static void test_add_overlapping_private_memory_regions(void)
+{
+ struct kvm_vm *vm;
+ int memfd;
+ int r;
+
+ pr_info("Testing ADD of overlapping KVM_MEM_GUEST_MEMFD memory regions\n");
+
+ vm = vm_create_barebones_protected_vm();
+
+ memfd = vm_create_guest_memfd(vm, MEM_REGION_SIZE * 4, 0);
+
+ vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD,
+ MEM_REGION_GPA, MEM_REGION_SIZE * 2, 0, memfd, 0);
+
+ vm_set_user_memory_region2(vm, MEM_REGION_SLOT + 1, KVM_MEM_GUEST_MEMFD,
+ MEM_REGION_GPA * 2, MEM_REGION_SIZE * 2,
+ 0, memfd, MEM_REGION_SIZE * 2);
+
+ /*
+ * Delete the first memslot, and then attempt to recreate it except
+ * with a "bad" offset that results in overlap in the guest_memfd().
+ */
+ vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD,
+ MEM_REGION_GPA, 0, NULL, -1, 0);
+
+ /* Overlap the front half of the other slot. */
+ r = __vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD,
+ MEM_REGION_GPA * 2 - MEM_REGION_SIZE,
+ MEM_REGION_SIZE * 2,
+ 0, memfd, 0);
+ TEST_ASSERT(r == -1 && errno == EEXIST, "%s",
+ "Overlapping guest_memfd() bindings should fail with EEXIST");
+
+ /* And now the back half of the other slot. */
+ r = __vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD,
+ MEM_REGION_GPA * 2 + MEM_REGION_SIZE,
+ MEM_REGION_SIZE * 2,
+ 0, memfd, 0);
+ TEST_ASSERT(r == -1 && errno == EEXIST, "%s",
+ "Overlapping guest_memfd() bindings should fail with EEXIST");
+
+ close(memfd);
+ kvm_vm_free(vm);
+}
+#endif
+
int main(int argc, char *argv[])
{
#ifdef __x86_64__
int i, loops;
-#endif
-#ifdef __x86_64__
/*
* FIXME: the zero-memslot test fails on aarch64 and s390x because
* KVM_RUN fails with ENOEXEC or EFAULT.
@@ -399,9 +540,19 @@ int main(int argc, char *argv[])
test_zero_memory_regions();
#endif
+ test_invalid_memory_region_flags();
+
test_add_max_memory_regions();
#ifdef __x86_64__
+ if (kvm_has_cap(KVM_CAP_GUEST_MEMFD) &&
+ (kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SW_PROTECTED_VM))) {
+ test_add_private_memory_region();
+ test_add_overlapping_private_memory_regions();
+ } else {
+ pr_info("Skipping tests for KVM_MEM_GUEST_MEMFD memory regions\n");
+ }
+
if (argc > 1)
loops = atoi_positive("Number of iterations", argv[1]);
else
diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c
index 171adfb2a6cb..bae0c5026f82 100644
--- a/tools/testing/selftests/kvm/steal_time.c
+++ b/tools/testing/selftests/kvm/steal_time.c
@@ -11,7 +11,9 @@
#include <pthread.h>
#include <linux/kernel.h>
#include <asm/kvm.h>
+#ifndef __riscv
#include <asm/kvm_para.h>
+#endif
#include "test_util.h"
#include "kvm_util.h"
@@ -203,6 +205,103 @@ static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpu_idx)
pr_info(" st_time: %ld\n", st->st_time);
}
+#elif defined(__riscv)
+
+/* SBI STA shmem must have 64-byte alignment */
+#define STEAL_TIME_SIZE ((sizeof(struct sta_struct) + 63) & ~63)
+
+static vm_paddr_t st_gpa[NR_VCPUS];
+
+struct sta_struct {
+ uint32_t sequence;
+ uint32_t flags;
+ uint64_t steal;
+ uint8_t preempted;
+ uint8_t pad[47];
+} __packed;
+
+static void sta_set_shmem(vm_paddr_t gpa, unsigned long flags)
+{
+ unsigned long lo = (unsigned long)gpa;
+#if __riscv_xlen == 32
+ unsigned long hi = (unsigned long)(gpa >> 32);
+#else
+ unsigned long hi = gpa == -1 ? -1 : 0;
+#endif
+ struct sbiret ret = sbi_ecall(SBI_EXT_STA, 0, lo, hi, flags, 0, 0, 0);
+
+ GUEST_ASSERT(ret.value == 0 && ret.error == 0);
+}
+
+static void check_status(struct sta_struct *st)
+{
+ GUEST_ASSERT(!(READ_ONCE(st->sequence) & 1));
+ GUEST_ASSERT(READ_ONCE(st->flags) == 0);
+ GUEST_ASSERT(READ_ONCE(st->preempted) == 0);
+}
+
+static void guest_code(int cpu)
+{
+ struct sta_struct *st = st_gva[cpu];
+ uint32_t sequence;
+ long out_val = 0;
+ bool probe;
+
+ probe = guest_sbi_probe_extension(SBI_EXT_STA, &out_val);
+ GUEST_ASSERT(probe && out_val == 1);
+
+ sta_set_shmem(st_gpa[cpu], 0);
+ GUEST_SYNC(0);
+
+ check_status(st);
+ WRITE_ONCE(guest_stolen_time[cpu], st->steal);
+ sequence = READ_ONCE(st->sequence);
+ check_status(st);
+ GUEST_SYNC(1);
+
+ check_status(st);
+ GUEST_ASSERT(sequence < READ_ONCE(st->sequence));
+ WRITE_ONCE(guest_stolen_time[cpu], st->steal);
+ check_status(st);
+ GUEST_DONE();
+}
+
+static bool is_steal_time_supported(struct kvm_vcpu *vcpu)
+{
+ uint64_t id = RISCV_SBI_EXT_REG(KVM_RISCV_SBI_EXT_STA);
+ unsigned long enabled;
+
+ vcpu_get_reg(vcpu, id, &enabled);
+ TEST_ASSERT(enabled == 0 || enabled == 1, "Expected boolean result");
+
+ return enabled;
+}
+
+static void steal_time_init(struct kvm_vcpu *vcpu, uint32_t i)
+{
+ /* ST_GPA_BASE is identity mapped */
+ st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
+ st_gpa[i] = addr_gva2gpa(vcpu->vm, (vm_vaddr_t)st_gva[i]);
+ sync_global_to_guest(vcpu->vm, st_gva[i]);
+ sync_global_to_guest(vcpu->vm, st_gpa[i]);
+}
+
+static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpu_idx)
+{
+ struct sta_struct *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]);
+ int i;
+
+ pr_info("VCPU%d:\n", vcpu_idx);
+ pr_info(" sequence: %d\n", st->sequence);
+ pr_info(" flags: %d\n", st->flags);
+ pr_info(" steal: %"PRIu64"\n", st->steal);
+ pr_info(" preempted: %d\n", st->preempted);
+ pr_info(" pad: ");
+ for (i = 0; i < 47; ++i)
+ pr_info("%d", st->pad[i]);
+ pr_info("\n");
+}
+
#endif
static void *do_steal_time(void *arg)
diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_clock.c b/tools/testing/selftests/kvm/x86_64/hyperv_clock.c
index f25749eaa6a8..f5e1e98f04f9 100644
--- a/tools/testing/selftests/kvm/x86_64/hyperv_clock.c
+++ b/tools/testing/selftests/kvm/x86_64/hyperv_clock.c
@@ -211,6 +211,8 @@ int main(void)
vm_vaddr_t tsc_page_gva;
int stage;
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_TIME));
+
vm = vm_create_with_one_vcpu(&vcpu, guest_main);
vcpu_set_hv_cpuid(vcpu);
diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_evmcs.c b/tools/testing/selftests/kvm/x86_64/hyperv_evmcs.c
index 7bde0c4dfdbd..4c7257ecd2a6 100644
--- a/tools/testing/selftests/kvm/x86_64/hyperv_evmcs.c
+++ b/tools/testing/selftests/kvm/x86_64/hyperv_evmcs.c
@@ -240,11 +240,12 @@ int main(int argc, char *argv[])
struct ucall uc;
int stage;
- vm = vm_create_with_one_vcpu(&vcpu, guest_code);
-
TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE));
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS));
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_DIRECT_TLBFLUSH));
+
+ vm = vm_create_with_one_vcpu(&vcpu, guest_code);
hcall_page = vm_vaddr_alloc_pages(vm, 1);
memset(addr_gva2hva(vm, hcall_page), 0x0, getpagesize());
diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c b/tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c
index e036db1f32b9..949e08e98f31 100644
--- a/tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c
+++ b/tools/testing/selftests/kvm/x86_64/hyperv_extended_hypercalls.c
@@ -43,6 +43,8 @@ int main(void)
uint64_t *outval;
struct ucall uc;
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_CPUID));
+
/* Verify if extended hypercalls are supported */
if (!kvm_cpuid_has(kvm_get_supported_hv_cpuid(),
HV_ENABLE_EXTENDED_HYPERCALLS)) {
diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c
index 9f28aa276c4e..4f4193fc74ff 100644
--- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c
+++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c
@@ -55,18 +55,18 @@ static void guest_msr(struct msr_data *msr)
if (msr->fault_expected)
__GUEST_ASSERT(vector == GP_VECTOR,
"Expected #GP on %sMSR(0x%x), got vector '0x%x'",
- msr->idx, msr->write ? "WR" : "RD", vector);
+ msr->write ? "WR" : "RD", msr->idx, vector);
else
__GUEST_ASSERT(!vector,
"Expected success on %sMSR(0x%x), got vector '0x%x'",
- msr->idx, msr->write ? "WR" : "RD", vector);
+ msr->write ? "WR" : "RD", msr->idx, vector);
if (vector || is_write_only_msr(msr->idx))
goto done;
if (msr->write)
__GUEST_ASSERT(!vector,
- "WRMSR(0x%x) to '0x%llx', RDMSR read '0x%llx'",
+ "WRMSR(0x%x) to '0x%lx', RDMSR read '0x%lx'",
msr->idx, msr->write_val, msr_val);
/* Invariant TSC bit appears when TSC invariant control MSR is written to */
@@ -102,11 +102,11 @@ static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall)
vector = __hyperv_hypercall(hcall->control, input, output, &res);
if (hcall->ud_expected) {
__GUEST_ASSERT(vector == UD_VECTOR,
- "Expected #UD for control '%u', got vector '0x%x'",
+ "Expected #UD for control '%lu', got vector '0x%x'",
hcall->control, vector);
} else {
__GUEST_ASSERT(!vector,
- "Expected no exception for control '%u', got vector '0x%x'",
+ "Expected no exception for control '%lu', got vector '0x%x'",
hcall->control, vector);
GUEST_ASSERT_EQ(res, hcall->expect);
}
@@ -690,6 +690,8 @@ static void guest_test_hcalls_access(void)
int main(void)
{
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_ENFORCE_CPUID));
+
pr_info("Testing access to Hyper-V specific MSRs\n");
guest_test_msrs_access();
diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_ipi.c b/tools/testing/selftests/kvm/x86_64/hyperv_ipi.c
index 6feb5ddb031d..65e5f4c05068 100644
--- a/tools/testing/selftests/kvm/x86_64/hyperv_ipi.c
+++ b/tools/testing/selftests/kvm/x86_64/hyperv_ipi.c
@@ -248,6 +248,8 @@ int main(int argc, char *argv[])
int stage = 1, r;
struct ucall uc;
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_SEND_IPI));
+
vm = vm_create_with_one_vcpu(&vcpu[0], sender_guest_code);
/* Hypercall input/output */
diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c
index 6c1278562090..c9b18707edc0 100644
--- a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c
+++ b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c
@@ -158,6 +158,7 @@ int main(int argc, char *argv[])
int stage;
TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM));
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_DIRECT_TLBFLUSH));
/* Create VM */
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_tlb_flush.c b/tools/testing/selftests/kvm/x86_64/hyperv_tlb_flush.c
index 4758b6ef5618..c4443f71f8dd 100644
--- a/tools/testing/selftests/kvm/x86_64/hyperv_tlb_flush.c
+++ b/tools/testing/selftests/kvm/x86_64/hyperv_tlb_flush.c
@@ -590,6 +590,8 @@ int main(int argc, char *argv[])
struct ucall uc;
int stage = 1, r, i;
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_TLBFLUSH));
+
vm = vm_create_with_one_vcpu(&vcpu[0], sender_guest_code);
/* Test data page */
diff --git a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c
deleted file mode 100644
index ce1ccc4c1503..000000000000
--- a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * mmio_warning_test
- *
- * Copyright (C) 2019, Google LLC.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.
- *
- * Test that we don't get a kernel warning when we call KVM_RUN after a
- * triple fault occurs. To get the triple fault to occur we call KVM_RUN
- * on a VCPU that hasn't been properly setup.
- *
- */
-
-#define _GNU_SOURCE
-#include <fcntl.h>
-#include <kvm_util.h>
-#include <linux/kvm.h>
-#include <processor.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <test_util.h>
-#include <unistd.h>
-
-#define NTHREAD 4
-#define NPROCESS 5
-
-struct thread_context {
- int kvmcpu;
- struct kvm_run *run;
-};
-
-void *thr(void *arg)
-{
- struct thread_context *tc = (struct thread_context *)arg;
- int res;
- int kvmcpu = tc->kvmcpu;
- struct kvm_run *run = tc->run;
-
- res = ioctl(kvmcpu, KVM_RUN, 0);
- pr_info("ret1=%d exit_reason=%d suberror=%d\n",
- res, run->exit_reason, run->internal.suberror);
-
- return 0;
-}
-
-void test(void)
-{
- int i, kvm, kvmvm, kvmcpu;
- pthread_t th[NTHREAD];
- struct kvm_run *run;
- struct thread_context tc;
-
- kvm = open("/dev/kvm", O_RDWR);
- TEST_ASSERT(kvm != -1, "failed to open /dev/kvm");
- kvmvm = __kvm_ioctl(kvm, KVM_CREATE_VM, NULL);
- TEST_ASSERT(kvmvm > 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, kvmvm));
- kvmcpu = ioctl(kvmvm, KVM_CREATE_VCPU, 0);
- TEST_ASSERT(kvmcpu != -1, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, kvmcpu));
- run = (struct kvm_run *)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED,
- kvmcpu, 0);
- tc.kvmcpu = kvmcpu;
- tc.run = run;
- srand(getpid());
- for (i = 0; i < NTHREAD; i++) {
- pthread_create(&th[i], NULL, thr, (void *)(uintptr_t)&tc);
- usleep(rand() % 10000);
- }
- for (i = 0; i < NTHREAD; i++)
- pthread_join(th[i], NULL);
-}
-
-int get_warnings_count(void)
-{
- int warnings;
- FILE *f;
-
- f = popen("dmesg | grep \"WARNING:\" | wc -l", "r");
- if (fscanf(f, "%d", &warnings) < 1)
- warnings = 0;
- pclose(f);
-
- return warnings;
-}
-
-int main(void)
-{
- int warnings_before, warnings_after;
-
- TEST_REQUIRE(host_cpu_is_intel);
-
- TEST_REQUIRE(!vm_is_unrestricted_guest(NULL));
-
- warnings_before = get_warnings_count();
-
- for (int i = 0; i < NPROCESS; ++i) {
- int status;
- int pid = fork();
-
- if (pid < 0)
- exit(1);
- if (pid == 0) {
- test();
- exit(0);
- }
- while (waitpid(pid, &status, __WALL) != pid)
- ;
- }
-
- warnings_after = get_warnings_count();
- TEST_ASSERT(warnings_before == warnings_after,
- "Warnings found in kernel. Run 'dmesg' to inspect them.");
-
- return 0;
-}
diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c
index 80aa3d8b18f8..853802641e1e 100644
--- a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c
+++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c
@@ -27,10 +27,12 @@ do { \
\
if (fault_wanted) \
__GUEST_ASSERT((vector) == UD_VECTOR, \
- "Expected #UD on " insn " for testcase '0x%x', got '0x%x'", vector); \
+ "Expected #UD on " insn " for testcase '0x%x', got '0x%x'", \
+ testcase, vector); \
else \
__GUEST_ASSERT(!(vector), \
- "Expected success on " insn " for testcase '0x%x', got '0x%x'", vector); \
+ "Expected success on " insn " for testcase '0x%x', got '0x%x'", \
+ testcase, vector); \
} while (0)
static void guest_monitor_wait(int testcase)
diff --git a/tools/testing/selftests/kvm/x86_64/private_mem_conversions_test.c b/tools/testing/selftests/kvm/x86_64/private_mem_conversions_test.c
new file mode 100644
index 000000000000..65ad38b6be1f
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/private_mem_conversions_test.c
@@ -0,0 +1,482 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022, Google LLC.
+ */
+#define _GNU_SOURCE /* for program_invocation_short_name */
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/kvm_para.h>
+#include <linux/memfd.h>
+#include <linux/sizes.h>
+
+#include <test_util.h>
+#include <kvm_util.h>
+#include <processor.h>
+
+#define BASE_DATA_SLOT 10
+#define BASE_DATA_GPA ((uint64_t)(1ull << 32))
+#define PER_CPU_DATA_SIZE ((uint64_t)(SZ_2M + PAGE_SIZE))
+
+/* Horrific macro so that the line info is captured accurately :-( */
+#define memcmp_g(gpa, pattern, size) \
+do { \
+ uint8_t *mem = (uint8_t *)gpa; \
+ size_t i; \
+ \
+ for (i = 0; i < size; i++) \
+ __GUEST_ASSERT(mem[i] == pattern, \
+ "Guest expected 0x%x at offset %lu (gpa 0x%lx), got 0x%x", \
+ pattern, i, gpa + i, mem[i]); \
+} while (0)
+
+static void memcmp_h(uint8_t *mem, uint64_t gpa, uint8_t pattern, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++)
+ TEST_ASSERT(mem[i] == pattern,
+ "Host expected 0x%x at gpa 0x%lx, got 0x%x",
+ pattern, gpa + i, mem[i]);
+}
+
+/*
+ * Run memory conversion tests with explicit conversion:
+ * Execute KVM hypercall to map/unmap gpa range which will cause userspace exit
+ * to back/unback private memory. Subsequent accesses by guest to the gpa range
+ * will not cause exit to userspace.
+ *
+ * Test memory conversion scenarios with following steps:
+ * 1) Access private memory using private access and verify that memory contents
+ * are not visible to userspace.
+ * 2) Convert memory to shared using explicit conversions and ensure that
+ * userspace is able to access the shared regions.
+ * 3) Convert memory back to private using explicit conversions and ensure that
+ * userspace is again not able to access converted private regions.
+ */
+
+#define GUEST_STAGE(o, s) { .offset = o, .size = s }
+
+enum ucall_syncs {
+ SYNC_SHARED,
+ SYNC_PRIVATE,
+};
+
+static void guest_sync_shared(uint64_t gpa, uint64_t size,
+ uint8_t current_pattern, uint8_t new_pattern)
+{
+ GUEST_SYNC5(SYNC_SHARED, gpa, size, current_pattern, new_pattern);
+}
+
+static void guest_sync_private(uint64_t gpa, uint64_t size, uint8_t pattern)
+{
+ GUEST_SYNC4(SYNC_PRIVATE, gpa, size, pattern);
+}
+
+/* Arbitrary values, KVM doesn't care about the attribute flags. */
+#define MAP_GPA_SET_ATTRIBUTES BIT(0)
+#define MAP_GPA_SHARED BIT(1)
+#define MAP_GPA_DO_FALLOCATE BIT(2)
+
+static void guest_map_mem(uint64_t gpa, uint64_t size, bool map_shared,
+ bool do_fallocate)
+{
+ uint64_t flags = MAP_GPA_SET_ATTRIBUTES;
+
+ if (map_shared)
+ flags |= MAP_GPA_SHARED;
+ if (do_fallocate)
+ flags |= MAP_GPA_DO_FALLOCATE;
+ kvm_hypercall_map_gpa_range(gpa, size, flags);
+}
+
+static void guest_map_shared(uint64_t gpa, uint64_t size, bool do_fallocate)
+{
+ guest_map_mem(gpa, size, true, do_fallocate);
+}
+
+static void guest_map_private(uint64_t gpa, uint64_t size, bool do_fallocate)
+{
+ guest_map_mem(gpa, size, false, do_fallocate);
+}
+
+struct {
+ uint64_t offset;
+ uint64_t size;
+} static const test_ranges[] = {
+ GUEST_STAGE(0, PAGE_SIZE),
+ GUEST_STAGE(0, SZ_2M),
+ GUEST_STAGE(PAGE_SIZE, PAGE_SIZE),
+ GUEST_STAGE(PAGE_SIZE, SZ_2M),
+ GUEST_STAGE(SZ_2M, PAGE_SIZE),
+};
+
+static void guest_test_explicit_conversion(uint64_t base_gpa, bool do_fallocate)
+{
+ const uint8_t def_p = 0xaa;
+ const uint8_t init_p = 0xcc;
+ uint64_t j;
+ int i;
+
+ /* Memory should be shared by default. */
+ memset((void *)base_gpa, def_p, PER_CPU_DATA_SIZE);
+ memcmp_g(base_gpa, def_p, PER_CPU_DATA_SIZE);
+ guest_sync_shared(base_gpa, PER_CPU_DATA_SIZE, def_p, init_p);
+
+ memcmp_g(base_gpa, init_p, PER_CPU_DATA_SIZE);
+
+ for (i = 0; i < ARRAY_SIZE(test_ranges); i++) {
+ uint64_t gpa = base_gpa + test_ranges[i].offset;
+ uint64_t size = test_ranges[i].size;
+ uint8_t p1 = 0x11;
+ uint8_t p2 = 0x22;
+ uint8_t p3 = 0x33;
+ uint8_t p4 = 0x44;
+
+ /*
+ * Set the test region to pattern one to differentiate it from
+ * the data range as a whole (contains the initial pattern).
+ */
+ memset((void *)gpa, p1, size);
+
+ /*
+ * Convert to private, set and verify the private data, and
+ * then verify that the rest of the data (map shared) still
+ * holds the initial pattern, and that the host always sees the
+ * shared memory (initial pattern). Unlike shared memory,
+ * punching a hole in private memory is destructive, i.e.
+ * previous values aren't guaranteed to be preserved.
+ */
+ guest_map_private(gpa, size, do_fallocate);
+
+ if (size > PAGE_SIZE) {
+ memset((void *)gpa, p2, PAGE_SIZE);
+ goto skip;
+ }
+
+ memset((void *)gpa, p2, size);
+ guest_sync_private(gpa, size, p1);
+
+ /*
+ * Verify that the private memory was set to pattern two, and
+ * that shared memory still holds the initial pattern.
+ */
+ memcmp_g(gpa, p2, size);
+ if (gpa > base_gpa)
+ memcmp_g(base_gpa, init_p, gpa - base_gpa);
+ if (gpa + size < base_gpa + PER_CPU_DATA_SIZE)
+ memcmp_g(gpa + size, init_p,
+ (base_gpa + PER_CPU_DATA_SIZE) - (gpa + size));
+
+ /*
+ * Convert odd-number page frames back to shared to verify KVM
+ * also correctly handles holes in private ranges.
+ */
+ for (j = 0; j < size; j += PAGE_SIZE) {
+ if ((j >> PAGE_SHIFT) & 1) {
+ guest_map_shared(gpa + j, PAGE_SIZE, do_fallocate);
+ guest_sync_shared(gpa + j, PAGE_SIZE, p1, p3);
+
+ memcmp_g(gpa + j, p3, PAGE_SIZE);
+ } else {
+ guest_sync_private(gpa + j, PAGE_SIZE, p1);
+ }
+ }
+
+skip:
+ /*
+ * Convert the entire region back to shared, explicitly write
+ * pattern three to fill in the even-number frames before
+ * asking the host to verify (and write pattern four).
+ */
+ guest_map_shared(gpa, size, do_fallocate);
+ memset((void *)gpa, p3, size);
+ guest_sync_shared(gpa, size, p3, p4);
+ memcmp_g(gpa, p4, size);
+
+ /* Reset the shared memory back to the initial pattern. */
+ memset((void *)gpa, init_p, size);
+
+ /*
+ * Free (via PUNCH_HOLE) *all* private memory so that the next
+ * iteration starts from a clean slate, e.g. with respect to
+ * whether or not there are pages/folios in guest_mem.
+ */
+ guest_map_shared(base_gpa, PER_CPU_DATA_SIZE, true);
+ }
+}
+
+static void guest_punch_hole(uint64_t gpa, uint64_t size)
+{
+ /* "Mapping" memory shared via fallocate() is done via PUNCH_HOLE. */
+ uint64_t flags = MAP_GPA_SHARED | MAP_GPA_DO_FALLOCATE;
+
+ kvm_hypercall_map_gpa_range(gpa, size, flags);
+}
+
+/*
+ * Test that PUNCH_HOLE actually frees memory by punching holes without doing a
+ * proper conversion. Freeing (PUNCH_HOLE) should zap SPTEs, and reallocating
+ * (subsequent fault) should zero memory.
+ */
+static void guest_test_punch_hole(uint64_t base_gpa, bool precise)
+{
+ const uint8_t init_p = 0xcc;
+ int i;
+
+ /*
+ * Convert the entire range to private, this testcase is all about
+ * punching holes in guest_memfd, i.e. shared mappings aren't needed.
+ */
+ guest_map_private(base_gpa, PER_CPU_DATA_SIZE, false);
+
+ for (i = 0; i < ARRAY_SIZE(test_ranges); i++) {
+ uint64_t gpa = base_gpa + test_ranges[i].offset;
+ uint64_t size = test_ranges[i].size;
+
+ /*
+ * Free all memory before each iteration, even for the !precise
+ * case where the memory will be faulted back in. Freeing and
+ * reallocating should obviously work, and freeing all memory
+ * minimizes the probability of cross-testcase influence.
+ */
+ guest_punch_hole(base_gpa, PER_CPU_DATA_SIZE);
+
+ /* Fault-in and initialize memory, and verify the pattern. */
+ if (precise) {
+ memset((void *)gpa, init_p, size);
+ memcmp_g(gpa, init_p, size);
+ } else {
+ memset((void *)base_gpa, init_p, PER_CPU_DATA_SIZE);
+ memcmp_g(base_gpa, init_p, PER_CPU_DATA_SIZE);
+ }
+
+ /*
+ * Punch a hole at the target range and verify that reads from
+ * the guest succeed and return zeroes.
+ */
+ guest_punch_hole(gpa, size);
+ memcmp_g(gpa, 0, size);
+ }
+}
+
+static void guest_code(uint64_t base_gpa)
+{
+ /*
+ * Run the conversion test twice, with and without doing fallocate() on
+ * the guest_memfd backing when converting between shared and private.
+ */
+ guest_test_explicit_conversion(base_gpa, false);
+ guest_test_explicit_conversion(base_gpa, true);
+
+ /*
+ * Run the PUNCH_HOLE test twice too, once with the entire guest_memfd
+ * faulted in, once with only the target range faulted in.
+ */
+ guest_test_punch_hole(base_gpa, false);
+ guest_test_punch_hole(base_gpa, true);
+ GUEST_DONE();
+}
+
+static void handle_exit_hypercall(struct kvm_vcpu *vcpu)
+{
+ struct kvm_run *run = vcpu->run;
+ uint64_t gpa = run->hypercall.args[0];
+ uint64_t size = run->hypercall.args[1] * PAGE_SIZE;
+ bool set_attributes = run->hypercall.args[2] & MAP_GPA_SET_ATTRIBUTES;
+ bool map_shared = run->hypercall.args[2] & MAP_GPA_SHARED;
+ bool do_fallocate = run->hypercall.args[2] & MAP_GPA_DO_FALLOCATE;
+ struct kvm_vm *vm = vcpu->vm;
+
+ TEST_ASSERT(run->hypercall.nr == KVM_HC_MAP_GPA_RANGE,
+ "Wanted MAP_GPA_RANGE (%u), got '%llu'",
+ KVM_HC_MAP_GPA_RANGE, run->hypercall.nr);
+
+ if (do_fallocate)
+ vm_guest_mem_fallocate(vm, gpa, size, map_shared);
+
+ if (set_attributes)
+ vm_set_memory_attributes(vm, gpa, size,
+ map_shared ? 0 : KVM_MEMORY_ATTRIBUTE_PRIVATE);
+ run->hypercall.ret = 0;
+}
+
+static bool run_vcpus;
+
+static void *__test_mem_conversions(void *__vcpu)
+{
+ struct kvm_vcpu *vcpu = __vcpu;
+ struct kvm_run *run = vcpu->run;
+ struct kvm_vm *vm = vcpu->vm;
+ struct ucall uc;
+
+ while (!READ_ONCE(run_vcpus))
+ ;
+
+ for ( ;; ) {
+ vcpu_run(vcpu);
+
+ if (run->exit_reason == KVM_EXIT_HYPERCALL) {
+ handle_exit_hypercall(vcpu);
+ continue;
+ }
+
+ TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+ "Wanted KVM_EXIT_IO, got exit reason: %u (%s)",
+ run->exit_reason, exit_reason_str(run->exit_reason));
+
+ switch (get_ucall(vcpu, &uc)) {
+ case UCALL_ABORT:
+ REPORT_GUEST_ASSERT(uc);
+ case UCALL_SYNC: {
+ uint64_t gpa = uc.args[1];
+ size_t size = uc.args[2];
+ size_t i;
+
+ TEST_ASSERT(uc.args[0] == SYNC_SHARED ||
+ uc.args[0] == SYNC_PRIVATE,
+ "Unknown sync command '%ld'", uc.args[0]);
+
+ for (i = 0; i < size; i += vm->page_size) {
+ size_t nr_bytes = min_t(size_t, vm->page_size, size - i);
+ uint8_t *hva = addr_gpa2hva(vm, gpa + i);
+
+ /* In all cases, the host should observe the shared data. */
+ memcmp_h(hva, gpa + i, uc.args[3], nr_bytes);
+
+ /* For shared, write the new pattern to guest memory. */
+ if (uc.args[0] == SYNC_SHARED)
+ memset(hva, uc.args[4], nr_bytes);
+ }
+ break;
+ }
+ case UCALL_DONE:
+ return NULL;
+ default:
+ TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd);
+ }
+ }
+}
+
+static void test_mem_conversions(enum vm_mem_backing_src_type src_type, uint32_t nr_vcpus,
+ uint32_t nr_memslots)
+{
+ /*
+ * Allocate enough memory so that each vCPU's chunk of memory can be
+ * naturally aligned with respect to the size of the backing store.
+ */
+ const size_t alignment = max_t(size_t, SZ_2M, get_backing_src_pagesz(src_type));
+ const size_t per_cpu_size = align_up(PER_CPU_DATA_SIZE, alignment);
+ const size_t memfd_size = per_cpu_size * nr_vcpus;
+ const size_t slot_size = memfd_size / nr_memslots;
+ struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+ pthread_t threads[KVM_MAX_VCPUS];
+ struct kvm_vm *vm;
+ int memfd, i, r;
+
+ const struct vm_shape shape = {
+ .mode = VM_MODE_DEFAULT,
+ .type = KVM_X86_SW_PROTECTED_VM,
+ };
+
+ TEST_ASSERT(slot_size * nr_memslots == memfd_size,
+ "The memfd size (0x%lx) needs to be cleanly divisible by the number of memslots (%u)",
+ memfd_size, nr_memslots);
+ vm = __vm_create_with_vcpus(shape, nr_vcpus, 0, guest_code, vcpus);
+
+ vm_enable_cap(vm, KVM_CAP_EXIT_HYPERCALL, (1 << KVM_HC_MAP_GPA_RANGE));
+
+ memfd = vm_create_guest_memfd(vm, memfd_size, 0);
+
+ for (i = 0; i < nr_memslots; i++)
+ vm_mem_add(vm, src_type, BASE_DATA_GPA + slot_size * i,
+ BASE_DATA_SLOT + i, slot_size / vm->page_size,
+ KVM_MEM_GUEST_MEMFD, memfd, slot_size * i);
+
+ for (i = 0; i < nr_vcpus; i++) {
+ uint64_t gpa = BASE_DATA_GPA + i * per_cpu_size;
+
+ vcpu_args_set(vcpus[i], 1, gpa);
+
+ /*
+ * Map only what is needed so that an out-of-bounds access
+ * results #PF => SHUTDOWN instead of data corruption.
+ */
+ virt_map(vm, gpa, gpa, PER_CPU_DATA_SIZE / vm->page_size);
+
+ pthread_create(&threads[i], NULL, __test_mem_conversions, vcpus[i]);
+ }
+
+ WRITE_ONCE(run_vcpus, true);
+
+ for (i = 0; i < nr_vcpus; i++)
+ pthread_join(threads[i], NULL);
+
+ kvm_vm_free(vm);
+
+ /*
+ * Allocate and free memory from the guest_memfd after closing the VM
+ * fd. The guest_memfd is gifted a reference to its owning VM, i.e.
+ * should prevent the VM from being fully destroyed until the last
+ * reference to the guest_memfd is also put.
+ */
+ r = fallocate(memfd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, memfd_size);
+ TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("fallocate()", r));
+
+ r = fallocate(memfd, FALLOC_FL_KEEP_SIZE, 0, memfd_size);
+ TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("fallocate()", r));
+}
+
+static void usage(const char *cmd)
+{
+ puts("");
+ printf("usage: %s [-h] [-m nr_memslots] [-s mem_type] [-n nr_vcpus]\n", cmd);
+ puts("");
+ backing_src_help("-s");
+ puts("");
+ puts(" -n: specify the number of vcpus (default: 1)");
+ puts("");
+ puts(" -m: specify the number of memslots (default: 1)");
+ puts("");
+}
+
+int main(int argc, char *argv[])
+{
+ enum vm_mem_backing_src_type src_type = DEFAULT_VM_MEM_SRC;
+ uint32_t nr_memslots = 1;
+ uint32_t nr_vcpus = 1;
+ int opt;
+
+ TEST_REQUIRE(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SW_PROTECTED_VM));
+
+ while ((opt = getopt(argc, argv, "hm:s:n:")) != -1) {
+ switch (opt) {
+ case 's':
+ src_type = parse_backing_src_type(optarg);
+ break;
+ case 'n':
+ nr_vcpus = atoi_positive("nr_vcpus", optarg);
+ break;
+ case 'm':
+ nr_memslots = atoi_positive("nr_memslots", optarg);
+ break;
+ case 'h':
+ default:
+ usage(argv[0]);
+ exit(0);
+ }
+ }
+
+ test_mem_conversions(src_type, nr_vcpus, nr_memslots);
+
+ return 0;
+}
diff --git a/tools/testing/selftests/kvm/x86_64/private_mem_kvm_exits_test.c b/tools/testing/selftests/kvm/x86_64/private_mem_kvm_exits_test.c
new file mode 100644
index 000000000000..13e72fcec8dd
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/private_mem_kvm_exits_test.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023, Google LLC.
+ */
+#include <linux/kvm.h>
+#include <pthread.h>
+#include <stdint.h>
+
+#include "kvm_util.h"
+#include "processor.h"
+#include "test_util.h"
+
+/* Arbitrarily selected to avoid overlaps with anything else */
+#define EXITS_TEST_GVA 0xc0000000
+#define EXITS_TEST_GPA EXITS_TEST_GVA
+#define EXITS_TEST_NPAGES 1
+#define EXITS_TEST_SIZE (EXITS_TEST_NPAGES * PAGE_SIZE)
+#define EXITS_TEST_SLOT 10
+
+static uint64_t guest_repeatedly_read(void)
+{
+ volatile uint64_t value;
+
+ while (true)
+ value = *((uint64_t *) EXITS_TEST_GVA);
+
+ return value;
+}
+
+static uint32_t run_vcpu_get_exit_reason(struct kvm_vcpu *vcpu)
+{
+ int r;
+
+ r = _vcpu_run(vcpu);
+ if (r) {
+ TEST_ASSERT(errno == EFAULT, KVM_IOCTL_ERROR(KVM_RUN, r));
+ TEST_ASSERT_EQ(vcpu->run->exit_reason, KVM_EXIT_MEMORY_FAULT);
+ }
+ return vcpu->run->exit_reason;
+}
+
+const struct vm_shape protected_vm_shape = {
+ .mode = VM_MODE_DEFAULT,
+ .type = KVM_X86_SW_PROTECTED_VM,
+};
+
+static void test_private_access_memslot_deleted(void)
+{
+ struct kvm_vm *vm;
+ struct kvm_vcpu *vcpu;
+ pthread_t vm_thread;
+ void *thread_return;
+ uint32_t exit_reason;
+
+ vm = vm_create_shape_with_one_vcpu(protected_vm_shape, &vcpu,
+ guest_repeatedly_read);
+
+ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+ EXITS_TEST_GPA, EXITS_TEST_SLOT,
+ EXITS_TEST_NPAGES,
+ KVM_MEM_GUEST_MEMFD);
+
+ virt_map(vm, EXITS_TEST_GVA, EXITS_TEST_GPA, EXITS_TEST_NPAGES);
+
+ /* Request to access page privately */
+ vm_mem_set_private(vm, EXITS_TEST_GPA, EXITS_TEST_SIZE);
+
+ pthread_create(&vm_thread, NULL,
+ (void *(*)(void *))run_vcpu_get_exit_reason,
+ (void *)vcpu);
+
+ vm_mem_region_delete(vm, EXITS_TEST_SLOT);
+
+ pthread_join(vm_thread, &thread_return);
+ exit_reason = (uint32_t)(uint64_t)thread_return;
+
+ TEST_ASSERT_EQ(exit_reason, KVM_EXIT_MEMORY_FAULT);
+ TEST_ASSERT_EQ(vcpu->run->memory_fault.flags, KVM_MEMORY_EXIT_FLAG_PRIVATE);
+ TEST_ASSERT_EQ(vcpu->run->memory_fault.gpa, EXITS_TEST_GPA);
+ TEST_ASSERT_EQ(vcpu->run->memory_fault.size, EXITS_TEST_SIZE);
+
+ kvm_vm_free(vm);
+}
+
+static void test_private_access_memslot_not_private(void)
+{
+ struct kvm_vm *vm;
+ struct kvm_vcpu *vcpu;
+ uint32_t exit_reason;
+
+ vm = vm_create_shape_with_one_vcpu(protected_vm_shape, &vcpu,
+ guest_repeatedly_read);
+
+ /* Add a non-private memslot (flags = 0) */
+ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+ EXITS_TEST_GPA, EXITS_TEST_SLOT,
+ EXITS_TEST_NPAGES, 0);
+
+ virt_map(vm, EXITS_TEST_GVA, EXITS_TEST_GPA, EXITS_TEST_NPAGES);
+
+ /* Request to access page privately */
+ vm_mem_set_private(vm, EXITS_TEST_GPA, EXITS_TEST_SIZE);
+
+ exit_reason = run_vcpu_get_exit_reason(vcpu);
+
+ TEST_ASSERT_EQ(exit_reason, KVM_EXIT_MEMORY_FAULT);
+ TEST_ASSERT_EQ(vcpu->run->memory_fault.flags, KVM_MEMORY_EXIT_FLAG_PRIVATE);
+ TEST_ASSERT_EQ(vcpu->run->memory_fault.gpa, EXITS_TEST_GPA);
+ TEST_ASSERT_EQ(vcpu->run->memory_fault.size, EXITS_TEST_SIZE);
+
+ kvm_vm_free(vm);
+}
+
+int main(int argc, char *argv[])
+{
+ TEST_REQUIRE(kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SW_PROTECTED_VM));
+
+ test_private_access_memslot_deleted();
+ test_private_access_memslot_not_private();
+}
diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c
index 7ee44496cf97..0c7ce3d4e83a 100644
--- a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c
+++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c
@@ -103,7 +103,7 @@ static void l1_guest_code(struct svm_test_data *svm, uint64_t is_nmi, uint64_t i
run_guest(vmcb, svm->vmcb_gpa);
__GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_VMMCALL,
- "Expected VMMCAL #VMEXIT, got '0x%x', info1 = '0x%llx, info2 = '0x%llx'",
+ "Expected VMMCAL #VMEXIT, got '0x%x', info1 = '0x%lx, info2 = '0x%lx'",
vmcb->control.exit_code,
vmcb->control.exit_info_1, vmcb->control.exit_info_2);
@@ -133,7 +133,7 @@ static void l1_guest_code(struct svm_test_data *svm, uint64_t is_nmi, uint64_t i
run_guest(vmcb, svm->vmcb_gpa);
__GUEST_ASSERT(vmcb->control.exit_code == SVM_EXIT_HLT,
- "Expected HLT #VMEXIT, got '0x%x', info1 = '0x%llx, info2 = '0x%llx'",
+ "Expected HLT #VMEXIT, got '0x%x', info1 = '0x%lx, info2 = '0x%lx'",
vmcb->control.exit_code,
vmcb->control.exit_info_1, vmcb->control.exit_info_2);
diff --git a/tools/testing/selftests/kvm/x86_64/ucna_injection_test.c b/tools/testing/selftests/kvm/x86_64/ucna_injection_test.c
index 85f34ca7e49e..0ed32ec903d0 100644
--- a/tools/testing/selftests/kvm/x86_64/ucna_injection_test.c
+++ b/tools/testing/selftests/kvm/x86_64/ucna_injection_test.c
@@ -271,7 +271,7 @@ int main(int argc, char *argv[])
kvm_check_cap(KVM_CAP_MCE);
- vm = __vm_create(VM_MODE_DEFAULT, 3, 0);
+ vm = __vm_create(VM_SHAPE_DEFAULT, 3, 0);
kvm_ioctl(vm->kvm_fd, KVM_X86_GET_MCE_CAP_SUPPORTED,
&supported_mcg_caps);
diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c
index ebbcb0a3f743..2a8d4ac2f020 100644
--- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c
+++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c
@@ -56,7 +56,7 @@ static void guest_test_perf_capabilities_gp(uint64_t val)
uint8_t vector = wrmsr_safe(MSR_IA32_PERF_CAPABILITIES, val);
__GUEST_ASSERT(vector == GP_VECTOR,
- "Expected #GP for value '0x%llx', got vector '0x%x'",
+ "Expected #GP for value '0x%lx', got vector '0x%x'",
val, vector);
}
diff --git a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c
index 41ea7028a1f8..67a62a5a8895 100644
--- a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c
+++ b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c
@@ -125,21 +125,25 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu)
/*
* Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without
- * setting the nested state but flags other than eVMCS must be clear.
- * The eVMCS flag can be set if the enlightened VMCS capability has
- * been enabled.
+ * setting the nested state. When the eVMCS flag is not set, the
+ * expected return value is '0'.
*/
set_default_vmx_state(state, state_sz);
+ state->flags = 0;
state->hdr.vmx.vmxon_pa = -1ull;
state->hdr.vmx.vmcs12_pa = -1ull;
- test_nested_state_expect_einval(vcpu, state);
+ test_nested_state(vcpu, state);
- state->flags &= KVM_STATE_NESTED_EVMCS;
+ /*
+ * When eVMCS is supported, the eVMCS flag can only be set if the
+ * enlightened VMCS capability has been enabled.
+ */
if (have_evmcs) {
+ state->flags = KVM_STATE_NESTED_EVMCS;
test_nested_state_expect_einval(vcpu, state);
vcpu_enable_evmcs(vcpu);
+ test_nested_state(vcpu, state);
}
- test_nested_state(vcpu, state);
/* It is invalid to have vmxon_pa == -1ull and SMM flags non-zero. */
state->hdr.vmx.smm.flags = 1;
diff --git a/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c b/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c
index 77d04a7bdadd..dc6217440db3 100644
--- a/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c
+++ b/tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c
@@ -25,7 +25,7 @@ do { \
\
__GUEST_ASSERT((__supported & (xfeatures)) != (xfeatures) || \
__supported == ((xfeatures) | (dependencies)), \
- "supported = 0x%llx, xfeatures = 0x%llx, dependencies = 0x%llx", \
+ "supported = 0x%lx, xfeatures = 0x%llx, dependencies = 0x%llx", \
__supported, (xfeatures), (dependencies)); \
} while (0)
@@ -42,7 +42,7 @@ do { \
uint64_t __supported = (supported_xcr0) & (xfeatures); \
\
__GUEST_ASSERT(!__supported || __supported == (xfeatures), \
- "supported = 0x%llx, xfeatures = 0x%llx", \
+ "supported = 0x%lx, xfeatures = 0x%llx", \
__supported, (xfeatures)); \
} while (0)
@@ -81,7 +81,7 @@ static void guest_code(void)
vector = xsetbv_safe(0, supported_xcr0);
__GUEST_ASSERT(!vector,
- "Expected success on XSETBV(0x%llx), got vector '0x%x'",
+ "Expected success on XSETBV(0x%lx), got vector '0x%x'",
supported_xcr0, vector);
for (i = 0; i < 64; i++) {
@@ -90,7 +90,7 @@ static void guest_code(void)
vector = xsetbv_safe(0, supported_xcr0 | BIT_ULL(i));
__GUEST_ASSERT(vector == GP_VECTOR,
- "Expected #GP on XSETBV(0x%llx), supported XCR0 = %llx, got vector '0x%x'",
+ "Expected #GP on XSETBV(0x%llx), supported XCR0 = %lx, got vector '0x%x'",
BIT_ULL(i), supported_xcr0, vector);
}
diff --git a/tools/testing/selftests/mm/hugepage-vmemmap.c b/tools/testing/selftests/mm/hugepage-vmemmap.c
index 5b354c209e93..894d28c3dd47 100644
--- a/tools/testing/selftests/mm/hugepage-vmemmap.c
+++ b/tools/testing/selftests/mm/hugepage-vmemmap.c
@@ -10,10 +10,7 @@
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
-
-#define MAP_LENGTH (2UL * 1024 * 1024)
-
-#define PAGE_SIZE 4096
+#include "vm_util.h"
#define PAGE_COMPOUND_HEAD (1UL << 15)
#define PAGE_COMPOUND_TAIL (1UL << 16)
@@ -39,6 +36,9 @@
#define MAP_FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
#endif
+static size_t pagesize;
+static size_t maplength;
+
static void write_bytes(char *addr, size_t length)
{
unsigned long i;
@@ -56,7 +56,7 @@ static unsigned long virt_to_pfn(void *addr)
if (fd < 0)
return -1UL;
- lseek(fd, (unsigned long)addr / PAGE_SIZE * sizeof(pagemap), SEEK_SET);
+ lseek(fd, (unsigned long)addr / pagesize * sizeof(pagemap), SEEK_SET);
read(fd, &pagemap, sizeof(pagemap));
close(fd);
@@ -86,7 +86,7 @@ static int check_page_flags(unsigned long pfn)
* this also verifies kernel has correctly set the fake page_head to tail
* while hugetlb_free_vmemmap is enabled.
*/
- for (i = 1; i < MAP_LENGTH / PAGE_SIZE; i++) {
+ for (i = 1; i < maplength / pagesize; i++) {
read(fd, &pageflags, sizeof(pageflags));
if ((pageflags & TAIL_PAGE_FLAGS) != TAIL_PAGE_FLAGS ||
(pageflags & HEAD_PAGE_FLAGS) == HEAD_PAGE_FLAGS) {
@@ -106,18 +106,25 @@ int main(int argc, char **argv)
void *addr;
unsigned long pfn;
- addr = mmap(MAP_ADDR, MAP_LENGTH, PROT_READ | PROT_WRITE, MAP_FLAGS, -1, 0);
+ pagesize = psize();
+ maplength = default_huge_page_size();
+ if (!maplength) {
+ printf("Unable to determine huge page size\n");
+ exit(1);
+ }
+
+ addr = mmap(MAP_ADDR, maplength, PROT_READ | PROT_WRITE, MAP_FLAGS, -1, 0);
if (addr == MAP_FAILED) {
perror("mmap");
exit(1);
}
/* Trigger allocation of HugeTLB page. */
- write_bytes(addr, MAP_LENGTH);
+ write_bytes(addr, maplength);
pfn = virt_to_pfn(addr);
if (pfn == -1UL) {
- munmap(addr, MAP_LENGTH);
+ munmap(addr, maplength);
perror("virt_to_pfn");
exit(1);
}
@@ -125,13 +132,13 @@ int main(int argc, char **argv)
printf("Returned address is %p whose pfn is %lx\n", addr, pfn);
if (check_page_flags(pfn) < 0) {
- munmap(addr, MAP_LENGTH);
+ munmap(addr, maplength);
perror("check_page_flags");
exit(1);
}
/* munmap() length of MAP_HUGETLB memory must be hugepage aligned */
- if (munmap(addr, MAP_LENGTH)) {
+ if (munmap(addr, maplength)) {
perror("munmap");
exit(1);
}
diff --git a/tools/testing/selftests/rcutorture/bin/mkinitrd.sh b/tools/testing/selftests/rcutorture/bin/mkinitrd.sh
index 212c52ca90b5..f3f867129560 100755
--- a/tools/testing/selftests/rcutorture/bin/mkinitrd.sh
+++ b/tools/testing/selftests/rcutorture/bin/mkinitrd.sh
@@ -67,7 +67,10 @@ ___EOF___
# build using nolibc on supported archs (smaller executable) and fall
# back to regular glibc on other ones.
if echo -e "#if __x86_64__||__i386__||__i486__||__i586__||__i686__" \
- "||__ARM_EABI__||__aarch64__||__s390x__||__loongarch__\nyes\n#endif" \
+ "||__ARM_EABI__||__aarch64__||(__mips__ && _ABIO32)" \
+ "||__powerpc__||(__riscv && __riscv_xlen == 64)" \
+ "||__s390x__||__loongarch__" \
+ "\nyes\n#endif" \
| ${CROSS_COMPILE}gcc -E -nostdlib -xc - \
| grep -q '^yes'; then
# architecture supported by nolibc
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot
index d44609937503..979edbf4c820 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07.boot
@@ -1 +1,4 @@
nohz_full=2-9
+rcutorture.stall_cpu=14
+rcutorture.stall_cpu_holdoff=90
+rcutorture.fwd_progress=0
diff --git a/tools/testing/selftests/riscv/hwprobe/Makefile b/tools/testing/selftests/riscv/hwprobe/Makefile
index f224b84591fb..cec81610a5f2 100644
--- a/tools/testing/selftests/riscv/hwprobe/Makefile
+++ b/tools/testing/selftests/riscv/hwprobe/Makefile
@@ -4,7 +4,7 @@
CFLAGS += -I$(top_srcdir)/tools/include
-TEST_GEN_PROGS := hwprobe cbo
+TEST_GEN_PROGS := hwprobe cbo which-cpus
include ../../lib.mk
@@ -13,3 +13,6 @@ $(OUTPUT)/hwprobe: hwprobe.c sys_hwprobe.S
$(OUTPUT)/cbo: cbo.c sys_hwprobe.S
$(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^
+
+$(OUTPUT)/which-cpus: which-cpus.c sys_hwprobe.S
+ $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^
diff --git a/tools/testing/selftests/riscv/hwprobe/hwprobe.c b/tools/testing/selftests/riscv/hwprobe/hwprobe.c
index c474891df307..d53e0889b59e 100644
--- a/tools/testing/selftests/riscv/hwprobe/hwprobe.c
+++ b/tools/testing/selftests/riscv/hwprobe/hwprobe.c
@@ -47,7 +47,7 @@ int main(int argc, char **argv)
ksft_test_result(out != 0, "Bad CPU set\n");
out = riscv_hwprobe(pairs, 8, 1, 0, 0);
- ksft_test_result(out != 0, "NULL CPU set with non-zero count\n");
+ ksft_test_result(out != 0, "NULL CPU set with non-zero size\n");
pairs[0].key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR;
out = riscv_hwprobe(pairs, 1, 1, &cpus, 0);
diff --git a/tools/testing/selftests/riscv/hwprobe/hwprobe.h b/tools/testing/selftests/riscv/hwprobe/hwprobe.h
index 721b0ce73a56..e3fccb390c4d 100644
--- a/tools/testing/selftests/riscv/hwprobe/hwprobe.h
+++ b/tools/testing/selftests/riscv/hwprobe/hwprobe.h
@@ -10,6 +10,6 @@
* contain the call.
*/
long riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
- size_t cpu_count, unsigned long *cpus, unsigned int flags);
+ size_t cpusetsize, unsigned long *cpus, unsigned int flags);
#endif
diff --git a/tools/testing/selftests/riscv/hwprobe/which-cpus.c b/tools/testing/selftests/riscv/hwprobe/which-cpus.c
new file mode 100644
index 000000000000..82c121412dfc
--- /dev/null
+++ b/tools/testing/selftests/riscv/hwprobe/which-cpus.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023 Ventana Micro Systems Inc.
+ *
+ * Test the RISCV_HWPROBE_WHICH_CPUS flag of hwprobe. Also provides a command
+ * line interface to get the cpu list for arbitrary hwprobe pairs.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sched.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "hwprobe.h"
+#include "../../kselftest.h"
+
+static void help(void)
+{
+ printf("\n"
+ "which-cpus: [-h] [<key=value> [<key=value> ...]]\n\n"
+ " Without parameters, tests the RISCV_HWPROBE_WHICH_CPUS flag of hwprobe.\n"
+ " With parameters, where each parameter is a hwprobe pair written as\n"
+ " <key=value>, outputs the cpulist for cpus which all match the given set\n"
+ " of pairs. 'key' and 'value' should be in numeric form, e.g. 4=0x3b\n");
+}
+
+static void print_cpulist(cpu_set_t *cpus)
+{
+ int start = 0, end = 0;
+
+ if (!CPU_COUNT(cpus)) {
+ printf("cpus: None\n");
+ return;
+ }
+
+ printf("cpus:");
+ for (int i = 0, c = 0; i < CPU_COUNT(cpus); i++, c++) {
+ if (start != end && !CPU_ISSET(c, cpus))
+ printf("-%d", end);
+
+ while (!CPU_ISSET(c, cpus))
+ ++c;
+
+ if (i != 0 && c == end + 1) {
+ end = c;
+ continue;
+ }
+
+ printf("%c%d", i == 0 ? ' ' : ',', c);
+ start = end = c;
+ }
+ if (start != end)
+ printf("-%d", end);
+ printf("\n");
+}
+
+static void do_which_cpus(int argc, char **argv, cpu_set_t *cpus)
+{
+ struct riscv_hwprobe *pairs;
+ int nr_pairs = argc - 1;
+ char *start, *end;
+ int rc;
+
+ pairs = malloc(nr_pairs * sizeof(struct riscv_hwprobe));
+ assert(pairs);
+
+ for (int i = 0; i < nr_pairs; i++) {
+ start = argv[i + 1];
+ pairs[i].key = strtol(start, &end, 0);
+ assert(end != start && *end == '=');
+ start = end + 1;
+ pairs[i].value = strtoul(start, &end, 0);
+ assert(end != start && *end == '\0');
+ }
+
+ rc = riscv_hwprobe(pairs, nr_pairs, sizeof(cpu_set_t), (unsigned long *)cpus, RISCV_HWPROBE_WHICH_CPUS);
+ assert(rc == 0);
+ print_cpulist(cpus);
+ free(pairs);
+}
+
+int main(int argc, char **argv)
+{
+ struct riscv_hwprobe pairs[2];
+ cpu_set_t cpus_aff, cpus;
+ __u64 ext0_all;
+ long rc;
+
+ rc = sched_getaffinity(0, sizeof(cpu_set_t), &cpus_aff);
+ assert(rc == 0);
+
+ if (argc > 1) {
+ if (!strcmp(argv[1], "-h"))
+ help();
+ else
+ do_which_cpus(argc, argv, &cpus_aff);
+ return 0;
+ }
+
+ ksft_print_header();
+ ksft_set_plan(7);
+
+ pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, };
+ rc = riscv_hwprobe(pairs, 1, 0, NULL, 0);
+ assert(rc == 0 && pairs[0].key == RISCV_HWPROBE_KEY_BASE_BEHAVIOR &&
+ pairs[0].value == RISCV_HWPROBE_BASE_BEHAVIOR_IMA);
+
+ pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, };
+ rc = riscv_hwprobe(pairs, 1, 0, NULL, 0);
+ assert(rc == 0 && pairs[0].key == RISCV_HWPROBE_KEY_IMA_EXT_0);
+ ext0_all = pairs[0].value;
+
+ pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
+ CPU_ZERO(&cpus);
+ rc = riscv_hwprobe(pairs, 1, 0, (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
+ ksft_test_result(rc == -EINVAL, "no cpusetsize\n");
+
+ pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
+ rc = riscv_hwprobe(pairs, 1, sizeof(cpu_set_t), NULL, RISCV_HWPROBE_WHICH_CPUS);
+ ksft_test_result(rc == -EINVAL, "NULL cpus\n");
+
+ pairs[0] = (struct riscv_hwprobe){ .key = 0xbadc0de, };
+ CPU_ZERO(&cpus);
+ rc = riscv_hwprobe(pairs, 1, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
+ ksft_test_result(rc == 0 && CPU_COUNT(&cpus) == 0, "unknown key\n");
+
+ pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
+ pairs[1] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
+ CPU_ZERO(&cpus);
+ rc = riscv_hwprobe(pairs, 2, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
+ ksft_test_result(rc == 0, "duplicate keys\n");
+
+ pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
+ pairs[1] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, .value = ext0_all, };
+ CPU_ZERO(&cpus);
+ rc = riscv_hwprobe(pairs, 2, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
+ ksft_test_result(rc == 0 && CPU_COUNT(&cpus) == sysconf(_SC_NPROCESSORS_ONLN), "set all cpus\n");
+
+ pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
+ pairs[1] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, .value = ext0_all, };
+ memcpy(&cpus, &cpus_aff, sizeof(cpu_set_t));
+ rc = riscv_hwprobe(pairs, 2, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
+ ksft_test_result(rc == 0 && CPU_EQUAL(&cpus, &cpus_aff), "set all affinity cpus\n");
+
+ pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
+ pairs[1] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, .value = ~ext0_all, };
+ memcpy(&cpus, &cpus_aff, sizeof(cpu_set_t));
+ rc = riscv_hwprobe(pairs, 2, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
+ ksft_test_result(rc == 0 && CPU_COUNT(&cpus) == 0, "clear all cpus\n");
+
+ ksft_finished();
+}
diff --git a/tools/testing/selftests/riscv/vector/vstate_prctl.c b/tools/testing/selftests/riscv/vector/vstate_prctl.c
index b348b475be57..8dcd399ef7fc 100644
--- a/tools/testing/selftests/riscv/vector/vstate_prctl.c
+++ b/tools/testing/selftests/riscv/vector/vstate_prctl.c
@@ -1,20 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <sys/prctl.h>
#include <unistd.h>
-#include <asm/hwprobe.h>
#include <errno.h>
#include <sys/wait.h>
+#include "../hwprobe/hwprobe.h"
#include "../../kselftest.h"
-/*
- * Rather than relying on having a new enough libc to define this, just do it
- * ourselves. This way we don't need to be coupled to a new-enough libc to
- * contain the call.
- */
-long riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
- size_t cpu_count, unsigned long *cpus, unsigned int flags);
-
#define NEXT_PROGRAM "./vstate_exec_nolibc"
static int launch_test(int test_inherit)
{
diff --git a/tools/testing/selftests/sgx/Makefile b/tools/testing/selftests/sgx/Makefile
index 50aab6b57da3..867f88ce2570 100644
--- a/tools/testing/selftests/sgx/Makefile
+++ b/tools/testing/selftests/sgx/Makefile
@@ -12,14 +12,16 @@ OBJCOPY := $(CROSS_COMPILE)objcopy
endif
INCLUDES := -I$(top_srcdir)/tools/include
-HOST_CFLAGS := -Wall -Werror -g $(INCLUDES) -fPIC -z noexecstack
-ENCL_CFLAGS := -Wall -Werror -static -nostdlib -nostartfiles -fPIC \
+HOST_CFLAGS := -Wall -Werror -g $(INCLUDES) -fPIC
+HOST_LDFLAGS := -z noexecstack -lcrypto
+ENCL_CFLAGS += -Wall -Werror -static-pie -nostdlib -ffreestanding -fPIE \
-fno-stack-protector -mrdrnd $(INCLUDES)
+ENCL_LDFLAGS := -Wl,-T,test_encl.lds,--build-id=none
+ifeq ($(CAN_BUILD_X86_64), 1)
TEST_CUSTOM_PROGS := $(OUTPUT)/test_sgx
TEST_FILES := $(OUTPUT)/test_encl.elf
-ifeq ($(CAN_BUILD_X86_64), 1)
all: $(TEST_CUSTOM_PROGS) $(OUTPUT)/test_encl.elf
endif
@@ -28,7 +30,7 @@ $(OUTPUT)/test_sgx: $(OUTPUT)/main.o \
$(OUTPUT)/sigstruct.o \
$(OUTPUT)/call.o \
$(OUTPUT)/sign_key.o
- $(CC) $(HOST_CFLAGS) -o $@ $^ -lcrypto
+ $(CC) $(HOST_CFLAGS) -o $@ $^ $(HOST_LDFLAGS)
$(OUTPUT)/main.o: main.c
$(CC) $(HOST_CFLAGS) -c $< -o $@
@@ -45,8 +47,8 @@ $(OUTPUT)/call.o: call.S
$(OUTPUT)/sign_key.o: sign_key.S
$(CC) $(HOST_CFLAGS) -c $< -o $@
-$(OUTPUT)/test_encl.elf: test_encl.lds test_encl.c test_encl_bootstrap.S
- $(CC) $(ENCL_CFLAGS) -T $^ -o $@ -Wl,--build-id=none
+$(OUTPUT)/test_encl.elf: test_encl.c test_encl_bootstrap.S
+ $(CC) $(ENCL_CFLAGS) $^ -o $@ $(ENCL_LDFLAGS)
EXTRA_CLEAN := \
$(OUTPUT)/test_encl.elf \
diff --git a/tools/testing/selftests/sgx/defines.h b/tools/testing/selftests/sgx/defines.h
index d8587c971941..402f8787a71c 100644
--- a/tools/testing/selftests/sgx/defines.h
+++ b/tools/testing/selftests/sgx/defines.h
@@ -13,6 +13,8 @@
#define __aligned(x) __attribute__((__aligned__(x)))
#define __packed __attribute__((packed))
+#define __used __attribute__((used))
+#define __section(x)__attribute__((__section__(x)))
#include "../../../../arch/x86/include/asm/sgx.h"
#include "../../../../arch/x86/include/asm/enclu.h"
diff --git a/tools/testing/selftests/sgx/load.c b/tools/testing/selftests/sgx/load.c
index 94bdeac1cf04..c9f658e44de6 100644
--- a/tools/testing/selftests/sgx/load.c
+++ b/tools/testing/selftests/sgx/load.c
@@ -136,11 +136,11 @@ static bool encl_ioc_add_pages(struct encl *encl, struct encl_segment *seg)
*/
uint64_t encl_get_entry(struct encl *encl, const char *symbol)
{
+ Elf64_Sym *symtab = NULL;
+ char *sym_names = NULL;
Elf64_Shdr *sections;
- Elf64_Sym *symtab;
Elf64_Ehdr *ehdr;
- char *sym_names;
- int num_sym;
+ int num_sym = 0;
int i;
ehdr = encl->bin;
@@ -161,6 +161,9 @@ uint64_t encl_get_entry(struct encl *encl, const char *symbol)
}
}
+ if (!symtab || !sym_names)
+ return 0;
+
for (i = 0; i < num_sym; i++) {
Elf64_Sym *sym = &symtab[i];
diff --git a/tools/testing/selftests/sgx/sigstruct.c b/tools/testing/selftests/sgx/sigstruct.c
index a07896a46364..d73b29becf5b 100644
--- a/tools/testing/selftests/sgx/sigstruct.c
+++ b/tools/testing/selftests/sgx/sigstruct.c
@@ -318,9 +318,9 @@ bool encl_measure(struct encl *encl)
struct sgx_sigstruct *sigstruct = &encl->sigstruct;
struct sgx_sigstruct_payload payload;
uint8_t digest[SHA256_DIGEST_LENGTH];
+ EVP_MD_CTX *ctx = NULL;
unsigned int siglen;
RSA *key = NULL;
- EVP_MD_CTX *ctx;
int i;
memset(sigstruct, 0, sizeof(*sigstruct));
@@ -384,7 +384,8 @@ bool encl_measure(struct encl *encl)
return true;
err:
- EVP_MD_CTX_destroy(ctx);
+ if (ctx)
+ EVP_MD_CTX_destroy(ctx);
RSA_free(key);
return false;
}
diff --git a/tools/testing/selftests/sgx/test_encl.c b/tools/testing/selftests/sgx/test_encl.c
index c0d6397295e3..2c4d709cce2d 100644
--- a/tools/testing/selftests/sgx/test_encl.c
+++ b/tools/testing/selftests/sgx/test_encl.c
@@ -5,11 +5,12 @@
#include "defines.h"
/*
- * Data buffer spanning two pages that will be placed first in .data
- * segment. Even if not used internally the second page is needed by
- * external test manipulating page permissions.
+ * Data buffer spanning two pages that will be placed first in the .data
+ * segment via the linker script. Even if not used internally the second page
+ * is needed by external test manipulating page permissions, so mark
+ * encl_buffer as "used" to make sure it is entirely preserved by the compiler.
*/
-static uint8_t encl_buffer[8192] = { 1 };
+static uint8_t __used __section(".data.encl_buffer") encl_buffer[8192] = { 1 };
enum sgx_enclu_function {
EACCEPT = 0x5,
@@ -24,10 +25,11 @@ static void do_encl_emodpe(void *_op)
secinfo.flags = op->flags;
asm volatile(".byte 0x0f, 0x01, 0xd7"
- :
+ : /* no outputs */
: "a" (EMODPE),
"b" (&secinfo),
- "c" (op->epc_addr));
+ "c" (op->epc_addr)
+ : "memory" /* read from secinfo pointer */);
}
static void do_encl_eaccept(void *_op)
@@ -42,7 +44,8 @@ static void do_encl_eaccept(void *_op)
: "=a" (rax)
: "a" (EACCEPT),
"b" (&secinfo),
- "c" (op->epc_addr));
+ "c" (op->epc_addr)
+ : "memory" /* read from secinfo pointer */);
op->ret = rax;
}
@@ -119,21 +122,41 @@ static void do_encl_op_nop(void *_op)
}
+/*
+ * Symbol placed at the start of the enclave image by the linker script.
+ * Declare this extern symbol with visibility "hidden" to ensure the compiler
+ * does not access it through the GOT and generates position-independent
+ * addressing as __encl_base(%rip), so we can get the actual enclave base
+ * during runtime.
+ */
+extern const uint8_t __attribute__((visibility("hidden"))) __encl_base;
+
+typedef void (*encl_op_t)(void *);
+static const encl_op_t encl_op_array[ENCL_OP_MAX] = {
+ do_encl_op_put_to_buf,
+ do_encl_op_get_from_buf,
+ do_encl_op_put_to_addr,
+ do_encl_op_get_from_addr,
+ do_encl_op_nop,
+ do_encl_eaccept,
+ do_encl_emodpe,
+ do_encl_init_tcs_page,
+};
+
void encl_body(void *rdi, void *rsi)
{
- const void (*encl_op_array[ENCL_OP_MAX])(void *) = {
- do_encl_op_put_to_buf,
- do_encl_op_get_from_buf,
- do_encl_op_put_to_addr,
- do_encl_op_get_from_addr,
- do_encl_op_nop,
- do_encl_eaccept,
- do_encl_emodpe,
- do_encl_init_tcs_page,
- };
-
- struct encl_op_header *op = (struct encl_op_header *)rdi;
-
- if (op->type < ENCL_OP_MAX)
- (*encl_op_array[op->type])(op);
+ struct encl_op_header *header = (struct encl_op_header *)rdi;
+ encl_op_t op;
+
+ if (header->type >= ENCL_OP_MAX)
+ return;
+
+ /*
+ * The enclave base address needs to be added, as this call site
+ * *cannot be* made rip-relative by the compiler, or fixed up by
+ * any other possible means.
+ */
+ op = ((uint64_t)&__encl_base) + encl_op_array[header->type];
+
+ (*op)(header);
}
diff --git a/tools/testing/selftests/sgx/test_encl.lds b/tools/testing/selftests/sgx/test_encl.lds
index a1ec64f7d91f..ffe851a1cac4 100644
--- a/tools/testing/selftests/sgx/test_encl.lds
+++ b/tools/testing/selftests/sgx/test_encl.lds
@@ -10,6 +10,7 @@ PHDRS
SECTIONS
{
. = 0;
+ __encl_base = .;
.tcs : {
*(.tcs*)
} : tcs
@@ -23,6 +24,7 @@ SECTIONS
} : text
.data : {
+ *(.data.encl_buffer)
*(.data*)
} : data
@@ -31,11 +33,9 @@ SECTIONS
*(.note*)
*(.debug*)
*(.eh_frame*)
+ *(.dyn*)
+ *(.gnu.hash)
}
}
-ASSERT(!DEFINED(.altinstructions), "ALTERNATIVES are not supported in enclaves")
-ASSERT(!DEFINED(.altinstr_replacement), "ALTERNATIVES are not supported in enclaves")
-ASSERT(!DEFINED(.discard.retpoline_safe), "RETPOLINE ALTERNATIVES are not supported in enclaves")
-ASSERT(!DEFINED(.discard.nospec), "RETPOLINE ALTERNATIVES are not supported in enclaves")
-ASSERT(!DEFINED(.got.plt), "Libcalls are not supported in enclaves")
+ASSERT(!DEFINED(_GLOBAL_OFFSET_TABLE_), "Libcalls through GOT are not supported in enclaves")
diff --git a/tools/testing/selftests/sgx/test_encl_bootstrap.S b/tools/testing/selftests/sgx/test_encl_bootstrap.S
index 03ae0f57e29d..d8c4ac94e032 100644
--- a/tools/testing/selftests/sgx/test_encl_bootstrap.S
+++ b/tools/testing/selftests/sgx/test_encl_bootstrap.S
@@ -42,9 +42,12 @@
encl_entry:
# RBX contains the base address for TCS, which is the first address
# inside the enclave for TCS #1 and one page into the enclave for
- # TCS #2. By adding the value of encl_stack to it, we get
- # the absolute address for the stack.
- lea (encl_stack)(%rbx), %rax
+ # TCS #2. First make it relative by substracting __encl_base and
+ # then add the address of encl_stack to get the address for the stack.
+ lea __encl_base(%rip), %rax
+ sub %rax, %rbx
+ lea encl_stack(%rip), %rax
+ add %rbx, %rax
jmp encl_entry_core
encl_dyn_entry:
# Entry point for dynamically created TCS page expected to follow
@@ -55,25 +58,12 @@ encl_entry_core:
push %rax
push %rcx # push the address after EENTER
- push %rbx # push the enclave base address
+ # NOTE: as the selftest enclave is *not* intended for production,
+ # simplify the code by not initializing ABI registers on entry or
+ # cleansing caller-save registers on exit.
call encl_body
- pop %rbx # pop the enclave base address
-
- /* Clear volatile GPRs, except RAX (EEXIT function). */
- xor %rcx, %rcx
- xor %rdx, %rdx
- xor %rdi, %rdi
- xor %rsi, %rsi
- xor %r8, %r8
- xor %r9, %r9
- xor %r10, %r10
- xor %r11, %r11
-
- # Reset status flags.
- add %rdx, %rdx # OF = SF = AF = CF = 0; ZF = PF = 1
-
# Prepare EEXIT target by popping the address of the instruction after
# EENTER to RBX.
pop %rbx
diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig
index 484d0873061c..184dab4ee871 100644
--- a/virt/kvm/Kconfig
+++ b/virt/kvm/Kconfig
@@ -4,13 +4,16 @@
config HAVE_KVM
bool
-config HAVE_KVM_PFNCACHE
+config KVM_COMMON
bool
+ select EVENTFD
+ select INTERVAL_TREE
+ select PREEMPT_NOTIFIERS
-config HAVE_KVM_IRQCHIP
+config HAVE_KVM_PFNCACHE
bool
-config HAVE_KVM_IRQFD
+config HAVE_KVM_IRQCHIP
bool
config HAVE_KVM_IRQ_ROUTING
@@ -39,10 +42,6 @@ config NEED_KVM_DIRTY_RING_WITH_BITMAP
bool
depends on HAVE_KVM_DIRTY_RING
-config HAVE_KVM_EVENTFD
- bool
- select EVENTFD
-
config KVM_MMIO
bool
@@ -92,3 +91,20 @@ config HAVE_KVM_PM_NOTIFIER
config KVM_GENERIC_HARDWARE_ENABLING
bool
+
+config KVM_GENERIC_MMU_NOTIFIER
+ select MMU_NOTIFIER
+ bool
+
+config KVM_GENERIC_MEMORY_ATTRIBUTES
+ depends on KVM_GENERIC_MMU_NOTIFIER
+ bool
+
+config KVM_PRIVATE_MEM
+ select XARRAY_MULTI
+ bool
+
+config KVM_GENERIC_PRIVATE_MEM
+ select KVM_GENERIC_MEMORY_ATTRIBUTES
+ select KVM_PRIVATE_MEM
+ bool
diff --git a/virt/kvm/Makefile.kvm b/virt/kvm/Makefile.kvm
index 2c27d5d0c367..724c89af78af 100644
--- a/virt/kvm/Makefile.kvm
+++ b/virt/kvm/Makefile.kvm
@@ -12,3 +12,4 @@ kvm-$(CONFIG_KVM_ASYNC_PF) += $(KVM)/async_pf.o
kvm-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(KVM)/irqchip.o
kvm-$(CONFIG_HAVE_KVM_DIRTY_RING) += $(KVM)/dirty_ring.o
kvm-$(CONFIG_HAVE_KVM_PFNCACHE) += $(KVM)/pfncache.o
+kvm-$(CONFIG_KVM_PRIVATE_MEM) += $(KVM)/guest_memfd.o
diff --git a/virt/kvm/dirty_ring.c b/virt/kvm/dirty_ring.c
index c1cd7dfe4a90..86d267db87bb 100644
--- a/virt/kvm/dirty_ring.c
+++ b/virt/kvm/dirty_ring.c
@@ -58,7 +58,7 @@ static void kvm_reset_dirty_gfn(struct kvm *kvm, u32 slot, u64 offset, u64 mask)
as_id = slot >> 16;
id = (u16)slot;
- if (as_id >= KVM_ADDRESS_SPACE_NUM || id >= KVM_USER_MEM_SLOTS)
+ if (as_id >= kvm_arch_nr_memslot_as_ids(kvm) || id >= KVM_USER_MEM_SLOTS)
return;
memslot = id_to_memslot(__kvm_memslots(kvm, as_id), id);
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c
index c0e230f4c3e9..229570059a1b 100644
--- a/virt/kvm/eventfd.c
+++ b/virt/kvm/eventfd.c
@@ -28,7 +28,7 @@
#include <kvm/iodev.h>
-#ifdef CONFIG_HAVE_KVM_IRQFD
+#ifdef CONFIG_HAVE_KVM_IRQCHIP
static struct workqueue_struct *irqfd_cleanup_wq;
@@ -526,21 +526,7 @@ void kvm_unregister_irq_ack_notifier(struct kvm *kvm,
synchronize_srcu(&kvm->irq_srcu);
kvm_arch_post_irq_ack_notifier_list_update(kvm);
}
-#endif
-
-void
-kvm_eventfd_init(struct kvm *kvm)
-{
-#ifdef CONFIG_HAVE_KVM_IRQFD
- spin_lock_init(&kvm->irqfds.lock);
- INIT_LIST_HEAD(&kvm->irqfds.items);
- INIT_LIST_HEAD(&kvm->irqfds.resampler_list);
- mutex_init(&kvm->irqfds.resampler_lock);
-#endif
- INIT_LIST_HEAD(&kvm->ioeventfds);
-}
-#ifdef CONFIG_HAVE_KVM_IRQFD
/*
* shutdown any irqfd's that match fd+gsi
*/
@@ -1012,3 +998,15 @@ kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
return kvm_assign_ioeventfd(kvm, args);
}
+
+void
+kvm_eventfd_init(struct kvm *kvm)
+{
+#ifdef CONFIG_HAVE_KVM_IRQCHIP
+ spin_lock_init(&kvm->irqfds.lock);
+ INIT_LIST_HEAD(&kvm->irqfds.items);
+ INIT_LIST_HEAD(&kvm->irqfds.resampler_list);
+ mutex_init(&kvm->irqfds.resampler_lock);
+#endif
+ INIT_LIST_HEAD(&kvm->ioeventfds);
+}
diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
new file mode 100644
index 000000000000..0f4e0cf4f158
--- /dev/null
+++ b/virt/kvm/guest_memfd.c
@@ -0,0 +1,532 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/backing-dev.h>
+#include <linux/falloc.h>
+#include <linux/kvm_host.h>
+#include <linux/pagemap.h>
+#include <linux/anon_inodes.h>
+
+#include "kvm_mm.h"
+
+struct kvm_gmem {
+ struct kvm *kvm;
+ struct xarray bindings;
+ struct list_head entry;
+};
+
+static struct folio *kvm_gmem_get_folio(struct inode *inode, pgoff_t index)
+{
+ struct folio *folio;
+
+ /* TODO: Support huge pages. */
+ folio = filemap_grab_folio(inode->i_mapping, index);
+ if (IS_ERR_OR_NULL(folio))
+ return NULL;
+
+ /*
+ * Use the up-to-date flag to track whether or not the memory has been
+ * zeroed before being handed off to the guest. There is no backing
+ * storage for the memory, so the folio will remain up-to-date until
+ * it's removed.
+ *
+ * TODO: Skip clearing pages when trusted firmware will do it when
+ * assigning memory to the guest.
+ */
+ if (!folio_test_uptodate(folio)) {
+ unsigned long nr_pages = folio_nr_pages(folio);
+ unsigned long i;
+
+ for (i = 0; i < nr_pages; i++)
+ clear_highpage(folio_page(folio, i));
+
+ folio_mark_uptodate(folio);
+ }
+
+ /*
+ * Ignore accessed, referenced, and dirty flags. The memory is
+ * unevictable and there is no storage to write back to.
+ */
+ return folio;
+}
+
+static void kvm_gmem_invalidate_begin(struct kvm_gmem *gmem, pgoff_t start,
+ pgoff_t end)
+{
+ bool flush = false, found_memslot = false;
+ struct kvm_memory_slot *slot;
+ struct kvm *kvm = gmem->kvm;
+ unsigned long index;
+
+ xa_for_each_range(&gmem->bindings, index, slot, start, end - 1) {
+ pgoff_t pgoff = slot->gmem.pgoff;
+
+ struct kvm_gfn_range gfn_range = {
+ .start = slot->base_gfn + max(pgoff, start) - pgoff,
+ .end = slot->base_gfn + min(pgoff + slot->npages, end) - pgoff,
+ .slot = slot,
+ .may_block = true,
+ };
+
+ if (!found_memslot) {
+ found_memslot = true;
+
+ KVM_MMU_LOCK(kvm);
+ kvm_mmu_invalidate_begin(kvm);
+ }
+
+ flush |= kvm_mmu_unmap_gfn_range(kvm, &gfn_range);
+ }
+
+ if (flush)
+ kvm_flush_remote_tlbs(kvm);
+
+ if (found_memslot)
+ KVM_MMU_UNLOCK(kvm);
+}
+
+static void kvm_gmem_invalidate_end(struct kvm_gmem *gmem, pgoff_t start,
+ pgoff_t end)
+{
+ struct kvm *kvm = gmem->kvm;
+
+ if (xa_find(&gmem->bindings, &start, end - 1, XA_PRESENT)) {
+ KVM_MMU_LOCK(kvm);
+ kvm_mmu_invalidate_end(kvm);
+ KVM_MMU_UNLOCK(kvm);
+ }
+}
+
+static long kvm_gmem_punch_hole(struct inode *inode, loff_t offset, loff_t len)
+{
+ struct list_head *gmem_list = &inode->i_mapping->i_private_list;
+ pgoff_t start = offset >> PAGE_SHIFT;
+ pgoff_t end = (offset + len) >> PAGE_SHIFT;
+ struct kvm_gmem *gmem;
+
+ /*
+ * Bindings must be stable across invalidation to ensure the start+end
+ * are balanced.
+ */
+ filemap_invalidate_lock(inode->i_mapping);
+
+ list_for_each_entry(gmem, gmem_list, entry)
+ kvm_gmem_invalidate_begin(gmem, start, end);
+
+ truncate_inode_pages_range(inode->i_mapping, offset, offset + len - 1);
+
+ list_for_each_entry(gmem, gmem_list, entry)
+ kvm_gmem_invalidate_end(gmem, start, end);
+
+ filemap_invalidate_unlock(inode->i_mapping);
+
+ return 0;
+}
+
+static long kvm_gmem_allocate(struct inode *inode, loff_t offset, loff_t len)
+{
+ struct address_space *mapping = inode->i_mapping;
+ pgoff_t start, index, end;
+ int r;
+
+ /* Dedicated guest is immutable by default. */
+ if (offset + len > i_size_read(inode))
+ return -EINVAL;
+
+ filemap_invalidate_lock_shared(mapping);
+
+ start = offset >> PAGE_SHIFT;
+ end = (offset + len) >> PAGE_SHIFT;
+
+ r = 0;
+ for (index = start; index < end; ) {
+ struct folio *folio;
+
+ if (signal_pending(current)) {
+ r = -EINTR;
+ break;
+ }
+
+ folio = kvm_gmem_get_folio(inode, index);
+ if (!folio) {
+ r = -ENOMEM;
+ break;
+ }
+
+ index = folio_next_index(folio);
+
+ folio_unlock(folio);
+ folio_put(folio);
+
+ /* 64-bit only, wrapping the index should be impossible. */
+ if (WARN_ON_ONCE(!index))
+ break;
+
+ cond_resched();
+ }
+
+ filemap_invalidate_unlock_shared(mapping);
+
+ return r;
+}
+
+static long kvm_gmem_fallocate(struct file *file, int mode, loff_t offset,
+ loff_t len)
+{
+ int ret;
+
+ if (!(mode & FALLOC_FL_KEEP_SIZE))
+ return -EOPNOTSUPP;
+
+ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+ return -EOPNOTSUPP;
+
+ if (!PAGE_ALIGNED(offset) || !PAGE_ALIGNED(len))
+ return -EINVAL;
+
+ if (mode & FALLOC_FL_PUNCH_HOLE)
+ ret = kvm_gmem_punch_hole(file_inode(file), offset, len);
+ else
+ ret = kvm_gmem_allocate(file_inode(file), offset, len);
+
+ if (!ret)
+ file_modified(file);
+ return ret;
+}
+
+static int kvm_gmem_release(struct inode *inode, struct file *file)
+{
+ struct kvm_gmem *gmem = file->private_data;
+ struct kvm_memory_slot *slot;
+ struct kvm *kvm = gmem->kvm;
+ unsigned long index;
+
+ /*
+ * Prevent concurrent attempts to *unbind* a memslot. This is the last
+ * reference to the file and thus no new bindings can be created, but
+ * dereferencing the slot for existing bindings needs to be protected
+ * against memslot updates, specifically so that unbind doesn't race
+ * and free the memslot (kvm_gmem_get_file() will return NULL).
+ */
+ mutex_lock(&kvm->slots_lock);
+
+ filemap_invalidate_lock(inode->i_mapping);
+
+ xa_for_each(&gmem->bindings, index, slot)
+ rcu_assign_pointer(slot->gmem.file, NULL);
+
+ synchronize_rcu();
+
+ /*
+ * All in-flight operations are gone and new bindings can be created.
+ * Zap all SPTEs pointed at by this file. Do not free the backing
+ * memory, as its lifetime is associated with the inode, not the file.
+ */
+ kvm_gmem_invalidate_begin(gmem, 0, -1ul);
+ kvm_gmem_invalidate_end(gmem, 0, -1ul);
+
+ list_del(&gmem->entry);
+
+ filemap_invalidate_unlock(inode->i_mapping);
+
+ mutex_unlock(&kvm->slots_lock);
+
+ xa_destroy(&gmem->bindings);
+ kfree(gmem);
+
+ kvm_put_kvm(kvm);
+
+ return 0;
+}
+
+static inline struct file *kvm_gmem_get_file(struct kvm_memory_slot *slot)
+{
+ /*
+ * Do not return slot->gmem.file if it has already been closed;
+ * there might be some time between the last fput() and when
+ * kvm_gmem_release() clears slot->gmem.file, and you do not
+ * want to spin in the meanwhile.
+ */
+ return get_file_active(&slot->gmem.file);
+}
+
+static struct file_operations kvm_gmem_fops = {
+ .open = generic_file_open,
+ .release = kvm_gmem_release,
+ .fallocate = kvm_gmem_fallocate,
+};
+
+void kvm_gmem_init(struct module *module)
+{
+ kvm_gmem_fops.owner = module;
+}
+
+static int kvm_gmem_migrate_folio(struct address_space *mapping,
+ struct folio *dst, struct folio *src,
+ enum migrate_mode mode)
+{
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+}
+
+static int kvm_gmem_error_folio(struct address_space *mapping, struct folio *folio)
+{
+ struct list_head *gmem_list = &mapping->i_private_list;
+ struct kvm_gmem *gmem;
+ pgoff_t start, end;
+
+ filemap_invalidate_lock_shared(mapping);
+
+ start = folio->index;
+ end = start + folio_nr_pages(folio);
+
+ list_for_each_entry(gmem, gmem_list, entry)
+ kvm_gmem_invalidate_begin(gmem, start, end);
+
+ /*
+ * Do not truncate the range, what action is taken in response to the
+ * error is userspace's decision (assuming the architecture supports
+ * gracefully handling memory errors). If/when the guest attempts to
+ * access a poisoned page, kvm_gmem_get_pfn() will return -EHWPOISON,
+ * at which point KVM can either terminate the VM or propagate the
+ * error to userspace.
+ */
+
+ list_for_each_entry(gmem, gmem_list, entry)
+ kvm_gmem_invalidate_end(gmem, start, end);
+
+ filemap_invalidate_unlock_shared(mapping);
+
+ return MF_DELAYED;
+}
+
+static const struct address_space_operations kvm_gmem_aops = {
+ .dirty_folio = noop_dirty_folio,
+ .migrate_folio = kvm_gmem_migrate_folio,
+ .error_remove_folio = kvm_gmem_error_folio,
+};
+
+static int kvm_gmem_getattr(struct mnt_idmap *idmap, const struct path *path,
+ struct kstat *stat, u32 request_mask,
+ unsigned int query_flags)
+{
+ struct inode *inode = path->dentry->d_inode;
+
+ generic_fillattr(idmap, request_mask, inode, stat);
+ return 0;
+}
+
+static int kvm_gmem_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+ struct iattr *attr)
+{
+ return -EINVAL;
+}
+static const struct inode_operations kvm_gmem_iops = {
+ .getattr = kvm_gmem_getattr,
+ .setattr = kvm_gmem_setattr,
+};
+
+static int __kvm_gmem_create(struct kvm *kvm, loff_t size, u64 flags)
+{
+ const char *anon_name = "[kvm-gmem]";
+ struct kvm_gmem *gmem;
+ struct inode *inode;
+ struct file *file;
+ int fd, err;
+
+ fd = get_unused_fd_flags(0);
+ if (fd < 0)
+ return fd;
+
+ gmem = kzalloc(sizeof(*gmem), GFP_KERNEL);
+ if (!gmem) {
+ err = -ENOMEM;
+ goto err_fd;
+ }
+
+ file = anon_inode_create_getfile(anon_name, &kvm_gmem_fops, gmem,
+ O_RDWR, NULL);
+ if (IS_ERR(file)) {
+ err = PTR_ERR(file);
+ goto err_gmem;
+ }
+
+ file->f_flags |= O_LARGEFILE;
+
+ inode = file->f_inode;
+ WARN_ON(file->f_mapping != inode->i_mapping);
+
+ inode->i_private = (void *)(unsigned long)flags;
+ inode->i_op = &kvm_gmem_iops;
+ inode->i_mapping->a_ops = &kvm_gmem_aops;
+ inode->i_mode |= S_IFREG;
+ inode->i_size = size;
+ mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
+ mapping_set_unmovable(inode->i_mapping);
+ /* Unmovable mappings are supposed to be marked unevictable as well. */
+ WARN_ON_ONCE(!mapping_unevictable(inode->i_mapping));
+
+ kvm_get_kvm(kvm);
+ gmem->kvm = kvm;
+ xa_init(&gmem->bindings);
+ list_add(&gmem->entry, &inode->i_mapping->i_private_list);
+
+ fd_install(fd, file);
+ return fd;
+
+err_gmem:
+ kfree(gmem);
+err_fd:
+ put_unused_fd(fd);
+ return err;
+}
+
+int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args)
+{
+ loff_t size = args->size;
+ u64 flags = args->flags;
+ u64 valid_flags = 0;
+
+ if (flags & ~valid_flags)
+ return -EINVAL;
+
+ if (size <= 0 || !PAGE_ALIGNED(size))
+ return -EINVAL;
+
+ return __kvm_gmem_create(kvm, size, flags);
+}
+
+int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
+ unsigned int fd, loff_t offset)
+{
+ loff_t size = slot->npages << PAGE_SHIFT;
+ unsigned long start, end;
+ struct kvm_gmem *gmem;
+ struct inode *inode;
+ struct file *file;
+ int r = -EINVAL;
+
+ BUILD_BUG_ON(sizeof(gfn_t) != sizeof(slot->gmem.pgoff));
+
+ file = fget(fd);
+ if (!file)
+ return -EBADF;
+
+ if (file->f_op != &kvm_gmem_fops)
+ goto err;
+
+ gmem = file->private_data;
+ if (gmem->kvm != kvm)
+ goto err;
+
+ inode = file_inode(file);
+
+ if (offset < 0 || !PAGE_ALIGNED(offset) ||
+ offset + size > i_size_read(inode))
+ goto err;
+
+ filemap_invalidate_lock(inode->i_mapping);
+
+ start = offset >> PAGE_SHIFT;
+ end = start + slot->npages;
+
+ if (!xa_empty(&gmem->bindings) &&
+ xa_find(&gmem->bindings, &start, end - 1, XA_PRESENT)) {
+ filemap_invalidate_unlock(inode->i_mapping);
+ goto err;
+ }
+
+ /*
+ * No synchronize_rcu() needed, any in-flight readers are guaranteed to
+ * be see either a NULL file or this new file, no need for them to go
+ * away.
+ */
+ rcu_assign_pointer(slot->gmem.file, file);
+ slot->gmem.pgoff = start;
+
+ xa_store_range(&gmem->bindings, start, end - 1, slot, GFP_KERNEL);
+ filemap_invalidate_unlock(inode->i_mapping);
+
+ /*
+ * Drop the reference to the file, even on success. The file pins KVM,
+ * not the other way 'round. Active bindings are invalidated if the
+ * file is closed before memslots are destroyed.
+ */
+ r = 0;
+err:
+ fput(file);
+ return r;
+}
+
+void kvm_gmem_unbind(struct kvm_memory_slot *slot)
+{
+ unsigned long start = slot->gmem.pgoff;
+ unsigned long end = start + slot->npages;
+ struct kvm_gmem *gmem;
+ struct file *file;
+
+ /*
+ * Nothing to do if the underlying file was already closed (or is being
+ * closed right now), kvm_gmem_release() invalidates all bindings.
+ */
+ file = kvm_gmem_get_file(slot);
+ if (!file)
+ return;
+
+ gmem = file->private_data;
+
+ filemap_invalidate_lock(file->f_mapping);
+ xa_store_range(&gmem->bindings, start, end - 1, NULL, GFP_KERNEL);
+ rcu_assign_pointer(slot->gmem.file, NULL);
+ synchronize_rcu();
+ filemap_invalidate_unlock(file->f_mapping);
+
+ fput(file);
+}
+
+int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
+ gfn_t gfn, kvm_pfn_t *pfn, int *max_order)
+{
+ pgoff_t index = gfn - slot->base_gfn + slot->gmem.pgoff;
+ struct kvm_gmem *gmem;
+ struct folio *folio;
+ struct page *page;
+ struct file *file;
+ int r;
+
+ file = kvm_gmem_get_file(slot);
+ if (!file)
+ return -EFAULT;
+
+ gmem = file->private_data;
+
+ if (WARN_ON_ONCE(xa_load(&gmem->bindings, index) != slot)) {
+ r = -EIO;
+ goto out_fput;
+ }
+
+ folio = kvm_gmem_get_folio(file_inode(file), index);
+ if (!folio) {
+ r = -ENOMEM;
+ goto out_fput;
+ }
+
+ if (folio_test_hwpoison(folio)) {
+ r = -EHWPOISON;
+ goto out_unlock;
+ }
+
+ page = folio_file_page(folio, index);
+
+ *pfn = page_to_pfn(page);
+ if (max_order)
+ *max_order = 0;
+
+ r = 0;
+
+out_unlock:
+ folio_unlock(folio);
+out_fput:
+ fput(file);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(kvm_gmem_get_pfn);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 7db96875ac46..10bfc88a69f7 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -533,31 +533,44 @@ void kvm_destroy_vcpus(struct kvm *kvm)
}
EXPORT_SYMBOL_GPL(kvm_destroy_vcpus);
-#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
+#ifdef CONFIG_KVM_GENERIC_MMU_NOTIFIER
static inline struct kvm *mmu_notifier_to_kvm(struct mmu_notifier *mn)
{
return container_of(mn, struct kvm, mmu_notifier);
}
-typedef bool (*hva_handler_t)(struct kvm *kvm, struct kvm_gfn_range *range);
+typedef bool (*gfn_handler_t)(struct kvm *kvm, struct kvm_gfn_range *range);
-typedef void (*on_lock_fn_t)(struct kvm *kvm, unsigned long start,
- unsigned long end);
+typedef void (*on_lock_fn_t)(struct kvm *kvm);
-typedef void (*on_unlock_fn_t)(struct kvm *kvm);
-
-struct kvm_hva_range {
- unsigned long start;
- unsigned long end;
+struct kvm_mmu_notifier_range {
+ /*
+ * 64-bit addresses, as KVM notifiers can operate on host virtual
+ * addresses (unsigned long) and guest physical addresses (64-bit).
+ */
+ u64 start;
+ u64 end;
union kvm_mmu_notifier_arg arg;
- hva_handler_t handler;
+ gfn_handler_t handler;
on_lock_fn_t on_lock;
- on_unlock_fn_t on_unlock;
bool flush_on_ret;
bool may_block;
};
/*
+ * The inner-most helper returns a tuple containing the return value from the
+ * arch- and action-specific handler, plus a flag indicating whether or not at
+ * least one memslot was found, i.e. if the handler found guest memory.
+ *
+ * Note, most notifiers are averse to booleans, so even though KVM tracks the
+ * return from arch code as a bool, outer helpers will cast it to an int. :-(
+ */
+typedef struct kvm_mmu_notifier_return {
+ bool ret;
+ bool found_memslot;
+} kvm_mn_ret_t;
+
+/*
* Use a dedicated stub instead of NULL to indicate that there is no callback
* function/handler. The compiler technically can't guarantee that a real
* function will have a non-zero address, and so it will generate code to
@@ -578,26 +591,29 @@ static const union kvm_mmu_notifier_arg KVM_MMU_NOTIFIER_NO_ARG;
node; \
node = interval_tree_iter_next(node, start, last)) \
-static __always_inline int __kvm_handle_hva_range(struct kvm *kvm,
- const struct kvm_hva_range *range)
+static __always_inline kvm_mn_ret_t __kvm_handle_hva_range(struct kvm *kvm,
+ const struct kvm_mmu_notifier_range *range)
{
- bool ret = false, locked = false;
+ struct kvm_mmu_notifier_return r = {
+ .ret = false,
+ .found_memslot = false,
+ };
struct kvm_gfn_range gfn_range;
struct kvm_memory_slot *slot;
struct kvm_memslots *slots;
int i, idx;
if (WARN_ON_ONCE(range->end <= range->start))
- return 0;
+ return r;
/* A null handler is allowed if and only if on_lock() is provided. */
if (WARN_ON_ONCE(IS_KVM_NULL_FN(range->on_lock) &&
IS_KVM_NULL_FN(range->handler)))
- return 0;
+ return r;
idx = srcu_read_lock(&kvm->srcu);
- for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+ for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
struct interval_tree_node *node;
slots = __kvm_memslots(kvm, i);
@@ -606,9 +622,9 @@ static __always_inline int __kvm_handle_hva_range(struct kvm *kvm,
unsigned long hva_start, hva_end;
slot = container_of(node, struct kvm_memory_slot, hva_node[slots->node_idx]);
- hva_start = max(range->start, slot->userspace_addr);
- hva_end = min(range->end, slot->userspace_addr +
- (slot->npages << PAGE_SHIFT));
+ hva_start = max_t(unsigned long, range->start, slot->userspace_addr);
+ hva_end = min_t(unsigned long, range->end,
+ slot->userspace_addr + (slot->npages << PAGE_SHIFT));
/*
* To optimize for the likely case where the address
@@ -627,71 +643,66 @@ static __always_inline int __kvm_handle_hva_range(struct kvm *kvm,
gfn_range.end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, slot);
gfn_range.slot = slot;
- if (!locked) {
- locked = true;
+ if (!r.found_memslot) {
+ r.found_memslot = true;
KVM_MMU_LOCK(kvm);
if (!IS_KVM_NULL_FN(range->on_lock))
- range->on_lock(kvm, range->start, range->end);
+ range->on_lock(kvm);
+
if (IS_KVM_NULL_FN(range->handler))
break;
}
- ret |= range->handler(kvm, &gfn_range);
+ r.ret |= range->handler(kvm, &gfn_range);
}
}
- if (range->flush_on_ret && ret)
+ if (range->flush_on_ret && r.ret)
kvm_flush_remote_tlbs(kvm);
- if (locked) {
+ if (r.found_memslot)
KVM_MMU_UNLOCK(kvm);
- if (!IS_KVM_NULL_FN(range->on_unlock))
- range->on_unlock(kvm);
- }
srcu_read_unlock(&kvm->srcu, idx);
- /* The notifiers are averse to booleans. :-( */
- return (int)ret;
+ return r;
}
static __always_inline int kvm_handle_hva_range(struct mmu_notifier *mn,
unsigned long start,
unsigned long end,
union kvm_mmu_notifier_arg arg,
- hva_handler_t handler)
+ gfn_handler_t handler)
{
struct kvm *kvm = mmu_notifier_to_kvm(mn);
- const struct kvm_hva_range range = {
+ const struct kvm_mmu_notifier_range range = {
.start = start,
.end = end,
.arg = arg,
.handler = handler,
.on_lock = (void *)kvm_null_fn,
- .on_unlock = (void *)kvm_null_fn,
.flush_on_ret = true,
.may_block = false,
};
- return __kvm_handle_hva_range(kvm, &range);
+ return __kvm_handle_hva_range(kvm, &range).ret;
}
static __always_inline int kvm_handle_hva_range_no_flush(struct mmu_notifier *mn,
unsigned long start,
unsigned long end,
- hva_handler_t handler)
+ gfn_handler_t handler)
{
struct kvm *kvm = mmu_notifier_to_kvm(mn);
- const struct kvm_hva_range range = {
+ const struct kvm_mmu_notifier_range range = {
.start = start,
.end = end,
.handler = handler,
.on_lock = (void *)kvm_null_fn,
- .on_unlock = (void *)kvm_null_fn,
.flush_on_ret = false,
.may_block = false,
};
- return __kvm_handle_hva_range(kvm, &range);
+ return __kvm_handle_hva_range(kvm, &range).ret;
}
static bool kvm_change_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
@@ -736,16 +747,29 @@ static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn,
kvm_handle_hva_range(mn, address, address + 1, arg, kvm_change_spte_gfn);
}
-void kvm_mmu_invalidate_begin(struct kvm *kvm, unsigned long start,
- unsigned long end)
+void kvm_mmu_invalidate_begin(struct kvm *kvm)
{
+ lockdep_assert_held_write(&kvm->mmu_lock);
/*
* The count increase must become visible at unlock time as no
* spte can be established without taking the mmu_lock and
* count is also read inside the mmu_lock critical section.
*/
kvm->mmu_invalidate_in_progress++;
+
if (likely(kvm->mmu_invalidate_in_progress == 1)) {
+ kvm->mmu_invalidate_range_start = INVALID_GPA;
+ kvm->mmu_invalidate_range_end = INVALID_GPA;
+ }
+}
+
+void kvm_mmu_invalidate_range_add(struct kvm *kvm, gfn_t start, gfn_t end)
+{
+ lockdep_assert_held_write(&kvm->mmu_lock);
+
+ WARN_ON_ONCE(!kvm->mmu_invalidate_in_progress);
+
+ if (likely(kvm->mmu_invalidate_range_start == INVALID_GPA)) {
kvm->mmu_invalidate_range_start = start;
kvm->mmu_invalidate_range_end = end;
} else {
@@ -765,16 +789,21 @@ void kvm_mmu_invalidate_begin(struct kvm *kvm, unsigned long start,
}
}
+bool kvm_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
+{
+ kvm_mmu_invalidate_range_add(kvm, range->start, range->end);
+ return kvm_unmap_gfn_range(kvm, range);
+}
+
static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
const struct mmu_notifier_range *range)
{
struct kvm *kvm = mmu_notifier_to_kvm(mn);
- const struct kvm_hva_range hva_range = {
+ const struct kvm_mmu_notifier_range hva_range = {
.start = range->start,
.end = range->end,
- .handler = kvm_unmap_gfn_range,
+ .handler = kvm_mmu_unmap_gfn_range,
.on_lock = kvm_mmu_invalidate_begin,
- .on_unlock = kvm_arch_guest_memory_reclaimed,
.flush_on_ret = true,
.may_block = mmu_notifier_range_blockable(range),
};
@@ -806,14 +835,21 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
gfn_to_pfn_cache_invalidate_start(kvm, range->start, range->end,
hva_range.may_block);
- __kvm_handle_hva_range(kvm, &hva_range);
+ /*
+ * If one or more memslots were found and thus zapped, notify arch code
+ * that guest memory has been reclaimed. This needs to be done *after*
+ * dropping mmu_lock, as x86's reclaim path is slooooow.
+ */
+ if (__kvm_handle_hva_range(kvm, &hva_range).found_memslot)
+ kvm_arch_guest_memory_reclaimed(kvm);
return 0;
}
-void kvm_mmu_invalidate_end(struct kvm *kvm, unsigned long start,
- unsigned long end)
+void kvm_mmu_invalidate_end(struct kvm *kvm)
{
+ lockdep_assert_held_write(&kvm->mmu_lock);
+
/*
* This sequence increase will notify the kvm page fault that
* the page that is going to be mapped in the spte could have
@@ -827,18 +863,24 @@ void kvm_mmu_invalidate_end(struct kvm *kvm, unsigned long start,
* in conjunction with the smp_rmb in mmu_invalidate_retry().
*/
kvm->mmu_invalidate_in_progress--;
+ KVM_BUG_ON(kvm->mmu_invalidate_in_progress < 0, kvm);
+
+ /*
+ * Assert that at least one range was added between start() and end().
+ * Not adding a range isn't fatal, but it is a KVM bug.
+ */
+ WARN_ON_ONCE(kvm->mmu_invalidate_range_start == INVALID_GPA);
}
static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn,
const struct mmu_notifier_range *range)
{
struct kvm *kvm = mmu_notifier_to_kvm(mn);
- const struct kvm_hva_range hva_range = {
+ const struct kvm_mmu_notifier_range hva_range = {
.start = range->start,
.end = range->end,
.handler = (void *)kvm_null_fn,
.on_lock = kvm_mmu_invalidate_end,
- .on_unlock = (void *)kvm_null_fn,
.flush_on_ret = false,
.may_block = mmu_notifier_range_blockable(range),
};
@@ -857,8 +899,6 @@ static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn,
*/
if (wake)
rcuwait_wake_up(&kvm->mn_memslots_update_rcuwait);
-
- BUG_ON(kvm->mmu_invalidate_in_progress < 0);
}
static int kvm_mmu_notifier_clear_flush_young(struct mmu_notifier *mn,
@@ -932,14 +972,14 @@ static int kvm_init_mmu_notifier(struct kvm *kvm)
return mmu_notifier_register(&kvm->mmu_notifier, current->mm);
}
-#else /* !(CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER) */
+#else /* !CONFIG_KVM_GENERIC_MMU_NOTIFIER */
static int kvm_init_mmu_notifier(struct kvm *kvm)
{
return 0;
}
-#endif /* CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER */
+#endif /* CONFIG_KVM_GENERIC_MMU_NOTIFIER */
#ifdef CONFIG_HAVE_KVM_PM_NOTIFIER
static int kvm_pm_notifier_call(struct notifier_block *bl,
@@ -985,6 +1025,9 @@ static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot *memslot)
/* This does not remove the slot from struct kvm_memslots data structures */
static void kvm_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
{
+ if (slot->flags & KVM_MEM_GUEST_MEMFD)
+ kvm_gmem_unbind(slot);
+
kvm_destroy_dirty_bitmap(slot);
kvm_arch_free_memslot(kvm, slot);
@@ -1166,6 +1209,9 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
spin_lock_init(&kvm->mn_invalidate_lock);
rcuwait_init(&kvm->mn_memslots_update_rcuwait);
xa_init(&kvm->vcpu_array);
+#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
+ xa_init(&kvm->mem_attr_array);
+#endif
INIT_LIST_HEAD(&kvm->gpc_list);
spin_lock_init(&kvm->gpc_lock);
@@ -1190,7 +1236,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
goto out_err_no_irq_srcu;
refcount_set(&kvm->users_count, 1);
- for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+ for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
for (j = 0; j < 2; j++) {
slots = &kvm->__memslots[i][j];
@@ -1222,7 +1268,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname)
if (r)
goto out_err_no_disable;
-#ifdef CONFIG_HAVE_KVM_IRQFD
+#ifdef CONFIG_HAVE_KVM_IRQCHIP
INIT_HLIST_HEAD(&kvm->irq_ack_notifier_list);
#endif
@@ -1256,7 +1302,7 @@ out_err:
out_err_no_debugfs:
kvm_coalesced_mmio_free(kvm);
out_no_coalesced_mmio:
-#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
+#ifdef CONFIG_KVM_GENERIC_MMU_NOTIFIER
if (kvm->mmu_notifier.ops)
mmu_notifier_unregister(&kvm->mmu_notifier, current->mm);
#endif
@@ -1315,7 +1361,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
kvm->buses[i] = NULL;
}
kvm_coalesced_mmio_free(kvm);
-#if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)
+#ifdef CONFIG_KVM_GENERIC_MMU_NOTIFIER
mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm);
/*
* At this point, pending calls to invalidate_range_start()
@@ -1324,20 +1370,30 @@ static void kvm_destroy_vm(struct kvm *kvm)
* No threads can be waiting in kvm_swap_active_memslots() as the
* last reference on KVM has been dropped, but freeing
* memslots would deadlock without this manual intervention.
+ *
+ * If the count isn't unbalanced, i.e. KVM did NOT unregister its MMU
+ * notifier between a start() and end(), then there shouldn't be any
+ * in-progress invalidations.
*/
WARN_ON(rcuwait_active(&kvm->mn_memslots_update_rcuwait));
- kvm->mn_active_invalidate_count = 0;
+ if (kvm->mn_active_invalidate_count)
+ kvm->mn_active_invalidate_count = 0;
+ else
+ WARN_ON(kvm->mmu_invalidate_in_progress);
#else
kvm_flush_shadow_all(kvm);
#endif
kvm_arch_destroy_vm(kvm);
kvm_destroy_devices(kvm);
- for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+ for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
kvm_free_memslots(kvm, &kvm->__memslots[i][0]);
kvm_free_memslots(kvm, &kvm->__memslots[i][1]);
}
cleanup_srcu_struct(&kvm->irq_srcu);
cleanup_srcu_struct(&kvm->srcu);
+#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
+ xa_destroy(&kvm->mem_attr_array);
+#endif
kvm_arch_free_vm(kvm);
preempt_notifier_dec();
hardware_disable_all();
@@ -1538,10 +1594,26 @@ static void kvm_replace_memslot(struct kvm *kvm,
}
}
-static int check_memory_region_flags(const struct kvm_userspace_memory_region *mem)
+/*
+ * Flags that do not access any of the extra space of struct
+ * kvm_userspace_memory_region2. KVM_SET_USER_MEMORY_REGION_V1_FLAGS
+ * only allows these.
+ */
+#define KVM_SET_USER_MEMORY_REGION_V1_FLAGS \
+ (KVM_MEM_LOG_DIRTY_PAGES | KVM_MEM_READONLY)
+
+static int check_memory_region_flags(struct kvm *kvm,
+ const struct kvm_userspace_memory_region2 *mem)
{
u32 valid_flags = KVM_MEM_LOG_DIRTY_PAGES;
+ if (kvm_arch_has_private_mem(kvm))
+ valid_flags |= KVM_MEM_GUEST_MEMFD;
+
+ /* Dirty logging private memory is not currently supported. */
+ if (mem->flags & KVM_MEM_GUEST_MEMFD)
+ valid_flags &= ~KVM_MEM_LOG_DIRTY_PAGES;
+
#ifdef __KVM_HAVE_READONLY_MEM
valid_flags |= KVM_MEM_READONLY;
#endif
@@ -1603,7 +1675,7 @@ static void kvm_swap_active_memslots(struct kvm *kvm, int as_id)
* space 0 will use generations 0, 2, 4, ... while address space 1 will
* use generations 1, 3, 5, ...
*/
- gen += KVM_ADDRESS_SPACE_NUM;
+ gen += kvm_arch_nr_memslot_as_ids(kvm);
kvm_arch_memslots_updated(kvm, gen);
@@ -1940,7 +2012,7 @@ static bool kvm_check_memslot_overlap(struct kvm_memslots *slots, int id,
* Must be called holding kvm->slots_lock for write.
*/
int __kvm_set_memory_region(struct kvm *kvm,
- const struct kvm_userspace_memory_region *mem)
+ const struct kvm_userspace_memory_region2 *mem)
{
struct kvm_memory_slot *old, *new;
struct kvm_memslots *slots;
@@ -1950,7 +2022,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
int as_id, id;
int r;
- r = check_memory_region_flags(mem);
+ r = check_memory_region_flags(kvm, mem);
if (r)
return r;
@@ -1969,7 +2041,11 @@ int __kvm_set_memory_region(struct kvm *kvm,
!access_ok((void __user *)(unsigned long)mem->userspace_addr,
mem->memory_size))
return -EINVAL;
- if (as_id >= KVM_ADDRESS_SPACE_NUM || id >= KVM_MEM_SLOTS_NUM)
+ if (mem->flags & KVM_MEM_GUEST_MEMFD &&
+ (mem->guest_memfd_offset & (PAGE_SIZE - 1) ||
+ mem->guest_memfd_offset + mem->memory_size < mem->guest_memfd_offset))
+ return -EINVAL;
+ if (as_id >= kvm_arch_nr_memslot_as_ids(kvm) || id >= KVM_MEM_SLOTS_NUM)
return -EINVAL;
if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr)
return -EINVAL;
@@ -2007,6 +2083,9 @@ int __kvm_set_memory_region(struct kvm *kvm,
if ((kvm->nr_memslot_pages + npages) < kvm->nr_memslot_pages)
return -EINVAL;
} else { /* Modify an existing slot. */
+ /* Private memslots are immutable, they can only be deleted. */
+ if (mem->flags & KVM_MEM_GUEST_MEMFD)
+ return -EINVAL;
if ((mem->userspace_addr != old->userspace_addr) ||
(npages != old->npages) ||
((mem->flags ^ old->flags) & KVM_MEM_READONLY))
@@ -2035,16 +2114,29 @@ int __kvm_set_memory_region(struct kvm *kvm,
new->npages = npages;
new->flags = mem->flags;
new->userspace_addr = mem->userspace_addr;
+ if (mem->flags & KVM_MEM_GUEST_MEMFD) {
+ r = kvm_gmem_bind(kvm, new, mem->guest_memfd, mem->guest_memfd_offset);
+ if (r)
+ goto out;
+ }
r = kvm_set_memslot(kvm, old, new, change);
if (r)
- kfree(new);
+ goto out_unbind;
+
+ return 0;
+
+out_unbind:
+ if (mem->flags & KVM_MEM_GUEST_MEMFD)
+ kvm_gmem_unbind(new);
+out:
+ kfree(new);
return r;
}
EXPORT_SYMBOL_GPL(__kvm_set_memory_region);
int kvm_set_memory_region(struct kvm *kvm,
- const struct kvm_userspace_memory_region *mem)
+ const struct kvm_userspace_memory_region2 *mem)
{
int r;
@@ -2056,7 +2148,7 @@ int kvm_set_memory_region(struct kvm *kvm,
EXPORT_SYMBOL_GPL(kvm_set_memory_region);
static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
- struct kvm_userspace_memory_region *mem)
+ struct kvm_userspace_memory_region2 *mem)
{
if ((u16)mem->slot >= KVM_USER_MEM_SLOTS)
return -EINVAL;
@@ -2089,7 +2181,7 @@ int kvm_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log,
as_id = log->slot >> 16;
id = (u16)log->slot;
- if (as_id >= KVM_ADDRESS_SPACE_NUM || id >= KVM_USER_MEM_SLOTS)
+ if (as_id >= kvm_arch_nr_memslot_as_ids(kvm) || id >= KVM_USER_MEM_SLOTS)
return -EINVAL;
slots = __kvm_memslots(kvm, as_id);
@@ -2151,7 +2243,7 @@ static int kvm_get_dirty_log_protect(struct kvm *kvm, struct kvm_dirty_log *log)
as_id = log->slot >> 16;
id = (u16)log->slot;
- if (as_id >= KVM_ADDRESS_SPACE_NUM || id >= KVM_USER_MEM_SLOTS)
+ if (as_id >= kvm_arch_nr_memslot_as_ids(kvm) || id >= KVM_USER_MEM_SLOTS)
return -EINVAL;
slots = __kvm_memslots(kvm, as_id);
@@ -2263,7 +2355,7 @@ static int kvm_clear_dirty_log_protect(struct kvm *kvm,
as_id = log->slot >> 16;
id = (u16)log->slot;
- if (as_id >= KVM_ADDRESS_SPACE_NUM || id >= KVM_USER_MEM_SLOTS)
+ if (as_id >= kvm_arch_nr_memslot_as_ids(kvm) || id >= KVM_USER_MEM_SLOTS)
return -EINVAL;
if (log->first_page & 63)
@@ -2335,6 +2427,200 @@ static int kvm_vm_ioctl_clear_dirty_log(struct kvm *kvm,
}
#endif /* CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT */
+#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
+/*
+ * Returns true if _all_ gfns in the range [@start, @end) have attributes
+ * matching @attrs.
+ */
+bool kvm_range_has_memory_attributes(struct kvm *kvm, gfn_t start, gfn_t end,
+ unsigned long attrs)
+{
+ XA_STATE(xas, &kvm->mem_attr_array, start);
+ unsigned long index;
+ bool has_attrs;
+ void *entry;
+
+ rcu_read_lock();
+
+ if (!attrs) {
+ has_attrs = !xas_find(&xas, end - 1);
+ goto out;
+ }
+
+ has_attrs = true;
+ for (index = start; index < end; index++) {
+ do {
+ entry = xas_next(&xas);
+ } while (xas_retry(&xas, entry));
+
+ if (xas.xa_index != index || xa_to_value(entry) != attrs) {
+ has_attrs = false;
+ break;
+ }
+ }
+
+out:
+ rcu_read_unlock();
+ return has_attrs;
+}
+
+static u64 kvm_supported_mem_attributes(struct kvm *kvm)
+{
+ if (!kvm || kvm_arch_has_private_mem(kvm))
+ return KVM_MEMORY_ATTRIBUTE_PRIVATE;
+
+ return 0;
+}
+
+static __always_inline void kvm_handle_gfn_range(struct kvm *kvm,
+ struct kvm_mmu_notifier_range *range)
+{
+ struct kvm_gfn_range gfn_range;
+ struct kvm_memory_slot *slot;
+ struct kvm_memslots *slots;
+ struct kvm_memslot_iter iter;
+ bool found_memslot = false;
+ bool ret = false;
+ int i;
+
+ gfn_range.arg = range->arg;
+ gfn_range.may_block = range->may_block;
+
+ for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
+ slots = __kvm_memslots(kvm, i);
+
+ kvm_for_each_memslot_in_gfn_range(&iter, slots, range->start, range->end) {
+ slot = iter.slot;
+ gfn_range.slot = slot;
+
+ gfn_range.start = max(range->start, slot->base_gfn);
+ gfn_range.end = min(range->end, slot->base_gfn + slot->npages);
+ if (gfn_range.start >= gfn_range.end)
+ continue;
+
+ if (!found_memslot) {
+ found_memslot = true;
+ KVM_MMU_LOCK(kvm);
+ if (!IS_KVM_NULL_FN(range->on_lock))
+ range->on_lock(kvm);
+ }
+
+ ret |= range->handler(kvm, &gfn_range);
+ }
+ }
+
+ if (range->flush_on_ret && ret)
+ kvm_flush_remote_tlbs(kvm);
+
+ if (found_memslot)
+ KVM_MMU_UNLOCK(kvm);
+}
+
+static bool kvm_pre_set_memory_attributes(struct kvm *kvm,
+ struct kvm_gfn_range *range)
+{
+ /*
+ * Unconditionally add the range to the invalidation set, regardless of
+ * whether or not the arch callback actually needs to zap SPTEs. E.g.
+ * if KVM supports RWX attributes in the future and the attributes are
+ * going from R=>RW, zapping isn't strictly necessary. Unconditionally
+ * adding the range allows KVM to require that MMU invalidations add at
+ * least one range between begin() and end(), e.g. allows KVM to detect
+ * bugs where the add() is missed. Relaxing the rule *might* be safe,
+ * but it's not obvious that allowing new mappings while the attributes
+ * are in flux is desirable or worth the complexity.
+ */
+ kvm_mmu_invalidate_range_add(kvm, range->start, range->end);
+
+ return kvm_arch_pre_set_memory_attributes(kvm, range);
+}
+
+/* Set @attributes for the gfn range [@start, @end). */
+static int kvm_vm_set_mem_attributes(struct kvm *kvm, gfn_t start, gfn_t end,
+ unsigned long attributes)
+{
+ struct kvm_mmu_notifier_range pre_set_range = {
+ .start = start,
+ .end = end,
+ .handler = kvm_pre_set_memory_attributes,
+ .on_lock = kvm_mmu_invalidate_begin,
+ .flush_on_ret = true,
+ .may_block = true,
+ };
+ struct kvm_mmu_notifier_range post_set_range = {
+ .start = start,
+ .end = end,
+ .arg.attributes = attributes,
+ .handler = kvm_arch_post_set_memory_attributes,
+ .on_lock = kvm_mmu_invalidate_end,
+ .may_block = true,
+ };
+ unsigned long i;
+ void *entry;
+ int r = 0;
+
+ entry = attributes ? xa_mk_value(attributes) : NULL;
+
+ mutex_lock(&kvm->slots_lock);
+
+ /* Nothing to do if the entire range as the desired attributes. */
+ if (kvm_range_has_memory_attributes(kvm, start, end, attributes))
+ goto out_unlock;
+
+ /*
+ * Reserve memory ahead of time to avoid having to deal with failures
+ * partway through setting the new attributes.
+ */
+ for (i = start; i < end; i++) {
+ r = xa_reserve(&kvm->mem_attr_array, i, GFP_KERNEL_ACCOUNT);
+ if (r)
+ goto out_unlock;
+ }
+
+ kvm_handle_gfn_range(kvm, &pre_set_range);
+
+ for (i = start; i < end; i++) {
+ r = xa_err(xa_store(&kvm->mem_attr_array, i, entry,
+ GFP_KERNEL_ACCOUNT));
+ KVM_BUG_ON(r, kvm);
+ }
+
+ kvm_handle_gfn_range(kvm, &post_set_range);
+
+out_unlock:
+ mutex_unlock(&kvm->slots_lock);
+
+ return r;
+}
+static int kvm_vm_ioctl_set_mem_attributes(struct kvm *kvm,
+ struct kvm_memory_attributes *attrs)
+{
+ gfn_t start, end;
+
+ /* flags is currently not used. */
+ if (attrs->flags)
+ return -EINVAL;
+ if (attrs->attributes & ~kvm_supported_mem_attributes(kvm))
+ return -EINVAL;
+ if (attrs->size == 0 || attrs->address + attrs->size < attrs->address)
+ return -EINVAL;
+ if (!PAGE_ALIGNED(attrs->address) || !PAGE_ALIGNED(attrs->size))
+ return -EINVAL;
+
+ start = attrs->address >> PAGE_SHIFT;
+ end = (attrs->address + attrs->size) >> PAGE_SHIFT;
+
+ /*
+ * xarray tracks data using "unsigned long", and as a result so does
+ * KVM. For simplicity, supports generic attributes only on 64-bit
+ * architectures.
+ */
+ BUILD_BUG_ON(sizeof(attrs->attributes) != sizeof(unsigned long));
+
+ return kvm_vm_set_mem_attributes(kvm, start, end, attrs->attributes);
+}
+#endif /* CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES */
+
struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
{
return __gfn_to_memslot(kvm_memslots(kvm), gfn);
@@ -4527,13 +4813,14 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
{
switch (arg) {
case KVM_CAP_USER_MEMORY:
+ case KVM_CAP_USER_MEMORY2:
case KVM_CAP_DESTROY_MEMORY_REGION_WORKS:
case KVM_CAP_JOIN_MEMORY_REGIONS_WORKS:
case KVM_CAP_INTERNAL_ERROR_DATA:
#ifdef CONFIG_HAVE_KVM_MSI
case KVM_CAP_SIGNAL_MSI:
#endif
-#ifdef CONFIG_HAVE_KVM_IRQFD
+#ifdef CONFIG_HAVE_KVM_IRQCHIP
case KVM_CAP_IRQFD:
#endif
case KVM_CAP_IOEVENTFD_ANY_LENGTH:
@@ -4555,9 +4842,11 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
case KVM_CAP_IRQ_ROUTING:
return KVM_MAX_IRQ_ROUTES;
#endif
-#if KVM_ADDRESS_SPACE_NUM > 1
+#if KVM_MAX_NR_ADDRESS_SPACES > 1
case KVM_CAP_MULTI_ADDRESS_SPACE:
- return KVM_ADDRESS_SPACE_NUM;
+ if (kvm)
+ return kvm_arch_nr_memslot_as_ids(kvm);
+ return KVM_MAX_NR_ADDRESS_SPACES;
#endif
case KVM_CAP_NR_MEMSLOTS:
return KVM_USER_MEM_SLOTS;
@@ -4578,7 +4867,16 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
#endif
case KVM_CAP_BINARY_STATS_FD:
case KVM_CAP_SYSTEM_EVENT_DATA:
+ case KVM_CAP_DEVICE_CTRL:
return 1;
+#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
+ case KVM_CAP_MEMORY_ATTRIBUTES:
+ return kvm_supported_mem_attributes(kvm);
+#endif
+#ifdef CONFIG_KVM_PRIVATE_MEM
+ case KVM_CAP_GUEST_MEMFD:
+ return !kvm || kvm_arch_has_private_mem(kvm);
+#endif
default:
break;
}
@@ -4657,7 +4955,7 @@ bool kvm_are_all_memslots_empty(struct kvm *kvm)
lockdep_assert_held(&kvm->slots_lock);
- for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
+ for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
if (!kvm_memslots_empty(__kvm_memslots(kvm, i)))
return false;
}
@@ -4783,6 +5081,14 @@ static int kvm_vm_ioctl_get_stats_fd(struct kvm *kvm)
return fd;
}
+#define SANITY_CHECK_MEM_REGION_FIELD(field) \
+do { \
+ BUILD_BUG_ON(offsetof(struct kvm_userspace_memory_region, field) != \
+ offsetof(struct kvm_userspace_memory_region2, field)); \
+ BUILD_BUG_ON(sizeof_field(struct kvm_userspace_memory_region, field) != \
+ sizeof_field(struct kvm_userspace_memory_region2, field)); \
+} while (0)
+
static long kvm_vm_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -4805,15 +5111,39 @@ static long kvm_vm_ioctl(struct file *filp,
r = kvm_vm_ioctl_enable_cap_generic(kvm, &cap);
break;
}
+ case KVM_SET_USER_MEMORY_REGION2:
case KVM_SET_USER_MEMORY_REGION: {
- struct kvm_userspace_memory_region kvm_userspace_mem;
+ struct kvm_userspace_memory_region2 mem;
+ unsigned long size;
+
+ if (ioctl == KVM_SET_USER_MEMORY_REGION) {
+ /*
+ * Fields beyond struct kvm_userspace_memory_region shouldn't be
+ * accessed, but avoid leaking kernel memory in case of a bug.
+ */
+ memset(&mem, 0, sizeof(mem));
+ size = sizeof(struct kvm_userspace_memory_region);
+ } else {
+ size = sizeof(struct kvm_userspace_memory_region2);
+ }
+
+ /* Ensure the common parts of the two structs are identical. */
+ SANITY_CHECK_MEM_REGION_FIELD(slot);
+ SANITY_CHECK_MEM_REGION_FIELD(flags);
+ SANITY_CHECK_MEM_REGION_FIELD(guest_phys_addr);
+ SANITY_CHECK_MEM_REGION_FIELD(memory_size);
+ SANITY_CHECK_MEM_REGION_FIELD(userspace_addr);
r = -EFAULT;
- if (copy_from_user(&kvm_userspace_mem, argp,
- sizeof(kvm_userspace_mem)))
+ if (copy_from_user(&mem, argp, size))
goto out;
- r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem);
+ r = -EINVAL;
+ if (ioctl == KVM_SET_USER_MEMORY_REGION &&
+ (mem.flags & ~KVM_SET_USER_MEMORY_REGION_V1_FLAGS))
+ goto out;
+
+ r = kvm_vm_ioctl_set_memory_region(kvm, &mem);
break;
}
case KVM_GET_DIRTY_LOG: {
@@ -4927,9 +5257,8 @@ static long kvm_vm_ioctl(struct file *filp,
goto out;
if (routing.nr) {
urouting = argp;
- entries = vmemdup_user(urouting->entries,
- array_size(sizeof(*entries),
- routing.nr));
+ entries = vmemdup_array_user(urouting->entries,
+ routing.nr, sizeof(*entries));
if (IS_ERR(entries)) {
r = PTR_ERR(entries);
goto out;
@@ -4941,6 +5270,18 @@ static long kvm_vm_ioctl(struct file *filp,
break;
}
#endif /* CONFIG_HAVE_KVM_IRQ_ROUTING */
+#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES
+ case KVM_SET_MEMORY_ATTRIBUTES: {
+ struct kvm_memory_attributes attrs;
+
+ r = -EFAULT;
+ if (copy_from_user(&attrs, argp, sizeof(attrs)))
+ goto out;
+
+ r = kvm_vm_ioctl_set_mem_attributes(kvm, &attrs);
+ break;
+ }
+#endif /* CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES */
case KVM_CREATE_DEVICE: {
struct kvm_create_device cd;
@@ -4968,6 +5309,18 @@ static long kvm_vm_ioctl(struct file *filp,
case KVM_GET_STATS_FD:
r = kvm_vm_ioctl_get_stats_fd(kvm);
break;
+#ifdef CONFIG_KVM_PRIVATE_MEM
+ case KVM_CREATE_GUEST_MEMFD: {
+ struct kvm_create_guest_memfd guest_memfd;
+
+ r = -EFAULT;
+ if (copy_from_user(&guest_memfd, argp, sizeof(guest_memfd)))
+ goto out;
+
+ r = kvm_gmem_create(kvm, &guest_memfd);
+ break;
+ }
+#endif
default:
r = kvm_arch_vm_ioctl(filp, ioctl, arg);
}
@@ -5139,11 +5492,6 @@ static long kvm_dev_ioctl(struct file *filp,
r += PAGE_SIZE; /* coalesced mmio ring page */
#endif
break;
- case KVM_TRACE_ENABLE:
- case KVM_TRACE_PAUSE:
- case KVM_TRACE_DISABLE:
- r = -EOPNOTSUPP;
- break;
default:
return kvm_arch_dev_ioctl(filp, ioctl, arg);
}
@@ -6104,6 +6452,8 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)
if (WARN_ON_ONCE(r))
goto err_vfio;
+ kvm_gmem_init(module);
+
/*
* Registration _must_ be the very last thing done, as this exposes
* /dev/kvm to userspace, i.e. all infrastructure must be setup!
diff --git a/virt/kvm/kvm_mm.h b/virt/kvm/kvm_mm.h
index 180f1a09e6ba..ecefc7ec51af 100644
--- a/virt/kvm/kvm_mm.h
+++ b/virt/kvm/kvm_mm.h
@@ -37,4 +37,30 @@ static inline void gfn_to_pfn_cache_invalidate_start(struct kvm *kvm,
}
#endif /* HAVE_KVM_PFNCACHE */
+#ifdef CONFIG_KVM_PRIVATE_MEM
+void kvm_gmem_init(struct module *module);
+int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args);
+int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
+ unsigned int fd, loff_t offset);
+void kvm_gmem_unbind(struct kvm_memory_slot *slot);
+#else
+static inline void kvm_gmem_init(struct module *module)
+{
+
+}
+
+static inline int kvm_gmem_bind(struct kvm *kvm,
+ struct kvm_memory_slot *slot,
+ unsigned int fd, loff_t offset)
+{
+ WARN_ON_ONCE(1);
+ return -EIO;
+}
+
+static inline void kvm_gmem_unbind(struct kvm_memory_slot *slot)
+{
+ WARN_ON_ONCE(1);
+}
+#endif /* CONFIG_KVM_PRIVATE_MEM */
+
#endif /* __KVM_MM_H__ */